Beispiel #1
0
static int esa_prepare_buffer(struct device *dev)
{
	unsigned long iova;
	int n, ret;

	/* Original firmware */
	si.fwmem = devm_kzalloc(dev, FWMEM_SIZE, GFP_KERNEL);
	if (!si.fwmem) {
		esa_err("Failed to alloc fwmem\n");
		goto err;
	}
	si.fwmem_pa = virt_to_phys(si.fwmem);

	/* Firmware backup for SRAM */
	si.fwmem_sram_bak = devm_kzalloc(dev, SRAM_FW_MAX, GFP_KERNEL);
	if (!si.fwmem_sram_bak) {
		esa_err("Failed to alloc fwmem\n");
		goto err;
	}

	/* Firmware for DRAM */
	for (n = 0; n < FWAREA_NUM; n++) {
		si.fwarea[n] = dma_alloc_coherent(dev, FWAREA_SIZE,
					&si.fwarea_pa[n], GFP_KERNEL);
		if (!si.fwarea[n]) {
			esa_err("Failed to alloc fwarea\n");
			goto err0;
		}
	}

	for (n = 0, iova = FWAREA_IOVA;
			n < FWAREA_NUM; n++, iova += FWAREA_SIZE) {
		ret = iommu_map(si.domain, iova,
				si.fwarea_pa[n], FWAREA_SIZE, 0);
		if (ret) {
			esa_err("Failed to map iommu\n");
			goto err1;
		}
	}

	/* Base address for IBUF, OBUF and FW LOG  */
	si.bufmem = si.fwarea[0] + BASEMEM_OFFSET;
	si.bufmem_pa = si.fwarea_pa[0];
	si.fw_log_buf = si.sram + FW_LOG_ADDR;

	return 0;
err1:
	for (n = 0, iova = FWAREA_IOVA;
			n < FWAREA_NUM; n++, iova += FWAREA_SIZE) {
		iommu_unmap(si.domain, iova, FWAREA_SIZE);
	}
err0:
	for (n = 0; n < FWAREA_NUM; n++) {
		if (si.fwarea[n])
			dma_free_coherent(dev, FWAREA_SIZE,
					si.fwarea[n], si.fwarea_pa[n]);
	}
err:
	return -ENOMEM;
}
Beispiel #2
0
static void esa_fw_request_complete(const struct firmware *fw_sram, void *ctx)
{
	const struct firmware *fw_dram;
	struct device *dev = ctx;

	if (!fw_sram) {
		esa_err("Failed to requset firmware[%s]\n", FW_SRAM_NAME);
		return;
	}

	if (request_firmware(&fw_dram, FW_DRAM_NAME, dev)) {
		esa_err("Failed to requset firmware[%s]\n", FW_DRAM_NAME);
		return;
	}

	si.fwmem_loaded = true;
	si.fw_sbin_size = fw_sram->size;
	si.fw_dbin_size = fw_dram->size;

	memcpy(si.fwmem, fw_sram->data, si.fw_sbin_size);
	memcpy(si.fwmem + si.fw_sbin_size, fw_dram->data, si.fw_dbin_size);

	esa_info("FW Loaded (SRAM = %d, DRAM = %d)\n",
			si.fw_sbin_size, si.fw_dbin_size);

	return;
}
Beispiel #3
0
static int esa_fw_startup(void)
{
#ifndef CONFIG_SND_SAMSUNG_SEIREN_OFFLOAD
	unsigned int dec_ver;
#endif
	int ret;

	if (si.fw_ready)
		return 0;

	if (!si.fwmem_loaded)
		return -EAGAIN;

	/* power on */
	si.fw_use_dram = true;
	esa_debug("Turn on CA5...\n");
	esa_fw_download();

	/* wait for fw ready */
	ret = wait_event_interruptible_timeout(esa_wq, si.fw_ready, HZ / 2);
	if (!ret) {
		esa_err("%s: fw not ready!!!\n", __func__);
		si.fw_use_dram = false;
		return -EBUSY;
	}

#ifndef CONFIG_SND_SAMSUNG_SEIREN_OFFLOAD
	/* check decoder version */
	esa_send_cmd(SYS_GET_STATUS);
	dec_ver = readl(si.mailbox) & 0xFF00;
	dec_ver = dec_ver >> 8;
	esa_debug("Decoder version : %x\n", dec_ver);
#endif
	return 0;
}
Beispiel #4
0
static ssize_t esa_write(struct file *file, const char *buffer,
					size_t size, loff_t *pos)
{
	int ret;

	mutex_lock(&esa_mutex);
	pm_runtime_get_sync(&si.pdev->dev);

	if (!si.fx_ext_on) {
		esa_debug("%s: fx ext not enabled\n", __func__);
		ret = -EINVAL;
		goto out;
	}

	if (!si.fx_work_buf) {
		esa_debug("%s: fx buf not ready\n", __func__);
		ret = -EBUSY;
		goto out;
	}

	if (copy_from_user(si.fx_work_buf, buffer, size)) {
		esa_err("%s: failed to copy_from_user\n", __func__);
		ret = -EFAULT;
	} else {
		esa_debug("%s: %lu bytes\n", __func__, size);
		ret = FX_BUF_SIZE;
	}
out:
	pm_runtime_mark_last_busy(&si.pdev->dev);
	pm_runtime_put_sync_autosuspend(&si.pdev->dev);
	mutex_unlock(&esa_mutex);

	return ret;
}
Beispiel #5
0
static int esa_open(struct inode *inode, struct file *file)
{
	struct esa_rtd *rtd;

	if (!si.fwmem_loaded) {
		esa_err("Firmware not ready\n");
		return -ENXIO;
	}

	/* alloc rtd */
	rtd = esa_alloc_rtd();
	if (!rtd) {
		esa_debug("%s: Not enough memory\n", __func__);
		return -EFAULT;
	}

	esa_debug("%s: idx:%d\n", __func__, rtd->idx);

	/* initialize */
	file->private_data = rtd;
	rtd->get_eos = EOS_NO;
	rtd->need_config = false;
	rtd->select_ibuf = 0;
	rtd->select_obuf = 0;
	rtd->obuf0_filled = false;
	rtd->obuf1_filled = false;

	return 0;
}
Beispiel #6
0
static int esa_send_cmd_(u32 cmd_code, bool sram_only)
{
	u32 cnt, val;
	int ret;

	si.isr_done = 0;
	writel(cmd_code, si.mailbox + CMD_CODE);	/* command */
	writel(1, si.regs + SW_INTR_CA5);		/* trigger ca5 */

	si.fw_use_dram = sram_only ? false : true;
	ret = wait_event_interruptible_timeout(esa_wq, si.isr_done, HZ / 2);
	if (!ret) {
		esa_err("%s: CMD(%08X) timed out!!!\n",
					__func__, cmd_code);
		esa_dump_fw_log();
		si.fw_use_dram = true;
		return -EBUSY;
	}

	cnt = msecs_to_loops(10);
	while (--cnt) {
		val = readl(si.regs + CA5_STATUS);
		if (val & CA5_STATUS_WFI)
			break;
		cpu_relax();
	}
	si.fw_use_dram = false;

	return 0;
}
Beispiel #7
0
static ssize_t esa_read(struct file *file, char *buffer,
				size_t size, loff_t *pos)
{
	int ret;

	mutex_lock(&esa_mutex);
	pm_runtime_get_sync(&si.pdev->dev);

	if (!si.fx_ext_on) {
		esa_debug("%s: fx ext not enabled\n", __func__);
		ret = -EINVAL;
		goto out;
	}

	ret = wait_event_interruptible_timeout(esa_fx_wq, si.fx_irq_done, HZ);
	if (!ret) {
		esa_err("%s: fx irq timeout\n", __func__);
		ret = -EBUSY;
		goto out;
	}

	si.fx_irq_done = false;
	si.fx_work_buf = (unsigned char *)(si.sram + FX_BUF_OFFSET);
	si.fx_work_buf += si.fx_next_idx * FX_BUF_SIZE;
	esa_debug("%s: buf_idx = %d\n", __func__, si.fx_next_idx);

	if (copy_to_user((void *)buffer, si.fx_work_buf, FX_BUF_SIZE)) {
		esa_err("%s: failed to copy_to_user\n", __func__);
		ret = -EFAULT;
	} else {
		ret = FX_BUF_SIZE;
	}
out:
	pm_runtime_mark_last_busy(&si.pdev->dev);
	pm_runtime_put_sync_autosuspend(&si.pdev->dev);
	mutex_unlock(&esa_mutex);

	return ret;
}
Beispiel #8
0
int esa_dma_send_cmd(u32 cmd, int ch, void __iomem *reg_ack)
{
	int n, ack;

	switch (cmd) {
	case CMD_DMA_PREPARE:
	case CMD_DMA_START:
	case CMD_DMA_STOP:
		break;
	default:
		esa_err("%s: unknown cmd %d\n", __func__, cmd);
		return -EIO;
	}

	spin_lock(&si.cmd_lock);

	writel(ch, si.mailbox + HANDLE_ID);		/* dma ch */
	writel(cmd, si.mailbox + CMD_CODE);		/* command */
	writel(1, si.regs + SW_INTR_CA5);		/* trigger ca5 */

	for (n = 0, ack = 0; n < 2000; n++) {
		if (readl(reg_ack)) {	/* Wait for ACK */
			ack = 1;
			break;
		}
		udelay(100);
	}
	writel(0, reg_ack);		/* clear ACK */

	spin_unlock(&si.cmd_lock);

	if (!ack) {
		esa_err("%s: No ack error!", __func__);
		esa_dump_fw_log();
	}

	return 0;
}
Beispiel #9
0
int esa_compr_send_buffer(const size_t copy_size, struct audio_processor *ap)
{
	int ret;

	/* write mp3 data to firmware */
	spin_lock(&si.compr_lock);
	writel(copy_size, si.mailbox + COMPR_SIZE_OF_FRAGMENT);

	ret = esa_compr_send_cmd(CMD_COMPR_WRITE, ap);
	if (ret) {
		esa_err("%s: can't send CMD_COMPR_WRITE (%d)\n",
			__func__, ret);
		spin_unlock(&si.compr_lock);
		return ret;
	}
	spin_unlock(&si.compr_lock);

	return 0;
}
Beispiel #10
0
static int esa_remove(struct platform_device *pdev)
{
	int ret = 0;

	free_irq(si.irq_ca5, 0);
	ret = misc_deregister(&esa_miscdev);
	if (ret)
		esa_err("Cannot deregister miscdev\n");

#ifndef CONFIG_PM_RUNTIME
	clk_disable_unprepare(si.clk_ca5);
	lpass_put_sync(&pdev->dev);
#endif
	clk_put(si.clk_ca5);
	clk_put(si.opclk_ca5);
#ifdef CONFIG_SND_SAMSUNG_SEIREN_DMA
	clk_put(si.clk_dmac);
	clk_put(si.clk_timer);
#endif
	return ret;
}
Beispiel #11
0
static long esa_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	int ret = 0;

	mutex_lock(&esa_mutex);
	pm_runtime_get_sync(&si.pdev->dev);

	switch (cmd) {
	case SEIREN_IOCTL_FX_EXT:
		si.fx_ext_on = arg ? true : false;
		writel(si.fx_ext_on ? 1 : 0, si.mailbox + EFFECT_EXT_ON);
		break;
	default:
		esa_err("%s: unknown cmd:%08X, arg:%08X\n",
			__func__, cmd, (unsigned int)arg);
		break;
	}

	pm_runtime_mark_last_busy(&si.pdev->dev);
	pm_runtime_put_sync_autosuspend(&si.pdev->dev);
	mutex_unlock(&esa_mutex);

	return ret;
}
Beispiel #12
0
int esa_compr_set_param(struct audio_processor* ap, uint8_t **buffer)
{
	unsigned int ip_type;
	unsigned char *ibuf;
	u32 ibuf_ca5_pa;
	u32 ibuf_offset;
	int ret;

	ptr_ap = ap;
	/* initialize in buffer */
	/* use free area in dram */
	ibuf = si.fwarea[1];
	ap->block_num = 1;

	/* calculate the physical address */
	ibuf_offset = ibuf - si.fwarea[ap->block_num];
	ibuf_ca5_pa = ibuf_offset + FWAREA_SIZE * ap->block_num;

	/* set buffer information at mailbox */
	spin_lock(&si.lock);
	writel(ap->buffer_size, si.mailbox + COMPR_SIZE_OF_INBUF);
	writel(ibuf_ca5_pa, si.mailbox + COMPR_PHY_ADDR_INBUF);
	writel(ap->sample_rate, si.mailbox + COMPR_PARAM_SAMPLE);
	writel(ap->num_channels, si.mailbox + COMPR_PARAM_CH);

	ip_type = ap->codec_id << 16;
	writel(ip_type, si.mailbox + COMPR_IP_TYPE);
	spin_unlock(&si.lock);

	si.isr_compr_created = 0;
	ret = esa_compr_send_cmd(CMD_COMPR_SET_PARAM, ap);
	if (ret) {
		esa_err("%s: can't send CMD_COMPR_SET_PARAM (%d)\n",
			__func__, ret);
		return ret;
	}

	/* wait until the parameter is set up */
	ret = wait_event_interruptible_timeout(esa_wq, si.isr_compr_created, HZ * 2);
	if (!ret) {
		esa_err("%s: compress set param timed out!!! (%d)\n",
			__func__, ret);
		writel(0, si.mailbox + COMPR_INTR_ACK);
		esa_dump_fw_log();
		si.fw_use_dram = true;
		ptr_ap = NULL;
		return -EBUSY;
	}

	/* created instance */
	ap->handle_id = readl(si.mailbox + COMPR_IP_ID);
	esa_info("%s: codec id:0x%x, ret_val:0x%x, handle_id:0x%x\n",
		__func__, (unsigned int)ap->codec_id,
		readl(si.mailbox + COMPR_RETURN_CMD),
		(unsigned int)ap->handle_id);

	/* return the buffer address for caller */
	*buffer = ibuf;
	esa_info("%s: allocated buffer address (0x%p), size(0x%x)\n",
		__func__, *buffer, ap->buffer_size);
#ifdef CONFIG_SND_ESA_SA_EFFECT
	si.effect_on = false;
#endif
	return 0;
}
Beispiel #13
0
static irqreturn_t esa_isr(int irqno, void *id)
{
	unsigned int fw_stat, log_size, val;
	bool wakeup = false;

#ifdef CONFIG_SND_SAMSUNG_SEIREN_OFFLOAD
	unsigned int size;
	int ret;
#endif
	writel(0, si.regs + SW_INTR_CPU);
	val = readl(si.mailbox + RETURN_CMD);
	if (val == 1)
		esa_err("%s: There is possibility of firmware CMD fail %u\n",
						__func__, val);
	fw_stat = val >> 16;
	esa_debug("fw_stat(%08x), val(%08x)\n", fw_stat, val);

	switch (fw_stat) {
	case INTR_WAKEUP:	/* handle wakeup interrupt from firmware  */
		si.isr_done = 1;
		wakeup = true;
		break;
	case INTR_READY:
		pr_debug("FW is ready!\n");
		si.fw_ready = true;
		wakeup = true;
		break;
#ifdef CONFIG_SND_SAMSUNG_SEIREN_DMA
	case INTR_DMA:
		val &= 0xFF;
		esa_debug("INTR_DMA (ch %d)\n", val);
		if (si.dma_cb[val])
			(*si.dma_cb[val])(si.dma_cb_param[val]);
		writel(0, si.mailbox + COMPR_INTR_DMA_ACK);
		break;
#endif
#ifdef CONFIG_SND_SAMSUNG_SEIREN_OFFLOAD
	case INTR_CREATED:
		esa_debug("INTR_CREATED\n");
		si.isr_compr_created = 1;
		wakeup = true;
		writel(0, si.mailbox + COMPR_INTR_ACK);
		break;
	case INTR_DECODED:
		/* check the error */
		val &= 0xFF;
		if (val) {
			esa_err("INTR_DECODED err(%d)\n", val);
			esa_dump_fw_log();
			writel(0, si.mailbox + COMPR_INTR_ACK);
			break;
		}
		/* update copied total bytes */
		size = readl(si.mailbox + COMPR_SIZE_OUT_DATA);
		esa_debug("INTR_DECODED(%d)\n", size);
		ret = ptr_ap->ops(fw_stat, size, ptr_ap->priv);
		if (ret)
			esa_err("INTR_DECODED handler err(%d)\n", ret);

		writel(0, si.mailbox + COMPR_INTR_ACK);
		break;
	case INTR_FLUSH:
		/* check the error */
		val &= 0xFF;
		if (val) {
			esa_err("INTR_FLUSH err(%d)\n", val);
			esa_dump_fw_log();
			writel(0, si.mailbox + COMPR_INTR_ACK);
			break;
		}
		/* flush done */
		ret = ptr_ap->ops(fw_stat, 0, ptr_ap->priv);
		if (ret)
			esa_err("INTR_FLUSH handler err(%d)\n", ret);
		writel(0, si.mailbox + COMPR_INTR_ACK);
		break;
	case INTR_PAUSED:
		/* check the error */
		val &= 0xFF;
		if (val) {
			esa_err("INTR_PAUSED err(%d)\n", val);
			esa_dump_fw_log();
			writel(0, si.mailbox + COMPR_INTR_ACK);
			break;
		}
		/* paused */
		ret = ptr_ap->ops(fw_stat, 0, ptr_ap->priv);
		if (ret)
			esa_err("INTR_PAUSED handler err(%d)\n", ret);
		writel(0, si.mailbox + COMPR_INTR_ACK);
		break;
	case INTR_EOS:
		ret = ptr_ap->ops(fw_stat, 0, ptr_ap->priv);
		if (ret)
			esa_err("INTR_EOS handler err(%d)\n", ret);
		writel(0, si.mailbox + COMPR_INTR_ACK);
		break;
	case INTR_DESTROY:
		/* check the error */
		val &= 0xFF;
		if (val) {
			esa_err("INTR_DESTROY err(%d)\n", val);
			esa_dump_fw_log();
			writel(0, si.mailbox + COMPR_INTR_ACK);
			break;
		}
		/* destroied */
		ret = ptr_ap->ops(fw_stat, 0, ptr_ap->priv);
		if (ret)
			esa_err("INTR_DESTROY handler err(%d)\n",  ret);
		writel(0, si.mailbox + COMPR_INTR_ACK);
		break;
	case INTR_FX_EXT:
		esa_info("INTR_FX_EXT: fw_stat(%08x), val(%08x)\n",
				fw_stat, val);
		si.fx_next_idx = val & 0xF;
		si.fx_irq_done = true;
		if (waitqueue_active(&esa_fx_wq))
			wake_up_interruptible(&esa_fx_wq);
		writel(0, si.mailbox + COMPR_INTR_ACK);
		break;
#endif
	case INTR_FW_LOG:	/* print debug message from firmware */
		log_size = readl(si.mailbox + RETURN_CMD) & 0x00FF;
		if (!log_size) {
			esa_debug("FW: %s", si.fw_log);
			si.fw_log_pos = 0;
		} else {
			val = readl(si.mailbox + FW_LOG_VAL1);
			memcpy(si.fw_log + si.fw_log_pos, &val, 4);
			val = readl(si.mailbox + FW_LOG_VAL2);
			memcpy(si.fw_log + si.fw_log_pos + 4, &val, 4);
			si.fw_log_pos += log_size;
			si.fw_log[si.fw_log_pos] = '\0';
		}
		writel(0, si.mailbox + RETURN_CMD);
		break;
	default:
		esa_err("%s: unknown intr_stat = 0x%08X\n",
						__func__, fw_stat);
		break;
	}

	if (wakeup && waitqueue_active(&esa_wq))
		wake_up_interruptible(&esa_wq);

	return IRQ_HANDLED;
}
Beispiel #14
0
static int esa_set_params(struct file *file, unsigned int param,
							unsigned long arg)
{
	struct esa_rtd *rtd = file->private_data;
	int ret = 0;

	switch (param) {
	case PCM_PARAM_MAX_SAMPLE_RATE:
		esa_debug("PCM_PARAM_MAX_SAMPLE_RATE: arg:%ld\n", arg);
		break;
	case PCM_PARAM_MAX_NUM_OF_CH:
		esa_debug("PCM_PARAM_MAX_NUM_OF_CH: arg:%ld\n", arg);
		break;
	case PCM_PARAM_MAX_BIT_PER_SAMPLE:
		esa_debug("PCM_PARAM_MAX_BIT_PER_SAMPLE: arg:%ld\n", arg);
		break;
	case PCM_PARAM_SAMPLE_RATE:
		esa_debug("%s: sampling rate: %ld\n", __func__, arg);
		writel(rtd->handle_id, si.mailbox + HANDLE_ID);
		writel((unsigned int)arg, si.mailbox + PARAMS_VAL1);
		esa_send_cmd((param << 16) | CMD_SET_PARAMS);
		break;
	case PCM_PARAM_NUM_OF_CH:
		esa_debug("%s: channel: %ld\n", __func__, arg);
		writel(rtd->handle_id, si.mailbox + HANDLE_ID);
		writel((unsigned int)arg, si.mailbox + PARAMS_VAL1);
		esa_send_cmd((param << 16) | CMD_SET_PARAMS);
		break;
	case PCM_PARAM_BIT_PER_SAMPLE:
		esa_debug("PCM_PARAM_BIT_PER_SAMPLE: arg:%ld\n", arg);
		break;
	case PCM_MAX_CONFIG_INFO:
		esa_debug("PCM_MAX_CONFIG_INFO: arg:%ld\n", arg);
		break;
	case PCM_CONFIG_INFO:
		esa_debug("PCM_CONFIG_INFO: arg:%ld\n", arg);
		break;
	case EQ_PARAM_NUM_OF_PRESETS:
		esa_debug("EQ_PARAM_NUM_OF_PRESETS: arg:%ld\n", arg);
		break;
	case EQ_PARAM_MAX_NUM_OF_BANDS:
		esa_debug("EQ_PARAM_MAX_NUM_OF_BANDS: arg:%ld\n", arg);
		break;
	case EQ_PARAM_RANGE_OF_BANDLEVEL:
		esa_debug("EQ_PARAM_RANGE_OF_BANDLEVEL: arg:%ld\n", arg);
		break;
	case EQ_PARAM_RANGE_OF_FREQ:
		esa_debug("EQ_PARAM_RANGE_OF_FREQ: arg:%ld\n", arg);
		break;
	case EQ_PARAM_PRESET_ID:
		esa_debug("%s: eq preset: %ld\n", __func__, arg);
		writel(rtd->handle_id, si.mailbox + HANDLE_ID);
		writel((unsigned int)arg, si.mailbox + PARAMS_VAL1);
		esa_send_cmd((param << 16) | CMD_SET_PARAMS);
		break;
	case EQ_PARAM_NUM_OF_BANDS:
		esa_debug("EQ_PARAM_NUM_OF_BANDS: arg:%ld\n", arg);
		break;
	case EQ_PARAM_CENTER_FREQ:
		esa_debug("EQ_PARAM_CENTER_FREQ: arg:%ld\n", arg);
		break;
	case EQ_PARAM_BANDLEVEL:
		esa_debug("EQ_PARAM_BANDLEVEL: arg:%ld\n", arg);
		break;
	case EQ_PARAM_BANDWIDTH:
		esa_debug("EQ_PARAM_BANDWIDTH: arg:%ld\n", arg);
		break;
	case EQ_MAX_CONFIG_INFO:
		esa_debug("EQ_MAX_CONFIG_INFO: arg:%ld\n", arg);
		break;
	case EQ_CONFIG_INFO:
		esa_debug("EQ_CONFIG_INFO: arg:%ld\n", arg);
		break;
	case EQ_BAND_INFO:
		esa_debug("EQ_BAND_INFO: arg:%ld\n", arg);
		break;
	case ADEC_PARAM_SET_EOS:
		writel(rtd->handle_id, si.mailbox + HANDLE_ID);
		esa_send_cmd((param << 16) | CMD_SET_PARAMS);
		esa_debug("ADEC_PARAM_SET_EOS: handle_id:%x\n", rtd->handle_id);
		rtd->get_eos = EOS_YET;
		break;
	case SET_IBUF_POOL_INFO:
		esa_debug("SET_IBUF_POOL_INFO: arg:%ld\n", arg);
		break;
	case SET_OBUF_POOL_INFO:
		esa_debug("SET_OBUF_POOL_INFO: arg:%ld\n", arg);
		break;
	default:
		esa_err("%s: Unknown %ld\n", __func__, arg);
		break;
	}

	return ret;
}
Beispiel #15
0
static ssize_t esa_read(struct file *file, char *buffer,
				size_t size, loff_t *pos)
{
	struct esa_rtd *rtd = file->private_data;
	unsigned char *obuf;
	unsigned int *obuf_filled_size;
	bool *obuf_filled;

	unsigned char *obuf_;
	unsigned int *obuf_filled_size_;
	bool *obuf_filled_;

	mutex_lock(&esa_mutex);
	pm_runtime_get_sync(&si.pdev->dev);

	/* select OBUF0 or OBUF1 */
	if (rtd->select_obuf == 0) {
		obuf = rtd->obuf0;
		obuf_filled = &rtd->obuf0_filled;
		obuf_filled_size = &rtd->obuf0_filled_size;

		obuf_ = rtd->obuf1;
		obuf_filled_ = &rtd->obuf1_filled;
		obuf_filled_size_ = &rtd->obuf1_filled_size;
		esa_debug("%s: use obuf0\n", __func__);
	} else {
		obuf = rtd->obuf1;
		obuf_filled = &rtd->obuf1_filled;
		obuf_filled_size = &rtd->obuf1_filled_size;

		obuf_ = rtd->obuf0;
		obuf_filled_ = &rtd->obuf0_filled;
		obuf_filled_size_ = &rtd->obuf0_filled_size;
		esa_debug("%s: use obuf1\n", __func__);
	}

	/* select OBUF0 or OBUF1 for next reading */
	rtd->select_obuf = !rtd->select_obuf;

	/* later... invalidate obuf cache */

	/* send pcm data to user */
	if (copy_to_user((void *)buffer, obuf, *obuf_filled_size)) {
		esa_err("%s: failed to copy_to_user\n", __func__);
		goto err;
	}

	/* if meet eos, it sholud also collect data of another buff */
	if (rtd->get_eos && !*obuf_filled_) {
		rtd->get_eos = EOS_FINAL;
	}

	esa_debug("%s: handle_id[%x], idx:[%d], obuf:[%d], obuf_filled_size:[%d]\n",
			__func__, rtd->handle_id, rtd->idx, !rtd->select_obuf,
			(u32)*obuf_filled_size);
	*obuf_filled = false;

	pm_runtime_mark_last_busy(&si.pdev->dev);
	pm_runtime_put_sync_autosuspend(&si.pdev->dev);
	mutex_unlock(&esa_mutex);

	return *obuf_filled_size;
err:
	pm_runtime_mark_last_busy(&si.pdev->dev);
	pm_runtime_put_sync_autosuspend(&si.pdev->dev);
	mutex_unlock(&esa_mutex);
	return -EFAULT;
}
Beispiel #16
0
static ssize_t esa_write(struct file *file, const char *buffer,
					size_t size, loff_t *pos)
{
	struct esa_rtd *rtd = file->private_data;
	unsigned char *ibuf;
	unsigned char *obuf;
	unsigned int *obuf_filled_size;
	bool *obuf_filled;
	int response, consumed_size = 0;

	mutex_lock(&esa_mutex);
	pm_runtime_get_sync(&si.pdev->dev);

	if (rtd->obuf0_filled && rtd->obuf1_filled) {
		esa_err("%s: There is no unfilled obuf\n", __func__);
		goto err;
	}

	/* select IBUF0 or IBUF1 */
	if (rtd->select_ibuf == 0) {
		ibuf = rtd->ibuf0;
		obuf = rtd->obuf0;
		obuf_filled = &rtd->obuf0_filled;
		obuf_filled_size = &rtd->obuf0_filled_size;
		esa_debug("%s: use ibuf0\n", __func__);
	} else {
		ibuf = rtd->ibuf1;
		obuf = rtd->obuf1;
		obuf_filled = &rtd->obuf1_filled;
		obuf_filled_size = &rtd->obuf1_filled_size;
		esa_debug("%s: use ibuf1\n", __func__);
	}

	/* receive stream data from user */
	if (copy_from_user(ibuf, buffer, size)) {
		esa_err("%s: failed to copy_from_user\n", __func__);
		goto err;
	}

	/* select IBUF0 or IBUF1 for next writing */
	rtd->select_ibuf = !rtd->select_ibuf;

	/* send execute command to FW for decoding */
	response = esa_send_cmd_exe(rtd, ibuf, obuf, size);

	/* filled size in OBUF */
	*obuf_filled_size = readl(si.mailbox + SIZE_OUT_DATA);

	/* consumed size */
	consumed_size = readl(si.mailbox + CONSUMED_BYTE_IN);

	if (response == 0 && *obuf_filled_size > 0) {
		*obuf_filled = true;
	} else {
		if (consumed_size <= 0)
			consumed_size = response;
		if (rtd->need_config)
			rtd->need_config = false;
		else if (size != 0)
			esa_debug("%s: No output? response:%x\n", __func__, response);
	}

	pm_runtime_mark_last_busy(&si.pdev->dev);
	pm_runtime_put_sync_autosuspend(&si.pdev->dev);
	mutex_unlock(&esa_mutex);

	esa_debug("%s: handle_id[%x], idx:[%d], consumed:[%d], filled_size:[%d], ibuf:[%d]\n",
			__func__, rtd->handle_id, rtd->idx, consumed_size,
			*obuf_filled_size, !rtd->select_ibuf);

	return consumed_size;
err:
	pm_runtime_mark_last_busy(&si.pdev->dev);
	pm_runtime_put_sync_autosuspend(&si.pdev->dev);
	mutex_unlock(&esa_mutex);
	return -EFAULT;
}
Beispiel #17
0
int esa_compr_send_cmd(int32_t cmd, struct audio_processor* ap)
{
	int n, ack;

	switch (cmd) {
	case CMD_COMPR_CREATE:
		esa_info("%s: CMD_COMPR_CREATE %d\n", __func__, cmd);
		break;
	case CMD_COMPR_DESTROY:
		esa_info("%s: CMD_COMPR_DESTROY %d\n", __func__, cmd);
		break;
	case CMD_COMPR_SET_PARAM:
		esa_info("%s: CMD_COMPR_SET_PARAM %d\n", __func__, cmd);
		break;
	case CMD_COMPR_WRITE:
		esa_debug("%s: CMD_COMPR_WRITE %d\n", __func__, cmd);
		break;
	case CMD_COMPR_READ:
		esa_debug("%s: CMD_COMPR_READ %d\n", __func__, cmd);
		break;
	case CMD_COMPR_START:
		esa_info("%s: CMD_COMPR_START %d\n", __func__, cmd);
		break;
	case CMD_COMPR_STOP:
		esa_info("%s: CMD_COMPR_STOP %d\n", __func__, cmd);
		break;
	case CMD_COMPR_PAUSE:
		esa_info("%s: CMD_COMPR_PAUSE %d\n", __func__, cmd);
		break;
	case CMD_COMPR_EOS:
		esa_info("%s: CMD_COMPR_EOS %d\n", __func__, cmd);
		break;
	case CMD_COMPR_GET_VOLUME:
		esa_debug("%s: CMD_COMPR_GET_VOLUME %d\n", __func__, cmd);
		break;
	case CMD_COMPR_SET_VOLUME:
		esa_debug("%s: CMD_COMPR_SET_VOLUME %d\n", __func__, cmd);
		break;
	default:
		esa_err("%s: unknown cmd %d\n", __func__, cmd);
		return -EIO;
	}

	spin_lock(&si.cmd_lock);
	writel(ap->handle_id, si.mailbox + COMPR_HANDLE_ID);
	writel(cmd, si.mailbox + COMPR_CMD_CODE);		/* command */
	writel(1, si.regs + SW_INTR_CA5);		/* trigger ca5 */

	for (n = 0, ack = 0; n < 2000; n++) {
		if (readl(ap->reg_ack)) {	/* Wait for ACK */
			ack = 1;
			break;
		}
		udelay(100);
	}
	writel(0, ap->reg_ack);		/* clear ACK */

	spin_unlock(&si.cmd_lock);

	if (!ack) {
		esa_err("%s: No ack error!(%x)", __func__, cmd);
		esa_dump_fw_log();
		return -EFAULT;
	}

	return 0;
}
Beispiel #18
0
static int esa_exe(struct file *file, unsigned int param,
							unsigned long arg)
{
	struct esa_rtd *rtd = file->private_data;
	struct audio_mem_info_t ibuf_info, obuf_info;
	int response, obuf_filled_size;
	unsigned char *ibuf = rtd->ibuf0;
	unsigned char *obuf = rtd->obuf0;
	int ret = 0;

	mutex_lock(&esa_mutex);

	/* receive ibuf_info from user */
	if (copy_from_user(&ibuf_info, (struct audio_mem_info_t *)arg,
					sizeof(struct audio_mem_info_t))) {
		esa_err("%s: failed to copy_from_user ibuf_info\n", __func__);
		goto err;
	}

	/* receive obuf_info from user */
	arg += sizeof(struct audio_mem_info_t);
	if (copy_from_user(&obuf_info, (struct audio_mem_info_t *)arg,
					sizeof(struct audio_mem_info_t))) {
		esa_err("%s: failed to copy_from_user obuf_info\n", __func__);
		goto err;
	}

	/* prevent test alarmed about tainted data */
	if (ibuf_info.mem_size > rtd->ibuf_size) {
		ibuf_info.mem_size = rtd->ibuf_size;
		esa_err("%s: There is too much input data", __func__);
	}

	/* receive pcm data from user */
	if (copy_from_user(ibuf, (void *)(u64)ibuf_info.virt_addr,
					ibuf_info.mem_size)) {
		esa_err("%s: failed to copy_from_user\n", __func__);
		goto err;
	}

	/* send execute command to FW for decoding */
	response = esa_send_cmd_exe(rtd, ibuf, obuf, ibuf_info.mem_size);

	/* filled size in OBUF */
	obuf_filled_size = readl(si.mailbox + SIZE_OUT_DATA);

	/* later... invalidate obuf cache */

	if (!response && obuf_filled_size > 0) {
		esa_debug("%s: cmd_exe OK!\n", __func__);
		/* send pcm data to user */
		if (copy_to_user((void *)(u64)obuf_info.virt_addr,
					obuf, obuf_filled_size)) {
			esa_err("%s: failed to copy_to_user obuf pcm\n",
					__func__);
			goto err;
		}
	} else {
		esa_debug("%s: cmd_exe Fail: %d\n", __func__, response);
	}

	esa_debug("%s: handle_id[%x], idx:[%d], filled_size:[%d]\n",
			__func__, rtd->handle_id, rtd->idx, obuf_filled_size);

	return ret;
err:
	mutex_unlock(&esa_mutex);
	return -EFAULT;
}
Beispiel #19
0
static int esa_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct device_node *np = pdev->dev.of_node;
	struct resource *res;
	int ret = 0;

	printk(banner);

	spin_lock_init(&si.lock);
