cregit-Linux how code gets into the kernel

Release 4.7 drivers/gpu/drm/sti/sti_hdmi_tx3g0c55phy.c

/*
 * Copyright (C) STMicroelectronics SA 2014
 * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
 * License terms:  GNU General Public License (GPL), version 2
 */

#include "sti_hdmi_tx3g0c55phy.h"


#define HDMI_SRZ_PLL_CFG                0x0504

#define HDMI_SRZ_TAP_1                  0x0508

#define HDMI_SRZ_TAP_2                  0x050C

#define HDMI_SRZ_TAP_3                  0x0510

#define HDMI_SRZ_CTRL                   0x0514


#define HDMI_SRZ_PLL_CFG_POWER_DOWN     BIT(0)

#define HDMI_SRZ_PLL_CFG_VCOR_SHIFT     1

#define HDMI_SRZ_PLL_CFG_VCOR_425MHZ    0

#define HDMI_SRZ_PLL_CFG_VCOR_850MHZ    1

#define HDMI_SRZ_PLL_CFG_VCOR_1700MHZ   2

#define HDMI_SRZ_PLL_CFG_VCOR_3000MHZ   3

#define HDMI_SRZ_PLL_CFG_VCOR_MASK      3

#define HDMI_SRZ_PLL_CFG_VCOR(x)        (x << HDMI_SRZ_PLL_CFG_VCOR_SHIFT)

#define HDMI_SRZ_PLL_CFG_NDIV_SHIFT     8

#define HDMI_SRZ_PLL_CFG_NDIV_MASK      (0x1F << HDMI_SRZ_PLL_CFG_NDIV_SHIFT)

#define HDMI_SRZ_PLL_CFG_MODE_SHIFT     16

#define HDMI_SRZ_PLL_CFG_MODE_13_5_MHZ  0x1

#define HDMI_SRZ_PLL_CFG_MODE_25_2_MHZ  0x4

#define HDMI_SRZ_PLL_CFG_MODE_27_MHZ    0x5

#define HDMI_SRZ_PLL_CFG_MODE_33_75_MHZ 0x6

#define HDMI_SRZ_PLL_CFG_MODE_40_5_MHZ  0x7

#define HDMI_SRZ_PLL_CFG_MODE_54_MHZ    0x8

#define HDMI_SRZ_PLL_CFG_MODE_67_5_MHZ  0x9

#define HDMI_SRZ_PLL_CFG_MODE_74_25_MHZ 0xA

#define HDMI_SRZ_PLL_CFG_MODE_81_MHZ    0xB

#define HDMI_SRZ_PLL_CFG_MODE_82_5_MHZ  0xC

#define HDMI_SRZ_PLL_CFG_MODE_108_MHZ   0xD

#define HDMI_SRZ_PLL_CFG_MODE_148_5_MHZ 0xE

#define HDMI_SRZ_PLL_CFG_MODE_165_MHZ   0xF

#define HDMI_SRZ_PLL_CFG_MODE_MASK      0xF

#define HDMI_SRZ_PLL_CFG_MODE(x)        (x << HDMI_SRZ_PLL_CFG_MODE_SHIFT)


#define HDMI_SRZ_CTRL_POWER_DOWN        (1 << 0)

#define HDMI_SRZ_CTRL_EXTERNAL_DATA_EN  (1 << 1)

/* sysconf registers */

#define HDMI_REJECTION_PLL_CONFIGURATION 0x0858	
/* SYSTEM_CONFIG2534 */

#define HDMI_REJECTION_PLL_STATUS        0x0948	
/* SYSTEM_CONFIG2594 */


#define REJECTION_PLL_HDMI_ENABLE_SHIFT 0

#define REJECTION_PLL_HDMI_ENABLE_MASK  (0x1 << REJECTION_PLL_HDMI_ENABLE_SHIFT)

#define REJECTION_PLL_HDMI_PDIV_SHIFT   24

#define REJECTION_PLL_HDMI_PDIV_MASK    (0x7 << REJECTION_PLL_HDMI_PDIV_SHIFT)

#define REJECTION_PLL_HDMI_NDIV_SHIFT   16

