Exemplo n.º 1
0
/*!
 *
 * @param mmio
 * @param pipe_reg
 * @param time_interval
 *
 * @return 0 on success
 * @return 1 on failure
 */
int wait_for_vblank_timeout_plb(
	unsigned char *mmio,
	unsigned long pipe_reg,
	unsigned long time_interval)
{
	int ret;
	unsigned long pipe_status_reg = pipe_reg + PIPE_STATUS_OFFSET;
	unsigned long tmp;
	os_alarm_t timeout;
	unsigned long request_for;

	EMGD_TRACE_ENTER;
	EMGD_DEBUG("Parameters: MMIO = %p, pipe_reg = %lx, time_interval = %lx",
		mmio, pipe_reg, time_interval);

	/* If pipe is off then just return */
	if(!((1L<<31) & EMGD_READ32(EMGD_MMIO(mmio) + pipe_reg))) {
		EMGD_DEBUG("Pipe disabled/Off");
		EMGD_TRACE_EXIT;
		return 1;
	}

	/*
	 * When VGA plane is on the normal wait for vblank won't work
	 * so just skip it.
	 */
	if(!(EMGD_READ32(EMGD_MMIO(mmio) + 0x71400) & 0x80000000)) {
		EMGD_DEBUG("VGA Plane On");
		EMGD_TRACE_EXIT;
		return 1;
	}

	/* 1. Request the interrupt handler to record the next VBlank: */
	request_for = VBINT_REQUEST(VBINT_WAIT,
		(pipe_status_reg == PIPEA_STAT) ? VBINT_PORT2 : VBINT_PORT4);
	mode_context->dispatch->full->request_vblanks(request_for, mmio);

	/* 2. Wait & poll for the next VBlank: */
	timeout = OS_SET_ALARM(time_interval);
	do {
		OS_SCHEDULE();
		tmp = mode_context->dispatch->full->vblank_occured(request_for);
	} while ((tmp == 0x00) && (!OS_TEST_ALARM(timeout)));
	if (tmp == 0) {
		EMGD_ERROR_EXIT("Timeout waiting for VBLANK");
		ret = 0;
	} else {
		ret = 1;
	}

	/* 3. End our request for the next VBlank: */
	mode_context->dispatch->full->end_request(request_for, mmio);


	EMGD_TRACE_EXIT;
	return ret;
} /* wait_for_vblank_timeout_plb */
Exemplo n.º 2
0
/**
 * Set the display to the surface specified by buffer.
 *
 * @param swap_chain (IN) Pointer to the swap chain associated with buffer.
 * @param buffer (IN) Pointer to the buffer to display.
 */
void emgddc_flip(emgddc_swapchain_t *swap_chain, emgddc_buffer_t *buffer)
{
	drm_emgd_priv_t *priv = buffer->priv;
	igd_context_t *context = priv->context;
	igd_surface_t surf;
	int ret;

	EMGD_TRACE_ENTER;
	EMGD_DEBUG("Parameters: swap_chain=0x%p", swap_chain);
	EMGD_DEBUG("  buffer=0x%p, *buffer->offset=0x%08lx",
		buffer, buffer->offset);

	if (EMGD_FALSE == swap_chain->valid) {
		EMGD_DEBUG("Not flipping--swap chain invalidated by a mode change.");
		EMGD_TRACE_EXIT;
		return;
	}

	surf.offset = buffer->offset;
	surf.pitch = buffer->pitch;
	surf.width = buffer->width;
	surf.height = buffer->height;
	surf.pixel_format = buffer->pixel_format;
	surf.flags = IGD_SURFACE_RENDER | IGD_SURFACE_DISPLAY;

	/* Flip the primary surface.  Select a different EMGD display depending on
	 * the DC & devinfo:
	 */
	if (IGD_DC_EXTENDED(priv->dc) &&
		(swap_chain->devinfo->which_devinfo == 1))  {
		ret = context->dispatch.set_surface(priv->secondary,
			IGD_PRIORITY_NORMAL, IGD_BUFFER_DISPLAY, &surf, NULL, 0);
		if (ret != 0) {
			printk(KERN_ERR "%s: set_surface() returned %d", __FUNCTION__, ret);
		}
	} else {
		ret = context->dispatch.set_surface(priv->primary,
			IGD_PRIORITY_NORMAL, IGD_BUFFER_DISPLAY, &surf, NULL, 0);
		if (ret != 0) {
			printk(KERN_ERR "%s: set_surface() returned %d", __FUNCTION__, ret);
		}
	}

	/* Flip the secondary surface: */
	if (IGD_DC_CLONE(priv->dc)) {
		/* If in clone mode, flip the other pipe too: */
		ret = context->dispatch.set_surface(priv->secondary,
			IGD_PRIORITY_NORMAL, IGD_BUFFER_DISPLAY, &surf, NULL, 0);
		if (ret != 0) {
			printk(KERN_ERR "%s: set_surface() returned %d", __FUNCTION__, ret);
		}
	}


	EMGD_TRACE_EXIT;
} /* emgddc_flip() */
Exemplo n.º 3
0
/*!
 * Non-Optional Init Module Components
 *
 * @param found_device
 * @param pdev
 *
 * @return 0 on success
 * @return -IGD_ERROR_NODEV on failure
 */
static int detect_device(iegd_pci_t **found_device,
	os_pci_dev_t *pdev)
{
	int i;

	/* Scan the PCI bus for supported device */
	for(i = 0; i < MAX_PCI_DEVICE_SUPPORTED; i++) {

		*pdev = OS_PCI_FIND_DEVICE(intel_pci_device_table[i].vendor_id,
			intel_pci_device_table[i].device_id,
			intel_pci_device_table[i].bus,
			intel_pci_device_table[i].dev,
			intel_pci_device_table[i].func,
			(os_pci_dev_t)0);

		if(*pdev) {
			*found_device = &intel_pci_device_table[i];
			break;
		}
	}
	if(!*pdev) {
		EMGD_ERROR("No supported VGA devices found.");
		return -IGD_ERROR_NODEV;
	}

	EMGD_DEBUG("VGA device found: 0x%x", (*found_device)->device_id);

	return 0;
}
Exemplo n.º 4
0
int alter_ovl2_tnc(igd_display_context_t *display,
	igd_surface_t       *src_surf,
	igd_rect_t          *src_rect,
	igd_rect_t          *dest_rect,
	igd_ovl_info_t      *ovl_info,
	unsigned int         flags)
{
	ovl2_reg_tnc_t spritec_regs_tnc;
	int ret=0;

	EMGD_TRACE_ENTER;

	/* Initialize structure so compilers don't complain */
	OS_MEMSET(&spritec_regs_tnc, 0, sizeof(ovl2_reg_tnc_t));

	if (micro_prepare_ovl2_tnc(display, src_surf, src_rect, dest_rect,
		ovl_info, &spritec_regs_tnc, flags)) {
		return -IGD_ERROR_HWERROR;
	}

	/* Send the instructions to the command queue */
	ret = ovl2_send_instr_tnc(display, &spritec_regs_tnc, flags);
	EMGD_DEBUG("Sprite C= %s",flags & IGD_OVL_ALTER_ON?"ON":"OFF");
	EMGD_TRACE_EXIT;
	return ret;
}
Exemplo n.º 5
0
void dsp_control_plane_format_tnc(igd_context_t *context,
                                  int enable, int plane, igd_plane_t *plane_override)
{
    igd_plane_t * pl = NULL;
    unsigned char *mmio = EMGD_MMIO(context->device_context.virt_mmadr);
    unsigned long tmp;

    if (plane_override == NULL) {
        pl = (plane == 0) ? &planea_tnc : &planeb_tnc;
    } else {
        pl = plane_override;
    }
    tmp = EMGD_READ32(mmio +  pl->plane_reg);
    /*
     * Pixel format bits (29:26) are in plane control register 0x70180 for
     * Plane A and 0x71180 for Plane B
     * 0110 = XRGB pixel format
     * 0111 = ARGB pixel format
     * Note that the plane control register is double buffered and will be
     * updated on the next VBLANK operation so there is no need to sync with
     * an explicit VSYNC.
     */
    if(enable) {
        if((tmp & DSPxCNTR_SRC_FMT_MASK) == DSPxCNTR_RGB_8888) {
            tmp = tmp & (~(DSPxCNTR_SRC_FMT_MASK));
            EMGD_WRITE32(tmp | DSPxCNTR_ARGB_8888, mmio + pl->plane_reg);
            EMGD_READ32(mmio + pl->plane_reg);
            tmp = EMGD_READ32(mmio + pl->plane_reg + 0x1c);
            EMGD_WRITE32(tmp, mmio + pl->plane_reg + 0x1c);
            EMGD_DEBUG("Changed pixel format from XRGB to ARGB\n");
        }
    } else {
        if((tmp & DSPxCNTR_SRC_FMT_MASK) == DSPxCNTR_ARGB_8888) {
            tmp = tmp & (~(DSPxCNTR_SRC_FMT_MASK));
            EMGD_WRITE32(tmp | DSPxCNTR_RGB_8888, mmio +  pl->plane_reg);
            EMGD_READ32(mmio + pl->plane_reg);
            tmp = EMGD_READ32(mmio + pl->plane_reg + 0x1c);
            EMGD_WRITE32(tmp, mmio + pl->plane_reg + 0x1c);
            OS_SLEEP(100);
            EMGD_DEBUG("Changed pixel format from ARGB to XRGB\n");
        }
    }
    EMGD_DEBUG("Plane register 0x%lX has value of 0x%X\n", pl->plane_reg,
               EMGD_READ32(mmio + pl->plane_reg));
}
Exemplo n.º 6
0
/*!
 *
 * @param mmio
 *
 * @return void
 */