#if defined(CONFIG_SND_SAMSUNG_SEIREN_DMA) || \
	defined(CONFIG_SND_SAMSUNG_SEIREN_OFFLOAD)
	spin_lock_init(&si.cmd_lock);
	spin_lock_init(&si.compr_lock);
#endif
	si.pdev = pdev;

	ret = misc_register(&esa_miscdev);
	if (ret) {
		esa_err("Cannot register miscdev\n");
		return -ENODEV;
	}

	si.regs = lpass_get_regs();
	if (!si.regs) {
		esa_err("Failed to get lpass regs\n");
		return -ENODEV;
	}

	si.sram = lpass_get_mem();
	if (!si.sram) {
		esa_err("Failed to get lpass sram\n");
		return -ENODEV;
	}

#ifdef CONFIG_SND_SAMSUNG_SEIREN_DMA
	si.dma_param = si.sram + DMA_PARAM_OFFSET;
#endif

#ifdef CONFIG_SND_ESA_SA_EFFECT
	si.effect_ram = si.sram + EFFECT_OFFSET;
#endif

	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	if (!res) {
		dev_err(dev, "Failed to get irq resource\n");
		return -ENXIO;
	}
	si.irq_ca5 = res->start;
	si.mailbox = si.regs + 0x80;

	si.clk_ca5 = clk_get(dev, "ca5");
	if (IS_ERR(si.clk_ca5)) {
		dev_err(dev, "ca5 clk not found\n");
		return -ENODEV;
	}

	si.opclk_ca5 = clk_get(dev, "ca5_opclk");
	if (IS_ERR(si.opclk_ca5)) {
		dev_err(dev, "ca5 opclk not found\n");
		clk_put(si.clk_ca5);
		return -ENODEV;
	}
