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