/*! * Get the stride and stereo values based on the display. This is also used * by the MI instructions. * * @param display Pointer to hardware device instance data * @param stride * @param stereo * @param flags Should the stereo be for the frontbuffer or backbuffer? * * @return stride - Stride of the display * @return stereo - Stereo address of the display */ static int mode_get_stride_stereo_plb(igd_display_context_t *display, unsigned long *stride, unsigned long *stereo, unsigned long flags) { unsigned long pitch = PLANE(display)->fb_info->screen_pitch; igd_timing_info_t *timing = PIPE(display)->timing; unsigned long base_offset; base_offset = PLANE(display)->fb_info->visible_offset; *stride = pitch; *stereo = 0; /* For field replication, valid for interlaced modes only * set stereo = fb_base, * stride = pitch */ if (timing->mode_info_flags & IGD_SCAN_INTERLACE) { if(timing->mode_info_flags & IGD_LINE_DOUBLE) { /* Interlaced + Line double flags means field replication. * same lines are sent for both fields. Program the * second eye to be same as the first. */ *stereo = base_offset; } else { /* Regular interlaced. Second eye starts on line 2. * Skip every other line. */ *stereo = base_offset + pitch; *stride = pitch * 2; } } return 0; }
/*! * Program Display Plane Values. * * @param display Pointer to hardware device instance data * @param status * * @return void */ static void program_plane_plb(igd_display_context_t *display, unsigned long status) { unsigned long stereo; unsigned long stride; unsigned long size; unsigned long plane_control; igd_timing_info_t *timing; igd_framebuffer_info_t *fb_info = PLANE(display)->fb_info; unsigned long plane_reg = PLANE(display)->plane_reg; unsigned long start_addr_reg = DSPAADDR; EMGD_TRACE_ENTER; EMGD_DEBUG("Program Plane: %s", status?"ENABLE":"DISABLE"); EMGD_DEBUG("Device power state: D%ld", GET_DEVICE_POWER_STATE(display)); igd_wait_vblank_plb((igd_display_h)display); plane_control = EMGD_READ32(MMIO(display) + plane_reg); if(PLANE(display)->plane_reg == DSPACNTR) { plane_control &= device_data->plane_a_preserve; } else { /* if it's plane b or plane c */ plane_control &= device_data->plane_b_c_preserve; start_addr_reg = 0x71184; } if((status == FALSE) || (GET_DEVICE_POWER_STATE(display) != IGD_POWERSTATE_D0)) { /* * Note: The vga programming code does not have an "off". So * when programming the plane to off we make sure VGA is off * as well. */ disable_vga_plb(MMIO(display)); /* * To turn off plane A or B, the program have to triger the plane A or B * start register. Or else, it will not work. */ EMGD_WRITE32(plane_control, MMIO(display) + plane_reg); EMGD_WRITE32(EMGD_READ32(MMIO(display) + start_addr_reg), MMIO(display) + start_addr_reg); igd_wait_vblank_plb((igd_display_h)display); return; } /* * Note: The very first pass through this function will be with * status false and timings == NULL. Don't use the timings before * the check above. */ timing = PIPE(display)->timing; /* There is a special case code for legacy VGA modes */ while (timing->extn_ptr) { timing = (igd_timing_info_t *)timing->extn_ptr; } if(MODE_IS_VGA(timing)) { program_plane_vga(display, timing); return; } disable_vga_plb(MMIO(display)); size = (((unsigned long)timing->height - 1)<<16) | (unsigned long)(timing->width - 1); /* enable plane, select pipe, enable gamma correction logic */ plane_control |= 0x80000000 | (PIPE(display)->pipe_num<<24); PIPE(display)->plane = PLANE(display); #ifndef CONFIG_MICRO plane_control |= (1<<30); #endif /* Here the settings: * If line + pixel dbling, set 21,20 to 01b, and set Horz Multiply * If line dbling only, set 21,20 to 11b * If pixel dbling only, set 21,20 to 00b, but set Horz Multiply * If no doubling, set 21,20 to 00b (no Horz Multiply) * For pixel doubling * --> both progressive/interlaced modes * For Line doubling * --> progressive modes only */ if (!(timing->mode_info_flags & IGD_SCAN_INTERLACE)) { /* Line doubling in progressive mode requires special bits */ if (timing->mode_info_flags & IGD_LINE_DOUBLE) { /* BIT 20 for line & pixel doubling*/ plane_control |= BIT20; /* check later, if no pixel doubling, set bit 21 too*/ } } if (timing->mode_info_flags & IGD_PIXEL_DOUBLE) { /* Horz pixel multiply must be set for double */ plane_control |= BIT11; /* TODO -> Plba can more than double, It can 3X, 4X etc. These arent exposed now */ } else if(plane_control & BIT20){ /* For line ONLY doubling, set bit 21 also '1' */ plane_control |= BIT21; } mode_get_stride_stereo_plb(display, &stride, &stereo, 0); /* set color depth */ switch (IGD_PF_DEPTH(fb_info->pixel_format)) { case PF_DEPTH_8: plane_control |= BIT27 | BIT30; break; case PF_DEPTH_16: plane_control |= BIT28 | BIT26; break; default: case PF_DEPTH_32: plane_control |= BIT28 | BIT27; break; } if(fb_info->flags & IGD_ENABLE_DISPLAY_GAMMA) { plane_control |= (BIT30); } EMGD_DEBUG(" Plane Control = 0x%lx", plane_control); EMGD_DEBUG(" Plane Base = 0x%lx", fb_info->visible_offset); EMGD_DEBUG(" Plane Pitch = 0x%lx", stride); EMGD_DEBUG(" Plane Size = 0x%lx", size); EMGD_WRITE32(stride, MMIO(display) + plane_reg + DSP_STRIDE_OFFSET); /* * In reality this only exists for plane B. It doesn't seem to hurt * plane A so just do it anyway and save us another case. */ EMGD_WRITE32(size, MMIO(display) + plane_reg + DSP_SIZE_OFFSET); /*EMGD_WRITE32(stereo, MMIO(display) + plane_reg + DSP_STEREO_OFFSET); - This register is Reserved ON plba */ EMGD_WRITE32(fb_info->visible_offset, MMIO(display) + plane_reg + DSP_START_OFFSET); /* It seems we need push or trigger plane A/B to start to work * on Poulsbo, especially for sDVO port. Let's write plane control * register and start address register at last. */ EMGD_WRITE32(plane_control, MMIO(display) + plane_reg); EMGD_WRITE32(EMGD_READ32(MMIO(display) + start_addr_reg), MMIO(display) + start_addr_reg); igd_wait_vblank_plb((igd_display_h)display); EMGD_TRACE_EXIT; return; }
//------------------------------------------------------------------ // Storm3D_Mesh_CollisionTable::ReBuild //------------------------------------------------------------------ void Storm3D_Mesh_CollisionTable::ReBuild(Storm3D_Mesh *mesh) { // TEMP!!! //return; int memory_before = 0; //frozenbyte::debug::Debug_MemoryManager::amountMemoryInUse(); // Set owner owner=mesh; // Allocate memory for collision table delete tree; tree = 0; if(!owner->vertexes || !owner->faces[0]) return; face_amount=owner->face_amount[0]; if (owner->collision_faces != -1) face_amount = owner->collision_faces; SAFE_DELETE_ARRAY(faces); faces = new CollisionFace[face_amount]; VC2 mmin(10000000.f, 10000000.f); VC2 mmax(-10000000.f, -10000000.f); // Create collision table for(int fi = 0; fi < face_amount; ++fi) { // Set vertexes faces[fi].vertex0=owner->vertexes[owner->faces[0][fi].vertex_index[0]].position; faces[fi].vertex1=owner->vertexes[owner->faces[0][fi].vertex_index[1]].position; faces[fi].vertex2=owner->vertexes[owner->faces[0][fi].vertex_index[2]].position; // Create edges faces[fi].e01=owner->vertexes[owner->faces[0][fi].vertex_index[1]].position-owner->vertexes[owner->faces[0][fi].vertex_index[0]].position; faces[fi].e02=owner->vertexes[owner->faces[0][fi].vertex_index[2]].position-owner->vertexes[owner->faces[0][fi].vertex_index[0]].position; VC3 e12=owner->vertexes[owner->faces[0][fi].vertex_index[2]].position-owner->vertexes[owner->faces[0][fi].vertex_index[1]].position; VC3 cross_e01_e02 = faces[fi].e01.GetCrossWith(faces[fi].e02); if(cross_e01_e02.GetSquareLength() < 0.0001f) { CollisionFace &face = faces[fi]; face.sphere.radius = 0; continue; } // Create plane faces[fi].plane=PLANE(cross_e01_e02.GetNormalized(),faces[fi].vertex0); // psd CollisionFace *face = &faces[fi]; face->sphere.position = (face->vertex0 + face->vertex1 + face->vertex2) / 3; face->sphere.radius = face->sphere.position.GetSquareRangeTo(face->vertex0); float tmp = face->sphere.position.GetSquareRangeTo(face->vertex1); if(tmp > face->sphere.radius) face->sphere.radius = tmp; tmp = face->sphere.position.GetSquareRangeTo(face->vertex2); if(tmp > face->sphere.radius) face->sphere.radius = tmp; face->sphere.radius = sqrtf(face->sphere.radius); if(face->sphere.position.x - face->sphere.radius < mmin.x) mmin.x = face->sphere.position.x - face->sphere.radius; if(face->sphere.position.z - face->sphere.radius < mmin.y) mmin.y = face->sphere.position.z - face->sphere.radius; if(face->sphere.position.x + face->sphere.radius > mmax.x) mmax.x = face->sphere.position.x + face->sphere.radius; if(face->sphere.position.z + face->sphere.radius > mmax.y) mmax.y = face->sphere.position.z + face->sphere.radius; } tree = new StaticQuadtree<CollisionFace>(mmin, mmax); //tree = new Quadtree<CollisionFace>(mmin, mmax); for(int i = 0; i < face_amount; ++i) { CollisionFace &face = faces[i]; if(face.sphere.radius < 0.001f) continue; //tree->insert(&face, face.sphere.position, face.sphere.radius); float mmin = min(face.vertex0.y, face.vertex1.y); mmin = min(mmin, face.vertex2.y); float mmax = max(face.vertex0.y, face.vertex1.y); mmax = max(mmax, face.vertex2.y); tree->insert(face, face.sphere.position, face.sphere.radius, mmin, mmax); } }
/*! * 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() */
/*! * Check user supplied timing against what is currently * programmed to see if it needs to change. If the timing * isn't going to change, then we don't want to turn off and * reprogram the port. * * NOTE: If this increases the size too much for vbios, then it * could be ifndef CONFIG_MICRO with an else that returns 1. That * would mean vbios wouldn't have these checks and always assume * the timing was changing. * * @param display * @param new_dc DC changes always require port/plane/pipe programming. * @param pt_info User supplied timing info to check. * @param fb_info User supplied framebuffer info. * @param port_number * @param display_mask Which display is being checked. * @param alter flags used to force the alter * * @return 1 timing has changed * @return 0 timing hasn't changed */ static int timing_changed(igd_display_context_t *display, unsigned long new_dc, unsigned long dc, igd_display_info_t *pt_info, igd_framebuffer_info_t *fb_info, unsigned long display_mask, unsigned long flags) { igd_framebuffer_info_t *cfb; EMGD_TRACE_ENTER; /* * will this cover every case? Can a change on one display effect * the timings of the other? I don't think so. */ if ((new_dc & display_mask) != (dc & display_mask)) { return 1; /* Ports are changing on this display, must re-program. */ } /* * Make sure the owner port has a pt_info, if not then we'll assume * that it hasn't been programmed yet and thus the timings are going * to change. */ if (PORT_OWNER(display)->pt_info == NULL) { return 1; } /* * Make sure we have valid timing info. If not, then don't try * and change the timings. */ if (!pt_info || !fb_info) { return 0; } /* * If the caller really wants to re-program the planes/pipes/ports * then do it */ if (flags & IGD_FORCE_ALTER) { return 1; } /* * Check only width, height, refresh. If these don't match, then we * know that something is changing. */ if ((pt_info->width == PORT_OWNER(display)->pt_info->width) && (pt_info->height == PORT_OWNER(display)->pt_info->height) && (pt_info->refresh == PORT_OWNER(display)->pt_info->refresh)) { /* Check framebuffer for changes, fb changes may change timing */ if ((cfb = PLANE(display)->fb_info) != NULL) { if ((cfb->width != fb_info->width) || (cfb->height != fb_info->height) || (cfb->pixel_format != fb_info->pixel_format) || (cfb->flags != fb_info->flags)) { /* Timing ok buf fb_info doesn't match */ return 1; } } } else { /* Timing doesn't match */ return 1; } /* Timing and fb have not changed */ EMGD_TRACE_EXIT; return 0; }
/*! * 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; }
unsigned int ovl2_send_instr_tnc( igd_display_context_t *display, ovl2_reg_tnc_t *spritec_regs_tnc, unsigned int flags) { unsigned char *mmio = MMIO(display); unsigned long tmp, pipe_reg, pipe_num; inter_module_dispatch_t *md; platform_context_tnc_t * platform; EMGD_TRACE_ENTER; /* We dont need the CMD_WAIT_OVL2_TNC instruction coz * our alter_ovl code already querried status * for last flip completion before getting here. See * micro_prepare_ovl2_tnc called by alter_ovl2_tnc. * It calls query overlay before the next flip */ /*If Overlay+FB Blend is requested and the FB is xRGB *turn on the ARGB format. */ if(ovl_context->fb_blend_ovl) { if((flags & IGD_OVL_ALTER_ON) == IGD_OVL_ALTER_ON) { tmp = EMGD_READ32(mmio + PLANE(display)->plane_reg); if((tmp & 0x3c000000) == 0x18000000) { tmp = tmp & 0xc3FFFFFF; EMGD_WRITE32(tmp | 0x1c000000, mmio + PLANE(display)->plane_reg); EMGD_READ32(mmio + PLANE(display)->plane_reg); tmp = EMGD_READ32(mmio + PLANE(display)->plane_reg + 0x1c); EMGD_WRITE32(tmp, mmio + PLANE(display)->plane_reg + 0x1c); } } else { tmp = EMGD_READ32(mmio + PLANE(display)->plane_reg); if((tmp & 0x3c000000) == 0x1c000000) { tmp = tmp & 0xc3FFFFFF; EMGD_WRITE32(tmp | 0x18000000, mmio + PLANE(display)->plane_reg); EMGD_READ32(mmio + PLANE(display)->plane_reg); tmp = EMGD_READ32(mmio + PLANE(display)->plane_reg + 0x1c); EMGD_WRITE32(tmp, mmio + PLANE(display)->plane_reg + 0x1c); OS_SLEEP(100); } } } /* Send a load register instruction to write the Plane C sprite address * which is the trigger register. * This is an instruction, so it happens after blend, and since it * is an instruction, we do not have to poll waiting for it. */ EMGD_WRITE32(spritec_regs_tnc->start, mmio + 0x7219C); /* Since the ISR bit 0x100 actually doesnt work, * we need to setup a trigger for a VBLANK event * on Pipe-B to guarantee that the Sprite-C had * actually completed its last flip. * (ISR bit was tested on Poulsbo D2 by capturing * timestamps of quick successive alter_overlays.. * checked ISR bit directly after the write to Sprite * C Address register in process_vqueue handling.. * the ISR bit never changed */ 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->set_flip_pending){ OS_PTHREAD_MUTEX_LOCK(&platform->flip_mutex); md->set_flip_pending(MMIO(display), pipe_reg); OS_PTHREAD_MUTEX_UNLOCK(&platform->flip_mutex); } ovl_context->sync2 = WAIT_FOR_FLIP; EMGD_TRACE_EXIT; return IGD_SUCCESS; }
unsigned int ovl2_send_instr_plb( igd_display_context_t *display, ovl2_reg_plb_t *spritec_regs_plb, unsigned int flags) { unsigned char * mmio = MMIO(display); unsigned long tmp; inter_module_dispatch_t *md; platform_context_plb_t * platform; unsigned int pipe_num; unsigned long pipe_reg; int ret; EMGD_TRACE_ENTER; /* We dont need the CMD_WAIT_OVL2_PLB instruction coz * our alter_ovl code already querried status * for last flip completion before getting here. See * micro_prepare_ovl2_plb called by alter_ovl2_plb. * It calls query overlay before the next flip */ /* * If Overlay + FB Blend is requested and the FB is xRGB * turn on the ARGB format. */ if(ovl_context->fb_blend_ovl) { if ((flags & IGD_OVL_ALTER_ON) != IGD_OVL_ALTER_ON) { tmp = EMGD_READ32(mmio + PLANE(display)->plane_reg); if((tmp & 0x3c000000) == 0x1c000000) { tmp = tmp & 0xc3FFFFFF; EMGD_WRITE32(tmp | 0x18000000, mmio + PLANE(display)->plane_reg); tmp = EMGD_READ32(mmio + PLANE(display)->plane_reg + 4); EMGD_WRITE32(tmp, mmio + PLANE(display)->plane_reg + 4); OS_SLEEP(100); } } else { tmp = EMGD_READ32(mmio + PLANE(display)->plane_reg); if((tmp & 0x3c000000) == 0x18000000) { EMGD_WRITE32(tmp | 0x1c000000, mmio + PLANE(display)->plane_reg); tmp = EMGD_READ32(mmio + PLANE(display)->plane_reg + 4); EMGD_WRITE32(tmp, mmio + PLANE(display)->plane_reg + 4); } } } /* Send a load register instruction to write the Plane C sprite address * which is the trigger register. * This is an instruction, so it happens after blend, and since it * is an instruction, we do not have to poll waiting for it. */ EMGD_WRITE32(spritec_regs_plb->start, mmio + 0x72184); md = &display->context->mod_dispatch; platform = (platform_context_plb_t *)display->context-> platform_context; pipe_num = PIPE(display)->pipe_num; if(pipe_num){ pipe_reg = 0x71024; } else { pipe_reg = 0x70024; } if(md && md->set_flip_pending){ /* For second overlay, Poulsbo has no ISR bit * to reflect the flip pending for Display * Sprite C. So we use Pipe-B vblank status * as a substitute */ ret = OS_PTHREAD_MUTEX_LOCK(&platform->flip_mutex); md->set_flip_pending(MMIO(display), pipe_reg); OS_PTHREAD_MUTEX_UNLOCK(&platform->flip_mutex); } ovl_context->sync2 = 0; display->context->dispatch.sync(display, IGD_PRIORITY_NORMAL, &ovl_context->sync2, IGD_SYNC_NONBLOCK); EMGD_TRACE_EXIT; return IGD_SUCCESS; }