#ifdef CONFIG_SND_SAMSUNG_SEIREN_DMA
	si.clk_dmac = clk_get(dev, "dmac");
	if (IS_ERR(si.clk_dmac)) {
		dev_err(dev, "dmac clk not found\n");
		clk_put(si.opclk_ca5);
		clk_put(si.clk_ca5);
		return -ENODEV;
	}

	si.clk_timer = clk_get(dev, "timer");
	if (IS_ERR(si.clk_timer)) {
		dev_err(dev, "timer clk not found\n");
		clk_put(si.clk_dmac);
		clk_put(si.opclk_ca5);
		clk_put(si.clk_ca5);
		return -ENODEV;
	}
#endif
	if (np) {
		if (of_find_property(np, "samsung,lpass-subip", NULL))
			lpass_register_subip(dev, "ca5");
	}

#ifdef CONFIG_SND_SAMSUNG_IOMMU
	si.domain = lpass_get_iommu_domain();
	if (!si.domain) {
		dev_err(dev, "iommu not available\n");
		goto err;
	}

	/* prepare buffer */
	if (esa_prepare_buffer(dev))
		goto err;
#else
	dev_err(dev, "iommu not available\n");
	goto err;
#endif

	ret = request_firmware_nowait(THIS_MODULE,
				      FW_ACTION_HOTPLUG,
				      FW_SRAM_NAME,
				      dev,
				      GFP_KERNEL,
				      dev,
				      esa_fw_request_complete);
	if (ret) {
		dev_err(dev, "could not load firmware\n");
		goto err;
	}

	ret = request_irq(si.irq_ca5, esa_isr, 0, "lpass-ca5", 0);
	if (ret < 0) {
		esa_err("Failed to claim CA5 irq\n");
		goto err;
	}

