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. # include <string.h>
  38. # include <stdio.h>
  39. #endif
  40.  
  41. #include "rhd.h"
  42. #include "edid.h"
  43.  
  44. #ifdef ATOM_BIOS
  45. # include "rhd_atombios.h"
  46. #endif
  47.  
  48. #include "rhd_connector.h"
  49. #include "rhd_output.h"
  50. #include "rhd_regs.h"
  51. #include "rhd_monitor.h"
  52. #include "rhd_card.h"
  53.  
  54. #include "xf86i2c.h"
  55. #include "rhd_i2c.h"
  56.  
  57.  
  58.  
  59. /*
  60.  *
  61.  */
  62. struct rhdHPD {
  63.     Bool Stored;
  64.     CARD32 StoreMask;
  65.     CARD32 StoreEnable;
  66. };
  67.  
  68. /*
  69.  *
  70.  */
  71. void
  72. RHDHPDSave(RHDPtr rhdPtr)
  73. {
  74.     struct rhdHPD *hpd = rhdPtr->HPD;
  75.  
  76.     RHDFUNC(rhdPtr);
  77.  
  78.     hpd->StoreMask = RHDRegRead(rhdPtr, DC_GPIO_HPD_MASK);
  79.     hpd->StoreEnable = RHDRegRead(rhdPtr, DC_GPIO_HPD_EN);
  80.  
  81.     hpd->Stored = TRUE;
  82. }
  83.  
  84. /*
  85.  *
  86.  */
  87. void
  88. RHDHPDRestore(RHDPtr rhdPtr)
  89. {
  90.   struct rhdHPD *hpd = rhdPtr->HPD;
  91.  
  92.   RHDFUNC(rhdPtr);
  93.  
  94.     if (hpd->Stored) {
  95.         RHDRegWrite(rhdPtr, DC_GPIO_HPD_MASK, hpd->StoreMask);
  96.         RHDRegWrite(rhdPtr, DC_GPIO_HPD_EN, hpd->StoreEnable);
  97.     } else
  98.         xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR,
  99.                    "%s: no registers stored.\n", __func__);
  100. }
  101.  
  102. /*
  103.  *
  104.  */
  105. static void
  106. RHDHPDSet(RHDPtr rhdPtr)
  107. {
  108.   RHDFUNC(rhdPtr);
  109.  
  110.     /* give the hw full control */
  111.     RHDRegWrite(rhdPtr, DC_GPIO_HPD_MASK, 0);
  112.     RHDRegWrite(rhdPtr, DC_GPIO_HPD_EN, 0);
  113.  
  114.   usleep(1);
  115. }
  116.  
  117. /*
  118.  *
  119.  */
  120. static Bool
  121. RHDHPDCheck(struct rhdConnector *Connector)
  122. {
  123.     Bool ret;
  124.  
  125.     RHDFUNC(Connector);
  126.  
  127.     ret = RHDRegRead(Connector, DC_GPIO_HPD_Y);
  128.     RHDDebug(Connector->scrnIndex, "%s returned: %x mask: %x\n",
  129.              __func__,ret, Connector->HPDMask);
  130.  
  131.     return (ret & Connector->HPDMask);
  132. }
  133.  
  134. struct rhdCsState {
  135.     int vga_cnt;
  136.     int dvi_cnt;
  137. };
  138.  
  139. /*
  140.  *
  141.  */
  142. static char *
  143. rhdConnectorSynthName(struct rhdConnectorInfo *ConnectorInfo,
  144.                       struct rhdCsState **state)
  145. {
  146.   char *str = NULL;
  147.     char *TypeName;
  148.   char *str1, *str2;
  149.     int cnt;
  150.  
  151.     ASSERT(state != NULL);
  152.  
  153.     if (!*state) {
  154.         if (!(*state = xcalloc(sizeof(struct rhdCsState), 1)))
  155.             return NULL;
  156.     }
  157.     switch (ConnectorInfo->Type) {
  158.         case RHD_CONNECTOR_NONE:
  159.             return NULL;
  160.         case RHD_CONNECTOR_DVI:
  161.         case RHD_CONNECTOR_DVI_SINGLE:
  162.             if (ConnectorInfo->Output[0] && ConnectorInfo->Output[1]) {
  163.                 TypeName = "DVI-I";
  164.                 cnt = ++(*state)->dvi_cnt;
  165.             } else if (ConnectorInfo->Output[0] == RHD_OUTPUT_DACA
  166.                      || ConnectorInfo->Output[0] == RHD_OUTPUT_DACB
  167.                      || ConnectorInfo->Output[1] == RHD_OUTPUT_DACA
  168.                      || ConnectorInfo->Output[1] == RHD_OUTPUT_DACB
  169.                 ) {
  170.                 if (ConnectorInfo->HPD == RHD_HPD_NONE) {
  171.                     TypeName = "VGA";
  172.                     cnt = ++(*state)->vga_cnt;
  173.                 } else {
  174.                     TypeName = "DVI-A";
  175.                     cnt = ++(*state)->dvi_cnt;
  176.                 }
  177.             } else {
  178.                 TypeName = "DVI-D";
  179.                 cnt = ++(*state)->dvi_cnt;
  180.             }
  181.             str = xalloc(12);
  182.             snprintf(str, 11, "%s %i",TypeName, cnt);
  183.             return str;
  184.  
  185.     case RHD_CONNECTOR_VGA:
  186.             str = xalloc(10);
  187.       snprintf(str, 9, "VGA %i",++(*state)->vga_cnt);
  188.             return str;
  189.  
  190.     case RHD_CONNECTOR_PANEL:
  191.             str = xalloc(10);
  192.             snprintf(str, 9, "PANEL");
  193.             return str;
  194.  
  195.     case RHD_CONNECTOR_TV:
  196.             str1 = xstrdup(ConnectorInfo->Name);
  197.             str = xalloc(20);
  198.       str2 = strchr(str1, ' ');
  199.       if (str2) *(str2) = '\0';
  200.         snprintf(str, 20, "TV %s",str1);
  201.             xfree(str1);
  202.             return str;
  203.  
  204.         case RHD_CONNECTOR_PCIE: /* should never get here */
  205.             return NULL;
  206.     }
  207.     return NULL;
  208. }
  209.  
  210. /*
  211.  *
  212.  */
  213. Bool
  214. RHDConnectorsInit(RHDPtr rhdPtr, struct rhdCard *Card)
  215. {
  216.   struct rhdConnectorInfo *ConnectorInfo;
  217.   struct rhdConnector *Connector;
  218.   struct rhdOutput *Output;
  219.   struct rhdCsState *csstate = NULL;
  220.   int i, j, k, l, hpd;
  221.   Bool InfoAllocated = FALSE;
  222.  
  223.     RHDFUNC(rhdPtr);
  224.  
  225.     /* Card->ConnectorInfo is there to work around quirks, so check it first */
  226.     if (Card && (Card->ConnectorInfo[0].Type != RHD_CONNECTOR_NONE)) {
  227.     ConnectorInfo = Card->ConnectorInfo;
  228.         xf86DrvMsg(rhdPtr->scrnIndex, X_INFO,
  229.                    "ConnectorInfo from quirk table:\n");
  230.         RhdPrintConnectorInfo (rhdPtr, ConnectorInfo);
  231.     } else {
  232. #ifdef ATOM_BIOS
  233.         /* common case */
  234.     AtomBiosArgRec data;
  235.     AtomBiosResult result;
  236.  
  237.   data.chipset = rhdPtr->ChipSet;
  238.   result = RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS,
  239.              ATOMBIOS_GET_CONNECTORS, &data);
  240.         if (result == ATOM_SUCCESS) {
  241.             ConnectorInfo = data.ConnectorInfo;
  242.             InfoAllocated = TRUE;
  243.         } else
  244. #endif
  245.     {
  246.             xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "%s: Failed to retrieve "
  247.                        "Connector information.\n", __func__);
  248.             return FALSE;
  249.     }
  250.   }
  251.  
  252.     /* Init HPD */
  253.     rhdPtr->HPD = xnfcalloc(sizeof(struct rhdHPD), 1);
  254.   RHDHPDSave(rhdPtr);
  255.   RHDHPDSet(rhdPtr);
  256.  
  257.     for (i = 0, j = 0; i < RHD_CONNECTORS_MAX; i++) {
  258.     if (ConnectorInfo[i].Type == RHD_CONNECTOR_NONE)
  259.       continue;
  260.  
  261.         RHDDebug(rhdPtr->scrnIndex, "%s: %d (%s) type %d, ddc %d, hpd %d\n",
  262.               __func__, i, ConnectorInfo[i].Name, ConnectorInfo[i].Type,
  263.                  ConnectorInfo[i].DDC, ConnectorInfo[i].HPD);
  264.  
  265.         Connector = xnfcalloc(sizeof(struct rhdConnector), 1);
  266.         Connector->scrnIndex = rhdPtr->scrnIndex;
  267.     Connector->Type = ConnectorInfo[i].Type;
  268.     Connector->Name = rhdConnectorSynthName(&ConnectorInfo[i], &csstate);
  269.  
  270.         /* Get the DDC bus of this connector */
  271.         if (ConnectorInfo[i].DDC != RHD_DDC_NONE) {
  272.             RHDI2CDataArg data;
  273.             int ret;
  274.  
  275.             data.i = ConnectorInfo[i].DDC;
  276.             ret = RHDI2CFunc(rhdPtr->scrnIndex,
  277.                              rhdPtr->I2C, RHD_I2C_GETBUS, &data);
  278.             if (ret == RHD_I2C_SUCCESS)
  279.         Connector->DDC = data.i2cBusPtr;
  280.     }
  281.  
  282.         /* attach HPD */
  283.     hpd = ConnectorInfo[i].HPD;
  284.         switch (rhdPtr->hpdUsage) {
  285.       case RHD_HPD_USAGE_OFF:
  286.       case RHD_HPD_USAGE_AUTO_OFF:
  287.         hpd = RHD_HPD_NONE;
  288.         break;
  289.       case RHD_HPD_USAGE_SWAP:
  290.       case RHD_HPD_USAGE_AUTO_SWAP:
  291.             switch (hpd) {
  292.           case RHD_HPD_0:
  293.             hpd = RHD_HPD_1;
  294.             break;
  295.           case RHD_HPD_1:
  296.             hpd = RHD_HPD_0;
  297.             break;
  298.         }
  299.         break;
  300.       default:
  301.         break;
  302.     }
  303.         switch(hpd) {
  304.       case RHD_HPD_0:
  305.         Connector->HPDMask = 0x00000001;
  306.         Connector->HPDCheck = RHDHPDCheck;
  307.         break;
  308.       case RHD_HPD_1:
  309.         Connector->HPDMask = 0x00000100;
  310.         Connector->HPDCheck = RHDHPDCheck;
  311.         break;
  312.       case RHD_HPD_2:
  313.         Connector->HPDMask = 0x00010000;
  314.         Connector->HPDCheck = RHDHPDCheck;
  315.         break;
  316.         case RHD_HPD_3:
  317.             Connector->HPDMask = 0x01000000;
  318.             Connector->HPDCheck = RHDHPDCheck;
  319.             break;
  320.       default:
  321.         Connector->HPDCheck = NULL;
  322.         break;
  323.     }
  324.  
  325.         /* create Outputs */
  326.         for (k = 0; k < 2; k++) {
  327.             if (ConnectorInfo[i].Output[k] == RHD_OUTPUT_NONE)
  328.         continue;
  329.  
  330.             /* Check whether the output exists already */
  331.             for (Output = rhdPtr->Outputs; Output; Output = Output->Next)
  332.         if (Output->Id == ConnectorInfo[i].Output[k])
  333.           break;
  334.  
  335.             if (!Output) {
  336.                 if (!RHDUseAtom(rhdPtr, NULL, atomUsageOutput)) {
  337.                 switch (ConnectorInfo[i].Output[k]) {
  338.           case RHD_OUTPUT_DACA:
  339.             Output = RHDDACAInit(rhdPtr);
  340.             RHDOutputAdd(rhdPtr, Output);
  341.             break;
  342.           case RHD_OUTPUT_DACB:
  343.             Output = RHDDACBInit(rhdPtr);
  344.             RHDOutputAdd(rhdPtr, Output);
  345.             break;
  346.           case RHD_OUTPUT_TMDSA:
  347.             Output = RHDTMDSAInit(rhdPtr);
  348.             RHDOutputAdd(rhdPtr, Output);
  349.             break;
  350.           case RHD_OUTPUT_LVTMA:
  351.             Output = RHDLVTMAInit(rhdPtr, ConnectorInfo[i].Type);
  352.             RHDOutputAdd(rhdPtr, Output);
  353.             break;
  354.                     case RHD_OUTPUT_DVO:
  355.                         Output = RHDDDIAInit(rhdPtr);
  356.                     if (Output)
  357.                         RHDOutputAdd(rhdPtr, Output);
  358.                     break;
  359.                 case RHD_OUTPUT_KLDSKP_LVTMA:
  360.                 case RHD_OUTPUT_UNIPHYA:
  361.                 case RHD_OUTPUT_UNIPHYB:
  362.                     Output = RHDDIGInit(rhdPtr, ConnectorInfo[i].Output[k], ConnectorInfo[i].Type);
  363.                     RHDOutputAdd(rhdPtr, Output);
  364.                     break;
  365.           default:
  366.                     xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR,
  367.                                    "%s: unhandled output id: %d. Trying fallback to AtomBIOS\n", __func__,
  368.                                ConnectorInfo[i].Output[k]);
  369.             break;
  370.         }
  371.             }
  372. #ifdef ATOM_BIOS
  373.                 if (!Output) {
  374.                     Output = RHDAtomOutputInit(rhdPtr, ConnectorInfo[i].Type,
  375.                                                ConnectorInfo[i].Output[k]);
  376.                     if (Output)
  377.                         RHDOutputAdd(rhdPtr, Output);
  378.                 }
  379. #endif
  380.             }
  381.  
  382.             if (Output) {
  383.                 xf86DrvMsg(rhdPtr->scrnIndex, X_PROBED,
  384.                            "Attaching Output %s to Connector %s\n",
  385.                            Output->Name, Connector->Name);
  386.         for (l = 0; l < 2; l++)
  387.                     if (!Connector->Output[l]) {
  388.             Connector->Output[l] = Output;
  389.             break;
  390.           }
  391.             }
  392.     }
  393.  
  394.     rhdPtr->Connector[j] = Connector;
  395.     j++;
  396.   }
  397.   if (csstate)
  398.         xfree(csstate);
  399.  
  400.     /* Deallocate what atombios code allocated */
  401.     if (ConnectorInfo && InfoAllocated) {
  402.     for (i = 0; i < RHD_CONNECTORS_MAX; i++)
  403.             if (ConnectorInfo[i].Type != RHD_CONNECTOR_NONE)
  404.                 xfree(ConnectorInfo[i].Name);
  405.         /* Don't free the Privates as they are hooked into the rhdConnector structures !!! */
  406.         xfree(ConnectorInfo);
  407.   }
  408.  
  409.   RHDHPDRestore(rhdPtr);
  410.  
  411.   return (j && 1);
  412. }
  413.  
  414. /*
  415.  *
  416.  */
  417. void
  418. RHDConnectorsDestroy(RHDPtr rhdPtr)
  419. {
  420.   struct rhdConnector *Connector;
  421.   int i;
  422.  
  423.   RHDFUNC(rhdPtr);
  424.  
  425.     for (i = 0; i < RHD_CONNECTORS_MAX; i++) {
  426.     Connector = rhdPtr->Connector[i];
  427.         if (Connector) {
  428.             if (Connector->Monitor)
  429.                 RHDMonitorDestroy(Connector->Monitor);
  430.             xfree(Connector->Name);
  431.             xfree(Connector);
  432.     }
  433.   }
  434. }
  435.  
  436. /*
  437.  *
  438.  */
  439. void
  440. RhdPrintConnectorInfo(RHDPtr rhdPtr, struct rhdConnectorInfo *cp)
  441. {
  442.   int n;
  443.   int scrnIndex=0;
  444.  
  445.   const char *c_name[] =
  446.         { "RHD_CONNECTOR_NONE", "RHD_CONNECTOR_VGA", "RHD_CONNECTOR_DVI",
  447.           "RHD_CONNECTOR_DVI_SINGLE", "RHD_CONNECTOR_PANEL",
  448.           "RHD_CONNECTOR_TV", "RHD_CONNECTOR_PCIE" };
  449.  
  450.   const char *ddc_name[] =
  451.         { "RHD_DDC_0", "RHD_DDC_1", "RHD_DDC_2", "RHD_DDC_3", "RHD_DDC_4" };
  452.  
  453.   const char *hpd_name_normal[] =
  454.         { "RHD_HPD_NONE", "RHD_HPD_0", "RHD_HPD_1", "RHD_HPD_2", "RHD_HPD_3" };
  455.   const char *hpd_name_off[] =
  456.         { "RHD_HPD_NONE", "RHD_HPD_NONE /*0*/", "RHD_HPD_NONE /*1*/", "RHD_HPD_NONE /*2*/", "RHD_HPD_NONE /*3*/" };
  457.     const char *hpd_name_swapped[] =
  458.         { "RHD_HPD_NONE", "RHD_HPD_1 /*swapped*/", "RHD_HPD_0 /*swapped*/", "RHD_HPD_2", "RHD_HPD_3" };
  459.  
  460.   const char *output_name[] =
  461.         { "RHD_OUTPUT_NONE", "RHD_OUTPUT_DACA", "RHD_OUTPUT_DACB", "RHD_OUTPUT_TMDSA",
  462.           "RHD_OUTPUT_LVTMA", "RHD_OUTPUT_DVO", "RHD_OUTPUT_KLDSKP_LVTMA",
  463.           "RHD_OUTPUT_UNIPHYA", "RHD_OUTPUT_UNIPHYB", "RHD_OUTPUT_UNIPHYC", "RHD_OUTPUT_UNIPHYD",
  464.           "RHD_OUTPUT_UNIPHYE", "RHD_OUTPUT_UNIPHYF" };
  465.   const char **hpd_name;
  466.  
  467.     switch (rhdPtr->hpdUsage) {
  468.     case RHD_HPD_USAGE_OFF:
  469.     case RHD_HPD_USAGE_AUTO_OFF:
  470.       hpd_name = hpd_name_off;
  471.       break;
  472.     case RHD_HPD_USAGE_SWAP:
  473.     case RHD_HPD_USAGE_AUTO_SWAP:
  474.       hpd_name = hpd_name_swapped;
  475.       break;
  476.     default:
  477.      hpd_name = hpd_name_normal;
  478.      break;
  479.   }
  480.  
  481.     for (n = 0; n < RHD_CONNECTORS_MAX; n++) {
  482.     if (cp[n].Type == RHD_CONNECTOR_NONE)
  483.             break;
  484.         xf86DrvMsg(scrnIndex, X_INFO, "Connector[%i] {%s, \"%s\", %s, %s, { %s, %s } }\n",
  485.                    n, c_name[cp[n].Type], cp[n].Name,
  486.                    cp[n].DDC == RHD_DDC_NONE ? "RHD_DDC_NONE" : ddc_name[cp[n].DDC],
  487.                    hpd_name[cp[n].HPD], output_name[cp[n].Output[0]],
  488.                    output_name[cp[n].Output[1]]);
  489.   }
  490. }
  491.  
  492. /*
  493.  * Should we enable HDMI on this connector?
  494.  */
  495. Bool RHDConnectorEnableHDMI(struct rhdConnector *Connector)
  496. {
  497.     RHDPtr rhdPtr = RHDPTRI(Connector);
  498.     RHDFUNC(rhdPtr);
  499.  
  500.     /* check if user forced HDMI on this connector */
  501. //    switch(RhdParseBooleanOption(&rhdPtr->hdmi, Connector->Name)) {
  502. //      case RHD_OPTION_ON:
  503. //      case RHD_OPTION_DEFAULT:
  504. //          xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "Enabling HDMI on %s because of config option\n", Connector->Name);
  505. //          return TRUE;
  506. //      case RHD_OPTION_OFF:
  507. //          xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "Disabling HDMI on %s because of config option\n", Connector->Name);
  508. //          return FALSE;
  509. //      case RHD_OPTION_NOT_SET:
  510. //          /* ask connected monitor if it supports HDMI */
  511. //          /* TODO: Not implemented yet! */
  512. //          return FALSE;
  513. //    }
  514.  
  515.     return FALSE;
  516. }
  517.