diff --git a/MAINTAINERS b/MAINTAINERS index c25f5f5972a9..67cfb4d37c7d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13824,7 +13824,6 @@ F: sound/soc/codecs/Makefile F: sound/soc/codecs/amlogic/* F: drivers/amlogic/audiodsp/* - AMLOGIC PPMGR DRIVER M: Guosong Zhou F: arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts diff --git a/include/linux/amlogic/media/sound/mixer.h b/include/linux/amlogic/media/sound/mixer.h new file mode 100644 index 000000000000..980c02f25e88 --- /dev/null +++ b/include/linux/amlogic/media/sound/mixer.h @@ -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 + +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 diff --git a/sound/soc/amlogic/auge/earc.c b/sound/soc/amlogic/auge/earc.c index 427a5ba7cc98..e92dd264c19d 100644 --- a/sound/soc/amlogic/auge/earc.c +++ b/sound/soc/amlogic/auge/earc.c @@ -37,6 +37,7 @@ #include #include +#include #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 = { diff --git a/sound/soc/amlogic/auge/earc_hw.c b/sound/soc/amlogic/auge/earc_hw.c index 2028090d0bac..14694c1452b0 100644 --- a/sound/soc/amlogic/auge/earc_hw.c +++ b/sound/soc/amlogic/auge/earc_hw.c @@ -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); +} diff --git a/sound/soc/amlogic/auge/earc_hw.h b/sound/soc/amlogic/auge/earc_hw.h index 9a01e9656de0..d40120985ec4 100644 --- a/sound/soc/amlogic/auge/earc_hw.h +++ b/sound/soc/amlogic/auge/earc_hw.h @@ -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