static void disable_vga_plb (unsigned char *mmio)
{
	unsigned long temp;
	unsigned char sr01;

	EMGD_TRACE_ENTER;

	/* Disable VGA plane if it is enabled. */
	temp = EMGD_READ32(EMGD_MMIO(mmio) + VGACNTRL);
	if ((temp & BIT31) == 0) {
		/* Read SR01 */
		READ_VGA(mmio, SR_PORT, 0x01, sr01);

		/* Turn on SR01 bit 5 */
		WRITE_VGA(mmio, SR_PORT, 0x01, sr01|BIT(5));
		/* Wait for 30us */
		OS_SLEEP(30);

		temp |= BIT31;     /* set bit 31 to disable */
		temp &= ~BIT30;    /* clear bit 30 to get VGA display in normal size */
		EMGD_WRITE32(temp, EMGD_MMIO(mmio) + VGACNTRL);
	}
	/*
	 * When turing off the VGA plane the palette sometimes gets stuck.
	 * if we do a couple reads to the palette it will unstuck.
	 */
	if((1L<<31) & EMGD_READ32( EMGD_MMIO(mmio) + PIPEA_CONF )) {
		EMGD_DEBUG("VGA Palette workaround");
		EMGD_READ32(EMGD_MMIO(mmio) + DPALETTE_A);
		EMGD_READ32(EMGD_MMIO(mmio) + DPALETTE_A);
	}
	if((1L<<31) & EMGD_READ32( EMGD_MMIO(mmio) + PIPEB_CONF )) {
		EMGD_DEBUG("VGA Palette workaround");
		EMGD_READ32(EMGD_MMIO(mmio) + DPALETTE_B);
		EMGD_READ32(EMGD_MMIO(mmio) + DPALETTE_B);
	}

	EMGD_TRACE_EXIT;
}
Exemplo n.º 7
0
/*
 * Create a virtual address mapping for physical pages of memory.
 *
 * This needs to handle requrests for both the EMGD display driver
 * and the IMG 2D/3D drivers.
 *
 * If the page offset falls below the 256MB limit for display,
 * then map display memory. If above, route to the IMG handler.
 */
int emgd_mmap(struct file *filp, struct vm_area_struct *vma)
{
	struct drm_file *file_priv;
	drm_emgd_priv_t *emgd_priv;
	gmm_chunk_t *chunk;
	unsigned long offset;

	/*
	 * re-direct offsets beyond the 256MB display range to PVRMMap
	 */
	if (vma->vm_pgoff > DRM_PSB_FILE_PAGE_OFFSET) {
		EMGD_DEBUG("emgd_mmap: Calling PVRMMap().");
		return PVRMMap(filp, vma);
	}

	file_priv = (struct drm_file *) filp->private_data;
	emgd_priv = (drm_emgd_priv_t *)file_priv->minor->dev->dev_private;
	offset = vma->vm_pgoff << PAGE_SHIFT;

	/*
	 * Look up the buffer in the gmm chunk list based on offset
	 * and size.
	 */
	/* chunk = emgd_priv->context->dispatch->gmm_get_chunk(vma->vm_pgoff);*/
	chunk = gmm_get_chunk(emgd_priv->context, offset);
	if (chunk == NULL) {
		printk(KERN_ERR "emgd_mmap: Failed to find memory at 0x%lx.", offset);
	}

	/*
	 * Fill in the vma
	 */
	vma->vm_ops = &emgd_vm_ops;
	vma->vm_private_data = chunk;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0)
	vma->vm_flags |= VM_IO | VM_MIXEDMAP | VM_DONTEXPAND | VM_DONTDUMP;
#else
	vma->vm_flags |= VM_RESERVED | VM_IO | VM_MIXEDMAP | VM_DONTEXPAND;
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,19,0)
	pgprot_val(vma->vm_page_prot) =
		pgprot_val(vma->vm_page_prot) | _PAGE_CACHE_MODE_UC_MINUS;
#else
	pgprot_val(vma->vm_page_prot) =
		pgprot_val(vma->vm_page_prot) | _PAGE_CACHE_UC_MINUS;
#endif

	return 0;
}
Exemplo n.º 8
0
/*!
 * Shutdown all modules in the required order. Optional modules must
 * only be called if they exist.
 *
 * @param context
 *
 * @return void
 */
static void shutdown_modules(igd_context_t *context)
{
	EMGD_TRACE_ENTER;

	if(context->mod_dispatch.shutdown_2d) {
		context->mod_dispatch.shutdown_2d(context);
	}
	if(context->mod_dispatch.blend_shutdown) {
		context->mod_dispatch.blend_shutdown(context);
	}
	if(context->mod_dispatch.interrupt_shutdown) {
		context->mod_dispatch.interrupt_shutdown(context);
	}
	if(context->mod_dispatch.appcontext_shutdown) {
		context->mod_dispatch.appcontext_shutdown(context);
	}
	if(context->mod_dispatch.reset_shutdown) {
		context->mod_dispatch.reset_shutdown(context);
	}
	if(context->mod_dispatch.mode_shutdown) {
		context->mod_dispatch.mode_shutdown(context);
	}
	if(context->mod_dispatch.pwr_shutdown) {
		context->mod_dispatch.pwr_shutdown(context);
	}
	if(context->mod_dispatch.overlay_shutdown) {
		context->mod_dispatch.overlay_shutdown(context);
	}
	if(context->mod_dispatch.cmd_shutdown) {
		context->mod_dispatch.cmd_shutdown(context);
	}
	/*
	 * GMM is not optional shutdown must exist.
	 */
	gmm_shutdown(context);

	/*
	 * Reg module must be last to restore the state of the device to the
	 * way it was before the driver started.
	 */
	EMGD_DEBUG("post reg_shutdown: %p", context->mod_dispatch.reg_shutdown);
	if(context->mod_dispatch.reg_shutdown) {
		context->mod_dispatch.reg_shutdown(context);
	}

	EMGD_TRACE_EXIT;
}
Exemplo n.º 9
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;
}
Exemplo n.º 10
0
/*!
 * 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;
}
Exemplo n.º 11
0
int pd_print(const char *funcname, const int error,
	const int error_exit, const char *format, ...)
{
#ifdef DEBUG_BUILD_TYPE
	va_list ap;
	unsigned int *blah;
	char *priority = error ? KERN_ERR : EMGD_DEBUG_MSG_PRIORITY;
	char *fmt = NULL;

	/* Can't directly use the EMGD_DEBUG_S macro (because "format" is a string
	 * variable), so duplicate some of it here:
	 */
	if (!(emgd_debug && emgd_debug-> MODULE_NAME)) {
		return 0;
	}

	va_start(ap, format);
	blah = (unsigned int *)ap;

	if (error_exit) {
		EMGD_DEBUG("EXIT With Error...");
	}

	/* Create a new format string, with all of the correct parts: */
	fmt = OS_ALLOC(strlen(priority) + strlen(funcname) +
		strlen(format) + 2);
	if (fmt == NULL) {
		printk(format, blah[0], blah[1], blah[2], blah[3], blah[4], blah[5],
			blah[6], blah[7], blah[8], blah[9]);
	} else {
		sprintf(fmt, "%s%s %s", priority, funcname, format);
		printk(fmt, blah[0], blah[1], blah[2], blah[3], blah[4], blah[5],
			blah[6], blah[7], blah[8], blah[9]);
		OS_FREE(fmt);
	}
	printk("\n");
	va_end(ap);

	return 0;
