예제 #1
0
/*!
 * This function is directly exported.
 *
 * @param driver_handle
 * @param dsp
 * @param params
 *
 * @return 0 on success
 * @return 1 on failure
 */
int igd_module_init(igd_driver_h driver_handle,
	igd_dispatch_t **dsp,
	igd_param_t *params)
{
	igd_context_t *context = (igd_context_t *)driver_handle;
	device_context_t *device;
	int ret = 0;

	EMGD_TRACE_ENTER;

	device = &context->device_context;
	context->device_context.power_state = IGD_POWERSTATE_D0;
	context->mod_dispatch.init_params = params;
	context->dispatch.idle = empty_idle;
	context->dispatch.sync = empty_sync;
	context->mod_dispatch.in_dih_clone_mode = 0;
	context->mod_dispatch.dih_clone_display = 0;
	context->mod_dispatch.fb_blend_ovl_override = 0;

	/* Intialize IGD Modules */
	ret = init_modules(params, context);
	if (ret) {
		EMGD_ERROR_EXIT("Init Modules Failed");
		return ret;
	}

	OPT_MICRO_VOID_CALL(_init_dispatch(context));

	*dsp = &context->dispatch;

	EMGD_TRACE_EXIT;
	return 0;
}
예제 #2
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 */
예제 #3
0
/**
 * Function that shuts-down and de-initializes this 3rd-party display driver.
 * This is called by the PVR services when it ends.
 *
 * @param dev (IN) The drm_device associated with this driver.
 */
void MAKENAME(_Cleanup)(struct drm_device unref__ *dev)
{
	EMGD_TRACE_ENTER;

	if (emgddc_deinit() != EMGD_OK) {
		EMGD_ERROR_EXIT(DRVNAME " de-init failed (" DISPLAY_DEVICE_NAME ")\n");
	}

	EMGD_TRACE_EXIT;
}
예제 #4
0
/**
 * Function that initializes and starts this 3rd-party display driver.  This is
 * called by the PVR services when it starts.
 *
 * @param dev (IN) The drm_device associated with this driver.
 */
int MAKENAME(_Init)(struct drm_device unref__ *dev)
{
	EMGD_TRACE_ENTER;

	if (emgddc_init(dev) != EMGD_OK) {
		EMGD_ERROR_EXIT(DRVNAME " init failed (" DISPLAY_DEVICE_NAME ")\n");
		return -ENODEV;
	}

	EMGD_TRACE_EXIT;
	return 0;
}
예제 #5
0
/*!
 * This function is directly exported.
 *
 * @param driver_handle
 *
 * @return 0 on success
 * @return 1 on failure
 */
int igd_driver_config(igd_driver_h driver_handle)
{
	igd_context_t *context = (igd_context_t *)driver_handle;
	int ret;

	EMGD_TRACE_ENTER;

	EMGD_ASSERT(context, "Null context!", -IGD_ERROR_INVAL);

	ret = init_dispatch->config(context, init_dispatch);
	if(ret) {
		EMGD_ERROR_EXIT("Device Dependent Config Failed");
		return ret;
	}


	EMGD_TRACE_EXIT;
	return 0;
}
예제 #6
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;
}
예제 #7
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;
}
예제 #8
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;
}
예제 #9
0
/*!
 * This function is directly exported.
 *
 * @param found_device
 * @param pdev
 *
 * @return igd_driver_h
 * @return NULL on failure
 */
