static void SetHDMIBuffer(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params)
{

	kal_uint32 volatile u4tmpMrg1;

	struct snd_pcm_runtime *runtime = substream->runtime;
	AFE_BLOCK_T *pblock = &(pMemControl->rBlock);

	pblock->pucPhysBufAddr = runtime->dma_addr;
	pblock->pucVirtBufAddr = runtime->dma_area;
	pblock->u4BufferSize = runtime->dma_bytes;
	pblock->u4SampleNumMask = 0x001f;	/* 32 byte align */
	pblock->u4WriteIdx = 0;
	pblock->u4DMAReadIdx = 0;
	pblock->u4DataRemained = 0;
	pblock->u4fsyncflag = false;
	pblock->uResetFlag = true;

	PRINTK_AUD_HDMI("%s, dma_bytes = %d, dma_area = %p, dma_addr = 0x%x\n",
		__func__, pblock->u4BufferSize, pblock->pucVirtBufAddr,
		pblock->pucPhysBufAddr);

	Afe_Set_Reg(AFE_HDMI_BASE, pblock->pucPhysBufAddr, 0xffffffff);
	Afe_Set_Reg(AFE_HDMI_END, pblock->pucPhysBufAddr + (pblock->u4BufferSize - 1),
		0xffffffff);

	u4tmpMrg1 = Afe_Get_Reg(AFE_HDMI_BASE);

	u4tmpMrg1 &= 0x00ffffff;

	PRINTK_AUD_HDMI("SetHDMIBuffer AFE_HDMI_BASE = 0x%x\n", u4tmpMrg1);
}
static int mtk_pcm_hdmi_silence(struct snd_pcm_substream *substream,
				int channel, snd_pcm_uframes_t pos, snd_pcm_uframes_t count)
{
	PRINTK_AUD_HDMI("%s\n", __func__);
	/* do nothing */
	return 0;
}
static int mtk_asoc_pcm_hdmi_new(struct snd_soc_pcm_runtime *rtd)
{
	int ret = 0;

	pruntimehdmi = rtd;
	PRINTK_AUD_HDMI("%s\n", __func__);
	return ret;
}
static int mtk_hdmi_probe(struct platform_device *pdev)
{
	PRINTK_AUD_HDMI("%s\n", __func__);

	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(64);

	if (!pdev->dev.dma_mask)
		pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;

	if (pdev->dev.of_node)
		dev_set_name(&pdev->dev, "%s", MT_SOC_HDMI_PCM);

	PRINTK_AUD_HDMI("%s: dev name %s\n", __func__, dev_name(&pdev->dev));


	return snd_soc_register_platform(&pdev->dev, &mtk_hdmi_soc_platform);
}
static int mtk_pcm_hdmi_hw_free(struct snd_pcm_substream *substream)
{
	PRINTK_AUD_HDMI("mtk_pcm_hdmi_hw_free\n");

	if (fake_buffer)
		return 0;

	return snd_pcm_lib_free_pages(substream);
}
static snd_pcm_uframes_t mtk_pcm_hdmi_pointer(struct snd_pcm_substream *substream)
{
	kal_int32 HW_memory_index = 0;
	kal_int32 HW_Cur_ReadIdx = 0;
	kal_uint32 Frameidx = 0;
	kal_int32 Afe_consumed_bytes = 0;
	AFE_BLOCK_T *Afe_Block = &(pMemControl->rBlock);

	PRINTK_AUD_HDMI("%s Afe_Block->u4DMAReadIdx = 0x%x\n", __func__,
		Afe_Block->u4DMAReadIdx);

	if (GetMemoryPathEnable(Soc_Aud_Digital_Block_MEM_HDMI) == true) {
		HW_Cur_ReadIdx = Afe_Get_Reg(AFE_HDMI_CUR);

		if (HW_Cur_ReadIdx == 0) {
			PRINTK_AUD_HDMI("[Auddrv] HW_Cur_ReadIdx == 0\n");
			HW_Cur_ReadIdx = Afe_Block->pucPhysBufAddr;
		}

		HW_memory_index = (HW_Cur_ReadIdx - Afe_Block->pucPhysBufAddr);

		if (HW_memory_index >= Afe_Block->u4DMAReadIdx)
			Afe_consumed_bytes = HW_memory_index - Afe_Block->u4DMAReadIdx;
		else {
			Afe_consumed_bytes = Afe_Block->u4BufferSize + HW_memory_index
				- Afe_Block->u4DMAReadIdx;
		}

		Afe_Block->u4DataRemained -= Afe_consumed_bytes;
		Afe_Block->u4DMAReadIdx += Afe_consumed_bytes;
		Afe_Block->u4DMAReadIdx %= Afe_Block->u4BufferSize;

		PRINTK_AUD_HDMI
			("[Auddrv] HW_Cur_ReadIdx = 0x%x, HW_memory_index = 0x%x, Afe_consumed_bytes = 0x%x\n",
			HW_Cur_ReadIdx, HW_memory_index, Afe_consumed_bytes);

		return audio_bytes_to_frame(substream, Afe_Block->u4DMAReadIdx);
	}

	Frameidx = audio_bytes_to_frame(substream, Afe_Block->u4DMAReadIdx);
	return Frameidx;
}
static int mtk_pcm_hdmi_hw_params(struct snd_pcm_substream *substream,
				  struct snd_pcm_hw_params *hw_params)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
	int ret = 0;

	pr_debug("mtk_pcm_hdmi_hw_params\n");

	dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
	dma_buf->dev.dev = substream->pcm->card->dev;
	dma_buf->private_data = NULL;

	if (fake_buffer) {
		PRINTK_AUD_HDMI("[mtk_pcm_hdmi_hw_params] HDMI_dma_buf->area\n");

#ifdef _NO_SRAM_USAGE_
		runtime->dma_area = HDMI_dma_buf->area;
		runtime->dma_addr = HDMI_dma_buf->addr;
		/* runtime->dma_bytes = HDMI_dma_buf->bytes; */
		/* runtime->buffer_size = HDMI_dma_buf->bytes; */
		runtime->dma_bytes = params_buffer_bytes(hw_params);
		runtime->buffer_size = runtime->dma_bytes;
#else
		runtime->dma_area = (unsigned char *)Get_Afe_SramBase_Pointer();
		runtime->dma_addr = AFE_INTERNAL_SRAM_PHY_BASE;
		runtime->dma_bytes = params_buffer_bytes(hw_params);
		runtime->buffer_size = runtime->dma_bytes;
#endif

	} else {
		PRINTK_AUD_HDMI("[mtk_pcm_hdmi_hw_params] snd_pcm_lib_malloc_pages\n");
		ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
	}
	PRINTK_AUD_HDMI("%s, dma_bytes = %zu, dma_area = %p, dma_addr = 0x%lx\n",
		__func__, substream->runtime->dma_bytes, substream->runtime->dma_area,
		(long)substream->runtime->dma_addr);

	SetHDMIBuffer(substream, hw_params);
	return ret;
}
Esempio n. 8
0
static snd_pcm_uframes_t mtk_pcm_hdmi_pointer(struct snd_pcm_substream *substream)
{
    kal_int32 HW_memory_index = 0;
    kal_int32 HW_Cur_ReadIdx = 0;
    AFE_BLOCK_T *Afe_Block = &(pMemControl->rBlock);

    PRINTK_AUD_HDMI("mtk_pcm_hdmi_pointer u4DMAReadIdx=%x\n",Afe_Block->u4DMAReadIdx);

    if (pMemControl->interruptTrigger == 1)
    {
        HW_Cur_ReadIdx = Afe_Get_Reg(AFE_HDMI_CUR);
        if (HW_Cur_ReadIdx == 0)
        {
            PRINTK_AUD_HDMI("[mtk_pcm_hdmi_pointer] HW_Cur_ReadIdx ==0 \n");
            HW_Cur_ReadIdx = Afe_Block->pucPhysBufAddr;
        }
        HW_memory_index = (HW_Cur_ReadIdx - Afe_Block->pucPhysBufAddr);
        Previous_Hw_cur = HW_memory_index;
        PRINTK_AUD_HDMI("[mtk_pcm_hdmi_pointer] HW_Cur_ReadIdx =0x%x HW_memory_index = 0x%x pointer return = 0x%x \n", HW_Cur_ReadIdx, HW_memory_index,(HW_memory_index >> 2));
        pMemControl->interruptTrigger = 0;
        return (HW_memory_index >> 2);
    }
static int mtk_pcm_hdmi_open(struct snd_pcm_substream *substream)
{
	int ret = 0;
	struct snd_pcm_runtime *runtime = substream->runtime;

	pr_debug("%s\n", __func__);

	AudDrv_ANA_Clk_On();
	AudDrv_Emi_Clk_On();
	AudDrv_Clk_On();

	runtime->hw = mtk_hdmi_hardware;

	pMemControl = Get_Mem_ControlT(Soc_Aud_Digital_Block_MEM_HDMI);

	memcpy((void *)(&(runtime->hw)), (void *)&mtk_hdmi_hardware,
	       sizeof(struct snd_pcm_hardware));


	ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
					 &constraints_sample_rates);

	if (ret < 0) {
		PRINTK_AUD_HDMI("snd_pcm_hw_constraint_integer failed\n");
		return ret;
	}

	/* print for hw pcm information */
	pr_debug("%s, runtime->rate = %d, channels = %d, substream->pcm->device = %d\n",
		__func__, runtime->rate, runtime->channels, substream->pcm->device);

	runtime->hw.info |= SNDRV_PCM_INFO_INTERLEAVED;
	runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
	runtime->hw.info |= SNDRV_PCM_INFO_MMAP_VALID;

	PRINTK_AUD_HDMI("mtk_pcm_hdmi_open return\n");

	return 0;
}
static int mtk_pcm_hdmi_trigger(struct snd_pcm_substream *substream, int cmd)
{
	PRINTK_AUD_HDMI("mtk_pcm_hdmi_trigger cmd = %d\n", cmd);

	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_RESUME:
		return mtk_pcm_hdmi_start(substream);
	case SNDRV_PCM_TRIGGER_STOP:
	case SNDRV_PCM_TRIGGER_SUSPEND:
		return mtk_pcm_hdmi_stop(substream);
	}
	return -EINVAL;
}
static int mtk_afe_hdmi_probe(struct snd_soc_platform *platform)
{

	HDMI_dma_buf = kmalloc(sizeof(struct snd_dma_buffer), GFP_KERNEL);
	memset((void *)HDMI_dma_buf, 0, sizeof(struct snd_dma_buffer));
	PRINTK_AUD_HDMI("mtk_afe_hdmi_probe dma_alloc_coherent HDMI_dma_buf->addr = 0x%lx\n",
			(long)HDMI_dma_buf->addr);

	HDMI_dma_buf->area = dma_alloc_coherent(platform->dev, HDMI_MAX_BUFFER_SIZE,
		&HDMI_dma_buf->addr, GFP_KERNEL);	/* virtual pointer */

	if (HDMI_dma_buf->area)
		HDMI_dma_buf->bytes = HDMI_MAX_BUFFER_SIZE;

	snd_soc_add_platform_controls(platform, Audio_snd_hdmi_controls,
				      ARRAY_SIZE(Audio_snd_hdmi_controls));
	return 0;
}
static int __init mtk_hdmi_soc_platform_init(void)
{
	int ret;

	PRINTK_AUD_HDMI("%s\n", __func__);
#ifndef CONFIG_OF
	soc_mtkhdmi_dev = platform_device_alloc(MT_SOC_HDMI_PCM, -1);

	if (!soc_mtkhdmi_dev)
		return -ENOMEM;

	ret = platform_device_add(soc_mtkhdmi_dev);
	if (ret != 0) {
		platform_device_put(soc_mtkhdmi_dev);
		return ret;
	}
#endif
	ret = platform_driver_register(&mtk_hdmi_driver);
	return ret;

}
static int mtk_pcm_hdmi_copy(struct snd_pcm_substream *substream,
			     int channel, snd_pcm_uframes_t pos,
			     void __user *dst, snd_pcm_uframes_t count)
{
	AFE_BLOCK_T *Afe_Block = NULL;
	int copy_size = 0, Afe_WriteIdx_tmp;
	unsigned long flags;
	char *data_w_ptr = (char *)dst;

	count = audio_frame_to_bytes(substream, count);

	/* check which memif need to be write */
	Afe_Block = &(pMemControl->rBlock);

	/* handle for buffer management */

	PRINTK_AUD_HDMI
		("[%s] count = %d, WriteIdx = %x, ReadIdx = %x, DataRemained = %x\n",
		__func__, (kal_uint32) count, Afe_Block->u4WriteIdx,
		Afe_Block->u4DMAReadIdx, Afe_Block->u4DataRemained);

	if (Afe_Block->u4BufferSize == 0) {
		pr_err("%s: u4BufferSize = 0, Error!!!\n", __func__);
		return 0;
	}

	spin_lock_irqsave(&auddrv_hdmi_lock, flags);
	/* free space of the buffer */
	copy_size = Afe_Block->u4BufferSize - Afe_Block->u4DataRemained;
	spin_unlock_irqrestore(&auddrv_hdmi_lock, flags);

	if (count <= copy_size) {
		if (copy_size < 0)
			copy_size = 0;
		else
			copy_size = count;
	}

	if (copy_size != 0) {
		spin_lock_irqsave(&auddrv_hdmi_lock, flags);
		Afe_WriteIdx_tmp = Afe_Block->u4WriteIdx;
		spin_unlock_irqrestore(&auddrv_hdmi_lock, flags);

		if (Afe_WriteIdx_tmp + copy_size < Afe_Block->u4BufferSize) {	/* copy once */
			if (!access_ok(VERIFY_READ, data_w_ptr, copy_size)) {
				pr_warn("[%s] 0 ptr invalid data_w_ptr = %p, size = %d,", __func__,
					data_w_ptr, copy_size);
				pr_warn(" u4BufferSize = %d, u4DataRemained = %d\n",
					Afe_Block->u4BufferSize, Afe_Block->u4DataRemained);
			} else {
				PRINTK_AUD_HDMI2
				("[%s] memcpy Afe_Block->pucVirtBufAddr+Afe_WriteIdx=%x, data_w_ptr=%p, copy_size=%x\n",
				Afe_Block->pucVirtBufAddr + Afe_WriteIdx_tmp, data_w_ptr, copy_size);

				if (copy_from_user((Afe_Block->pucVirtBufAddr + Afe_WriteIdx_tmp),
					data_w_ptr, copy_size)) {
					pr_err("[%s] Fail copy from user\n", __func__);
					return -1;
				}
			}

			spin_lock_irqsave(&auddrv_hdmi_lock, flags);
			Afe_Block->u4DataRemained += copy_size;
			Afe_Block->u4WriteIdx = Afe_WriteIdx_tmp + copy_size;
			Afe_Block->u4WriteIdx %= Afe_Block->u4BufferSize;
			spin_unlock_irqrestore(&auddrv_hdmi_lock, flags);
			data_w_ptr += copy_size;
			count -= copy_size;

			PRINTK_AUD_HDMI2
				("[%s] finish 1, copy_size:%x, WriteIdx:%x, ReadIdx:%x, DataRemained:%x\n",
				__func__, copy_size, Afe_Block->u4WriteIdx, Afe_Block->u4DMAReadIdx,
				Afe_Block->u4DataRemained);

		} else {	/* copy twice */
			kal_uint32 size_1 = 0, size_2 = 0;

			size_1 = Afe_Block->u4BufferSize - Afe_WriteIdx_tmp;
			size_2 = copy_size - size_1;

			if (!access_ok(VERIFY_READ, data_w_ptr, size_1)) {
				pr_warn("[%s] 1 ptr invalid data_w_ptr = %p, size_1 = %d,",
					__func__, data_w_ptr, size_1);
				pr_warn(" u4BufferSize = %d, u4DataRemained = %d\n",
					Afe_Block->u4BufferSize, Afe_Block->u4DataRemained);
			} else {
				PRINTK_AUD_HDMI2
				("[%s] mcmcpy Afe_Block->pucVirtBufAddr+Afe_WriteIdx=%x, data_w_ptr=%p, size_1=%x\n",
				__func__, Afe_Block->pucVirtBufAddr + Afe_WriteIdx_tmp, data_w_ptr, size_1);

				if ((copy_from_user((Afe_Block->pucVirtBufAddr + Afe_WriteIdx_tmp),
					data_w_ptr, size_1))) {
					pr_err("[%s] Fail 1 copy from user\n", __func__);
					return -1;
				}
			}

			spin_lock_irqsave(&auddrv_hdmi_lock, flags);
			Afe_Block->u4DataRemained += size_1;
			Afe_Block->u4WriteIdx = Afe_WriteIdx_tmp + size_1;
			Afe_Block->u4WriteIdx %= Afe_Block->u4BufferSize;
			Afe_WriteIdx_tmp = Afe_Block->u4WriteIdx;
			spin_unlock_irqrestore(&auddrv_hdmi_lock, flags);

			if (!access_ok(VERIFY_READ, data_w_ptr + size_1, size_2)) {
				pr_warn("[%s] 2 ptr invalid data_w_ptr = %p, size_1 = %d, size_2 = %d,",
					__func__, data_w_ptr, size_1, size_2);
				pr_warn(" u4BufferSize = %d, u4DataRemained = %d\n",
					Afe_Block->u4BufferSize, Afe_Block->u4DataRemained);
			} else {
				PRINTK_AUD_HDMI2
					("[%s] mcmcpy Afe_Block->pucVirtBufAddr+Afe_WriteIdx=%x,\n",
					__func__, Afe_Block->pucVirtBufAddr + Afe_WriteIdx_tmp);
				PRINTK_AUD_HDMI2
					(" data_w_ptr+size_1=%p, size_2=%x\n", data_w_ptr + size_1, size_2);

				if ((copy_from_user((Afe_Block->pucVirtBufAddr + Afe_WriteIdx_tmp),
					(data_w_ptr + size_1), size_2))) {
					pr_err("[%s] Fail 2 copy from user\n", __func__);
					return -1;
				}
			}

			spin_lock_irqsave(&auddrv_hdmi_lock, flags);

			Afe_Block->u4DataRemained += size_2;
			Afe_Block->u4WriteIdx = Afe_WriteIdx_tmp + size_2;
			Afe_Block->u4WriteIdx %= Afe_Block->u4BufferSize;
			spin_unlock_irqrestore(&auddrv_hdmi_lock, flags);
			count -= copy_size;
			data_w_ptr += copy_size;

			PRINTK_AUD_HDMI2
				("[%s] finish 2, copy size:%x, WriteIdx:%x, ReadIdx:%x, DataRemained:%x\n",
				__func__, copy_size, Afe_Block->u4WriteIdx, Afe_Block->u4DMAReadIdx,
				Afe_Block->u4DataRemained);
		}
	}

	return 0;
}
static void __exit mtk_hdmi_soc_platform_exit(void)
{
	PRINTK_AUD_HDMI("%s\n", __func__);

	platform_driver_unregister(&mtk_hdmi_driver);
}
static int mtk_hdmi_remove(struct platform_device *pdev)
{
	PRINTK_AUD_HDMI("%s\n", __func__);
	snd_soc_unregister_platform(&pdev->dev);
	return 0;
}
static struct page *mtk_pcm_page(struct snd_pcm_substream *substream, unsigned long offset)
{
	PRINTK_AUD_HDMI("%s\n", __func__);
	return virt_to_page(dummy_page[substream->stream]);	/* the same page */
}