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. #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. #endif
  38.  
  39. #include "rhd.h"
  40. #include "rhd_crtc.h"
  41. #include "rhd_connector.h"
  42. #include "rhd_output.h"
  43. #include "rhd_regs.h"
  44. #ifdef ATOM_BIOS
  45. #include "rhd_atombios.h"
  46. #endif
  47.  
  48. struct DDIAPrivate
  49. {
  50.     Bool RunDualLink;
  51.     CARD32 PcieCfgReg7;
  52.     CARD32 CapabilityFlag;
  53.  
  54.     Bool Stored;
  55.  
  56.     CARD32 DdiaPathControl;
  57.     CARD32 DdiaCntl;
  58.     CARD32 DdiaDcbalancerControl;
  59.     CARD32 DdiaPcieLinkControl2;
  60.     CARD32 DdiaBitDepthControl;
  61. };
  62.  
  63. /*
  64.  *
  65.  */
  66. static ModeStatus
  67. DDIAModeValid(struct rhdOutput *Output, DisplayModePtr Mode)
  68. {
  69.     RHDFUNC(Output);
  70.  
  71.     if (Mode->Flags & V_INTERLACE)
  72.         return MODE_NO_INTERLACE;
  73.  
  74.     if (Mode->Clock < 25000)
  75.         return MODE_CLOCK_LOW;
  76.  
  77.     if (Output->Connector->Type == RHD_CONNECTOR_DVI_SINGLE) {
  78.         if (Mode->Clock > 165000)
  79.             return MODE_CLOCK_HIGH;
  80.     } else if (Output->Connector->Type == RHD_CONNECTOR_DVI) {
  81.         if (Mode->Clock > 330000) /* could go higher still */
  82.             return MODE_CLOCK_HIGH;
  83.     }
  84.  
  85.     return MODE_OK;
  86. }
  87.  
  88. /*
  89.  *
  90.  */
  91. static void
  92. DDIAMode(struct rhdOutput *Output, DisplayModePtr Mode)
  93. {
  94.     struct DDIAPrivate *Private = (struct DDIAPrivate *)Output->Private;
  95.     CARD32 mux0, mux1, mux2, mux3;
  96.     Bool LaneReversal;
  97.     RHDPtr rhdPtr = RHDPTRI(Output);
  98.  
  99.     RHDFUNC(Output);
  100.  
  101.     if (Mode->SynthClock >= 165000)
  102.         Private->RunDualLink = TRUE;
  103.     else
  104.         Private->RunDualLink = FALSE;
  105.  
  106.     /* reset on - will be enabled at POWER_ON */
  107.     RHDRegMask(Output, RS69_DDIA_PATH_CONTROL, RS69_DDIA_PIXVLD_RESET, RS69_DDIA_PIXVLD_RESET);
  108.     /* RGB 4:4:4 */
  109.     RHDRegMask(Output, RS69_DDIA_CNTL, 0, RS69_DDIA_PIXEL_ENCODING);
  110.     /* TMDS_AC */
  111.     RHDRegMask(Output, RS69_DDIA_PATH_CONTROL,
  112.                2 << RS69_DDIA_PATH_SELECT_SHIFT,
  113.                0x3 << RS69_DDIA_PATH_SELECT_SHIFT);
  114.     /* dual link */
  115.     RHDRegMask(Output, RS69_DDIA_CNTL, Private->RunDualLink ?
  116.                RS69_DDIA_DUAL_LINK_ENABLE : 0, RS69_DDIA_DUAL_LINK_ENABLE);
  117.     RHDRegMask(Output, RS69_DDIA_DCBALANCER_CONTROL,
  118.                RS69_DDIA_DCBALANCER_EN,
  119.                RS69_DDIA_SYNC_DCBAL_EN_MASK | RS69_DDIA_DCBALANCER_EN);
  120.  
  121.     RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL2, 0x0, 0x80);
  122.     RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL2, 0x0, 0x100);
  123.  
  124.     mux0 = Private->PcieCfgReg7 & 0x3;
  125.     mux1 = (Private->PcieCfgReg7 >> 2) & 0x3;
  126.     mux2 = (Private->PcieCfgReg7 >> 4) & 0x3;
  127.     mux3 = (Private->PcieCfgReg7 >> 6) & 0x3;
  128.  
  129.     RHDRegMask(Output, RS69_DDIA_PCIE_LINK_CONTROL2,
  130.                (mux0 << RS69_DDIA_PCIE_OUTPUT_MUX_SEL0)
  131.                | (mux1 << RS69_DDIA_PCIE_OUTPUT_MUX_SEL1)
  132.                | (mux2 << RS69_DDIA_PCIE_OUTPUT_MUX_SEL2)
  133.                | (mux3 << RS69_DDIA_PCIE_OUTPUT_MUX_SEL3),
  134.                (3 << RS69_DDIA_PCIE_OUTPUT_MUX_SEL0)
  135.                | (3 << RS69_DDIA_PCIE_OUTPUT_MUX_SEL1)
  136.                | (3 << RS69_DDIA_PCIE_OUTPUT_MUX_SEL2)
  137.                | (3 << RS69_DDIA_PCIE_OUTPUT_MUX_SEL3)
  138.         );
  139.     LaneReversal = Private->PcieCfgReg7 & (0x1 << 10);
  140.     RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL2, 0x0, 0x3);
  141.     RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL2, 0x2, 0x2);
  142.  
  143.     RHDRegMask(Output, RS69_DDIA_PCIE_LINK_CONTROL3,
  144.                LaneReversal ? RS69_DDIA_PCIE_MIRROR_EN : 0,
  145.                RS69_DDIA_PCIE_MIRROR_EN);
  146.  
  147.     RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL2, 0x70, 0x70);
  148.  
  149.     RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0, 0x10);
  150.     RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0, 0x60);
  151.     RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0, 0x4000000);
  152.  
  153.     switch (rhdPtr->PciDeviceID) {
  154.         case 0x791E:
  155.             if (Mode->SynthClock <= 25000) {
  156.                 RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x2780, 0x3f80);
  157.                 RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x0, 0xc000);
  158.                 RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x039f0000, 0x03000000 | 0x039f0000);
  159.             } else if (Mode->SynthClock <= 60000) {
  160.                 RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x2780, 0x3f80);
  161.                 RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x0, 0xc000);
  162.                 RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x024f0000, 0x03000000 | 0x024f0000);
  163.             } else {
  164.                 RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x0980, 0x3f80);
  165.                 RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x0, 0xc000);
  166.                 RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x01270000, 0x03000000 | 0x01270000);
  167.             }
  168.             break;
  169.         case 0x791F:
  170.                 RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x0980, 0x3f80);
  171.                 RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x4000, 0xc000);
  172.                 RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x00ac0000, 0x03000000 | 0x00ac0000);
  173.                 if (Private->CapabilityFlag & 0x10) {
  174.                     RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x0, 0xc000);
  175.                     if (Mode->SynthClock <= 6500)
  176.                         RHDRegMask(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x01ac0000, 0x03ff0000);
  177.                     else
  178.                         RHDRegMaskD(Output,  RS69_DDIA_PCIE_PHY_CONTROL1, 0x01110000, 0x03ff0000);
  179.                 }
  180.             break;
  181.     }
  182.     usleep (1);
  183.     RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x04000000, 0x04000000);
  184.     RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x60, 0x60);
  185.     usleep(30);
  186.     RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x01, 0x01);
  187.     usleep(1);
  188.     RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x02, 0x02);
  189.     usleep(1);
  190.     RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x04, 0x04);
  191.     usleep(1);
  192.     RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x08, 0x08);
  193.     usleep(1);
  194.     RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x10, 0x10);
  195.     RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x0, 0xf);
  196.  
  197.     RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL2, 0x0180, 0x0180);
  198.     RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL2, 0x600, 0x600);
  199.     usleep(5);
  200.     RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL2, 0x0, 0x600);
  201.  
  202.     /* hw reset will be turned off at POWER_ON */
  203.  
  204.     /* select crtc source, sync_a, no stereosync */
  205.     RHDRegMask(Output, RS69_DDIA_SOURCE_SELECT, Output->Crtc->Id,
  206.                RS69_DDIA_SOURCE_SELECT_BIT
  207.                | RS69_DDIA_SYNC_SELECT
  208.                | RS69_DDIA_STEREOSYNC_SELECT);
  209. }
  210.  
  211. /*
  212.  *
  213.  */
  214. static void
  215. DDIAPower(struct rhdOutput *Output, int Power)
  216. {
  217.     RHDDebug(Output->scrnIndex, "%s(%s,%s)\n",__func__,Output->Name,
  218.              rhdPowerString[Power]);
  219.  
  220.     switch (Power) {
  221.         case RHD_POWER_ON:
  222.             RHDRegMask(Output, RS69_DDIA_PATH_CONTROL, RS69_DDIA_PIXVLD_RESET,
  223.                        RS69_DDIA_PIXVLD_RESET);
  224.             RHDRegWrite(Output, RS69_DDIA_BIT_DEPTH_CONTROL, 0);
  225.             RHDRegMask(Output, RS69_DDIA_BIT_DEPTH_CONTROL,
  226.                        RS69_DDIA_TEMPORAL_DITHER_RESET, RS69_DDIA_TEMPORAL_DITHER_RESET);
  227.             RHDRegMask(Output, RS69_DDIA_BIT_DEPTH_CONTROL,
  228.                        0, RS69_DDIA_TEMPORAL_DITHER_RESET);
  229.             RHDRegMask(Output, RS69_DDIA_CNTL, RS69_DDIA_ENABLE, RS69_DDIA_ENABLE);
  230.             RHDRegMask(Output, RS69_DDIA_PATH_CONTROL, 0, RS69_DDIA_PIXVLD_RESET);
  231.             return;
  232.         case RHD_POWER_RESET:
  233.             RHDRegMask(Output, RS69_DDIA_CNTL, 0, RS69_DDIA_ENABLE);
  234.             return;
  235.         case RHD_POWER_SHUTDOWN:
  236.             RHDRegMask(Output, RS69_DDIA_BIT_DEPTH_CONTROL,
  237.                        RS69_DDIA_TEMPORAL_DITHER_RESET, RS69_DDIA_TEMPORAL_DITHER_RESET);
  238.             RHDRegMask(Output, RS69_DDIA_BIT_DEPTH_CONTROL,
  239.                        0, RS69_DDIA_TEMPORAL_DITHER_RESET);
  240.             RHDRegMask(Output, RS69_DDIA_BIT_DEPTH_CONTROL,
  241.                        0,
  242.                        RS69_DDIA_TRUNCATE_EN
  243.                        | RS69_DDIA_TRUNCATE_DEPTH
  244.                        | RS69_DDIA_SPATIAL_DITHER_EN
  245.                        | RS69_DDIA_SPATIAL_DITHER_DEPTH);
  246.             RHDRegMask(Output, RS69_DDIA_BIT_DEPTH_CONTROL,
  247.                        0,
  248.                        RS69_DDIA_TEMPORAL_DITHER_EN
  249.                        | RS69_DDIA_TEMPORAL_DITHER_EN
  250.                        | RS69_DDIA_TEMPORAL_DITHER_DEPTH
  251.                        | RS69_DDIA_TEMPORAL_LEVEL);
  252.             RHDRegMask(Output, RS69_DDIA_CNTL, 0, RS69_DDIA_ENABLE);
  253.             return;
  254.         default:
  255.             return;
  256.     }
  257. }
  258.  
  259. /*
  260.  *
  261.  */
  262. static void
  263. DDIASave(struct rhdOutput *Output)
  264. {
  265.     struct DDIAPrivate *Private = (struct DDIAPrivate *)Output->Private;
  266.  
  267.     RHDFUNC(Output);
  268.  
  269.     Private->DdiaPathControl = RHDRegRead(Output, RS69_DDIA_PATH_CONTROL);
  270.     Private->DdiaCntl = RHDRegRead(Output, RS69_DDIA_CNTL);
  271.     Private->DdiaDcbalancerControl = RHDRegRead(Output, RS69_DDIA_DCBALANCER_CONTROL);
  272.     Private->DdiaPcieLinkControl2 = RHDRegRead(Output, RS69_DDIA_PCIE_LINK_CONTROL2);
  273.     Private->DdiaBitDepthControl = RHDRegRead(Output, RS69_DDIA_BIT_DEPTH_CONTROL);
  274.  
  275.     Private->Stored = TRUE;
  276. }
  277.  
  278. /*
  279.  *
  280.  */
  281. static void
  282. DDIARestore(struct rhdOutput *Output)
  283. {
  284.     struct DDIAPrivate *Private = (struct DDIAPrivate *)Output->Private;
  285.     RHDFUNC(Output);
  286.  
  287.     if (!Private->Stored)
  288.         return;
  289.  
  290.     /* disalbe */
  291.     RHDRegMask(Output, RS69_DDIA_CNTL, 0, RS69_DDIA_ENABLE);
  292.     /* reset on */
  293.     RHDRegMask(Output, RS69_DDIA_PATH_CONTROL, RS69_DDIA_PIXVLD_RESET, RS69_DDIA_PIXVLD_RESET);
  294.     RHDRegWrite(Output, RS69_DDIA_PATH_CONTROL, Private->DdiaPathControl | RS69_DDIA_PIXVLD_RESET);
  295.  
  296.     RHDRegWrite(Output, RS69_DDIA_BIT_DEPTH_CONTROL, Private->DdiaBitDepthControl);
  297.     /* temporal dither reset on */
  298.     RHDRegWrite(Output, RS69_DDIA_BIT_DEPTH_CONTROL, Private->DdiaBitDepthControl
  299.                | RS69_DDIA_TEMPORAL_DITHER_RESET);
  300.     /* temporal dither reset off */
  301.     RHDRegWrite(Output, RS69_DDIA_BIT_DEPTH_CONTROL, Private->DdiaBitDepthControl);
  302.  
  303.     RHDRegWrite(Output, RS69_DDIA_DCBALANCER_CONTROL, Private->DdiaDcbalancerControl);
  304.     RHDRegWrite(Output, RS69_DDIA_PCIE_LINK_CONTROL2, Private->DdiaPcieLinkControl2);
  305.     /* enable if enabled at startup */
  306.     RHDRegWrite(Output, RS69_DDIA_CNTL, Private->DdiaCntl);
  307.     /* reset off */
  308.     RHDRegWrite(Output, RS69_DDIA_PATH_CONTROL, Private->DdiaPathControl);
  309. }
  310.  
  311. /*
  312.  *
  313.  */
  314. static void
  315. DDIADestroy(struct rhdOutput *Output)
  316. {
  317.     struct DDIAPrivate *Private = (struct DDIAPrivate *)Output->Private;
  318.  
  319.     RHDFUNC(Output);
  320.  
  321.     xfree(Private);
  322.     Output->Private = NULL;
  323. }
  324.  
  325. /*
  326.  *
  327.  */
  328. struct rhdOutput *
  329. RHDDDIAInit(RHDPtr rhdPtr)
  330. {
  331. #ifdef ATOM_BIOS
  332.     struct rhdOutput *Output;
  333.     struct DDIAPrivate *Private;
  334.     AtomBiosArgRec data;
  335.  
  336.     RHDFUNC(rhdPtr);
  337.  
  338.     /*
  339.      * This needs to be handled separately
  340.      * for now we only deal with it here.
  341.      */
  342.     if (rhdPtr->ChipSet < RHD_RS600 || rhdPtr->ChipSet >= RHD_RS740)
  343.         return FALSE;
  344.  
  345.     Output = xnfcalloc(sizeof(struct rhdOutput), 1);
  346.  
  347.     Output->Name = "DDIA";
  348.  
  349.     Output->scrnIndex = rhdPtr->scrnIndex;
  350.     Output->Id = RHD_OUTPUT_DVO;
  351.  
  352.     Output->Sense = NULL;
  353.     Output->ModeValid = DDIAModeValid;
  354.     Output->Mode = DDIAMode;
  355.     Output->Power = DDIAPower;
  356.     Output->Save = DDIASave;
  357.     Output->Restore = DDIARestore;
  358.     Output->Destroy = DDIADestroy;
  359.  
  360.     Private = xnfcalloc(1, sizeof(struct DDIAPrivate));
  361.     Output->Private = Private;
  362.     Private->Stored = FALSE;
  363.  
  364.     if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS,
  365.                         ATOM_GET_PCIENB_CFG_REG7, &data) == ATOM_SUCCESS) {
  366.         Private->PcieCfgReg7 = data.val;
  367.     } else {
  368.         xf86DrvMsg(Output->scrnIndex, X_ERROR, "Retrieval of PCIE MUX values failed. "
  369.                    "no DDIA block support available\n");
  370.         goto error;
  371.     }
  372.     if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS,
  373.                          ATOM_GET_CAPABILITY_FLAG, &data) == ATOM_SUCCESS) {
  374.         Private->CapabilityFlag = data.val;
  375.     } else {
  376.         xf86DrvMsg(Output->scrnIndex, X_ERROR, "Retrieval of Capability flag failed. "
  377.                    "no DDIA block support available\n");
  378.         goto error;
  379.     }
  380.  
  381.     return Output;
  382. error:
  383.     xfree(Private);
  384.     return NULL;
  385.  
  386. #else
  387.     return NULL;
  388. #endif
  389. }
  390.