Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2003 NVIDIA, Corporation
0003  * Copyright 2006 Dave Airlie
0004  * Copyright 2007 Maarten Maathuis
0005  * Copyright 2007-2009 Stuart Bennett
0006  *
0007  * Permission is hereby granted, free of charge, to any person obtaining a
0008  * copy of this software and associated documentation files (the "Software"),
0009  * to deal in the Software without restriction, including without limitation
0010  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0011  * and/or sell copies of the Software, and to permit persons to whom the
0012  * Software is furnished to do so, subject to the following conditions:
0013  *
0014  * The above copyright notice and this permission notice (including the next
0015  * paragraph) shall be included in all copies or substantial portions of the
0016  * Software.
0017  *
0018  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0019  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0020  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0021  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0022  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
0023  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
0024  * DEALINGS IN THE SOFTWARE.
0025  */
0026 
0027 #include <drm/drm_crtc_helper.h>
0028 
0029 #include "nouveau_drv.h"
0030 #include "nouveau_encoder.h"
0031 #include "nouveau_connector.h"
0032 #include "nouveau_crtc.h"
0033 #include "hw.h"
0034 #include "nvreg.h"
0035 
0036 #include <subdev/bios/gpio.h>
0037 #include <subdev/gpio.h>
0038 
0039 #include <nvif/timer.h>
0040 
0041 int nv04_dac_output_offset(struct drm_encoder *encoder)
0042 {
0043     struct dcb_output *dcb = nouveau_encoder(encoder)->dcb;
0044     int offset = 0;
0045 
0046     if (dcb->or & (8 | DCB_OUTPUT_C))
0047         offset += 0x68;
0048     if (dcb->or & (8 | DCB_OUTPUT_B))
0049         offset += 0x2000;
0050 
0051     return offset;
0052 }
0053 
0054 /*
0055  * arbitrary limit to number of sense oscillations tolerated in one sample
0056  * period (observed to be at least 13 in "nvidia")
0057  */
0058 #define MAX_HBLANK_OSC 20
0059 
0060 /*
0061  * arbitrary limit to number of conflicting sample pairs to tolerate at a
0062  * voltage step (observed to be at least 5 in "nvidia")
0063  */
0064 #define MAX_SAMPLE_PAIRS 10
0065 
0066 static int sample_load_twice(struct drm_device *dev, bool sense[2])
0067 {
0068     struct nouveau_drm *drm = nouveau_drm(dev);
0069     struct nvif_object *device = &drm->client.device.object;
0070     int i;
0071 
0072     for (i = 0; i < 2; i++) {
0073         bool sense_a, sense_b, sense_b_prime;
0074         int j = 0;
0075 
0076         /*
0077          * wait for bit 0 clear -- out of hblank -- (say reg value 0x4),
0078          * then wait for transition 0x4->0x5->0x4: enter hblank, leave
0079          * hblank again
0080          * use a 10ms timeout (guards against crtc being inactive, in
0081          * which case blank state would never change)
0082          */
0083         if (nvif_msec(&drm->client.device, 10,
0084             if (!(nvif_rd32(device, NV_PRMCIO_INP0__COLOR) & 1))
0085                 break;
0086         ) < 0)
0087             return -EBUSY;
0088 
0089         if (nvif_msec(&drm->client.device, 10,
0090             if ( (nvif_rd32(device, NV_PRMCIO_INP0__COLOR) & 1))
0091                 break;
0092         ) < 0)
0093             return -EBUSY;
0094 
0095         if (nvif_msec(&drm->client.device, 10,
0096             if (!(nvif_rd32(device, NV_PRMCIO_INP0__COLOR) & 1))
0097                 break;
0098         ) < 0)
0099             return -EBUSY;
0100 
0101         udelay(100);
0102         /* when level triggers, sense is _LO_ */
0103         sense_a = nvif_rd08(device, NV_PRMCIO_INP0) & 0x10;
0104 
0105         /* take another reading until it agrees with sense_a... */
0106         do {
0107             udelay(100);
0108             sense_b = nvif_rd08(device, NV_PRMCIO_INP0) & 0x10;
0109             if (sense_a != sense_b) {
0110                 sense_b_prime =
0111                     nvif_rd08(device, NV_PRMCIO_INP0) & 0x10;
0112                 if (sense_b == sense_b_prime) {
0113                     /* ... unless two consecutive subsequent
0114                      * samples agree; sense_a is replaced */
0115                     sense_a = sense_b;
0116                     /* force mis-match so we loop */
0117                     sense_b = !sense_a;
0118                 }
0119             }
0120         } while ((sense_a != sense_b) && ++j < MAX_HBLANK_OSC);
0121 
0122         if (j == MAX_HBLANK_OSC)
0123             /* with so much oscillation, default to sense:LO */
0124             sense[i] = false;
0125         else
0126             sense[i] = sense_a;
0127     }
0128 
0129     return 0;
0130 }
0131 
0132 static enum drm_connector_status nv04_dac_detect(struct drm_encoder *encoder,
0133                          struct drm_connector *connector)
0134 {
0135     struct drm_device *dev = encoder->dev;
0136     struct nvif_object *device = &nouveau_drm(dev)->client.device.object;
0137     struct nouveau_drm *drm = nouveau_drm(dev);
0138     uint8_t saved_seq1, saved_pi, saved_rpc1, saved_cr_mode;
0139     uint8_t saved_palette0[3], saved_palette_mask;
0140     uint32_t saved_rtest_ctrl, saved_rgen_ctrl;
0141     int i;
0142     uint8_t blue;
0143     bool sense = true;
0144 
0145     /*
0146      * for this detection to work, there needs to be a mode set up on the
0147      * CRTC.  this is presumed to be the case
0148      */
0149 
0150     if (nv_two_heads(dev))
0151         /* only implemented for head A for now */
0152         NVSetOwner(dev, 0);
0153 
0154     saved_cr_mode = NVReadVgaCrtc(dev, 0, NV_CIO_CR_MODE_INDEX);
0155     NVWriteVgaCrtc(dev, 0, NV_CIO_CR_MODE_INDEX, saved_cr_mode | 0x80);
0156 
0157     saved_seq1 = NVReadVgaSeq(dev, 0, NV_VIO_SR_CLOCK_INDEX);
0158     NVWriteVgaSeq(dev, 0, NV_VIO_SR_CLOCK_INDEX, saved_seq1 & ~0x20);
0159 
0160     saved_rtest_ctrl = NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL);
0161     NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL,
0162               saved_rtest_ctrl & ~NV_PRAMDAC_TEST_CONTROL_PWRDWN_DAC_OFF);
0163 
0164     msleep(10);
0165 
0166     saved_pi = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_PIXEL_INDEX);
0167     NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_PIXEL_INDEX,
0168                saved_pi & ~(0x80 | MASK(NV_CIO_CRE_PIXEL_FORMAT)));
0169     saved_rpc1 = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_RPC1_INDEX);
0170     NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_RPC1_INDEX, saved_rpc1 & ~0xc0);
0171 
0172     nvif_wr08(device, NV_PRMDIO_READ_MODE_ADDRESS, 0x0);
0173     for (i = 0; i < 3; i++)
0174         saved_palette0[i] = nvif_rd08(device, NV_PRMDIO_PALETTE_DATA);
0175     saved_palette_mask = nvif_rd08(device, NV_PRMDIO_PIXEL_MASK);
0176     nvif_wr08(device, NV_PRMDIO_PIXEL_MASK, 0);
0177 
0178     saved_rgen_ctrl = NVReadRAMDAC(dev, 0, NV_PRAMDAC_GENERAL_CONTROL);
0179     NVWriteRAMDAC(dev, 0, NV_PRAMDAC_GENERAL_CONTROL,
0180               (saved_rgen_ctrl & ~(NV_PRAMDAC_GENERAL_CONTROL_BPC_8BITS |
0181                        NV_PRAMDAC_GENERAL_CONTROL_TERMINATION_75OHM)) |
0182               NV_PRAMDAC_GENERAL_CONTROL_PIXMIX_ON);
0183 
0184     blue = 8;   /* start of test range */
0185 
0186     do {
0187         bool sense_pair[2];
0188 
0189         nvif_wr08(device, NV_PRMDIO_WRITE_MODE_ADDRESS, 0);
0190         nvif_wr08(device, NV_PRMDIO_PALETTE_DATA, 0);
0191         nvif_wr08(device, NV_PRMDIO_PALETTE_DATA, 0);
0192         /* testing blue won't find monochrome monitors.  I don't care */
0193         nvif_wr08(device, NV_PRMDIO_PALETTE_DATA, blue);
0194 
0195         i = 0;
0196         /* take sample pairs until both samples in the pair agree */
0197         do {
0198             if (sample_load_twice(dev, sense_pair))
0199                 goto out;
0200         } while ((sense_pair[0] != sense_pair[1]) &&
0201                             ++i < MAX_SAMPLE_PAIRS);
0202 
0203         if (i == MAX_SAMPLE_PAIRS)
0204             /* too much oscillation defaults to LO */
0205             sense = false;
0206         else
0207             sense = sense_pair[0];
0208 
0209     /*
0210      * if sense goes LO before blue ramps to 0x18, monitor is not connected.
0211      * ergo, if blue gets to 0x18, monitor must be connected
0212      */
0213     } while (++blue < 0x18 && sense);
0214 
0215 out:
0216     nvif_wr08(device, NV_PRMDIO_PIXEL_MASK, saved_palette_mask);
0217     NVWriteRAMDAC(dev, 0, NV_PRAMDAC_GENERAL_CONTROL, saved_rgen_ctrl);
0218     nvif_wr08(device, NV_PRMDIO_WRITE_MODE_ADDRESS, 0);
0219     for (i = 0; i < 3; i++)
0220         nvif_wr08(device, NV_PRMDIO_PALETTE_DATA, saved_palette0[i]);
0221     NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL, saved_rtest_ctrl);
0222     NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_PIXEL_INDEX, saved_pi);
0223     NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_RPC1_INDEX, saved_rpc1);
0224     NVWriteVgaSeq(dev, 0, NV_VIO_SR_CLOCK_INDEX, saved_seq1);
0225     NVWriteVgaCrtc(dev, 0, NV_CIO_CR_MODE_INDEX, saved_cr_mode);
0226 
0227     if (blue == 0x18) {
0228         NV_DEBUG(drm, "Load detected on head A\n");
0229         return connector_status_connected;
0230     }
0231 
0232     return connector_status_disconnected;
0233 }
0234 
0235 uint32_t nv17_dac_sample_load(struct drm_encoder *encoder)
0236 {
0237     struct drm_device *dev = encoder->dev;
0238     struct nouveau_drm *drm = nouveau_drm(dev);
0239     struct nvif_object *device = &nouveau_drm(dev)->client.device.object;
0240     struct nvkm_gpio *gpio = nvxx_gpio(&drm->client.device);
0241     struct dcb_output *dcb = nouveau_encoder(encoder)->dcb;
0242     uint32_t sample, testval, regoffset = nv04_dac_output_offset(encoder);
0243     uint32_t saved_powerctrl_2 = 0, saved_powerctrl_4 = 0, saved_routput,
0244         saved_rtest_ctrl, saved_gpio0 = 0, saved_gpio1 = 0, temp, routput;
0245     int head;
0246 
0247 #define RGB_TEST_DATA(r, g, b) (r << 0 | g << 10 | b << 20)
0248     if (dcb->type == DCB_OUTPUT_TV) {
0249         testval = RGB_TEST_DATA(0xa0, 0xa0, 0xa0);
0250 
0251         if (drm->vbios.tvdactestval)
0252             testval = drm->vbios.tvdactestval;
0253     } else {
0254         testval = RGB_TEST_DATA(0x140, 0x140, 0x140); /* 0x94050140 */
0255 
0256         if (drm->vbios.dactestval)
0257             testval = drm->vbios.dactestval;
0258     }
0259 
0260     saved_rtest_ctrl = NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset);
0261     NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset,
0262               saved_rtest_ctrl & ~NV_PRAMDAC_TEST_CONTROL_PWRDWN_DAC_OFF);
0263 
0264     saved_powerctrl_2 = nvif_rd32(device, NV_PBUS_POWERCTRL_2);
0265 
0266     nvif_wr32(device, NV_PBUS_POWERCTRL_2, saved_powerctrl_2 & 0xd7ffffff);
0267     if (regoffset == 0x68) {
0268         saved_powerctrl_4 = nvif_rd32(device, NV_PBUS_POWERCTRL_4);
0269         nvif_wr32(device, NV_PBUS_POWERCTRL_4, saved_powerctrl_4 & 0xffffffcf);
0270     }
0271 
0272     if (gpio) {
0273         saved_gpio1 = nvkm_gpio_get(gpio, 0, DCB_GPIO_TVDAC1, 0xff);
0274         saved_gpio0 = nvkm_gpio_get(gpio, 0, DCB_GPIO_TVDAC0, 0xff);
0275         nvkm_gpio_set(gpio, 0, DCB_GPIO_TVDAC1, 0xff, dcb->type == DCB_OUTPUT_TV);
0276         nvkm_gpio_set(gpio, 0, DCB_GPIO_TVDAC0, 0xff, dcb->type == DCB_OUTPUT_TV);
0277     }
0278 
0279     msleep(4);
0280 
0281     saved_routput = NVReadRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset);
0282     head = (saved_routput & 0x100) >> 8;
0283 
0284     /* if there's a spare crtc, using it will minimise flicker */
0285     if (!(NVReadVgaCrtc(dev, head, NV_CIO_CRE_RPC1_INDEX) & 0xC0))
0286         head ^= 1;
0287 
0288     /* nv driver and nv31 use 0xfffffeee, nv34 and 6600 use 0xfffffece */
0289     routput = (saved_routput & 0xfffffece) | head << 8;
0290 
0291     if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_CURIE) {
0292         if (dcb->type == DCB_OUTPUT_TV)
0293             routput |= 0x1a << 16;
0294         else
0295             routput &= ~(0x1a << 16);
0296     }
0297 
0298     NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset, routput);
0299     msleep(1);
0300 
0301     temp = NVReadRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset);
0302     NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset, temp | 1);
0303 
0304     NVWriteRAMDAC(dev, head, NV_PRAMDAC_TESTPOINT_DATA,
0305               NV_PRAMDAC_TESTPOINT_DATA_NOTBLANK | testval);
0306     temp = NVReadRAMDAC(dev, head, NV_PRAMDAC_TEST_CONTROL);
0307     NVWriteRAMDAC(dev, head, NV_PRAMDAC_TEST_CONTROL,
0308               temp | NV_PRAMDAC_TEST_CONTROL_TP_INS_EN_ASSERTED);
0309     msleep(5);
0310 
0311     sample = NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset);
0312     /* do it again just in case it's a residual current */
0313     sample &= NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset);
0314 
0315     temp = NVReadRAMDAC(dev, head, NV_PRAMDAC_TEST_CONTROL);
0316     NVWriteRAMDAC(dev, head, NV_PRAMDAC_TEST_CONTROL,
0317               temp & ~NV_PRAMDAC_TEST_CONTROL_TP_INS_EN_ASSERTED);
0318     NVWriteRAMDAC(dev, head, NV_PRAMDAC_TESTPOINT_DATA, 0);
0319 
0320     /* bios does something more complex for restoring, but I think this is good enough */
0321     NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset, saved_routput);
0322     NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset, saved_rtest_ctrl);
0323     if (regoffset == 0x68)
0324         nvif_wr32(device, NV_PBUS_POWERCTRL_4, saved_powerctrl_4);
0325     nvif_wr32(device, NV_PBUS_POWERCTRL_2, saved_powerctrl_2);
0326 
0327     if (gpio) {
0328         nvkm_gpio_set(gpio, 0, DCB_GPIO_TVDAC1, 0xff, saved_gpio1);
0329         nvkm_gpio_set(gpio, 0, DCB_GPIO_TVDAC0, 0xff, saved_gpio0);
0330     }
0331 
0332     return sample;
0333 }
0334 
0335 static enum drm_connector_status
0336 nv17_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
0337 {
0338     struct nouveau_drm *drm = nouveau_drm(encoder->dev);
0339     struct dcb_output *dcb = nouveau_encoder(encoder)->dcb;
0340 
0341     if (nv04_dac_in_use(encoder))
0342         return connector_status_disconnected;
0343 
0344     if (nv17_dac_sample_load(encoder) &
0345         NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI) {
0346         NV_DEBUG(drm, "Load detected on output %c\n",
0347              '@' + ffs(dcb->or));
0348         return connector_status_connected;
0349     } else {
0350         return connector_status_disconnected;
0351     }
0352 }
0353 
0354 static bool nv04_dac_mode_fixup(struct drm_encoder *encoder,
0355                 const struct drm_display_mode *mode,
0356                 struct drm_display_mode *adjusted_mode)
0357 {
0358     if (nv04_dac_in_use(encoder))
0359         return false;
0360 
0361     return true;
0362 }
0363 
0364 static void nv04_dac_prepare(struct drm_encoder *encoder)
0365 {
0366     const struct drm_encoder_helper_funcs *helper = encoder->helper_private;
0367     struct drm_device *dev = encoder->dev;
0368     int head = nouveau_crtc(encoder->crtc)->index;
0369 
0370     helper->dpms(encoder, DRM_MODE_DPMS_OFF);
0371 
0372     nv04_dfp_disable(dev, head);
0373 }
0374 
0375 static void nv04_dac_mode_set(struct drm_encoder *encoder,
0376                   struct drm_display_mode *mode,
0377                   struct drm_display_mode *adjusted_mode)
0378 {
0379     struct drm_device *dev = encoder->dev;
0380     struct nouveau_drm *drm = nouveau_drm(dev);
0381     int head = nouveau_crtc(encoder->crtc)->index;
0382 
0383     if (nv_gf4_disp_arch(dev)) {
0384         struct drm_encoder *rebind;
0385         uint32_t dac_offset = nv04_dac_output_offset(encoder);
0386         uint32_t otherdac;
0387 
0388         /* bit 16-19 are bits that are set on some G70 cards,
0389          * but don't seem to have much effect */
0390         NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + dac_offset,
0391                   head << 8 | NV_PRAMDAC_DACCLK_SEL_DACCLK);
0392         /* force any other vga encoders to bind to the other crtc */
0393         list_for_each_entry(rebind, &dev->mode_config.encoder_list, head) {
0394             if (rebind == encoder
0395                 || nouveau_encoder(rebind)->dcb->type != DCB_OUTPUT_ANALOG)
0396                 continue;
0397 
0398             dac_offset = nv04_dac_output_offset(rebind);
0399             otherdac = NVReadRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + dac_offset);
0400             NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + dac_offset,
0401                       (otherdac & ~0x0100) | (head ^ 1) << 8);
0402         }
0403     }
0404 
0405     /* This could use refinement for flatpanels, but it should work this way */
0406     if (drm->client.device.info.chipset < 0x44)
0407         NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0xf0000000);
0408     else
0409         NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0x00100000);
0410 }
0411 
0412 static void nv04_dac_commit(struct drm_encoder *encoder)
0413 {
0414     struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
0415     struct nouveau_drm *drm = nouveau_drm(encoder->dev);
0416     struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
0417     const struct drm_encoder_helper_funcs *helper = encoder->helper_private;
0418 
0419     helper->dpms(encoder, DRM_MODE_DPMS_ON);
0420 
0421     NV_DEBUG(drm, "Output %s is running on CRTC %d using output %c\n",
0422          nv04_encoder_get_connector(nv_encoder)->base.name,
0423          nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));
0424 }
0425 
0426 void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable)
0427 {
0428     struct drm_device *dev = encoder->dev;
0429     struct dcb_output *dcb = nouveau_encoder(encoder)->dcb;
0430 
0431     if (nv_gf4_disp_arch(dev)) {
0432         uint32_t *dac_users = &nv04_display(dev)->dac_users[ffs(dcb->or) - 1];
0433         int dacclk_off = NV_PRAMDAC_DACCLK + nv04_dac_output_offset(encoder);
0434         uint32_t dacclk = NVReadRAMDAC(dev, 0, dacclk_off);
0435 
0436         if (enable) {
0437             *dac_users |= 1 << dcb->index;
0438             NVWriteRAMDAC(dev, 0, dacclk_off, dacclk | NV_PRAMDAC_DACCLK_SEL_DACCLK);
0439 
0440         } else {
0441             *dac_users &= ~(1 << dcb->index);
0442             if (!*dac_users)
0443                 NVWriteRAMDAC(dev, 0, dacclk_off,
0444                     dacclk & ~NV_PRAMDAC_DACCLK_SEL_DACCLK);
0445         }
0446     }
0447 }
0448 
0449 /* Check if the DAC corresponding to 'encoder' is being used by
0450  * someone else. */
0451 bool nv04_dac_in_use(struct drm_encoder *encoder)
0452 {
0453     struct drm_device *dev = encoder->dev;
0454     struct dcb_output *dcb = nouveau_encoder(encoder)->dcb;
0455 
0456     return nv_gf4_disp_arch(encoder->dev) &&
0457         (nv04_display(dev)->dac_users[ffs(dcb->or) - 1] & ~(1 << dcb->index));
0458 }
0459 
0460 static void nv04_dac_dpms(struct drm_encoder *encoder, int mode)
0461 {
0462     struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
0463     struct nouveau_drm *drm = nouveau_drm(encoder->dev);
0464 
0465     if (nv_encoder->last_dpms == mode)
0466         return;
0467     nv_encoder->last_dpms = mode;
0468 
0469     NV_DEBUG(drm, "Setting dpms mode %d on vga encoder (output %d)\n",
0470          mode, nv_encoder->dcb->index);
0471 
0472     nv04_dac_update_dacclk(encoder, mode == DRM_MODE_DPMS_ON);
0473 }
0474 
0475 static void nv04_dac_save(struct drm_encoder *encoder)
0476 {
0477     struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
0478     struct drm_device *dev = encoder->dev;
0479 
0480     if (nv_gf4_disp_arch(dev))
0481         nv_encoder->restore.output = NVReadRAMDAC(dev, 0, NV_PRAMDAC_DACCLK +
0482                               nv04_dac_output_offset(encoder));
0483 }
0484 
0485 static void nv04_dac_restore(struct drm_encoder *encoder)
0486 {
0487     struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
0488     struct drm_device *dev = encoder->dev;
0489 
0490     if (nv_gf4_disp_arch(dev))
0491         NVWriteRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + nv04_dac_output_offset(encoder),
0492                   nv_encoder->restore.output);
0493 
0494     nv_encoder->last_dpms = NV_DPMS_CLEARED;
0495 }
0496 
0497 static void nv04_dac_destroy(struct drm_encoder *encoder)
0498 {
0499     struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
0500 
0501     drm_encoder_cleanup(encoder);
0502     kfree(nv_encoder);
0503 }
0504 
0505 static const struct drm_encoder_helper_funcs nv04_dac_helper_funcs = {
0506     .dpms = nv04_dac_dpms,
0507     .mode_fixup = nv04_dac_mode_fixup,
0508     .prepare = nv04_dac_prepare,
0509     .commit = nv04_dac_commit,
0510     .mode_set = nv04_dac_mode_set,
0511     .detect = nv04_dac_detect
0512 };
0513 
0514 static const struct drm_encoder_helper_funcs nv17_dac_helper_funcs = {
0515     .dpms = nv04_dac_dpms,
0516     .mode_fixup = nv04_dac_mode_fixup,
0517     .prepare = nv04_dac_prepare,
0518     .commit = nv04_dac_commit,
0519     .mode_set = nv04_dac_mode_set,
0520     .detect = nv17_dac_detect
0521 };
0522 
0523 static const struct drm_encoder_funcs nv04_dac_funcs = {
0524     .destroy = nv04_dac_destroy,
0525 };
0526 
0527 int
0528 nv04_dac_create(struct drm_connector *connector, struct dcb_output *entry)
0529 {
0530     const struct drm_encoder_helper_funcs *helper;
0531     struct nouveau_encoder *nv_encoder = NULL;
0532     struct drm_device *dev = connector->dev;
0533     struct drm_encoder *encoder;
0534 
0535     nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
0536     if (!nv_encoder)
0537         return -ENOMEM;
0538 
0539     encoder = to_drm_encoder(nv_encoder);
0540 
0541     nv_encoder->dcb = entry;
0542     nv_encoder->or = ffs(entry->or) - 1;
0543 
0544     nv_encoder->enc_save = nv04_dac_save;
0545     nv_encoder->enc_restore = nv04_dac_restore;
0546 
0547     if (nv_gf4_disp_arch(dev))
0548         helper = &nv17_dac_helper_funcs;
0549     else
0550         helper = &nv04_dac_helper_funcs;
0551 
0552     drm_encoder_init(dev, encoder, &nv04_dac_funcs, DRM_MODE_ENCODER_DAC,
0553              NULL);
0554     drm_encoder_helper_add(encoder, helper);
0555 
0556     encoder->possible_crtcs = entry->heads;
0557     encoder->possible_clones = 0;
0558 
0559     drm_connector_attach_encoder(connector, encoder);
0560     return 0;
0561 }