1296548Sdumbbell/* 2296548Sdumbbell * 3296548Sdumbbell * Copyright (c) 2012 Gilles Dartiguelongue, Thomas Richter 4296548Sdumbbell * 5296548Sdumbbell * All Rights Reserved. 6296548Sdumbbell * 7296548Sdumbbell * Permission is hereby granted, free of charge, to any person obtaining a 8296548Sdumbbell * copy of this software and associated documentation files (the 9296548Sdumbbell * "Software"), to deal in the Software without restriction, including 10296548Sdumbbell * without limitation the rights to use, copy, modify, merge, publish, 11296548Sdumbbell * distribute, sub license, and/or sell copies of the Software, and to 12296548Sdumbbell * permit persons to whom the Software is furnished to do so, subject to 13296548Sdumbbell * the following conditions: 14296548Sdumbbell * 15296548Sdumbbell * The above copyright notice and this permission notice (including the 16296548Sdumbbell * next paragraph) shall be included in all copies or substantial portions 17296548Sdumbbell * of the Software. 18296548Sdumbbell * 19296548Sdumbbell * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20296548Sdumbbell * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21296548Sdumbbell * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 22296548Sdumbbell * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 23296548Sdumbbell * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24296548Sdumbbell * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25296548Sdumbbell * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26296548Sdumbbell * 27296548Sdumbbell */ 28296548Sdumbbell 29296548Sdumbbell#include <sys/cdefs.h> 30296548Sdumbbell__FBSDID("$FreeBSD$"); 31296548Sdumbbell 32296548Sdumbbell#include "dvo.h" 33296548Sdumbbell#include "i915_reg.h" 34296548Sdumbbell#include "i915_drv.h" 35296548Sdumbbell 36296548Sdumbbell#define NS2501_VID 0x1305 37296548Sdumbbell#define NS2501_DID 0x6726 38296548Sdumbbell 39296548Sdumbbell#define NS2501_VID_LO 0x00 40296548Sdumbbell#define NS2501_VID_HI 0x01 41296548Sdumbbell#define NS2501_DID_LO 0x02 42296548Sdumbbell#define NS2501_DID_HI 0x03 43296548Sdumbbell#define NS2501_REV 0x04 44296548Sdumbbell#define NS2501_RSVD 0x05 45296548Sdumbbell#define NS2501_FREQ_LO 0x06 46296548Sdumbbell#define NS2501_FREQ_HI 0x07 47296548Sdumbbell 48296548Sdumbbell#define NS2501_REG8 0x08 49296548Sdumbbell#define NS2501_8_VEN (1<<5) 50296548Sdumbbell#define NS2501_8_HEN (1<<4) 51296548Sdumbbell#define NS2501_8_DSEL (1<<3) 52296548Sdumbbell#define NS2501_8_BPAS (1<<2) 53296548Sdumbbell#define NS2501_8_RSVD (1<<1) 54296548Sdumbbell#define NS2501_8_PD (1<<0) 55296548Sdumbbell 56296548Sdumbbell#define NS2501_REG9 0x09 57296548Sdumbbell#define NS2501_9_VLOW (1<<7) 58296548Sdumbbell#define NS2501_9_MSEL_MASK (0x7<<4) 59296548Sdumbbell#define NS2501_9_TSEL (1<<3) 60296548Sdumbbell#define NS2501_9_RSEN (1<<2) 61296548Sdumbbell#define NS2501_9_RSVD (1<<1) 62296548Sdumbbell#define NS2501_9_MDI (1<<0) 63296548Sdumbbell 64296548Sdumbbell#define NS2501_REGC 0x0c 65296548Sdumbbell 66296548Sdumbbellstruct ns2501_priv { 67296548Sdumbbell //I2CDevRec d; 68296548Sdumbbell bool quiet; 69296548Sdumbbell int reg_8_shadow; 70296548Sdumbbell int reg_8_set; 71296548Sdumbbell // Shadow registers for i915 72296548Sdumbbell int dvoc; 73296548Sdumbbell int pll_a; 74296548Sdumbbell int srcdim; 75296548Sdumbbell int fw_blc; 76296548Sdumbbell}; 77296548Sdumbbell 78296548Sdumbbell#define NSPTR(d) ((NS2501Ptr)(d->DriverPrivate.ptr)) 79296548Sdumbbell 80296548Sdumbbell/* 81296548Sdumbbell * For reasons unclear to me, the ns2501 at least on the Fujitsu/Siemens 82296548Sdumbbell * laptops does not react on the i2c bus unless 83296548Sdumbbell * both the PLL is running and the display is configured in its native 84296548Sdumbbell * resolution. 85296548Sdumbbell * This function forces the DVO on, and stores the registers it touches. 86296548Sdumbbell * Afterwards, registers are restored to regular values. 87296548Sdumbbell * 88296548Sdumbbell * This is pretty much a hack, though it works. 89296548Sdumbbell * Without that, ns2501_readb and ns2501_writeb fail 90296548Sdumbbell * when switching the resolution. 91296548Sdumbbell */ 92296548Sdumbbell 93296548Sdumbbellstatic void enable_dvo(struct intel_dvo_device *dvo) 94296548Sdumbbell{ 95296548Sdumbbell struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); 96296548Sdumbbell device_t adapter = dvo->i2c_bus; 97296548Sdumbbell /* 98296548Sdumbbell * FIXME Linux<->FreeBSD: device_get_softc() returns a struct 99296548Sdumbbell * intel_iic_softc in reality, where struct intel_gmbus is 100296548Sdumbbell * the first member. struct intel_iic_softc is defined in 101296548Sdumbbell * intel_iic.c. 102296548Sdumbbell */ 103296548Sdumbbell struct intel_gmbus *bus = 104296548Sdumbbell (struct intel_gmbus *)device_get_softc(adapter); 105296548Sdumbbell struct drm_i915_private *dev_priv = bus->dev_priv; 106296548Sdumbbell 107296548Sdumbbell DRM_DEBUG_KMS("%s: Trying to re-enable the DVO\n", __FUNCTION__); 108296548Sdumbbell 109296548Sdumbbell ns->dvoc = I915_READ(DVO_C); 110296548Sdumbbell ns->pll_a = I915_READ(_DPLL_A); 111296548Sdumbbell ns->srcdim = I915_READ(DVOC_SRCDIM); 112296548Sdumbbell ns->fw_blc = I915_READ(FW_BLC); 113296548Sdumbbell 114296548Sdumbbell I915_WRITE(DVOC, 0x10004084); 115296548Sdumbbell I915_WRITE(_DPLL_A, 0xd0820000); 116296548Sdumbbell I915_WRITE(DVOC_SRCDIM, 0x400300); // 1024x768 117296548Sdumbbell I915_WRITE(FW_BLC, 0x1080304); 118296548Sdumbbell 119296548Sdumbbell I915_WRITE(DVOC, 0x90004084); 120296548Sdumbbell} 121296548Sdumbbell 122296548Sdumbbell/* 123296548Sdumbbell * Restore the I915 registers modified by the above 124296548Sdumbbell * trigger function. 125296548Sdumbbell */ 126296548Sdumbbellstatic void restore_dvo(struct intel_dvo_device *dvo) 127296548Sdumbbell{ 128296548Sdumbbell device_t adapter = dvo->i2c_bus; 129296548Sdumbbell /* 130296548Sdumbbell * FIXME Linux<->FreeBSD: device_get_softc() returns a struct 131296548Sdumbbell * intel_iic_softc in reality, where struct intel_gmbus is 132296548Sdumbbell * the first member. struct intel_iic_softc is defined in 133296548Sdumbbell * intel_iic.c. 134296548Sdumbbell */ 135296548Sdumbbell struct intel_gmbus *bus = 136296548Sdumbbell (struct intel_gmbus *)device_get_softc(adapter); 137296548Sdumbbell struct drm_i915_private *dev_priv = bus->dev_priv; 138296548Sdumbbell struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); 139296548Sdumbbell 140296548Sdumbbell I915_WRITE(DVOC, ns->dvoc); 141296548Sdumbbell I915_WRITE(_DPLL_A, ns->pll_a); 142296548Sdumbbell I915_WRITE(DVOC_SRCDIM, ns->srcdim); 143296548Sdumbbell I915_WRITE(FW_BLC, ns->fw_blc); 144296548Sdumbbell} 145296548Sdumbbell 146296548Sdumbbell/* 147296548Sdumbbell** Read a register from the ns2501. 148296548Sdumbbell** Returns true if successful, false otherwise. 149296548Sdumbbell** If it returns false, it might be wise to enable the 150296548Sdumbbell** DVO with the above function. 151296548Sdumbbell*/ 152296548Sdumbbellstatic bool ns2501_readb(struct intel_dvo_device *dvo, int addr, uint8_t * ch) 153296548Sdumbbell{ 154296548Sdumbbell struct ns2501_priv *ns = dvo->dev_priv; 155296548Sdumbbell device_t adapter = dvo->i2c_bus; 156296548Sdumbbell u8 out_buf[2]; 157296548Sdumbbell u8 in_buf[2]; 158296548Sdumbbell 159296548Sdumbbell struct iic_msg msgs[] = { 160296548Sdumbbell { 161296548Sdumbbell .slave = dvo->slave_addr << 1, 162296548Sdumbbell .flags = 0, 163296548Sdumbbell .len = 1, 164296548Sdumbbell .buf = out_buf, 165296548Sdumbbell }, 166296548Sdumbbell { 167296548Sdumbbell .slave = dvo->slave_addr << 1, 168296548Sdumbbell .flags = I2C_M_RD, 169296548Sdumbbell .len = 1, 170296548Sdumbbell .buf = in_buf, 171296548Sdumbbell } 172296548Sdumbbell }; 173296548Sdumbbell 174296548Sdumbbell out_buf[0] = addr; 175296548Sdumbbell out_buf[1] = 0; 176296548Sdumbbell 177296548Sdumbbell if (-iicbus_transfer(adapter, msgs, 2) == 0) { 178296548Sdumbbell *ch = in_buf[0]; 179296548Sdumbbell return true; 180296548Sdumbbell } 181296548Sdumbbell 182296548Sdumbbell if (!ns->quiet) { 183296548Sdumbbell DRM_DEBUG_KMS 184296548Sdumbbell ("Unable to read register 0x%02x from %s:0x%02x.\n", addr, 185296548Sdumbbell device_get_nameunit(adapter), dvo->slave_addr); 186296548Sdumbbell } 187296548Sdumbbell 188296548Sdumbbell return false; 189296548Sdumbbell} 190296548Sdumbbell 191296548Sdumbbell/* 192296548Sdumbbell** Write a register to the ns2501. 193296548Sdumbbell** Returns true if successful, false otherwise. 194296548Sdumbbell** If it returns false, it might be wise to enable the 195296548Sdumbbell** DVO with the above function. 196296548Sdumbbell*/ 197296548Sdumbbellstatic bool ns2501_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) 198296548Sdumbbell{ 199296548Sdumbbell struct ns2501_priv *ns = dvo->dev_priv; 200296548Sdumbbell device_t adapter = dvo->i2c_bus; 201296548Sdumbbell uint8_t out_buf[2]; 202296548Sdumbbell 203296548Sdumbbell struct iic_msg msg = { 204296548Sdumbbell .slave = dvo->slave_addr << 1, 205296548Sdumbbell .flags = 0, 206296548Sdumbbell .len = 2, 207296548Sdumbbell .buf = out_buf, 208296548Sdumbbell }; 209296548Sdumbbell 210296548Sdumbbell out_buf[0] = addr; 211296548Sdumbbell out_buf[1] = ch; 212296548Sdumbbell 213296548Sdumbbell if (-iicbus_transfer(adapter, &msg, 1) == 0) { 214296548Sdumbbell return true; 215296548Sdumbbell } 216296548Sdumbbell 217296548Sdumbbell if (!ns->quiet) { 218296548Sdumbbell DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d\n", 219296548Sdumbbell addr, device_get_nameunit(adapter), dvo->slave_addr); 220296548Sdumbbell } 221296548Sdumbbell 222296548Sdumbbell return false; 223296548Sdumbbell} 224296548Sdumbbell 225296548Sdumbbell/* National Semiconductor 2501 driver for chip on i2c bus 226296548Sdumbbell * scan for the chip on the bus. 227296548Sdumbbell * Hope the VBIOS initialized the PLL correctly so we can 228296548Sdumbbell * talk to it. If not, it will not be seen and not detected. 229296548Sdumbbell * Bummer! 230296548Sdumbbell */ 231296548Sdumbbellstatic bool ns2501_init(struct intel_dvo_device *dvo, 232296548Sdumbbell device_t adapter) 233296548Sdumbbell{ 234296548Sdumbbell /* this will detect the NS2501 chip on the specified i2c bus */ 235296548Sdumbbell struct ns2501_priv *ns; 236296548Sdumbbell unsigned char ch; 237296548Sdumbbell 238296548Sdumbbell ns = malloc(sizeof(struct ns2501_priv), DRM_MEM_KMS, M_NOWAIT | M_ZERO); 239296548Sdumbbell if (ns == NULL) 240296548Sdumbbell return false; 241296548Sdumbbell 242296548Sdumbbell dvo->i2c_bus = adapter; 243296548Sdumbbell dvo->dev_priv = ns; 244296548Sdumbbell ns->quiet = true; 245296548Sdumbbell 246296548Sdumbbell if (!ns2501_readb(dvo, NS2501_VID_LO, &ch)) 247296548Sdumbbell goto out; 248296548Sdumbbell 249296548Sdumbbell if (ch != (NS2501_VID & 0xff)) { 250296548Sdumbbell DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n", 251296548Sdumbbell ch, device_get_nameunit(adapter), dvo->slave_addr); 252296548Sdumbbell goto out; 253296548Sdumbbell } 254296548Sdumbbell 255296548Sdumbbell if (!ns2501_readb(dvo, NS2501_DID_LO, &ch)) 256296548Sdumbbell goto out; 257296548Sdumbbell 258296548Sdumbbell if (ch != (NS2501_DID & 0xff)) { 259296548Sdumbbell DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n", 260296548Sdumbbell ch, device_get_nameunit(adapter), dvo->slave_addr); 261296548Sdumbbell goto out; 262296548Sdumbbell } 263296548Sdumbbell ns->quiet = false; 264296548Sdumbbell ns->reg_8_set = 0; 265296548Sdumbbell ns->reg_8_shadow = 266296548Sdumbbell NS2501_8_PD | NS2501_8_BPAS | NS2501_8_VEN | NS2501_8_HEN; 267296548Sdumbbell 268296548Sdumbbell DRM_DEBUG_KMS("init ns2501 dvo controller successfully!\n"); 269296548Sdumbbell return true; 270296548Sdumbbell 271296548Sdumbbellout: 272296548Sdumbbell free(ns, DRM_MEM_KMS); 273296548Sdumbbell return false; 274296548Sdumbbell} 275296548Sdumbbell 276296548Sdumbbellstatic enum drm_connector_status ns2501_detect(struct intel_dvo_device *dvo) 277296548Sdumbbell{ 278296548Sdumbbell /* 279296548Sdumbbell * This is a Laptop display, it doesn't have hotplugging. 280296548Sdumbbell * Even if not, the detection bit of the 2501 is unreliable as 281296548Sdumbbell * it only works for some display types. 282296548Sdumbbell * It is even more unreliable as the PLL must be active for 283296548Sdumbbell * allowing reading from the chiop. 284296548Sdumbbell */ 285296548Sdumbbell return connector_status_connected; 286296548Sdumbbell} 287296548Sdumbbell 288296548Sdumbbellstatic enum drm_mode_status ns2501_mode_valid(struct intel_dvo_device *dvo, 289296548Sdumbbell struct drm_display_mode *mode) 290296548Sdumbbell{ 291296548Sdumbbell DRM_DEBUG_KMS 292296548Sdumbbell ("%s: is mode valid (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d)\n", 293296548Sdumbbell __FUNCTION__, mode->hdisplay, mode->htotal, mode->vdisplay, 294296548Sdumbbell mode->vtotal); 295296548Sdumbbell 296296548Sdumbbell /* 297296548Sdumbbell * Currently, these are all the modes I have data from. 298296548Sdumbbell * More might exist. Unclear how to find the native resolution 299296548Sdumbbell * of the panel in here so we could always accept it 300296548Sdumbbell * by disabling the scaler. 301296548Sdumbbell */ 302296548Sdumbbell if ((mode->hdisplay == 800 && mode->vdisplay == 600) || 303296548Sdumbbell (mode->hdisplay == 640 && mode->vdisplay == 480) || 304296548Sdumbbell (mode->hdisplay == 1024 && mode->vdisplay == 768)) { 305296548Sdumbbell return MODE_OK; 306296548Sdumbbell } else { 307296548Sdumbbell return MODE_ONE_SIZE; /* Is this a reasonable error? */ 308296548Sdumbbell } 309296548Sdumbbell} 310296548Sdumbbell 311296548Sdumbbellstatic void ns2501_mode_set(struct intel_dvo_device *dvo, 312296548Sdumbbell struct drm_display_mode *mode, 313296548Sdumbbell struct drm_display_mode *adjusted_mode) 314296548Sdumbbell{ 315296548Sdumbbell bool ok; 316296548Sdumbbell bool restore = false; 317296548Sdumbbell struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); 318296548Sdumbbell 319296548Sdumbbell DRM_DEBUG_KMS 320296548Sdumbbell ("%s: set mode (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d).\n", 321296548Sdumbbell __FUNCTION__, mode->hdisplay, mode->htotal, mode->vdisplay, 322296548Sdumbbell mode->vtotal); 323296548Sdumbbell 324296548Sdumbbell /* 325296548Sdumbbell * Where do I find the native resolution for which scaling is not required??? 326296548Sdumbbell * 327296548Sdumbbell * First trigger the DVO on as otherwise the chip does not appear on the i2c 328296548Sdumbbell * bus. 329296548Sdumbbell */ 330296548Sdumbbell do { 331296548Sdumbbell ok = true; 332296548Sdumbbell 333296548Sdumbbell if (mode->hdisplay == 800 && mode->vdisplay == 600) { 334296548Sdumbbell /* mode 277 */ 335296548Sdumbbell ns->reg_8_shadow &= ~NS2501_8_BPAS; 336296548Sdumbbell DRM_DEBUG_KMS("%s: switching to 800x600\n", 337296548Sdumbbell __FUNCTION__); 338296548Sdumbbell 339296548Sdumbbell /* 340296548Sdumbbell * No, I do not know where this data comes from. 341296548Sdumbbell * It is just what the video bios left in the DVO, so 342296548Sdumbbell * I'm just copying it here over. 343296548Sdumbbell * This also means that I cannot support any other modes 344296548Sdumbbell * except the ones supported by the bios. 345296548Sdumbbell */ 346296548Sdumbbell ok &= ns2501_writeb(dvo, 0x11, 0xc8); // 0xc7 also works. 347296548Sdumbbell ok &= ns2501_writeb(dvo, 0x1b, 0x19); 348296548Sdumbbell ok &= ns2501_writeb(dvo, 0x1c, 0x62); // VBIOS left 0x64 here, but 0x62 works nicer 349296548Sdumbbell ok &= ns2501_writeb(dvo, 0x1d, 0x02); 350296548Sdumbbell 351296548Sdumbbell ok &= ns2501_writeb(dvo, 0x34, 0x03); 352296548Sdumbbell ok &= ns2501_writeb(dvo, 0x35, 0xff); 353296548Sdumbbell 354296548Sdumbbell ok &= ns2501_writeb(dvo, 0x80, 0x27); 355296548Sdumbbell ok &= ns2501_writeb(dvo, 0x81, 0x03); 356296548Sdumbbell ok &= ns2501_writeb(dvo, 0x82, 0x41); 357296548Sdumbbell ok &= ns2501_writeb(dvo, 0x83, 0x05); 358296548Sdumbbell 359296548Sdumbbell ok &= ns2501_writeb(dvo, 0x8d, 0x02); 360296548Sdumbbell ok &= ns2501_writeb(dvo, 0x8e, 0x04); 361296548Sdumbbell ok &= ns2501_writeb(dvo, 0x8f, 0x00); 362296548Sdumbbell 363296548Sdumbbell ok &= ns2501_writeb(dvo, 0x90, 0xfe); /* vertical. VBIOS left 0xff here, but 0xfe works better */ 364296548Sdumbbell ok &= ns2501_writeb(dvo, 0x91, 0x07); 365296548Sdumbbell ok &= ns2501_writeb(dvo, 0x94, 0x00); 366296548Sdumbbell ok &= ns2501_writeb(dvo, 0x95, 0x00); 367296548Sdumbbell 368296548Sdumbbell ok &= ns2501_writeb(dvo, 0x96, 0x00); 369296548Sdumbbell 370296548Sdumbbell ok &= ns2501_writeb(dvo, 0x99, 0x00); 371296548Sdumbbell ok &= ns2501_writeb(dvo, 0x9a, 0x88); 372296548Sdumbbell 373296548Sdumbbell ok &= ns2501_writeb(dvo, 0x9c, 0x23); /* Looks like first and last line of the image. */ 374296548Sdumbbell ok &= ns2501_writeb(dvo, 0x9d, 0x00); 375296548Sdumbbell ok &= ns2501_writeb(dvo, 0x9e, 0x25); 376296548Sdumbbell ok &= ns2501_writeb(dvo, 0x9f, 0x03); 377296548Sdumbbell 378296548Sdumbbell ok &= ns2501_writeb(dvo, 0xa4, 0x80); 379296548Sdumbbell 380296548Sdumbbell ok &= ns2501_writeb(dvo, 0xb6, 0x00); 381296548Sdumbbell 382296548Sdumbbell ok &= ns2501_writeb(dvo, 0xb9, 0xc8); /* horizontal? */ 383296548Sdumbbell ok &= ns2501_writeb(dvo, 0xba, 0x00); /* horizontal? */ 384296548Sdumbbell 385296548Sdumbbell ok &= ns2501_writeb(dvo, 0xc0, 0x05); /* horizontal? */ 386296548Sdumbbell ok &= ns2501_writeb(dvo, 0xc1, 0xd7); 387296548Sdumbbell 388296548Sdumbbell ok &= ns2501_writeb(dvo, 0xc2, 0x00); 389296548Sdumbbell ok &= ns2501_writeb(dvo, 0xc3, 0xf8); 390296548Sdumbbell 391296548Sdumbbell ok &= ns2501_writeb(dvo, 0xc4, 0x03); 392296548Sdumbbell ok &= ns2501_writeb(dvo, 0xc5, 0x1a); 393296548Sdumbbell 394296548Sdumbbell ok &= ns2501_writeb(dvo, 0xc6, 0x00); 395296548Sdumbbell ok &= ns2501_writeb(dvo, 0xc7, 0x73); 396296548Sdumbbell ok &= ns2501_writeb(dvo, 0xc8, 0x02); 397296548Sdumbbell 398296548Sdumbbell } else if (mode->hdisplay == 640 && mode->vdisplay == 480) { 399296548Sdumbbell /* mode 274 */ 400296548Sdumbbell DRM_DEBUG_KMS("%s: switching to 640x480\n", 401296548Sdumbbell __FUNCTION__); 402296548Sdumbbell /* 403296548Sdumbbell * No, I do not know where this data comes from. 404296548Sdumbbell * It is just what the video bios left in the DVO, so 405296548Sdumbbell * I'm just copying it here over. 406296548Sdumbbell * This also means that I cannot support any other modes 407296548Sdumbbell * except the ones supported by the bios. 408296548Sdumbbell */ 409296548Sdumbbell ns->reg_8_shadow &= ~NS2501_8_BPAS; 410296548Sdumbbell 411296548Sdumbbell ok &= ns2501_writeb(dvo, 0x11, 0xa0); 412296548Sdumbbell ok &= ns2501_writeb(dvo, 0x1b, 0x11); 413296548Sdumbbell ok &= ns2501_writeb(dvo, 0x1c, 0x54); 414296548Sdumbbell ok &= ns2501_writeb(dvo, 0x1d, 0x03); 415296548Sdumbbell 416296548Sdumbbell ok &= ns2501_writeb(dvo, 0x34, 0x03); 417296548Sdumbbell ok &= ns2501_writeb(dvo, 0x35, 0xff); 418296548Sdumbbell 419296548Sdumbbell ok &= ns2501_writeb(dvo, 0x80, 0xff); 420296548Sdumbbell ok &= ns2501_writeb(dvo, 0x81, 0x07); 421296548Sdumbbell ok &= ns2501_writeb(dvo, 0x82, 0x3d); 422296548Sdumbbell ok &= ns2501_writeb(dvo, 0x83, 0x05); 423296548Sdumbbell 424296548Sdumbbell ok &= ns2501_writeb(dvo, 0x8d, 0x02); 425296548Sdumbbell ok &= ns2501_writeb(dvo, 0x8e, 0x10); 426296548Sdumbbell ok &= ns2501_writeb(dvo, 0x8f, 0x00); 427296548Sdumbbell 428296548Sdumbbell ok &= ns2501_writeb(dvo, 0x90, 0xff); /* vertical */ 429296548Sdumbbell ok &= ns2501_writeb(dvo, 0x91, 0x07); 430296548Sdumbbell ok &= ns2501_writeb(dvo, 0x94, 0x00); 431296548Sdumbbell ok &= ns2501_writeb(dvo, 0x95, 0x00); 432296548Sdumbbell 433296548Sdumbbell ok &= ns2501_writeb(dvo, 0x96, 0x05); 434296548Sdumbbell 435296548Sdumbbell ok &= ns2501_writeb(dvo, 0x99, 0x00); 436296548Sdumbbell ok &= ns2501_writeb(dvo, 0x9a, 0x88); 437296548Sdumbbell 438296548Sdumbbell ok &= ns2501_writeb(dvo, 0x9c, 0x24); 439296548Sdumbbell ok &= ns2501_writeb(dvo, 0x9d, 0x00); 440296548Sdumbbell ok &= ns2501_writeb(dvo, 0x9e, 0x25); 441296548Sdumbbell ok &= ns2501_writeb(dvo, 0x9f, 0x03); 442296548Sdumbbell 443296548Sdumbbell ok &= ns2501_writeb(dvo, 0xa4, 0x84); 444296548Sdumbbell 445296548Sdumbbell ok &= ns2501_writeb(dvo, 0xb6, 0x09); 446296548Sdumbbell 447296548Sdumbbell ok &= ns2501_writeb(dvo, 0xb9, 0xa0); /* horizontal? */ 448296548Sdumbbell ok &= ns2501_writeb(dvo, 0xba, 0x00); /* horizontal? */ 449296548Sdumbbell 450296548Sdumbbell ok &= ns2501_writeb(dvo, 0xc0, 0x05); /* horizontal? */ 451296548Sdumbbell ok &= ns2501_writeb(dvo, 0xc1, 0x90); 452296548Sdumbbell 453296548Sdumbbell ok &= ns2501_writeb(dvo, 0xc2, 0x00); 454296548Sdumbbell ok &= ns2501_writeb(dvo, 0xc3, 0x0f); 455296548Sdumbbell 456296548Sdumbbell ok &= ns2501_writeb(dvo, 0xc4, 0x03); 457296548Sdumbbell ok &= ns2501_writeb(dvo, 0xc5, 0x16); 458296548Sdumbbell 459296548Sdumbbell ok &= ns2501_writeb(dvo, 0xc6, 0x00); 460296548Sdumbbell ok &= ns2501_writeb(dvo, 0xc7, 0x02); 461296548Sdumbbell ok &= ns2501_writeb(dvo, 0xc8, 0x02); 462296548Sdumbbell 463296548Sdumbbell } else if (mode->hdisplay == 1024 && mode->vdisplay == 768) { 464296548Sdumbbell /* mode 280 */ 465296548Sdumbbell DRM_DEBUG_KMS("%s: switching to 1024x768\n", 466296548Sdumbbell __FUNCTION__); 467296548Sdumbbell /* 468296548Sdumbbell * This might or might not work, actually. I'm silently 469296548Sdumbbell * assuming here that the native panel resolution is 470296548Sdumbbell * 1024x768. If not, then this leaves the scaler disabled 471296548Sdumbbell * generating a picture that is likely not the expected. 472296548Sdumbbell * 473296548Sdumbbell * Problem is that I do not know where to take the panel 474296548Sdumbbell * dimensions from. 475296548Sdumbbell * 476296548Sdumbbell * Enable the bypass, scaling not required. 477296548Sdumbbell * 478296548Sdumbbell * The scaler registers are irrelevant here.... 479296548Sdumbbell * 480296548Sdumbbell */ 481296548Sdumbbell ns->reg_8_shadow |= NS2501_8_BPAS; 482296548Sdumbbell ok &= ns2501_writeb(dvo, 0x37, 0x44); 483296548Sdumbbell } else { 484296548Sdumbbell /* 485296548Sdumbbell * Data not known. Bummer! 486296548Sdumbbell * Hopefully, the code should not go here 487296548Sdumbbell * as mode_OK delivered no other modes. 488296548Sdumbbell */ 489296548Sdumbbell ns->reg_8_shadow |= NS2501_8_BPAS; 490296548Sdumbbell } 491296548Sdumbbell ok &= ns2501_writeb(dvo, NS2501_REG8, ns->reg_8_shadow); 492296548Sdumbbell 493296548Sdumbbell if (!ok) { 494296548Sdumbbell if (restore) 495296548Sdumbbell restore_dvo(dvo); 496296548Sdumbbell enable_dvo(dvo); 497296548Sdumbbell restore = true; 498296548Sdumbbell } 499296548Sdumbbell } while (!ok); 500296548Sdumbbell /* 501296548Sdumbbell * Restore the old i915 registers before 502296548Sdumbbell * forcing the ns2501 on. 503296548Sdumbbell */ 504296548Sdumbbell if (restore) 505296548Sdumbbell restore_dvo(dvo); 506296548Sdumbbell} 507296548Sdumbbell 508296548Sdumbbell/* set the NS2501 power state */ 509296548Sdumbbellstatic bool ns2501_get_hw_state(struct intel_dvo_device *dvo) 510296548Sdumbbell{ 511296548Sdumbbell unsigned char ch; 512296548Sdumbbell 513296548Sdumbbell if (!ns2501_readb(dvo, NS2501_REG8, &ch)) 514296548Sdumbbell return false; 515296548Sdumbbell 516296548Sdumbbell if (ch & NS2501_8_PD) 517296548Sdumbbell return true; 518296548Sdumbbell else 519296548Sdumbbell return false; 520296548Sdumbbell} 521296548Sdumbbell 522296548Sdumbbell/* set the NS2501 power state */ 523296548Sdumbbellstatic void ns2501_dpms(struct intel_dvo_device *dvo, bool enable) 524296548Sdumbbell{ 525296548Sdumbbell bool ok; 526296548Sdumbbell bool restore = false; 527296548Sdumbbell struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); 528296548Sdumbbell unsigned char ch; 529296548Sdumbbell 530296548Sdumbbell DRM_DEBUG_KMS("%s: Trying set the dpms of the DVO to %i\n", 531296548Sdumbbell __FUNCTION__, enable); 532296548Sdumbbell 533296548Sdumbbell ch = ns->reg_8_shadow; 534296548Sdumbbell 535296548Sdumbbell if (enable) 536296548Sdumbbell ch |= NS2501_8_PD; 537296548Sdumbbell else 538296548Sdumbbell ch &= ~NS2501_8_PD; 539296548Sdumbbell 540296548Sdumbbell if (ns->reg_8_set == 0 || ns->reg_8_shadow != ch) { 541296548Sdumbbell ns->reg_8_set = 1; 542296548Sdumbbell ns->reg_8_shadow = ch; 543296548Sdumbbell 544296548Sdumbbell do { 545296548Sdumbbell ok = true; 546296548Sdumbbell ok &= ns2501_writeb(dvo, NS2501_REG8, ch); 547296548Sdumbbell ok &= 548296548Sdumbbell ns2501_writeb(dvo, 0x34, 549296548Sdumbbell enable ? 0x03 : 0x00); 550296548Sdumbbell ok &= 551296548Sdumbbell ns2501_writeb(dvo, 0x35, 552296548Sdumbbell enable ? 0xff : 0x00); 553296548Sdumbbell if (!ok) { 554296548Sdumbbell if (restore) 555296548Sdumbbell restore_dvo(dvo); 556296548Sdumbbell enable_dvo(dvo); 557296548Sdumbbell restore = true; 558296548Sdumbbell } 559296548Sdumbbell } while (!ok); 560296548Sdumbbell 561296548Sdumbbell if (restore) 562296548Sdumbbell restore_dvo(dvo); 563296548Sdumbbell } 564296548Sdumbbell} 565296548Sdumbbell 566296548Sdumbbellstatic void ns2501_dump_regs(struct intel_dvo_device *dvo) 567296548Sdumbbell{ 568296548Sdumbbell uint8_t val; 569296548Sdumbbell 570296548Sdumbbell ns2501_readb(dvo, NS2501_FREQ_LO, &val); 571296548Sdumbbell DRM_LOG_KMS("NS2501_FREQ_LO: 0x%02x\n", val); 572296548Sdumbbell ns2501_readb(dvo, NS2501_FREQ_HI, &val); 573296548Sdumbbell DRM_LOG_KMS("NS2501_FREQ_HI: 0x%02x\n", val); 574296548Sdumbbell ns2501_readb(dvo, NS2501_REG8, &val); 575296548Sdumbbell DRM_LOG_KMS("NS2501_REG8: 0x%02x\n", val); 576296548Sdumbbell ns2501_readb(dvo, NS2501_REG9, &val); 577296548Sdumbbell DRM_LOG_KMS("NS2501_REG9: 0x%02x\n", val); 578296548Sdumbbell ns2501_readb(dvo, NS2501_REGC, &val); 579296548Sdumbbell DRM_LOG_KMS("NS2501_REGC: 0x%02x\n", val); 580296548Sdumbbell} 581296548Sdumbbell 582296548Sdumbbellstatic void ns2501_destroy(struct intel_dvo_device *dvo) 583296548Sdumbbell{ 584296548Sdumbbell struct ns2501_priv *ns = dvo->dev_priv; 585296548Sdumbbell 586296548Sdumbbell if (ns) { 587296548Sdumbbell free(ns, DRM_MEM_KMS); 588296548Sdumbbell dvo->dev_priv = NULL; 589296548Sdumbbell } 590296548Sdumbbell} 591296548Sdumbbell 592296548Sdumbbellstruct intel_dvo_dev_ops ns2501_ops = { 593296548Sdumbbell .init = ns2501_init, 594296548Sdumbbell .detect = ns2501_detect, 595296548Sdumbbell .mode_valid = ns2501_mode_valid, 596296548Sdumbbell .mode_set = ns2501_mode_set, 597296548Sdumbbell .dpms = ns2501_dpms, 598296548Sdumbbell .get_hw_state = ns2501_get_hw_state, 599296548Sdumbbell .dump_regs = ns2501_dump_regs, 600296548Sdumbbell .destroy = ns2501_destroy, 601296548Sdumbbell}; 602