aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/emgd/emgd/pal/lvds/lvds.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/emgd/emgd/pal/lvds/lvds.c')
-rw-r--r--drivers/gpu/drm/emgd/emgd/pal/lvds/lvds.c1546
1 files changed, 0 insertions, 1546 deletions
diff --git a/drivers/gpu/drm/emgd/emgd/pal/lvds/lvds.c b/drivers/gpu/drm/emgd/emgd/pal/lvds/lvds.c
deleted file mode 100644
index 6493c5c39101..000000000000
--- a/drivers/gpu/drm/emgd/emgd/pal/lvds/lvds.c
+++ /dev/null
@@ -1,1546 +0,0 @@
-/* -*- pse-c -*-
- *-----------------------------------------------------------------------------
- * Filename: lvds.c
- * $Revision: 1.14 $
- *-----------------------------------------------------------------------------
- * 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:
- * This file is contains all necessary functions for Internal
- * LVDS PORT DRIVER.
- * This is written according to the port interface defined in pd.h.
- *-----------------------------------------------------------------------------
- */
-#include <linux/kernel.h>
-
-#include <config.h>
-#include <igd_pd.h>
-#include <pd.h>
-#include <pd_print.h>
-
-#include "lvds.h"
-
-/* One space between the #define and the backslash,else compilers complain */
-#define PTR_OFFSET_UCHAR(ptr,offset) (*((unsigned char *)ptr + offset))
-#define PTR_OFFSET_USHORT(ptr, offset) (*(unsigned short *)((unsigned char *)ptr + offset))
-
-#define PTR_OFFSET_ULONG(ptr, offset) (*(unsigned long *)((unsigned char *)ptr + offset))
-/* END OF OPTIMIZATION MACROS */
-
-/* This constant = 10,000,000. The value is used to
- * get effective results from the integer math, and
- * to not divide by 0. */
-#define PWM_FREQ_CALC_CONSTANT_1 0x00989680
-/* This constant is 1,000,000 - to multiply to get
- * the Display Clock Frequency to the order of Mhz */
-#define PWM_FREQ_CALC_CONSTANT_2 0x000F4240
-
-
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(p) (sizeof(p)/sizeof((p)[0]))
-#endif
-
-static pd_version_t lvds_version = {11, 0, 0, 0}; /* driver version */
-static unsigned long lvds_dab_list[] = {
- PD_DAB_LIST_END
-}; /* dab list */
-
-static unsigned long supported_chipset[] =
-{
-#ifdef CONFIG_855
- PCI_DEVICE_ID_VGA_855,
-#endif
-#ifdef CONFIG_915AL
- PCI_DEVICE_ID_VGA_915AL,
-#endif
-#ifdef CONFIG_945GM
- PCI_DEVICE_ID_VGA_945GM,
- PCI_DEVICE_ID_VGA_945GME,
-#endif
-#ifdef CONFIG_965GM
- PCI_DEVICE_ID_VGA_GM965,
- PCI_DEVICE_ID_VGA_GME965,
-#endif
-#ifdef CONFIG_CTG
- PCI_DEVICE_ID_VGA_CTG,
-#endif
-#ifdef CONFIG_PLB
- PCI_DEVICE_ID_VGA_PLB,
-#endif
-#ifdef CONFIG_TNC
- PCI_DEVICE_ID_VGA_TNC,
- PCI_DEVICE_ID_VGA_TNC_A0,
- PCI_DEVICE_ID_VGA_LNC,
-#endif
-};
-
-static pd_driver_t lvds_driver = {
- PD_SDK_VERSION,
- "Internal LVDS Port Driver",
- 0,
- &lvds_version,
- PD_DISPLAY_LVDS_INT,
- PD_FLAG_UP_SCALING,
- lvds_dab_list,
- 100,
- lvds_validate,
- lvds_open,
- lvds_init_device,
- lvds_close,
- lvds_set_mode,
- lvds_post_set_mode,
- lvds_set_attrs,
- lvds_get_attrs,
- lvds_get_timing_list,
- lvds_set_power,
- lvds_get_power,
- lvds_save,
- lvds_restore,
- lvds_get_port_status
-};
-
-/* This is a common attribute table for all chipsets. At the end of the table
- * there are multiple end entries to add chipset specific attributes.
- * Chipset specific attributes:
- * 965GM/GM45- Maintain aspect ratio
- * Note:
- * 1. Make sure to update the chipset_attr_index whenever adding a
- * chipset specific new attr.
- */
-static pd_attr_t lvds_attrs[] =
-{
- /* Range attributes */
-
- /*<-------ID-----------> <----TYPE--------> <---NAME-----> <----flag----> <---DEF_VAL----> <--CURR_VALUE--> min max st */
- PD_MAKE_ATTR (PD_ATTR_ID_FP_PWR_T1, PD_ATTR_TYPE_RANGE, "FP Power T1", PD_ATTR_FLAG_USER_INVISIBLE, 0, 0, 0, 819, 1),
- PD_MAKE_ATTR (PD_ATTR_ID_FP_PWR_T2, PD_ATTR_TYPE_RANGE, "FP Power T2", PD_ATTR_FLAG_USER_INVISIBLE, 0, 0, 0, 819, 1),
- PD_MAKE_ATTR (PD_ATTR_ID_FP_PWR_T3, PD_ATTR_TYPE_RANGE, "FP Power T3", PD_ATTR_FLAG_USER_INVISIBLE, 0, 0, 0, 819, 1),
- PD_MAKE_ATTR (PD_ATTR_ID_FP_PWR_T4, PD_ATTR_TYPE_RANGE, "FP Power T4", PD_ATTR_FLAG_USER_INVISIBLE, 0, 0, 0, 819, 1),
- PD_MAKE_ATTR (PD_ATTR_ID_FP_PWR_T5, PD_ATTR_TYPE_RANGE, "FP Power T5", PD_ATTR_FLAG_USER_INVISIBLE, 400, 400, 0, 3000, 1),
- PD_MAKE_ATTR (PD_ATTR_ID_PANEL_DEPTH, PD_ATTR_TYPE_RANGE, "Panel Depth", PD_ATTR_FLAG_USER_INVISIBLE, LVDS_DEF_PANEL_DEPTH, LVDS_DEF_PANEL_DEPTH, 18, 24, 6),
-
- PD_MAKE_ATTR (PD_ATTR_ID_PWM_INTENSITY, PD_ATTR_TYPE_RANGE, "PWM cycle", PD_ATTR_FLAG_USER_INVISIBLE, 100, 0, 0, 100, 0),
- PD_MAKE_ATTR (PD_ATTR_ID_INVERTER_FREQ, PD_ATTR_TYPE_RANGE, "Inverter Frequency", PD_ATTR_FLAG_USER_INVISIBLE, 100, 0, 0, 0, 0),
- PD_MAKE_ATTR (PD_ATTR_ID_BLM_LEGACY_MODE, PD_ATTR_TYPE_BOOL, "Backlight Legacy mode", PD_ATTR_FLAG_USER_INVISIBLE, 0, 0, 0, 0, 0),
-
- /*<-------ID------------> <----TYPE--------> <---NAME-----> <------flag---------------> <---DEF_VAL----> <--CURR_VALUE--> <---pad--> */
- PD_MAKE_ATTR (PD_ATTR_ID_2_CHANNEL_PANEL, PD_ATTR_TYPE_BOOL, "Dual-channel panel", PD_ATTR_FLAG_USER_INVISIBLE, 0, 0, 0, 0, 0),
- PD_MAKE_ATTR (PD_ATTR_ID_LVDS_PANEL_TYPE, PD_ATTR_TYPE_BOOL, "Panel Type", PD_ATTR_FLAG_USER_INVISIBLE, 0, 0, 0, 0, 0),
- PD_MAKE_ATTR (PD_ATTR_ID_PANEL_FIT, PD_ATTR_TYPE_BOOL, "Panel Upscale", PD_ATTR_FLAG_USER_INVISIBLE, LVDS_DEF_PANEL_FIT,LVDS_DEF_PANEL_FIT,0, 0, 0),
- PD_MAKE_ATTR (PD_ATTR_ID_DITHER, PD_ATTR_TYPE_BOOL, "Dither", PD_ATTR_FLAG_USER_INVISIBLE, LVDS_DEF_DITHER, LVDS_DEF_DITHER, 0, 0, 0),
- PD_MAKE_ATTR (LVDS_ATTR_ID_TC_LVDS_CLK, PD_ATTR_TYPE_BOOL, "TC LVDS CLK 110MHz", PD_ATTR_FLAG_USER_INVISIBLE, 0, 0, 0, 0, 0),
-
- /* Start of chipset specific attributes */
- /* Maintain aspect ratio */
- PD_MAKE_ATTR (PD_ATTR_LIST_END, 0, "", 0, 0, 0, 0, 0, 0),
- /* Text tuning */
- PD_MAKE_ATTR (PD_ATTR_LIST_END, 0, "", 0, 0, 0, 0, 0, 0),
-
- /* Attribute list end */
- PD_MAKE_ATTR (PD_ATTR_LIST_END, 0, "", 0, 0, 0, 0, 0, 0)
-};
-
-/* Rightnow it is -3 to reach starting of chipset specific attributes */
-static unsigned short chipset_attr_index = (unsigned short)
- sizeof(lvds_attrs)/sizeof(pd_attr_t) - 3;
-
-static pd_attr_t lvds_965gm_attrs[] = {
- PD_MAKE_ATTR (PD_ATTR_ID_MAINTAIN_ASPECT_RATIO,PD_ATTR_TYPE_BOOL, "Maintain Aspect Ratio",0, 0, 0, 0, 0, 0),
- PD_MAKE_ATTR (PD_ATTR_ID_TEXT_TUNING, PD_ATTR_TYPE_RANGE, "Text Enhancement", 0, 0, 0, 0, 2, 1),
-};
-
-static void lvds_write_reg(lvds_context_t *pd_context, unsigned long reg,
- unsigned long value, unsigned long change_bits, unsigned long reg_type);
-
-static unsigned long lvds_read_reg(lvds_context_t *pd_context,
- unsigned long reg, unsigned long reg_type);
-static void lvds_panel_fit(lvds_context_t *pd_context);
-
-static void lvds_get_dclk(lvds_context_t *pd_context, pd_dvo_info_t *lvds_info);
-
-/*----------------------------------------------------------------------------
- *
- * Function: PD_MODULE_INIT(lvds_init)
- *
- * Description:
- * This is the entry function into LVDS port driver when
- * it first loads. This will call pd_register() to register
- * with Display driver. Only the driver object is initialized in this
- * function, similar to DrverEntry() in a WDM driver.
- *
- * Parameters:
- * [OUT] *handle: Not used. Place holder for supporting dynamic pd
- *
- * Return:
- * PD_SUCCESS(0) success
- * PD_ERR_XXXXXX otherwise
- *
- *----------------------------------------------------------------------------
- */
-
-int PD_MODULE_INIT(lvds_init, (void *handle))
-{
- /* register the LVDS driver */
- return pd_register(handle, &lvds_driver);
-}
-
-/*----------------------------------------------------------------------------
- *
- * Function: PD_MODULE_EXIT(lvds_exit, (void))
- *
- * Description:
- * This function cleans up resources used by the LVDS driver
- *
- * Parameters:
- * None
- *
- * Return:
- * PD_SUCCESS(0): always returns this
- *
- *----------------------------------------------------------------------------
- */
-
-int PD_MODULE_EXIT(lvds_exit, (void))
-{
- return PD_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- *
- * Function: lvds_validate
- *
- * Description:
- * Place holder for a future function
- *
- * Parameters:
- * TBD
- *
- * Return:
- * TBD
- *
- *----------------------------------------------------------------------------
- */
-
-unsigned long lvds_validate (unsigned long cookie)
-{ /* lvds_validate */
- /* Validate magic cookie */
- /* TODO: Implement the magic cookie algorithm */
- return cookie;
-} /* lvds_validate */
-
-/*----------------------------------------------------------------------------
- *
- * Function: lvds_open
- *
- * Description:
- * This function creates an LVDS context and intialize it with LVDS
- * attributes.
- *
- * Internal LVDS port is available only on MGM platform, this port driver
- * reads the GMCH device ID with pd_read_regs(PD_REG_PCI) to verify that
- * it is supported on the current platform.
- *
- * Parameters:
- * [IN] callback: callback context
- * [INOUT] context: Device context. This function will set the attributes
- * for this context, provided it is already allocated,
- * i.e. not NULL.
- *
- * Return:
- * PD_ERR_NULL_PTR: if either of the parameters is NULL
- * PD_ERR_NODEV: if an LVDS device is already up and running
- * PD_ERR_NOMEM: if a memory allocation failed
- * PD_SUCCESS: if successful
- *
- *----------------------------------------------------------------------------
- */
-
-/* lvds context structure being declared and initialized */
-
-static lvds_context_t lvds_context = { /* lvds context structure */
- 0, /* fp_width */
- 0, /* fp_height */
- 0, /* dual_channel: Default single channel */
- 0, /* panel_type : 0-SPWG 1-OpenLDI*/
- LVDS_DEF_PANEL_FIT, /* panel_fit */
- LVDS_DEF_PANEL_DEPTH,/* panel_depth */
- 0xFFFF, /* dither */
- 0, /* Main aspect ratio, default no */
- 0, /* panel filter: Default fuzzy filtering */
- 100, /* PWM Intensity */
- 0xFFFF, /* Inverter Frequency*/
- 0, /* BLM Legacy Mode */
-
- PD_POWER_MODE_D0, /* power_state */
- 0, /* chipset */
- 0, /* init_done */
- 0, /* num_attrs */
- 0, /* PIPE flags */
- 0, /* Graphics Frequency */
- 0, /* is gn4 based LVDS controller? */
- 0, /* is pwm_done? */
- 0, /* is tc_110MHz_clk? i.e., TC max LVDS to 110MHz*/
-
- NULL, /* ptr to callback */
- NULL, /* ptr to timing table */
- lvds_attrs, /* ptr to attribute list */
- NULL, /* ptr to native timing */
- NULL, /* current mode */
-};
-
-int lvds_open(pd_callback_t *callback, void **context)
-{ /* lvds_open */
- lvds_context_t *pd_context = (lvds_context_t*) &(lvds_context); /* static Global */
- pd_reg_t reg_list[2];
- int ret, i, valid_chipset = 0;
- unsigned short chipset;
-
- PD_TRACE_ENTER;
-
-
-
- /* make sure parameters are valid */
- if (!callback || !context) {
- PD_ERROR("invalid parameter");
- return (PD_ERR_NULL_PTR);
- }
- /* GMCH cannot support more than one device */
- if (lvds_driver.num_devices > 0) {
- return (PD_ERR_NODEV);
- }
- /* Verify that this is an GMCH with Internal LVDS available */
- reg_list[0].reg = 2;
- reg_list[1].reg = PD_REG_LIST_END;
- ret = callback->read_regs(callback->callback_context, reg_list, PD_REG_PCI);
- if(ret != PD_SUCCESS) {
- return ret;
- }
- chipset = (unsigned short)(reg_list[0].value & 0xffff);
- for (i = 0; i < ARRAY_SIZE(supported_chipset); i++) {
- if (chipset == supported_chipset[i]){
- valid_chipset = 1;
- break;
- }
- }
- if(!valid_chipset){
- return PD_ERR_NODEV;
- }
-
- /* Special handling for gn4 and beyond chipsets */
- if (chipset == PCI_DEVICE_ID_VGA_GM965 ||
- chipset == PCI_DEVICE_ID_VGA_GME965 ||
- chipset == PCI_DEVICE_ID_VGA_CTG ||
- chipset == PCI_DEVICE_ID_VGA_TNC ||
- chipset == PCI_DEVICE_ID_VGA_TNC_A0 ||
- chipset == PCI_DEVICE_ID_VGA_LNC) {
- lvds_context.gn4_plus = 1;
- }
-
- /* Initialize number of attributes */
- /* +1 is to include the end attribute */
- lvds_context.num_attrs = (unsigned char)chipset_attr_index + 1;
-
- /* Add chipset specific attrbutes.
- * This can be expanded into a switch statement in future if required. */
- if (lvds_context.gn4_plus) {
- lvds_context.num_attrs += sizeof(lvds_965gm_attrs)/sizeof(pd_attr_t);
- for (i=0; i < sizeof(lvds_965gm_attrs)/sizeof(pd_attr_t); i++) {
- lvds_attrs[chipset_attr_index+i] = lvds_965gm_attrs[i];
- }
- }
- /* Make this a compile time so that size of vBIOS doesn't become > 64KB */
-#if defined(CONFIG_PLB) || defined(CONFIG_TNC)
- /* pwm backlight control needs graphics frequency. we currently implement
- * pwm backlight control for pouslbo only to limit the vbios lvds size. Each
- * chipset have a different method of getting this value and chipset has a
- * different multiplier. */
- if (chipset == PCI_DEVICE_ID_VGA_PLB ||
- chipset == PCI_DEVICE_ID_VGA_TNC ||
- chipset == PCI_DEVICE_ID_VGA_TNC_A0 ||
- chipset == PCI_DEVICE_ID_VGA_LNC) {
-
- /* For plb/tnc, graphics frequency is obtained by sending an opcode to
- * port 5 in the SCH Message Network. We call the read_regs with
- * PD_REG_BRIDGE_OPCODE specifically for this purpose only.
- *
- * The input for this read_reg is the opcode that register data that
- * we send into the Message control register*/
- reg_list[1].reg = PD_REG_LIST_END;
- ret = callback->read_regs(callback->callback_context,
- reg_list, PD_REG_BRIDGE_OPCODE);
- if(ret != PD_SUCCESS) {
- return ret;
- }
-
- /*set the graphics frequency*/
- pd_context->gfx_freq = (unsigned short) reg_list[0].value;
- }
-#endif
-
- pd_context->callback = callback; /* Save callback context */
- pd_context->chipset = chipset; /* save the chipset ID */
- *context = (void *) pd_context;
-
- PD_TRACE_EXIT;
- return PD_SUCCESS;
-} /* lvds_open */
-
-/*----------------------------------------------------------------------------
- *
- * Function: lvds_init_device
- *
- * Description:
- * Initializes the LVDS device, using the device context from the parameter
- *
- * Parameters:
- * [INOUT] context: device context
- *
- * Return:
- * PD_ERR_NULL_PTR: if parameter is invalid
- * PD_SUCCESS: if successful
- *
- *----------------------------------------------------------------------------
- */
-
-int lvds_init_device (void *context)
-{ /* lvds_init_device */
- if (!context) {
- return (PD_ERR_NULL_PTR);
- }
-
- /* Don't need to do much to initialize this device */
- ((lvds_context_t *)context)->init_done = 1;
- lvds_driver.num_devices++;
-
- return (PD_SUCCESS);
-} /* lvds_init_device */
-
-
-/*----------------------------------------------------------------------------
- *
- * Function: lvds_close
- *
- * Description:
- * Releases resources allocated during lvds_open(). This function
- * essentially frees a device object.
- *
- * Parameters:
- * [INOUT] device_context: device to be freed
- *
- * Return:
- * PD_SUCCESS: always returns this
- *
- *----------------------------------------------------------------------------
- */
-
-int lvds_close(void *device_context)
-{
-#ifndef CONFIG_MICRO
-
- lvds_context_t *pd_context = (lvds_context_t *)device_context;
-
- /* lvds_close */
-
- PD_TRACE_ENTER;
-
- /* Deallocate memory occupied by this device */
- if (device_context) {
- if ( NULL != pd_context->timing_table) {
- pd_free(pd_context->timing_table);
- }
-
- /* Free attribute list, if necessary */
- /* FIXME -- The following test will never call pd_free(), because the
- * expression "!lvds_driver.num_devices" will yield 0 or 1, and that
- * will never be greater than 1. This is a potentially small memory
- * leak, unless some other code frees it.
- */
- if (!lvds_driver.num_devices > 1) {
- pd_free(pd_context->attr_list);
- }
- /* This allocated statically no need to free it */
- /* pd_free(device_context); */
- lvds_driver.num_devices--;
- pd_context->init_done = 0;
- }
-
- PD_TRACE_EXIT;
-#endif
- return (PD_SUCCESS);
-} /* lvds_close */
-
-/*----------------------------------------------------------------------------
- *
- * Function: lvds_set_mode
- *
- * Description:
- * Sets LVDS to a new mode, specified by "mode".
- *
- * Parameters:
- * [INOUT] context: device context
- * [IN] mode: information about the mode to switch to
- * [IN] flags: can contain the following value
- * PD_SET_MODE_FLAG_TEST: only testing to see if mode is supported
- *
- * Return:
- * PD_ERR_NULL_PTR: if invalid parameter detected
- * PD_ERR_MODE_NOTSUPP: if mode specified is not supported
- * PD_SUCCESS: if successful
- *
- *----------------------------------------------------------------------------
- */
-int lvds_set_mode(void *context, pd_timing_t *mode, unsigned long flags)
-{
- lvds_context_t *pd_context = NULL;
-
- PD_DEBUG("lvds_set_mode)\n");
- PD_TRACE_ENTER;
-
- pd_context = (lvds_context_t *)context;
-
- /* Make sure these parameters are valid */
- if (!pd_context || !mode) {
- return (PD_ERR_NULL_PTR);
- }
- PD_DEBUG("lvds_set_mode: %ux%u", mode->width, mode->height);
-
- /* Make sure specified mode is supported */
- if ((pd_context->fp_width && (mode->width > pd_context->fp_width)) ||
- (pd_context->fp_height && (mode->height > pd_context->fp_height))) {
- return PD_ERR_MODE_NOTSUPP;
- }
-
- /* Do nothing if we are only want to know if a mode is supported */
- if (flags & PD_SET_MODE_FLAG_TEST) {
- return PD_SUCCESS;
- }
-
- pd_context->current_mode = mode;
- pd_context->pipe = flags;
- /* Enable panel fitting and return */
- lvds_panel_fit(pd_context);
-
- PD_TRACE_EXIT;
-
- return PD_SUCCESS;
-}
-
-int lvds_post_set_mode(void *context, pd_timing_t *mode, unsigned long flags)
-{ /* lvds_set_mode */
- lvds_context_t *pd_context = NULL;
- unsigned long port_control = 0;
- unsigned long preserve = 0;
- int ret = 0;
-
- PD_TRACE_ENTER;
- pd_context = (lvds_context_t *)context;
-
- PD_DEBUG("lvds_post_set_mode)\n");
- /* Make sure these parameters are valide */
- if (!pd_context || !mode) {
- return (PD_ERR_NULL_PTR);
- }
-
- /* Before enabling the LVDS port, make sure that display PLL for this pipe
- * is enabled and the port is power sequenced on using the panel power
- * sequencing logic. */
-
- preserve = 0x3E007803;
- port_control = preserve & lvds_read_reg(pd_context, 0x61180, PD_REG_MIO);
- port_control |= BIT(31); /* enable LVDS port */
- if (flags & PD_SET_MODE_PIPE_B) {
- port_control |= BIT(30);
- }
- port_control |= (BIT(9)|BIT(8)); /* power up */
- port_control &= ~(BIT(21)|BIT(20)); /* Default sync polarites active high */
-
- /* For gn4+, dither moved to port_control from panel_fit reg */
- if (pd_context->gn4_plus) {
- if (pd_context->panel_depth == 18) {
- port_control |= BIT(25);
- }
-
- if (pd_context->dither != 0xFFFF) {
- if (pd_context->dither) {
- port_control |= BIT(25);
- } else {
- port_control &= ~BIT(25);
- }
- }
- }
-
- if((!pd_context->panel_fit) &&
- ( mode->width < pd_context->fp_width ||
- mode->height < pd_context->fp_height ) ){
- port_control |= BIT(15); /* enable border in active for centering */
- }
-
- /*
- * Bit 24 for OpenLDI should be set to a 0 (1x18.0, 2x18.0, 1x24.0, 2x24.0).
- * From (B-Spec, Ref# 22316, section 1.15.3.8.3)
- *
- * Bit 24 for SPWG should be set to a 1 (1x24.1 or 2x24.1).
- *
- * This was verified by comparing the timing diagram for 1x24.0 in
- * OpenLDI spec (5.4.2.2 24-bit Single Pixel Mode, Unbalanced) with the
- * same diagram in the Display BSpec for Napa or Gen4.
- * A0 – A3 signals match the 1x24.0.
- *
- * From the OpenLDI spec (bit mappings are different):
- *
- * Table 5-2, Bit Number Mappings
- * 18 bpp bit# 24 bpp bit# OpenLDI bit#
- * 5 7 5
- * 4 6 4
- * 3 5 3
- * 2 4 2
- * 1 3 1
- * 0 2 0
- * 1 7
- * 0 6
- */
-
- /* Attribute panel_type description:
- * Attr ID Attr Value IntLVDS dataformat
- * ======= =============== ==================
- * 49 0 (SPWG) 1 (value of Bit 24)
- * 49 1 (OpenLDI) 0 (value of Bit 24)
- */
- if (pd_context->panel_type == 0) {
- port_control |= BIT(24); /* Dataformat 0 = SPWG, 1 = OpenLDI */
- }
-
- /* If the dual-channel is required, then power up second channel
- * ClkB and B0, B1, B2, (B3) */
- if (pd_context->dual_channel) {
- port_control |= (BIT(5)|BIT(4)); /* ClkB */
- port_control |= (BIT(3)|BIT(2)); /* B0, B1, B2, (B3) */
- }
-
- /* Check for 18 or 24 bit panel */
- if (pd_context->panel_depth == 24) {
- /* If the panel is 24-bit (8-bpp), enable A3, (B3) pair. */
- port_control |= (BIT(7)|BIT(6));
- }
-
- /* Set the sync polarities correctly if there is a native dtd */
- if (pd_context->native_dtd) {
- /* Set bit 20 for hsync active low */
- if ((pd_context->native_dtd->mode_info_flags & PD_HSYNC_HIGH) == 0) {
- port_control |= BIT(20);
- }
- /* Set bit 21 for vsync active low */
- if ((pd_context->native_dtd->mode_info_flags & PD_VSYNC_HIGH) == 0) {
- port_control |= BIT(21);
- }
- }
-
- lvds_write_reg(pd_context, 0x61180, port_control, 0xFFFFFFFF, PD_REG_MIO);
- ret = lvds_set_power(pd_context, PD_POWER_MODE_D0);
- if (ret) {
- PD_ERROR("PD set_power (D0) returned: 0x%x", ret);
- return ret;
- }
-
- PD_TRACE_EXIT;
- /* Set the mode as per given timings */
- return PD_SUCCESS;
-} /* lvds_set_mode */
-
-/*----------------------------------------------------------------------------
- *
- * Function: lvds_set_attrs
- *
- * Description:
- * Incorporate attributes in "list" into the device context. This function
- * will override the initial attributes set by init_attrs.
- *
- * Parameters:
- * [INOUT] context: device context
- * [IN] num: not used, but must not be 0.
- * [IN] list: list of attributes to incorporate into device context
- *
- * Return:
- * PD_ERR_NULL_PTR: if one of the parameters is invalid
- * PD_ERR_ATTR_CANT_CHANGE: attributes cannot be modified
- * PD_SUCCESS: if successful
- *
- *----------------------------------------------------------------------------
- */
-/* Tables required by Optimization Code. lvds_set_attrs() */
-typedef struct _opt_table_data {
- unsigned long id;
- unsigned short block;
- unsigned short offset;
-} lvds_opt_table_data_t;
-static lvds_opt_table_data_t table_opt_data1[] = {
-
- /*<--- id ----------> <---block---> <------ offset -------------------> */
- {PD_ATTR_ID_PANEL_DEPTH, 1, PD_OFFSETOF(lvds_context_t, panel_depth) },
-
- {PD_ATTR_ID_2_CHANNEL_PANEL, 1, PD_OFFSETOF(lvds_context_t, dual_channel)},
- {PD_ATTR_ID_LVDS_PANEL_TYPE, 1, PD_OFFSETOF(lvds_context_t, panel_type) },
- {PD_ATTR_ID_PANEL_FIT, 1, PD_OFFSETOF(lvds_context_t, panel_fit) },
- {PD_ATTR_ID_DITHER, 1, PD_OFFSETOF(lvds_context_t, dither) },
- {PD_ATTR_ID_MAINTAIN_ASPECT_RATIO,1,PD_OFFSETOF(lvds_context_t,aspect_ratio)},
- {PD_ATTR_ID_TEXT_TUNING, 1, PD_OFFSETOF(lvds_context_t, text_tune)},
- {PD_ATTR_ID_PWM_INTENSITY, 1, PD_OFFSETOF(lvds_context_t, pwm_intensity)},
- {PD_ATTR_ID_INVERTER_FREQ, 1, PD_OFFSETOF(lvds_context_t, inverter_freq)},
- {PD_ATTR_ID_BLM_LEGACY_MODE, 1, PD_OFFSETOF(lvds_context_t, blm_legacy_mode)},
- {LVDS_ATTR_ID_TC_LVDS_CLK, 1, PD_OFFSETOF(lvds_context_t, tc_110MHz_clk)},
-
- /*<--- id ----------> <---block---> <------ offset -------------------> */
- {PD_ATTR_ID_FP_PWR_T1, 2, 0 }, /* 6 */
- {PD_ATTR_ID_FP_PWR_T2, 2, 0 }, /* 7 */
- {PD_ATTR_ID_FP_PWR_T3, 2, 0 }, /* 8 */
- {PD_ATTR_ID_FP_PWR_T4, 2, 0 }, /* 9 */
- {PD_ATTR_ID_FP_PWR_T5, 2, 0 } /* 10 */
-};
-/* End of Tables required by Optimization Code. lvds_set_attrs() */
-
-int lvds_set_attrs (void *context, unsigned long num, pd_attr_t *list)
-{
- lvds_context_t *pd_context = (lvds_context_t *) context;
- pd_attr_t *attr = NULL;
- unsigned short i = 0;
- unsigned short j = 0;
- int ret = PD_SUCCESS;
- /* no of case IDs in the global table */
- int num_case_ids = sizeof(table_opt_data1)/sizeof(lvds_opt_table_data_t);
-
- /* basic parameter check */
- if (!context || !num || !list) {
- return PD_ERR_NULL_PTR;
- }
-
- PD_DEBUG("lvds_set_attrs()\n");
- for (i = 0; i < num; i++, list++) {
- /* do nothing if the attribute has not been changed */
- if (!(list->flags & PD_ATTR_FLAG_VALUE_CHANGED)) {
- continue;
- }
-
- /* attributes can't be changed after init has been completed */
- if (list->flags & PD_ATTR_FLAG_USER_INVISIBLE &&
- pd_context->init_done) {
- return PD_ERR_ATTR_CANT_CHANGE;
- }
-
- /* Set the internal attributes' list. Note that although get_attr() can
- * return NULL theortically, it will not do so here because all the
- * attribute IDs in this switch statement comes from lvds_attrs[],
- * a list that is automatically initialized into pd_context. This is
- * why we are not checking for NULL after calling get_attr().
- */
-#if 0 /* ORIGINAL SWITCH STATEMENT */
- switch (list->id) {
- case PD_ATTR_ID_FP_PWR_T1:
- case PD_ATTR_ID_FP_PWR_T2:
- case PD_ATTR_ID_FP_PWR_T3:
- case PD_ATTR_ID_FP_PWR_T4:
- case PD_ATTR_ID_FP_PWR_T5:
- /* current_value should not exceed the predefined max value */
- attr = pd_get_attr(pd_context->attr_list, pd_context->num_attrs,
- list->id, 0);
- attr->current_value = LVDS_MIN(
- ((pd_range_attr_t *)list)->current_value,
- attr->_pad1);
- break;
-
- case PD_ATTR_ID_PANEL_DEPTH:
- attr = pd_get_attr(pd_context->attr_list, pd_context->num_attrs,
- list->id, 0);
- attr->current_value = list->current_value;
- pd_context->panel_depth = (unsigned char) attr->current_value;
- break;
-
- case PD_ATTR_ID_2_CHANNEL_PANEL:
- attr = pd_get_attr(pd_context->attr_list, pd_context->num_attrs,
- list->id, 0);
- attr->current_value = ((pd_bool_attr_t *)list)->current_value;
- pd_context->dual_channel = (attr->current_value?1:0);
- break;
-
- case PD_ATTR_ID_LVDS_PANEL_TYPE:
- attr = pd_get_attr(pd_context->attr_list, pd_context->num_attrs,
- list->id, 0);
- attr->current_value = ((pd_bool_attr_t *)list)->current_value;
- pd_context->panel_type = (attr->current_value?1:0);
- break;
-
- case PD_ATTR_ID_PANEL_FIT:
- attr = pd_get_attr(pd_context->attr_list, pd_context->num_attrs,
- list->id, 0);
- attr->current_value = ((pd_bool_attr_t *)list)->current_value;
- pd_context->panel_fit = (attr->current_value?1:0);
- break;
-
- default:
- /* do nothing if we have an unknown ID */
- break;
- }
-#endif
- /* OPTIMIZATION CODE BEGINS FOR THE ABOVE SWITCH
- *----------------------------------------------
- * Step 1: First identify the code common to all case blocks.
- * This we call it "common code block" Since this is to be
- * executed by all the case blocks.
- *
- * Step 2: Group the cases into blocks based on how we can combine them
- *
- * Eg: case 0: ptr->x = 1; break; // similar code
- * case 1: ptr->y = 1; break; // similar code
- * ------Combined block ----
- * case 0:
- * case 1: PTR_OFFSET_TYPE(ptr, table[i].offset) = 1; break;
- * This is an important step because we save code space by
- * mapping many cases to smaller number of blocks. In the above
- * we use index to get the right offset of the ptr.
- *
- * Step 3: Assign block IDs to each block. Put the case ID, block ID
- * and other information such as offsets of ptr in a global
- * table.
- *
- * Step 4: During run-time , search through the global table, find the
- * matching case ID, and execute the common code. Next get the
- * block ID and execute the block specific code. For the index,
- * retrieve it from the table for the corresponding case ID.
- *
- * Step 5: If no matching case ID is found, error it out.
- *
- * Let's look at the optimization code for the above switch.
- * The code below searches for the list->id in a global table where
- * we store all the case values along with block numbers and other
- * information. After we find a valid id in the table , we execute the
- * common code for all cases first and then we retrieve the block id.
- * The block id is necesary to determine which block does the id belong
- * to. This is used to execute block specific code. Similar to switch
- * cases ONLY here we try to minimize the no of blocks.
- *
- * In this example , we store the offsets of field names of a ptr in the
- * global table.This is necessary to combine cases with "similar" but
- * not "same" codes.
- *
- * Eg: case 0: ptr->x = 1; break; // similar code
- * case 1: ptr->y = 1; break; // similar code
- * -- Combined block ----
- * case 0:
- * case 1: PTR_OFFSET_TYPE(ptr, table[i].offset) = 1; break;
- *
- * By reducing the number of blocks we save on Code space. After we
- * finish our work , we exit the for loop and check for invalid ID
- * passed by the upper layer. This is akin to default in the
- * switch block
- *
- * CAUTION: If there is any change in the switch above, this code
- * along with the tables have to be re-written and changed according
- * to the new behaviour of the switch. Examples include adding a new
- * case in the switch. The reason for all this mumbo-jumbo is to
- * reduce code size in VBIOS, where we are running out of code space.
- */
- for(j = 0; j < num_case_ids; j++) {
- /* Search for the attribute ID in the global table */
- if(list->id == table_opt_data1[j].id) {
- /* Run the common code for all the blocks */
- attr = pd_get_attr(pd_context->attr_list, pd_context->num_attrs,
- list->id, 0);
- /* Once we get a valid ID, need to find out which block it
- * belongs so we can execute block specific code.
- */
- if(table_opt_data1[j].block == 1) { /* block 1 */
- /* Got the block. Need the offset to the struct for that ID
- * so we can store value at corresponding offset to get the
- * desired behaviour for that ID.This is the code that makes
- * the whole optimization work because we are combining the
- * case IDs into a single block which saves code.
- */
- attr->current_value = list->current_value;
- PTR_OFFSET_USHORT(pd_context, table_opt_data1[j].offset) =
- (unsigned short) attr->current_value;
-
- } else { /* block 2. We only have two blocks. */
- attr->current_value = LVDS_MIN(
- list->current_value, ((pd_range_attr_t *)attr)->max);
- }
- break; /* We found a valid ID, so break inner for loop */
- }
- }
- }
- PD_DEBUG("IntLVDS: dual_channel=%u", pd_context->dual_channel);
- PD_DEBUG("IntLVDS: panel_type=%u panel_fit=%u panel_dep=%u dither=%u",
- pd_context->panel_type, pd_context->panel_fit,
- pd_context->panel_depth, pd_context->dither);
- PD_DEBUG("IntLVDS: keep_aspect_ratio=%u text_tune=%lu",
- pd_context->aspect_ratio, pd_context->text_tune);
- PD_DEBUG("IntLVDS: PWM Intensity=%u Inverter Freq=%u, BLM legacy mode =%u",
- pd_context->pwm_intensity, pd_context->inverter_freq,
- pd_context->blm_legacy_mode);
- PD_DEBUG("IntLVDS: tc_110MHz_clk = %u", pd_context->tc_110MHz_clk);
-
- /* panel_type 0 (SPWG) isn't available for 18-bit depth */
-
- PD_DEBUG("in LVDS_set_attributes()\n");
- if (pd_context->panel_depth == 18) {
- pd_context->panel_type = 1;
- }
-
- if (pd_context->init_done) {
- /* When emgd_driver_pre_init() pokes new attrs into this port driver,
- * pd_context->current_mode must be set before calling
- * lvds_panel_fit(), so set it to the first entry in the timing table:
- */
- if (pd_context->current_mode == NULL) {
- pd_context->current_mode = pd_context->timing_table;
- }
- lvds_panel_fit(pd_context);
- }
-
- return ret;
-} /* lvds_set_attrs */
-
-/*----------------------------------------------------------------------------
- *
- * Function: lvds_get_attrs
- *
- * Description:
- * Extracts the attribute list and the number of elements in the list
- * from the device context.
- *
- * Parameters:
- * [IN] context: device context to extract information from
- * [OUT] num: number of elements in list
- * [OUT] list: list of attributes from the device context
- *
- * Return:
- * PD_ERR_NULL_PTR: if one of the parameters is invalid
- * PD_SUCCESS: if successful
- *
- *----------------------------------------------------------------------------
- */
-int lvds_get_attrs (void *context, unsigned long *num, pd_attr_t **list)
-{ /* lvds_get_attrs */
- /* basic parameter check */
- if (!context || !num || !list) {
- return PD_ERR_NULL_PTR;
- }
-
- PD_DEBUG("lvds_get_attrs()\n");
- /* Nothing fancy, just extracting the elements from the list */
- *list = ((lvds_context_t *)context)->attr_list;
- *num = ((lvds_context_t *)context)->num_attrs;
-
- return PD_SUCCESS;
-} /* lvds_get_attrs */
-
-/*----------------------------------------------------------------------------
- *
- * Function: lvds_get_timing_list
- *
- * Description:
- *
- *
- * Parameters:
- * [IN] context: device context to extract information from
- * [OUT] in_list:
- * [OUT] list:
- *
- * Return:
- * PD_ERR_NULL_PTR: if one of the parameters is invalid
- * PD_ERR_NOMEM: if internal memory allocate failed
- * PD_SUCCESS: if successful
- *
- *----------------------------------------------------------------------------
- */
-int lvds_get_timing_list (void *context, pd_timing_t *in_list,
- pd_timing_t **list)
-{ /* lvds_get_timing_list */
- lvds_context_t *pd_context = (lvds_context_t *)context;
- pd_dvo_info_t lvds_info = {0, 0, 1, 0, 0, 0, 0, 0};
- pd_display_info_t lvds_display_info = {0, 0, 0, 0, NULL};
- int ret;
-
- PD_DEBUG("lvds_get_timing_list()\n");
- lvds_get_dclk( pd_context, &lvds_info );
-
- PD_DEBUG("chipset = 0x%x", pd_context->chipset);
- lvds_display_info.panel_fit = (unsigned char) pd_context->panel_fit;
- ret = pd_filter_timings(pd_context->callback->callback_context,
- in_list, &pd_context->timing_table, &lvds_info, &lvds_display_info);
-
- /* Helper function will return the below values */
- pd_context->native_dtd = lvds_display_info.native_dtd;
- pd_context->fp_width = lvds_display_info.width;
- pd_context->fp_height = lvds_display_info.height;
-
- *list = pd_context->timing_table;
- return ret;
-} /* lvds_get_timing_list */
-
-/*----------------------------------------------------------------------------
- *
- * Function: lvds_set_power
- *
- * Description:
- * Sets LVDS to the specified power state
- *
- * Conversion between IEGD timer values to LVDS port timer values
- *
- * SEPG(?) IEGD LVDS Port Program bits min max
- * ---- ------- ------------ ---------------- ------ ---------
- * T1+T2 T1 ms T1+T2 100us 0x61208 [28:16] 0 ms 819.2 ms
- * T5 T2 ms T5 100us 0x61208 [12:00] 0 ms 819.2 ms
- * T6 T3 ms Tx 100us 0x6120C [12:00] 0 ms 819.2 ms
- * T3 T4 ms T3 100us 0x6120C [28:16] 0 ms 819.2 ms
- * T4 T5 ms T4 100ms 0x61210 [04:00] 0 ms 3200 ms
- *
- * Reg = Value
- * ------ -------
- * 0x61208 = [T1 T2]
- * 0x6120C = [T4 T3]
- * 0x61210 = [ T5]
- *
- * Parameters:
- * [IN] context: device context to extract information from
- * [OUT] in_list:
- * [OUT] list:
- *
- * Return:
- * PD_ERR_NULL_PTR: if context is NULL
- * PD_ERR_INVALID_POWER: if "state" is invalid
- * PD_SUCCESS: if successful
- *
- *----------------------------------------------------------------------------
- */
-/* Tables required by the optimization codes in lvds_set_power() */
-typedef struct {
- unsigned char id1;
- unsigned char id2;
- unsigned char bit;
- unsigned long reg;
-} opt_set_power_t;
-
-static opt_set_power_t table_set_power[] = {
- /* id1 id2 bit reg */
- { PD_ATTR_ID_FP_PWR_T1, PD_ATTR_ID_FP_PWR_T2, 1, 0x61208 }, /* D0 */
- { PD_ATTR_ID_FP_PWR_T4, PD_ATTR_ID_FP_PWR_T3, 0, 0x6120C }, /* Dx */
-};
-
-int lvds_set_power(void *context, unsigned long state)
-{ /* lvds_set_power */
- unsigned long i = 0;
- lvds_context_t *pd_context = (lvds_context_t *)context;
- pd_attr_t *tattr = NULL; /* holds time delay b/ pwr transition */
- unsigned long delay = 0, delay1;
-
- PD_DEBUG("state = %lu", state);
-
- PD_DEBUG("lvds_set_power() to state = %lu\n",state);
- /* Basic parameter check */
- if (!context) {
- return PD_ERR_NULL_PTR;
- }
-
- /* Check for invalid state */
- if (state > PD_POWER_MODE_D3) {
- return PD_ERR_INVALID_POWER;
- }
-
- /* Get the index into above table */
- if (state == PD_POWER_MODE_D0) {
- i = 0;
- } else {
- i = 1;
- }
-
- /* Program panel power up/down delays: Either T1/T2 or T3/T4*/
- tattr = pd_get_attr(pd_context->attr_list,
- pd_context->num_attrs, table_set_power[i].id1, 0);
- /* Convert ms to 100us */
- delay1 = tattr->current_value;
- delay = (tattr->current_value * 10) << 16;
- tattr = pd_get_attr(pd_context->attr_list,
- pd_context->num_attrs, table_set_power[i].id2, 0);
- delay1 += tattr->current_value;
- delay |= tattr->current_value * 10;
-
- lvds_write_reg(pd_context, table_set_power[i].reg, delay, 0x1FFF1FFF, PD_REG_MIO);
-
- /* Program power cycle delay: convert ms to 100ms */
- delay = pd_get_attr(pd_context->attr_list,
- pd_context->num_attrs, PD_ATTR_ID_FP_PWR_T5, 0)->current_value;
- delay1 += delay;
- /* TODO: Write reference divider [31:8] */
- delay = ((delay/100+1) & 0xFF) | ((pd_context->gfx_freq*100/2-1)<<8);
- lvds_write_reg(pd_context, 0x61210, delay, 0xFFFFFFFF, PD_REG_MIO);
-
- /* Power state target */
- lvds_write_reg(pd_context, 0x61204, table_set_power[i].bit, BIT(0), PD_REG_MIO);
-
- /* Power down on reset available on crestline onwards */
- if (pd_context->gn4_plus) {
- lvds_write_reg(pd_context, 0x61204, BIT(1), BIT(1), PD_REG_MIO);
- }
-
-/* Make this a compile time so that size of vBIOS doesn't become > 64KB */
-#if defined(CONFIG_PLB) || defined(CONFIG_TNC)
- /* PWM is a method of controlling the backlight intensity.
- * It is not method to turn on baclkight.
- * We still need the PD method to turn on the backlight.
- *
- * This feature is for Pouslbo Only. We check that the user has set the
- * inverter frequency. Default intensity, if not set, is 100%
- *
- * Due to the high amount of calculation, we want to only set this register
- * if it has not been ser previously. The register could be
- * "brought forward" from VBIOS.
- */
- if(pd_context->inverter_freq != 0xFFFF && /* Overwritten by set_attr */
- (pd_context->chipset == PCI_DEVICE_ID_VGA_PLB ||
- pd_context->chipset == PCI_DEVICE_ID_VGA_TNC ||
- pd_context->chipset == PCI_DEVICE_ID_VGA_TNC_A0 ||
- pd_context->chipset == PCI_DEVICE_ID_VGA_LNC) &&
- !pd_context->pwm_done) {
- unsigned long reg_value = 0;
- unsigned long percentage = 0;
- unsigned long calculation = 0;
- unsigned long blc_pwm_ctl2 = 0;
-
- /* We first need to get the graphics frequency, which will be used to
- * calculate Backlight Modulation Frequency[BMF]. BMF will be used to
- * fill up the 15 MSB in the 0x61254 register
- *
- * The calculation for the Modulation Frequency field in the
- * BLC_PWM_CTL Register is:
- *
- * Reference Clock Freq 1
- * ----------------------- x ------------------
- * Divider PWM Freq in Hz
- *
- */
-#if 0
- /* GMA accurate calculation that requires "calculation" to be an
- * unsigned long long typedef */
- calculation = pd_context->gfx_freq * PWM_FREQ_CALC_CONSTANT_2;
- calculation = calculation / 0x20; /*pouslbo specific divider*/
- calculation = calculation * PWM_FREQ_CALC_CONSTANT_1;
- calculation = calculation / pd_context->inverter_freq;
- calculation = calculation / PWM_FREQ_CALC_CONSTANT_1;
-#endif
- /* Some system bios cannot take 64 bit data type. Using a more
- * simplified calculation that is not too accurate if the inputs
- * are not round numbers */
- calculation = pd_context->inverter_freq * 0x20; /* plb/tnc divider */
- calculation = (pd_context->gfx_freq * PWM_FREQ_CALC_CONSTANT_2) /
- calculation;
-
- /* Writing the register: 15 MSB is the max lvds clock / 32.
- * Bit 16 can either be legacy or non legacy depending upon Attr #72. */
- if (pd_context->gn4_plus) {
- blc_pwm_ctl2 = (1L << 31) |
- (pd_context->blm_legacy_mode << 30) |
- ((pd_context->pipe == PD_SET_MODE_PIPE_B)?1L:0L << 29);
- lvds_write_reg(pd_context, 0x61250, blc_pwm_ctl2, 0xFFFFFFFF, PD_REG_MIO);
- reg_value = (calculation & 0xFFFF)<<16;
- } else {
- reg_value = ((calculation & 0xFFFE) |
- pd_context->blm_legacy_mode)<<16;
- }
-
- /* The 16 LSB is a value that the user sets in configuration.
- * user sets the value in percentage.
- * We convert it into the clock speed */
- percentage = ( pd_context->pwm_intensity * (unsigned long)calculation);
- reg_value |= (unsigned long)( percentage / (int)100 ) & 0xFFFE;
- lvds_write_reg(pd_context, 0x61254, reg_value, 0xFFFFFFFF, PD_REG_MIO);
-
- /* set the flag so that we only do this function once */
- pd_context->pwm_done = 1;
- }
-#endif
-
- if (state != PD_POWER_MODE_D0) {
- /* Wait until the current power up/down sequence is complete */
- i = 0;
- while(lvds_read_reg(pd_context, 0x61200, PD_REG_MIO) & 0x80000000L) {
- i++;
- if(i > 0x100000L) {
- break;
- }
- }
- lvds_write_reg(pd_context, 0x61180, 0, BIT(31), PD_REG_MIO);
- }
-
-#ifdef CONFIG_TNC
-#if 0
-
-/*-----------------------------------------------------------------------------
- * LPC Register Offsets. Used for LVDS BKLT control. Registers are part
- * Atom E6xx [D31:F0]
- ----------------------------------------------------------------------------*/
-#define RGEN 0x20
-#define RGIO 0x24
-#define RGLVL 0x28
-#define TNC_LVDS_VDDEN BIT(0)
-#define TNC_LVDS_BKLTEN BIT(1)
-#define TNC_LVDS_BKLTCTL BIT(2)
-
- if (pd_context->chipset == PCI_DEVICE_ID_VGA_TNC ||
- pd_context->chipset == PCI_DEVICE_ID_VGA_TNC_A0 ||
- pd_context->chipset == PCI_DEVICE_ID_VGA_LNC) {
- unsigned long value;
-
- /* Enable backlight for LVDS: based on observed si behavior:
- * Subject to change based on si DE feedback */
- if (state == PD_POWER_MODE_D0) {
- value = TNC_LVDS_BKLTCTL|TNC_LVDS_BKLTEN|TNC_LVDS_BKLTCTL;
- } else {
- value = 0;
- }
- lvds_write_reg(pd_context, RGEN, value,
- TNC_LVDS_BKLTCTL|TNC_LVDS_BKLTEN|TNC_LVDS_BKLTCTL, PD_REG_LPC);
- lvds_write_reg(pd_context, RGIO, value,
- TNC_LVDS_BKLTCTL|TNC_LVDS_BKLTEN|TNC_LVDS_BKLTCTL, PD_REG_LPC);
- }
-#endif
-#endif
-
- /* update power state */
- pd_context->power_state = state;
- return PD_SUCCESS;
-} /* lvds_set_power */
-
-/*----------------------------------------------------------------------------
- *
- * Function: lvds_get_power
- *
- * Description:
- * Returns the current LVDS power state back to the caller.
- *
- * Parameters:
- * [IN] context: device context to extract information from
- * [OUT] state: current power state
- *
- * Return:
- * PD_ERR_NULL_PTR: if one of the parameters is invalid
- * PD_SUCCESS: if successful
- *
- *----------------------------------------------------------------------------
- */
-
-int lvds_get_power (void *context, unsigned long *state)
-{ /* lvds_get_power */
- if ((NULL == context) || (NULL == state)) {
- return PD_ERR_NULL_PTR;
- }
- PD_DEBUG("lvds_get_power()\n");
- /* The caller should be able to do this himself, but whatever */
- *state = ((lvds_context_t *) context)->power_state;
- return PD_SUCCESS;
-} /* lvds_get_power */
-
-int lvds_save(void *context, void **state, unsigned long flags)
-{
- *state = NULL;
- return PD_SUCCESS;
-}
-
-int lvds_restore(void *context, void *state, unsigned long flags)
-{
- int ret = PD_SUCCESS;
- return ret;
-}
-
-/*----------------------------------------------------------------------
- * Function: lvds_get_port_status()
- *
- * Description: It is called to get the information about the display
- *
- * Parameters: context - Port driver's context
- * port_status - Returns the display type and connection state
- *
- * Return: PD_SUCCESS(0) success
- * PD_ERR_XXXXXX otherwise
- *----------------------------------------------------------------------*/
-int lvds_get_port_status(void *context, pd_port_status_t *port_status)
-{
- /* Display connection cannot be determined */
- port_status->display_type = PD_DISPLAY_LVDS_INT;
- port_status->connected = PD_DISP_STATUS_UNKNOWN;
- return PD_SUCCESS;
-}
-
-static unsigned long lvds_read_reg(lvds_context_t *pd_context,unsigned long reg,
- unsigned long reg_type)
-{
- pd_reg_t list[2];
- int ret;
-
- list[0].reg = reg;
- list[0].value = 0;
- list[1].reg = PD_REG_LIST_END;
- ret = pd_context->callback->read_regs(
- pd_context->callback->callback_context, list, reg_type);
- if (ret) {
- PD_ERROR("LVDS read regs: Failed.");
- }
- return list[0].value;
-}
-
-/*----------------------------------------------------------------------------
- *
- * Function: lvds_write_reg
- *
- * Description:
- * Writes bits in "value" into a register. Bits written are dictated by
- * the "change_bits" mask.
- *
- * Parameters:
- * [IN] pd_context: device context, dispatcher to the actual write_reg
- * function
- * [IN] reg: register to write value to
- * [IN] value: value to change the register to
- * [IN] change_bits: bit mask, the bits set to "1" will be modified by
- * the corresponding bits in "value"
- *
- * Return:
- * None
- *
- *----------------------------------------------------------------------------
- */
-static void lvds_write_reg(lvds_context_t *pd_context, unsigned long reg,
- unsigned long value,
- unsigned long change_bits,
- unsigned long reg_type)
-{ /* lvds_write_reg */
- pd_reg_t list[2];
- int ret;
-
- list[0].reg = reg;
- list[0].value = (lvds_read_reg(pd_context, reg, PD_REG_MIO) & ~change_bits) | value;
- list[1].reg = PD_REG_LIST_END;
- ret = pd_context->callback->write_regs(
- pd_context->callback->callback_context, list, reg_type);
- if (ret) {
- PD_ERROR("LVDS write regs: Failed.");
- }
- return;
-} /* lvds_write_reg */
-
-/*----------------------------------------------------------------------------
- *
- * Function: lvds_panel_fit
- *
- * Description:
- * Enables panel fitting
- *
- * Parameters:
- * [IN] pd_context: device context
- *
- * Return:
- * None
- *
- *----------------------------------------------------------------------------
- */
-static void lvds_panel_fit(lvds_context_t *pd_context)
-{
- /* enable auto vertical ratio */
- /* enable auto horizantal ratio */
- /* no dither */
- unsigned long panel_fit_reg = 0x00000220;
- PD_DEBUG("lvds_panel_fit() \n");
-
- PD_TRACE_ENTER;
-
- if (pd_context->current_mode->width != pd_context->fp_width ||
- pd_context->current_mode->height != pd_context->fp_height) {
- /* Enable panel fitting */
- /* vertical interpolation = bilinear */
- /* horizontal interpolation = bilinear */
- panel_fit_reg |= 0x80000440;
- }
- /* Enable dither based on default/user-set value:
- * By default
- * dither = 1 for 18-bit panels
- * = 0 for 24-bit panels.
- * But this behavior can be changed by setting the DITHER attribute.
- * When user sets the attribute, dither will be updated
- * as part of attribute processing in set attributes. */
- /* For gn4 based chipsets dither is controlled in port_control register */
- if (!pd_context->gn4_plus) {
- /* Default behavior */
- if (pd_context->panel_depth == 18) {
- panel_fit_reg |= BIT(3);
- }
-
- /* Overwritten by set attribute */
- if (pd_context->dither != 0xFFFF) {
- if (pd_context->dither) {
- panel_fit_reg |= BIT(3);
- } else {
- panel_fit_reg &= ~BIT(3);
- }
- }
- }
-
- if (pd_context->gn4_plus) {
- unsigned long src_ratio, dest_ratio;
- panel_fit_reg = 0;
- if (pd_context->native_dtd &&
- (pd_context->current_mode->width != pd_context->native_dtd->width ||
- pd_context->current_mode->height !=
- pd_context->native_dtd->height)) {
- /* Enable panel fitter */
- panel_fit_reg = 0x80000000;
-
- /* Select the pipe */
- if (pd_context->pipe & PD_SET_MODE_PIPE_B) {
- panel_fit_reg |= BIT(29); /* bits[30:29] = 01 for pipe B */
- }
-
- /* Scaling mode:
- * Default - Auto scaling src_ratio == dest_ratio
- * Piller box scaling - src_ratio < dest_ratio
- * Letter box scaling - src_ratio > dest_ratio */
-
- /* To make this work correctly, port driver shall know the
- * size of the framebuffer, not the src mode. Most of the
- * times the src mode is fb, but not all the cases.
- * User has an attribute to change
- * 1. Between Pillerbox and auto, and vice versa
- * and
- * 2. Between Letterbox and auto, and vice versa.
- */
- if (pd_context->aspect_ratio) {
- src_ratio = (pd_context->current_mode->width << 10)/
- (pd_context->current_mode->height);
- dest_ratio = (pd_context->native_dtd->width << 10)/
- (pd_context->native_dtd->height);
-
- if (dest_ratio > src_ratio) {
- /* Pillarbox scaling */
- panel_fit_reg |= BIT(27);
- } else if (dest_ratio < src_ratio) {
- /* Letterbox scaling */
- panel_fit_reg |= BIT(27) | BIT(26);
- }
- }
-
- /* Filter coefficient select: pd_context->text_tune = 0,1,2 */
- panel_fit_reg |= (pd_context->text_tune << 24);
- }
- }
-
- lvds_write_reg(pd_context, 0x61230, panel_fit_reg, 0xFFFFFFFF, PD_REG_MIO);
- PD_DEBUG("panel_fit_reg 0x61230 = 0x%lx", panel_fit_reg);
-}
-
-
-/*----------------------------------------------------------------------------
- *
- * Function: lvds_get_dclk
- *
- * Description:
- * Gets the Dclk for LVDS
- *
- * Parameters:
- * [IN] pd_context: device context
- * [OUT]lvds_info: Structure that contains the min and max dclk
- *
- * Return:
- * None
- *
- *----------------------------------------------------------------------------
- */
-static void lvds_get_dclk(lvds_context_t *pd_context, pd_dvo_info_t *lvds_info )
-{
- PD_DEBUG("lvds_get_dclk()\n");
- /* Get the min and max dclks for lvds */
- if (pd_context->dual_channel) {
- lvds_info->min_dclk = LVDS_MIN_DCLK * 2 ;
- lvds_info->max_dclk = LVDS_MAX_DCLK * 2;
- } else {
- lvds_info->min_dclk = LVDS_MIN_DCLK;
- lvds_info->max_dclk = LVDS_MAX_DCLK;
- }
-/* This #define is the result of code size reduction effort. */
-#ifdef CONFIG_CTG
- /* Set dclk for GM965 */
- if(pd_context->chipset==PCI_DEVICE_ID_VGA_CTG){
- /* Set dclk for GM965/CTG */
- if (pd_context->dual_channel) {
- lvds_info->min_dclk = LVDS_GM965_DUAL_MIN_DCLK ;
- lvds_info->max_dclk = LVDS_GM965_DUAL_MAX_DCLK;
- } else {
- lvds_info->min_dclk = LVDS_GM965_SINGLE_MIN_DCLK;
- lvds_info->max_dclk = LVDS_GM965_SINGLE_MAX_DCLK;
- }
- }
-#else
-
- /* Set dclk for 915GM */
- if(pd_context->chipset==PCI_DEVICE_ID_VGA_915AL){
- if (pd_context->dual_channel) {
- lvds_info->min_dclk = LVDS_915GM_DUAL_MIN_DCLK ;
- lvds_info->max_dclk = LVDS_915GM_DUAL_MAX_DCLK;
- } else {
- lvds_info->min_dclk = LVDS_915GM_SINGLE_MIN_DCLK;
- lvds_info->max_dclk = LVDS_915GM_SINGLE_MAX_DCLK;
- }
- } else if(pd_context->chipset==PCI_DEVICE_ID_VGA_945GM ||
- pd_context->chipset==PCI_DEVICE_ID_VGA_945GME){
- /* Set dclk for 945GM */
- if (pd_context->dual_channel) {
- lvds_info->min_dclk = LVDS_945GM_DUAL_MIN_DCLK ;
- lvds_info->max_dclk = LVDS_945GM_DUAL_MAX_DCLK;
- } else {
- lvds_info->min_dclk = LVDS_945GM_SINGLE_MIN_DCLK;
- lvds_info->max_dclk = LVDS_945GM_SINGLE_MAX_DCLK;
- }
- } else if(pd_context->chipset==PCI_DEVICE_ID_VGA_GM965 ||
- pd_context->chipset==PCI_DEVICE_ID_VGA_GME965){
- /* Set dclk for GM965 */
- if (pd_context->dual_channel) {
- lvds_info->min_dclk = LVDS_GM965_DUAL_MIN_DCLK ;
- lvds_info->max_dclk = LVDS_GM965_DUAL_MAX_DCLK;
- } else {
- lvds_info->min_dclk = LVDS_GM965_SINGLE_MIN_DCLK;
- lvds_info->max_dclk = LVDS_GM965_SINGLE_MAX_DCLK;
- }
- }
-#endif
-
-#ifdef CONFIG_TNC
- /* Get the min and max dclks for Atom E6xx lvds */
- if ((pd_context->chipset == PCI_DEVICE_ID_VGA_TNC) ||
- (pd_context->chipset == PCI_DEVICE_ID_VGA_TNC_A0) ||
- (pd_context->chipset == PCI_DEVICE_ID_VGA_LNC)) {
- lvds_info->min_dclk = LVDS_TNC_SINGLE_MIN_DCLK;
- /* Experimental feature to raise TC LVDS clk to 110MHz. */
- if (pd_context->tc_110MHz_clk) {
- lvds_info->max_dclk = 110000L;
- } else {
- lvds_info->max_dclk = LVDS_TNC_SINGLE_MAX_DCLK;
- }
- }
-#endif
-}
-/*----------------------------------------------------------------------------
- * File Revision History
- * $Id: lvds.c,v 1.14 2010/09/20 17:26:48 astead Exp $
- * $Source: /nfs/fm/proj/eia/cvsroot/koheo/linux/egd_drm/emgd/pal/lvds/lvds.c,v $
- *----------------------------------------------------------------------------
- */