#endif
}
Exemplo n.º 12
0
/*!
 * This function is exported directly. It will shutdown an instance
 * of the HAL that was initialized with igd_driver_init.
 *
 * Since the symbol is exported as part of the documented API it must
 * always exist, however it becomes an empty function when the init
 * module is not fully included.
 *
 * @param driver_handle
 *
 * @return void
 */
void igd_driver_shutdown(igd_driver_h driver_handle)
{
	igd_context_t *context = (igd_context_t *)driver_handle;

	EMGD_TRACE_ENTER;

	EMGD_ASSERT(context, "Null Driver Handle", );


	/* Shutdown the device context */
	init_dispatch->shutdown(context);

	/* release the driver's context */
	if(context) {
		EMGD_DEBUG("Freeing context");
		OS_FREE(context);
	}

	EMGD_TRACE_EXIT;
	return;
}
Exemplo n.º 13
0
/*!
 *
 * @param display
 * @param port_number
 * @param status
 *
 * @return 0 on success
 * @return -IGD_ERROR_INVAL on failure
 */
static int	program_port_plb(igd_display_context_t *display,
	unsigned short port_number,
	unsigned long status)
{
	unsigned long pipe_number;
	unsigned long port_control;
	unsigned long port_control_analog = 0;
	unsigned long mult_port_control;
	unsigned long pd_powerstate = 0;
	unsigned long upscale = 0;
	pd_timing_t *timing;
	pd_timing_t local_timing;
	unsigned long port_type;
	int ret;

	/* get the pipe	number */
	pipe_number = PIPE(display)->pipe_num;

	/* get the timings */
	timing = PIPE(display)->timing;

	/* keep the port type as local as we access it frequently */
	port_type = PORT(display, port_number)->port_type;

	/* Reading the preservation	bits */
	port_control = PORT(display, port_number)->preserve &
		READ_MMIO_REG(display, PORT(display, port_number)->port_reg);

	/* Reading the preservation bits for SDVO Gang Mode */
	mult_port_control = PORT(display, port_number)->mult_preserve &
		READ_MMIO_REG(display, PORT(display, port_number)->port_reg);

	/* If status is false, quickly disable the display */
	if(status == FALSE) {
		ret = PORT(display, port_number)->pd_driver->set_power(
				PORT(display, port_number)->pd_context, PD_POWER_MODE_D3);

		if (ret) {
			EMGD_ERROR_EXIT("PD set_power() returned: 0x%x", ret);
			return -IGD_ERROR_INVAL;
		}

		if(port_type == IGD_PORT_DIGITAL) {
			WRITE_MMIO_REG(display, PORT(display, port_number)->port_reg,
					port_control);

			if(PORT(display, port_number)->mult_port) {
				/* either gang mode or RGBA */
				WRITE_MMIO_REG(display,
						PORT(display, port_number)->mult_port->port_reg,
						mult_port_control);
			}
		} else if (port_type == IGD_PORT_ANALOG) {
			port_control |= (BIT11 | BIT10);	 /* put in D3 state */
			WRITE_MMIO_REG(display, PORT(display, port_number)->port_reg,
				port_control);

			return 0;
		}
		return 0;
	}

	EMGD_DEBUG("status isn't false, Check port enabled");

	if(! (PORT(display, port_number)->pt_info->flags & IGD_DISPLAY_ENABLE)) {
		return 0;
	}

	/*
	 * Is this is the magic mode then turn on VGA syncs
	 */
	EMGD_DEBUG("Check vga_sync");
	if(PORT(display, port_number)->vga_sync == 1) {
		/*
		 * Is this is the magic mode then turn on VGA syncs
		 */
		EMGD_DEBUG("VGA sync true, is width x height 720 x 400?");
		if((timing->width == 720) && (timing->height == 400)) {
			EMGD_DEBUG("Modify port control and multi_port_control");
			port_control |= (1L<<15);
			mult_port_control |= (1L<<15);
		}
	}

	EMGD_DEBUG("Check analog port");
	if(port_type == IGD_PORT_ANALOG) {
		port_control |= (0x80000000 | (pipe_number<<30));
		if(timing->mode_info_flags & IGD_VSYNC_HIGH) {
			port_control |= (1L<<4);
		}
		if(timing->mode_info_flags & IGD_HSYNC_HIGH) {
			port_control |= (1L<<3);
		}
		/* To differentiate	between	analog and other ports */
		port_control_analog = port_control;
	}

	EMGD_DEBUG("Get power state");
	EMGD_DEBUG("power state = %ld ", GET_DISPLAY_POWER_STATE(display, port_number));
	switch(GET_DISPLAY_POWER_STATE(display, port_number)) {
	case IGD_POWERSTATE_D0:
		EMGD_DEBUG("Power State is D0");
		pi_pd_find_attr_and_value(PORT(display, port_number),
			PD_ATTR_ID_PANEL_FIT,
			0, /*no PD_FLAG for UPSCALING */
			NULL, /* dont need the attr ptr*/
			&upscale);
		if(port_type == IGD_PORT_DIGITAL) {
			/* Reach the end timing if upscaling is enabled */
			if (timing->extn_ptr && upscale) {
				timing = (pd_timing_t *)timing->extn_ptr;
			}

			local_timing = *timing;
			if (upscale) {
				/* For timings smaller than width 360 and height 200,
				 * double the size. This is because the active area of the mode
				 * is double the size of the resolution for these modes
				 *  - Very tricky huh */
				if (local_timing.width <= 360) {
					local_timing.width <<= 1;
				}
				if (local_timing.height <= 200) {
					local_timing.height <<= 1;
				}
			}

			ret = PORT(display, port_number)->pd_driver->set_mode(
				PORT(display, port_number)->pd_context, &local_timing, 0);
			if (ret) {
				EMGD_ERROR_EXIT("PD set_mode returned: 0x%x", ret);
				return -IGD_ERROR_INVAL;
			}

			/* in Plba B-Speecs, there are no bits, *
			 * for the polarity of the H-sync/V-sync */

			/* in Plba B-Speecs, there are no bits,	 *
			 * for data ordering/format for DVO data */
			/* Gang-Mode and RGBA models are "exclusive-or" */
			if((PORT(display, port_number)->pd_driver->flags) &
					PD_FLAG_GANG_MODE) {
				mult_port_control |= (1L<<16);
			} else if(PORT(display, port_number)->pd_type == PD_DISPLAY_RGBA) {
				mult_port_control |= (1L<<2);
			}

			timing = PIPE(display)->timing;

			if(timing->dclk > 100000) {
				/* 100MPs < pixel rate < 200MPs */
				/* SDVO clock rate multiplier = 1x */
				/*
				port_control &=	~BIT23;
				mult_port_control |= ~BIT23;
					redundant code since BIT23 is
					already 0 at this point
				*/
			} else if(timing->dclk > 50000) {
				/* 50MPs < pixel rate < 100MPs */
				/* SDVO clock rate multiplier = 2x */
				port_control |= (1L<<23);
				mult_port_control |= (1L<<23);
			} else {
				/* 25MPs < pixel rate < 50MPs */
				/* SDVO clock rate multiplier = 4x */
				port_control |= (3L<<23);
				mult_port_control |= (3L<<23);
			}

			/*
			 * BIT7 = enable the border
			 *   Do we need to disable the SDVO border for native
			 *   VGA timings(i.e.,	use	DE)?
			 * BIT22->BIT19 = setup the clock phase-9
			 * BIT29 = enable the stall
			 *   Only set stall on DVO-B for gang mode
			 * BIT30 = pipe number
			 * BIT31 = port enable
			 */
			port_control |= ( ( pipe_number<<30 ) | (BIT31) | ((0x9l) << 19) |
					(BIT29) | (BIT7) );
			mult_port_control |= ( (BIT31) | ((0x9l) << 19) | (BIT7) );

			WRITE_MMIO_REG(display, PORT(display, port_number)->port_reg,
					port_control);

			if(PORT(display, port_number)->mult_port) { /* gang mode or rgba*/
				WRITE_MMIO_REG(display,
						PORT(display, port_number)->mult_port->port_reg,
						mult_port_control);
			}
			return 0;
		} else if(port_type == IGD_PORT_LVDS) {
			/*
			 * There is	a special case for LVDS	scaling. If	the	timing is
			 * the native one and the extension	points to another non-vga
			 * mode	then send the extension	pointer.
			 */
			/* Reach the end timing to get user requested mode */
			if(timing->extn_ptr) {
				timing = (pd_timing_t *)timing->extn_ptr;
			}
		}
		/* set mode	will take care of port control */
		ret = PORT(display, port_number)->pd_driver->set_mode(
			PORT(display, port_number)->pd_context, (pd_timing_t *)timing,
			1<<PIPE(display)->pipe_num);
		if (ret) {
			EMGD_ERROR_EXIT("PD set_mode returned: 0x%x",ret);
			return -IGD_INVAL;
		}
		break;
	case IGD_POWERSTATE_D1:
		port_control_analog &= ~0x80000000;
		port_control_analog |= 0x00000800 &
			~(PORT(display, port_number)->preserve);
		pd_powerstate =PD_POWER_MODE_D1;
		break;
	case IGD_POWERSTATE_D2:
		port_control_analog &= ~0x80000000;
		port_control_analog |= 0x00000400 &
			~(PORT(display, port_number)->preserve);
		pd_powerstate = PD_POWER_MODE_D2;
		break;
	case IGD_POWERSTATE_D3:
		port_control_analog &= ~0x80000000;
		port_control_analog |= 0x00003c00 &
			~(PORT(display, port_number)->preserve);
		pd_powerstate = PD_POWER_MODE_D3;
		break;
	default:
		EMGD_ERROR_EXIT("Invalid power state: 0x%lx",
			GET_DISPLAY_POWER_STATE(display, port_number));
		return -IGD_ERROR_INVAL;
	}

	ret = PORT(display, port_number)->pd_driver->set_power(
			PORT(display, port_number)->pd_context, pd_powerstate);
	if (ret) {
		EMGD_ERROR_EXIT("PD set_power returned: 0x%x", ret);
		return -IGD_ERROR_INVAL;
	}

	if(port_type == IGD_PORT_DIGITAL) {
		EMGD_DEBUG("Port_control = 0x%lx", port_control);

		WRITE_MMIO_REG(display, PORT(display, port_number)->port_reg,
				port_control);
		if(PORT(display, port_number)->mult_port) { /* gang mode or rgba*/
			WRITE_MMIO_REG(display,
					PORT(display, port_number)->mult_port->port_reg,
					mult_port_control);
		}
	}

	EMGD_TRACE_EXIT;
	return 0;
}
Exemplo n.º 14
0
/*!
 * This function programs the Timing registers and clock registers and
 * other control registers for PIPE.
 *
 * @param display
 * @param status
 *
 * @return void
 */
