static int thermal_hot_pm_notify(struct notifier_block *nb, unsigned long event,
	void *dummy)
{
    static gctUINT orgFscale, minFscale, maxFscale;
    static gctBOOL bAlreadyTooHot = gcvFALSE;
    gckHARDWARE hardware = galDevice->kernels[gcvCORE_MAJOR]->hardware;

    if (event && !bAlreadyTooHot) {
        gckHARDWARE_GetFscaleValue(hardware,&orgFscale,&minFscale, &maxFscale);
        gckHARDWARE_SetFscaleValue(hardware, minFscale);
        bAlreadyTooHot = gcvTRUE;
        gckOS_Print("System is too hot. GPU3D will work at %d/64 clock.\n", minFscale);
    } else if (!event && bAlreadyTooHot) {
        gckHARDWARE_SetFscaleValue(hardware, orgFscale);
        gckOS_Print("Hot alarm is canceled. GPU3D clock will return to %d/64\n", orgFscale);
        bAlreadyTooHot = gcvFALSE;
    }
    return NOTIFY_OK;
}
gceSTATUS
_SetPower(
    IN gckPLATFORM Platform,
    IN gceCORE GPU,
    IN gctBOOL Enable
    )
{
    struct imx_priv* priv = Platform->priv;
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
    int ret;
#endif
#endif

    if (Enable)
    {
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
        if(!IS_ERR(priv->gpu_regulator)) {
            ret = regulator_enable(priv->gpu_regulator);
            if (ret != 0)
                gckOS_Print("%s(%d): fail to enable pu regulator %d!\n",
                    __FUNCTION__, __LINE__, ret);
        }
#else
        imx_gpc_power_up_pu(true);
#endif
#endif

#ifdef CONFIG_PM
		pm_runtime_get_sync(priv->pmdev);
#endif
	}
    else
    {
#ifdef CONFIG_PM
        pm_runtime_put_sync(priv->pmdev);
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
        if(!IS_ERR(priv->gpu_regulator))
            regulator_disable(priv->gpu_regulator);
#else
        imx_gpc_power_up_pu(false);
#endif
#endif

    }

    return gcvSTATUS_OK;
}
static int thermal_hot_pm_notify(struct notifier_block *nb, unsigned long event,
       void *dummy)
{
    static gctUINT orgFscale, minFscale, maxFscale;
    static gctBOOL bAlreadyTooHot = gcvFALSE;
    gckHARDWARE hardware;
    gckGALDEVICE galDevice;

    galDevice = platform_get_drvdata(pdevice);
    if (!galDevice)
    {
        /* GPU is not ready, so it is meaningless to change GPU freq. */
        return NOTIFY_OK;
    }

    if (!galDevice->kernels[gcvCORE_MAJOR])
    {
        return NOTIFY_OK;
    }

    hardware = galDevice->kernels[gcvCORE_MAJOR]->hardware;

    if (!hardware)
    {
        return NOTIFY_OK;
    }

    if (event && !bAlreadyTooHot) {
        gckHARDWARE_GetFscaleValue(hardware,&orgFscale,&minFscale, &maxFscale);
        gckHARDWARE_SetFscaleValue(hardware, minFscale);
        bAlreadyTooHot = gcvTRUE;
        gckOS_Print("System is too hot. GPU3D will work at %d/64 clock.\n", minFscale);
    } else if (!event && bAlreadyTooHot) {
        gckHARDWARE_SetFscaleValue(hardware, orgFscale);
        gckOS_Print("Hot alarm is canceled. GPU3D clock will return to %d/64\n", orgFscale);
        bAlreadyTooHot = gcvFALSE;
    }
    return NOTIFY_OK;
}
static int thermal_hot_pm_notify(struct notifier_block *nb, unsigned long event,
	void *dummy)
{
    static gctUINT orgFscale, minFscale, maxFscale;
    static gctBOOL critical;
    gckHARDWARE hardware = galDevice->kernels[gcvCORE_MAJOR]->hardware;

    if (event > 4) {
	critical = gcvTRUE;
        gckHARDWARE_GetFscaleValue(hardware,&orgFscale,&minFscale, &maxFscale);
        gckHARDWARE_SetFscaleValue(hardware, minFscale);
        gckOS_Print("System is too hot. GPU3D scalign to %d/64 clock.\n", minFscale);
    } else if (event > 1) {
        gckHARDWARE_GetFscaleValue(hardware,&orgFscale,&minFscale, &maxFscale);
        gckHARDWARE_SetFscaleValue(hardware, maxFscale - (8 * event));
    } else if (orgFscale) {
        gckHARDWARE_SetFscaleValue(hardware, orgFscale);
	if (critical) {
            gckOS_Print("Hot alarm is canceled. GPU3D clock will return to %d/64\n", orgFscale);
            critical = gcvFALSE;
        }
    }
    return NOTIFY_OK;
}
gceSTATUS
_GetPower(
    IN gckPLATFORM Platform
    )
{
    struct device* pdev = &Platform->device->dev;
    struct imx_priv *priv = Platform->priv;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
    struct reset_control *rstc;
#endif

#ifdef CONFIG_PM
    /*Init runtime pm for gpu*/
    pm_runtime_enable(pdev);
    priv->pmdev = pdev;
#endif


#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
    rstc = devm_reset_control_get(pdev, "gpu3d");
    priv->rstc[gcvCORE_MAJOR] = IS_ERR(rstc) ? NULL : rstc;
    rstc = devm_reset_control_get(pdev, "gpu2d");
    priv->rstc[gcvCORE_2D] = IS_ERR(rstc) ? NULL : rstc;
    rstc = devm_reset_control_get(pdev, "gpuvg");
    priv->rstc[gcvCORE_VG] = IS_ERR(rstc) ? NULL : rstc;
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
    /*get gpu regulator*/
    priv->gpu_regulator = regulator_get(pdev, "cpu_vddgpu");
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
    priv->gpu_regulator = devm_regulator_get(pdev, "pu");
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
    if (IS_ERR(priv->gpu_regulator)) {
       gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER,
               "%s(%d): Failed to get gpu regulator \n",
               __FUNCTION__, __LINE__);
       return gcvSTATUS_NOT_FOUND;
    }
