root/drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sti_hdmi_tx3g4c28phy_start
  2. sti_hdmi_tx3g4c28phy_stop

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright (C) STMicroelectronics SA 2014
   4  * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
   5  */
   6 
   7 #include <drm/drm_print.h>
   8 
   9 #include "sti_hdmi_tx3g4c28phy.h"
  10 
  11 #define HDMI_SRZ_CFG                             0x504
  12 #define HDMI_SRZ_PLL_CFG                         0x510
  13 #define HDMI_SRZ_ICNTL                           0x518
  14 #define HDMI_SRZ_CALCODE_EXT                     0x520
  15 
  16 #define HDMI_SRZ_CFG_EN                          BIT(0)
  17 #define HDMI_SRZ_CFG_DISABLE_BYPASS_SINK_CURRENT BIT(1)
  18 #define HDMI_SRZ_CFG_EXTERNAL_DATA               BIT(16)
  19 #define HDMI_SRZ_CFG_RBIAS_EXT                   BIT(17)
  20 #define HDMI_SRZ_CFG_EN_SINK_TERM_DETECTION      BIT(18)
  21 #define HDMI_SRZ_CFG_EN_BIASRES_DETECTION        BIT(19)
  22 #define HDMI_SRZ_CFG_EN_SRC_TERMINATION          BIT(24)
  23 
  24 #define HDMI_SRZ_CFG_INTERNAL_MASK  (HDMI_SRZ_CFG_EN     | \
  25                 HDMI_SRZ_CFG_DISABLE_BYPASS_SINK_CURRENT | \
  26                 HDMI_SRZ_CFG_EXTERNAL_DATA               | \
  27                 HDMI_SRZ_CFG_RBIAS_EXT                   | \
  28                 HDMI_SRZ_CFG_EN_SINK_TERM_DETECTION      | \
  29                 HDMI_SRZ_CFG_EN_BIASRES_DETECTION        | \
  30                 HDMI_SRZ_CFG_EN_SRC_TERMINATION)
  31 
  32 #define PLL_CFG_EN                               BIT(0)
  33 #define PLL_CFG_NDIV_SHIFT                       (8)
  34 #define PLL_CFG_IDF_SHIFT                        (16)
  35 #define PLL_CFG_ODF_SHIFT                        (24)
  36 
  37 #define ODF_DIV_1                                (0)
  38 #define ODF_DIV_2                                (1)
  39 #define ODF_DIV_4                                (2)
  40 #define ODF_DIV_8                                (3)
  41 
  42 #define HDMI_TIMEOUT_PLL_LOCK  50  /*milliseconds */
  43 
  44 struct plldividers_s {
  45         uint32_t min;
  46         uint32_t max;
  47         uint32_t idf;
  48         uint32_t odf;
  49 };
  50 
  51 /*
  52  * Functional specification recommended values
  53  */
  54 #define NB_PLL_MODE 5
  55 static struct plldividers_s plldividers[NB_PLL_MODE] = {
  56         {0, 20000000, 1, ODF_DIV_8},
  57         {20000000, 42500000, 2, ODF_DIV_8},
  58         {42500000, 85000000, 4, ODF_DIV_4},
  59         {85000000, 170000000, 8, ODF_DIV_2},
  60         {170000000, 340000000, 16, ODF_DIV_1}
  61 };
  62 
  63 #define NB_HDMI_PHY_CONFIG 2
  64 static struct hdmi_phy_config hdmiphy_config[NB_HDMI_PHY_CONFIG] = {
  65         {0, 250000000, {0x0, 0x0, 0x0, 0x0} },
  66         {250000000, 300000000, {0x1110, 0x0, 0x0, 0x0} },
  67 };
  68 
  69 /**
  70  * Start hdmi phy macro cell tx3g4c28
  71  *
  72  * @hdmi: pointer on the hdmi internal structure
  73  *
  74  * Return false if an error occur
  75  */
  76 static bool sti_hdmi_tx3g4c28phy_start(struct sti_hdmi *hdmi)
  77 {
  78         u32 ckpxpll = hdmi->mode.clock * 1000;
  79         u32 val, tmdsck, idf, odf, pllctrl = 0;
  80         bool foundplldivides = false;
  81         int i;
  82 
  83         DRM_DEBUG_DRIVER("ckpxpll = %dHz\n", ckpxpll);
  84 
  85         for (i = 0; i < NB_PLL_MODE; i++) {
  86                 if (ckpxpll >= plldividers[i].min &&
  87                     ckpxpll < plldividers[i].max) {
  88                         idf = plldividers[i].idf;
  89                         odf = plldividers[i].odf;
  90                         foundplldivides = true;
  91                         break;
  92                 }
  93         }
  94 
  95         if (!foundplldivides) {
  96                 DRM_ERROR("input TMDS clock speed (%d) not supported\n",
  97                           ckpxpll);
  98                 goto err;
  99         }
 100 
 101         /* Assuming no pixel repetition and 24bits color */
 102         tmdsck = ckpxpll;
 103         pllctrl |= 40 << PLL_CFG_NDIV_SHIFT;
 104 
 105         if (tmdsck > 340000000) {
 106                 DRM_ERROR("output TMDS clock (%d) out of range\n", tmdsck);
 107                 goto err;
 108         }
 109 
 110         pllctrl |= idf << PLL_CFG_IDF_SHIFT;
 111         pllctrl |= odf << PLL_CFG_ODF_SHIFT;
 112 
 113         /*
 114          * Configure and power up the PHY PLL
 115          */
 116         hdmi->event_received = false;
 117         DRM_DEBUG_DRIVER("pllctrl = 0x%x\n", pllctrl);
 118         hdmi_write(hdmi, (pllctrl | PLL_CFG_EN), HDMI_SRZ_PLL_CFG);
 119 
 120         /* wait PLL interrupt */
 121         wait_event_interruptible_timeout(hdmi->wait_event,
 122                                          hdmi->event_received == true,
 123                                          msecs_to_jiffies
 124                                          (HDMI_TIMEOUT_PLL_LOCK));
 125 
 126         if ((hdmi_read(hdmi, HDMI_STA) & HDMI_STA_DLL_LCK) == 0) {
 127                 DRM_ERROR("hdmi phy pll not locked\n");
 128                 goto err;
 129         }
 130 
 131         DRM_DEBUG_DRIVER("got PHY PLL Lock\n");
 132 
 133         val = (HDMI_SRZ_CFG_EN |
 134                HDMI_SRZ_CFG_EXTERNAL_DATA |
 135                HDMI_SRZ_CFG_EN_BIASRES_DETECTION |
 136                HDMI_SRZ_CFG_EN_SINK_TERM_DETECTION);
 137 
 138         if (tmdsck > 165000000)
 139                 val |= HDMI_SRZ_CFG_EN_SRC_TERMINATION;
 140 
 141         /*
 142          * To configure the source termination and pre-emphasis appropriately
 143          * for different high speed TMDS clock frequencies a phy configuration
 144          * table must be provided, tailored to the SoC and board combination.
 145          */
 146         for (i = 0; i < NB_HDMI_PHY_CONFIG; i++) {
 147                 if ((hdmiphy_config[i].min_tmds_freq <= tmdsck) &&
 148                     (hdmiphy_config[i].max_tmds_freq >= tmdsck)) {
 149                         val |= (hdmiphy_config[i].config[0]
 150                                 & ~HDMI_SRZ_CFG_INTERNAL_MASK);
 151                         hdmi_write(hdmi, val, HDMI_SRZ_CFG);
 152 
 153                         val = hdmiphy_config[i].config[1];
 154                         hdmi_write(hdmi, val, HDMI_SRZ_ICNTL);
 155 
 156                         val = hdmiphy_config[i].config[2];
 157                         hdmi_write(hdmi, val, HDMI_SRZ_CALCODE_EXT);
 158 
 159                         DRM_DEBUG_DRIVER("serializer cfg 0x%x 0x%x 0x%x\n",
 160                                          hdmiphy_config[i].config[0],
 161                                          hdmiphy_config[i].config[1],
 162                                          hdmiphy_config[i].config[2]);
 163                         return true;
 164                 }
 165         }
 166 
 167         /*
 168          * Default, power up the serializer with no pre-emphasis or
 169          * output swing correction
 170          */
 171         hdmi_write(hdmi, val,  HDMI_SRZ_CFG);
 172         hdmi_write(hdmi, 0x0, HDMI_SRZ_ICNTL);
 173         hdmi_write(hdmi, 0x0, HDMI_SRZ_CALCODE_EXT);
 174 
 175         return true;
 176 
 177 err:
 178         return false;
 179 }
 180 
 181 /**
 182  * Stop hdmi phy macro cell tx3g4c28
 183  *
 184  * @hdmi: pointer on the hdmi internal structure
 185  */
 186 static void sti_hdmi_tx3g4c28phy_stop(struct sti_hdmi *hdmi)
 187 {
 188         int val = 0;
 189 
 190         DRM_DEBUG_DRIVER("\n");
 191 
 192         hdmi->event_received = false;
 193 
 194         val = HDMI_SRZ_CFG_EN_SINK_TERM_DETECTION;
 195         val |= HDMI_SRZ_CFG_EN_BIASRES_DETECTION;
 196 
 197         hdmi_write(hdmi, val, HDMI_SRZ_CFG);
 198         hdmi_write(hdmi, 0, HDMI_SRZ_PLL_CFG);
 199 
 200         /* wait PLL interrupt */
 201         wait_event_interruptible_timeout(hdmi->wait_event,
 202                                          hdmi->event_received == true,
 203                                          msecs_to_jiffies
 204                                          (HDMI_TIMEOUT_PLL_LOCK));
 205 
 206         if (hdmi_read(hdmi, HDMI_STA) & HDMI_STA_DLL_LCK)
 207                 DRM_ERROR("hdmi phy pll not well disabled\n");
 208 }
 209 
 210 struct hdmi_phy_ops tx3g4c28phy_ops = {
 211         .start = sti_hdmi_tx3g4c28phy_start,
 212         .stop = sti_hdmi_tx3g4c28phy_stop,
 213 };

/* [<][>][^][v][top][bottom][index][help] */