//-----------------------------------------------------------------------------
// get_copy_sg_list_from_smd_contig_memory
//
// Utility method for forming the scatter-gather list for multipart copy 
// buffers from SMD memory which is contiguous in DRAM.
//-----------------------------------------------------------------------------
static 
sec_result_t get_copy_sg_list_from_smd_contig_memory(sec_multipart_buff_list_t *buff_list, 
                                          int read_write,
                                          int copy_parts,
                                          sfaf_mem_ptr_t **sg_list,
                                          unsigned int   *sg_count )
{
    sec_result_t rc = SEC_SUCCESS;
    int i = 0;      //index for a part in multipart list
    int j = 0;
    unsigned long* sg_args = NULL;
    sec_addr_t  phy_addr = 0;
    sec_addr_t  vir_addr = 0;
   
    *sg_count = 0;
    *sg_list = NULL;

    if (!buff_list)
        goto exit;

    *sg_count = copy_parts;
    *sg_list = (sfaf_mem_ptr_t*) OS_ALLOC(sizeof(sfaf_mem_ptr_t) * (*sg_count));
    VERIFY( *sg_list != NULL, exit, rc, SEC_OUT_OF_MEMORY);
    memset(*sg_list, 0, sizeof(sfaf_mem_ptr_t) * (*sg_count));

    for(i =0, j = 0; i < buff_list->nParts; i++)
    {
        if ( buff_list->part[i].copyonly == 1)      //deals with COPY parts only
        {
            vir_addr = (sec_address_t)(read_write == USER_BUF_RO ?
                        buff_list->part[i].src_buffer : buff_list->part[i].dst_buffer);

            phy_addr = find_pa_of_smd_memory(vir_addr);
            VERIFY( phy_addr != 0, exit, rc, SEC_FAIL);
    
            (*sg_list)[j].address = (void*)(phy_addr);
            (*sg_list)[j].length  = buff_list->part[i].size_bytes;
            (*sg_list)[j].external = 1;  
            (*sg_list)[j].swap = 1;     
            (*sg_list)[j].pmr_type = (read_write == USER_BUF_RO) ? 0 : PMR_TYPE_CMP_VIDEO;     
            (*sg_list)[j].rsvd = 0;

            //swap the endianness for SEC
            sg_args = (unsigned long *)&((*sg_list)[j].external);
            sg_args[0] = bswap(sg_args[0]); 

            j++;
        }
    }

exit: 
    return rc;
}
os_lock_t os_create_lock(void)
{
    os_lock_pvt_t *p_lock = NULL;

    if(NULL == (p_lock = OS_ALLOC(sizeof(os_lock_pvt_t)))) {
        OS_ERROR("OS_ALLOC failed\n");
        goto error;
    }

    if(NULL == (p_lock->p_sema = OS_ALLOC(sizeof(os_sema_t)))) {
        OS_ERROR("OS_ALLOC failed\n");
        goto error;
    }

    os_sema_init(p_lock->p_sema, 1);
    return ((os_lock_t)p_lock);

error:
    if(p_lock != NULL) {
        OS_FREE(p_lock);
    }
    return (NULL);
}
pci_dev_t *pci_find_device(
        unsigned int vid,
        unsigned int did,
        pci_dev_t *pci_dev)
{
    pci_dev_t *     device;
    FILE*           fDevices;
    char            buf[BUF_SIZE];
    unsigned int    nDevAddr, nVenDevId, irqnum;

    if(NULL == (fDevices = fopen("/proc/bus/pci/devices", "r"))) {
        return NULL;
    }

    while(NULL != fgets(buf, BUF_SIZE, fDevices))
    {
        if(3 != sscanf(buf, "%x %x %x", &nDevAddr, &nVenDevId, &irqnum))
        {
            fclose(fDevices);
            return NULL;
        }

        //if looking for the next device, go past current dev
        if((pci_dev != NULL) && ((nDevAddr << 8) <= pci_dev->slot_address)) {
            continue;
        }

        OS_DEBUG("OSAL_PCI cur id: 0x%X, seeking id: 0x%X\n", nVenDevId, (did | (vid<<16)));

        if(nVenDevId == (did | (vid<<16))) {
            OS_DEBUG("Device Found!\n");
            device = (pci_dev_t *) OS_ALLOC(sizeof(pci_dev_t));
            if(NULL == device) {
                fclose(fDevices);
                return NULL; 
            }
            device->slot_address = nDevAddr << 8; //for Windows compatibility
            device->irq = irqnum;
            OS_DEBUG("slot address: 0x%08X\n", nDevAddr << 8);
            fclose(fDevices);
            return(device);
        }
    }

    OS_DEBUG("Device NOT found!\n");
    fclose(fDevices);
    return(NULL);
}
//-----------------------------------------------------------------------------
// get_copy_sg_list_from_non_contig_memory
//
// Utility method for forming the scatter-gather list for multipart copy 
// buffers which are non-contiguous in DRAM.
//-----------------------------------------------------------------------------
static 
sec_result_t get_copy_sg_list_from_non_contig_memory(sec_multipart_buff_list_t *buff_list, 
                                    int read_write,
                                    int copy_parts,
                                    user_buf_t     **user_buf_list,
                                    sfaf_mem_ptr_t **sg_list,
                                    unsigned int   *sg_count )
{
    sec_result_t rc = SEC_SUCCESS;
    user_buf_t  * user_buff = NULL;
    int i = 0;      //index for a part in multipart list
    int j = 0;      //index for a user_buf_t in user_buf_list
    sec_address_t vir_addr;

    *sg_count = 0;
    *sg_list = NULL;

    if (!copy_parts)
        goto exit; 

    *user_buf_list = (user_buf_t*)OS_ALLOC (sizeof(user_buf_t) * copy_parts);
    VERIFY( *user_buf_list != NULL, exit, rc, SEC_OUT_OF_MEMORY);
    memset(*user_buf_list, 0, (sizeof(user_buf_t) * copy_parts));

    for(i =0; i < buff_list->nParts; i++)
    {
        if ( buff_list->part[i].copyonly == 1)      //deals with ONLY copy parts
        {
            user_buff = ((user_buf_t*)(*user_buf_list) + j);
            j++;
            vir_addr = (sec_address_t)(read_write == USER_BUF_RO ?
                        buff_list->part[i].src_buffer : buff_list->part[i].dst_buffer);
            rc = form_sfaf_sg_list( user_buff,
                    vir_addr,
                    buff_list->part[i].size_bytes,
                    read_write,
                    sg_list,
                    sg_count );
            VERIFY_QUICK( rc == SEC_SUCCESS, exit);
        }
    }

exit:
    return rc;
}
示例#5
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
}
osal_result os_pci_device_from_slot(os_pci_dev_t *pci_dev, unsigned int slot)
{
    pci_dev_t *device;
    FILE* fDev;
    char szDevAddr[64];

    *pci_dev = NULL;

    if(21 != snprintf(szDevAddr, sizeof(szDevAddr),
                        "/proc/bus/pci/%2.2x/%2.2x.%1.1x",
                        (unsigned int)PCI_BUS(slot),
                        (unsigned int)PCI_DEV(slot),
                        (unsigned int)PCI_FUNC(slot))) {
        return OSAL_ERROR;
    }

    if(NULL == (fDev = fopen(szDevAddr, "r"))) {
        return OSAL_NOT_FOUND;
    }

    device = (pci_dev_t*) OS_ALLOC(sizeof(pci_dev_t));

    if(device == NULL) {
        fclose(fDev);
        return OSAL_INSUFFICIENT_MEMORY;
    }

    device->slot_address = slot;
    *pci_dev = ((os_pci_dev_t*) device);

    fclose(fDev);

    OS_DEBUG("OSAL_PCI Found Dev: %s\n", szDevAddr);

    return OSAL_SUCCESS;
}
/* This is user space implementation of osal_firmware_request()
   It copies fw image file to a malloced buffer and update the
   size and buffer pointer in fw_ctxt.
*/
osal_result os_firmware_request(const char *fw_image_fs_path,
                                os_firmware_t *fw_ctxt)
{
   FILE *fp = NULL;
   osal_result os_ret = OSAL_ERROR;

   if ( NULL != fw_ctxt) {
      fp = fopen(fw_image_fs_path, "rb");
      if (NULL != fp) {
         fseek(fp, 0L, SEEK_END);
         fw_ctxt->fw_size = ftell(fp); /* get image size */
         fseek(fp, 0L, SEEK_SET );
     
         /*Allocate buffer for fw image */ 
         fw_ctxt->fw_address = OS_ALLOC(fw_ctxt->fw_size);
         if (NULL != fw_ctxt->fw_address) {
            size_t data_read;

            data_read = fread(fw_ctxt->fw_address, 1, fw_ctxt->fw_size, fp);

            if (data_read == fw_ctxt->fw_size) {
               os_ret = OSAL_SUCCESS;       
            }
         }

         fclose(fp);
      } else {
         OS_PRINT("ERR: %s file not found \n", fw_image_fs_path);
      }
   } else {
      os_ret = OSAL_INVALID_PARAM;
      OS_PRINT("ERR: fw_ctxt is NULL\n");
   }

   return os_ret;
}
示例#8
0
/*!
 * This function is directly exported.
 *
 * @param found_device
 * @param pdev
 *
 * @return igd_driver_h
 * @return NULL on failure
 */