#define REJECTION_PLL_HDMI_NDIV_MASK    (0xFF << REJECTION_PLL_HDMI_NDIV_SHIFT)

#define REJECTION_PLL_HDMI_MDIV_SHIFT   8

#define REJECTION_PLL_HDMI_MDIV_MASK    (0xFF << REJECTION_PLL_HDMI_MDIV_SHIFT)


#define REJECTION_PLL_HDMI_REJ_PLL_LOCK BIT(0)


#define HDMI_TIMEOUT_PLL_LOCK  50   
/*milliseconds */

/**
 * pll mode structure
 *
 * A pointer to an array of these structures is passed to a TMDS (HDMI) output
 * via the control interface to provide board and SoC specific
 * configurations of the HDMI PHY. Each entry in the array specifies a hardware
 * specific configuration for a given TMDS clock frequency range. The array
 * should be terminated with an entry that has all fields set to zero.
 *
 * @min: Lower bound of TMDS clock frequency this entry applies to
 * @max: Upper bound of TMDS clock frequency this entry applies to
 * @mode: SoC specific register configuration
 */

struct pllmode {
	
u32 min;
	
u32 max;
	
u32 mode;
};


#define NB_PLL_MODE 7

static struct pllmode pllmodes[NB_PLL_MODE] = {
	{13500000, 13513500, HDMI_SRZ_PLL_CFG_MODE_13_5_MHZ},
	{25174800, 25200000, HDMI_SRZ_PLL_CFG_MODE_25_2_MHZ},
	{27000000, 27027000, HDMI_SRZ_PLL_CFG_MODE_27_MHZ},
	{54000000, 54054000, HDMI_SRZ_PLL_CFG_MODE_54_MHZ},
	{72000000, 74250000, HDMI_SRZ_PLL_CFG_MODE_74_25_MHZ},
	{108000000, 108108000, HDMI_SRZ_PLL_CFG_MODE_108_MHZ},
	{148351648, 297000000, HDMI_SRZ_PLL_CFG_MODE_148_5_MHZ}
};


#define NB_HDMI_PHY_CONFIG 5

static struct hdmi_phy_config hdmiphy_config[NB_HDMI_PHY_CONFIG] = {
	{0, 40000000, {0x00101010, 0x00101010, 0x00101010, 0x02} },
	{40000000, 140000000, {0x00111111, 0x00111111, 0x00111111, 0x02} },
	{140000000, 160000000, {0x00131313, 0x00101010, 0x00101010, 0x02} },
	{160000000, 250000000, {0x00131313, 0x00111111, 0x00111111, 0x03FE} },
	{250000000, 300000000, {0x00151515, 0x00101010, 0x00101010, 0x03FE} },
};


#define PLL_CHANGE_DELAY	1 
/* ms */

/**
 * Disable the pll rejection
 *
 * @hdmi: pointer on the hdmi internal structure
 *
 * return true if the pll has been disabled
 */

static bool disable_pll_rejection(struct sti_hdmi *hdmi) { u32 val; DRM_DEBUG_DRIVER("\n"); val = readl(hdmi->syscfg + HDMI_REJECTION_PLL_CONFIGURATION); val &= ~REJECTION_PLL_HDMI_ENABLE_MASK; writel(val, hdmi->syscfg + HDMI_REJECTION_PLL_CONFIGURATION); msleep(PLL_CHANGE_DELAY); val = readl(hdmi->syscfg + HDMI_REJECTION_PLL_STATUS); return !(val & REJECTION_PLL_HDMI_REJ_PLL_LOCK); }

Contributors

PersonTokensPropCommitsCommitProp
benjamin gaignardbenjamin gaignard70100.00%1100.00%
Total70100.00%1100.00%