static void program_pipe_plb(igd_display_context_t *display,
	unsigned long status)
{
	unsigned long   timing_reg;
	unsigned long   pipe_conf;
	unsigned long   hactive, vactive;
	igd_timing_info_t  *pTimings;
	unsigned long temp;
#ifndef CONFIG_MICRO
	igd_display_port_t *port;
	int i;
#endif

	EMGD_TRACE_ENTER;
	EMGD_DEBUG("Program Pipe: %s", status?"ENABLE":"DISABLE");
	EMGD_DEBUG("Device power state: D%ld", GET_DEVICE_POWER_STATE(display));

	pipe_conf = device_data->pipe_preserve &
		EMGD_READ32(MMIO(display) + PIPE(display)->pipe_reg);

	/* Reset the plane of this pipe back to NULL, it will be set on the
	 * call to program_plane, which is ok, since program_pipe occurs
	 * before program_plane */
	PIPE(display)->plane = NULL;

	if((status == FALSE) ||
		(GET_DEVICE_POWER_STATE(display) == IGD_POWERSTATE_D3)) {
		/* Disable pipe */
		EMGD_WRITE32(pipe_conf & (~0x80000000),
			MMIO(display) + PIPE(display)->pipe_reg);

		return;
	}

	pTimings = PIPE(display)->timing;

	/*
	 * If the mode is VGA and the PD says it handles all VGA modes without
	 * reprogramming then just set the mode and leave centering off.
	 */
	if(pTimings->mode_info_flags & IGD_MODE_VESA) {
		if (pTimings->mode_number <= VGA_MODE_NUM_MAX) {
			/* Pipe timings and clocks are not used but it must be on anyway */
			EMGD_WRITE32(pipe_conf | 0x80000000,
				MMIO(display) + PIPE(display)->pipe_reg);
			program_pipe_vga_plb(display);
			return;
		} else {
#ifdef CONFIG_MICRO
			set_256_palette(MMIO(display));
#endif
		}
	}

	/* Program dot clock divisors. */
	program_clock_plb(display, PIPE(display)->clock_reg, pTimings->dclk);

	/* Program timing registers for the pipe */
	timing_reg = PIPE(display)->timing_reg;
	if (pTimings->mode_info_flags & IGD_PIXEL_DOUBLE) {
		hactive = (unsigned long)pTimings->width*2 - 1;
	} else {
		hactive = (unsigned long)pTimings->width - 1;
	}

	if (pTimings->mode_info_flags & IGD_LINE_DOUBLE) {
		if (pTimings->mode_info_flags & IGD_SCAN_INTERLACE) {
			vactive = (unsigned long)pTimings->height - 1;
		} else {
			vactive = (unsigned long)pTimings->height*2 - 1;
		}
	} else {
		if (pTimings->mode_info_flags & IGD_SCAN_INTERLACE) {
			vactive = (unsigned long)pTimings->height/2 - 1;
		} else {
			vactive = (unsigned long)pTimings->height - 1;
		}
	}

	/*
	 * DPLL should be on at this point which is required for touching
	 * the palette.
	 */
#ifndef CONFIG_MICRO
	/* reset the palette */
	for (i = 0; i < 256; i++) {
		EMGD_WRITE32(((i<<16) | (i<<8) | i),
			MMIO(display) + PIPE(display)->palette_reg + i*4);
	}

	/* apply color correction */
	port = PORT_OWNER(display);
	for( i = 0; PD_ATTR_LIST_END != port->attributes[i].id; i++ ) {

		if ((PD_ATTR_ID_FB_GAMMA      == (port->attributes[i].id)) ||
			(PD_ATTR_ID_FB_BRIGHTNESS == (port->attributes[i].id)) ||
			(PD_ATTR_ID_FB_BRIGHTNESS == (port->attributes[i].id)))  {

			mode_context->dispatch->full->set_color_correct(display);
		}
	}
#endif

	/*
	 * NOTE: For size reasons the timng table contains unsigned short
	 * values. Don't shift them past 16. Use a temp instead.
	 * All register offsets and bit shift are verified for Napa
	 */
	temp = ((unsigned long)pTimings->htotal << 16) | hactive;
	EMGD_WRITE32(temp, MMIO(display) + timing_reg);

	temp = ((unsigned long)pTimings->hblank_end << 16) |
		(unsigned long)pTimings->hblank_start;
	EMGD_WRITE32(temp, MMIO(display) + timing_reg + 0x04);

	temp = ((unsigned long)pTimings->hsync_end << 16) |
		(unsigned long)pTimings->hsync_start;
	EMGD_WRITE32(temp, MMIO(display) + timing_reg + 0x08);

	temp = ((unsigned long)pTimings->vtotal << 16) | vactive;
	EMGD_WRITE32(temp, MMIO(display) + timing_reg + 0x0C);

	temp = ((unsigned long)pTimings->vblank_end << 16) |
		(unsigned long)pTimings->vblank_start;
	EMGD_WRITE32(temp, MMIO(display) + timing_reg + 0x10);

	temp = ((unsigned long)pTimings->vsync_end << 16) |
		(unsigned long)pTimings->vsync_start;
	EMGD_WRITE32(temp, MMIO(display) + timing_reg + 0x14);

	/*
	 * If there is a linked mode it is either the VGA or a scaled
	 * mode. If it is scaled then we need to use it as the source size.
	 */
	if(pTimings->extn_ptr) {
		igd_timing_info_t *scaled_timings =
			(igd_timing_info_t *)pTimings->extn_ptr;
		if((scaled_timings->mode_info_flags & IGD_MODE_VESA) &&
			(scaled_timings->mode_number <= VGA_MODE_NUM_MAX)) {
			temp = (hactive << 16) | vactive;
		} else {
			temp = (unsigned long)scaled_timings->width  - 1;
			temp = (temp << 16) |
				(unsigned long)(scaled_timings->height - 1);
		}
	} else {
		temp = (hactive << 16) | vactive;
	}
	EMGD_WRITE32(temp, MMIO(display) + timing_reg + 0x1C);

	/* Set other registers */

	/*
	 * FIXME: max_dclk needs to be determined from core clock
	 * at init time. 915 etc has several skus with different
	 * clocks for the same device ID.
	 *
	 */

	/* These values are derived from the Poulsbo B-Spec as
	 * the suggested values */
	WRITE_MMIO_REG (display, FW_BLC1, device_data->fw_blc1);
	WRITE_MMIO_REG (display, FW_BLC2, device_data->fw_blc2);
	WRITE_MMIO_REG (display, FW_BLC3, device_data->fw_blc3);
	WRITE_MMIO_REG (display, FW_BLC_SELF, device_data->fw_self);
	WRITE_MMIO_REG (display, DSP_ARB, device_data->dsp_arb);

	/* The SGX 2D engine can saturate the memory bus and starve
	 * the display engine causing visible screen tearing.
	 * This reduces the priority of the SGX vs. display engine
	 */
	temp = READ_MMIO_REG (display, G_DEBUG);
	WRITE_MMIO_REG (display, G_DEBUG, (temp | (1 << 11)));

	pipe_conf |= PIPE_ENABLE;
	WRITE_MMIO_REG(display, PIPE(display)->pipe_reg, pipe_conf);

	/*
	 * Set the VGA address range to 0xa0000 so that a normal (not VGA)
	 * mode can be accessed through 0xa0000 in a 16bit world.
	 */
	WRITE_AR(MMIO(display), 0x10, 0xb);
	WRITE_VGA(MMIO(display), GR_PORT, 0x06, 0x5);
	WRITE_VGA(MMIO(display), GR_PORT, 0x10, 0x1);

	if(pTimings->extn_ptr) {
		/* This means either internal scaling (LVDS) or centered VGA */
		pTimings = pTimings->extn_ptr;
		if(pTimings->extn_ptr) {
			/* This is both the scaled and centered VGA */
			pTimings = pTimings->extn_ptr;
		}
		if(pTimings->mode_info_flags & IGD_MODE_VESA) {
			if (pTimings->mode_number <= VGA_MODE_NUM_MAX) {
				program_pipe_vga_plb(display);
			} else {
#ifdef CONFIG_MICRO
				set_256_palette(MMIO(display));
#endif
			}
		}
	}

	EMGD_TRACE_EXIT;
	return;
}
Exemplo n.º 15
0
/*!
 * Program Display Plane Values.
 *
 * @param display Pointer to hardware device instance data
 * @param status
 *
 * @return void
 */
