Subversion Repositories Kolibri OS

Rev

Go to most recent revision | 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. /*
  27.  * Deals with the Primary TMDS device (TMDSA) of R500s, R600s.
  28.  * Gets replaced by DDIA on RS690 and DIG/UNIPHY on RV620.
  29.  */
  30.  
  31. #ifdef HAVE_CONFIG_H
  32. #include "config.h"
  33. #endif
  34.  
  35. #include "xf86.h"
  36.  
  37. /* for usleep */
  38. #if HAVE_XF86_ANSIC_H
  39. # include "xf86_ansic.h"
  40. #else
  41. # include <unistd.h>
  42. #endif
  43. #include "rhd.h"
  44. #include "rhd_crtc.h"
  45. #include "rhd_connector.h"
  46. #include "rhd_output.h"
  47. #include "rhd_regs.h"
  48. #include "rhd_hdmi.h"
  49.  
  50. #ifdef ATOM_BIOS
  51. #include "rhd_atombios.h"
  52. #endif
  53.  
  54. struct rhdTMDSPrivate {
  55.     Bool RunsDualLink;
  56.     DisplayModePtr Mode;
  57.     Bool Coherent;
  58.     int PowerState;
  59.  
  60.     struct rhdHdmi *Hdmi;
  61.  
  62.     Bool Stored;
  63.  
  64.     CARD32 StoreControl;
  65.     CARD32 StoreSource;
  66.     CARD32 StoreFormat;
  67.     CARD32 StoreForce;
  68.     CARD32 StoreReduction;
  69.     CARD32 StoreDCBalancer;
  70.     CARD32 StoreDataSynchro;
  71.     CARD32 StoreTXEnable;
  72.     CARD32 StoreMacro;
  73.     CARD32 StoreTXControl;
  74.     CARD32 StoreTXAdjust;
  75. };
  76.  
  77. /*
  78.  * We cannot sense for dual link here at all, plus, we need a bit more work
  79.  * for enabling the transmitter for sensing to happen on most R5xx cards.
  80.  * RV570 (0x7280) and R600 and above seem ok.
  81.  */
  82. static enum rhdSensedOutput
  83. TMDSASense(struct rhdOutput *Output, struct rhdConnector *Connector)
  84. {
  85.     RHDPtr rhdPtr = RHDPTRI(Output);
  86.     CARD32 Enable, Control, Detect;
  87.     enum rhdConnectorType Type = Connector->Type;
  88.     Bool ret;
  89.  
  90.     RHDFUNC(Output);
  91.  
  92.     if ((Type != RHD_CONNECTOR_DVI) && (Type != RHD_CONNECTOR_DVI_SINGLE)) {
  93.         xf86DrvMsg(Output->scrnIndex, X_WARNING,
  94.                    "%s: connector type %d is not supported.\n",
  95.                    __func__, Type);
  96.         return RHD_SENSED_NONE;
  97.     }
  98.  
  99.     Enable = RHDRegRead(Output, TMDSA_TRANSMITTER_ENABLE);
  100.     Control = RHDRegRead(Output, TMDSA_TRANSMITTER_CONTROL);
  101.     Detect = RHDRegRead(Output, TMDSA_LOAD_DETECT);
  102.  
  103.     if (rhdPtr->ChipSet < RHD_R600) {
  104.         RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0x00000003, 0x00000003);
  105.         RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x00000001, 0x00000003);
  106.     }
  107.  
  108.     RHDRegMask(Output, TMDSA_LOAD_DETECT, 0x00000001, 0x00000001);
  109.     usleep(1);
  110.     ret = RHDRegRead(Output, TMDSA_LOAD_DETECT) & 0x00000010;
  111.  
  112.     RHDRegMask(Output, TMDSA_LOAD_DETECT, Detect, 0x00000001);
  113.  
  114.     if (rhdPtr->ChipSet < RHD_R600) {
  115.         RHDRegWrite(Output, TMDSA_TRANSMITTER_ENABLE, Enable);
  116.         RHDRegWrite(Output, TMDSA_TRANSMITTER_CONTROL, Control);
  117.     }
  118.  
  119.     RHDDebug(Output->scrnIndex, "%s: %s\n", __func__,
  120.              ret ? "Attached" : "Disconnected");
  121.  
  122.     if (ret)
  123.         return RHD_SENSED_DVI;
  124.     else
  125.         return RHD_SENSED_NONE;
  126. }
  127.  
  128. /*
  129.  *
  130.  */
  131. static ModeStatus
  132. TMDSAModeValid(struct rhdOutput *Output, DisplayModePtr Mode)
  133. {
  134.     RHDFUNC(Output);
  135.  
  136.     if (Mode->Flags & V_INTERLACE)
  137.         return MODE_NO_INTERLACE;
  138.  
  139.     if (Mode->Clock < 25000)
  140.         return MODE_CLOCK_LOW;
  141.  
  142.     if (Output->Connector->Type == RHD_CONNECTOR_DVI_SINGLE) {
  143.         if (Mode->Clock > 165000)
  144.             return MODE_CLOCK_HIGH;
  145.     } else if (Output->Connector->Type == RHD_CONNECTOR_DVI) {
  146.         if (Mode->Clock > 330000) /* could go higher still */
  147.             return MODE_CLOCK_HIGH;
  148.     }
  149.  
  150.     return MODE_OK;
  151. }
  152.  
  153. /*
  154.  * This information is not provided in an atombios data table.
  155.  */
  156. static struct R5xxTMDSAMacro {
  157.     CARD16 Device;
  158.     CARD32 Macro;
  159. } R5xxTMDSAMacro[] = {
  160.     { 0x7104, 0x00C00414 }, /* R520  */
  161.     { 0x7142, 0x00A00415 }, /* RV515 */
  162.     { 0x7145, 0x00A00416 }, /* M54   */
  163.     { 0x7146, 0x00C0041F }, /* RV515 */
  164.     { 0x7147, 0x00C00418 }, /* RV505 */
  165.     { 0x7149, 0x00800416 }, /* M56   */
  166.     { 0x7152, 0x00A00415 }, /* RV515 */
  167.     { 0x7183, 0x00600412 }, /* RV530 */
  168.     { 0x71C1, 0x00C0041F }, /* RV535 */
  169.     { 0x71C2, 0x00A00416 }, /* RV530 */
  170.     { 0x71C4, 0x00A00416 }, /* M56   */
  171.     { 0x71C5, 0x00A00416 }, /* M56   */
  172.     { 0x71C6, 0x00A00513 }, /* RV530 */
  173.     { 0x71D2, 0x00A00513 }, /* RV530 */
  174.     { 0x71D5, 0x00A00513 }, /* M66   */
  175.     { 0x7249, 0x00A00513 }, /* R580  */
  176.     { 0x724B, 0x00A00513 }, /* R580  */
  177.     { 0x7280, 0x00C0041F }, /* RV570 */
  178.     { 0x7288, 0x00C0041F }, /* RV570 */
  179.     { 0x9400, 0x00910419 }, /* R600: */
  180.     { 0, 0} /* End marker */
  181. };
  182.  
  183. static struct Rv6xxTMDSAMacro {
  184.     CARD16 Device;
  185.     CARD32 PLL;
  186.     CARD32 TX;
  187. } Rv6xxTMDSAMacro[] = {
  188.     { 0x94C1, 0x00010416, 0x00010308 }, /* RV610 */
  189.     { 0x94C3, 0x00010416, 0x00010308 }, /* RV610 */
  190.     { 0x9501, 0x00010416, 0x00010308 }, /* RV670: != atombios */
  191.     { 0x9505, 0x00010416, 0x00010308 }, /* RV670: != atombios */
  192.     { 0x950F, 0x00010416, 0x00010308 }, /* R680 : != atombios */
  193.     { 0x9581, 0x00030410, 0x00301044 }, /* M76 */
  194.     { 0x9587, 0x00010416, 0x00010308 }, /* RV630 */
  195.     { 0x9588, 0x00010416, 0x00010388 }, /* RV630 */
  196.     { 0x9589, 0x00010416, 0x00010388 }, /* RV630 */
  197.     { 0, 0, 0} /* End marker */
  198. };
  199.  
  200. static void
  201. TMDSAVoltageControl(struct rhdOutput *Output)
  202. {
  203.     RHDPtr rhdPtr = RHDPTRI(Output);
  204.     int i;
  205.  
  206.     if (rhdPtr->ChipSet < RHD_RV610) {
  207.         for (i = 0; R5xxTMDSAMacro[i].Device; i++)
  208.             if (R5xxTMDSAMacro[i].Device == rhdPtr->PciDeviceID) {
  209.                 RHDRegWrite(Output, TMDSA_MACRO_CONTROL, R5xxTMDSAMacro[i].Macro);
  210.                 return;
  211.             }
  212.  
  213.         xf86DrvMsg(Output->scrnIndex, X_ERROR, "%s: unhandled chipset: 0x%04X.\n",
  214.                    __func__, rhdPtr->PciDeviceID);
  215.         xf86DrvMsg(Output->scrnIndex, X_INFO, "TMDSA_MACRO_CONTROL: 0x%08X\n",
  216.                    (unsigned int) RHDRegRead(Output, TMDSA_MACRO_CONTROL));
  217.     } else {
  218.         for (i = 0; Rv6xxTMDSAMacro[i].Device; i++)
  219.             if (Rv6xxTMDSAMacro[i].Device == rhdPtr->PciDeviceID) {
  220.                 RHDRegWrite(Output, TMDSA_PLL_ADJUST, Rv6xxTMDSAMacro[i].PLL);
  221.                 RHDRegWrite(Output, TMDSA_TRANSMITTER_ADJUST, Rv6xxTMDSAMacro[i].TX);
  222.                 return;
  223.             }
  224.         xf86DrvMsg(Output->scrnIndex, X_ERROR, "%s: unhandled chipset: 0x%04X.\n",
  225.                    __func__, rhdPtr->PciDeviceID);
  226.         xf86DrvMsg(Output->scrnIndex, X_INFO, "TMDSA_PLL_ADJUST: 0x%08X\n",
  227.                    (unsigned int) RHDRegRead(Output, TMDSA_PLL_ADJUST));
  228.         xf86DrvMsg(Output->scrnIndex, X_INFO, "TMDSA_TRANSMITTER_ADJUST: 0x%08X\n",
  229.                    (unsigned int) RHDRegRead(Output, TMDSA_TRANSMITTER_ADJUST));
  230.     }
  231. }
  232.  
  233. /*
  234.  *
  235.  */
  236. static Bool
  237. TMDSAPropertyControl(struct rhdOutput *Output,
  238.              enum rhdPropertyAction Action, enum rhdOutputProperty Property, union rhdPropertyData *val)
  239. {
  240.     struct rhdTMDSPrivate *Private = (struct rhdTMDSPrivate *) Output->Private;
  241.  
  242.     RHDFUNC(Output);
  243.     switch (Action) {
  244.         case rhdPropertyCheck:
  245.         switch (Property) {
  246.             case RHD_OUTPUT_COHERENT:
  247.                 return TRUE;
  248.             default:
  249.                 return FALSE;
  250.         }
  251.         case rhdPropertyGet:
  252.             switch (Property) {
  253.                 case RHD_OUTPUT_COHERENT:
  254.                     val->Bool = Private->Coherent;
  255.                     return TRUE;
  256.                     break;
  257.                 default:
  258.                     return FALSE;
  259.             }
  260.             break;
  261.         case rhdPropertySet:
  262.             switch (Property) {
  263.                 case RHD_OUTPUT_COHERENT:
  264.                     Private->Coherent = val->Bool;
  265.                     Output->Mode(Output, Private->Mode);
  266.                     Output->Power(Output, RHD_POWER_ON);
  267.                     break;
  268.                 default:
  269.                     return FALSE;
  270.             }
  271.             break;
  272.     }
  273.     return TRUE;
  274. }
  275.  
  276. /*
  277.  *
  278.  */
  279. static void
  280. TMDSASet(struct rhdOutput *Output, DisplayModePtr Mode)
  281. {
  282.     RHDPtr rhdPtr = RHDPTRI(Output);
  283.     struct rhdTMDSPrivate *Private = (struct rhdTMDSPrivate *) Output->Private;
  284.  
  285.     RHDFUNC(Output);
  286.  
  287.     /* Clear out some HPD events first: this should be under driver control. */
  288.     RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0, 0x0000000C);
  289.     RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0, 0x00070000);
  290.     RHDRegMask(Output, TMDSA_CNTL, 0, 0x00000010);
  291.  
  292.     /* Disable the transmitter */
  293.     RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0, 0x00001D1F);
  294.  
  295.     /* Disable bit reduction and reset temporal dither */
  296.     RHDRegMask(Output, TMDSA_BIT_DEPTH_CONTROL, 0, 0x00010101);
  297.     if (rhdPtr->ChipSet < RHD_R600) {
  298.         RHDRegMask(Output, TMDSA_BIT_DEPTH_CONTROL, 0x04000000, 0x04000000);
  299.         usleep(2);
  300.         RHDRegMask(Output, TMDSA_BIT_DEPTH_CONTROL, 0, 0x04000000);
  301.     } else {
  302.         RHDRegMask(Output, TMDSA_BIT_DEPTH_CONTROL, 0x02000000, 0x02000000);
  303.         usleep(2);
  304.         RHDRegMask(Output, TMDSA_BIT_DEPTH_CONTROL, 0, 0x02000000);
  305.     }
  306.  
  307.     /* reset phase on vsync and use RGB */
  308.     RHDRegMask(Output, TMDSA_CNTL, 0x00001000, 0x00011000);
  309.  
  310.     /* Select CRTC, select syncA, no stereosync */
  311.     RHDRegMask(Output, TMDSA_SOURCE_SELECT, Output->Crtc->Id, 0x00010101);
  312.  
  313.     /* Single link, for now */
  314.     RHDRegWrite(Output, TMDSA_COLOR_FORMAT, 0);
  315.  
  316.     /* store this for TRANSMITTER_ENABLE in TMDSAPower */
  317.     Private->Mode = Mode;
  318.     if (Mode->SynthClock > 165000) {
  319.         RHDRegMask(Output, TMDSA_CNTL, 0x01000000, 0x01000000);
  320.         Private->RunsDualLink = TRUE; /* for TRANSMITTER_ENABLE in TMDSAPower */
  321.     } else {
  322.         RHDRegMask(Output, TMDSA_CNTL, 0, 0x01000000);
  323.         Private->RunsDualLink = FALSE;
  324.     }
  325.  
  326.     /* Disable force data */
  327.     RHDRegMask(Output, TMDSA_FORCE_OUTPUT_CNTL, 0, 0x00000001);
  328.  
  329.     /* DC balancer enable */
  330.     RHDRegMask(Output, TMDSA_DCBALANCER_CONTROL, 0x00000001, 0x00000001);
  331.  
  332.     TMDSAVoltageControl(Output);
  333.  
  334.     /* use IDCLK */
  335.     RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x00000010, 0x00000010);
  336.  
  337.     if (Private->Coherent)
  338.         RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x00000000, 0x10000000);
  339.     else
  340.         RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x10000000, 0x10000000);
  341.  
  342.     RHDHdmiSetMode(Private->Hdmi, Mode);
  343. }
  344.  
  345. /*
  346.  *
  347.  */
  348. static void
  349. TMDSAPower(struct rhdOutput *Output, int Power)
  350. {
  351.     RHDPtr rhdPtr = RHDPTRI(Output);
  352.     struct rhdTMDSPrivate *Private = (struct rhdTMDSPrivate *) Output->Private;
  353.  
  354.     RHDDebug(Output->scrnIndex, "%s(%s,%s)\n",__func__,Output->Name,
  355.              rhdPowerString[Power]);
  356.  
  357.     switch (Power) {
  358.     case RHD_POWER_ON:
  359.         if (Private->PowerState == RHD_POWER_SHUTDOWN
  360.             || Private->PowerState == RHD_POWER_UNKNOWN) {
  361.             RHDRegMask(Output, TMDSA_CNTL, 0x1, 0x00000001);
  362.  
  363.         RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x00000001, 0x00000001);
  364.         usleep(20);
  365.  
  366.         /* reset transmitter PLL */
  367.         RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x00000002, 0x00000002);
  368.         usleep(2);
  369.         RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0, 0x00000002);
  370.  
  371.         usleep(30);
  372.  
  373.         /* restart data synchronisation */
  374.   if (rhdPtr->ChipSet < RHD_R600) {
  375.             RHDRegMask(Output, TMDSA_DATA_SYNCHRONIZATION_R500, 0x00000001, 0x00000001);
  376.             usleep(2);
  377.             RHDRegMask(Output, TMDSA_DATA_SYNCHRONIZATION_R500, 0x00000100, 0x00000100);
  378.             RHDRegMask(Output, TMDSA_DATA_SYNCHRONIZATION_R500, 0, 0x00000001);
  379.         } else {
  380.             RHDRegMask(Output, TMDSA_DATA_SYNCHRONIZATION_R600, 0x00000001, 0x00000001);
  381.             usleep(2);
  382.             RHDRegMask(Output, TMDSA_DATA_SYNCHRONIZATION_R600, 0x00000100, 0x00000100);
  383.             RHDRegMask(Output, TMDSA_DATA_SYNCHRONIZATION_R600, 0, 0x00000001);
  384.         }
  385.         }
  386.  
  387.         if (Private->RunsDualLink) {
  388.             /* bit 9 is not known by anything below RV610, but is ignored by
  389.                the hardware anyway */
  390.             RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0x00001F1F, 0x00001F1F);
  391.         } else
  392.             RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0x0000001F, 0x00001F1F);
  393.  
  394.         if(Output->Connector != NULL && RHDConnectorEnableHDMI(Output->Connector))
  395.             RHDHdmiEnable(Private->Hdmi, TRUE);
  396.         else
  397.             RHDHdmiEnable(Private->Hdmi, FALSE);
  398.         Private->PowerState = RHD_POWER_ON;
  399.         return;
  400.  
  401.     case RHD_POWER_RESET:
  402.         RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0, 0x00001F1F);
  403.         /* if we do a RESET after a SHUTDOWN don't raise the power level,
  404.          * and similarly, don't raise from UNKNOWN state. */
  405.         if (Private->PowerState == RHD_POWER_ON)
  406.             Private->PowerState = RHD_POWER_RESET;
  407.         return;
  408.  
  409.     case RHD_POWER_SHUTDOWN:
  410.     default:
  411.         RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x00000002, 0x00000002);
  412.         usleep(2);
  413.         RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0, 0x00000001);
  414.         RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0, 0x00001F1F);
  415.         RHDRegMask(Output, TMDSA_CNTL, 0, 0x00000001);
  416.         RHDHdmiEnable(Private->Hdmi, FALSE);
  417.         Private->PowerState = RHD_POWER_SHUTDOWN;
  418.         return;
  419.     }
  420. }
  421.  
  422. /*
  423.  *
  424.  */
  425. static void
  426. TMDSASave(struct rhdOutput *Output)
  427. {
  428.     int ChipSet = RHDPTRI(Output)->ChipSet;
  429.     struct rhdTMDSPrivate *Private = (struct rhdTMDSPrivate *) Output->Private;
  430.  
  431.     RHDFUNC(Output);
  432.  
  433.     Private->StoreControl = RHDRegRead(Output, TMDSA_CNTL);
  434.     Private->StoreSource = RHDRegRead(Output, TMDSA_SOURCE_SELECT);
  435.     Private->StoreFormat = RHDRegRead(Output, TMDSA_COLOR_FORMAT);
  436.     Private->StoreForce = RHDRegRead(Output, TMDSA_FORCE_OUTPUT_CNTL);
  437.     Private->StoreReduction = RHDRegRead(Output, TMDSA_BIT_DEPTH_CONTROL);
  438.     Private->StoreDCBalancer = RHDRegRead(Output, TMDSA_DCBALANCER_CONTROL);
  439.  
  440.     if (ChipSet < RHD_R600)
  441.         Private->StoreDataSynchro = RHDRegRead(Output, TMDSA_DATA_SYNCHRONIZATION_R500);
  442.     else
  443.         Private->StoreDataSynchro = RHDRegRead(Output, TMDSA_DATA_SYNCHRONIZATION_R600);
  444.  
  445.     Private->StoreTXEnable = RHDRegRead(Output, TMDSA_TRANSMITTER_ENABLE);
  446.     Private->StoreMacro = RHDRegRead(Output, TMDSA_MACRO_CONTROL);
  447.     Private->StoreTXControl = RHDRegRead(Output, TMDSA_TRANSMITTER_CONTROL);
  448.  
  449.     if (ChipSet >= RHD_RV610)
  450.         Private->StoreTXAdjust = RHDRegRead(Output, TMDSA_TRANSMITTER_ADJUST);
  451.  
  452.     RHDHdmiSave(Private->Hdmi);
  453.  
  454.     Private->Stored = TRUE;
  455. }
  456.  
  457. /*
  458.  *
  459.  */
  460. static void
  461. TMDSARestore(struct rhdOutput *Output)
  462. {
  463.     int ChipSet = RHDPTRI(Output)->ChipSet;
  464.     struct rhdTMDSPrivate *Private = (struct rhdTMDSPrivate *) Output->Private;
  465.  
  466.     RHDFUNC(Output);
  467.  
  468.     if (!Private->Stored) {
  469.         xf86DrvMsg(Output->scrnIndex, X_ERROR,
  470.                    "%s: No registers stored.\n", __func__);
  471.         return;
  472.     }
  473.  
  474.     RHDRegWrite(Output, TMDSA_CNTL, Private->StoreControl);
  475.     RHDRegWrite(Output, TMDSA_SOURCE_SELECT, Private->StoreSource);
  476.     RHDRegWrite(Output, TMDSA_COLOR_FORMAT, Private->StoreFormat);
  477.     RHDRegWrite(Output, TMDSA_FORCE_OUTPUT_CNTL, Private->StoreForce);
  478.     RHDRegWrite(Output, TMDSA_BIT_DEPTH_CONTROL, Private->StoreReduction);
  479.     RHDRegWrite(Output, TMDSA_DCBALANCER_CONTROL, Private->StoreDCBalancer);
  480.  
  481.     if (ChipSet < RHD_R600)
  482.         RHDRegWrite(Output, TMDSA_DATA_SYNCHRONIZATION_R500, Private->StoreDataSynchro);
  483.     else
  484.         RHDRegWrite(Output, TMDSA_DATA_SYNCHRONIZATION_R600, Private->StoreDataSynchro);
  485.  
  486.     RHDRegWrite(Output, TMDSA_TRANSMITTER_ENABLE, Private->StoreTXEnable);
  487.     RHDRegWrite(Output, TMDSA_MACRO_CONTROL, Private->StoreMacro);
  488.     RHDRegWrite(Output, TMDSA_TRANSMITTER_CONTROL, Private->StoreTXControl);
  489.  
  490.     if (ChipSet >= RHD_RV610)
  491.         RHDRegWrite(Output, TMDSA_TRANSMITTER_ADJUST, Private->StoreTXAdjust);
  492.  
  493.     RHDHdmiRestore(Private->Hdmi);
  494. }
  495.  
  496. /*
  497.  *
  498.  */
  499. static void
  500. TMDSADestroy(struct rhdOutput *Output)
  501. {
  502.     struct rhdTMDSPrivate *Private = (struct rhdTMDSPrivate *) Output->Private;
  503.     RHDFUNC(Output);
  504.  
  505.     if (!Private)
  506.         return;
  507.  
  508.     RHDHdmiDestroy(Private->Hdmi);
  509.  
  510.     xfree(Private);
  511.     Output->Private = NULL;
  512. }
  513.  
  514. /*
  515.  *
  516.  */
  517. struct rhdOutput *
  518. RHDTMDSAInit(RHDPtr rhdPtr)
  519. {
  520.     struct rhdOutput *Output;
  521.     struct rhdTMDSPrivate *Private;
  522.  
  523.     RHDFUNC(rhdPtr);
  524.  
  525.     Output = xnfcalloc(sizeof(struct rhdOutput), 1);
  526.  
  527.     Output->scrnIndex = rhdPtr->scrnIndex;
  528.     Output->Name = "TMDS A";
  529.     Output->Id = RHD_OUTPUT_TMDSA;
  530.  
  531.     Output->Sense = TMDSASense;
  532.     Output->ModeValid = TMDSAModeValid;
  533.     Output->Mode = TMDSASet;
  534.     Output->Power = TMDSAPower;
  535.     Output->Save = TMDSASave;
  536.     Output->Restore = TMDSARestore;
  537.     Output->Destroy = TMDSADestroy;
  538.     Output->Property = TMDSAPropertyControl;
  539.  
  540.     Private = xnfcalloc(sizeof(struct rhdTMDSPrivate), 1);
  541.     Private->RunsDualLink = FALSE;
  542.     Private->Coherent = FALSE;
  543.     Private->PowerState = RHD_POWER_UNKNOWN;
  544.  
  545.     Output->Private = Private;
  546.  
  547.     return Output;
  548. }
  549.