static int s3c_g3d_resume(struct platform_device *pdev) { #ifndef USE_G3D_DOMAIN_GATING clk_g3d_enable(); #endif if(!g_G3D_CriticalFlag) { /*power on 3D PM right after 3D APIs are used*/ g_G3D_SelfPowerOFF=True; } return 0; }
static int s3c_g3d_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { u32 val; DMA_BLOCK_STRUCT dma_block; s3c_3d_dma_info dma_info; DECLARE_COMPLETION_ONSTACK(complete); struct mm_struct *mm = current->mm; struct s3c_3d_mem_alloc param; struct s3c_3d_pm_status param_pm; unsigned int timer; switch (cmd) { case WAIT_FOR_FLUSH: //if fifo has already been flushed, return; val = __raw_readl(s3c_g3d_base+FGGB_PIPESTATE); //printk("read pipestate = 0x%x\n",val); if((val & arg) ==0) break; // enable interrupt interrupt_already_recevied = 0; __raw_writel(0x0001171f,s3c_g3d_base+FGGB_PIPEMASK); __raw_writel(1,s3c_g3d_base+FGGB_INTMASK); //printk("wait for flush (arg=0x%lx)\n",arg); timer = 1000000; while(timer) { wait_event_interruptible_timeout(waitq, (interrupt_already_recevied>0), 1*HZ); __raw_writel(0,s3c_g3d_base+FGGB_INTMASK); interrupt_already_recevied = 0; //if(interrupt_already_recevied==0)interruptible_sleep_on(&waitq); val = __raw_readl(s3c_g3d_base+FGGB_PIPESTATE); //printk("in while read pipestate = 0x%x\n",val); if(val & arg){ } else{ break; } __raw_writel(1,s3c_g3d_base+FGGB_INTMASK); timer --; } break; case GET_CONFIG: if (copy_to_user((void *)arg,&g3d_config,sizeof(G3D_CONFIG_STRUCT))) { printk("G3D: copy_to_user failed to get g3d_config\n"); return -EFAULT; } break; case START_DMA_BLOCK: if (copy_from_user(&dma_block,(void *)arg,sizeof(DMA_BLOCK_STRUCT))) { printk("G3D: copy_to_user failed to get dma_block\n"); return -EFAULT; } if (dma_block.offset%4!=0) { printk("G3D: dma offset is not aligned by word\n"); return -EINVAL; } if (dma_block.size%4!=0) { printk("G3D: dma size is not aligned by word\n"); return -EINVAL; } if (dma_block.offset+dma_block.size >g3d_config.dma_buffer_size) { printk("G3D: offset+size exceeds dam buffer\n"); return -EINVAL; } dma_info.src = g3d_config.dma_buffer_addr+dma_block.offset; dma_info.len = dma_block.size; dma_info.dst = s3c_g3d_base_physical+FGGB_HOSTINTERFACE; DEBUG(" dma src=0x%x\n", dma_info.src); DEBUG(" dma len =%u\n", dma_info.len); DEBUG(" dma dst = 0x%x\n", dma_info.dst); dma_3d_done = &complete; if (s3c2410_dma_request(DMACH_3D_M2M, &s3c6410_3d_dma_client, NULL)) { printk(KERN_WARNING "Unable to get DMA channel(DMACH_3D_M2M).\n"); return -EFAULT; } s3c2410_dma_set_buffdone_fn(DMACH_3D_M2M, s3c_g3d_dma_finish); s3c2410_dma_devconfig(DMACH_3D_M2M, S3C_DMA_MEM2MEM, 1, (u_long) dma_info.src); s3c2410_dma_config(DMACH_3D_M2M, 4, 4); s3c2410_dma_setflags(DMACH_3D_M2M, S3C2410_DMAF_AUTOSTART); //consistent_sync((void *) dma_info.dst, dma_info.len, DMA_FROM_DEVICE); // s3c2410_dma_enqueue(DMACH_3D_M2M, NULL, (dma_addr_t) virt_to_dma(NULL, dma_info.dst), dma_info.len); s3c2410_dma_enqueue(DMACH_3D_M2M, NULL, (dma_addr_t) dma_info.dst, dma_info.len); // printk("wait for end of dma operation\n"); wait_for_completion(&complete); // printk("dma operation is performed\n"); s3c2410_dma_free(DMACH_3D_M2M, &s3c6410_3d_dma_client); break; case S3C_3D_MEM_ALLOC: mutex_lock(&mem_alloc_lock); if(copy_from_user(¶m, (struct s3c_3d_mem_alloc *)arg, sizeof(struct s3c_3d_mem_alloc))){ mutex_unlock(&mem_alloc_lock); return -EFAULT; } flag = MEM_ALLOC; param.size = s3c_g3d_available_chunk_size(param.size,(unsigned int)file->private_data); if (param.size == 0){ printk("S3C_3D_MEM_ALLOC FAILED because there is no block memory bigger than you request\n"); flag = 0; mutex_unlock(&mem_alloc_lock); return -EFAULT; } param.vir_addr = do_mmap(file, 0, param.size, PROT_READ|PROT_WRITE, MAP_SHARED, 0); DEBUG("param.vir_addr = %08x\n", param.vir_addr); if(param.vir_addr == -EINVAL) { printk("S3C_3D_MEM_ALLOC FAILED\n"); flag = 0; mutex_unlock(&mem_alloc_lock); return -EFAULT; } param.phy_addr = physical_address; // printk("alloc %d\n", param.size); DEBUG("KERNEL MALLOC : param.phy_addr = 0x%X \t size = %d \t param.vir_addr = 0x%X\n", param.phy_addr, param.size, param.vir_addr); if(copy_to_user((struct s3c_3d_mem_alloc *)arg, ¶m, sizeof(struct s3c_3d_mem_alloc))){ flag = 0; mutex_unlock(&mem_alloc_lock); return -EFAULT; } flag = 0; // printk("\n\n====Success the malloc from kernel=====\n"); mutex_unlock(&mem_alloc_lock); break; case S3C_3D_MEM_FREE: mutex_lock(&mem_free_lock); if(copy_from_user(¶m, (struct s3c_3d_mem_alloc *)arg, sizeof(struct s3c_3d_mem_alloc))){ mutex_unlock(&mem_free_lock); return -EFAULT; } DEBUG("KERNEL FREE : param.phy_addr = 0x%X \t size = %d \t param.vir_addr = 0x%X\n", param.phy_addr, param.size, param.vir_addr); /* if (do_munmap(mm, param.vir_addr, param.size) < 0) { printk("do_munmap() failed !!\n"); mutex_unlock(&mem_free_lock); return -EINVAL; } */ s3c_g3d_release_chunk(param.phy_addr, param.size); //printk("KERNEL : virt_addr = 0x%X\n", virt_addr); //printk("free %d\n", param.size); param.size = 0; DEBUG("do_munmap() succeed !!\n"); if(copy_to_user((struct s3c_3d_mem_alloc *)arg, ¶m, sizeof(struct s3c_3d_mem_alloc))){ mutex_unlock(&mem_free_lock); return -EFAULT; } mutex_unlock(&mem_free_lock); break; case S3C_3D_SFR_LOCK: mutex_lock(&mem_sfr_lock); mutex_lock_processID = (unsigned int)file->private_data; DEBUG("s3c_g3d_ioctl() : You got a muxtex lock !!\n"); break; case S3C_3D_SFR_UNLOCK: mutex_lock_processID = 0; mutex_unlock(&mem_sfr_lock); DEBUG("s3c_g3d_ioctl() : The muxtex unlock called !!\n"); break; case S3C_3D_MEM_ALLOC_SHARE: mutex_lock(&mem_alloc_share_lock); if(copy_from_user(¶m, (struct s3c_3d_mem_alloc *)arg, sizeof(struct s3c_3d_mem_alloc))){ mutex_unlock(&mem_alloc_share_lock); return -EFAULT; } flag = MEM_ALLOC_SHARE; physical_address = param.phy_addr; DEBUG("param.phy_addr = %08x\n", physical_address); param.vir_addr = do_mmap(file, 0, param.size, PROT_READ|PROT_WRITE, MAP_SHARED, 0); DEBUG("param.vir_addr = %08x\n", param.vir_addr); if(param.vir_addr == -EINVAL) { printk("S3C_3D_MEM_ALLOC_SHARE FAILED\n"); flag = 0; mutex_unlock(&mem_alloc_share_lock); return -EFAULT; } DEBUG("MALLOC_SHARE : param.phy_addr = 0x%X \t size = %d \t param.vir_addr = 0x%X\n", param.phy_addr, param.size, param.vir_addr); if(copy_to_user((struct s3c_3d_mem_alloc *)arg, ¶m, sizeof(struct s3c_3d_mem_alloc))){ flag = 0; mutex_unlock(&mem_alloc_share_lock); return -EFAULT; } flag = 0; mutex_unlock(&mem_alloc_share_lock); break; case S3C_3D_MEM_SHARE_FREE: mutex_lock(&mem_share_free_lock); if(copy_from_user(¶m, (struct s3c_3d_mem_alloc *)arg, sizeof(struct s3c_3d_mem_alloc))){ mutex_unlock(&mem_share_free_lock); return -EFAULT; } DEBUG("MEM_SHARE_FREE : param.phy_addr = 0x%X \t size = %d \t param.vir_addr = 0x%X\n", param.phy_addr, param.size, param.vir_addr); if (do_munmap(mm, param.vir_addr, param.size) < 0) { printk("do_munmap() failed - MEM_SHARE_FREE!!\n"); mutex_unlock(&mem_share_free_lock); return -EINVAL; } param.vir_addr = 0; DEBUG("do_munmap() succeed !! - MEM_SHARE_FREE\n"); if(copy_to_user((struct s3c_3d_mem_alloc *)arg, ¶m, sizeof(struct s3c_3d_mem_alloc))){ mutex_unlock(&mem_share_free_lock); return -EFAULT; } mutex_unlock(&mem_share_free_lock); break; case S3C_3D_CACHE_INVALID: mutex_lock(&cache_invalid_lock); if(copy_from_user(¶m, (struct s3c_3d_mem_alloc *)arg, sizeof(struct s3c_3d_mem_alloc))){ printk("ERR: Invalid Cache Error\n"); mutex_unlock(&cache_invalid_lock); return -EFAULT; } dmac_inv_range((unsigned int) param.vir_addr,(unsigned int)param.vir_addr + param.size); mutex_unlock(&cache_invalid_lock); break; case S3C_3D_CACHE_CLEAN: mutex_lock(&cache_clean_lock); if(copy_from_user(¶m, (struct s3c_3d_mem_alloc *)arg, sizeof(struct s3c_3d_mem_alloc))){ printk("ERR: Invalid Cache Error\n"); mutex_unlock(&cache_clean_lock); return -EFAULT; } dmac_clean_range((unsigned int) param.vir_addr,(unsigned int)param.vir_addr + param.size); mutex_unlock(&cache_clean_lock); break; case S3C_3D_CACHE_CLEAN_INVALID: mutex_lock(&cache_clean_invalid_lock); if(copy_from_user(¶m, (struct s3c_3d_mem_alloc *)arg, sizeof(struct s3c_3d_mem_alloc))){ mutex_unlock(&cache_clean_invalid_lock); printk("ERR: Invalid Cache Error\n"); return -EFAULT; } dmac_flush_range((unsigned int) param.vir_addr,(unsigned int)param.vir_addr + param.size); mutex_unlock(&cache_clean_invalid_lock); break; case S3C_3D_POWER_INIT: if(copy_from_user(¶m_pm, (struct s3c_3d_pm_status *)arg, sizeof(struct s3c_3d_pm_status))){ printk("ERR: Invalid Cache Error\n"); return -EFAULT; } break; case S3C_3D_CRITICAL_SECTION: #ifdef USE_G3D_DOMAIN_GATING mutex_lock(&pm_critical_section_lock); if(copy_from_user(¶m_pm, (struct s3c_3d_pm_status *)arg, sizeof(struct s3c_3d_pm_status))){ printk("ERR: Invalid Cache Error\n"); mutex_unlock(&pm_critical_section_lock); return -EFAULT; } // param_pm.memStatus = check_memStatus((unsigned int)file->private_data); if(param_pm.criticalSection) g_G3D_CriticalFlag++; else g_G3D_CriticalFlag--; if(g_G3D_CriticalFlag==0) {/*kick power off*/ /*power off*/ /*kick timer*/ mod_timer(&g3d_pm_timer, jiffies + TIMER_INTERVAL); } else if(g_G3D_CriticalFlag>0) {/*kick power on*/ if(domain_off_check(S3C64XX_DOMAIN_G)) {/*if powered off*/ if(g_G3D_SelfPowerOFF) {/*powered off by 3D PM or by Resume*/ /*power on*/ s3c_set_normal_cfg(S3C64XX_DOMAIN_G, S3C64XX_ACTIVE_MODE, S3C64XX_3D); if(s3c_wait_blk_pwr_ready(S3C64XX_BLK_G)) { printk("[3D] s3c_wait_blk_pwr_ready err\n"); mutex_unlock(&pm_critical_section_lock); return -EFAULT; } clk_g3d_enable(); /*Need here??*/ softReset_g3d(); // printk("[3D] Power on\n"); } else { /*powered off by the system :: error*/ printk("Error on the system :: app tries to work during sleep\n"); mutex_unlock(&pm_critical_section_lock); return -EFAULT; } } else { /*already powered on : nothing to do*/ //g_G3D_SelfPowerOFF=0; } } else if(g_G3D_CriticalFlag < 0) { printk("Error on the system :: g_G3D_CriticalFlag < 0\n"); } // printk("S3C_3D_CRITICAL_SECTION: param_pm.criticalSection=%d\n",param_pm.criticalSection); if (copy_to_user((void *)arg,¶m_pm,sizeof(struct s3c_3d_pm_status))) { printk("G3D: copy_to_user failed to get s3c_3d_pm_status\n"); mutex_unlock(&pm_critical_section_lock); return -EFAULT; } mutex_unlock(&pm_critical_section_lock); #endif /* USE_G3D_DOMAIN_GATING */ break; default: DEBUG("s3c_g3d_ioctl() : default !!\n"); return -EINVAL; } return 0; }
int s3c_g3d_probe(struct platform_device *pdev) { struct resource *res; int ret; int size; int i, loop_i; DEBUG("s3c_g3d probe() called\n"); #ifdef USE_G3D_DOMAIN_GATING s3c_set_normal_cfg(S3C64XX_DOMAIN_G, S3C64XX_ACTIVE_MODE, S3C64XX_3D); if(s3c_wait_blk_pwr_ready(S3C64XX_BLK_G)) { return -1; } #endif /* USE_G3D_DOMAIN_GATING */ g3d_clock = clk_get(&pdev->dev, "hclk_g3d"); if(g3d_clock == NULL) { printk(KERN_ERR PFX "failed to find post clock source\n"); ret = -ENOENT; goto err_clock; } clk_g3d_enable(); /* get the memory region for the post processor driver */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if(res == NULL) { printk(KERN_ERR PFX "failed to get memory region resouce\n"); ret = -ENOENT; goto err_mem; } s3c_g3d_base_physical = (unsigned int)res->start; size = (res->end-res->start)+1; s3c_g3d_mem = request_mem_region(res->start, size, pdev->name); if(s3c_g3d_mem == NULL) { printk(KERN_ERR PFX "failed to reserve memory region\n"); ret = -ENOENT; goto err_mem; } s3c_g3d_base = ioremap(res->start, size); if(s3c_g3d_base == NULL) { printk(KERN_ERR PFX "failed ioremap\n"); ret = -ENOENT; goto err_ioremap; } res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if(res == NULL) { printk(KERN_ERR PFX "failed to get irq resource\n"); ret = -ENOENT; goto err_irq; } s3c_g3d_irq = res->start; ret = request_irq(res->start, s3c_g3d_isr, 0, pdev->name, pdev); if (ret != 0) { printk(KERN_ERR PFX "failed to install irq (%d)\n", ret); goto err_irq; } init_waitqueue_head(&waitq); ret = misc_register(&s3c_g3d_dev); if (ret < 0) { printk (KERN_ERR "cannot register miscdev on minor=%d (%d)\n", G3D_MINOR, ret); goto err_misc_register; } #ifdef USE_G3D_DOMAIN_GATING /* init pm timer */ init_timer(&g3d_pm_timer); g3d_pm_timer.function = s3c_g3d_timer; #endif /* USE_G3D_DOMAIN_GATING */ /* device reset */ __raw_writel(1,s3c_g3d_base+FGGB_RST); for(i=0;i<1000;i++); __raw_writel(0,s3c_g3d_base+FGGB_RST); for(i=0;i<1000;i++); G3D_CHUNK_NUM = G3D_RESERVED_MEM_SIZE /SZ_2M; if (g3d_bootm == NULL) g3d_bootm = kmalloc(sizeof(s3c_g3d_bootmem) * G3D_CHUNK_NUM, GFP_KERNEL); printk("s3c_g3d version : 0x%x\n",__raw_readl(s3c_g3d_base + FGGB_VERSION)); printk("G3D_RESERVED_MEM_SIZE : %d MB\n", G3D_RESERVED_MEM_SIZE/SZ_1M); printk("G3D_CHUNK_SIZE : %d MB\n", G3D_CHUNK_SIZE/SZ_1M); printk("G3D_CHUNK_NUM : %d (SAFE_CHUNK:%d)\n", G3D_CHUNK_NUM, G3D_SAFE_CHUNK_NUM); for( loop_i = 0; loop_i < G3D_CHUNK_NUM; loop_i++ ){ g3d_bootm[loop_i].vir_addr = (unsigned int)Malloc_3D_ChunkMem(G3D_CHUNK_SIZE, loop_i); g3d_bootm[loop_i].phy_addr = (unsigned int)virt_to_phys((void*)g3d_bootm[loop_i].vir_addr); g3d_bootm[loop_i].in_used = G3D_CHUCNK_AVALIABLE; g3d_bootm[loop_i].size = G3D_CHUNK_SIZE; g3d_bootm[loop_i].file_desc_id = 0; printk("%d th virt_addr = 0x%p, phy_addr = 0x%p\n", (int)loop_i, (void*)(g3d_bootm[loop_i].vir_addr), (void*)(g3d_bootm[loop_i].phy_addr)); } /* check to see if everything is setup correctly */ return 0; err_misc_register: free_irq(res->start, pdev); err_irq: iounmap(s3c_g3d_base); err_ioremap: release_resource(s3c_g3d_mem); kfree(s3c_g3d_mem); s3c_g3d_mem = NULL; err_mem: clk_g3d_enable(); err_clock: #ifdef USE_G3D_DOMAIN_GATING s3c_set_normal_cfg(S3C64XX_DOMAIN_G, S3C64XX_LP_MODE, S3C64XX_3D); #endif /* USE_G3D_DOMAIN_GATING */ return ret; }