#ifdef CONFIG_PROC_FS
	si.proc_file = proc_create("driver/seiren", 0, NULL, &esa_proc_fops);
	if (!si.proc_file)
		esa_info("Failed to register /proc/driver/seiren\n");
#endif
	/* hold reset */
	lpass_reset(LPASS_IP_CA5, LPASS_OP_RESET);

	esa_debug("regs       = %p\n", si.regs);
	esa_debug("mailbox    = %p\n", si.mailbox);
	esa_debug("bufmem_pa  = %p\n", (void*)si.bufmem_pa);
	esa_debug("fwmem_pa   = %p\n", (void*)si.fwmem_pa);
	esa_debug("ca5 opclk  = %ldHz\n", clk_get_rate(si.opclk_ca5));

#ifdef CONFIG_PM_RUNTIME
	pm_runtime_use_autosuspend(dev);
	pm_runtime_set_autosuspend_delay(dev, 300);
	pm_runtime_enable(dev);
	pm_runtime_get_sync(dev);
	pm_runtime_put_sync(dev);
#else
	esa_do_resume(dev);
#endif
#ifdef CONFIG_PM_DEVFREQ
	si.mif_qos = 0;
	si.int_qos = 0;
	pm_qos_add_request(&si.ca5_mif_qos, PM_QOS_BUS_THROUGHPUT, 0);
	pm_qos_add_request(&si.ca5_int_qos, PM_QOS_DEVICE_THROUGHPUT, 0);
