/*! * * @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 */
/** * 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() */
/*! * 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; }
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; }
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)); }
/*! * * @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; }
/* * 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; }
/*! * 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; }
/*! * 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; }
/*! * 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; }
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 }
/*! * 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; }
/*! * * @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; }
/*! * 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; }
/*! * 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; }
/*! * * @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; }
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; }
/*! * 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; }
/* 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; }
/*! * 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; }
/*! * 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; }
/*! * 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; }
/*! * 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() */