Subversion Repositories Kolibri OS

Rev

Rev 5354 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  *
  3.  * Copyright (c) 2012 Gilles Dartiguelongue, Thomas Richter
  4.  *
  5.  * All Rights Reserved.
  6.  *
  7.  * Permission is hereby granted, free of charge, to any person obtaining a
  8.  * copy of this software and associated documentation files (the
  9.  * "Software"), to deal in the Software without restriction, including
  10.  * without limitation the rights to use, copy, modify, merge, publish,
  11.  * distribute, sub license, and/or sell copies of the Software, and to
  12.  * permit persons to whom the Software is furnished to do so, subject to
  13.  * the following conditions:
  14.  *
  15.  * The above copyright notice and this permission notice (including the
  16.  * next paragraph) shall be included in all copies or substantial portions
  17.  * of the Software.
  18.  *
  19.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  20.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  21.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  22.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  23.  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  24.  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  25.  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  26.  *
  27.  */
  28.  
  29. #include "dvo.h"
  30. #include "i915_reg.h"
  31. #include "i915_drv.h"
  32.  
  33. #define NS2501_VID 0x1305
  34. #define NS2501_DID 0x6726
  35.  
  36. #define NS2501_VID_LO 0x00
  37. #define NS2501_VID_HI 0x01
  38. #define NS2501_DID_LO 0x02
  39. #define NS2501_DID_HI 0x03
  40. #define NS2501_REV 0x04
  41. #define NS2501_RSVD 0x05
  42. #define NS2501_FREQ_LO 0x06
  43. #define NS2501_FREQ_HI 0x07
  44.  
  45. #define NS2501_REG8 0x08
  46. #define NS2501_8_VEN (1<<5)
  47. #define NS2501_8_HEN (1<<4)
  48. #define NS2501_8_DSEL (1<<3)
  49. #define NS2501_8_BPAS (1<<2)
  50. #define NS2501_8_RSVD (1<<1)
  51. #define NS2501_8_PD (1<<0)
  52.  
  53. #define NS2501_REG9 0x09
  54. #define NS2501_9_VLOW (1<<7)
  55. #define NS2501_9_MSEL_MASK (0x7<<4)
  56. #define NS2501_9_TSEL (1<<3)
  57. #define NS2501_9_RSEN (1<<2)
  58. #define NS2501_9_RSVD (1<<1)
  59. #define NS2501_9_MDI (1<<0)
  60.  
  61. #define NS2501_REGC 0x0c
  62.  
  63. /*
  64.  * The following registers are not part of the official datasheet
  65.  * and are the result of reverse engineering.
  66.  */
  67.  
  68. /*
  69.  * Register c0 controls how the DVO synchronizes with
  70.  * its input.
  71.  */
  72. #define NS2501_REGC0 0xc0
  73. #define NS2501_C0_ENABLE (1<<0) /* enable the DVO sync in general */
  74. #define NS2501_C0_HSYNC (1<<1)  /* synchronize horizontal with input */
  75. #define NS2501_C0_VSYNC (1<<2)  /* synchronize vertical with input */
  76. #define NS2501_C0_RESET (1<<7)  /* reset the synchronization flip/flops */
  77.  
  78. /*
  79.  * Register 41 is somehow related to the sync register and sync
  80.  * configuration. It should be 0x32 whenever regC0 is 0x05 (hsync off)
  81.  * and 0x00 otherwise.
  82.  */
  83. #define NS2501_REG41 0x41
  84.  
  85. /*
  86.  * this register controls the dithering of the DVO
  87.  * One bit enables it, the other define the dithering depth.
  88.  * The higher the value, the lower the dithering depth.
  89.  */
  90. #define NS2501_F9_REG 0xf9
  91. #define NS2501_F9_ENABLE (1<<0)         /* if set, dithering is enabled */
  92. #define NS2501_F9_DITHER_MASK (0x7f<<1) /* controls the dither depth */
  93. #define NS2501_F9_DITHER_SHIFT 1        /* shifts the dither mask */
  94.  
  95. /*
  96.  * PLL configuration register. This is a pair of registers,
  97.  * one single byte register at 1B, and a pair at 1C,1D.
  98.  * These registers are counters/dividers.
  99.  */
  100. #define NS2501_REG1B 0x1b /* one byte PLL control register */
  101. #define NS2501_REG1C 0x1c /* low-part of the second register */
  102. #define NS2501_REG1D 0x1d /* high-part of the second register */
  103.  
  104. /*
  105.  * Scaler control registers. Horizontal at b8,b9,
  106.  * vertical at 10,11. The scale factor is computed as
  107.  * 2^16/control-value. The low-byte comes first.
  108.  */
  109. #define NS2501_REG10 0x10 /* low-byte vertical scaler */
  110. #define NS2501_REG11 0x11 /* high-byte vertical scaler */
  111. #define NS2501_REGB8 0xb8 /* low-byte horizontal scaler */
  112. #define NS2501_REGB9 0xb9 /* high-byte horizontal scaler */
  113.  
  114. /*
  115.  * Display window definition. This consists of four registers
  116.  * per dimension. One register pair defines the start of the
  117.  * display, one the end.
  118.  * As far as I understand, this defines the window within which
  119.  * the scaler samples the input.
  120.  */
  121. #define NS2501_REGC1 0xc1 /* low-byte horizontal display start */
  122. #define NS2501_REGC2 0xc2 /* high-byte horizontal display start */
  123. #define NS2501_REGC3 0xc3 /* low-byte horizontal display stop */
  124. #define NS2501_REGC4 0xc4 /* high-byte horizontal display stop */
  125. #define NS2501_REGC5 0xc5 /* low-byte vertical display start */
  126. #define NS2501_REGC6 0xc6 /* high-byte vertical display start */
  127. #define NS2501_REGC7 0xc7 /* low-byte vertical display stop */
  128. #define NS2501_REGC8 0xc8 /* high-byte vertical display stop */
  129.  
  130. /*
  131.  * The following register pair seems to define the start of
  132.  * the vertical sync. If automatic syncing is enabled, and the
  133.  * register value defines a sync pulse that is later than the
  134.  * incoming sync, then the register value is ignored and the
  135.  * external hsync triggers the synchronization.
  136.  */
  137. #define NS2501_REG80 0x80 /* low-byte vsync-start */
  138. #define NS2501_REG81 0x81 /* high-byte vsync-start */
  139.  
  140. /*
  141.  * The following register pair seems to define the total number
  142.  * of lines created at the output side of the scaler.
  143.  * This is again a low-high register pair.
  144.  */
  145. #define NS2501_REG82 0x82 /* output display height, low byte */
  146. #define NS2501_REG83 0x83 /* output display height, high byte */
  147.  
  148. /*
  149.  * The following registers define the end of the front-porch
  150.  * in horizontal and vertical position and hence allow to shift
  151.  * the image left/right or up/down.
  152.  */
  153. #define NS2501_REG98 0x98 /* horizontal start of display + 256, low */
  154. #define NS2501_REG99 0x99 /* horizontal start of display + 256, high */
  155. #define NS2501_REG8E 0x8e /* vertical start of the display, low byte */
  156. #define NS2501_REG8F 0x8f /* vertical start of the display, high byte */
  157.  
  158. /*
  159.  * The following register pair control the function of the
  160.  * backlight and the DVO output. To enable the corresponding
  161.  * function, the corresponding bit must be set in both registers.
  162.  */
  163. #define NS2501_REG34 0x34 /* DVO enable functions, first register */
  164. #define NS2501_REG35 0x35 /* DVO enable functions, second register */
  165. #define NS2501_34_ENABLE_OUTPUT (1<<0) /* enable DVO output */
  166. #define NS2501_34_ENABLE_BACKLIGHT (1<<1) /* enable backlight */
  167.  
  168. /*
  169.  * Registers 9C and 9D define the vertical output offset
  170.  * of the visible region.
  171.  */
  172. #define NS2501_REG9C 0x9c
  173. #define NS2501_REG9D 0x9d
  174.  
  175. /*
  176.  * The register 9F defines the dithering. This requires the
  177.  * scaler to be ON. Bit 0 enables dithering, the remaining
  178.  * bits control the depth of the dither. The higher the value,
  179.  * the LOWER the dithering amplitude. A good value seems to be
  180.  * 15 (total register value).
  181.  */
  182. #define NS2501_REGF9 0xf9
  183. #define NS2501_F9_ENABLE_DITHER (1<<0) /* enable dithering */
  184. #define NS2501_F9_DITHER_MASK (0x7f<<1) /* dither masking */
  185. #define NS2501_F9_DITHER_SHIFT 1        /* upshift of the dither mask */
  186.  
  187. enum {
  188.         MODE_640x480,
  189.         MODE_800x600,
  190.         MODE_1024x768,
  191. };
  192.  
  193. struct ns2501_reg {
  194.          uint8_t offset;
  195.          uint8_t value;
  196. };
  197.  
  198. /*
  199.  * The following structure keeps the complete configuration of
  200.  * the DVO, given a specific output configuration.
  201.  * This is pretty much guess-work from reverse-engineering, so
  202.  * read all this with a grain of salt.
  203.  */
  204. struct ns2501_configuration {
  205.         uint8_t sync;           /* configuration of the C0 register */
  206.         uint8_t conf;           /* configuration register 8 */
  207.         uint8_t syncb;          /* configuration register 41 */
  208.         uint8_t dither;         /* configuration of the dithering */
  209.         uint8_t pll_a;          /* PLL configuration, register A, 1B */
  210.         uint16_t pll_b;         /* PLL configuration, register B, 1C/1D */
  211.         uint16_t hstart;        /* horizontal start, registers C1/C2 */
  212.         uint16_t hstop;         /* horizontal total, registers C3/C4 */
  213.         uint16_t vstart;        /* vertical start, registers C5/C6 */
  214.         uint16_t vstop;         /* vertical total, registers C7/C8 */
  215.         uint16_t vsync;         /* manual vertical sync start, 80/81 */
  216.         uint16_t vtotal;        /* number of lines generated, 82/83 */
  217.         uint16_t hpos;          /* horizontal position + 256, 98/99  */
  218.         uint16_t vpos;          /* vertical position, 8e/8f */
  219.         uint16_t voffs;         /* vertical output offset, 9c/9d */
  220.         uint16_t hscale;        /* horizontal scaling factor, b8/b9 */
  221.         uint16_t vscale;        /* vertical scaling factor, 10/11 */
  222. };
  223.  
  224. /*
  225.  * DVO configuration values, partially based on what the BIOS
  226.  * of the Fujitsu Lifebook S6010 writes into registers,
  227.  * partially found by manual tweaking. These configurations assume
  228.  * a 1024x768 panel.
  229.  */
  230. static const struct ns2501_configuration ns2501_modes[] = {
  231.         [MODE_640x480] = {
  232.                 .sync   = NS2501_C0_ENABLE | NS2501_C0_VSYNC,
  233.                 .conf   = NS2501_8_VEN | NS2501_8_HEN | NS2501_8_PD,
  234.                 .syncb  = 0x32,
  235.                 .dither = 0x0f,
  236.                 .pll_a  = 17,
  237.                 .pll_b  = 852,
  238.                 .hstart = 144,
  239.                 .hstop  = 783,
  240.                 .vstart = 22,
  241.                 .vstop  = 514,
  242.                 .vsync  = 2047, /* actually, ignored with this config */
  243.                 .vtotal = 1341,
  244.                 .hpos   = 0,
  245.                 .vpos   = 16,
  246.                 .voffs  = 36,
  247.                 .hscale = 40960,
  248.                 .vscale = 40960
  249.         },
  250.         [MODE_800x600] = {
  251.                 .sync   = NS2501_C0_ENABLE |
  252.                           NS2501_C0_HSYNC | NS2501_C0_VSYNC,
  253.                 .conf   = NS2501_8_VEN | NS2501_8_HEN | NS2501_8_PD,
  254.                 .syncb  = 0x00,
  255.                 .dither = 0x0f,
  256.                 .pll_a  = 25,
  257.                 .pll_b  = 612,
  258.                 .hstart = 215,
  259.                 .hstop  = 1016,
  260.                 .vstart = 26,
  261.                 .vstop  = 627,
  262.                 .vsync  = 807,
  263.                 .vtotal = 1341,
  264.                 .hpos   = 0,
  265.                 .vpos   = 4,
  266.                 .voffs  = 35,
  267.                 .hscale = 51248,
  268.                 .vscale = 51232
  269.         },
  270.         [MODE_1024x768] = {
  271.                 .sync   = NS2501_C0_ENABLE | NS2501_C0_VSYNC,
  272.                 .conf   = NS2501_8_VEN | NS2501_8_HEN | NS2501_8_PD,
  273.                 .syncb  = 0x32,
  274.                 .dither = 0x0f,
  275.                 .pll_a  = 11,
  276.                 .pll_b  = 1350,
  277.                 .hstart = 276,
  278.                 .hstop  = 1299,
  279.                 .vstart = 15,
  280.                 .vstop  = 1056,
  281.                 .vsync  = 2047,
  282.                 .vtotal = 1341,
  283.                 .hpos   = 0,
  284.                 .vpos   = 7,
  285.                 .voffs  = 27,
  286.                 .hscale = 65535,
  287.                 .vscale = 65535
  288.         }
  289. };
  290.  
  291. /*
  292.  * Other configuration values left by the BIOS of the
  293.  * Fujitsu S6010 in the DVO control registers. Their
  294.  * value does not depend on the BIOS and their meaning
  295.  * is unknown.
  296.  */
  297.  
  298. static const struct ns2501_reg mode_agnostic_values[] = {
  299.         /* 08 is mode specific */
  300.         [0] = { .offset = 0x0a, .value = 0x81, },
  301.         /* 10,11 are part of the mode specific configuration */
  302.         [1] = { .offset = 0x12, .value = 0x02, },
  303.         [2] = { .offset = 0x18, .value = 0x07, },
  304.         [3] = { .offset = 0x19, .value = 0x00, },
  305.         [4] = { .offset = 0x1a, .value = 0x00, }, /* PLL?, ignored */
  306.         /* 1b,1c,1d are part of the mode specific configuration */
  307.         [5] = { .offset = 0x1e, .value = 0x02, },
  308.         [6] = { .offset = 0x1f, .value = 0x40, },
  309.         [7] = { .offset = 0x20, .value = 0x00, },
  310.         [8] = { .offset = 0x21, .value = 0x00, },
  311.         [9] = { .offset = 0x22, .value = 0x00, },
  312.         [10] = { .offset = 0x23, .value = 0x00, },
  313.         [11] = { .offset = 0x24, .value = 0x00, },
  314.         [12] = { .offset = 0x25, .value = 0x00, },
  315.         [13] = { .offset = 0x26, .value = 0x00, },
  316.         [14] = { .offset = 0x27, .value = 0x00, },
  317.         [15] = { .offset = 0x7e, .value = 0x18, },
  318.         /* 80-84 are part of the mode-specific configuration */
  319.         [16] = { .offset = 0x84, .value = 0x00, },
  320.         [17] = { .offset = 0x85, .value = 0x00, },
  321.         [18] = { .offset = 0x86, .value = 0x00, },
  322.         [19] = { .offset = 0x87, .value = 0x00, },
  323.         [20] = { .offset = 0x88, .value = 0x00, },
  324.         [21] = { .offset = 0x89, .value = 0x00, },
  325.         [22] = { .offset = 0x8a, .value = 0x00, },
  326.         [23] = { .offset = 0x8b, .value = 0x00, },
  327.         [24] = { .offset = 0x8c, .value = 0x10, },
  328.         [25] = { .offset = 0x8d, .value = 0x02, },
  329.         /* 8e,8f are part of the mode-specific configuration */
  330.         [26] = { .offset = 0x90, .value = 0xff, },
  331.         [27] = { .offset = 0x91, .value = 0x07, },
  332.         [28] = { .offset = 0x92, .value = 0xa0, },
  333.         [29] = { .offset = 0x93, .value = 0x02, },
  334.         [30] = { .offset = 0x94, .value = 0x00, },
  335.         [31] = { .offset = 0x95, .value = 0x00, },
  336.         [32] = { .offset = 0x96, .value = 0x05, },
  337.         [33] = { .offset = 0x97, .value = 0x00, },
  338.         /* 98,99 are part of the mode-specific configuration */
  339.         [34] = { .offset = 0x9a, .value = 0x88, },
  340.         [35] = { .offset = 0x9b, .value = 0x00, },
  341.         /* 9c,9d are part of the mode-specific configuration */
  342.         [36] = { .offset = 0x9e, .value = 0x25, },
  343.         [37] = { .offset = 0x9f, .value = 0x03, },
  344.         [38] = { .offset = 0xa0, .value = 0x28, },
  345.         [39] = { .offset = 0xa1, .value = 0x01, },
  346.         [40] = { .offset = 0xa2, .value = 0x28, },
  347.         [41] = { .offset = 0xa3, .value = 0x05, },
  348.         /* register 0xa4 is mode specific, but 0x80..0x84 works always */
  349.         [42] = { .offset = 0xa4, .value = 0x84, },
  350.         [43] = { .offset = 0xa5, .value = 0x00, },
  351.         [44] = { .offset = 0xa6, .value = 0x00, },
  352.         [45] = { .offset = 0xa7, .value = 0x00, },
  353.         [46] = { .offset = 0xa8, .value = 0x00, },
  354.         /* 0xa9 to 0xab are mode specific, but have no visible effect */
  355.         [47] = { .offset = 0xa9, .value = 0x04, },
  356.         [48] = { .offset = 0xaa, .value = 0x70, },
  357.         [49] = { .offset = 0xab, .value = 0x4f, },
  358.         [50] = { .offset = 0xac, .value = 0x00, },
  359.         [51] = { .offset = 0xad, .value = 0x00, },
  360.         [52] = { .offset = 0xb6, .value = 0x09, },
  361.         [53] = { .offset = 0xb7, .value = 0x03, },
  362.         /* b8,b9 are part of the mode-specific configuration */
  363.         [54] = { .offset = 0xba, .value = 0x00, },
  364.         [55] = { .offset = 0xbb, .value = 0x20, },
  365.         [56] = { .offset = 0xf3, .value = 0x90, },
  366.         [57] = { .offset = 0xf4, .value = 0x00, },
  367.         [58] = { .offset = 0xf7, .value = 0x88, },
  368.         /* f8 is mode specific, but the value does not matter */
  369.         [59] = { .offset = 0xf8, .value = 0x0a, },
  370.         [60] = { .offset = 0xf9, .value = 0x00, }
  371. };
  372.  
  373. static const struct ns2501_reg regs_init[] = {
  374.         [0] = { .offset = 0x35, .value = 0xff, },
  375.         [1] = { .offset = 0x34, .value = 0x00, },
  376.         [2] = { .offset = 0x08, .value = 0x30, },
  377. };
  378.  
  379. struct ns2501_priv {
  380.         bool quiet;
  381.         const struct ns2501_configuration *conf;
  382. };
  383.  
  384. #define NSPTR(d) ((NS2501Ptr)(d->DriverPrivate.ptr))
  385.  
  386. /*
  387. ** Read a register from the ns2501.
  388. ** Returns true if successful, false otherwise.
  389. ** If it returns false, it might be wise to enable the
  390. ** DVO with the above function.
  391. */
  392. static bool ns2501_readb(struct intel_dvo_device *dvo, int addr, uint8_t * ch)
  393. {
  394.         struct ns2501_priv *ns = dvo->dev_priv;
  395.         struct i2c_adapter *adapter = dvo->i2c_bus;
  396.         u8 out_buf[2];
  397.         u8 in_buf[2];
  398.  
  399.         struct i2c_msg msgs[] = {
  400.                 {
  401.                  .addr = dvo->slave_addr,
  402.                  .flags = 0,
  403.                  .len = 1,
  404.                  .buf = out_buf,
  405.                  },
  406.                 {
  407.                  .addr = dvo->slave_addr,
  408.                  .flags = I2C_M_RD,
  409.                  .len = 1,
  410.                  .buf = in_buf,
  411.                  }
  412.         };
  413.  
  414.         out_buf[0] = addr;
  415.         out_buf[1] = 0;
  416.  
  417.         if (i2c_transfer(adapter, msgs, 2) == 2) {
  418.                 *ch = in_buf[0];
  419.                 return true;
  420.         }
  421.  
  422.         if (!ns->quiet) {
  423.                 DRM_DEBUG_KMS
  424.                     ("Unable to read register 0x%02x from %s:0x%02x.\n", addr,
  425.                      adapter->name, dvo->slave_addr);
  426.         }
  427.  
  428.         return false;
  429. }
  430.  
  431. /*
  432. ** Write a register to the ns2501.
  433. ** Returns true if successful, false otherwise.
  434. ** If it returns false, it might be wise to enable the
  435. ** DVO with the above function.
  436. */
  437. static bool ns2501_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
  438. {
  439.         struct ns2501_priv *ns = dvo->dev_priv;
  440.         struct i2c_adapter *adapter = dvo->i2c_bus;
  441.         uint8_t out_buf[2];
  442.  
  443.         struct i2c_msg msg = {
  444.                 .addr = dvo->slave_addr,
  445.                 .flags = 0,
  446.                 .len = 2,
  447.                 .buf = out_buf,
  448.         };
  449.  
  450.         out_buf[0] = addr;
  451.         out_buf[1] = ch;
  452.  
  453.         if (i2c_transfer(adapter, &msg, 1) == 1) {
  454.                 return true;
  455.         }
  456.  
  457.         if (!ns->quiet) {
  458.                 DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d\n",
  459.                               addr, adapter->name, dvo->slave_addr);
  460.         }
  461.  
  462.         return false;
  463. }
  464.  
  465. /* National Semiconductor 2501 driver for chip on i2c bus
  466.  * scan for the chip on the bus.
  467.  * Hope the VBIOS initialized the PLL correctly so we can
  468.  * talk to it. If not, it will not be seen and not detected.
  469.  * Bummer!
  470.  */
  471. static bool ns2501_init(struct intel_dvo_device *dvo,
  472.                         struct i2c_adapter *adapter)
  473. {
  474.         /* this will detect the NS2501 chip on the specified i2c bus */
  475.         struct ns2501_priv *ns;
  476.         unsigned char ch;
  477.  
  478.         ns = kzalloc(sizeof(struct ns2501_priv), GFP_KERNEL);
  479.         if (ns == NULL)
  480.                 return false;
  481.  
  482.         dvo->i2c_bus = adapter;
  483.         dvo->dev_priv = ns;
  484.         ns->quiet = true;
  485.  
  486.         if (!ns2501_readb(dvo, NS2501_VID_LO, &ch))
  487.                 goto out;
  488.  
  489.         if (ch != (NS2501_VID & 0xff)) {
  490.                 DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n",
  491.                               ch, adapter->name, dvo->slave_addr);
  492.                 goto out;
  493.         }
  494.  
  495.         if (!ns2501_readb(dvo, NS2501_DID_LO, &ch))
  496.                 goto out;
  497.  
  498.         if (ch != (NS2501_DID & 0xff)) {
  499.                 DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n",
  500.                               ch, adapter->name, dvo->slave_addr);
  501.                 goto out;
  502.         }
  503.         ns->quiet = false;
  504.  
  505.         DRM_DEBUG_KMS("init ns2501 dvo controller successfully!\n");
  506.  
  507.         return true;
  508.  
  509. out:
  510.         kfree(ns);
  511.         return false;
  512. }
  513.  
  514. static enum drm_connector_status ns2501_detect(struct intel_dvo_device *dvo)
  515. {
  516.         /*
  517.          * This is a Laptop display, it doesn't have hotplugging.
  518.          * Even if not, the detection bit of the 2501 is unreliable as
  519.          * it only works for some display types.
  520.          * It is even more unreliable as the PLL must be active for
  521.          * allowing reading from the chiop.
  522.          */
  523.         return connector_status_connected;
  524. }
  525.  
  526. static enum drm_mode_status ns2501_mode_valid(struct intel_dvo_device *dvo,
  527.                                               struct drm_display_mode *mode)
  528. {
  529.         DRM_DEBUG_KMS
  530.             ("is mode valid (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d)\n",
  531.              mode->hdisplay, mode->htotal, mode->vdisplay, mode->vtotal);
  532.  
  533.         /*
  534.          * Currently, these are all the modes I have data from.
  535.          * More might exist. Unclear how to find the native resolution
  536.          * of the panel in here so we could always accept it
  537.          * by disabling the scaler.
  538.          */
  539.         if ((mode->hdisplay == 640 && mode->vdisplay == 480 && mode->clock == 25175) ||
  540.             (mode->hdisplay == 800 && mode->vdisplay == 600 && mode->clock == 40000) ||
  541.             (mode->hdisplay == 1024 && mode->vdisplay == 768 && mode->clock == 65000)) {
  542.                 return MODE_OK;
  543.         } else {
  544.                 return MODE_ONE_SIZE;   /* Is this a reasonable error? */
  545.         }
  546. }
  547.  
  548. static void ns2501_mode_set(struct intel_dvo_device *dvo,
  549.                             const struct drm_display_mode *mode,
  550.                             const struct drm_display_mode *adjusted_mode)
  551. {
  552.         const struct ns2501_configuration *conf;
  553.         struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
  554.         int mode_idx, i;
  555.  
  556.         DRM_DEBUG_KMS
  557.             ("set mode (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d).\n",
  558.              mode->hdisplay, mode->htotal, mode->vdisplay, mode->vtotal);
  559.  
  560.         DRM_DEBUG_KMS("Detailed requested mode settings are:\n"
  561.                         "clock          : %d kHz\n"
  562.                         "hdisplay       : %d\n"
  563.                         "hblank start   : %d\n"
  564.                         "hblank end     : %d\n"
  565.                         "hsync start    : %d\n"
  566.                         "hsync end      : %d\n"
  567.                         "htotal         : %d\n"
  568.                         "hskew          : %d\n"
  569.                         "vdisplay       : %d\n"
  570.                         "vblank start   : %d\n"
  571.                         "hblank end     : %d\n"
  572.                         "vsync start    : %d\n"
  573.                         "vsync end      : %d\n"
  574.                         "vtotal         : %d\n",
  575.                         adjusted_mode->crtc_clock,
  576.                         adjusted_mode->crtc_hdisplay,
  577.                         adjusted_mode->crtc_hblank_start,
  578.                         adjusted_mode->crtc_hblank_end,
  579.                         adjusted_mode->crtc_hsync_start,
  580.                         adjusted_mode->crtc_hsync_end,
  581.                         adjusted_mode->crtc_htotal,
  582.                         adjusted_mode->crtc_hskew,
  583.                         adjusted_mode->crtc_vdisplay,
  584.                         adjusted_mode->crtc_vblank_start,
  585.                         adjusted_mode->crtc_vblank_end,
  586.                         adjusted_mode->crtc_vsync_start,
  587.                         adjusted_mode->crtc_vsync_end,
  588.                         adjusted_mode->crtc_vtotal);
  589.  
  590.         if (mode->hdisplay == 640 && mode->vdisplay == 480)
  591.                 mode_idx = MODE_640x480;
  592.         else if (mode->hdisplay == 800 && mode->vdisplay == 600)
  593.                 mode_idx = MODE_800x600;
  594.         else if (mode->hdisplay == 1024 && mode->vdisplay == 768)
  595.                 mode_idx = MODE_1024x768;
  596.         else
  597.                 return;
  598.  
  599.         /* Hopefully doing it every time won't hurt... */
  600.         for (i = 0; i < ARRAY_SIZE(regs_init); i++)
  601.                 ns2501_writeb(dvo, regs_init[i].offset, regs_init[i].value);
  602.  
  603.         /* Write the mode-agnostic values */
  604.         for (i = 0; i < ARRAY_SIZE(mode_agnostic_values); i++)
  605.                 ns2501_writeb(dvo, mode_agnostic_values[i].offset,
  606.                                 mode_agnostic_values[i].value);
  607.  
  608.         /* Write now the mode-specific configuration */
  609.         conf = ns2501_modes + mode_idx;
  610.         ns->conf = conf;
  611.  
  612.         ns2501_writeb(dvo, NS2501_REG8, conf->conf);
  613.         ns2501_writeb(dvo, NS2501_REG1B, conf->pll_a);
  614.         ns2501_writeb(dvo, NS2501_REG1C, conf->pll_b & 0xff);
  615.         ns2501_writeb(dvo, NS2501_REG1D, conf->pll_b >> 8);
  616.         ns2501_writeb(dvo, NS2501_REGC1, conf->hstart & 0xff);
  617.         ns2501_writeb(dvo, NS2501_REGC2, conf->hstart >> 8);
  618.         ns2501_writeb(dvo, NS2501_REGC3, conf->hstop & 0xff);
  619.         ns2501_writeb(dvo, NS2501_REGC4, conf->hstop >> 8);
  620.         ns2501_writeb(dvo, NS2501_REGC5, conf->vstart & 0xff);
  621.         ns2501_writeb(dvo, NS2501_REGC6, conf->vstart >> 8);
  622.         ns2501_writeb(dvo, NS2501_REGC7, conf->vstop & 0xff);
  623.         ns2501_writeb(dvo, NS2501_REGC8, conf->vstop >> 8);
  624.         ns2501_writeb(dvo, NS2501_REG80, conf->vsync & 0xff);
  625.         ns2501_writeb(dvo, NS2501_REG81, conf->vsync >> 8);
  626.         ns2501_writeb(dvo, NS2501_REG82, conf->vtotal & 0xff);
  627.         ns2501_writeb(dvo, NS2501_REG83, conf->vtotal >> 8);
  628.         ns2501_writeb(dvo, NS2501_REG98, conf->hpos & 0xff);
  629.         ns2501_writeb(dvo, NS2501_REG99, conf->hpos >> 8);
  630.         ns2501_writeb(dvo, NS2501_REG8E, conf->vpos & 0xff);
  631.         ns2501_writeb(dvo, NS2501_REG8F, conf->vpos >> 8);
  632.         ns2501_writeb(dvo, NS2501_REG9C, conf->voffs & 0xff);
  633.         ns2501_writeb(dvo, NS2501_REG9D, conf->voffs >> 8);
  634.         ns2501_writeb(dvo, NS2501_REGB8, conf->hscale & 0xff);
  635.         ns2501_writeb(dvo, NS2501_REGB9, conf->hscale >> 8);
  636.         ns2501_writeb(dvo, NS2501_REG10, conf->vscale & 0xff);
  637.         ns2501_writeb(dvo, NS2501_REG11, conf->vscale >> 8);
  638.         ns2501_writeb(dvo, NS2501_REGF9, conf->dither);
  639.         ns2501_writeb(dvo, NS2501_REG41, conf->syncb);
  640.         ns2501_writeb(dvo, NS2501_REGC0, conf->sync);
  641. }
  642.  
  643. /* set the NS2501 power state */
  644. static bool ns2501_get_hw_state(struct intel_dvo_device *dvo)
  645. {
  646.         unsigned char ch;
  647.  
  648.         if (!ns2501_readb(dvo, NS2501_REG8, &ch))
  649.                 return false;
  650.  
  651.         return ch & NS2501_8_PD;
  652. }
  653.  
  654. /* set the NS2501 power state */
  655. static void ns2501_dpms(struct intel_dvo_device *dvo, bool enable)
  656. {
  657.         struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
  658.  
  659.         DRM_DEBUG_KMS("Trying set the dpms of the DVO to %i\n", enable);
  660.  
  661.         if (enable) {
  662.                 ns2501_writeb(dvo, NS2501_REGC0, ns->conf->sync | 0x08);
  663.  
  664.                 ns2501_writeb(dvo, NS2501_REG41, ns->conf->syncb);
  665.  
  666.                 ns2501_writeb(dvo, NS2501_REG34, NS2501_34_ENABLE_OUTPUT);
  667.                 msleep(15);
  668.  
  669.                 ns2501_writeb(dvo, NS2501_REG8,
  670.                                 ns->conf->conf | NS2501_8_BPAS);
  671.                 if (!(ns->conf->conf & NS2501_8_BPAS))
  672.                         ns2501_writeb(dvo, NS2501_REG8, ns->conf->conf);
  673.                 msleep(200);
  674.  
  675.                 ns2501_writeb(dvo, NS2501_REG34,
  676.                         NS2501_34_ENABLE_OUTPUT | NS2501_34_ENABLE_BACKLIGHT);
  677.  
  678.                 ns2501_writeb(dvo, NS2501_REGC0, ns->conf->sync);
  679.         } else {
  680.                 ns2501_writeb(dvo, NS2501_REG34, NS2501_34_ENABLE_OUTPUT);
  681.                 msleep(200);
  682.  
  683.                 ns2501_writeb(dvo, NS2501_REG8, NS2501_8_VEN | NS2501_8_HEN |
  684.                                 NS2501_8_BPAS);
  685.                 msleep(15);
  686.  
  687.                 ns2501_writeb(dvo, NS2501_REG34, 0x00);
  688.         }
  689. }
  690.  
  691. static void ns2501_destroy(struct intel_dvo_device *dvo)
  692. {
  693.         struct ns2501_priv *ns = dvo->dev_priv;
  694.  
  695.         if (ns) {
  696.                 kfree(ns);
  697.                 dvo->dev_priv = NULL;
  698.         }
  699. }
  700.  
  701. struct intel_dvo_dev_ops ns2501_ops = {
  702.         .init = ns2501_init,
  703.         .detect = ns2501_detect,
  704.         .mode_valid = ns2501_mode_valid,
  705.         .mode_set = ns2501_mode_set,
  706.         .dpms = ns2501_dpms,
  707.         .get_hw_state = ns2501_get_hw_state,
  708.         .destroy = ns2501_destroy,
  709. };
  710.