audio: auge: add mixer for eARC RX/TX latency and capability [1/1]

PD#SWPL-6918

Problem:
lack function to read/write eARC RX/TX latency and capability

Solution:
add mixer for eARC RX set/get latency and capability
add mixer for eARC RX get latency and capability

Verify:
ab311

Change-Id: I0d8aa00af7d856493417dc881a1a8c40497b12a5
Signed-off-by: Xing Wang <xing.wang@amlogic.com>
This commit is contained in:
Xing Wang
2019-11-01 15:47:10 +08:00
committed by Tao Zeng
parent b183f51456
commit 960f88fbb7
5 changed files with 516 additions and 14 deletions

View File

@@ -13824,7 +13824,6 @@ F: sound/soc/codecs/Makefile
F: sound/soc/codecs/amlogic/*
F: drivers/amlogic/audiodsp/*
AMLOGIC PPMGR DRIVER
M: Guosong Zhou <guosong.zhou@amlogic.com>
F: arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts

View File

@@ -0,0 +1,43 @@
/*
* include/linux/amlogic/media/sound/mixer.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 __MIXER_H__
#define __MIXER_H__
#include <sound/control.h>
static int snd_int_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 0xffffffff;
uinfo->count = 1;
return 0;
}
#define SND_INT(xname, xhandler_get, xhandler_put) \
{ \
.iface = SNDRV_CTL_ELEM_IFACE_PCM, \
.name = xname, \
.info = snd_int_info, \
.get = xhandler_get, \
.put = xhandler_put, \
}
#endif

View File

@@ -37,6 +37,7 @@
#include <sound/pcm_params.h>
#include <linux/amlogic/media/sound/hdmi_earc.h>
#include <linux/amlogic/media/sound/mixer.h>
#include "ddr_mngr.h"
#include "earc_hw.h"
@@ -153,17 +154,24 @@ static irqreturn_t earc_rx_isr(int irq, void *data)
if (status0)
earcrx_cdmc_clr_irqs(p_earc->rx_top_map, status0);
if (status0 & INT_EARCRX_CMDC_TIMEOUT) {
earcrx_update_attend_event(p_earc,
false, false);
pr_debug("%s EARCRX_CMDC_TIMEOUT\n", __func__);
}
if (status0 & INT_EARCRX_CMDC_IDLE2) {
earcrx_update_attend_event(p_earc,
false, true);
pr_debug("%s EARCRX_CMDC_IDLE2\n", __func__);
pr_info("%s EARCRX_CMDC_IDLE2\n", __func__);
}
if (status0 & INT_EARCRX_CMDC_IDLE1) {
earcrx_update_attend_event(p_earc,
false, false);
pr_debug("%s EARCRX_CMDC_IDLE1\n", __func__);
pr_info("%s EARCRX_CMDC_IDLE1\n", __func__);
}
if (status0 & INT_EARCRX_CMDC_DISC2)
pr_debug("%s EARCRX_CMDC_DISC2\n", __func__);
@@ -181,12 +189,6 @@ static irqreturn_t earc_rx_isr(int irq, void *data)
*/
if (status0 & INT_EARCRX_CMDC_LOSTHB)
pr_debug("%s EARCRX_CMDC_LOSTHB\n", __func__);
if (status0 & INT_EARCRX_CMDC_TIMEOUT) {
earcrx_update_attend_event(p_earc,
false, false);
pr_debug("%s EARCRX_CMDC_TIMEOUT\n", __func__);
}
if (p_earc->rx_dmac_clk_on) {
unsigned int status1 = earcrx_dmac_get_irqs(p_earc->rx_top_map);
@@ -936,21 +938,205 @@ int earctx_set_attend_type(struct snd_kcontrol *kcontrol,
return 0;
}
static const struct snd_kcontrol_new earc_controls[] = {
SOC_ENUM_EXT("eARC_RX attended type",
attended_type_enum,
earcrx_get_attend_type,
earcrx_set_attend_type),
int earcrx_get_latency(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct earc *p_earc = dev_get_drvdata(component->dev);
enum cmdc_st state;
u8 val = 0;
if (!p_earc || IS_ERR(p_earc->rx_top_map))
return 0;
state = earcrx_cmdc_get_state(p_earc->rx_cmdc_map);
if (state != CMDC_ST_EARC)
return 0;
earcrx_cmdc_get_latency(p_earc->rx_cmdc_map, &val);
ucontrol->value.integer.value[0] = val;
return 0;
}
int earcrx_set_latency(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct earc *p_earc = dev_get_drvdata(component->dev);
u8 latency = ucontrol->value.integer.value[0];
enum cmdc_st state;
if (!p_earc || IS_ERR(p_earc->rx_top_map))
return 0;
state = earcrx_cmdc_get_state(p_earc->rx_cmdc_map);
if (state != CMDC_ST_EARC)
return 0;
earcrx_cmdc_set_latency(p_earc->rx_cmdc_map, &latency);
return 0;
}
int earcrx_get_cds(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct earc *p_earc = dev_get_drvdata(component->dev);
struct soc_bytes_ext *bytes_ext =
(struct soc_bytes_ext *)kcontrol->private_value;
u8 *value = (u8 *)ucontrol->value.bytes.data;
enum cmdc_st state;
int i;
u8 data[256];
if (!p_earc || IS_ERR(p_earc->rx_top_map))
return 0;
state = earcrx_cmdc_get_state(p_earc->rx_cmdc_map);
if (state != CMDC_ST_EARC)
return 0;
earcrx_cmdc_get_cds(p_earc->rx_cmdc_map, data);
for (i = 0; i < bytes_ext->max; i++)
*value++ = data[i];
return 0;
}
int earcrx_set_cds(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct earc *p_earc = dev_get_drvdata(component->dev);
struct soc_bytes_ext *params = (void *)kcontrol->private_value;
u8 *data;
enum cmdc_st state;
if (!p_earc || IS_ERR(p_earc->rx_top_map))
return 0;
state = earcrx_cmdc_get_state(p_earc->rx_cmdc_map);
if (state != CMDC_ST_EARC)
return 0;
data = kmemdup(ucontrol->value.bytes.data,
params->max, GFP_KERNEL | GFP_DMA);
if (!data)
return -ENOMEM;
earcrx_cmdc_set_cds(p_earc->rx_cmdc_map, data);
kfree(data);
return 0;
}
int earctx_get_latency(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct earc *p_earc = dev_get_drvdata(component->dev);
enum cmdc_st state;
u8 val = 0;
if (!p_earc || IS_ERR(p_earc->tx_top_map))
return 0;
state = earctx_cmdc_get_state(p_earc->tx_cmdc_map);
if (state != CMDC_ST_EARC)
return 0;
earctx_cmdc_get_latency(p_earc->tx_cmdc_map, &val);
ucontrol->value.integer.value[0] = val;
return 0;
}
int earctx_set_latency(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct earc *p_earc = dev_get_drvdata(component->dev);
u8 latency = ucontrol->value.integer.value[0];
enum cmdc_st state;
if (!p_earc || IS_ERR(p_earc->tx_top_map))
return 0;
state = earctx_cmdc_get_state(p_earc->tx_cmdc_map);
if (state != CMDC_ST_EARC)
return 0;
earctx_cmdc_set_latency(p_earc->tx_cmdc_map, &latency);
return 0;
}
int earctx_get_cds(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct earc *p_earc = dev_get_drvdata(component->dev);
struct soc_bytes_ext *bytes_ext =
(struct soc_bytes_ext *)kcontrol->private_value;
u8 *value = (u8 *)ucontrol->value.bytes.data;
enum cmdc_st state;
u8 data[256];
int i;
if (!p_earc || IS_ERR(p_earc->tx_top_map))
return 0;
state = earctx_cmdc_get_state(p_earc->tx_cmdc_map);
if (state != CMDC_ST_EARC)
return 0;
earctx_cmdc_get_cds(p_earc->tx_cmdc_map, data);
for (i = 0; i < bytes_ext->max; i++)
*value++ = data[i];
return 0;
}
static const struct snd_kcontrol_new earc_controls[] = {
SOC_SINGLE_BOOL_EXT("HDMI ARC Switch",
0,
earcrx_arc_get_enable,
earcrx_arc_set_enable),
SOC_ENUM_EXT("eARC_RX attended type",
attended_type_enum,
earcrx_get_attend_type,
earcrx_set_attend_type),
SOC_ENUM_EXT("eARC_TX attended type",
attended_type_enum,
earctx_get_attend_type,
earctx_set_attend_type),
SND_INT("eARC_RX Latency",
earcrx_get_latency,
earcrx_set_latency),
SND_INT("eARC_TX Latency",
earctx_get_latency,
earctx_set_latency),
SND_SOC_BYTES_EXT("eARC_RX CDS",
CDS_MAX_BYTES,
earcrx_get_cds,
earcrx_set_cds),
SND_SOC_BYTES_EXT("eARC_TX CDS",
CDS_MAX_BYTES,
earctx_get_cds,
NULL),
};
static const struct snd_soc_component_driver earc_component = {

View File

@@ -612,3 +612,250 @@ void earctx_enable(struct regmap *top_map,
enable << 30);
}
}
static void earcrx_cmdc_get_reg(struct regmap *cmdc_map, int dev_id, int offset,
u8 *data, int bytes)
{
int i;
mmio_update_bits(cmdc_map, EARC_RX_CMDC_DEVICE_ID_CTRL,
0x1 << 31 | /* apb_write */
0x1 << 30 | /* apb_read */
0x1 << 29 | /* apb_w_r_done */
0xff << 8 | /* apb_rwid */
0xff << 0, /* apbrw_start_addr */
0x0 << 31 |
0x1 << 30 |
0x0 << 29 |
dev_id << 8 |
offset << 0);
for (i = 0; i < bytes; i++) {
data[i] = mmio_read(cmdc_map, EARC_RX_CMDC_DEVICE_RDATA);
pr_info("%s, data[%d]:%#x\n", __func__, i, data[i]);
}
mmio_update_bits(cmdc_map, EARC_RX_CMDC_DEVICE_ID_CTRL,
0x1 << 29, 0x1 << 29);
mmio_update_bits(cmdc_map, EARC_RX_CMDC_DEVICE_ID_CTRL,
0x1 << 29, 0x0 << 29);
}
static void earcrx_cmdc_set_reg(struct regmap *cmdc_map, int dev_id, int offset,
u8 *data, int bytes)
{
int i;
mmio_update_bits(cmdc_map, EARC_RX_CMDC_DEVICE_ID_CTRL,
0x1 << 31 | /* apb_write */
0x1 << 30 | /* apb_read */
0x1 << 29 | /* apb_w_r_done */
0xff << 8 | /* apb_rwid */
0xff << 0, /* apbrw_start_addr */
0x1 << 31 |
0x0 << 30 |
0x0 << 29 |
dev_id << 8 |
offset << 0);
for (i = 0; i < bytes; i++) {
pr_info("%s, data[%d]:%#x\n", __func__, i, data[i]);
mmio_write(cmdc_map, EARC_RX_CMDC_DEVICE_WDATA, data[i]);
}
mmio_update_bits(cmdc_map, EARC_RX_CMDC_DEVICE_ID_CTRL,
0x1 << 29, 0x1 << 29);
mmio_update_bits(cmdc_map, EARC_RX_CMDC_DEVICE_ID_CTRL,
0x1 << 29, 0x0 << 29);
}
/* Latency */
void earcrx_cmdc_get_latency(struct regmap *cmdc_map, u8 *latency)
{
earcrx_cmdc_get_reg(cmdc_map,
STAT_CTRL_DEV_ID,
ERX_LATENCY_REG,
latency,
1);
}
void earcrx_cmdc_set_latency(struct regmap *cmdc_map, u8 *latency)
{
earcrx_cmdc_set_reg(cmdc_map,
STAT_CTRL_DEV_ID,
ERX_LATENCY_REG,
latency,
1);
}
void earcrx_cmdc_get_cds(struct regmap *cmdc_map, u8 *cds)
{
earcrx_cmdc_get_reg(cmdc_map,
CAP_DEV_ID,
0x0,
cds,
CDS_MAX_BYTES);
}
void earcrx_cmdc_set_cds(struct regmap *cmdc_map, u8 *cds)
{
earcrx_cmdc_set_reg(cmdc_map,
CAP_DEV_ID,
0x0,
cds,
CDS_MAX_BYTES);
}
static int earctx_cmdc_get_reg(struct regmap *cmdc_map, int dev_id, int offset,
u8 *data, int bytes)
{
int val = 0, i;
int ret = -1;
mmio_update_bits(cmdc_map, EARC_TX_CMDC_MASTER_CTRL,
0x1 << 31 | /* master_cmd_rw, read */
0x1 << 30 | /* master_hb_ignore */
0xf << 24 | /* hb_cmd_val_th */
0xff << 16 | /* master_cmd_count */
0xff << 8 | /* master_cmd_id */
0xff << 0, /* master_cmd_address */
0x0 << 31 |
0x1 << 30 |
0x4 << 24 |
(bytes - 1) << 16 |
dev_id << 8 |
offset << 0);
/* wait read from rx done */
while (!(val & (1 << 29))) {
usleep_range(500, 1500);
val = mmio_read(cmdc_map, EARC_TX_CMDC_MASTER_CTRL);
}
mmio_update_bits(cmdc_map, EARC_TX_CMDC_DEVICE_ID_CTRL,
0x1 << 31 | /* apb_write */
0x1 << 30 | /* apb_read */
0x1 << 29 | /* apb_rw_done */
0x1 << 16 | /* hpb_rst_enable */
0xff << 8 | /* apb_rwid */
0xff << 0, /* apbrw_start_addr */
0x0 << 31 |
0x1 << 30 |
0x0 << 29 |
0x1 << 16 |
dev_id << 8 |
offset << 0);
for (i = 0; i < bytes; i++) {
data[i] = mmio_read(cmdc_map, EARC_TX_CMDC_DEVICE_RDATA);
pr_info("%s, bytes:%d, data[%d]:%#x\n",
__func__,
bytes,
i,
data[i]);
}
mmio_update_bits(cmdc_map, EARC_TX_CMDC_DEVICE_ID_CTRL,
0x1 << 29, 0x1 << 29);
mmio_update_bits(cmdc_map, EARC_TX_CMDC_DEVICE_ID_CTRL,
0x1 << 29, 0x0 << 29);
if (val & (1 << 29))
ret = 0;
return ret;
}
static int earctx_cmdc_set_reg(struct regmap *cmdc_map, int dev_id, int offset,
u8 *data, int bytes)
{
int val = 0, i;
int ret = -1;
int cnt = 0;
mmio_update_bits(cmdc_map, EARC_TX_CMDC_DEVICE_ID_CTRL,
0x1 << 31 | /* apb_write */
0x1 << 30 | /* apb_read */
0x1 << 29 | /* apb_rw_done */
0x1 << 16 | /* hpb_rst_enable */
0xff << 8 | /* apb_rwid */
0xff << 0, /* apbrw_start_addr */
0x1 << 31 |
0x0 << 30 |
0x0 << 29 |
0x1 << 16 |
dev_id << 8 |
offset << 0);
for (i = 0; i < bytes; i++) {
mmio_update_bits(cmdc_map, EARC_TX_CMDC_DEVICE_WDATA,
0xff << 0,
data[i] << 0);
pr_info("%s, data[%d]:%#x, bytes:%d\n",
__func__,
i,
data[i],
bytes);
}
mmio_update_bits(cmdc_map, EARC_TX_CMDC_MASTER_CTRL,
0x1 << 31 | /* master_cmd_rw, write */
0x1 << 30 | /* master_hb_ignore */
0xf << 24 | /* hb_cmd_cal_th */
0xff << 16 | /* master_cmd_count */
0xff << 8 | /* master_cmd_id */
0xff << 0, /* master_cmd_address */
0x1 << 31 |
0x1 << 30 |
4 << 24 |
(bytes - 1) << 16 |
dev_id << 8 |
offset << 0);
/* wait write done */
while (!(val & (1 << 29))) {
usleep_range(500, 1500);
val = mmio_read(cmdc_map, EARC_TX_CMDC_MASTER_CTRL);
cnt++;
}
pr_info("%s, cnt:%d\n", __func__, cnt);
mmio_update_bits(cmdc_map, EARC_TX_CMDC_DEVICE_ID_CTRL,
0x1 << 29, 0x1 << 29);
mmio_update_bits(cmdc_map, EARC_TX_CMDC_DEVICE_ID_CTRL,
0x1 << 29, 0x0 << 29);
if (val & (1 << 29))
ret = 0;
return ret;
}
/* Latency */
void earctx_cmdc_get_latency(struct regmap *cmdc_map, u8 *latency)
{
earctx_cmdc_get_reg(cmdc_map,
STAT_CTRL_DEV_ID,
ERX_LATENCY_REG,
latency,
1);
}
void earctx_cmdc_set_latency(struct regmap *cmdc_map, u8 *latency)
{
earctx_cmdc_set_reg(cmdc_map,
STAT_CTRL_DEV_ID,
ERX_LATENCY_REQ_REG,
latency,
1);
}
/* Capability Data Structure, fetch CDS from RX */
void earctx_cmdc_get_cds(struct regmap *cmdc_map, u8 *cds)
{
earctx_cmdc_get_reg(cmdc_map,
CAP_DEV_ID,
0x0,
cds,
CDS_MAX_BYTES);
}

View File

@@ -107,6 +107,24 @@ enum tx_hd_hdp_mux {
GPIOW_5
};
enum device_id {
/* Capabilities Data Structure */
CAP_DEV_ID = 0xA0,
/* eARC status and latency control registers */
STAT_CTRL_DEV_ID = 0x74
};
enum reg_offset {
/* eARC Status Register Offset */
EARCRX_STAT_REG = 0xD0,
EARCTX_STAT_REG = 0xD1,
/* eARC Latency Registers Offset */
ERX_LATENCY_REG = 0xD2,
ERX_LATENCY_REQ_REG = 0xD3
};
#define CDS_MAX_BYTES 256
void earcrx_pll_refresh(struct regmap *top_map);
void earcrx_cmdc_init(struct regmap *top_map);
void earcrx_cmdc_arc_connect(struct regmap *cmdc_map, bool init);
@@ -144,4 +162,13 @@ void earctx_enable(struct regmap *top_map,
struct regmap *dmac_map,
bool enable);
void earcrx_cmdc_get_latency(struct regmap *cmdc_map, u8 *latency);
void earcrx_cmdc_set_latency(struct regmap *cmdc_map, u8 *latency);
void earcrx_cmdc_get_cds(struct regmap *cmdc_map, u8 *cds);
void earcrx_cmdc_set_cds(struct regmap *cmdc_map, u8 *cds);
void earctx_cmdc_get_latency(struct regmap *cmdc_map, u8 *latency);
void earctx_cmdc_set_latency(struct regmap *cmdc_map, u8 *latency);
void earctx_cmdc_get_cds(struct regmap *cmdc_map, u8 *cds);
#endif