#endif
#endif

    /*Initialize the clock structure*/
    priv->clk_3d_core = clk_get(pdev, "gpu3d_clk");
    if (!IS_ERR(priv->clk_3d_core)) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
        if (cpu_is_mx6q()) {
               priv->clk_3d_shader = clk_get(pdev, "gpu3d_shader_clk");
               if (IS_ERR(priv->clk_3d_shader)) {
                   clk_put(priv->clk_3d_core);
                   priv->clk_3d_core = NULL;
                   priv->clk_3d_shader = NULL;
                   gckOS_Print("galcore: clk_get gpu3d_shader_clk failed, disable 3d!\n");
               }
             }
#else
               priv->clk_3d_axi = clk_get(pdev, "gpu3d_axi_clk");
               priv->clk_3d_shader = clk_get(pdev, "gpu3d_shader_clk");
               if (IS_ERR(priv->clk_3d_shader)) {
                   clk_put(priv->clk_3d_core);
                   priv->clk_3d_core = NULL;
                   priv->clk_3d_shader = NULL;
                   gckOS_Print("galcore: clk_get gpu3d_shader_clk failed, disable 3d!\n");
               }
#endif
    } else {
        priv->clk_3d_core = NULL;
        gckOS_Print("galcore: clk_get gpu3d_clk failed, disable 3d!\n");
    }

    priv->clk_2d_core = clk_get(pdev, "gpu2d_clk");
    if (IS_ERR(priv->clk_2d_core)) {
        priv->clk_2d_core = NULL;
        gckOS_Print("galcore: clk_get 2d core clock failed, disable 2d/vg!\n");
    } else {
        priv->clk_2d_axi = clk_get(pdev, "gpu2d_axi_clk");
        if (IS_ERR(priv->clk_2d_axi)) {
            priv->clk_2d_axi = NULL;
            gckOS_Print("galcore: clk_get 2d axi clock failed, disable 2d\n");
        }

        priv->clk_vg_axi = clk_get(pdev, "openvg_axi_clk");
        if (IS_ERR(priv->clk_vg_axi)) {
               priv->clk_vg_axi = NULL;
               gckOS_Print("galcore: clk_get vg clock failed, disable vg!\n");
        }
    }


#if gcdENABLE_FSCALE_VAL_ADJUST
    pdevice = Platform->device;
    REG_THERMAL_NOTIFIER(&thermal_hot_pm_notifier);
    {
        int ret = 0;
        ret = driver_create_file(pdevice->dev.driver, &driver_attr_gpu3DMinClock);
        if(ret)
            dev_err(&pdevice->dev, "create gpu3DMinClock attr failed (%d)\n", ret);
    }
#endif

#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
    imx6sx_optimize_qosc_for_GPU(Platform);