static void program_plane_plb(igd_display_context_t *display,
	unsigned long status)
{
	unsigned long stereo;
	unsigned long stride;
	unsigned long size;
	unsigned long plane_control;
	igd_timing_info_t *timing;
	igd_framebuffer_info_t *fb_info = PLANE(display)->fb_info;
	unsigned long plane_reg = PLANE(display)->plane_reg;
	unsigned long start_addr_reg = DSPAADDR;

	EMGD_TRACE_ENTER;

	EMGD_DEBUG("Program Plane: %s", status?"ENABLE":"DISABLE");
	EMGD_DEBUG("Device power state: D%ld", GET_DEVICE_POWER_STATE(display));

	igd_wait_vblank_plb((igd_display_h)display);

	plane_control = EMGD_READ32(MMIO(display) + plane_reg);
	if(PLANE(display)->plane_reg == DSPACNTR) {
		plane_control &= device_data->plane_a_preserve;
	}
	else { /* if it's plane b or plane c */
		plane_control &= device_data->plane_b_c_preserve;
		start_addr_reg = 0x71184;
	}

	if((status == FALSE) ||
		(GET_DEVICE_POWER_STATE(display) != IGD_POWERSTATE_D0)) {

		/*
		 * Note: The vga programming code does not have an "off". So
		 * when programming the plane to off we make sure VGA is off
		 * as well.
		 */
		disable_vga_plb(MMIO(display));

		/*
		 * To turn off plane A or B, the program have to triger the plane A or B
		 * start register.  Or else, it will not work.
		 */
		EMGD_WRITE32(plane_control, MMIO(display) + plane_reg);
		EMGD_WRITE32(EMGD_READ32(MMIO(display) + start_addr_reg),
			MMIO(display) + start_addr_reg);

		igd_wait_vblank_plb((igd_display_h)display);
		return;
	}
	/*
	 * Note: The very first pass through this function will be with
	 * status false and timings == NULL. Don't use the timings before
	 * the check above.
	 */
	timing = PIPE(display)->timing;
	/* There is a special case code for legacy VGA modes */
	while (timing->extn_ptr) {
		timing = (igd_timing_info_t *)timing->extn_ptr;
	}
	if(MODE_IS_VGA(timing)) {
		program_plane_vga(display, timing);
		return;
	}

	disable_vga_plb(MMIO(display));

	size = (((unsigned long)timing->height - 1)<<16) |
		(unsigned long)(timing->width - 1);

	/* enable plane, select pipe, enable gamma correction logic */
	plane_control |= 0x80000000 | (PIPE(display)->pipe_num<<24);
	PIPE(display)->plane = PLANE(display);
#ifndef CONFIG_MICRO
	plane_control |= (1<<30);
#endif

	/* Here the settings:
	 *   If line + pixel dbling, set 21,20 to 01b, and set Horz Multiply
	 *   If line dbling only,    set 21,20 to 11b
	 *   If pixel dbling only,   set 21,20 to 00b, but set Horz Multiply
	 *   If no doubling,         set 21,20 to 00b (no Horz Multiply)
	 * For pixel doubling
	 *           --> both progressive/interlaced modes
	 * For Line doubling
	 *           --> progressive modes only
	 */

	if (!(timing->mode_info_flags & IGD_SCAN_INTERLACE)) {
		/* Line doubling in progressive mode requires special bits */
		if (timing->mode_info_flags & IGD_LINE_DOUBLE) {
			/* BIT 20 for line & pixel doubling*/
			plane_control |= BIT20;
			/* check later, if no pixel doubling, set bit 21 too*/
		}
	}
	if (timing->mode_info_flags & IGD_PIXEL_DOUBLE) {
		/* Horz pixel multiply must be set for double */
		plane_control |= BIT11;
		/* TODO -> Plba can more than double,
		It can 3X, 4X etc. These arent exposed now */
	}
	else if(plane_control & BIT20){
		/* For line ONLY doubling, set bit 21 also '1' */
		plane_control |= BIT21;
	}

	mode_get_stride_stereo_plb(display, &stride, &stereo, 0);

	/* set color depth */
	switch (IGD_PF_DEPTH(fb_info->pixel_format)) {
	case PF_DEPTH_8:
		plane_control |= BIT27 | BIT30;
		break;
	case PF_DEPTH_16:
		plane_control |= BIT28 | BIT26;
		break;
	default:
	case PF_DEPTH_32:
		plane_control |= BIT28 | BIT27;
		break;
	}

	if(fb_info->flags & IGD_ENABLE_DISPLAY_GAMMA) {
		plane_control |= (BIT30);
	}

	EMGD_DEBUG(" Plane Control = 0x%lx", plane_control);
	EMGD_DEBUG(" Plane Base = 0x%lx", fb_info->visible_offset);
	EMGD_DEBUG(" Plane Pitch = 0x%lx", stride);
	EMGD_DEBUG(" Plane Size = 0x%lx", size);

	EMGD_WRITE32(stride, MMIO(display) + plane_reg + DSP_STRIDE_OFFSET);
	/*
	 * In reality this only exists for plane B. It doesn't seem to hurt
	 * plane A so just do it anyway and save us another case.
	 */
	EMGD_WRITE32(size, MMIO(display) + plane_reg + DSP_SIZE_OFFSET);

	/*EMGD_WRITE32(stereo, MMIO(display) + plane_reg + DSP_STEREO_OFFSET);
		- This register is Reserved ON plba */
	EMGD_WRITE32(fb_info->visible_offset,
		MMIO(display) + plane_reg + DSP_START_OFFSET);

	/* It seems we need push or trigger plane A/B to start to work
	 * on Poulsbo, especially for sDVO port. Let's write plane control
	 * register and start address register at last.
	 */
	EMGD_WRITE32(plane_control, MMIO(display) + plane_reg);
	EMGD_WRITE32(EMGD_READ32(MMIO(display) + start_addr_reg),
		MMIO(display) + start_addr_reg);

	igd_wait_vblank_plb((igd_display_h)display);

	EMGD_TRACE_EXIT;
	return;
}
Exemplo n.º 16
0
/*!
 *
 * @param display Pointer to hardware device instance data
 *
 * @return void
 */