igd_driver_h igd_driver_init( igd_init_info_t *init_info )
{
	igd_context_t *context;
	os_pci_dev_t pdev = (os_pci_dev_t)NULL;
	os_pci_dev_t vga_disable_dev;
	iegd_pci_t *found_device;
	int ret;
	int i;

	EMGD_TRACE_ENTER;

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

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

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

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

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

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

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

	EMGD_TRACE_EXIT;

	return (igd_driver_h)context;
}
示例#9
0
/*!
 * Function to allocate memory
 *
 * @param handle
 * @param pd_driver
 *
 * @return void
 */
void *igd_pd_malloc(unsigned long size)
{
	return OS_ALLOC(size);
} /* end igd_pd_malloc */
//-----------------------------------------------------------------------------
// form_sfaf_sg_list
//
// This method forms the scatter-gather list understood by SEC firmware.
// This is the sequence of steps:
//      1. Lock physical pages corresponding to virtual memory by using
//         get_user_pages Linux Kernel API.
//      2. Alloc memory for a scatter-gather element
//      3. Set physical start address, length and various parameters in the 
//         scatter-gather element.
//      4. get_user_pages returns a reference to every page found in 
//         vir_buffer - vir+buffer+vir_buffer_size range. Whereas, SEC needs
//         a SG list with elements which are contiguous, irrespective of page 
//         boundaries. Therefore, we need additional manipulation for this.
//      5. Loop 2(by expanding memory for SG list) & 3 until all the physical
//         pages are covered.
//-----------------------------------------------------------------------------
static 
sec_result_t form_sfaf_sg_list(user_buf_t * user_buffer,
                                sec_address_t vir_buffer, 
                                unsigned long vir_buffer_size,
                                int write,
                                sfaf_mem_ptr_t **sg_list,
                                unsigned int    *sg_count )
{
    sec_result_t rc = SEC_SUCCESS;
    int xfer_size = 0;
    int num_pages_processed = 0;  //to keep track of pages returned by get_user_pages API
    bool need_another_sg_entry = true; //to keep track of elements in SG list provided to SEC

    sfaf_mem_ptr_t * new_sg_list = NULL;
    int new_sg_count = 0;
    unsigned long* sg_args = NULL;

    VERIFY( sg_list != NULL, exit, rc, SEC_NULL_POINTER);
    VERIFY( sg_count != NULL, exit, rc, SEC_NULL_POINTER);
    
    //Step 1 : get_user_pages API call
    rc = sec_kernel_user_buf_lock( user_buffer, 
            (sec_address_t) vir_buffer,
            vir_buffer_size,
            write);
    VERIFY_QUICK(rc == SEC_SUCCESS, exit);

    //We traverse the 'user_buffer' list returned by get_user_pages kernel API,
    while (need_another_sg_entry)
    {
        //Step 2: realloc memory for a additional sfaf_const_mem_ptr data structure and 
        //update it's variables
        new_sg_count = (*sg_count) + 1;
        new_sg_list = (sfaf_mem_ptr_t*) OS_ALLOC(sizeof(sfaf_mem_ptr_t) * (new_sg_count));
        VERIFY( new_sg_list != NULL, exit, rc, SEC_OUT_OF_MEMORY);

        if (*sg_list)
        {
            memcpy(new_sg_list, *sg_list, sizeof(sfaf_mem_ptr_t) * (new_sg_count -1));
            OS_FREE(*sg_list);
        }
        //Update the method output pointers
        *sg_count = new_sg_count;
        *sg_list = new_sg_list;

        //Step 3: Set SG elements
        xfer_size = PWU_MIN(user_buffer->page_bytes, user_buffer->size);
        new_sg_list[new_sg_count - 1].address = (void*)(user_buffer->page_addr + user_buffer->offset);
        new_sg_list[new_sg_count - 1].length  = xfer_size;
        new_sg_list[new_sg_count - 1].external = 1;  
        new_sg_list[new_sg_count - 1].swap = 1;      
        new_sg_list[new_sg_count - 1].pmr_type = 0;     
        new_sg_list[new_sg_count - 1].rsvd = 0;

        //swap the endianness for SEC
        sg_args = (unsigned long *)&(new_sg_list[new_sg_count - 1].external);
        sg_args[0] = bswap(sg_args[0]); 

        need_another_sg_entry = false;
        num_pages_processed++;

        if (num_pages_processed == user_buffer->num_pages)
        {
            //we are done processing the buffer...get out now
            goto exit;
        }

        //Step 4: get_user_pages returns a reference to every page found in 
        //vir_buffer - vir+buffer+vir_buffer_size range. Whereas, SEC needs
        //a SG list with elements which are contiguous, irrespective of page 
        //boundaries. Therefore, we need additional manipulation for this.
        rc = user_buf_advance( user_buffer, xfer_size);
        VERIFY_QUICK(rc == SEC_SUCCESS , exit);
        xfer_size = PWU_MIN(user_buffer->page_bytes, user_buffer->size);
        while ((num_pages_processed < user_buffer->num_pages) && (!need_another_sg_entry))
        {
            //navigate through for every page in user_buf_t
            if ((void*)(user_buffer->page_addr + user_buffer->offset) != 
                    (new_sg_list[new_sg_count - 1].address + new_sg_list[new_sg_count - 1].length))
            {
                //until you finish the list or the page's start address is not next to previous page's end address
                //generate another sfaf_const_mem_ptr data structure and follow the process
                need_another_sg_entry = true;
            }
            else
            {
                new_sg_list[new_sg_count - 1].length += xfer_size;
                num_pages_processed++;

                if (num_pages_processed == user_buffer->num_pages)
                {
                    //we are done processing the buffer...get out now
                    goto exit;
                }

                rc = user_buf_advance( user_buffer, xfer_size);
                VERIFY_QUICK(rc == SEC_SUCCESS , exit);
                xfer_size = PWU_MIN(user_buffer->page_bytes, user_buffer->size);
            }
        }
    }

exit:
    return rc;
}
sec_result_t pr2_multipart_op(sec_kernel_ipc_t * ipc_arg,
                              ipl_t *            ipl,
                              opl_t *            opl,
                              ipc_shmem_t *      ish_pl )
{
    sec_ipc_return_t    ipc_ret = IPC_RET_COMMAND_COMPLETE;
    sec_result_t rc = SEC_SUCCESS;
    sec_address_t buf_addr;
    uint32_t buf_size = 0;

    uint32_t sg_count = 0;
    user_buf_t *user_buf_list = NULL;
    sfaf_mem_ptr_t *sg_list = NULL;

    buf_addr = (sec_address_t) ipc_arg->src;
    buf_size = ipc_arg->src_size;

    if(buf_addr && buf_size)
    {
        /* Enter here only if we have to do scatter gather */
        user_buf_list = (user_buf_t*)OS_ALLOC (sizeof(user_buf_t));
        VERIFY( user_buf_list != NULL, exit, rc, SEC_OUT_OF_MEMORY);
        memset(user_buf_list, 0, (sizeof(user_buf_t)));

        rc = form_sfaf_sg_list( user_buf_list,
                buf_addr,
                buf_size,
                USER_BUF_RO,
                &sg_list,
                &sg_count );
        
        VERIFY_QUICK( rc == SEC_SUCCESS, exit);
#if 0        
        {
            int i;
            sfaf_mem_ptr_t *temp = sg_list;
            for(i=0; i<sg_count; i++)
            {
                pv(temp[i].address, temp[i].length);
            }
        }
#endif
        // Put the scatter gather list in the ipl
        if(ipc_arg->sub_cmd.sc_pr2 == IPC_SC_PR2_CALCULATE_OMAC)
        {
            ipl->pr2_sg_op.pr2_calc_omac.pr2_sg_data_start = (uint32_t) OS_VIRT_TO_PHYS(sg_list);
            ipl->pr2_sg_op.pr2_calc_omac.pr2_sg_data_count = sg_count;
        }
        else if(ipc_arg->sub_cmd.sc_pr2 == IPC_SC_PR2_HASH_VALUE)
        {
            ipl->pr2_sg_op.pr2_hash_value.pr2_sg_data_start = (uint32_t) OS_VIRT_TO_PHYS(sg_list);
            ipl->pr2_sg_op.pr2_hash_value.pr2_sg_data_count = sg_count;
        }
    }

    ipc_ret = sec_kernel_ipc(ipc_arg->cmd,
                             ipc_arg->sub_cmd,
                             ipc_arg->io_sizes,
                             ipl,
                             opl,
                             ish_pl,
                             NULL);
    rc = ipc2sec(ipc_ret);

exit: 
    free_user_buffer_list( user_buf_list, 1);
    OS_FREE(sg_list);
    return rc;
}
pci_dev_t *pci_find_device_by_class(
        unsigned char subclass,
        unsigned char baseclass,
        unsigned char pi,
        pci_dev_t *pci_dev)
{
    pci_dev_t *     device;
    pci_dev_t       temp_dev;
    FILE*           fDevices;
    char            buf[BUF_SIZE];
    unsigned int    nDevAddr;
    unsigned int    tempData;
    unsigned char   curSubclass, curBaseclass, curPi;

    if(NULL == (fDevices = fopen("/proc/bus/pci/devices", "r"))) {
        return NULL;
    }

    while(NULL != fgets(buf, BUF_SIZE, fDevices)) {
        if(1 != sscanf(buf, "%x", &nDevAddr)) {
            fclose(fDevices);
            return NULL;
        }

        //if looking for the next device, go past current dev
        if((pci_dev != NULL) && ((nDevAddr << 8) <= pci_dev->slot_address)) {
            continue;
        }

        temp_dev.slot_address = nDevAddr << 8; //for Windows compatibility

        if(OSAL_SUCCESS != os_pci_read_config_32(&temp_dev, 0x8, &tempData)) {
            fclose(fDevices);
            return NULL;
        }

        curPi = (tempData & 0xFF00) >> 8;
        curSubclass = (tempData & 0xFF0000) >> 16;
        curBaseclass = (tempData & 0xFF000000) >> 24;

        OS_DEBUG("OSAL_PCI (BaseClass, SubClass, PI) Current: (0x%X, 0x%X, 0x%X), seeking: (0x%X, 0x%X, 0x%X)\n", curBaseclass, curSubclass, curPi, baseclass, subclass, pi);

        if( (curBaseclass == baseclass)
        &&  (curSubclass == subclass)
        &&  (curPi == pi)) {
            OS_DEBUG("Device Found!\n");
            device = (pci_dev_t *) OS_ALLOC(sizeof(pci_dev_t));
            if(NULL == device) {
                fclose(fDevices);
                return NULL;
            }
            device->slot_address = nDevAddr << 8; //for Windows compatibility
            OS_DEBUG("slot address: 0x%08X\n", nDevAddr << 8);
            fclose(fDevices);
            return(device);
        }
    }

    OS_DEBUG("Device NOT found!\n");
    fclose(fDevices);
    return(NULL);
}
示例#13
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;
}
示例#14
0
/*!
 * Calculates the Edid like data (ELD) if port supports audio transmission
 *
 * @param port
 * @param timing_info
 *
 * @return 0
 */