#endif
    return gcvSTATUS_OK;
}
gceSTATUS
gckPLATFORM_AdjustParam(
    IN gckPLATFORM Platform,
    OUT gcsMODULE_PARAMETERS *Args
    )
{
     struct resource* res;
     struct platform_device* pdev = Platform->device;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
       struct device_node *dn =pdev->dev.of_node;
       const u32 *prop;
#else
       struct viv_gpu_platform_data *pdata;
#endif

    res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phys_baseaddr");
    if (res)
        Args->baseAddress = res->start;

    res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_3d");
    if (res)
        Args->irqLine = res->start;

    res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_3d");
    if (res)
    {
        Args->registerMemBase = res->start;
        Args->registerMemSize = res->end - res->start + 1;
    }

    res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_2d");
    if (res)
        Args->irqLine2D = res->start;

    res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_2d");
    if (res)
    {
        Args->registerMemBase2D = res->start;
        Args->registerMemSize2D = res->end - res->start + 1;
    }

    res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_vg");
    if (res)
        Args->irqLineVG = res->start;

    res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_vg");
    if (res)
    {
        Args->registerMemBaseVG = res->start;
        Args->registerMemSizeVG = res->end - res->start + 1;
    }

#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
       Args->contiguousBase = 0;
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
       prop = of_get_property(dn, "contiguousbase", NULL);
       if(prop)
               Args->contiguousBase = *prop;
       of_property_read_u32(dn,"contiguoussize", (u32 *)&contiguousSize);
#else
    pdata = pdev->dev.platform_data;
    if (pdata) {
        Args->contiguousBase = pdata->reserved_mem_base;
       Args->contiguousSize = pdata->reserved_mem_size;
     }
#endif
    if (Args->contiguousSize == 0)
       gckOS_Print("Warning: No contiguous memory is reserverd for gpu.!\n ");

    Args->gpu3DMinClock = initgpu3DMinClock;

  if(Args->physSize == 0)
    Args->physSize = 0x80000000;

    return gcvSTATUS_OK;
}
static int force_contiguous_lowmem_shrink(IN gckKERNEL Kernel)
{
	struct task_struct *p;
	struct task_struct *selected = NULL;
	int tasksize;
        int ret = -1;
	int min_adj = 0;
	int selected_tasksize = 0;
	int selected_oom_adj;
	/*
	 * If we already have a death outstanding, then
	 * bail out right away; indicating to vmscan
	 * that we have nothing further to offer on
	 * this pass.
	 *
	 */
	if (lowmem_deathpending &&
	    time_before_eq(jiffies, lowmem_deathpending_timeout))
		return 0;
	selected_oom_adj = min_adj;

       rcu_read_lock();
	for_each_process(p) {
		struct mm_struct *mm;
		struct signal_struct *sig;
                gcuDATABASE_INFO info;
		int oom_adj;

		task_lock(p);
		mm = p->mm;
		sig = p->signal;
		if (!mm || !sig) {
			task_unlock(p);
			continue;
		}
		oom_adj = sig->oom_score_adj;
		if (oom_adj < min_adj) {
			task_unlock(p);
			continue;
		}

		tasksize = 0;
		task_unlock(p);
               rcu_read_unlock();

		if (gckKERNEL_QueryProcessDB(Kernel, p->pid, gcvFALSE, gcvDB_VIDEO_MEMORY, &info) == gcvSTATUS_OK){
			tasksize += info.counters.bytes / PAGE_SIZE;
		}
		if (gckKERNEL_QueryProcessDB(Kernel, p->pid, gcvFALSE, gcvDB_CONTIGUOUS, &info) == gcvSTATUS_OK){
			tasksize += info.counters.bytes / PAGE_SIZE;
		}

               rcu_read_lock();

		if (tasksize <= 0)
			continue;

		gckOS_Print("<gpu> pid %d (%s), adj %d, size %d \n", p->pid, p->comm, oom_adj, tasksize);

		if (selected) {
			if (oom_adj < selected_oom_adj)
				continue;
			if (oom_adj == selected_oom_adj &&
			    tasksize <= selected_tasksize)
				continue;
		}
		selected = p;
		selected_tasksize = tasksize;
		selected_oom_adj = oom_adj;
	}
	if (selected) {
		gckOS_Print("<gpu> send sigkill to %d (%s), adj %d, size %d\n",
			     selected->pid, selected->comm,
			     selected_oom_adj, selected_tasksize);
		lowmem_deathpending = selected;
		lowmem_deathpending_timeout = jiffies + HZ;
		force_sig(SIGKILL, selected);
		ret = 0;
	}
       rcu_read_unlock();
	return ret;
}
/*******************************************************************************
**
**  gckGALDEVICE_Construct
**
**  Constructor.
**
**  INPUT:
**
**  OUTPUT:
**
**      gckGALDEVICE * Device
**          Pointer to a variable receiving the gckGALDEVICE object pointer on
**          success.
*/
gceSTATUS
gckGALDEVICE_Construct(
    IN gctINT IrqLine,
    IN gctUINT32 RegisterMemBase,
    IN gctSIZE_T RegisterMemSize,
    IN gctINT IrqLine2D,
    IN gctUINT32 RegisterMemBase2D,
    IN gctSIZE_T RegisterMemSize2D,
    IN gctINT IrqLineVG,
    IN gctUINT32 RegisterMemBaseVG,
    IN gctSIZE_T RegisterMemSizeVG,
    IN gctUINT32 ContiguousBase,
    IN gctSIZE_T ContiguousSize,
    IN gctSIZE_T BankSize,
    IN gctINT FastClear,
    IN gctINT Compression,
    IN gctUINT32 PhysBaseAddr,
    IN gctUINT32 PhysSize,
    IN gctINT Signal,
    IN gctUINT LogFileSize,
    IN struct device *pdev,
    IN gctINT PowerManagement,
    OUT gckGALDEVICE *Device
    )
{
    gctUINT32 internalBaseAddress = 0, internalAlignment = 0;
    gctUINT32 externalBaseAddress = 0, externalAlignment = 0;
    gctUINT32 horizontalTileSize, verticalTileSize;
    struct resource* mem_region;
    gctUINT32 physAddr;
    gctUINT32 physical;
    gckGALDEVICE device;
    gceSTATUS status;
    gctINT32 i;
    gceHARDWARE_TYPE type;
    gckDB sharedDB = gcvNULL;
    gckKERNEL kernel = gcvNULL;

    gcmkHEADER_ARG("IrqLine=%d RegisterMemBase=0x%08x RegisterMemSize=%u "
                   "IrqLine2D=%d RegisterMemBase2D=0x%08x RegisterMemSize2D=%u "
                   "IrqLineVG=%d RegisterMemBaseVG=0x%08x RegisterMemSizeVG=%u "
                   "ContiguousBase=0x%08x ContiguousSize=%lu BankSize=%lu "
                   "FastClear=%d Compression=%d PhysBaseAddr=0x%x PhysSize=%d Signal=%d",
                   IrqLine, RegisterMemBase, RegisterMemSize,
                   IrqLine2D, RegisterMemBase2D, RegisterMemSize2D,
                   IrqLineVG, RegisterMemBaseVG, RegisterMemSizeVG,
                   ContiguousBase, ContiguousSize, BankSize, FastClear, Compression,
                   PhysBaseAddr, PhysSize, Signal);

    /* Allocate device structure. */
    device = kmalloc(sizeof(struct _gckGALDEVICE), GFP_KERNEL | __GFP_NOWARN);

    if (!device)
    {
        gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
    }

    memset(device, 0, sizeof(struct _gckGALDEVICE));

   device->dbgnode = gcvNULL;
   if(LogFileSize != 0)
   {
	if(gckDebugFileSystemCreateNode(LogFileSize,PARENT_FILE,DEBUG_FILE,&(device->dbgnode)) != 0)
	{
		gcmkTRACE_ZONE(
		gcvLEVEL_ERROR, gcvZONE_DRIVER,
		"%s(%d): Failed to create  the debug file system  %s/%s \n",
		__FUNCTION__, __LINE__,
		PARENT_FILE, DEBUG_FILE
		);
	}
	else
	{
		/*Everything is OK*/
	 	gckDebugFileSystemSetCurrentNode(device->dbgnode);
	}
    }
#ifdef CONFIG_PM
    /*Init runtime pm for gpu*/
    pm_runtime_enable(pdev);
    device->pmdev = pdev;
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
    /*get gpu regulator*/
    device->gpu_regulator = regulator_get(pdev, "cpu_vddgpu");
    if (IS_ERR(device->gpu_regulator)) {
	gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER,
		"%s(%d): Failed to get gpu regulator  %s/%s \n",
		__FUNCTION__, __LINE__,
		PARENT_FILE, DEBUG_FILE);
	gcmkONERROR(gcvSTATUS_NOT_FOUND);
    }
