From 1a5ab21c2e0f3d6b25ee9f7ca3429fac57027f76 Mon Sep 17 00:00:00 2001 From: Jie Yang Date: Fri, 27 Feb 2015 12:54:29 +0800 Subject: [PATCH 01/32] ASoC: Intel: Add suspend_pre and resume_post for Broadwell snd_soc_card For broadwell machine, we need do some machine related setting before suspend and after resume, e.g. disable/enable jack detection, here adding snd_soc_card suspend_pre and resume_post for this task. Signed-off-by: Jie Yang Signed-off-by: Mark Brown --- sound/soc/intel/broadwell.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/sound/soc/intel/broadwell.c b/sound/soc/intel/broadwell.c index fba2ef5dac42..af5d73070f60 100644 --- a/sound/soc/intel/broadwell.c +++ b/sound/soc/intel/broadwell.c @@ -225,6 +225,32 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { }, }; +static int broadwell_suspend(struct snd_soc_card *card){ + struct snd_soc_codec *codec; + + list_for_each_entry(codec, &card->codec_dev_list, card_list) { + if (!strcmp(codec->component.name, "i2c-INT343A:00")) { + dev_dbg(codec->dev, "disabling jack detect before going to suspend.\n"); + rt286_mic_detect(codec, NULL); + break; + } + } + return 0; +} + +static int broadwell_resume(struct snd_soc_card *card){ + struct snd_soc_codec *codec; + + list_for_each_entry(codec, &card->codec_dev_list, card_list) { + if (!strcmp(codec->component.name, "i2c-INT343A:00")) { + dev_dbg(codec->dev, "enabling jack detect for resume.\n"); + rt286_mic_detect(codec, &broadwell_headset); + break; + } + } + return 0; +} + /* broadwell audio machine driver for WPT + RT286S */ static struct snd_soc_card broadwell_rt286 = { .name = "broadwell-rt286", @@ -238,6 +264,8 @@ static struct snd_soc_card broadwell_rt286 = { .dapm_routes = broadwell_rt286_map, .num_dapm_routes = ARRAY_SIZE(broadwell_rt286_map), .fully_routed = true, + .suspend_pre = broadwell_suspend, + .resume_post = broadwell_resume, }; static int broadwell_audio_probe(struct platform_device *pdev) From bd22f9d405eb14cc074d294919d0b909e0bc6170 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 9 Mar 2015 16:55:22 +0800 Subject: [PATCH 02/32] ASoC: rt5670: Revert Keep sysclk on patch The "Keep sysclk on if JD func is used" patch force enable/disable pin in rt5670_set_dai_sysclk. But some machine driver call it in dapm widget event. It will cause kernel crash. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 592f961b5de5..32cd26678bae 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2273,13 +2273,6 @@ static int rt5670_set_dai_sysclk(struct snd_soc_dai *dai, if (freq == rt5670->sysclk && clk_id == rt5670->sysclk_src) return 0; - if (rt5670->pdata.jd_mode) { - if (clk_id == RT5670_SCLK_S_PLL1) - snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1"); - else - snd_soc_dapm_disable_pin(&codec->dapm, "PLL1"); - snd_soc_dapm_sync(&codec->dapm); - } switch (clk_id) { case RT5670_SCLK_S_MCLK: reg_val |= RT5670_SCLK_SRC_MCLK; @@ -2724,10 +2717,6 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, } if (rt5670->pdata.jd_mode) { - regmap_update_bits(rt5670->regmap, RT5670_GLB_CLK, - RT5670_SCLK_SRC_MASK, RT5670_SCLK_SRC_RCCLK); - rt5670->sysclk = 0; - rt5670->sysclk_src = RT5670_SCLK_S_RCCLK; regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG1, RT5670_PWR_MB, RT5670_PWR_MB); regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG2, From 485372dc24ca2eaac18ce41a51b9dd017bc11400 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 9 Mar 2015 16:55:23 +0800 Subject: [PATCH 03/32] ASoC: rt5670: Check sysclk source by private data Currently, is_sys_clk_from_pll check sysclk source by reading codec register value. And it will be invoked before updating dapm widget power. In some machine driver, snd_soc_dai_set_sysclk is called in dapm event to switch codec sysclk to RC clock in idle mode. And in some use cases (such as syspend/resume) hw_params will not be called when the dapm widget is powered up. As a result, is_sys_clk_from_pll will return 0 although it is supposed to be 1. To solve this, we let is_sys_clk_from_pll check sysclk sysclk_src which is stored in private data and don't change the value of sysclk_src when codec sysclk is switched to internal clock. The internal clock can only be used in idle mode, so it sould be fine if we don't set sysclk_src to internal clock. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 32cd26678bae..9e3bc43178f1 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -517,11 +517,10 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w, static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { - unsigned int val; + struct snd_soc_codec *codec = source->codec; + struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); - val = snd_soc_read(source->codec, RT5670_GLB_CLK); - val &= RT5670_SCLK_SRC_MASK; - if (val == RT5670_SCLK_SRC_PLL1) + if (rt5670->sysclk_src == RT5670_SCLK_S_PLL1) return 1; else return 0; @@ -2270,9 +2269,6 @@ static int rt5670_set_dai_sysclk(struct snd_soc_dai *dai, struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); unsigned int reg_val = 0; - if (freq == rt5670->sysclk && clk_id == rt5670->sysclk_src) - return 0; - switch (clk_id) { case RT5670_SCLK_S_MCLK: reg_val |= RT5670_SCLK_SRC_MCLK; @@ -2290,7 +2286,8 @@ static int rt5670_set_dai_sysclk(struct snd_soc_dai *dai, snd_soc_update_bits(codec, RT5670_GLB_CLK, RT5670_SCLK_SRC_MASK, reg_val); rt5670->sysclk = freq; - rt5670->sysclk_src = clk_id; + if (clk_id != RT5670_SCLK_S_RCCLK) + rt5670->sysclk_src = clk_id; dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); From 8d0c38a3f2a6bb70e952f127ed817fc7a08db52c Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Tue, 10 Mar 2015 09:05:38 +0800 Subject: [PATCH 04/32] ASoC: Intel: move sysclk source setting to platform_clock_control for balance. A playback noise happens after suspend/resume on Braswell. The issue is due to the codec PLL and codec ASRC are not enabled correctly due to the incorrect sysclk setting after resume. This patch resets the sysclk source setting in platform clock control widget handler. Signed-off-by: Bard Liao Signed-off-by: Jin Yao Signed-off-by: Mark Brown --- sound/soc/intel/cht_bsw_rt5672.c | 38 +++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c index bc8dcacd5e6a..279df4c43de1 100644 --- a/sound/soc/intel/cht_bsw_rt5672.c +++ b/sound/soc/intel/cht_bsw_rt5672.c @@ -50,6 +50,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, struct snd_soc_dapm_context *dapm = w->dapm; struct snd_soc_card *card = dapm->card; struct snd_soc_dai *codec_dai; + int ret; codec_dai = cht_get_codec_dai(card); if (!codec_dai) { @@ -57,17 +58,31 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, return -EIO; } - if (!SND_SOC_DAPM_EVENT_OFF(event)) - return 0; - - /* Set codec sysclk source to its internal clock because codec PLL will - * be off when idle and MCLK will also be off by ACPI when codec is - * runtime suspended. Codec needs clock for jack detection and button - * press. - */ - snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK, - 0, SND_SOC_CLOCK_IN); + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* set codec PLL source to the 19.2MHz platform clock (MCLK) */ + ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_MCLK, + CHT_PLAT_CLK_3_HZ, 48000 * 512); + if (ret < 0) { + dev_err(card->dev, "can't set codec pll: %d\n", ret); + return ret; + } + /* set codec sysclk source to PLL */ + ret = snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_PLL1, + 48000 * 512, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "can't set codec sysclk: %d\n", ret); + return ret; + } + } else { + /* Set codec sysclk source to its internal clock because codec + * PLL will be off when idle and MCLK will also be off by ACPI + * when codec is runtime suspended. Codec needs clock for jack + * detection and button press. + */ + snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK, + 48000 * 512, SND_SOC_CLOCK_IN); + } return 0; } @@ -77,7 +92,8 @@ static const struct snd_soc_dapm_widget cht_dapm_widgets[] = { SND_SOC_DAPM_MIC("Int Mic", NULL), SND_SOC_DAPM_SPK("Ext Spk", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_POST_PMD), + platform_clock_control, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), }; static const struct snd_soc_dapm_route cht_audio_map[] = { From d3ef70543429b754dacc87fc68c30c2c34502337 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 11 Mar 2015 11:42:44 +0800 Subject: [PATCH 05/32] ASoC: rt5670: Add IRQ function This patch adds the IRQ function support of rt5670. We use a flag named dev_gpio in platform data to inform codec driver if the IRQ function is used or not. Also, we export rt5670_set_jack_detect for machine driver to pass the jack point. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- include/sound/rt5670.h | 1 + sound/soc/codecs/rt5670.c | 176 +++++++++++++++++++++++++++++++++++++- sound/soc/codecs/rt5670.h | 4 + 3 files changed, 179 insertions(+), 2 deletions(-) diff --git a/include/sound/rt5670.h b/include/sound/rt5670.h index bd311197a3b5..b7d60510819b 100644 --- a/include/sound/rt5670.h +++ b/include/sound/rt5670.h @@ -14,6 +14,7 @@ struct rt5670_platform_data { int jd_mode; bool in2_diff; + bool dev_gpio; bool dmic_en; unsigned int dmic1_data_pin; diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 1a6a9c4dc879..a900db5fb1d9 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -403,6 +403,171 @@ static bool rt5670_readable_register(struct device *dev, unsigned int reg) } } +/** + * rt5670_headset_detect - Detect headset. + * @codec: SoC audio codec device. + * @jack_insert: Jack insert or not. + * + * Detect whether is headset or not when jack inserted. + * + * Returns detect status. + */ + +static int rt5670_headset_detect(struct snd_soc_codec *codec, int jack_insert) +{ + int val; + struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); + + if (jack_insert) { + snd_soc_dapm_force_enable_pin(&codec->dapm, + "Mic Det Power"); + snd_soc_dapm_sync(&codec->dapm); + snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x0); + snd_soc_update_bits(codec, RT5670_CJ_CTRL2, + RT5670_CBJ_DET_MODE | RT5670_CBJ_MN_JD, + RT5670_CBJ_MN_JD); + snd_soc_write(codec, RT5670_GPIO_CTRL2, 0x0004); + snd_soc_update_bits(codec, RT5670_GPIO_CTRL1, + RT5670_GP1_PIN_MASK, RT5670_GP1_PIN_IRQ); + snd_soc_update_bits(codec, RT5670_CJ_CTRL1, + RT5670_CBJ_BST1_EN, RT5670_CBJ_BST1_EN); + snd_soc_write(codec, RT5670_JD_CTRL3, 0x00f0); + snd_soc_update_bits(codec, RT5670_CJ_CTRL2, + RT5670_CBJ_MN_JD, RT5670_CBJ_MN_JD); + snd_soc_update_bits(codec, RT5670_CJ_CTRL2, + RT5670_CBJ_MN_JD, 0); + msleep(300); + val = snd_soc_read(codec, RT5670_CJ_CTRL3) & 0x7; + if (val == 0x1 || val == 0x2) { + rt5670->jack_type = SND_JACK_HEADSET; + /* for push button */ + snd_soc_update_bits(codec, RT5670_INT_IRQ_ST, 0x8, 0x8); + snd_soc_update_bits(codec, RT5670_IL_CMD, 0x40, 0x40); + snd_soc_read(codec, RT5670_IL_CMD); + } else { + snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x4); + rt5670->jack_type = SND_JACK_HEADPHONE; + snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power"); + snd_soc_dapm_sync(&codec->dapm); + } + } else { + snd_soc_update_bits(codec, RT5670_INT_IRQ_ST, 0x8, 0x0); + snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x4); + rt5670->jack_type = 0; + snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power"); + snd_soc_dapm_sync(&codec->dapm); + } + + return rt5670->jack_type; +} + +static int rt5670_button_detect(struct snd_soc_codec *codec) +{ + int btn_type, val; + + val = snd_soc_read(codec, RT5670_IL_CMD); + btn_type = val & 0xff80; + snd_soc_write(codec, RT5670_IL_CMD, val); + if (btn_type != 0) { + msleep(20); + val = snd_soc_read(codec, RT5670_IL_CMD); + snd_soc_write(codec, RT5670_IL_CMD, val); + } + + return btn_type; +} + +static int rt5670_irq_detection(void *data) +{ + struct rt5670_priv *rt5670 = (struct rt5670_priv *)data; + struct snd_soc_jack_gpio *gpio = &rt5670->hp_gpio; + struct snd_soc_jack *jack = rt5670->jack; + int val, btn_type, report = jack->status; + + if (rt5670->pdata.jd_mode == 1) /* 2 port */ + val = snd_soc_read(rt5670->codec, RT5670_A_JD_CTRL1) & 0x0070; + else + val = snd_soc_read(rt5670->codec, RT5670_A_JD_CTRL1) & 0x0020; + + switch (val) { + /* jack in */ + case 0x30: /* 2 port */ + case 0x0: /* 1 port or 2 port */ + if (rt5670->jack_type == 0) { + report = rt5670_headset_detect(rt5670->codec, 1); + /* for push button and jack out */ + gpio->debounce_time = 25; + break; + } + btn_type = 0; + if (snd_soc_read(rt5670->codec, RT5670_INT_IRQ_ST) & 0x4) { + /* button pressed */ + report = SND_JACK_HEADSET; + btn_type = rt5670_button_detect(rt5670->codec); + switch (btn_type) { + case 0x2000: /* up */ + report |= SND_JACK_BTN_1; + break; + case 0x0400: /* center */ + report |= SND_JACK_BTN_0; + break; + case 0x0080: /* down */ + report |= SND_JACK_BTN_2; + break; + default: + dev_err(rt5670->codec->dev, + "Unexpected button code 0x%04x\n", + btn_type); + break; + } + } + if (btn_type == 0)/* button release */ + report = rt5670->jack_type; + + break; + /* jack out */ + case 0x70: /* 2 port */ + case 0x10: /* 2 port */ + case 0x20: /* 1 port */ + report = 0; + snd_soc_update_bits(rt5670->codec, RT5670_INT_IRQ_ST, 0x1, 0x0); + rt5670_headset_detect(rt5670->codec, 0); + gpio->debounce_time = 150; /* for jack in */ + break; + default: + break; + } + + return report; +} + +int rt5670_set_jack_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *jack) +{ + struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); + int ret; + + rt5670->jack = jack; + rt5670->hp_gpio.gpiod_dev = codec->dev; + rt5670->hp_gpio.name = "headphone detect"; + rt5670->hp_gpio.report = SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2; + rt5670->hp_gpio.debounce_time = 150; + rt5670->hp_gpio.wake = true; + rt5670->hp_gpio.data = (struct rt5670_priv *)rt5670; + rt5670->hp_gpio.jack_status_check = rt5670_irq_detection; + + ret = snd_soc_jack_add_gpios(rt5670->jack, 1, + &rt5670->hp_gpio); + if (ret) { + dev_err(codec->dev, "Adding jack GPIO failed\n"); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(rt5670_set_jack_detect); + static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); @@ -2506,6 +2671,7 @@ static int rt5670_remove(struct snd_soc_codec *codec) struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); regmap_write(rt5670->regmap, RT5670_RESET, 0); + snd_soc_jack_free_gpios(rt5670->jack, 1, &rt5670->hp_gpio); return 0; } @@ -2665,6 +2831,7 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, if (dmi_check_system(dmi_platform_intel_braswell)) { rt5670->pdata.dmic_en = true; rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P; + rt5670->pdata.dev_gpio = true; rt5670->pdata.jd_mode = 1; } @@ -2706,12 +2873,17 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt5670->regmap, RT5670_IN2, RT5670_IN_DF2, RT5670_IN_DF2); - if (i2c->irq) { + if (rt5670->pdata.dev_gpio) { + /* for push button */ + regmap_write(rt5670->regmap, RT5670_IL_CMD, 0x0000); + regmap_write(rt5670->regmap, RT5670_IL_CMD2, 0x0010); + regmap_write(rt5670->regmap, RT5670_IL_CMD3, 0x0014); + /* for irq */ regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL1, RT5670_GP1_PIN_MASK, RT5670_GP1_PIN_IRQ); regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL2, RT5670_GP1_PF_MASK, RT5670_GP1_PF_OUT); - + regmap_update_bits(rt5670->regmap, RT5670_DIG_MISC, 0x8, 0x8); } if (rt5670->pdata.jd_mode) { diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h index 0a67adbcfbc3..0f3255aeeb9b 100644 --- a/sound/soc/codecs/rt5670.h +++ b/sound/soc/codecs/rt5670.h @@ -1988,6 +1988,8 @@ struct rt5670_priv { struct snd_soc_codec *codec; struct rt5670_platform_data pdata; struct regmap *regmap; + struct snd_soc_jack *jack; + struct snd_soc_jack_gpio hp_gpio; int sysclk; int sysclk_src; @@ -2004,4 +2006,6 @@ struct rt5670_priv { int jack_type; }; +int rt5670_set_jack_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *jack); #endif /* __RT5670_H__ */ From cc3c340d28b9f730fdc6bc5caa77e3bbd1e2377c Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 11 Mar 2015 11:42:45 +0800 Subject: [PATCH 06/32] ASoC: rt5670: export jack suspend/resume APIs We force enable "Mic Det Power" when a jack is inserted. Also, we set codec idle_bias_off = true. As a result, codec driver will not suspend as we expect. On Braswell, we don't need the jack detection when suspend but need it after resume, so export the jack suspend/resume APIs which are provided for machine driver to control during suspend/resume. Signed-off-by: Jie Yang Signed-off-by: Jin Yao Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 18 ++++++++++++++++++ sound/soc/codecs/rt5670.h | 3 +++ 2 files changed, 21 insertions(+) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index a900db5fb1d9..91d2069a9313 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -461,6 +461,24 @@ static int rt5670_headset_detect(struct snd_soc_codec *codec, int jack_insert) return rt5670->jack_type; } +void rt5670_jack_suspend(struct snd_soc_codec *codec) +{ + struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); + + rt5670->jack_type_saved = rt5670->jack_type; + rt5670_headset_detect(codec, 0); +} +EXPORT_SYMBOL_GPL(rt5670_jack_suspend); + +void rt5670_jack_resume(struct snd_soc_codec *codec) +{ + struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); + + if (rt5670->jack_type_saved) + rt5670_headset_detect(codec, 1); +} +EXPORT_SYMBOL_GPL(rt5670_jack_resume); + static int rt5670_button_detect(struct snd_soc_codec *codec) { int btn_type, val; diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h index 0f3255aeeb9b..dc2b46236c5c 100644 --- a/sound/soc/codecs/rt5670.h +++ b/sound/soc/codecs/rt5670.h @@ -2004,8 +2004,11 @@ struct rt5670_priv { int dsp_sw; /* expected parameter setting */ int dsp_rate; int jack_type; + int jack_type_saved; }; +void rt5670_jack_suspend(struct snd_soc_codec *codec); +void rt5670_jack_resume(struct snd_soc_codec *codec); int rt5670_set_jack_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack); #endif /* __RT5670_H__ */ From 9449d39b990d6d3d6386fbb92f3b86c808157b47 Mon Sep 17 00:00:00 2001 From: "Lu, Han" Date: Tue, 10 Mar 2015 10:41:20 +0800 Subject: [PATCH 07/32] ASoC: Intel: add function to load firmware image Add a general method to load firmware image, and apply to base firmware image loading. With the method, the driver will support loading multiple different modules in order to support different features. Signed-off-by: Lu, Han Signed-off-by: Mark Brown --- sound/soc/intel/sst-dsp-priv.h | 13 +++++ sound/soc/intel/sst-firmware.c | 1 + sound/soc/intel/sst-haswell-dsp.c | 1 + sound/soc/intel/sst-haswell-ipc.c | 83 ++++++++++++++++++++++++++++--- sound/soc/intel/sst-haswell-ipc.h | 6 +++ 5 files changed, 98 insertions(+), 6 deletions(-) diff --git a/sound/soc/intel/sst-dsp-priv.h b/sound/soc/intel/sst-dsp-priv.h index b9da030e312d..396d54510350 100644 --- a/sound/soc/intel/sst-dsp-priv.h +++ b/sound/soc/intel/sst-dsp-priv.h @@ -172,6 +172,16 @@ struct sst_module_runtime_context { u32 *buffer; }; +/* + * Audio DSP Module State + */ +enum sst_module_state { + SST_MODULE_STATE_UNLOADED = 0, /* default state */ + SST_MODULE_STATE_LOADED, + SST_MODULE_STATE_INITIALIZED, /* and inactive */ + SST_MODULE_STATE_ACTIVE, +}; + /* * Audio DSP Generic Module. * @@ -203,6 +213,9 @@ struct sst_module { struct list_head list; /* DSP list of modules */ struct list_head list_fw; /* FW list of modules */ struct list_head runtime_list; /* list of runtime module objects*/ + + /* state */ + enum sst_module_state state; }; /* diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/sst-firmware.c index 5f71ef607a57..5e5800897da2 100644 --- a/sound/soc/intel/sst-firmware.c +++ b/sound/soc/intel/sst-firmware.c @@ -498,6 +498,7 @@ struct sst_module *sst_module_new(struct sst_fw *sst_fw, sst_module->scratch_size = template->scratch_size; sst_module->persistent_size = template->persistent_size; sst_module->entry = template->entry; + sst_module->state = SST_MODULE_STATE_UNLOADED; INIT_LIST_HEAD(&sst_module->block_list); INIT_LIST_HEAD(&sst_module->runtime_list); diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c index 402b728c0a06..8ad733befbbd 100644 --- a/sound/soc/intel/sst-haswell-dsp.c +++ b/sound/soc/intel/sst-haswell-dsp.c @@ -169,6 +169,7 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, block = (void *)block + sizeof(*block) + block->size; } + mod->state = SST_MODULE_STATE_LOADED; return 0; } diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index 863a9ca34b8e..ec688f598320 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c @@ -1844,6 +1844,8 @@ int sst_hsw_dsp_runtime_resume(struct sst_hsw *hsw) if (ret < 0) dev_err(dev, "error: audio DSP boot failure\n"); + sst_hsw_init_module_state(hsw); + ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete, msecs_to_jiffies(IPC_BOOT_MSECS)); if (ret == 0) { @@ -1886,6 +1888,74 @@ struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw) return hsw->dsp; } +void sst_hsw_init_module_state(struct sst_hsw *hsw) +{ + struct sst_module *module; + enum sst_hsw_module_id id; + + /* the base fw contains several modules */ + for (id = SST_HSW_MODULE_BASE_FW; id < SST_HSW_MAX_MODULE_ID; id++) { + module = sst_module_get_from_id(hsw->dsp, id); + if (module) + module->state = SST_MODULE_STATE_ACTIVE; + } +} + +int sst_hsw_module_load(struct sst_hsw *hsw, + u32 module_id, u32 instance_id, char *name) +{ + int ret = 0; + const struct firmware *fw = NULL; + struct sst_fw *hsw_sst_fw; + struct sst_module *module; + struct device *dev = hsw->dev; + struct sst_dsp *dsp = hsw->dsp; + + dev_dbg(dev, "sst_hsw_module_load id=%d, name='%s'", module_id, name); + + module = sst_module_get_from_id(dsp, module_id); + if (module == NULL) { + /* loading for the first time */ + if (module_id == SST_HSW_MODULE_BASE_FW) { + /* for base module: use fw requested in acpi probe */ + fw = dsp->pdata->fw; + if (!fw) { + dev_err(dev, "request Base fw failed\n"); + return -ENODEV; + } + } else { + /* try and load any other optional modules if they are + * available. Use dev_info instead of dev_err in case + * request firmware failed */ + ret = request_firmware(&fw, name, dev); + if (ret) { + dev_info(dev, "fw image %s not available(%d)\n", + name, ret); + return ret; + } + } + hsw_sst_fw = sst_fw_new(dsp, fw, hsw); + if (hsw_sst_fw == NULL) { + dev_err(dev, "error: failed to load firmware\n"); + ret = -ENOMEM; + goto out; + } + module = sst_module_get_from_id(dsp, module_id); + if (module == NULL) { + dev_err(dev, "error: no module %d in firmware %s\n", + module_id, name); + } + } else + dev_info(dev, "module %d (%s) already loaded\n", + module_id, name); +out: + /* release fw, but base fw should be released by acpi driver */ + if (fw && module_id != SST_HSW_MODULE_BASE_FW) + release_firmware(fw); + + return ret; +} + static struct sst_dsp_device hsw_dev = { .thread = hsw_irq_thread, .ops = &haswell_ops, @@ -1947,12 +2017,10 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) /* keep the DSP in reset state for base FW loading */ sst_dsp_reset(hsw->dsp); - hsw->sst_fw = sst_fw_new(hsw->dsp, pdata->fw, hsw); - if (hsw->sst_fw == NULL) { - ret = -ENODEV; - dev_err(dev, "error: failed to load firmware\n"); + /* load base module and other modules in base firmware image */ + ret = sst_hsw_module_load(hsw, SST_HSW_MODULE_BASE_FW, 0, "Base"); + if (ret < 0) goto fw_err; - } /* allocate scratch mem regions */ ret = sst_block_alloc_scratch(hsw->dsp); @@ -1971,6 +2039,9 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) goto boot_err; } + /* init module state after boot */ + sst_hsw_init_module_state(hsw); + /* get the FW version */ sst_hsw_fw_get_version(hsw, &version); @@ -1986,7 +2057,7 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) boot_err: sst_dsp_reset(hsw->dsp); - sst_fw_free(hsw->sst_fw); + sst_fw_free_all(hsw->dsp); fw_err: dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE, hsw->dx_context, hsw->dx_context_paddr); diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h index 858096041cb1..e071b3a54eae 100644 --- a/sound/soc/intel/sst-haswell-ipc.h +++ b/sound/soc/intel/sst-haswell-ipc.h @@ -467,6 +467,12 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata); void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata); struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw); +/* fw module function */ +void sst_hsw_init_module_state(struct sst_hsw *hsw); + +int sst_hsw_module_load(struct sst_hsw *hsw, + u32 module_id, u32 instance_id, char *name); + /* runtime module management */ struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw, int mod_id, int offset); From 8c43fc2fdda0858879ee4dd7d7ed8e67890f699f Mon Sep 17 00:00:00 2001 From: "Lu, Han" Date: Tue, 10 Mar 2015 10:41:21 +0800 Subject: [PATCH 08/32] ASoC: Intel: add function to load sound effect module waves Try to load module waves and allocate runtime blocks for it if the firmware image of module waves exists. Signed-off-by: Lu, Han Signed-off-by: Mark Brown --- sound/soc/intel/sst-haswell-dsp.c | 2 ++ sound/soc/intel/sst-haswell-ipc.c | 23 +++++++++++++++++++++-- sound/soc/intel/sst-haswell-ipc.h | 1 + sound/soc/intel/sst-haswell-pcm.c | 21 +++++++++++++++++++-- 4 files changed, 43 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c index 8ad733befbbd..b3e957d46933 100644 --- a/sound/soc/intel/sst-haswell-dsp.c +++ b/sound/soc/intel/sst-haswell-dsp.c @@ -100,6 +100,7 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, && module->type != SST_HSW_MODULE_PCM && module->type != SST_HSW_MODULE_PCM_REFERENCE && module->type != SST_HSW_MODULE_PCM_CAPTURE + && module->type != SST_HSW_MODULE_WAVES && module->type != SST_HSW_MODULE_LPAL) return 0; @@ -139,6 +140,7 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, mod->type = SST_MEM_IRAM; break; case SST_HSW_DRAM: + case SST_HSW_REGS: ram = dsp->addr.lpe; mod->offset = block->ram_offset; mod->type = SST_MEM_DRAM; diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index ec688f598320..63740e36dd26 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c @@ -1896,11 +1896,27 @@ void sst_hsw_init_module_state(struct sst_hsw *hsw) /* the base fw contains several modules */ for (id = SST_HSW_MODULE_BASE_FW; id < SST_HSW_MAX_MODULE_ID; id++) { module = sst_module_get_from_id(hsw->dsp, id); - if (module) - module->state = SST_MODULE_STATE_ACTIVE; + if (module) { + /* module waves is active only after being enabled */ + if (id == SST_HSW_MODULE_WAVES) + module->state = SST_MODULE_STATE_INITIALIZED; + else + module->state = SST_MODULE_STATE_ACTIVE; + } } } +bool sst_hsw_is_module_loaded(struct sst_hsw *hsw, u32 module_id) +{ + struct sst_module *module; + + module = sst_module_get_from_id(hsw->dsp, module_id); + if (module == NULL || module->state == SST_MODULE_STATE_UNLOADED) + return false; + else + return true; +} + int sst_hsw_module_load(struct sst_hsw *hsw, u32 module_id, u32 instance_id, char *name) { @@ -2022,6 +2038,9 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) if (ret < 0) goto fw_err; + /* try to load module waves */ + sst_hsw_module_load(hsw, SST_HSW_MODULE_WAVES, 0, "intel/IntcPP01.bin"); + /* allocate scratch mem regions */ ret = sst_block_alloc_scratch(hsw->dsp); if (ret < 0) diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h index e071b3a54eae..208724b74cf7 100644 --- a/sound/soc/intel/sst-haswell-ipc.h +++ b/sound/soc/intel/sst-haswell-ipc.h @@ -469,6 +469,7 @@ struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw); /* fw module function */ void sst_hsw_init_module_state(struct sst_hsw *hsw); +bool sst_hsw_is_module_loaded(struct sst_hsw *hsw, u32 module_id); int sst_hsw_module_load(struct sst_hsw *hsw, u32 module_id, u32 instance_id, char *name); diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 7e21e8f85885..a604cc442111 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c @@ -807,6 +807,17 @@ static int hsw_pcm_create_modules(struct hsw_priv_data *pdata) pcm_data->runtime->persistent_offset; } + /* create runtime blocks for module waves */ + if (sst_hsw_is_module_loaded(hsw, SST_HSW_MODULE_WAVES)) { + pcm_data = &pdata->pcm[HSW_PCM_COUNT-1][0]; + pcm_data->runtime = sst_hsw_runtime_module_create(hsw, + SST_HSW_MODULE_WAVES, pcm_data->persistent_offset); + if (pcm_data->runtime == NULL) + goto err; + pcm_data->persistent_offset = + pcm_data->runtime->persistent_offset; + } + return 0; err: @@ -820,12 +831,16 @@ err: static void hsw_pcm_free_modules(struct hsw_priv_data *pdata) { + struct sst_hsw *hsw = pdata->hsw; struct hsw_pcm_data *pcm_data; int i; for (i = 0; i < ARRAY_SIZE(mod_map); i++) { pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; - + sst_hsw_runtime_module_free(pcm_data->runtime); + } + if (sst_hsw_is_module_loaded(hsw, SST_HSW_MODULE_WAVES)) { + pcm_data = &pdata->pcm[HSW_PCM_COUNT-1][0]; sst_hsw_runtime_module_free(pcm_data->runtime); } } @@ -984,7 +999,9 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) } /* allocate runtime modules */ - hsw_pcm_create_modules(priv_data); + ret = hsw_pcm_create_modules(priv_data); + if (ret < 0) + goto err; /* enable runtime PM with auto suspend */ pm_runtime_set_autosuspend_delay(platform->dev, From e8e79ede44ec99e09f8604c23ee99dc25065a343 Mon Sep 17 00:00:00 2001 From: "Lu, Han" Date: Tue, 10 Mar 2015 10:41:22 +0800 Subject: [PATCH 09/32] ASoC: Intel: add function to enable/disable sound effect module waves Signed-off-by: Lu, Han Signed-off-by: Mark Brown --- sound/soc/intel/sst-haswell-ipc.c | 175 ++++++++++++++++++++++++++++++ sound/soc/intel/sst-haswell-ipc.h | 11 ++ 2 files changed, 186 insertions(+) diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index 63740e36dd26..265d754a4090 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c @@ -79,6 +79,15 @@ #define IPC_LOG_ID_MASK (0xf << IPC_LOG_ID_SHIFT) #define IPC_LOG_ID(x) (x << IPC_LOG_ID_SHIFT) +/* Module Message */ +#define IPC_MODULE_OPERATION_SHIFT 20 +#define IPC_MODULE_OPERATION_MASK (0xf << IPC_MODULE_OPERATION_SHIFT) +#define IPC_MODULE_OPERATION(x) (x << IPC_MODULE_OPERATION_SHIFT) + +#define IPC_MODULE_ID_SHIFT 16 +#define IPC_MODULE_ID_MASK (0xf << IPC_MODULE_ID_SHIFT) +#define IPC_MODULE_ID(x) (x << IPC_MODULE_ID_SHIFT) + /* IPC message timeout (msecs) */ #define IPC_TIMEOUT_MSECS 300 #define IPC_BOOT_MSECS 200 @@ -115,6 +124,7 @@ enum ipc_glb_type { IPC_GLB_ENTER_DX_STATE = 12, IPC_GLB_GET_MIXER_STREAM_INFO = 13, /* Request mixer stream params */ IPC_GLB_DEBUG_LOG_MESSAGE = 14, /* Message to or from the debug logger. */ + IPC_GLB_MODULE_OPERATION = 15, /* Message to loadable fw module */ IPC_GLB_REQUEST_TRANSFER = 16, /* < Request Transfer for host */ IPC_GLB_MAX_IPC_MESSAGE_TYPE = 17, /* Maximum message number */ }; @@ -133,6 +143,16 @@ enum ipc_glb_reply { IPC_GLB_REPLY_SOURCE_NOT_STARTED = 10, /* Source was not started. */ }; +enum ipc_module_operation { + IPC_MODULE_NOTIFICATION = 0, + IPC_MODULE_ENABLE = 1, + IPC_MODULE_DISABLE = 2, + IPC_MODULE_GET_PARAMETER = 3, + IPC_MODULE_SET_PARAMETER = 4, + IPC_MODULE_GET_INFO = 5, + IPC_MODULE_MAX_MESSAGE +}; + /* Stream Message - Types */ enum ipc_str_operation { IPC_STR_RESET = 0, @@ -352,6 +372,16 @@ static inline u32 msg_get_notify_reason(u32 msg) return (msg & IPC_STG_TYPE_MASK) >> IPC_STG_TYPE_SHIFT; } +static inline u32 msg_get_module_operation(u32 msg) +{ + return (msg & IPC_MODULE_OPERATION_MASK) >> IPC_MODULE_OPERATION_SHIFT; +} + +static inline u32 msg_get_module_id(u32 msg) +{ + return (msg & IPC_MODULE_ID_MASK) >> IPC_MODULE_ID_SHIFT; +} + u32 create_channel_map(enum sst_hsw_channel_config config) { switch (config) { @@ -795,6 +825,31 @@ static int hsw_process_reply(struct sst_hsw *hsw, u32 header) return 1; } +static int hsw_module_message(struct sst_hsw *hsw, u32 header) +{ + u32 operation, module_id; + int handled = 0; + + operation = msg_get_module_operation(header); + module_id = msg_get_module_id(header); + dev_dbg(hsw->dev, "received module message header: 0x%8.8x\n", + header); + dev_dbg(hsw->dev, "operation: 0x%8.8x module_id: 0x%8.8x\n", + operation, module_id); + + switch (operation) { + case IPC_MODULE_NOTIFICATION: + dev_dbg(hsw->dev, "module notification received"); + handled = 1; + break; + default: + handled = hsw_process_reply(hsw, header); + break; + } + + return handled; +} + static int hsw_stream_message(struct sst_hsw *hsw, u32 header) { u32 stream_msg, stream_id, stage_type; @@ -890,6 +945,9 @@ static int hsw_process_notification(struct sst_hsw *hsw) case IPC_GLB_DEBUG_LOG_MESSAGE: handled = hsw_log_message(hsw, header); break; + case IPC_GLB_MODULE_OPERATION: + handled = hsw_module_message(hsw, header); + break; default: dev_err(hsw->dev, "error: unexpected type %d hdr 0x%8.8x\n", type, header); @@ -1917,6 +1975,17 @@ bool sst_hsw_is_module_loaded(struct sst_hsw *hsw, u32 module_id) return true; } +bool sst_hsw_is_module_active(struct sst_hsw *hsw, u32 module_id) +{ + struct sst_module *module; + + module = sst_module_get_from_id(hsw->dsp, module_id); + if (module != NULL && module->state == SST_MODULE_STATE_ACTIVE) + return true; + else + return false; +} + int sst_hsw_module_load(struct sst_hsw *hsw, u32 module_id, u32 instance_id, char *name) { @@ -1972,6 +2041,112 @@ out: return ret; } +int sst_hsw_module_enable(struct sst_hsw *hsw, + u32 module_id, u32 instance_id) +{ + int ret; + u32 header = 0; + struct sst_hsw_ipc_module_config config; + struct sst_module *module; + struct sst_module_runtime *runtime; + struct device *dev = hsw->dev; + struct sst_dsp *dsp = hsw->dsp; + + if (!sst_hsw_is_module_loaded(hsw, module_id)) { + dev_dbg(dev, "module %d not loaded\n", module_id); + return 0; + } + + if (sst_hsw_is_module_active(hsw, module_id)) { + dev_info(dev, "module %d already enabled\n", module_id); + return 0; + } + + module = sst_module_get_from_id(dsp, module_id); + if (module == NULL) { + dev_err(dev, "module %d not valid\n", module_id); + return -ENXIO; + } + + runtime = sst_module_runtime_get_from_id(module, module_id); + if (runtime == NULL) { + dev_err(dev, "runtime %d not valid", module_id); + return -ENXIO; + } + + header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) | + IPC_MODULE_OPERATION(IPC_MODULE_ENABLE) | + IPC_MODULE_ID(module_id); + dev_dbg(dev, "module enable header: %x\n", header); + + config.map.module_entries_count = 1; + config.map.module_entries[0].module_id = module->id; + config.map.module_entries[0].entry_point = module->entry; + + config.persistent_mem.offset = + sst_dsp_get_offset(dsp, + runtime->persistent_offset, SST_MEM_DRAM); + config.persistent_mem.size = module->persistent_size; + + config.scratch_mem.offset = + sst_dsp_get_offset(dsp, + dsp->scratch_offset, SST_MEM_DRAM); + config.scratch_mem.size = module->scratch_size; + dev_dbg(dev, "mod %d enable p:%d @ %x, s:%d @ %x, ep: %x", + config.map.module_entries[0].module_id, + config.persistent_mem.size, + config.persistent_mem.offset, + config.scratch_mem.size, config.scratch_mem.offset, + config.map.module_entries[0].entry_point); + + ret = ipc_tx_message_wait(hsw, header, + &config, sizeof(config), NULL, 0); + if (ret < 0) + dev_err(dev, "ipc: module enable failed - %d\n", ret); + else + module->state = SST_MODULE_STATE_ACTIVE; + + return ret; +} + +int sst_hsw_module_disable(struct sst_hsw *hsw, + u32 module_id, u32 instance_id) +{ + int ret; + u32 header; + struct sst_module *module; + struct device *dev = hsw->dev; + struct sst_dsp *dsp = hsw->dsp; + + if (!sst_hsw_is_module_loaded(hsw, module_id)) { + dev_dbg(dev, "module %d not loaded\n", module_id); + return 0; + } + + if (!sst_hsw_is_module_active(hsw, module_id)) { + dev_info(dev, "module %d already disabled\n", module_id); + return 0; + } + + module = sst_module_get_from_id(dsp, module_id); + if (module == NULL) { + dev_err(dev, "module %d not valid\n", module_id); + return -ENXIO; + } + + header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) | + IPC_MODULE_OPERATION(IPC_MODULE_DISABLE) | + IPC_MODULE_ID(module_id); + + ret = ipc_tx_message_wait(hsw, header, NULL, 0, NULL, 0); + if (ret < 0) + dev_err(dev, "module disable failed - %d\n", ret); + else + module->state = SST_MODULE_STATE_INITIALIZED; + + return ret; +} + static struct sst_dsp_device hsw_dev = { .thread = hsw_irq_thread, .ops = &haswell_ops, diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h index 208724b74cf7..30c65b28fa60 100644 --- a/sound/soc/intel/sst-haswell-ipc.h +++ b/sound/soc/intel/sst-haswell-ipc.h @@ -215,6 +215,12 @@ struct sst_hsw_fx_enable { struct sst_hsw_memory_info persistent_mem; } __attribute__((packed)); +struct sst_hsw_ipc_module_config { + struct sst_hsw_module_map map; + struct sst_hsw_memory_info persistent_mem; + struct sst_hsw_memory_info scratch_mem; +} __attribute__((packed)); + struct sst_hsw_get_fx_param { u32 parameter_id; u32 param_size; @@ -470,9 +476,14 @@ struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw); /* fw module function */ void sst_hsw_init_module_state(struct sst_hsw *hsw); bool sst_hsw_is_module_loaded(struct sst_hsw *hsw, u32 module_id); +bool sst_hsw_is_module_active(struct sst_hsw *hsw, u32 module_id); int sst_hsw_module_load(struct sst_hsw *hsw, u32 module_id, u32 instance_id, char *name); +int sst_hsw_module_enable(struct sst_hsw *hsw, + u32 module_id, u32 instance_id); +int sst_hsw_module_disable(struct sst_hsw *hsw, + u32 module_id, u32 instance_id); /* runtime module management */ struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw, From 66454b3eb31e8109387606c054ae02f3cfd6543e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 15 Jan 2015 12:52:15 +0100 Subject: [PATCH 10/32] ASoC: rt5670: Replace w->codec snd_soc_dapm_to_codec(w->dapm) The codec field of the snd_soc_widget struct is eventually going to be removed, use snd_soc_dapm_to_codec(w->dapm) instead. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 91d2069a9313..cc7f84a150a7 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -699,7 +699,7 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w, static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink) { - struct snd_soc_codec *codec = source->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); if (rt5670->sysclk_src == RT5670_SCLK_S_PLL1) From 76c07b8265c68d9a89fb4c0a634e373a087f11be Mon Sep 17 00:00:00 2001 From: "Lu, Han" Date: Thu, 12 Mar 2015 13:53:00 +0800 Subject: [PATCH 11/32] ASoC: Intel: add kcontrol to enable/disable sound effect module waves Add kcontrol to enable/disable module waves. IPC is valid only when module is loaded. Also track module state over suspend so it's state can be restored on resume. Signed-off-by: Lu, Han Signed-off-by: Mark Brown --- sound/soc/intel/sst-haswell-ipc.c | 19 +++++++++ sound/soc/intel/sst-haswell-ipc.h | 3 ++ sound/soc/intel/sst-haswell-pcm.c | 68 +++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+) diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index 265d754a4090..ebca9035efce 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c @@ -337,6 +337,10 @@ struct sst_hsw { /* FW log stream */ struct sst_hsw_log_stream log_stream; + + /* flags bit field to track module state when resume from RTD3, + * each bit represent state (enabled/disabled) of single module */ + u32 enabled_modules_rtd3; }; #define CREATE_TRACE_POINTS @@ -1986,6 +1990,21 @@ bool sst_hsw_is_module_active(struct sst_hsw *hsw, u32 module_id) return false; } +void sst_hsw_set_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id) +{ + hsw->enabled_modules_rtd3 |= (1 << module_id); +} + +void sst_hsw_set_module_disabled_rtd3(struct sst_hsw *hsw, u32 module_id) +{ + hsw->enabled_modules_rtd3 &= ~(1 << module_id); +} + +bool sst_hsw_is_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id) +{ + return hsw->enabled_modules_rtd3 & (1 << module_id); +} + int sst_hsw_module_load(struct sst_hsw *hsw, u32 module_id, u32 instance_id, char *name) { diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h index 30c65b28fa60..48290a1cfe5d 100644 --- a/sound/soc/intel/sst-haswell-ipc.h +++ b/sound/soc/intel/sst-haswell-ipc.h @@ -477,6 +477,9 @@ struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw); void sst_hsw_init_module_state(struct sst_hsw *hsw); bool sst_hsw_is_module_loaded(struct sst_hsw *hsw, u32 module_id); bool sst_hsw_is_module_active(struct sst_hsw *hsw, u32 module_id); +void sst_hsw_set_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id); +void sst_hsw_set_module_disabled_rtd3(struct sst_hsw *hsw, u32 module_id); +bool sst_hsw_is_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id); int sst_hsw_module_load(struct sst_hsw *hsw, u32 module_id, u32 instance_id, char *name); diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index a604cc442111..b3de87aac373 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c @@ -318,6 +318,54 @@ static int hsw_volume_get(struct snd_kcontrol *kcontrol, return 0; } +static int hsw_waves_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); + struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); + struct sst_hsw *hsw = pdata->hsw; + enum sst_hsw_module_id id = SST_HSW_MODULE_WAVES; + + ucontrol->value.integer.value[0] = + (sst_hsw_is_module_active(hsw, id) || + sst_hsw_is_module_enabled_rtd3(hsw, id)); + return 0; +} + +static int hsw_waves_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); + struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); + struct sst_hsw *hsw = pdata->hsw; + int ret = 0; + enum sst_hsw_module_id id = SST_HSW_MODULE_WAVES; + bool switch_on = (bool)ucontrol->value.integer.value[0]; + + /* if module is in RAM on the DSP, apply user settings to module through + * ipc. If module is not in RAM on the DSP, store user setting for + * track */ + if (sst_hsw_is_module_loaded(hsw, id)) { + if (switch_on == sst_hsw_is_module_active(hsw, id)) + return 0; + + if (switch_on) + ret = sst_hsw_module_enable(hsw, id, 0); + else + ret = sst_hsw_module_disable(hsw, id, 0); + } else { + if (switch_on == sst_hsw_is_module_enabled_rtd3(hsw, id)) + return 0; + + if (switch_on) + sst_hsw_set_module_enabled_rtd3(hsw, id); + else + sst_hsw_set_module_disabled_rtd3(hsw, id); + } + + return ret; +} + /* TLV used by both global and stream volumes */ static const DECLARE_TLV_DB_SCALE(hsw_vol_tlv, -9000, 300, 1); @@ -339,6 +387,9 @@ static const struct snd_kcontrol_new hsw_volume_controls[] = { SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 4, 0, 8, ARRAY_SIZE(volume_map) - 1, 0, hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), + /* enable/disable module waves */ + SOC_SINGLE_BOOL_EXT("Waves Switch", 0, + hsw_waves_switch_get, hsw_waves_switch_put), }; /* Create DMA buffer page table for DSP */ @@ -1118,10 +1169,18 @@ static int hsw_pcm_runtime_suspend(struct device *dev) { struct hsw_priv_data *pdata = dev_get_drvdata(dev); struct sst_hsw *hsw = pdata->hsw; + int ret; if (pdata->pm_state >= HSW_PM_STATE_RTD3) return 0; + /* fw modules will be unloaded on RTD3, set flag to track */ + if (sst_hsw_is_module_active(hsw, SST_HSW_MODULE_WAVES)) { + ret = sst_hsw_module_disable(hsw, SST_HSW_MODULE_WAVES, 0); + if (ret < 0) + return ret; + sst_hsw_set_module_enabled_rtd3(hsw, SST_HSW_MODULE_WAVES); + } sst_hsw_dsp_runtime_suspend(hsw); sst_hsw_dsp_runtime_sleep(hsw); pdata->pm_state = HSW_PM_STATE_RTD3; @@ -1156,6 +1215,15 @@ static int hsw_pcm_runtime_resume(struct device *dev) else if (ret == 1) /* no action required */ return 0; + /* check flag when resume */ + if (sst_hsw_is_module_enabled_rtd3(hsw, SST_HSW_MODULE_WAVES)) { + ret = sst_hsw_module_enable(hsw, SST_HSW_MODULE_WAVES, 0); + if (ret < 0) + return ret; + /* unset flag */ + sst_hsw_set_module_disabled_rtd3(hsw, SST_HSW_MODULE_WAVES); + } + pdata->pm_state = HSW_PM_STATE_D0; return ret; } From 201892268b8335ae8c9dc7cc9a0d4bf6e1336f0e Mon Sep 17 00:00:00 2001 From: "Lu, Han" Date: Thu, 12 Mar 2015 13:53:01 +0800 Subject: [PATCH 12/32] ASoC: Intel: add function to set parameter to sound effect module waves Add function to set parameters to module waves. The parameters can be set only when module is enabled, and parameter size is limited to 500 Bytes. Signed-off-by: Lu, Han Signed-off-by: Mark Brown --- sound/soc/intel/sst-haswell-ipc.c | 59 +++++++++++++++++++++++++++++++ sound/soc/intel/sst-haswell-ipc.h | 26 ++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index ebca9035efce..a97324dff8fa 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c @@ -2166,6 +2166,65 @@ int sst_hsw_module_disable(struct sst_hsw *hsw, return ret; } +int sst_hsw_module_set_param(struct sst_hsw *hsw, + u32 module_id, u32 instance_id, u32 parameter_id, + u32 param_size, char *param) +{ + int ret; + unsigned char *data = NULL; + u32 header = 0; + u32 payload_size = 0, transfer_parameter_size = 0; + dma_addr_t dma_addr = 0; + struct sst_hsw_transfer_parameter *parameter; + struct device *dev = hsw->dev; + + header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) | + IPC_MODULE_OPERATION(IPC_MODULE_SET_PARAMETER) | + IPC_MODULE_ID(module_id); + dev_dbg(dev, "sst_hsw_module_set_param header=%x\n", header); + + payload_size = param_size + + sizeof(struct sst_hsw_transfer_parameter) - + sizeof(struct sst_hsw_transfer_list); + dev_dbg(dev, "parameter size : %d\n", param_size); + dev_dbg(dev, "payload size : %d\n", payload_size); + + if (payload_size <= SST_HSW_IPC_MAX_SHORT_PARAMETER_SIZE) { + /* short parameter, mailbox can contain data */ + dev_dbg(dev, "transfer parameter size : %d\n", + transfer_parameter_size); + + transfer_parameter_size = ALIGN(payload_size, 4); + dev_dbg(dev, "transfer parameter aligned size : %d\n", + transfer_parameter_size); + + parameter = kzalloc(transfer_parameter_size, GFP_KERNEL); + if (parameter == NULL) + return -ENOMEM; + + memcpy(parameter->data, param, param_size); + } else { + dev_warn(dev, "transfer parameter size too large!"); + return 0; + } + + parameter->parameter_id = parameter_id; + parameter->data_size = param_size; + + ret = ipc_tx_message_wait(hsw, header, + parameter, transfer_parameter_size , NULL, 0); + if (ret < 0) + dev_err(dev, "ipc: module set parameter failed - %d\n", ret); + + kfree(parameter); + + if (data) + dma_free_coherent(hsw->dsp->dma_dev, + param_size, (void *)data, dma_addr); + + return ret; +} + static struct sst_dsp_device hsw_dev = { .thread = hsw_irq_thread, .ops = &haswell_ops, diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h index 48290a1cfe5d..16bec433265c 100644 --- a/sound/soc/intel/sst-haswell-ipc.h +++ b/sound/soc/intel/sst-haswell-ipc.h @@ -37,6 +37,7 @@ #define SST_HSW_IPC_MAX_PAYLOAD_SIZE 400 #define SST_HSW_MAX_INFO_SIZE 64 #define SST_HSW_BUILD_HASH_LENGTH 40 +#define SST_HSW_IPC_MAX_SHORT_PARAMETER_SIZE 500 struct sst_hsw; struct sst_hsw_stream; @@ -187,6 +188,28 @@ enum sst_hsw_performance_action { SST_HSW_PERF_STOP = 1, }; +struct sst_hsw_transfer_info { + uint32_t destination; /* destination address */ + uint32_t reverse:1; /* if 1 data flows from destination */ + uint32_t size:31; /* transfer size in bytes.*/ + uint16_t first_page_offset; /* offset to data in the first page. */ + uint8_t packed_pages; /* page addresses. Each occupies 20 bits */ +} __attribute__((packed)); + +struct sst_hsw_transfer_list { + uint32_t transfers_count; + struct sst_hsw_transfer_info transfers; +} __attribute__((packed)); + +struct sst_hsw_transfer_parameter { + uint32_t parameter_id; + uint32_t data_size; + union { + uint8_t data[1]; + struct sst_hsw_transfer_list transfer_list; + }; +} __attribute__((packed)); + /* SST firmware module info */ struct sst_hsw_module_info { u8 name[SST_HSW_MAX_INFO_SIZE]; @@ -487,6 +510,9 @@ int sst_hsw_module_enable(struct sst_hsw *hsw, u32 module_id, u32 instance_id); int sst_hsw_module_disable(struct sst_hsw *hsw, u32 module_id, u32 instance_id); +int sst_hsw_module_set_param(struct sst_hsw *hsw, + u32 module_id, u32 instance_id, u32 parameter_id, + u32 param_size, char *param); /* runtime module management */ struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw, From 3814c204446822cd3c82ec4e8616600732c1f94e Mon Sep 17 00:00:00 2001 From: "Lu, Han" Date: Thu, 12 Mar 2015 13:53:02 +0800 Subject: [PATCH 13/32] ASoC: Intel: add kcontrol to set parameter to sound effect module waves Each kcontrol command includes a line of parameters up to 128 bytes. kcontrol command to set param: cset "name='Waves Set Param' <0x01,0xff,...>" or cset-bin-file "name='Waves Set Param' " The parameter lines are stored in a buffer array, so can be read back from buffer rather than from DSP, and be relaunched to DSP when resume from RTD3. The buffer size is 160 parameter lines. kcontrol command to reset the buffer: cset "name='Waves Set Param' 0xff" alsa-lib v1.0.29 or commit 6ea14c36 and f47480af are required to support the kcontrol commands. Signed-off-by: Lu, Han Signed-off-by: Mark Brown --- sound/soc/intel/sst-haswell-ipc.c | 64 +++++++++++++++++++++++++++++++ sound/soc/intel/sst-haswell-ipc.h | 6 +++ sound/soc/intel/sst-haswell-pcm.c | 50 ++++++++++++++++++++++++ 3 files changed, 120 insertions(+) diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index a97324dff8fa..43fb5f339168 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c @@ -341,6 +341,11 @@ struct sst_hsw { /* flags bit field to track module state when resume from RTD3, * each bit represent state (enabled/disabled) of single module */ u32 enabled_modules_rtd3; + + /* buffer to store parameter lines */ + u32 param_idx_w; /* write index */ + u32 param_idx_r; /* read index */ + u8 param_buf[WAVES_PARAM_LINES][WAVES_PARAM_COUNT]; }; #define CREATE_TRACE_POINTS @@ -2005,6 +2010,62 @@ bool sst_hsw_is_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id) return hsw->enabled_modules_rtd3 & (1 << module_id); } +void sst_hsw_reset_param_buf(struct sst_hsw *hsw) +{ + hsw->param_idx_w = 0; + hsw->param_idx_r = 0; + memset((void *)hsw->param_buf, 0, sizeof(hsw->param_buf)); +} + +int sst_hsw_store_param_line(struct sst_hsw *hsw, u8 *buf) +{ + /* save line to the first available position of param buffer */ + if (hsw->param_idx_w > WAVES_PARAM_LINES - 1) { + dev_warn(hsw->dev, "warning: param buffer overflow!\n"); + return -EPERM; + } + memcpy(hsw->param_buf[hsw->param_idx_w], buf, WAVES_PARAM_COUNT); + hsw->param_idx_w++; + return 0; +} + +int sst_hsw_load_param_line(struct sst_hsw *hsw, u8 *buf) +{ + u8 id = 0; + + /* read the first matching line from param buffer */ + while (hsw->param_idx_r < WAVES_PARAM_LINES) { + id = hsw->param_buf[hsw->param_idx_r][0]; + hsw->param_idx_r++; + if (buf[0] == id) { + memcpy(buf, hsw->param_buf[hsw->param_idx_r], + WAVES_PARAM_COUNT); + break; + } + } + if (hsw->param_idx_r > WAVES_PARAM_LINES - 1) { + dev_dbg(hsw->dev, "end of buffer, roll to the beginning\n"); + hsw->param_idx_r = 0; + return 0; + } + return 0; +} + +int sst_hsw_launch_param_buf(struct sst_hsw *hsw) +{ + int ret, idx; + + /* put all param lines to DSP through ipc */ + for (idx = 0; idx < hsw->param_idx_w; idx++) { + ret = sst_hsw_module_set_param(hsw, + SST_HSW_MODULE_WAVES, 0, hsw->param_buf[idx][0], + WAVES_PARAM_COUNT, hsw->param_buf[idx]); + if (ret < 0) + return ret; + } + return 0; +} + int sst_hsw_module_load(struct sst_hsw *hsw, u32 module_id, u32 instance_id, char *name) { @@ -2299,6 +2360,9 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) if (ret < 0) goto boot_err; + /* init param buffer */ + sst_hsw_reset_param_buf(hsw); + /* wait for DSP boot completion */ sst_dsp_boot(hsw->dsp); ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete, diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h index 16bec433265c..06d71aefa1fe 100644 --- a/sound/soc/intel/sst-haswell-ipc.h +++ b/sound/soc/intel/sst-haswell-ipc.h @@ -38,6 +38,8 @@ #define SST_HSW_MAX_INFO_SIZE 64 #define SST_HSW_BUILD_HASH_LENGTH 40 #define SST_HSW_IPC_MAX_SHORT_PARAMETER_SIZE 500 +#define WAVES_PARAM_COUNT 128 +#define WAVES_PARAM_LINES 160 struct sst_hsw; struct sst_hsw_stream; @@ -503,6 +505,10 @@ bool sst_hsw_is_module_active(struct sst_hsw *hsw, u32 module_id); void sst_hsw_set_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id); void sst_hsw_set_module_disabled_rtd3(struct sst_hsw *hsw, u32 module_id); bool sst_hsw_is_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id); +void sst_hsw_reset_param_buf(struct sst_hsw *hsw); +int sst_hsw_store_param_line(struct sst_hsw *hsw, u8 *buf); +int sst_hsw_load_param_line(struct sst_hsw *hsw, u8 *buf); +int sst_hsw_launch_param_buf(struct sst_hsw *hsw); int sst_hsw_module_load(struct sst_hsw *hsw, u32 module_id, u32 instance_id, char *name); diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index b3de87aac373..b40ec746bc19 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c @@ -366,6 +366,49 @@ static int hsw_waves_switch_put(struct snd_kcontrol *kcontrol, return ret; } +static int hsw_waves_param_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); + struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); + struct sst_hsw *hsw = pdata->hsw; + + /* return a matching line from param buffer */ + return sst_hsw_load_param_line(hsw, ucontrol->value.bytes.data); +} + +static int hsw_waves_param_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); + struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); + struct sst_hsw *hsw = pdata->hsw; + int ret; + enum sst_hsw_module_id id = SST_HSW_MODULE_WAVES; + int param_id = ucontrol->value.bytes.data[0]; + int param_size = WAVES_PARAM_COUNT; + + /* clear param buffer and reset buffer index */ + if (param_id == 0xFF) { + sst_hsw_reset_param_buf(hsw); + return 0; + } + + /* store params into buffer */ + ret = sst_hsw_store_param_line(hsw, ucontrol->value.bytes.data); + if (ret < 0) + return ret; + + if (sst_hsw_is_module_loaded(hsw, id)) { + if (!sst_hsw_is_module_active(hsw, id)) + return 0; + + ret = sst_hsw_module_set_param(hsw, id, 0, param_id, + param_size, ucontrol->value.bytes.data); + } + return ret; +} + /* TLV used by both global and stream volumes */ static const DECLARE_TLV_DB_SCALE(hsw_vol_tlv, -9000, 300, 1); @@ -390,6 +433,9 @@ static const struct snd_kcontrol_new hsw_volume_controls[] = { /* enable/disable module waves */ SOC_SINGLE_BOOL_EXT("Waves Switch", 0, hsw_waves_switch_get, hsw_waves_switch_put), + /* set parameters to module waves */ + SND_SOC_BYTES_EXT("Waves Set Param", WAVES_PARAM_COUNT, + hsw_waves_param_get, hsw_waves_param_put), }; /* Create DMA buffer page table for DSP */ @@ -1218,6 +1264,10 @@ static int hsw_pcm_runtime_resume(struct device *dev) /* check flag when resume */ if (sst_hsw_is_module_enabled_rtd3(hsw, SST_HSW_MODULE_WAVES)) { ret = sst_hsw_module_enable(hsw, SST_HSW_MODULE_WAVES, 0); + if (ret < 0) + return ret; + /* put parameters from buffer to dsp */ + ret = sst_hsw_launch_param_buf(hsw); if (ret < 0) return ret; /* unset flag */ From 066d7b87fa11213d7eca7af8fdd8447e1c62117b Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Tue, 17 Mar 2015 10:23:30 +0800 Subject: [PATCH 14/32] ASoC: Intel: Add suspend_pre and resume_post for Braswell snd_soc_card On Braswell, we need to add some machine specific setting before suspend and after resume. For example, disable/enable jack detection in codec so use snd_soc_card suspend_pre and resume_post ops for this purpose. Signed-off-by: Jin Yao Signed-off-by: Mark Brown --- sound/soc/intel/cht_bsw_rt5672.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c index 279df4c43de1..c41fae3eb9ca 100644 --- a/sound/soc/intel/cht_bsw_rt5672.c +++ b/sound/soc/intel/cht_bsw_rt5672.c @@ -267,6 +267,35 @@ static struct snd_soc_dai_link cht_dailink[] = { }, }; +static int cht_suspend_pre(struct snd_soc_card *card) +{ + struct snd_soc_codec *codec; + + list_for_each_entry(codec, &card->codec_dev_list, card_list) { + if (!strcmp(codec->component.name, "i2c-10EC5670:00")) { + dev_dbg(codec->dev, "disabling jack detect before going to suspend.\n"); + rt5670_jack_suspend(codec); + break; + } + } + return 0; +} + +static int cht_resume_post(struct snd_soc_card *card) +{ + struct snd_soc_codec *codec; + + list_for_each_entry(codec, &card->codec_dev_list, card_list) { + if (!strcmp(codec->component.name, "i2c-10EC5670:00")) { + dev_dbg(codec->dev, "enabling jack detect for resume.\n"); + rt5670_jack_resume(codec); + break; + } + } + + return 0; +} + /* SoC card */ static struct snd_soc_card snd_soc_card_cht = { .name = "cherrytrailcraudio", @@ -278,6 +307,8 @@ static struct snd_soc_card snd_soc_card_cht = { .num_dapm_routes = ARRAY_SIZE(cht_audio_map), .controls = cht_mc_controls, .num_controls = ARRAY_SIZE(cht_mc_controls), + .suspend_pre = cht_suspend_pre, + .resume_post = cht_resume_post, }; static int snd_cht_mc_probe(struct platform_device *pdev) From 6b3b58d97fb2d03f8f1d009a77baece311aa0d16 Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Tue, 17 Mar 2015 10:23:31 +0800 Subject: [PATCH 15/32] ASoC: Intel: move the jack creation to Braswell machine driver The jack creation code was in rt5670 codec driver before due to the jack resources (gpio/irq) were defined under the node of codec device in ACPI on Braswell. We used the snd_soc_jack_new() to create a jack instance. But now snd_soc_jack_new() is removed from upstream and we can't use snd_soc_card_jack_new() in codec driver, so we move the jack creation code to machine driver and pass the jack instance to codec driver for further processing. Signed-off-by: Bard Liao Signed-off-by: Jin Yao Signed-off-by: Mark Brown --- sound/soc/intel/cht_bsw_rt5672.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c index c41fae3eb9ca..4204fc4f1bad 100644 --- a/sound/soc/intel/cht_bsw_rt5672.c +++ b/sound/soc/intel/cht_bsw_rt5672.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "../codecs/rt5670.h" #include "sst-atom-controls.h" @@ -29,6 +30,20 @@ #define CHT_PLAT_CLK_3_HZ 19200000 #define CHT_CODEC_DAI "rt5670-aif1" +static struct snd_soc_jack cht_bsw_headset; + +/* Headset jack detection DAPM pins */ +static struct snd_soc_jack_pin cht_bsw_headset_pins[] = { + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, +}; + static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) { int i; @@ -178,6 +193,15 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) | RT5670_AD_MONO_L_FILTER | RT5670_AD_MONO_R_FILTER, RT5670_CLK_SEL_I2S1_ASRC); + + ret = snd_soc_card_jack_new(runtime->card, "Headset", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2, &cht_bsw_headset, + cht_bsw_headset_pins, ARRAY_SIZE(cht_bsw_headset_pins)); + if (ret) + return ret; + + rt5670_set_jack_detect(codec, &cht_bsw_headset); return 0; } From 06ac0cd1c4e4e51fa84f866ef69b518488ffa05f Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 18 Mar 2015 10:07:19 +0200 Subject: [PATCH 16/32] ASoC: Intel: Remove support for Intel MID DMA from firmware loader Intel MID DMA driver is going to be removed by the coming commit 36111da7838e ("dmaengine: intel-mid-dma: remove the driver") in spi.git tree. Since there are no users for SST_DMA_TYPE_MID type the support for it can be removed from here in advance. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/intel/sst-dsp.h | 1 - sound/soc/intel/sst-firmware.c | 3 --- 2 files changed, 4 deletions(-) diff --git a/sound/soc/intel/sst-dsp.h b/sound/soc/intel/sst-dsp.h index f291e32f0077..3412474083ff 100644 --- a/sound/soc/intel/sst-dsp.h +++ b/sound/soc/intel/sst-dsp.h @@ -28,7 +28,6 @@ /* Supported SST DMA Devices */ #define SST_DMA_TYPE_DW 1 -#define SST_DMA_TYPE_MID 2 /* autosuspend delay 5s*/ #define SST_RUNTIME_SUSPEND_DELAY (5 * 1000) diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/sst-firmware.c index 5e5800897da2..38881f1fb990 100644 --- a/sound/soc/intel/sst-firmware.c +++ b/sound/soc/intel/sst-firmware.c @@ -277,9 +277,6 @@ int sst_dma_new(struct sst_dsp *sst) case SST_DMA_TYPE_DW: dma_dev_name = "dw_dmac"; break; - case SST_DMA_TYPE_MID: - dma_dev_name = "Intel MID DMA"; - break; default: dev_err(sst->dev, "error: invalid DMA engine %d\n", sst->pdata->dma_engine); From 91b0d9aa933a2335f6f11983b19eaf9ebe3c2033 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 18 Mar 2015 10:07:20 +0200 Subject: [PATCH 17/32] ASoC: Intel: Remove vague commit about slave DMA config from firmware loader Intel MID DMA driver is going to be removed, commit should be a few lines down near to dmaengine_slave_config() call in order to not confuse and at quick look Synopsys DesignWare does seem to use some of the slave config structure fields (see drivers/dma/dw/core.c: dwc_config()). Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/intel/sst-firmware.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/sst-firmware.c index 38881f1fb990..b5659ecb80de 100644 --- a/sound/soc/intel/sst-firmware.c +++ b/sound/soc/intel/sst-firmware.c @@ -221,8 +221,6 @@ int sst_dsp_dma_get_channel(struct sst_dsp *dsp, int chan_id) dma_cap_mask_t mask; int ret; - /* The Intel MID DMA engine driver needs the slave config set but - * Synopsis DMA engine driver safely ignores the slave config */ dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); dma_cap_set(DMA_MEMCPY, mask); From 5d5b275d727753372f0a390b4121738d073f3e94 Mon Sep 17 00:00:00 2001 From: "Lu, Han" Date: Thu, 19 Mar 2015 08:38:00 +0800 Subject: [PATCH 18/32] Intel: ASoC: Add condition check before set param to waves Check waves state before set parameter through ipc to prevent unexpected operation. Also remove redundant check. Signed-off-by: Lu, Han Signed-off-by: Mark Brown --- sound/soc/intel/sst-haswell-ipc.c | 5 +++++ sound/soc/intel/sst-haswell-pcm.c | 6 +----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index 43fb5f339168..20b629a011de 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c @@ -2055,6 +2055,11 @@ int sst_hsw_launch_param_buf(struct sst_hsw *hsw) { int ret, idx; + if (!sst_hsw_is_module_active(hsw, SST_HSW_MODULE_WAVES)) { + dev_dbg(hsw->dev, "module waves is not active\n"); + return 0; + } + /* put all param lines to DSP through ipc */ for (idx = 0; idx < hsw->param_idx_w; idx++) { ret = sst_hsw_module_set_param(hsw, diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index b40ec746bc19..6c6229ae4a02 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c @@ -399,13 +399,9 @@ static int hsw_waves_param_put(struct snd_kcontrol *kcontrol, if (ret < 0) return ret; - if (sst_hsw_is_module_loaded(hsw, id)) { - if (!sst_hsw_is_module_active(hsw, id)) - return 0; - + if (sst_hsw_is_module_active(hsw, id)) ret = sst_hsw_module_set_param(hsw, id, 0, param_id, param_size, ucontrol->value.bytes.data); - } return ret; } From 2c0ed6349287a15f7be73bba00e520106087cd1b Mon Sep 17 00:00:00 2001 From: "Lu, Han" Date: Fri, 27 Mar 2015 15:03:57 +0800 Subject: [PATCH 19/32] ASoC: Intel: fix warning reported by static check tool smatch The smatch tool report warning: ... CHECK sound/soc/intel/sst-haswell-pcm.c sound/soc/intel/sst-haswell-pcm.c:1110 hsw_pcm_probe() error: buffer overflow\ 'hsw_dais' 4 <= 4 sound/soc/intel/sst-haswell-pcm.c:1112 hsw_pcm_probe() error: buffer overflow\ 'hsw_dais' 4 <= 4 ... fix it by use its own struct member for post-process module, rather than sharing unused pcm member. Signed-off-by: Lu, Han Acked-by: Jie Yang Signed-off-by: Mark Brown --- sound/soc/intel/sst-haswell-pcm.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 6c6229ae4a02..31ffc0f0498f 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c @@ -137,6 +137,7 @@ struct hsw_priv_data { struct device *dev; enum hsw_pm_state pm_state; struct snd_soc_card *soc_card; + struct sst_module_runtime *runtime_waves; /* sound effect module */ /* page tables */ struct snd_dma_buffer dmab[HSW_PCM_COUNT][2]; @@ -902,13 +903,10 @@ static int hsw_pcm_create_modules(struct hsw_priv_data *pdata) /* create runtime blocks for module waves */ if (sst_hsw_is_module_loaded(hsw, SST_HSW_MODULE_WAVES)) { - pcm_data = &pdata->pcm[HSW_PCM_COUNT-1][0]; - pcm_data->runtime = sst_hsw_runtime_module_create(hsw, - SST_HSW_MODULE_WAVES, pcm_data->persistent_offset); - if (pcm_data->runtime == NULL) + pdata->runtime_waves = sst_hsw_runtime_module_create(hsw, + SST_HSW_MODULE_WAVES, 0); + if (pdata->runtime_waves == NULL) goto err; - pcm_data->persistent_offset = - pcm_data->runtime->persistent_offset; } return 0; @@ -933,8 +931,7 @@ static void hsw_pcm_free_modules(struct hsw_priv_data *pdata) sst_hsw_runtime_module_free(pcm_data->runtime); } if (sst_hsw_is_module_loaded(hsw, SST_HSW_MODULE_WAVES)) { - pcm_data = &pdata->pcm[HSW_PCM_COUNT-1][0]; - sst_hsw_runtime_module_free(pcm_data->runtime); + sst_hsw_runtime_module_free(pdata->runtime_waves); } } From 2106241a680397f6f49da796a4ce11eb5cf2698e Mon Sep 17 00:00:00 2001 From: Jie Yang Date: Thu, 2 Apr 2015 15:37:00 +0800 Subject: [PATCH 20/32] ASoC: Intel: create common folder and move common files in Restructure the sound/soc/intel/ directory: create common folder, and move sst common files here. Signed-off-by: Jie Yang Acked-by: Jarkko Nikula Tested-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/intel/Makefile | 6 +----- sound/soc/intel/common/Makefile | 6 ++++++ sound/soc/intel/{ => common}/sst-acpi.c | 0 sound/soc/intel/{ => common}/sst-dsp-priv.h | 0 sound/soc/intel/{ => common}/sst-dsp.c | 0 sound/soc/intel/{ => common}/sst-dsp.h | 0 sound/soc/intel/{ => common}/sst-firmware.c | 0 sound/soc/intel/sst/sst.c | 2 +- sound/soc/intel/sst/sst_acpi.c | 2 +- sound/soc/intel/sst/sst_drv_interface.c | 2 +- sound/soc/intel/sst/sst_ipc.c | 2 +- sound/soc/intel/sst/sst_loader.c | 2 +- sound/soc/intel/sst/sst_pvt.c | 2 +- sound/soc/intel/sst/sst_stream.c | 2 +- 14 files changed, 14 insertions(+), 12 deletions(-) create mode 100644 sound/soc/intel/common/Makefile rename sound/soc/intel/{ => common}/sst-acpi.c (100%) rename sound/soc/intel/{ => common}/sst-dsp-priv.h (100%) rename sound/soc/intel/{ => common}/sst-dsp.c (100%) rename sound/soc/intel/{ => common}/sst-dsp.h (100%) rename sound/soc/intel/{ => common}/sst-firmware.c (100%) diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index a8e53c45c6b6..28de8cd6f321 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -1,6 +1,5 @@ # Core support -snd-soc-sst-dsp-objs := sst-dsp.o sst-firmware.o -snd-soc-sst-acpi-objs := sst-acpi.o +obj-$(CONFIG_SND_SOC_INTEL_SST) += common/ snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o \ sst-mfld-platform-compress.o sst-atom-controls.o @@ -9,9 +8,6 @@ snd-soc-mfld-machine-objs := mfld_machine.o obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o obj-$(CONFIG_SND_MFLD_MACHINE) += snd-soc-mfld-machine.o -obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o -obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o - # Platform Support snd-soc-sst-haswell-pcm-objs := \ sst-haswell-ipc.o sst-haswell-pcm.o sst-haswell-dsp.o diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile new file mode 100644 index 000000000000..3df0e1ca76c0 --- /dev/null +++ b/sound/soc/intel/common/Makefile @@ -0,0 +1,6 @@ +snd-soc-sst-dsp-objs := sst-dsp.o sst-firmware.o +snd-soc-sst-acpi-objs := sst-acpi.o + +obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o +obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o + diff --git a/sound/soc/intel/sst-acpi.c b/sound/soc/intel/common/sst-acpi.c similarity index 100% rename from sound/soc/intel/sst-acpi.c rename to sound/soc/intel/common/sst-acpi.c diff --git a/sound/soc/intel/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h similarity index 100% rename from sound/soc/intel/sst-dsp-priv.h rename to sound/soc/intel/common/sst-dsp-priv.h diff --git a/sound/soc/intel/sst-dsp.c b/sound/soc/intel/common/sst-dsp.c similarity index 100% rename from sound/soc/intel/sst-dsp.c rename to sound/soc/intel/common/sst-dsp.c diff --git a/sound/soc/intel/sst-dsp.h b/sound/soc/intel/common/sst-dsp.h similarity index 100% rename from sound/soc/intel/sst-dsp.h rename to sound/soc/intel/common/sst-dsp.h diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/common/sst-firmware.c similarity index 100% rename from sound/soc/intel/sst-firmware.c rename to sound/soc/intel/common/sst-firmware.c diff --git a/sound/soc/intel/sst/sst.c b/sound/soc/intel/sst/sst.c index 1a7eeec444b1..26b1e31c5003 100644 --- a/sound/soc/intel/sst/sst.c +++ b/sound/soc/intel/sst/sst.c @@ -32,7 +32,7 @@ #include #include "../sst-mfld-platform.h" #include "sst.h" -#include "../sst-dsp.h" +#include "../common/sst-dsp.h" MODULE_AUTHOR("Vinod Koul "); MODULE_AUTHOR("Harsha Priya "); diff --git a/sound/soc/intel/sst/sst_acpi.c b/sound/soc/intel/sst/sst_acpi.c index b782dfdcdbba..2a19cbcac811 100644 --- a/sound/soc/intel/sst/sst_acpi.c +++ b/sound/soc/intel/sst/sst_acpi.c @@ -39,7 +39,7 @@ #include #include #include "../sst-mfld-platform.h" -#include "../sst-dsp.h" +#include "../common/sst-dsp.h" #include "sst.h" struct sst_machines { diff --git a/sound/soc/intel/sst/sst_drv_interface.c b/sound/soc/intel/sst/sst_drv_interface.c index f0e4b99b3aeb..36d68b8dfd28 100644 --- a/sound/soc/intel/sst/sst_drv_interface.c +++ b/sound/soc/intel/sst/sst_drv_interface.c @@ -32,7 +32,7 @@ #include #include "../sst-mfld-platform.h" #include "sst.h" -#include "../sst-dsp.h" +#include "../common/sst-dsp.h" diff --git a/sound/soc/intel/sst/sst_ipc.c b/sound/soc/intel/sst/sst_ipc.c index 484e60978477..3943ae856c31 100644 --- a/sound/soc/intel/sst/sst_ipc.c +++ b/sound/soc/intel/sst/sst_ipc.c @@ -32,7 +32,7 @@ #include #include "../sst-mfld-platform.h" #include "sst.h" -#include "../sst-dsp.h" +#include "../common/sst-dsp.h" struct sst_block *sst_create_block(struct intel_sst_drv *ctx, u32 msg_id, u32 drv_id) diff --git a/sound/soc/intel/sst/sst_loader.c b/sound/soc/intel/sst/sst_loader.c index e88907ae8b15..6622e66e1796 100644 --- a/sound/soc/intel/sst/sst_loader.c +++ b/sound/soc/intel/sst/sst_loader.c @@ -37,7 +37,7 @@ #include #include "../sst-mfld-platform.h" #include "sst.h" -#include "../sst-dsp.h" +#include "../common/sst-dsp.h" void memcpy32_toio(void __iomem *dst, const void *src, int count) { diff --git a/sound/soc/intel/sst/sst_pvt.c b/sound/soc/intel/sst/sst_pvt.c index 4b7720864492..2bb0e9e0677d 100644 --- a/sound/soc/intel/sst/sst_pvt.c +++ b/sound/soc/intel/sst/sst_pvt.c @@ -34,7 +34,7 @@ #include #include "../sst-mfld-platform.h" #include "sst.h" -#include "../sst-dsp.h" +#include "../common/sst-dsp.h" int sst_shim_write(void __iomem *addr, int offset, int value) { diff --git a/sound/soc/intel/sst/sst_stream.c b/sound/soc/intel/sst/sst_stream.c index dae2a41997aa..7638fca02de0 100644 --- a/sound/soc/intel/sst/sst_stream.c +++ b/sound/soc/intel/sst/sst_stream.c @@ -31,7 +31,7 @@ #include #include "../sst-mfld-platform.h" #include "sst.h" -#include "../sst-dsp.h" +#include "../common/sst-dsp.h" int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params) { From ba57f68235cf6e9105bf649b01cf9eafc321ea7b Mon Sep 17 00:00:00 2001 From: Jie Yang Date: Thu, 2 Apr 2015 15:37:01 +0800 Subject: [PATCH 21/32] ASoC: Intel: create haswell folder and move haswell platform files in Restructure the sound/soc/intel/ directory: create haswell folder, and move haswell platform files here. Signed-off-by: Jie Yang Reviewed-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/intel/Makefile | 4 +--- sound/soc/intel/haswell/Makefile | 4 ++++ sound/soc/intel/{ => haswell}/sst-haswell-dsp.c | 6 +++--- sound/soc/intel/{ => haswell}/sst-haswell-ipc.c | 4 ++-- sound/soc/intel/{ => haswell}/sst-haswell-ipc.h | 0 sound/soc/intel/{ => haswell}/sst-haswell-pcm.c | 6 +++--- 6 files changed, 13 insertions(+), 11 deletions(-) create mode 100644 sound/soc/intel/haswell/Makefile rename sound/soc/intel/{ => haswell}/sst-haswell-dsp.c (99%) rename sound/soc/intel/{ => haswell}/sst-haswell-ipc.c (99%) rename sound/soc/intel/{ => haswell}/sst-haswell-ipc.h (100%) rename sound/soc/intel/{ => haswell}/sst-haswell-pcm.c (99%) diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index 28de8cd6f321..eb3efce4ec24 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -9,12 +9,10 @@ obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o obj-$(CONFIG_SND_MFLD_MACHINE) += snd-soc-mfld-machine.o # Platform Support -snd-soc-sst-haswell-pcm-objs := \ - sst-haswell-ipc.o sst-haswell-pcm.o sst-haswell-dsp.o +obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/ snd-soc-sst-baytrail-pcm-objs := \ sst-baytrail-ipc.o sst-baytrail-pcm.o sst-baytrail-dsp.o -obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += snd-soc-sst-haswell-pcm.o obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += snd-soc-sst-baytrail-pcm.o # Machine support diff --git a/sound/soc/intel/haswell/Makefile b/sound/soc/intel/haswell/Makefile new file mode 100644 index 000000000000..9c1723112d22 --- /dev/null +++ b/sound/soc/intel/haswell/Makefile @@ -0,0 +1,4 @@ +snd-soc-sst-haswell-pcm-objs := \ + sst-haswell-ipc.o sst-haswell-pcm.o sst-haswell-dsp.o + +obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += snd-soc-sst-haswell-pcm.o diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/haswell/sst-haswell-dsp.c similarity index 99% rename from sound/soc/intel/sst-haswell-dsp.c rename to sound/soc/intel/haswell/sst-haswell-dsp.c index b3e957d46933..7f94920c8a4d 100644 --- a/sound/soc/intel/sst-haswell-dsp.c +++ b/sound/soc/intel/haswell/sst-haswell-dsp.c @@ -28,9 +28,9 @@ #include #include -#include "sst-dsp.h" -#include "sst-dsp-priv.h" -#include "sst-haswell-ipc.h" +#include "../common/sst-dsp.h" +#include "../common/sst-dsp-priv.h" +#include "../haswell/sst-haswell-ipc.h" #include diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c similarity index 99% rename from sound/soc/intel/sst-haswell-ipc.c rename to sound/soc/intel/haswell/sst-haswell-ipc.c index 20b629a011de..28667d8e2005 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/haswell/sst-haswell-ipc.c @@ -34,8 +34,8 @@ #include #include "sst-haswell-ipc.h" -#include "sst-dsp.h" -#include "sst-dsp-priv.h" +#include "../common/sst-dsp.h" +#include "../common/sst-dsp-priv.h" /* Global Message - Generic */ #define IPC_GLB_TYPE_SHIFT 24 diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/haswell/sst-haswell-ipc.h similarity index 100% rename from sound/soc/intel/sst-haswell-ipc.h rename to sound/soc/intel/haswell/sst-haswell-ipc.h diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/haswell/sst-haswell-pcm.c similarity index 99% rename from sound/soc/intel/sst-haswell-pcm.c rename to sound/soc/intel/haswell/sst-haswell-pcm.c index 31ffc0f0498f..157b3a6c509e 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/haswell/sst-haswell-pcm.c @@ -29,9 +29,9 @@ #include #include -#include "sst-haswell-ipc.h" -#include "sst-dsp-priv.h" -#include "sst-dsp.h" +#include "../haswell/sst-haswell-ipc.h" +#include "../common/sst-dsp-priv.h" +#include "../common/sst-dsp.h" #define HSW_PCM_COUNT 6 #define HSW_VOLUME_MAX 0x7FFFFFFF /* 0dB */ From e56c72d5f201044b14191c5b83a25e17f2d68ccf Mon Sep 17 00:00:00 2001 From: Jie Yang Date: Thu, 2 Apr 2015 15:37:02 +0800 Subject: [PATCH 22/32] ASoC: Intel: create boards folder and move sst boards files in Restructure the sound/soc/intel/ directory: create boards folder, and move sst boards files here. Signed-off-by: Jie Yang Acked-by: Vinod Koul Acked-by: Jarkko Nikula Tested-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/intel/Makefile | 16 +--------------- sound/soc/intel/boards/Makefile | 15 +++++++++++++++ sound/soc/intel/{ => boards}/broadwell.c | 6 +++--- sound/soc/intel/{ => boards}/byt-max98090.c | 2 +- sound/soc/intel/{ => boards}/byt-rt5640.c | 4 ++-- .../bytcr_rt5640.c} | 4 ++-- sound/soc/intel/{ => boards}/cht_bsw_rt5645.c | 4 ++-- sound/soc/intel/{ => boards}/cht_bsw_rt5672.c | 4 ++-- sound/soc/intel/{ => boards}/haswell.c | 6 +++--- sound/soc/intel/{ => boards}/mfld_machine.c | 0 10 files changed, 31 insertions(+), 30 deletions(-) create mode 100644 sound/soc/intel/boards/Makefile rename sound/soc/intel/{ => boards}/broadwell.c (98%) rename sound/soc/intel/{ => boards}/byt-max98090.c (99%) rename sound/soc/intel/{ => boards}/byt-rt5640.c (98%) rename sound/soc/intel/{bytcr_dpcm_rt5640.c => boards/bytcr_rt5640.c} (98%) rename sound/soc/intel/{ => boards}/cht_bsw_rt5645.c (99%) rename sound/soc/intel/{ => boards}/cht_bsw_rt5672.c (99%) rename sound/soc/intel/{ => boards}/haswell.c (98%) rename sound/soc/intel/{ => boards}/mfld_machine.c (100%) diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index eb3efce4ec24..ac0248f100ff 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -16,21 +16,7 @@ snd-soc-sst-baytrail-pcm-objs := \ obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += snd-soc-sst-baytrail-pcm.o # Machine support -snd-soc-sst-haswell-objs := haswell.o -snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o -snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o -snd-soc-sst-broadwell-objs := broadwell.o -snd-soc-sst-bytcr-dpcm-rt5640-objs := bytcr_dpcm_rt5640.o -snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o -snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o - -obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o -obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o -obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o -obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o -obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-dpcm-rt5640.o -obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o -obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o +obj-$(CONFIG_SND_SOC_INTEL_SST) += boards/ # DSP driver obj-$(CONFIG_SND_SST_IPC) += sst/ diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile new file mode 100644 index 000000000000..f8237f0044eb --- /dev/null +++ b/sound/soc/intel/boards/Makefile @@ -0,0 +1,15 @@ +snd-soc-sst-haswell-objs := haswell.o +snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o +snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o +snd-soc-sst-broadwell-objs := broadwell.o +snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o +snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o +snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o + +obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o +obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o +obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o +obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o +obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o +obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o +obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o diff --git a/sound/soc/intel/broadwell.c b/sound/soc/intel/boards/broadwell.c similarity index 98% rename from sound/soc/intel/broadwell.c rename to sound/soc/intel/boards/broadwell.c index 6c75b6bd0049..8bafaf6ceab1 100644 --- a/sound/soc/intel/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -22,10 +22,10 @@ #include #include -#include "sst-dsp.h" -#include "sst-haswell-ipc.h" +#include "../common/sst-dsp.h" +#include "../haswell/sst-haswell-ipc.h" -#include "../codecs/rt286.h" +#include "../../codecs/rt286.h" static struct snd_soc_jack broadwell_headset; /* Headset jack detection DAPM pins */ diff --git a/sound/soc/intel/byt-max98090.c b/sound/soc/intel/boards/byt-max98090.c similarity index 99% rename from sound/soc/intel/byt-max98090.c rename to sound/soc/intel/boards/byt-max98090.c index d8b1f038da1c..7ab8cc9fbfd5 100644 --- a/sound/soc/intel/byt-max98090.c +++ b/sound/soc/intel/boards/byt-max98090.c @@ -24,7 +24,7 @@ #include #include #include -#include "../codecs/max98090.h" +#include "../../codecs/max98090.h" struct byt_max98090_private { struct snd_soc_jack jack; diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/boards/byt-rt5640.c similarity index 98% rename from sound/soc/intel/byt-rt5640.c rename to sound/soc/intel/boards/byt-rt5640.c index 354eaad886e1..ae89b9b966d9 100644 --- a/sound/soc/intel/byt-rt5640.c +++ b/sound/soc/intel/boards/byt-rt5640.c @@ -23,9 +23,9 @@ #include #include #include -#include "../codecs/rt5640.h" +#include "../../codecs/rt5640.h" -#include "sst-dsp.h" +#include "../common/sst-dsp.h" static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), diff --git a/sound/soc/intel/bytcr_dpcm_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c similarity index 98% rename from sound/soc/intel/bytcr_dpcm_rt5640.c rename to sound/soc/intel/boards/bytcr_rt5640.c index 3b262d01c1b3..5c2d8fabb5ed 100644 --- a/sound/soc/intel/bytcr_dpcm_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -26,8 +26,8 @@ #include #include #include -#include "../codecs/rt5640.h" -#include "sst-atom-controls.h" +#include "../../codecs/rt5640.h" +#include "../sst-atom-controls.h" static const struct snd_soc_dapm_widget byt_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), diff --git a/sound/soc/intel/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c similarity index 99% rename from sound/soc/intel/cht_bsw_rt5645.c rename to sound/soc/intel/boards/cht_bsw_rt5645.c index 012227997ed9..93bb6711ba3d 100644 --- a/sound/soc/intel/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -27,8 +27,8 @@ #include #include #include -#include "../codecs/rt5645.h" -#include "sst-atom-controls.h" +#include "../../codecs/rt5645.h" +#include "../sst-atom-controls.h" #define CHT_PLAT_CLK_3_HZ 19200000 #define CHT_CODEC_DAI "rt5645-aif1" diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c similarity index 99% rename from sound/soc/intel/cht_bsw_rt5672.c rename to sound/soc/intel/boards/cht_bsw_rt5672.c index 4204fc4f1bad..2cea002a31bb 100644 --- a/sound/soc/intel/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -23,8 +23,8 @@ #include #include #include -#include "../codecs/rt5670.h" -#include "sst-atom-controls.h" +#include "../../codecs/rt5670.h" +#include "../sst-atom-controls.h" /* The platform clock #3 outputs 19.2Mhz clock to codec as I2S MCLK */ #define CHT_PLAT_CLK_3_HZ 19200000 diff --git a/sound/soc/intel/haswell.c b/sound/soc/intel/boards/haswell.c similarity index 98% rename from sound/soc/intel/haswell.c rename to sound/soc/intel/boards/haswell.c index 00fddd3f5dfb..22558572cb9c 100644 --- a/sound/soc/intel/haswell.c +++ b/sound/soc/intel/boards/haswell.c @@ -21,10 +21,10 @@ #include #include -#include "sst-dsp.h" -#include "sst-haswell-ipc.h" +#include "../common/sst-dsp.h" +#include "../haswell/sst-haswell-ipc.h" -#include "../codecs/rt5640.h" +#include "../../codecs/rt5640.h" /* Haswell ULT platforms have a Headphone and Mic jack */ static const struct snd_soc_dapm_widget haswell_widgets[] = { diff --git a/sound/soc/intel/mfld_machine.c b/sound/soc/intel/boards/mfld_machine.c similarity index 100% rename from sound/soc/intel/mfld_machine.c rename to sound/soc/intel/boards/mfld_machine.c From 66a6fd9846f0aecdbab9324b792b319fd8e95e77 Mon Sep 17 00:00:00 2001 From: Jie Yang Date: Thu, 2 Apr 2015 15:37:03 +0800 Subject: [PATCH 23/32] ASoC: Intel: create baytrail folder and move baytrail platform files in Restructure the sound/soc/intel/ directory: create baytrail folder, and move sst baytrail platform files here. Signed-off-by: Jie Yang Acked-by: Jarkko Nikula Tested-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/intel/Makefile | 5 +---- sound/soc/intel/baytrail/Makefile | 4 ++++ sound/soc/intel/{ => baytrail}/sst-baytrail-dsp.c | 4 ++-- sound/soc/intel/{ => baytrail}/sst-baytrail-ipc.c | 4 ++-- sound/soc/intel/{ => baytrail}/sst-baytrail-ipc.h | 0 sound/soc/intel/{ => baytrail}/sst-baytrail-pcm.c | 4 ++-- 6 files changed, 11 insertions(+), 10 deletions(-) create mode 100644 sound/soc/intel/baytrail/Makefile rename sound/soc/intel/{ => baytrail}/sst-baytrail-dsp.c (99%) rename sound/soc/intel/{ => baytrail}/sst-baytrail-ipc.c (99%) rename sound/soc/intel/{ => baytrail}/sst-baytrail-ipc.h (100%) rename sound/soc/intel/{ => baytrail}/sst-baytrail-pcm.c (99%) diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index ac0248f100ff..62de82af6703 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -10,10 +10,7 @@ obj-$(CONFIG_SND_MFLD_MACHINE) += snd-soc-mfld-machine.o # Platform Support obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/ -snd-soc-sst-baytrail-pcm-objs := \ - sst-baytrail-ipc.o sst-baytrail-pcm.o sst-baytrail-dsp.o - -obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += snd-soc-sst-baytrail-pcm.o +obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += baytrail/ # Machine support obj-$(CONFIG_SND_SOC_INTEL_SST) += boards/ diff --git a/sound/soc/intel/baytrail/Makefile b/sound/soc/intel/baytrail/Makefile new file mode 100644 index 000000000000..488408cadf6d --- /dev/null +++ b/sound/soc/intel/baytrail/Makefile @@ -0,0 +1,4 @@ +snd-soc-sst-baytrail-pcm-objs := \ + sst-baytrail-ipc.o sst-baytrail-pcm.o sst-baytrail-dsp.o + +obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += snd-soc-sst-baytrail-pcm.o diff --git a/sound/soc/intel/sst-baytrail-dsp.c b/sound/soc/intel/baytrail/sst-baytrail-dsp.c similarity index 99% rename from sound/soc/intel/sst-baytrail-dsp.c rename to sound/soc/intel/baytrail/sst-baytrail-dsp.c index 5a9e56700f31..01d023cc05dd 100644 --- a/sound/soc/intel/sst-baytrail-dsp.c +++ b/sound/soc/intel/baytrail/sst-baytrail-dsp.c @@ -22,8 +22,8 @@ #include #include -#include "sst-dsp.h" -#include "sst-dsp-priv.h" +#include "../common/sst-dsp.h" +#include "../common/sst-dsp-priv.h" #include "sst-baytrail-ipc.h" #define SST_BYT_FW_SIGNATURE_SIZE 4 diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/baytrail/sst-baytrail-ipc.c similarity index 99% rename from sound/soc/intel/sst-baytrail-ipc.c rename to sound/soc/intel/baytrail/sst-baytrail-ipc.c index b4ad98c43e5c..aabb9b0f48b8 100644 --- a/sound/soc/intel/sst-baytrail-ipc.c +++ b/sound/soc/intel/baytrail/sst-baytrail-ipc.c @@ -29,8 +29,8 @@ #include #include "sst-baytrail-ipc.h" -#include "sst-dsp.h" -#include "sst-dsp-priv.h" +#include "../common/sst-dsp.h" +#include "../common/sst-dsp-priv.h" /* IPC message timeout */ #define IPC_TIMEOUT_MSECS 300 diff --git a/sound/soc/intel/sst-baytrail-ipc.h b/sound/soc/intel/baytrail/sst-baytrail-ipc.h similarity index 100% rename from sound/soc/intel/sst-baytrail-ipc.h rename to sound/soc/intel/baytrail/sst-baytrail-ipc.h diff --git a/sound/soc/intel/sst-baytrail-pcm.c b/sound/soc/intel/baytrail/sst-baytrail-pcm.c similarity index 99% rename from sound/soc/intel/sst-baytrail-pcm.c rename to sound/soc/intel/baytrail/sst-baytrail-pcm.c index 224c49c9f135..79547bec558b 100644 --- a/sound/soc/intel/sst-baytrail-pcm.c +++ b/sound/soc/intel/baytrail/sst-baytrail-pcm.c @@ -20,8 +20,8 @@ #include #include #include "sst-baytrail-ipc.h" -#include "sst-dsp-priv.h" -#include "sst-dsp.h" +#include "../common/sst-dsp-priv.h" +#include "../common/sst-dsp.h" #define BYT_PCM_COUNT 2 From b97169da06992ef04081e66ed22bbdb23dbf6610 Mon Sep 17 00:00:00 2001 From: Jie Yang Date: Thu, 2 Apr 2015 15:37:04 +0800 Subject: [PATCH 24/32] ASoC: Intel: create atom folder and move atom platform files in Restructure the sound/soc/intel/ directory: create atom folder, and move sst atom platform files here. Signed-off-by: Jie Yang Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/Makefile | 11 +---------- sound/soc/intel/atom/Makefile | 7 +++++++ sound/soc/intel/{ => atom}/sst-atom-controls.c | 0 sound/soc/intel/{ => atom}/sst-atom-controls.h | 0 sound/soc/intel/{ => atom}/sst-mfld-dsp.h | 0 .../soc/intel/{ => atom}/sst-mfld-platform-compress.c | 0 sound/soc/intel/{ => atom}/sst-mfld-platform-pcm.c | 0 sound/soc/intel/{ => atom}/sst-mfld-platform.h | 0 sound/soc/intel/{ => atom}/sst/Makefile | 0 sound/soc/intel/{ => atom}/sst/sst.c | 2 +- sound/soc/intel/{ => atom}/sst/sst.h | 0 sound/soc/intel/{ => atom}/sst/sst_acpi.c | 2 +- sound/soc/intel/{ => atom}/sst/sst_drv_interface.c | 2 +- sound/soc/intel/{ => atom}/sst/sst_ipc.c | 2 +- sound/soc/intel/{ => atom}/sst/sst_loader.c | 2 +- sound/soc/intel/{ => atom}/sst/sst_pci.c | 0 sound/soc/intel/{ => atom}/sst/sst_pvt.c | 2 +- sound/soc/intel/{ => atom}/sst/sst_stream.c | 2 +- sound/soc/intel/boards/bytcr_rt5640.c | 2 +- sound/soc/intel/boards/cht_bsw_rt5645.c | 2 +- sound/soc/intel/boards/cht_bsw_rt5672.c | 2 +- 21 files changed, 18 insertions(+), 20 deletions(-) create mode 100644 sound/soc/intel/atom/Makefile rename sound/soc/intel/{ => atom}/sst-atom-controls.c (100%) rename sound/soc/intel/{ => atom}/sst-atom-controls.h (100%) rename sound/soc/intel/{ => atom}/sst-mfld-dsp.h (100%) rename sound/soc/intel/{ => atom}/sst-mfld-platform-compress.c (100%) rename sound/soc/intel/{ => atom}/sst-mfld-platform-pcm.c (100%) rename sound/soc/intel/{ => atom}/sst-mfld-platform.h (100%) rename sound/soc/intel/{ => atom}/sst/Makefile (100%) rename sound/soc/intel/{ => atom}/sst/sst.c (99%) rename sound/soc/intel/{ => atom}/sst/sst.h (100%) rename sound/soc/intel/{ => atom}/sst/sst_acpi.c (99%) rename sound/soc/intel/{ => atom}/sst/sst_drv_interface.c (99%) rename sound/soc/intel/{ => atom}/sst/sst_ipc.c (99%) rename sound/soc/intel/{ => atom}/sst/sst_loader.c (99%) rename sound/soc/intel/{ => atom}/sst/sst_pci.c (100%) rename sound/soc/intel/{ => atom}/sst/sst_pvt.c (99%) rename sound/soc/intel/{ => atom}/sst/sst_stream.c (99%) diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index 62de82af6703..cd9aee9871a3 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -1,19 +1,10 @@ # Core support obj-$(CONFIG_SND_SOC_INTEL_SST) += common/ -snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o \ - sst-mfld-platform-compress.o sst-atom-controls.o -snd-soc-mfld-machine-objs := mfld_machine.o - -obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o -obj-$(CONFIG_SND_MFLD_MACHINE) += snd-soc-mfld-machine.o - # Platform Support obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/ obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += baytrail/ +obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += atom/ # Machine support obj-$(CONFIG_SND_SOC_INTEL_SST) += boards/ - -# DSP driver -obj-$(CONFIG_SND_SST_IPC) += sst/ diff --git a/sound/soc/intel/atom/Makefile b/sound/soc/intel/atom/Makefile new file mode 100644 index 000000000000..ce8074fa6d66 --- /dev/null +++ b/sound/soc/intel/atom/Makefile @@ -0,0 +1,7 @@ +snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o \ + sst-mfld-platform-compress.o sst-atom-controls.o + +obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o + +# DSP driver +obj-$(CONFIG_SND_SST_IPC) += sst/ diff --git a/sound/soc/intel/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c similarity index 100% rename from sound/soc/intel/sst-atom-controls.c rename to sound/soc/intel/atom/sst-atom-controls.c diff --git a/sound/soc/intel/sst-atom-controls.h b/sound/soc/intel/atom/sst-atom-controls.h similarity index 100% rename from sound/soc/intel/sst-atom-controls.h rename to sound/soc/intel/atom/sst-atom-controls.h diff --git a/sound/soc/intel/sst-mfld-dsp.h b/sound/soc/intel/atom/sst-mfld-dsp.h similarity index 100% rename from sound/soc/intel/sst-mfld-dsp.h rename to sound/soc/intel/atom/sst-mfld-dsp.h diff --git a/sound/soc/intel/sst-mfld-platform-compress.c b/sound/soc/intel/atom/sst-mfld-platform-compress.c similarity index 100% rename from sound/soc/intel/sst-mfld-platform-compress.c rename to sound/soc/intel/atom/sst-mfld-platform-compress.c diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c similarity index 100% rename from sound/soc/intel/sst-mfld-platform-pcm.c rename to sound/soc/intel/atom/sst-mfld-platform-pcm.c diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/atom/sst-mfld-platform.h similarity index 100% rename from sound/soc/intel/sst-mfld-platform.h rename to sound/soc/intel/atom/sst-mfld-platform.h diff --git a/sound/soc/intel/sst/Makefile b/sound/soc/intel/atom/sst/Makefile similarity index 100% rename from sound/soc/intel/sst/Makefile rename to sound/soc/intel/atom/sst/Makefile diff --git a/sound/soc/intel/sst/sst.c b/sound/soc/intel/atom/sst/sst.c similarity index 99% rename from sound/soc/intel/sst/sst.c rename to sound/soc/intel/atom/sst/sst.c index 26b1e31c5003..96c2e420cce6 100644 --- a/sound/soc/intel/sst/sst.c +++ b/sound/soc/intel/atom/sst/sst.c @@ -32,7 +32,7 @@ #include #include "../sst-mfld-platform.h" #include "sst.h" -#include "../common/sst-dsp.h" +#include "../../common/sst-dsp.h" MODULE_AUTHOR("Vinod Koul "); MODULE_AUTHOR("Harsha Priya "); diff --git a/sound/soc/intel/sst/sst.h b/sound/soc/intel/atom/sst/sst.h similarity index 100% rename from sound/soc/intel/sst/sst.h rename to sound/soc/intel/atom/sst/sst.h diff --git a/sound/soc/intel/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c similarity index 99% rename from sound/soc/intel/sst/sst_acpi.c rename to sound/soc/intel/atom/sst/sst_acpi.c index 2a19cbcac811..678f36ed97a5 100644 --- a/sound/soc/intel/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -39,7 +39,7 @@ #include #include #include "../sst-mfld-platform.h" -#include "../common/sst-dsp.h" +#include "../../common/sst-dsp.h" #include "sst.h" struct sst_machines { diff --git a/sound/soc/intel/sst/sst_drv_interface.c b/sound/soc/intel/atom/sst/sst_drv_interface.c similarity index 99% rename from sound/soc/intel/sst/sst_drv_interface.c rename to sound/soc/intel/atom/sst/sst_drv_interface.c index 36d68b8dfd28..718838b3fc24 100644 --- a/sound/soc/intel/sst/sst_drv_interface.c +++ b/sound/soc/intel/atom/sst/sst_drv_interface.c @@ -32,7 +32,7 @@ #include #include "../sst-mfld-platform.h" #include "sst.h" -#include "../common/sst-dsp.h" +#include "../../common/sst-dsp.h" diff --git a/sound/soc/intel/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c similarity index 99% rename from sound/soc/intel/sst/sst_ipc.c rename to sound/soc/intel/atom/sst/sst_ipc.c index 3943ae856c31..5a278618466c 100644 --- a/sound/soc/intel/sst/sst_ipc.c +++ b/sound/soc/intel/atom/sst/sst_ipc.c @@ -32,7 +32,7 @@ #include #include "../sst-mfld-platform.h" #include "sst.h" -#include "../common/sst-dsp.h" +#include "../../common/sst-dsp.h" struct sst_block *sst_create_block(struct intel_sst_drv *ctx, u32 msg_id, u32 drv_id) diff --git a/sound/soc/intel/sst/sst_loader.c b/sound/soc/intel/atom/sst/sst_loader.c similarity index 99% rename from sound/soc/intel/sst/sst_loader.c rename to sound/soc/intel/atom/sst/sst_loader.c index 6622e66e1796..33917146d9c4 100644 --- a/sound/soc/intel/sst/sst_loader.c +++ b/sound/soc/intel/atom/sst/sst_loader.c @@ -37,7 +37,7 @@ #include #include "../sst-mfld-platform.h" #include "sst.h" -#include "../common/sst-dsp.h" +#include "../../common/sst-dsp.h" void memcpy32_toio(void __iomem *dst, const void *src, int count) { diff --git a/sound/soc/intel/sst/sst_pci.c b/sound/soc/intel/atom/sst/sst_pci.c similarity index 100% rename from sound/soc/intel/sst/sst_pci.c rename to sound/soc/intel/atom/sst/sst_pci.c diff --git a/sound/soc/intel/sst/sst_pvt.c b/sound/soc/intel/atom/sst/sst_pvt.c similarity index 99% rename from sound/soc/intel/sst/sst_pvt.c rename to sound/soc/intel/atom/sst/sst_pvt.c index 2bb0e9e0677d..3c178444638b 100644 --- a/sound/soc/intel/sst/sst_pvt.c +++ b/sound/soc/intel/atom/sst/sst_pvt.c @@ -34,7 +34,7 @@ #include #include "../sst-mfld-platform.h" #include "sst.h" -#include "../common/sst-dsp.h" +#include "../../common/sst-dsp.h" int sst_shim_write(void __iomem *addr, int offset, int value) { diff --git a/sound/soc/intel/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c similarity index 99% rename from sound/soc/intel/sst/sst_stream.c rename to sound/soc/intel/atom/sst/sst_stream.c index 7638fca02de0..a74c64c7053c 100644 --- a/sound/soc/intel/sst/sst_stream.c +++ b/sound/soc/intel/atom/sst/sst_stream.c @@ -31,7 +31,7 @@ #include #include "../sst-mfld-platform.h" #include "sst.h" -#include "../common/sst-dsp.h" +#include "../../common/sst-dsp.h" int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params) { diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 5c2d8fabb5ed..7f55d59024a8 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -27,7 +27,7 @@ #include #include #include "../../codecs/rt5640.h" -#include "../sst-atom-controls.h" +#include "../atom/sst-atom-controls.h" static const struct snd_soc_dapm_widget byt_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 93bb6711ba3d..20a28b22e30f 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -28,7 +28,7 @@ #include #include #include "../../codecs/rt5645.h" -#include "../sst-atom-controls.h" +#include "../atom/sst-atom-controls.h" #define CHT_PLAT_CLK_3_HZ 19200000 #define CHT_CODEC_DAI "rt5645-aif1" diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 2cea002a31bb..2c9cc5be439e 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -24,7 +24,7 @@ #include #include #include "../../codecs/rt5670.h" -#include "../sst-atom-controls.h" +#include "../atom/sst-atom-controls.h" /* The platform clock #3 outputs 19.2Mhz clock to codec as I2S MCLK */ #define CHT_PLAT_CLK_3_HZ 19200000 From f34c4bc7e599bb895f77381c4d91ccc77635d68f Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Tue, 7 Apr 2015 03:06:06 +0800 Subject: [PATCH 25/32] ASoC: Intel: read_shim_data() can be static Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_pvt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst_pvt.c b/sound/soc/intel/atom/sst/sst_pvt.c index 3c178444638b..2d7424956d05 100644 --- a/sound/soc/intel/atom/sst/sst_pvt.c +++ b/sound/soc/intel/atom/sst/sst_pvt.c @@ -111,7 +111,7 @@ int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx, } -unsigned long long read_shim_data(struct intel_sst_drv *sst, int addr) +static unsigned long long read_shim_data(struct intel_sst_drv *sst, int addr) { unsigned long long val = 0; @@ -124,7 +124,7 @@ unsigned long long read_shim_data(struct intel_sst_drv *sst, int addr) return val; } -void write_shim_data(struct intel_sst_drv *sst, int addr, +static void write_shim_data(struct intel_sst_drv *sst, int addr, unsigned long long data) { switch (sst->dev_id) { From 8e64aedf80ae14b852abc0d7ca262530b69e9a18 Mon Sep 17 00:00:00 2001 From: Jie Yang Date: Tue, 7 Apr 2015 20:14:59 +0800 Subject: [PATCH 26/32] ASoC: Intel: Fix a buffer overflow issue 0day robot reported a buffer overflow issue: ... sound/soc/intel/haswell/sst-haswell-pcm.c:1107 hsw_pcm_probe() error: buffer\ overflow 'hsw_dais' 4 <= 4 sound/soc/intel/haswell/sst-haswell-pcm.c:1109 hsw_pcm_probe() error: buffer\ overflow 'hsw_dais' 4 <= 4 ... Fix it by initializing the index(i) to correct value. Signed-off-by: Jie Yang Signed-off-by: Mark Brown --- sound/soc/intel/haswell/sst-haswell-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/haswell/sst-haswell-pcm.c b/sound/soc/intel/haswell/sst-haswell-pcm.c index 157b3a6c509e..23ae0400d6db 100644 --- a/sound/soc/intel/haswell/sst-haswell-pcm.c +++ b/sound/soc/intel/haswell/sst-haswell-pcm.c @@ -1103,7 +1103,7 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) return 0; err: - for (;i >= 0; i--) { + for (--i; i >= 0; i--) { if (hsw_dais[i].playback.channels_min) snd_dma_free_pages(&priv_data->dmab[i][0]); if (hsw_dais[i].capture.channels_min) From 1f544fd8ff377127a512e20358045cc9b92c245c Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Wed, 8 Apr 2015 18:34:25 +0530 Subject: [PATCH 27/32] ASoC: Intel: remove unused functions these functions were never called by anyone. Signed-off-by: Sudip Mukherjee Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_pvt.c | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst_pvt.c b/sound/soc/intel/atom/sst/sst_pvt.c index 2d7424956d05..adb32fefd693 100644 --- a/sound/soc/intel/atom/sst/sst_pvt.c +++ b/sound/soc/intel/atom/sst/sst_pvt.c @@ -111,30 +111,6 @@ int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx, } -static unsigned long long read_shim_data(struct intel_sst_drv *sst, int addr) -{ - unsigned long long val = 0; - - switch (sst->dev_id) { - case SST_MRFLD_PCI_ID: - case SST_BYT_ACPI_ID: - val = sst_shim_read64(sst->shim, addr); - break; - } - return val; -} - -static void write_shim_data(struct intel_sst_drv *sst, int addr, - unsigned long long data) -{ - switch (sst->dev_id) { - case SST_MRFLD_PCI_ID: - case SST_BYT_ACPI_ID: - sst_shim_write64(sst->shim, addr, (u64) data); - break; - } -} - /* * sst_wait_timeout - wait on event for timeout * From 75afbd052b3675e9b812f9327e19be63f3e7b5de Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 9 Apr 2015 12:02:39 +0300 Subject: [PATCH 28/32] ASoC: Intel: do cast earlier in sst_cdev_tstamp() My static checker complains about these because it looks like the multiply can overflow and then we cast to a larger data type. I don't think this is a problem, but it's also harmless to do the cast earlier so let's silence the static checker warning. Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_drv_interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/atom/sst/sst_drv_interface.c b/sound/soc/intel/atom/sst/sst_drv_interface.c index 718838b3fc24..7b50a9d17ec1 100644 --- a/sound/soc/intel/atom/sst/sst_drv_interface.c +++ b/sound/soc/intel/atom/sst/sst_drv_interface.c @@ -381,7 +381,7 @@ static int sst_cdev_tstamp(struct device *dev, unsigned int str_id, tstamp->copied_total = fw_tstamp.ring_buffer_counter; tstamp->pcm_frames = fw_tstamp.frames_decoded; tstamp->pcm_io_frames = div_u64(fw_tstamp.hardware_counter, - (u64)((stream->num_ch) * SST_GET_BYTES_PER_SAMPLE(24))); + (u64)stream->num_ch * SST_GET_BYTES_PER_SAMPLE(24)); tstamp->sampling_rate = fw_tstamp.sampling_frequency; dev_dbg(dev, "PCM = %u\n", tstamp->pcm_io_frames); From a33c1ec5cf82efb76f0e7339b13f11cfb53a2a2f Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Tue, 7 Apr 2015 09:33:30 +0800 Subject: [PATCH 29/32] ASoC: Intel: Refactor common IPC/mailbox code into generic APIs Currently in Intel SST driver, some similar IPC/mailbox processing code are used in different platforms (e.g. in baytrail/broadwell). This patch extracts the common code and creates new files (sst-ipc.c/sst-ipc.h) to contain the common code and provide the generic APIs for IPC/mailbox processing. Signed-off-by: Jin Yao Acked-by: Jie Yang Signed-off-by: Mark Brown --- sound/soc/intel/common/Makefile | 3 +- sound/soc/intel/common/sst-ipc.c | 294 +++++++++++++++++++++++++++++++ sound/soc/intel/common/sst-ipc.h | 91 ++++++++++ 3 files changed, 387 insertions(+), 1 deletion(-) create mode 100644 sound/soc/intel/common/sst-ipc.c create mode 100644 sound/soc/intel/common/sst-ipc.h diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index 3df0e1ca76c0..f24154ca4e98 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -1,6 +1,7 @@ snd-soc-sst-dsp-objs := sst-dsp.o sst-firmware.o snd-soc-sst-acpi-objs := sst-acpi.o +snd-soc-sst-ipc-objs := sst-ipc.o -obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o +obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o diff --git a/sound/soc/intel/common/sst-ipc.c b/sound/soc/intel/common/sst-ipc.c new file mode 100644 index 000000000000..4b62a553823c --- /dev/null +++ b/sound/soc/intel/common/sst-ipc.c @@ -0,0 +1,294 @@ +/* + * Intel SST generic IPC Support + * + * Copyright (C) 2015, Intel Corporation. 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 version + * 2 as published by the Free Software Foundation. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sst-dsp.h" +#include "sst-dsp-priv.h" +#include "sst-ipc.h" + +/* IPC message timeout (msecs) */ +#define IPC_TIMEOUT_MSECS 300 + +#define IPC_EMPTY_LIST_SIZE 8 + +/* locks held by caller */ +static struct ipc_message *msg_get_empty(struct sst_generic_ipc *ipc) +{ + struct ipc_message *msg = NULL; + + if (!list_empty(&ipc->empty_list)) { + msg = list_first_entry(&ipc->empty_list, struct ipc_message, + list); + list_del(&msg->list); + } + + return msg; +} + +static int tx_wait_done(struct sst_generic_ipc *ipc, + struct 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_TIMEOUT_MSECS)); + + spin_lock_irqsave(&ipc->dsp->spinlock, flags); + if (ret == 0) { + if (ipc->ops.shim_dbg != NULL) + ipc->ops.shim_dbg(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 sst_generic_ipc *ipc, u64 header, + void *tx_data, size_t tx_bytes, void *rx_data, + size_t rx_bytes, int wait) +{ + struct ipc_message *msg; + unsigned long flags; + + spin_lock_irqsave(&ipc->dsp->spinlock, flags); + + msg = msg_get_empty(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); + + queue_kthread_work(&ipc->kworker, &ipc->kwork); + + if (wait) + return tx_wait_done(ipc, msg, rx_data); + else + return 0; +} + +static int msg_empty_list_init(struct sst_generic_ipc *ipc) +{ + int i; + + ipc->msg = kzalloc(sizeof(struct ipc_message) * + IPC_EMPTY_LIST_SIZE, GFP_KERNEL); + if (ipc->msg == NULL) + return -ENOMEM; + + for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { + init_waitqueue_head(&ipc->msg[i].waitq); + list_add(&ipc->msg[i].list, &ipc->empty_list); + } + + return 0; +} + +static void ipc_tx_msgs(struct kthread_work *work) +{ + struct sst_generic_ipc *ipc = + container_of(work, struct sst_generic_ipc, kwork); + struct ipc_message *msg; + unsigned long flags; + u64 ipcx; + + 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*/ + ipcx = sst_dsp_shim_read_unlocked(ipc->dsp, SST_IPCX); + if (ipcx & (SST_IPCX_BUSY | SST_IPCX_DONE)) { + spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); + return; + } + + msg = list_first_entry(&ipc->tx_list, struct 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 sst_ipc_tx_message_wait(struct sst_generic_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(sst_ipc_tx_message_wait); + +int sst_ipc_tx_message_nowait(struct sst_generic_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(sst_ipc_tx_message_nowait); + +struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc, + u64 header) +{ + struct ipc_message *msg; + u64 mask; + + if (ipc->ops.reply_msg_match != NULL) + header = ipc->ops.reply_msg_match(header, &mask); + + if (list_empty(&ipc->rx_list)) { + dev_err(ipc->dev, "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(sst_ipc_reply_find_msg); + +/* locks held by caller */ +void sst_ipc_tx_msg_reply_complete(struct sst_generic_ipc *ipc, + struct 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(sst_ipc_tx_msg_reply_complete); + +void sst_ipc_drop_all(struct sst_generic_ipc *ipc) +{ + struct 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) + dev_err(ipc->dev, "dropped IPC msg RX=%d, TX=%d\n", + tx_drop_cnt, rx_drop_cnt); +} +EXPORT_SYMBOL_GPL(sst_ipc_drop_all); + +int sst_ipc_init(struct sst_generic_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 = msg_empty_list_init(ipc); + if (ret < 0) + return -ENOMEM; + + /* start the IPC message thread */ + init_kthread_worker(&ipc->kworker); + ipc->tx_thread = kthread_run(kthread_worker_fn, + &ipc->kworker, "%s", + dev_name(ipc->dev)); + if (IS_ERR(ipc->tx_thread)) { + dev_err(ipc->dev, "error: failed to create message TX task\n"); + ret = PTR_ERR(ipc->tx_thread); + kfree(ipc->msg); + return ret; + } + + init_kthread_work(&ipc->kwork, ipc_tx_msgs); + return 0; +} +EXPORT_SYMBOL_GPL(sst_ipc_init); + +void sst_ipc_fini(struct sst_generic_ipc *ipc) +{ + if (ipc->tx_thread) + kthread_stop(ipc->tx_thread); + + if (ipc->msg) + kfree(ipc->msg); +} +EXPORT_SYMBOL_GPL(sst_ipc_fini); + +/* Module information */ +MODULE_AUTHOR("Jin Yao"); +MODULE_DESCRIPTION("Intel SST IPC generic"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/intel/common/sst-ipc.h b/sound/soc/intel/common/sst-ipc.h new file mode 100644 index 000000000000..125ea451a373 --- /dev/null +++ b/sound/soc/intel/common/sst-ipc.h @@ -0,0 +1,91 @@ +/* + * Intel SST generic IPC Support + * + * Copyright (C) 2015, Intel Corporation. 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 version + * 2 as published by the Free Software Foundation. + * + * 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 __SST_GENERIC_IPC_H +#define __SST_GENERIC_IPC_H + +#include +#include +#include +#include +#include +#include +#include + +#define IPC_MAX_MAILBOX_BYTES 256 + +struct ipc_message { + struct list_head list; + u64 header; + + /* direction wrt host CPU */ + char tx_data[IPC_MAX_MAILBOX_BYTES]; + size_t tx_size; + char rx_data[IPC_MAX_MAILBOX_BYTES]; + size_t rx_size; + + wait_queue_head_t waitq; + bool pending; + bool complete; + bool wait; + int errno; +}; + +struct sst_generic_ipc; + +struct sst_plat_ipc_ops { + void (*tx_msg)(struct sst_generic_ipc *, struct ipc_message *); + void (*shim_dbg)(struct sst_generic_ipc *, const char *); + void (*tx_data_copy)(struct ipc_message *, char *, size_t); + u64 (*reply_msg_match)(u64 header, u64 *mask); +}; + +/* SST generic IPC data */ +struct sst_generic_ipc { + struct device *dev; + struct sst_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 ipc_message *msg; + + struct sst_plat_ipc_ops ops; +}; + +int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header, + void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes); + +int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, u64 header, + void *tx_data, size_t tx_bytes); + +struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc, + u64 header); + +void sst_ipc_tx_msg_reply_complete(struct sst_generic_ipc *ipc, + struct ipc_message *msg); + +void sst_ipc_drop_all(struct sst_generic_ipc *ipc); +int sst_ipc_init(struct sst_generic_ipc *ipc); +void sst_ipc_fini(struct sst_generic_ipc *ipc); + +#endif From 48cec59b6f383c63b2b828b93656ee2030abecc0 Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Tue, 7 Apr 2015 09:33:31 +0800 Subject: [PATCH 30/32] ASoC: Intel: Use the generic IPC/mailbox APIs in Baytrail Use the generic IPC/mailbox APIs to replace the original processing code for Baytrail platform. Signed-off-by: Jin Yao Acked-by: Jie Yang Signed-off-by: Mark Brown --- sound/soc/intel/baytrail/sst-baytrail-ipc.c | 360 +++++--------------- 1 file changed, 77 insertions(+), 283 deletions(-) diff --git a/sound/soc/intel/baytrail/sst-baytrail-ipc.c b/sound/soc/intel/baytrail/sst-baytrail-ipc.c index aabb9b0f48b8..1efb33b36303 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-ipc.c +++ b/sound/soc/intel/baytrail/sst-baytrail-ipc.c @@ -31,6 +31,7 @@ #include "sst-baytrail-ipc.h" #include "../common/sst-dsp.h" #include "../common/sst-dsp-priv.h" +#include "../common/sst-ipc.h" /* IPC message timeout */ #define IPC_TIMEOUT_MSECS 300 @@ -142,23 +143,6 @@ struct sst_byt_fw_init { u8 debug_info; } __packed; -/* driver internal IPC message structure */ -struct ipc_message { - struct list_head list; - u64 header; - - /* direction wrt host CPU */ - char tx_data[SST_BYT_IPC_MAX_PAYLOAD_SIZE]; - size_t tx_size; - char rx_data[SST_BYT_IPC_MAX_PAYLOAD_SIZE]; - size_t rx_size; - - wait_queue_head_t waitq; - bool complete; - bool wait; - int errno; -}; - struct sst_byt_stream; struct sst_byt; @@ -195,14 +179,7 @@ struct sst_byt { struct sst_fw *fw; /* 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; - struct ipc_message *msg; + struct sst_generic_ipc ipc; }; static inline u64 sst_byt_header(int msg_id, int data, bool large, int str_id) @@ -246,209 +223,6 @@ static struct sst_byt_stream *sst_byt_get_stream(struct sst_byt *byt, return NULL; } -static void sst_byt_ipc_shim_dbg(struct sst_byt *byt, const char *text) -{ - struct sst_dsp *sst = byt->dsp; - u64 isr, ipcd, imrx, ipcx; - - ipcx = sst_dsp_shim_read64_unlocked(sst, SST_IPCX); - isr = sst_dsp_shim_read64_unlocked(sst, SST_ISRX); - ipcd = sst_dsp_shim_read64_unlocked(sst, SST_IPCD); - imrx = sst_dsp_shim_read64_unlocked(sst, SST_IMRX); - - dev_err(byt->dev, - "ipc: --%s-- ipcx 0x%llx isr 0x%llx ipcd 0x%llx imrx 0x%llx\n", - text, ipcx, isr, ipcd, imrx); -} - -/* locks held by caller */ -static struct ipc_message *sst_byt_msg_get_empty(struct sst_byt *byt) -{ - struct ipc_message *msg = NULL; - - if (!list_empty(&byt->empty_list)) { - msg = list_first_entry(&byt->empty_list, - struct ipc_message, list); - list_del(&msg->list); - } - - return msg; -} - -static void sst_byt_ipc_tx_msgs(struct kthread_work *work) -{ - struct sst_byt *byt = - container_of(work, struct sst_byt, kwork); - struct ipc_message *msg; - u64 ipcx; - unsigned long flags; - - spin_lock_irqsave(&byt->dsp->spinlock, flags); - if (list_empty(&byt->tx_list)) { - spin_unlock_irqrestore(&byt->dsp->spinlock, flags); - return; - } - - /* if the DSP is busy we will TX messages after IRQ */ - ipcx = sst_dsp_shim_read64_unlocked(byt->dsp, SST_IPCX); - if (ipcx & SST_BYT_IPCX_BUSY) { - spin_unlock_irqrestore(&byt->dsp->spinlock, flags); - return; - } - - msg = list_first_entry(&byt->tx_list, struct ipc_message, list); - - list_move(&msg->list, &byt->rx_list); - - /* send the message */ - if (msg->header & IPC_HEADER_LARGE(true)) - sst_dsp_outbox_write(byt->dsp, msg->tx_data, msg->tx_size); - sst_dsp_shim_write64_unlocked(byt->dsp, SST_IPCX, msg->header); - - spin_unlock_irqrestore(&byt->dsp->spinlock, flags); -} - -static inline void sst_byt_tx_msg_reply_complete(struct sst_byt *byt, - struct ipc_message *msg) -{ - msg->complete = true; - - if (!msg->wait) - list_add_tail(&msg->list, &byt->empty_list); - else - wake_up(&msg->waitq); -} - -static void sst_byt_drop_all(struct sst_byt *byt) -{ - struct ipc_message *msg, *tmp; - unsigned long flags; - - /* drop all TX and Rx messages before we stall + reset DSP */ - spin_lock_irqsave(&byt->dsp->spinlock, flags); - list_for_each_entry_safe(msg, tmp, &byt->tx_list, list) { - list_move(&msg->list, &byt->empty_list); - } - - list_for_each_entry_safe(msg, tmp, &byt->rx_list, list) { - list_move(&msg->list, &byt->empty_list); - } - - spin_unlock_irqrestore(&byt->dsp->spinlock, flags); -} - -static int sst_byt_tx_wait_done(struct sst_byt *byt, struct ipc_message *msg, - void *rx_data) -{ - unsigned long flags; - int ret; - - /* wait for DSP completion */ - ret = wait_event_timeout(msg->waitq, msg->complete, - msecs_to_jiffies(IPC_TIMEOUT_MSECS)); - - spin_lock_irqsave(&byt->dsp->spinlock, flags); - if (ret == 0) { - list_del(&msg->list); - sst_byt_ipc_shim_dbg(byt, "message timeout"); - - 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, &byt->empty_list); - spin_unlock_irqrestore(&byt->dsp->spinlock, flags); - return ret; -} - -static int sst_byt_ipc_tx_message(struct sst_byt *byt, u64 header, - void *tx_data, size_t tx_bytes, - void *rx_data, size_t rx_bytes, int wait) -{ - unsigned long flags; - struct ipc_message *msg; - - spin_lock_irqsave(&byt->dsp->spinlock, flags); - - msg = sst_byt_msg_get_empty(byt); - if (msg == NULL) { - spin_unlock_irqrestore(&byt->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->complete = false; - - if (tx_bytes) { - /* msg content = lower 32-bit of the header + data */ - *(u32 *)msg->tx_data = (u32)(header & (u32)-1); - memcpy(msg->tx_data + sizeof(u32), tx_data, tx_bytes); - msg->tx_size += sizeof(u32); - } - - list_add_tail(&msg->list, &byt->tx_list); - spin_unlock_irqrestore(&byt->dsp->spinlock, flags); - - queue_kthread_work(&byt->kworker, &byt->kwork); - - if (wait) - return sst_byt_tx_wait_done(byt, msg, rx_data); - else - return 0; -} - -static inline int sst_byt_ipc_tx_msg_wait(struct sst_byt *byt, u64 header, - void *tx_data, size_t tx_bytes, - void *rx_data, size_t rx_bytes) -{ - return sst_byt_ipc_tx_message(byt, header, tx_data, tx_bytes, - rx_data, rx_bytes, 1); -} - -static inline int sst_byt_ipc_tx_msg_nowait(struct sst_byt *byt, u64 header, - void *tx_data, size_t tx_bytes) -{ - return sst_byt_ipc_tx_message(byt, header, tx_data, tx_bytes, - NULL, 0, 0); -} - -static struct ipc_message *sst_byt_reply_find_msg(struct sst_byt *byt, - u64 header) -{ - struct ipc_message *msg = NULL, *_msg; - u64 mask; - - /* match reply to message sent based on msg and stream IDs */ - mask = IPC_HEADER_MSG_ID_MASK | - IPC_HEADER_STR_ID_MASK << IPC_HEADER_STR_ID_SHIFT; - header &= mask; - - if (list_empty(&byt->rx_list)) { - dev_err(byt->dev, - "ipc: rx list is empty but received 0x%llx\n", header); - goto out; - } - - list_for_each_entry(_msg, &byt->rx_list, list) { - if ((_msg->header & mask) == header) { - msg = _msg; - break; - } - } - -out: - return msg; -} - static void sst_byt_stream_update(struct sst_byt *byt, struct ipc_message *msg) { struct sst_byt_stream *stream; @@ -477,7 +251,7 @@ static int sst_byt_process_reply(struct sst_byt *byt, u64 header) { struct ipc_message *msg; - msg = sst_byt_reply_find_msg(byt, header); + msg = sst_ipc_reply_find_msg(&byt->ipc, header); if (msg == NULL) return 1; @@ -491,7 +265,7 @@ static int sst_byt_process_reply(struct sst_byt *byt, u64 header) list_del(&msg->list); /* wake up */ - sst_byt_tx_msg_reply_complete(byt, msg); + sst_ipc_tx_msg_reply_complete(&byt->ipc, msg); return 1; } @@ -538,6 +312,7 @@ static irqreturn_t sst_byt_irq_thread(int irq, void *context) { struct sst_dsp *sst = (struct sst_dsp *) context; struct sst_byt *byt = sst_dsp_get_thread_context(sst); + struct sst_generic_ipc *ipc = &byt->ipc; u64 header; unsigned long flags; @@ -569,7 +344,7 @@ static irqreturn_t sst_byt_irq_thread(int irq, void *context) spin_unlock_irqrestore(&sst->spinlock, flags); /* continue to send any remaining messages... */ - queue_kthread_work(&byt->kworker, &byt->kwork); + queue_kthread_work(&ipc->kworker, &ipc->kwork); return IRQ_HANDLED; } @@ -656,7 +431,8 @@ int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream) header = sst_byt_header(IPC_IA_ALLOC_STREAM, sizeof(*str_req) + sizeof(u32), true, stream->str_id); - ret = sst_byt_ipc_tx_msg_wait(byt, header, str_req, sizeof(*str_req), + ret = sst_ipc_tx_message_wait(&byt->ipc, header, str_req, + sizeof(*str_req), reply, sizeof(*reply)); if (ret < 0) { dev_err(byt->dev, "ipc: error stream commit failed\n"); @@ -679,7 +455,7 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream) goto out; header = sst_byt_header(IPC_IA_FREE_STREAM, 0, false, stream->str_id); - ret = sst_byt_ipc_tx_msg_wait(byt, header, NULL, 0, NULL, 0); + ret = sst_ipc_tx_message_wait(&byt->ipc, header, NULL, 0, NULL, 0); if (ret < 0) { dev_err(byt->dev, "ipc: free stream %d failed\n", stream->str_id); @@ -703,9 +479,11 @@ static int sst_byt_stream_operations(struct sst_byt *byt, int type, header = sst_byt_header(type, 0, false, stream_id); if (wait) - return sst_byt_ipc_tx_msg_wait(byt, header, NULL, 0, NULL, 0); + return sst_ipc_tx_message_wait(&byt->ipc, header, NULL, + 0, NULL, 0); else - return sst_byt_ipc_tx_msg_nowait(byt, header, NULL, 0); + return sst_ipc_tx_message_nowait(&byt->ipc, header, + NULL, 0); } /* stream ALSA trigger operations */ @@ -725,7 +503,7 @@ int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream, tx_msg = &start_stream; size = sizeof(start_stream); - ret = sst_byt_ipc_tx_msg_nowait(byt, header, tx_msg, size); + ret = sst_ipc_tx_message_nowait(&byt->ipc, header, tx_msg, size); if (ret < 0) dev_err(byt->dev, "ipc: error failed to start stream %d\n", stream->str_id); @@ -790,23 +568,6 @@ int sst_byt_get_dsp_position(struct sst_byt *byt, return do_div(fw_tstamp.ring_buffer_counter, buffer_size); } -static int msg_empty_list_init(struct sst_byt *byt) -{ - struct ipc_message *msg; - int i; - - byt->msg = kzalloc(sizeof(*msg) * IPC_EMPTY_LIST_SIZE, GFP_KERNEL); - if (byt->msg == NULL) - return -ENOMEM; - - for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { - init_waitqueue_head(&byt->msg[i].waitq); - list_add(&byt->msg[i].list, &byt->empty_list); - } - - return 0; -} - struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt) { return byt->dsp; @@ -823,7 +584,7 @@ int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata) dev_dbg(byt->dev, "dsp reset\n"); sst_dsp_reset(byt->dsp); - sst_byt_drop_all(byt); + sst_ipc_drop_all(&byt->ipc); dev_dbg(byt->dev, "dsp in reset\n"); dev_dbg(byt->dev, "free all blocks and unload fw\n"); @@ -876,9 +637,52 @@ int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata) } EXPORT_SYMBOL_GPL(sst_byt_dsp_wait_for_ready); +static void byt_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) +{ + if (msg->header & IPC_HEADER_LARGE(true)) + sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size); + + sst_dsp_shim_write64_unlocked(ipc->dsp, SST_IPCX, msg->header); +} + +static void byt_shim_dbg(struct sst_generic_ipc *ipc, const char *text) +{ + struct sst_dsp *sst = ipc->dsp; + u64 isr, ipcd, imrx, ipcx; + + ipcx = sst_dsp_shim_read64_unlocked(sst, SST_IPCX); + isr = sst_dsp_shim_read64_unlocked(sst, SST_ISRX); + ipcd = sst_dsp_shim_read64_unlocked(sst, SST_IPCD); + imrx = sst_dsp_shim_read64_unlocked(sst, SST_IMRX); + + dev_err(ipc->dev, + "ipc: --%s-- ipcx 0x%llx isr 0x%llx ipcd 0x%llx imrx 0x%llx\n", + text, ipcx, isr, ipcd, imrx); +} + +static void byt_tx_data_copy(struct ipc_message *msg, char *tx_data, + size_t tx_size) +{ + /* msg content = lower 32-bit of the header + data */ + *(u32 *)msg->tx_data = (u32)(msg->header & (u32)-1); + memcpy(msg->tx_data + sizeof(u32), tx_data, tx_size); + msg->tx_size += sizeof(u32); +} + +static u64 byt_reply_msg_match(u64 header, u64 *mask) +{ + /* match reply to message sent based on msg and stream IDs */ + *mask = IPC_HEADER_MSG_ID_MASK | + IPC_HEADER_STR_ID_MASK << IPC_HEADER_STR_ID_SHIFT; + header &= *mask; + + return header; +} + int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) { struct sst_byt *byt; + struct sst_generic_ipc *ipc; struct sst_fw *byt_sst_fw; struct sst_byt_fw_init init; int err; @@ -889,39 +693,30 @@ int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) if (byt == NULL) return -ENOMEM; - byt->dev = dev; + ipc = &byt->ipc; + ipc->dev = dev; + ipc->ops.tx_msg = byt_tx_msg; + ipc->ops.shim_dbg = byt_shim_dbg; + ipc->ops.tx_data_copy = byt_tx_data_copy; + ipc->ops.reply_msg_match = byt_reply_msg_match; + + err = sst_ipc_init(ipc); + if (err != 0) + goto ipc_init_err; + INIT_LIST_HEAD(&byt->stream_list); - INIT_LIST_HEAD(&byt->tx_list); - INIT_LIST_HEAD(&byt->rx_list); - INIT_LIST_HEAD(&byt->empty_list); init_waitqueue_head(&byt->boot_wait); - init_waitqueue_head(&byt->wait_txq); - - err = msg_empty_list_init(byt); - if (err < 0) - return -ENOMEM; - - /* start the IPC message thread */ - init_kthread_worker(&byt->kworker); - byt->tx_thread = kthread_run(kthread_worker_fn, - &byt->kworker, "%s", - dev_name(byt->dev)); - if (IS_ERR(byt->tx_thread)) { - err = PTR_ERR(byt->tx_thread); - dev_err(byt->dev, "error failed to create message TX task\n"); - goto err_free_msg; - } - init_kthread_work(&byt->kwork, sst_byt_ipc_tx_msgs); - byt_dev.thread_context = byt; /* init SST shim */ byt->dsp = sst_dsp_new(dev, &byt_dev, pdata); if (byt->dsp == NULL) { err = -ENODEV; - goto dsp_err; + goto dsp_new_err; } + ipc->dsp = byt->dsp; + /* keep the DSP in reset state for base FW loading */ sst_dsp_reset(byt->dsp); @@ -961,10 +756,10 @@ boot_err: sst_fw_free(byt_sst_fw); fw_err: sst_dsp_free(byt->dsp); -dsp_err: - kthread_stop(byt->tx_thread); -err_free_msg: - kfree(byt->msg); +dsp_new_err: + sst_ipc_fini(ipc); +ipc_init_err: + kfree(byt); return err; } @@ -977,7 +772,6 @@ void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata) sst_dsp_reset(byt->dsp); sst_fw_free_all(byt->dsp); sst_dsp_free(byt->dsp); - kthread_stop(byt->tx_thread); - kfree(byt->msg); + sst_ipc_fini(&byt->ipc); } EXPORT_SYMBOL_GPL(sst_byt_dsp_free); From 0e7921e9583b72be93d8fa82536a7594974b7eea Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Tue, 7 Apr 2015 09:33:32 +0800 Subject: [PATCH 31/32] ASoC: Intel: Use the generic IPC/mailbox APIs in Broadwell Use the generic IPC/mailbox APIs to replace the original processing code for Broadwell platform. Signed-off-by: Jin Yao Acked-by: Jie Yang Signed-off-by: Mark Brown --- sound/soc/intel/haswell/sst-haswell-ipc.c | 382 +++++----------------- 1 file changed, 87 insertions(+), 295 deletions(-) diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c index 28667d8e2005..d75f09eb30b7 100644 --- a/sound/soc/intel/haswell/sst-haswell-ipc.c +++ b/sound/soc/intel/haswell/sst-haswell-ipc.c @@ -36,6 +36,7 @@ #include "sst-haswell-ipc.h" #include "../common/sst-dsp.h" #include "../common/sst-dsp-priv.h" +#include "../common/sst-ipc.h" /* Global Message - Generic */ #define IPC_GLB_TYPE_SHIFT 24 @@ -210,23 +211,6 @@ struct sst_hsw_ipc_fw_ready { u8 fw_info[IPC_MAX_MAILBOX_BYTES - 5 * sizeof(u32)]; } __attribute__((packed)); -struct ipc_message { - struct list_head list; - u32 header; - - /* direction wrt host CPU */ - char tx_data[IPC_MAX_MAILBOX_BYTES]; - size_t tx_size; - char rx_data[IPC_MAX_MAILBOX_BYTES]; - size_t rx_size; - - wait_queue_head_t waitq; - bool pending; - bool complete; - bool wait; - int errno; -}; - struct sst_hsw_stream; struct sst_hsw; @@ -325,15 +309,7 @@ struct sst_hsw { bool shutdown; /* 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 ipc_message *msg; + struct sst_generic_ipc ipc; /* FW log stream */ struct sst_hsw_log_stream log_stream; @@ -456,159 +432,6 @@ static struct sst_hsw_stream *get_stream_by_id(struct sst_hsw *hsw, return NULL; } -static void ipc_shim_dbg(struct sst_hsw *hsw, const char *text) -{ - struct sst_dsp *sst = hsw->dsp; - u32 isr, ipcd, imrx, ipcx; - - ipcx = sst_dsp_shim_read_unlocked(sst, SST_IPCX); - isr = sst_dsp_shim_read_unlocked(sst, SST_ISRX); - ipcd = sst_dsp_shim_read_unlocked(sst, SST_IPCD); - imrx = sst_dsp_shim_read_unlocked(sst, SST_IMRX); - - dev_err(hsw->dev, "ipc: --%s-- ipcx 0x%8.8x isr 0x%8.8x ipcd 0x%8.8x imrx 0x%8.8x\n", - text, ipcx, isr, ipcd, imrx); -} - -/* locks held by caller */ -static struct ipc_message *msg_get_empty(struct sst_hsw *hsw) -{ - struct ipc_message *msg = NULL; - - if (!list_empty(&hsw->empty_list)) { - msg = list_first_entry(&hsw->empty_list, struct ipc_message, - list); - list_del(&msg->list); - } - - return msg; -} - -static void ipc_tx_msgs(struct kthread_work *work) -{ - struct sst_hsw *hsw = - container_of(work, struct sst_hsw, kwork); - struct ipc_message *msg; - unsigned long flags; - u32 ipcx; - - spin_lock_irqsave(&hsw->dsp->spinlock, flags); - - if (list_empty(&hsw->tx_list) || hsw->pending) { - spin_unlock_irqrestore(&hsw->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*/ - ipcx = sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCX); - if (ipcx & (SST_IPCX_BUSY | SST_IPCX_DONE)) { - spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); - return; - } - - msg = list_first_entry(&hsw->tx_list, struct ipc_message, list); - - list_move(&msg->list, &hsw->rx_list); - - /* send the message */ - sst_dsp_outbox_write(hsw->dsp, msg->tx_data, msg->tx_size); - sst_dsp_ipc_msg_tx(hsw->dsp, msg->header | SST_IPCX_BUSY); - - spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); -} - -/* locks held by caller */ -static void tx_msg_reply_complete(struct sst_hsw *hsw, struct ipc_message *msg) -{ - msg->complete = true; - trace_ipc_reply("completed", msg->header); - - if (!msg->wait) - list_add_tail(&msg->list, &hsw->empty_list); - else - wake_up(&msg->waitq); -} - -static int tx_wait_done(struct sst_hsw *hsw, struct 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_TIMEOUT_MSECS)); - - spin_lock_irqsave(&hsw->dsp->spinlock, flags); - if (ret == 0) { - ipc_shim_dbg(hsw, "message timeout"); - - trace_ipc_error("error message timeout for", msg->header); - 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, &hsw->empty_list); - spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); - return ret; -} - -static int ipc_tx_message(struct sst_hsw *hsw, u32 header, void *tx_data, - size_t tx_bytes, void *rx_data, size_t rx_bytes, int wait) -{ - struct ipc_message *msg; - unsigned long flags; - - spin_lock_irqsave(&hsw->dsp->spinlock, flags); - - msg = msg_get_empty(hsw); - if (msg == NULL) { - spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); - return -EBUSY; - } - - if (tx_bytes) - memcpy(msg->tx_data, tx_data, tx_bytes); - - 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; - - list_add_tail(&msg->list, &hsw->tx_list); - spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); - - queue_kthread_work(&hsw->kworker, &hsw->kwork); - - if (wait) - return tx_wait_done(hsw, msg, rx_data); - else - return 0; -} - -static inline int ipc_tx_message_wait(struct sst_hsw *hsw, u32 header, - void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes) -{ - return ipc_tx_message(hsw, header, tx_data, tx_bytes, rx_data, - rx_bytes, 1); -} - -static inline int ipc_tx_message_nowait(struct sst_hsw *hsw, u32 header, - void *tx_data, size_t tx_bytes) -{ - return ipc_tx_message(hsw, header, tx_data, tx_bytes, NULL, 0, 0); -} - static void hsw_fw_ready(struct sst_hsw *hsw, u32 header) { struct sst_hsw_ipc_fw_ready fw_ready; @@ -696,27 +519,6 @@ static void hsw_notification_work(struct work_struct *work) sst_dsp_shim_update_bits(hsw->dsp, SST_IMRX, SST_IMRX_BUSY, 0); } -static struct ipc_message *reply_find_msg(struct sst_hsw *hsw, u32 header) -{ - struct ipc_message *msg; - - /* clear reply bits & status bits */ - header &= ~(IPC_STATUS_MASK | IPC_GLB_REPLY_MASK); - - if (list_empty(&hsw->rx_list)) { - dev_err(hsw->dev, "error: rx list empty but received 0x%x\n", - header); - return NULL; - } - - list_for_each_entry(msg, &hsw->rx_list, list) { - if (msg->header == header) - return msg; - } - - return NULL; -} - static void hsw_stream_update(struct sst_hsw *hsw, struct ipc_message *msg) { struct sst_hsw_stream *stream; @@ -755,7 +557,7 @@ static int hsw_process_reply(struct sst_hsw *hsw, u32 header) trace_ipc_reply("processing -->", header); - msg = reply_find_msg(hsw, header); + msg = sst_ipc_reply_find_msg(&hsw->ipc, header); if (msg == NULL) { trace_ipc_error("error: can't find message header", header); return -EIO; @@ -766,14 +568,14 @@ static int hsw_process_reply(struct sst_hsw *hsw, u32 header) case IPC_GLB_REPLY_PENDING: trace_ipc_pending_reply("received", header); msg->pending = true; - hsw->pending = true; + hsw->ipc.pending = true; return 1; case IPC_GLB_REPLY_SUCCESS: if (msg->pending) { trace_ipc_pending_reply("completed", header); sst_dsp_inbox_read(hsw->dsp, msg->rx_data, msg->rx_size); - hsw->pending = false; + hsw->ipc.pending = false; } else { /* copy data from the DSP */ sst_dsp_outbox_read(hsw->dsp, msg->rx_data, @@ -829,7 +631,7 @@ static int hsw_process_reply(struct sst_hsw *hsw, u32 header) /* wake up and return the error if we have waiters on this message ? */ list_del(&msg->list); - tx_msg_reply_complete(hsw, msg); + sst_ipc_tx_msg_reply_complete(&hsw->ipc, msg); return 1; } @@ -970,6 +772,7 @@ static irqreturn_t hsw_irq_thread(int irq, void *context) { struct sst_dsp *sst = (struct sst_dsp *) context; struct sst_hsw *hsw = sst_dsp_get_thread_context(sst); + struct sst_generic_ipc *ipc = &hsw->ipc; u32 ipcx, ipcd; int handled; unsigned long flags; @@ -1016,7 +819,7 @@ static irqreturn_t hsw_irq_thread(int irq, void *context) spin_unlock_irqrestore(&sst->spinlock, flags); /* continue to send any remaining messages... */ - queue_kthread_work(&hsw->kworker, &hsw->kwork); + queue_kthread_work(&ipc->kworker, &ipc->kwork); return IRQ_HANDLED; } @@ -1026,7 +829,8 @@ int sst_hsw_fw_get_version(struct sst_hsw *hsw, { int ret; - ret = ipc_tx_message_wait(hsw, IPC_GLB_TYPE(IPC_GLB_GET_FW_VERSION), + ret = sst_ipc_tx_message_wait(&hsw->ipc, + IPC_GLB_TYPE(IPC_GLB_GET_FW_VERSION), NULL, 0, version, sizeof(*version)); if (ret < 0) dev_err(hsw->dev, "error: get version failed\n"); @@ -1090,7 +894,8 @@ int sst_hsw_stream_set_volume(struct sst_hsw *hsw, req->channel = channel; } - ret = ipc_tx_message_wait(hsw, header, req, sizeof(*req), NULL, 0); + ret = sst_ipc_tx_message_wait(&hsw->ipc, header, req, + sizeof(*req), NULL, 0); if (ret < 0) { dev_err(hsw->dev, "error: set stream volume failed\n"); return ret; @@ -1155,7 +960,8 @@ int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, req.curve_type = hsw->curve_type; req.target_volume = volume; - ret = ipc_tx_message_wait(hsw, header, &req, sizeof(req), NULL, 0); + ret = sst_ipc_tx_message_wait(&hsw->ipc, header, &req, + sizeof(req), NULL, 0); if (ret < 0) { dev_err(hsw->dev, "error: set mixer volume failed\n"); return ret; @@ -1213,7 +1019,7 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream) stream->free_req.stream_id = stream->reply.stream_hw_id; header = IPC_GLB_TYPE(IPC_GLB_FREE_STREAM); - ret = ipc_tx_message_wait(hsw, header, &stream->free_req, + ret = sst_ipc_tx_message_wait(&hsw->ipc, header, &stream->free_req, sizeof(stream->free_req), NULL, 0); if (ret < 0) { dev_err(hsw->dev, "error: free stream %d failed\n", @@ -1405,8 +1211,8 @@ int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream) header = IPC_GLB_TYPE(IPC_GLB_ALLOCATE_STREAM); - ret = ipc_tx_message_wait(hsw, header, str_req, sizeof(*str_req), - reply, sizeof(*reply)); + ret = sst_ipc_tx_message_wait(&hsw->ipc, header, str_req, + sizeof(*str_req), reply, sizeof(*reply)); if (ret < 0) { dev_err(hsw->dev, "error: stream commit failed\n"); return ret; @@ -1455,7 +1261,8 @@ int sst_hsw_mixer_get_info(struct sst_hsw *hsw) trace_ipc_request("get global mixer info", 0); - ret = ipc_tx_message_wait(hsw, header, NULL, 0, reply, sizeof(*reply)); + ret = sst_ipc_tx_message_wait(&hsw->ipc, header, NULL, 0, + reply, sizeof(*reply)); if (ret < 0) { dev_err(hsw->dev, "error: get stream info failed\n"); return ret; @@ -1476,9 +1283,10 @@ static int sst_hsw_stream_operations(struct sst_hsw *hsw, int type, header |= (stream_id << IPC_STR_ID_SHIFT); if (wait) - return ipc_tx_message_wait(hsw, header, NULL, 0, NULL, 0); + return sst_ipc_tx_message_wait(&hsw->ipc, header, + NULL, 0, NULL, 0); else - return ipc_tx_message_nowait(hsw, header, NULL, 0); + return sst_ipc_tx_message_nowait(&hsw->ipc, header, NULL, 0); } /* Stream ALSA trigger operations */ @@ -1605,8 +1413,8 @@ int sst_hsw_device_set_config(struct sst_hsw *hsw, header = IPC_GLB_TYPE(IPC_GLB_SET_DEVICE_FORMATS); - ret = ipc_tx_message_wait(hsw, header, &config, sizeof(config), - NULL, 0); + ret = sst_ipc_tx_message_wait(&hsw->ipc, header, &config, + sizeof(config), NULL, 0); if (ret < 0) dev_err(hsw->dev, "error: set device formats failed\n"); @@ -1626,8 +1434,8 @@ int sst_hsw_dx_set_state(struct sst_hsw *hsw, trace_ipc_request("PM enter Dx state", state); - ret = ipc_tx_message_wait(hsw, header, &state_, sizeof(state_), - dx, sizeof(*dx)); + ret = sst_ipc_tx_message_wait(&hsw->ipc, header, &state_, + sizeof(state_), dx, sizeof(*dx)); if (ret < 0) { dev_err(hsw->dev, "ipc: error set dx state %d failed\n", state); return ret; @@ -1770,32 +1578,6 @@ static int sst_hsw_dx_state_restore(struct sst_hsw *hsw) return 0; } -static void sst_hsw_drop_all(struct sst_hsw *hsw) -{ - struct 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(&hsw->dsp->spinlock, flags); - - list_for_each_entry_safe(msg, tmp, &hsw->tx_list, list) { - list_move(&msg->list, &hsw->empty_list); - tx_drop_cnt++; - } - - list_for_each_entry_safe(msg, tmp, &hsw->rx_list, list) { - list_move(&msg->list, &hsw->empty_list); - rx_drop_cnt++; - } - - spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); - - if (tx_drop_cnt || rx_drop_cnt) - dev_err(hsw->dev, "dropped IPC msg RX=%d, TX=%d\n", - tx_drop_cnt, rx_drop_cnt); -} - int sst_hsw_dsp_load(struct sst_hsw *hsw) { struct sst_dsp *dsp = hsw->dsp; @@ -1875,7 +1657,7 @@ int sst_hsw_dsp_runtime_suspend(struct sst_hsw *hsw) if (ret < 0) return ret; - sst_hsw_drop_all(hsw); + sst_ipc_drop_all(&hsw->ipc); return 0; } @@ -1933,23 +1715,6 @@ int sst_hsw_dsp_runtime_resume(struct sst_hsw *hsw) } #endif -static int msg_empty_list_init(struct sst_hsw *hsw) -{ - int i; - - hsw->msg = kzalloc(sizeof(struct ipc_message) * - IPC_EMPTY_LIST_SIZE, GFP_KERNEL); - if (hsw->msg == NULL) - return -ENOMEM; - - for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { - init_waitqueue_head(&hsw->msg[i].waitq); - list_add(&hsw->msg[i].list, &hsw->empty_list); - } - - return 0; -} - struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw) { return hsw->dsp; @@ -2184,7 +1949,7 @@ int sst_hsw_module_enable(struct sst_hsw *hsw, config.scratch_mem.size, config.scratch_mem.offset, config.map.module_entries[0].entry_point); - ret = ipc_tx_message_wait(hsw, header, + ret = sst_ipc_tx_message_wait(&hsw->ipc, header, &config, sizeof(config), NULL, 0); if (ret < 0) dev_err(dev, "ipc: module enable failed - %d\n", ret); @@ -2223,7 +1988,7 @@ int sst_hsw_module_disable(struct sst_hsw *hsw, IPC_MODULE_OPERATION(IPC_MODULE_DISABLE) | IPC_MODULE_ID(module_id); - ret = ipc_tx_message_wait(hsw, header, NULL, 0, NULL, 0); + ret = sst_ipc_tx_message_wait(&hsw->ipc, header, NULL, 0, NULL, 0); if (ret < 0) dev_err(dev, "module disable failed - %d\n", ret); else @@ -2277,7 +2042,7 @@ int sst_hsw_module_set_param(struct sst_hsw *hsw, parameter->parameter_id = parameter_id; parameter->data_size = param_size; - ret = ipc_tx_message_wait(hsw, header, + ret = sst_ipc_tx_message_wait(&hsw->ipc, header, parameter, transfer_parameter_size , NULL, 0); if (ret < 0) dev_err(dev, "ipc: module set parameter failed - %d\n", ret); @@ -2296,10 +2061,48 @@ static struct sst_dsp_device hsw_dev = { .ops = &haswell_ops, }; +static void hsw_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) +{ + /* send the message */ + sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size); + sst_dsp_ipc_msg_tx(ipc->dsp, msg->header); +} + +static void hsw_shim_dbg(struct sst_generic_ipc *ipc, const char *text) +{ + struct sst_dsp *sst = ipc->dsp; + u32 isr, ipcd, imrx, ipcx; + + ipcx = sst_dsp_shim_read_unlocked(sst, SST_IPCX); + isr = sst_dsp_shim_read_unlocked(sst, SST_ISRX); + ipcd = sst_dsp_shim_read_unlocked(sst, SST_IPCD); + imrx = sst_dsp_shim_read_unlocked(sst, SST_IMRX); + + dev_err(ipc->dev, + "ipc: --%s-- ipcx 0x%8.8x isr 0x%8.8x ipcd 0x%8.8x imrx 0x%8.8x\n", + text, ipcx, isr, ipcd, imrx); +} + +static void hsw_tx_data_copy(struct ipc_message *msg, char *tx_data, + size_t tx_size) +{ + memcpy(msg->tx_data, tx_data, tx_size); +} + +static u64 hsw_reply_msg_match(u64 header, u64 *mask) +{ + /* clear reply bits & status bits */ + header &= ~(IPC_STATUS_MASK | IPC_GLB_REPLY_MASK); + *mask = (u64)-1; + + return header; +} + int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) { struct sst_hsw_ipc_fw_version version; struct sst_hsw *hsw; + struct sst_generic_ipc *ipc; int ret; dev_dbg(dev, "initialising Audio DSP IPC\n"); @@ -2308,39 +2111,30 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) if (hsw == NULL) return -ENOMEM; - hsw->dev = dev; + ipc = &hsw->ipc; + ipc->dev = dev; + ipc->ops.tx_msg = hsw_tx_msg; + ipc->ops.shim_dbg = hsw_shim_dbg; + ipc->ops.tx_data_copy = hsw_tx_data_copy; + ipc->ops.reply_msg_match = hsw_reply_msg_match; + + ret = sst_ipc_init(ipc); + if (ret != 0) + goto ipc_init_err; + INIT_LIST_HEAD(&hsw->stream_list); - INIT_LIST_HEAD(&hsw->tx_list); - INIT_LIST_HEAD(&hsw->rx_list); - INIT_LIST_HEAD(&hsw->empty_list); init_waitqueue_head(&hsw->boot_wait); - init_waitqueue_head(&hsw->wait_txq); - - ret = msg_empty_list_init(hsw); - if (ret < 0) - return -ENOMEM; - - /* start the IPC message thread */ - init_kthread_worker(&hsw->kworker); - hsw->tx_thread = kthread_run(kthread_worker_fn, - &hsw->kworker, "%s", - dev_name(hsw->dev)); - if (IS_ERR(hsw->tx_thread)) { - ret = PTR_ERR(hsw->tx_thread); - dev_err(hsw->dev, "error: failed to create message TX task\n"); - goto err_free_msg; - } - init_kthread_work(&hsw->kwork, ipc_tx_msgs); - hsw_dev.thread_context = hsw; /* init SST shim */ hsw->dsp = sst_dsp_new(dev, &hsw_dev, pdata); if (hsw->dsp == NULL) { ret = -ENODEV; - goto dsp_err; + goto dsp_new_err; } + ipc->dsp = hsw->dsp; + /* allocate DMA buffer for context storage */ hsw->dx_context = dma_alloc_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE, &hsw->dx_context_paddr, GFP_KERNEL); @@ -2404,11 +2198,10 @@ fw_err: hsw->dx_context, hsw->dx_context_paddr); dma_err: sst_dsp_free(hsw->dsp); -dsp_err: - kthread_stop(hsw->tx_thread); -err_free_msg: - kfree(hsw->msg); - +dsp_new_err: + sst_ipc_fini(ipc); +ipc_init_err: + kfree(hsw); return ret; } EXPORT_SYMBOL_GPL(sst_hsw_dsp_init); @@ -2422,7 +2215,6 @@ void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata) dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE, hsw->dx_context, hsw->dx_context_paddr); sst_dsp_free(hsw->dsp); - kthread_stop(hsw->tx_thread); - kfree(hsw->msg); + sst_ipc_fini(&hsw->ipc); } EXPORT_SYMBOL_GPL(sst_hsw_dsp_free); From a5e5e12bd4ed5cd1123ace4300b5c07230fbf21e Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Mon, 13 Apr 2015 02:16:21 +0800 Subject: [PATCH 32/32] ASoC: Intel: fix array_size.cocci warnings sound/soc/intel/haswell/sst-haswell-ipc.c:646:28-29: WARNING: Use ARRAY_SIZE Use ARRAY_SIZE instead of dividing sizeof array with sizeof an element Semantic patch information: This makes an effort to find cases where ARRAY_SIZE can be used such as where there is a division of sizeof the array by the sizeof its first element or by any indexed element or the element type. It replaces the division of the two sizeofs by ARRAY_SIZE. Generated by: scripts/coccinelle/misc/array_size.cocci CC: Jie Yang Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown --- sound/soc/intel/haswell/sst-haswell-ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c index d75f09eb30b7..344a1e9bbce5 100644 --- a/sound/soc/intel/haswell/sst-haswell-ipc.c +++ b/sound/soc/intel/haswell/sst-haswell-ipc.c @@ -466,7 +466,7 @@ static void hsw_fw_ready(struct sst_hsw *hsw, u32 header) /* log the FW version info got from the mailbox here. */ memcpy(fw_info, fw_ready.fw_info, fw_ready.fw_info_size); pinfo = &fw_info[0]; - for (i = 0; i < sizeof(tmp) / sizeof(char *); i++) + for (i = 0; i < ARRAY_SIZE(tmp); i++) tmp[i] = strsep(&pinfo, " "); dev_info(hsw->dev, "FW loaded, mailbox readback FW info: type %s, - " "version: %s.%s, build %s, source commit id: %s\n",