/** * Enable the old BCH/rejection PLL is now reused to provide the CLKPXPLL * clock input to the new PHY PLL that generates the serializer clock * (TMDS*10) and the TMDS clock which is now fed back into the HDMI * formatter instead of the TMDS clock line from ClockGenB. * * @hdmi: pointer on the hdmi internal structure * * return true if pll has been correctly set */
static bool enable_pll_rejection(struct sti_hdmi *hdmi) { unsigned int inputclock; u32 mdiv, ndiv, pdiv, val; DRM_DEBUG_DRIVER("\n"); if (!disable_pll_rejection(hdmi)) return false; inputclock = hdmi->mode.clock * 1000; DRM_DEBUG_DRIVER("hdmi rejection pll input clock = %dHz\n", inputclock); /* Power up the HDMI rejection PLL * Note: On this SoC (stiH416) we are forced to have the input clock * be equal to the HDMI pixel clock. * * The values here have been suggested by validation however they are * still provisional and subject to change. * * PLLout = (Fin*Mdiv) / ((2 * Ndiv) / 2^Pdiv) */ if (inputclock < 50000000) { /* * For slower clocks we need to multiply more to keep the * internal VCO frequency within the physical specification * of the PLL. */ pdiv = 4; ndiv = 240; mdiv = 30; } else { pdiv = 2; ndiv = 60; mdiv = 30; } val = readl(hdmi->syscfg + HDMI_REJECTION_PLL_CONFIGURATION); val &= ~(REJECTION_PLL_HDMI_PDIV_MASK | REJECTION_PLL_HDMI_NDIV_MASK | REJECTION_PLL_HDMI_MDIV_MASK | REJECTION_PLL_HDMI_ENABLE_MASK); val |= (pdiv << REJECTION_PLL_HDMI_PDIV_SHIFT) | (ndiv << REJECTION_PLL_HDMI_NDIV_SHIFT) | (mdiv << REJECTION_PLL_HDMI_MDIV_SHIFT) | (0x1 << REJECTION_PLL_HDMI_ENABLE_SHIFT); writel(val, hdmi->syscfg + HDMI_REJECTION_PLL_CONFIGURATION); msleep(PLL_CHANGE_DELAY); val = readl(hdmi->syscfg + HDMI_REJECTION_PLL_STATUS); return (val & REJECTION_PLL_HDMI_REJ_PLL_LOCK); }

Contributors

PersonTokensPropCommitsCommitProp
benjamin gaignardbenjamin gaignard178100.00%1100.00%
Total178100.00%1100.00%