#endif
    /*Initialize the clock structure*/
    if (IrqLine != -1) {
        device->clk_3d_core = clk_get(pdev, "gpu3d_clk");
        if (!IS_ERR(device->clk_3d_core)) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
            if (cpu_is_mx6q()) {
	            device->clk_3d_shader = clk_get(pdev, "gpu3d_shader_clk");
	            if (IS_ERR(device->clk_3d_shader)) {
	                IrqLine = -1;
	                clk_put(device->clk_3d_core);
	                device->clk_3d_core = NULL;
	                device->clk_3d_shader = NULL;
	                gckOS_Print("galcore: clk_get gpu3d_shader_clk failed, disable 3d!\n");
	            }
	          }
#else
	            device->clk_3d_axi = clk_get(pdev, "gpu3d_axi_clk");
	            device->clk_3d_shader = clk_get(pdev, "gpu3d_shader_clk");
	            if (IS_ERR(device->clk_3d_shader)) {
	                IrqLine = -1;
	                clk_put(device->clk_3d_core);
	                device->clk_3d_core = NULL;
	                device->clk_3d_shader = NULL;
	                gckOS_Print("galcore: clk_get gpu3d_shader_clk failed, disable 3d!\n");
	            }
#endif
        } else {
            IrqLine = -1;
            device->clk_3d_core = NULL;
            gckOS_Print("galcore: clk_get gpu3d_clk failed, disable 3d!\n");
        }
    }
    if ((IrqLine2D != -1) || (IrqLineVG != -1)) {
        device->clk_2d_core = clk_get(pdev, "gpu2d_clk");
        if (IS_ERR(device->clk_2d_core)) {
            IrqLine2D = -1;
            IrqLineVG = -1;
            device->clk_2d_core = NULL;
            gckOS_Print("galcore: clk_get 2d core clock failed, disable 2d/vg!\n");
        } else {
	    if (IrqLine2D != -1) {
                device->clk_2d_axi = clk_get(pdev, "gpu2d_axi_clk");
                if (IS_ERR(device->clk_2d_axi)) {
                    device->clk_2d_axi = NULL;
                    IrqLine2D = -1;
                    gckOS_Print("galcore: clk_get 2d axi clock failed, disable 2d\n");
                }
            }
            if (IrqLineVG != -1) {
                device->clk_vg_axi = clk_get(pdev, "openvg_axi_clk");
                if (IS_ERR(device->clk_vg_axi)) {
                    IrqLineVG = -1;
	                device->clk_vg_axi = NULL;
	                gckOS_Print("galcore: clk_get vg clock failed, disable vg!\n");
                }
            }
        }
    }

    if (IrqLine != -1)
    {
        device->requestedRegisterMemBases[gcvCORE_MAJOR]    = RegisterMemBase;
        device->requestedRegisterMemSizes[gcvCORE_MAJOR]    = RegisterMemSize;
    }

    if (IrqLine2D != -1)
    {
        device->requestedRegisterMemBases[gcvCORE_2D]       = RegisterMemBase2D;
        device->requestedRegisterMemSizes[gcvCORE_2D]       = RegisterMemSize2D;
    }

    if (IrqLineVG != -1)
    {
        device->requestedRegisterMemBases[gcvCORE_VG]       = RegisterMemBaseVG;
        device->requestedRegisterMemSizes[gcvCORE_VG]       = RegisterMemSizeVG;
    }

    device->requestedContiguousBase  = 0;
    device->requestedContiguousSize  = 0;


    for (i = 0; i < gcdMAX_GPU_COUNT; i++)
    {
        physical = device->requestedRegisterMemBases[i];

        /* Set up register memory region. */
        if (physical != 0)
        {
            mem_region = request_mem_region(
                physical, device->requestedRegisterMemSizes[i], "galcore register region"
                );

            if (mem_region == gcvNULL)
            {
                gcmkTRACE_ZONE(
                    gcvLEVEL_ERROR, gcvZONE_DRIVER,
                    "%s(%d): Failed to claim %lu bytes @ 0x%08X\n",
                    __FUNCTION__, __LINE__,
                    physical, device->requestedRegisterMemSizes[i]
                    );

                gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
            }

            device->registerBases[i] = (gctPOINTER) ioremap_nocache(
                physical, device->requestedRegisterMemSizes[i]);

            if (device->registerBases[i] == gcvNULL)
            {
                gcmkTRACE_ZONE(
                    gcvLEVEL_ERROR, gcvZONE_DRIVER,
                    "%s(%d): Unable to map %ld bytes @ 0x%08X\n",
                    __FUNCTION__, __LINE__,
                    physical, device->requestedRegisterMemSizes[i]
                    );

                gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
            }

            physical += device->requestedRegisterMemSizes[i];
        }
        else
        {
            device->registerBases[i] = gcvNULL;
        }
    }

    /* Set the base address */
    device->baseAddress = PhysBaseAddr;

    /* Construct the gckOS object. */
    gcmkONERROR(gckOS_Construct(device, &device->os));

    if (IrqLine != -1)
    {
        /* Construct the gckKERNEL object. */
        gcmkONERROR(gckKERNEL_Construct(
            device->os, gcvCORE_MAJOR, device,
            gcvNULL, &device->kernels[gcvCORE_MAJOR]));

        sharedDB = device->kernels[gcvCORE_MAJOR]->db;

        /* Initialize core mapping */
        for (i = 0; i < 8; i++)
        {
            device->coreMapping[i] = gcvCORE_MAJOR;
        }

        /* Setup the ISR manager. */
        gcmkONERROR(gckHARDWARE_SetIsrManager(
            device->kernels[gcvCORE_MAJOR]->hardware,
            (gctISRMANAGERFUNC) gckGALDEVICE_Setup_ISR,
            (gctISRMANAGERFUNC) gckGALDEVICE_Release_ISR,
            device
            ));

        gcmkONERROR(gckHARDWARE_SetFastClear(
            device->kernels[gcvCORE_MAJOR]->hardware, FastClear, Compression
            ));

        gcmkONERROR(gckHARDWARE_SetPowerManagement(
            device->kernels[gcvCORE_MAJOR]->hardware, PowerManagement
            ));

#if COMMAND_PROCESSOR_VERSION == 1
        /* Start the command queue. */
        gcmkONERROR(gckCOMMAND_Start(device->kernels[gcvCORE_MAJOR]->command));
#endif
    }
    else
    {
        device->kernels[gcvCORE_MAJOR] = gcvNULL;
    }

    if (IrqLine2D != -1)
    {
        gcmkONERROR(gckKERNEL_Construct(
            device->os, gcvCORE_2D, device,
            sharedDB, &device->kernels[gcvCORE_2D]));

        if (sharedDB == gcvNULL) sharedDB = device->kernels[gcvCORE_2D]->db;

        /* Verify the hardware type */
        gcmkONERROR(gckHARDWARE_GetType(device->kernels[gcvCORE_2D]->hardware, &type));

        if (type != gcvHARDWARE_2D)
        {
            gcmkTRACE_ZONE(
                gcvLEVEL_ERROR, gcvZONE_DRIVER,
                "%s(%d): Unexpected hardware type: %d\n",
                __FUNCTION__, __LINE__,
                type
                );

            gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
        }

        /* Initialize core mapping */
        if (device->kernels[gcvCORE_MAJOR] == gcvNULL)
        {
            for (i = 0; i < 8; i++)
            {
                device->coreMapping[i] = gcvCORE_2D;
            }
        }
        else
        {
            device->coreMapping[gcvHARDWARE_2D] = gcvCORE_2D;
        }

        /* Setup the ISR manager. */
        gcmkONERROR(gckHARDWARE_SetIsrManager(
            device->kernels[gcvCORE_2D]->hardware,
            (gctISRMANAGERFUNC) gckGALDEVICE_Setup_ISR_2D,
            (gctISRMANAGERFUNC) gckGALDEVICE_Release_ISR_2D,
            device
            ));

        gcmkONERROR(gckHARDWARE_SetPowerManagement(
            device->kernels[gcvCORE_2D]->hardware, PowerManagement
            ));

#if COMMAND_PROCESSOR_VERSION == 1
        /* Start the command queue. */
        gcmkONERROR(gckCOMMAND_Start(device->kernels[gcvCORE_2D]->command));
#endif
    }
    else
    {
        device->kernels[gcvCORE_2D] = gcvNULL;
    }

    if (IrqLineVG != -1)
    {
#if gcdENABLE_VG
        gcmkONERROR(gckKERNEL_Construct(
            device->os, gcvCORE_VG, device,
            sharedDB, &device->kernels[gcvCORE_VG]));
        /* Initialize core mapping */
        if (device->kernels[gcvCORE_MAJOR] == gcvNULL
            && device->kernels[gcvCORE_2D] == gcvNULL
            )
        {
            for (i = 0; i < 8; i++)
            {
                device->coreMapping[i] = gcvCORE_VG;
            }
        }
        else
        {
            device->coreMapping[gcvHARDWARE_VG] = gcvCORE_VG;
        }


        gcmkONERROR(gckVGHARDWARE_SetPowerManagement(
            device->kernels[gcvCORE_VG]->vg->hardware,
            PowerManagement
            ));
#endif
    }
    else
    {
        device->kernels[gcvCORE_VG] = gcvNULL;
    }

    /* Initialize the ISR. */
    device->irqLines[gcvCORE_MAJOR] = IrqLine;
    device->irqLines[gcvCORE_2D]    = IrqLine2D;
    device->irqLines[gcvCORE_VG]    = IrqLineVG;

    /* Initialize the kernel thread semaphores. */
    for (i = 0; i < gcdMAX_GPU_COUNT; i++)
    {
        if (device->irqLines[i] != -1) sema_init(&device->semas[i], 0);
    }

    device->signal = Signal;

    for (i = 0; i < gcdMAX_GPU_COUNT; i++)
    {
        if (device->kernels[i] != gcvNULL) break;
    }

    if (i == gcdMAX_GPU_COUNT)
	{
		gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
	}

