aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/emgd/emgd/display/mode/tnc/clocks_tnc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/emgd/emgd/display/mode/tnc/clocks_tnc.c')
-rw-r--r--drivers/gpu/drm/emgd/emgd/display/mode/tnc/clocks_tnc.c591
1 files changed, 0 insertions, 591 deletions
diff --git a/drivers/gpu/drm/emgd/emgd/display/mode/tnc/clocks_tnc.c b/drivers/gpu/drm/emgd/emgd/display/mode/tnc/clocks_tnc.c
deleted file mode 100644
index 8be11994221b..000000000000
--- a/drivers/gpu/drm/emgd/emgd/display/mode/tnc/clocks_tnc.c
+++ /dev/null
@@ -1,591 +0,0 @@
-/* -*- pse-c -*-
- *-----------------------------------------------------------------------------
- * Filename: clocks_tnc.c
- * $Revision: 1.11 $
- *-----------------------------------------------------------------------------
- * Copyright © 2002-2010, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- *-----------------------------------------------------------------------------
- * Description:
- * Clock programming for Atom E6xx
- * program clocks used for LVDS port based on Lincroft
- * program clocks used for SDVO port based on Atom E6xx overlay
- *-----------------------------------------------------------------------------
- */
-
-#define MODULE_NAME hal.mode
-
-#include <io.h>
-#include <sched.h>
-
-#include <igd_init.h>
-#include <igd_mode.h>
-
-#include <context.h>
-#include <dsp.h>
-#include <utils.h>
-#include <mode.h>
-#include <pi.h>
-#include <intelpci.h>
-
-#include <tnc/regs.h>
-
-/*!
- * @addtogroup display_group
- * @{
- */
-
-/* Enable this if calculated values are wrong and required fixed table */
-#define CONFIG_FIXED_TABLE 0
-
-#ifdef CONFIG_TNC
-
-extern int program_clock_sdvo_tnc(igd_display_context_t *display,
- igd_clock_t *clock, unsigned long dclk);
-
-/*===========================================================================
-; File Global Data
-;--------------------------------------------------------------------------*/
-#if CONFIG_FIXED_TABLE
-typedef struct _fixed_clock {
- unsigned long dclk;
- unsigned long n;
- unsigned long m;
- unsigned long p1;
-} fixed_clock_t;
-
-/* set mmio register required values */
-static fixed_clock_t lvds_fixed_clock_table[] = {
- /* Clock N M P1 */
- { 65000, 0x01, 0x00, 0x00 },
- { 0xffffffff, 0x01, 0x00, 0x00}
-};
-
-/* set mmio register required values */
-static fixed_clock_t sdvo_fixed_clock_table[] = {
- /* Clock N M P1 */
- { 65000, 0x00, 0x00, 0x00 },
- { 0xffffffff, 0x00, 0x00, 0x00}
-};
-#endif
-
-#define LVDS_M_MIN 10
-
-/* This table is also used by mode_tnc.c */
-const unsigned long lvds_m_converts[] = {
- 0x2B, 0x15, 0x2A, 0x35, 0x1A, 0x0D, 0x26, 0x33, 0x19, 0x2C,
- 0x36, 0x3B, 0x1D, 0x2E, 0x37, 0x1B, 0x2D, 0x16, 0x0B, 0x25,
- 0x12, 0x09, 0x24, 0x32, 0x39, 0x1c,
-};
-
-const unsigned long LVDS_M_CONVERTS_LEN=26; /* Length of the array above*/
-
-#define TARGET_ERROR 46
-
-typedef const struct _tnc_limits {
- unsigned long ref_freq;
- unsigned long min_m;
- unsigned long max_m;
-
- unsigned long min_n;
- unsigned long max_n;
-
- unsigned long min_p1;
- unsigned long max_p1;
-
- unsigned long min_p2;
- unsigned long max_p2;
-
- unsigned long min_vco;
- unsigned long max_vco;
-} tnc_limits_t;
-
-/* m, n, p value limits:
- * source: http://moss.amr.ith.intel.com/sites/LCD/LNC/HAS/Secured
- * %20Documents/LNC%20HAS%20work%20area/Lincroft%20DPLL_1.2_ww31_08.docx
- *
- * Note:
- * VCO range for 100L is not given: so put a range big enough to go through
- * calculations for the for loop.
- */
-static tnc_limits_t tnc_lvds_limits[] =
-{
- /* reffreq m n p1 p2 vco */
- { 200000, 10, 17, 1, 1, 2, 8, 14, 14, 2000000, 3400000}, /* SKU 100 */
- { 100000, 20, 34, 1, 1, 2, 8, 14, 14, 1000000, 3400000}, /* SKU 100L */
- { 166000, 12, 20, 1, 1, 2, 7, 14, 14, 2000000, 3333333}, /* SKU 83 */
-};
-
-static tnc_limits_t tnc_sdvo_limits[] =
-{
- /* reffreq m n p1 p2 vco */
- { 96000, 80,137, 3, 7, 1, 2, 10, 10, 1400000, 2800000}, /* SDVO */
-};
-
-/*!
- *
- * @param dclk
- * @param ref_freq
- * @param limits
- * @param m
- * @param n
- * @param p
- * @param target_error
- *
- * @return 0 on success
- * @return 1 on failure
- */
-static int calculate_clock(unsigned long dclk,
- unsigned long ref_freq,
- tnc_limits_t *l,
- unsigned long *m,
- unsigned long *n,
- unsigned long *p1,
- unsigned long target_error,
- unsigned long *actual_dclk,
- unsigned long port_type,
- unsigned long pd_type)
-{
- unsigned long pdiv;
- unsigned long target_vco, actual_freq;
- long freq_error, min_error;
- unsigned long dclk_10000;
-
- unsigned long current_m, current_n, current_p1;
-
- EMGD_TRACE_ENTER;
-
- min_error = 100000;
-
- *m = 0;
- *n = 0;
- *p1 = 0;
-
- /* dclk * 10000, so it does not have to be calculated within the
- * loop */
- dclk_10000 = dclk * 10000;
-
- for(current_m = l->min_m; current_m <= l->max_m; current_m++) {
- for(current_n = l->min_n; current_n <= l->max_n; current_n++) {
- for(current_p1 = l->min_p1; current_p1 <= l->max_p1; current_p1++) {
-
- /* For both LVDS/SDVO ports min_p2 and max_p2 are same,
- * so assign use either min/max p2 */
- pdiv = current_p1 * l->min_p2;
- target_vco = dclk * pdiv;
-
- if (target_vco > l->max_vco) {
- /* target_vco continues to increase, so start with
- * next current_n */
- break;
- }
-
- if (target_vco >= l->min_vco) {
- /* Frequency calculations for SDVO and LVDS are different
- * SDVO Dotclock_frequency = (Reference Frequency * (M+2)) / (N*(P1*P2))
- * LVDS DotClk_Frequency = (ReferenceFrequency * M)/ (P1* P2)
- * need to find a way to differentiate SDVO and LVDS
- * Works for now but signal generated will be different */
- actual_freq = (ref_freq * current_m) / (current_n*pdiv);
- freq_error = 10000 - (dclk_10000 / actual_freq);
-
- if (freq_error < -min_error) {
- /* freq_error continues to decrease once this
- * point is reached, so start with next
- * current_n */
- break;
- }
-
- if (freq_error < 0) {
- freq_error = -freq_error;
- }
- if (freq_error < min_error) {
- *n = current_n;
- *m = current_m;
- *p1 = current_p1;
- min_error = freq_error;
- *actual_dclk = actual_freq;
- }
- }
- }
- }
- if (min_error == 0) {
- break;
- }
- }
-
- if (pd_type == PD_DISPLAY_TVOUT) {
- EMGD_TRACE_EXIT;
- return 0;
- }
- /*
- * No clock found that meets error requirement
- */
- if (min_error > (long)target_error) {
- EMGD_TRACE_EXIT;
- return 1;
- }
-
- EMGD_DEBUG("dclk = (ref*m)/(n*p1*p2) => %lu = (%lu*%lu)/(%lu*%lu*%lu) = %lu",
- dclk, ref_freq, *m, *n, *p1, l->min_p2,
- (ref_freq*(*m))/((*n)*(*p1)*l->min_p2));
- EMGD_DEBUG("min_error:%ld", min_error);
- EMGD_TRACE_EXIT;
- return 0;
-}
-
-/*!
- *
- * @param dclk
- * @param ref_freq
- * @param limits
- * @param m
- * @param n
- * @param p
- * @param target_error
- * @param port_type
- * @param pd_type
- *
- * @return 0 on success
- * @return 1 on failure
- */
-static int get_clock(unsigned long dclk,
- unsigned long ref_freq,
- tnc_limits_t *l,
- unsigned long *m,
- unsigned long *n,
- unsigned long *p1,
- unsigned long target_error,
- unsigned long port_type,
- unsigned long *actual_dclk,
- unsigned long pd_type)
-{
-
-#if CONFIG_FIXED_TABLE
- fixed_clock_t *fixed;
- EMGD_TRACE_ENTER;
- /* Enable this if calculated values are wrong and required fixed table */
- if (port_type == IGD_PORT_LVDS) {
- fixed = lvds_fixed_clock_table;
- } else {
- fixed = sdvo_fixed_clock_table;
- }
-
- /* First check for a fixed clock from the table. These are ones that
- * can't be calculated correctly. */
- while (fixed->dclk != 0xffffffff) {
- if (fixed->dclk == dclk) {
- EMGD_DEBUG("Using Fixed Clock From table for clock %ld", dclk);
- *m = fixed->m;
- *n = fixed->n;
- *p1 = fixed->p1;
- EMGD_TRACE_EXIT;
- return 0;
- }
- fixed++;
- }
-#endif
-
- EMGD_TRACE_ENTER;
- /* No fixed clock found so calculate one. */
- EMGD_DEBUG("Calculating dynamic clock for clock %ld", dclk);
-
- if (calculate_clock(dclk, ref_freq, l, m, n, p1, target_error, actual_dclk, port_type, pd_type)) {
- /* No usable clock. Cannot use 640x480@60 as default, because
- * there are several vcos and several reference clocks. */
- EMGD_ERROR("Could not calculate clock %ld, returning default.", dclk);
- EMGD_TRACE_EXIT;
- return 1;
- }
-
- if (pd_type == PD_DISPLAY_TVOUT) {
- *p1 = 2;
- *m = 100;
- *n = 5;
- }
-
- /* Translate returned values to m,n,p1 register values */
- /* No change required for *n value */
- if (port_type == IGD_PORT_SDVO) {
- *p1 = (1L << (*p1 - 1));
- *m -= 2;
- *n = (1L << (*n -1));
- } else {
- *p1 = (1L << (*p1 - 2));
- *m = lvds_m_converts[*m - LVDS_M_MIN];
- }
-
- EMGD_DEBUG("reg m=%lu n=%lu p1=%lu p2=%lu", *m, *n, *p1, l->min_p2);
-
- EMGD_TRACE_EXIT;
- return 0;
-}
-
-/*!
- *
- * @param display
- * @param clock
- * @param dclk
- *
- * @return 0 on success
- * @return 1 on failure
- */
-int program_clock_lvds_tnc(igd_display_context_t *display,
- igd_clock_t *clock,
- unsigned long dclk)
-{
- int ret;
- unsigned long m, n, p1;
- unsigned long control;
- unsigned long ref_freq;
- igd_display_port_t *port;
- tnc_limits_t *l = NULL;
- unsigned long count;
-
- EMGD_TRACE_ENTER;
-
- port = PORT_OWNER(display);
-
- /* LNC ref_freq is determined by SKU, convert to KHz */
-#if 0
- ref_freq = display->context->device_context.gfx_freq * 1000L;
-#else
- ref_freq = display->context->device_context.core_freq;
- ref_freq = ref_freq * 1000;
-#endif
-
-#if 0
- /* Find m,n,p,vco limits */
- if (ref_freq == 200000) {
- l = &tnc_lvds_limits[0];
- } else if (ref_freq == 100000) {
- l = &tnc_lvds_limits[1];
- } else if (ref_freq == 166000) {
- l = &tnc_lvds_limits[2];
- }
-#endif
-
- for(count=0; count<3; count++){
- if (tnc_lvds_limits[count].ref_freq == ref_freq){
- l = &tnc_lvds_limits[count];
- break;
- }
- }
-
-/* PO Debug */
-#if 0
- /* WRITE_PORT80(0xED); */
-
- if(ref_freq == 166000){
- WRITE_PORT80(0xEF);
- }
-
- if (!l){
- /* FATAL ERROR */
- DEAD_LOOP(0xDD);
- }
-#endif
-
- /* Per UMG, there is no defined target_error for LVDS, it supposed to
- * work for all expected dclks. */
-#if 1
- ret = get_clock(dclk, ref_freq, l, &m, &n, &p1, dclk /* target_error */,
- port->port_type, &clock->actual_dclk, port->pd_driver->type);
- if (ret) {
- EMGD_ERROR_EXIT("Clock %ld could not be programmed", dclk);
- /* DEAD_LOOP(0xFF); */
- return ret;
- }
-#else
- /* Hard code the values for now */
- m = 0x2D; // ITP uses 0x2E, should change
- p1 = 2;
-
-#endif
-
-#if 0
- /* If clocks are already running at required clocks, just return */
- if (PIPE(display)->dclk == dclk) {
- return 0;
- }
-#endif
-
- /* Disable DPLL */
-#if 0
- control = BIT28 | (1<<clock->p_shift); //Why are we shifting 1 to P1, GMA carry over???
-#else
- control = BIT28;
-#endif
- WRITE_MMIO_REG(display, clock->dpll_control, control);
- EMGD_DEBUG("lvds: EMGD_WRITE32: 0x%lx = 0x%lx",
- clock->dpll_control, control);
-
- /* Program M */
- WRITE_MMIO_REG(display, clock->mnp, (m<<8));
-
- WRITE_MMIO_REG(display, 0xF044, (m<<8)); //BUGBUG
-
- EMGD_DEBUG("lvds: EMGD_WRITE32: 0x%lx = 0x%lx",
- clock->mnp, (m<<8));
-
- /* Enable DPLL */
- control = (BIT31 | BIT28 | BIT27) | (p1<<clock->p_shift);
-
-/* PO Debug..*/
-#if 0
- /* set VCO select */
- if (ref_freq == 166000) {
- control |= BIT16;
- }
-#endif
-
-
- WRITE_MMIO_REG(display, clock->dpll_control, control);
- EMGD_DEBUG("lvds: EMGD_WRITE32: 0x%lx = 0x%lx",
- clock->dpll_control, control);
-
- /* Wait 150us for the DPLL to stabilize */
- OS_SLEEP(150);
- PIPE(display)->dclk = dclk;
-
- EMGD_TRACE_EXIT;
- return 0;
-}
-
-/*!
- *
- * @param display
- * @param clock
- * @param dclk
- *
- * @return 0 on success
- * @return 1 on failure
- */
-int program_clock_sdvo_tnc(igd_display_context_t *display,
- igd_clock_t *clock,
- unsigned long dclk)
-{
- int ret;
- unsigned long m, n, p1;
- unsigned long control;
- unsigned long ref_freq;
- unsigned long port_mult, vga_mult;
- unsigned long target_error, actual_dclk;
- igd_display_port_t *port;
- tnc_limits_t *l;
-
- EMGD_DEBUG("Enter program_clock");
-
- port = PORT_OWNER(display);
-
- /* FIXME: No info available in EAS and waiting for info. */
- if (dclk > 100000) { /* 100-200 MHz */
- port_mult = 1;
- } else if (dclk > 50000) { /* 50-100 Mhz */
- port_mult = 2;
- } else { /* 25-50 Mhz */
- port_mult = 4;
- }
-
- dclk *= port_mult;
-
- l = &tnc_sdvo_limits[0];
- ref_freq = l->ref_freq;
-
- vga_mult = READ_MMIO_REG_TNC(IGD_PORT_SDVO, clock->dpll_control) & 0x3;
-
- target_error = TARGET_ERROR;
-
- /* For external clock sources always use ref_clock == dclk */
- if(port->pd_flags & PD_FLAG_CLK_SOURCE) {
- ref_freq = dclk;
- /* When clock source sdvo device, allowed error is 0. */
- target_error = 0;
- }
-
- ret = get_clock(dclk, ref_freq, l, &m, &n, &p1, target_error,
- IGD_PORT_SDVO, &actual_dclk, port->pd_driver->type);
-
- clock->actual_dclk = actual_dclk/port_mult;
-
- if (ret) {
- EMGD_ERROR("Clock %ld could not be programmed", dclk);
- return ret;
- }
-
- /* Disable DPLL, Write 2 into P for saftey */
- control = BIT28 | (2<<clock->p_shift) | vga_mult;
-
- WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, clock->dpll_control, control);
- EMGD_DEBUG("sdvo: EMGD_WRITE32: 0x%lx = 0x%lx",
- clock->dpll_control, control);
-
- /* Program N, M */
- WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, clock->mnp, (n<<16) | m);
- EMGD_DEBUG("sdvo: EMGD_WRITE32: 0x%lx = 0x%lx",
- clock->mnp, (n<<16)|m);
-
- /* Enable DPLL, Disable VGA mode and sitck in new P values */
- control = BIT31 | BIT30 | BIT28 | (p1<<clock->p_shift) | vga_mult;
-
- /* Set the clock source correctly based on PD settings */
- if(port->pd_flags & PD_FLAG_CLK_SOURCE) {
- control |= port->clock_bits;
- }
-
- /* sDVO Multiplier bits[7:0] */
- if (port_mult == 2) {
- control |= (1 << 4);
- } else if (port_mult == 3) {
- control |= (2 << 4);
- } else if (port_mult == 4) {
- control |= (3 << 4);
- }
-
- /* Double buffered */
- WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, clock->dpll_control, control);
- WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, clock->dpll_control, control);
- EMGD_DEBUG("sdvo: EMGD_WRITE32: 0x%lx = 0x%lx",
- clock->dpll_control, control);
-
- /* We must wait for 150 us for the dpll clock to warm up */
- OS_SLEEP(150);
-
- return 0;
-}
-
-int program_clock_tnc(igd_display_context_t *display,
- igd_clock_t *clock,
- unsigned long dclk)
-{
- EMGD_TRACE_ENTER;
-
- if (PORT_TYPE(display) == IGD_PORT_LVDS) {
- EMGD_TRACE_EXIT;
- return program_clock_lvds_tnc(display, clock, dclk);
- } else {
- EMGD_TRACE_EXIT;
- return program_clock_sdvo_tnc(display, clock, dclk);
- }
-}
-#endif
-
-/*----------------------------------------------------------------------------
- * File Revision History
- * $Id: clocks_tnc.c,v 1.11 2010/09/20 17:26:48 astead Exp $
- * $Source: /nfs/fm/proj/eia/cvsroot/koheo/linux/egd_drm/emgd/display/mode/tnc/clocks_tnc.c,v $
- *----------------------------------------------------------------------------
- */