linux/drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.c
<<
>>
Prefs
   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
  44struct 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
  55static 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
  64static 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 */
  76static 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
 177err:
 178        return false;
 179}
 180
 181/**
 182 * Stop hdmi phy macro cell tx3g4c28
 183 *
 184 * @hdmi: pointer on the hdmi internal structure
 185 */
 186static 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
 210struct hdmi_phy_ops tx3g4c28phy_ops = {
 211        .start = sti_hdmi_tx3g4c28phy_start,
 212        .stop = sti_hdmi_tx3g4c28phy_stop,
 213};
 214