igd_driver_h igd_driver_init( igd_init_info_t *init_info )
{
	igd_context_t *context;
	os_pci_dev_t pdev = (os_pci_dev_t)NULL;
	os_pci_dev_t vga_disable_dev;
	iegd_pci_t *found_device;
	int ret;
	int i;

	EMGD_TRACE_ENTER;

	/* Allocate a context */
	context = (void *) OS_ALLOC(sizeof(igd_context_t));
	fixme_vbios_context = context;
	if(!context) {
		EMGD_ERROR_EXIT("igd_driver_init failed to create context");
		return NULL;
	}
	OS_MEMSET(context, 0, sizeof(igd_context_t));

	/* Search VGA devices for a supported one */
	ret = detect_device(&found_device, &pdev);
	if(ret) {
		OS_FREE(context);
		return NULL;
	}

	/*
	 * Some platforms (currently only Atom E6xx) use two PCI devices (the
	 * second device being for SDVO) and this causes the VGA arbiter to get
	 * involved.  Legacy VGA decoding must be disabled for all PCI devices
	 * except one, otherwise the VGA arbiter will prevent DRI usage in the
	 * X server.
	 */
	for (i = 0; i < MAX_LEGACY_VGA_DISABLE; i++) {
		vga_disable_dev = os_pci_find_device(PCI_VENDOR_ID_INTEL,
				PCI_DEVICE_ID_SDVO_TNC, 0xFFFF, 0, 0, NULL);
		if (vga_disable_dev) {
			printk(KERN_INFO "VGA arbiter detected; disabling legacy VGA"
					" decoding on SDVO device\n");
			os_pci_disable_legacy_vga_decoding(vga_disable_dev);
			os_pci_free_device(vga_disable_dev);
		}
	}

	context->device_context.did = found_device->device_id;
	init_dispatch = (init_dispatch_t *)dispatch_acquire(context,
		init_dispatch_table);

	if(!init_dispatch) {
		EMGD_ERROR_EXIT("No dispatch found for listed device");
		return NULL;
	}

	ret = init_dispatch->query(context, init_dispatch, pdev, &init_info->bus,
		&init_info->slot, &init_info->func);
	if(ret) {
		OS_FREE(context);
		EMGD_ERROR_EXIT("Device Dependent Query Failed");
		return NULL;
	}

	/* init info */
	init_info->vendor_id = found_device->vendor_id;
	init_info->device_id = found_device->device_id;
	init_info->name = init_dispatch->name;
	init_info->chipset = init_dispatch->chipset;
	init_info->default_pd_list = init_dispatch->default_pd_list;

	EMGD_TRACE_EXIT;

	return (igd_driver_h)context;
}
예제 #10
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;
}
예제 #11
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() */
예제 #12
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;
}
예제 #13
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;
}
예제 #14
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;
}
예제 #15
0
unsigned int ovl2_check_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)
{
	igd_timing_info_t *timing;
	unsigned int min_w, min_h;

	EMGD_TRACE_ENTER;

	if (!display){
	    EMGD_ERROR_EXIT("display is null");
	    return -IGD_ERROR_INVAL;
	}
	if (!PIPE(display)){
	    EMGD_ERROR_EXIT("PIPE(display) is null");
	    return -IGD_ERROR_INVAL;
	}

	timing = PIPE(display)->timing;

	/* The following parameters are only valid if the overlay is on, so
	 * return success if the overlay is being turned off. */
	if ((flags & IGD_OVL_ALTER_ON) == IGD_OVL_ALTER_OFF) {
		EMGD_TRACE_EXIT;
		return IGD_SUCCESS;
	}

	timing = PIPE(display)->timing;

	if(!timing) {
	    EMGD_ERROR_EXIT("timing is null\n");
	    return -IGD_ERROR_INVAL;
	}

	/*************************************************************************
	 * Ensure the framebuffer dotclock does not exceed the board SKU
	 * max dotclock
	 *************************************************************************/
	/* Make it chipset-specific */
	/* DCT-PC99TA crashes with dotclock > 300MHz */
	if(timing->dclk >= 340000){
		EMGD_ERROR_EXIT("Cannot support dotclock > 340MHz for this SKU");
		return -IGD_ERROR_HWERROR;
	}

	/*************************************************************************
	 * Ensure the overlay surface is ok and can be properly displayed.
	 * This ensures the following is valid:
	 *    - Ensure x1, x2, y1, y2 are pixel aligned
	 *    - 2 pixels or greater in width and height
	 *    - Pixel format is supported by the overlay
	 *    - Pitch is <= 16KB
	 *    - Based on the pixel format, the width is supported
	 *************************************************************************/
	if (!src_surf){
	    EMGD_ERROR_EXIT("src_surf is null");
	    return -IGD_ERROR_INVAL;
	}
	if (!src_rect){
	    EMGD_ERROR_EXIT("src_rect is null");
	    return -IGD_ERROR_INVAL;
	}
	/* Get the minimum size of 1 pixel in width and height for y, u, and v.
	 */
	min_w = 1 << get_uv_shift_x(src_surf->pixel_format);
	min_h = 1 << get_uv_shift_y(src_surf->pixel_format);

	if (((src_rect->x2 - src_rect->x1) < min_w*2) ||
		((src_rect->y2 - src_rect->y1) < min_h*2)) {
		EMGD_ERROR_EXIT(
			"Overlay2 source width or height is < 2 pixels (%dx%d)\n",
			src_rect->x2 - src_rect->x1, src_rect->y2 - src_rect->y1);
		return -IGD_ERROR_INVAL;
	}

	if (FALSE == ovl2_check_pf_tnc(display, src_surf->pixel_format)) {
		EMGD_ERROR_EXIT("Overlay2 source pixel format unsupported (pf:0x%lx)",
			src_surf->pixel_format);
		return -IGD_ERROR_HWERROR;
	}

	if (src_surf->pitch > 16384) {
		EMGD_ERROR_EXIT("Overlay2 source pitch (%d) > 16KB",
			src_surf->pitch);
		return -IGD_ERROR_HWERROR;
	}

	/*************************************************************************
	 * Ensure the location on the framebuffer is ok and can be properly
	 * displayed
	 * This ensures the following is valid:
	 *    - Greater than 1 pixel width and height
	 *    - Will be displayed on screen (not panned off)
	 *************************************************************************/
	if (!dest_rect){
	    EMGD_ERROR_EXIT("dest_rect is null");
	    return -IGD_ERROR_INVAL;
	}
	if (((dest_rect->x2 - dest_rect->x1) <= 1) ||
		((dest_rect->y2 - dest_rect->y1) <= 1)) {
		EMGD_ERROR_EXIT(
			"Overlay2 dest width or height is single pixel (%dx%d)\n",
			dest_rect->x2 - dest_rect->x1, dest_rect->y2 - dest_rect->y1);
		return -IGD_ERROR_INVAL;
	}

	if ((dest_rect->x1 >= timing->width) ||
		(dest_rect->y1 >= timing->height)) {
		EMGD_ERROR_EXIT(
			"Overlay2 dest is panned off the screen (%d,%d)\n",
			dest_rect->x1, dest_rect->y1);
		return -IGD_ERROR_INVAL;
	}

	EMGD_TRACE_EXIT;
	return IGD_SUCCESS;
}