aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/emgd/emgd/display/mode/cmn/micro_mode.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/emgd/emgd/display/mode/cmn/micro_mode.c')
-rw-r--r--drivers/gpu/drm/emgd/emgd/display/mode/cmn/micro_mode.c1645
1 files changed, 0 insertions, 1645 deletions
diff --git a/drivers/gpu/drm/emgd/emgd/display/mode/cmn/micro_mode.c b/drivers/gpu/drm/emgd/emgd/display/mode/cmn/micro_mode.c
deleted file mode 100644
index 3e4bfd0e056b..000000000000
--- a/drivers/gpu/drm/emgd/emgd/display/mode/cmn/micro_mode.c
+++ /dev/null
@@ -1,1645 +0,0 @@
-/* -*- pse-c -*-
- *-----------------------------------------------------------------------------
- * Filename: micro_mode.c
- * $Revision: 1.16 $
- *-----------------------------------------------------------------------------
- * 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:
- * Contains client interface support functions for display allocations
- *-----------------------------------------------------------------------------
- */
-
-#define MODULE_NAME hal.mode
-
-#include <config.h>
-#include <io.h>
-#include <memory.h>
-#include <sched.h>
-
-#include <igd.h>
-#include <igd_init.h>
-#include <igd_mode.h>
-#include <igd_render.h>
-#include <igd_pwr.h>
-#include <igd_errno.h>
-#include <igd_gmm.h>
-#include <igd_pd.h>
-
-#include <debug.h>
-#include <context.h>
-#include <rb.h>
-#include <pd.h>
-#include <intelpci.h>
-#include <dsp.h>
-#include <pi.h>
-#include <pd_init.h>
-#include <dispatch.h>
-#include <mode.h>
-#include <mode_access.h>
-#include <dsp.h>
-#include <utils.h>
-#include <general.h>
-#include <module_init.h>
-
-#include "match.h"
-#include "mode_dispatch.h"
-
-/*!
- * @addtogroup display_group
- * @{
- */
-
-#ifndef CONFIG_MICRO
-#define TIMING_CHANGED(a,b,c,d,e,f,g) timing_changed(a,b,c,d,e,f,g)
-#define CALCULATE_ELD_INFOFRAMES
-#else
-#define TIMING_CHANGED(a,b,c,d,e,f,g) 1
-#endif /* CONFIG_MICRO */
-
-#define MODE_MIN(x, y) (x<y)?x:y
-
-
-/*
- * NOTE: Do not add comma's to this dispatch table. The macro's
- * remove the entire entry.
- */
-static dispatch_table_t mode_dispatch[] = {
- DISPATCH_PLB( &mode_dispatch_plb )
- DISPATCH_TNC( &mode_dispatch_tnc )
- DISPATCH_END
-};
-
-/*
- * Do not malloc the context for two reasons.
- * 1) vBIOS needs to minimize mallocs
- * 2) Mode context needs to stay around until after all modules are
- * shut down for the register restore functionality.
-*/
-mode_context_t mode_context[1];
-
-
-#ifndef CONFIG_MICRO
-
-/*!
- * Check user supplied timing against what is currently
- * programmed to see if it needs to change. If the timing
- * isn't going to change, then we don't want to turn off and
- * reprogram the port.
- *
- * NOTE: If this increases the size too much for vbios, then it
- * could be ifndef CONFIG_MICRO with an else that returns 1. That
- * would mean vbios wouldn't have these checks and always assume
- * the timing was changing.
- *
- * @param display
- * @param new_dc DC changes always require port/plane/pipe programming.
- * @param pt_info User supplied timing info to check.
- * @param fb_info User supplied framebuffer info.
- * @param port_number
- * @param display_mask Which display is being checked.
- * @param alter flags used to force the alter
- *
- * @return 1 timing has changed
- * @return 0 timing hasn't changed
- */
-static int timing_changed(igd_display_context_t *display,
- unsigned long new_dc,
- unsigned long dc,
- igd_display_info_t *pt_info,
- igd_framebuffer_info_t *fb_info,
- unsigned long display_mask,
- unsigned long flags)
-{
- igd_framebuffer_info_t *cfb;
-
- EMGD_TRACE_ENTER;
-
- /*
- * will this cover every case? Can a change on one display effect
- * the timings of the other? I don't think so.
- */
- if ((new_dc & display_mask) != (dc & display_mask)) {
- return 1; /* Ports are changing on this display, must re-program. */
- }
-
- /*
- * Make sure the owner port has a pt_info, if not then we'll assume
- * that it hasn't been programmed yet and thus the timings are going
- * to change.
- */
- if (PORT_OWNER(display)->pt_info == NULL) {
- return 1;
- }
-
- /*
- * Make sure we have valid timing info. If not, then don't try
- * and change the timings.
- */
- if (!pt_info || !fb_info) {
- return 0;
- }
-
- /*
- * If the caller really wants to re-program the planes/pipes/ports
- * then do it
- */
-
- if (flags & IGD_FORCE_ALTER) {
- return 1;
- }
-
- /*
- * Check only width, height, refresh. If these don't match, then we
- * know that something is changing.
- */
-
- if ((pt_info->width == PORT_OWNER(display)->pt_info->width) &&
- (pt_info->height == PORT_OWNER(display)->pt_info->height) &&
- (pt_info->refresh == PORT_OWNER(display)->pt_info->refresh)) {
-
- /* Check framebuffer for changes, fb changes may change timing */
- if ((cfb = PLANE(display)->fb_info) != NULL) {
- if ((cfb->width != fb_info->width) ||
- (cfb->height != fb_info->height) ||
- (cfb->pixel_format != fb_info->pixel_format) ||
- (cfb->flags != fb_info->flags)) {
- /* Timing ok buf fb_info doesn't match */
- return 1;
- }
- }
- } else {
- /* Timing doesn't match */
- return 1;
- }
-
- /* Timing and fb have not changed */
- EMGD_TRACE_EXIT;
- return 0;
-}
-#endif
-
-/*!
- * Update internal data structures for the plane, pipe, and port as
- * requested. Allocate a new framebuffer if the new parameters do not
- * match the existing framebuffer.
- *
- * @param display
- * @param port_number
- * @param timing
- * @param pt_info User supplied timing info to check.
- * @param fb_info User supplied framebuffer info.
- * @param flags
- *
- * @return 0 on success
- * @return -IGD_ERROR_INVAL on failure
- */
-static int mode_update_plane_pipe_ports(
- igd_display_context_t *display,
- unsigned short port_number,
- igd_timing_info_t *timing,
- igd_framebuffer_info_t *fb_info,
- igd_display_info_t *pt_info,
- unsigned long flags)
-{
- int ret;
- int alloc_fb;
- unsigned long size = 0;
- igd_framebuffer_info_t *plane_fb_info;
- igd_display_plane_t *mirror;
-
- EMGD_TRACE_ENTER;
-
- EMGD_DEBUG("Port Number (%d)", port_number);
-
- EMGD_ASSERT( (fb_info || pt_info), "ERROR: fb_info & pt_info are NULL",
- -IGD_ERROR_INVAL);
-
- EMGD_ASSERT( PLANE(display)->fb_info, "ERROR: fb_info in plane is NULL",
- -IGD_ERROR_INVAL);
-
- plane_fb_info = PLANE(display)->fb_info;
- mirror = PLANE(display)->mirror;
-
- /*
- * If there is a mirror plane (for Clone) and the mirror is populated
- * then update our plane from the mirror. If the mirror is not populated
- * then update the mirror from ours.
- */
- if (mirror) {
- if(mirror->fb_info->flags) {
- OS_MEMCPY(plane_fb_info, mirror->fb_info,
- sizeof(igd_framebuffer_info_t));
- } else {
- OS_MEMCPY(mirror->fb_info, plane_fb_info,
- sizeof(igd_framebuffer_info_t));
- }
- }
-
- if (PORT(display, port_number)->pt_info == NULL) {
- if ((PORT(display, port_number)->pt_info = (igd_display_info_t *)
- OS_ALLOC(sizeof(igd_display_info_t))) == NULL) {
- EMGD_ERROR_EXIT("unable to alloc a pt_info struct in pipe.");
- return -IGD_ERROR_INVAL;
- }
- }
-
- /*
- * If the fb_info was provided, and either we were asked to update
- * the internal structures via the flags, or we are allocating a new
- * framebuffer.
- */
- if(fb_info && (flags & MODE_UPDATE_PLANE)) {
-
- /* Assume we will be allocating a FB */
- alloc_fb = 1;
-
- /* If the frambuffer parameters are unchanged then do not re-alloc */
- if((fb_info->width == plane_fb_info->width) &&
- (fb_info->height == plane_fb_info->height) &&
- (fb_info->pixel_format == plane_fb_info->pixel_format) &&
- (fb_info->flags == plane_fb_info->flags)) {
- alloc_fb = 0;
- }
-
- /* Do not re-alloc a framebuffer if the re-use flag is set. */
- if(fb_info->flags & IGD_REUSE_FB) {
- alloc_fb = 0;
- /* May need to get the MIN_PITCH flags */
- plane_fb_info->flags = (fb_info->flags & IGD_FB_FLAGS_MASK) |
- (plane_fb_info->flags & ~IGD_FB_FLAGS_MASK);
- }
-
- /*
- * If we don't have a framebuffer at all then we MUST allocate
- * one.
- */
- if(!plane_fb_info->allocated && !fb_info->allocated) {
- alloc_fb = 1;
- }
-
- EMGD_DEBUG("plane_fb_info->fb_base_offset = 0x%08lx",
- plane_fb_info->fb_base_offset);
- if(alloc_fb) {
- if(plane_fb_info->allocated) {
- /* Free frame buffer memory */
- display->context->dispatch.gmm_free(
- plane_fb_info->fb_base_offset);
- plane_fb_info->allocated = 0;
- }
-
- fb_info->fb_base_offset = plane_fb_info->fb_base_offset;
- /*
- * Keep the FB flags, add in Displayable flag and blank out
- * the rest. This insures that any tiled or usage flags from an
- * earlier call do not get reused.
- */
- fb_info->flags = (fb_info->flags & IGD_FB_FLAGS_MASK) |
- IGD_SURFACE_DISPLAY;
-
- /*
- * Framebuffer allocations must always come from a reservation
- * if the IAL changes the address the new address must also be
- * from a reservation.
- */
- GMM_SET_DEBUG_NAME("Framebuffer");
- ret = display->context->dispatch.gmm_alloc_surface(
- &fb_info->fb_base_offset,
- fb_info->pixel_format,
- &fb_info->width,
- &fb_info->height,
- &fb_info->screen_pitch,
- &size,
- IGD_GMM_ALLOC_TYPE_RESERVATION,
- &fb_info->flags);
- if(ret) {
- EMGD_ERROR_EXIT("Allocation of Front buffer failed: %d", ret);
- return ret;
- }
- fb_info->allocated = 1;
- /* Set the visible offset to the newly-allocated offset: */
- fb_info->visible_offset = fb_info->fb_base_offset;
- } else {
- /* If not reallocating, use back the offset in plane_fb_info */
- fb_info->fb_base_offset = plane_fb_info->fb_base_offset;
- }
-
- OS_MEMCPY(plane_fb_info, fb_info, sizeof(igd_framebuffer_info_t));
- plane_fb_info->allocated = 1;
- EMGD_DEBUG("plane_fb_info->fb_base_offset = 0x%08lx",
- plane_fb_info->fb_base_offset);
-
- }
-
- if(timing && (flags & MODE_UPDATE_PIPE)) {
- EMGD_DEBUG("Updating pipe timing.");
- PIPE(display)->timing = timing;
- PIPE(display)->owner = display;
- }
-
- if(pt_info && (flags & MODE_UPDATE_PORT)) {
- EMGD_DEBUG("OLD_PT========NEW PT ");
- IGD_PRINTK_PTINFO_2(PORT(display, port_number)->pt_info, pt_info);
- OS_MEMCPY(PORT(display, port_number)->pt_info, pt_info,
- sizeof(igd_display_info_t));
- }
-
- EMGD_TRACE_EXIT;
- return 0;
-} /* end mode_update_plane_pipe_ports() */
-
-#ifdef CALCULATE_ELD_INFOFRAMES
-
-/*!
- * Calculates infoframes information top be used by HDMI port drivers
- *
- * @param port
- * @param timing_info
- * @param temp_cea
- *
- * @return 0
- */
-static int calculate_infoframes(
- igd_display_port_t *port,
- igd_timing_info_t *timing_info,
- cea_extension_t *temp_cea)
-{
-
- pd_timing_t *cea_timings = NULL, *cea_timing_temp = NULL;
-
- EMGD_TRACE_ENTER;
-
- /* VBIOS has no access to CEA timing tables and this is not supported
- there as well */
- if(timing_info->mode_info_flags & PD_MODE_CEA){
- if(timing_info->width != 640 && timing_info->height != 480){
- port->edid->cea->quantization = HDMI_QUANTIZATION_RGB_220;
- }
-
- /* Based on DPG algorithm. If monitors support more than 2 channels
- for 192Khz or/and 92Khz then set two pixel repeat one.
- KIV: Add pruning for pixel PIX_REPLICATION_3 if required */
- if(temp_cea->audio_cap[CAP_192_KHZ].max_channels>2 ||
- temp_cea->audio_cap[CAP_96_KHZ].max_channels>2){
- port->edid->cea->pixel_rep = PIX_REPLICATION_1;
- }
-
-
- /* Based on HDMI spec 6.7.1 & 6.7.2 */
- if ((timing_info->width == 720) && ((timing_info->height == 480) ||
- (timing_info->height== 576))){
- port->edid->cea->colorimetry = HDMI_COLORIMETRY_ITU601;
- } else if(((timing_info->width==1280) && (timing_info->height==720)) ||
- ((timing_info->width == 1920) && (timing_info->height == 1080))){
- port->edid->cea->colorimetry = HDMI_COLORIMETRY_ITU709;
- }
-
- cea_timings = (igd_timing_info_t *) OS_ALLOC(cea_timing_table_size);
- OS_MEMCPY(cea_timings, cea_timing_table, cea_timing_table_size);
- cea_timing_temp = cea_timings;
-
- while (cea_timings->width != IGD_TIMING_TABLE_END){
- if(cea_timings->width == timing_info->width &&
- cea_timings->height == timing_info->height &&
- cea_timings->refresh == timing_info->refresh &&
- cea_timings->dclk == timing_info->dclk &&
- (cea_timings->mode_info_flags &
- (PD_ASPECT_16_9| IGD_SCAN_INTERLACE)) ==
- (timing_info->mode_info_flags &
- (PD_ASPECT_16_9| IGD_SCAN_INTERLACE))){
- port->edid->cea->video_code = cea_timings->mode_number;
- break;
- }
- cea_timings++;
- }
-
- OS_FREE(cea_timing_temp);
-
- }
-
- EMGD_TRACE_EXIT;
- return 0;
-}
-#endif /* CALCULATE_ELD_INFOFRAMES */
-
-/*!
- * Calculates the Edid like data (ELD) if port supports audio transmission
- *
- * @param port
- * @param timing_info
- *
- * @return 0
- */
-static int calculate_eld(
- igd_display_port_t *port,
- igd_timing_info_t *timing_info)
-{
- /* Calculate for non-content protected & content protected(Array of 2) */
-#ifdef CALCULATE_ELD_INFOFRAMES
- unsigned long cal_NPL[2]; /* Number of packer per line calculate*/
- unsigned long poss_NPL[2]; /* Number of packer per line possible*/
- unsigned long max_bitRate_2[2],max_bitRate_8[2];
- unsigned long h_refresh, audio_freq;
- unsigned char input;
- int i,j,pix_rep;
-#endif
- cea_extension_t *temp_cea = NULL ;
-
- EMGD_TRACE_ENTER;
- /* Only calculate eld for HDMI port */
- if((port->pd_driver->type != PD_DISPLAY_HDMI_EXT &&
- port->pd_driver->type != PD_DISPLAY_HDMI_INT)){
- return 0;
- }
- if(port->firmware_type == PI_FIRMWARE_EDID){
- temp_cea = (cea_extension_t*)port->edid->cea;
- }
- /* Displayid unsupported for now. Uncomment this code when audio
- information is available for Display ID
- temp_cea = (&cea_extension_t)port->displayid->cea;*/
-
- if(temp_cea == NULL){
- /* CEA data unavailable, display does not have audio capability? */
- /* We would allocate dummy edid structure and here and we should ony
- used canned ELD */
- if(port->edid == NULL) {
- port->edid = (edid_t *) OS_ALLOC(sizeof(edid_t));
- OS_MEMSET(port->edid, 0 , (sizeof(edid_t)));
- }
-
- port->edid->cea = (cea_extension_t *) OS_ALLOC(sizeof(cea_extension_t));
- OS_MEMSET(port->edid->cea, 0 , (sizeof(cea_extension_t)));
- port->edid->cea->canned_eld = 1;
- temp_cea = (cea_extension_t*)port->edid->cea;
- port->callback->eld = &(port->edid->cea);
- }
-
- /* Default to canned ELD data */
- temp_cea->LPCM_CAD[0] = 0x9;
- temp_cea->speaker_alloc_block[0] = 0x1;
- /* Default 0 Pixel replication */
- port->edid->cea->pixel_rep = PIX_REPLICATION_0;
- /* Default */
- port->edid->cea->colorimetry = HDMI_COLORIMETRY_NODATA;
- /* Default RGB 256 wuantization full range */
- port->edid->cea->quantization = HDMI_QUANTIZATION_RGB_256;
- /* Default Unknown video code */
- port->edid->cea->video_code = 0;
- port->edid->cea->aspect_ratio = (timing_info->mode_info_flags & PD_ASPECT_16_9)
- ? PD_ASPECT_RATIO_16_9 : PD_ASPECT_RATIO_4_3;
-
-#ifdef CALCULATE_ELD_INFOFRAMES
- calculate_infoframes(port,timing_info,temp_cea);
- /* If canned eld is not set and audio info from transmitter is available */
- if(temp_cea->canned_eld != 1 && (temp_cea->audio_flag & PD_AUDIO_CHAR_AVAIL)){
- pix_rep = port->edid->cea->pixel_rep;
- /*h_refresh = timing_info->dclk/timing_info->htotal;*/
- h_refresh = timing_info->refresh;
- cal_NPL[0] = (pix_rep*(timing_info->hsync_end - timing_info->hsync_start) -
- port->edid->cea->K0) /32;
- cal_NPL[1] = (pix_rep*(timing_info->hsync_end - timing_info->hsync_start) -
- port->edid->cea->K1) /32;
-
- poss_NPL[0] = MODE_MIN(cal_NPL[0],port->edid->cea->NPL);
- poss_NPL[1] = MODE_MIN(cal_NPL[1],port->edid->cea->NPL);
-
- max_bitRate_2[0] = h_refresh * poss_NPL[0] - 1500;
- max_bitRate_2[1] = h_refresh * poss_NPL[1] - 1500;
-
- max_bitRate_8[0] = h_refresh * poss_NPL[0] * 4 - 1500;
- max_bitRate_8[1] = h_refresh * poss_NPL[1] * 4 - 1500;
-
- /* Loop trough Content Protection disabled then enabled */
- for(i=0 ; i<2; i++){
- for(j=0 ; j<3; j++){
- input = 0;
- audio_freq = 48000 * (1<<j); /* 48Khz->96Khz->192Khz */
- if(max_bitRate_8[i] >= audio_freq){
- input = 7;
- }else if(max_bitRate_2[i] >= audio_freq){
- input = 1;
- }
- /* take the minimum value min(transmitter, receiver) */
- input = MODE_MIN(input,temp_cea->audio_cap[j].max_channels);
- temp_cea->LPCM_CAD[j] |= input<<((1-i)*3);
- if(temp_cea->audio_cap[j]._24bit){
- temp_cea->LPCM_CAD[j] |= BIT(7);
- }
- if(temp_cea->audio_cap[j]._20bit){
- temp_cea->LPCM_CAD[j] |= BIT(6);
- }
- }
- }
-
- /* TODO: Further construction of ELD from Monitor Name String begins here
- for now we only support VSDB */
- /* By default we don send any vendor specific block unless latency value
- use for audio sync feature is available */
- temp_cea->vsdbl = 0;
- /* This means the latecy field is available VSBD_LATENCY_FIELD = 8*/
- if(temp_cea->vendor_block.vendor_block_size > VSBD_LATENCY_FIELD){
- OS_MEMCPY(temp_cea->misc_data, temp_cea->vendor_data_block,
- temp_cea->vendor_block.vendor_block_size);
- temp_cea->vsdbl = temp_cea->vendor_block.vendor_block_size;
- /* If the VSBD has latency fields */
- if(*(temp_cea->vendor_data_block + VSBD_LATENCY_FIELD - 1) & 0x80){
- if(timing_info->mode_info_flags & IGD_SCAN_INTERLACE){
- if(*(temp_cea->vendor_data_block + VSBD_LATENCY_FIELD - 1) & 0x40){
- temp_cea->vendor_block.p_latency = 1;
- temp_cea->vendor_block.i_latency = 1;
- }else{
- /* No latency available: Since it is an interlace mode but no
- vsbd_intlc_fld_present is available */
- temp_cea->vendor_block.p_latency = 0;
- temp_cea->vendor_block.i_latency = 0;
- }
- }else{
- temp_cea->vendor_block.p_latency = 1;
- temp_cea->vendor_block.i_latency = 0;
- }
- }
- }
- }
-#endif /* CALCULATE_ELD_INFOFRAMES */
- temp_cea->audio_flag |= ELD_AVAIL;
- EMGD_TRACE_EXIT;
- return 0;
-}
-
-/*!
- * Configure either the primary or secondary display. This means all the
- * timings, the framebuffer, the ports, the plane, and the pipe.
- *
- * The port range could be calculated based on primary or secondary
- * display but it seems easier at this point to pass the port range
- * in since it is used for all the for loops.
- *
- * @param driver_handle
- * @param display
- * @param pt_info
- * @param fb_info
- * @param dc
- * @param p0
- * @param pn
- * @param flags
- *
- * @return 0 on success
- * @return -IGD_ERROR_INVAL on failure
- */
-static int configure_display(
- igd_driver_h driver_handle,
- igd_display_context_t *display,
- igd_display_info_t *pt_info,
- igd_framebuffer_info_t *fb_info,
- unsigned long dc,
- int p0, int pn,
- unsigned long flags)
-{
- igd_context_t *context = (igd_context_t *)driver_handle;
- int p;
- igd_display_port_t *port;
- igd_timing_info_t *timing_info;
- unsigned long update_flags;
- unsigned short port_number = 0;
- int ret;
- int seamless = FALSE;
-
- EMGD_TRACE_ENTER;
-
- /* FIXME: Should this be an assert? */
- if (display == NULL) {
- EMGD_DEBUG("Trying to configure a NULL display");
- return 0;
- }
-
- EMGD_DEBUG("Configure timings");
- for (p = pn; p > p0; p--) {
- EMGD_DEBUG("Configure port %d", DC_PORT_NUMBER(dc, p));
- if ((port_number = DC_PORT_NUMBER(dc, p))) {
- port = context->mod_dispatch.dsp_port_list[port_number];
- if (!port) {
- EMGD_DEBUG("Port %d not found", port_number);
- } else {
-
- /* Put a copy of the timings in the port's structure */
- if (pt_info) {
- if (port->pt_info == NULL) {
- port->pt_info = OS_ALLOC(sizeof(igd_display_info_t));
- if (!port->pt_info) {
- EMGD_ERROR_EXIT("unable to alloc a pt_info "
- "struct in port.");
- return -IGD_ERROR_INVAL;
- }
- }
- OS_MEMCPY(port->pt_info, pt_info,
- sizeof(igd_display_info_t));
- } else {
- EMGD_ERROR("No primary timing info!");
- }
- }
- }
- }
-
- if(!(pt_info->flags & IGD_DISPLAY_ENABLE)) {
- EMGD_ERROR_EXIT("Ptinfo has no IGD_DISPLAY_ENABLE!");
- return 0;
- }
-
- display->port_number = DC_PORT_NUMBER(dc, (p0 + 1));
-
- /* Set mode */
- EMGD_DEBUG("Set mode, using port %ld", display->port_number);
- port = PORT(display, display->port_number);
-
- EMGD_DEBUG("Calling matchmode on display");
- ret = match_mode(display, port->timing_table, fb_info, pt_info,
- &timing_info);
- if(ret) {
- EMGD_DEBUG("Match Mode for display failed");
- EMGD_TRACE_EXIT;
- return -IGD_ERROR_INVAL;
- }
-
- /* Now b4, we program the timing_info, let's first see if seamless
- * option is requested, if it is then
- * We need to make sure the incoming dc, timing, framebuffer
- * info and etc match. We must respect the FORCE_ALTER flag.
- *
- * Seamless option buys you a one-time ticket for the seamless
- * experience from the firmware to the driver. After the first mode set
- * in driver, you don't get it the next time when you alter display.
- *
- */
-#ifndef CONFIG_MICRO
- if(dc && !(flags & IGD_FORCE_ALTER) &&
- (mode_context->seamless == TRUE) ) {
-
- /* User wants seamless */
- if(mode_context->fw_info != NULL) {
-
- OPT_MICRO_CALL_RET(seamless, query_seamless(dc,
- (p0/4),
- timing_info,
- fb_info,
- 0));
-
- EMGD_DEBUG(":Seamless = %s", seamless ?"ON" : "OFF");
- mode_context->seamless = FALSE;
- /* FIXME: For clone you get called twice. Need to
- * Fix that corner case
- */
-
- }
- }
-#endif
- /* In case the seamless is FALSE, we do reset_plane_pipe_ports
- * which is supposed to be called in alter_displays anyway.
- * But we have to delay it since the user asked for seamless.
- * And we don't want to switch-off the display during
- * seamless.
- * Now we know that even though the user asked for it, we cannot
- * support seamless, so we call reset_plane_pipe_ports now.
- */
- if(seamless == FALSE) {
-
- /* Reset planes/pipes/ports before doing first alter display */
- if (mode_context->first_alter) {
- mode_context->dispatch->reset_plane_pipe_ports(
- mode_context->context);
- mode_context->first_alter = FALSE;
- }
-
- }
-
- if(calculate_eld(port, timing_info)){
- EMGD_DEBUG("Fail to calculate ELD");
- }
- /* turn on all ports */
- EMGD_DEBUG("turn on displays plane_pipe_ports %d..%d", (p0 + 1), (pn-1));
-
- for (p = (p0 + 1); p <= pn; p++) {
- if (DC_PORT_NUMBER(dc, p)) {
- port = context->mod_dispatch.dsp_port_list[DC_PORT_NUMBER(dc, p)];
-
- display->allocated = 1;
-
- /* Update mode info for the port */
- if (p == (p0 + 1)) {
- update_flags = MODE_UPDATE_PLANE | MODE_UPDATE_PIPE |
- MODE_UPDATE_PORT;
- } else {
- update_flags = MODE_UPDATE_PORT;
- }
- ret = mode_update_plane_pipe_ports(display, DC_PORT_NUMBER(dc, p),
- timing_info, fb_info, pt_info, update_flags);
- if (ret) {
- /*
- * This could happen if there was no memory for the
- * framebuffer or the FB was an invalid format. The
- * first is a too bad failure. The second should have
- * been checked by the IAL.
- */
- EMGD_ERROR_EXIT("mode_update_plane_pipe_ports returned error "
- "%d", ret);
- port->pt_info->flags &= ~IGD_DISPLAY_ENABLE;
- return ret;
- }
-
- /* Program the port registers */
- if(seamless == TRUE) {
- /* Don't have to program the registers, Since it's
- * all updated. Just return 0
- */
- ret = 0;
- } else {
- ret = mode_context->dispatch->program_port(display,
- DC_PORT_NUMBER(dc, p), TRUE);
- }
- if (ret == 0) {
- port->inuse = 1;
- } else {
- port->pt_info->flags &= ~IGD_DISPLAY_ENABLE;
- }
- }
- }
- EMGD_DEBUG("done - turn on displays plane_pipe_ports %d", p);
-
- /* Clear the Framebuffer after the planes, pipes and ports are
- * disabled and before they are enabled. */
- if (flags & IGD_CLEAR_FB) {
- OPT_MICRO_VOID_CALL(full_clear_fb(mode_context, fb_info, NULL));
- }
-
- /* program the pipe/plane/port if seamless is FALSE */
- if(seamless == FALSE) {
-
- EMGD_DEBUG("Seamless is FALSE");
-
- ret = TRUE;
-
- do{
- /* turn on pipe */
- mode_context->dispatch->program_pipe(display, TRUE);
-
- /* turn on plane */
- mode_context->dispatch->program_plane(display, TRUE);
-
- /* turn on port */
- for (p = pn; p > p0; p--) {
- if (DC_PORT_NUMBER(dc, p)) {
- mode_context->dispatch->post_program_port(display,
- DC_PORT_NUMBER(dc, p), 0);
- }
- }
-
- /* Check is display working fine */
- OPT_MICRO_CALL_RET(ret, mode_context->dispatch->
- check_display(display, DC_PORT_NUMBER(dc, p),TRUE));
-
- if(!ret){
- /* turn off plane and pipe */
- mode_context->dispatch->program_plane(display, FALSE);
- mode_context->dispatch->program_pipe(display, FALSE);
- }
- }while(!ret);
-
- }
-#ifndef CONFIG_MICRO
- else { /* Seamless is TRUE */
-
- /* Updating the plane registers, does not require us to
- * turn-off the pipe and we can still have seamless
- * because the display is not turned-off
- */
-
- EMGD_DEBUG(" Seamless is TRUE");
- if(mode_context->fw_info->program_plane == 1) {
-
- /* This means we have to update the plane registers
- * with the new values.eg. Change in pitch size between
- * firmware values and driver values. But we MUST also
- * update the palette registers for this to work and
- * palette registers are programmed when pipe is programmed.
- * This means we program the pipe , followed by the plane.
- */
-
- /* By doing this, we update the palette */
- mode_context->dispatch->program_pipe(display, TRUE);
-
- /* update the plane registers */
- mode_context->dispatch->program_plane(display, TRUE);
- }
- }
-#endif
-
- EMGD_TRACE_EXIT;
- return 0;
-}
-
-
-#ifndef CONFIG_MICRO
-
-/*!
- * This function checks whether all the ports on the primary pipe of a dc are
- * moving to a secondary pipe on a new dc.
- *
- * @param current_dc current_dc the system is in.
- * @param dc new requested dc.
- *
- * @return 0 if not all the ports are moving
- * @return 1 if all the ports are moving
- */
-int all_ports_moving(unsigned long current_dc, unsigned long dc)
-{
- unsigned long index, index2, port;
- int found_port;
- int result = 1;
-
- /*
- * We need to look for each of the primary ports on the current dc,
- * and see if they exist on the secondary port of the new dc.
- */
- for (index = IGD_DC_IDX_PRIMARY_MASTER;
- index <= IGD_DC_IDX_PRIMARY_TWIN3; index++) {
- found_port = 0;
- port = IGD_DC_PORT_NUMBER(current_dc, index);
- /* If there is a port, let's look for it. */
- if (port) {
- /* Try to find this port on the secondary pipe */
- for (index2 = IGD_DC_IDX_SECONDARY_MASTER;
- index2 <= IGD_DC_IDX_SECONDARY_TWIN2; index2++) {
- /*
- * We found the port, let's stop looking for this port and
- * move on to the next port
- */
- if (port == IGD_DC_PORT_NUMBER(dc, index2)) {
- found_port = 1;
- break;
- }
- }
- /* As soon as there is a port that we don't find, we can exit */
- if (!found_port) {
- result = 0;
- break;
- }
- }
- }
-
- return result;
-}
-
-/*!
- * This function checks whether a specified port exists in a dc, and if it does
- * it returns the pipe master index for the pipe which contained the port.
- *
- * @param dc the dc to check for a port.
- * @param port the port to check for.
- *
- * @return 0 if the specified does not exist
- * @return IGD_DC_IDX_PRIMARY_MASTER if the port was found on the primary pipe
- * @return IGD_DC_IDX_SECONDARY_MASTER if the port was found on the secondary
- * pipe
- */
-int dc_contains_port_type(unsigned long dc, unsigned long port)
-{
- unsigned long index;
- int result = 0;
-
- for (index = IGD_DC_IDX_PRIMARY_MASTER;
- index <= IGD_DC_IDX_PRIMARY_TWIN3; index++) {
-
- if (IGD_DC_PORT_NUMBER(dc, index) == port) {
- result = IGD_DC_IDX_PRIMARY_MASTER;
- break;
- }
- }
-
- for (index = IGD_DC_IDX_SECONDARY_MASTER;
- index <= IGD_DC_IDX_SECONDARY_TWIN2; index++) {
-
- if (IGD_DC_PORT_NUMBER(dc, index) == port) {
- result = IGD_DC_IDX_SECONDARY_MASTER;
- break;
- }
- }
-
- return result;
-}
-
-/*!
- * This function checks whether a frame buffer swap and cursor
- * swap is required based on given current_dc and new_dc.
- *
- * @param current_dc current_dc the system is in.
- * @param dc new requested dc.
- * @param dsp pointer to a display context pointer
- *
- * @return 0 if no swap is required
- * @return 1 if swap is required
- */
-int swap_required(
- unsigned long current_dc,
- unsigned long dc,
- igd_display_context_t **dsp)
-{
-
- /*
- * Note: Preserve the order of conditions as is. Changing the order
- * of below conditions require relook into the whole function to
- * make sure sematics match to return right value.
- */
-
- /* Do not swap if no dc or current_dc */
- if (!dc || !current_dc) {
- return 0;
- }
-
- /*
- * Do NOT swap the frame buffer and cursor if dc is going
- * from twin to extended and not all the ports are moving to the other
- * pipe. If all the ports are moving to the other pipe, then DO swap
- * the frame buffer and cursor.
- * We also need to make sure we are not in the special case where our
- * extended mode contains LVDS and we are on a platform which does not
- * support LVDS on PIPE A. In this case we do not want to swap here because
- * we will not be swapping later since the twin configuration will stay on
- * PIPE A so that the LVDS can move to PIPE B.
- */
- if (IGD_DC_TWIN(current_dc) && IGD_DC_EXTENDED(dc)) {
- if (dsp && *dsp && all_ports_moving(current_dc, dc) &&
- !(dc_contains_port_type(dc, IGD_PORT_TYPE_LVDS) &&
- !(PIPE(*dsp)->pipe_features & IGD_PORT_SHARE_LVDS))) {
- return 1;
- } else {
- return 0;
- }
- }
-
- /*
- * Do NOT swap if dc is changing from Single to clone or
- * vice versa. In this case there is only 1 fb and no swap is required
- * and it stays with primary display.
- */
- if ((IGD_DC_SINGLE(current_dc) && IGD_DC_CLONE(dc)) ||
- (IGD_DC_CLONE(current_dc) && IGD_DC_SINGLE(dc))) {
- return 0;
- }
-
- /*
- * If secondary master port is moving to primary master or
- * primary master is moving to secondary master, try
- * and keep the framebuffer address and cursor the same.
- */
- if (DC_PORT_NUMBER(current_dc, 5) == DC_PORT_NUMBER(dc, 1) ||
- (DC_PORT_NUMBER(current_dc, 1) == DC_PORT_NUMBER(dc, 5))) {
- /*
- Note: This was previosuly return 1 to indicate swap required, which will cause
- a frame buffer swap when changing display from twin to clone. If the display is
- in extended mode before changing from twin to clone, then both Plane A and Plane B
- will point to the secondary frame buffer offset adress in clone mode and cause
- blank screen (.
- */
- return 0;
- }
- return 0;
-}
-#endif
-
-/*!
- * This function sets up planes, pipes, and ports
- * with the configuration passed in and returnes either one
- * or two display handle lists.
- *
- * @param driver_handle from igd_init_driver().
- * @param primary on return, this points to a list of displays.
- * @param primary_ptinfo incoming timing info for the primary.
- * @param primary_fbinfo incoming framebuffer info.
- * @param secondary on return, this points to a list of displays.
- * @param secondary_fbinfo incoming framebuffer info.
- * @param dc display configuration
- * @param flags modify function behavior
- *
- * @return 0 on success
- * @return -IGD_INVAL on failure
- */
-int igd_alter_displays(
- igd_driver_h driver_handle,
- igd_display_h *_primary,
- igd_display_info_t *primary_pt_info,
- igd_framebuffer_info_t *primary_fb_info,
- igd_display_h *_secondary,
- igd_display_info_t *secondary_pt_info,
- igd_framebuffer_info_t *secondary_fb_info,
- unsigned long dc,
- unsigned long flags)
-{
- igd_context_t *context = (igd_context_t *)driver_handle;
- igd_display_context_t **primary = (igd_display_context_t **)_primary;
- igd_display_context_t **secondary = (igd_display_context_t **)_secondary;
- igd_framebuffer_info_t *fb_info = NULL;
- igd_display_context_t *display = NULL,*tv_display=NULL;
- int p;
- int ret;
- unsigned short tv_port_num=0;
- int p_chng = 1, s_chng = 1;
- unsigned char disable_plane_pipe = 0;
- unsigned long current_dc;
-
-#if 0 /* Ian Elliott is taking this out ... see comment below */
-#ifndef CONFIG_MICRO
- igd_framebuffer_info_t *plane_fb_info = NULL;
-#endif
-#endif /* 0 -- Ian is taking this out */
-
- EMGD_TRACE_ENTER;
-
- /*
- * Make sure the DC is valid
- *
- * vBIOS won't be able to do this every time, for now only have
- * the drivers's do the check.
- */
-#ifndef CONFIG_MICRO
- if (dc && !dsp_valid_dc(dc, 0)) {
- EMGD_ERROR_EXIT("Invalid display configuration: 0x%08lx", dc);
- return -IGD_ERROR_INVAL;
- }
-#endif
-
-
- /*
- * Can all display_info's and fb_info's be NULL? I.E. make this
- * function do an alloc of display handles only? If so, then
- * check for that condition and return without error. Otherwise
- * return an error.
- */
- if (dc && (!primary_pt_info && !primary_fb_info) &&
- (!secondary_pt_info && !secondary_fb_info)) {
- EMGD_ERROR_EXIT("Invalid timing and framebuffer info");
- return -IGD_ERROR_INVAL;
- }
-
-#ifndef CONFIG_MICRO
- /* FIXME: GDK Change this to dispatch->idle() */
- if (dsp_wait_rb(mode_context->context) != 0) {
- return -IGD_ERROR_INVAL;
- }
-#endif
-
- /* If seamless request is NOT set , then do reset_plane_pipe_ports
- * else delay it until we cannot support it.
- * If seamless is requested by the user and we CAN support it
- * then we need to make sure reset_plane_pipe_ports is NOT
- * called. That's the whole point anyway. Not to reset anything
- * during seamless transition
- */
- if(mode_context->seamless != TRUE) {
-
- /* Reset planes/pipes/ports before doing first alter display */
- if (mode_context->first_alter) {
- mode_context->dispatch->reset_plane_pipe_ports(
- mode_context->context);
- mode_context->first_alter = FALSE;
- }
- }
-
- current_dc = *(context->mod_dispatch.dsp_current_dc);
-
- /*
- * Turn off the planes, pipes, and ports associated with the current
- * DC. However, limit the change to the primary if the secondary
- * display handle is NULL or limit the change to the secondary if the
- * the pimary display handle is NULL.
- */
- for (p = 7; p > 0; p--) {
- if (p > 4) {
- display = NULL;
- if (DC_PORT_NUMBER(current_dc, p)) {
- display = context->mod_dispatch.
- dsp_display_list[IGD_DC_SECONDARY(current_dc)];
- s_chng = TIMING_CHANGED(display, dc, current_dc,
- secondary_pt_info, secondary_fb_info,
- (unsigned long)0xfff00000, flags);
- }
-
- if (s_chng && display && secondary) {
- /* if the port is TV, then don't set the power to S3 as this causes
- * blank screen and system hang on LVDS on FSDOS, probably because the
- * external clock needs to be on till the pipes and
- * DPLLs are off
- */
- if(PORT(display,DC_PORT_NUMBER(current_dc, p))->pd_type ==
- PD_DISPLAY_TVOUT) {
- tv_display = display;
- tv_port_num = DC_PORT_NUMBER(current_dc, p);
- } else {
- ret = mode_context->dispatch->program_port(display,
- DC_PORT_NUMBER(current_dc, p), FALSE);
- }
- /* The secondary pipe master */
- if (p == 5) {
- disable_plane_pipe = 1;
- }
- }
- } else {
- display = NULL;
- if (DC_PORT_NUMBER(current_dc, p)) {
- display = context->mod_dispatch.
- dsp_display_list[IGD_DC_PRIMARY(current_dc)];
- p_chng = TIMING_CHANGED(display, dc, current_dc,
- primary_pt_info, primary_fb_info,
- (unsigned long)0x000ffff0, flags);
- }
-
- if (p_chng && display && primary) {
- /* if the port is TV, then don't set the power to S3 as this causes
- * blank screen and system hang on LVDS on FSDOS, probably because the
- * external clock needs to be on till the pipes and
- * DPLLs are off
- */
- if(PORT(display,DC_PORT_NUMBER(current_dc, p))->pd_type ==
- PD_DISPLAY_TVOUT) {
- tv_display = display;
- tv_port_num = DC_PORT_NUMBER(current_dc, p);
- } else {
- ret = mode_context->dispatch->program_port(display,
- DC_PORT_NUMBER(current_dc, p), FALSE);
- }
- /* The primary pipe master */
- if (p == 1) {
- disable_plane_pipe = 1;
- }
- }
- }
-
- /* Disable plane and pipe after disabling the ports */
- if (disable_plane_pipe) {
- if(mode_context->dispatch->full) {
- mode_context->dispatch->full->program_cursor(display, FALSE);
- }
- mode_context->dispatch->program_plane(display, FALSE);
- mode_context->dispatch->program_pipe(display, FALSE);
- /*pipes and dplls are off, now turn off tv port */
- if(tv_display) {
- ret = mode_context->dispatch->program_port(tv_display,
- tv_port_num, FALSE);
- tv_display = NULL;
- }
- disable_plane_pipe = 0;
- }
- }
-
-#ifndef CONFIG_MICRO
- /* If DC is zero, then return here. A zero dc turns everything off */
- /* This never happens for VBIOS since it only always calls *
- * alter_displays at the same point with the same valid DC */
- if (!dc) {
- int i;
- mode_context->dispatch->reset_plane_pipe_ports(mode_context->context);
- /* Should de-allocate everything here */
- dsp_alloc(driver_handle, dc, flags);
- /*
- * FIXME: This should be done inside dsp alloc, mode module does
- * not own this information.
- * When dc = 0, set all displays allocated to 0.
- */
- for (i=0; i<IGD_MAX_PORTS+1; i++) {
- if (context->mod_dispatch.dsp_display_list[i]) {
- context->mod_dispatch.dsp_display_list[i]->allocated = 0;
- }
- context->mod_dispatch.dsp_display_list[i] = NULL;
- }
-
- return 0;
- }
-#endif
-
- /*
- * Check the DC (display configuration). If it is the same as the
- * current configuration, then don't change any allocations, only
- * modify the framebuffers and timings.
- */
- if (dc != current_dc) {
- EMGD_DEBUG("Allocate display handles based on DC");
-
-#ifndef CONFIG_MICRO
- if (swap_required(current_dc, dc, primary)) {
- swap_fb_cursor();
- }
-#endif
- /*
- * This function should never be called after VBIOS initialization *
- * The dsp_alloc is discarded after VBIOS init and is over- *
- * written by font tables. Thus in VBIOS IAL, alter_displays *
- * is never get called with a different DC from the 1st time *
- */
- dsp_alloc(driver_handle, dc, flags);
-
- }
-
- /* Attach the displays to the caller's pointers */
- if (primary) {
- *primary = context->mod_dispatch.dsp_display_list[IGD_DC_PRIMARY(dc)];
-#ifndef CONFIG_MICRO
- if (*primary && context->mod_dispatch.alloc_queues) {
- ret = context->mod_dispatch.alloc_queues(driver_handle,
- (*primary)->pipe, flags);
- if (ret) {
- EMGD_ERROR("unable to allocate command queues");
- }
- }
-#endif
- }
- if (secondary) {
- EMGD_DEBUG("Attaching display 1 to secondary pointer");
- *secondary = context->mod_dispatch.
- dsp_display_list[IGD_DC_SECONDARY(dc)];
-#ifndef CONFIG_MICRO
- if (*secondary && context->mod_dispatch.alloc_queues) {
- ret = context->mod_dispatch.alloc_queues(driver_handle,
- (*secondary)->pipe, flags);
- if (ret) {
- EMGD_ERROR("unable to allocate command queues");
- }
- }
-#endif
- }
-
- /*
- * Configure the primary display. This configures the timings and the
- * framebuffer. Once configured, it turns everythying on.
- */
- if(primary && *primary && (primary_pt_info || primary_fb_info) && p_chng) {
- EMGD_DEBUG("Configure primary timings");
- /* make framebuffer changes */
- if (primary_fb_info) {
- /* set up new frame buffer info */
- fb_info = primary_fb_info;
- } else {
- fb_info = PLANE(*primary)->fb_info;
- }
-
- ret = configure_display(driver_handle,
- (igd_display_context_t *)(*primary), primary_pt_info,
- fb_info, dc, 0, 4, flags);
- if (ret) {
- EMGD_DEBUG("Primary display disabled.");
- }
- }
-
- /*
- * Configure the secondary display. This configures the timings and the
- * framebuffer. Once configured, it turns everythying on.
- *
- * How close is this code to the code for the primary? Could this
- * be moved to a separate function?
- */
- if (secondary != NULL) {
-
-#ifndef CONFIG_MICRO
- /*
- * In the case where we are in extended or clone and our pipe is not
- * turned on, we need to turn the pipes on.
- * We can run into this situation on pre-Cantiga Gen platforms on Linux
- * where LVDS was the primary display and was assigned PIPE B. Then we
- * are switching from LVDS to another display and that other display
- * wants to take PIPE A. In this case PIPE B will be turned on, the
- * display's new port will take PIPE A and turn on PIPE A. The second
- * display thinks it is still PIPE A and nothing has changed for it.
- * In this case where our pipe is not turned on, we need to let the
- * system know that something has changed.
- */
- if ((IGD_DC_CLONE(dc) || IGD_DC_EXTENDED(dc))
- && !(EMGD_READ32(MMIO(*secondary) + PIPE(*secondary)->pipe_reg)
- & 0x80000000)) {
- s_chng = 1;
- }
-#endif
-
- EMGD_DEBUG("Starting secondary pipe programming");
- if ((*secondary != NULL) && (secondary_pt_info || secondary_fb_info) &&
- s_chng){
- /*
- * Configure the framebuffer. For clone, it is the same
- * as the primary. For DIH, it is a unique fb.
- */
- EMGD_DEBUG("configure secondary framebuffer");
- if (dc & IGD_DISPLAY_CONFIG_CLONE) {
- fb_info = PLANE(*primary)->fb_info;
- } else {
- if (secondary_fb_info) {
- fb_info = secondary_fb_info;
- } else {
- fb_info = PLANE(*secondary)->fb_info;
- }
- }
-
- ret = configure_display(driver_handle,
- (igd_display_context_t *)(*secondary), secondary_pt_info,
- fb_info, dc, 4, 7, flags);
- if (ret) {
- EMGD_DEBUG("Secondary display disabled.");
- EMGD_ERROR("Secondary display disabled.");
- }
- }
- } else {
- EMGD_DEBUG("Skipped secondary programming, NULL handle");
- }
-
- /*
- * Workaround: wait for Vblank to avoid people accessing display
- * plane registers before the register is updated properly.
- */
- if (primary && *primary) {
- EMGD_DEBUG("Wait for vblank on primary display (%p)", primary);
- EMGD_DEBUG("Wait for vblank on primary display (%p)", *primary);
- mode_context->dispatch->wait_vblank(*primary);
- } else if (secondary && *secondary) {
- EMGD_DEBUG("Wait for vblank on secondary display");
- mode_context->dispatch->wait_vblank(*secondary);
- }
-
- EMGD_TRACE_EXIT;
- return 0;
-}
-
-/*!
- * This function sets the power state for the passed
- * display handle. This only updates the power state for the
- * display/port. The pipe, plane, and ringbuffer are left in
- * the same power state. There is also no need to
- * alter_display, since only the port is modified.
- *
- * @param driver_handle from igd_init().
- * @param port_number
- * @param power_state
- *
- * @return 0 on success
- * @return -IGD_INVAL on failure
- */
-int igd_power_display(igd_driver_h driver_handle,
- unsigned short port_number,
- unsigned int power_state)
-{
- igd_context_t *context = (igd_context_t *)driver_handle;
- igd_display_context_t *display;
-
- EMGD_TRACE_ENTER;
- EMGD_DEBUG("Requested power state = %d", power_state);
-
- /* Get the display context that is currently using this port. */
- display = context->mod_dispatch.dsp_display_list[port_number];
- if(!display) {
- return -IGD_ERROR_INVAL;
- }
-
- /* If this display is allocated, but has not been altered, return
- * an error. */
- if (!PORT(display, port_number)->pt_info || !PIPE(display)->timing) {
- EMGD_TRACE_EXIT;
- return -IGD_ERROR_INVAL;
- }
-
- /* Set the desired power state to the display handle and let program_port
- * take care of the rest
- */
- PORT(display, port_number)->power_state = (unsigned long)power_state;
-
- switch(power_state) {
- case IGD_POWERSTATE_D0:
- mode_context->dispatch->program_port(display, port_number, TRUE);
- mode_context->dispatch->post_program_port(display, port_number, 0);
- break;
- case IGD_POWERSTATE_D1:
- case IGD_POWERSTATE_D2:
- case IGD_POWERSTATE_D3:
- mode_context->dispatch->program_port(display, port_number, TRUE);
- break;
- default:
- break;
- }
-
- EMGD_TRACE_EXIT;
- return 0;
-}
-
-/*!
- *
- * @param driver_handle from igd_init().
- * @param port_number
- * @param edid_ptr
- * @param block_number
- *
- * @return 0 on success
- * @return -IGD_ERROR_INVAL or -IGD_ERROR_EDID on failure
- */
-/* FIXME: Move this to PI */
-static int igd_get_EDID_block(igd_driver_h driver_handle,
- unsigned short port_number,
- unsigned char FAR *edid_ptr,
- unsigned char block_number)
-{
- igd_context_t *context = (igd_context_t *)driver_handle;
- igd_display_port_t *port;
- int ret;
-
- EMGD_TRACE_ENTER;
-
- EMGD_ASSERT(driver_handle, "Null driver_handle", -IGD_ERROR_INVAL);
- EMGD_ASSERT(edid_ptr, "Null edid_ptr", -IGD_ERROR_INVAL);
-
- port = context->mod_dispatch.dsp_port_list[port_number];
- if(!port) {
- EMGD_TRACE_EXIT;
- return -IGD_ERROR_INVAL;
- }
- /* Read EDID */
- ret = context->mod_dispatch.i2c_read_regs(
- context,
- port->ddc_reg,
- 10, /* DDC speed 10 KHz */
- port->ddc_dab,
- 128*block_number,
- edid_ptr,
- 128);
-
- if (ret) {
- EMGD_TRACE_EXIT;
- return -IGD_ERROR_EDID;
- }
-
- EMGD_TRACE_EXIT;
- return 0;
-} /* end igd_get_EDID_block() */
-
-/*!
- * Return either a pointer to the live mode list or a copy of the mode list
- * for the requested display. This will be the mode list for the master port
- * on the pipe.
- *
- * @note Currently (AS of 3.3 development) the mode list is
- * described as a igd_display_info_t. However IT IS NOT, this
- * pointer must be cast to a igd_timing_info_t to be used. After
- * 3.3 the igd_display_info_t will be altered to match the
- * igd_timing_info_t with the exception of the private pointers.
- *
- * @param driver_handle handle returned from a successful call to
- * igd_driver_init().
- * @param dc Display configuration that will determine which port
- * controlls the pipe timings and thus, which set of timings to return.
- * @param mode_list The returned mode list. This data may be LIVE. If
- * a live list is returned, care should be taken to not free or alter
- * the data.
- * @param flags The flags will determine which display to query (primary
- * or secondary) and if the mode list returned should be the live list.
- *
- * @return 0 on success.
- * @return -IGD_INVAL if an error occured (memory allocation failed)
- */
-int igd_query_mode_list(igd_driver_h driver_handle,
- unsigned long dc,
- igd_display_info_t **mode_list,
- unsigned long flags)
-{
- igd_context_t *context;
- unsigned short port_number;
- igd_display_port_t *port;
-
- EMGD_TRACE_ENTER;
-
- context = (igd_context_t *)driver_handle;
- *mode_list = NULL;
-
- /* given the DC and flags, which port number to check? */
- port_number = (flags & IGD_QUERY_SECONDARY_MODES) ? DC_PORT_NUMBER(dc, 5) :
- DC_PORT_NUMBER(dc, 1);
-
- port = context->mod_dispatch.dsp_port_list[port_number];
- if (port) {
- if (flags & IGD_QUERY_LIVE_MODES) {
- /*
- * FIXME:
- * timing_table is not an igd_dislay_info_t structure but
- * eventually it will be?
- */
- *mode_list = (igd_display_info_t *)port->timing_table;
- } else {
- OPT_MICRO_CALL(full_mode_query(driver_handle, dc, mode_list,
- port));
- }
- }
-
- if (*mode_list == NULL) {
- EMGD_DEBUG("No port on requested pipe");
- return -IGD_ERROR_INVAL;
- }
-
- EMGD_TRACE_EXIT;
- return 0;
-}
-
-/*!
- * This function is used to initialize any module/dsp
- * module specific structures or tables etc.
- *
- * @param context SS level igd_context.
- *
- * @return 0 on success.
- * @return -IGD_INVAL or -IGD_ERROR_NODEV on failure
- */
-int mode_init(igd_context_t *context)
-{
- igd_dispatch_t *dispatch = &context->dispatch;
- inter_module_dispatch_t *md;
-
- EMGD_TRACE_ENTER;
-
- EMGD_DEBUG("Allocating a mode context...");
-
- /* Clear the allocated memory for mode context */
- OS_MEMSET((void *)mode_context, 0, sizeof(mode_context_t));
-
- /* Set the pointer to igd level context */
- mode_context->context = context;
- mode_context->first_alter = TRUE;
- mode_context->display_color =
- context->mod_dispatch.init_params->display_color;
-
- /* Get mode's dispatch table */
- mode_context->dispatch = (mode_dispatch_t *)
- dispatch_acquire(context, mode_dispatch);
- if(!mode_context->dispatch) {
- EMGD_ERROR_EXIT("Unsupported Device");
- return -IGD_ERROR_NODEV;
- }
-
- md = &context->mod_dispatch;
-
- /* Set the fw_info to 0 */
- mode_context->fw_info = NULL;
-
- /* Hook up the IGD dispatch table entires for mode */
- dispatch->get_EDID_block = igd_get_EDID_block;
- dispatch->power_display = igd_power_display;
- dispatch->query_mode_list = igd_query_mode_list;
- dispatch->alter_displays = igd_alter_displays;
-
- OPT_MICRO_CALL(full_mode_init(context, mode_context));
-
- /* Hook up inter-module dispatch functions */
- md->mode_get_gpio_sets = mode_context->dispatch->get_gpio_sets;
- md->mode_reset_plane_pipe_ports =
- mode_context->dispatch->reset_plane_pipe_ports;
- md->filter_modes = mode_context->dispatch->filter_modes;
-
- /* Hook up Core specific IGD dispatch table entries */
- dispatch->set_palette_entries =
- mode_context->dispatch->full->set_palette_entries;
- dispatch->set_palette_entry = mode_context->dispatch->set_palette_entry;
- dispatch->get_palette_entry = mode_context->dispatch->get_palette_entry;
- dispatch->wait_vblank = mode_context->dispatch->wait_vblank;
-
- /* Initialize dsp module */
- if (dsp_init(context)) {
- EMGD_ERROR("dsp_init() failed.");
- return -IGD_INVAL;
- }
-
- /* Initialze port interface (pi) module */
- if (pi_init(context)) {
- EMGD_ERROR_EXIT("pi_init() failed.");
- if(md->dsp_shutdown) {
- md->dsp_shutdown(context);
- }
- return -IGD_ERROR_INVAL;
- }
-
- if (mode_context->dispatch->full && md->reg_get_mod_state) {
- /* Save mode state */
- module_state_h *state = NULL;
- unsigned long *flags = NULL;
- md->reg_get_mod_state(REG_MODE_STATE, &state, &flags);
- md->mode_save(context, state, flags);
- }
-
- /* Initialize the Display Configuration List */
- /* FIXME: This should be done in dsp init */
- dsp_dc_init(context);
-
- EMGD_TRACE_EXIT;
- return 0;
-}