cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sti_hdmi_tx3g4c28phy.c (5945B)


      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 * sti_hdmi_tx3g4c28phy_start - 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 * sti_hdmi_tx3g4c28phy_stop - 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};