mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 11:50:43 +09:00
audio: merge from mainline
PD#SWPL-15312 Change-Id: I827a1db0d6c948682812ea04a6db2c7b5757dbfb Signed-off-by: Lei Qian <lei.qian@amlogic.com>
This commit is contained in:
@@ -142,6 +142,8 @@ source "drivers/amlogic/dolby_fw/Kconfig"
|
||||
|
||||
source "drivers/amlogic/ircut/Kconfig"
|
||||
|
||||
source "drivers/amlogic/hifi4dsp/Kconfig"
|
||||
|
||||
source "drivers/amlogic/pixel_probe/Kconfig"
|
||||
|
||||
source "drivers/amlogic/firmware/Kconfig"
|
||||
|
||||
@@ -106,6 +106,8 @@ obj-$(CONFIG_AMLOGIC_BT_DEVICE) += bluetooth/
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_WIFI) += wifi/
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_HIFI4DSP) += hifi4dsp/
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_POWER) += power/
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_PCIE) += pci/
|
||||
|
||||
11
drivers/amlogic/hifi4dsp/Kconfig
Normal file
11
drivers/amlogic/hifi4dsp/Kconfig
Normal file
@@ -0,0 +1,11 @@
|
||||
# audio hifi4dsp configuration
|
||||
#
|
||||
menu "AMLOGIC HiFi4DSP process"
|
||||
|
||||
config AMLOGIC_HIFI4DSP
|
||||
tristate "hifi4dsp control support"
|
||||
default n
|
||||
help
|
||||
support the amlogic hifi4dsp;
|
||||
|
||||
endmenu
|
||||
19
drivers/amlogic/hifi4dsp/Makefile
Normal file
19
drivers/amlogic/hifi4dsp/Makefile
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
# Makefile for tm2 hifi4dsp
|
||||
|
||||
hifi4dsp-objs = hifi4dsp_module.o \
|
||||
hifi4dsp_firmware.o \
|
||||
hifi4dsp_dsp.o \
|
||||
hifi4dsp_ipc.o \
|
||||
tm2_dsp_top.o
|
||||
|
||||
#audiodsp-objs += pcmenc_module.o pcmenc_stream.o
|
||||
#audiodsp-objs += spdif_module.o
|
||||
|
||||
ifneq ($(KBUILD_SRC),)
|
||||
TOP_KBUILD_SRC := $(KBUILD_SRC)/
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_HIFI4DSP) +=hifi4dsp.o
|
||||
|
||||
#EXTRA_CFLAGS = -DENABLE_WAIT_FORMAT
|
||||
43
drivers/amlogic/hifi4dsp/hifi4dsp_api.h
Normal file
43
drivers/amlogic/hifi4dsp/hifi4dsp_api.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* drivers/amlogic/hifi4dsp/hifi4dsp_api.h
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AML_HIFI4DSP_API_H__
|
||||
#define __AML_HIFI4DSP_API_H__
|
||||
|
||||
struct hifi4dsp_info_t {
|
||||
char id; /*dsp_id 0,1,2...*/
|
||||
char fw_id;
|
||||
char fw_name[32]; /*name of firmware which used for dsp*/
|
||||
long phy_addr; /*phy address of firmware wille be loaded on*/
|
||||
};
|
||||
|
||||
#define HIFI4DSP_IOC_MAGIC 'H'
|
||||
|
||||
#define HIFI4DSP_LOAD _IOWR(HIFI4DSP_IOC_MAGIC, 1, struct hifi4dsp_info_t)
|
||||
#define HIFI4DSP_RESET _IOWR(HIFI4DSP_IOC_MAGIC, 2, struct hifi4dsp_info_t)
|
||||
#define HIFI4DSP_START _IOWR(HIFI4DSP_IOC_MAGIC, 3, struct hifi4dsp_info_t)
|
||||
#define HIFI4DSP_STOP _IOWR(HIFI4DSP_IOC_MAGIC, 4, struct hifi4dsp_info_t)
|
||||
#define HIFI4DSP_SLEEP _IOWR(HIFI4DSP_IOC_MAGIC, 5, struct hifi4dsp_info_t)
|
||||
#define HIFI4DSP_WAKE _IOWR(HIFI4DSP_IOC_MAGIC, 6, struct hifi4dsp_info_t)
|
||||
|
||||
#define HIFI4DSP_GET_INFO _IOWR((HIFI4DSP_IOC_MAGIC), (18), \
|
||||
struct hifi4dsp_info_t)
|
||||
|
||||
#define HIFI4DSP_TEST _IO(HIFI4DSP_IOC_MAGIC, 255)
|
||||
|
||||
|
||||
#endif /*__AML_AUDIO_HIFI4DSP_API_H__ */
|
||||
397
drivers/amlogic/hifi4dsp/hifi4dsp_dsp.c
Normal file
397
drivers/amlogic/hifi4dsp/hifi4dsp_dsp.c
Normal file
@@ -0,0 +1,397 @@
|
||||
/*
|
||||
* drivers/amlogic/hifi4dsp/hifi4dsp_dsp.c
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
#define DEBUG
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/amlogic/major.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include "hifi4dsp_priv.h"
|
||||
#include "hifi4dsp_firmware.h"
|
||||
#include "hifi4dsp_dsp.h"
|
||||
|
||||
//static struct hifi4dsp_dsp *dsp_g;
|
||||
|
||||
/* Internal generic low-level hifi4dsp share memory write/read functions*/
|
||||
void hifi4dsp_smem_write(void __iomem *addr, u32 offset, u32 value)
|
||||
{
|
||||
writel(value, addr + offset);
|
||||
}
|
||||
EXPORT_SYMBOL(hifi4dsp_smem_write);
|
||||
|
||||
u32 hifi4dsp_smem_read(void __iomem *addr, u32 offset)
|
||||
{
|
||||
return readl(addr + offset);
|
||||
}
|
||||
EXPORT_SYMBOL(hifi4dsp_smem_read);
|
||||
|
||||
void hifi4dsp_smem_write64(void __iomem *addr, u32 offset, u64 value)
|
||||
{
|
||||
memcpy_toio(addr + offset, &value, sizeof(value));
|
||||
}
|
||||
EXPORT_SYMBOL(hifi4dsp_smem_write64);
|
||||
|
||||
u64 hifi4dsp_smem_read64(void __iomem *addr, u32 offset)
|
||||
{
|
||||
u64 val;
|
||||
|
||||
memcpy_fromio(&val, addr + offset, sizeof(val));
|
||||
return val;
|
||||
}
|
||||
EXPORT_SYMBOL(hifi4dsp_smem_read64);
|
||||
|
||||
static inline void _hifi4dsp_memcpy_toio_32(u32 __iomem *dest,
|
||||
u32 *src, size_t bytes)
|
||||
{
|
||||
int i, words = bytes >> 2;
|
||||
|
||||
for (i = 0; i < words; i++)
|
||||
writel(src[i], dest + i);
|
||||
}
|
||||
|
||||
static inline void _hifi4dsp_memcpy_fromio_32(u32 *dest,
|
||||
const __iomem u32 *src, size_t bytes)
|
||||
{
|
||||
int i, words = bytes >> 2;
|
||||
|
||||
for (i = 0; i < words; i++)
|
||||
dest[i] = readl(src + i);
|
||||
}
|
||||
|
||||
void hifi4dsp_memcpy_toio_32(struct hifi4dsp_dsp *dsp,
|
||||
void __iomem *dest, void *src, size_t bytes)
|
||||
{
|
||||
_hifi4dsp_memcpy_toio_32(dest, src, bytes);
|
||||
}
|
||||
EXPORT_SYMBOL(hifi4dsp_memcpy_toio_32);
|
||||
|
||||
void hifi4dsp_memcpy_fromio_32(struct hifi4dsp_dsp *dsp, void *dest,
|
||||
void __iomem *src, size_t bytes)
|
||||
{
|
||||
_hifi4dsp_memcpy_fromio_32(dest, src, bytes);
|
||||
}
|
||||
EXPORT_SYMBOL(hifi4dsp_memcpy_fromio_32);
|
||||
|
||||
/* Public API */
|
||||
void hifi4dsp_dsp_smem_write(struct hifi4dsp_dsp *dsp, u32 offset, u32 value)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dsp->spinlock, flags);
|
||||
dsp->ops->write(dsp->addr.smem, offset, value);
|
||||
spin_unlock_irqrestore(&dsp->spinlock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(hifi4dsp_dsp_smem_write);
|
||||
|
||||
u32 hifi4dsp_dsp_smem_read(struct hifi4dsp_dsp *dsp, u32 offset)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&dsp->spinlock, flags);
|
||||
val = dsp->ops->read(dsp->addr.smem, offset);
|
||||
spin_unlock_irqrestore(&dsp->spinlock, flags);
|
||||
|
||||
return val;
|
||||
}
|
||||
EXPORT_SYMBOL(hifi4dsp_dsp_smem_read);
|
||||
|
||||
void hifi4dsp_dsp_smem_write64(struct hifi4dsp_dsp *dsp, u32 offset, u64 value)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dsp->spinlock, flags);
|
||||
dsp->ops->write64(dsp->addr.smem, offset, value);
|
||||
spin_unlock_irqrestore(&dsp->spinlock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(hifi4dsp_dsp_smem_write64);
|
||||
|
||||
u64 hifi4dsp_dsp_smem_read64(struct hifi4dsp_dsp *dsp, u32 offset)
|
||||
{
|
||||
unsigned long flags;
|
||||
u64 val;
|
||||
|
||||
spin_lock_irqsave(&dsp->spinlock, flags);
|
||||
val = dsp->ops->read64(dsp->addr.smem, offset);
|
||||
spin_unlock_irqrestore(&dsp->spinlock, flags);
|
||||
|
||||
return val;
|
||||
}
|
||||
EXPORT_SYMBOL(hifi4dsp_dsp_smem_read64);
|
||||
|
||||
void hifi4dsp_dsp_smem_write_unlocked(struct hifi4dsp_dsp *dsp,
|
||||
u32 offset, u32 value)
|
||||
{
|
||||
dsp->ops->write(dsp->addr.smem, offset, value);
|
||||
}
|
||||
EXPORT_SYMBOL(hifi4dsp_dsp_smem_write_unlocked);
|
||||
|
||||
u32 hifi4dsp_dsp_smem_read_unlocked(struct hifi4dsp_dsp *dsp,
|
||||
u32 offset)
|
||||
{
|
||||
return dsp->ops->read(dsp->addr.smem, offset);
|
||||
}
|
||||
EXPORT_SYMBOL(hifi4dsp_dsp_smem_read_unlocked);
|
||||
|
||||
void hifi4dsp_dsp_smem_write64_unlocked(struct hifi4dsp_dsp *dsp,
|
||||
u32 offset, u64 value)
|
||||
{
|
||||
dsp->ops->write64(dsp->addr.smem, offset, value);
|
||||
}
|
||||
EXPORT_SYMBOL(hifi4dsp_dsp_smem_write64_unlocked);
|
||||
|
||||
u64 hifi4dsp_dsp_smem_read64_unlocked(struct hifi4dsp_dsp *dsp,
|
||||
u32 offset)
|
||||
{
|
||||
return dsp->ops->read64(dsp->addr.smem, offset);
|
||||
}
|
||||
EXPORT_SYMBOL(hifi4dsp_dsp_smem_read64_unlocked);
|
||||
|
||||
int hifi4dsp_dsp_smem_update_bits_unlocked(struct hifi4dsp_dsp *dsp,
|
||||
u32 offset, u32 mask, u32 value)
|
||||
{
|
||||
bool change;
|
||||
unsigned int old, new;
|
||||
u32 ret;
|
||||
|
||||
ret = hifi4dsp_dsp_smem_read_unlocked(dsp, offset);
|
||||
|
||||
old = ret;
|
||||
new = (old & (~mask)) | (value & mask);
|
||||
|
||||
change = (old != new);
|
||||
if (change)
|
||||
hifi4dsp_dsp_smem_write_unlocked(dsp, offset, new);
|
||||
|
||||
return change;
|
||||
}
|
||||
EXPORT_SYMBOL(hifi4dsp_dsp_smem_update_bits_unlocked);
|
||||
|
||||
void hifi4dsp_dsp_smem_update_bits_forced_unlocked(struct hifi4dsp_dsp *dsp,
|
||||
u32 offset, u32 mask, u32 value)
|
||||
{
|
||||
unsigned int old, new;
|
||||
u32 ret;
|
||||
|
||||
ret = hifi4dsp_dsp_smem_read_unlocked(dsp, offset);
|
||||
|
||||
old = ret;
|
||||
new = (old & (~mask)) | (value & mask);
|
||||
|
||||
hifi4dsp_dsp_smem_write_unlocked(dsp, offset, new);
|
||||
}
|
||||
EXPORT_SYMBOL(hifi4dsp_dsp_smem_update_bits_forced_unlocked);
|
||||
|
||||
int hifi4dsp_dsp_smem_update_bits64_unlocked(struct hifi4dsp_dsp *dsp,
|
||||
u32 offset, u64 mask, u64 value)
|
||||
{
|
||||
bool change;
|
||||
u64 old, new;
|
||||
|
||||
old = hifi4dsp_dsp_smem_read64_unlocked(dsp, offset);
|
||||
|
||||
new = (old & (~mask)) | (value & mask);
|
||||
|
||||
change = (old != new);
|
||||
if (change)
|
||||
hifi4dsp_dsp_smem_write64_unlocked(dsp, offset, new);
|
||||
|
||||
return change;
|
||||
}
|
||||
EXPORT_SYMBOL(hifi4dsp_dsp_smem_update_bits64_unlocked);
|
||||
|
||||
int hifi4dsp_dsp_smem_update_bits(struct hifi4dsp_dsp *dsp, u32 offset,
|
||||
u32 mask, u32 value)
|
||||
{
|
||||
unsigned long flags;
|
||||
bool change;
|
||||
|
||||
spin_lock_irqsave(&dsp->spinlock, flags);
|
||||
change = hifi4dsp_dsp_smem_update_bits_unlocked(dsp,
|
||||
offset, mask, value);
|
||||
spin_unlock_irqrestore(&dsp->spinlock, flags);
|
||||
return change;
|
||||
}
|
||||
EXPORT_SYMBOL(hifi4dsp_dsp_smem_update_bits);
|
||||
|
||||
void hifi4dsp_dsp_smem_update_bits_forced(struct hifi4dsp_dsp *dsp,
|
||||
u32 offset, u32 mask, u32 value)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dsp->spinlock, flags);
|
||||
hifi4dsp_dsp_smem_update_bits_forced_unlocked(dsp, offset, mask, value);
|
||||
spin_unlock_irqrestore(&dsp->spinlock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(hifi4dsp_dsp_smem_update_bits_forced);
|
||||
|
||||
int hifi4dsp_dsp_smem_update_bits64(struct hifi4dsp_dsp *dsp,
|
||||
u32 offset, u64 mask, u64 value)
|
||||
{
|
||||
unsigned long flags;
|
||||
bool change;
|
||||
|
||||
spin_lock_irqsave(&dsp->spinlock, flags);
|
||||
change = hifi4dsp_dsp_smem_update_bits64_unlocked(dsp,
|
||||
offset, mask, value);
|
||||
spin_unlock_irqrestore(&dsp->spinlock, flags);
|
||||
return change;
|
||||
}
|
||||
EXPORT_SYMBOL(hifi4dsp_dsp_smem_update_bits64);
|
||||
|
||||
int hifi4dsp_dsp_mailbox_init(struct hifi4dsp_dsp *dsp,
|
||||
u32 outbox_offset, size_t outbox_size,
|
||||
u32 inbox_offset, size_t inbox_size)
|
||||
{
|
||||
dsp->mailbox.out_base = dsp->addr.smem + outbox_offset;
|
||||
dsp->mailbox.in_base = dsp->addr.smem + inbox_offset;
|
||||
dsp->mailbox.out_size = outbox_size;
|
||||
dsp->mailbox.in_size = inbox_size;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hifi4dsp_dsp_mailbox_init);
|
||||
|
||||
void hifi4dsp_dsp_mailbox_outbox_write(struct hifi4dsp_dsp *dsp,
|
||||
void *message, size_t bytes)
|
||||
{
|
||||
memcpy_toio(dsp->mailbox.out_base, message, bytes);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hifi4dsp_dsp_mailbox_outbox_write);
|
||||
|
||||
void hifi4dsp_dsp_mailbox_outbox_read(struct hifi4dsp_dsp *dsp,
|
||||
void *message, size_t bytes)
|
||||
{
|
||||
memcpy_fromio(message, dsp->mailbox.out_base, bytes);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hifi4dsp_dsp_mailbox_outbox_read);
|
||||
|
||||
void hifi4dsp_dsp_mailbox_inbox_write(struct hifi4dsp_dsp *dsp,
|
||||
void *message, size_t bytes)
|
||||
{
|
||||
memcpy_toio(dsp->mailbox.in_base, message, bytes);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hifi4dsp_dsp_mailbox_inbox_write);
|
||||
|
||||
void hifi4dsp_dsp_mailbox_inbox_read(struct hifi4dsp_dsp *dsp,
|
||||
void *message, size_t bytes)
|
||||
{
|
||||
memcpy_fromio(message, dsp->mailbox.in_base, bytes);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hifi4dsp_dsp_mailbox_inbox_read);
|
||||
|
||||
int hifi4dsp_dsp_boot(struct hifi4dsp_dsp *dsp)
|
||||
{
|
||||
if (dsp->ops->boot)
|
||||
dsp->ops->boot(dsp);
|
||||
pr_debug("%s done\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(hifi4dsp_dsp_boot);
|
||||
|
||||
void hifi4dsp_dsp_reset(struct hifi4dsp_dsp *dsp)
|
||||
{
|
||||
if (dsp->ops->reset)
|
||||
dsp->ops->reset(dsp);
|
||||
pr_debug("%s done\n", __func__);
|
||||
}
|
||||
EXPORT_SYMBOL(hifi4dsp_dsp_reset);
|
||||
|
||||
void hifi4dsp_dsp_sleep(struct hifi4dsp_dsp *dsp)
|
||||
{
|
||||
if (dsp->ops->sleep)
|
||||
dsp->ops->sleep(dsp);
|
||||
}
|
||||
EXPORT_SYMBOL(hifi4dsp_dsp_sleep);
|
||||
|
||||
int hifi4dsp_dsp_wake(struct hifi4dsp_dsp *dsp)
|
||||
{
|
||||
if (dsp->ops->wake)
|
||||
return dsp->ops->wake(dsp);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(hifi4dsp_dsp_wake);
|
||||
|
||||
void hifi4dsp_dsp_dump(struct hifi4dsp_dsp *dsp)
|
||||
{
|
||||
if (dsp->ops->dump)
|
||||
dsp->ops->dump(dsp);
|
||||
}
|
||||
EXPORT_SYMBOL(hifi4dsp_dsp_dump);
|
||||
|
||||
struct hifi4dsp_dsp *hifi4dsp_dsp_new(struct hifi4dsp_priv *priv,
|
||||
struct hifi4dsp_pdata *pdata,
|
||||
struct hifi4dsp_dsp_device *dsp_dev)
|
||||
{
|
||||
int err = 0;
|
||||
struct hifi4dsp_dsp *dsp;
|
||||
|
||||
dsp = kzalloc(sizeof(struct hifi4dsp_dsp), GFP_KERNEL);
|
||||
if (dsp == NULL)
|
||||
goto dsp_malloc_error;
|
||||
|
||||
mutex_init(&dsp->mutex);
|
||||
spin_lock_init(&dsp->spinlock);
|
||||
spin_lock_init(&dsp->fw_spinlock);
|
||||
INIT_LIST_HEAD(&dsp->fw_list);
|
||||
|
||||
dsp->id = pdata->id;
|
||||
dsp->irq = pdata->irq;
|
||||
dsp->major_id = MAJOR(priv->dev->devt);
|
||||
dsp->dev = priv->dev;
|
||||
dsp->pdata = pdata;
|
||||
dsp->priv = priv;
|
||||
dsp->ops = dsp_dev->ops;
|
||||
|
||||
/* Initialise Audio DSP */
|
||||
if (dsp->ops->init) {
|
||||
err = dsp->ops->init(dsp, pdata);
|
||||
if (err < 0)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*Register the ISR here if necessary*/
|
||||
/*
|
||||
* err = request_threaded_irq(dsp->irq, dsp->ops->irq_handler,
|
||||
* dsp_dev->thread, IRQF_SHARED, "HIFI4DSP", dsp);
|
||||
* if (err)
|
||||
* goto irq_err;
|
||||
*/
|
||||
goto dsp_new_done;
|
||||
/*
|
||||
* irq_err:
|
||||
* if (dsp->ops->free)
|
||||
* dsp->ops->free(dsp);
|
||||
*/
|
||||
dsp_malloc_error:
|
||||
dsp_new_done:
|
||||
return dsp;
|
||||
}
|
||||
EXPORT_SYMBOL(hifi4dsp_dsp_new);
|
||||
|
||||
MODULE_AUTHOR("Shuyu Li");
|
||||
MODULE_DESCRIPTION("HiFi DSP Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
228
drivers/amlogic/hifi4dsp/hifi4dsp_dsp.h
Normal file
228
drivers/amlogic/hifi4dsp/hifi4dsp_dsp.h
Normal file
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* drivers/amlogic/hifi4dsp/hifi4dsp_dsp.h
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HIFI4DSP_DSP_H
|
||||
#define _HIFI4DSP_DSP_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/irqreturn.h>
|
||||
|
||||
#include "hifi4dsp_firmware.h"
|
||||
|
||||
struct firmware;
|
||||
struct hifi4dsp_pdata;
|
||||
struct hifi4dsp_dsp;
|
||||
|
||||
/*
|
||||
* DSP memory offsets and addresses.
|
||||
*/
|
||||
struct hifi4dsp_addr {
|
||||
u32 smem_paddr;
|
||||
u32 smem_size;
|
||||
u32 reg_paddr;
|
||||
u32 reg_size;
|
||||
u32 fw_paddr;
|
||||
u32 fw_size;
|
||||
void __iomem *smem;
|
||||
void __iomem *reg;
|
||||
void __iomem *fw;
|
||||
};
|
||||
/*
|
||||
* DSP Mailbox configuration.
|
||||
*/
|
||||
struct hifi4dsp_mailbox {
|
||||
void __iomem *in_base;
|
||||
void __iomem *out_base;
|
||||
size_t in_size;
|
||||
size_t out_size;
|
||||
};
|
||||
|
||||
/*
|
||||
* DSP Operations exported by platform Audio DSP driver.
|
||||
*/
|
||||
struct hifi4dsp_ops {
|
||||
int (*boot)(struct hifi4dsp_dsp *);
|
||||
int (*reset)(struct hifi4dsp_dsp *);
|
||||
int (*wake)(struct hifi4dsp_dsp *);
|
||||
int (*sleep)(struct hifi4dsp_dsp *);
|
||||
/* Shim IO */
|
||||
void (*write)(void __iomem *addr, u32 offset, u32 value);
|
||||
u32 (*read)(void __iomem *addr, u32 offset);
|
||||
|
||||
/* DSP I/DRAM IO */
|
||||
void (*ram_read)(struct hifi4dsp_dsp *dsp,
|
||||
void *dest, void __iomem *src, size_t bytes);
|
||||
void (*ram_write)(struct hifi4dsp_dsp *dsp,
|
||||
void __iomem *dest, void *src, size_t bytes);
|
||||
void (*write64)(void __iomem *addr, u32 offset, u64 value);
|
||||
u64 (*read64)(void __iomem *addr, u32 offset);
|
||||
|
||||
void (*dump)(struct hifi4dsp_dsp *);
|
||||
|
||||
/* IRQ handlers */
|
||||
irqreturn_t (*irq_handler)(int irq, void *context);
|
||||
|
||||
/* hifi4dsp init and free */
|
||||
int (*init)(struct hifi4dsp_dsp *dsp, struct hifi4dsp_pdata *pdata);
|
||||
void (*free)(struct hifi4dsp_dsp *dsp);
|
||||
|
||||
/* FW module parser/loader */
|
||||
int (*parse_fw)(struct hifi4dsp_firmware *dsp_fw, void *pinfo);
|
||||
};
|
||||
|
||||
/*
|
||||
* hifi4dsp dsp device.
|
||||
*/
|
||||
struct hifi4dsp_dsp_device {
|
||||
struct hifi4dsp_ops *ops;
|
||||
irqreturn_t (*thread)(int irq, void *thread_context);
|
||||
void *thread_context;
|
||||
};
|
||||
|
||||
/*
|
||||
* hifi4dsp Platform Data.
|
||||
*/
|
||||
struct hifi4dsp_pdata {
|
||||
int id;
|
||||
const char *name;
|
||||
int irq;
|
||||
unsigned int clk_freq;
|
||||
phys_addr_t reg_paddr;
|
||||
unsigned int reg_size;
|
||||
void *reg;
|
||||
/* Share memory */
|
||||
phys_addr_t smem_paddr;
|
||||
unsigned int smem_size;
|
||||
|
||||
/* Firmware */
|
||||
char fw_name[32];
|
||||
phys_addr_t fw_paddr; /*physical address of fw data*/
|
||||
void *fw_buf;
|
||||
int fw_size;
|
||||
int fw_fmt;
|
||||
int fw_max_size;
|
||||
|
||||
void *ops;
|
||||
void *dsp; /*pointer to dsp*/
|
||||
void *priv; /*pointer to priv*/
|
||||
};
|
||||
|
||||
struct hifi4dsp_dsp {
|
||||
u32 id;
|
||||
int irq;
|
||||
int freq;
|
||||
/* runtime */
|
||||
spinlock_t spinlock; /* used for IPC */
|
||||
struct mutex mutex; /* used for fw */
|
||||
struct device *dev;
|
||||
struct device *dma_dev;
|
||||
u32 major_id;
|
||||
void *thread_context;
|
||||
|
||||
struct hifi4dsp_dsp_device *dsp_dev;
|
||||
/* operations */
|
||||
struct hifi4dsp_ops *ops;
|
||||
|
||||
/* base addresses */
|
||||
struct hifi4dsp_addr addr;
|
||||
|
||||
/* mailbox */
|
||||
struct hifi4dsp_mailbox mailbox;
|
||||
|
||||
/* platform data */
|
||||
struct hifi4dsp_pdata *pdata;
|
||||
|
||||
/*fw support*/
|
||||
struct hifi4dsp_firmware *dsp_fw;/*def fw*/
|
||||
u32 fw_cnt;
|
||||
spinlock_t fw_spinlock;
|
||||
struct list_head fw_list;
|
||||
|
||||
u32 intr_status;
|
||||
struct firmware *fw;
|
||||
|
||||
struct clk *dsp_clk;
|
||||
struct clk *dsp_gate;
|
||||
|
||||
void *info;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
/* Internal generic low-level hifi4dsp share memory write/read functions*/
|
||||
extern void hifi4dsp_smem_write(void __iomem *addr, u32 offset, u32 value);
|
||||
extern u32 hifi4dsp_smem_read(void __iomem *addr, u32 offset);
|
||||
extern void hifi4dsp_smem_write64(void __iomem *addr, u32 offset, u64 value);
|
||||
extern u64 hifi4dsp_smem_read64(void __iomem *addr, u32 offset);
|
||||
extern void hifi4dsp_memcpy_toio_32(struct hifi4dsp_dsp *dsp,
|
||||
void __iomem *dest, void *src, size_t bytes);
|
||||
extern void hifi4dsp_memcpy_fromio_32(struct hifi4dsp_dsp *dsp,
|
||||
void *dest, void __iomem *src, size_t bytes);
|
||||
|
||||
extern void hifi4dsp_dsp_smem_write(struct hifi4dsp_dsp *dsp,
|
||||
u32 offset, u32 value);
|
||||
extern u32 hifi4dsp_dsp_smem_read(struct hifi4dsp_dsp *dsp,
|
||||
u32 offset);
|
||||
extern void hifi4dsp_dsp_smem_write64(struct hifi4dsp_dsp *dsp,
|
||||
u32 offset, u64 value);
|
||||
extern u64 hifi4dsp_dsp_smem_read64(struct hifi4dsp_dsp *dsp,
|
||||
u32 offset);
|
||||
extern void hifi4dsp_dsp_smem_write_unlocked(struct hifi4dsp_dsp *dsp,
|
||||
u32 offset, u32 value);
|
||||
extern u32 hifi4dsp_dsp_smem_read_unlocked(struct hifi4dsp_dsp *dsp,
|
||||
u32 offset);
|
||||
extern void hifi4dsp_dsp_smem_write64_unlocked(struct hifi4dsp_dsp *dsp,
|
||||
u32 offset, u64 value);
|
||||
extern u64 hifi4dsp_dsp_smem_read64_unlocked(struct hifi4dsp_dsp *dsp,
|
||||
u32 offset);
|
||||
extern int hifi4dsp_dsp_smem_update_bits_unlocked(
|
||||
struct hifi4dsp_dsp *dsp, u32 offset, u32 mask, u32 value);
|
||||
extern void hifi4dsp_dsp_smem_update_bits_forced_unlocked(
|
||||
struct hifi4dsp_dsp *dsp, u32 offset, u32 mask, u32 value);
|
||||
extern int hifi4dsp_dsp_smem_update_bits64_unlocked(
|
||||
struct hifi4dsp_dsp *dsp, u32 offset, u64 mask, u64 value);
|
||||
extern int hifi4dsp_dsp_smem_update_bits(struct hifi4dsp_dsp *dsp,
|
||||
u32 offset, u32 mask, u32 value);
|
||||
extern void hifi4dsp_dsp_smem_update_bits_forced(struct hifi4dsp_dsp *dsp,
|
||||
u32 offset, u32 mask, u32 value);
|
||||
extern int hifi4dsp_dsp_smem_update_bits64(struct hifi4dsp_dsp *dsp,
|
||||
u32 offset, u64 mask, u64 value);
|
||||
|
||||
extern int hifi4dsp_dsp_mailbox_init(struct hifi4dsp_dsp *dsp,
|
||||
u32 outbox_offset, size_t outbox_size,
|
||||
u32 inbox_offset, size_t inbox_size);
|
||||
extern void hifi4dsp_dsp_mailbox_outbox_write(struct hifi4dsp_dsp *dsp,
|
||||
void *message, size_t bytes);
|
||||
extern void hifi4dsp_dsp_mailbox_outbox_read(struct hifi4dsp_dsp *dsp,
|
||||
void *message, size_t bytes);
|
||||
extern void hifi4dsp_dsp_mailbox_inbox_write(struct hifi4dsp_dsp *dsp,
|
||||
void *message, size_t bytes);
|
||||
extern void hifi4dsp_dsp_mailbox_inbox_read(struct hifi4dsp_dsp *dsp,
|
||||
void *message, size_t bytes);
|
||||
extern int hifi4dsp_dsp_boot(struct hifi4dsp_dsp *dsp);
|
||||
extern void hifi4dsp_dsp_reset(struct hifi4dsp_dsp *dsp);
|
||||
extern void hifi4dsp_dsp_sleep(struct hifi4dsp_dsp *dsp);
|
||||
extern int hifi4dsp_dsp_wake(struct hifi4dsp_dsp *dsp);
|
||||
extern void hifi4dsp_dsp_dump(struct hifi4dsp_dsp *dsp);
|
||||
//extern struct hifi4dsp_dsp * hifi4dsp_dsp_new(struct hifi4dsp_priv *priv,
|
||||
// struct hifi4dsp_pdata *pdata, struct hifi4dsp_ops *ops);
|
||||
extern struct hifi4dsp_dsp *hifi4dsp_dsp_new(struct hifi4dsp_priv *priv,
|
||||
struct hifi4dsp_pdata *pdata, struct hifi4dsp_dsp_device *dsp_dev);
|
||||
|
||||
#endif /*_HIFI4DSP_DSP_H*/
|
||||
259
drivers/amlogic/hifi4dsp/hifi4dsp_firmware.c
Normal file
259
drivers/amlogic/hifi4dsp/hifi4dsp_firmware.c
Normal file
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* drivers/amlogic/hifi4dsp/hifi4dsp_firmware.c
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/amlogic/major.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include "hifi4dsp_priv.h"
|
||||
#include "hifi4dsp_firmware.h"
|
||||
#include "hifi4dsp_dsp.h"
|
||||
|
||||
static inline void hifi4dsp_fw_memcpy(void __iomem *dest,
|
||||
void *src, u32 bytes)
|
||||
{
|
||||
memcpy_toio(dest, src, bytes);
|
||||
}
|
||||
|
||||
/* general a new hifi4dsp_firmware object, called by hi-level functions */
|
||||
struct hifi4dsp_firmware *hifi4dsp_fw_new(struct hifi4dsp_dsp *dsp,
|
||||
const struct firmware *fw, void *private)
|
||||
{
|
||||
struct hifi4dsp_firmware *dsp_fw;
|
||||
|
||||
dsp_fw = kzalloc(sizeof(struct hifi4dsp_firmware), GFP_KERNEL);
|
||||
if (dsp_fw == NULL)
|
||||
goto dsp_fw_malloc_err;
|
||||
|
||||
dsp_fw->dsp = dsp;
|
||||
dsp_fw->priv = dsp->priv;
|
||||
if (private != NULL)
|
||||
dsp_fw->private = private;
|
||||
if (fw != NULL)
|
||||
dsp_fw->size = fw->size;
|
||||
pr_debug("%s done\n", __func__);
|
||||
|
||||
dsp_fw_malloc_err:
|
||||
return dsp_fw;
|
||||
}
|
||||
/*dsp_fw must be initied before this operation,
|
||||
*special the *dsp pointer must not be null
|
||||
*/
|
||||
int hifi4dsp_fw_add(struct hifi4dsp_firmware *dsp_fw)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct hifi4dsp_dsp *dsp;
|
||||
|
||||
if ((dsp_fw == NULL) || (dsp_fw->dsp == NULL))
|
||||
return -1;
|
||||
dsp = dsp_fw->dsp;
|
||||
spin_lock_irqsave(&dsp->fw_spinlock, flags);
|
||||
list_add_tail(&dsp_fw->list, &dsp->fw_list);
|
||||
dsp->fw_cnt++;
|
||||
dsp_fw->id = dsp->fw_cnt;
|
||||
spin_unlock_irqrestore(&dsp->fw_spinlock, flags);
|
||||
pr_debug("%s done\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct hifi4dsp_firmware *hifi4dsp_fw_search_by_name(
|
||||
struct hifi4dsp_dsp *dsp, char *name)
|
||||
{
|
||||
struct hifi4dsp_firmware *dsp_fw = NULL;
|
||||
struct hifi4dsp_firmware *pfw = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dsp->fw_spinlock, flags);
|
||||
if (list_empty(&dsp->fw_list)) {
|
||||
pfw = NULL;
|
||||
pr_err("Firmware list is empty\n");
|
||||
}
|
||||
|
||||
list_for_each_entry(dsp_fw, &dsp->fw_list, list) {
|
||||
if (memcmp(dsp_fw->name, name, strlen(name)) == 0) {
|
||||
pfw = dsp_fw;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&dsp->fw_spinlock, flags);
|
||||
return pfw;
|
||||
}
|
||||
|
||||
int hifi4dsp_dump_memory(const void *buf, unsigned int bytes, int col)
|
||||
{
|
||||
int i = 0, n = 0, size = 0;
|
||||
const u8 *pdata;
|
||||
char str[1024];
|
||||
char a_str[24];
|
||||
|
||||
pdata = (u8 *)buf;
|
||||
size = bytes;
|
||||
memset(str, '\0', sizeof(a_str));
|
||||
memset(str, '\0', sizeof(str));
|
||||
while (n < size) {
|
||||
sprintf(a_str, "%p: ", pdata);
|
||||
strcat(str, a_str);
|
||||
col = ((size-n) > col)?col:(size-n);
|
||||
for (i = 0; i < col; i++) {
|
||||
sprintf(a_str, "%02x ", *(pdata+i));
|
||||
strcat(str, a_str);
|
||||
}
|
||||
pr_info("%s\n", str);
|
||||
memset(str, '\0', sizeof(str));/*re-init buf*/
|
||||
pdata += col;
|
||||
n += col;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//resource res;
|
||||
int hifi4dsp_fw_copy_to_ddr(const struct firmware *fw,
|
||||
struct hifi4dsp_firmware *dsp_fw)
|
||||
{
|
||||
int fw_bytes = 0;
|
||||
const u8 *fw_src;
|
||||
void *fw_dst;
|
||||
|
||||
fw_src = fw->data;
|
||||
fw_bytes = fw->size;
|
||||
fw_dst = dsp_fw->buf;
|
||||
hifi4dsp_dump_memory(fw_src, 32, 16);
|
||||
hifi4dsp_dump_memory(fw_src+fw_bytes-32, 32, 16);
|
||||
pr_debug("%s fw_src:0x%p, pdata_dst=0x%p ,szie=%d bytes\n",
|
||||
__func__, fw_src, fw_dst, fw_bytes);
|
||||
//memcpy(fw_dst, fw_src, fw_bytes);
|
||||
memcpy_toio(fw_dst, fw_src, fw_bytes);
|
||||
//do memory barrier
|
||||
//mb();
|
||||
/*TODO, if need add membarrier code*/
|
||||
hifi4dsp_dump_memory(fw_dst, 32, 16);
|
||||
hifi4dsp_dump_memory(fw_dst+fw_bytes-32, 32, 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hifi4dsp_fw_load(struct hifi4dsp_firmware *dsp_fw)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
struct hifi4dsp_priv *priv;
|
||||
struct hifi4dsp_dsp *dsp;
|
||||
int err = 0;
|
||||
|
||||
pr_info("%s loading firmware %s\n", __func__, dsp_fw->name);
|
||||
|
||||
if ((dsp_fw == NULL) || (dsp_fw->dsp == NULL))
|
||||
return -1;
|
||||
priv = dsp_fw->priv;
|
||||
dsp = dsp_fw->dsp;
|
||||
err = request_firmware(&fw, dsp_fw->name, priv->dev);
|
||||
if (err < 0) {
|
||||
HIFI4DSP_PRNT("can't load the %s,err=%d\n", dsp_fw->name, err);
|
||||
goto done;
|
||||
}
|
||||
if (fw == NULL) {
|
||||
HIFI4DSP_PRNT("firmware pointer==NULL\n");
|
||||
goto done;
|
||||
}
|
||||
if (dsp_fw == NULL) {
|
||||
HIFI4DSP_PRNT("hifi4dsp_firmware pointer==NULL\n");
|
||||
err = ENOMEM;
|
||||
goto release;
|
||||
}
|
||||
dsp_fw->size = fw->size;
|
||||
hifi4dsp_fw_copy_to_ddr(fw, dsp_fw);
|
||||
release:
|
||||
release_firmware(fw);
|
||||
done:
|
||||
return err;
|
||||
}
|
||||
|
||||
int hifi4dsp_fw_reload(struct hifi4dsp_dsp *dsp,
|
||||
struct hifi4dsp_firmware *dsp_fw)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int hifi4dsp_fw_unload(struct hifi4dsp_firmware *dsp_fw)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* create a hifi4dsp_firmware object and
|
||||
* add it to the fw_list of hifi4dsp_dsp
|
||||
*/
|
||||
struct hifi4dsp_firmware *hifi4dsp_fw_register(struct hifi4dsp_dsp *dsp,
|
||||
char *name)
|
||||
{
|
||||
struct hifi4dsp_firmware *dsp_fw;
|
||||
int str_len = 0;
|
||||
|
||||
dsp_fw = hifi4dsp_fw_search_by_name(dsp, name);
|
||||
if (dsp_fw != NULL) {
|
||||
pr_info("%s firmware( %s ) has been registered\n",
|
||||
__func__, name);
|
||||
return dsp_fw;
|
||||
}
|
||||
dsp_fw = hifi4dsp_fw_new(dsp, NULL, NULL);
|
||||
if (dsp_fw != NULL) {
|
||||
str_len = sizeof(dsp_fw->name) - 1;
|
||||
strncpy(dsp_fw->name, name, str_len);
|
||||
hifi4dsp_fw_add(dsp_fw);
|
||||
pr_info("%s %s done\n", __func__, dsp_fw->name);
|
||||
}
|
||||
return dsp_fw;
|
||||
}
|
||||
|
||||
/* free single firmware object */
|
||||
void hifi4dsp_fw_free(struct hifi4dsp_firmware *dsp_fw)
|
||||
{
|
||||
struct hifi4dsp_dsp *dsp = dsp_fw->dsp;
|
||||
|
||||
mutex_lock(&dsp->mutex);
|
||||
list_del(&dsp_fw->list);
|
||||
kfree(dsp_fw);
|
||||
mutex_unlock(&dsp->mutex);
|
||||
}
|
||||
|
||||
/* free all firmware objects */
|
||||
void hifi4dsp_fw_free_all(struct hifi4dsp_dsp *dsp)
|
||||
{
|
||||
struct hifi4dsp_firmware *dsp_fw, *t;
|
||||
|
||||
mutex_lock(&dsp->mutex);
|
||||
list_for_each_entry_safe(dsp_fw, t, &dsp->fw_list, list) {
|
||||
list_del(&dsp_fw->list);
|
||||
kfree(dsp_fw);
|
||||
}
|
||||
mutex_unlock(&dsp->mutex);
|
||||
}
|
||||
|
||||
58
drivers/amlogic/hifi4dsp/hifi4dsp_firmware.h
Normal file
58
drivers/amlogic/hifi4dsp/hifi4dsp_firmware.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* drivers/amlogic/hifi4dsp/hifi4dsp_firmware.h
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HIFI4DSP_FIRMWARE_H
|
||||
#define _HIFI4DSP_FIRMWARE_H
|
||||
|
||||
struct firmware;
|
||||
struct hifi4dsp_priv;
|
||||
struct hifi4dsp_dsp;
|
||||
|
||||
struct hifi4dsp_firmware_block {
|
||||
int id;
|
||||
struct list_head list;
|
||||
phys_addr_t paddr;
|
||||
};
|
||||
|
||||
struct hifi4dsp_firmware {
|
||||
int id;
|
||||
char name[32];
|
||||
int size;
|
||||
int fmt;
|
||||
struct list_head list; /*fw list of DSP*/
|
||||
phys_addr_t paddr; /*physical address of fw data*/
|
||||
void *buf; /*virtual address of fw data*/
|
||||
|
||||
struct hifi4dsp_priv *priv;
|
||||
struct hifi4dsp_dsp *dsp;
|
||||
|
||||
void *private;
|
||||
};
|
||||
|
||||
extern int hifi4dsp_fw_load(struct hifi4dsp_firmware *dsp_fw);
|
||||
extern int hifi4dsp_fw_unload(struct hifi4dsp_firmware *dsp_fw);
|
||||
extern void hifi4dsp_fw_free(struct hifi4dsp_firmware *dsp_fw);
|
||||
extern int hifi4dsp_fw_add(struct hifi4dsp_firmware *dsp_fw);
|
||||
extern void hifi4dsp_fw_free_all(struct hifi4dsp_dsp *dsp);
|
||||
extern struct hifi4dsp_firmware *hifi4dsp_fw_new(struct hifi4dsp_dsp *dsp,
|
||||
const struct firmware *fw, void *private);
|
||||
extern struct hifi4dsp_firmware *hifi4dsp_fw_register(struct hifi4dsp_dsp *dsp,
|
||||
char *fw_name);
|
||||
extern int hifi4dsp_dump_memory(const void *buf, unsigned int bytes, int col);
|
||||
|
||||
|
||||
#endif /*_HIFI4DSP_FIRMWARE_H*/
|
||||
323
drivers/amlogic/hifi4dsp/hifi4dsp_ipc.c
Normal file
323
drivers/amlogic/hifi4dsp/hifi4dsp_ipc.c
Normal file
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
* drivers/amlogic/hifi4dsp/hifi4dsp_ipc.c
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/amlogic/major.h>
|
||||
|
||||
#include "hifi4dsp_priv.h"
|
||||
#include "hifi4dsp_firmware.h"
|
||||
#include "hifi4dsp_dsp.h"
|
||||
#include "hifi4dsp_ipc.h"
|
||||
|
||||
/* locks held by caller */
|
||||
static struct hifi4dsp_ipc_message *ipc_get_empty_msg(
|
||||
struct hifi4dsp_ipc *ipc)
|
||||
{
|
||||
struct hifi4dsp_ipc_message *msg = NULL;
|
||||
|
||||
if (!list_empty(&ipc->empty_list)) {
|
||||
msg = list_first_entry(&ipc->empty_list,
|
||||
struct hifi4dsp_ipc_message, list);
|
||||
list_del(&msg->list);
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
static int tx_wait_done(struct hifi4dsp_ipc *ipc,
|
||||
struct hifi4dsp_ipc_message *msg, void *rx_data)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
/* wait for DSP completion (in all cases atm inc pending) */
|
||||
ret = wait_event_timeout(msg->waitq, msg->complete,
|
||||
msecs_to_jiffies(IPC_MSG_TIMEOUT_MSECS));
|
||||
|
||||
spin_lock_irqsave(&ipc->dsp->spinlock, flags);
|
||||
if (ret == 0) {
|
||||
if (ipc->ops.debug_info != NULL)
|
||||
ipc->ops.debug_info(ipc, "message timeout");
|
||||
|
||||
list_del(&msg->list);
|
||||
ret = -ETIMEDOUT;
|
||||
} else {
|
||||
|
||||
/* copy the data returned from DSP */
|
||||
if (msg->rx_size)
|
||||
memcpy(rx_data, msg->rx_data, msg->rx_size);
|
||||
ret = msg->errno;
|
||||
}
|
||||
|
||||
list_add_tail(&msg->list, &ipc->empty_list);
|
||||
spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ipc_tx_message(struct hifi4dsp_ipc *ipc, u64 header,
|
||||
void *tx_data, size_t tx_bytes, void *rx_data,
|
||||
size_t rx_bytes, int wait)
|
||||
{
|
||||
struct hifi4dsp_ipc_message *msg;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ipc->dsp->spinlock, flags);
|
||||
|
||||
msg = ipc_get_empty_msg(ipc);
|
||||
if (msg == NULL) {
|
||||
spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
msg->header = header;
|
||||
msg->tx_size = tx_bytes;
|
||||
msg->rx_size = rx_bytes;
|
||||
msg->wait = wait;
|
||||
msg->errno = 0;
|
||||
msg->pending = false;
|
||||
msg->complete = false;
|
||||
|
||||
if ((tx_bytes) && (ipc->ops.tx_data_copy != NULL))
|
||||
ipc->ops.tx_data_copy(msg, tx_data, tx_bytes);
|
||||
|
||||
list_add_tail(&msg->list, &ipc->tx_list);
|
||||
spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
|
||||
|
||||
kthread_queue_work(&ipc->kworker, &ipc->kwork);
|
||||
|
||||
if (wait)
|
||||
return tx_wait_done(ipc, msg, rx_data);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipc_msg_empty_list_init(struct hifi4dsp_ipc *ipc)
|
||||
{
|
||||
int i;
|
||||
|
||||
ipc->msg = kzalloc(sizeof(struct hifi4dsp_ipc_message) *
|
||||
IPC_EMPTY_LIST_SIZE, GFP_KERNEL);
|
||||
if (ipc->msg == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) {
|
||||
ipc->msg[i].tx_data = kzalloc
|
||||
(ipc->tx_data_max_size, GFP_KERNEL);
|
||||
if (ipc->msg[i].tx_data == NULL)
|
||||
goto free_mem;
|
||||
|
||||
ipc->msg[i].rx_data = kzalloc
|
||||
(ipc->rx_data_max_size, GFP_KERNEL);
|
||||
if (ipc->msg[i].rx_data == NULL) {
|
||||
kfree(ipc->msg[i].tx_data);
|
||||
goto free_mem;
|
||||
}
|
||||
|
||||
init_waitqueue_head(&ipc->msg[i].waitq);
|
||||
list_add(&ipc->msg[i].list, &ipc->empty_list);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
free_mem:
|
||||
while (i > 0) {
|
||||
kfree(ipc->msg[i-1].tx_data);
|
||||
kfree(ipc->msg[i-1].rx_data);
|
||||
--i;
|
||||
}
|
||||
kfree(ipc->msg);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void ipc_tx_msgs(struct kthread_work *work)
|
||||
{
|
||||
struct hifi4dsp_ipc *ipc =
|
||||
container_of(work, struct hifi4dsp_ipc, kwork);
|
||||
struct hifi4dsp_ipc_message *msg;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ipc->dsp->spinlock, flags);
|
||||
|
||||
if (list_empty(&ipc->tx_list) || ipc->pending) {
|
||||
spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
/* if the DSP is busy, we will TX messages after IRQ.
|
||||
* also postpone if we are in the middle of procesing completion irq
|
||||
*/
|
||||
if (ipc->ops.is_dsp_busy && ipc->ops.is_dsp_busy(ipc->dsp)) {
|
||||
pr_err("ipc_tx_msgs dsp busy\n");
|
||||
spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
msg = list_first_entry(&ipc->tx_list,
|
||||
struct hifi4dsp_ipc_message, list);
|
||||
list_move(&msg->list, &ipc->rx_list);
|
||||
|
||||
if (ipc->ops.tx_msg != NULL)
|
||||
ipc->ops.tx_msg(ipc, msg);
|
||||
|
||||
spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
|
||||
}
|
||||
|
||||
int hifi4dsp_ipc_tx_message_wait(struct hifi4dsp_ipc *ipc, u64 header,
|
||||
void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes)
|
||||
{
|
||||
return ipc_tx_message(ipc, header, tx_data, tx_bytes,
|
||||
rx_data, rx_bytes, 1);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hifi4dsp_ipc_tx_message_wait);
|
||||
|
||||
int hifi4dsp_ipc_tx_message_nowait(struct hifi4dsp_ipc *ipc, u64 header,
|
||||
void *tx_data, size_t tx_bytes)
|
||||
{
|
||||
return ipc_tx_message(ipc, header, tx_data, tx_bytes,
|
||||
NULL, 0, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hifi4dsp_ipc_tx_message_nowait);
|
||||
|
||||
struct hifi4dsp_ipc_message *hifi4dsp_ipc_reply_find_msg(
|
||||
struct hifi4dsp_ipc *ipc, u64 header)
|
||||
{
|
||||
struct hifi4dsp_ipc_message *msg;
|
||||
u64 mask = 0;
|
||||
|
||||
if (ipc->ops.reply_msg_match != NULL)
|
||||
header = ipc->ops.reply_msg_match(header, &mask);
|
||||
|
||||
if (list_empty(&ipc->rx_list)) {
|
||||
pr_err("error: rx list empty but received 0x%llx\n",
|
||||
header);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_for_each_entry(msg, &ipc->rx_list, list) {
|
||||
if ((msg->header & mask) == header)
|
||||
return msg;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hifi4dsp_ipc_reply_find_msg);
|
||||
|
||||
/* locks held by caller */
|
||||
void hifi4dsp_ipc_tx_msg_reply_complete(struct hifi4dsp_ipc *ipc,
|
||||
struct hifi4dsp_ipc_message *msg)
|
||||
{
|
||||
msg->complete = true;
|
||||
|
||||
if (!msg->wait)
|
||||
list_add_tail(&msg->list, &ipc->empty_list);
|
||||
else
|
||||
wake_up(&msg->waitq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hifi4dsp_ipc_tx_msg_reply_complete);
|
||||
|
||||
void hifi4dsp_ipc_drop_all(struct hifi4dsp_ipc *ipc)
|
||||
{
|
||||
struct hifi4dsp_ipc_message *msg, *tmp;
|
||||
unsigned long flags;
|
||||
int tx_drop_cnt = 0, rx_drop_cnt = 0;
|
||||
|
||||
/* drop all TX and Rx messages before we stall + reset DSP */
|
||||
spin_lock_irqsave(&ipc->dsp->spinlock, flags);
|
||||
|
||||
list_for_each_entry_safe(msg, tmp, &ipc->tx_list, list) {
|
||||
list_move(&msg->list, &ipc->empty_list);
|
||||
tx_drop_cnt++;
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(msg, tmp, &ipc->rx_list, list) {
|
||||
list_move(&msg->list, &ipc->empty_list);
|
||||
rx_drop_cnt++;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
|
||||
|
||||
if (tx_drop_cnt || rx_drop_cnt)
|
||||
pr_err("dropped IPC tx_msg cnt %d, rx_msg=%d\n",
|
||||
tx_drop_cnt, rx_drop_cnt);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hifi4dsp_ipc_drop_all);
|
||||
|
||||
int hifi4dsp_ipc_init(struct hifi4dsp_ipc *ipc)
|
||||
{
|
||||
int ret;
|
||||
|
||||
INIT_LIST_HEAD(&ipc->tx_list);
|
||||
INIT_LIST_HEAD(&ipc->rx_list);
|
||||
INIT_LIST_HEAD(&ipc->empty_list);
|
||||
init_waitqueue_head(&ipc->wait_txq);
|
||||
|
||||
ret = ipc_msg_empty_list_init(ipc);
|
||||
if (ret < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
/* start the IPC message thread */
|
||||
kthread_init_worker(&ipc->kworker);
|
||||
ipc->tx_thread = kthread_run(kthread_worker_fn,
|
||||
&ipc->kworker, "%s",
|
||||
dev_name(ipc->dev));
|
||||
if (IS_ERR(ipc->tx_thread)) {
|
||||
pr_err("error: failed to create message TX task\n");
|
||||
ret = PTR_ERR(ipc->tx_thread);
|
||||
kfree(ipc->msg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
kthread_init_work(&ipc->kwork, ipc_tx_msgs);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hifi4dsp_ipc_init);
|
||||
|
||||
void hifi4dsp_ipc_finish(struct hifi4dsp_ipc *ipc)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (ipc->tx_thread)
|
||||
kthread_stop(ipc->tx_thread);
|
||||
|
||||
if (ipc->msg) {
|
||||
for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) {
|
||||
kfree(ipc->msg[i].tx_data);
|
||||
kfree(ipc->msg[i].rx_data);
|
||||
}
|
||||
kfree(ipc->msg);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hifi4dsp_ipc_finish);
|
||||
|
||||
97
drivers/amlogic/hifi4dsp/hifi4dsp_ipc.h
Normal file
97
drivers/amlogic/hifi4dsp/hifi4dsp_ipc.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* drivers/amlogic/hifi4dsp/hifi4dsp_ipc.h
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HIFI4DSP_IPC_H
|
||||
#define _HIFI4DSP_IPC_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kthread.h>
|
||||
|
||||
#include "hifi4dsp_dsp.h"
|
||||
|
||||
struct hifi4dsp_ipc;
|
||||
|
||||
#define IPC_MAILBOX_MAX_BYTES 256
|
||||
#define IPC_EMPTY_LIST_SIZE 8
|
||||
#define IPC_MSG_TIMEOUT_MSECS 300 /* IPC message timeout (msecs) */
|
||||
|
||||
struct hifi4dsp_ipc_message {
|
||||
struct list_head list;
|
||||
u64 header;
|
||||
|
||||
char *tx_data;
|
||||
size_t tx_size;
|
||||
char *rx_data;
|
||||
size_t rx_size;
|
||||
|
||||
wait_queue_head_t waitq;
|
||||
bool pending;
|
||||
bool complete;
|
||||
bool wait;
|
||||
int errno;
|
||||
};
|
||||
|
||||
struct hifi4dsp_ipc_plat_ops {
|
||||
void (*tx_msg)(struct hifi4dsp_ipc *, struct hifi4dsp_ipc_message *);
|
||||
void (*tx_data_copy)(struct hifi4dsp_ipc_message *, char *, size_t);
|
||||
bool (*is_dsp_busy)(struct hifi4dsp_dsp *dsp);
|
||||
void (*debug_info)(struct hifi4dsp_ipc *, const char *);
|
||||
u64 (*reply_msg_match)(u64 header, u64 *mask);
|
||||
};
|
||||
|
||||
struct hifi4dsp_ipc {
|
||||
struct device *dev;
|
||||
struct hifi4dsp_dsp *dsp;
|
||||
|
||||
/* IPC messaging */
|
||||
struct list_head tx_list;
|
||||
struct list_head rx_list;
|
||||
struct list_head empty_list;
|
||||
wait_queue_head_t wait_txq;
|
||||
struct task_struct *tx_thread;
|
||||
struct kthread_worker kworker;
|
||||
struct kthread_work kwork;
|
||||
bool pending;
|
||||
struct hifi4dsp_ipc_message *msg;
|
||||
int tx_data_max_size;
|
||||
int rx_data_max_size;
|
||||
|
||||
struct hifi4dsp_ipc_plat_ops ops;
|
||||
};
|
||||
|
||||
int hifi4dsp_ipc_tx_message_wait(struct hifi4dsp_ipc *ipc, u64 header,
|
||||
void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes);
|
||||
|
||||
int hifi4dsp_ipc_tx_message_nowait(struct hifi4dsp_ipc *ipc, u64 header,
|
||||
void *tx_data, size_t tx_bytes);
|
||||
|
||||
struct hifi4dsp_ipc_message *hifi4dsp_ipc_reply_find_msg(
|
||||
struct hifi4dsp_ipc *ipc, u64 header);
|
||||
|
||||
void hifi4dsp_ipc_tx_msg_reply_complete(struct hifi4dsp_ipc *ipc,
|
||||
struct hifi4dsp_ipc_message *msg);
|
||||
|
||||
void hifi4dsp_ipc_drop_all(struct hifi4dsp_ipc *ipc);
|
||||
int hifi4dsp_ipc_init(struct hifi4dsp_ipc *ipc);
|
||||
void hifi4dsp_ipc_fini(struct hifi4dsp_ipc *ipc);
|
||||
|
||||
#endif /*_HIFI4DSP_IPC_H*/
|
||||
1141
drivers/amlogic/hifi4dsp/hifi4dsp_module.c
Normal file
1141
drivers/amlogic/hifi4dsp/hifi4dsp_module.c
Normal file
File diff suppressed because it is too large
Load Diff
78
drivers/amlogic/hifi4dsp/hifi4dsp_priv.h
Normal file
78
drivers/amlogic/hifi4dsp/hifi4dsp_priv.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* drivers/amlogic/hifi4dsp/hifi4dsp_priv.h
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HIFI4DSP_PRIV_H
|
||||
#define _HIFI4DSP_PRIV_H
|
||||
#include <linux/device.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/miscdevice.h>
|
||||
|
||||
/*
|
||||
* #include <asm/dsp/hifi4dsp_control.h>
|
||||
* #include <asm/dsp/dsp_register.h>
|
||||
*/
|
||||
//#include "hifi4dsp_control.h"
|
||||
#include <linux/amlogic/media/sound/dsp_register.h>
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include "hifi4dsp_api.h"
|
||||
#include "hifi4dsp_dsp.h"
|
||||
#include "hifi4dsp_firmware.h"
|
||||
#include "hifi4dsp_ipc.h"
|
||||
|
||||
struct class;
|
||||
|
||||
struct hifi4dsp_priv {
|
||||
char name[12];
|
||||
struct class *class;
|
||||
struct device *dev;
|
||||
struct device *dma_dev;
|
||||
|
||||
u32 dsp_freq;
|
||||
bool dsp_is_started;
|
||||
|
||||
struct hifi4dsp_dsp *dsp;
|
||||
struct hifi4dsp_dsp_device *dsp_dev;
|
||||
struct hifi4dsp_firmware *dsp_fw;
|
||||
struct hifi4dsp_mailbox *mailbox;
|
||||
struct hifi4dsp_pdata *pdata;
|
||||
struct hifi4dsp_ipc ipc;
|
||||
|
||||
struct clk *p_clk;
|
||||
struct clk *p_clk_gate;
|
||||
};
|
||||
|
||||
struct hifi4dsp_miscdev_t {
|
||||
struct miscdevice dsp_miscdev;
|
||||
struct hifi4dsp_priv *priv;
|
||||
};
|
||||
|
||||
struct hifi4dsp_resource_t {
|
||||
struct resource res_iomem;
|
||||
struct clk *p_clk_gate;
|
||||
struct clk *p_clk;
|
||||
int irq;
|
||||
};
|
||||
|
||||
struct hifi4dsp_priv *hifi4dsp_privdata(void);
|
||||
|
||||
#ifndef HIFI4DSP_PRNT
|
||||
#define HIFI4DSP_PRNT(...) pr_info(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#endif /*_HIFI4DSP_PRIV_H*/
|
||||
525
drivers/amlogic/hifi4dsp/tm2_dsp_top.c
Normal file
525
drivers/amlogic/hifi4dsp/tm2_dsp_top.c
Normal file
@@ -0,0 +1,525 @@
|
||||
/*
|
||||
* drivers/amlogic/hifi4dsp/tm2_dsp_top.c
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/amlogic/major.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include <linux/amlogic/scpi_protocol.h>
|
||||
|
||||
#include "hifi4dsp_priv.h"
|
||||
#include "hifi4dsp_firmware.h"
|
||||
#include "hifi4dsp_dsp.h"
|
||||
|
||||
/*AO_RTI*/
|
||||
#define AO_RTI_ADDR_BASE (0xff800000)
|
||||
#define REG_AO_RTI_GEN_PWR_SLEEP0 (0x03a << 2)
|
||||
#define REG_AO_RTI_GEN_PWR_ISO0 (0x03b << 2)
|
||||
|
||||
/*HIU*/
|
||||
#define HUI_ADDR_BASE (0xff63c000)
|
||||
#define REG_HHI_DSP_CLK_CNTL (0x0fc << 2)
|
||||
#define REG_HHI_DSP_MEM_PD_REG0 (0x044 << 2)
|
||||
|
||||
/*reset*/
|
||||
#define RESET_ADDR_BASE (0xffd01000)
|
||||
#define REG_RESET1_LEVEL (0x84)
|
||||
#define REG_RESET4_LEVEL (0x90)
|
||||
|
||||
/*DSP TOP*/
|
||||
#define DSPA_REG_BASE (0xff680000)
|
||||
#define DSPB_REG_BASE (0xff690000)
|
||||
|
||||
#define REG_DSP_CFG0 (0x0)
|
||||
#define REG_DSP_CFG1 (0x4)
|
||||
#define REG_DSP_CFG2 (0x8)
|
||||
#define REG_DSP_RESET_VEC (0x004 << 2)
|
||||
|
||||
struct reg_iomem_t {
|
||||
void __iomem *dsp_addr;
|
||||
void __iomem *dspa_addr;
|
||||
void __iomem *dspb_addr;
|
||||
void __iomem *hiu_addr; /*HIU*/
|
||||
void __iomem *ao_rti_addr; /*AO_RTI*/
|
||||
void __iomem *reset_addr;
|
||||
void __iomem *sleep_addr;
|
||||
};
|
||||
|
||||
static struct reg_iomem_t g_regbases;
|
||||
static bool regs_iomem_is_inited;
|
||||
|
||||
static void __iomem *reg_iomem_init(phys_addr_t paddr, u32 size)
|
||||
{
|
||||
void __iomem *vaddr = NULL;
|
||||
|
||||
vaddr = ioremap_nocache(paddr, size);
|
||||
pr_debug("%s phys: %llx, virt: %p, size:%x Bytes\n",
|
||||
__func__,
|
||||
(unsigned long long)paddr,
|
||||
vaddr,
|
||||
size);
|
||||
return vaddr;
|
||||
}
|
||||
|
||||
static inline void tm2_dsp_top_reg_dump(char *name,
|
||||
void __iomem *reg_base, u32 reg_offset)
|
||||
{
|
||||
pr_info("%s (%p) = 0x%x\n", name,
|
||||
(reg_base + reg_offset),
|
||||
readl(reg_base + reg_offset));
|
||||
}
|
||||
|
||||
void tm2_dsp_regs_iomem_init(void)
|
||||
{
|
||||
if (regs_iomem_is_inited == true) {
|
||||
pr_info("%s has been done\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
g_regbases.dspa_addr = reg_iomem_init(DSPA_REG_BASE, 0x8B*4);
|
||||
g_regbases.dspb_addr = reg_iomem_init(DSPB_REG_BASE, 0x8B*4);
|
||||
|
||||
g_regbases.hiu_addr = reg_iomem_init(HUI_ADDR_BASE, 0xFF*4);
|
||||
g_regbases.ao_rti_addr = reg_iomem_init(AO_RTI_ADDR_BASE, 0xFF*4);
|
||||
g_regbases.reset_addr = reg_iomem_init(RESET_ADDR_BASE, 0x40*4);
|
||||
|
||||
regs_iomem_is_inited = true;
|
||||
|
||||
pr_debug("%s done\n", __func__);
|
||||
}
|
||||
|
||||
void tm2_dsp_regs_iounmem(void)
|
||||
{
|
||||
iounmap(g_regbases.dspa_addr);
|
||||
iounmap(g_regbases.dspb_addr);
|
||||
|
||||
iounmap(g_regbases.hiu_addr);
|
||||
iounmap(g_regbases.ao_rti_addr);
|
||||
iounmap(g_regbases.reset_addr);
|
||||
|
||||
regs_iomem_is_inited = false;
|
||||
|
||||
pr_debug("%s done\n", __func__);
|
||||
}
|
||||
|
||||
static inline void __iomem *get_hiu_addr(void)
|
||||
{
|
||||
return g_regbases.hiu_addr;
|
||||
}
|
||||
|
||||
static inline void __iomem *get_ao_rti_addr(void)
|
||||
{
|
||||
return g_regbases.ao_rti_addr;
|
||||
}
|
||||
|
||||
static inline void __iomem *get_reset_addr(void)
|
||||
{
|
||||
return g_regbases.reset_addr;
|
||||
}
|
||||
|
||||
static inline void __iomem *get_dsp_addr(int dsp_id)
|
||||
{
|
||||
if (dsp_id == 1)
|
||||
return g_regbases.dspb_addr;
|
||||
else
|
||||
return g_regbases.dspa_addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* clk_util_set_dsp_clk
|
||||
* freq_sel: 0:286MHz fclk_7
|
||||
* 1:400MHz fclk_5
|
||||
* 2:500MHz fclk_2/2
|
||||
* 3:667MHz fclk_3
|
||||
* 4:1000MHz fclk_2
|
||||
* others:286MHz fclk/7
|
||||
*/
|
||||
//crt_clk_div_mux4_ns #(8)
|
||||
// u_crt_dspa_clk_mux_div(
|
||||
// .clk0 (fclk_div2 ),
|
||||
// .clk1 (fclk_div3 ),
|
||||
// .clk2 (fclk_div5 ),
|
||||
// .clk3 (fclk_div7 ),
|
||||
// .reset_n (crt_reset_n ),
|
||||
// .force_oscin_clk (1'b0 ),
|
||||
// .cts_oscin_clk (1'b0 ),
|
||||
//
|
||||
// .clk_div (hi_dsp_clk_cntl[7:0] ),
|
||||
// .clk_en (hi_dsp_clk_cntl[15] ),
|
||||
// .clk_sel (hi_dsp_clk_cntl[9:8] ),
|
||||
// .clk_out (cts_dspa_clk ));
|
||||
|
||||
static void clk_util_set_dsp_clk(uint32_t id, uint32_t freq_sel)
|
||||
{
|
||||
uint32_t clk_sel = 0;
|
||||
uint32_t clk_div = 0;
|
||||
uint32_t read;
|
||||
void __iomem *reg;
|
||||
|
||||
reg = get_hiu_addr() + REG_HHI_DSP_CLK_CNTL;
|
||||
switch (freq_sel) {
|
||||
case 1:
|
||||
clk_sel = 2;
|
||||
clk_div = 0;
|
||||
pr_debug("CLK_UTIL:dsp:fclk/5:400MHz\n");
|
||||
break;
|
||||
case 2:
|
||||
clk_sel = 0;
|
||||
clk_div = 1;
|
||||
pr_debug("CLK_UTIL:dsp:fclk/4:500MHz\n");
|
||||
break;
|
||||
case 3:
|
||||
//clk_sel = 1;
|
||||
//clk_div = 0;
|
||||
//pr_debug("CLK_UTIL:dsp:fclk/3:667MHz\n");
|
||||
break;
|
||||
case 4:
|
||||
clk_sel = 1;
|
||||
clk_div = 1;
|
||||
pr_debug("CLK_UTIL:dsp:fclk/3/2:333MHz\n");
|
||||
break;
|
||||
case 5:
|
||||
clk_sel = 0;
|
||||
clk_div = 3;
|
||||
pr_debug("CLK_UTIL:dsp:fclk/2:250MHz\n");
|
||||
break;
|
||||
case 6:
|
||||
clk_sel = 2;
|
||||
clk_div = 1;
|
||||
pr_debug("CLK_UTIL:dsp:fclk/4/2:200MHz\n");
|
||||
break;
|
||||
case 7:
|
||||
clk_sel = 2;
|
||||
clk_div = 3;
|
||||
pr_debug("CLK_UTIL:dsp:fclk/4/4:100MHz\n");
|
||||
break;
|
||||
case 8:
|
||||
clk_sel = 4;
|
||||
clk_div = 0;
|
||||
pr_debug("CLK_UTIL:dsp:oscin:24MHz\n");
|
||||
break;
|
||||
case 10:
|
||||
//clk_sel = 0;
|
||||
//clk_div = 0;
|
||||
//pr_debug("CLK_UTIL:dsp:fclk/2:1000MHz\n");
|
||||
break;
|
||||
default:
|
||||
clk_sel = 3;
|
||||
clk_div = 0;
|
||||
pr_debug("CLK_UTIL:dsp:fclk/7:286MHz\n");
|
||||
break;
|
||||
}
|
||||
|
||||
read = readl(reg);
|
||||
if (id == 0) {
|
||||
//read = (read & ~((0x3<<8) | (0xff<<0)));
|
||||
//read = read | ((1<<15) | (clk_sel<<8) | (clk_div<<0));
|
||||
if (read & (1 << 15)) { //if sync_mux ==1, sel mux 0
|
||||
read &= (~((1 << 15) | (0xf << 0) | (0x7 << 4)));
|
||||
read |= (1 << 7) | (clk_div << 0) | (clk_sel << 4);
|
||||
} else {
|
||||
read &= (~((1 << 15) | (0xf << 8) | (0x7 << 12)));
|
||||
read |= (1 << 7) | (clk_div << 8);
|
||||
read |= (clk_sel << 12) | (1 << 15);
|
||||
}
|
||||
} else {
|
||||
//read = (read & ~((0x3<<24) | (0xff<<16)));
|
||||
//read = read | ((1<<31) | (clk_sel<<24) | (clk_div<<16));
|
||||
if (read & (1 << 31)) { //if sync_mux ==1, sel mux 0
|
||||
read &= (~((1 << 31) | (0xf << 16) | (0x7 << 20)));
|
||||
read |= (1 << 23) | (clk_div << 16) | (clk_sel << 20);
|
||||
} else {
|
||||
read &= (~((1 << 31) | (0xf << 24) | (0x7 << 28)));
|
||||
read |= (1 << 23) | (clk_div << 24);
|
||||
read |= (clk_sel << 28) | (1 << 31);
|
||||
}
|
||||
}
|
||||
writel(read, reg);
|
||||
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
}
|
||||
|
||||
static void start_dsp(uint32_t dsp_id, uint32_t reset_addr)
|
||||
{
|
||||
uint32_t StatVectorSel;
|
||||
uint32_t strobe = 1;
|
||||
uint32_t tmp;
|
||||
uint32_t read;
|
||||
void __iomem *reg;
|
||||
|
||||
reg = get_dsp_addr(dsp_id);
|
||||
StatVectorSel = (reset_addr != 0xfffa0000);
|
||||
|
||||
// the bit 0 is no use, dsp in tm2 is non-secure
|
||||
tmp = 0x1 | StatVectorSel<<1 | strobe<<2;
|
||||
scpi_init_dsp_cfg0(dsp_id, reset_addr, tmp);
|
||||
|
||||
|
||||
read = readl(reg+REG_DSP_CFG0);
|
||||
pr_debug("REG_DSP_CFG0 read=0x%x\n", read);
|
||||
if (dsp_id == 0) {
|
||||
read = read & (~((1 << 31) | (1 << 30) | (0xffff << 0)));
|
||||
read = read | (1 << 29) | (0 << 0); // 29 irq_clk_en
|
||||
} else {
|
||||
read = read & (~((1 << 31) | (1 << 30) | (0xffff << 0)));
|
||||
read = read | (1 << 29) | (1 << 0);
|
||||
}
|
||||
writel(read, reg+REG_DSP_CFG0);
|
||||
tm2_dsp_top_reg_dump("REG_DSP_CFG0", reg, REG_DSP_CFG0);
|
||||
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
}
|
||||
|
||||
static void power_switch_to_dsp_a(int pwr_cntl)
|
||||
{
|
||||
uint32_t tmp;
|
||||
void __iomem *reg;
|
||||
|
||||
pr_info("[PWR]: Power %s DSP A\n", pwr_cntl?"On":"Off");
|
||||
if (pwr_cntl == 1) {
|
||||
// Powerup dsp a
|
||||
reg = get_ao_rti_addr() + REG_AO_RTI_GEN_PWR_SLEEP0;
|
||||
tmp = readl(reg) & (~(0x1<<21));
|
||||
writel(tmp, reg);// power on
|
||||
udelay(5);
|
||||
|
||||
// Power up memory
|
||||
reg = get_hiu_addr() + REG_HHI_DSP_MEM_PD_REG0;
|
||||
tmp = readl(reg) & (~(0xffff<<0));
|
||||
writel(tmp, reg);
|
||||
udelay(5);
|
||||
|
||||
// reset
|
||||
reg = get_reset_addr() + REG_RESET4_LEVEL;
|
||||
tmp = readl(reg) & (~(0x1<<0));
|
||||
writel(tmp, reg);
|
||||
|
||||
reg = get_reset_addr() + REG_RESET1_LEVEL;
|
||||
tmp = readl(reg) & (~(0x1<<20));
|
||||
writel(tmp, reg);
|
||||
|
||||
// remove isolation
|
||||
reg = get_ao_rti_addr() + REG_AO_RTI_GEN_PWR_ISO0;
|
||||
tmp = readl(reg) & (~(0x1<<21));
|
||||
writel(tmp, reg);
|
||||
|
||||
// pull up reset
|
||||
reg = get_reset_addr() + REG_RESET4_LEVEL;
|
||||
tmp = readl(reg) | (0x1<<0);
|
||||
writel(tmp, reg);
|
||||
|
||||
reg = get_reset_addr() + REG_RESET1_LEVEL;
|
||||
tmp = readl(reg) | (0x1<<20);
|
||||
writel(tmp, reg);
|
||||
} else {
|
||||
// reset
|
||||
reg = get_reset_addr() + REG_RESET4_LEVEL;
|
||||
tmp = readl(reg) & (~(0x1<<0));
|
||||
writel(tmp, reg);
|
||||
|
||||
reg = get_reset_addr() + REG_RESET1_LEVEL;
|
||||
tmp = readl(reg) & (~(0x1<<20));
|
||||
writel(tmp, reg);
|
||||
|
||||
// add isolation
|
||||
reg = get_ao_rti_addr() + REG_AO_RTI_GEN_PWR_ISO0;
|
||||
tmp = readl(reg) | (0x1<<21);
|
||||
writel(tmp, reg);
|
||||
udelay(5);
|
||||
|
||||
// power down memory
|
||||
reg = get_hiu_addr() + REG_HHI_DSP_MEM_PD_REG0;
|
||||
tmp = readl(reg) | (0xffff<<0);
|
||||
writel(tmp, reg);
|
||||
udelay(5);
|
||||
|
||||
// power down dsp a
|
||||
reg = get_ao_rti_addr() + REG_AO_RTI_GEN_PWR_SLEEP0;
|
||||
tmp = readl(reg) | (0x1<<21);
|
||||
writel(tmp, reg);
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void power_switch_to_dsp_b(int pwr_cntl)
|
||||
{
|
||||
uint32_t tmp;
|
||||
void __iomem *reg;
|
||||
|
||||
if (pwr_cntl == 1) {
|
||||
pr_info("[PWR]: Power on DSP B\n");
|
||||
// Powerup dsp a
|
||||
reg = get_ao_rti_addr() + REG_AO_RTI_GEN_PWR_SLEEP0;
|
||||
tmp = readl(reg) & (~(0x1<<22));
|
||||
writel(tmp, reg);// power on
|
||||
udelay(5);
|
||||
|
||||
// Power up memory
|
||||
reg = get_hiu_addr() + REG_HHI_DSP_MEM_PD_REG0;
|
||||
tmp = readl(reg) & (~(0xffff<<16));
|
||||
writel(tmp, reg);
|
||||
udelay(5);
|
||||
|
||||
// reset
|
||||
reg = get_reset_addr() + REG_RESET4_LEVEL;
|
||||
tmp = readl(reg) & (~(0x1<<1));
|
||||
writel(tmp, reg);
|
||||
|
||||
reg = get_reset_addr() + REG_RESET1_LEVEL;
|
||||
tmp = readl(reg) & (~(0x1<<21));
|
||||
writel(tmp, reg);
|
||||
|
||||
// remove isolation
|
||||
reg = get_ao_rti_addr() + REG_AO_RTI_GEN_PWR_ISO0;
|
||||
tmp = readl(reg) & (~(0x1<<22));
|
||||
writel(tmp, reg);
|
||||
|
||||
// pull up reset
|
||||
reg = get_reset_addr() + REG_RESET4_LEVEL;
|
||||
tmp = readl(reg) | (0x1<<1);
|
||||
writel(tmp, reg);
|
||||
|
||||
reg = get_reset_addr() + REG_RESET1_LEVEL;
|
||||
tmp = readl(reg) | (0x1<<21);
|
||||
writel(tmp, reg);
|
||||
} else {
|
||||
pr_info("[PWR]: Power off DSP B\n");
|
||||
// reset
|
||||
reg = get_reset_addr() + REG_RESET4_LEVEL;
|
||||
tmp = readl(reg) & (~(0x1<<1));
|
||||
writel(tmp, reg);
|
||||
|
||||
reg = get_reset_addr() + REG_RESET1_LEVEL;
|
||||
tmp = readl(reg) & (~(0x1<<21));
|
||||
writel(tmp, reg);
|
||||
|
||||
// add isolation
|
||||
reg = get_ao_rti_addr() + REG_AO_RTI_GEN_PWR_ISO0;
|
||||
tmp = readl(reg) | (0x1<<22);
|
||||
writel(tmp, reg);
|
||||
udelay(5);
|
||||
|
||||
// power down memory
|
||||
reg = get_hiu_addr() + REG_HHI_DSP_MEM_PD_REG0;
|
||||
tmp = readl(reg) | (0xffff<<16);
|
||||
writel(tmp, reg);
|
||||
udelay(5);
|
||||
|
||||
// power down dsp a
|
||||
reg = get_ao_rti_addr() + REG_AO_RTI_GEN_PWR_SLEEP0;
|
||||
tmp = readl(reg) | (0x1<<22);
|
||||
writel(tmp, reg);
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void tm2_dsp_power_switch(int dsp_id, int pwr_cntl)
|
||||
{
|
||||
if (dsp_id == 0)
|
||||
power_switch_to_dsp_a(pwr_cntl);
|
||||
else if (dsp_id == 1)
|
||||
power_switch_to_dsp_b(pwr_cntl);
|
||||
else
|
||||
pr_err("%s param: dsp_id=%d error\n", __func__, dsp_id);
|
||||
}
|
||||
|
||||
void tm2_dsp_top_regs_dump(int dsp_id)
|
||||
{
|
||||
void __iomem *reg;
|
||||
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
reg = get_dsp_addr(dsp_id);
|
||||
pr_debug("%s base=%p\n", __func__, reg);
|
||||
|
||||
tm2_dsp_top_reg_dump("REG_DSP_CFG0", reg, REG_DSP_CFG0);
|
||||
tm2_dsp_top_reg_dump("REG_DSP_CFG1", reg, REG_DSP_CFG1);
|
||||
tm2_dsp_top_reg_dump("REG_DSP_CFG2", reg, REG_DSP_CFG2);
|
||||
tm2_dsp_top_reg_dump("REG_DSP_RESET_VEC", reg, REG_DSP_RESET_VEC);
|
||||
|
||||
reg = get_hiu_addr();
|
||||
tm2_dsp_top_reg_dump("REG_HHI_DSP_CLK_CNTL", reg,
|
||||
REG_HHI_DSP_CLK_CNTL);
|
||||
tm2_dsp_top_reg_dump("REG_HHI_DSP_MEM_PD_REG0", reg,
|
||||
REG_HHI_DSP_MEM_PD_REG0);
|
||||
|
||||
reg = get_ao_rti_addr();
|
||||
tm2_dsp_top_reg_dump("REG_AO_RTI_GEN_PWR_SLEEP0", reg,
|
||||
REG_AO_RTI_GEN_PWR_SLEEP0);
|
||||
tm2_dsp_top_reg_dump("REG_AO_RTI_GEN_PWR_ISO0", reg,
|
||||
REG_AO_RTI_GEN_PWR_ISO0);
|
||||
|
||||
reg = get_reset_addr();
|
||||
tm2_dsp_top_reg_dump("REG_RESET1_LEVEL", reg, REG_RESET1_LEVEL);
|
||||
tm2_dsp_top_reg_dump("REG_RESET4_LEVEL", reg, REG_RESET4_LEVEL);
|
||||
|
||||
}
|
||||
|
||||
static void tm2_dsp_set_clk(int dsp_id, int freq_sel)
|
||||
{
|
||||
clk_util_set_dsp_clk(dsp_id, freq_sel);
|
||||
}
|
||||
|
||||
void tm2_dsp_hw_init(int dsp_id, int freq_sel)
|
||||
{
|
||||
int pwr_cntl = 1;
|
||||
|
||||
tm2_dsp_regs_iomem_init();
|
||||
tm2_dsp_set_clk(dsp_id, freq_sel);
|
||||
tm2_dsp_power_switch(dsp_id, pwr_cntl);
|
||||
|
||||
pr_debug("%s done\n", __func__);
|
||||
}
|
||||
|
||||
void tm2_dsp_start(int dsp_id, int freq_sel)
|
||||
{
|
||||
start_dsp(dsp_id, freq_sel);
|
||||
}
|
||||
|
||||
void tm2_dsp_bootup(int dsp_id, uint32_t reset_addr, int freq_sel)
|
||||
{
|
||||
int pwr_cntl = 1;
|
||||
|
||||
//reset_addr = 0x30000000;
|
||||
//dsp_id = 0;
|
||||
freq_sel = 1;
|
||||
|
||||
pr_debug("%s dsp_id=%d, address=0x%x\n",
|
||||
__func__, dsp_id, reset_addr);
|
||||
|
||||
tm2_dsp_set_clk(dsp_id, freq_sel);
|
||||
tm2_dsp_power_switch(dsp_id, pwr_cntl);
|
||||
tm2_dsp_start(dsp_id, reset_addr);
|
||||
|
||||
msleep(5*1000);
|
||||
tm2_dsp_top_regs_dump(dsp_id);
|
||||
}
|
||||
36
drivers/amlogic/hifi4dsp/tm2_dsp_top.h
Normal file
36
drivers/amlogic/hifi4dsp/tm2_dsp_top.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* drivers/amlogic/hifi4dsp/tm2_dsp_top.h
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _TM2_DSP_TOP_H
|
||||
#define _TM2_DSP_TOP_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/irqreturn.h>
|
||||
|
||||
#include "hifi4dsp_priv.h"
|
||||
#include "hifi4dsp_firmware.h"
|
||||
#include "hifi4dsp_dsp.h"
|
||||
|
||||
extern void tm2_dsp_bootup(int dsp_id, uint32_t reset_addr, int freq_sel);
|
||||
extern void tm2_dsp_regs_iomem_init(void);
|
||||
extern void tm2_dsp_hw_init(int dsp_id, int freq_sel);
|
||||
extern void tm2_dsp_top_regs_dump(int dsp_id);
|
||||
|
||||
#endif /*_TM2_DSP_TOP_H*/
|
||||
@@ -89,6 +89,8 @@ int hdcp22_on;
|
||||
MODULE_PARM_DESC(hdcp22_on, "\n hdcp22_on\n");
|
||||
module_param(hdcp22_on, int, 0664);
|
||||
|
||||
/* test for HBR CTS, audio module can set it to force 8ch */
|
||||
int hbr_force_8ch = 1;
|
||||
/*
|
||||
* hdcp14_key_mode:hdcp1.4 key handle method select
|
||||
* NORMAL_MODE:systemcontrol path
|
||||
@@ -1793,130 +1795,146 @@ else
|
||||
*/
|
||||
int hdmirx_audio_init(void)
|
||||
{
|
||||
/* 0=I2S 2-channel; 1=I2S 4 x 2-channel. */
|
||||
int err = 0;
|
||||
unsigned long data32 = 0;
|
||||
/* 0=I2S 2-channel; 1=I2S 4 x 2-channel. */
|
||||
int err = 0;
|
||||
unsigned long data32 = 0;
|
||||
|
||||
data32 |= 7 << 13;
|
||||
data32 |= 0 << 12;
|
||||
data32 |= 1 << 11;
|
||||
data32 |= 0 << 10;
|
||||
data32 |= 7 << 13;
|
||||
data32 |= 0 << 12;
|
||||
data32 |= 1 << 11;
|
||||
data32 |= 0 << 10;
|
||||
|
||||
data32 |= 0 << 9;
|
||||
data32 |= 1 << 8;
|
||||
data32 |= 1 << 6;
|
||||
data32 |= 3 << 4;
|
||||
data32 |= 0 << 3;
|
||||
data32 |= acr_mode << 2;
|
||||
data32 |= acr_mode << 1;
|
||||
data32 |= acr_mode << 0;
|
||||
hdmirx_wr_top(TOP_ACR_CNTL_STAT, data32);
|
||||
data32 |= 0 << 9;
|
||||
data32 |= 1 << 8;
|
||||
data32 |= 1 << 6;
|
||||
data32 |= 3 << 4;
|
||||
data32 |= 0 << 3;
|
||||
data32 |= acr_mode << 2;
|
||||
data32 |= acr_mode << 1;
|
||||
data32 |= acr_mode << 0;
|
||||
hdmirx_wr_top(TOP_ACR_CNTL_STAT, data32);
|
||||
|
||||
/*
|
||||
*recover to default value, bit[27:24]
|
||||
*set aud_pll_lock filter
|
||||
*data32 = 0;
|
||||
*data32 |= 0 << 28;
|
||||
*data32 |= 0 << 24;
|
||||
*hdmirx_wr_dwc(DWC_AUD_PLL_CTRL, data32);
|
||||
*/
|
||||
if (rx.chip_id >= CHIP_ID_TL1) {
|
||||
data32 = 0;
|
||||
data32 |= 0 << 2;/*meas_mode*/
|
||||
data32 |= 1 << 1;/*enable*/
|
||||
data32 |= 1 << 0;/*reset*/
|
||||
if (acr_mode)
|
||||
data32 |= 2 << 16;/*aud pll*/
|
||||
else
|
||||
data32 |= 500 << 16;/*acr*/
|
||||
hdmirx_wr_top(TOP_AUDMEAS_CTRL, data32);
|
||||
hdmirx_wr_top(TOP_AUDMEAS_CYCLES_M1, 65535);
|
||||
/*start messure*/
|
||||
hdmirx_wr_top(TOP_AUDMEAS_CTRL, data32 & (~0x1));
|
||||
}
|
||||
|
||||
/* AFIFO depth 1536word.*/
|
||||
/*increase start threshold to middle position */
|
||||
data32 = 0;
|
||||
data32 |= 160 << 18; /* start */
|
||||
data32 |= 200 << 9; /* max */
|
||||
data32 |= 8 << 0; /* min */
|
||||
hdmirx_wr_dwc(DWC_AUD_FIFO_TH, data32);
|
||||
/*
|
||||
*recover to default value, bit[27:24]
|
||||
*set aud_pll_lock filter
|
||||
*data32 = 0;
|
||||
*data32 |= 0 << 28;
|
||||
*data32 |= 0 << 24;
|
||||
*hdmirx_wr_dwc(DWC_AUD_PLL_CTRL, data32);
|
||||
*/
|
||||
|
||||
/* recover to default value.*/
|
||||
/*remain code for some time.*/
|
||||
/*if no side effect then remove it */
|
||||
/*
|
||||
*data32 = 0;
|
||||
*data32 |= 1 << 16;
|
||||
*data32 |= 0 << 0;
|
||||
*hdmirx_wr_dwc(DWC_AUD_FIFO_CTRL, data32);
|
||||
*/
|
||||
/* AFIFO depth 1536word.*/
|
||||
/*increase start threshold to middle position */
|
||||
data32 = 0;
|
||||
data32 |= 160 << 18; /* start */
|
||||
data32 |= 200 << 9; /* max */
|
||||
data32 |= 8 << 0; /* min */
|
||||
hdmirx_wr_dwc(DWC_AUD_FIFO_TH, data32);
|
||||
|
||||
data32 = 0;
|
||||
data32 |= 0 << 8;
|
||||
data32 |= 1 << 7;
|
||||
data32 |= aud_ch_map << 2;
|
||||
data32 |= 1 << 0;
|
||||
hdmirx_wr_dwc(DWC_AUD_CHEXTR_CTRL, data32);
|
||||
/* recover to default value.*/
|
||||
/*remain code for some time.*/
|
||||
/*if no side effect then remove it */
|
||||
/*
|
||||
*data32 = 0;
|
||||
*data32 |= 1 << 16;
|
||||
*data32 |= 0 << 0;
|
||||
*hdmirx_wr_dwc(DWC_AUD_FIFO_CTRL, data32);
|
||||
*/
|
||||
|
||||
data32 = 0;
|
||||
/* [22:21] aport_shdw_ctrl */
|
||||
data32 |= 3 << 21;
|
||||
/* [20:19] auto_aclk_mute */
|
||||
data32 |= auto_aclk_mute << 19;
|
||||
/* [16:10] aud_mute_speed */
|
||||
data32 |= 1 << 10;
|
||||
/* [7] aud_avmute_en */
|
||||
data32 |= aud_avmute_en << 7;
|
||||
/* [6:5] aud_mute_sel */
|
||||
data32 |= aud_mute_sel << 5;
|
||||
/* [4:3] aud_mute_mode */
|
||||
data32 |= 1 << 3;
|
||||
/* [2:1] aud_ttone_fs_sel */
|
||||
data32 |= 0 << 1;
|
||||
/* [0] testtone_en */
|
||||
data32 |= 0 << 0;
|
||||
hdmirx_wr_dwc(DWC_AUD_MUTE_CTRL, data32);
|
||||
data32 = 0;
|
||||
data32 |= 0 << 8;
|
||||
data32 |= 1 << 7;
|
||||
data32 |= aud_ch_map << 2;
|
||||
data32 |= 1 << 0;
|
||||
hdmirx_wr_dwc(DWC_AUD_CHEXTR_CTRL, data32);
|
||||
|
||||
/* recover to default value.*/
|
||||
/*remain code for some time.*/
|
||||
/*if no side effect then remove it */
|
||||
/*
|
||||
*data32 = 0;
|
||||
*data32 |= 0 << 16;
|
||||
*data32 |= 0 << 12;
|
||||
*data32 |= 0 << 4;
|
||||
*data32 |= 0 << 1;
|
||||
*data32 |= 0 << 0;
|
||||
*hdmirx_wr_dwc(DWC_AUD_PAO_CTRL, data32);
|
||||
*/
|
||||
data32 = 0;
|
||||
/* [22:21] aport_shdw_ctrl */
|
||||
data32 |= 3 << 21;
|
||||
/* [20:19] auto_aclk_mute */
|
||||
data32 |= auto_aclk_mute << 19;
|
||||
/* [16:10] aud_mute_speed */
|
||||
data32 |= 1 << 10;
|
||||
/* [7] aud_avmute_en */
|
||||
data32 |= aud_avmute_en << 7;
|
||||
/* [6:5] aud_mute_sel */
|
||||
data32 |= aud_mute_sel << 5;
|
||||
/* [4:3] aud_mute_mode */
|
||||
data32 |= 1 << 3;
|
||||
/* [2:1] aud_ttone_fs_sel */
|
||||
data32 |= 0 << 1;
|
||||
/* [0] testtone_en */
|
||||
data32 |= 0 << 0;
|
||||
hdmirx_wr_dwc(DWC_AUD_MUTE_CTRL, data32);
|
||||
|
||||
/* recover to default value.*/
|
||||
/*remain code for some time.*/
|
||||
/*if no side effect then remove it */
|
||||
/*
|
||||
*data32 = 0;
|
||||
*data32 |= 0 << 8;
|
||||
*hdmirx_wr_dwc(DWC_PDEC_AIF_CTRL, data32);
|
||||
*/
|
||||
/* recover to default value.*/
|
||||
/*remain code for some time.*/
|
||||
/*if no side effect then remove it */
|
||||
/*
|
||||
*data32 = 0;
|
||||
*data32 |= 0 << 16;
|
||||
*data32 |= 0 << 12;
|
||||
*data32 |= 0 << 4;
|
||||
*data32 |= 0 << 1;
|
||||
*data32 |= 0 << 0;
|
||||
*hdmirx_wr_dwc(DWC_AUD_PAO_CTRL, data32);
|
||||
*/
|
||||
|
||||
data32 = 0;
|
||||
/* [4:2] deltacts_irqtrig */
|
||||
data32 |= 0 << 2;
|
||||
/* [1:0] cts_n_meas_mode */
|
||||
data32 |= 0 << 0;
|
||||
/* DEFAULT: {27'd0, 3'd0, 2'd1} */
|
||||
hdmirx_wr_dwc(DWC_PDEC_ACRM_CTRL, data32);
|
||||
/* recover to default value.*/
|
||||
/*remain code for some time.*/
|
||||
/*if no side effect then remove it */
|
||||
/*
|
||||
*data32 = 0;
|
||||
*data32 |= 0 << 8;
|
||||
*hdmirx_wr_dwc(DWC_PDEC_AIF_CTRL, data32);
|
||||
*/
|
||||
|
||||
hdmirx_wr_bits_dwc(DWC_AUD_CTRL, DWC_AUD_HBR_ENABLE, 1);
|
||||
data32 = 0;
|
||||
/* [4:2] deltacts_irqtrig */
|
||||
data32 |= 0 << 2;
|
||||
/* [1:0] cts_n_meas_mode */
|
||||
data32 |= 0 << 0;
|
||||
/* DEFAULT: {27'd0, 3'd0, 2'd1} */
|
||||
hdmirx_wr_dwc(DWC_PDEC_ACRM_CTRL, data32);
|
||||
|
||||
/* SAO cfg, disable I2S output, no use */
|
||||
data32 = 0;
|
||||
data32 |= 1 << 10;
|
||||
data32 |= 0 << 9;
|
||||
data32 |= 0x0f << 5;
|
||||
data32 |= 0 << 1;
|
||||
data32 |= 1 << 0;
|
||||
hdmirx_wr_dwc(DWC_AUD_SAO_CTRL, data32);
|
||||
/* unsupport HBR serial mode. invalid bit */
|
||||
/* hdmirx_wr_bits_dwc(DWC_AUD_CTRL, DWC_AUD_HBR_ENABLE, 1); */
|
||||
|
||||
data32 = 0;
|
||||
data32 |= 1 << 6;
|
||||
data32 |= 0xf << 2;
|
||||
hdmirx_wr_dwc(DWC_PDEC_ASP_CTRL, data32);
|
||||
/* SAO cfg, disable I2S output, no use */
|
||||
data32 = 0;
|
||||
data32 |= 1 << 10;
|
||||
data32 |= 0 << 9;
|
||||
data32 |= 0x0f << 5;
|
||||
data32 |= 0 << 1;
|
||||
data32 |= 1 << 0;
|
||||
hdmirx_wr_dwc(DWC_AUD_SAO_CTRL, data32);
|
||||
|
||||
return err;
|
||||
data32 = 0;
|
||||
data32 |= 1 << 6;
|
||||
data32 |= 0xf << 2;
|
||||
hdmirx_wr_dwc(DWC_PDEC_ASP_CTRL, data32);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* snps phy g3 initial
|
||||
*/
|
||||
* snps phy g3 initial
|
||||
*/
|
||||
void snps_phyg3_init(void)
|
||||
{
|
||||
unsigned int data32;
|
||||
|
||||
@@ -151,6 +151,26 @@ struct __extcon_info {
|
||||
.id = EXTCON_SPDIFIN_AUDIOTYPE,
|
||||
.name = "SPDIFIN-AUDIOTYPE",
|
||||
},
|
||||
[EXTCON_EARCRX_ATNDTYP_ARC] = {
|
||||
.type = EXTCON_TYPE_MISC,
|
||||
.id = EXTCON_EARCRX_ATNDTYP_ARC,
|
||||
.name = "EARCRX-ARC",
|
||||
},
|
||||
[EXTCON_EARCRX_ATNDTYP_EARC] = {
|
||||
.type = EXTCON_TYPE_MISC,
|
||||
.id = EXTCON_EARCRX_ATNDTYP_EARC,
|
||||
.name = "EARCRX-EARC",
|
||||
},
|
||||
[EXTCON_EARCTX_ATNDTYP_ARC] = {
|
||||
.type = EXTCON_TYPE_MISC,
|
||||
.id = EXTCON_EARCTX_ATNDTYP_ARC,
|
||||
.name = "EARCTX-ARC",
|
||||
},
|
||||
[EXTCON_EARCTX_ATNDTYP_EARC] = {
|
||||
.type = EXTCON_TYPE_MISC,
|
||||
.id = EXTCON_EARCTX_ATNDTYP_EARC,
|
||||
.name = "EARCTX-EARC",
|
||||
},
|
||||
#endif
|
||||
/* Display external connector */
|
||||
[EXTCON_DISP_HDMI] = {
|
||||
|
||||
@@ -67,6 +67,10 @@
|
||||
#ifdef CONFIG_AMLOGIC_SND_SOC_AUGE
|
||||
#define EXTCON_SPDIFIN_SAMPLERATE 28 /* spdif in sample rate changed */
|
||||
#define EXTCON_SPDIFIN_AUDIOTYPE 29 /* spdif in PcPd detect */
|
||||
#define EXTCON_EARCRX_ATNDTYP_ARC 30 /* attended type, RX ARC */
|
||||
#define EXTCON_EARCRX_ATNDTYP_EARC 31 /* attended type, RX eARC */
|
||||
#define EXTCON_EARCTX_ATNDTYP_ARC 32 /* attended type, TX ARC */
|
||||
#define EXTCON_EARCTX_ATNDTYP_EARC 33 /* attended type, TX eARC */
|
||||
#endif
|
||||
/* Display external connector */
|
||||
#define EXTCON_DISP_HDMI 40 /* High-Definition Multimedia Interface */
|
||||
|
||||
@@ -6,7 +6,6 @@ obj-$(CONFIG_AMLOGIC_SND_SOC_AUGE) += audio_controller.o \
|
||||
tl1,clocks.o \
|
||||
sm1,clocks.o \
|
||||
tm2,clocks.o \
|
||||
card.o \
|
||||
card_utils.o \
|
||||
tdm.o \
|
||||
tdm_hw.o \
|
||||
@@ -37,4 +36,5 @@ obj-$(CONFIG_AMLOGIC_SND_SOC_AUGE) += audio_controller.o \
|
||||
vad_hw.o \
|
||||
vad_dev.o \
|
||||
earc.o \
|
||||
earc_hw.o
|
||||
earc_hw.o \
|
||||
card.o
|
||||
|
||||
@@ -99,6 +99,8 @@ static int audio_clocks_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
pr_info("%s done\n", __func__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -109,7 +111,16 @@ static struct platform_driver audio_clocks_driver = {
|
||||
},
|
||||
.probe = audio_clocks_probe,
|
||||
};
|
||||
module_platform_driver(audio_clocks_driver);
|
||||
|
||||
int __init audio_clocks_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = platform_driver_register(&audio_clocks_driver);
|
||||
|
||||
return ret;
|
||||
}
|
||||
core_initcall(audio_clocks_init);
|
||||
|
||||
MODULE_AUTHOR("Amlogic, Inc.");
|
||||
MODULE_DESCRIPTION("Amlogic audio clocks ASoc driver");
|
||||
|
||||
@@ -84,6 +84,15 @@ do { \
|
||||
&_name##_gate.hw, &clk_gate_ops, \
|
||||
CLK_SET_RATE_NO_REPARENT)
|
||||
|
||||
#define REGISTER_CLK_COM_PARENTS(_name, pnames) \
|
||||
clk_register_composite(NULL, #_name, \
|
||||
pnames##_parent_names, \
|
||||
ARRAY_SIZE(pnames##_parent_names), \
|
||||
&_name##_mux.hw, &clk_mux_ops, \
|
||||
&_name##_div.hw, &clk_divider_ops, \
|
||||
&_name##_gate.hw, &clk_gate_ops, \
|
||||
CLK_SET_RATE_NO_REPARENT)
|
||||
|
||||
struct audio_clk_init {
|
||||
int clk_num;
|
||||
int (*clk_gates)(struct clk **clks, void __iomem *iobase);
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/clk-provider.h>
|
||||
|
||||
#include <linux/amlogic/media/sound/iomapres.h>
|
||||
|
||||
#include "audio_io.h"
|
||||
#include "regs.h"
|
||||
|
||||
@@ -35,11 +37,8 @@ static unsigned int aml_audio_mmio_read(struct aml_audio_controller *actrlr,
|
||||
unsigned int reg)
|
||||
{
|
||||
struct regmap *regmap = actrlr->regmap;
|
||||
unsigned int val;
|
||||
|
||||
regmap_read(regmap, (reg << 2), &val);
|
||||
|
||||
return val;
|
||||
return mmio_read(regmap, reg);
|
||||
}
|
||||
|
||||
static int aml_audio_mmio_write(struct aml_audio_controller *actrlr,
|
||||
@@ -47,7 +46,12 @@ static int aml_audio_mmio_write(struct aml_audio_controller *actrlr,
|
||||
{
|
||||
struct regmap *regmap = actrlr->regmap;
|
||||
|
||||
return regmap_write(regmap, (reg << 2), value);
|
||||
pr_debug("audio top reg:[%s] addr: [%#x] val: [%#x]\n",
|
||||
top_register_table[reg].name,
|
||||
top_register_table[reg].addr,
|
||||
value);
|
||||
|
||||
return mmio_write(regmap, reg, value);
|
||||
}
|
||||
|
||||
static int aml_audio_mmio_update_bits(struct aml_audio_controller *actrlr,
|
||||
@@ -55,7 +59,12 @@ static int aml_audio_mmio_update_bits(struct aml_audio_controller *actrlr,
|
||||
{
|
||||
struct regmap *regmap = actrlr->regmap;
|
||||
|
||||
return regmap_update_bits(regmap, (reg << 2), mask, value);
|
||||
pr_debug("audio top reg:[%s] addr: [%#x] mask: [%#x] val: [%#x]\n",
|
||||
top_register_table[reg].name,
|
||||
top_register_table[reg].addr,
|
||||
mask, value);
|
||||
|
||||
return mmio_update_bits(regmap, reg, mask, value);
|
||||
}
|
||||
|
||||
struct aml_audio_ctrl_ops aml_actrl_mmio_ops = {
|
||||
|
||||
@@ -84,7 +84,7 @@ struct aml_card_data {
|
||||
int micphone_gpio_det;
|
||||
int mic_detect_flag;
|
||||
bool mic_det_enable;
|
||||
|
||||
bool av_mute_enable;
|
||||
struct aml_chipset_info *chipinfo;
|
||||
};
|
||||
|
||||
@@ -559,29 +559,48 @@ static int aml_card_dai_link_of(struct device_node *node,
|
||||
goto dai_link_of_err;
|
||||
}
|
||||
|
||||
dai_link->cpu_of_node = of_parse_phandle(cpu, DAI, 0);
|
||||
if (!dai_link->cpu_of_node) {
|
||||
dev_err(dev, "error getting cpu phandle\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = aml_card_parse_daifmt(dev, node, codec,
|
||||
prefix, &dai_link->dai_fmt);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s, dai fmt not found\n",
|
||||
__func__);
|
||||
goto dai_link_of_err;
|
||||
|
||||
}
|
||||
of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs);
|
||||
|
||||
ret = aml_card_parse_cpu(cpu, dai_link,
|
||||
DAI, CELL, &single_cpu);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s, dai-link idx:%d, error getting cpu dai name:%s\n",
|
||||
__func__,
|
||||
idx,
|
||||
dai_link->cpu_dai_name);
|
||||
goto dai_link_of_err;
|
||||
}
|
||||
|
||||
#if 0
|
||||
ret = aml_card_parse_codec(codec, dai_link, DAI, CELL);
|
||||
#else
|
||||
ret = snd_soc_of_get_dai_link_codecs(dev, codec, dai_link);
|
||||
#endif
|
||||
if (ret < 0)
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s, dai-link idx:%d, error getting codec dai name:%s\n",
|
||||
__func__,
|
||||
idx,
|
||||
dai_link->codec_dai_name);
|
||||
goto dai_link_of_err;
|
||||
}
|
||||
|
||||
ret = aml_card_parse_platform(plat, dai_link, DAI, CELL);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s, platform not found\n",
|
||||
__func__);
|
||||
|
||||
goto dai_link_of_err;
|
||||
}
|
||||
|
||||
ret = snd_soc_of_parse_tdm_slot(cpu, &cpu_dai->tx_slot_mask,
|
||||
&cpu_dai->rx_slot_mask,
|
||||
@@ -605,12 +624,6 @@ static int aml_card_dai_link_of(struct device_node *node,
|
||||
if (ret < 0)
|
||||
goto dai_link_of_err;
|
||||
|
||||
#if 0
|
||||
ret = aml_card_parse_clk_codec(codec, dai_link, codec_dai);
|
||||
if (ret < 0)
|
||||
goto dai_link_of_err;
|
||||
#endif
|
||||
|
||||
ret = aml_card_canonicalize_dailink(dai_link);
|
||||
if (ret < 0)
|
||||
goto dai_link_of_err;
|
||||
@@ -749,20 +762,28 @@ static int aml_card_parse_gpios(struct device_node *node,
|
||||
snd_soc_add_card_controls(soc_card, card_controls,
|
||||
ARRAY_SIZE(card_controls));
|
||||
}
|
||||
|
||||
pr_info("add line-out mute controls\n");
|
||||
}
|
||||
#if !defined(CONFIG_ARCH_MESON64_ODROID_COMMON)
|
||||
priv->avout_mute_desc = gpiod_get(dev,
|
||||
"avout_mute", GPIOF_OUT_INIT_LOW);
|
||||
if (IS_ERR_OR_NULL(priv->avout_mute_desc)) {
|
||||
priv->avout_mute_desc = gpiod_get(dev,
|
||||
"avout_mute", GPIOF_OUT_INIT_LOW);
|
||||
}
|
||||
if (!IS_ERR(priv->avout_mute_desc)) {
|
||||
msleep(500);
|
||||
gpiod_direction_output(priv->avout_mute_desc,
|
||||
GPIOF_OUT_INIT_HIGH);
|
||||
pr_info("av out status: %s\n",
|
||||
gpiod_get_value(priv->avout_mute_desc) ?
|
||||
"high" : "low");
|
||||
|
||||
if (!priv->av_mute_enable) {
|
||||
msleep(500);
|
||||
gpiod_direction_output(priv->avout_mute_desc,
|
||||
GPIOF_OUT_INIT_HIGH);
|
||||
pr_info("av out status: %s\n",
|
||||
gpiod_get_value(priv->avout_mute_desc) ?
|
||||
"high" : "low");
|
||||
} else {
|
||||
gpiod_direction_output(priv->avout_mute_desc,
|
||||
GPIOF_OUT_INIT_LOW);
|
||||
pr_info("av out status: %s\n",
|
||||
gpiod_get_value(priv->avout_mute_desc) ?
|
||||
"high" : "low");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
@@ -778,7 +799,6 @@ static void aml_init_work(struct work_struct *init_work)
|
||||
struct aml_card_data, init_work);
|
||||
dev = aml_priv_to_dev(priv);
|
||||
np = dev->of_node;
|
||||
|
||||
aml_card_parse_gpios(np, priv);
|
||||
}
|
||||
|
||||
@@ -823,6 +843,7 @@ static int aml_card_parse_of(struct device_node *node,
|
||||
ret = aml_card_dai_link_of(np, priv,
|
||||
i, false);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "parse dai_link-%d fail\n", i);
|
||||
of_node_put(np);
|
||||
goto card_parse_end;
|
||||
}
|
||||
@@ -876,6 +897,29 @@ static const struct of_device_id auge_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, auge_of_match);
|
||||
|
||||
static int card_suspend_pre(struct snd_soc_card *card)
|
||||
{
|
||||
struct aml_card_data *priv = snd_soc_card_get_drvdata(card);
|
||||
|
||||
priv->av_mute_enable = 1;
|
||||
INIT_WORK(&priv->init_work, aml_init_work);
|
||||
schedule_work(&priv->init_work);
|
||||
pr_info("it is card_pre_suspend\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int card_resume_post(struct snd_soc_card *card)
|
||||
{
|
||||
struct aml_card_data *priv = snd_soc_card_get_drvdata(card);
|
||||
|
||||
priv->av_mute_enable = 0;
|
||||
INIT_WORK(&priv->init_work, aml_init_work);
|
||||
schedule_work(&priv->init_work);
|
||||
pr_info("it is card_post_resume\n");
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int aml_card_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct aml_card_data *priv;
|
||||
@@ -916,13 +960,17 @@ static int aml_card_probe(struct platform_device *pdev)
|
||||
priv->snd_card.dev = dev;
|
||||
priv->snd_card.dai_link = priv->dai_link;
|
||||
priv->snd_card.num_links = num;
|
||||
priv->snd_card.suspend_pre = card_suspend_pre;
|
||||
priv->snd_card.resume_post = card_resume_post;
|
||||
|
||||
if (np && of_device_is_available(np)) {
|
||||
|
||||
ret = aml_card_parse_of(np, priv);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s, parse error %d\n",
|
||||
__func__, ret);
|
||||
dev_err(dev, "%s, aml_card_parse_of error %d %s\n",
|
||||
__func__,
|
||||
ret,
|
||||
(ret == -EPROBE_DEFER) ? "PROBE RETRY" : "");
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -960,6 +1008,7 @@ static int aml_card_probe(struct platform_device *pdev)
|
||||
sizeof(priv->dai_props->codec_dai));
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
snd_soc_card_set_drvdata(&priv->snd_card, priv);
|
||||
|
||||
ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
|
||||
@@ -986,7 +1035,7 @@ static int aml_card_probe(struct platform_device *pdev)
|
||||
audio_jack_detect(priv);
|
||||
audio_extcon_register(priv, dev);
|
||||
}
|
||||
|
||||
priv->av_mute_enable = 0;
|
||||
INIT_WORK(&priv->init_work, aml_init_work);
|
||||
schedule_work(&priv->init_work);
|
||||
|
||||
@@ -1009,6 +1058,16 @@ static int aml_card_remove(struct platform_device *pdev)
|
||||
return aml_card_clean_reference(card);
|
||||
}
|
||||
|
||||
static void aml_card_platform_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
||||
struct aml_card_data *priv = snd_soc_card_get_drvdata(card);
|
||||
|
||||
priv->av_mute_enable = 1;
|
||||
INIT_WORK(&priv->init_work, aml_init_work);
|
||||
schedule_work(&priv->init_work);
|
||||
}
|
||||
|
||||
static struct platform_driver aml_card = {
|
||||
.driver = {
|
||||
.name = "asoc-aml-card",
|
||||
@@ -1017,6 +1076,7 @@ static struct platform_driver aml_card = {
|
||||
},
|
||||
.probe = aml_card_probe,
|
||||
.remove = aml_card_remove,
|
||||
.shutdown = aml_card_platform_shutdown,
|
||||
};
|
||||
|
||||
module_platform_driver(aml_card);
|
||||
|
||||
@@ -106,7 +106,6 @@ static struct toddr *register_toddr_l(struct device *dev,
|
||||
/* (1 << 31)|(1 << mask_bit));*/
|
||||
|
||||
to->dev = dev;
|
||||
to->actrl = actrl;
|
||||
to->in_use = true;
|
||||
pr_debug("toddrs[%d] registered by device %s\n", i, dev_name(dev));
|
||||
return to;
|
||||
@@ -147,7 +146,6 @@ static int unregister_toddr_l(struct device *dev, void *data)
|
||||
|
||||
free_irq(to->irq, data);
|
||||
to->dev = NULL;
|
||||
to->actrl = NULL;
|
||||
to->in_use = false;
|
||||
pr_debug("toddrs[%d] released by device %s\n", i, dev_name(dev));
|
||||
|
||||
@@ -901,7 +899,6 @@ static struct frddr *register_frddr_l(struct device *dev,
|
||||
return NULL;
|
||||
}
|
||||
from->dev = dev;
|
||||
from->actrl = actrl;
|
||||
from->in_use = true;
|
||||
pr_debug("frddrs[%d] registered by device %s\n", i, dev_name(dev));
|
||||
return from;
|
||||
@@ -942,7 +939,6 @@ static int unregister_frddr_l(struct device *dev, void *data)
|
||||
|
||||
free_irq(from->irq, data);
|
||||
from->dev = NULL;
|
||||
from->actrl = NULL;
|
||||
from->in_use = false;
|
||||
pr_debug("frddrs[%d] released by device %s\n", i, dev_name(dev));
|
||||
return 0;
|
||||
@@ -1019,10 +1015,6 @@ int aml_check_sharebuffer_valid(struct frddr *fr, int ss_sel)
|
||||
if (frddrs[i].in_use
|
||||
&& (frddrs[i].fifo_id != current_fifo_id)
|
||||
&& (frddrs[i].dest == ss_sel)) {
|
||||
|
||||
pr_debug("%s, ss_sel:%d used, not for share buffer at same time\n",
|
||||
__func__,
|
||||
ss_sel);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
@@ -1295,20 +1287,42 @@ void aml_frddr_set_format(struct frddr *fr,
|
||||
static void aml_aed_enable(struct frddr_attach *p_attach_aed, bool enable)
|
||||
{
|
||||
struct frddr *fr = fetch_frddr_by_src(p_attach_aed->attach_module);
|
||||
int aed_version = check_aed_version();
|
||||
|
||||
if (check_aed_v2()) {
|
||||
if (aed_version == VERSION2 || aed_version == VERSION3) {
|
||||
struct aml_audio_controller *actrl = fr->actrl;
|
||||
unsigned int reg_base = fr->reg_base;
|
||||
unsigned int reg;
|
||||
|
||||
reg = calc_frddr_address(EE_AUDIO_FRDDR_A_CTRL2, reg_base);
|
||||
aml_audiobus_update_bits(actrl,
|
||||
reg, 0x1 << 3, enable << 3);
|
||||
|
||||
aed_set_ctrl(enable, 0, p_attach_aed->attach_module);
|
||||
aed_set_format(fr->msb, fr->type, fr->fifo_id);
|
||||
aed_enable(enable);
|
||||
} else {
|
||||
if (enable) {
|
||||
aml_audiobus_update_bits(actrl,
|
||||
reg, 0x1 << 3, enable << 3);
|
||||
if (aed_version == VERSION3) {
|
||||
aed_set_ctrl(enable, 0,
|
||||
p_attach_aed->attach_module, 1);
|
||||
aed_set_format(fr->msb,
|
||||
fr->type, fr->fifo_id, 1);
|
||||
} else {
|
||||
aed_set_ctrl(enable, 0,
|
||||
p_attach_aed->attach_module, 0);
|
||||
aed_set_format(fr->msb,
|
||||
fr->type, fr->fifo_id, 0);
|
||||
}
|
||||
aed_enable(enable);
|
||||
} else {
|
||||
aed_enable(enable);
|
||||
if (aed_version == VERSION3) {
|
||||
aed_set_ctrl(enable, 0,
|
||||
p_attach_aed->attach_module, 1);
|
||||
} else {
|
||||
aed_set_ctrl(enable, 0,
|
||||
p_attach_aed->attach_module, 0);
|
||||
}
|
||||
aml_audiobus_update_bits(actrl,
|
||||
reg, 0x1 << 3, enable << 3);
|
||||
}
|
||||
} else if (aed_version == VERSION1) {
|
||||
if (enable) {
|
||||
/* frddr type and bit depth for AED */
|
||||
aml_aed_format_set(fr->dest);
|
||||
@@ -1479,7 +1493,8 @@ static int toddr_src_enum_set(struct snd_kcontrol *kcontrol,
|
||||
static int frddr_src_idx = -1;
|
||||
|
||||
static const char *const frddr_src_sel_texts[] = {
|
||||
"TDMOUT_A", "TDMOUT_B", "TDMOUT_C", "SPDIFOUT_A", "SPDIFOUT_B"
|
||||
"TDMOUT_A", "TDMOUT_B", "TDMOUT_C",
|
||||
"SPDIFOUT_A", "SPDIFOUT_B", "EARCTX_DMAC"
|
||||
};
|
||||
|
||||
static const struct soc_enum frddr_output_source_enum =
|
||||
@@ -1493,7 +1508,7 @@ int frddr_src_get(void)
|
||||
|
||||
const char *frddr_src_get_str(int idx)
|
||||
{
|
||||
if (idx < 0 || idx > 4)
|
||||
if (idx < 0 || idx >= FRDDR_MAX)
|
||||
return NULL;
|
||||
|
||||
return frddr_src_sel_texts[idx];
|
||||
@@ -1627,77 +1642,93 @@ static struct notifier_block ddr_pm_notifier_block = {
|
||||
.notifier_call = ddr_pm_event,
|
||||
};
|
||||
|
||||
/* table Must in order */
|
||||
static struct ddr_info ddr_info[] = {
|
||||
{EE_AUDIO_TODDR_A_CTRL0, EE_AUDIO_FRDDR_A_CTRL0, "toddr_a", "frddr_a"},
|
||||
{EE_AUDIO_TODDR_B_CTRL0, EE_AUDIO_FRDDR_B_CTRL0, "toddr_b", "frddr_b"},
|
||||
{EE_AUDIO_TODDR_C_CTRL0, EE_AUDIO_FRDDR_C_CTRL0, "toddr_c", "frddr_c"},
|
||||
{EE_AUDIO_TODDR_D_CTRL0, EE_AUDIO_FRDDR_D_CTRL0, "toddr_d", "frddr_d"},
|
||||
};
|
||||
|
||||
static int ddr_get_toddr_base_addr_by_idx(int idx)
|
||||
{
|
||||
return ddr_info[idx].toddr_addr;
|
||||
}
|
||||
|
||||
static int ddr_get_frddr_base_addr_by_idx(int idx)
|
||||
{
|
||||
return ddr_info[idx].frddr_addr;
|
||||
}
|
||||
|
||||
static char *ddr_get_toddr_name_by_idx(int idx)
|
||||
{
|
||||
return ddr_info[idx].toddr_name;
|
||||
}
|
||||
|
||||
static char *ddr_get_frddr_name_by_idx(int idx)
|
||||
{
|
||||
return ddr_info[idx].frddr_name;
|
||||
}
|
||||
|
||||
static int aml_ddr_mngr_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
struct device_node *node_prt = NULL;
|
||||
struct platform_device *pdev_parent;
|
||||
struct aml_audio_controller *actrl = NULL;
|
||||
struct ddr_chipinfo *p_ddr_chipinfo;
|
||||
int ddr_num = 3; /* early chipset support max 3 ddr num */
|
||||
int i, ret;
|
||||
|
||||
/* get audio controller */
|
||||
node_prt = of_get_parent(node);
|
||||
if (!node_prt)
|
||||
return -ENXIO;
|
||||
|
||||
pdev_parent = of_find_device_by_node(node_prt);
|
||||
of_node_put(node_prt);
|
||||
actrl = (struct aml_audio_controller *)
|
||||
platform_get_drvdata(pdev_parent);
|
||||
|
||||
p_ddr_chipinfo = (struct ddr_chipinfo *)
|
||||
of_device_get_match_data(&pdev->dev);
|
||||
if (!p_ddr_chipinfo)
|
||||
dev_warn_once(&pdev->dev,
|
||||
"check whether to update ddr_mngr chipinfo\n");
|
||||
|
||||
/* irqs */
|
||||
toddrs[DDR_A].irq = platform_get_irq_byname(pdev, "toddr_a");
|
||||
toddrs[DDR_B].irq = platform_get_irq_byname(pdev, "toddr_b");
|
||||
toddrs[DDR_C].irq = platform_get_irq_byname(pdev, "toddr_c");
|
||||
|
||||
frddrs[DDR_A].irq = platform_get_irq_byname(pdev, "frddr_a");
|
||||
frddrs[DDR_B].irq = platform_get_irq_byname(pdev, "frddr_b");
|
||||
frddrs[DDR_C].irq = platform_get_irq_byname(pdev, "frddr_c");
|
||||
|
||||
if (p_ddr_chipinfo
|
||||
&& (p_ddr_chipinfo->fifo_num == 4)) {
|
||||
toddrs[DDR_D].irq = platform_get_irq_byname(pdev, "toddr_d");
|
||||
frddrs[DDR_D].irq = platform_get_irq_byname(pdev, "frddr_d");
|
||||
if (toddrs[DDR_D].irq < 0 || frddrs[DDR_D].irq < 0)
|
||||
dev_err(&pdev->dev, "check irq for DDR_D\n");
|
||||
ddr_num = p_ddr_chipinfo->fifo_num;
|
||||
if (!p_ddr_chipinfo) {
|
||||
dev_err(&pdev->dev,
|
||||
"check to update ddr_mngr chipinfo\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (p_ddr_chipinfo->fifo_num == 2)
|
||||
ddr_num = p_ddr_chipinfo->fifo_num;
|
||||
else if (p_ddr_chipinfo->fifo_num == 4)
|
||||
ddr_num = p_ddr_chipinfo->fifo_num;
|
||||
|
||||
for (i = 0; i < ddr_num; i++) {
|
||||
pr_info("%d, irqs toddr %d, frddr %d\n",
|
||||
i, toddrs[i].irq, frddrs[i].irq);
|
||||
toddrs[i].irq =
|
||||
platform_get_irq_byname(pdev,
|
||||
ddr_get_toddr_name_by_idx(i));
|
||||
toddrs[i].reg_base = ddr_get_toddr_base_addr_by_idx(i);
|
||||
toddrs[i].fifo_id = i;
|
||||
toddrs[i].chipinfo = p_ddr_chipinfo;
|
||||
toddrs[i].actrl = actrl;
|
||||
|
||||
frddrs[i].irq =
|
||||
platform_get_irq_byname(pdev,
|
||||
ddr_get_frddr_name_by_idx(i));
|
||||
frddrs[i].reg_base = ddr_get_frddr_base_addr_by_idx(i);
|
||||
frddrs[i].fifo_id = i;
|
||||
frddrs[i].chipinfo = p_ddr_chipinfo;
|
||||
frddrs[i].actrl = actrl;
|
||||
|
||||
dev_info(&pdev->dev, "%d, irqs toddr %d, frddr %d\n",
|
||||
i, toddrs[i].irq, frddrs[i].irq);
|
||||
|
||||
if (toddrs[i].irq <= 0 || frddrs[i].irq <= 0) {
|
||||
dev_err(&pdev->dev, "platform_get_irq_byname failed\n");
|
||||
dev_err(&pdev->dev, "%s, get irq failed\n", __func__);
|
||||
return -ENXIO;
|
||||
}
|
||||
}
|
||||
|
||||
/* inits */
|
||||
toddrs[DDR_A].reg_base = EE_AUDIO_TODDR_A_CTRL0;
|
||||
toddrs[DDR_B].reg_base = EE_AUDIO_TODDR_B_CTRL0;
|
||||
toddrs[DDR_C].reg_base = EE_AUDIO_TODDR_C_CTRL0;
|
||||
toddrs[DDR_A].fifo_id = DDR_A;
|
||||
toddrs[DDR_B].fifo_id = DDR_B;
|
||||
toddrs[DDR_C].fifo_id = DDR_C;
|
||||
|
||||
frddrs[DDR_A].reg_base = EE_AUDIO_FRDDR_A_CTRL0;
|
||||
frddrs[DDR_B].reg_base = EE_AUDIO_FRDDR_B_CTRL0;
|
||||
frddrs[DDR_C].reg_base = EE_AUDIO_FRDDR_C_CTRL0;
|
||||
frddrs[DDR_A].fifo_id = DDR_A;
|
||||
frddrs[DDR_B].fifo_id = DDR_B;
|
||||
frddrs[DDR_C].fifo_id = DDR_C;
|
||||
|
||||
if (p_ddr_chipinfo) {
|
||||
toddrs[DDR_A].chipinfo = p_ddr_chipinfo;
|
||||
toddrs[DDR_B].chipinfo = p_ddr_chipinfo;
|
||||
toddrs[DDR_C].chipinfo = p_ddr_chipinfo;
|
||||
frddrs[DDR_A].chipinfo = p_ddr_chipinfo;
|
||||
frddrs[DDR_B].chipinfo = p_ddr_chipinfo;
|
||||
frddrs[DDR_C].chipinfo = p_ddr_chipinfo;
|
||||
|
||||
if (p_ddr_chipinfo->fifo_num == 4) {
|
||||
toddrs[DDR_D].reg_base = EE_AUDIO_TODDR_D_CTRL0;
|
||||
toddrs[DDR_D].fifo_id = DDR_D;
|
||||
|
||||
frddrs[DDR_D].reg_base = EE_AUDIO_FRDDR_D_CTRL0;
|
||||
frddrs[DDR_D].fifo_id = DDR_D;
|
||||
}
|
||||
}
|
||||
|
||||
ret = register_pm_notifier(&ddr_pm_notifier_block);
|
||||
if (ret)
|
||||
pr_warn("[%s] failed to register PM notifier %d\n",
|
||||
|
||||
@@ -90,6 +90,8 @@ enum frddr_dest {
|
||||
TDMOUT_C,
|
||||
SPDIFOUT_A,
|
||||
SPDIFOUT_B,
|
||||
EARCTX_DMAC,
|
||||
FRDDR_MAX
|
||||
};
|
||||
|
||||
enum status_sel {
|
||||
@@ -228,6 +230,13 @@ struct frddr {
|
||||
struct ddr_chipinfo *chipinfo;
|
||||
};
|
||||
|
||||
struct ddr_info {
|
||||
unsigned int toddr_addr;
|
||||
unsigned int frddr_addr;
|
||||
char *toddr_name;
|
||||
char *frddr_name;
|
||||
};
|
||||
|
||||
/* to ddrs */
|
||||
struct toddr *fetch_toddr_by_src(int toddr_src);
|
||||
struct toddr *aml_audio_register_toddr(struct device *dev,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,112 +15,583 @@
|
||||
*
|
||||
*/
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include <linux/amlogic/media/sound/spdif_info.h>
|
||||
#include "earc_hw.h"
|
||||
|
||||
|
||||
void earcrx_cmdc_init(void)
|
||||
void earcrx_cmdc_init(struct regmap *top_map)
|
||||
{
|
||||
/* set irq mask */
|
||||
earcrx_top_write(EARCRX_CMDC_INT_MASK,
|
||||
(0 << 15) | /* idle2_int */
|
||||
(0 << 14) | /* idle1_int */
|
||||
(0 << 13) | /* disc2_int */
|
||||
(0 << 12) | /* disc1_int */
|
||||
(0 << 11) | /* earc_int */
|
||||
(1 << 10) | /* hb_status_int */
|
||||
(0 << 9) | /* losthb_int */
|
||||
(0 << 8) | /* timeout_int */
|
||||
(0 << 7) | /* status_ch_int */
|
||||
(0 << 6) | /* int_rec_invalid_id */
|
||||
(0 << 5) | /* int_rec_invalid_offset */
|
||||
(0 << 4) | /* int_rec_unexp */
|
||||
(0 << 3) | /* int_rec_ecc_err */
|
||||
(0 << 2) | /* int_rec_parity_err */
|
||||
(0 << 1) | /* int_recv_packet */
|
||||
(0 << 0) /* int_rec_time_out */
|
||||
);
|
||||
mmio_write(top_map, EARCRX_CMDC_INT_MASK,
|
||||
(1 << 15) | /* idle2_int */
|
||||
(1 << 14) | /* idle1_int */
|
||||
(1 << 13) | /* disc2_int */
|
||||
(1 << 12) | /* disc1_int */
|
||||
(1 << 11) | /* earc_int */
|
||||
(1 << 10) | /* hb_status_int */
|
||||
(1 << 9) | /* losthb_int */
|
||||
(1 << 8) | /* timeout_int */
|
||||
(0 << 7) | /* status_ch_int */
|
||||
(0 << 6) | /* int_rec_invalid_id */
|
||||
(0 << 5) | /* int_rec_invalid_offset */
|
||||
(0 << 4) | /* int_rec_unexp */
|
||||
(0 << 3) | /* int_rec_ecc_err */
|
||||
(0 << 2) | /* int_rec_parity_err */
|
||||
(0 << 1) | /* int_recv_packet */
|
||||
(0 << 0) /* int_rec_time_out */
|
||||
);
|
||||
|
||||
earcrx_top_write(EARCRX_ANA_CTRL0, 0x90884814);
|
||||
earcrx_top_write(EARCRX_PLL_CTRL3, 0x242000);
|
||||
earcrx_top_write(EARCRX_PLL_CTRL0, 0x10800400);
|
||||
mmio_write(top_map, EARCRX_ANA_CTRL0,
|
||||
0x1 << 31 | /* earcrx_en_d2a */
|
||||
0x10 << 24 | /* earcrx_cmdcrx_reftrim */
|
||||
0x8 << 20 | /* earcrx_idr_trim */
|
||||
0x10 << 15 | /* earcrx_rterm_trim */
|
||||
0x4 << 12 | /* earcrx_cmdctx_ack_hystrim */
|
||||
0x10 << 7 | /* earcrx_cmdctx_ack_reftrim */
|
||||
0x1 << 4 | /* earcrx_cmdcrx_rcfilter_sel */
|
||||
0x4 << 0 /* earcrx_cmdcrx_hystrim */
|
||||
);
|
||||
|
||||
mmio_write(top_map, EARCRX_PLL_CTRL3,
|
||||
0x2 << 20 | /* earcrx_pll_bias_adj */
|
||||
0x4 << 16 | /* earcrx_pll_rou */
|
||||
0x1 << 13 /* earcrx_pll_dco_sdm_e */
|
||||
);
|
||||
|
||||
mmio_write(top_map, EARCRX_PLL_CTRL0,
|
||||
0x1 << 28 | /* earcrx_pll_en */
|
||||
0x1 << 23 | /* earcrx_pll_dmacrx_sqout_rstn_sel */
|
||||
0x1 << 10 /* earcrx_pll_n */
|
||||
);
|
||||
}
|
||||
|
||||
void earcrx_dmac_init(void)
|
||||
void earcrx_cmdc_arc_connect(struct regmap *cmdc_map, bool init)
|
||||
{
|
||||
earcrx_dmac_write(EARCRX_DMAC_SYNC_CTRL0,
|
||||
(1 << 16) | /* reg_ana_buf_data_sel_en */
|
||||
(3 << 12) | /* reg_ana_buf_data_sel */
|
||||
(7 << 8) | /* reg_ana_clr_cnt */
|
||||
(7 << 4) /* reg_ana_set_cnt */
|
||||
);
|
||||
earcrx_dmac_write(EARCRX_DMAC_UBIT_CTRL0,
|
||||
(47 << 16) | /* reg_fifo_thd */
|
||||
(1 << 12) | /* reg_user_lr */
|
||||
(29 << 0) /* reg_data_bit */
|
||||
);
|
||||
earcrx_dmac_write(EARCRX_ANA_RST_CTRL0, 1 << 31);
|
||||
if (init)
|
||||
mmio_update_bits(cmdc_map,
|
||||
EARC_RX_CMDC_VSM_CTRL0,
|
||||
0x7 << 25,
|
||||
0x1 << 27 | /* arc_initiated */
|
||||
0x0 << 26 | /* arc_terminated */
|
||||
0x1 << 25 /* arc_enable */
|
||||
);
|
||||
else
|
||||
mmio_update_bits(cmdc_map,
|
||||
EARC_RX_CMDC_VSM_CTRL0,
|
||||
0x7 << 25,
|
||||
0x0 << 27 | /* arc_initiated */
|
||||
0x1 << 26 | /* arc_terminated */
|
||||
0x0 << 25 /* arc_enable */
|
||||
);
|
||||
}
|
||||
|
||||
void earc_arc_init(void)
|
||||
void earcrx_cmdc_hpd_detect(struct regmap *cmdc_map, bool st)
|
||||
{
|
||||
earcrx_dmac_write(EARCRX_SPDIFIN_CTRL0,
|
||||
(1 << 31) | /* reg_work_en */
|
||||
(1 << 30) | /* reg_chnum_sel */
|
||||
(1 << 25) | /* reg_findpapb_en */
|
||||
(0xFFF<<12) /* reg_nonpcm2pcm_th */
|
||||
);
|
||||
earcrx_dmac_write(EARCRX_SPDIFIN_CTRL2,
|
||||
(1 << 14) | /* reg_earc_auto */
|
||||
(1 << 13) /* reg_earcin_papb_lr */
|
||||
);
|
||||
earcrx_dmac_write(EARCRX_SPDIFIN_CTRL3,
|
||||
(0xEC37<<16) | /* reg_earc_pa_value */
|
||||
(0x5A5A<<0) /* reg_earc_pb_value */
|
||||
);
|
||||
}
|
||||
if (st) {
|
||||
mmio_update_bits(cmdc_map,
|
||||
EARC_RX_CMDC_VSM_CTRL0,
|
||||
0x1 << 19,
|
||||
0x1 << 19 /* comma_cnt_rst */
|
||||
);
|
||||
|
||||
void earc_rx_enable(bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
earcrx_dmac_update_bits(EARCRX_DMAC_SYNC_CTRL0,
|
||||
1 << 30, /* reg_rst_afifo_out_n */
|
||||
1 << 30);
|
||||
|
||||
earcrx_dmac_update_bits(EARCRX_DMAC_SYNC_CTRL0,
|
||||
1 << 29, /* reg_rst_afifo_in_n */
|
||||
0x1 << 29);
|
||||
|
||||
earcrx_dmac_update_bits(EARCRX_ERR_CORRECT_CTRL0,
|
||||
1 << 29, /* reg_rst_afifo_out_n */
|
||||
1 << 29
|
||||
);
|
||||
earcrx_dmac_update_bits(EARCRX_ERR_CORRECT_CTRL0,
|
||||
1 << 28, /* reg_rst_afifo_in_n */
|
||||
1 << 28 /* reg_rst_afifo_in_n */
|
||||
);
|
||||
mmio_update_bits(cmdc_map,
|
||||
EARC_RX_CMDC_VSM_CTRL0,
|
||||
0x1 << 19 | 0xff << 0,
|
||||
0x1 << 19 | /* comma_cnt_rst */
|
||||
0xff << 0
|
||||
);
|
||||
} else {
|
||||
earcrx_dmac_update_bits(EARCRX_DMAC_SYNC_CTRL0,
|
||||
0x3 << 29,
|
||||
0x0 << 29);
|
||||
/* soft reset */
|
||||
mmio_update_bits(cmdc_map,
|
||||
EARC_RX_CMDC_TOP_CTRL1,
|
||||
0xf << 0,
|
||||
0xf << 0);
|
||||
mmio_update_bits(cmdc_map,
|
||||
EARC_RX_CMDC_TOP_CTRL1,
|
||||
0xf << 0,
|
||||
0x0 << 0);
|
||||
}
|
||||
}
|
||||
|
||||
earcrx_dmac_update_bits(EARCRX_ERR_CORRECT_CTRL0,
|
||||
0x3 << 28, 0x0 << 28);
|
||||
void earcrx_dmac_init(struct regmap *top_map, struct regmap *dmac_map)
|
||||
{
|
||||
mmio_write(top_map, EARCRX_DMAC_INT_MASK,
|
||||
(0x0 << 17) | /* earcrx_ana_rst c_new_format_set */
|
||||
(0x0 << 16) | /* earcrx_ana_rst c_earcrx_div2_hold_set */
|
||||
(0x0 << 15) | /* earcrx_err_correct c_bcherr_int_set */
|
||||
(0x0 << 14) | /* earcrx_err_correct r_afifo_overflow_set */
|
||||
(0x0 << 13) | /* earcrx_err_correct r_fifo_overflow_set */
|
||||
(0x0 << 12) | /* earcrx_user_bit_check r_fifo_overflow */
|
||||
(0x0 << 11) | /* earcrx_user_bit_check c_fifo_thd_pass */
|
||||
(0x0 << 10) | /* earcrx_user_bit_check c_u_pk_lost_int_set */
|
||||
(0x0 << 9) | /* arcrx_user_bit_check c_iu_pk_end */
|
||||
(0x0 << 8) | /* arcrx_biphase_decode c_chst_mute_clr */
|
||||
(0x1 << 7) | /* arcrx_biphase_decode c_find_papb */
|
||||
(0x1 << 6) | /* arcrx_biphase_decode c_valid_change */
|
||||
(0x1 << 5) | /* arcrx_biphase_decode c_find_nonpcm2pcm */
|
||||
(0x1 << 4) | /* arcrx_biphase_decode c_pcpd_change */
|
||||
(0x1 << 3) | /* arcrx_biphase_decode c_ch_status_change */
|
||||
(0x1 << 2) | /* arcrx_biphase_decode sample_mod_change */
|
||||
(0x1 << 1) | /* arcrx_biphase_decode r_parity_err */
|
||||
(0x0 << 0) /* arcrx_dmac_sync afifo_overflow */
|
||||
);
|
||||
|
||||
mmio_write(dmac_map, EARCRX_DMAC_SYNC_CTRL0,
|
||||
(1 << 16) | /* reg_ana_buf_data_sel_en */
|
||||
(3 << 12) | /* reg_ana_buf_data_sel */
|
||||
(7 << 8) | /* reg_ana_clr_cnt */
|
||||
(7 << 4) /* reg_ana_set_cnt */
|
||||
);
|
||||
mmio_write(dmac_map, EARCRX_DMAC_UBIT_CTRL0,
|
||||
(47 << 16) | /* reg_fifo_thd */
|
||||
(1 << 12) | /* reg_user_lr */
|
||||
(29 << 0) /* reg_data_bit */
|
||||
);
|
||||
mmio_write(dmac_map, EARCRX_ANA_RST_CTRL0, 1 << 31);
|
||||
}
|
||||
|
||||
void earcrx_arc_init(struct regmap *dmac_map)
|
||||
{
|
||||
unsigned int spdifin_clk = 500000000;
|
||||
|
||||
/* sysclk/rate/32(bit)/2(ch)/2(bmc) */
|
||||
unsigned int counter_32k = (spdifin_clk / (32000 * 64));
|
||||
unsigned int counter_44k = (spdifin_clk / (44100 * 64));
|
||||
unsigned int counter_48k = (spdifin_clk / (48000 * 64));
|
||||
unsigned int counter_88k = (spdifin_clk / (88200 * 64));
|
||||
unsigned int counter_96k = (spdifin_clk / (96000 * 64));
|
||||
unsigned int counter_176k = (spdifin_clk / (176400 * 64));
|
||||
unsigned int counter_192k = (spdifin_clk / (192000 * 64));
|
||||
unsigned int mode0_th = 3 * (counter_32k + counter_44k) >> 1;
|
||||
unsigned int mode1_th = 3 * (counter_44k + counter_48k) >> 1;
|
||||
unsigned int mode2_th = 3 * (counter_48k + counter_88k) >> 1;
|
||||
unsigned int mode3_th = 3 * (counter_88k + counter_96k) >> 1;
|
||||
unsigned int mode4_th = 3 * (counter_96k + counter_176k) >> 1;
|
||||
unsigned int mode5_th = 3 * (counter_176k + counter_192k) >> 1;
|
||||
unsigned int mode0_timer = counter_32k >> 1;
|
||||
unsigned int mode1_timer = counter_44k >> 1;
|
||||
unsigned int mode2_timer = counter_48k >> 1;
|
||||
unsigned int mode3_timer = counter_88k >> 1;
|
||||
unsigned int mode4_timer = counter_96k >> 1;
|
||||
unsigned int mode5_timer = (counter_176k >> 1);
|
||||
unsigned int mode6_timer = (counter_192k >> 1);
|
||||
|
||||
mmio_write(dmac_map,
|
||||
EARCRX_SPDIFIN_SAMPLE_CTRL0,
|
||||
0x0 << 28 | /* detect by max_width */
|
||||
(spdifin_clk / 10000) << 0 /* base timer */
|
||||
);
|
||||
|
||||
mmio_write(dmac_map,
|
||||
EARCRX_SPDIFIN_SAMPLE_CTRL1,
|
||||
mode0_th << 20 |
|
||||
mode1_th << 10 |
|
||||
mode2_th << 0);
|
||||
|
||||
mmio_write(dmac_map,
|
||||
EARCRX_SPDIFIN_SAMPLE_CTRL2,
|
||||
mode3_th << 20 |
|
||||
mode4_th << 10 |
|
||||
mode5_th << 0);
|
||||
|
||||
mmio_write(dmac_map,
|
||||
EARCRX_SPDIFIN_SAMPLE_CTRL3,
|
||||
(mode0_timer << 24) |
|
||||
(mode1_timer << 16) |
|
||||
(mode2_timer << 8) |
|
||||
(mode3_timer << 0)
|
||||
);
|
||||
|
||||
mmio_write(dmac_map,
|
||||
EARCRX_SPDIFIN_SAMPLE_CTRL4,
|
||||
(mode4_timer << 24) |
|
||||
(mode5_timer << 16) |
|
||||
(mode6_timer << 8)
|
||||
);
|
||||
|
||||
mmio_write(dmac_map,
|
||||
EARCRX_SPDIFIN_CTRL0,
|
||||
0x1 << 31 | /* reg_work_en */
|
||||
0x1 << 30 | /* reg_chnum_sel */
|
||||
0x1 << 25 | /* reg_findpapb_en */
|
||||
0x1 << 24 | /* nonpcm2pcm_th enable */
|
||||
0xFFF << 12 /* reg_nonpcm2pcm_th */
|
||||
);
|
||||
mmio_write(dmac_map,
|
||||
EARCRX_SPDIFIN_CTRL2,
|
||||
(1 << 14) | /* reg_earc_auto */
|
||||
(1 << 13) /* reg_earcin_papb_lr */
|
||||
);
|
||||
mmio_write(dmac_map,
|
||||
EARCRX_SPDIFIN_CTRL3,
|
||||
(0xEC37 << 16) | /* reg_earc_pa_value */
|
||||
(0x5A5A << 0) /* reg_earc_pb_value */
|
||||
);
|
||||
}
|
||||
|
||||
enum cmdc_st earcrx_cmdc_get_state(struct regmap *cmdc_map)
|
||||
{
|
||||
int val = mmio_read(cmdc_map, EARC_RX_CMDC_STATUS0);
|
||||
enum cmdc_st state = (enum cmdc_st)(val & 0x7);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
enum attend_type earcrx_cmdc_get_attended_type(struct regmap *cmdc_map)
|
||||
{
|
||||
int val = mmio_read(cmdc_map, EARC_RX_CMDC_STATUS0);
|
||||
enum cmdc_st state = (enum cmdc_st)(val & 0x7);
|
||||
enum attend_type type = ATNDTYP_DISCNCT;
|
||||
|
||||
if ((val & (1 << 0x3)) && (state == CMDC_ST_ARC))
|
||||
type = ATNDTYP_ARC;
|
||||
else if ((val & (1 << 0x4)) && (state == CMDC_ST_EARC))
|
||||
type = ATNDTYP_EARC;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
void earcrx_cdmc_clr_irqs(struct regmap *top_map, int clr)
|
||||
{
|
||||
mmio_write(top_map, EARCRX_CMDC_INT_PENDING, clr);
|
||||
}
|
||||
|
||||
int earcrx_cdmc_get_irqs(struct regmap *top_map)
|
||||
{
|
||||
return mmio_read(top_map, EARCRX_CMDC_INT_PENDING);
|
||||
}
|
||||
|
||||
void earcrx_dmac_clr_irqs(struct regmap *top_map, int clr)
|
||||
{
|
||||
mmio_write(top_map, EARCRX_DMAC_INT_PENDING, clr);
|
||||
}
|
||||
|
||||
int earcrx_dmac_get_irqs(struct regmap *top_map)
|
||||
{
|
||||
return mmio_read(top_map, EARCRX_DMAC_INT_PENDING);
|
||||
}
|
||||
|
||||
void earcrx_enable(struct regmap *cmdc_map,
|
||||
struct regmap *dmac_map, bool enable)
|
||||
{
|
||||
enum attend_type type = earcrx_cmdc_get_attended_type(cmdc_map);
|
||||
|
||||
if (enable) {
|
||||
mmio_update_bits(dmac_map, EARCRX_DMAC_SYNC_CTRL0,
|
||||
1 << 30, /* reg_rst_afifo_out_n */
|
||||
1 << 30);
|
||||
|
||||
mmio_update_bits(dmac_map, EARCRX_DMAC_SYNC_CTRL0,
|
||||
1 << 29, /* reg_rst_afifo_in_n */
|
||||
0x1 << 29);
|
||||
|
||||
mmio_update_bits(dmac_map, EARCRX_ERR_CORRECT_CTRL0,
|
||||
1 << 29, /* reg_rst_afifo_out_n */
|
||||
1 << 29
|
||||
);
|
||||
mmio_update_bits(dmac_map, EARCRX_ERR_CORRECT_CTRL0,
|
||||
1 << 28, /* reg_rst_afifo_in_n */
|
||||
1 << 28 /* reg_rst_afifo_in_n */
|
||||
);
|
||||
} else {
|
||||
mmio_update_bits(dmac_map, EARCRX_DMAC_SYNC_CTRL0,
|
||||
0x3 << 29,
|
||||
0x0 << 29);
|
||||
|
||||
mmio_update_bits(dmac_map, EARCRX_ERR_CORRECT_CTRL0,
|
||||
0x3 << 28, 0x0 << 28);
|
||||
}
|
||||
|
||||
earcrx_dmac_update_bits(EARCRX_DMAC_SYNC_CTRL0,
|
||||
1 << 31, /* reg_work_en */
|
||||
enable << 31);
|
||||
if (type == ATNDTYP_EARC)
|
||||
mmio_update_bits(dmac_map, EARCRX_DMAC_SYNC_CTRL0,
|
||||
1 << 31, /* reg_work_en */
|
||||
enable << 31);
|
||||
else if (type == ATNDTYP_ARC) {
|
||||
mmio_update_bits(dmac_map,
|
||||
EARCRX_SPDIFIN_SAMPLE_CTRL0,
|
||||
0x1 << 31, /* reg_work_enable */
|
||||
enable << 31);
|
||||
|
||||
earcrx_dmac_update_bits(EARCRX_DMAC_UBIT_CTRL0,
|
||||
1 << 31, /* reg_work_enable */
|
||||
enable << 31);
|
||||
mmio_write(dmac_map, EARCRX_DMAC_SYNC_CTRL0, 0x0);
|
||||
}
|
||||
|
||||
earcrx_dmac_update_bits(EARCRX_ERR_CORRECT_CTRL0,
|
||||
1 << 31,
|
||||
enable << 31); /* reg_work_en */
|
||||
mmio_update_bits(dmac_map, EARCRX_DMAC_UBIT_CTRL0,
|
||||
1 << 31, /* reg_work_enable */
|
||||
enable << 31);
|
||||
|
||||
earcrx_dmac_update_bits(EARCRX_DMAC_TOP_CTRL0,
|
||||
1 << 31,
|
||||
enable << 31); /* reg_top_work_en */
|
||||
mmio_update_bits(dmac_map, EARCRX_ERR_CORRECT_CTRL0,
|
||||
1 << 31,
|
||||
enable << 31); /* reg_work_en */
|
||||
|
||||
mmio_update_bits(dmac_map, EARCRX_DMAC_TOP_CTRL0,
|
||||
1 << 31,
|
||||
enable << 31); /* reg_top_work_en */
|
||||
}
|
||||
|
||||
void earctx_cmdc_int_mask(struct regmap *top_map)
|
||||
{
|
||||
mmio_write(top_map, EARCTX_CMDC_INT_MASK,
|
||||
(0x0 << 17) | /* hpd_high_int */
|
||||
(0x0 << 16) | /* hpd_low_int */
|
||||
(0x1 << 15) | /* idle2_int */
|
||||
(0x1 << 14) | /* idle1_int */
|
||||
(0x1 << 13) | /* disc2_int */
|
||||
(0x1 << 12) | /* disc1_int */
|
||||
(0x1 << 11) | /* earc_int */
|
||||
(0x0 << 10) | /* hb_status_int */
|
||||
(0x1 << 9) | /* losthb_int */
|
||||
(0x1 << 8) | /* timeout_int */
|
||||
(0x0 << 7) | /* status_ch_int */
|
||||
(0x0 << 6) | /* int_recv_finished */
|
||||
(0x0 << 5) | /* int_recv_nack */
|
||||
(0x0 << 4) | /* int_recv_norsp */
|
||||
(0x0 << 3) | /* int_recv_unexp */
|
||||
(0x0 << 2) | /* int_recv_data */
|
||||
(0x0 << 1) | /* int_recv_ack */
|
||||
(0x0 << 0) /* int_recv_ecc_err */
|
||||
);
|
||||
}
|
||||
|
||||
void earctx_cmdc_init(struct regmap *top_map)
|
||||
{
|
||||
/* ana */
|
||||
mmio_write(top_map, EARCTX_ANA_CTRL0,
|
||||
0x1 << 31 | /* earctx_en_d2a */
|
||||
0x1 << 28 | /* earctx_cmdcrx_rcfilter_sel */
|
||||
0x4 << 26 | /* earctx_cmdcrx_hystrim */
|
||||
0x8 << 20 | /* earctx_idr_trim */
|
||||
0x10 << 12 | /* earctx_rterm_trim */
|
||||
0x4 << 8 | /* earctx_dmac_slew_con */
|
||||
0x4 << 5 | /* earctx_cmdctx_ack_hystrim */
|
||||
0x10 << 0 /* earctx_cmdctx_ack_reftrim */
|
||||
);
|
||||
}
|
||||
|
||||
void earctx_cmdc_arc_connect(struct regmap *cmdc_map, bool init)
|
||||
{
|
||||
if (init)
|
||||
mmio_update_bits(cmdc_map,
|
||||
EARC_TX_CMDC_VSM_CTRL0,
|
||||
0x7 << 25,
|
||||
0x1 << 27 | /* arc_initiated */
|
||||
0x0 << 26 | /* arc_terminated */
|
||||
0x1 << 25 /* arc_enable */
|
||||
);
|
||||
else
|
||||
mmio_update_bits(cmdc_map,
|
||||
EARC_TX_CMDC_VSM_CTRL0,
|
||||
0x7 << 25,
|
||||
0x0 << 27 | /* arc_initiated */
|
||||
0x1 << 26 | /* arc_terminated */
|
||||
0x0 << 25 /* arc_enable */
|
||||
);
|
||||
}
|
||||
|
||||
void earctx_cmdc_hpd_detect(struct regmap *top_map,
|
||||
struct regmap *cmdc_map,
|
||||
int earc_port, bool st)
|
||||
{
|
||||
/* select hdmirx_hpd */
|
||||
mmio_update_bits(cmdc_map,
|
||||
EARC_TX_CMDC_VSM_CTRL1,
|
||||
0x1 << 8, /* cntl_hpd_sel */
|
||||
0x1 << 8);
|
||||
|
||||
/* select hdmi_hpd mux */
|
||||
mmio_update_bits(top_map, EARCTX_TOP_CTRL0,
|
||||
0xf << 8,
|
||||
0x1 << 11 | /* hdmi_hpd invent */
|
||||
earc_port << 8 /* hdmi_hpd mux, port 0/1/2 */
|
||||
);
|
||||
|
||||
if (st) {
|
||||
mmio_update_bits(cmdc_map,
|
||||
EARC_TX_CMDC_VSM_CTRL0,
|
||||
0x1 << 19,
|
||||
0x1 << 19 /* comma_cnt_rst */
|
||||
);
|
||||
|
||||
mmio_update_bits(cmdc_map,
|
||||
EARC_TX_CMDC_VSM_CTRL0,
|
||||
0x1 << 19 | 0xf << 20,
|
||||
0x0 << 19 | /* comma_cnt_rst */
|
||||
0x3 << 20 | 0x3 << 22
|
||||
);
|
||||
|
||||
/* no timeout */
|
||||
mmio_update_bits(cmdc_map,
|
||||
EARC_TX_CMDC_VSM_CTRL5,
|
||||
0x3 << 0,
|
||||
0x1 << 1
|
||||
);
|
||||
|
||||
mmio_update_bits(cmdc_map,
|
||||
EARC_TX_CMDC_VSM_CTRL1,
|
||||
0xff << 0,
|
||||
0xa << 0 /* comma_cnt_th */
|
||||
);
|
||||
} else {
|
||||
/* soft reset */
|
||||
mmio_update_bits(cmdc_map,
|
||||
EARC_TX_CMDC_TOP_CTRL1,
|
||||
0xf << 0,
|
||||
0xf << 0);
|
||||
mmio_update_bits(cmdc_map,
|
||||
EARC_TX_CMDC_TOP_CTRL1,
|
||||
0xf << 0,
|
||||
0x0 << 0);
|
||||
}
|
||||
}
|
||||
|
||||
void earctx_dmac_init(struct regmap *top_map, struct regmap *dmac_map)
|
||||
{
|
||||
mmio_update_bits(dmac_map, EARCTX_SPDIFOUT_CTRL0,
|
||||
0x3 << 28,
|
||||
0x0 << 28);
|
||||
mmio_update_bits(dmac_map, EARCTX_SPDIFOUT_CTRL0,
|
||||
0x1 << 29, /* afifo out reset */
|
||||
0x1 << 29);
|
||||
mmio_update_bits(dmac_map, EARCTX_SPDIFOUT_CTRL0,
|
||||
0x1 << 28 | /* afifo in reset */
|
||||
0x1 << 26 | /* user Bit select */
|
||||
0x1 << 24 | /* chdata select*/
|
||||
0x1 << 20 | /* reg_data_sel, 1: data from 27bit */
|
||||
0x1 << 19 | /* 0: lsb first */
|
||||
0x1 << 18 | /* biphase encode valid Bit value sel */
|
||||
0xff << 4, /* lane mask */
|
||||
0x1 << 28 |
|
||||
0x1 << 26 |
|
||||
0x1 << 24 |
|
||||
0x1 << 20 |
|
||||
0x0 << 19 |
|
||||
0x1 << 18 |
|
||||
0x3 << 4 // ODO: lane 0 now
|
||||
);
|
||||
|
||||
mmio_update_bits(dmac_map, EARCTX_ERR_CORRT_CTRL0,
|
||||
0x1 << 16 | /* reg_ubit_fifo_init_n */
|
||||
0x7 << 8 | /* r channel select */
|
||||
0x7 << 4, /* l channel select */
|
||||
0x1 << 16 |
|
||||
0x1 << 8 |
|
||||
0x0 << 4);
|
||||
|
||||
mmio_update_bits(dmac_map, EARCTX_ERR_CORRT_CTRL4,
|
||||
0xf << 17,
|
||||
0x1 << 19 | /* userBit sel, 1: reg_value */
|
||||
0x1 << 18 | /* validBit sel, 1: reg_value */
|
||||
0x1 << 17 /* reg_chst_sel, 1: reg_value */
|
||||
);
|
||||
}
|
||||
|
||||
void earctx_dmac_set_format(struct regmap *dmac_map,
|
||||
int frddr_idx, int msb, int frddr_type)
|
||||
{
|
||||
mmio_update_bits(dmac_map, EARCTX_SPDIFOUT_CTRL1,
|
||||
0x7 << 24 | /* frddr src */
|
||||
0xff << 16 | /* waiting count after enabled */
|
||||
0x1f << 8 | /* msb position */
|
||||
0x7 << 4, /* frddr type */
|
||||
frddr_idx << 24 |
|
||||
0x40 << 16 |
|
||||
msb << 8 |
|
||||
frddr_type << 4);
|
||||
|
||||
mmio_update_bits(dmac_map, EARCTX_ERR_CORRT_CTRL4,
|
||||
0x1f << 25,
|
||||
0x1f << 25 /* msb */
|
||||
);
|
||||
|
||||
/* for raw data */
|
||||
mmio_update_bits(dmac_map, EARCTX_ERR_CORRT_CTRL3,
|
||||
0x1f << 24,
|
||||
0x17 << 24
|
||||
);
|
||||
}
|
||||
|
||||
void earctx_set_channel_status_info(struct regmap *dmac_map,
|
||||
struct iec958_chsts *chsts)
|
||||
{
|
||||
/* ch status = reg_chsts0~B */
|
||||
|
||||
/* L Channel */
|
||||
mmio_write(dmac_map, EARCTX_SPDIFOUT_CHSTS0,
|
||||
((chsts->chstat1_l >> 8) & 0xf) << 24 | chsts->chstat0_l);
|
||||
|
||||
/* R Channel */
|
||||
mmio_write(dmac_map, EARCTX_SPDIFOUT_CHSTS6,
|
||||
((chsts->chstat1_r >> 8) & 0xf) << 24 | chsts->chstat0_r);
|
||||
}
|
||||
|
||||
enum attend_type earctx_cmdc_get_attended_type(struct regmap *cmdc_map)
|
||||
{
|
||||
int val = mmio_read(cmdc_map, EARC_TX_CMDC_STATUS0);
|
||||
enum cmdc_st state = (enum cmdc_st)(val & 0x7);
|
||||
enum attend_type tx_type = ATNDTYP_DISCNCT;
|
||||
|
||||
if ((val & (1 << 0x3)) && (state == CMDC_ST_ARC))
|
||||
tx_type = ATNDTYP_ARC;
|
||||
else if ((val & (1 << 0x4)) && (state == CMDC_ST_EARC))
|
||||
tx_type = ATNDTYP_EARC;
|
||||
|
||||
return tx_type;
|
||||
}
|
||||
|
||||
void earctx_cdmc_clr_irqs(struct regmap *top_map, int clr)
|
||||
{
|
||||
mmio_write(top_map, EARCTX_CMDC_INT_PENDING, clr);
|
||||
}
|
||||
|
||||
int earctx_cdmc_get_irqs(struct regmap *top_map)
|
||||
{
|
||||
return mmio_read(top_map, EARCTX_CMDC_INT_PENDING);
|
||||
}
|
||||
|
||||
void earctx_dmac_clr_irqs(struct regmap *top_map, int clr)
|
||||
{
|
||||
mmio_write(top_map, EARCTX_DMAC_INT_PENDING, clr);
|
||||
}
|
||||
|
||||
int earctx_dmac_get_irqs(struct regmap *top_map)
|
||||
{
|
||||
return mmio_read(top_map, EARCTX_DMAC_INT_PENDING);
|
||||
}
|
||||
|
||||
void earctx_enable(struct regmap *top_map,
|
||||
struct regmap *cmdc_map,
|
||||
struct regmap *dmac_map,
|
||||
bool enable)
|
||||
{
|
||||
mmio_update_bits(dmac_map, EARCTX_SPDIFOUT_CTRL0,
|
||||
0x1 << 31,
|
||||
enable << 31);
|
||||
|
||||
mmio_update_bits(dmac_map, EARC_RX_CMDC_BIPHASE_CTRL1,
|
||||
0x1 << 30,
|
||||
enable << 30);
|
||||
|
||||
if (enable)
|
||||
mmio_write(top_map, EARCTX_DMAC_INT_MASK,
|
||||
(0x1 << 4) | /* fe_modulation c_hold_clr */
|
||||
(0x1 << 3) | /* fe_modulation c_hold_start */
|
||||
(0x1 << 2) | /* err_correct c_fifo_thd_less_pass */
|
||||
(0x1 << 1) | /* err_correct r_fifo_overflow_set */
|
||||
(0x1 << 0) /* err_correct c_fifo_empty_set */
|
||||
);
|
||||
else
|
||||
mmio_write(top_map, EARCTX_DMAC_INT_MASK,
|
||||
0x0
|
||||
);
|
||||
|
||||
if (earctx_cmdc_get_attended_type(cmdc_map) == ATNDTYP_EARC) {
|
||||
if (spdifout_is_raw()) {
|
||||
mmio_update_bits(dmac_map, EARCTX_ERR_CORRT_CTRL3,
|
||||
0x1 << 29,
|
||||
enable << 29);
|
||||
}
|
||||
mmio_update_bits(dmac_map, EARCTX_FE_CTRL0,
|
||||
0x1 << 30,
|
||||
enable << 30);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,9 +19,126 @@
|
||||
|
||||
#include "regs.h"
|
||||
#include "iomap.h"
|
||||
#include <linux/amlogic/media/sound/iomapres.h>
|
||||
#include <linux/amlogic/media/sound/spdif_info.h>
|
||||
|
||||
#define INT_EARCRX_CMDC_IDLE2 (0x1 << 15)
|
||||
#define INT_EARCRX_CMDC_IDLE1 (0x1 << 14)
|
||||
#define INT_EARCRX_CMDC_DISC2 (0x1 << 13)
|
||||
#define INT_EARCRX_CMDC_DISC1 (0x1 << 12)
|
||||
#define INT_EARCRX_CMDC_EARC (0x1 << 11)
|
||||
#define INT_EARCRX_CMDC_HB_STATUS (0x1 << 10)
|
||||
#define INT_EARCRX_CMDC_LOSTHB (0x1 << 9)
|
||||
#define INT_EARCRX_CMDC_TIMEOUT (0x1 << 8)
|
||||
#define INT_EARCRX_CMDC_STATUS_CH (0x1 << 7)
|
||||
#define INT_EARCRX_CMDC_REC_INVALID_ID (0x1 << 6)
|
||||
#define INT_EARCRX_CMDC_REC_INVALID_OFFSET (0x1 << 5)
|
||||
#define INT_EARCRX_CMDC_REC_UNEXP (0x1 << 4)
|
||||
#define INT_EARCRX_CMDC_REC_ECC_ERR (0x1 << 3)
|
||||
#define INT_EARCRX_CMDC_REC_PARITY_ERR (0x1 << 2)
|
||||
#define INT_EARCRX_CMDC_RECV_PACKET (0x1 << 1)
|
||||
#define INT_EARCRX_CMDC_REC_TIME_OUT (0x1 << 0)
|
||||
|
||||
#define INT_EARCRX_ANA_RST_C_NEW_FORMAT_SET (0x1 << 17)
|
||||
#define INT_EARCRX_ANA_RST_C_EARCRX_DIV2_HOLD_SET (0x1 << 16)
|
||||
#define INT_EARCRX_ERR_CORRECT_C_BCHERR_INT_SET (0x1 << 15)
|
||||
#define INT_EARCRX_ERR_CORRECT_R_AFIFO_OVERFLOW_SET (0x1 << 14)
|
||||
#define INT_EARCRX_ERR_CORRECT_R_FIFO_OVERFLOW_SET (0x1 << 13)
|
||||
#define INT_EARCRX_USER_BIT_CHECK_R_FIFO_OVERFLOW (0x1 << 12)
|
||||
#define INT_EARCRX_USER_BIT_CHECK_C_FIFO_THD_PASS (0x1 << 11)
|
||||
#define INT_EARCRX_USER_BIT_CHECK_C_U_PK_LOST_INT_SET (0x1 << 10)
|
||||
#define INT_ARCRX_USER_BIT_CHECK_C_IU_PK_END (0x1 << 9)
|
||||
#define INT_ARCRX_BIPHASE_DECODE_C_CHST_MUTE_CLR (0x1 << 8)
|
||||
#define INT_ARCRX_BIPHASE_DECODE_C_FIND_PAPB (0x1 << 7)
|
||||
#define INT_ARCRX_BIPHASE_DECODE_C_VALID_CHANGE (0x1 << 6)
|
||||
#define INT_ARCRX_BIPHASE_DECODE_C_FIND_NONPCM2PCM (0x1 << 5)
|
||||
#define INT_ARCRX_BIPHASE_DECODE_C_PCPD_CHANGE (0x1 << 4)
|
||||
#define INT_ARCRX_BIPHASE_DECODE_C_CH_STATUS_CHANGE (0x1 << 3)
|
||||
#define INT_ARCRX_BIPHASE_DECODE_I_SAMPLE_MODE_CHANGE (0x1 << 2)
|
||||
#define INT_ARCRX_BIPHASE_DECODE_R_PARITY_ERR (0x1 << 1)
|
||||
#define INT_ARCRX_DMAC_SYNC_AFIFO_OVERFLOW (0x1 << 0)
|
||||
|
||||
#define INT_EARCTX_CMDC_HPD_H (0x1 << 17)
|
||||
#define INT_EARCTX_CMDC_HPD_L (0x1 << 16)
|
||||
#define INT_EARCTX_CMDC_IDLE2 (0x1 << 15)
|
||||
#define INT_EARCTX_CMDC_IDLE1 (0x1 << 14)
|
||||
#define INT_EARCTX_CMDC_DISC2 (0x1 << 13)
|
||||
#define INT_EARCTX_CMDC_DISC1 (0x1 << 12)
|
||||
#define INT_EARCTX_CMDC_EARC (0x1 << 11)
|
||||
#define INT_EARCTX_CMDC_HB_STATUS (0x1 << 10)
|
||||
#define INT_EARCTX_CMDC_LOSTHB (0x1 << 9)
|
||||
#define INT_EARCTX_CMDC_TIMEOUT (0x1 << 8)
|
||||
#define INT_EARCTX_CMDC_STATUS_CH (0x1 << 7)
|
||||
#define INT_EARCTX_CMDC_RECV_FINISHED (0x1 << 6)
|
||||
#define INT_EARCTX_CMDC_RECV_NACK (0x1 << 5)
|
||||
#define INT_EARCTX_CMDC_RECV_NORSP (0x1 << 4)
|
||||
#define INT_EARCTX_CMDC_RECV_UNEXP (0x1 << 3)
|
||||
#define INT_EARCTX_CMDC_RECV_DATA (0x1 << 2)
|
||||
#define INT_EARCTX_CMDC_RECV_ACK (0x1 << 1)
|
||||
#define INT_EARCTX_CMDC_RECV_ECC_ERR (0x1 << 0)
|
||||
|
||||
#define INT_EARCTX_FEM_C_HOLD_CLR (0x1 << 4)
|
||||
#define INT_EARCTX_FEM_C_HOLD_START (0x1 << 3)
|
||||
#define INT_EARCTX_ERRCORR_C_FIFO_THD_LESS_PASS (0x1 << 2)
|
||||
#define INT_EARCTX_ERRCORR_C_FIFO_OVERFLOW (0x1 << 1)
|
||||
#define INT_EARCTX_ERRCORR_C_FIFO_EMPTY (0x1 << 0)
|
||||
|
||||
/* cmdc discovery and disconnect state */
|
||||
enum cmdc_st {
|
||||
CMDC_ST_OFF,
|
||||
CMDC_ST_IDLE1,
|
||||
CMDC_ST_IDLE2,
|
||||
CMDC_ST_DISC1,
|
||||
CMDC_ST_DISC2,
|
||||
CMDC_ST_EARC,
|
||||
CMDC_ST_ARC
|
||||
};
|
||||
|
||||
/* attended type: disconect, ARC, eARC */
|
||||
enum attend_type {
|
||||
ATNDTYP_DISCNCT,
|
||||
ATNDTYP_ARC,
|
||||
ATNDTYP_EARC
|
||||
};
|
||||
|
||||
enum tx_hd_hdp_mux {
|
||||
GPIOW_1,
|
||||
GPIOW_9,
|
||||
GPIOW_5
|
||||
};
|
||||
|
||||
void earcrx_cmdc_init(struct regmap *top_map);
|
||||
void earcrx_cmdc_arc_connect(struct regmap *cmdc_map, bool init);
|
||||
void earcrx_cmdc_hpd_detect(struct regmap *cmdc_map, bool st);
|
||||
void earcrx_dmac_init(struct regmap *top_map, struct regmap *dmac_map);
|
||||
void earcrx_arc_init(struct regmap *dmac_map);
|
||||
enum cmdc_st earcrx_cmdc_get_state(struct regmap *cmdc_map);
|
||||
enum attend_type earcrx_cmdc_get_attended_type(struct regmap *cmdc_map);
|
||||
void earcrx_cdmc_clr_irqs(struct regmap *top_map, int clr);
|
||||
int earcrx_cdmc_get_irqs(struct regmap *top_map);
|
||||
void earcrx_dmac_clr_irqs(struct regmap *top_map, int clr);
|
||||
int earcrx_dmac_get_irqs(struct regmap *top_map);
|
||||
void earcrx_enable(struct regmap *cmdc_map,
|
||||
struct regmap *dmac_map, bool enable);
|
||||
void earctx_cmdc_int_mask(struct regmap *top_map);
|
||||
|
||||
void earctx_cmdc_init(struct regmap *top_map);
|
||||
void earctx_cmdc_arc_connect(struct regmap *cmdc_map, bool init);
|
||||
void earctx_cmdc_hpd_detect(struct regmap *top_map,
|
||||
struct regmap *cmdc_map,
|
||||
int earc_port, bool st);
|
||||
void earctx_dmac_init(struct regmap *top_map, struct regmap *dmac_map);
|
||||
void earctx_dmac_set_format(struct regmap *dmac_map,
|
||||
int frddr_idx, int msb, int frddr_type);
|
||||
void earctx_set_channel_status_info(struct regmap *dmac_map,
|
||||
struct iec958_chsts *chsts);
|
||||
void earctx_cdmc_clr_irqs(struct regmap *top_map, int clr);
|
||||
int earctx_cdmc_get_irqs(struct regmap *top_map);
|
||||
void earctx_dmac_clr_irqs(struct regmap *top_map, int clr);
|
||||
int earctx_dmac_get_irqs(struct regmap *top_map);
|
||||
void earctx_enable(struct regmap *top_map,
|
||||
struct regmap *cmdc_map,
|
||||
struct regmap *dmac_map,
|
||||
bool enable);
|
||||
|
||||
extern void earcrx_cmdc_init(void);
|
||||
extern void earcrx_dmac_init(void);
|
||||
extern void earc_arc_init(void);
|
||||
extern void earc_rx_enable(bool enable);
|
||||
#endif
|
||||
|
||||
@@ -235,7 +235,35 @@ void aed_set_lane_and_channels(int lane_mask, int ch_mask)
|
||||
0xff << 12, (ch_num - 1) << 12);
|
||||
}
|
||||
|
||||
void aed_set_ctrl(bool enable, int sel, enum frddr_dest module)
|
||||
/* max 16ch, 8 lane*/
|
||||
void aed_set_lane_and_channels_v3(int lane_mask, int ch_mask)
|
||||
{
|
||||
int ch_num = 0, lane_num = 0, i = 0;
|
||||
int val_ch = ch_mask & 0xffff;
|
||||
int val_lane = lane_mask & 0xff;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
if ((val_ch & 0x1) == 0x1)
|
||||
ch_num++;
|
||||
if ((val_lane & 0x1) == 0x1)
|
||||
lane_num = i;
|
||||
val_ch >>= 1;
|
||||
val_lane >>= 1;
|
||||
}
|
||||
|
||||
eqdrc_update_bits(AED_TOP_CTL1,
|
||||
0xf << 20 | 0xf << 16 | 0x1 << 5 | 0x1 << 4 | 0xf,
|
||||
(lane_num * 2 + 1) << 20 | (lane_num * 2) << 16 |
|
||||
0x1 << 5 | 0x1 << 4 | (ch_num - 1));
|
||||
|
||||
eqdrc_update_bits(AED_TOP_CTL2,
|
||||
0xff << 12, (ch_num - 1) << 12);
|
||||
|
||||
/*pr_info("ch_num = %d, lane_num = %d", ch_num, lane_num);*/
|
||||
}
|
||||
|
||||
|
||||
void aed_set_ctrl(bool enable, int sel, enum frddr_dest module, int offset)
|
||||
{
|
||||
int mask = 0, val = 0;
|
||||
|
||||
@@ -258,7 +286,8 @@ void aed_set_ctrl(bool enable, int sel, enum frddr_dest module)
|
||||
return;
|
||||
}
|
||||
|
||||
eqdrc_update_bits(AED_TOP_REQ_CTL, mask, val);
|
||||
/*AED_TOP_REQ_CTL or AED_TOP_CTL2*/
|
||||
eqdrc_update_bits((AED_TOP_REQ_CTL + offset), mask, val);
|
||||
|
||||
/* Effect Module */
|
||||
if (module <= TDMOUT_C && module >= TDMOUT_A) {
|
||||
@@ -271,11 +300,12 @@ void aed_set_ctrl(bool enable, int sel, enum frddr_dest module)
|
||||
|
||||
}
|
||||
|
||||
void aed_set_format(int msb, enum ddr_types frddr_type, enum ddr_num source)
|
||||
void aed_set_format(int msb, enum ddr_types frddr_type,
|
||||
enum ddr_num source, int offset)
|
||||
{
|
||||
eqdrc_update_bits(AED_TOP_CTL,
|
||||
0x7 << 11 | 0x1f << 6 | 0x3 << 4,
|
||||
frddr_type << 11 | msb << 6 | source << 4);
|
||||
frddr_type << 11 | msb << 6 | source << (4 - offset));
|
||||
}
|
||||
|
||||
void aed_enable(bool enable)
|
||||
|
||||
@@ -33,8 +33,11 @@ void aed_set_multiband_drc_enable(bool enable);
|
||||
void aed_set_volume(unsigned int master_volume,
|
||||
unsigned int Lch_vol, unsigned int Rch_vol);
|
||||
void aed_set_lane_and_channels(int lane_mask, int ch_mask);
|
||||
void aed_set_ctrl(bool enable, int sel, enum frddr_dest module);
|
||||
void aed_set_format(int msb, enum ddr_types frddr_type, enum ddr_num source);
|
||||
void aed_set_lane_and_channels_v3(int lane_mask, int ch_mask);
|
||||
void aed_set_ctrl(bool enable, int sel,
|
||||
enum frddr_dest module, int offset);
|
||||
void aed_set_format(int msb, enum ddr_types frddr_type,
|
||||
enum ddr_num source, int offset);
|
||||
void aed_enable(bool enable);
|
||||
void aed_set_mixer_params(void);
|
||||
void aed_eq_taps(unsigned int eq1_taps);
|
||||
|
||||
@@ -49,8 +49,10 @@ enum {
|
||||
struct effect_chipinfo {
|
||||
/* v1 is for G12X(g12a, g12b)
|
||||
* v2 is for tl1
|
||||
* v3 is for sm1/tm2
|
||||
*/
|
||||
bool v2;
|
||||
int version;
|
||||
bool reserved_frddr;
|
||||
};
|
||||
|
||||
struct audioeffect {
|
||||
@@ -90,17 +92,24 @@ static struct audioeffect *get_audioeffects(void)
|
||||
return s_effect;
|
||||
}
|
||||
|
||||
bool check_aed_v2(void)
|
||||
int get_aed_dst(void)
|
||||
{
|
||||
struct audioeffect *p_effect = get_audioeffects();
|
||||
|
||||
if (!p_effect)
|
||||
return false;
|
||||
return -1;
|
||||
else
|
||||
return p_effect->effect_module;
|
||||
}
|
||||
|
||||
if (p_effect->chipinfo && p_effect->chipinfo->v2)
|
||||
return true;
|
||||
int check_aed_version(void)
|
||||
{
|
||||
struct audioeffect *p_effect = get_audioeffects();
|
||||
|
||||
return false;
|
||||
if ((!p_effect) || (!p_effect->chipinfo))
|
||||
return -1;
|
||||
|
||||
return p_effect->chipinfo->version;
|
||||
}
|
||||
|
||||
static int eqdrc_clk_set(struct audioeffect *p_effect)
|
||||
@@ -577,7 +586,13 @@ int card_add_effect_v2_kcontrols(struct snd_soc_card *card)
|
||||
}
|
||||
|
||||
static struct effect_chipinfo tl1_effect_chipinfo = {
|
||||
.v2 = true,
|
||||
.version = VERSION2,
|
||||
.reserved_frddr = true,
|
||||
};
|
||||
|
||||
static struct effect_chipinfo sm1_effect_chipinfo = {
|
||||
.version = VERSION3,
|
||||
.reserved_frddr = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id effect_device_id[] = {
|
||||
@@ -589,8 +604,8 @@ static const struct of_device_id effect_device_id[] = {
|
||||
.data = &tl1_effect_chipinfo,
|
||||
},
|
||||
{
|
||||
.compatible = "amlogic, tl1-effect",
|
||||
.data = &tl1_effect_chipinfo,
|
||||
.compatible = "amlogic, snd-effect-v3",
|
||||
.data = &sm1_effect_chipinfo,
|
||||
},
|
||||
{}
|
||||
};
|
||||
@@ -701,8 +716,16 @@ static int effect_platform_probe(struct platform_device *pdev)
|
||||
p_effect->ch_mask = channel_mask;
|
||||
p_effect->effect_module = eqdrc_module;
|
||||
|
||||
p_effect->dev = dev;
|
||||
s_effect = p_effect;
|
||||
dev_set_drvdata(&pdev->dev, p_effect);
|
||||
|
||||
/*set eq/drc module lane & channels*/
|
||||
aed_set_lane_and_channels(lane_mask, channel_mask);
|
||||
if (check_aed_version() == VERSION3)
|
||||
aed_set_lane_and_channels_v3(lane_mask, channel_mask);
|
||||
else
|
||||
aed_set_lane_and_channels(lane_mask, channel_mask);
|
||||
|
||||
/*set master & channel volume gain to 0dB*/
|
||||
aed_set_volume(0xc0, 0x30, 0x30);
|
||||
/*set default mixer gain*/
|
||||
@@ -720,9 +743,10 @@ static int effect_platform_probe(struct platform_device *pdev)
|
||||
/*set EQ/DRC module enable*/
|
||||
aml_set_aed(1, p_effect->effect_module);
|
||||
|
||||
p_effect->dev = dev;
|
||||
s_effect = p_effect;
|
||||
dev_set_drvdata(&pdev->dev, p_effect);
|
||||
if (p_effect->chipinfo &&
|
||||
p_effect->chipinfo->reserved_frddr) {
|
||||
aml_aed_set_frddr_reserved();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,13 @@
|
||||
#ifndef __EFFECTS_V2_H__
|
||||
#define __EFFECTS_V2_H__
|
||||
|
||||
extern bool check_aed_v2(void);
|
||||
enum {
|
||||
VERSION1 = 0,
|
||||
VERSION2,
|
||||
VERSION3
|
||||
};
|
||||
|
||||
extern int check_aed_version(void);
|
||||
extern int card_add_effect_v2_kcontrols(struct snd_soc_card *card);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <sound/control.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#include "ddr_mngr.h"
|
||||
#include "audio_utils.h"
|
||||
@@ -45,11 +46,19 @@
|
||||
|
||||
#define MAX_INT 0x7ffffff
|
||||
|
||||
#define DYNC_KCNTL_CNT 2
|
||||
|
||||
struct extn_chipinfo {
|
||||
/* try to check papb before fetch pcpd
|
||||
* no nonpcm2pcm irq for tl1
|
||||
*/
|
||||
bool no_nonpcm2pcm_clr;
|
||||
|
||||
/* eARC-ARC or CEC-ARC
|
||||
* CEC-ARC: tl1
|
||||
* eARC-ARC: sm1/tm2, etc
|
||||
*/
|
||||
bool cec_arc;
|
||||
};
|
||||
|
||||
struct extn {
|
||||
@@ -89,6 +98,8 @@ struct extn {
|
||||
bool nonpcm_flag;
|
||||
|
||||
struct extn_chipinfo *chipinfo;
|
||||
struct snd_kcontrol *controls[DYNC_KCNTL_CNT];
|
||||
|
||||
};
|
||||
|
||||
#define PREALLOC_BUFFER (256 * 1024)
|
||||
@@ -134,6 +145,17 @@ static irqreturn_t extn_ddr_isr(int irq, void *devid)
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct device *dev = rtd->platform->dev;
|
||||
struct extn *p_extn = (struct extn *)dev_get_drvdata(dev);
|
||||
int timeout_thres = 5;
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_MEDIA_TVIN_HDMI
|
||||
int sample_rate_index = get_hdmi_sample_rate_index();
|
||||
|
||||
/*192K audio*/
|
||||
if (sample_rate_index == 7)
|
||||
timeout_thres = 10;
|
||||
else
|
||||
timeout_thres = 5;
|
||||
#endif
|
||||
|
||||
if (!snd_pcm_running(substream))
|
||||
return IRQ_HANDLED;
|
||||
@@ -356,10 +378,19 @@ struct snd_soc_platform_driver extn_platform = {
|
||||
.pcm_new = extn_new,
|
||||
};
|
||||
|
||||
static int extn_create_controls(struct snd_card *card,
|
||||
struct extn *p_extn);
|
||||
|
||||
static int extn_dai_probe(struct snd_soc_dai *cpu_dai)
|
||||
{
|
||||
struct snd_card *card = cpu_dai->component->card->snd_card;
|
||||
struct extn *p_extn = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
|
||||
pr_info("asoc debug: %s-%d\n", __func__, __LINE__);
|
||||
|
||||
if (p_extn->chipinfo && p_extn->chipinfo->cec_arc)
|
||||
extn_create_controls(card, p_extn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -607,8 +638,10 @@ static int arc_get_src(
|
||||
struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct extn *p_extn = dev_get_drvdata(component->dev);
|
||||
struct extn *p_extn = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
if (!p_extn)
|
||||
return 0;
|
||||
|
||||
ucontrol->value.integer.value[0] = p_extn->arc_src;
|
||||
|
||||
@@ -619,8 +652,10 @@ static int arc_set_src(
|
||||
struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct extn *p_extn = dev_get_drvdata(component->dev);
|
||||
struct extn *p_extn = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
if (!p_extn)
|
||||
return 0;
|
||||
|
||||
p_extn->arc_src = ucontrol->value.integer.value[0];
|
||||
|
||||
@@ -633,8 +668,10 @@ static int arc_get_enable(
|
||||
struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct extn *p_extn = dev_get_drvdata(component->dev);
|
||||
struct extn *p_extn = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
if (!p_extn)
|
||||
return 0;
|
||||
|
||||
ucontrol->value.integer.value[0] = p_extn->arc_en;
|
||||
|
||||
@@ -645,8 +682,10 @@ static int arc_set_enable(
|
||||
struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct extn *p_extn = dev_get_drvdata(component->dev);
|
||||
struct extn *p_extn = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
if (!p_extn)
|
||||
return 0;
|
||||
|
||||
p_extn->arc_en = ucontrol->value.integer.value[0];
|
||||
|
||||
@@ -662,6 +701,9 @@ static int frhdmirx_get_mode(
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct extn *p_extn = dev_get_drvdata(component->dev);
|
||||
|
||||
if (!p_extn)
|
||||
return 0;
|
||||
|
||||
ucontrol->value.integer.value[0] = p_extn->hdmirx_mode;
|
||||
|
||||
return 0;
|
||||
@@ -674,6 +716,9 @@ static int frhdmirx_set_mode(
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct extn *p_extn = dev_get_drvdata(component->dev);
|
||||
|
||||
if (!p_extn)
|
||||
return 0;
|
||||
|
||||
p_extn->hdmirx_mode = ucontrol->value.integer.value[0];
|
||||
|
||||
return 0;
|
||||
@@ -745,6 +790,9 @@ static int hdmirx_audio_type_get_enum(
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct extn *p_extn = dev_get_drvdata(component->dev);
|
||||
|
||||
if (!p_extn)
|
||||
return 0;
|
||||
|
||||
ucontrol->value.enumerated.item[0] =
|
||||
hdmiin_check_audio_type(p_extn);
|
||||
|
||||
@@ -752,8 +800,7 @@ static int hdmirx_audio_type_get_enum(
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct snd_kcontrol_new extn_controls[] = {
|
||||
/* Out */
|
||||
static const struct snd_kcontrol_new extn_arc_controls[DYNC_KCNTL_CNT] = {
|
||||
SOC_ENUM_EXT("HDMI ARC Source",
|
||||
arc_src_enum,
|
||||
arc_get_src,
|
||||
@@ -763,6 +810,34 @@ static const struct snd_kcontrol_new extn_controls[] = {
|
||||
0,
|
||||
arc_get_enable,
|
||||
arc_set_enable),
|
||||
};
|
||||
|
||||
static int extn_create_controls(struct snd_card *card,
|
||||
struct extn *p_extn)
|
||||
{
|
||||
int i, err = 0;
|
||||
|
||||
memset(p_extn->controls, 0, sizeof(p_extn->controls));
|
||||
|
||||
for (i = 0; i < DYNC_KCNTL_CNT; i++) {
|
||||
p_extn->controls[i] =
|
||||
snd_ctl_new1(&extn_arc_controls[i], p_extn);
|
||||
err = snd_ctl_add(card, p_extn->controls[i]);
|
||||
if (err < 0)
|
||||
goto __error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
__error:
|
||||
for (i = 0; i < DYNC_KCNTL_CNT; i++)
|
||||
if (p_extn->controls[i])
|
||||
snd_ctl_remove(card, p_extn->controls[i]);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new extn_controls[] = {
|
||||
|
||||
/* In */
|
||||
SOC_SINGLE_BOOL_EXT("SPDIFIN PAO",
|
||||
@@ -831,12 +906,12 @@ static const struct snd_soc_component_driver extn_component = {
|
||||
|
||||
struct extn_chipinfo tl1_extn_chipinfo = {
|
||||
.no_nonpcm2pcm_clr = true,
|
||||
.cec_arc = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id extn_device_id[] = {
|
||||
{
|
||||
.compatible = "amlogic, snd-extn",
|
||||
.data = &tl1_extn_chipinfo,
|
||||
},
|
||||
{
|
||||
.compatible = "amlogic, tl1-snd-extn",
|
||||
@@ -898,10 +973,10 @@ static int extn_platform_probe(struct platform_device *pdev)
|
||||
/* Default: PAO mode */
|
||||
p_extn->hdmirx_mode = 1;
|
||||
|
||||
ret = snd_soc_register_component(&pdev->dev,
|
||||
&extn_component,
|
||||
extn_dai,
|
||||
ARRAY_SIZE(extn_dai));
|
||||
ret = devm_snd_soc_register_component(&pdev->dev,
|
||||
&extn_component,
|
||||
extn_dai,
|
||||
ARRAY_SIZE(extn_dai));
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"snd_soc_register_component failed\n");
|
||||
|
||||
@@ -231,87 +231,6 @@ void vad_update_bits(unsigned int reg,
|
||||
}
|
||||
EXPORT_SYMBOL(vad_update_bits);
|
||||
|
||||
int earcrx_cmdc_read(unsigned int reg)
|
||||
{
|
||||
int ret, val = 0;
|
||||
|
||||
ret = aml_snd_read(IO_EARCRX_CMDC, reg, &val);
|
||||
|
||||
if (ret) {
|
||||
pr_err("read audio reg %x error %d\n", reg, ret);
|
||||
return -1;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
EXPORT_SYMBOL(earcrx_cmdc_read);
|
||||
|
||||
void earcrx_cmdc_write(unsigned int reg, unsigned int val)
|
||||
{
|
||||
aml_snd_write(IO_EARCRX_CMDC, reg, val);
|
||||
}
|
||||
EXPORT_SYMBOL(earcrx_cmdc_write);
|
||||
|
||||
void earcrx_cmdc_update_bits(unsigned int reg,
|
||||
unsigned int mask, unsigned int val)
|
||||
{
|
||||
aml_snd_update_bits(IO_EARCRX_CMDC, reg, mask, val);
|
||||
}
|
||||
EXPORT_SYMBOL(earcrx_cmdc_update_bits);
|
||||
|
||||
int earcrx_dmac_read(unsigned int reg)
|
||||
{
|
||||
int ret, val = 0;
|
||||
|
||||
ret = aml_snd_read(IO_EARCRX_DMAC, reg, &val);
|
||||
|
||||
if (ret) {
|
||||
pr_err("read audio reg %x error %d\n", reg, ret);
|
||||
return -1;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
EXPORT_SYMBOL(earcrx_dmac_read);
|
||||
|
||||
void earcrx_dmac_write(unsigned int reg, unsigned int val)
|
||||
{
|
||||
aml_snd_write(IO_EARCRX_DMAC, reg, val);
|
||||
}
|
||||
EXPORT_SYMBOL(earcrx_dmac_write);
|
||||
|
||||
void earcrx_dmac_update_bits(unsigned int reg,
|
||||
unsigned int mask, unsigned int val)
|
||||
{
|
||||
aml_snd_update_bits(IO_EARCRX_DMAC, reg, mask, val);
|
||||
}
|
||||
EXPORT_SYMBOL(earcrx_dmac_update_bits);
|
||||
|
||||
int earcrx_top_read(unsigned int reg)
|
||||
{
|
||||
int ret, val = 0;
|
||||
|
||||
ret = aml_snd_read(IO_EARCRX_TOP, reg, &val);
|
||||
|
||||
if (ret) {
|
||||
pr_err("read audio reg %x error %d\n", reg, ret);
|
||||
return -1;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
EXPORT_SYMBOL(earcrx_top_read);
|
||||
|
||||
void earcrx_top_write(unsigned int reg, unsigned int val)
|
||||
{
|
||||
aml_snd_write(IO_EARCRX_TOP, reg, val);
|
||||
}
|
||||
EXPORT_SYMBOL(earcrx_top_write);
|
||||
|
||||
void earcrx_top_update_bits(unsigned int reg,
|
||||
unsigned int mask, unsigned int val)
|
||||
{
|
||||
aml_snd_update_bits(IO_EARCRX_TOP, reg, mask, val);
|
||||
}
|
||||
EXPORT_SYMBOL(earcrx_top_update_bits);
|
||||
|
||||
static int snd_iomap_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource res;
|
||||
|
||||
@@ -25,9 +25,6 @@ enum{
|
||||
IO_EQDRC_BUS,
|
||||
IO_RESET,
|
||||
IO_VAD,
|
||||
IO_EARCRX_CMDC,
|
||||
IO_EARCRX_DMAC,
|
||||
IO_EARCRX_TOP,
|
||||
|
||||
IO_MAX,
|
||||
};
|
||||
@@ -61,17 +58,4 @@ extern int vad_read(unsigned int reg);
|
||||
extern void vad_write(unsigned int reg, unsigned int val);
|
||||
extern void vad_update_bits(unsigned int reg,
|
||||
unsigned int mask, unsigned int val);
|
||||
|
||||
extern int earcrx_cmdc_read(unsigned int reg);
|
||||
extern void earcrx_cmdc_write(unsigned int reg, unsigned int val);
|
||||
extern void earcrx_cmdc_update_bits(unsigned int reg,
|
||||
unsigned int mask, unsigned int val);
|
||||
extern int earcrx_dmac_read(unsigned int reg);
|
||||
extern void earcrx_dmac_write(unsigned int reg, unsigned int val);
|
||||
extern void earcrx_dmac_update_bits(unsigned int reg,
|
||||
unsigned int mask, unsigned int val);
|
||||
extern int earcrx_top_read(unsigned int reg);
|
||||
extern void earcrx_top_write(unsigned int reg, unsigned int val);
|
||||
extern void earcrx_top_update_bits(unsigned int reg,
|
||||
unsigned int mask, unsigned int val);
|
||||
#endif
|
||||
|
||||
@@ -75,7 +75,8 @@ struct loopback {
|
||||
unsigned int datalb_chnum;
|
||||
unsigned int datalb_chmask;
|
||||
unsigned int datalb_lane_mask; /* related with data lane */
|
||||
|
||||
unsigned int lb_format;
|
||||
unsigned int lb_lane_chmask;
|
||||
unsigned int sysclk_freq;
|
||||
|
||||
struct toddr *tddr;
|
||||
@@ -430,8 +431,8 @@ static int loopback_dai_startup(
|
||||
|
||||
/* datalb */
|
||||
switch (p_loopback->datalb_src) {
|
||||
case TDMINLB_TDMOUTA ... TDMINLB_PAD_TDMINC:
|
||||
tdminlb_startup(p_loopback);
|
||||
case TDMINLB_TDMOUTA ... TDMINLB_PAD_TDMINC_D:
|
||||
/*tdminlb_startup(p_loopback);*/
|
||||
break;
|
||||
case SPDIFINLB_SPDIFOUTA ... SPDIFINLB_SPDIFOUTB:
|
||||
break;
|
||||
@@ -472,8 +473,8 @@ static void loopback_dai_shutdown(
|
||||
|
||||
/* datalb */
|
||||
switch (p_loopback->datalb_src) {
|
||||
case TDMINLB_TDMOUTA ... TDMINLB_PAD_TDMINC:
|
||||
tdminlb_shutdown(p_loopback);
|
||||
case TDMINLB_TDMOUTA ... TDMINLB_PAD_TDMINC_D:
|
||||
/*tdminlb_shutdown(p_loopback);*/
|
||||
break;
|
||||
case SPDIFINLB_SPDIFOUTA ... SPDIFINLB_SPDIFOUTB:
|
||||
break;
|
||||
@@ -554,12 +555,7 @@ static int loopback_set_ctrl(struct loopback *p_loopback, int bitwidth)
|
||||
}
|
||||
|
||||
switch (p_loopback->datalb_src) {
|
||||
case TDMINLB_TDMOUTA:
|
||||
case TDMINLB_TDMOUTB:
|
||||
case TDMINLB_TDMOUTC:
|
||||
case TDMINLB_PAD_TDMINA:
|
||||
case TDMINLB_PAD_TDMINB:
|
||||
case TDMINLB_PAD_TDMINC:
|
||||
case TDMINLB_TDMOUTA ... TDMINLB_PAD_TDMINC_D:
|
||||
if (bitwidth == 24) {
|
||||
datalb_toddr_type = 4;
|
||||
datalb_msb = 32 - 1;
|
||||
@@ -603,9 +599,10 @@ static int loopback_set_ctrl(struct loopback *p_loopback, int bitwidth)
|
||||
lb_set_datain_cfg(p_loopback->id, &datain_cfg);
|
||||
lb_set_datalb_cfg(p_loopback->id, &datalb_cfg);
|
||||
|
||||
tdminlb_set_format(1); /* tdmin_lb i2s mode */
|
||||
tdminlb_set_format(p_loopback->lb_format == SND_SOC_DAIFMT_I2S);
|
||||
tdminlb_set_lanemask_and_chswap(0x76543210,
|
||||
p_loopback->datalb_lane_mask);
|
||||
p_loopback->datalb_lane_mask,
|
||||
p_loopback->lb_lane_chmask);
|
||||
tdminlb_set_ctrl(p_loopback->datalb_src);
|
||||
|
||||
return 0;
|
||||
@@ -714,6 +711,10 @@ static int loopback_dai_prepare(
|
||||
case TDMINLB_PAD_TDMINB:
|
||||
case TDMINLB_PAD_TDMINC:
|
||||
break;
|
||||
case TDMINLB_PAD_TDMINA_D:
|
||||
case TDMINLB_PAD_TDMINB_D:
|
||||
case TDMINLB_PAD_TDMINC_D:
|
||||
break;
|
||||
case SPDIFINLB_SPDIFOUTA:
|
||||
case SPDIFINLB_SPDIFOUTB:
|
||||
break;
|
||||
@@ -861,8 +862,8 @@ static int loopback_dai_hw_params(
|
||||
|
||||
/* datalb */
|
||||
switch (p_loopback->datalb_src) {
|
||||
case TDMINLB_TDMOUTA ... TDMINLB_PAD_TDMINC:
|
||||
datalb_tdminlb_set_clk(p_loopback);
|
||||
case TDMINLB_TDMOUTA ... TDMINLB_PAD_TDMINC_D:
|
||||
/*datalb_tdminlb_set_clk(p_loopback);*/
|
||||
break;
|
||||
case SPDIFINLB_SPDIFOUTA ... SPDIFINLB_SPDIFOUTB:
|
||||
break;
|
||||
@@ -1008,6 +1009,9 @@ static const char *const datalb_tdminlb_texts[] = {
|
||||
"TDMIN_A",
|
||||
"TDMIN_B",
|
||||
"TDMIN_C",
|
||||
"TDMIN_A_D",
|
||||
"TDMIN_B_D",
|
||||
"TDMIN_C_D",
|
||||
};
|
||||
|
||||
static const struct soc_enum datalb_tdminlb_enum =
|
||||
@@ -1247,6 +1251,39 @@ err:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static unsigned int loopback_parse_format(struct device_node *node)
|
||||
{
|
||||
unsigned int format = 0;
|
||||
int ret = 0;
|
||||
const char *str;
|
||||
struct {
|
||||
char *name;
|
||||
unsigned int val;
|
||||
} fmt_table[] = {
|
||||
{"i2s", SND_SOC_DAIFMT_I2S},
|
||||
{"dsp_a", SND_SOC_DAIFMT_DSP_A},
|
||||
{"dsp_b", SND_SOC_DAIFMT_DSP_B}
|
||||
};
|
||||
|
||||
ret = of_property_read_string(node, "datalb-format", &str);
|
||||
if (ret == 0) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fmt_table); i++) {
|
||||
if (strcmp(str, fmt_table[i].name) == 0) {
|
||||
format |= fmt_table[i].val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* default format is I2S */
|
||||
if (format == 0)
|
||||
format = SND_SOC_DAIFMT_I2S;
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
static int loopback_parse_of(
|
||||
struct device_node *node,
|
||||
struct loopback *p_loopback)
|
||||
@@ -1320,6 +1357,15 @@ static int loopback_parse_of(
|
||||
goto fail;
|
||||
}
|
||||
|
||||
p_loopback->lb_format = loopback_parse_format(node);
|
||||
snd_soc_of_get_slot_mask
|
||||
(node,
|
||||
"datalb-channels-mask",
|
||||
&p_loopback->lb_lane_chmask);
|
||||
if (p_loopback->lb_lane_chmask == 0) {
|
||||
/* default format is I2S and mask two channels */
|
||||
p_loopback->lb_lane_chmask = 0x3;
|
||||
}
|
||||
pr_info("\tdatain_src:%d, datain_chnum:%d, datain_chumask:%x\n",
|
||||
p_loopback->datain_src,
|
||||
p_loopback->datain_chnum,
|
||||
@@ -1331,6 +1377,8 @@ static int loopback_parse_of(
|
||||
pr_info("\tdatain_lane_mask:0x%x, datalb_lane_mask:0x%x\n",
|
||||
p_loopback->datain_lane_mask,
|
||||
p_loopback->datalb_lane_mask);
|
||||
pr_info("datalb_format: %d, chmask for lanes: %#x\n",
|
||||
p_loopback->lb_format, p_loopback->lb_lane_chmask);
|
||||
|
||||
ret = datain_parse_of(node, p_loopback);
|
||||
if (ret) {
|
||||
|
||||
@@ -55,6 +55,10 @@ enum datalb_src {
|
||||
TDMINLB_PAD_TDMINB,
|
||||
TDMINLB_PAD_TDMINC,
|
||||
|
||||
TDMINLB_PAD_TDMINA_D,
|
||||
TDMINLB_PAD_TDMINB_D,
|
||||
TDMINLB_PAD_TDMINC_D,
|
||||
|
||||
SPDIFINLB_SPDIFOUTA,
|
||||
SPDIFINLB_SPDIFOUTB,
|
||||
};
|
||||
|
||||
@@ -22,35 +22,40 @@
|
||||
#include "regs.h"
|
||||
#include "iomap.h"
|
||||
|
||||
static unsigned int
|
||||
get_tdmin_id_from_lb_src(enum datalb_src lb_src)
|
||||
{
|
||||
return lb_src % TDMINLB_PAD_TDMINA;
|
||||
}
|
||||
|
||||
void tdminlb_set_clk(int datatlb_src, int sclk_div, int ratio, bool enable)
|
||||
void tdminlb_set_clk(enum datalb_src lb_src,
|
||||
int sclk_div, int ratio, bool enable)
|
||||
{
|
||||
unsigned int bclk_sel, fsclk_sel;
|
||||
unsigned int tdmin_src;
|
||||
|
||||
/* config for external codec */
|
||||
if (datatlb_src >= 3) {
|
||||
unsigned int clk_id = datatlb_src - 3;
|
||||
if (lb_src >= TDMINLB_PAD_TDMINA) {
|
||||
unsigned int id = get_tdmin_id_from_lb_src(lb_src);
|
||||
unsigned int offset, reg;
|
||||
unsigned int fsclk_hi;
|
||||
|
||||
fsclk_hi = ratio / 2;
|
||||
bclk_sel = clk_id;
|
||||
fsclk_sel = clk_id;
|
||||
bclk_sel = id;
|
||||
fsclk_sel = id;
|
||||
|
||||
/*sclk, lrclk*/
|
||||
offset = EE_AUDIO_MST_B_SCLK_CTRL0 - EE_AUDIO_MST_A_SCLK_CTRL0;
|
||||
reg = EE_AUDIO_MST_A_SCLK_CTRL0 + offset * clk_id;
|
||||
reg = EE_AUDIO_MST_A_SCLK_CTRL0 + offset * id;
|
||||
audiobus_update_bits(reg,
|
||||
0x3 << 30 | 0x3ff << 20 | 0x3ff<<10 | 0x3ff,
|
||||
(enable ? 0x3 : 0x0) << 30
|
||||
| sclk_div << 20 | fsclk_hi << 10
|
||||
| ratio);
|
||||
|
||||
|
||||
tdmin_src = datatlb_src - 3;
|
||||
tdmin_src = id;
|
||||
} else
|
||||
tdmin_src = datatlb_src;
|
||||
tdmin_src = lb_src;
|
||||
|
||||
audiobus_update_bits(
|
||||
EE_AUDIO_CLK_TDMIN_LB_CTRL,
|
||||
@@ -72,11 +77,11 @@ void tdminlb_set_format(int i2s_fmt)
|
||||
{
|
||||
audiobus_update_bits(EE_AUDIO_TDMIN_LB_CTRL,
|
||||
0x1 << 30,
|
||||
i2s_fmt << 30 /* 0:tdm mode; 1: i2s mode; */
|
||||
!!i2s_fmt << 30 /* 0:tdm mode; 1: i2s mode; */
|
||||
);
|
||||
}
|
||||
|
||||
void tdminlb_set_ctrl(int src)
|
||||
void tdminlb_set_ctrl(enum datalb_src src)
|
||||
{
|
||||
audiobus_update_bits(
|
||||
EE_AUDIO_TDMIN_LB_CTRL,
|
||||
@@ -101,14 +106,13 @@ static void tdminlb_set_lane_mask(int lane, int mask)
|
||||
audiobus_write(EE_AUDIO_TDMIN_LB_MASK0 + lane, mask);
|
||||
}
|
||||
|
||||
void tdminlb_set_lanemask_and_chswap(int swap, int lane_mask)
|
||||
void tdminlb_set_lanemask_and_chswap(int swap, int lane_mask, unsigned int mask)
|
||||
{
|
||||
unsigned int mask;
|
||||
unsigned int i;
|
||||
|
||||
pr_debug("tdmin_lb lane swap:0x%x mask:0x%x\n", swap, lane_mask);
|
||||
|
||||
mask = 0x3; /* i2s format */
|
||||
pr_debug
|
||||
("%s() lane swap:0x%x lane mask:0x%x, chmask:%#x\n",
|
||||
__func__, swap, lane_mask, mask);
|
||||
|
||||
/* channel swap */
|
||||
audiobus_write(EE_AUDIO_TDMIN_LB_SWAP0, swap);
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#define __AML_LOOPBACK_HW_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include "loopback.h"
|
||||
|
||||
struct data_cfg {
|
||||
/*
|
||||
@@ -46,20 +47,20 @@ struct data_cfg {
|
||||
bool ch_ctrl_switch;
|
||||
};
|
||||
|
||||
extern void tdminlb_set_clk(int datatlb_src,
|
||||
int sclk_div, int ratio, bool enable);
|
||||
void tdminlb_set_clk(enum datalb_src lb_src,
|
||||
int sclk_div, int ratio, bool enable);
|
||||
|
||||
extern void tdminlb_set_format(int i2s_fmt);
|
||||
|
||||
extern void tdminlb_set_ctrl(int src);
|
||||
void tdminlb_set_ctrl(enum datalb_src src);
|
||||
|
||||
extern void tdminlb_enable(int tdm_index, int in_enable);
|
||||
|
||||
extern void tdminlb_fifo_enable(int is_enable);
|
||||
|
||||
extern void tdminlb_set_format(int i2s_fmt);
|
||||
extern void tdminlb_set_lanemask_and_chswap(int swap, int lane_mask);
|
||||
|
||||
void tdminlb_set_lanemask_and_chswap
|
||||
(int swap, int lane_mask, unsigned int mask);
|
||||
|
||||
extern void tdminlb_set_src(int src);
|
||||
extern void lb_set_datain_src(int id, int src);
|
||||
|
||||
@@ -880,6 +880,9 @@ enum clk_sel {
|
||||
#define AED_TOP_CTL 0x83
|
||||
#define AED_TOP_REQ_CTL 0x84
|
||||
|
||||
#define AED_TOP_CTL0 0x83
|
||||
#define AED_TOP_CTL1 0x84
|
||||
#define AED_TOP_CTL2 0x85
|
||||
|
||||
/*
|
||||
* VAD, Voice activity detection
|
||||
|
||||
@@ -34,6 +34,11 @@ static const char *const audioclk_parent_names[] = {
|
||||
"i_slv_sclk_d", "i_slv_sclk_e", "i_slv_sclk_f", "i_slv_sclk_g",
|
||||
"i_slv_sclk_h", "i_slv_sclk_i", "i_slv_sclk_j"};
|
||||
|
||||
static const char *const mclk_pad_parent_names[] = {
|
||||
"mclk_a", "mclk_b", "mclk_c",
|
||||
"mclk_d", "mclk_e", "mclk_f"
|
||||
};
|
||||
|
||||
CLOCK_GATE(audio_ddr_arb, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 0);
|
||||
CLOCK_GATE(audio_pdm, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 1);
|
||||
CLOCK_GATE(audio_tdmina, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 2);
|
||||
@@ -194,6 +199,15 @@ CLOCK_COM_GATE(mclk_d, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_D_CTRL(1)), 31);
|
||||
CLOCK_COM_MUX(mclk_e, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_E_CTRL(1)), 0x7, 24);
|
||||
CLOCK_COM_DIV(mclk_e, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_E_CTRL(1)), 0, 16);
|
||||
CLOCK_COM_GATE(mclk_e, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_E_CTRL(1)), 31);
|
||||
/* mclk_pad0 */
|
||||
CLOCK_COM_MUX(mclk_pad0, AUD_ADDR_OFFSET(EE_AUDIO_MST_PAD_CTRL0(1)), 0x7, 8);
|
||||
CLOCK_COM_DIV(mclk_pad0, AUD_ADDR_OFFSET(EE_AUDIO_MST_PAD_CTRL0(1)), 0, 8);
|
||||
CLOCK_COM_GATE(mclk_pad0, AUD_ADDR_OFFSET(EE_AUDIO_MST_PAD_CTRL0(1)), 15);
|
||||
/* mclk_pad1 */
|
||||
CLOCK_COM_MUX(mclk_pad1, AUD_ADDR_OFFSET(EE_AUDIO_MST_PAD_CTRL0(1)), 0x7, 24);
|
||||
CLOCK_COM_DIV(mclk_pad1, AUD_ADDR_OFFSET(EE_AUDIO_MST_PAD_CTRL0(1)), 16, 8);
|
||||
CLOCK_COM_GATE(mclk_pad1, AUD_ADDR_OFFSET(EE_AUDIO_MST_PAD_CTRL0(1)), 31);
|
||||
|
||||
/* mclk_f */
|
||||
CLOCK_COM_MUX(mclk_f, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_F_CTRL(1)), 0x7, 24);
|
||||
CLOCK_COM_DIV(mclk_f, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_F_CTRL(1)), 0, 16);
|
||||
@@ -369,6 +383,16 @@ static int sm1_clks_init(struct clk **clks, void __iomem *iobase)
|
||||
clks[CLKID_EARCRX_DMAC] = REGISTER_CLK_COM(earcrx_dmac);
|
||||
WARN_ON(IS_ERR_OR_NULL(clks[CLKID_EARCRX_DMAC]));
|
||||
|
||||
IOMAP_COM_CLK(mclk_pad0, iobase);
|
||||
clks[CLKID_AUDIO_MCLK_PAD0] =
|
||||
REGISTER_CLK_COM_PARENTS(mclk_pad0, mclk_pad);
|
||||
WARN_ON(IS_ERR_OR_NULL(clks[CLKID_AUDIO_MCLK_PAD0]));
|
||||
|
||||
IOMAP_COM_CLK(mclk_pad1, iobase);
|
||||
clks[CLKID_AUDIO_MCLK_PAD1] =
|
||||
REGISTER_CLK_COM_PARENTS(mclk_pad1, mclk_pad);
|
||||
WARN_ON(IS_ERR_OR_NULL(clks[CLKID_AUDIO_MCLK_PAD1]));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -273,6 +273,62 @@ static int aml_audio_set_spdif_mute(struct snd_kcontrol *kcontrol,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aml_spdif_platform_suspend(
|
||||
struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
struct aml_spdif *p_spdif = dev_get_drvdata(&pdev->dev);
|
||||
struct pinctrl_state *pstate = NULL;
|
||||
int stream = SNDRV_PCM_STREAM_PLAYBACK;
|
||||
|
||||
if (!IS_ERR_OR_NULL(p_spdif->pin_ctl)) {
|
||||
pstate = pinctrl_lookup_state
|
||||
(p_spdif->pin_ctl, "spdif_pins_mute");
|
||||
if (!IS_ERR_OR_NULL(pstate))
|
||||
pinctrl_select_state(p_spdif->pin_ctl, pstate);
|
||||
}
|
||||
aml_spdif_enable(p_spdif->actrl,
|
||||
stream, p_spdif->id, false);
|
||||
pr_info("%s is mute\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aml_spdif_platform_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct aml_spdif *p_spdif = dev_get_drvdata(&pdev->dev);
|
||||
struct pinctrl_state *state = NULL;
|
||||
int stream = SNDRV_PCM_STREAM_PLAYBACK;
|
||||
|
||||
if (!IS_ERR_OR_NULL(p_spdif->pin_ctl)) {
|
||||
state = pinctrl_lookup_state
|
||||
(p_spdif->pin_ctl, "spdif_pins");
|
||||
if (!IS_ERR_OR_NULL(state))
|
||||
pinctrl_select_state(p_spdif->pin_ctl, state);
|
||||
}
|
||||
aml_spdif_enable(p_spdif->actrl,
|
||||
stream, p_spdif->id, true);
|
||||
pr_info("%s is unmute\n", __func__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void aml_spdif_platform_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct aml_spdif *p_spdif = dev_get_drvdata(&pdev->dev);
|
||||
struct pinctrl_state *pstate = NULL;
|
||||
int stream = SNDRV_PCM_STREAM_PLAYBACK;
|
||||
|
||||
if (!IS_ERR_OR_NULL(p_spdif->pin_ctl)) {
|
||||
pstate = pinctrl_lookup_state
|
||||
(p_spdif->pin_ctl, "spdif_pins_mute");
|
||||
if (!IS_ERR_OR_NULL(pstate))
|
||||
pinctrl_select_state(p_spdif->pin_ctl, pstate);
|
||||
}
|
||||
aml_spdif_enable(p_spdif->actrl,
|
||||
stream, p_spdif->id, false);
|
||||
pr_info("%s is mute\n", __func__);
|
||||
|
||||
}
|
||||
|
||||
static int aml_audio_get_spdif_mute(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
@@ -658,7 +714,7 @@ static void spdifin_status_event(struct aml_spdif *p_spdif)
|
||||
if (p_spdif->chipinfo
|
||||
&& p_spdif->chipinfo->pcpd_separated) {
|
||||
if (intrpt_status & 0x8) {
|
||||
pr_info("Pc changed, try to read spdifin audio type\n");
|
||||
pr_debug("Pc changed, try to read spdifin audio type\n");
|
||||
|
||||
extcon_set_state(p_spdif->edev,
|
||||
EXTCON_SPDIFIN_AUDIOTYPE, 1);
|
||||
@@ -672,7 +728,7 @@ static void spdifin_status_event(struct aml_spdif *p_spdif)
|
||||
#endif
|
||||
}
|
||||
if (intrpt_status & 0x10)
|
||||
pr_info("Pd changed\n");
|
||||
pr_debug("Pd changed\n");
|
||||
} else {
|
||||
if (intrpt_status & 0x8)
|
||||
pr_debug("CH status changed\n");
|
||||
@@ -1586,6 +1642,9 @@ struct platform_driver aml_spdif_driver = {
|
||||
.of_match_table = aml_spdif_device_id,
|
||||
},
|
||||
.probe = aml_spdif_platform_probe,
|
||||
.suspend = aml_spdif_platform_suspend,
|
||||
.resume = aml_spdif_platform_resume,
|
||||
.shutdown = aml_spdif_platform_shutdown,
|
||||
};
|
||||
module_platform_driver(aml_spdif_driver);
|
||||
|
||||
|
||||
@@ -83,6 +83,8 @@ struct aml_tdm {
|
||||
struct clk *clk;
|
||||
struct clk *clk_gate;
|
||||
struct clk *mclk;
|
||||
/* mclk mux out to pad */
|
||||
struct clk *mclk2pad;
|
||||
struct clk *samesrc_srcpll;
|
||||
struct clk *samesrc_clk;
|
||||
bool contns_clk;
|
||||
@@ -723,12 +725,11 @@ static int aml_tdm_set_lanes(struct aml_tdm *p_tdm,
|
||||
#if 1
|
||||
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
/* set lanes mask acordingly */
|
||||
if (p_tdm->chipinfo
|
||||
&& p_tdm->chipinfo->oe_fn
|
||||
&& p_tdm->setting.lane_oe_mask_out)
|
||||
lane_mask = setting->lane_mask_out;
|
||||
/* compatible using oe masks */
|
||||
if (!lane_mask && setting->lane_oe_mask_out)
|
||||
lane_mask = setting->lane_oe_mask_out;
|
||||
else
|
||||
lane_mask = setting->lane_mask_out;
|
||||
|
||||
for (i = 0; i < p_tdm->lane_cnt; i++) {
|
||||
if (((1 << i) & lane_mask) && lanes) {
|
||||
aml_tdm_set_channel_mask(p_tdm->actrl,
|
||||
@@ -844,12 +845,17 @@ static int aml_tdm_set_clk_pad(struct aml_tdm *p_tdm)
|
||||
if (p_tdm->chipinfo && (!p_tdm->chipinfo->mclkpad_no_offset))
|
||||
mpad_offset = 1;
|
||||
|
||||
aml_tdm_clk_pad_select(p_tdm->actrl,
|
||||
p_tdm->mclk_pad,
|
||||
mpad_offset,
|
||||
p_tdm->id,
|
||||
p_tdm->id,
|
||||
p_tdm->clk_sel);
|
||||
if (p_tdm->mclk_pad >= 0) {
|
||||
aml_tdm_mclk_pad_select(p_tdm->actrl,
|
||||
p_tdm->mclk_pad,
|
||||
mpad_offset,
|
||||
p_tdm->clk_sel);
|
||||
}
|
||||
|
||||
aml_tdm_sclk_pad_select(p_tdm->actrl,
|
||||
mpad_offset,
|
||||
p_tdm->id,
|
||||
p_tdm->id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1131,21 +1137,17 @@ static int aml_dai_set_tdm_slot(struct snd_soc_dai *cpu_dai,
|
||||
unsigned int lanes_oe_out_cnt = 0, lanes_oe_in_cnt = 0;
|
||||
unsigned int force_oe = 0, oe_val = 0;
|
||||
unsigned int lanes_lb_cnt = 0;
|
||||
int out_lanes, in_lanes;
|
||||
int out_lanes = 0, in_lanes = 0;
|
||||
int in_src = -1;
|
||||
|
||||
lanes_out_cnt = pop_count(p_tdm->setting.lane_mask_out);
|
||||
lanes_in_cnt = pop_count(p_tdm->setting.lane_mask_in);
|
||||
lanes_oe_out_cnt = pop_count(p_tdm->setting.lane_oe_mask_out);
|
||||
lanes_oe_in_cnt = pop_count(p_tdm->setting.lane_oe_mask_in);
|
||||
lanes_lb_cnt = pop_count(p_tdm->setting.lane_lb_mask_in);
|
||||
|
||||
pr_debug("%s(), txmask(%#x), rxmask(%#x)\n",
|
||||
__func__, tx_mask, rx_mask);
|
||||
pr_debug("\tlanes_out_cnt(%d), lanes_in_cnt(%d)\n",
|
||||
lanes_out_cnt, lanes_in_cnt);
|
||||
pr_debug("\tlanes_oe_out_cnt(%d), lanes_oe_in_cnt(%d)\n",
|
||||
lanes_oe_out_cnt, lanes_oe_in_cnt);
|
||||
pr_debug("\tlanes_lb_cnt(%d)\n",
|
||||
lanes_lb_cnt);
|
||||
pr_debug("\tslots(%d), slot_width(%d)\n",
|
||||
@@ -1179,9 +1181,30 @@ static int aml_dai_set_tdm_slot(struct snd_soc_dai *cpu_dai,
|
||||
p_tdm->setting.lane_lb_mask_in
|
||||
& p_tdm->setting.lane_oe_mask_in);
|
||||
|
||||
lanes_oe_out_cnt = pop_count(p_tdm->setting.lane_oe_mask_out);
|
||||
lanes_oe_in_cnt = pop_count(p_tdm->setting.lane_oe_mask_in);
|
||||
pr_debug
|
||||
("\tlanes_oe_out_cnt(%d), lanes_oe_in_cnt(%d)\n",
|
||||
lanes_oe_out_cnt, lanes_oe_in_cnt);
|
||||
|
||||
if (lanes_oe_out_cnt) {
|
||||
force_oe = p_tdm->setting.lane_oe_mask_out;
|
||||
unsigned int oe_fn_version = p_tdm->chipinfo->oe_fn;
|
||||
|
||||
force_oe = (1 << p_tdm->chipinfo->lane_cnt) - 1;
|
||||
oe_val = p_tdm->setting.lane_oe_mask_out;
|
||||
if (oe_fn_version == OE_FUNCTION_V1) {
|
||||
aml_tdm_set_oe_v1
|
||||
(p_tdm->actrl, p_tdm->id,
|
||||
force_oe, oe_val);
|
||||
} else if (oe_fn_version == OE_FUNCTION_V2) {
|
||||
aml_tdm_set_oe_v2
|
||||
(p_tdm->actrl, p_tdm->id,
|
||||
force_oe, oe_val);
|
||||
} else {
|
||||
pr_err
|
||||
("%s(), oe version(%d) not support\n",
|
||||
__func__, oe_fn_version);
|
||||
}
|
||||
}
|
||||
|
||||
if (lanes_lb_cnt)
|
||||
@@ -1201,7 +1224,7 @@ static int aml_dai_set_tdm_slot(struct snd_soc_dai *cpu_dai,
|
||||
}
|
||||
}
|
||||
|
||||
out_lanes = lanes_out_cnt + lanes_oe_out_cnt;
|
||||
out_lanes = lanes_out_cnt;
|
||||
in_lanes = lanes_in_cnt + lanes_oe_in_cnt + lanes_lb_cnt;
|
||||
|
||||
if (p_tdm->chipinfo
|
||||
@@ -1216,8 +1239,7 @@ static int aml_dai_set_tdm_slot(struct snd_soc_dai *cpu_dai,
|
||||
|
||||
if (out_lanes > 0 && out_lanes <= LANE_MAX3)
|
||||
aml_tdm_set_slot_out(p_tdm->actrl,
|
||||
p_tdm->id, slots, slot_width,
|
||||
force_oe, oe_val);
|
||||
p_tdm->id, slots, slot_width);
|
||||
|
||||
/* constrains hw channels_max by DTS configs */
|
||||
drv->playback.channels_max = slots * out_lanes;
|
||||
@@ -1564,7 +1586,7 @@ static int aml_tdm_platform_probe(struct platform_device *pdev)
|
||||
ret = of_parse_tdm_lane_slot_out(node,
|
||||
&p_tdm->setting.lane_mask_out);
|
||||
if (ret < 0)
|
||||
p_tdm->setting.lane_mask_out = 0x0;
|
||||
p_tdm->setting.lane_mask_out = 0x1;
|
||||
|
||||
/* get tdm lanes oe info. if not, set to default 0 */
|
||||
ret = of_parse_tdm_lane_oe_slot_in(node,
|
||||
@@ -1606,6 +1628,28 @@ static int aml_tdm_platform_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* clk tree style after SM1, instead of legacy prop */
|
||||
p_tdm->mclk2pad = devm_clk_get(&pdev->dev, "mclk_pad");
|
||||
if (!IS_ERR(p_tdm->mclk2pad)) {
|
||||
ret = clk_set_parent(p_tdm->mclk2pad, p_tdm->mclk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Can't set tdm mclk_pad parent\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
clk_prepare_enable(p_tdm->mclk2pad);
|
||||
p_tdm->mclk_pad = -1;
|
||||
} else {
|
||||
/* mclk pad ctrl */
|
||||
ret = of_property_read_u32(node, "mclk_pad",
|
||||
&p_tdm->mclk_pad);
|
||||
if (ret < 0) {
|
||||
/* No mclk in defalut if chip needs mclk pad mux. */
|
||||
p_tdm->mclk_pad = -1;
|
||||
dev_warn_once(&pdev->dev,
|
||||
"neither mclk_pad nor mclk2pad set\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* complete mclk for tdm */
|
||||
if (get_meson_cpu_version(MESON_CPU_VERSION_LVL_MINOR) == 0xa)
|
||||
meson_clk_measure((1<<16) | 0x67);
|
||||
@@ -1625,12 +1669,6 @@ static int aml_tdm_platform_probe(struct platform_device *pdev)
|
||||
/*set default clk for output*/
|
||||
aml_set_default_tdm_clk(p_tdm);
|
||||
|
||||
/* mclk pad ctrl */
|
||||
ret = of_property_read_u32(node, "mclk_pad",
|
||||
&p_tdm->mclk_pad);
|
||||
if (ret < 0)
|
||||
p_tdm->mclk_pad = -1; /* not use mclk in defalut. */
|
||||
|
||||
p_tdm->dev = dev;
|
||||
/* For debug to disable share buffer */
|
||||
p_tdm->en_share = 1;
|
||||
|
||||
@@ -454,34 +454,64 @@ void aml_update_tdmin_rev_ws(struct aml_audio_controller *actrl,
|
||||
|
||||
off_set = EE_AUDIO_TDMIN_B_CTRL - EE_AUDIO_TDMIN_A_CTRL;
|
||||
reg_in = EE_AUDIO_TDMIN_A_CTRL + off_set * idx;
|
||||
aml_audiobus_update_bits(actrl, reg_in,
|
||||
aml_audiobus_update_bits
|
||||
(actrl, reg_in,
|
||||
0x1 << 25, is_rev << 25);
|
||||
}
|
||||
|
||||
void aml_tdm_set_slot_out(
|
||||
void aml_tdm_set_oe_v1(
|
||||
struct aml_audio_controller *actrl,
|
||||
int index, int slots, int slot_width,
|
||||
int force_oe, int oe_val)
|
||||
int index, int force_oe, int oe_val)
|
||||
{
|
||||
unsigned int reg, offset;
|
||||
|
||||
offset = EE_AUDIO_TDMOUT_B_CTRL0 - EE_AUDIO_TDMOUT_A_CTRL0;
|
||||
reg = EE_AUDIO_TDMOUT_A_CTRL0 + offset * index;
|
||||
aml_audiobus_update_bits(actrl, reg,
|
||||
0x3ff, ((slots - 1) << 5) | (slot_width - 1));
|
||||
|
||||
if (force_oe) {
|
||||
offset = EE_AUDIO_TDMOUT_B_CTRL2 - EE_AUDIO_TDMOUT_A_CTRL2;
|
||||
reg = EE_AUDIO_TDMOUT_A_CTRL2 + offset * index;
|
||||
|
||||
aml_audiobus_update_bits(actrl, reg, 0xf << 24, force_oe << 24);
|
||||
|
||||
/* force oe val, in or out */
|
||||
reg = EE_AUDIO_TDMOUT_A_CTRL1 + offset * index;
|
||||
aml_audiobus_update_bits(actrl, reg, 0xf, oe_val);
|
||||
}
|
||||
}
|
||||
|
||||
void aml_tdm_set_oe_v2(
|
||||
struct aml_audio_controller *actrl,
|
||||
int index, int force_oe, int oe_val)
|
||||
{
|
||||
unsigned int reg, offset;
|
||||
|
||||
if (force_oe) {
|
||||
offset = EE_AUDIO_TDMOUT_B_CTRL2 - EE_AUDIO_TDMOUT_A_CTRL2;
|
||||
reg = EE_AUDIO_TDMOUT_A_CTRL2 + offset * index;
|
||||
|
||||
aml_audiobus_update_bits(actrl, reg, 0xff << 8, force_oe << 8);
|
||||
|
||||
/* force oe val, in or out */
|
||||
if (oe_val) {
|
||||
reg = EE_AUDIO_TDMOUT_A_CTRL1 + offset * index;
|
||||
aml_audiobus_update_bits(actrl, reg,
|
||||
0xf << 0, oe_val << 0);
|
||||
aml_audiobus_update_bits
|
||||
(actrl, reg, 0xff << 16, oe_val << 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void aml_tdm_set_slot_out(
|
||||
struct aml_audio_controller *actrl,
|
||||
int index, int slots, int slot_width)
|
||||
{
|
||||
unsigned int reg, offset;
|
||||
|
||||
offset = EE_AUDIO_TDMOUT_B_CTRL0 - EE_AUDIO_TDMOUT_A_CTRL0;
|
||||
reg = EE_AUDIO_TDMOUT_A_CTRL0 + offset * index;
|
||||
aml_audiobus_update_bits
|
||||
(actrl, reg, 0x3ff, ((slots - 1) << 5) | (slot_width - 1));
|
||||
}
|
||||
|
||||
void aml_tdm_set_slot_in(
|
||||
struct aml_audio_controller *actrl,
|
||||
int index, int in_src, int slot_width)
|
||||
@@ -675,39 +705,40 @@ void aml_tdmout_enable_gain(int tdmout_id, int en)
|
||||
audiobus_update_bits(reg, 0x1 << 26, !!en << 26);
|
||||
}
|
||||
|
||||
void aml_tdm_clk_pad_select(
|
||||
struct aml_audio_controller *actrl,
|
||||
int mpad, int mpad_offset, int mclk_sel,
|
||||
int tdm_index, int clk_sel)
|
||||
void aml_tdm_mclk_pad_select(struct aml_audio_controller *actrl,
|
||||
int mpad, int mpad_offset, int mclk_sel)
|
||||
{
|
||||
unsigned int reg, mask_offset, val_offset;
|
||||
|
||||
if (mpad >= 0) {
|
||||
switch (mpad) {
|
||||
case 0:
|
||||
mask_offset = 0x7 << 0;
|
||||
val_offset = mclk_sel << 0;
|
||||
break;
|
||||
case 1:
|
||||
mask_offset = 0x7 << 4;
|
||||
val_offset = mclk_sel << 4;
|
||||
break;
|
||||
default:
|
||||
mask_offset = 0;
|
||||
val_offset = 0;
|
||||
pr_info("unknown tdm mpad:%d\n", mpad);
|
||||
break;
|
||||
}
|
||||
switch (mpad) {
|
||||
case 0:
|
||||
mask_offset = 0x7 << 0;
|
||||
val_offset = mclk_sel << 0;
|
||||
break;
|
||||
case 1:
|
||||
mask_offset = 0x7 << 4;
|
||||
val_offset = mclk_sel << 4;
|
||||
break;
|
||||
default:
|
||||
mask_offset = 0x7 << 4;
|
||||
val_offset = 0;
|
||||
pr_info("unknown tdm mpad:%d\n", mpad);
|
||||
break;
|
||||
}
|
||||
|
||||
reg = EE_AUDIO_MST_PAD_CTRL0(mpad_offset);
|
||||
if (actrl)
|
||||
aml_audiobus_update_bits(actrl, reg,
|
||||
mask_offset, val_offset);
|
||||
else
|
||||
audiobus_update_bits(reg,
|
||||
mask_offset, val_offset);
|
||||
} else
|
||||
pr_warn("mclk is not configured\n");
|
||||
reg = EE_AUDIO_MST_PAD_CTRL0(mpad_offset);
|
||||
if (actrl)
|
||||
aml_audiobus_update_bits(actrl, reg,
|
||||
mask_offset, val_offset);
|
||||
else
|
||||
audiobus_update_bits(reg,
|
||||
mask_offset, val_offset);
|
||||
}
|
||||
|
||||
void aml_tdm_sclk_pad_select(struct aml_audio_controller *actrl,
|
||||
int mpad_offset, int tdm_index, int clk_sel)
|
||||
{
|
||||
unsigned int reg, mask_offset, val_offset;
|
||||
|
||||
reg = EE_AUDIO_MST_PAD_CTRL1(mpad_offset);
|
||||
switch (tdm_index) {
|
||||
|
||||
@@ -107,8 +107,7 @@ extern void aml_update_tdmin_rev_ws(struct aml_audio_controller *actrl,
|
||||
|
||||
extern void aml_tdm_set_slot_out(
|
||||
struct aml_audio_controller *actrl,
|
||||
int index, int slots, int slot_width,
|
||||
int force_oe, int oe_val);
|
||||
int index, int slots, int slot_width);
|
||||
|
||||
extern void aml_tdm_set_slot_in(
|
||||
struct aml_audio_controller *actrl,
|
||||
@@ -151,6 +150,10 @@ extern void aml_tdm_clk_pad_select(
|
||||
struct aml_audio_controller *actrl,
|
||||
int mpad, int mpad_offset, int mclk_sel,
|
||||
int tdm_index, int clk_sel);
|
||||
void aml_tdm_mclk_pad_select(struct aml_audio_controller *actrl,
|
||||
int mpad, int mpad_offset, int mclk_sel);
|
||||
void aml_tdm_sclk_pad_select(struct aml_audio_controller *actrl,
|
||||
int mpad_offset, int tdm_index, int clk_sel);
|
||||
|
||||
extern void i2s_to_hdmitx_ctrl(int tdm_index);
|
||||
extern void i2s_to_hdmitx_disable(void);
|
||||
@@ -164,4 +167,12 @@ void aml_tdm_mute_capture(
|
||||
int tdm_index,
|
||||
bool mute,
|
||||
int lane_cnt);
|
||||
void aml_tdm_out_reset(unsigned int tdm_id, int offset);
|
||||
void aml_tdm_set_oe_v1(
|
||||
struct aml_audio_controller *actrl,
|
||||
int index, int force_oe, int oe_val);
|
||||
void aml_tdm_set_oe_v2(
|
||||
struct aml_audio_controller *actrl,
|
||||
int index, int force_oe, int oe_val);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -15,6 +15,15 @@
|
||||
*
|
||||
*/
|
||||
|
||||
/* For OE function V1:
|
||||
* OE is set by EE_AUDIO_TDMOUT_A_CTRL0 & EE_AUDIO_TDMOUT_A_CTRL1
|
||||
*/
|
||||
#define OE_FUNCTION_V1 1
|
||||
/* For OE function V2:
|
||||
* OE is set by EE_AUDIO_TDMOUT_A_CTRL2
|
||||
*/
|
||||
#define OE_FUNCTION_V2 2
|
||||
|
||||
struct tdm_chipinfo {
|
||||
/* device id */
|
||||
unsigned int id;
|
||||
@@ -26,7 +35,7 @@ struct tdm_chipinfo {
|
||||
bool sclk_ws_inv;
|
||||
|
||||
/* output en (oe) for pinmux */
|
||||
bool oe_fn;
|
||||
unsigned int oe_fn;
|
||||
|
||||
/* clk pad */
|
||||
bool no_mclkpad_ctrl;
|
||||
@@ -76,7 +85,7 @@ struct tdm_chipinfo g12a_tdma_chipinfo = {
|
||||
struct tdm_chipinfo g12a_tdmb_chipinfo = {
|
||||
.id = TDM_B,
|
||||
.sclk_ws_inv = true,
|
||||
.oe_fn = true,
|
||||
.oe_fn = OE_FUNCTION_V1,
|
||||
.same_src_fn = true,
|
||||
.mclkpad_no_offset = true,
|
||||
};
|
||||
@@ -84,7 +93,7 @@ struct tdm_chipinfo g12a_tdmb_chipinfo = {
|
||||
struct tdm_chipinfo g12a_tdmc_chipinfo = {
|
||||
.id = TDM_C,
|
||||
.sclk_ws_inv = true,
|
||||
.oe_fn = true,
|
||||
.oe_fn = OE_FUNCTION_V1,
|
||||
.same_src_fn = true,
|
||||
.mclkpad_no_offset = true,
|
||||
};
|
||||
@@ -92,7 +101,7 @@ struct tdm_chipinfo g12a_tdmc_chipinfo = {
|
||||
struct tdm_chipinfo g12a_tdminlb_chipinfo = {
|
||||
.id = TDM_LB,
|
||||
.sclk_ws_inv = true,
|
||||
.oe_fn = true,
|
||||
.oe_fn = OE_FUNCTION_V1,
|
||||
.same_src_fn = true,
|
||||
.mclkpad_no_offset = true,
|
||||
};
|
||||
@@ -100,7 +109,7 @@ struct tdm_chipinfo g12a_tdminlb_chipinfo = {
|
||||
struct tdm_chipinfo tl1_tdma_chipinfo = {
|
||||
.id = TDM_A,
|
||||
.sclk_ws_inv = true,
|
||||
.oe_fn = true,
|
||||
.oe_fn = OE_FUNCTION_V1,
|
||||
.same_src_fn = true,
|
||||
.adc_fn = true,
|
||||
};
|
||||
@@ -108,7 +117,7 @@ struct tdm_chipinfo tl1_tdma_chipinfo = {
|
||||
struct tdm_chipinfo tl1_tdmb_chipinfo = {
|
||||
.id = TDM_B,
|
||||
.sclk_ws_inv = true,
|
||||
.oe_fn = true,
|
||||
.oe_fn = OE_FUNCTION_V1,
|
||||
.same_src_fn = true,
|
||||
.adc_fn = true,
|
||||
};
|
||||
@@ -116,7 +125,7 @@ struct tdm_chipinfo tl1_tdmb_chipinfo = {
|
||||
struct tdm_chipinfo tl1_tdmc_chipinfo = {
|
||||
.id = TDM_C,
|
||||
.sclk_ws_inv = true,
|
||||
.oe_fn = true,
|
||||
.oe_fn = OE_FUNCTION_V1,
|
||||
.same_src_fn = true,
|
||||
.adc_fn = true,
|
||||
};
|
||||
@@ -124,7 +133,7 @@ struct tdm_chipinfo tl1_tdmc_chipinfo = {
|
||||
struct tdm_chipinfo tl1_tdminlb_chipinfo = {
|
||||
.id = TDM_LB,
|
||||
.sclk_ws_inv = true,
|
||||
.oe_fn = true,
|
||||
.oe_fn = OE_FUNCTION_V1,
|
||||
.same_src_fn = true,
|
||||
.adc_fn = true,
|
||||
};
|
||||
@@ -132,7 +141,7 @@ struct tdm_chipinfo tl1_tdminlb_chipinfo = {
|
||||
struct tdm_chipinfo sm1_tdma_chipinfo = {
|
||||
.id = TDM_A,
|
||||
.sclk_ws_inv = true,
|
||||
.oe_fn = true,
|
||||
.oe_fn = OE_FUNCTION_V2,
|
||||
.same_src_fn = true,
|
||||
.lane_cnt = LANE_MAX0,
|
||||
};
|
||||
@@ -140,7 +149,7 @@ struct tdm_chipinfo sm1_tdma_chipinfo = {
|
||||
struct tdm_chipinfo sm1_tdmb_chipinfo = {
|
||||
.id = TDM_B,
|
||||
.sclk_ws_inv = true,
|
||||
.oe_fn = true,
|
||||
.oe_fn = OE_FUNCTION_V2,
|
||||
.same_src_fn = true,
|
||||
.lane_cnt = LANE_MAX3,
|
||||
};
|
||||
@@ -148,7 +157,7 @@ struct tdm_chipinfo sm1_tdmb_chipinfo = {
|
||||
struct tdm_chipinfo sm1_tdmc_chipinfo = {
|
||||
.id = TDM_C,
|
||||
.sclk_ws_inv = true,
|
||||
.oe_fn = true,
|
||||
.oe_fn = OE_FUNCTION_V2,
|
||||
.same_src_fn = true,
|
||||
.lane_cnt = LANE_MAX1,
|
||||
};
|
||||
@@ -156,7 +165,7 @@ struct tdm_chipinfo sm1_tdmc_chipinfo = {
|
||||
struct tdm_chipinfo sm1_tdminlb_chipinfo = {
|
||||
.id = TDM_LB,
|
||||
.sclk_ws_inv = true,
|
||||
.oe_fn = true,
|
||||
.oe_fn = OE_FUNCTION_V2,
|
||||
.same_src_fn = true,
|
||||
.lane_cnt = LANE_MAX3,
|
||||
};
|
||||
@@ -164,7 +173,7 @@ struct tdm_chipinfo sm1_tdminlb_chipinfo = {
|
||||
struct tdm_chipinfo tm2_tdma_chipinfo = {
|
||||
.id = TDM_A,
|
||||
.sclk_ws_inv = true,
|
||||
.oe_fn = true,
|
||||
.oe_fn = OE_FUNCTION_V2,
|
||||
.same_src_fn = true,
|
||||
.adc_fn = true,
|
||||
.lane_cnt = LANE_MAX3,
|
||||
@@ -173,7 +182,7 @@ struct tdm_chipinfo tm2_tdma_chipinfo = {
|
||||
struct tdm_chipinfo tm2_tdmb_chipinfo = {
|
||||
.id = TDM_B,
|
||||
.sclk_ws_inv = true,
|
||||
.oe_fn = true,
|
||||
.oe_fn = OE_FUNCTION_V2,
|
||||
.same_src_fn = true,
|
||||
.adc_fn = true,
|
||||
.lane_cnt = LANE_MAX1,
|
||||
@@ -182,7 +191,7 @@ struct tdm_chipinfo tm2_tdmb_chipinfo = {
|
||||
struct tdm_chipinfo tm2_tdmc_chipinfo = {
|
||||
.id = TDM_C,
|
||||
.sclk_ws_inv = true,
|
||||
.oe_fn = true,
|
||||
.oe_fn = OE_FUNCTION_V2,
|
||||
.same_src_fn = true,
|
||||
.adc_fn = true,
|
||||
.lane_cnt = LANE_MAX1,
|
||||
@@ -191,7 +200,7 @@ struct tdm_chipinfo tm2_tdmc_chipinfo = {
|
||||
struct tdm_chipinfo tm2_tdminlb_chipinfo = {
|
||||
.id = TDM_LB,
|
||||
.sclk_ws_inv = true,
|
||||
.oe_fn = true,
|
||||
.oe_fn = OE_FUNCTION_V2,
|
||||
.same_src_fn = true,
|
||||
.lane_cnt = LANE_MAX3,
|
||||
};
|
||||
|
||||
@@ -34,6 +34,11 @@ static const char *const audioclk_parent_names[] = {
|
||||
"i_slv_sclk_d", "i_slv_sclk_e", "i_slv_sclk_f", "i_slv_sclk_g",
|
||||
"i_slv_sclk_h", "i_slv_sclk_i", "i_slv_sclk_j"};
|
||||
|
||||
static const char *const mclk_pad_parent_names[] = {
|
||||
"mclk_a", "mclk_b", "mclk_c",
|
||||
"mclk_d", "mclk_e", "mclk_f"
|
||||
};
|
||||
|
||||
CLOCK_GATE(audio_ddr_arb, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 0);
|
||||
CLOCK_GATE(audio_pdm, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 1);
|
||||
CLOCK_GATE(audio_tdmina, AUD_ADDR_OFFSET(EE_AUDIO_CLK_GATE_EN0), 2);
|
||||
@@ -214,6 +219,15 @@ CLOCK_COM_GATE(mclk_e, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_E_CTRL(1)), 31);
|
||||
CLOCK_COM_MUX(mclk_f, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_F_CTRL(1)), 0x7, 24);
|
||||
CLOCK_COM_DIV(mclk_f, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_F_CTRL(1)), 0, 16);
|
||||
CLOCK_COM_GATE(mclk_f, AUD_ADDR_OFFSET(EE_AUDIO_MCLK_F_CTRL(1)), 31);
|
||||
/* mclk_pad0 */
|
||||
CLOCK_COM_MUX(mclk_pad0, AUD_ADDR_OFFSET(EE_AUDIO_MST_PAD_CTRL0(1)), 0x7, 8);
|
||||
CLOCK_COM_DIV(mclk_pad0, AUD_ADDR_OFFSET(EE_AUDIO_MST_PAD_CTRL0(1)), 0, 8);
|
||||
CLOCK_COM_GATE(mclk_pad0, AUD_ADDR_OFFSET(EE_AUDIO_MST_PAD_CTRL0(1)), 15);
|
||||
/* mclk_pad1 */
|
||||
CLOCK_COM_MUX(mclk_pad1, AUD_ADDR_OFFSET(EE_AUDIO_MST_PAD_CTRL0(1)), 0x7, 24);
|
||||
CLOCK_COM_DIV(mclk_pad1, AUD_ADDR_OFFSET(EE_AUDIO_MST_PAD_CTRL0(1)), 16, 8);
|
||||
CLOCK_COM_GATE(mclk_pad1, AUD_ADDR_OFFSET(EE_AUDIO_MST_PAD_CTRL0(1)), 31);
|
||||
|
||||
/* spdifin */
|
||||
CLOCK_COM_MUX(spdifin, AUD_ADDR_OFFSET(EE_AUDIO_CLK_SPDIFIN_CTRL), 0x7, 24);
|
||||
CLOCK_COM_DIV(spdifin, AUD_ADDR_OFFSET(EE_AUDIO_CLK_SPDIFIN_CTRL), 0, 8);
|
||||
@@ -385,6 +399,16 @@ static int tm2_clks_init(struct clk **clks, void __iomem *iobase)
|
||||
clks[CLKID_EARCRX_DMAC] = REGISTER_CLK_COM(earcrx_dmac);
|
||||
WARN_ON(IS_ERR_OR_NULL(clks[CLKID_EARCRX_DMAC]));
|
||||
|
||||
IOMAP_COM_CLK(mclk_pad0, iobase);
|
||||
clks[CLKID_AUDIO_MCLK_PAD0] =
|
||||
REGISTER_CLK_COM_PARENTS(mclk_pad0, mclk_pad);
|
||||
WARN_ON(IS_ERR_OR_NULL(clks[CLKID_AUDIO_MCLK_PAD0]));
|
||||
|
||||
IOMAP_COM_CLK(mclk_pad1, iobase);
|
||||
clks[CLKID_AUDIO_MCLK_PAD1] =
|
||||
REGISTER_CLK_COM_PARENTS(mclk_pad1, mclk_pad);
|
||||
WARN_ON(IS_ERR_OR_NULL(clks[CLKID_AUDIO_MCLK_PAD1]));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
obj-y += notify.o \
|
||||
spdif_info.o \
|
||||
misc.o
|
||||
misc.o \
|
||||
iomapres.o
|
||||
|
||||
75
sound/soc/amlogic/common/iomapres.c
Normal file
75
sound/soc/amlogic/common/iomapres.c
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* sound/soc/amlogic/common/iomapres.c
|
||||
*
|
||||
* Copyright (C) 2019 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#include <linux/amlogic/media/sound/iomapres.h>
|
||||
|
||||
struct regmap *regmap_resource(struct device *dev, char *name)
|
||||
{
|
||||
struct resource res;
|
||||
void __iomem *base;
|
||||
struct device_node *node = dev->of_node;
|
||||
static struct regmap_config aud_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
};
|
||||
int i;
|
||||
|
||||
i = of_property_match_string(node, "reg-names", name);
|
||||
if (of_address_to_resource(node, i, &res))
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
base = devm_ioremap_resource(dev, &res);
|
||||
if (IS_ERR(base))
|
||||
return ERR_CAST(base);
|
||||
|
||||
pr_info("%s, %s, start:%#x, size:%#x\n",
|
||||
__func__, name, (u32)res.start, (u32)resource_size(&res));
|
||||
|
||||
aud_regmap_config.max_register = resource_size(&res) - 4;
|
||||
aud_regmap_config.name =
|
||||
devm_kasprintf(dev, GFP_KERNEL, "%s-%s", node->name, name);
|
||||
if (!aud_regmap_config.name)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
return devm_regmap_init_mmio(dev, base, &aud_regmap_config);
|
||||
}
|
||||
|
||||
unsigned int mmio_read(struct regmap *map, unsigned int reg_ofs)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
regmap_read(map, (reg_ofs << 2), &val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
int mmio_write(struct regmap *map, unsigned int reg_ofs, unsigned int value)
|
||||
{
|
||||
return regmap_write(map, (reg_ofs << 2), value);
|
||||
}
|
||||
|
||||
int mmio_update_bits(struct regmap *map,
|
||||
unsigned int reg_ofs,
|
||||
unsigned int mask,
|
||||
unsigned int value)
|
||||
{
|
||||
return regmap_update_bits(map, (reg_ofs << 2), mask, value);
|
||||
}
|
||||
@@ -34,6 +34,11 @@
|
||||
unsigned int IEC958_mode_codec;
|
||||
EXPORT_SYMBOL(IEC958_mode_codec);
|
||||
|
||||
bool spdifout_is_raw(void)
|
||||
{
|
||||
return (IEC958_mode_codec && IEC958_mode_codec != 9);
|
||||
}
|
||||
|
||||
bool spdif_is_4x_clk(void)
|
||||
{
|
||||
bool is_4x = false;
|
||||
|
||||
@@ -69,7 +69,7 @@ static int ad82584f_set_eq_drc(struct snd_soc_codec *codec);
|
||||
/* Power-up register defaults */
|
||||
static const
|
||||
struct reg_default ad82584f_reg_defaults[AD82584F_REGISTER_COUNT] = {
|
||||
{0x00, 0x00},//##State_Control_1
|
||||
{0x00, 0x04},//##State_Control_1
|
||||
{0x01, 0x04},//##State_Control_2
|
||||
{0x02, 0x30},//##State_Control_3
|
||||
{0x03, 0x4e},//##Master_volume_control
|
||||
@@ -207,7 +207,7 @@ struct reg_default ad82584f_reg_defaults[AD82584F_REGISTER_COUNT] = {
|
||||
};
|
||||
|
||||
static const int m_reg_tab[AD82584F_REGISTER_COUNT][2] = {
|
||||
{0x00, 0x00},//##State_Control_1
|
||||
{0x00, 0x04},//##State_Control_1
|
||||
{0x01, 0x04},//##State_Control_2
|
||||
{0x02, 0x30},//##State_Control_3
|
||||
{0x03, 0x4e},//##Master_volume_control
|
||||
@@ -856,7 +856,7 @@ static int ad82584f_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct ad82584f_priv *ad82584f = snd_soc_codec_get_drvdata(codec);
|
||||
struct ad82584f_platform_data *pdata = ad82584f->pdata;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
#ifdef CONFIG_HAS_EARLYSUSPEND
|
||||
ad82584f->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN;
|
||||
@@ -866,12 +866,15 @@ static int ad82584f_probe(struct snd_soc_codec *codec)
|
||||
register_early_suspend(&(ad82584f->early_suspend));
|
||||
#endif
|
||||
|
||||
ret = devm_gpio_request_one(codec->dev, pdata->reset_pin,
|
||||
GPIOF_OUT_INIT_LOW,
|
||||
"ad82584f-reset-pin");
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "ad82584f get gpio error!\n");
|
||||
return -1;
|
||||
if (pdata->reset_pin > 0) {
|
||||
ret = devm_gpio_request_one(codec->dev, pdata->reset_pin,
|
||||
GPIOF_OUT_INIT_LOW,
|
||||
"ad82584f-reset-pin");
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "ad82584f get gpio error!\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ad82584f_init(codec);
|
||||
|
||||
@@ -133,7 +133,7 @@ static int tas5782m_ch2_vol_info(struct snd_kcontrol *kcontrol,
|
||||
static int tas5782m_ch1_mute_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
|
||||
uinfo->access = SNDRV_CTL_ELEM_ACCESS_TLV_READ
|
||||
| SNDRV_CTL_ELEM_ACCESS_READWRITE;
|
||||
uinfo->count = 1;
|
||||
@@ -148,7 +148,7 @@ static int tas5782m_ch1_mute_info(struct snd_kcontrol *kcontrol,
|
||||
static int tas5782m_ch2_mute_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
|
||||
uinfo->access = SNDRV_CTL_ELEM_ACCESS_TLV_READ
|
||||
| SNDRV_CTL_ELEM_ACCESS_READWRITE;
|
||||
uinfo->count = 1;
|
||||
@@ -361,14 +361,14 @@ static const struct snd_kcontrol_new tas5782m_snd_controls[] = {
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Ch1 Mute",
|
||||
.name = "Ch1 Switch",
|
||||
.info = tas5782m_ch1_mute_info,
|
||||
.get = tas5782m_ch1_mute_get,
|
||||
.put = tas5782m_ch1_mute_set,
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Ch2 Mute",
|
||||
.name = "Ch2 Switch",
|
||||
.info = tas5782m_ch2_mute_info,
|
||||
.get = tas5782m_ch2_mute_get,
|
||||
.put = tas5782m_ch2_mute_set,
|
||||
@@ -671,6 +671,11 @@ static void tas5782m_init_func(struct work_struct *p_work)
|
||||
}
|
||||
|
||||
tas5782m_init_i2s_tdm_mode(codec, g_sample_bitsize);
|
||||
|
||||
tas5782m_set_mute(codec, tas5782m->Ch1_mute, tas5782m->Ch2_mute);
|
||||
|
||||
tas5782m_set_volume(codec, 255-tas5782m->Ch1_vol, 0);
|
||||
tas5782m_set_volume(codec, 255-tas5782m->Ch2_vol, 1);
|
||||
}
|
||||
|
||||
static int tas5782m_probe(struct snd_soc_codec *codec)
|
||||
@@ -688,6 +693,11 @@ static int tas5782m_probe(struct snd_soc_codec *codec)
|
||||
tas5782m = snd_soc_codec_get_drvdata(codec);
|
||||
tas5782m->codec = codec;
|
||||
|
||||
tas5782m->Ch1_mute = 0;
|
||||
tas5782m->Ch2_mute = 0;
|
||||
tas5782m->Ch1_vol = 0;
|
||||
tas5782m->Ch2_vol = 0;
|
||||
|
||||
INIT_WORK(&tas5782m->work, tas5782m_init_func);
|
||||
schedule_work(&tas5782m->work);
|
||||
|
||||
|
||||
@@ -649,10 +649,10 @@ const uint32_t tas5805m_volume[] = {
|
||||
#define TAS5805_EQPARAM_LENGTH 610
|
||||
#define TAS5805_EQ_LENGTH 245
|
||||
#define FILTER_PARAM_BYTE 244
|
||||
static int m_eq_tab[TAS5805_EQPARAM_LENGTH][2] = {0};
|
||||
static int m_eq_tab[TAS5805_EQPARAM_LENGTH][2];
|
||||
#define TAS5805_DRC_PARAM_LENGTH 29
|
||||
#define TAS5805_DRC_PARAM_COUNT 58
|
||||
static int m_drc_tab[TAS5805_DRC_PARAM_LENGTH][2] = {0};
|
||||
static int m_drc_tab[TAS5805_DRC_PARAM_LENGTH][2];
|
||||
|
||||
struct tas5805m_priv {
|
||||
struct regmap *regmap;
|
||||
|
||||
Reference in New Issue
Block a user