#endif
	return 0;

err:
#ifdef CONFIG_SND_SAMSUNG_SEIREN_DMA
	clk_put(si.clk_timer);
	clk_put(si.clk_dmac);
#endif
	clk_put(si.opclk_ca5);
	clk_put(si.clk_ca5);
	return -ENODEV;
}
static int compr_free(struct snd_compr_stream *cstream)
{
    struct snd_compr_runtime *runtime = cstream->runtime;
    struct runtime_data *prtd = runtime->private_data;
    struct snd_pcm_substream *substream;
    struct snd_soc_dai *cpu_dai;
    struct snd_soc_dai *codec_dai;
    const struct snd_soc_dai_ops *cpu_dai_ops;
    const struct snd_soc_dai_ops *codec_dai_ops;
    unsigned long flags;
    int ret;
#ifdef AUDIO_PERF
    u64 playback_time, total_time = 0;
    int idx;
#endif
    pr_debug("%s\n", __func__);

    if (!prtd) {
        pr_info("compress dai has already freed.\n");
        return 0;
    }

    substream = &prtd->substream;
    cpu_dai = prtd->cpu_dai;
    codec_dai = prtd->codec_dai;
    cpu_dai_ops = cpu_dai->driver->ops;
    codec_dai_ops = codec_dai->driver->ops;

    if (atomic_read(&prtd->eos)) {
        /* ALSA Framework callback to notify drain complete */
        snd_compr_drain_notify(cstream);
        atomic_set(&prtd->eos, 0);
        pr_debug("%s Call Drain notify to wakeup\n", __func__);
    }

    if (atomic_read(&prtd->created)) {
        spin_lock_irqsave(&prtd->lock, flags);
        atomic_set(&prtd->created, 0);
        prtd->exit_ack = 0;
        ret = esa_compr_send_cmd(CMD_COMPR_DESTROY, prtd->ap);
        if (ret) {
            esa_err("%s: can't send CMD_COMPR_DESTROY (%d)\n",
                    __func__, ret);
            spin_unlock_irqrestore(&prtd->lock, flags);
        } else {
            spin_unlock_irqrestore(&prtd->lock, flags);
            ret = wait_event_interruptible_timeout(prtd->exit_wait,
                                                   prtd->exit_ack, 1 * HZ);
            if (!ret)
                pr_err("%s: CMD_DESTROY timed out!!!\n", __func__);
        }
    }

#ifdef CONFIG_SND_ESA_SA_EFFECT
    aud_vol.ap[COMPR_DAI_MULTIMEDIA_1] = NULL;
#endif
    esa_compr_set_state(false);
    /* codec hw_free -> cpu hw_free ->
       cpu shutdown -> codec shutdown */
    if (codec_dai_ops->hw_free)
        (*codec_dai_ops->hw_free)(substream, codec_dai);

    if (cpu_dai_ops->hw_free)
        (*cpu_dai_ops->hw_free)(substream, cpu_dai);

    if (cpu_dai_ops->shutdown)
        (*cpu_dai_ops->shutdown)(substream, cpu_dai);

    if (codec_dai_ops->shutdown)
        (*codec_dai_ops->shutdown)(substream, codec_dai);

    if (substream->runtime)
        kfree(substream->runtime->hw_constraints.rules);
    kfree(substream->runtime);
    esa_compr_close();
#ifdef AUDIO_PERF
    prtd->end_time[OPEN_T] = sched_clock();
    playback_time = prtd->end_time[OPEN_T] - prtd->start_time[OPEN_T];

    for (idx = 0; idx < TOTAL_TIMES; idx++) {
        total_time += prtd->total_time[idx];
    }
    pr_debug("%s: measure the audio waken time : %llu\n", __func__,
             total_time);
    pr_debug("%s: may be the ap sleep time : (%llu/%llu)\n", __func__,
             playback_time - total_time, playback_time);
#endif
    kfree(prtd->ap);
    kfree(prtd);
    return 0;
}
Beispiel #21
0
static int esa_get_params(struct file *file, unsigned int param,
							unsigned long arg)
{
	struct esa_rtd *rtd = file->private_data;
	struct audio_mem_info_t *argp = (struct audio_mem_info_t *)arg;
	struct audio_pcm_config_info_t *argp_pcm_info;
	unsigned long val;
	int ret = 0;

	switch (param) {
	case PCM_PARAM_MAX_SAMPLE_RATE:
		esa_debug("PCM_PARAM_MAX_SAMPLE_RATE: arg:%ld\n", arg);
		break;
	case PCM_PARAM_MAX_NUM_OF_CH:
		esa_debug("PCM_PARAM_MAX_NUM_OF_CH: arg:%ld\n", arg);
		break;
	case PCM_PARAM_MAX_BIT_PER_SAMPLE:
		esa_debug("PCM_PARAM_MAX_BIT_PER_SAMPLE: arg:%ld\n", arg);
		break;
	case PCM_PARAM_SAMPLE_RATE:
		writel(rtd->handle_id, si.mailbox + HANDLE_ID);
		esa_send_cmd((param << 16) | CMD_GET_PARAMS);
		val = readl(si.mailbox + PARAMS_VAL1);
		esa_debug("%s: sampling rate:%ld\n", __func__, val);

		if (val >= SAMPLE_RATE_MIN) {
			esa_debug("SAMPLE_RATE: SUCCESS: arg:0x%p\n", (void*)arg);
			ret = copy_to_user((unsigned long *)arg, &val,
						sizeof(unsigned long));
		} else
			esa_debug("SAMPLE_RATE: FAILED: arg:0x%p\n", (void*)arg);
		break;
	case PCM_PARAM_NUM_OF_CH:
		writel(rtd->handle_id, si.mailbox + HANDLE_ID);
		esa_send_cmd((param << 16) | CMD_GET_PARAMS);
		val = readl(si.mailbox + PARAMS_VAL1);
		esa_debug("%s: Channel:%ld\n", __func__, val);

		if (val >= CH_NUM_MIN) {
			esa_debug("PCM_CONFIG_NUM_CH: SUCCESS: arg:0x%p\n", (void*)arg);
			ret = copy_to_user((unsigned long *)arg, &val,
						sizeof(unsigned long));
		} else
			esa_debug("PCM_PARAM_NUM_CH: FAILED: arg:0x%p\n", (void*)arg);
		break;
	case PCM_PARAM_BIT_PER_SAMPLE:
		esa_debug("PCM_PARAM_BIT_PER_SAMPLE: arg:%ld\n", arg);
		break;
	case PCM_MAX_CONFIG_INFO:
		esa_debug("PCM_MAX_CONFIG_INFO: arg:%ld\n", arg);
		break;
	case PCM_CONFIG_INFO:
		argp_pcm_info = (struct audio_pcm_config_info_t *)arg;
		rtd->pcm_info.sample_rate = readl(si.mailbox + FREQ_SAMPLE);
		rtd->pcm_info.num_of_channel = readl(si.mailbox + CH_NUM);
		esa_debug("%s: rate:%d, ch:%d\n", __func__,
					rtd->pcm_info.sample_rate,
					rtd->pcm_info.num_of_channel);
		if (rtd->pcm_info.sample_rate >= 8000 &&
			rtd->pcm_info.num_of_channel > 0) {
			esa_debug("PCM_CONFIG_INFO: SUCCESS: arg:0x%p\n", (void*)arg);
			ret = copy_to_user(argp_pcm_info, &rtd->ibuf_info,
					sizeof(struct audio_pcm_config_info_t));
		} else
			esa_debug("PCM_CONFIG_INFO: FAILED: arg:0x%p\n", (void*)arg);
		break;
	case ADEC_PARAM_GET_OUTPUT_STATUS:
		writel(rtd->handle_id, si.mailbox + HANDLE_ID);
		esa_send_cmd((param << 16) | CMD_GET_PARAMS);
		val = readl(si.mailbox + PARAMS_VAL1);
		esa_debug("OUTPUT_STATUS:%ld, handle_id:%x\n", val, rtd->handle_id);
		if (val && rtd->get_eos == EOS_YET)
			val = 0;
		ret = copy_to_user((unsigned long *)arg, &val,
					sizeof(unsigned long));
		break;
	case GET_IBUF_POOL_INFO:
		esa_debug("GET_IBUF_POOL_INFO: arg:0x%p\n", (void*)arg);
		rtd->ibuf_info.mem_size = rtd->ibuf_size;
		rtd->ibuf_info.block_count = rtd->ibuf_count;
		ret = copy_to_user(argp, &rtd->ibuf_info,
					sizeof(struct audio_mem_info_t));
		break;
	case GET_OBUF_POOL_INFO:
		esa_debug("GET_OBUF_POOL_INFO: arg:0x%p\n", (void*)arg);
		rtd->obuf_info.mem_size = rtd->obuf_size;
		rtd->obuf_info.block_count = rtd->obuf_count;
		ret = copy_to_user(argp, &rtd->obuf_info,
					sizeof(struct audio_mem_info_t));
		break;
	default:
		esa_err("%s: Unknown %ld\n", __func__, arg);
		break;
	}

	if (ret)
		esa_err("%s: failed to copy_to_user\n", __func__);

	return ret;
}