Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright 2007, 2008  Luc Verhaegen <lverhaegen@novell.com>
  3.  * Copyright 2007, 2008  Matthias Hopf <mhopf@novell.com>
  4.  * Copyright 2007, 2008  Egbert Eich   <eich@novell.com>
  5.  * Copyright 2007, 2008  Advanced Micro Devices, Inc.
  6.  *
  7.  * Permission is hereby granted, free of charge, to any person obtaining a
  8.  * copy of this software and associated documentation files (the "Software"),
  9.  * to deal in the Software without restriction, including without limitation
  10.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  11.  * and/or sell copies of the Software, and to permit persons to whom the
  12.  * Software is furnished to do so, subject to the following conditions:
  13.  *
  14.  * The above copyright notice and this permission notice shall be included in
  15.  * all copies or substantial portions of the Software.
  16.  *
  17.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  20.  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  21.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  22.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  23.  * OTHER DEALINGS IN THE SOFTWARE.
  24.  */
  25.  
  26. #ifdef HAVE_CONFIG_H
  27. #include "config.h"
  28. #endif
  29.  
  30. #include "xf86.h"
  31.  
  32. /* for usleep */
  33. #if HAVE_XF86_ANSIC_H
  34. # include "xf86_ansic.h"
  35. #else
  36. # include <unistd.h>
  37. # include <string.h>
  38. # include <stdio.h>
  39. #endif
  40.  
  41. #include "rhd.h"
  42. #include "rhd_connector.h"
  43. #include "rhd_output.h"
  44. #include "rhd_crtc.h"
  45. #include "rhd_regs.h"
  46. #ifdef ATOM_BIOS
  47. # include "rhd_atombios.h"
  48. #endif
  49.  
  50. #define REG_DACA_OFFSET 0
  51. #define RV620_REG_DACA_OFFSET 0
  52. #define REG_DACB_OFFSET 0x200
  53. #define RV620_REG_DACB_OFFSET 0x100
  54.  
  55. struct rhdDACPrivate {
  56.     Bool Stored;
  57.  
  58.     CARD32 Store_Powerdown;
  59.     CARD32 Store_Force_Output_Control;
  60.     CARD32 Store_Force_Data;
  61.     CARD32 Store_Source_Select;
  62.     CARD32 Store_Sync_Select;
  63.     CARD32 Store_Enable;
  64.     CARD32 Store_Control1;
  65.     CARD32 Store_Control2;
  66.     CARD32 Store_Tristate_Control;
  67.     CARD32 Store_Auto_Calib_Control;
  68.     CARD32 Store_Dac_Bgadj_Src;
  69. };
  70.  
  71. /* ----------------------------------------------------------- */
  72.  
  73. /*
  74.  *
  75.  */
  76. static unsigned char
  77. DACSense(struct rhdOutput *Output, CARD32 offset, Bool TV)
  78. {
  79.   CARD32 CompEnable, Control1, Control2, DetectControl, Enable;
  80.   CARD8 ret;
  81.  
  82.     CompEnable = RHDRegRead(Output, offset + DACA_COMPARATOR_ENABLE);
  83.     Control1 = RHDRegRead(Output, offset + DACA_CONTROL1);
  84.     Control2 = RHDRegRead(Output, offset + DACA_CONTROL2);
  85.     DetectControl = RHDRegRead(Output, offset + DACA_AUTODETECT_CONTROL);
  86.     Enable = RHDRegRead(Output, offset + DACA_ENABLE);
  87.  
  88.     RHDRegWrite(Output, offset + DACA_ENABLE, 1);
  89.     /* ack autodetect */
  90.     RHDRegMask(Output, offset + DACA_AUTODETECT_INT_CONTROL, 0x01, 0x01);
  91.     RHDRegMask(Output, offset + DACA_AUTODETECT_CONTROL, 0, 0x00000003);
  92.     RHDRegMask(Output, offset + DACA_CONTROL2, 0, 0x00000001);
  93.     RHDRegMask(Output, offset + DACA_CONTROL2, 0, 0x00ff0000);
  94.  
  95.     if (offset) { /* We can do TV on DACA but only DACB has mux for separate connector */
  96.   if (TV)
  97.         RHDRegMask(Output, offset + DACA_CONTROL2, 0x00000100, 0x00000100);
  98.   else
  99.         RHDRegMask(Output, offset + DACA_CONTROL2, 0, 0x00000100);
  100.     }
  101.     RHDRegWrite(Output, offset + DACA_FORCE_DATA, 0);
  102.     RHDRegMask(Output, offset + DACA_CONTROL2, 0x00000001, 0x0000001);
  103.  
  104.     RHDRegMask(Output, offset + DACA_COMPARATOR_ENABLE, 0x00070000, 0x00070101);
  105.     RHDRegWrite(Output, offset + DACA_CONTROL1, 0x00050802);
  106.     RHDRegMask(Output, offset + DACA_POWERDOWN, 0, 0x00000001); /* Shut down Bandgap Voltage Reference Power */
  107.   usleep(5);
  108.  
  109.     RHDRegMask(Output, offset + DACA_POWERDOWN, 0, 0x01010100); /* Shut down RGB */
  110.  
  111.     RHDRegWrite(Output, offset + DACA_FORCE_DATA, 0x1e6); /* 486 out of 1024 */
  112.     usleep(200);
  113.  
  114.     RHDRegMask(Output, offset + DACA_POWERDOWN, 0x01010100, 0x01010100); /* Enable RGB */
  115.     usleep(88);
  116.  
  117.     RHDRegMask(Output, offset + DACA_POWERDOWN, 0, 0x01010100); /* Shut down RGB */
  118.  
  119.     RHDRegMask(Output, offset + DACA_COMPARATOR_ENABLE, 0x00000100, 0x00000100);
  120.   usleep(100);
  121.  
  122.   /* Get RGB detect values
  123.    * If only G is detected, we could have a monochrome monitor,
  124.    * but we don't bother with this at the moment.
  125.    */
  126.     ret = (RHDRegRead(Output, offset + DACA_COMPARATOR_OUTPUT) & 0x0E) >> 1;
  127.  
  128.     RHDRegMask(Output, offset + DACA_COMPARATOR_ENABLE, CompEnable, 0x00FFFFFF);
  129.     RHDRegWrite(Output, offset + DACA_CONTROL1, Control1);
  130.     RHDRegMask(Output, offset + DACA_CONTROL2, Control2, 0x000001FF);
  131.     RHDRegMask(Output, offset + DACA_AUTODETECT_CONTROL, DetectControl, 0x000000FF);
  132.     RHDRegMask(Output, offset + DACA_ENABLE, Enable, 0x000000FF);
  133.  
  134.     RHDDebug(Output->scrnIndex, "%s: DAC: 0x0%1X\n", __func__, ret);
  135.  
  136.   return ret;
  137. }
  138.  
  139. /*
  140.  *
  141.  */
  142. static enum rhdSensedOutput
  143. DACASense(struct rhdOutput *Output, struct rhdConnector *Connector)
  144. {
  145.     enum rhdConnectorType Type = Connector->Type;
  146.   RHDFUNC(Output);
  147.  
  148.     switch (Type) {
  149.     case RHD_CONNECTOR_DVI:
  150.     case RHD_CONNECTOR_DVI_SINGLE:
  151.     case RHD_CONNECTOR_VGA:
  152.         return  (DACSense(Output, REG_DACA_OFFSET, FALSE) == 0x7)
  153.             ? RHD_SENSED_VGA
  154.             : RHD_SENSED_NONE;
  155.     default:
  156.         xf86DrvMsg(Output->scrnIndex, X_WARNING,
  157.                    "%s: connector type %d is not supported on DACA.\n",
  158.                    __func__, Type);
  159.         return RHD_SENSED_NONE;
  160.     }
  161. }
  162.  
  163. /*
  164.  *
  165.  */
  166. static enum rhdSensedOutput
  167. DACBSense(struct rhdOutput *Output, struct rhdConnector *Connector)
  168. {
  169.     enum rhdConnectorType Type = Connector->Type;
  170.     RHDFUNC(Output);
  171.  
  172.     switch (Type) {
  173.     case RHD_CONNECTOR_DVI:
  174.     case RHD_CONNECTOR_DVI_SINGLE:
  175.     case RHD_CONNECTOR_VGA:
  176.         return  (DACSense(Output, REG_DACB_OFFSET, FALSE) == 0x7)
  177.             ? RHD_SENSED_VGA
  178.             : RHD_SENSED_NONE;
  179.     case RHD_CONNECTOR_TV:
  180.         switch (DACSense(Output, REG_DACB_OFFSET, TRUE) & 0x7) {
  181.             case 0x7:
  182.                 return RHD_SENSED_TV_COMPONENT;
  183.             case 0x6:
  184.                 return RHD_SENSED_TV_SVIDEO;
  185.             case 0x1:
  186.                 return RHD_SENSED_TV_COMPOSITE;
  187.     default:
  188.                 return RHD_SENSED_NONE;
  189.         }
  190.     default:
  191.         xf86DrvMsg(Output->scrnIndex, X_WARNING,
  192.                    "%s: connector type %d is not supported on DACB.\n",
  193.                    __func__, Type);
  194.         return RHD_SENSED_NONE;
  195.     }
  196. }
  197.  
  198. enum outputType {
  199.     TvPAL = 0,
  200.     TvNTSC,
  201.     VGA,
  202.     TvCV,
  203.     typeLast = VGA
  204. };
  205.  
  206. /*
  207.  *
  208.  */
  209. static void
  210. DACGetElectrical(RHDPtr rhdPtr, enum outputType type, int dac, CARD8 *bandgap, CARD8 *whitefine)
  211. {
  212. #ifdef ATOM_BIOS
  213.     enum _AtomBiosRequestID bg = 0, wf = 0;
  214.     AtomBiosArgRec atomBiosArg;
  215. #endif
  216.     struct
  217.     {
  218.         CARD16 pciIdMin;
  219.         CARD16 pciIdMax;
  220.         CARD8 bandgap[2][4];
  221.         CARD8 whitefine[2][4];
  222.     } list[] = {
  223.         { 0x791E, 0x791F,
  224.           { { 0x07, 0x07, 0x07, 0x07 },
  225.             { 0x07, 0x07, 0x07, 0x07 } },
  226.           { { 0x09, 0x09, 0x04, 0x09 },
  227.             { 0x09, 0x09, 0x04, 0x09 } },
  228.         },
  229.         { 0x793F, 0x7942,
  230.           { { 0x09, 0x09, 0x09, 0x09 },
  231.             { 0x09, 0x09, 0x09, 0x09 } },
  232.           { { 0x0a, 0x0a, 0x08, 0x0a },
  233.             { 0x0a, 0x0a, 0x08, 0x0a } },
  234.         },
  235.         { 0x9500, 0x9519,
  236.           { { 0x00, 0x00, 0x00, 0x00 },
  237.             { 0x00, 0x00, 0x00, 0x00 } },
  238.           { { 0x00, 0x00, 0x20, 0x00 },
  239.             { 0x25, 0x25, 0x26, 0x26 } },
  240.         },
  241.         { 0, 0,
  242.           { { 0, 0, 0, 0 },
  243.             { 0, 0, 0, 0 } },
  244.           { { 0, 0, 0, 0 },
  245.             { 0, 0, 0, 0 } }
  246.         }
  247.     };
  248.  
  249.     *bandgap = *whitefine = 0;
  250.  
  251. #ifdef ATOM_BIOS
  252.     switch (type) {
  253.         case TvPAL:
  254.             bg = ATOM_DAC2_PAL_BG_ADJ;
  255.             wf = ATOM_DAC2_PAL_DAC_ADJ;
  256.             break;
  257.         case TvNTSC:
  258.             bg = ATOM_DAC2_NTSC_BG_ADJ;
  259.             wf = ATOM_DAC2_NTSC_DAC_ADJ;
  260.             break;
  261.         case TvCV:
  262.             bg = ATOM_DAC2_CV_BG_ADJ;
  263.             wf = ATOM_DAC2_CV_DAC_ADJ;
  264.             break;
  265.         case VGA:
  266.             switch (dac) {
  267.                 case 0:
  268.                     bg = ATOM_DAC1_BG_ADJ;
  269.                     wf = ATOM_DAC1_DAC_ADJ;
  270.                     break;
  271.                 default:
  272.                     bg = ATOM_DAC2_CRTC2_BG_ADJ;
  273.                     wf = ATOM_DAC2_CRTC2_DAC_ADJ;
  274.                     break;
  275.             }
  276.             break;
  277.     }
  278.     if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, bg, &atomBiosArg)
  279.         == ATOM_SUCCESS) {
  280.         *bandgap = atomBiosArg.val;
  281.         RHDDebug(rhdPtr->scrnIndex, "%s: BandGap found in CompassionateData.\n",__func__);
  282.     }
  283.     if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, wf, &atomBiosArg)
  284.         == ATOM_SUCCESS) {
  285.         *whitefine = atomBiosArg.val;
  286.         RHDDebug(rhdPtr->scrnIndex, "%s: WhiteFine found in CompassionateData.\n",__func__);
  287.     }
  288.     if (*whitefine == 0) {
  289.         CARD8 w_f = 0, b_g = 0;
  290.  
  291.         if (atomBiosArg.val = 0x18,
  292.             RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS,
  293.                                    ATOMBIOS_GET_CODE_DATA_TABLE,
  294.                                    &atomBiosArg) == ATOM_SUCCESS) {
  295.             struct AtomDacCodeTableData *data
  296.                 = (struct AtomDacCodeTableData *)atomBiosArg.CommandDataTable.loc;
  297.             if (atomBiosArg.CommandDataTable.size
  298.                 < (sizeof (struct AtomDacCodeTableData) >> (dac ? 0 : 1))) { /* IGPs only have 1 DAC -> table_size / 2 */
  299.                 xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR,
  300.                            "Code table data size: %i doesn't match expected size: %u\n",
  301.                            atomBiosArg.CommandDataTable.size,
  302.                            (unsigned int) sizeof (struct AtomDacCodeTableData));
  303.                 return;
  304.             }
  305.             RHDDebug(rhdPtr->scrnIndex, "%s: WhiteFine found in Code Table.\n",__func__);
  306.             switch (type) {
  307.                 case TvPAL:
  308.                     w_f = dac ? data->DAC2PALWhiteFine : data->DAC1PALWhiteFine;
  309.                     b_g = dac ? data->DAC2PALBandGap : data->DAC1PALBandGap;
  310.                     break;
  311.                 case TvNTSC:
  312.                     w_f = dac ? data->DAC2NTSCWhiteFine : data->DAC1NTSCWhiteFine;
  313.                     b_g = dac ? data->DAC2NTSCBandGap : data->DAC1NTSCBandGap;
  314.                     break;
  315.                 case TvCV:
  316.                     w_f = dac ? data->DAC2CVWhiteFine : data->DAC1CVWhiteFine;
  317.                     b_g = dac ? data->DAC2CVBandGap : data->DAC1CVBandGap;
  318.                     break;
  319.                 case VGA:
  320.                     w_f = dac ? data->DAC2VGAWhiteFine : data->DAC1VGAWhiteFine;
  321.                     b_g = dac ? data->DAC2VGABandGap : data->DAC1VGABandGap;
  322.                     break;
  323.             }
  324.             *whitefine = w_f;
  325.             if (rhdPtr->ChipSet >= RHD_RV770)  /* Dunno why this is broken on older ASICs */
  326.                 *bandgap = b_g;
  327.         }
  328.     }
  329. #endif
  330.     if (*bandgap == 0 || *whitefine == 0) {
  331.         int i = 0;
  332.         while (list[i].pciIdMin != 0) {
  333.             if (list[i].pciIdMin <= rhdPtr->PciDeviceID
  334.                 && list[i].pciIdMax >= rhdPtr->PciDeviceID) {
  335. #if 0
  336.                 ErrorF(">> %x %x %x -- %x %x\n",list[i].pciIdMin,
  337.                        rhdPtr->PciDeviceID,list[i].pciIdMax,
  338.                        list[i].bandgap[dac][type],list[i].whitefine[dac][type]);
  339.                 ErrorF(">> %i %i\n",dac,type);
  340. #endif
  341.                 if (*bandgap == 0) *bandgap = list[i].bandgap[dac][type];
  342.                 if (*whitefine == 0) *whitefine = list[i].whitefine[dac][type];
  343.                 break;
  344.             }
  345.             i++;
  346.         }
  347.         if (list[i].pciIdMin != 0)
  348.             RHDDebug(rhdPtr->scrnIndex, "%s: BandGap and WhiteFine found in Table.\n",__func__);
  349.     }
  350.     RHDDebug(rhdPtr->scrnIndex, "%s: DAC[%i] BandGap: 0x%2.2x WhiteFine: 0x%2.2x\n",
  351.              __func__, dac, *bandgap, *whitefine);
  352. }
  353.  
  354. /*
  355.  *
  356.  */
  357. static inline void
  358. DACSet(struct rhdOutput *Output, CARD16 offset)
  359. {
  360.     RHDPtr rhdPtr = RHDPTRI(Output);
  361.     CARD8 Standard, WhiteFine, Bandgap;
  362.     Bool TV;
  363.     CARD32 Mask = 0;
  364.  
  365.     switch (Output->SensedType) {
  366.     case RHD_SENSED_TV_SVIDEO:
  367.     case RHD_SENSED_TV_COMPOSITE:
  368.         /* might want to selectively enable lines based on type */
  369.         TV = TRUE;
  370.  
  371.     switch (rhdPtr->tvMode) {
  372.         case RHD_TV_NTSC:
  373.         case RHD_TV_NTSCJ:
  374.             DACGetElectrical(rhdPtr, TvNTSC, offset ? 1 : 0, &Bandgap, &WhiteFine);
  375.             Standard = 1; /* NTSC */
  376.             break;
  377.         case RHD_TV_PAL:
  378.         case RHD_TV_PALN:
  379.         case RHD_TV_PALCN:
  380.         case RHD_TV_PAL60:
  381.         default:
  382.             DACGetElectrical(rhdPtr, TvPAL, offset ? 1 : 0, &Bandgap, &WhiteFine);
  383.             Standard = 0; /* PAL */
  384.             break;
  385.     }
  386.         break;
  387.  
  388.         case RHD_SENSED_TV_COMPONENT:
  389.         TV = TRUE;
  390.             DACGetElectrical(rhdPtr, TvCV, offset ? 1 : 0, &Bandgap, &WhiteFine);
  391.         Standard = 3; /* HDTV */
  392.         break;
  393.  
  394.         case RHD_SENSED_VGA:
  395.         default:
  396.         TV = FALSE;
  397.             DACGetElectrical(rhdPtr, VGA, offset ? 1 : 0, &Bandgap, &WhiteFine);
  398.         Standard = 2; /* VGA */
  399.             break;
  400.     }
  401.     if (Bandgap) Mask |= 0xFF << 16;
  402.     if (WhiteFine) Mask |= 0xFF << 8;
  403.  
  404.     RHDRegMask(Output, offset + DACA_CONTROL1, Standard, 0x000000FF);
  405.     /* white level fine adjust */
  406.     RHDRegMask(Output, offset + DACA_CONTROL1, (Bandgap << 16) | (WhiteFine << 8), Mask);
  407.  
  408.     if (TV) {
  409.         /* tv enable */
  410.         if (offset) /* TV mux only available on DACB */
  411.             RHDRegMask(Output, offset + DACA_CONTROL2, 0x00000100, 0x0000FF00);
  412.         /* select tv encoder */
  413.         RHDRegMask(Output, offset + DACA_SOURCE_SELECT, 0x00000002, 0x00000003);
  414.     } else {
  415.         if (offset) /* TV mux only available on DACB */
  416.             RHDRegMask(Output, offset + DACA_CONTROL2, 0, 0x0000FF00);
  417.         /* select a crtc */
  418.         RHDRegMask(Output, offset + DACA_SOURCE_SELECT, Output->Crtc->Id & 0x01, 0x00000003);
  419.     }
  420.  
  421.     RHDRegMask(Output, offset + DACA_FORCE_OUTPUT_CNTL, 0x00000701, 0x00000701);
  422.     RHDRegMask(Output, offset + DACA_FORCE_DATA, 0, 0x0000FFFF);
  423. }
  424.  
  425. /*
  426.  *
  427.  */
  428. static void
  429. DACASet(struct rhdOutput *Output, DisplayModePtr unused)
  430. {
  431.     RHDFUNC(Output);
  432.  
  433.     DACSet(Output, REG_DACA_OFFSET);
  434. }
  435.  
  436. /*
  437.  *
  438.  */
  439. static void
  440. DACBSet(struct rhdOutput *Output, DisplayModePtr unused)
  441. {
  442.     RHDFUNC(Output);
  443.  
  444.     DACSet(Output, REG_DACB_OFFSET);
  445. }
  446.  
  447. /*
  448.  *
  449.  */
  450. static inline void
  451. DACPower(struct rhdOutput *Output, CARD16 offset, int Power)
  452. {
  453.     CARD32 powerdown;
  454.  
  455.     RHDDebug(Output->scrnIndex, "%s(%s,%s)\n",__func__,Output->Name,
  456.              rhdPowerString[Power]);
  457.  
  458.     switch (Power) {
  459.     case RHD_POWER_ON:
  460.         switch (Output->SensedType) {
  461.             case RHD_SENSED_TV_SVIDEO:
  462.                 powerdown = 0 /* 0x100 */;
  463.                 break;
  464.             case RHD_SENSED_TV_COMPOSITE:
  465.                 powerdown = 0 /* 0x1010000 */;
  466.                 break;
  467.             case RHD_SENSED_TV_COMPONENT:
  468.             powerdown = 0;
  469.                 break;
  470.             case RHD_SENSED_VGA:
  471.             default:
  472.                 powerdown = 0;
  473.                 break;
  474.         }
  475.         RHDRegWrite(Output, offset + DACA_ENABLE, 1);
  476.       RHDRegWrite(Output, offset + DACA_POWERDOWN, 0);
  477.         usleep (14);
  478.         RHDRegMask(Output,  offset + DACA_POWERDOWN, powerdown, 0xFFFFFF00);
  479.         usleep(2);
  480.         RHDRegWrite(Output, offset + DACA_FORCE_OUTPUT_CNTL, 0);
  481.         RHDRegMask(Output,  offset + DACA_SYNC_SELECT, 0, 0x00000101);
  482.         RHDRegWrite(Output, offset + DACA_SYNC_TRISTATE_CONTROL, 0);
  483.       return;
  484.     case RHD_POWER_RESET: /* don't bother */
  485.       return;
  486.     case RHD_POWER_SHUTDOWN:
  487.     default:
  488.         RHDRegMask(Output, offset + DACA_FORCE_DATA, 0, 0x0000FFFF);
  489.         RHDRegMask(Output, offset + DACA_FORCE_OUTPUT_CNTL, 0x0000701, 0x0000701);
  490.         RHDRegWrite(Output, offset + DACA_POWERDOWN, 0x01010100);
  491.       RHDRegWrite(Output, offset + DACA_POWERDOWN, 0x01010101);
  492.       RHDRegWrite(Output, offset + DACA_ENABLE, 0);
  493.         RHDRegWrite(Output, offset + DACA_ENABLE, 0);
  494.       return;
  495.   }
  496. }
  497.  
  498. /*
  499.  *
  500.  */
  501. static void
  502. DACAPower(struct rhdOutput *Output, int Power)
  503. {
  504.     RHDFUNC(Output);
  505.  
  506.     DACPower(Output, REG_DACA_OFFSET, Power);
  507. }
  508.  
  509. /*
  510.  *
  511.  */
  512. static void
  513. DACBPower(struct rhdOutput *Output, int Power)
  514. {
  515.     RHDFUNC(Output);
  516.  
  517.     DACPower(Output, REG_DACB_OFFSET, Power);
  518. }
  519.  
  520. /*
  521.  *
  522.  */
  523. static inline void
  524. DACSave(struct rhdOutput *Output, CARD16 offset)
  525. {
  526.     struct rhdDACPrivate *Private = (struct rhdDACPrivate *) Output->Private;
  527.  
  528.     Private->Store_Powerdown = RHDRegRead(Output, offset + DACA_POWERDOWN);
  529.     Private->Store_Force_Output_Control = RHDRegRead(Output, offset + DACA_FORCE_OUTPUT_CNTL);
  530.     Private->Store_Force_Data = RHDRegRead(Output, offset + DACA_FORCE_DATA);
  531.     Private->Store_Source_Select = RHDRegRead(Output, offset + DACA_SOURCE_SELECT);
  532.     Private->Store_Sync_Select = RHDRegRead(Output, offset + DACA_SYNC_SELECT);
  533.     Private->Store_Enable = RHDRegRead(Output, offset + DACA_ENABLE);
  534.     Private->Store_Control1 = RHDRegRead(Output, offset + DACA_CONTROL1);
  535.     Private->Store_Control2 = RHDRegRead(Output, offset + DACA_CONTROL2);
  536.     Private->Store_Tristate_Control = RHDRegRead(Output, offset + DACA_SYNC_TRISTATE_CONTROL);
  537.  
  538.     Private->Stored = TRUE;
  539. }
  540.  
  541. /*
  542.  *
  543.  */
  544. static void
  545. DACASave(struct rhdOutput *Output)
  546. {
  547.     RHDFUNC(Output);
  548.  
  549.     DACSave(Output, REG_DACA_OFFSET);
  550. }
  551.  
  552. /*
  553.  *
  554.  */
  555. static void
  556. DACBSave(struct rhdOutput *Output)
  557. {
  558.     RHDFUNC(Output);
  559.  
  560.     DACSave(Output, REG_DACB_OFFSET);
  561. }
  562.  
  563. /*
  564.  *
  565.  */
  566. static inline void
  567. DACRestore(struct rhdOutput *Output, CARD16 offset)
  568. {
  569.     struct rhdDACPrivate *Private = (struct rhdDACPrivate *) Output->Private;
  570.  
  571.     RHDRegWrite(Output, offset + DACA_POWERDOWN, Private->Store_Powerdown);
  572.     RHDRegWrite(Output, offset + DACA_FORCE_OUTPUT_CNTL, Private->Store_Force_Output_Control);
  573.     RHDRegWrite(Output, offset + DACA_FORCE_DATA, Private->Store_Force_Data);
  574.     RHDRegWrite(Output, offset + DACA_SOURCE_SELECT, Private->Store_Source_Select);
  575.     RHDRegWrite(Output, offset + DACA_SYNC_SELECT, Private->Store_Sync_Select);
  576.     RHDRegWrite(Output, offset + DACA_ENABLE, Private->Store_Enable);
  577.     RHDRegWrite(Output, offset + DACA_CONTROL1, Private->Store_Control1);
  578.     RHDRegWrite(Output, offset + DACA_CONTROL2, Private->Store_Control2);
  579.     RHDRegWrite(Output, offset + DACA_SYNC_TRISTATE_CONTROL, Private->Store_Tristate_Control);
  580. }
  581.  
  582. /*
  583.  *
  584.  */
  585. static void
  586. DACARestore(struct rhdOutput *Output)
  587. {
  588.   RHDFUNC(Output);
  589.  
  590.     if (!((struct rhdDACPrivate *) Output->Private)->Stored) {
  591.         xf86DrvMsg(Output->scrnIndex, X_ERROR,
  592.                    "%s: No registers stored.\n", __func__);
  593.     return;
  594.   }
  595.  
  596.   DACRestore(Output, REG_DACA_OFFSET);
  597. }
  598.  
  599. /*
  600.  *
  601.  */
  602. static void
  603. DACBRestore(struct rhdOutput *Output)
  604. {
  605.     RHDFUNC(Output);
  606.  
  607.     if (!((struct rhdDACPrivate *) Output->Private)->Stored) {
  608.         xf86DrvMsg(Output->scrnIndex, X_ERROR,
  609.                    "%s: No registers stored.\n", __func__);
  610.         return;
  611.     }
  612.  
  613.     DACRestore(Output, REG_DACB_OFFSET);
  614. }
  615.  
  616. /* ----------------------------------------------------------- */
  617.  
  618. /*
  619.  *
  620.  */
  621. static CARD32
  622. DACSenseRV620(struct rhdOutput *Output, CARD32 offset, Bool TV)
  623. {
  624.     CARD32 ret;
  625.     CARD32 DetectControl, AutodetectIntCtl, ForceData,
  626.         Control1, Control2, CompEnable;
  627.  
  628.     RHDFUNC(Output);
  629.  
  630.     Control1 = RHDRegRead(Output, offset + RV620_DACA_MACRO_CNTL); /* 7ef4 */
  631.     Control2 = RHDRegRead(Output, offset + RV620_DACA_CONTROL2); /* 7058 */
  632.     ForceData = RHDRegRead(Output, offset + RV620_DACA_FORCE_DATA);
  633.     AutodetectIntCtl = RHDRegRead(Output, offset + RV620_DACA_AUTODETECT_INT_CONTROL);
  634.     DetectControl = RHDRegRead(Output, offset + RV620_DACA_AUTODETECT_CONTROL);
  635.     CompEnable = RHDRegRead(Output, offset + RV620_DACA_COMPARATOR_ENABLE);
  636.  
  637.     if (offset) {  /* We can do TV on DACA but only DACB has mux for separate connector */
  638.     if (TV)
  639.         RHDRegMask(Output, offset + RV620_DACA_CONTROL2, 0x100, 0xff00);
  640.     else
  641.         RHDRegMask(Output, offset + RV620_DACA_CONTROL2, 0x00, 0xff00);
  642.     }
  643.     RHDRegMask(Output, offset + RV620_DACA_FORCE_DATA, 0x18, 0xffff);
  644.     RHDRegMask(Output, offset + RV620_DACA_AUTODETECT_INT_CONTROL, 0x01, 0x01);
  645.     RHDRegMask(Output, offset + RV620_DACA_AUTODETECT_CONTROL, 0x00, 0xff);
  646.     RHDRegMask(Output, offset + RV620_DACA_MACRO_CNTL,
  647.                (offset > 0) ? 0x2502 :  0x2002, 0xffff);
  648.     /* enable comparators for R/G/B, disable DDET and SDET reference */
  649.     RHDRegMask(Output, offset + RV620_DACA_COMPARATOR_ENABLE, 0x70000, 0x070101);
  650.     RHDRegMask(Output, offset + RV620_DACA_AUTODETECT_CONTROL, 0x01, 0xff);
  651.     usleep(32);
  652.     ret = RHDRegRead(Output, offset + RV620_DACA_AUTODETECT_STATUS);
  653.     RHDRegWrite(Output, offset + RV620_DACA_AUTODETECT_CONTROL, DetectControl);
  654.     RHDRegWrite(Output, offset + RV620_DACA_MACRO_CNTL, Control1);
  655.     RHDRegWrite(Output, offset + RV620_DACA_CONTROL2, Control2);
  656.     RHDRegWrite(Output, offset + RV620_DACA_FORCE_DATA, ForceData);
  657.     RHDRegWrite(Output, offset + RV620_DACA_AUTODETECT_INT_CONTROL, AutodetectIntCtl);
  658. #ifdef DEBUG
  659.     RHDDebug(Output->scrnIndex, "DAC%i: ret = 0x%x %s\n",offset ? "A" : "B",
  660.              ret,TV ? "TV" : "");
  661. #endif
  662.     return ret;
  663. }
  664.  
  665. /*
  666.  *
  667.  */
  668. static enum rhdSensedOutput
  669. DACASenseRV620(struct rhdOutput *Output, struct rhdConnector *Connector)
  670. {
  671.     enum rhdConnectorType Type = Connector->Type;
  672.     RHDFUNC(Output);
  673.  
  674.     switch (Type) {
  675.     case RHD_CONNECTOR_DVI:
  676.     case RHD_CONNECTOR_DVI_SINGLE:
  677.     case RHD_CONNECTOR_VGA:
  678.         return  (DACSenseRV620(Output, RV620_REG_DACA_OFFSET, FALSE)
  679.                   & 0x1010100) ? RHD_SENSED_VGA : RHD_SENSED_NONE;
  680.     case RHD_CONNECTOR_TV:
  681.         switch (DACSenseRV620(Output, RV620_REG_DACA_OFFSET, TRUE)
  682.                 & 0x1010100) {
  683.             case 0x1010100:
  684.                 return RHD_SENSED_NONE; /* on DAC A we cannot distinguish VGA and CV */
  685.             case 0x10100:
  686.                 return RHD_SENSED_TV_SVIDEO;
  687.             case 0x1000000:
  688.                 return RHD_SENSED_TV_COMPOSITE;
  689.             default:
  690.                 return RHD_SENSED_NONE;
  691.         }
  692.     default:
  693.         xf86DrvMsg(Output->scrnIndex, X_WARNING,
  694.                    "%s: connector type %d is not supported.\n",
  695.                    __func__, Type);
  696.         return RHD_SENSED_NONE;
  697.     }
  698. }
  699.  
  700. /*
  701.  *
  702.  */
  703. static enum rhdSensedOutput
  704. DACBSenseRV620(struct rhdOutput *Output, struct rhdConnector *Connector)
  705. {
  706.     enum rhdConnectorType Type = Connector->Type;
  707.     RHDFUNC(Output);
  708.  
  709.     switch (Type) {
  710.     case RHD_CONNECTOR_DVI:
  711.     case RHD_CONNECTOR_DVI_SINGLE:
  712.     case RHD_CONNECTOR_VGA:
  713.         return  (DACSenseRV620(Output, RV620_REG_DACB_OFFSET, FALSE)
  714.                   & 0x1010100) ? RHD_SENSED_VGA : RHD_SENSED_NONE;
  715.     case RHD_CONNECTOR_TV:
  716.         switch (DACSenseRV620(Output, RV620_REG_DACB_OFFSET, TRUE)
  717.                 & 0x1010100) {
  718.             case 0x1000000:
  719.                 return RHD_SENSED_TV_COMPONENT;
  720.             case 0x1010100:
  721.                 return RHD_SENSED_TV_SVIDEO;
  722.             case 0x10100:
  723.                 return RHD_SENSED_TV_COMPOSITE;
  724.             default:
  725.                 return RHD_SENSED_NONE;
  726.         }
  727.     default:
  728.         xf86DrvMsg(Output->scrnIndex, X_WARNING,
  729.                    "%s: connector type %d is not supported.\n",
  730.                    __func__, Type);
  731.         return RHD_SENSED_NONE;
  732.     }
  733. }
  734.  
  735. /*
  736.  *
  737.  */
  738. static inline void
  739. DACSetRV620(struct rhdOutput *Output, CARD16 offset)
  740. {
  741.     RHDPtr rhdPtr = RHDPTRI(Output);
  742.     CARD32 Source;
  743.     CARD32 Mode;
  744.     CARD32 TV;
  745.     CARD8 WhiteFine, Bandgap;
  746.     CARD32 Mask = 0;
  747.  
  748.     switch (Output->SensedType) {
  749.         case RHD_SENSED_TV_SVIDEO:
  750.         case RHD_SENSED_TV_COMPOSITE:
  751.             TV = 0x1;
  752.             Source = 0x2; /* tv encoder */
  753.     switch (rhdPtr->tvMode) {
  754.         case RHD_TV_NTSC:
  755.         case RHD_TV_NTSCJ:
  756.                     DACGetElectrical(rhdPtr, TvNTSC, offset ? 1 : 0, &Bandgap, &WhiteFine);
  757.                     Mode = 1;
  758.             break;
  759.         case RHD_TV_PAL:
  760.         case RHD_TV_PALN:
  761.         case RHD_TV_PALCN:
  762.         case RHD_TV_PAL60:
  763.         default:
  764.                     DACGetElectrical(rhdPtr, TvPAL, offset ? 1 : 0, &Bandgap, &WhiteFine);
  765.                     Mode = 0;
  766.             break;
  767.     }
  768.             break;
  769.         case RHD_SENSED_TV_COMPONENT:
  770.             DACGetElectrical(rhdPtr, TvCV, offset ? 1 : 0, &Bandgap, &WhiteFine);
  771.             Mode = 3; /* HDTV */
  772.             TV = 0x1; /* tv on?? */
  773.             Source = 0x2; /* tv encoder  ?? */
  774.             break;
  775.         case RHD_SENSED_VGA:
  776.         default:
  777.             DACGetElectrical(rhdPtr, VGA, offset ? 1 : 0, &Bandgap, &WhiteFine);
  778.             Mode = 2;
  779.             TV = 0;
  780.             Source = Output->Crtc->Id;
  781.             break;
  782.     }
  783.     if (Bandgap) Mask |= 0xFF << 16;
  784.     if (WhiteFine) Mask |= 0xFF << 8;
  785.  
  786.     RHDRegMask(Output, offset + RV620_DACA_MACRO_CNTL, Mode, 0xFF); /* no fine control yet */
  787.     RHDRegMask(Output,  offset + RV620_DACA_SOURCE_SELECT, Source, 0x00000003);
  788.     if (offset) /* TV mux only present on DACB */
  789.         RHDRegMask(Output,  offset + RV620_DACA_CONTROL2, TV << 8, 0x0100); /* tv enable/disable */
  790.     /* use fine control from white_fine control register */
  791.     RHDRegMask(Output, offset + RV620_DACA_AUTO_CALIB_CONTROL, 0x0, 0x4);
  792.     RHDRegMask(Output, offset + RV620_DACA_BGADJ_SRC, 0x0, 0x30);
  793.     RHDRegMask(Output, offset + RV620_DACA_MACRO_CNTL, (Bandgap << 16) | (WhiteFine << 8), Mask);
  794.     /* Reset the FMT register on CRTC leading to this output */
  795.     Output->Crtc->FMTModeSet(Output->Crtc, NULL);
  796. }
  797.  
  798. /*
  799.  *
  800.  */
  801. static void
  802. DACASetRV620(struct rhdOutput *Output, DisplayModePtr unused)
  803. {
  804.     RHDFUNC(Output);
  805.  
  806.     DACSetRV620(Output, RV620_REG_DACA_OFFSET);
  807. }
  808.  
  809. /*
  810.  *
  811.  */
  812. static void
  813. DACBSetRV620(struct rhdOutput *Output, DisplayModePtr unused)
  814. {
  815.     RHDFUNC(Output);
  816.  
  817.     DACSetRV620(Output, RV620_REG_DACB_OFFSET);
  818. }
  819.  
  820. /*
  821.  *
  822.  */
  823. static inline void
  824. DACPowerRV620(struct rhdOutput *Output, CARD16 offset, int Power)
  825. {
  826.     CARD32 powerdown;
  827.  
  828.     switch (Power) {
  829.         case RHD_POWER_ON:
  830.             switch (Output->SensedType) {
  831.                 case RHD_SENSED_TV_SVIDEO:
  832.                     powerdown = 0 /* 0x100 */;
  833.                     break;
  834.                 case RHD_SENSED_TV_COMPOSITE:
  835.                     powerdown = 0 /* 0x1010000 */;
  836.                     break;
  837.                 case RHD_SENSED_TV_COMPONENT:
  838.                     powerdown = 0;
  839.                     break;
  840.                 case RHD_SENSED_VGA:
  841.                 default:
  842.                     powerdown = 0;
  843.                     break;
  844.             }
  845.  
  846.             if (!(RHDRegRead(Output, offset + RV620_DACA_ENABLE) & 0x01))
  847.                 RHDRegMask(Output, offset + RV620_DACA_ENABLE, 0x1, 0xff);
  848.             RHDRegMask(Output,  offset + RV620_DACA_FORCE_OUTPUT_CNTL, 0x01, 0x01);
  849.             RHDRegMask(Output,  offset + RV620_DACA_POWERDOWN, 0x0, 0xff);
  850.             usleep (0x14);
  851.             RHDRegMask(Output,  offset + RV620_DACA_POWERDOWN, powerdown, 0xffffff00);
  852.             usleep(2);
  853.             RHDRegMask(Output,  offset + RV620_DACA_FORCE_DATA, 0, 0x0000ffff);
  854.             RHDRegWrite(Output, offset + RV620_DACA_FORCE_OUTPUT_CNTL, 0x0);
  855.             RHDRegWrite(Output, offset + RV620_DACA_SYNC_TRISTATE_CONTROL, 0);
  856.             return;
  857.         case RHD_POWER_RESET: /* don't bother */
  858.             return;
  859.         case RHD_POWER_SHUTDOWN:
  860.         default:
  861.             RHDRegWrite(Output, offset + RV620_DACA_POWERDOWN, 0x01010100);
  862.             RHDRegWrite(Output, offset + RV620_DACA_POWERDOWN, 0x01010101);
  863.             RHDRegWrite(Output, offset + RV620_DACA_ENABLE, 0);
  864.             RHDRegMask(Output, offset + RV620_DACA_FORCE_DATA, 0, 0xffff);
  865.             RHDRegMask(Output, offset + RV620_DACA_FORCE_OUTPUT_CNTL, 0x701, 0x701);
  866.             return;
  867.     }
  868. }
  869.  
  870. /*
  871.  *
  872.  */
  873. static void
  874. DACAPowerRV620(struct rhdOutput *Output, int Power)
  875. {
  876.     RHDFUNC(Output);
  877.  
  878.     DACPowerRV620(Output, RV620_REG_DACA_OFFSET, Power);
  879. }
  880.  
  881. /*
  882.  *
  883.  */
  884. static void
  885. DACBPowerRV620(struct rhdOutput *Output, int Power)
  886. {
  887.     RHDFUNC(Output);
  888.  
  889.     DACPowerRV620(Output, RV620_REG_DACB_OFFSET, Power);
  890. }
  891.  
  892. /*
  893.  *
  894.  */
  895. static inline void
  896. DACSaveRV620(struct rhdOutput *Output, CARD16 offset)
  897. {
  898.     struct rhdDACPrivate *Private = (struct rhdDACPrivate *) Output->Private;
  899.  
  900.     Private->Store_Powerdown = RHDRegRead(Output, offset + RV620_DACA_POWERDOWN);
  901.     Private->Store_Force_Output_Control = RHDRegRead(Output, offset + RV620_DACA_FORCE_OUTPUT_CNTL);
  902.     Private->Store_Force_Data = RHDRegRead(Output, offset + RV620_DACA_FORCE_DATA);
  903.     Private->Store_Source_Select = RHDRegRead(Output, offset + RV620_DACA_SOURCE_SELECT);
  904.     Private->Store_Enable = RHDRegRead(Output, offset + RV620_DACA_ENABLE);
  905.     Private->Store_Control1 = RHDRegRead(Output, offset + RV620_DACA_MACRO_CNTL);
  906.     Private->Store_Control2 = RHDRegRead(Output, offset + RV620_DACA_CONTROL2);
  907.     Private->Store_Tristate_Control = RHDRegRead(Output, offset + RV620_DACA_SYNC_TRISTATE_CONTROL);
  908.     Private->Store_Auto_Calib_Control = RHDRegRead(Output, offset + RV620_DACA_AUTO_CALIB_CONTROL);
  909.     Private->Store_Dac_Bgadj_Src = RHDRegRead(Output, offset + RV620_DACA_BGADJ_SRC);
  910.  
  911.     Private->Stored = TRUE;
  912. }
  913.  
  914. /*
  915.  *
  916.  */
  917. static void
  918. DACASaveRV620(struct rhdOutput *Output)
  919. {
  920.     RHDFUNC(Output);
  921.  
  922.     DACSaveRV620(Output, RV620_REG_DACA_OFFSET);
  923. }
  924.  
  925. /*
  926.  *
  927.  */
  928. static void
  929. DACBSaveRV620(struct rhdOutput *Output)
  930. {
  931.     RHDFUNC(Output);
  932.  
  933.     DACSaveRV620(Output, RV620_REG_DACB_OFFSET);
  934. }
  935.  
  936. /*
  937.  *
  938.  */
  939. static inline void
  940. DACRestoreRV620(struct rhdOutput *Output, CARD16 offset)
  941. {
  942.     struct rhdDACPrivate *Private = (struct rhdDACPrivate *) Output->Private;
  943.  
  944.     RHDRegWrite(Output, offset + RV620_DACA_BGADJ_SRC, Private->Store_Dac_Bgadj_Src);
  945.     RHDRegWrite(Output, offset + RV620_DACA_AUTO_CALIB_CONTROL, Private->Store_Auto_Calib_Control);
  946.     RHDRegWrite(Output, offset + RV620_DACA_POWERDOWN, Private->Store_Powerdown);
  947.     RHDRegWrite(Output, offset + RV620_DACA_FORCE_OUTPUT_CNTL, Private->Store_Force_Output_Control);
  948.     RHDRegWrite(Output, offset + RV620_DACA_FORCE_DATA, Private->Store_Force_Data);
  949.     RHDRegWrite(Output, offset + RV620_DACA_SOURCE_SELECT, Private->Store_Source_Select);
  950.     RHDRegWrite(Output, offset + RV620_DACA_ENABLE, Private->Store_Enable);
  951.     RHDRegWrite(Output, offset + RV620_DACA_MACRO_CNTL, Private->Store_Control1);
  952.     RHDRegWrite(Output, offset + RV620_DACA_CONTROL2, Private->Store_Control2);
  953.     RHDRegWrite(Output, offset + RV620_DACA_SYNC_TRISTATE_CONTROL, Private->Store_Tristate_Control);
  954.  
  955. }
  956.  
  957. /*
  958.  *
  959.  */
  960. static void
  961. DACARestoreRV620(struct rhdOutput *Output)
  962. {
  963.     RHDFUNC(Output);
  964.  
  965.     if (!((struct rhdDACPrivate *) Output->Private)->Stored) {
  966.         xf86DrvMsg(Output->scrnIndex, X_ERROR,
  967.                    "%s: No registers stored.\n", __func__);
  968.         return;
  969.     }
  970.     DACRestoreRV620(Output, RV620_REG_DACA_OFFSET);
  971. }
  972.  
  973. /*
  974.  *
  975.  */
  976. static void
  977. DACBRestoreRV620(struct rhdOutput *Output)
  978. {
  979.     RHDFUNC(Output);
  980.  
  981.     if (!((struct rhdDACPrivate *) Output->Private)->Stored) {
  982.         xf86DrvMsg(Output->scrnIndex, X_ERROR,
  983.                    "%s: No registers stored.\n", __func__);
  984.         return;
  985.     }
  986.  
  987.     DACRestoreRV620(Output, RV620_REG_DACB_OFFSET);
  988. }
  989.  
  990. /* ----------------------------------------------------------- */
  991.  
  992. /*
  993.  *
  994.  */
  995. static ModeStatus
  996. DACModeValid(struct rhdOutput *Output, DisplayModePtr Mode)
  997. {
  998.     RHDFUNC(Output);
  999.  
  1000.     if (Mode->Clock < 20000)
  1001.         return MODE_CLOCK_LOW;
  1002.  
  1003.     if (Mode->Clock > 400000)
  1004.         return MODE_CLOCK_HIGH;
  1005.  
  1006.     return MODE_OK;
  1007. }
  1008.  
  1009. /*
  1010.  *
  1011.  */
  1012. static void
  1013. DACDestroy(struct rhdOutput *Output)
  1014. {
  1015.     RHDFUNC(Output);
  1016.  
  1017.     if (!Output->Private)
  1018.         return;
  1019.  
  1020.     xfree(Output->Private);
  1021.     Output->Private = NULL;
  1022. }
  1023.  
  1024. /*
  1025.  *
  1026.  */
  1027. struct rhdOutput *
  1028. RHDDACAInit(RHDPtr rhdPtr)
  1029. {
  1030.     struct rhdOutput *Output;
  1031.     struct rhdDACPrivate *Private;
  1032.  
  1033.     RHDFUNC(rhdPtr);
  1034.  
  1035.     Output = xnfcalloc(sizeof(struct rhdOutput), 1);
  1036.  
  1037.     Output->scrnIndex = rhdPtr->scrnIndex;
  1038.     Output->Name = "DAC A";
  1039.     Output->Id = RHD_OUTPUT_DACA;
  1040.  
  1041.     if (rhdPtr->ChipSet < RHD_RV620) {
  1042.         Output->Sense = DACASense;
  1043.     Output->Mode = DACASet;
  1044.     Output->Power = DACAPower;
  1045.     Output->Save = DACASave;
  1046.     Output->Restore = DACARestore;
  1047.     } else {
  1048.         Output->Sense = DACASenseRV620;
  1049.         Output->Mode = DACASetRV620;
  1050.         Output->Power = DACAPowerRV620;
  1051.         Output->Save = DACASaveRV620;
  1052.         Output->Restore = DACARestoreRV620;
  1053.     }
  1054.     Output->ModeValid = DACModeValid;
  1055.     Output->Destroy = DACDestroy;
  1056.     Private = xnfcalloc(sizeof(struct rhdDACPrivate), 1);
  1057.     Output->Private = Private;
  1058.  
  1059.     return Output;
  1060. }
  1061.  
  1062. /*
  1063.  *
  1064.  */
  1065. struct rhdOutput *
  1066. RHDDACBInit(RHDPtr rhdPtr)
  1067. {
  1068.     struct rhdOutput *Output;
  1069.     struct rhdDACPrivate *Private;
  1070.  
  1071.     RHDFUNC(rhdPtr);
  1072.  
  1073.     Output = xnfcalloc(sizeof(struct rhdOutput), 1);
  1074.  
  1075.     Output->scrnIndex = rhdPtr->scrnIndex;
  1076.     Output->Name = "DAC B";
  1077.     Output->Id = RHD_OUTPUT_DACB;
  1078.  
  1079.     if (rhdPtr->ChipSet < RHD_RV620) {
  1080.         Output->Sense = DACBSense;
  1081.     Output->Mode = DACBSet;
  1082.     Output->Power = DACBPower;
  1083.     Output->Save = DACBSave;
  1084.     Output->Restore = DACBRestore;
  1085.     } else {
  1086.         Output->Sense = DACBSenseRV620;
  1087.         Output->Mode = DACBSetRV620;
  1088.         Output->Power = DACBPowerRV620;
  1089.         Output->Save = DACBSaveRV620;
  1090.         Output->Restore = DACBRestoreRV620;
  1091.     }
  1092.     Output->ModeValid = DACModeValid;
  1093.     Output->Destroy = DACDestroy;
  1094.  
  1095.     Private = xnfcalloc(sizeof(struct rhdDACPrivate), 1);
  1096.     Output->Private = Private;
  1097.  
  1098.     return Output;
  1099. }
  1100.