static int calculate_eld(
	igd_display_port_t *port,
	igd_timing_info_t *timing_info)
{
	/* Calculate for non-content protected & content protected(Array of 2) */
#ifdef CALCULATE_ELD_INFOFRAMES
	unsigned long cal_NPL[2]; /* Number of packer per line calculate*/
	unsigned long poss_NPL[2]; /* Number of packer per line possible*/
	unsigned long max_bitRate_2[2],max_bitRate_8[2];
	unsigned long h_refresh, audio_freq;
	unsigned char input;
	int i,j,pix_rep;
#endif
	cea_extension_t *temp_cea = NULL ;

	EMGD_TRACE_ENTER;
	/* Only calculate eld for HDMI port */
	if((port->pd_driver->type !=  PD_DISPLAY_HDMI_EXT &&
		port->pd_driver->type !=  PD_DISPLAY_HDMI_INT)){
		return 0;
	}
	if(port->firmware_type == PI_FIRMWARE_EDID){
		temp_cea = (cea_extension_t*)port->edid->cea;
	}
	/* Displayid unsupported for now. Uncomment this code when audio
	information is available for Display ID
	temp_cea = (&cea_extension_t)port->displayid->cea;*/

	if(temp_cea == NULL){
		/* CEA data unavailable, display does not have audio capability? */
		/* We would allocate dummy edid structure and here and we should ony
		   used canned ELD */
		if(port->edid == NULL) {
			port->edid = (edid_t *) OS_ALLOC(sizeof(edid_t));
			OS_MEMSET(port->edid, 0 , (sizeof(edid_t)));
		}

		port->edid->cea = (cea_extension_t *) OS_ALLOC(sizeof(cea_extension_t));
		OS_MEMSET(port->edid->cea, 0 , (sizeof(cea_extension_t)));
		port->edid->cea->canned_eld = 1;
		temp_cea = (cea_extension_t*)port->edid->cea;
		port->callback->eld = &(port->edid->cea);
	}

	/* Default to canned ELD data */
	temp_cea->LPCM_CAD[0] = 0x9;
	temp_cea->speaker_alloc_block[0] = 0x1;
	/* Default 0 Pixel replication */
	port->edid->cea->pixel_rep = PIX_REPLICATION_0;
	/* Default */
	port->edid->cea->colorimetry = HDMI_COLORIMETRY_NODATA;
	/* Default RGB 256 wuantization full range */
	port->edid->cea->quantization = HDMI_QUANTIZATION_RGB_256;
	/* Default Unknown video code */
	port->edid->cea->video_code = 0;
	port->edid->cea->aspect_ratio = (timing_info->mode_info_flags & PD_ASPECT_16_9)
	             ? PD_ASPECT_RATIO_16_9 : PD_ASPECT_RATIO_4_3;

#ifdef CALCULATE_ELD_INFOFRAMES
	calculate_infoframes(port,timing_info,temp_cea);
	/* If canned eld is not set and audio info from transmitter is available */
	if(temp_cea->canned_eld != 1 && (temp_cea->audio_flag & PD_AUDIO_CHAR_AVAIL)){
		pix_rep = port->edid->cea->pixel_rep;
		/*h_refresh = timing_info->dclk/timing_info->htotal;*/
		h_refresh = timing_info->refresh;
		cal_NPL[0] = (pix_rep*(timing_info->hsync_end - timing_info->hsync_start) -
					port->edid->cea->K0) /32;
		cal_NPL[1] = (pix_rep*(timing_info->hsync_end - timing_info->hsync_start) -
					port->edid->cea->K1) /32;

		poss_NPL[0] = MODE_MIN(cal_NPL[0],port->edid->cea->NPL);
		poss_NPL[1] = MODE_MIN(cal_NPL[1],port->edid->cea->NPL);

		max_bitRate_2[0] = h_refresh * poss_NPL[0] - 1500;
		max_bitRate_2[1] = h_refresh * poss_NPL[1] - 1500;

		max_bitRate_8[0] = h_refresh * poss_NPL[0] * 4 - 1500;
		max_bitRate_8[1] = h_refresh * poss_NPL[1] * 4 - 1500;

		/* Loop trough Content Protection disabled then enabled */
		for(i=0 ; i<2; i++){
			for(j=0 ; j<3; j++){
				input = 0;
				audio_freq = 48000 * (1<<j); /* 48Khz->96Khz->192Khz */
				if(max_bitRate_8[i] >= audio_freq){
					input = 7;
				}else if(max_bitRate_2[i] >= audio_freq){
					input = 1;
				}
				/* take the minimum value min(transmitter, receiver) */
				input = MODE_MIN(input,temp_cea->audio_cap[j].max_channels);
				temp_cea->LPCM_CAD[j] |= input<<((1-i)*3);
				if(temp_cea->audio_cap[j]._24bit){
					temp_cea->LPCM_CAD[j] |= BIT(7);
				}
				if(temp_cea->audio_cap[j]._20bit){
					temp_cea->LPCM_CAD[j] |= BIT(6);
				}
			}
		}

		/* TODO: Further construction of ELD from Monitor Name String begins here
		   for now we only support VSDB */
		/* By default we don send any vendor specific block unless latency value
		   use for audio sync feature is available */
		temp_cea->vsdbl = 0;
		/* This means the latecy field is available VSBD_LATENCY_FIELD = 8*/
		if(temp_cea->vendor_block.vendor_block_size > VSBD_LATENCY_FIELD){
			OS_MEMCPY(temp_cea->misc_data, temp_cea->vendor_data_block,
				temp_cea->vendor_block.vendor_block_size);
			temp_cea->vsdbl = temp_cea->vendor_block.vendor_block_size;
			/* If the VSBD has latency fields */
			if(*(temp_cea->vendor_data_block + VSBD_LATENCY_FIELD - 1) & 0x80){
				if(timing_info->mode_info_flags & IGD_SCAN_INTERLACE){
					if(*(temp_cea->vendor_data_block + VSBD_LATENCY_FIELD - 1) & 0x40){
						temp_cea->vendor_block.p_latency = 1;
						temp_cea->vendor_block.i_latency = 1;
					}else{
						/* No latency available: Since it is an interlace mode but no
						   vsbd_intlc_fld_present is available */
						temp_cea->vendor_block.p_latency = 0;
						temp_cea->vendor_block.i_latency = 0;
					}
				}else{
					temp_cea->vendor_block.p_latency = 1;
					temp_cea->vendor_block.i_latency = 0;
				}
			}
		}
	}
#endif /* CALCULATE_ELD_INFOFRAMES */
	temp_cea->audio_flag |= ELD_AVAIL;
	EMGD_TRACE_EXIT;
	return 0;
}
示例#15
0
/*!
 * Calculates infoframes information top be used by HDMI port drivers
 *
 * @param port
 * @param timing_info
 * @param temp_cea
 *
 * @return 0
 */