static void program_pipe_vga_plb(
	igd_display_context_t *display)
{
	igd_timing_info_t *timing;
	unsigned long vga_control;
	unsigned long upscale = 0;
	int centering = 1;

	EMGD_TRACE_ENTER;

#ifdef CONFIG_MICRO
	/*
	 * We cannot set a VGA mode unless the display planes are turned off.
     * This becomes evident during a Windows BSOD.  Since neither Windows
     * nor IEGD got a chance to turn off these registers, and the VGA mode was
     * set by the VBIOS, the screen gets corrupted.  In order to fix this
     * problem, we will turn the cursor and display planes here.
     *
     * Note: Removing previous partial-fix in favor of this complete one.
	 */
    /* Cursor A */
	WRITE_MMIO_REG(display, 0x70080, 0);
	WRITE_MMIO_REG(display, 0x70084, 0);
    /* Cursor B */
	WRITE_MMIO_REG(display, 0x700C0, 0);
	WRITE_MMIO_REG(display, 0x700C4, 0);
    /* Display A */
	WRITE_MMIO_REG(display, 0x70180, 0);
	WRITE_MMIO_REG(display, 0x70184, 0);
    /* Display B */
	WRITE_MMIO_REG(display, 0x71180, 0);
	WRITE_MMIO_REG(display, 0x71184, 0);
    /* Display C */
	WRITE_MMIO_REG(display, 0x72180, 0);
	WRITE_MMIO_REG(display, 0x72184, 0);
#endif

	/*
	 * VGA Plane can attach to only one pipe at a time. LVDS can
	 * only attach to pipe B. We need to use the display passed to
	 * determine the pipe number to use. (Plba is same as Alm).
	 */

	/*
	 * We can come here with following cases:
	 *   1. magic->vga    CRT, DVI type displays
	 *   2. native->vga   int-lvds, and up-scaling lvds displays
	 *   3. pipe->vga     TV and other unscaled-lvds displays
	 */
	vga_control = READ_MMIO_REG(display, 0x71400);
	vga_control &= 0x18e3ff00;
	vga_control |= 0x8e;

	timing = PIPE(display)->timing;
	if(!timing->extn_ptr) {
		EMGD_ERROR_EXIT("No Extension pointer in program_pipe_vga_plb");
		return;
	}

	/*
	 * FIXME: For CONFIG_NEW_MATCH this should be replaced with a simple
	 *  check of fp_native_dtd. Do not query the attribute.
	 */

	/* Find UPSCALING attr value*/
	pi_pd_find_attr_and_value(PORT_OWNER(display),
			PD_ATTR_ID_PANEL_FIT,
			0,/*no PD_FLAG for UPSCALING */
			NULL, /* dont need the attr ptr*/
			&upscale);
	/* this PI func will not modify value of upscale if attr does not exist */

	/* magic->vga or native->vga cases */
	if ((timing->width == 720 && timing->height == 400) || upscale) {
		centering = 0;
	}

	/* Enable border */
	if((timing->width >= 800) && !upscale) {
		EMGD_DEBUG("Enable VGA Border");
		vga_control |= (1L<<26);
	}

	if(timing->width == 640) {
		EMGD_DEBUG("Enable Nine Dot Disable");
		vga_control |= (1L<<18);
	}

	if(centering) {
		EMGD_DEBUG("Enable VGA Center Centering");
		vga_control |= 1L<<24;

		if(timing->height >= 960) {
			if(timing->width >= 1280) {
				EMGD_DEBUG("Enable VGA 2x (Nine Dot Disable)");
				vga_control |= (1L<<30) | (1L<<18);
			}
		}
	} else {
		if(PORT_OWNER(display)->port_type == IGD_PORT_LVDS) {
			EMGD_DEBUG("Enable VGA Upper-Left Centering & Nine Dot Disable");
			vga_control |= (1L<<25 | (1L<<18));
		} else if (upscale) {
			EMGD_DEBUG("Enable VGA Center Upper-left for upscale ports");
			vga_control |= 1L<<25;
		}
	}

	if(PIPE(display)->pipe_num) {
		vga_control |= 1L<<29;
	}

	program_pipe_vga(display, (igd_timing_info_t *)timing->extn_ptr);
	WRITE_MMIO_REG(display, 0x71400, vga_control);

	EMGD_TRACE_EXIT;
	return;
}
Exemplo n.º 17
0
int query_ovl2_tnc(igd_display_h display_h,
	unsigned int flags)
{
	igd_display_context_t *display = (igd_display_context_t *)display_h;
	inter_module_dispatch_t *md;
	platform_context_tnc_t * platform;
	os_alarm_t timeout;
	int ret;
	unsigned long pipe_reg, pipe_num;

	EMGD_TRACE_ENTER;

	switch (flags) {
	case IGD_OVL_QUERY_IS_HW_SUPPORTED:
		/* This is the second overlay, so HW overlay is not supported */
		break;

	case IGD_OVL_QUERY_IS_LAST_FLIP_DONE:
		/* If there no sync to wait on, then the last flip is done, and the
		 * Register Update has occured, simply return TRUE (Flip done).
		 */
		if (!ovl_context->sync2) {
			EMGD_DEBUG("Overlay already synced");
			EMGD_TRACE_EXIT;
			return TRUE;
		}

		/* According to the PBL B-spec, there doesnt seem to exist any bit
		 * for Sprite C Flip-Pending status. Testing 0x20AC in code during
		 * virt queue's REG write shows nothing changed for Bit8. Thus, we
		 * are using state of the VBLANK ISR bit as ovl2 flip status.
		 * Assumption is that if were running 2nd overlay, its either clone
		 * display or VEXT in WinCE. In either case, were not doing full screen
		 * FB flipping, so this check should be 'statefully' accurate
		 */
		md = &display->context->mod_dispatch;
		platform = (platform_context_tnc_t *)display->context->
						platform_context;

		pipe_num = PIPE(display)->pipe_num; 
		if(pipe_num){ 
			pipe_reg = PIPEB_STAT; 
		} else { 
			pipe_reg = PIPEA_STAT; 
		} 

		if(md && md->check_flip_pending){
			ret = OS_PTHREAD_MUTEX_LOCK(&platform->flip_mutex);
			if(md->check_flip_pending(MMIO(display), pipe_reg)){
				OS_PTHREAD_MUTEX_UNLOCK(&platform->flip_mutex);
				EMGD_DEBUG("Overlay2 Sync done but Flip not done");
				return FALSE;
			}
			OS_PTHREAD_MUTEX_UNLOCK(&platform->flip_mutex);
		}

		/* Now that we know the last flip is done and the register update is
		 * complete, set the sync to 0 and return TRUE (Flip done). */
		ovl_context->sync2 = FLIP_DONE;
		break;
	case IGD_OVL_QUERY_WAIT_LAST_FLIP_DONE:
		/* Wait for 200 milliseconds for the last flip to complete.  If not
		 * done in that time, there is likely a hardware problem so return
		 * FALSE. */
		timeout = OS_SET_ALARM(200);
		do {
			if (TRUE ==
				query_ovl2_tnc(display_h, IGD_OVL_QUERY_IS_LAST_FLIP_DONE)) {
				EMGD_TRACE_EXIT;
				return TRUE;
			}
		} while (!OS_TEST_ALARM(timeout));
		EMGD_ERROR_EXIT("Timeout waiting for last flip done");
		return FALSE;
		break;
	case IGD_OVL_QUERY_IS_GAMMA_SUPPORTED:
		return TRUE;
		break;
	case IGD_OVL_QUERY_IS_VIDEO_PARAM_SUPPORTED:
		return TRUE;
		break;
	}

	EMGD_TRACE_EXIT;
	return TRUE;
}
Exemplo n.º 18
0
/*!
 * 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);

#ifndef CONFIG_MICRO
	/* Check if platform needs force alter
	* 	to make sure we run tuning code. This
	* 	is for TNC-B0 workaround.*/
	if (mode_context->dispatch->dsp_is_force_alter_required){
		if (mode_context->dispatch-> dsp_is_force_alter_required(context->
						mod_dispatch.dsp_display_list[IGD_DC_PRIMARY(current_dc)],
						current_dc, dc)){
				flags |= IGD_FORCE_ALTER;
		}
	}
