static int s3c_dma_prepare(struct snd_pcm_substream *substream) { struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; int ret = 0; pr_debug("Entered %s\n", __func__); /* return if this is a bufferless transfer e.g. * codec <--> BT codec or GSM modem -- lg FIXME */ if (!prtd->params) return 0; /* channel needs configuring for mem=>device, increment memory addr, * sync to pclk, half-word transfers to the IIS-FIFO. */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { s3c2410_dma_devconfig(prtd->params->channel, S3C2410_DMASRC_MEM, prtd->params->dma_addr); } else { s3c2410_dma_devconfig(prtd->params->channel, S3C2410_DMASRC_HW, prtd->params->dma_addr); } s3c2410_dma_config(prtd->params->channel, prtd->params->dma_size); /* flush the DMA channel */ s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH); prtd->dma_loaded = 0; prtd->dma_pos = prtd->dma_start; /* enqueue dma buffers */ s3c_dma_enqueue(substream); return ret; }
static int s3c_iis_dma_init(audio_stream_t *s,int mode) { /* play mode */ if(mode == 0) { s3c2410_dma_devconfig(s->dma, S3C2410_DMASRC_MEM, S3C2410_DISRCC_INC | S3C2410_DISRCC_APB, S3C2410_PA_IIS + S3C2410_IISFIFO); } /* capture mode */ if(mode ==1) { s3c2410_dma_devconfig(s->dma,S3C2410_DMASRC_HW, S3C2410_DISRCC_INC | S3C2410_DISRCC_APB, S3C2410_PA_IIS + S3C2410_IISFIFORX); } s3c2410_dma_config(s->dma, 4, S3C2410_DCON_SYNC_PCLK |S3C2410_DCON_HANDSHAKE); s3c2410_dma_set_buffdone_fn(s->dma, audio_dma_callback); s3c2410_dma_setflags(s->dma, S3C2410_DMAF_AUTOSTART); return 0; }
int s3c_mem_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { unsigned long *virt_addr; struct mm_struct *mm = current->mm; struct s3c_mem_alloc param; struct s3c_mem_dma_param dma_param; switch (cmd) { case S3C_MEM_ALLOC: mutex_lock(&mem_alloc_lock); if(copy_from_user(¶m, (struct s3c_mem_alloc *)arg, sizeof(struct s3c_mem_alloc))){ mutex_unlock(&mem_alloc_lock); return -EFAULT; } flag = MEM_ALLOC; param.vir_addr = do_mmap(file, 0, param.size, PROT_READ|PROT_WRITE, MAP_SHARED, 0); DEBUG("param.vir_addr = %08x, %d\n", param.vir_addr, __LINE__); if(param.vir_addr == -EINVAL) { printk("S3C_MEM_ALLOC FAILED\n"); flag = 0; mutex_unlock(&mem_alloc_lock); return -EFAULT; } param.phy_addr = physical_address; DEBUG("KERNEL MALLOC : param.phy_addr = 0x%X \t size = %d \t param.vir_addr = 0x%X, %d\n", param.phy_addr, param.size, param.vir_addr, __LINE__); if(copy_to_user((struct s3c_mem_alloc *)arg, ¶m, sizeof(struct s3c_mem_alloc))){ flag = 0; mutex_unlock(&mem_alloc_lock); return -EFAULT; } flag = 0; mutex_unlock(&mem_alloc_lock); break; case S3C_MEM_CACHEABLE_ALLOC: mutex_lock(&mem_cacheable_alloc_lock); if(copy_from_user(¶m, (struct s3c_mem_alloc *)arg, sizeof(struct s3c_mem_alloc))){ mutex_unlock(&mem_cacheable_alloc_lock); return -EFAULT; } flag = MEM_ALLOC_CACHEABLE; param.vir_addr = do_mmap(file, 0, param.size, PROT_READ|PROT_WRITE, MAP_SHARED, 0); DEBUG("param.vir_addr = %08x, %d\n", param.vir_addr, __LINE__); if(param.vir_addr == -EINVAL) { printk("S3C_MEM_ALLOC FAILED\n"); flag = 0; mutex_unlock(&mem_cacheable_alloc_lock); return -EFAULT; } param.phy_addr = physical_address; DEBUG("KERNEL MALLOC : param.phy_addr = 0x%X \t size = %d \t param.vir_addr = 0x%X, %d\n", param.phy_addr, param.size, param.vir_addr, __LINE__); if(copy_to_user((struct s3c_mem_alloc *)arg, ¶m, sizeof(struct s3c_mem_alloc))){ flag = 0; mutex_unlock(&mem_cacheable_alloc_lock); return -EFAULT; } flag = 0; mutex_unlock(&mem_cacheable_alloc_lock); break; case S3C_MEM_SHARE_ALLOC: mutex_lock(&mem_share_alloc_lock); if(copy_from_user(¶m, (struct s3c_mem_alloc *)arg, sizeof(struct s3c_mem_alloc))){ mutex_unlock(&mem_share_alloc_lock); return -EFAULT; } flag = MEM_ALLOC_SHARE; physical_address = param.phy_addr; DEBUG("param.phy_addr = %08x, %d\n", physical_address, __LINE__); param.vir_addr = do_mmap(file, 0, param.size, PROT_READ|PROT_WRITE, MAP_SHARED, 0); DEBUG("param.vir_addr = %08x, %d\n", param.vir_addr, __LINE__); if(param.vir_addr == -EINVAL) { printk("S3C_MEM_SHARE_ALLOC FAILED\n"); flag = 0; mutex_unlock(&mem_share_alloc_lock); return -EFAULT; } DEBUG("MALLOC_SHARE : param.phy_addr = 0x%X \t size = %d \t param.vir_addr = 0x%X, %d\n", param.phy_addr, param.size, param.vir_addr, __LINE__); if(copy_to_user((struct s3c_mem_alloc *)arg, ¶m, sizeof(struct s3c_mem_alloc))){ flag = 0; mutex_unlock(&mem_share_alloc_lock); return -EFAULT; } flag = 0; mutex_unlock(&mem_share_alloc_lock); break; case S3C_MEM_CACHEABLE_SHARE_ALLOC: mutex_lock(&mem_cacheable_share_alloc_lock); if(copy_from_user(¶m, (struct s3c_mem_alloc *)arg, sizeof(struct s3c_mem_alloc))){ mutex_unlock(&mem_cacheable_share_alloc_lock); return -EFAULT; } flag = MEM_ALLOC_CACHEABLE_SHARE; physical_address = param.phy_addr; DEBUG("param.phy_addr = %08x, %d\n", physical_address, __LINE__); param.vir_addr = do_mmap(file, 0, param.size, PROT_READ|PROT_WRITE, MAP_SHARED, 0); DEBUG("param.vir_addr = %08x, %d\n", param.vir_addr, __LINE__); if(param.vir_addr == -EINVAL) { printk("S3C_MEM_SHARE_ALLOC FAILED\n"); flag = 0; mutex_unlock(&mem_cacheable_share_alloc_lock); return -EFAULT; } DEBUG("MALLOC_SHARE : param.phy_addr = 0x%X \t size = %d \t param.vir_addr = 0x%X, %d\n", param.phy_addr, param.size, param.vir_addr, __LINE__); if(copy_to_user((struct s3c_mem_alloc *)arg, ¶m, sizeof(struct s3c_mem_alloc))){ flag = 0; mutex_unlock(&mem_cacheable_share_alloc_lock); return -EFAULT; } flag = 0; mutex_unlock(&mem_cacheable_share_alloc_lock); break; case S3C_MEM_FREE: mutex_lock(&mem_free_lock); if(copy_from_user(¶m, (struct s3c_mem_alloc *)arg, sizeof(struct s3c_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, %d\n", param.phy_addr, param.size, param.vir_addr, __LINE__); if (do_munmap(mm, param.vir_addr, param.size) < 0) { printk("do_munmap() failed !!\n"); mutex_unlock(&mem_free_lock); return -EINVAL; } virt_addr = (unsigned long *)phys_to_virt(param.phy_addr); kfree(virt_addr); param.size = 0; DEBUG("do_munmap() succeed !!\n"); if(copy_to_user((struct s3c_mem_alloc *)arg, ¶m, sizeof(struct s3c_mem_alloc))){ mutex_unlock(&mem_free_lock); return -EFAULT; } mutex_unlock(&mem_free_lock); break; case S3C_MEM_SHARE_FREE: mutex_lock(&mem_share_free_lock); if(copy_from_user(¶m, (struct s3c_mem_alloc *)arg, sizeof(struct s3c_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, %d\n", param.phy_addr, param.size, param.vir_addr, __LINE__); 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_mem_alloc *)arg, ¶m, sizeof(struct s3c_mem_alloc))){ mutex_unlock(&mem_share_free_lock); return -EFAULT; } mutex_unlock(&mem_share_free_lock); break; #if 0 /* IOCTL for Old PL-080 codes (dma-pl080.c) */ case S3C_MEM_DMA_COPY: if(copy_from_user(&dma_param, (struct s3c_mem_dma_param *)arg, sizeof(struct s3c_mem_dma_param))) { return -EFAULT; } //printk("S3C_MEM_DMA_COPY called\n"); if (s3c2410_dma_request(DMACH_3D_M2M, &s3c_m2m_dma_client, NULL)) { printk(KERN_WARNING "Unable to get DMA channel.\n"); return -1; } s3c2410_dma_set_buffdone_fn(DMACH_3D_M2M, s3c_m2m_dma_finish); //dma_cache_maint(dma_param.src_addr,sizeof(unsigned long long), DMA_BIDIRECTIONAL); // printk("MEMCPY src=%p,dst=%p,size=%d\n", dma_param.src_addr,dma_param.dst_addr, dma_param.size); /* Source address */ s3c2410_dma_devconfig(DMACH_3D_M2M, S3C_DMA_MEM2MEM, dma_param.src_addr); s3c2410_dma_config(DMACH_3D_M2M, 8); /* Destination address : Data buffer address */ s3c2410_dma_enqueue(DMACH_3D_M2M, 0, dma_param.dst_addr, dma_param.size); s3c2410_dma_ctrl(DMACH_3D_M2M, S3C2410_DMAOP_START); wait_for_completion(&s3c_m2m_dma_complete); #if 0 /* Test code with hard coding */ /* Destination address : Data buffer address */ s3c2410_dma_enqueue(DMACH_3D_M2M, 0, 0x27a00000, 0x4000); s3c2410_dma_enqueue(DMACH_3D_M2M, 0, 0x27a00000+0x10000, 0x4000); s3c2410_dma_enqueue(DMACH_3D_M2M, 0, 0x27a00000+0x20000, 0x4000); s3c2410_dma_ctrl(DMACH_3D_M2M, S3C2410_DMAOP_START); wait_for_completion(&s3c_m2m_dma_complete); //wait_for_completion(&s3c_m2m_dma_complete); //wait_for_completion(&s3c_m2m_dma_complete); s3c2410_dma_enqueue(DMACH_3D_M2M, 0, 0x27a00000+0x30000, 0x4000); s3c2410_dma_enqueue(DMACH_3D_M2M, 0, 0x27a00000+0x40000, 0x4000); s3c2410_dma_ctrl(DMACH_3D_M2M, S3C2410_DMAOP_START); wait_for_completion(&s3c_m2m_dma_complete); //wait_for_completion(&s3c_m2m_dma_complete); s3c2410_dma_enqueue(DMACH_3D_M2M, 0, 0x27a00000+0x50000, 0x4000); s3c2410_dma_ctrl(DMACH_3D_M2M, S3C2410_DMAOP_START); wait_for_completion(&s3c_m2m_dma_complete); #endif /* Test code with hard coding */ s3c2410_dma_free(DMACH_3D_M2M, &s3c_m2m_dma_client); if(copy_to_user((struct s3c_mem_dma_param *)arg, &dma_param, sizeof(struct s3c_mem_dma_param))) { return -EFAULT; } break; case S3C_MEM_DMA_SET: if(copy_from_user(&dma_param, (struct s3c_mem_dma_param *)arg, sizeof(struct s3c_mem_dma_param))) { return -EFAULT; } if (s3c2410_dma_request(DMACH_3D_M2M, &s3c_m2m_dma_client, NULL)) { printk(KERN_WARNING "Unable to get DMA channel.\n"); return -1; } s3c2410_dma_set_buffdone_fn(DMACH_3D_M2M, s3c_m2m_dma_finish); //dma_cache_maint(dma_param.src_addr,sizeof(unsigned long long), DMA_BIDIRECTIONAL); // printk("MEMSET src=%p,dst=%p,size=%d\n", dma_param.src_addr,dma_param.dst_addr, dma_param.size); /* Source address */ s3c2410_dma_devconfig(DMACH_3D_M2M, S3C_DMA_MEM2MEM_SET, dma_param.src_addr); s3c2410_dma_config(DMACH_3D_M2M, 8); /* Destination address : Data buffer address */ s3c2410_dma_enqueue(DMACH_3D_M2M, 0, dma_param.dst_addr, dma_param.size); s3c2410_dma_ctrl(DMACH_3D_M2M, S3C2410_DMAOP_START); wait_for_completion(&s3c_m2m_dma_complete); s3c2410_dma_free(DMACH_3D_M2M, &s3c_m2m_dma_client); if(copy_to_user((struct s3c_mem_dma_param *)arg, &dma_param, sizeof(struct s3c_mem_dma_param))) { return -EFAULT; } break; #endif default: DEBUG("s3c_mem_ioctl() : default !!\n"); return -EINVAL; } return 0; }
static int s5p_pcm_hw_params_nm(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime = substream->runtime; struct s5p_runtime_data *prtd = runtime->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct s5p_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data; unsigned long totbytes = params_buffer_bytes(params); int ret=0; s3cdbg("Entered %s, params = %p \n", __FUNCTION__, prtd->params); /* By Jung */ if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK) totbytes = params_buffer_bytes(params) * ANDROID_BUF_NUM; else totbytes = params_buffer_bytes(params); /* return if this is a bufferless transfer e.g. * codec <--> BT codec or GSM modem -- lg FIXME */ if (!dma) return 0; /* this may get called several times by oss emulation * with different params */ if (prtd->params == NULL) { prtd->params = dma; s3cdbg("params %p, client %p, channel %d\n", prtd->params, prtd->params->client, prtd->params->channel); /* prepare DMA */ ret = s3c2410_dma_request(prtd->params->channel, prtd->params->client, NULL); if (ret) { printk(KERN_ERR "failed to get dma channel\n"); return ret; } } else if (prtd->params != dma) { s3c2410_dma_free(prtd->params->channel, prtd->params->client); prtd->params = dma; s3cdbg("params %p, client %p, channel %d\n", prtd->params, prtd->params->client, prtd->params->channel); /* prepare DMA */ ret = s3c2410_dma_request(prtd->params->channel, prtd->params->client, NULL); if (ret) { printk(KERN_ERR "failed to get dma channel\n"); return ret; } } /* channel needs configuring for mem=>device, increment memory addr, * sync to pclk, half-word transfers to the IIS-FIFO. */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { s3c2410_dma_devconfig(prtd->params->channel, S3C2410_DMASRC_MEM, 0, prtd->params->dma_addr); s3c2410_dma_config(prtd->params->channel, prtd->params->dma_size, 0); } else { s3c2410_dma_devconfig(prtd->params->channel, S3C2410_DMASRC_HW, 0, prtd->params->dma_addr); s3c2410_dma_config(prtd->params->channel, prtd->params->dma_size, 0); } s3c2410_dma_set_buffdone_fn(prtd->params->channel, s5p_audio_buffdone); snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); runtime->dma_bytes = totbytes; spin_lock_irq(&prtd->lock); prtd->dma_loaded = 0; prtd->dma_limit = runtime->hw.periods_min; prtd->dma_period = params_period_bytes(params); prtd->dma_start = runtime->dma_addr; prtd->dma_pos = prtd->dma_start; prtd->dma_end = prtd->dma_start + totbytes; spin_unlock_irq(&prtd->lock); s3cdbg("DmaAddr=@%x Total=%lubytes PrdSz=%u #Prds=%u\n", runtime->dma_addr, totbytes, params_period_bytes(params), runtime->hw.periods_min); return 0; }
static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime = substream->runtime; struct s3c24xx_runtime_data *prtd = runtime->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct s3c24xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data; unsigned long totbytes; int ret=0; s3cdbg("Entered %s, params = %p \n", __FUNCTION__, prtd->params); if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK) totbytes = params_buffer_bytes(params) * ANDROID_BUF_NUM; else totbytes = params_buffer_bytes(params); // printk("[%d]:ring_buf_num %d\n", substream->stream, ring_buf_num); /* return if this is a bufferless transfer e.g. * codec <--> BT codec or GSM modem -- lg FIXME */ if (!dma) return 0; /* this may get called several times by oss emulation * with different params */ if (prtd->params == NULL) { prtd->params = dma; s3cdbg("params %p, client %p, channel %d\n", prtd->params, prtd->params->client, prtd->params->channel); /* prepare DMA */ ret = s3c2410_dma_request(prtd->params->channel, prtd->params->client, NULL); if (ret) { printk(KERN_ERR "failed to get dma channel\n"); return ret; } } else if (prtd->params != dma) { s3c2410_dma_free(prtd->params->channel, prtd->params->client); prtd->params = dma; s3cdbg("params %p, client %p, channel %d\n", prtd->params, prtd->params->client, prtd->params->channel); /* prepare DMA */ ret = s3c2410_dma_request(prtd->params->channel, prtd->params->client, NULL); if (ret) { printk(KERN_ERR "failed to get dma channel\n"); return ret; } } /* channel needs configuring for mem=>device, increment memory addr, * sync to pclk, half-word transfers to the IIS-FIFO. */ #if !defined (CONFIG_CPU_S3C6400) && !defined (CONFIG_CPU_S3C6410) && !defined(CONFIG_CPU_S5PC100) && !defined (CONFIG_CPU_S5P6440) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { s3c2410_dma_devconfig(prtd->params->channel, S3C2410_DMASRC_MEM, S3C2410_DISRCC_INC | S3C2410_DISRCC_APB, prtd->params->dma_addr); s3c2410_dma_config(prtd->params->channel, prtd->params->dma_size, S3C2410_DCON_SYNC_PCLK | S3C2410_DCON_HANDSHAKE); } else { s3c2410_dma_config(prtd->params->channel, prtd->params->dma_size, S3C2410_DCON_HANDSHAKE | S3C2410_DCON_SYNC_PCLK); s3c2410_dma_devconfig(prtd->params->channel, S3C2410_DMASRC_HW, 0x3, prtd->params->dma_addr); } #else if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { s3c2410_dma_devconfig(prtd->params->channel, S3C2410_DMASRC_MEM, prtd->params->dma_addr); s3c2410_dma_config(prtd->params->channel, prtd->params->dma_size); } else { s3c2410_dma_devconfig(prtd->params->channel, S3C2410_DMASRC_HW, prtd->params->dma_addr); s3c2410_dma_config(prtd->params->channel, prtd->params->dma_size); } #endif s3c2410_dma_set_buffdone_fn(prtd->params->channel, s3c24xx_audio_buffdone); snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); runtime->dma_bytes = totbytes; spin_lock_irq(&prtd->lock); prtd->dma_limit = runtime->hw.periods_min; prtd->dma_period = params_period_bytes(params); prtd->dma_start = runtime->dma_addr; prtd->dma_pos = prtd->dma_start; prtd->dma_end = prtd->dma_start + totbytes; spin_unlock_irq(&prtd->lock); s3cdbg("Entered %s, line %d \n", __FUNCTION__, __LINE__); 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); 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); while(1){ wait_event_interruptible(waitq, (interrupt_already_recevied>0)); __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); } break; case GET_CONFIG: copy_to_user((void *)arg,&g3d_config,sizeof(G3D_CONFIG_STRUCT)); break; case START_DMA_BLOCK: copy_from_user(&dma_block,(void *)arg,sizeof(DMA_BLOCK_STRUCT)); 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; // printk(" dma src=0x%x\n",dma_info.src); // printk(" dma len =%u\n",dma_info.len); // printk(" dma dst = 0x%x\n",dma_info.dst); dma_3d_done = &complete; if (s3c2410_dma_request(DMACH_3D_IN, &s3c6410_3d_dma_client, NULL)) { printk(KERN_WARNING "Unable to get DMA channel.\n"); return -EFAULT; } s3c2410_dma_set_buffdone_fn(DMACH_3D_IN, s3c_g3d_dma_finish); s3c2410_dma_devconfig(DMACH_3D_IN, S3C_DMA_MEM2G3D, 1, (u_long) dma_info.src); s3c2410_dma_config(DMACH_3D_IN, 4, 4); s3c2410_dma_setflags(DMACH_3D_IN, S3C2410_DMAF_AUTOSTART); //consistent_sync((void *) dma_info.dst, dma_info.len, DMA_FROM_DEVICE); // s3c2410_dma_enqueue(DMACH_3D_IN, NULL, (dma_addr_t) virt_to_dma(NULL, dma_info.dst), dma_info.len); s3c2410_dma_enqueue(DMACH_3D_IN, 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_IN, &s3c6410_3d_dma_client); break; default: return -EINVAL; } 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; }