1fa225cbcSrjs/* -*- c-basic-offset: 4 -*- */ 2fa225cbcSrjs/* 3fa225cbcSrjs * Copyright � 2006 Intel Corporation 4fa225cbcSrjs * 5fa225cbcSrjs * Permission is hereby granted, free of charge, to any person obtaining a 6fa225cbcSrjs * copy of this software and associated documentation files (the "Software"), 7fa225cbcSrjs * to deal in the Software without restriction, including without limitation 8fa225cbcSrjs * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9fa225cbcSrjs * and/or sell copies of the Software, and to permit persons to whom the 10fa225cbcSrjs * Software is furnished to do so, subject to the following conditions: 11fa225cbcSrjs * 12fa225cbcSrjs * The above copyright notice and this permission notice (including the next 13fa225cbcSrjs * paragraph) shall be included in all copies or substantial portions of the 14fa225cbcSrjs * Software. 15fa225cbcSrjs * 16fa225cbcSrjs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17fa225cbcSrjs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18fa225cbcSrjs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19fa225cbcSrjs * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20fa225cbcSrjs * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21fa225cbcSrjs * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22fa225cbcSrjs * SOFTWARE. 23fa225cbcSrjs * 24fa225cbcSrjs * Authors: 25fa225cbcSrjs * Eric Anholt <eric@anholt.net> 26fa225cbcSrjs * 27fa225cbcSrjs */ 28fa225cbcSrjs 29fa225cbcSrjs#ifdef HAVE_CONFIG_H 30fa225cbcSrjs#include "config.h" 31fa225cbcSrjs#endif 32fa225cbcSrjs 33fa225cbcSrjs#include <unistd.h> 34fa225cbcSrjs#include <string.h> 35fa225cbcSrjs#include <assert.h> 36fa225cbcSrjs#include <stdlib.h> 37fa225cbcSrjs#include <math.h> 38fa225cbcSrjs#include <sys/ioctl.h> 39fa225cbcSrjs 40fa225cbcSrjs#include "xf86.h" 41fa225cbcSrjs#include "i830.h" 42fa225cbcSrjs#include "i830_bios.h" 43fa225cbcSrjs#include "i830_display.h" 44fa225cbcSrjs#include "i830_debug.h" 45fa225cbcSrjs#include "xf86Modes.h" 46fa225cbcSrjs 47fa225cbcSrjstypedef struct { 48fa225cbcSrjs /* given values */ 49fa225cbcSrjs int n; 50fa225cbcSrjs int m1, m2; 51fa225cbcSrjs int p1, p2; 52fa225cbcSrjs /* derived values */ 53fa225cbcSrjs int dot; 54fa225cbcSrjs int vco; 55fa225cbcSrjs int m; 56fa225cbcSrjs int p; 57fa225cbcSrjs} intel_clock_t; 58fa225cbcSrjs 59fa225cbcSrjstypedef struct { 60fa225cbcSrjs int min, max; 61fa225cbcSrjs} intel_range_t; 62fa225cbcSrjs 63fa225cbcSrjstypedef struct { 64fa225cbcSrjs int dot_limit; 65fa225cbcSrjs int p2_slow, p2_fast; 66fa225cbcSrjs} intel_p2_t; 67fa225cbcSrjs 68fa225cbcSrjs#define INTEL_P2_NUM 2 69fa225cbcSrjs 70fa225cbcSrjstypedef struct intel_limit intel_limit_t; 71fa225cbcSrjsstruct intel_limit { 72fa225cbcSrjs intel_range_t dot, vco, n, m, m1, m2, p, p1; 73fa225cbcSrjs intel_p2_t p2; 74fa225cbcSrjs Bool (* find_pll)(const intel_limit_t *, xf86CrtcPtr, 75fa225cbcSrjs int, int, intel_clock_t *); 76fa225cbcSrjs}; 77fa225cbcSrjs 78fa225cbcSrjs#define I8XX_DOT_MIN 25000 79fa225cbcSrjs#define I8XX_DOT_MAX 350000 80fa225cbcSrjs#define I8XX_VCO_MIN 930000 81fa225cbcSrjs#define I8XX_VCO_MAX 1400000 82fa225cbcSrjs#define I8XX_N_MIN 3 83fa225cbcSrjs#define I8XX_N_MAX 16 84fa225cbcSrjs#define I8XX_M_MIN 96 85fa225cbcSrjs#define I8XX_M_MAX 140 86fa225cbcSrjs#define I8XX_M1_MIN 18 87fa225cbcSrjs#define I8XX_M1_MAX 26 88fa225cbcSrjs#define I8XX_M2_MIN 6 89fa225cbcSrjs#define I8XX_M2_MAX 16 90fa225cbcSrjs#define I8XX_P_MIN 4 91fa225cbcSrjs#define I8XX_P_MAX 128 92fa225cbcSrjs#define I8XX_P1_MIN 2 93fa225cbcSrjs#define I8XX_P1_MAX 33 94fa225cbcSrjs#define I8XX_P1_LVDS_MIN 1 95fa225cbcSrjs#define I8XX_P1_LVDS_MAX 6 96fa225cbcSrjs#define I8XX_P2_SLOW 4 97fa225cbcSrjs#define I8XX_P2_FAST 2 98fa225cbcSrjs#define I8XX_P2_LVDS_SLOW 14 99fa225cbcSrjs#define I8XX_P2_LVDS_FAST 7 100fa225cbcSrjs#define I8XX_P2_SLOW_LIMIT 165000 101fa225cbcSrjs 102fa225cbcSrjs#define I9XX_DOT_MIN 20000 103fa225cbcSrjs#define I9XX_DOT_MAX 400000 104fa225cbcSrjs#define I9XX_VCO_MIN 1400000 105fa225cbcSrjs#define I9XX_VCO_MAX 2800000 106fa225cbcSrjs#define IGD_VCO_MIN 1700000 107fa225cbcSrjs#define IGD_VCO_MAX 3500000 108fa225cbcSrjs 109fa225cbcSrjs/* Haven't found any reason to go this fast, but newer chips support it */ 110fa225cbcSrjs#define I96X_VCO_MAX 3200000 111fa225cbcSrjs 112fa225cbcSrjs/* 113fa225cbcSrjs * These values are taken from the broadwater/crestline PLL spreadsheet. 114fa225cbcSrjs * All of the defines here are for the programmed register value, not 115fa225cbcSrjs * the 'counter' value (e.g. Ncounter = Nregister + 2) 116fa225cbcSrjs */ 117fa225cbcSrjs#define I9XX_N_MIN 1 118fa225cbcSrjs#define I9XX_N_MAX 6 119fa225cbcSrjs/* IGD's Ncounter is a ring counter */ 120fa225cbcSrjs#define IGD_N_MIN 3 121fa225cbcSrjs#define IGD_N_MAX 6 122fa225cbcSrjs#define I9XX_M_MIN 70 123fa225cbcSrjs#define I9XX_M_MAX 120 124fa225cbcSrjs#define IGD_M_MIN 2 125fa225cbcSrjs#define IGD_M_MAX 256 126fa225cbcSrjs 127fa225cbcSrjs/* these two come from the calm1 macro */ 128fa225cbcSrjs#define I9XX_M1_MIN 10 129fa225cbcSrjs#define I9XX_M1_MAX 22 130fa225cbcSrjs#define I9XX_M2_MIN 5 131fa225cbcSrjs#define I9XX_M2_MAX 9 132fa225cbcSrjs/* IGD M1 is reserved, and must be 0 */ 133fa225cbcSrjs#define IGD_M1_MIN 0 134fa225cbcSrjs#define IGD_M1_MAX 0 135fa225cbcSrjs#define IGD_M2_MIN 0 136fa225cbcSrjs#define IGD_M2_MAX 254 137fa225cbcSrjs 138fa225cbcSrjs#define I9XX_P_SDVO_DAC_MIN 5 139fa225cbcSrjs#define I9XX_P_SDVO_DAC_MAX 80 140fa225cbcSrjs#define I9XX_P_LVDS_MIN 7 141fa225cbcSrjs#define I9XX_P_LVDS_MAX 98 142fa225cbcSrjs#define IGD_P_LVDS_MIN 7 143fa225cbcSrjs#define IGD_P_LVDS_MAX 112 144fa225cbcSrjs#define I9XX_P1_MIN 1 145fa225cbcSrjs#define I9XX_P1_MAX 8 146fa225cbcSrjs#define I9XX_P2_SDVO_DAC_SLOW 10 147fa225cbcSrjs#define I9XX_P2_SDVO_DAC_FAST 5 148fa225cbcSrjs#define I9XX_P2_SDVO_DAC_SLOW_LIMIT 200000 149fa225cbcSrjs#define I9XX_P2_LVDS_SLOW 14 150fa225cbcSrjs#define I9XX_P2_LVDS_FAST 7 151fa225cbcSrjs#define I9XX_P2_LVDS_SLOW_LIMIT 112000 152fa225cbcSrjs 153fa225cbcSrjs#define INTEL_LIMIT_I8XX_DVO_DAC 0 154fa225cbcSrjs#define INTEL_LIMIT_I8XX_LVDS 1 155fa225cbcSrjs#define INTEL_LIMIT_I9XX_SDVO_DAC 2 156fa225cbcSrjs#define INTEL_LIMIT_I9XX_LVDS 3 157fa225cbcSrjs#define INTEL_LIMIT_IGD_SDVO_DAC 4 158fa225cbcSrjs#define INTEL_LIMIT_IGD_LVDS 5 159fa225cbcSrjs#define INTEL_LIMIT_G4X_SDVO 6 160fa225cbcSrjs#define INTEL_LIMIT_G4X_HDMI_DAC 7 161fa225cbcSrjs#define INTEL_LIMIT_G4X_SINGLE_LVDS 8 162fa225cbcSrjs#define INTEL_LIMIT_G4X_DUAL_LVDS 9 163fa225cbcSrjs 164fa225cbcSrjs/*The parameter is for SDVO on G4x platform*/ 165fa225cbcSrjs#define G4X_VCO_MIN 1750000 166fa225cbcSrjs#define G4X_VCO_MAX 3500000 167fa225cbcSrjs#define G4X_DOT_SDVO_MIN 25000 168fa225cbcSrjs#define G4X_DOT_SDVO_MAX 270000 169fa225cbcSrjs#define G4X_N_SDVO_MIN 1 170fa225cbcSrjs#define G4X_N_SDVO_MAX 4 171fa225cbcSrjs#define G4X_M_SDVO_MIN 104 172fa225cbcSrjs#define G4X_M_SDVO_MAX 138 173fa225cbcSrjs#define G4X_M1_SDVO_MIN 17 174fa225cbcSrjs#define G4X_M1_SDVO_MAX 23 175fa225cbcSrjs#define G4X_M2_SDVO_MIN 5 176fa225cbcSrjs#define G4X_M2_SDVO_MAX 11 177fa225cbcSrjs#define G4X_P_SDVO_MIN 10 178fa225cbcSrjs#define G4X_P_SDVO_MAX 30 179fa225cbcSrjs#define G4X_P1_SDVO_MIN 1 180fa225cbcSrjs#define G4X_P1_SDVO_MAX 3 181fa225cbcSrjs#define G4X_P2_SDVO_SLOW 10 182fa225cbcSrjs#define G4X_P2_SDVO_FAST 10 183fa225cbcSrjs#define G4X_P2_SDVO_LIMIT 270000 184fa225cbcSrjs 185fa225cbcSrjs/*The parameter is for HDMI_DAC on G4x platform*/ 186fa225cbcSrjs#define G4X_DOT_HDMI_DAC_MIN 22000 187fa225cbcSrjs#define G4X_DOT_HDMI_DAC_MAX 400000 188fa225cbcSrjs#define G4X_N_HDMI_DAC_MIN 1 189fa225cbcSrjs#define G4X_N_HDMI_DAC_MAX 4 190fa225cbcSrjs#define G4X_M_HDMI_DAC_MIN 104 191fa225cbcSrjs#define G4X_M_HDMI_DAC_MAX 138 192fa225cbcSrjs#define G4X_M1_HDMI_DAC_MIN 16 193fa225cbcSrjs#define G4X_M1_HDMI_DAC_MAX 23 194fa225cbcSrjs#define G4X_M2_HDMI_DAC_MIN 5 195fa225cbcSrjs#define G4X_M2_HDMI_DAC_MAX 11 196fa225cbcSrjs#define G4X_P_HDMI_DAC_MIN 5 197fa225cbcSrjs#define G4X_P_HDMI_DAC_MAX 80 198fa225cbcSrjs#define G4X_P1_HDMI_DAC_MIN 1 199fa225cbcSrjs#define G4X_P1_HDMI_DAC_MAX 8 200fa225cbcSrjs#define G4X_P2_HDMI_DAC_SLOW 10 201fa225cbcSrjs#define G4X_P2_HDMI_DAC_FAST 5 202fa225cbcSrjs#define G4X_P2_HDMI_DAC_LIMIT 165000 203fa225cbcSrjs 204fa225cbcSrjs/*The parameter is for SINGLE_LVDS on G4x platform*/ 205fa225cbcSrjs#define G4X_DOT_SINGLE_LVDS_MIN 20000 206fa225cbcSrjs#define G4X_DOT_SINGLE_LVDS_MAX 115000 207fa225cbcSrjs#define G4X_N_SINGLE_LVDS_MIN 1 208fa225cbcSrjs#define G4X_N_SINGLE_LVDS_MAX 3 209fa225cbcSrjs#define G4X_M_SINGLE_LVDS_MIN 104 210fa225cbcSrjs#define G4X_M_SINGLE_LVDS_MAX 138 211fa225cbcSrjs#define G4X_M1_SINGLE_LVDS_MIN 17 212fa225cbcSrjs#define G4X_M1_SINGLE_LVDS_MAX 23 213fa225cbcSrjs#define G4X_M2_SINGLE_LVDS_MIN 5 214fa225cbcSrjs#define G4X_M2_SINGLE_LVDS_MAX 11 215fa225cbcSrjs#define G4X_P_SINGLE_LVDS_MIN 28 216fa225cbcSrjs#define G4X_P_SINGLE_LVDS_MAX 112 217fa225cbcSrjs#define G4X_P1_SINGLE_LVDS_MIN 2 218fa225cbcSrjs#define G4X_P1_SINGLE_LVDS_MAX 8 219fa225cbcSrjs#define G4X_P2_SINGLE_LVDS_SLOW 14 220fa225cbcSrjs#define G4X_P2_SINGLE_LVDS_FAST 14 221fa225cbcSrjs#define G4X_P2_SINGLE_LVDS_LIMIT 0 222fa225cbcSrjs 223fa225cbcSrjs/*The parameter is for DUAL_LVDS on G4x platform*/ 224fa225cbcSrjs#define G4X_DOT_DUAL_LVDS_MIN 80000 225fa225cbcSrjs#define G4X_DOT_DUAL_LVDS_MAX 224000 226fa225cbcSrjs#define G4X_N_DUAL_LVDS_MIN 1 227fa225cbcSrjs#define G4X_N_DUAL_LVDS_MAX 3 228fa225cbcSrjs#define G4X_M_DUAL_LVDS_MIN 104 229fa225cbcSrjs#define G4X_M_DUAL_LVDS_MAX 138 230fa225cbcSrjs#define G4X_M1_DUAL_LVDS_MIN 17 231fa225cbcSrjs#define G4X_M1_DUAL_LVDS_MAX 23 232fa225cbcSrjs#define G4X_M2_DUAL_LVDS_MIN 5 233fa225cbcSrjs#define G4X_M2_DUAL_LVDS_MAX 11 234fa225cbcSrjs#define G4X_P_DUAL_LVDS_MIN 14 235fa225cbcSrjs#define G4X_P_DUAL_LVDS_MAX 42 236fa225cbcSrjs#define G4X_P1_DUAL_LVDS_MIN 2 237fa225cbcSrjs#define G4X_P1_DUAL_LVDS_MAX 6 238fa225cbcSrjs#define G4X_P2_DUAL_LVDS_SLOW 7 239fa225cbcSrjs#define G4X_P2_DUAL_LVDS_FAST 7 240fa225cbcSrjs#define G4X_P2_DUAL_LVDS_LIMIT 0 241fa225cbcSrjs 242fa225cbcSrjsstatic Bool 243fa225cbcSrjsintel_find_pll_i8xx_and_i9xx(const intel_limit_t *, xf86CrtcPtr, 244fa225cbcSrjs int, int, intel_clock_t *); 245fa225cbcSrjsstatic Bool 246fa225cbcSrjsintel_find_pll_g4x(const intel_limit_t *, xf86CrtcPtr, 247fa225cbcSrjs int, int, intel_clock_t *); 248fa225cbcSrjsstatic void 249fa225cbcSrjsi830_crtc_load_lut(xf86CrtcPtr crtc); 250fa225cbcSrjs 251fa225cbcSrjsstatic const intel_limit_t intel_limits[] = { 252fa225cbcSrjs { /* INTEL_LIMIT_I8XX_DVO_DAC */ 253fa225cbcSrjs .dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX }, 254fa225cbcSrjs .vco = { .min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX }, 255fa225cbcSrjs .n = { .min = I8XX_N_MIN, .max = I8XX_N_MAX }, 256fa225cbcSrjs .m = { .min = I8XX_M_MIN, .max = I8XX_M_MAX }, 257fa225cbcSrjs .m1 = { .min = I8XX_M1_MIN, .max = I8XX_M1_MAX }, 258fa225cbcSrjs .m2 = { .min = I8XX_M2_MIN, .max = I8XX_M2_MAX }, 259fa225cbcSrjs .p = { .min = I8XX_P_MIN, .max = I8XX_P_MAX }, 260fa225cbcSrjs .p1 = { .min = I8XX_P1_MIN, .max = I8XX_P1_MAX }, 261fa225cbcSrjs .p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT, 262fa225cbcSrjs .p2_slow = I8XX_P2_SLOW, .p2_fast = I8XX_P2_FAST }, 263fa225cbcSrjs .find_pll = intel_find_pll_i8xx_and_i9xx, 264fa225cbcSrjs }, 265fa225cbcSrjs { /* INTEL_LIMIT_I8XX_LVDS */ 266fa225cbcSrjs .dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX }, 267fa225cbcSrjs .vco = { .min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX }, 268fa225cbcSrjs .n = { .min = I8XX_N_MIN, .max = I8XX_N_MAX }, 269fa225cbcSrjs .m = { .min = I8XX_M_MIN, .max = I8XX_M_MAX }, 270fa225cbcSrjs .m1 = { .min = I8XX_M1_MIN, .max = I8XX_M1_MAX }, 271fa225cbcSrjs .m2 = { .min = I8XX_M2_MIN, .max = I8XX_M2_MAX }, 272fa225cbcSrjs .p = { .min = I8XX_P_MIN, .max = I8XX_P_MAX }, 273fa225cbcSrjs .p1 = { .min = I8XX_P1_LVDS_MIN, .max = I8XX_P1_LVDS_MAX }, 274fa225cbcSrjs .p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT, 275fa225cbcSrjs .p2_slow = I8XX_P2_LVDS_SLOW, .p2_fast = I8XX_P2_LVDS_FAST }, 276fa225cbcSrjs .find_pll = intel_find_pll_i8xx_and_i9xx, 277fa225cbcSrjs }, 278fa225cbcSrjs { /* INTEL_LIMIT_I9XX_SDVO_DAC */ 279fa225cbcSrjs .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX }, 280fa225cbcSrjs .vco = { .min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX }, 281fa225cbcSrjs .n = { .min = I9XX_N_MIN, .max = I9XX_N_MAX }, 282fa225cbcSrjs .m = { .min = I9XX_M_MIN, .max = I9XX_M_MAX }, 283fa225cbcSrjs .m1 = { .min = I9XX_M1_MIN, .max = I9XX_M1_MAX }, 284fa225cbcSrjs .m2 = { .min = I9XX_M2_MIN, .max = I9XX_M2_MAX }, 285fa225cbcSrjs .p = { .min = I9XX_P_SDVO_DAC_MIN, .max = I9XX_P_SDVO_DAC_MAX }, 286fa225cbcSrjs .p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX }, 287fa225cbcSrjs .p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT, 288fa225cbcSrjs .p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST }, 289fa225cbcSrjs .find_pll = intel_find_pll_i8xx_and_i9xx, 290fa225cbcSrjs }, 291fa225cbcSrjs { /* INTEL_LIMIT_I9XX_LVDS */ 292fa225cbcSrjs .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX }, 293fa225cbcSrjs .vco = { .min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX }, 294fa225cbcSrjs .n = { .min = I9XX_N_MIN, .max = I9XX_N_MAX }, 295fa225cbcSrjs .m = { .min = I9XX_M_MIN, .max = I9XX_M_MAX }, 296fa225cbcSrjs .m1 = { .min = I9XX_M1_MIN, .max = I9XX_M1_MAX }, 297fa225cbcSrjs .m2 = { .min = I9XX_M2_MIN, .max = I9XX_M2_MAX }, 298fa225cbcSrjs .p = { .min = I9XX_P_LVDS_MIN, .max = I9XX_P_LVDS_MAX }, 299fa225cbcSrjs .p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX }, 300fa225cbcSrjs /* The single-channel range is 25-112Mhz, and dual-channel 301fa225cbcSrjs * is 80-224Mhz. Prefer single channel as much as possible. 302fa225cbcSrjs */ 303fa225cbcSrjs .p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT, 304fa225cbcSrjs .p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_FAST }, 305fa225cbcSrjs .find_pll = intel_find_pll_i8xx_and_i9xx, 306fa225cbcSrjs }, 307fa225cbcSrjs { /* INTEL_LIMIT_IGD_SDVO */ 308fa225cbcSrjs .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX}, 309fa225cbcSrjs .vco = { .min = IGD_VCO_MIN, .max = IGD_VCO_MAX }, 310fa225cbcSrjs .n = { .min = IGD_N_MIN, .max = IGD_N_MAX }, 311fa225cbcSrjs .m = { .min = IGD_M_MIN, .max = IGD_M_MAX }, 312fa225cbcSrjs .m1 = { .min = IGD_M1_MIN, .max = IGD_M1_MAX }, 313fa225cbcSrjs .m2 = { .min = IGD_M2_MIN, .max = IGD_M2_MAX }, 314fa225cbcSrjs .p = { .min = I9XX_P_SDVO_DAC_MIN, .max = I9XX_P_SDVO_DAC_MAX }, 315fa225cbcSrjs .p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX }, 316fa225cbcSrjs .p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT, 317fa225cbcSrjs .p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST }, 318fa225cbcSrjs .find_pll = intel_find_pll_i8xx_and_i9xx, 319fa225cbcSrjs }, 320fa225cbcSrjs { /* INTEL_LIMIT_IGD_LVDS */ 321fa225cbcSrjs .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX }, 322fa225cbcSrjs .vco = { .min = IGD_VCO_MIN, .max = IGD_VCO_MAX }, 323fa225cbcSrjs .n = { .min = IGD_N_MIN, .max = IGD_N_MAX }, 324fa225cbcSrjs .m = { .min = IGD_M_MIN, .max = IGD_M_MAX }, 325fa225cbcSrjs .m1 = { .min = IGD_M1_MIN, .max = IGD_M1_MAX }, 326fa225cbcSrjs .m2 = { .min = IGD_M2_MIN, .max = IGD_M2_MAX }, 327fa225cbcSrjs .p = { .min = IGD_P_LVDS_MIN, .max = IGD_P_LVDS_MAX }, 328fa225cbcSrjs .p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX }, 329fa225cbcSrjs /* IGD only supports single-channel mode. */ 330fa225cbcSrjs .p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT, 331fa225cbcSrjs .p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_SLOW }, 332fa225cbcSrjs .find_pll = intel_find_pll_i8xx_and_i9xx, 333fa225cbcSrjs }, 334fa225cbcSrjs /* below parameter and function is for G4X Chipset Family*/ 335fa225cbcSrjs { /* INTEL_LIMIT_G4X_SDVO */ 336fa225cbcSrjs .dot = { .min = G4X_DOT_SDVO_MIN, .max = G4X_DOT_SDVO_MAX }, 337fa225cbcSrjs .vco = { .min = G4X_VCO_MIN, .max = G4X_VCO_MAX}, 338fa225cbcSrjs .n = { .min = G4X_N_SDVO_MIN, .max = G4X_N_SDVO_MAX }, 339fa225cbcSrjs .m = { .min = G4X_M_SDVO_MIN, .max = G4X_M_SDVO_MAX }, 340fa225cbcSrjs .m1 = { .min = G4X_M1_SDVO_MIN, .max = G4X_M1_SDVO_MAX }, 341fa225cbcSrjs .m2 = { .min = G4X_M2_SDVO_MIN, .max = G4X_M2_SDVO_MAX }, 342fa225cbcSrjs .p = { .min = G4X_P_SDVO_MIN, .max = G4X_P_SDVO_MAX }, 343fa225cbcSrjs .p1 = { .min = G4X_P1_SDVO_MIN, .max = G4X_P1_SDVO_MAX}, 344fa225cbcSrjs .p2 = { .dot_limit = G4X_P2_SDVO_LIMIT, 345fa225cbcSrjs .p2_slow = G4X_P2_SDVO_SLOW, 346fa225cbcSrjs .p2_fast = G4X_P2_SDVO_FAST }, 347fa225cbcSrjs .find_pll = intel_find_pll_g4x, 348fa225cbcSrjs }, 349fa225cbcSrjs { /* INTEL_LIMIT_G4X_HDMI_DAC */ 350fa225cbcSrjs .dot = { .min = G4X_DOT_HDMI_DAC_MIN, .max = G4X_DOT_HDMI_DAC_MAX }, 351fa225cbcSrjs .vco = { .min = G4X_VCO_MIN, .max = G4X_VCO_MAX}, 352fa225cbcSrjs .n = { .min = G4X_N_HDMI_DAC_MIN, .max = G4X_N_HDMI_DAC_MAX }, 353fa225cbcSrjs .m = { .min = G4X_M_HDMI_DAC_MIN, .max = G4X_M_HDMI_DAC_MAX }, 354fa225cbcSrjs .m1 = { .min = G4X_M1_HDMI_DAC_MIN, .max = G4X_M1_HDMI_DAC_MAX }, 355fa225cbcSrjs .m2 = { .min = G4X_M2_HDMI_DAC_MIN, .max = G4X_M2_HDMI_DAC_MAX }, 356fa225cbcSrjs .p = { .min = G4X_P_HDMI_DAC_MIN, .max = G4X_P_HDMI_DAC_MAX }, 357fa225cbcSrjs .p1 = { .min = G4X_P1_HDMI_DAC_MIN, .max = G4X_P1_HDMI_DAC_MAX}, 358fa225cbcSrjs .p2 = { .dot_limit = G4X_P2_HDMI_DAC_LIMIT, 359fa225cbcSrjs .p2_slow = G4X_P2_HDMI_DAC_SLOW, 360fa225cbcSrjs .p2_fast = G4X_P2_HDMI_DAC_FAST }, 361fa225cbcSrjs .find_pll = intel_find_pll_g4x, 362fa225cbcSrjs }, 363fa225cbcSrjs { /* INTEL_LIMIT_G4X_SINGLE_LVDS */ 364fa225cbcSrjs .dot = { .min = G4X_DOT_SINGLE_LVDS_MIN, 365fa225cbcSrjs .max = G4X_DOT_SINGLE_LVDS_MAX }, 366fa225cbcSrjs .vco = { .min = G4X_VCO_MIN, 367fa225cbcSrjs .max = G4X_VCO_MAX }, 368fa225cbcSrjs .n = { .min = G4X_N_SINGLE_LVDS_MIN, 369fa225cbcSrjs .max = G4X_N_SINGLE_LVDS_MAX }, 370fa225cbcSrjs .m = { .min = G4X_M_SINGLE_LVDS_MIN, 371fa225cbcSrjs .max = G4X_M_SINGLE_LVDS_MAX }, 372fa225cbcSrjs .m1 = { .min = G4X_M1_SINGLE_LVDS_MIN, 373fa225cbcSrjs .max = G4X_M1_SINGLE_LVDS_MAX }, 374fa225cbcSrjs .m2 = { .min = G4X_M2_SINGLE_LVDS_MIN, 375fa225cbcSrjs .max = G4X_M2_SINGLE_LVDS_MAX }, 376fa225cbcSrjs .p = { .min = G4X_P_SINGLE_LVDS_MIN, 377fa225cbcSrjs .max = G4X_P_SINGLE_LVDS_MAX }, 378fa225cbcSrjs .p1 = { .min = G4X_P1_SINGLE_LVDS_MIN, 379fa225cbcSrjs .max = G4X_P1_SINGLE_LVDS_MAX }, 380fa225cbcSrjs .p2 = { .dot_limit = G4X_P2_SINGLE_LVDS_LIMIT, 381fa225cbcSrjs .p2_slow = G4X_P2_SINGLE_LVDS_SLOW, 382fa225cbcSrjs .p2_fast = G4X_P2_SINGLE_LVDS_FAST }, 383fa225cbcSrjs .find_pll = intel_find_pll_g4x, 384fa225cbcSrjs }, 385fa225cbcSrjs { /* INTEL_LIMIT_G4X_DUAL_LVDS */ 386fa225cbcSrjs .dot = { .min = G4X_DOT_DUAL_LVDS_MIN, 387fa225cbcSrjs .max = G4X_DOT_DUAL_LVDS_MAX }, 388fa225cbcSrjs .vco = { .min = G4X_VCO_MIN, 389fa225cbcSrjs .max = G4X_VCO_MAX}, 390fa225cbcSrjs .n = { .min = G4X_N_DUAL_LVDS_MIN, 391fa225cbcSrjs .max = G4X_N_DUAL_LVDS_MAX }, 392fa225cbcSrjs .m = { .min = G4X_M_DUAL_LVDS_MIN, 393fa225cbcSrjs .max = G4X_M_DUAL_LVDS_MAX }, 394fa225cbcSrjs .m1 = { .min = G4X_M1_DUAL_LVDS_MIN, 395fa225cbcSrjs .max = G4X_M1_DUAL_LVDS_MAX }, 396fa225cbcSrjs .m2 = { .min = G4X_M2_DUAL_LVDS_MIN, 397fa225cbcSrjs .max = G4X_M2_DUAL_LVDS_MAX }, 398fa225cbcSrjs .p = { .min = G4X_P_DUAL_LVDS_MIN, 399fa225cbcSrjs .max = G4X_P_DUAL_LVDS_MAX }, 400fa225cbcSrjs .p1 = { .min = G4X_P1_DUAL_LVDS_MIN, 401fa225cbcSrjs .max = G4X_P1_DUAL_LVDS_MAX}, 402fa225cbcSrjs .p2 = { .dot_limit = G4X_P2_DUAL_LVDS_LIMIT, 403fa225cbcSrjs .p2_slow = G4X_P2_DUAL_LVDS_SLOW, 404fa225cbcSrjs .p2_fast = G4X_P2_DUAL_LVDS_FAST }, 405fa225cbcSrjs .find_pll = intel_find_pll_g4x, 406fa225cbcSrjs }, 407fa225cbcSrjs}; 408fa225cbcSrjs 409fa225cbcSrjsstatic const intel_limit_t *intel_limit_g4x (xf86CrtcPtr crtc) 410fa225cbcSrjs{ 411fa225cbcSrjs ScrnInfoPtr pScrn = crtc->scrn; 412fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 413fa225cbcSrjs const intel_limit_t *limit; 414fa225cbcSrjs 415fa225cbcSrjs if (i830PipeHasType (crtc, I830_OUTPUT_LVDS)) { 416fa225cbcSrjs if ((INREG(LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP) { 417fa225cbcSrjs /* LVDS with dual channel */ 418fa225cbcSrjs limit = &intel_limits[INTEL_LIMIT_G4X_DUAL_LVDS]; 419fa225cbcSrjs } else /* LVDS with single channel */ 420fa225cbcSrjs limit = &intel_limits[INTEL_LIMIT_G4X_SINGLE_LVDS]; 421fa225cbcSrjs } else if (i830PipeHasType (crtc, I830_OUTPUT_HDMI) || 422fa225cbcSrjs i830PipeHasType (crtc, I830_OUTPUT_ANALOG)) { 423fa225cbcSrjs limit = &intel_limits[INTEL_LIMIT_G4X_HDMI_DAC]; 424fa225cbcSrjs } else if (i830PipeHasType (crtc, I830_OUTPUT_SDVO)) { 425fa225cbcSrjs limit = &intel_limits[INTEL_LIMIT_G4X_SDVO]; 426fa225cbcSrjs } else /* The option is for other outputs */ 427fa225cbcSrjs limit = &intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC]; 428fa225cbcSrjs return limit; 429fa225cbcSrjs} 430fa225cbcSrjs 431fa225cbcSrjsstatic const intel_limit_t *intel_limit (xf86CrtcPtr crtc) 432fa225cbcSrjs{ 433fa225cbcSrjs ScrnInfoPtr pScrn = crtc->scrn; 434fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 435fa225cbcSrjs const intel_limit_t *limit; 436fa225cbcSrjs 437fa225cbcSrjs if (IS_G4X(pI830)) { 438fa225cbcSrjs limit = intel_limit_g4x(crtc); 439fa225cbcSrjs } else if (IS_I9XX(pI830) && !IS_IGD(pI830)) { 440fa225cbcSrjs if (i830PipeHasType (crtc, I830_OUTPUT_LVDS)) 441fa225cbcSrjs limit = &intel_limits[INTEL_LIMIT_I9XX_LVDS]; 442fa225cbcSrjs else 443fa225cbcSrjs limit = &intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC]; 444fa225cbcSrjs } else if (IS_IGD(pI830)) { 445fa225cbcSrjs if (i830PipeHasType (crtc, I830_OUTPUT_LVDS)) 446fa225cbcSrjs limit = &intel_limits[INTEL_LIMIT_IGD_LVDS]; 447fa225cbcSrjs else 448fa225cbcSrjs limit = &intel_limits[INTEL_LIMIT_IGD_SDVO_DAC]; 449fa225cbcSrjs } else { 450fa225cbcSrjs if (i830PipeHasType (crtc, I830_OUTPUT_LVDS)) 451fa225cbcSrjs limit = &intel_limits[INTEL_LIMIT_I8XX_LVDS]; 452fa225cbcSrjs else 453fa225cbcSrjs limit = &intel_limits[INTEL_LIMIT_I8XX_DVO_DAC]; 454fa225cbcSrjs } 455fa225cbcSrjs 456fa225cbcSrjs return limit; 457fa225cbcSrjs} 458fa225cbcSrjs 459fa225cbcSrjs/** Derive the pixel clock for the given refclk and divisors for 8xx chips. */ 460fa225cbcSrjs 461fa225cbcSrjsstatic void i8xx_clock(int refclk, intel_clock_t *clock) 462fa225cbcSrjs{ 463fa225cbcSrjs clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); 464fa225cbcSrjs clock->p = clock->p1 * clock->p2; 465fa225cbcSrjs clock->vco = refclk * clock->m / (clock->n + 2); 466fa225cbcSrjs clock->dot = clock->vco / clock->p; 467fa225cbcSrjs} 468fa225cbcSrjs 469fa225cbcSrjs/** Derive the pixel clock for the given refclk and divisors for 9xx chips. */ 470fa225cbcSrjs 471fa225cbcSrjsstatic void i9xx_clock(int refclk, intel_clock_t *clock) 472fa225cbcSrjs{ 473fa225cbcSrjs clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); 474fa225cbcSrjs clock->p = clock->p1 * clock->p2; 475fa225cbcSrjs clock->vco = refclk * clock->m / (clock->n + 2); 476fa225cbcSrjs clock->dot = clock->vco / clock->p; 477fa225cbcSrjs} 478fa225cbcSrjs 479fa225cbcSrjs/* m1 is reserved as 0 in IGD, n is a ring counter */ 480fa225cbcSrjsstatic void igd_clock(int refclk, intel_clock_t *clock) 481fa225cbcSrjs{ 482fa225cbcSrjs clock->m = clock->m2 + 2; 483fa225cbcSrjs clock->p = clock->p1 * clock->p2; 484fa225cbcSrjs clock->vco = refclk * clock->m / clock->n; 485fa225cbcSrjs clock->dot = clock->vco / clock->p; 486fa225cbcSrjs} 487fa225cbcSrjs 488fa225cbcSrjsstatic void intel_clock(I830Ptr pI830, int refclk, intel_clock_t *clock) 489fa225cbcSrjs{ 490fa225cbcSrjs if (IS_I9XX(pI830)) { 491fa225cbcSrjs if (IS_IGD(pI830)) 492fa225cbcSrjs igd_clock(refclk, clock); 493fa225cbcSrjs else 494fa225cbcSrjs i9xx_clock (refclk, clock); 495fa225cbcSrjs } else 496fa225cbcSrjs i8xx_clock (refclk, clock); 497fa225cbcSrjs} 498fa225cbcSrjs 499fa225cbcSrjsstatic void 500fa225cbcSrjsi830PrintPll(ScrnInfoPtr pScrn, char *prefix, intel_clock_t *clock) 501fa225cbcSrjs{ 502fa225cbcSrjs xf86DrvMsg(pScrn->scrnIndex, X_INFO, 503fa225cbcSrjs "%s: dotclock %d vco %d ((m %d, m1 %d, m2 %d), n %d, " 504fa225cbcSrjs "(p %d, p1 %d, p2 %d))\n", 505fa225cbcSrjs prefix, clock->dot, clock->vco, 506fa225cbcSrjs clock->m, clock->m1, clock->m2, 507fa225cbcSrjs clock->n, 508fa225cbcSrjs clock->p, clock->p1, clock->p2); 509fa225cbcSrjs} 510fa225cbcSrjs 511fa225cbcSrjs/** 512fa225cbcSrjs * Returns whether any output on the specified pipe is of the specified type 513fa225cbcSrjs */ 514fa225cbcSrjsBool 515fa225cbcSrjsi830PipeHasType (xf86CrtcPtr crtc, int type) 516fa225cbcSrjs{ 517fa225cbcSrjs ScrnInfoPtr pScrn = crtc->scrn; 518fa225cbcSrjs xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 519fa225cbcSrjs int i; 520fa225cbcSrjs 521fa225cbcSrjs for (i = 0; i < xf86_config->num_output; i++) 522fa225cbcSrjs { 523fa225cbcSrjs xf86OutputPtr output = xf86_config->output[i]; 524fa225cbcSrjs if (output->crtc == crtc) 525fa225cbcSrjs { 526fa225cbcSrjs I830OutputPrivatePtr intel_output = output->driver_private; 527fa225cbcSrjs if (intel_output->type == type) 528fa225cbcSrjs return TRUE; 529fa225cbcSrjs } 530fa225cbcSrjs } 531fa225cbcSrjs return FALSE; 532fa225cbcSrjs} 533fa225cbcSrjs 534fa225cbcSrjs#define i830PllInvalid(s) { /* ErrorF (s) */; return FALSE; } 535fa225cbcSrjs/** 536fa225cbcSrjs * Returns whether the given set of divisors are valid for a given refclk with 537fa225cbcSrjs * the given outputs. 538fa225cbcSrjs */ 539fa225cbcSrjs 540fa225cbcSrjsstatic Bool 541fa225cbcSrjsi830PllIsValid(xf86CrtcPtr crtc, intel_clock_t *clock) 542fa225cbcSrjs{ 543fa225cbcSrjs const intel_limit_t *limit = intel_limit (crtc); 544fa225cbcSrjs ScrnInfoPtr pScrn = crtc->scrn; 545fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 546fa225cbcSrjs 547fa225cbcSrjs if (clock->p1 < limit->p1.min || limit->p1.max < clock->p1) 548fa225cbcSrjs i830PllInvalid ("p1 out of range\n"); 549fa225cbcSrjs if (clock->p < limit->p.min || limit->p.max < clock->p) 550fa225cbcSrjs i830PllInvalid ("p out of range\n"); 551fa225cbcSrjs if (clock->m2 < limit->m2.min || limit->m2.max < clock->m2) 552fa225cbcSrjs i830PllInvalid ("m2 out of range\n"); 553fa225cbcSrjs if (clock->m1 < limit->m1.min || limit->m1.max < clock->m1) 554fa225cbcSrjs i830PllInvalid ("m1 out of range\n"); 555fa225cbcSrjs if (clock->m1 <= clock->m2 && !IS_IGD(pI830)) 556fa225cbcSrjs i830PllInvalid ("m1 <= m2\n"); 557fa225cbcSrjs if (clock->m < limit->m.min || limit->m.max < clock->m) 558fa225cbcSrjs i830PllInvalid ("m out of range\n"); 559fa225cbcSrjs if (clock->n < limit->n.min || limit->n.max < clock->n) 560fa225cbcSrjs i830PllInvalid ("n out of range\n"); 561fa225cbcSrjs if (clock->vco < limit->vco.min || limit->vco.max < clock->vco) 562fa225cbcSrjs i830PllInvalid ("vco out of range\n"); 563fa225cbcSrjs /* XXX: We may need to be checking "Dot clock" depending on the multiplier, 564fa225cbcSrjs * output, etc., rather than just a single range. 565fa225cbcSrjs */ 566fa225cbcSrjs if (clock->dot < limit->dot.min || limit->dot.max < clock->dot) 567fa225cbcSrjs i830PllInvalid ("dot out of range\n"); 568fa225cbcSrjs 569fa225cbcSrjs return TRUE; 570fa225cbcSrjs} 571fa225cbcSrjs 572fa225cbcSrjsstatic Bool 573fa225cbcSrjsintel_find_pll_i8xx_and_i9xx(const intel_limit_t * limit, xf86CrtcPtr crtc, 574fa225cbcSrjs int target, int refclk, intel_clock_t *best_clock) 575fa225cbcSrjs{ 576fa225cbcSrjs ScrnInfoPtr pScrn = crtc->scrn; 577fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 578fa225cbcSrjs intel_clock_t clock; 579fa225cbcSrjs int err = target; 580fa225cbcSrjs 581fa225cbcSrjs if (i830PipeHasType(crtc, I830_OUTPUT_LVDS)) 582fa225cbcSrjs { 583fa225cbcSrjs /* For LVDS, if the panel is on, just rely on its current settings for 584fa225cbcSrjs * dual-channel. We haven't figured out how to reliably set up 585fa225cbcSrjs * different single/dual channel state, if we even can. 586fa225cbcSrjs */ 587fa225cbcSrjs if ((INREG(LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP) 588fa225cbcSrjs clock.p2 = limit->p2.p2_fast; 589fa225cbcSrjs else 590fa225cbcSrjs clock.p2 = limit->p2.p2_slow; 591fa225cbcSrjs } else { 592fa225cbcSrjs if (target < limit->p2.dot_limit) 593fa225cbcSrjs clock.p2 = limit->p2.p2_slow; 594fa225cbcSrjs else 595fa225cbcSrjs clock.p2 = limit->p2.p2_fast; 596fa225cbcSrjs } 597fa225cbcSrjs 598fa225cbcSrjs memset (best_clock, 0, sizeof (*best_clock)); 599fa225cbcSrjs 600fa225cbcSrjs for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) 601fa225cbcSrjs { 602fa225cbcSrjs for (clock.m2 = limit->m2.min; clock.m2 <= limit->m2.max; clock.m2++) 603fa225cbcSrjs { 604fa225cbcSrjs /* m1 is always 0 in IGD */ 605fa225cbcSrjs if (clock.m2 >= clock.m1 && !IS_IGD(pI830)) 606fa225cbcSrjs break; 607fa225cbcSrjs for (clock.n = limit->n.min; clock.n <= limit->n.max; clock.n++) 608fa225cbcSrjs { 609fa225cbcSrjs for (clock.p1 = limit->p1.min; clock.p1 <= limit->p1.max; clock.p1++) 610fa225cbcSrjs { 611fa225cbcSrjs int this_err; 612fa225cbcSrjs 613fa225cbcSrjs intel_clock (pI830, refclk, &clock); 614fa225cbcSrjs 615fa225cbcSrjs if (!i830PllIsValid(crtc, &clock)) 616fa225cbcSrjs continue; 617fa225cbcSrjs 618fa225cbcSrjs this_err = abs(clock.dot - target); 619fa225cbcSrjs if (this_err < err) { 620fa225cbcSrjs *best_clock = clock; 621fa225cbcSrjs err = this_err; 622fa225cbcSrjs } 623fa225cbcSrjs } 624fa225cbcSrjs } 625fa225cbcSrjs } 626fa225cbcSrjs } 627fa225cbcSrjs return (err != target); 628fa225cbcSrjs} 629fa225cbcSrjs 630fa225cbcSrjsstatic Bool 631fa225cbcSrjsintel_find_pll_g4x(const intel_limit_t * limit, xf86CrtcPtr crtc, 632fa225cbcSrjs int target, int refclk, intel_clock_t *best_clock) 633fa225cbcSrjs{ 634fa225cbcSrjs ScrnInfoPtr pScrn = crtc->scrn; 635fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 636fa225cbcSrjs intel_clock_t clock; 637fa225cbcSrjs int max_n; 638fa225cbcSrjs Bool found = FALSE; 639fa225cbcSrjs int err_most = target * 0.0048; 640fa225cbcSrjs 641fa225cbcSrjs if (i830PipeHasType(crtc, I830_OUTPUT_LVDS)) 642fa225cbcSrjs { 643fa225cbcSrjs /* For LVDS, if the panel is on, just rely on its current settings for 644fa225cbcSrjs * dual-channel. We haven't figured out how to reliably set up 645fa225cbcSrjs * different single/dual channel state, if we even can. 646fa225cbcSrjs */ 647fa225cbcSrjs if ((INREG(LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP) 648fa225cbcSrjs clock.p2 = limit->p2.p2_fast; 649fa225cbcSrjs else 650fa225cbcSrjs clock.p2 = limit->p2.p2_slow; 651fa225cbcSrjs } else { 652fa225cbcSrjs if (target < limit->p2.dot_limit) 653fa225cbcSrjs clock.p2 = limit->p2.p2_slow; 654fa225cbcSrjs else 655fa225cbcSrjs clock.p2 = limit->p2.p2_fast; 656fa225cbcSrjs } 657fa225cbcSrjs 658fa225cbcSrjs max_n = limit->n.max; 659fa225cbcSrjs /* based on hardware requirement prefer smaller n to precision */ 660fa225cbcSrjs for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) { 661fa225cbcSrjs /* based on hardware requirement prefere larger m1,m2, p1*/ 662fa225cbcSrjs for (clock.m1 = limit->m1.max; 663fa225cbcSrjs clock.m1 >= limit->m1.min; clock.m1--) { 664fa225cbcSrjs for (clock.m2 = limit->m2.max; 665fa225cbcSrjs clock.m2 >= limit->m2.min; clock.m2--) { 666fa225cbcSrjs for (clock.p1 = limit->p1.max; 667fa225cbcSrjs clock.p1 >= limit->p1.min; clock.p1--) { 668fa225cbcSrjs int this_err; 669fa225cbcSrjs 670fa225cbcSrjs intel_clock (pI830, refclk, &clock); 671fa225cbcSrjs if (!i830PllIsValid(crtc, &clock)) 672fa225cbcSrjs continue; 673fa225cbcSrjs this_err = abs(clock.dot - target) ; 674fa225cbcSrjs if (this_err < err_most) { 675fa225cbcSrjs memcpy(best_clock, &clock, sizeof(intel_clock_t)); 676fa225cbcSrjs err_most = this_err; 677fa225cbcSrjs /* prefer smaller n to precision */ 678fa225cbcSrjs max_n = clock.n; 679fa225cbcSrjs found = TRUE; 680fa225cbcSrjs } 681fa225cbcSrjs } 682fa225cbcSrjs } 683fa225cbcSrjs } 684fa225cbcSrjs } 685fa225cbcSrjs return found; 686fa225cbcSrjs} 687fa225cbcSrjs 688fa225cbcSrjsvoid 689fa225cbcSrjsi830WaitForVblank(ScrnInfoPtr pScreen) 690fa225cbcSrjs{ 691fa225cbcSrjs /* Wait for 20ms, i.e. one cycle at 50hz. */ 692fa225cbcSrjs usleep(30000); 693fa225cbcSrjs} 694fa225cbcSrjs 695fa225cbcSrjsvoid 696fa225cbcSrjsi830PipeSetBase(xf86CrtcPtr crtc, int x, int y) 697fa225cbcSrjs{ 698fa225cbcSrjs ScrnInfoPtr pScrn = crtc->scrn; 699fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 700fa225cbcSrjs I830CrtcPrivatePtr intel_crtc = crtc->driver_private; 701fa225cbcSrjs int plane = intel_crtc->plane; 702fa225cbcSrjs unsigned long Start, Offset, Stride; 703fa225cbcSrjs int dspbase = (plane == 0 ? DSPABASE : DSPBBASE); 704fa225cbcSrjs int dspsurf = (plane == 0 ? DSPASURF : DSPBSURF); 705fa225cbcSrjs int dsptileoff = (plane == 0 ? DSPATILEOFF : DSPBTILEOFF); 706fa225cbcSrjs int dspstride = (plane == 0) ? DSPASTRIDE : DSPBSTRIDE; 707fa225cbcSrjs 708fa225cbcSrjs Offset = ((y * pScrn->displayWidth + x) * pI830->cpp); 709fa225cbcSrjs Stride = pScrn->displayWidth * pI830->cpp; 710fa225cbcSrjs if (pI830->front_buffer == NULL) { 711fa225cbcSrjs /* During startup we may be called as part of monitor detection while 712fa225cbcSrjs * there is no memory allocation done, so just supply a dummy base 713fa225cbcSrjs * address. 714fa225cbcSrjs */ 715fa225cbcSrjs Start = 0; 716fa225cbcSrjs } else if (crtc->rotatedData != NULL) { 717fa225cbcSrjs /* offset is done by shadow painting code, not here */ 718fa225cbcSrjs Start = (char *)crtc->rotatedData - (char *)pI830->FbBase; 719fa225cbcSrjs Offset = 0; 720fa225cbcSrjs Stride = intel_crtc->rotate_mem->pitch; 721fa225cbcSrjs } else { 722fa225cbcSrjs Start = pI830->front_buffer->offset; 723fa225cbcSrjs } 724fa225cbcSrjs 725fa225cbcSrjs crtc->x = x; 726fa225cbcSrjs crtc->y = y; 727fa225cbcSrjs 728fa225cbcSrjs OUTREG(dspstride, Stride); 729fa225cbcSrjs if (IS_I965G(pI830)) { 730fa225cbcSrjs OUTREG(dspbase, Offset); 731fa225cbcSrjs POSTING_READ(dspbase); 732fa225cbcSrjs OUTREG(dspsurf, Start); 733fa225cbcSrjs POSTING_READ(dspsurf); 734fa225cbcSrjs OUTREG(dsptileoff, (y << 16) | x); 735fa225cbcSrjs } else { 736fa225cbcSrjs OUTREG(dspbase, Start + Offset); 737fa225cbcSrjs POSTING_READ(dspbase); 738fa225cbcSrjs } 739fa225cbcSrjs} 740fa225cbcSrjs 741fa225cbcSrjs/* 742fa225cbcSrjs * Both crtc activation and video overlay enablement on pipe B 743fa225cbcSrjs * will fail on i830 if pipe A is not running. This function 744fa225cbcSrjs * makes sure pipe A is active for these cases 745fa225cbcSrjs */ 746fa225cbcSrjs 747fa225cbcSrjsint 748fa225cbcSrjsi830_crtc_pipe (xf86CrtcPtr crtc) 749fa225cbcSrjs{ 750fa225cbcSrjs if (crtc == NULL) 751fa225cbcSrjs return 0; 752fa225cbcSrjs return ((I830CrtcPrivatePtr) crtc->driver_private)->pipe; 753fa225cbcSrjs} 754fa225cbcSrjs 755fa225cbcSrjsstatic xf86CrtcPtr 756fa225cbcSrjsi830_crtc_for_pipe (ScrnInfoPtr scrn, int pipe) 757fa225cbcSrjs{ 758fa225cbcSrjs xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 759fa225cbcSrjs int c; 760fa225cbcSrjs 761fa225cbcSrjs for (c = 0; c < xf86_config->num_crtc; c++) 762fa225cbcSrjs { 763fa225cbcSrjs xf86CrtcPtr crtc = xf86_config->crtc[c]; 764fa225cbcSrjs if (i830_crtc_pipe (crtc) == pipe) 765fa225cbcSrjs return crtc; 766fa225cbcSrjs } 767fa225cbcSrjs return NULL; 768fa225cbcSrjs} 769fa225cbcSrjs 770fa225cbcSrjsBool 771fa225cbcSrjsi830_pipe_a_require_activate (ScrnInfoPtr scrn) 772fa225cbcSrjs{ 773fa225cbcSrjs xf86CrtcPtr crtc = i830_crtc_for_pipe (scrn, 0); 774fa225cbcSrjs /* VESA 640x480x72Hz mode to set on the pipe */ 775fa225cbcSrjs static DisplayModeRec mode = { 776fa225cbcSrjs NULL, NULL, "640x480", MODE_OK, M_T_DEFAULT, 777fa225cbcSrjs 31500, 778fa225cbcSrjs 640, 664, 704, 832, 0, 779fa225cbcSrjs 480, 489, 491, 520, 0, 780fa225cbcSrjs V_NHSYNC | V_NVSYNC, 781fa225cbcSrjs 0, 0, 782fa225cbcSrjs 0, 0, 0, 0, 0, 0, 0, 783fa225cbcSrjs 0, 0, 0, 0, 0, 0, 784fa225cbcSrjs FALSE, FALSE, 0, NULL, 0, 0.0, 0.0 785fa225cbcSrjs }; 786fa225cbcSrjs 787fa225cbcSrjs if (!crtc) 788fa225cbcSrjs return FALSE; 789fa225cbcSrjs if (crtc->enabled) 790fa225cbcSrjs return FALSE; 791fa225cbcSrjs xf86SetModeCrtc (&mode, INTERLACE_HALVE_V); 792fa225cbcSrjs crtc->funcs->mode_set (crtc, &mode, &mode, 0, 0); 793fa225cbcSrjs crtc->funcs->dpms (crtc, DPMSModeOn); 794fa225cbcSrjs return TRUE; 795fa225cbcSrjs} 796fa225cbcSrjs 797fa225cbcSrjsvoid 798fa225cbcSrjsi830_pipe_a_require_deactivate (ScrnInfoPtr scrn) 799fa225cbcSrjs{ 800fa225cbcSrjs xf86CrtcPtr crtc = i830_crtc_for_pipe (scrn, 0); 801fa225cbcSrjs 802fa225cbcSrjs if (!crtc) 803fa225cbcSrjs return; 804fa225cbcSrjs if (crtc->enabled) 805fa225cbcSrjs return; 806fa225cbcSrjs crtc->funcs->dpms (crtc, DPMSModeOff); 807fa225cbcSrjs return; 808fa225cbcSrjs} 809fa225cbcSrjs 810fa225cbcSrjs/* FIXME: use pixmap private instead if possible */ 811fa225cbcSrjsstatic Bool 812fa225cbcSrjsi830_display_tiled(xf86CrtcPtr crtc) 813fa225cbcSrjs{ 814fa225cbcSrjs ScrnInfoPtr pScrn = crtc->scrn; 815fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 816fa225cbcSrjs 817fa225cbcSrjs /* Rotated data is currently linear, allocated either via XAA or EXA */ 818fa225cbcSrjs if (crtc->rotatedData) 819fa225cbcSrjs return FALSE; 820fa225cbcSrjs 821fa225cbcSrjs if (pI830->front_buffer && pI830->front_buffer->tiling != TILE_NONE) 822fa225cbcSrjs return TRUE; 823fa225cbcSrjs 824fa225cbcSrjs return FALSE; 825fa225cbcSrjs} 826fa225cbcSrjs 827fa225cbcSrjs/* 828fa225cbcSrjs * Several restrictions: 829fa225cbcSrjs * - DSP[AB]CNTR - no line duplication && no pixel multiplier 830fa225cbcSrjs * - pixel format == 15 bit, 16 bit, or 32 bit xRGB_8888 831fa225cbcSrjs * - no alpha buffer discard 832fa225cbcSrjs * - no dual wide display 833fa225cbcSrjs * - progressive mode only (DSP[AB]CNTR) 834fa225cbcSrjs * - uncompressed fb is <= 2048 in width, 0 mod 8 835fa225cbcSrjs * - uncompressed fb is <= 1536 in height, 0 mod 2 836fa225cbcSrjs * - SR display watermarks must be equal between 16bpp and 32bpp? 837fa225cbcSrjs * 838fa225cbcSrjs * FIXME: verify above conditions are true 839fa225cbcSrjs * 840fa225cbcSrjs * Enable 8xx style FB compression 841fa225cbcSrjs */ 842fa225cbcSrjsstatic void 843fa225cbcSrjsi830_enable_fb_compression_8xx(xf86CrtcPtr crtc) 844fa225cbcSrjs{ 845fa225cbcSrjs ScrnInfoPtr pScrn = crtc->scrn; 846fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 847fa225cbcSrjs I830CrtcPrivatePtr intel_crtc = crtc->driver_private; 848fa225cbcSrjs uint32_t fbc_ctl = 0; 849fa225cbcSrjs unsigned long compressed_stride; 850fa225cbcSrjs int plane = (intel_crtc->plane == 0 ? FBC_CTL_PLANEA : FBC_CTL_PLANEB); 851fa225cbcSrjs unsigned long uncompressed_stride = pScrn->displayWidth * pI830->cpp; 852fa225cbcSrjs unsigned long interval = 1000; 853fa225cbcSrjs 854fa225cbcSrjs if (INREG(FBC_CONTROL) & FBC_CTL_EN) 855fa225cbcSrjs return; 856fa225cbcSrjs 857fa225cbcSrjs compressed_stride = pI830->compressed_front_buffer->size / 858fa225cbcSrjs FBC_LL_SIZE; 859fa225cbcSrjs 860fa225cbcSrjs if (uncompressed_stride < compressed_stride) 861fa225cbcSrjs compressed_stride = uncompressed_stride; 862fa225cbcSrjs 863fa225cbcSrjs /* FBC_CTL wants 64B units */ 864fa225cbcSrjs compressed_stride = (compressed_stride / 64) - 1; 865fa225cbcSrjs 866fa225cbcSrjs /* Set it up... */ 867fa225cbcSrjs /* Wait for compressing bit to clear */ 868fa225cbcSrjs while (INREG(FBC_STATUS) & FBC_STAT_COMPRESSING) 869fa225cbcSrjs ; /* nothing */ 870fa225cbcSrjs i830WaitForVblank(pScrn); 871fa225cbcSrjs OUTREG(FBC_CFB_BASE, pI830->compressed_front_buffer->bus_addr); 872fa225cbcSrjs OUTREG(FBC_LL_BASE, pI830->compressed_ll_buffer->bus_addr + 6); 873fa225cbcSrjs OUTREG(FBC_CONTROL2, FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | 874fa225cbcSrjs FBC_CTL_CPU_FENCE | plane); 875fa225cbcSrjs OUTREG(FBC_FENCE_OFF, crtc->y); 876fa225cbcSrjs 877fa225cbcSrjs /* Zero buffers */ 878fa225cbcSrjs memset(pI830->FbBase + pI830->compressed_front_buffer->offset, 0, 879fa225cbcSrjs pI830->compressed_front_buffer->size); 880fa225cbcSrjs memset(pI830->FbBase + pI830->compressed_ll_buffer->offset, 0, 881fa225cbcSrjs pI830->compressed_ll_buffer->size); 882fa225cbcSrjs 883fa225cbcSrjs /* enable it... */ 884fa225cbcSrjs fbc_ctl |= FBC_CTL_EN | FBC_CTL_PERIODIC; 885fa225cbcSrjs fbc_ctl |= (compressed_stride & 0xff) << FBC_CTL_STRIDE_SHIFT; 886fa225cbcSrjs fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT; 887fa225cbcSrjs fbc_ctl |= FBC_CTL_UNCOMPRESSIBLE; 888fa225cbcSrjs fbc_ctl |= pI830->front_buffer->fence_nr; 889fa225cbcSrjs OUTREG(FBC_CONTROL, fbc_ctl); 890fa225cbcSrjs} 891fa225cbcSrjs 892fa225cbcSrjs/* 893fa225cbcSrjs * Disable 8xx style FB compression 894fa225cbcSrjs */ 895fa225cbcSrjsstatic void 896fa225cbcSrjsi830_disable_fb_compression_8xx(xf86CrtcPtr crtc) 897fa225cbcSrjs{ 898fa225cbcSrjs ScrnInfoPtr pScrn = crtc->scrn; 899fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 900fa225cbcSrjs uint32_t fbc_ctl; 901fa225cbcSrjs 902fa225cbcSrjs /* Disable compression */ 903fa225cbcSrjs fbc_ctl = INREG(FBC_CONTROL); 904fa225cbcSrjs fbc_ctl &= ~FBC_CTL_EN; 905fa225cbcSrjs OUTREG(FBC_CONTROL, fbc_ctl); 906fa225cbcSrjs 907fa225cbcSrjs /* Wait for compressing bit to clear */ 908fa225cbcSrjs while (INREG(FBC_STATUS) & FBC_STAT_COMPRESSING) 909fa225cbcSrjs ; /* nothing */ 910fa225cbcSrjs} 911fa225cbcSrjs 912fa225cbcSrjsstatic void 913fa225cbcSrjsi830_disable_fb_compression2(xf86CrtcPtr crtc) 914fa225cbcSrjs{ 915fa225cbcSrjs ScrnInfoPtr pScrn = crtc->scrn; 916fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 917fa225cbcSrjs uint32_t dpfc_ctl; 918fa225cbcSrjs 919fa225cbcSrjs /* Disable compression */ 920fa225cbcSrjs dpfc_ctl = INREG(DPFC_CONTROL); 921fa225cbcSrjs dpfc_ctl &= ~DPFC_CTL_EN; 922fa225cbcSrjs OUTREG(DPFC_CONTROL, dpfc_ctl); 923fa225cbcSrjs i830WaitForVblank(pScrn); 924fa225cbcSrjs} 925fa225cbcSrjs 926fa225cbcSrjsstatic void 927fa225cbcSrjsi830_enable_fb_compression2(xf86CrtcPtr crtc) 928fa225cbcSrjs{ 929fa225cbcSrjs ScrnInfoPtr pScrn = crtc->scrn; 930fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 931fa225cbcSrjs I830CrtcPrivatePtr intel_crtc = crtc->driver_private; 932fa225cbcSrjs int plane = (intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB); 933fa225cbcSrjs unsigned long stall_watermark = 200, frames = 50; 934fa225cbcSrjs 935fa225cbcSrjs if (INREG(DPFC_CONTROL) & DPFC_CTL_EN) 936fa225cbcSrjs return; 937fa225cbcSrjs 938fa225cbcSrjs /* Set it up... */ 939fa225cbcSrjs i830_disable_fb_compression2(crtc); 940fa225cbcSrjs OUTREG(DPFC_CB_BASE, pI830->compressed_front_buffer->offset); 941fa225cbcSrjs /* Update i830_memory.c too if compression ratio changes */ 942fa225cbcSrjs OUTREG(DPFC_CONTROL, plane | DPFC_CTL_FENCE_EN | DPFC_CTL_LIMIT_4X | 943fa225cbcSrjs pI830->front_buffer->fence_nr); 944fa225cbcSrjs OUTREG(DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN | 945fa225cbcSrjs (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) | 946fa225cbcSrjs (frames << DPFC_RECOMP_TIMER_COUNT_SHIFT)); 947fa225cbcSrjs OUTREG(DPFC_FENCE_YOFF, crtc->y); 948fa225cbcSrjs 949fa225cbcSrjs /* Zero buffers */ 950fa225cbcSrjs memset(pI830->FbBase + pI830->compressed_front_buffer->offset, 0, 951fa225cbcSrjs pI830->compressed_front_buffer->size); 952fa225cbcSrjs 953fa225cbcSrjs /* enable it... */ 954fa225cbcSrjs OUTREG(DPFC_CONTROL, INREG(DPFC_CONTROL) | DPFC_CTL_EN); 955fa225cbcSrjs} 956fa225cbcSrjs 957fa225cbcSrjsstatic void 958fa225cbcSrjsi830_enable_fb_compression(xf86CrtcPtr crtc) 959fa225cbcSrjs{ 960fa225cbcSrjs ScrnInfoPtr pScrn = crtc->scrn; 961fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 962fa225cbcSrjs 963fa225cbcSrjs if (IS_GM45(pI830)) 964fa225cbcSrjs return i830_enable_fb_compression2(crtc); 965fa225cbcSrjs 966fa225cbcSrjs i830_enable_fb_compression_8xx(crtc); 967fa225cbcSrjs} 968fa225cbcSrjs 969fa225cbcSrjsstatic void 970fa225cbcSrjsi830_disable_fb_compression(xf86CrtcPtr crtc) 971fa225cbcSrjs{ 972fa225cbcSrjs ScrnInfoPtr pScrn = crtc->scrn; 973fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 974fa225cbcSrjs 975fa225cbcSrjs if (IS_GM45(pI830)) 976fa225cbcSrjs return i830_disable_fb_compression2(crtc); 977fa225cbcSrjs 978fa225cbcSrjs i830_disable_fb_compression_8xx(crtc); 979fa225cbcSrjs} 980fa225cbcSrjs 981fa225cbcSrjsstatic Bool 982fa225cbcSrjsi830_use_fb_compression(xf86CrtcPtr crtc) 983fa225cbcSrjs{ 984fa225cbcSrjs ScrnInfoPtr pScrn = crtc->scrn; 985fa225cbcSrjs xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 986fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 987fa225cbcSrjs I830CrtcPrivatePtr intel_crtc = crtc->driver_private; 988fa225cbcSrjs unsigned long uncompressed_size; 989fa225cbcSrjs int plane = (intel_crtc->plane == 0 ? FBC_CTL_PLANEA : FBC_CTL_PLANEB); 990fa225cbcSrjs int i, count = 0; 991fa225cbcSrjs 992fa225cbcSrjs /* Only available on one pipe at a time */ 993fa225cbcSrjs for (i = 0; i < xf86_config->num_crtc; i++) { 994fa225cbcSrjs if (xf86_config->crtc[i]->enabled) 995fa225cbcSrjs count++; 996fa225cbcSrjs } 997fa225cbcSrjs 998fa225cbcSrjs /* Here we disable it to catch one->two pipe enabled configs */ 999fa225cbcSrjs if (count > 1) { 1000fa225cbcSrjs if (i830_fb_compression_supported(pI830)) 1001fa225cbcSrjs i830_disable_fb_compression(crtc); 1002fa225cbcSrjs return FALSE; 1003fa225cbcSrjs } 1004fa225cbcSrjs 1005fa225cbcSrjs if (!pI830->fb_compression) 1006fa225cbcSrjs return FALSE; 1007fa225cbcSrjs 1008fa225cbcSrjs if (!i830_display_tiled(crtc)) 1009fa225cbcSrjs return FALSE; 1010fa225cbcSrjs 1011fa225cbcSrjs /* Pre-965 only supports plane A */ 1012fa225cbcSrjs if (!IS_I965GM(pI830) && plane != FBC_CTL_PLANEA) 1013fa225cbcSrjs return FALSE; 1014fa225cbcSrjs 1015fa225cbcSrjs /* Need 15, 16, or 32 (w/alpha) pixel format */ 1016fa225cbcSrjs if (!(pScrn->bitsPerPixel == 16 || /* covers 15 bit mode as well */ 1017fa225cbcSrjs pScrn->bitsPerPixel == 32)) /* mode_set dtrt if fbc is in use */ 1018fa225cbcSrjs return FALSE; 1019fa225cbcSrjs 1020fa225cbcSrjs /* Can't cache more lines than we can track */ 1021fa225cbcSrjs if (crtc->mode.VDisplay > FBC_LL_SIZE) 1022fa225cbcSrjs return FALSE; 1023fa225cbcSrjs 1024fa225cbcSrjs /* 1025fa225cbcSrjs * Make sure the compressor doesn't go past the end of our compressed 1026fa225cbcSrjs * buffer if the uncompressed size is large. 1027fa225cbcSrjs */ 1028fa225cbcSrjs uncompressed_size = crtc->mode.HDisplay * crtc->mode.VDisplay * 1029fa225cbcSrjs pI830->cpp; 1030fa225cbcSrjs if (pI830->compressed_front_buffer->size < uncompressed_size) 1031fa225cbcSrjs return FALSE; 1032fa225cbcSrjs 1033fa225cbcSrjs /* 1034fa225cbcSrjs * No checks for pixel multiply, incl. horizontal, or interlaced modes 1035fa225cbcSrjs * since they're currently unused. 1036fa225cbcSrjs */ 1037fa225cbcSrjs return TRUE; 1038fa225cbcSrjs} 1039fa225cbcSrjs 1040fa225cbcSrjs#if defined(DRM_IOCTL_MODESET_CTL) 1041fa225cbcSrjsstatic void i830_modeset_ctl(xf86CrtcPtr crtc, int pre) 1042fa225cbcSrjs{ 1043fa225cbcSrjs ScrnInfoPtr pScrn = crtc->scrn; 1044fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 1045fa225cbcSrjs I830CrtcPrivatePtr intel_crtc = crtc->driver_private; 1046fa225cbcSrjs struct drm_modeset_ctl modeset; 1047fa225cbcSrjs 1048fa225cbcSrjs if (pI830->directRenderingType <= DRI_NONE) 1049fa225cbcSrjs return; 1050fa225cbcSrjs 1051fa225cbcSrjs modeset.crtc = intel_crtc->pipe; 1052fa225cbcSrjs 1053fa225cbcSrjs /* 1054fa225cbcSrjs * DPMS will be called many times (especially off), but we only 1055fa225cbcSrjs * want to catch the transition from on->off and off->on. 1056fa225cbcSrjs */ 1057fa225cbcSrjs if (pre && intel_crtc->dpms_mode != DPMSModeOff) { 1058fa225cbcSrjs /* On -> off is a pre modeset */ 1059fa225cbcSrjs modeset.cmd = _DRM_PRE_MODESET; 1060fa225cbcSrjs ioctl(pI830->drmSubFD, DRM_IOCTL_MODESET_CTL, &modeset); 1061fa225cbcSrjs } else if (!pre && intel_crtc->dpms_mode == DPMSModeOff) { 1062fa225cbcSrjs /* Off -> on means post modeset */ 1063fa225cbcSrjs modeset.cmd = _DRM_POST_MODESET; 1064fa225cbcSrjs ioctl(pI830->drmSubFD, DRM_IOCTL_MODESET_CTL, &modeset); 1065fa225cbcSrjs } 1066fa225cbcSrjs} 1067fa225cbcSrjs#else 1068fa225cbcSrjsstatic void i830_modeset_ctl(xf86CrtcPtr crtc, int dpms_state) 1069fa225cbcSrjs{ 1070fa225cbcSrjs return; 1071fa225cbcSrjs} 1072fa225cbcSrjs#endif /* DRM_IOCTL_MODESET_CTL */ 1073fa225cbcSrjs 1074fa225cbcSrjsstatic void 1075fa225cbcSrjsi830_disable_vga_plane (xf86CrtcPtr crtc) 1076fa225cbcSrjs{ 1077fa225cbcSrjs ScrnInfoPtr pScrn = crtc->scrn; 1078fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 1079fa225cbcSrjs uint8_t sr01; 1080fa225cbcSrjs 1081fa225cbcSrjs /* 1082fa225cbcSrjs * Bug #17235: G4X machine needs following steps 1083fa225cbcSrjs * for disable VGA. 1084fa225cbcSrjs * - set bit 5 of SR01; 1085fa225cbcSrjs * - Wait 30us; 1086fa225cbcSrjs * - disable vga plane; 1087fa225cbcSrjs * - restore SR01; 1088fa225cbcSrjs */ 1089fa225cbcSrjs if (IS_G4X(pI830)) { 1090fa225cbcSrjs OUTREG8(SRX, 1); 1091fa225cbcSrjs sr01 = INREG8(SRX + 1); 1092fa225cbcSrjs OUTREG8(SRX + 1, sr01 | (1 << 5)); 1093fa225cbcSrjs usleep(30); 1094fa225cbcSrjs } 1095fa225cbcSrjs 1096fa225cbcSrjs OUTREG(VGACNTRL, VGA_DISP_DISABLE); 1097fa225cbcSrjs i830WaitForVblank(pScrn); 1098fa225cbcSrjs 1099fa225cbcSrjs /* restore SR01 */ 1100fa225cbcSrjs if (IS_G4X(pI830)) { 1101fa225cbcSrjs OUTREG8(SRX, 1); 1102fa225cbcSrjs OUTREG8(SRX + 1, sr01); 1103fa225cbcSrjs } 1104fa225cbcSrjs} 1105fa225cbcSrjs 1106fa225cbcSrjsstatic void 1107fa225cbcSrjsi830_crtc_enable(xf86CrtcPtr crtc) 1108fa225cbcSrjs{ 1109fa225cbcSrjs ScrnInfoPtr pScrn = crtc->scrn; 1110fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 1111fa225cbcSrjs I830CrtcPrivatePtr intel_crtc = crtc->driver_private; 1112fa225cbcSrjs int pipe = intel_crtc->pipe; 1113fa225cbcSrjs int plane = intel_crtc->plane; 1114fa225cbcSrjs int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; 1115fa225cbcSrjs int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; 1116fa225cbcSrjs int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR; 1117fa225cbcSrjs int dspbase_reg = (plane == 0) ? DSPABASE : DSPBBASE; 1118fa225cbcSrjs uint32_t temp; 1119fa225cbcSrjs 1120fa225cbcSrjs /* Enable the DPLL */ 1121fa225cbcSrjs temp = INREG(dpll_reg); 1122fa225cbcSrjs if ((temp & DPLL_VCO_ENABLE) == 0) 1123fa225cbcSrjs { 1124fa225cbcSrjs OUTREG(dpll_reg, temp); 1125fa225cbcSrjs POSTING_READ(dpll_reg); 1126fa225cbcSrjs /* Wait for the clocks to stabilize. */ 1127fa225cbcSrjs usleep(150); 1128fa225cbcSrjs OUTREG(dpll_reg, temp | DPLL_VCO_ENABLE); 1129fa225cbcSrjs POSTING_READ(dpll_reg); 1130fa225cbcSrjs /* Wait for the clocks to stabilize. */ 1131fa225cbcSrjs usleep(150); 1132fa225cbcSrjs OUTREG(dpll_reg, temp | DPLL_VCO_ENABLE); 1133fa225cbcSrjs POSTING_READ(dpll_reg); 1134fa225cbcSrjs /* Wait for the clocks to stabilize. */ 1135fa225cbcSrjs usleep(150); 1136fa225cbcSrjs } 1137fa225cbcSrjs 1138fa225cbcSrjs /* Enable the pipe */ 1139fa225cbcSrjs temp = INREG(pipeconf_reg); 1140fa225cbcSrjs if ((temp & PIPEACONF_ENABLE) == 0) 1141fa225cbcSrjs OUTREG(pipeconf_reg, temp | PIPEACONF_ENABLE); 1142fa225cbcSrjs 1143fa225cbcSrjs /* Enable the plane */ 1144fa225cbcSrjs temp = INREG(dspcntr_reg); 1145fa225cbcSrjs if ((temp & DISPLAY_PLANE_ENABLE) == 0) 1146fa225cbcSrjs { 1147fa225cbcSrjs OUTREG(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE); 1148fa225cbcSrjs /* Flush the plane changes */ 1149fa225cbcSrjs OUTREG(dspbase_reg, INREG(dspbase_reg)); 1150fa225cbcSrjs } 1151fa225cbcSrjs 1152fa225cbcSrjs i830_crtc_load_lut(crtc); 1153fa225cbcSrjs 1154fa225cbcSrjs /* Give the overlay scaler a chance to enable if it's on this pipe */ 1155fa225cbcSrjs i830_crtc_dpms_video(crtc, TRUE); 1156fa225cbcSrjs 1157fa225cbcSrjs /* Reenable compression if needed */ 1158fa225cbcSrjs if (i830_use_fb_compression(crtc)) 1159fa225cbcSrjs i830_enable_fb_compression(crtc); 1160fa225cbcSrjs i830_modeset_ctl(crtc, 0); 1161fa225cbcSrjs} 1162fa225cbcSrjs 1163fa225cbcSrjsvoid 1164fa225cbcSrjsi830_crtc_disable(xf86CrtcPtr crtc, Bool disable_pipe) 1165fa225cbcSrjs{ 1166fa225cbcSrjs ScrnInfoPtr pScrn = crtc->scrn; 1167fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 1168fa225cbcSrjs I830CrtcPrivatePtr intel_crtc = crtc->driver_private; 1169fa225cbcSrjs int pipe = intel_crtc->pipe; 1170fa225cbcSrjs int plane = intel_crtc->plane; 1171fa225cbcSrjs int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; 1172fa225cbcSrjs int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; 1173fa225cbcSrjs int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR; 1174fa225cbcSrjs int dspbase_reg = (plane == 0) ? DSPABASE : DSPBBASE; 1175fa225cbcSrjs uint32_t temp; 1176fa225cbcSrjs 1177fa225cbcSrjs i830_modeset_ctl(crtc, 1); 1178fa225cbcSrjs /* Shut off compression if in use */ 1179fa225cbcSrjs if (i830_use_fb_compression(crtc)) 1180fa225cbcSrjs i830_disable_fb_compression(crtc); 1181fa225cbcSrjs 1182fa225cbcSrjs /* Give the overlay scaler a chance to disable if it's on this pipe */ 1183fa225cbcSrjs i830_crtc_dpms_video(crtc, FALSE); 1184fa225cbcSrjs 1185fa225cbcSrjs /* 1186fa225cbcSrjs * The documentation says : 1187fa225cbcSrjs * - Disable planes (VGA or hires) 1188fa225cbcSrjs * - Disable pipe 1189fa225cbcSrjs * - Disable VGA display 1190fa225cbcSrjs */ 1191fa225cbcSrjs 1192fa225cbcSrjs /* Disable display plane */ 1193fa225cbcSrjs temp = INREG(dspcntr_reg); 1194fa225cbcSrjs if ((temp & DISPLAY_PLANE_ENABLE) != 0) 1195fa225cbcSrjs { 1196fa225cbcSrjs OUTREG(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE); 1197fa225cbcSrjs /* Flush the plane changes */ 1198fa225cbcSrjs OUTREG(dspbase_reg, INREG(dspbase_reg)); 1199fa225cbcSrjs POSTING_READ(dspbase_reg); 1200fa225cbcSrjs } 1201fa225cbcSrjs 1202fa225cbcSrjs if (!IS_I9XX(pI830)) { 1203fa225cbcSrjs /* Wait for vblank for the disable to take effect */ 1204fa225cbcSrjs i830WaitForVblank(pScrn); 1205fa225cbcSrjs } 1206fa225cbcSrjs 1207fa225cbcSrjs /* May need to leave pipe A on */ 1208fa225cbcSrjs if (disable_pipe) 1209fa225cbcSrjs { 1210fa225cbcSrjs /* Next, disable display pipes */ 1211fa225cbcSrjs temp = INREG(pipeconf_reg); 1212fa225cbcSrjs if ((temp & PIPEACONF_ENABLE) != 0) { 1213fa225cbcSrjs OUTREG(pipeconf_reg, temp & ~PIPEACONF_ENABLE); 1214fa225cbcSrjs POSTING_READ(pipeconf_reg); 1215fa225cbcSrjs } 1216fa225cbcSrjs 1217fa225cbcSrjs /* Wait for vblank for the disable to take effect. */ 1218fa225cbcSrjs i830WaitForVblank(pScrn); 1219fa225cbcSrjs 1220fa225cbcSrjs temp = INREG(dpll_reg); 1221fa225cbcSrjs if ((temp & DPLL_VCO_ENABLE) != 0) { 1222fa225cbcSrjs OUTREG(dpll_reg, temp & ~DPLL_VCO_ENABLE); 1223fa225cbcSrjs POSTING_READ(dpll_reg); 1224fa225cbcSrjs } 1225fa225cbcSrjs 1226fa225cbcSrjs /* Wait for the clocks to turn off. */ 1227fa225cbcSrjs usleep(150); 1228fa225cbcSrjs } 1229fa225cbcSrjs 1230fa225cbcSrjs /* Disable the VGA plane that we never use. */ 1231fa225cbcSrjs i830_disable_vga_plane (crtc); 1232fa225cbcSrjs} 1233fa225cbcSrjs 1234fa225cbcSrjs/** 1235fa225cbcSrjs * Sets the power management mode of the pipe and plane. 1236fa225cbcSrjs * 1237fa225cbcSrjs * This code should probably grow support for turning the cursor off and back 1238fa225cbcSrjs * on appropriately at the same time as we're turning the pipe off/on. 1239fa225cbcSrjs */ 1240fa225cbcSrjsstatic void 1241fa225cbcSrjsi830_crtc_dpms(xf86CrtcPtr crtc, int mode) 1242fa225cbcSrjs{ 1243fa225cbcSrjs ScrnInfoPtr pScrn = crtc->scrn; 1244fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 1245fa225cbcSrjs I830CrtcPrivatePtr intel_crtc = crtc->driver_private; 1246fa225cbcSrjs int pipe = intel_crtc->pipe; 1247fa225cbcSrjs Bool disable_pipe = TRUE; 1248fa225cbcSrjs 1249fa225cbcSrjs /* XXX: When our outputs are all unaware of DPMS modes other than off and 1250fa225cbcSrjs * on, we should map those modes to DPMSModeOff in the CRTC. 1251fa225cbcSrjs */ 1252fa225cbcSrjs switch (mode) { 1253fa225cbcSrjs case DPMSModeOn: 1254fa225cbcSrjs case DPMSModeStandby: 1255fa225cbcSrjs case DPMSModeSuspend: 1256fa225cbcSrjs i830_crtc_enable(crtc); 1257fa225cbcSrjs break; 1258fa225cbcSrjs case DPMSModeOff: 1259fa225cbcSrjs if ((pipe == 0) && (pI830->quirk_flag & QUIRK_PIPEA_FORCE)) 1260fa225cbcSrjs disable_pipe = FALSE; 1261fa225cbcSrjs i830_crtc_disable(crtc, disable_pipe); 1262fa225cbcSrjs intel_crtc->enabled = FALSE; 1263fa225cbcSrjs break; 1264fa225cbcSrjs } 1265fa225cbcSrjs 1266fa225cbcSrjs intel_crtc->dpms_mode = mode; 1267fa225cbcSrjs} 1268fa225cbcSrjs 1269fa225cbcSrjsstatic Bool 1270fa225cbcSrjsi830_crtc_lock (xf86CrtcPtr crtc) 1271fa225cbcSrjs{ 1272fa225cbcSrjs /* Sync the engine before mode switch, to finish any outstanding 1273fa225cbcSrjs * WAIT_FOR_EVENTS that may rely on CRTC state. 1274fa225cbcSrjs */ 1275fa225cbcSrjs I830Sync(crtc->scrn); 1276fa225cbcSrjs 1277fa225cbcSrjs return FALSE; 1278fa225cbcSrjs} 1279fa225cbcSrjs 1280fa225cbcSrjsstatic void 1281fa225cbcSrjsi830_crtc_unlock (xf86CrtcPtr crtc) 1282fa225cbcSrjs{ 1283fa225cbcSrjs} 1284fa225cbcSrjs 1285fa225cbcSrjsstatic void 1286fa225cbcSrjsi830_crtc_prepare (xf86CrtcPtr crtc) 1287fa225cbcSrjs{ 1288fa225cbcSrjs I830CrtcPrivatePtr intel_crtc = crtc->driver_private; 1289fa225cbcSrjs /* Temporarily turn off FB compression during modeset */ 1290fa225cbcSrjs if (i830_use_fb_compression(crtc)) 1291fa225cbcSrjs i830_disable_fb_compression(crtc); 1292fa225cbcSrjs if (intel_crtc->enabled) 1293fa225cbcSrjs crtc->funcs->hide_cursor (crtc); 1294fa225cbcSrjs crtc->funcs->dpms (crtc, DPMSModeOff); 1295fa225cbcSrjs} 1296fa225cbcSrjs 1297fa225cbcSrjsstatic void 1298fa225cbcSrjsi830_crtc_commit (xf86CrtcPtr crtc) 1299fa225cbcSrjs{ 1300fa225cbcSrjs I830CrtcPrivatePtr intel_crtc = crtc->driver_private; 1301fa225cbcSrjs Bool deactivate = FALSE; 1302fa225cbcSrjs 1303fa225cbcSrjs if (!intel_crtc->enabled && intel_crtc->pipe != 0) 1304fa225cbcSrjs deactivate = i830_pipe_a_require_activate (crtc->scrn); 1305fa225cbcSrjs 1306fa225cbcSrjs intel_crtc->enabled = TRUE; 1307fa225cbcSrjs 1308fa225cbcSrjs crtc->funcs->dpms (crtc, DPMSModeOn); 1309fa225cbcSrjs if (crtc->scrn->pScreen != NULL) 1310fa225cbcSrjs xf86_reload_cursors (crtc->scrn->pScreen); 1311fa225cbcSrjs if (deactivate) 1312fa225cbcSrjs i830_pipe_a_require_deactivate (crtc->scrn); 1313fa225cbcSrjs 1314fa225cbcSrjs /* Reenable FB compression if possible */ 1315fa225cbcSrjs if (i830_use_fb_compression(crtc)) 1316fa225cbcSrjs i830_enable_fb_compression(crtc); 1317fa225cbcSrjs} 1318fa225cbcSrjs 1319fa225cbcSrjsvoid 1320fa225cbcSrjsi830_output_prepare (xf86OutputPtr output) 1321fa225cbcSrjs{ 1322fa225cbcSrjs output->funcs->dpms (output, DPMSModeOff); 1323fa225cbcSrjs} 1324fa225cbcSrjs 1325fa225cbcSrjsvoid 1326fa225cbcSrjsi830_output_commit (xf86OutputPtr output) 1327fa225cbcSrjs{ 1328fa225cbcSrjs output->funcs->dpms (output, DPMSModeOn); 1329fa225cbcSrjs} 1330fa225cbcSrjs 1331fa225cbcSrjsstatic Bool 1332fa225cbcSrjsi830_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode, 1333fa225cbcSrjs DisplayModePtr adjusted_mode) 1334fa225cbcSrjs{ 1335fa225cbcSrjs return TRUE; 1336fa225cbcSrjs} 1337fa225cbcSrjs 1338fa225cbcSrjs/** Returns the core display clock speed for i830 - i945 */ 1339fa225cbcSrjsstatic int 1340fa225cbcSrjsi830_get_core_clock_speed(ScrnInfoPtr pScrn) 1341fa225cbcSrjs{ 1342fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 1343fa225cbcSrjs 1344fa225cbcSrjs /* Core clock values taken from the published datasheets. 1345fa225cbcSrjs * The 830 may go up to 166 Mhz, which we should check. 1346fa225cbcSrjs */ 1347fa225cbcSrjs if (IS_I945G(pI830) || (IS_G33CLASS(pI830) && !IS_IGDGM(pI830))) 1348fa225cbcSrjs return 400000; 1349fa225cbcSrjs else if (IS_I915G(pI830)) 1350fa225cbcSrjs return 333000; 1351fa225cbcSrjs else if (IS_I945GM(pI830) || IS_845G(pI830) || IS_IGDGM(pI830)) 1352fa225cbcSrjs return 200000; 1353fa225cbcSrjs else if (IS_I915GM(pI830)) { 1354fa225cbcSrjs uint16_t gcfgc; 1355fa225cbcSrjs 1356fa225cbcSrjs pci_device_cfg_read_u16 (pI830->PciInfo, &gcfgc, I915_GCFGC); 1357fa225cbcSrjs if (gcfgc & I915_LOW_FREQUENCY_ENABLE) 1358fa225cbcSrjs return 133000; 1359fa225cbcSrjs else { 1360fa225cbcSrjs switch (gcfgc & I915_DISPLAY_CLOCK_MASK) { 1361fa225cbcSrjs case I915_DISPLAY_CLOCK_333_MHZ: 1362fa225cbcSrjs return 333000; 1363fa225cbcSrjs default: 1364fa225cbcSrjs case I915_DISPLAY_CLOCK_190_200_MHZ: 1365fa225cbcSrjs return 190000; 1366fa225cbcSrjs } 1367fa225cbcSrjs } 1368fa225cbcSrjs } else if (IS_I865G(pI830)) 1369fa225cbcSrjs return 266000; 1370fa225cbcSrjs else if (IS_I855(pI830)) { 1371fa225cbcSrjs struct pci_device *bridge = intel_host_bridge (); 1372fa225cbcSrjs uint16_t hpllcc; 1373fa225cbcSrjs pci_device_cfg_read_u16 (bridge, &hpllcc, I855_HPLLCC); 1374fa225cbcSrjs 1375fa225cbcSrjs /* Assume that the hardware is in the high speed state. This 1376fa225cbcSrjs * should be the default. 1377fa225cbcSrjs */ 1378fa225cbcSrjs switch (hpllcc & I855_CLOCK_CONTROL_MASK) { 1379fa225cbcSrjs case I855_CLOCK_133_200: 1380fa225cbcSrjs case I855_CLOCK_100_200: 1381fa225cbcSrjs return 200000; 1382fa225cbcSrjs case I855_CLOCK_166_250: 1383fa225cbcSrjs return 250000; 1384fa225cbcSrjs case I855_CLOCK_100_133: 1385fa225cbcSrjs return 133000; 1386fa225cbcSrjs } 1387fa225cbcSrjs } else /* 852, 830 */ 1388fa225cbcSrjs return 133000; 1389fa225cbcSrjs 1390fa225cbcSrjs return 0; /* Silence gcc warning */ 1391fa225cbcSrjs} 1392fa225cbcSrjs 1393fa225cbcSrjs/** 1394fa225cbcSrjs * Return the pipe currently connected to the panel fitter, 1395fa225cbcSrjs * or -1 if the panel fitter is not present or not in use 1396fa225cbcSrjs */ 1397fa225cbcSrjsstatic int 1398fa225cbcSrjsi830_panel_fitter_pipe(I830Ptr pI830) 1399fa225cbcSrjs{ 1400fa225cbcSrjs uint32_t pfit_control; 1401fa225cbcSrjs 1402fa225cbcSrjs /* i830 doesn't have a panel fitter */ 1403fa225cbcSrjs if (IS_I830(pI830)) 1404fa225cbcSrjs return -1; 1405fa225cbcSrjs 1406fa225cbcSrjs pfit_control = INREG(PFIT_CONTROL); 1407fa225cbcSrjs 1408fa225cbcSrjs /* See if the panel fitter is in use */ 1409fa225cbcSrjs if ((pfit_control & PFIT_ENABLE) == 0) 1410fa225cbcSrjs return -1; 1411fa225cbcSrjs 1412fa225cbcSrjs /* 965 can place panel fitter on either pipe */ 1413fa225cbcSrjs if (IS_I965G(pI830)) 1414fa225cbcSrjs return (pfit_control & PFIT_PIPE_MASK) >> PFIT_PIPE_SHIFT; 1415fa225cbcSrjs 1416fa225cbcSrjs /* older chips can only use pipe 1 */ 1417fa225cbcSrjs return 1; 1418fa225cbcSrjs} 1419fa225cbcSrjs 1420fa225cbcSrjs/** 1421fa225cbcSrjs * Sets up the DSPARB register to split the display fifo appropriately between 1422fa225cbcSrjs * the display planes. 1423fa225cbcSrjs * 1424fa225cbcSrjs * Adjusting this register requires that the planes be off. 1425fa225cbcSrjs */ 1426fa225cbcSrjsstatic void 1427fa225cbcSrjsi830_update_dsparb(ScrnInfoPtr pScrn) 1428fa225cbcSrjs{ 1429fa225cbcSrjs xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1430fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 1431fa225cbcSrjs int total_hdisplay = 0, planea_hdisplay = 0, planeb_hdisplay = 0; 1432fa225cbcSrjs int fifo_entries = 0, planea_entries = 0, planeb_entries = 0, i; 1433fa225cbcSrjs 1434fa225cbcSrjs if ((INREG(DSPACNTR) & DISPLAY_PLANE_ENABLE) && 1435fa225cbcSrjs (INREG(DSPBCNTR) & DISPLAY_PLANE_ENABLE)) 1436fa225cbcSrjs xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1437fa225cbcSrjs "tried to update DSPARB with both planes enabled!\n"); 1438fa225cbcSrjs 1439fa225cbcSrjs /* 1440fa225cbcSrjs * FIFO entries will be split based on programmed modes 1441fa225cbcSrjs */ 1442fa225cbcSrjs if (IS_I965GM(pI830)) 1443fa225cbcSrjs fifo_entries = 127; 1444fa225cbcSrjs else if (IS_I9XX(pI830)) 1445fa225cbcSrjs fifo_entries = 95; 1446fa225cbcSrjs else if (IS_MOBILE(pI830)) { 1447fa225cbcSrjs fifo_entries = 255; 1448fa225cbcSrjs } else { 1449fa225cbcSrjs /* The 845/865 only have a AEND field. Though the field size would 1450fa225cbcSrjs * allow 128 entries, the 865 rendered the cursor wrong then. 1451fa225cbcSrjs * The BIOS set it up for 96. 1452fa225cbcSrjs */ 1453fa225cbcSrjs fifo_entries = 95; 1454fa225cbcSrjs } 1455fa225cbcSrjs 1456fa225cbcSrjs for (i = 0; i < xf86_config->num_crtc; i++) { 1457fa225cbcSrjs xf86CrtcPtr crtc = xf86_config->crtc[i]; 1458fa225cbcSrjs I830CrtcPrivatePtr intel_crtc = crtc->driver_private; 1459fa225cbcSrjs if (crtc->enabled) { 1460fa225cbcSrjs total_hdisplay += crtc->mode.HDisplay; 1461fa225cbcSrjs if (intel_crtc->plane == 0) 1462fa225cbcSrjs planea_hdisplay = crtc->mode.HDisplay; 1463fa225cbcSrjs else 1464fa225cbcSrjs planeb_hdisplay = crtc->mode.HDisplay; 1465fa225cbcSrjs } 1466fa225cbcSrjs } 1467fa225cbcSrjs 1468fa225cbcSrjs planea_entries = fifo_entries * planea_hdisplay / total_hdisplay; 1469fa225cbcSrjs planeb_entries = fifo_entries * planeb_hdisplay / total_hdisplay; 1470fa225cbcSrjs 1471fa225cbcSrjs if (IS_I9XX(pI830)) 1472fa225cbcSrjs OUTREG(DSPARB, 1473fa225cbcSrjs ((planea_entries + planeb_entries) << DSPARB_CSTART_SHIFT) | 1474fa225cbcSrjs (planea_entries << DSPARB_BSTART_SHIFT)); 1475fa225cbcSrjs else if (IS_MOBILE(pI830)) 1476fa225cbcSrjs OUTREG(DSPARB, 1477fa225cbcSrjs ((planea_entries + planeb_entries) << DSPARB_BEND_SHIFT) | 1478fa225cbcSrjs (planea_entries << DSPARB_AEND_SHIFT)); 1479fa225cbcSrjs else 1480fa225cbcSrjs OUTREG(DSPARB, planea_entries << DSPARB_AEND_SHIFT); 1481fa225cbcSrjs} 1482fa225cbcSrjs 1483fa225cbcSrjs/** 1484fa225cbcSrjs * Sets up registers for the given mode/adjusted_mode pair. 1485fa225cbcSrjs * 1486fa225cbcSrjs * The clocks, CRTCs and outputs attached to this CRTC must be off. 1487fa225cbcSrjs * 1488fa225cbcSrjs * This shouldn't enable any clocks, CRTCs, or outputs, but they should 1489fa225cbcSrjs * be easily turned on/off after this. 1490fa225cbcSrjs */ 1491fa225cbcSrjsstatic void 1492fa225cbcSrjsi830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, 1493fa225cbcSrjs DisplayModePtr adjusted_mode, 1494fa225cbcSrjs int x, int y) 1495fa225cbcSrjs{ 1496fa225cbcSrjs ScrnInfoPtr pScrn = crtc->scrn; 1497fa225cbcSrjs xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1498fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 1499fa225cbcSrjs I830CrtcPrivatePtr intel_crtc = crtc->driver_private; 1500fa225cbcSrjs I830OutputPrivatePtr intel_output; 1501fa225cbcSrjs int pipe = intel_crtc->pipe; 1502fa225cbcSrjs int plane = intel_crtc->plane; 1503fa225cbcSrjs int fp_reg = (pipe == 0) ? FPA0 : FPB0; 1504fa225cbcSrjs int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; 1505fa225cbcSrjs int dpll_md_reg = (pipe == 0) ? DPLL_A_MD : DPLL_B_MD; 1506fa225cbcSrjs int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; 1507fa225cbcSrjs int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B; 1508fa225cbcSrjs int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B; 1509fa225cbcSrjs int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B; 1510fa225cbcSrjs int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B; 1511fa225cbcSrjs int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B; 1512fa225cbcSrjs int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B; 1513fa225cbcSrjs int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC; 1514fa225cbcSrjs int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR; 1515fa225cbcSrjs int dsppos_reg = (plane == 0) ? DSPAPOS : DSPBPOS; 1516fa225cbcSrjs int dspsize_reg = (plane == 0) ? DSPASIZE : DSPBSIZE; 1517fa225cbcSrjs int i, num_outputs = 0; 1518fa225cbcSrjs int refclk; 1519fa225cbcSrjs intel_clock_t clock; 1520fa225cbcSrjs uint32_t dpll = 0, fp = 0, dspcntr, pipeconf, lvds_bits = 0; 1521fa225cbcSrjs Bool ok, is_sdvo = FALSE, is_dvo = FALSE; 1522fa225cbcSrjs Bool is_crt = FALSE, is_lvds = FALSE, is_tv = FALSE; 1523fa225cbcSrjs const intel_limit_t *limit; 1524fa225cbcSrjs 1525fa225cbcSrjs /* Set up some convenient bools for what outputs are connected to 1526fa225cbcSrjs * our pipe, used in DPLL setup. 1527fa225cbcSrjs */ 1528fa225cbcSrjs for (i = 0; i < xf86_config->num_output; i++) { 1529fa225cbcSrjs xf86OutputPtr output = xf86_config->output[i]; 1530fa225cbcSrjs intel_output = output->driver_private; 1531fa225cbcSrjs 1532fa225cbcSrjs if (output->crtc != crtc) 1533fa225cbcSrjs continue; 1534fa225cbcSrjs 1535fa225cbcSrjs switch (intel_output->type) { 1536fa225cbcSrjs case I830_OUTPUT_LVDS: 1537fa225cbcSrjs is_lvds = TRUE; 1538fa225cbcSrjs lvds_bits = intel_output->lvds_bits; 1539fa225cbcSrjs break; 1540fa225cbcSrjs case I830_OUTPUT_SDVO: 1541fa225cbcSrjs case I830_OUTPUT_HDMI: 1542fa225cbcSrjs is_sdvo = TRUE; 1543fa225cbcSrjs if (intel_output->needs_tv_clock) 1544fa225cbcSrjs is_tv = TRUE; 1545fa225cbcSrjs break; 1546fa225cbcSrjs case I830_OUTPUT_DVO_TMDS: 1547fa225cbcSrjs case I830_OUTPUT_DVO_LVDS: 1548fa225cbcSrjs case I830_OUTPUT_DVO_TVOUT: 1549fa225cbcSrjs is_dvo = TRUE; 1550fa225cbcSrjs break; 1551fa225cbcSrjs case I830_OUTPUT_TVOUT: 1552fa225cbcSrjs is_tv = TRUE; 1553fa225cbcSrjs break; 1554fa225cbcSrjs case I830_OUTPUT_ANALOG: 1555fa225cbcSrjs is_crt = TRUE; 1556fa225cbcSrjs break; 1557fa225cbcSrjs } 1558fa225cbcSrjs 1559fa225cbcSrjs num_outputs++; 1560fa225cbcSrjs } 1561fa225cbcSrjs 1562fa225cbcSrjs if (num_outputs > 1) 1563fa225cbcSrjs xf86DrvMsg(pScrn->scrnIndex, X_INFO, "clone detected, disabling SSC\n"); 1564fa225cbcSrjs 1565fa225cbcSrjs /* Don't use SSC when cloned */ 1566fa225cbcSrjs if (is_lvds && pI830->lvds_use_ssc && num_outputs < 2) { 1567fa225cbcSrjs refclk = pI830->lvds_ssc_freq * 1000; 1568fa225cbcSrjs xf86DrvMsg(pScrn->scrnIndex, X_INFO, 1569fa225cbcSrjs "using SSC reference clock of %d MHz\n", refclk / 1000); 1570fa225cbcSrjs } else if (IS_I9XX(pI830)) { 1571fa225cbcSrjs refclk = 96000; 1572fa225cbcSrjs } else { 1573fa225cbcSrjs refclk = 48000; 1574fa225cbcSrjs } 1575fa225cbcSrjs 1576fa225cbcSrjs /* 1577fa225cbcSrjs * Returns a set of divisors for the desired target clock with the given 1578fa225cbcSrjs * refclk, or FALSE. The returned values represent the clock equation: 1579fa225cbcSrjs * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. 1580fa225cbcSrjs */ 1581fa225cbcSrjs limit = intel_limit (crtc); 1582fa225cbcSrjs ok = limit->find_pll(limit, crtc, adjusted_mode->Clock, refclk, &clock); 1583fa225cbcSrjs if (!ok) 1584fa225cbcSrjs FatalError("Couldn't find PLL settings for mode!\n"); 1585fa225cbcSrjs 1586fa225cbcSrjs if (fabs(adjusted_mode->Clock - clock.dot) / clock.dot > .02) { 1587fa225cbcSrjs xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 1588fa225cbcSrjs "Chosen PLL clock of %.1f Mhz more than 2%% away from " 1589fa225cbcSrjs "desired %.1f Mhz\n", 1590fa225cbcSrjs (float)clock.dot / 1000, 1591fa225cbcSrjs (float)adjusted_mode->Clock / 1000); 1592fa225cbcSrjs } 1593fa225cbcSrjs 1594fa225cbcSrjs /* SDVO TV has fixed PLL values depends on its clock range, 1595fa225cbcSrjs this mirrors vbios setting. */ 1596fa225cbcSrjs if (is_sdvo && is_tv) { 1597fa225cbcSrjs if (adjusted_mode->Clock >= 100000 && 1598fa225cbcSrjs adjusted_mode->Clock < 140500) { 1599fa225cbcSrjs clock.p1 = 2; 1600fa225cbcSrjs clock.p2 = 10; 1601fa225cbcSrjs clock.n = 3; 1602fa225cbcSrjs clock.m1 = 16; 1603fa225cbcSrjs clock.m2 = 8; 1604fa225cbcSrjs } else if (adjusted_mode->Clock >= 140500 && 1605fa225cbcSrjs adjusted_mode->Clock <= 200000) { 1606fa225cbcSrjs clock.p1 = 1; 1607fa225cbcSrjs clock.p2 = 10; 1608fa225cbcSrjs clock.n = 6; 1609fa225cbcSrjs clock.m1 = 12; 1610fa225cbcSrjs clock.m2 = 8; 1611fa225cbcSrjs } 1612fa225cbcSrjs } 1613fa225cbcSrjs 1614fa225cbcSrjs if (IS_IGD(pI830)) 1615fa225cbcSrjs fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2; 1616fa225cbcSrjs else 1617fa225cbcSrjs fp = clock.n << 16 | clock.m1 << 8 | clock.m2; 1618fa225cbcSrjs 1619fa225cbcSrjs dpll = DPLL_VGA_MODE_DIS; 1620fa225cbcSrjs if (IS_I9XX(pI830)) { 1621fa225cbcSrjs if (is_lvds) 1622fa225cbcSrjs dpll |= DPLLB_MODE_LVDS; 1623fa225cbcSrjs else 1624fa225cbcSrjs dpll |= DPLLB_MODE_DAC_SERIAL; 1625fa225cbcSrjs if (is_sdvo) 1626fa225cbcSrjs { 1627fa225cbcSrjs dpll |= DPLL_DVO_HIGH_SPEED; 1628fa225cbcSrjs if ((IS_I945G(pI830) || IS_I945GM(pI830) || IS_G33CLASS(pI830))) 1629fa225cbcSrjs { 1630fa225cbcSrjs int sdvo_pixel_multiply = adjusted_mode->Clock / mode->Clock; 1631fa225cbcSrjs dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; 1632fa225cbcSrjs } 1633fa225cbcSrjs } 1634fa225cbcSrjs 1635fa225cbcSrjs /* compute bitmask from p1 value */ 1636fa225cbcSrjs if (IS_IGD(pI830)) 1637fa225cbcSrjs dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT_IGD; 1638fa225cbcSrjs else 1639fa225cbcSrjs dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; 1640fa225cbcSrjs switch (clock.p2) { 1641fa225cbcSrjs case 5: 1642fa225cbcSrjs dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5; 1643fa225cbcSrjs break; 1644fa225cbcSrjs case 7: 1645fa225cbcSrjs dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7; 1646fa225cbcSrjs break; 1647fa225cbcSrjs case 10: 1648fa225cbcSrjs dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10; 1649fa225cbcSrjs break; 1650fa225cbcSrjs case 14: 1651fa225cbcSrjs dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14; 1652fa225cbcSrjs break; 1653fa225cbcSrjs } 1654fa225cbcSrjs if (IS_I965G(pI830) && !IS_GM45(pI830)) 1655fa225cbcSrjs dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT); 1656fa225cbcSrjs } else { 1657fa225cbcSrjs if (is_lvds) { 1658fa225cbcSrjs dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; 1659fa225cbcSrjs } else { 1660fa225cbcSrjs if (clock.p1 == 2) 1661fa225cbcSrjs dpll |= PLL_P1_DIVIDE_BY_TWO; 1662fa225cbcSrjs else 1663fa225cbcSrjs dpll |= (clock.p1 - 2) << DPLL_FPA01_P1_POST_DIV_SHIFT; 1664fa225cbcSrjs if (clock.p2 == 4) 1665fa225cbcSrjs dpll |= PLL_P2_DIVIDE_BY_4; 1666fa225cbcSrjs } 1667fa225cbcSrjs } 1668fa225cbcSrjs 1669fa225cbcSrjs if (is_sdvo && is_tv) 1670fa225cbcSrjs dpll |= PLL_REF_INPUT_TVCLKINBC; 1671fa225cbcSrjs else if (is_tv) 1672fa225cbcSrjs { 1673fa225cbcSrjs /* XXX: just matching BIOS for now */ 1674fa225cbcSrjs/* dpll |= PLL_REF_INPUT_TVCLKINBC; */ 1675fa225cbcSrjs dpll |= 3; 1676fa225cbcSrjs } 1677fa225cbcSrjs else if (is_lvds && pI830->lvds_use_ssc && num_outputs < 2) 1678fa225cbcSrjs dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN; 1679fa225cbcSrjs else 1680fa225cbcSrjs dpll |= PLL_REF_INPUT_DREFCLK; 1681fa225cbcSrjs 1682fa225cbcSrjs /* Set up the display plane register */ 1683fa225cbcSrjs dspcntr = DISPPLANE_GAMMA_ENABLE; 1684fa225cbcSrjs switch (pScrn->bitsPerPixel) { 1685fa225cbcSrjs case 8: 1686fa225cbcSrjs dspcntr |= DISPPLANE_8BPP; 1687fa225cbcSrjs break; 1688fa225cbcSrjs case 16: 1689fa225cbcSrjs if (pScrn->depth == 15) 1690fa225cbcSrjs dspcntr |= DISPPLANE_15_16BPP; 1691fa225cbcSrjs else 1692fa225cbcSrjs dspcntr |= DISPPLANE_16BPP; 1693fa225cbcSrjs break; 1694fa225cbcSrjs case 32: 1695fa225cbcSrjs dspcntr |= DISPPLANE_32BPP_NO_ALPHA; 1696fa225cbcSrjs break; 1697fa225cbcSrjs default: 1698fa225cbcSrjs FatalError("unknown display bpp\n"); 1699fa225cbcSrjs } 1700fa225cbcSrjs 1701fa225cbcSrjs if (pipe == 0) 1702fa225cbcSrjs dspcntr |= DISPPLANE_SEL_PIPE_A; 1703fa225cbcSrjs else 1704fa225cbcSrjs dspcntr |= DISPPLANE_SEL_PIPE_B; 1705fa225cbcSrjs 1706fa225cbcSrjs if (IS_I965G(pI830) && i830_display_tiled(crtc)) 1707fa225cbcSrjs dspcntr |= DISPLAY_PLANE_TILED; 1708fa225cbcSrjs 1709fa225cbcSrjs pipeconf = INREG(pipeconf_reg); 1710fa225cbcSrjs if (pipe == 0 && !IS_I965G(pI830)) 1711fa225cbcSrjs { 1712fa225cbcSrjs /* Enable pixel doubling when the dot clock is > 90% of the (display) 1713fa225cbcSrjs * core speed. 1714fa225cbcSrjs * 1715fa225cbcSrjs * XXX: No double-wide on 915GM pipe B. Is that the only reason for the 1716fa225cbcSrjs * pipe == 0 check? 1717fa225cbcSrjs */ 1718fa225cbcSrjs if (mode->Clock > i830_get_core_clock_speed(pScrn) * 9 / 10) 1719fa225cbcSrjs pipeconf |= PIPEACONF_DOUBLE_WIDE; 1720fa225cbcSrjs else 1721fa225cbcSrjs pipeconf &= ~PIPEACONF_DOUBLE_WIDE; 1722fa225cbcSrjs } 1723fa225cbcSrjs /* 1724fa225cbcSrjs * This "shouldn't" be needed as the dpms on code 1725fa225cbcSrjs * will be run after the mode is set. On 9xx, it helps. 1726fa225cbcSrjs * On 855, it can lock up the chip (and the entire machine) 1727fa225cbcSrjs */ 1728fa225cbcSrjs if (!IS_I85X (pI830)) 1729fa225cbcSrjs { 1730fa225cbcSrjs dspcntr |= DISPLAY_PLANE_ENABLE; 1731fa225cbcSrjs pipeconf |= PIPEACONF_ENABLE; 1732fa225cbcSrjs dpll |= DPLL_VCO_ENABLE; 1733fa225cbcSrjs } 1734fa225cbcSrjs 1735fa225cbcSrjs /* Disable the panel fitter if it was on our pipe */ 1736fa225cbcSrjs if (i830_panel_fitter_pipe (pI830) == pipe) 1737fa225cbcSrjs OUTREG(PFIT_CONTROL, 0); 1738fa225cbcSrjs 1739fa225cbcSrjs if (pI830->debug_modes) { 1740fa225cbcSrjs xf86DrvMsg(pScrn->scrnIndex, X_INFO, 1741fa225cbcSrjs "Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); 1742fa225cbcSrjs xf86PrintModeline(pScrn->scrnIndex, mode); 1743fa225cbcSrjs if (!xf86ModesEqual(mode, adjusted_mode)) { 1744fa225cbcSrjs xf86DrvMsg(pScrn->scrnIndex, X_INFO, 1745fa225cbcSrjs "Adjusted mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); 1746fa225cbcSrjs xf86PrintModeline(pScrn->scrnIndex, adjusted_mode); 1747fa225cbcSrjs } 1748fa225cbcSrjs i830PrintPll(pScrn, "chosen", &clock); 1749fa225cbcSrjs } 1750fa225cbcSrjs 1751fa225cbcSrjs if (dpll & DPLL_VCO_ENABLE) 1752fa225cbcSrjs { 1753fa225cbcSrjs OUTREG(fp_reg, fp); 1754fa225cbcSrjs OUTREG(dpll_reg, dpll & ~DPLL_VCO_ENABLE); 1755fa225cbcSrjs POSTING_READ(dpll_reg); 1756fa225cbcSrjs usleep(150); 1757fa225cbcSrjs } 1758fa225cbcSrjs 1759fa225cbcSrjs /* The LVDS pin pair needs to be on before the DPLLs are enabled. 1760fa225cbcSrjs * This is an exception to the general rule that mode_set doesn't turn 1761fa225cbcSrjs * things on. 1762fa225cbcSrjs */ 1763fa225cbcSrjs if (is_lvds) 1764fa225cbcSrjs { 1765fa225cbcSrjs uint32_t lvds = INREG(LVDS); 1766fa225cbcSrjs 1767fa225cbcSrjs lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT; 1768fa225cbcSrjs /* Set the B0-B3 data pairs corresponding to whether we're going to 1769fa225cbcSrjs * set the DPLLs for dual-channel mode or not. 1770fa225cbcSrjs */ 1771fa225cbcSrjs if (clock.p2 == I9XX_P2_LVDS_FAST) 1772fa225cbcSrjs lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; 1773fa225cbcSrjs else 1774fa225cbcSrjs lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); 1775fa225cbcSrjs 1776fa225cbcSrjs if (pI830->lvds_24_bit_mode) { 1777fa225cbcSrjs /* Option set which requests 24-bit mode 1778fa225cbcSrjs * (LVDS_A3_POWER_UP, as opposed to 18-bit mode) here; we 1779fa225cbcSrjs * still need to look more thoroughly into how panels 1780fa225cbcSrjs * behave in the two modes. This option enables that 1781fa225cbcSrjs * experimentation. 1782fa225cbcSrjs */ 1783fa225cbcSrjs xf86DrvMsg(pScrn->scrnIndex, X_INFO, 1784fa225cbcSrjs "Selecting less common 24 bit TMDS pixel format.\n"); 1785fa225cbcSrjs lvds |= LVDS_A3_POWER_UP; 1786fa225cbcSrjs lvds |= LVDS_DATA_FORMAT_DOT_ONE; 1787fa225cbcSrjs } else { 1788fa225cbcSrjs xf86DrvMsg(pScrn->scrnIndex, X_INFO, 1789fa225cbcSrjs "Selecting standard 18 bit TMDS pixel format.\n"); 1790fa225cbcSrjs } 1791fa225cbcSrjs 1792fa225cbcSrjs /* Enable dithering if we're in 18-bit mode. */ 1793fa225cbcSrjs if (IS_I965G(pI830)) 1794fa225cbcSrjs { 1795fa225cbcSrjs if ((lvds & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP) 1796fa225cbcSrjs lvds &= ~LVDS_DITHER_ENABLE; 1797fa225cbcSrjs else 1798fa225cbcSrjs lvds |= LVDS_DITHER_ENABLE; 1799fa225cbcSrjs } 1800fa225cbcSrjs 1801fa225cbcSrjs lvds |= lvds_bits; 1802fa225cbcSrjs 1803fa225cbcSrjs OUTREG(LVDS, lvds); 1804fa225cbcSrjs POSTING_READ(LVDS); 1805fa225cbcSrjs } 1806fa225cbcSrjs 1807fa225cbcSrjs OUTREG(fp_reg, fp); 1808fa225cbcSrjs OUTREG(dpll_reg, dpll); 1809fa225cbcSrjs POSTING_READ(dpll_reg); 1810fa225cbcSrjs /* Wait for the clocks to stabilize. */ 1811fa225cbcSrjs usleep(150); 1812fa225cbcSrjs 1813fa225cbcSrjs if (IS_I965G(pI830)) { 1814fa225cbcSrjs int sdvo_pixel_multiply = adjusted_mode->Clock / mode->Clock; 1815fa225cbcSrjs OUTREG(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | 1816fa225cbcSrjs ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT)); 1817fa225cbcSrjs } else { 1818fa225cbcSrjs /* write it again -- the BIOS does, after all */ 1819fa225cbcSrjs OUTREG(dpll_reg, dpll); 1820fa225cbcSrjs } 1821fa225cbcSrjs POSTING_READ(dpll_reg); 1822fa225cbcSrjs /* Wait for the clocks to stabilize. */ 1823fa225cbcSrjs usleep(150); 1824fa225cbcSrjs 1825fa225cbcSrjs if (!DSPARB_HWCONTROL(pI830)) 1826fa225cbcSrjs i830_update_dsparb(pScrn); 1827fa225cbcSrjs 1828fa225cbcSrjs OUTREG(htot_reg, (adjusted_mode->CrtcHDisplay - 1) | 1829fa225cbcSrjs ((adjusted_mode->CrtcHTotal - 1) << 16)); 1830fa225cbcSrjs OUTREG(hblank_reg, (adjusted_mode->CrtcHBlankStart - 1) | 1831fa225cbcSrjs ((adjusted_mode->CrtcHBlankEnd - 1) << 16)); 1832fa225cbcSrjs OUTREG(hsync_reg, (adjusted_mode->CrtcHSyncStart - 1) | 1833fa225cbcSrjs ((adjusted_mode->CrtcHSyncEnd - 1) << 16)); 1834fa225cbcSrjs OUTREG(vtot_reg, (adjusted_mode->CrtcVDisplay - 1) | 1835fa225cbcSrjs ((adjusted_mode->CrtcVTotal - 1) << 16)); 1836fa225cbcSrjs 1837fa225cbcSrjs OUTREG(vblank_reg, (adjusted_mode->CrtcVBlankStart - 1) | 1838fa225cbcSrjs ((adjusted_mode->CrtcVBlankEnd - 1) << 16)); 1839fa225cbcSrjs OUTREG(vsync_reg, (adjusted_mode->CrtcVSyncStart - 1) | 1840fa225cbcSrjs ((adjusted_mode->CrtcVSyncEnd - 1) << 16)); 1841fa225cbcSrjs /* pipesrc and dspsize control the size that is scaled from, which should 1842fa225cbcSrjs * always be the user's requested size. 1843fa225cbcSrjs */ 1844fa225cbcSrjs OUTREG(dspsize_reg, ((mode->VDisplay - 1) << 16) | (mode->HDisplay - 1)); 1845fa225cbcSrjs OUTREG(dsppos_reg, 0); 1846fa225cbcSrjs OUTREG(pipesrc_reg, ((mode->HDisplay - 1) << 16) | (mode->VDisplay - 1)); 1847fa225cbcSrjs OUTREG(pipeconf_reg, pipeconf); 1848fa225cbcSrjs POSTING_READ(pipeconf_reg); 1849fa225cbcSrjs i830WaitForVblank(pScrn); 1850fa225cbcSrjs 1851fa225cbcSrjs OUTREG(dspcntr_reg, dspcntr); 1852fa225cbcSrjs /* Flush the plane changes */ 1853fa225cbcSrjs i830PipeSetBase(crtc, x, y); 1854fa225cbcSrjs 1855fa225cbcSrjs i830WaitForVblank(pScrn); 1856fa225cbcSrjs} 1857fa225cbcSrjs 1858fa225cbcSrjs 1859fa225cbcSrjs/** Loads the palette/gamma unit for the CRTC with the prepared values */ 1860fa225cbcSrjsstatic void 1861fa225cbcSrjsi830_crtc_load_lut(xf86CrtcPtr crtc) 1862fa225cbcSrjs{ 1863fa225cbcSrjs ScrnInfoPtr pScrn = crtc->scrn; 1864fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 1865fa225cbcSrjs I830CrtcPrivatePtr intel_crtc = crtc->driver_private; 1866fa225cbcSrjs int palreg = (intel_crtc->pipe == 0) ? PALETTE_A : PALETTE_B; 1867fa225cbcSrjs int i; 1868fa225cbcSrjs 1869fa225cbcSrjs /* The clocks have to be on to load the palette. */ 1870fa225cbcSrjs if (!crtc->enabled) 1871fa225cbcSrjs return; 1872fa225cbcSrjs 1873fa225cbcSrjs for (i = 0; i < 256; i++) { 1874fa225cbcSrjs OUTREG(palreg + 4 * i, 1875fa225cbcSrjs (intel_crtc->lut_r[i] << 16) | 1876fa225cbcSrjs (intel_crtc->lut_g[i] << 8) | 1877fa225cbcSrjs intel_crtc->lut_b[i]); 1878fa225cbcSrjs } 1879fa225cbcSrjs} 1880fa225cbcSrjs 1881fa225cbcSrjs/** Sets the color ramps on behalf of RandR */ 1882fa225cbcSrjsstatic void 1883fa225cbcSrjsi830_crtc_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue, 1884fa225cbcSrjs int size) 1885fa225cbcSrjs{ 1886fa225cbcSrjs I830CrtcPrivatePtr intel_crtc = crtc->driver_private; 1887fa225cbcSrjs int i; 1888fa225cbcSrjs 1889fa225cbcSrjs assert(size == 256); 1890fa225cbcSrjs 1891fa225cbcSrjs for (i = 0; i < 256; i++) { 1892fa225cbcSrjs intel_crtc->lut_r[i] = red[i] >> 8; 1893fa225cbcSrjs intel_crtc->lut_g[i] = green[i] >> 8; 1894fa225cbcSrjs intel_crtc->lut_b[i] = blue[i] >> 8; 1895fa225cbcSrjs } 1896fa225cbcSrjs 1897fa225cbcSrjs i830_crtc_load_lut(crtc); 1898fa225cbcSrjs} 1899fa225cbcSrjs 1900fa225cbcSrjs/** 1901fa225cbcSrjs * Allocates memory for a locked-in-framebuffer shadow of the given 1902fa225cbcSrjs * width and height for this CRTC's rotated shadow framebuffer. 1903fa225cbcSrjs */ 1904fa225cbcSrjs 1905fa225cbcSrjsstatic void * 1906fa225cbcSrjsi830_crtc_shadow_allocate (xf86CrtcPtr crtc, int width, int height) 1907fa225cbcSrjs{ 1908fa225cbcSrjs ScrnInfoPtr pScrn = crtc->scrn; 1909fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 1910fa225cbcSrjs I830CrtcPrivatePtr intel_crtc = crtc->driver_private; 1911fa225cbcSrjs unsigned long rotate_pitch; 1912fa225cbcSrjs int align = KB(4), size; 1913fa225cbcSrjs 1914fa225cbcSrjs width = i830_pad_drawable_width(width, pI830->cpp); 1915fa225cbcSrjs rotate_pitch = width * pI830->cpp; 1916fa225cbcSrjs size = rotate_pitch * height; 1917fa225cbcSrjs 1918fa225cbcSrjs assert(intel_crtc->rotate_mem == NULL); 1919fa225cbcSrjs intel_crtc->rotate_mem = i830_allocate_memory(pScrn, "rotated crtc", 1920fa225cbcSrjs size, rotate_pitch, align, 1921fa225cbcSrjs 0, TILE_NONE); 1922fa225cbcSrjs if (intel_crtc->rotate_mem == NULL) { 1923fa225cbcSrjs xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1924fa225cbcSrjs "Couldn't allocate shadow memory for rotated CRTC\n"); 1925fa225cbcSrjs return NULL; 1926fa225cbcSrjs } 1927fa225cbcSrjs memset(pI830->FbBase + intel_crtc->rotate_mem->offset, 0, size); 1928fa225cbcSrjs 1929fa225cbcSrjs return pI830->FbBase + intel_crtc->rotate_mem->offset; 1930fa225cbcSrjs} 1931fa225cbcSrjs 1932fa225cbcSrjs/** 1933fa225cbcSrjs * Creates a pixmap for this CRTC's rotated shadow framebuffer. 1934fa225cbcSrjs */ 1935fa225cbcSrjsstatic PixmapPtr 1936fa225cbcSrjsi830_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) 1937fa225cbcSrjs{ 1938fa225cbcSrjs ScrnInfoPtr pScrn = crtc->scrn; 1939fa225cbcSrjs I830CrtcPrivatePtr intel_crtc = crtc->driver_private; 1940fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 1941fa225cbcSrjs int rotate_pitch; 1942fa225cbcSrjs PixmapPtr rotate_pixmap; 1943fa225cbcSrjs 1944fa225cbcSrjs if (!data) 1945fa225cbcSrjs data = i830_crtc_shadow_allocate (crtc, width, height); 1946fa225cbcSrjs 1947fa225cbcSrjs rotate_pitch = i830_pad_drawable_width(width, pI830->cpp) * pI830->cpp; 1948fa225cbcSrjs 1949fa225cbcSrjs rotate_pixmap = GetScratchPixmapHeader(pScrn->pScreen, 1950fa225cbcSrjs width, height, 1951fa225cbcSrjs pScrn->depth, 1952fa225cbcSrjs pScrn->bitsPerPixel, 1953fa225cbcSrjs rotate_pitch, 1954fa225cbcSrjs data); 1955fa225cbcSrjs 1956fa225cbcSrjs if (rotate_pixmap == NULL) { 1957fa225cbcSrjs xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1958fa225cbcSrjs "Couldn't allocate shadow pixmap for rotated CRTC\n"); 1959fa225cbcSrjs } 1960fa225cbcSrjs if (intel_crtc->rotate_mem && intel_crtc->rotate_mem->bo) 1961fa225cbcSrjs i830_set_pixmap_bo(rotate_pixmap, intel_crtc->rotate_mem->bo); 1962fa225cbcSrjs return rotate_pixmap; 1963fa225cbcSrjs} 1964fa225cbcSrjs 1965fa225cbcSrjsstatic void 1966fa225cbcSrjsi830_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) 1967fa225cbcSrjs{ 1968fa225cbcSrjs ScrnInfoPtr pScrn = crtc->scrn; 1969fa225cbcSrjs I830CrtcPrivatePtr intel_crtc = crtc->driver_private; 1970fa225cbcSrjs 1971fa225cbcSrjs if (rotate_pixmap) { 1972fa225cbcSrjs i830_set_pixmap_bo(rotate_pixmap, NULL); 1973fa225cbcSrjs FreeScratchPixmapHeader(rotate_pixmap); 1974fa225cbcSrjs } 1975fa225cbcSrjs 1976fa225cbcSrjs if (data) { 1977fa225cbcSrjs /* Be sure to sync acceleration before the memory gets unbound. */ 1978fa225cbcSrjs I830Sync(pScrn); 1979fa225cbcSrjs i830_free_memory(pScrn, intel_crtc->rotate_mem); 1980fa225cbcSrjs intel_crtc->rotate_mem = NULL; 1981fa225cbcSrjs } 1982fa225cbcSrjs} 1983fa225cbcSrjs 1984fa225cbcSrjs#if RANDR_13_INTERFACE 1985fa225cbcSrjsstatic void 1986fa225cbcSrjsi830_crtc_set_origin(xf86CrtcPtr crtc, int x, int y) 1987fa225cbcSrjs{ 1988fa225cbcSrjs if (crtc->enabled) 1989fa225cbcSrjs i830PipeSetBase(crtc, x, y); 1990fa225cbcSrjs} 1991fa225cbcSrjs#endif 1992fa225cbcSrjs 1993fa225cbcSrjs/* The screen bo has changed, reset each active crtc to point at 1994fa225cbcSrjs * the same location that it currently points at, but in the new bo 1995fa225cbcSrjs */ 1996fa225cbcSrjsvoid 1997fa225cbcSrjsi830_set_new_crtc_bo(ScrnInfoPtr pScrn) 1998fa225cbcSrjs{ 1999fa225cbcSrjs xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 2000fa225cbcSrjs int i; 2001fa225cbcSrjs 2002fa225cbcSrjs for (i = 0; i < xf86_config->num_crtc; i++) { 2003fa225cbcSrjs xf86CrtcPtr crtc = xf86_config->crtc[i]; 2004fa225cbcSrjs 2005fa225cbcSrjs if (crtc->enabled && !crtc->transform_in_use) 2006fa225cbcSrjs i830PipeSetBase(crtc, crtc->x, crtc->y); 2007fa225cbcSrjs } 2008fa225cbcSrjs} 2009fa225cbcSrjs 2010fa225cbcSrjsvoid 2011fa225cbcSrjsi830DescribeOutputConfiguration(ScrnInfoPtr pScrn) 2012fa225cbcSrjs{ 2013fa225cbcSrjs xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 2014fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 2015fa225cbcSrjs int i; 2016fa225cbcSrjs 2017fa225cbcSrjs xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Output configuration:\n"); 2018fa225cbcSrjs 2019fa225cbcSrjs for (i = 0; i < xf86_config->num_crtc; i++) { 2020fa225cbcSrjs xf86CrtcPtr crtc = xf86_config->crtc[i]; 2021fa225cbcSrjs I830CrtcPrivatePtr intel_crtc = crtc ? crtc->driver_private : NULL; 2022fa225cbcSrjs uint32_t dspcntr = intel_crtc->plane == 0 ? INREG(DSPACNTR) : 2023fa225cbcSrjs INREG(DSPBCNTR); 2024fa225cbcSrjs uint32_t pipeconf = i == 0 ? INREG(PIPEACONF) : 2025fa225cbcSrjs INREG(PIPEBCONF); 2026fa225cbcSrjs Bool hw_plane_enable = (dspcntr & DISPLAY_PLANE_ENABLE) != 0; 2027fa225cbcSrjs Bool hw_pipe_enable = (pipeconf & PIPEACONF_ENABLE) != 0; 2028fa225cbcSrjs 2029fa225cbcSrjs xf86DrvMsg(pScrn->scrnIndex, X_INFO, 2030fa225cbcSrjs " Pipe %c is %s\n", 2031fa225cbcSrjs 'A' + i, crtc->enabled ? "on" : "off"); 2032fa225cbcSrjs xf86DrvMsg(pScrn->scrnIndex, X_INFO, 2033fa225cbcSrjs " Display plane %c is now %s and connected to pipe %c.\n", 2034fa225cbcSrjs 'A' + intel_crtc->plane, 2035fa225cbcSrjs hw_plane_enable ? "enabled" : "disabled", 2036fa225cbcSrjs dspcntr & DISPPLANE_SEL_PIPE_MASK ? 'B' : 'A'); 2037fa225cbcSrjs if (hw_pipe_enable != crtc->enabled) { 2038fa225cbcSrjs xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 2039fa225cbcSrjs " Hardware claims pipe %c is %s while software " 2040fa225cbcSrjs "believes it is %s\n", 2041fa225cbcSrjs 'A' + i, hw_pipe_enable ? "on" : "off", 2042fa225cbcSrjs crtc->enabled ? "on" : "off"); 2043fa225cbcSrjs } 2044fa225cbcSrjs if (hw_plane_enable != crtc->enabled) { 2045fa225cbcSrjs xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 2046fa225cbcSrjs " Hardware claims plane %c is %s while software " 2047fa225cbcSrjs "believes it is %s\n", 2048fa225cbcSrjs 'A' + i, hw_plane_enable ? "on" : "off", 2049fa225cbcSrjs crtc->enabled ? "on" : "off"); 2050fa225cbcSrjs } 2051fa225cbcSrjs } 2052fa225cbcSrjs 2053fa225cbcSrjs for (i = 0; i < xf86_config->num_output; i++) { 2054fa225cbcSrjs xf86OutputPtr output = xf86_config->output[i]; 2055fa225cbcSrjs xf86CrtcPtr crtc = output->crtc; 2056fa225cbcSrjs I830CrtcPrivatePtr intel_crtc = crtc ? crtc->driver_private : NULL; 2057fa225cbcSrjs 2058fa225cbcSrjs xf86DrvMsg(pScrn->scrnIndex, X_INFO, 2059fa225cbcSrjs " Output %s is connected to pipe %s\n", 2060fa225cbcSrjs output->name, intel_crtc == NULL ? "none" : 2061fa225cbcSrjs (intel_crtc->pipe == 0 ? "A" : "B")); 2062fa225cbcSrjs } 2063fa225cbcSrjs} 2064fa225cbcSrjs 2065fa225cbcSrjs/** 2066fa225cbcSrjs * Get a pipe with a simple mode set on it for doing load-based monitor 2067fa225cbcSrjs * detection. 2068fa225cbcSrjs * 2069fa225cbcSrjs * It will be up to the load-detect code to adjust the pipe as appropriate for 2070fa225cbcSrjs * its requirements. The pipe will be connected to no other outputs. 2071fa225cbcSrjs * 2072fa225cbcSrjs * Currently this code will only succeed if there is a pipe with no outputs 2073fa225cbcSrjs * configured for it. In the future, it could choose to temporarily disable 2074fa225cbcSrjs * some outputs to free up a pipe for its use. 2075fa225cbcSrjs * 2076fa225cbcSrjs * \return crtc, or NULL if no pipes are available. 2077fa225cbcSrjs */ 2078fa225cbcSrjs 2079fa225cbcSrjs/* VESA 640x480x72Hz mode to set on the pipe */ 2080fa225cbcSrjsstatic DisplayModeRec load_detect_mode = { 2081fa225cbcSrjs NULL, NULL, "640x480", MODE_OK, M_T_DEFAULT, 2082fa225cbcSrjs 31500, 2083fa225cbcSrjs 640, 664, 704, 832, 0, 2084fa225cbcSrjs 480, 489, 491, 520, 0, 2085fa225cbcSrjs V_NHSYNC | V_NVSYNC, 2086fa225cbcSrjs 0, 0, 2087fa225cbcSrjs 2088fa225cbcSrjs 640, 640, 664, 704, 832, 832, 0, 2089fa225cbcSrjs 480, 489, 489, 491, 520, 520, 2090fa225cbcSrjs FALSE, FALSE, 0, NULL, 0, 0.0, 0.0 2091fa225cbcSrjs}; 2092fa225cbcSrjs 2093fa225cbcSrjsxf86CrtcPtr 2094fa225cbcSrjsi830GetLoadDetectPipe(xf86OutputPtr output, DisplayModePtr mode, int *dpms_mode) 2095fa225cbcSrjs{ 2096fa225cbcSrjs ScrnInfoPtr pScrn = output->scrn; 2097fa225cbcSrjs xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 2098fa225cbcSrjs I830OutputPrivatePtr intel_output = output->driver_private; 2099fa225cbcSrjs I830CrtcPrivatePtr intel_crtc; 2100fa225cbcSrjs xf86CrtcPtr supported_crtc =NULL; 2101fa225cbcSrjs xf86CrtcPtr crtc = NULL; 2102fa225cbcSrjs int i; 2103fa225cbcSrjs 2104fa225cbcSrjs if (output->crtc) 2105fa225cbcSrjs { 2106fa225cbcSrjs crtc = output->crtc; 2107fa225cbcSrjs /* 2108fa225cbcSrjs * Make sure the crtc and output are running 2109fa225cbcSrjs */ 2110fa225cbcSrjs intel_crtc = crtc->driver_private; 2111fa225cbcSrjs *dpms_mode = intel_crtc->dpms_mode; 2112fa225cbcSrjs if (intel_crtc->dpms_mode != DPMSModeOn) 2113fa225cbcSrjs { 2114fa225cbcSrjs crtc->funcs->dpms (crtc, DPMSModeOn); 2115fa225cbcSrjs output->funcs->dpms (output, DPMSModeOn); 2116fa225cbcSrjs } 2117fa225cbcSrjs return crtc; 2118fa225cbcSrjs } 2119fa225cbcSrjs 2120fa225cbcSrjs for (i = 0; i < xf86_config->num_crtc; i++) 2121fa225cbcSrjs { 2122fa225cbcSrjs xf86CrtcPtr possible_crtc; 2123fa225cbcSrjs if (!(output->possible_crtcs & (1 << i))) 2124fa225cbcSrjs continue; 2125fa225cbcSrjs possible_crtc = xf86_config->crtc[i]; 2126fa225cbcSrjs if (!possible_crtc->enabled) 2127fa225cbcSrjs { 2128fa225cbcSrjs crtc = possible_crtc; 2129fa225cbcSrjs break; 2130fa225cbcSrjs } 2131fa225cbcSrjs if (!supported_crtc) 2132fa225cbcSrjs supported_crtc = possible_crtc; 2133fa225cbcSrjs } 2134fa225cbcSrjs if (!crtc) 2135fa225cbcSrjs { 2136fa225cbcSrjs crtc = supported_crtc; 2137fa225cbcSrjs if (!crtc) 2138fa225cbcSrjs return NULL; 2139fa225cbcSrjs } 2140fa225cbcSrjs 2141fa225cbcSrjs output->crtc = crtc; 2142fa225cbcSrjs intel_output->load_detect_temp = TRUE; 2143fa225cbcSrjs 2144fa225cbcSrjs intel_crtc = crtc->driver_private; 2145fa225cbcSrjs *dpms_mode = intel_crtc->dpms_mode; 2146fa225cbcSrjs 2147fa225cbcSrjs if (!crtc->enabled) 2148fa225cbcSrjs { 2149fa225cbcSrjs if (!mode) 2150fa225cbcSrjs mode = &load_detect_mode; 2151fa225cbcSrjs xf86CrtcSetMode (crtc, mode, RR_Rotate_0, 0, 0); 2152fa225cbcSrjs } 2153fa225cbcSrjs else 2154fa225cbcSrjs { 2155fa225cbcSrjs if (intel_crtc->dpms_mode != DPMSModeOn) 2156fa225cbcSrjs crtc->funcs->dpms (crtc, DPMSModeOn); 2157fa225cbcSrjs 2158fa225cbcSrjs /* Add this output to the crtc */ 2159fa225cbcSrjs output->funcs->mode_set (output, &crtc->mode, &crtc->mode); 2160fa225cbcSrjs output->funcs->commit (output); 2161fa225cbcSrjs } 2162fa225cbcSrjs /* let the output get through one full cycle before testing */ 2163fa225cbcSrjs i830WaitForVblank (pScrn); 2164fa225cbcSrjs 2165fa225cbcSrjs return crtc; 2166fa225cbcSrjs} 2167fa225cbcSrjs 2168fa225cbcSrjsvoid 2169fa225cbcSrjsi830ReleaseLoadDetectPipe(xf86OutputPtr output, int dpms_mode) 2170fa225cbcSrjs{ 2171fa225cbcSrjs ScrnInfoPtr pScrn = output->scrn; 2172fa225cbcSrjs I830OutputPrivatePtr intel_output = output->driver_private; 2173fa225cbcSrjs xf86CrtcPtr crtc = output->crtc; 2174fa225cbcSrjs 2175fa225cbcSrjs if (intel_output->load_detect_temp) 2176fa225cbcSrjs { 2177fa225cbcSrjs output->crtc = NULL; 2178fa225cbcSrjs intel_output->load_detect_temp = FALSE; 2179fa225cbcSrjs crtc->enabled = xf86CrtcInUse (crtc); 2180fa225cbcSrjs xf86DisableUnusedFunctions(pScrn); 2181fa225cbcSrjs } 2182fa225cbcSrjs /* 2183fa225cbcSrjs * Switch crtc and output back off if necessary 2184fa225cbcSrjs */ 2185fa225cbcSrjs if (crtc->enabled && dpms_mode != DPMSModeOn) 2186fa225cbcSrjs { 2187fa225cbcSrjs if (output->crtc == crtc) 2188fa225cbcSrjs output->funcs->dpms (output, dpms_mode); 2189fa225cbcSrjs crtc->funcs->dpms (crtc, dpms_mode); 2190fa225cbcSrjs } 2191fa225cbcSrjs} 2192fa225cbcSrjs 2193fa225cbcSrjs/* Returns the clock of the currently programmed mode of the given pipe. */ 2194fa225cbcSrjsstatic int 2195fa225cbcSrjsi830_crtc_clock_get(ScrnInfoPtr pScrn, xf86CrtcPtr crtc) 2196fa225cbcSrjs{ 2197fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 2198fa225cbcSrjs I830CrtcPrivatePtr intel_crtc = crtc->driver_private; 2199fa225cbcSrjs int pipe = intel_crtc->pipe; 2200fa225cbcSrjs uint32_t dpll = INREG((pipe == 0) ? DPLL_A : DPLL_B); 2201fa225cbcSrjs uint32_t fp; 2202fa225cbcSrjs intel_clock_t clock; 2203fa225cbcSrjs 2204fa225cbcSrjs if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) 2205fa225cbcSrjs fp = INREG((pipe == 0) ? FPA0 : FPB0); 2206fa225cbcSrjs else 2207fa225cbcSrjs fp = INREG((pipe == 0) ? FPA1 : FPB1); 2208fa225cbcSrjs 2209fa225cbcSrjs clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT; 2210fa225cbcSrjs if (IS_IGD(pI830)) { 2211fa225cbcSrjs clock.n = ffs((fp & FP_N_IGD_DIV_MASK) >> FP_N_DIV_SHIFT) - 1; 2212fa225cbcSrjs clock.m2 = (fp & FP_M2_IGD_DIV_MASK) >> FP_M2_DIV_SHIFT; 2213fa225cbcSrjs } else { 2214fa225cbcSrjs clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT; 2215fa225cbcSrjs clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT; 2216fa225cbcSrjs } 2217fa225cbcSrjs if (IS_I9XX(pI830)) { 2218fa225cbcSrjs if (IS_IGD(pI830)) 2219fa225cbcSrjs clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_IGD) >> 2220fa225cbcSrjs DPLL_FPA01_P1_POST_DIV_SHIFT_IGD); 2221fa225cbcSrjs else 2222fa225cbcSrjs clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK) >> 2223fa225cbcSrjs DPLL_FPA01_P1_POST_DIV_SHIFT); 2224fa225cbcSrjs 2225fa225cbcSrjs switch (dpll & DPLL_MODE_MASK) { 2226fa225cbcSrjs case DPLLB_MODE_DAC_SERIAL: 2227fa225cbcSrjs clock.p2 = dpll & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ? 5 : 10; 2228fa225cbcSrjs break; 2229fa225cbcSrjs case DPLLB_MODE_LVDS: 2230fa225cbcSrjs clock.p2 = dpll & DPLLB_LVDS_P2_CLOCK_DIV_7 ? 7 : 14; 2231fa225cbcSrjs break; 2232fa225cbcSrjs default: 2233fa225cbcSrjs xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 2234fa225cbcSrjs "Unknown DPLL mode %08x in programmed mode\n", 2235fa225cbcSrjs (int)(dpll & DPLL_MODE_MASK)); 2236fa225cbcSrjs return 0; 2237fa225cbcSrjs } 2238fa225cbcSrjs 2239fa225cbcSrjs if ((dpll & PLL_REF_INPUT_MASK) == PLLB_REF_INPUT_SPREADSPECTRUMIN) 2240fa225cbcSrjs intel_clock(pI830, 100000, &clock); 2241fa225cbcSrjs else 2242fa225cbcSrjs intel_clock(pI830, 96000, &clock); 2243fa225cbcSrjs } else { 2244fa225cbcSrjs Bool is_lvds = (pipe == 1) && (INREG(LVDS) & LVDS_PORT_EN); 2245fa225cbcSrjs 2246fa225cbcSrjs if (is_lvds) { 2247fa225cbcSrjs clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >> 2248fa225cbcSrjs DPLL_FPA01_P1_POST_DIV_SHIFT); 2249fa225cbcSrjs 2250fa225cbcSrjs /* if LVDS is dual-channel, p2 = 7 */ 2251fa225cbcSrjs if ((INREG(LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP) 2252fa225cbcSrjs clock.p2 = 7; 2253fa225cbcSrjs else 2254fa225cbcSrjs clock.p2 = 14; 2255fa225cbcSrjs 2256fa225cbcSrjs if ((dpll & PLL_REF_INPUT_MASK) == PLLB_REF_INPUT_SPREADSPECTRUMIN) 2257fa225cbcSrjs intel_clock(pI830, 66000, &clock); /* XXX: might not be 66MHz */ 2258fa225cbcSrjs else 2259fa225cbcSrjs intel_clock(pI830, 48000, &clock); 2260fa225cbcSrjs } else { 2261fa225cbcSrjs if (dpll & PLL_P1_DIVIDE_BY_TWO) { 2262fa225cbcSrjs clock.p1 = 2; 2263fa225cbcSrjs } else { 2264fa225cbcSrjs clock.p1 = ((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830) >> 2265fa225cbcSrjs DPLL_FPA01_P1_POST_DIV_SHIFT) + 2; 2266fa225cbcSrjs } 2267fa225cbcSrjs if (dpll & PLL_P2_DIVIDE_BY_4) 2268fa225cbcSrjs clock.p2 = 4; 2269fa225cbcSrjs else 2270fa225cbcSrjs clock.p2 = 2; 2271fa225cbcSrjs 2272fa225cbcSrjs intel_clock(pI830, 48000, &clock); 2273fa225cbcSrjs } 2274fa225cbcSrjs } 2275fa225cbcSrjs 2276fa225cbcSrjs /* XXX: It would be nice to validate the clocks, but we can't reuse 2277fa225cbcSrjs * i830PllIsValid() because it relies on the xf86_config output 2278fa225cbcSrjs * configuration being accurate, which it isn't necessarily. 2279fa225cbcSrjs */ 2280fa225cbcSrjs if (0) 2281fa225cbcSrjs i830PrintPll(pScrn, "probed", &clock); 2282fa225cbcSrjs 2283fa225cbcSrjs return clock.dot; 2284fa225cbcSrjs} 2285fa225cbcSrjs 2286fa225cbcSrjs/** Returns the currently programmed mode of the given pipe. */ 2287fa225cbcSrjsDisplayModePtr 2288fa225cbcSrjsi830_crtc_mode_get(ScrnInfoPtr pScrn, xf86CrtcPtr crtc) 2289fa225cbcSrjs{ 2290fa225cbcSrjs I830Ptr pI830 = I830PTR(pScrn); 2291fa225cbcSrjs I830CrtcPrivatePtr intel_crtc = crtc->driver_private; 2292fa225cbcSrjs int pipe = intel_crtc->pipe; 2293fa225cbcSrjs DisplayModePtr mode; 2294fa225cbcSrjs int htot = INREG((pipe == 0) ? HTOTAL_A : HTOTAL_B); 2295fa225cbcSrjs int hsync = INREG((pipe == 0) ? HSYNC_A : HSYNC_B); 2296fa225cbcSrjs int vtot = INREG((pipe == 0) ? VTOTAL_A : VTOTAL_B); 2297fa225cbcSrjs int vsync = INREG((pipe == 0) ? VSYNC_A : VSYNC_B); 2298fa225cbcSrjs 2299fa225cbcSrjs mode = xcalloc(1, sizeof(DisplayModeRec)); 2300fa225cbcSrjs if (mode == NULL) 2301fa225cbcSrjs return NULL; 2302fa225cbcSrjs 2303fa225cbcSrjs mode->Clock = i830_crtc_clock_get(pScrn, crtc); 2304fa225cbcSrjs mode->HDisplay = (htot & 0xffff) + 1; 2305fa225cbcSrjs mode->HTotal = ((htot & 0xffff0000) >> 16) + 1; 2306fa225cbcSrjs mode->HSyncStart = (hsync & 0xffff) + 1; 2307fa225cbcSrjs mode->HSyncEnd = ((hsync & 0xffff0000) >> 16) + 1; 2308fa225cbcSrjs mode->VDisplay = (vtot & 0xffff) + 1; 2309fa225cbcSrjs mode->VTotal = ((vtot & 0xffff0000) >> 16) + 1; 2310fa225cbcSrjs mode->VSyncStart = (vsync & 0xffff) + 1; 2311fa225cbcSrjs mode->VSyncEnd = ((vsync & 0xffff0000) >> 16) + 1; 2312fa225cbcSrjs xf86SetModeDefaultName(mode); 2313fa225cbcSrjs xf86SetModeCrtc(mode, 0); 2314fa225cbcSrjs 2315fa225cbcSrjs return mode; 2316fa225cbcSrjs} 2317fa225cbcSrjs 2318fa225cbcSrjsstatic const xf86CrtcFuncsRec i830_crtc_funcs = { 2319fa225cbcSrjs .dpms = i830_crtc_dpms, 2320fa225cbcSrjs .save = NULL, /* XXX */ 2321fa225cbcSrjs .restore = NULL, /* XXX */ 2322fa225cbcSrjs .lock = i830_crtc_lock, 2323fa225cbcSrjs .unlock = i830_crtc_unlock, 2324fa225cbcSrjs .mode_fixup = i830_crtc_mode_fixup, 2325fa225cbcSrjs .prepare = i830_crtc_prepare, 2326fa225cbcSrjs .mode_set = i830_crtc_mode_set, 2327fa225cbcSrjs .commit = i830_crtc_commit, 2328fa225cbcSrjs .gamma_set = i830_crtc_gamma_set, 2329fa225cbcSrjs .shadow_create = i830_crtc_shadow_create, 2330fa225cbcSrjs .shadow_allocate = i830_crtc_shadow_allocate, 2331fa225cbcSrjs .shadow_destroy = i830_crtc_shadow_destroy, 2332fa225cbcSrjs .set_cursor_colors = i830_crtc_set_cursor_colors, 2333fa225cbcSrjs .set_cursor_position = i830_crtc_set_cursor_position, 2334fa225cbcSrjs .show_cursor = i830_crtc_show_cursor, 2335fa225cbcSrjs .hide_cursor = i830_crtc_hide_cursor, 2336fa225cbcSrjs .load_cursor_argb = i830_crtc_load_cursor_argb, 2337fa225cbcSrjs .destroy = NULL, /* XXX */ 2338fa225cbcSrjs#if RANDR_13_INTERFACE 2339fa225cbcSrjs .set_origin = i830_crtc_set_origin, 2340fa225cbcSrjs#endif 2341fa225cbcSrjs}; 2342fa225cbcSrjs 2343fa225cbcSrjsvoid 2344fa225cbcSrjsi830_crtc_init(ScrnInfoPtr pScrn, int pipe) 2345fa225cbcSrjs{ 2346fa225cbcSrjs xf86CrtcPtr crtc; 2347fa225cbcSrjs I830CrtcPrivatePtr intel_crtc; 2348fa225cbcSrjs int i; 2349fa225cbcSrjs 2350fa225cbcSrjs crtc = xf86CrtcCreate (pScrn, &i830_crtc_funcs); 2351fa225cbcSrjs if (crtc == NULL) 2352fa225cbcSrjs return; 2353fa225cbcSrjs 2354fa225cbcSrjs intel_crtc = xnfcalloc (sizeof (I830CrtcPrivateRec), 1); 2355fa225cbcSrjs intel_crtc->pipe = pipe; 2356fa225cbcSrjs intel_crtc->dpms_mode = DPMSModeOff; 2357fa225cbcSrjs intel_crtc->plane = pipe; 2358fa225cbcSrjs 2359fa225cbcSrjs /* Initialize the LUTs for when we turn on the CRTC. */ 2360fa225cbcSrjs for (i = 0; i < 256; i++) { 2361fa225cbcSrjs intel_crtc->lut_r[i] = i; 2362fa225cbcSrjs intel_crtc->lut_g[i] = i; 2363fa225cbcSrjs intel_crtc->lut_b[i] = i; 2364fa225cbcSrjs } 2365fa225cbcSrjs crtc->driver_private = intel_crtc; 2366fa225cbcSrjs} 2367fa225cbcSrjs 2368