#endif

	/*
	 * 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;
}
Exemplo n.º 19
0
/* FIXME: All modules should get params from mod_dispatch */
static int init_modules(igd_param_t *params, igd_context_t *context)
{
	unsigned int ret;

	EMGD_TRACE_ENTER;

	/*
	 * Reg module must be first so that the state of the device can be
	 * saved before anything else is touched.
	 */
	ret = REG_INIT(context, (params->preserve_regs)?IGD_DRIVER_SAVE_RESTORE:0);
	if (ret) {
		EMGD_DEBUG("Error initializing register module");
	}

	/*
	 *  GMM is not optional. Its init function must exist.
	 */
	ret = gmm_init(context, params->page_request, params->max_fb_size);
	if(ret) {
		EMGD_ERROR_EXIT("GMM Module Init Failed");
		return ret;
	}

	ret = CMD_INIT(context);
	if(ret) {
		EMGD_ERROR_EXIT("Command Module Init Failed");
		return ret;
	}

	/*
	 *  Mode is not optional. Its init function must exist.
	 */
	ret = mode_init(context);
	if (ret) {
		EMGD_ERROR_EXIT("Mode Module Init Failed");
		return ret;
	}

	ret = APPCONTEXT_INIT(context);
	if (ret) {
		EMGD_ERROR_EXIT("Appcontext Module Init Failed");
		return ret;
	}

	ret = OVERLAY_INIT(context, params);
	if(ret) {
		EMGD_ERROR_EXIT("Overlay Module Init Failed");
		return ret;
	}

	ret = PWR_INIT(context);
	if(ret) {
		EMGD_DEBUG("Error initializing power module");
	}

	ret = RESET_INIT(context);
	if(ret) {
		EMGD_DEBUG("Error initializing reset module");
	}

	ret = OS_INIT_INTERRUPT(context->device_context.did,
		context->device_context.virt_mmadr);
	if(ret) {
		EMGD_ERROR_EXIT("Interrupt Module Init Failed");
		return ret;
	}

	ret = BLEND_INIT(context);
	if(ret) {
		EMGD_DEBUG("Error initializing blend module");
	}

	ret = INIT_2D(context);
	if(ret) {
		EMGD_DEBUG("Error initializing 2d module");
	}

	EMGD_TRACE_EXIT;
	return 0;
}
Exemplo n.º 20
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;
	mode_context->ref_freq =
		context->mod_dispatch.init_params->ref_freq;
	mode_context->tuning_wa =
		context->mod_dispatch.init_params->tuning_wa;

	/* 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;
}
Exemplo n.º 21
0
/*!
 * Common mode filter algorithm for all port drivers
 *
 * @param call_back
 * @param in_list
 * @param out_list
 * @param dvo_info
 * @param display_info
 *
 * @return PD_SUCCESS on success
 * @return PD_ERR_NULL_PTR or PD_ERR_NOMEM on failure
 */