static int calculate_infoframes(
	igd_display_port_t *port,
	igd_timing_info_t *timing_info,
	cea_extension_t *temp_cea)
{

	pd_timing_t     *cea_timings = NULL, *cea_timing_temp = NULL;

	EMGD_TRACE_ENTER;

	/* VBIOS has no access to CEA timing tables and this is not supported
	   there as well */
	if(timing_info->mode_info_flags & PD_MODE_CEA){
		if(timing_info->width != 640 && timing_info->height != 480){
			port->edid->cea->quantization	= HDMI_QUANTIZATION_RGB_220;
		}

		/* Based on DPG algorithm. If monitors support more than 2 channels
		   for 192Khz or/and 92Khz then set two pixel repeat one.
		   KIV: Add pruning for pixel PIX_REPLICATION_3 if required  */
		if(temp_cea->audio_cap[CAP_192_KHZ].max_channels>2 ||
			temp_cea->audio_cap[CAP_96_KHZ].max_channels>2){
			port->edid->cea->pixel_rep = PIX_REPLICATION_1;
		}


		/* Based on HDMI spec 6.7.1 & 6.7.2 */
		if ((timing_info->width == 720) && ((timing_info->height == 480) ||
			 (timing_info->height== 576))){
			port->edid->cea->colorimetry	= HDMI_COLORIMETRY_ITU601;
		} else if(((timing_info->width==1280) && (timing_info->height==720)) ||
			((timing_info->width == 1920) && (timing_info->height == 1080))){
			port->edid->cea->colorimetry	= HDMI_COLORIMETRY_ITU709;
		}

		cea_timings = (igd_timing_info_t *) OS_ALLOC(cea_timing_table_size);
		OS_MEMCPY(cea_timings, cea_timing_table, cea_timing_table_size);
		cea_timing_temp = cea_timings;

		while (cea_timings->width != IGD_TIMING_TABLE_END){
			if(cea_timings->width == timing_info->width &&
			   cea_timings->height == timing_info->height &&
			   cea_timings->refresh == timing_info->refresh &&
			   cea_timings->dclk == timing_info->dclk &&
			   (cea_timings->mode_info_flags &
			   (PD_ASPECT_16_9| IGD_SCAN_INTERLACE)) ==
			   (timing_info->mode_info_flags &
			   (PD_ASPECT_16_9| IGD_SCAN_INTERLACE))){
					port->edid->cea->video_code		= cea_timings->mode_number;
					break;
				}
			cea_timings++;
		}

		OS_FREE(cea_timing_temp);

	}

	EMGD_TRACE_EXIT;
	return 0;
}
示例#16
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() */