From 1a74f1c0db3a39bdc0a9e85e68fccccc14e22473 Mon Sep 17 00:00:00 2001 From: Xing Wang Date: Wed, 27 Feb 2019 14:12:11 +0800 Subject: [PATCH] audio: auge: fix PAO for frhdmirx [1/2] PD#SWPL-4010 Problem: Not detect audio type by PAO for frhdmirx Solution: Add hw detect for frdhmirx PAO audio type is checked by hw for PCM too Verify: x301 Change-Id: Ib60d738c69f336866250a8181609503912bf0485 Signed-off-by: Xing Wang --- sound/soc/amlogic/auge/extn.c | 101 ++++++++++++++++++++++++++++++++--- sound/soc/amlogic/auge/frhdmirx_hw.c | 99 ++++++++++++++++++++++++---------- sound/soc/amlogic/auge/frhdmirx_hw.h | 5 ++ sound/soc/amlogic/auge/spdif.c | 2 +- sound/soc/amlogic/auge/tdm.c | 2 +- 5 files changed, 172 insertions(+), 37 deletions(-) diff --git a/sound/soc/amlogic/auge/extn.c b/sound/soc/amlogic/auge/extn.c index 65c4e8d..722957b 100644 --- a/sound/soc/amlogic/auge/extn.c +++ b/sound/soc/amlogic/auge/extn.c @@ -42,6 +42,15 @@ #define DRV_NAME "EXTN" +#define MAX_INT 0x7ffffff + +struct extn_chipinfo { + /* try to check papb before fetch pcpd + * no nonpcm2pcm irq for tl1 + */ + bool no_nonpcm2pcm_clr; +}; + struct extn { struct aml_audio_controller *actrl; struct device *dev; @@ -69,9 +78,19 @@ struct extn { int arc_src; int arc_en; + /* check whether irq generating + * if not, reset + * 'cuase no irq from nonpcm2pcm, do it by sw. + */ + unsigned int frhdmirx_cnt; /* irq counter */ + unsigned int frhdmirx_last_cnt; + unsigned int frhdmirx_same_cnt; + bool nonpcm_flag; + + struct extn_chipinfo *chipinfo; }; -#define PREALLOC_BUFFER (128 * 1024) +#define PREALLOC_BUFFER (256 * 1024) #define PREALLOC_BUFFER_MAX (256 * 1024) #define EXTN_RATES (SNDRV_PCM_RATE_8000_192000) @@ -100,21 +119,58 @@ static const struct snd_pcm_hardware extn_hardware = { .channels_max = 32, }; +static void frhdmirx_nonpcm2pcm_clr_reset(struct extn *p_extn) +{ + p_extn->frhdmirx_cnt = 0; + p_extn->frhdmirx_last_cnt = 0; + p_extn->frhdmirx_same_cnt = 0; +} + static irqreturn_t extn_ddr_isr(int irq, void *devid) { struct snd_pcm_substream *substream = (struct snd_pcm_substream *)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); if (!snd_pcm_running(substream)) return IRQ_HANDLED; snd_pcm_period_elapsed(substream); + /* check pcm or nonpcm */ + if (p_extn && + p_extn->chipinfo && + p_extn->chipinfo->no_nonpcm2pcm_clr) { + if (p_extn->frhdmirx_last_cnt == p_extn->frhdmirx_cnt) { + + p_extn->frhdmirx_same_cnt++; + + if (p_extn->frhdmirx_same_cnt > 5) + frhdmirx_nonpcm2pcm_clr_reset(p_extn); + + if (p_extn->frhdmirx_cnt == 0) + p_extn->nonpcm_flag = false; + } else { + p_extn->frhdmirx_last_cnt = p_extn->frhdmirx_cnt; + p_extn->frhdmirx_same_cnt = 0; + p_extn->nonpcm_flag = true; + frhdmirx_clr_PAO_irq_bits(); + } + } + return IRQ_HANDLED; } static irqreturn_t frhdmirx_isr(int irq, void *devid) { + struct extn *p_extn = (struct extn *)devid; + + p_extn->frhdmirx_cnt++; + if (p_extn->frhdmirx_cnt > MAX_INT - 2) + frhdmirx_nonpcm2pcm_clr_reset(p_extn); + return IRQ_HANDLED; } @@ -177,8 +233,12 @@ static int extn_close(struct snd_pcm_substream *substream) else { aml_audio_unregister_toddr(p_extn->dev, substream); - if (toddr_src_get() == FRHDMIRX) + if (toddr_src_get() == FRHDMIRX) { + frhdmirx_nonpcm2pcm_clr_reset(p_extn); + if (p_extn->hdmirx_mode == 1) + frhdmirx_clr_PAO_irq_bits(); free_irq(p_extn->irq_frhdmirx, p_extn); + } } runtime->private_data = NULL; @@ -639,7 +699,7 @@ static const struct sppdif_audio_info type_texts[] = { {3, 0xb, "DTS-I"}, {3, 0x0c, "DTS-II"}, {3, 0x0d, "DTS-III"}, - {3, 0x11, "DTS-IV"}, + {4, 0x11, "DTS-IV"}, {4, 0, "DTS-HD"}, {5, 0x16, "TRUEHD"}, {6, 0x103, "PAUSE"}, @@ -651,13 +711,16 @@ static const struct soc_enum hdmirx_audio_type_enum = SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(spdif_audio_type_texts), spdif_audio_type_texts); -static int hdmiin_check_audio_type(void) +static int hdmiin_check_audio_type(struct extn *p_extn) { int total_num = sizeof(type_texts)/sizeof(struct sppdif_audio_info); int pc = frhdmirx_get_chan_status_pc(); int audio_type = 0; int i; + if (!p_extn->nonpcm_flag) + return audio_type; + for (i = 0; i < total_num; i++) { if (pc == type_texts[i].pc) { audio_type = type_texts[i].aud_type; @@ -674,8 +737,12 @@ static int hdmirx_audio_type_get_enum( 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); + ucontrol->value.enumerated.item[0] = - hdmiin_check_audio_type(); + hdmiin_check_audio_type(p_extn); + return 0; } #endif @@ -735,6 +802,7 @@ static const struct snd_kcontrol_new extn_controls[] = { 0, aml_get_atmos_audio_edid, aml_set_atmos_audio_edid), + SOC_ENUM_EXT("HDMIIN Audio Type", hdmirx_audio_type_enum, hdmirx_audio_type_get_enum, @@ -749,9 +817,18 @@ static const struct snd_soc_component_driver extn_component = { .name = DRV_NAME, }; +struct extn_chipinfo tl1_extn_chipinfo = { + .no_nonpcm2pcm_clr = true, +}; + static const struct of_device_id extn_device_id[] = { { .compatible = "amlogic, snd-extn", + .data = &tl1_extn_chipinfo, + }, + { + .compatible = "amlogic, tl1-snd-extn", + .data = &tl1_extn_chipinfo, }, {}, }; @@ -766,9 +843,9 @@ static int extn_platform_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct aml_audio_controller *actrl = NULL; struct extn *p_extn = NULL; + struct extn_chipinfo *p_chipinfo; int ret = 0; - p_extn = devm_kzalloc(dev, sizeof(struct extn), GFP_KERNEL); if (!p_extn) return -ENOMEM; @@ -776,6 +853,14 @@ static int extn_platform_probe(struct platform_device *pdev) p_extn->dev = dev; dev_set_drvdata(dev, p_extn); + /* match data */ + p_chipinfo = (struct extn_chipinfo *) + of_device_get_match_data(dev); + if (!p_chipinfo) + dev_warn_once(dev, "check whether to update chipinfo\n"); + else + p_extn->chipinfo = p_chipinfo; + /* get audio controller */ node_prt = of_get_parent(node); if (node_prt == NULL) @@ -798,8 +883,8 @@ static int extn_platform_probe(struct platform_device *pdev) /* Default ARC SRC */ p_extn->arc_src = 1; - /* Default: SPDIF in mode */ - p_extn->hdmirx_mode = 0; + /* Default: PAO mode */ + p_extn->hdmirx_mode = 1; ret = snd_soc_register_component(&pdev->dev, &extn_component, diff --git a/sound/soc/amlogic/auge/frhdmirx_hw.c b/sound/soc/amlogic/auge/frhdmirx_hw.c index 19c55f4..1dd0593 100644 --- a/sound/soc/amlogic/auge/frhdmirx_hw.c +++ b/sound/soc/amlogic/auge/frhdmirx_hw.c @@ -15,6 +15,7 @@ * */ #include +#include #include "frhdmirx_hw.h" #include "regs.h" @@ -48,7 +49,7 @@ void frhdmirx_src_select(int src) (bool)src << 23); } -void frhdmirx_enable_irq_bits(int channels, int src) +static void frhdmirx_enable_irq_bits(int channels, int src) { int lane, int_bits = 0, i; @@ -59,10 +60,11 @@ void frhdmirx_enable_irq_bits(int channels, int src) /* interrupt bits */ if (src) { /* PAO mode */ - int_bits = (0x1 << 24 | /* PAO data: find papb */ - 0x1 << 16 /* PAO data: find pcpd changed */ + int_bits = ( + 0x1 << INT_PAO_PAPB_MASK | /* find papb */ + 0x1 << INT_PAO_PCPD_MASK /* find pcpd changed */ ); - } else { /* SPDIF Lane*/ + } else { /* SPDIF Lane */ int lane_irq_bits = (0x1 << 7 | /* lane: find papb */ 0x1 << 6 | /* lane: find papb */ 0x1 << 5 | /* lane: find nonpcm to pcm */ @@ -77,6 +79,39 @@ void frhdmirx_enable_irq_bits(int channels, int src) audiobus_write(EE_AUDIO_FRHDMIRX_CTRL2, int_bits); } +void frhdmirx_clr_irq_bits(int channels, int src) +{ + int lane, int_clr_mask = 0, i; + + if (channels % 2) + lane = channels / 2 + 1; + else + lane = channels / 2; + + /* interrupt bits */ + if (src) { /* PAO mode */ + int_clr_mask = ( + 0x1 << INT_PAO_PAPB_MASK | /* find papb */ + 0x1 << INT_PAO_PCPD_MASK /* find pcpd changed */ + ); + } else { /* SPDIF Lane */ + int lane_irq_bits = (0x1 << 7 | /* lane: find papb */ + 0x1 << 6 | /* lane: find valid changed; */ + 0x1 << 5 | /* lane: find nonpcm to pcm */ + 0x1 << 4 | /* lane: find pcpd changed */ + 0x1 << 3 | /* lane: find ch status changed */ + 0x1 << 1 /* lane: find parity error */ + ); + + for (i = 0; i < lane; i++) + int_clr_mask |= (lane_irq_bits << i); + } + audiobus_write(EE_AUDIO_FRHDMIRX_CTRL3, ~int_clr_mask); + audiobus_write(EE_AUDIO_FRHDMIRX_CTRL3, int_clr_mask); + audiobus_write(EE_AUDIO_FRHDMIRX_CTRL4, ~int_clr_mask); + audiobus_write(EE_AUDIO_FRHDMIRX_CTRL4, int_clr_mask); +} + void frhdmirx_ctrl(int channels, int src) { int lane, lane_mask = 0, i; @@ -84,30 +119,27 @@ void frhdmirx_ctrl(int channels, int src) /* PAO mode */ if (src) { audiobus_write(EE_AUDIO_FRHDMIRX_CTRL0, - 0x1 << 23 | /* slect pao mode */ 0x1 << 22 | /* capture input by fall edge*/ - 0x1 << 7 | /* start sending ch num info out */ 0x1 << 8 | /* start detect PAPB */ - 0x1 << 6 /* chan status sel: pao pc/pd value */); - return; - } - - if (channels % 2) - lane = channels / 2 + 1; - else - lane = channels / 2; - - for (i = 0; i < lane; i++) - lane_mask |= (1 << i); + 0x4 << 4 /* chan status sel: pao pc/pd value */ + ); + } else { + if (channels % 2) + lane = channels / 2 + 1; + else + lane = channels / 2; - audiobus_update_bits(EE_AUDIO_FRHDMIRX_CTRL0, - 0x1 << 30 | 0xf << 24 | 0x1 << 22 | 0x3 << 11, - 0x1 << 30 | /* chnum_sel */ - lane_mask << 24 | /* chnum_sel */ - 0x1 << 22 | /* clk_inv */ - 0x0 << 11 /* req_sel, Sync 4 spdifin by which */ - ); + for (i = 0; i < lane; i++) + lane_mask |= (1 << i); + audiobus_update_bits(EE_AUDIO_FRHDMIRX_CTRL0, + 0x1 << 30 | 0xf << 24 | 0x1 << 22 | 0x3 << 11, + 0x1 << 30 | /* chnum_sel */ + lane_mask << 24 | /* chnum_sel */ + 0x1 << 22 | /* clk_inv */ + 0x0 << 11 /* req_sel, Sync 4 spdifin by which */ + ); + } /* nonpcm2pcm_th */ audiobus_write(EE_AUDIO_FRHDMIRX_CTRL1, 0xff << 20); @@ -115,6 +147,22 @@ void frhdmirx_ctrl(int channels, int src) frhdmirx_enable_irq_bits(channels, src); } +void frhdmirx_clr_PAO_irq_bits(void) +{ + audiobus_update_bits(EE_AUDIO_FRHDMIRX_CTRL4, + 0x1 << INT_PAO_PAPB_MASK | 0x1 << INT_PAO_PCPD_MASK, + 0x1 << INT_PAO_PAPB_MASK | 0x1 << INT_PAO_PCPD_MASK); + + audiobus_update_bits(EE_AUDIO_FRHDMIRX_CTRL4, + 0x1 << INT_PAO_PAPB_MASK | 0x1 << INT_PAO_PCPD_MASK, + 0x0 << INT_PAO_PAPB_MASK | 0x0 << INT_PAO_PCPD_MASK); +} + +unsigned int frhdmirx_get_ch_status0to31(void) +{ + return (unsigned int)audiobus_read(EE_AUDIO_FRHDMIRX_STAT0); +} + unsigned int frhdmirx_get_chan_status_pc(void) { unsigned int val; @@ -122,6 +170,3 @@ unsigned int frhdmirx_get_chan_status_pc(void) val = audiobus_read(EE_AUDIO_FRHDMIRX_STAT1); return (val >> 16) & 0xff; } - - - diff --git a/sound/soc/amlogic/auge/frhdmirx_hw.h b/sound/soc/amlogic/auge/frhdmirx_hw.h index e0ebfe4..7c83dd0 100644 --- a/sound/soc/amlogic/auge/frhdmirx_hw.h +++ b/sound/soc/amlogic/auge/frhdmirx_hw.h @@ -17,8 +17,13 @@ #ifndef __FRHDMIRX_HW_H__ #define __FRHDMIRX_HW_H__ +#define INT_PAO_PAPB_MASK 24 +#define INT_PAO_PCPD_MASK 16 + extern void frhdmirx_enable(bool enable); extern void frhdmirx_src_select(int src); extern void frhdmirx_ctrl(int channels, int src); +extern void frhdmirx_clr_PAO_irq_bits(void); +extern unsigned int frhdmirx_get_ch_status0to31(void); extern unsigned int frhdmirx_get_chan_status_pc(void); #endif diff --git a/sound/soc/amlogic/auge/spdif.c b/sound/soc/amlogic/auge/spdif.c index 8567d7e..0205867 100644 --- a/sound/soc/amlogic/auge/spdif.c +++ b/sound/soc/amlogic/auge/spdif.c @@ -907,7 +907,7 @@ static struct snd_pcm_ops aml_spdif_ops = { .mmap = aml_spdif_mmap, }; -#define PREALLOC_BUFFER (128 * 1024) +#define PREALLOC_BUFFER (256 * 1024) #define PREALLOC_BUFFER_MAX (256 * 1024) static int aml_spdif_new(struct snd_soc_pcm_runtime *rtd) { diff --git a/sound/soc/amlogic/auge/tdm.c b/sound/soc/amlogic/auge/tdm.c index 79742b3..0d0c150 100644 --- a/sound/soc/amlogic/auge/tdm.c +++ b/sound/soc/amlogic/auge/tdm.c @@ -409,7 +409,7 @@ static struct snd_pcm_ops aml_tdm_ops = { .mmap = aml_tdm_mmap, }; -#define PREALLOC_BUFFER (128 * 1024) +#define PREALLOC_BUFFER (256 * 1024) #define PREALLOC_BUFFER_MAX (256 * 1024) static int aml_tdm_new(struct snd_soc_pcm_runtime *rtd) { -- 2.7.4