#if gcdENABLE_VG
    if (i == gcvCORE_VG)
    {
        /* Query the ceiling of the system memory. */
        gcmkONERROR(gckVGHARDWARE_QuerySystemMemory(
                device->kernels[i]->vg->hardware,
                &device->systemMemorySize,
                &device->systemMemoryBaseAddress
                ));
            /* query the amount of video memory */
        gcmkONERROR(gckVGHARDWARE_QueryMemory(
            device->kernels[i]->vg->hardware,
            &device->internalSize, &internalBaseAddress, &internalAlignment,
            &device->externalSize, &externalBaseAddress, &externalAlignment,
            &horizontalTileSize, &verticalTileSize
            ));
    }
    else
#endif
    {
        /* Query the ceiling of the system memory. */
        gcmkONERROR(gckHARDWARE_QuerySystemMemory(
                device->kernels[i]->hardware,
                &device->systemMemorySize,
                &device->systemMemoryBaseAddress
                ));

            /* query the amount of video memory */
        gcmkONERROR(gckHARDWARE_QueryMemory(
            device->kernels[i]->hardware,
            &device->internalSize, &internalBaseAddress, &internalAlignment,
            &device->externalSize, &externalBaseAddress, &externalAlignment,
            &horizontalTileSize, &verticalTileSize
            ));
    }


    /* Grab the first availiable kernel */
    for (i = 0; i < gcdMAX_GPU_COUNT; i++)
    {
        if (device->irqLines[i] != -1)
        {
            kernel = device->kernels[i];
            break;
        }
    }

    /* Set up the internal memory region. */
    if (device->internalSize > 0)
    {
        status = gckVIDMEM_Construct(
            device->os,
            internalBaseAddress, device->internalSize, internalAlignment,
            0, &device->internalVidMem
            );

        if (gcmIS_ERROR(status))
        {
            /* Error, disable internal heap. */
            device->internalSize = 0;
        }
        else
        {
            /* Map internal memory. */
            device->internalLogical
                = (gctPOINTER) ioremap_nocache(physical, device->internalSize);

            if (device->internalLogical == gcvNULL)
            {
                gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
            }

            device->internalPhysical = (gctPHYS_ADDR)(gctUINTPTR_T) physical;
            device->internalPhysicalName = gcmPTR_TO_NAME(device->internalPhysical);
            physical += device->internalSize;
        }
    }

    if (device->externalSize > 0)
    {
        /* create the external memory heap */
        status = gckVIDMEM_Construct(
            device->os,
            externalBaseAddress, device->externalSize, externalAlignment,
            0, &device->externalVidMem
            );

        if (gcmIS_ERROR(status))
        {
            /* Error, disable internal heap. */
            device->externalSize = 0;
        }
        else
        {
            /* Map external memory. */
            device->externalLogical
                = (gctPOINTER) ioremap_nocache(physical, device->externalSize);

            if (device->externalLogical == gcvNULL)
            {
                gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
            }

            device->externalPhysical = (gctPHYS_ADDR)(gctUINTPTR_T) physical;
            device->externalPhysicalName = gcmPTR_TO_NAME(device->externalPhysical);
            physical += device->externalSize;
        }
    }

    /* set up the contiguous memory */
    device->contiguousSize = ContiguousSize;

    if (ContiguousSize > 0)
    {
        if (ContiguousBase == 0)
        {
            while (device->contiguousSize > 0)
            {
                /* Allocate contiguous memory. */
                status = _AllocateMemory(
                    device,
                    device->contiguousSize,
                    &device->contiguousBase,
                    &device->contiguousPhysical,
                    &physAddr
                    );

                if (gcmIS_SUCCESS(status))
                {
                    device->contiguousPhysicalName = gcmPTR_TO_NAME(device->contiguousPhysical);
                    status = gckVIDMEM_Construct(
                        device->os,
                        physAddr | device->systemMemoryBaseAddress,
                        device->contiguousSize,
                        64,
                        BankSize,
                        &device->contiguousVidMem
                        );

                    if (gcmIS_SUCCESS(status))
                    {
                        break;
                    }

                    gcmkONERROR(_FreeMemory(
                        device,
                        device->contiguousBase,
                        device->contiguousPhysical
                        ));

                    gcmRELEASE_NAME(device->contiguousPhysicalName);
                    device->contiguousBase     = gcvNULL;
                    device->contiguousPhysical = gcvNULL;
                }

                if (device->contiguousSize <= (4 << 20))
                {
                    device->contiguousSize = 0;
                }
                else
                {
                    device->contiguousSize -= (4 << 20);
                }
            }
        }
        else
        {
            /* Create the contiguous memory heap. */
            status = gckVIDMEM_Construct(
                device->os,
                ContiguousBase | device->systemMemoryBaseAddress,
                ContiguousSize,
                64, BankSize,
                &device->contiguousVidMem
                );

            if (gcmIS_ERROR(status))
            {
                /* Error, disable contiguous memory pool. */
                device->contiguousVidMem = gcvNULL;
                device->contiguousSize   = 0;
            }
            else
            {
                mem_region = request_mem_region(
                    ContiguousBase, ContiguousSize, "galcore managed memory"
                    );

                if (mem_region == gcvNULL)
                {
                    gcmkTRACE_ZONE(
                        gcvLEVEL_ERROR, gcvZONE_DRIVER,
                        "%s(%d): Failed to claim %ld bytes @ 0x%08X\n",
                        __FUNCTION__, __LINE__,
                        ContiguousSize, ContiguousBase
                        );

                    gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
                }

                device->requestedContiguousBase  = ContiguousBase;
                device->requestedContiguousSize  = ContiguousSize;

#if !gcdDYNAMIC_MAP_RESERVED_MEMORY && gcdENABLE_VG
                if (gcmIS_CORE_PRESENT(device, gcvCORE_VG))
                {
                    device->contiguousBase
#if gcdPAGED_MEMORY_CACHEABLE
                        = (gctPOINTER) ioremap_cached(ContiguousBase, ContiguousSize);
#else
                        = (gctPOINTER) ioremap_nocache(ContiguousBase, ContiguousSize);
#endif
                    if (device->contiguousBase == gcvNULL)
                    {
                        device->contiguousVidMem = gcvNULL;
                        device->contiguousSize = 0;

                        gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
                    }
                }
#endif

                device->contiguousPhysical = gcvNULL;
                device->contiguousPhysicalName = 0;
                device->contiguousSize     = ContiguousSize;
                device->contiguousMapped   = gcvTRUE;
            }
        }
    }
