|
@@ -1,336 +0,0 @@
|
|
|
-/*
|
|
|
- * 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);
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * 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);
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * 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;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * 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);
|
|
|
-}
|
|
|
-
|
|
|
-struct hdmi_phy_ops tx3g0c55phy_ops = {
|
|
|
- .start = sti_hdmi_tx3g0c55phy_start,
|
|
|
- .stop = sti_hdmi_tx3g0c55phy_stop,
|
|
|
-};
|