/** * Start hdmi phy macro cell tx3g0c55 * * @hdmi: pointer on the hdmi internal structure * * Return false if an error occur */
static bool sti_hdmi_tx3g0c55phy_start(struct sti_hdmi *hdmi) { u32 ckpxpll = hdmi->mode.clock * 1000; u32 val, tmdsck, freqvco, pllctrl = 0; unsigned int i; if (!enable_pll_rejection(hdmi)) return false; DRM_DEBUG_DRIVER("ckpxpll = %dHz\n", ckpxpll); /* Assuming no pixel repetition and 24bits color */ tmdsck = ckpxpll; pllctrl = 2 << HDMI_SRZ_PLL_CFG_NDIV_SHIFT; /* * Setup the PLL mode parameter based on the ckpxpll. If we haven't got * a clock frequency supported by one of the specific PLL modes then we * will end up using the generic mode (0) which only supports a 10x * multiplier, hence only 24bit color. */ for (i = 0; i < NB_PLL_MODE; i++) { if (ckpxpll >= pllmodes[i].min && ckpxpll <= pllmodes[i].max) pllctrl |= HDMI_SRZ_PLL_CFG_MODE(pllmodes[i].mode); } freqvco = tmdsck * 10; if (freqvco <= 425000000UL) pllctrl |= HDMI_SRZ_PLL_CFG_VCOR(HDMI_SRZ_PLL_CFG_VCOR_425MHZ); else if (freqvco <= 850000000UL) pllctrl |= HDMI_SRZ_PLL_CFG_VCOR(HDMI_SRZ_PLL_CFG_VCOR_850MHZ); else if (freqvco <= 1700000000UL) pllctrl |= HDMI_SRZ_PLL_CFG_VCOR(HDMI_SRZ_PLL_CFG_VCOR_1700MHZ); else if (freqvco <= 2970000000UL) pllctrl |= HDMI_SRZ_PLL_CFG_VCOR(HDMI_SRZ_PLL_CFG_VCOR_3000MHZ); else { DRM_ERROR("PHY serializer clock out of range\n"); goto err; } /* * Configure and power up the PHY PLL */ hdmi->event_received = false; DRM_DEBUG_DRIVER("pllctrl = 0x%x\n", pllctrl); hdmi_write(hdmi, pllctrl, HDMI_SRZ_PLL_CFG); /* wait PLL interrupt */ wait_event_interruptible_timeout(hdmi->wait_event, hdmi->event_received == true, msecs_to_jiffies (HDMI_TIMEOUT_PLL_LOCK)); if ((hdmi_read(hdmi, HDMI_STA) & HDMI_STA_DLL_LCK) == 0) { DRM_ERROR("hdmi phy pll not locked\n"); goto err; } DRM_DEBUG_DRIVER("got PHY PLL Lock\n"); /* * To configure the source termination and pre-emphasis appropriately * for different high speed TMDS clock frequencies a phy configuration * table must be provided, tailored to the SoC and board combination. */ for (i = 0; i < NB_HDMI_PHY_CONFIG; i++) { if ((hdmiphy_config[i].min_tmds_freq <= tmdsck) && (hdmiphy_config[i].max_tmds_freq >= tmdsck)) { val = hdmiphy_config[i].config[0]; hdmi_write(hdmi, val, HDMI_SRZ_TAP_1); val = hdmiphy_config[i].config[1]; hdmi_write(hdmi, val, HDMI_SRZ_TAP_2); val = hdmiphy_config[i].config[2]; hdmi_write(hdmi, val, HDMI_SRZ_TAP_3); val = hdmiphy_config[i].config[3]; val |= HDMI_SRZ_CTRL_EXTERNAL_DATA_EN; val &= ~HDMI_SRZ_CTRL_POWER_DOWN; hdmi_write(hdmi, val, HDMI_SRZ_CTRL); DRM_DEBUG_DRIVER("serializer cfg 0x%x 0x%x 0x%x 0x%x\n", hdmiphy_config[i].config[0], hdmiphy_config[i].config[1], hdmiphy_config[i].config[2], hdmiphy_config[i].config[3]); return true; } } /* * Default, power up the serializer with no pre-emphasis or source * termination. */ hdmi_write(hdmi, 0x0, HDMI_SRZ_TAP_1); hdmi_write(hdmi, 0x0, HDMI_SRZ_TAP_2); hdmi_write(hdmi, 0x0, HDMI_SRZ_TAP_3); hdmi_write(hdmi, HDMI_SRZ_CTRL_EXTERNAL_DATA_EN, HDMI_SRZ_CTRL); return true; err: disable_pll_rejection(hdmi); return false; }

Contributors

PersonTokensPropCommitsCommitProp
benjamin gaignardbenjamin gaignard491100.00%1100.00%
Total491100.00%1100.00%

/** * Stop hdmi phy macro cell tx3g0c55 * * @hdmi: pointer on the hdmi internal structure */
static void sti_hdmi_tx3g0c55phy_stop(struct sti_hdmi *hdmi) { DRM_DEBUG_DRIVER("\n"); hdmi->event_received = false; hdmi_write(hdmi, HDMI_SRZ_CTRL_POWER_DOWN, HDMI_SRZ_CTRL); hdmi_write(hdmi, HDMI_SRZ_PLL_CFG_POWER_DOWN, HDMI_SRZ_PLL_CFG); /* wait PLL interrupt */ wait_event_interruptible_timeout(hdmi->wait_event, hdmi->event_received == true, msecs_to_jiffies (HDMI_TIMEOUT_PLL_LOCK)); if (hdmi_read(hdmi, HDMI_STA) & HDMI_STA_DLL_LCK) DRM_ERROR("hdmi phy pll not well disabled\n"); disable_pll_rejection(hdmi); }

Contributors

PersonTokensPropCommitsCommitProp
benjamin gaignardbenjamin gaignard80100.00%1100.00%
Total80100.00%1100.00%

struct hdmi_phy_ops tx3g0c55phy_ops = { .start = sti_hdmi_tx3g0c55phy_start, .stop = sti_hdmi_tx3g0c55phy_stop, };

Overall Contributors

PersonTokensPropCommitsCommitProp
benjamin gaignardbenjamin gaignard1217100.00%1100.00%
Total1217100.00%1100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}