static int __devinit gpu_probe(struct platform_device *pdev)
#endif
{
    int ret = -ENODEV;
    struct resource* res;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
	struct contiguous_mem_pool *pool;
	struct reset_control *rstc;
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
	struct device_node *dn =pdev->dev.of_node;
	const u32 *prop;
#else
	struct viv_gpu_platform_data *pdata;
#endif
    gcmkHEADER();

    res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phys_baseaddr");
    if (res)
        baseAddress = res->start;

    res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_3d");
    if (res)
        irqLine = res->start;

    res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_3d");
    if (res)
    {
        registerMemBase = res->start;
        registerMemSize = res->end - res->start + 1;
    }

    res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_2d");
    if (res)
        irqLine2D = res->start;

    res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_2d");
    if (res)
    {
        registerMemBase2D = res->start;
        registerMemSize2D = res->end - res->start + 1;
    }

    res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_vg");
    if (res)
        irqLineVG = res->start;

    res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_vg");
    if (res)
    {
        registerMemBaseVG = res->start;
        registerMemSizeVG = res->end - res->start + 1;
    }

#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
	pool = devm_kzalloc(&pdev->dev, sizeof(*pool), GFP_KERNEL);
	if (!pool)
		return -ENOMEM;
	pool->size = contiguousSize;
	init_dma_attrs(&pool->attrs);
	dma_set_attr(DMA_ATTR_WRITE_COMBINE, &pool->attrs);
	pool->virt = dma_alloc_attrs(&pdev->dev, pool->size, &pool->phys,
				     GFP_KERNEL, &pool->attrs);
	if (!pool->virt) {
		dev_err(&pdev->dev, "Failed to allocate contiguous memory\n");
		return -ENOMEM;
	}
	contiguousBase = pool->phys;
	dev_set_drvdata(&pdev->dev, pool);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
	prop = of_get_property(dn, "contiguousbase", NULL);
	if(prop)
		contiguousBase = *prop;
	of_property_read_u32(dn,"contiguoussize", (u32 *)&contiguousSize);
#else
    pdata = pdev->dev.platform_data;
    if (pdata) {
        contiguousBase = pdata->reserved_mem_base;
        contiguousSize = pdata->reserved_mem_size;
     }
#endif
    if (contiguousSize == 0)
       gckOS_Print("Warning: No contiguous memory is reserverd for gpu.!\n ");
    ret = drv_init(&pdev->dev);

    if (!ret)
    {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
	rstc = devm_reset_control_get(&pdev->dev, "gpu3d");
	galDevice->rstc[gcvCORE_MAJOR] = IS_ERR(rstc) ? NULL : rstc;

	rstc = devm_reset_control_get(&pdev->dev, "gpu2d");
	galDevice->rstc[gcvCORE_2D] = IS_ERR(rstc) ? NULL : rstc;

	rstc = devm_reset_control_get(&pdev->dev, "gpuvg");
	galDevice->rstc[gcvCORE_VG] = IS_ERR(rstc) ? NULL : rstc;
#endif
        platform_set_drvdata(pdev, galDevice);

#if gcdENABLE_FSCALE_VAL_ADJUST
        if (galDevice->kernels[gcvCORE_MAJOR])
            REG_THERMAL_NOTIFIER(&thermal_hot_pm_notifier);
#endif
        gcmkFOOTER_NO();
        return ret;
    }
#if gcdENABLE_FSCALE_VAL_ADJUST
    UNREG_THERMAL_NOTIFIER(&thermal_hot_pm_notifier);
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
	dma_free_attrs(&pdev->dev, pool->size, pool->virt, pool->phys,
		       &pool->attrs);
#endif
    gcmkFOOTER_ARG(KERN_INFO "Failed to register gpu driver: %d\n", ret);
    return ret;
}