int pd_filter_timings(
	void *callback_context,
	pd_timing_t *in_list,
	pd_timing_t **out_list,
	pd_dvo_info_t *dvo_info,
	pd_display_info_t *display_info)
{
	igd_display_port_t *port = (igd_display_port_t *)callback_context;
	pd_timing_t    *timing   = NULL, *native_dtd = NULL;
	int            j;
	int            count     = 0;
	unsigned short fp_refresh = 60;
	pd_timing_t    *olist = NULL;
	unsigned long  fixed_timing = 0;
	int i, ret;

	if (!port || !in_list || !out_list) {
		return PD_ERR_NULL_PTR;
	}

	/* Start with fixed_res = 0 */
	display_info->fixed_res = 0;

	/* DisplayID FP width are specified */
	if (port->firmware_type == PI_FIRMWARE_DISPLAYID) {
		display_info->width = port->displayid->display_params.horz_pixels;
		display_info->height = port->displayid->display_params.vert_pixels;
		fixed_timing = port->displayid->display_params.fixed_timing;
		display_info->fixed_res = port->displayid->display_params.fixed_res;
	}

	/* Overwrite DisplayID FP values with config fpinfo, later
	 * these will be overwritten by native DTD width, height */
	if (port->fp_info) {
		/* This is done for backward compatibility:
		 * Set width, height from display port fp_info
		 * This also required dropping fp_info width and height attributes
		 * from all port drivers */
		display_info->width = (unsigned short) port->fp_info->fp_width;
		display_info->height = (unsigned short) port->fp_info->fp_height;
		/* Backward compatibility: If width and height are specified,
		 * that means it is a fixed resolution panel */
		if (port->fp_info->fp_width && port->fp_info->fp_height) {
			display_info->fixed_res = 1;
			fp_refresh = 60;
		}
	}

	/* If fixed timing also comes from user attributes then override DisplayID
	 * fixed timing and fpinfo values */
	ret = pi_get_port_init_attr(port, PD_ATTR_ID_FIXED_TIMING, &fixed_timing);
	if (fixed_timing) {
		display_info->fixed_res = 1;
		fp_refresh = 60;
	}

	/* Do gmch filtering:
	 * There is no way to get the mode context inorder to reach the
	 * gmch filtering function */

	/* First find the native resolution */
	get_native_dtd(in_list, PI_SUPPORTED_TIMINGS,
		&display_info->native_dtd, PD_MODE_DTD_FP_NATIVE);

	/* If no FP Native DTD provided, then get the native DTD
	 *   either user DTD or edid DTD */
	if (!display_info->native_dtd) {
		get_native_dtd(in_list, PI_SUPPORTED_TIMINGS,
			&display_info->native_dtd, PD_MODE_DTD_USER);
	}
	if (!display_info->native_dtd) {
		get_native_dtd(in_list, PI_SUPPORTED_TIMINGS,
			&display_info->native_dtd, PD_MODE_DTD);
	}

	/* Set up the fp width, height and refresh for the comparison */
	if (display_info->native_dtd) {
#ifndef CONFIG_MICRO
		/* If fp width, height doesn' match with native width and height,
		 * Configuration isn't correct */
		if ((display_info->width &&
				(display_info->width != display_info->native_dtd->width)) &&
			(display_info->height &&
				(display_info->height != display_info->native_dtd->height))) {
			EMGD_DEBUG("FP Width Height doesn't match with Native DTD.");
		}
#endif
		/* Overwrite native width height as panel width and height */
		display_info->width = display_info->native_dtd->width;
		display_info->height = display_info->native_dtd->height;
		fp_refresh = display_info->native_dtd->refresh;
	} else if (ret &&
		port->firmware_type != PI_FIRMWARE_DISPLAYID &&
		dvo_info->upscale) {
		/* TODO:
		 * For time being this function has to assume all upscaling encoders
		 * are connected to a fixed timing panel if no fixed_timing is
		 * specified.
		 *
		 * Once fixed_timing init-time attribute becomes mandatory, below check
		 * can be removed.
		 *
		 * If customer uses old config system and didn't specified init time
		 * fixed_timing attribute, then driver assumes it is a fixed-resolution
		 * panel. If user do specifies fixed_timing attribute, then above check
		 * will fail, and algorithm continues with whatever value set to
		 * fixed_res attr.
		 *
		 * ret != 0 means no fixed_timing user attribute
		 * firmware_type == DISPLAYID means firmware provided fixed_timing,
		 * so don't change it.
		 */
		display_info->fixed_res = 1;
	}

	/* Check native_dtd for fixed_res display */
	if (display_info->fixed_res && !display_info->native_dtd) {
		/* This happens if user provides fp_width, fp_height and didn't set
		 * fixed res parameter. In this case native_dtd will be set as part
		 * of the while loop while filtering the modes */
		EMGD_DEBUG("pd_filter_timings: No native dtd for fixed_resolution");
	}

	if (!display_info->width && !display_info->height) {
		/* If fp width and height isn't known, then enable all modes as
		 * non-fixed res display */
		display_info->fixed_res = 0;
	}

	EMGD_DEBUG("fixed_res = %u fixed_timing = %lu",
		display_info->fixed_res, fixed_timing);
	EMGD_DEBUG("fp_width = %u, fp_height = %u, fp_refresh = %u",
		display_info->width, display_info->height, fp_refresh);
	EMGD_DEBUG("min_dclk = %lu, max_dclk = %lu",
		dvo_info->min_dclk, dvo_info->max_dclk);

	/* This function can be called with following
	 * ---------------------------------------------------------------
	 *  DVO device PanelFit Display AvailableModes
	 *  DOWN  UP            Fixed?
	 * --------------------------------------------------------
	 *   0     0      0       0     All supported modes
	 *   1     0      0       0     All supported modes
	 *   0     1      0       0     All supported modes
	 *   1     1      0       0     All supported modes
	 *   0     0      1       0     All supported modes
	 *   1     0      1       0     All supported modes
	 *   0     1      1       0     All supported modes
	 *   1     1      1       0     All supported modes
	 *
	 *   0     0      0       Y     Only one mode
	 *   1     0      0       Y     Only one mode
	 *   0     1      0       Y     Only one mode
	 *   1     1      0       Y     Only one mode
	 *   0     0      1       Y     Only one mode
	 *
	 *   0     1      1       Y     All upscalable modes
	 *   1     0      1       Y     All downscalable modes
	 *
	 *   1     1      1       Y     All UP & DOWN scalable modes
	 * -------------------------------------------------------------------------
	 */

	for (i = 0; i < 2; ++i) {
		j = 0;
		timing = in_list;
		while(timing->width != PD_TIMING_LIST_END) {
			/* If mode supported and dclk is within the range */
			if ((timing->mode_info_flags & PD_MODE_SUPPORTED) &&
				((!dvo_info->max_dclk || (timing->dclk <= dvo_info->max_dclk))&&
				(!dvo_info->min_dclk || (timing->dclk >= dvo_info->min_dclk)))){

				if (
					/* fixed_res = 0 */
					!display_info->fixed_res ||

					/* no panel fit */
					(!display_info->panel_fit &&
					timing->refresh == fp_refresh &&
					timing->width   == display_info->width &&
					timing->height  == display_info->height) ||

					/* panel fit and upscale or downscale */
					(display_info->panel_fit &&
					timing->refresh == fp_refresh &&
					((dvo_info->upscale &&
					timing->width  <= display_info->width &&
					timing->height <= display_info->height &&
					(!dvo_info->upscale_min_width ||
						timing->width  >= dvo_info->upscale_min_width) &&
					(!dvo_info->upscale_min_height ||
					timing->height >= dvo_info->upscale_min_height))
#if 0
					||
					(dvo_info->downscale &&
					timing->width  >= display_info->width &&
					timing->height >= display_info->height &&
					(!dvo_info->downscale_max_width ||
						timing->width  <= dvo_info->downscale_max_width) &&
					(!dvo_info->downscale_max_height ||
						timing->height >= dvo_info->downscale_max_height))
#endif
					))) {

					if(!i){
						count++;
					} else {
						/* copy timing */
						olist[j] = *timing;

						/* save the native_dtd timing */
						if ((timing->width   == display_info->width) &&
							(timing->height  == display_info->height) &&
							(timing->refresh == fp_refresh)) {
							native_dtd = &(olist[j]);
						}

						/* The native DTD pointer is pointing in the in_list,
						 * reset this pointer to point in the out_list */
						if (timing == display_info->native_dtd) {
							display_info->native_dtd = &olist[j];
						}

						j++;
					}
				}
			}
			timing++;
			if ((timing->width == PD_TIMING_LIST_END) && timing->extn_ptr) {
				timing = timing->extn_ptr;
			}
		}
		if(!i) {
			count++;
			olist = (pd_timing_t *) pd_malloc(count * sizeof(pd_timing_t));
			if(!olist) {
				return PD_ERR_NOMEM;
			}
		} else {
			/* Copy the END of LIST entry */
			olist[j] = *timing;
		}
	}

	/* If there is no native_dtd, then use the first matching
	 * resolution with fp width and height as native dtd */
	if (!display_info->native_dtd) {
		display_info->native_dtd = native_dtd;
	}
	if (display_info->native_dtd) {
		EMGD_DEBUG("pd_filter_timings: NativeDTD: %ux%u@%u",
			display_info->native_dtd->width,
			display_info->native_dtd->height,
			display_info->native_dtd->refresh);
		display_info->native_dtd->mode_info_flags |= PD_MODE_DTD_FP_NATIVE;
	}

	*out_list = olist;
	return PD_SUCCESS;
}
Exemplo n.º 22
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),*/
				PIPE(display)->pipe_num,
			    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), TRUE);
			}
		}

			/* 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;
}
Exemplo n.º 23
0
/*!
 * 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() */