ALSA: Add SoC on-chip internal ram support for DMA buffer allocation
Now it's quite common that an SoC contains its on-chip internal RAM. By using this RAM space for DMA buffer during audio playback/record, we can shutdown the voltage for external RAM to save power. So add new DEV type with iram malloc()/free() and accordingly modify current default mmap() for the iram circumstance. Signed-off-by: Nicolin Chen <b42378@freescale.com> Reviewed-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
		
							parent
							
								
									861e66d341
								
							
						
					
					
						commit
						055032142c
					
				| @ -52,6 +52,7 @@ struct snd_dma_device { | ||||
| #else | ||||
| #define SNDRV_DMA_TYPE_DEV_SG	SNDRV_DMA_TYPE_DEV /* no SG-buf support */ | ||||
| #endif | ||||
| #define SNDRV_DMA_TYPE_DEV_IRAM		4	/* generic device iram-buffer */ | ||||
| 
 | ||||
| /*
 | ||||
|  * info for buffer allocation | ||||
|  | ||||
| @ -30,6 +30,7 @@ | ||||
| #include <linux/seq_file.h> | ||||
| #include <asm/uaccess.h> | ||||
| #include <linux/dma-mapping.h> | ||||
| #include <linux/genalloc.h> | ||||
| #include <linux/moduleparam.h> | ||||
| #include <linux/mutex.h> | ||||
| #include <sound/memalloc.h> | ||||
| @ -157,6 +158,46 @@ static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr, | ||||
| 	dec_snd_pages(pg); | ||||
| 	dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * snd_malloc_dev_iram - allocate memory from on-chip internal ram | ||||
|  * @dmab: buffer allocation record to store the allocated data | ||||
|  * @size: number of bytes to allocate from the iram | ||||
|  * | ||||
|  * This function requires iram phandle provided via of_node | ||||
|  */ | ||||
| void snd_malloc_dev_iram(struct snd_dma_buffer *dmab, size_t size) | ||||
| { | ||||
| 	struct device *dev = dmab->dev.dev; | ||||
| 	struct gen_pool *pool = NULL; | ||||
| 
 | ||||
| 	if (dev->of_node) | ||||
| 		pool = of_get_named_gen_pool(dev->of_node, "iram", 0); | ||||
| 
 | ||||
| 	if (!pool) | ||||
| 		return; | ||||
| 
 | ||||
| 	/* Assign the pool into private_data field */ | ||||
| 	dmab->private_data = pool; | ||||
| 
 | ||||
| 	dmab->area = (void *)gen_pool_alloc(pool, size); | ||||
| 	if (!dmab->area) | ||||
| 		return; | ||||
| 
 | ||||
| 	dmab->addr = gen_pool_virt_to_phys(pool, (unsigned long)dmab->area); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * snd_free_dev_iram - free allocated specific memory from on-chip internal ram | ||||
|  * @dmab: buffer allocation record to store the allocated data | ||||
|  */ | ||||
| void snd_free_dev_iram(struct snd_dma_buffer *dmab) | ||||
| { | ||||
| 	struct gen_pool *pool = dmab->private_data; | ||||
| 
 | ||||
| 	if (pool && dmab->area) | ||||
| 		gen_pool_free(pool, (unsigned long)dmab->area, dmab->bytes); | ||||
| } | ||||
| #endif /* CONFIG_HAS_DMA */ | ||||
| 
 | ||||
| /*
 | ||||
| @ -197,6 +238,14 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, | ||||
| 		dmab->addr = 0; | ||||
| 		break; | ||||
| #ifdef CONFIG_HAS_DMA | ||||
| 	case SNDRV_DMA_TYPE_DEV_IRAM: | ||||
| 		snd_malloc_dev_iram(dmab, size); | ||||
| 		if (dmab->area) | ||||
| 			break; | ||||
| 		/* Internal memory might have limited size and no enough space,
 | ||||
| 		 * so if we fail to malloc, try to fetch memory traditionally. | ||||
| 		 */ | ||||
| 		dmab->dev.type = SNDRV_DMA_TYPE_DEV; | ||||
| 	case SNDRV_DMA_TYPE_DEV: | ||||
| 		dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr); | ||||
| 		break; | ||||
| @ -269,6 +318,9 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab) | ||||
| 		snd_free_pages(dmab->area, dmab->bytes); | ||||
| 		break; | ||||
| #ifdef CONFIG_HAS_DMA | ||||
| 	case SNDRV_DMA_TYPE_DEV_IRAM: | ||||
| 		snd_free_dev_iram(dmab); | ||||
| 		break; | ||||
| 	case SNDRV_DMA_TYPE_DEV: | ||||
| 		snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); | ||||
| 		break; | ||||
|  | ||||
| @ -3199,6 +3199,12 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream, | ||||
| 			     struct vm_area_struct *area) | ||||
| { | ||||
| 	area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; | ||||
| 	if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV_IRAM) { | ||||
| 		area->vm_page_prot = pgprot_writecombine(area->vm_page_prot); | ||||
| 		return remap_pfn_range(area, area->vm_start, | ||||
| 				substream->dma_buffer.addr >> PAGE_SHIFT, | ||||
| 				area->vm_end - area->vm_start, area->vm_page_prot); | ||||
| 	} | ||||
| #ifdef ARCH_HAS_DMA_MMAP_COHERENT | ||||
| 	if (!substream->ops->page && | ||||
| 	    substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user