Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
8707344e
K
Kernel
项目概览
openeuler
/
Kernel
1 年多 前同步成功
通知
8
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
Kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
8707344e
编写于
10月 26, 2015
作者:
M
Mark Brown
浏览文件
操作
浏览文件
下载
差异文件
Merge remote-tracking branches 'asoc/topic/imx' and 'asoc/topic/intel' into asoc-next
上级
f72362e6
43ac9469
6abca1d7
变更
22
隐藏空白更改
内联
并排
Showing
22 changed file
with
1905 addition
and
88 deletion
+1905
-88
sound/soc/fsl/imx-spdif.c
sound/soc/fsl/imx-spdif.c
+1
-0
sound/soc/intel/Kconfig
sound/soc/intel/Kconfig
+14
-0
sound/soc/intel/boards/Makefile
sound/soc/intel/boards/Makefile
+2
-0
sound/soc/intel/boards/skl_rt286.c
sound/soc/intel/boards/skl_rt286.c
+259
-0
sound/soc/intel/common/Makefile
sound/soc/intel/common/Makefile
+5
-1
sound/soc/intel/common/sst-dsp-priv.h
sound/soc/intel/common/sst-dsp-priv.h
+1
-0
sound/soc/intel/common/sst-dsp.c
sound/soc/intel/common/sst-dsp.c
+2
-0
sound/soc/intel/common/sst-dsp.h
sound/soc/intel/common/sst-dsp.h
+2
-0
sound/soc/intel/common/sst-firmware.c
sound/soc/intel/common/sst-firmware.c
+2
-8
sound/soc/intel/skylake/Makefile
sound/soc/intel/skylake/Makefile
+2
-1
sound/soc/intel/skylake/skl-messages.c
sound/soc/intel/skylake/skl-messages.c
+39
-5
sound/soc/intel/skylake/skl-nhlt.c
sound/soc/intel/skylake/skl-nhlt.c
+5
-5
sound/soc/intel/skylake/skl-pcm.c
sound/soc/intel/skylake/skl-pcm.c
+114
-29
sound/soc/intel/skylake/skl-sst-dsp.c
sound/soc/intel/skylake/skl-sst-dsp.c
+6
-1
sound/soc/intel/skylake/skl-sst-ipc.c
sound/soc/intel/skylake/skl-sst-ipc.c
+12
-0
sound/soc/intel/skylake/skl-sst-ipc.h
sound/soc/intel/skylake/skl-sst-ipc.h
+1
-0
sound/soc/intel/skylake/skl-sst.c
sound/soc/intel/skylake/skl-sst.c
+30
-26
sound/soc/intel/skylake/skl-topology.c
sound/soc/intel/skylake/skl-topology.c
+1252
-0
sound/soc/intel/skylake/skl-topology.h
sound/soc/intel/skylake/skl-topology.h
+34
-2
sound/soc/intel/skylake/skl-tplg-interface.h
sound/soc/intel/skylake/skl-tplg-interface.h
+83
-0
sound/soc/intel/skylake/skl.c
sound/soc/intel/skylake/skl.c
+25
-7
sound/soc/intel/skylake/skl.h
sound/soc/intel/skylake/skl.h
+14
-3
未找到文件。
sound/soc/fsl/imx-spdif.c
浏览文件 @
8707344e
...
...
@@ -89,6 +89,7 @@ MODULE_DEVICE_TABLE(of, imx_spdif_dt_ids);
static
struct
platform_driver
imx_spdif_driver
=
{
.
driver
=
{
.
name
=
"imx-spdif"
,
.
pm
=
&
snd_soc_pm_ops
,
.
of_match_table
=
imx_spdif_dt_ids
,
},
.
probe
=
imx_spdif_audio_probe
,
...
...
sound/soc/intel/Kconfig
浏览文件 @
8707344e
...
...
@@ -139,4 +139,18 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH
config SND_SOC_INTEL_SKYLAKE
tristate
select SND_HDA_EXT_CORE
select SND_SOC_TOPOLOGY
select SND_SOC_INTEL_SST
config SND_SOC_INTEL_SKL_RT286_MACH
tristate "ASoC Audio driver for SKL with RT286 I2S mode"
depends on X86 && ACPI
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SKYLAKE
select SND_SOC_RT286
select SND_SOC_DMIC
help
This adds support for ASoC machine driver for Skylake platforms
with RT286 I2S audio codec.
Say Y if you have such a device
If unsure select "N".
sound/soc/intel/boards/Makefile
浏览文件 @
8707344e
...
...
@@ -6,6 +6,7 @@ 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
snd-soc-sst-cht-bsw-max98090_ti-objs
:=
cht_bsw_max98090_ti.o
snd-soc-skl_rt286-objs
:=
skl_rt286.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
...
...
@@ -15,3 +16,4 @@ 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
obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH)
+=
snd-soc-sst-cht-bsw-max98090_ti.o
obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH)
+=
snd-soc-skl_rt286.o
sound/soc/intel/boards/skl_rt286.c
0 → 100644
浏览文件 @
8707344e
/*
* Intel Skylake I2S Machine Driver
*
* Copyright (C) 2014-2015, Intel Corporation. All rights reserved.
*
* Modified from:
* Intel Broadwell Wildcatpoint SST Audio
*
* Copyright (C) 2013, 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 <linux/module.h>
#include <linux/platform_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/jack.h>
#include <sound/pcm_params.h>
#include "../../codecs/rt286.h"
static
struct
snd_soc_jack
skylake_headset
;
/* Headset jack detection DAPM pins */
static
struct
snd_soc_jack_pin
skylake_headset_pins
[]
=
{
{
.
pin
=
"Mic Jack"
,
.
mask
=
SND_JACK_MICROPHONE
,
},
{
.
pin
=
"Headphone Jack"
,
.
mask
=
SND_JACK_HEADPHONE
,
},
};
static
const
struct
snd_kcontrol_new
skylake_controls
[]
=
{
SOC_DAPM_PIN_SWITCH
(
"Speaker"
),
SOC_DAPM_PIN_SWITCH
(
"Headphone Jack"
),
SOC_DAPM_PIN_SWITCH
(
"Mic Jack"
),
};
static
const
struct
snd_soc_dapm_widget
skylake_widgets
[]
=
{
SND_SOC_DAPM_HP
(
"Headphone Jack"
,
NULL
),
SND_SOC_DAPM_SPK
(
"Speaker"
,
NULL
),
SND_SOC_DAPM_MIC
(
"Mic Jack"
,
NULL
),
SND_SOC_DAPM_MIC
(
"DMIC2"
,
NULL
),
SND_SOC_DAPM_MIC
(
"SoC DMIC"
,
NULL
),
};
static
const
struct
snd_soc_dapm_route
skylake_rt286_map
[]
=
{
/* speaker */
{
"Speaker"
,
NULL
,
"SPOR"
},
{
"Speaker"
,
NULL
,
"SPOL"
},
/* HP jack connectors - unknown if we have jack deteck */
{
"Headphone Jack"
,
NULL
,
"HPO Pin"
},
/* other jacks */
{
"MIC1"
,
NULL
,
"Mic Jack"
},
/* digital mics */
{
"DMIC1 Pin"
,
NULL
,
"DMIC2"
},
{
"DMIC AIF"
,
NULL
,
"SoC DMIC"
},
/* CODEC BE connections */
{
"AIF1 Playback"
,
NULL
,
"ssp0 Tx"
},
{
"ssp0 Tx"
,
NULL
,
"codec0_out"
},
{
"ssp0 Tx"
,
NULL
,
"codec1_out"
},
{
"codec0_in"
,
NULL
,
"ssp0 Rx"
},
{
"codec1_in"
,
NULL
,
"ssp0 Rx"
},
{
"ssp0 Rx"
,
NULL
,
"AIF1 Capture"
},
{
"dmic01_hifi"
,
NULL
,
"DMIC01 Rx"
},
{
"DMIC01 Rx"
,
NULL
,
"Capture"
},
{
"hif1"
,
NULL
,
"iDisp Tx"
},
{
"iDisp Tx"
,
NULL
,
"iDisp_out"
},
};
static
int
skylake_rt286_codec_init
(
struct
snd_soc_pcm_runtime
*
rtd
)
{
struct
snd_soc_codec
*
codec
=
rtd
->
codec
;
int
ret
;
ret
=
snd_soc_card_jack_new
(
rtd
->
card
,
"Headset"
,
SND_JACK_HEADSET
|
SND_JACK_BTN_0
,
&
skylake_headset
,
skylake_headset_pins
,
ARRAY_SIZE
(
skylake_headset_pins
));
if
(
ret
)
return
ret
;
rt286_mic_detect
(
codec
,
&
skylake_headset
);
return
0
;
}
static
int
skylake_ssp0_fixup
(
struct
snd_soc_pcm_runtime
*
rtd
,
struct
snd_pcm_hw_params
*
params
)
{
struct
snd_interval
*
rate
=
hw_param_interval
(
params
,
SNDRV_PCM_HW_PARAM_RATE
);
struct
snd_interval
*
channels
=
hw_param_interval
(
params
,
SNDRV_PCM_HW_PARAM_CHANNELS
);
/* The output is 48KHz, stereo, 16bits */
rate
->
min
=
rate
->
max
=
48000
;
channels
->
min
=
channels
->
max
=
2
;
params_set_format
(
params
,
SNDRV_PCM_FORMAT_S16_LE
);
return
0
;
}
static
int
skylake_rt286_hw_params
(
struct
snd_pcm_substream
*
substream
,
struct
snd_pcm_hw_params
*
params
)
{
struct
snd_soc_pcm_runtime
*
rtd
=
substream
->
private_data
;
struct
snd_soc_dai
*
codec_dai
=
rtd
->
codec_dai
;
int
ret
;
ret
=
snd_soc_dai_set_sysclk
(
codec_dai
,
RT286_SCLK_S_PLL
,
24000000
,
SND_SOC_CLOCK_IN
);
if
(
ret
<
0
)
dev_err
(
rtd
->
dev
,
"set codec sysclk failed: %d
\n
"
,
ret
);
return
ret
;
}
static
struct
snd_soc_ops
skylake_rt286_ops
=
{
.
hw_params
=
skylake_rt286_hw_params
,
};
/* skylake digital audio interface glue - connects codec <--> CPU */
static
struct
snd_soc_dai_link
skylake_rt286_dais
[]
=
{
/* Front End DAI links */
{
.
name
=
"Skl Audio Port"
,
.
stream_name
=
"Audio"
,
.
cpu_dai_name
=
"System Pin"
,
.
platform_name
=
"0000:00:1f.3"
,
.
nonatomic
=
1
,
.
dynamic
=
1
,
.
codec_name
=
"snd-soc-dummy"
,
.
codec_dai_name
=
"snd-soc-dummy-dai"
,
.
trigger
=
{
SND_SOC_DPCM_TRIGGER_POST
,
SND_SOC_DPCM_TRIGGER_POST
},
.
dpcm_playback
=
1
,
},
{
.
name
=
"Skl Audio Capture Port"
,
.
stream_name
=
"Audio Record"
,
.
cpu_dai_name
=
"System Pin"
,
.
platform_name
=
"0000:00:1f.3"
,
.
nonatomic
=
1
,
.
dynamic
=
1
,
.
codec_name
=
"snd-soc-dummy"
,
.
codec_dai_name
=
"snd-soc-dummy-dai"
,
.
trigger
=
{
SND_SOC_DPCM_TRIGGER_POST
,
SND_SOC_DPCM_TRIGGER_POST
},
.
dpcm_capture
=
1
,
},
{
.
name
=
"Skl Audio Reference cap"
,
.
stream_name
=
"refcap"
,
.
cpu_dai_name
=
"Reference Pin"
,
.
codec_name
=
"snd-soc-dummy"
,
.
codec_dai_name
=
"snd-soc-dummy-dai"
,
.
platform_name
=
"0000:00:1f.3"
,
.
init
=
NULL
,
.
dpcm_capture
=
1
,
.
ignore_suspend
=
1
,
.
nonatomic
=
1
,
.
dynamic
=
1
,
},
/* Back End DAI links */
{
/* SSP0 - Codec */
.
name
=
"SSP0-Codec"
,
.
be_id
=
0
,
.
cpu_dai_name
=
"SSP0 Pin"
,
.
platform_name
=
"0000:00:1f.3"
,
.
no_pcm
=
1
,
.
codec_name
=
"i2c-INT343A:00"
,
.
codec_dai_name
=
"rt286-aif1"
,
.
init
=
skylake_rt286_codec_init
,
.
dai_fmt
=
SND_SOC_DAIFMT_I2S
|
SND_SOC_DAIFMT_NB_NF
|
SND_SOC_DAIFMT_CBS_CFS
,
.
ignore_suspend
=
1
,
.
ignore_pmdown_time
=
1
,
.
be_hw_params_fixup
=
skylake_ssp0_fixup
,
.
ops
=
&
skylake_rt286_ops
,
.
dpcm_playback
=
1
,
.
dpcm_capture
=
1
,
},
{
.
name
=
"dmic01"
,
.
be_id
=
1
,
.
cpu_dai_name
=
"DMIC01 Pin"
,
.
codec_name
=
"dmic-codec"
,
.
codec_dai_name
=
"dmic-hifi"
,
.
platform_name
=
"0000:00:1f.3"
,
.
ignore_suspend
=
1
,
.
dpcm_capture
=
1
,
.
no_pcm
=
1
,
},
};
/* skylake audio machine driver for SPT + RT286S */
static
struct
snd_soc_card
skylake_rt286
=
{
.
name
=
"skylake-rt286"
,
.
owner
=
THIS_MODULE
,
.
dai_link
=
skylake_rt286_dais
,
.
num_links
=
ARRAY_SIZE
(
skylake_rt286_dais
),
.
controls
=
skylake_controls
,
.
num_controls
=
ARRAY_SIZE
(
skylake_controls
),
.
dapm_widgets
=
skylake_widgets
,
.
num_dapm_widgets
=
ARRAY_SIZE
(
skylake_widgets
),
.
dapm_routes
=
skylake_rt286_map
,
.
num_dapm_routes
=
ARRAY_SIZE
(
skylake_rt286_map
),
.
fully_routed
=
true
,
};
static
int
skylake_audio_probe
(
struct
platform_device
*
pdev
)
{
skylake_rt286
.
dev
=
&
pdev
->
dev
;
return
devm_snd_soc_register_card
(
&
pdev
->
dev
,
&
skylake_rt286
);
}
static
struct
platform_driver
skylake_audio
=
{
.
probe
=
skylake_audio_probe
,
.
driver
=
{
.
name
=
"skl_alc286s_i2s"
,
},
};
module_platform_driver
(
skylake_audio
)
/* Module information */
MODULE_AUTHOR
(
"Omair Mohammed Abdullah <omair.m.abdullah@intel.com>"
);
MODULE_DESCRIPTION
(
"Intel SST Audio for Skylake"
);
MODULE_LICENSE
(
"GPL v2"
);
MODULE_ALIAS
(
"platform:skl_alc286s_i2s"
);
sound/soc/intel/common/Makefile
浏览文件 @
8707344e
snd-soc-sst-dsp-objs
:=
sst-dsp.o
sst-firmware.o
snd-soc-sst-dsp-objs
:=
sst-dsp.o
snd-soc-sst-acpi-objs
:=
sst-acpi.o
snd-soc-sst-ipc-objs
:=
sst-ipc.o
ifneq
($(CONFIG_DW_DMAC_CORE),)
snd-soc-sst-dsp-objs
+=
sst-firmware.o
endif
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
sound/soc/intel/common/sst-dsp-priv.h
浏览文件 @
8707344e
...
...
@@ -314,6 +314,7 @@ struct sst_dsp {
int
sst_state
;
struct
skl_cl_dev
cl_dev
;
u32
intr_status
;
const
struct
firmware
*
fw
;
};
/* Size optimised DRAM/IRAM memcpy */
...
...
sound/soc/intel/common/sst-dsp.c
浏览文件 @
8707344e
...
...
@@ -420,6 +420,7 @@ void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes)
}
EXPORT_SYMBOL_GPL
(
sst_dsp_inbox_read
);
#if IS_ENABLED(CONFIG_DW_DMAC_CORE)
struct
sst_dsp
*
sst_dsp_new
(
struct
device
*
dev
,
struct
sst_dsp_device
*
sst_dev
,
struct
sst_pdata
*
pdata
)
{
...
...
@@ -484,6 +485,7 @@ void sst_dsp_free(struct sst_dsp *sst)
sst_dma_free
(
sst
->
dma
);
}
EXPORT_SYMBOL_GPL
(
sst_dsp_free
);
#endif
/* Module information */
MODULE_AUTHOR
(
"Liam Girdwood"
);
...
...
sound/soc/intel/common/sst-dsp.h
浏览文件 @
8707344e
...
...
@@ -216,10 +216,12 @@ struct sst_pdata {
void
*
dsp
;
};
#if IS_ENABLED(CONFIG_DW_DMAC_CORE)
/* Initialization */
struct
sst_dsp
*
sst_dsp_new
(
struct
device
*
dev
,
struct
sst_dsp_device
*
sst_dev
,
struct
sst_pdata
*
pdata
);
void
sst_dsp_free
(
struct
sst_dsp
*
sst
);
#endif
/* SHIM Read / Write */
void
sst_dsp_shim_write
(
struct
sst_dsp
*
sst
,
u32
offset
,
u32
value
);
...
...
sound/soc/intel/common/sst-firmware.c
浏览文件 @
8707344e
...
...
@@ -26,7 +26,6 @@
#include <linux/acpi.h>
/* supported DMA engine drivers */
#include <linux/platform_data/dma-dw.h>
#include <linux/dma/dw.h>
#include <asm/page.h>
...
...
@@ -169,12 +168,6 @@ static int block_list_prepare(struct sst_dsp *dsp,
return
ret
;
}
static
struct
dw_dma_platform_data
dw_pdata
=
{
.
is_private
=
1
,
.
chan_allocation_order
=
CHAN_ALLOCATION_ASCENDING
,
.
chan_priority
=
CHAN_PRIORITY_ASCENDING
,
};
static
struct
dw_dma_chip
*
dw_probe
(
struct
device
*
dev
,
struct
resource
*
mem
,
int
irq
)
{
...
...
@@ -195,7 +188,8 @@ static struct dw_dma_chip *dw_probe(struct device *dev, struct resource *mem,
return
ERR_PTR
(
err
);
chip
->
dev
=
dev
;
err
=
dw_dma_probe
(
chip
,
&
dw_pdata
);
err
=
dw_dma_probe
(
chip
,
NULL
);
if
(
err
)
return
ERR_PTR
(
err
);
...
...
sound/soc/intel/skylake/Makefile
浏览文件 @
8707344e
snd-soc-skl-objs
:=
skl.o skl-pcm.o skl-nhlt.o skl-messages.o
snd-soc-skl-objs
:=
skl.o skl-pcm.o skl-nhlt.o skl-messages.o
\
skl-topology.o
obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE)
+=
snd-soc-skl.o
...
...
sound/soc/intel/skylake/skl-messages.c
浏览文件 @
8707344e
...
...
@@ -54,6 +54,24 @@ static int skl_free_dma_buf(struct device *dev, struct snd_dma_buffer *dmab)
return
0
;
}
#define NOTIFICATION_PARAM_ID 3
#define NOTIFICATION_MASK 0xf
/* disable notfication for underruns/overruns from firmware module */
static
void
skl_dsp_enable_notification
(
struct
skl_sst
*
ctx
,
bool
enable
)
{
struct
notification_mask
mask
;
struct
skl_ipc_large_config_msg
msg
=
{
0
};
mask
.
notify
=
NOTIFICATION_MASK
;
mask
.
enable
=
enable
;
msg
.
large_param_id
=
NOTIFICATION_PARAM_ID
;
msg
.
param_data_size
=
sizeof
(
mask
);
skl_ipc_set_large_config
(
&
ctx
->
ipc
,
&
msg
,
(
u32
*
)
&
mask
);
}
int
skl_init_dsp
(
struct
skl
*
skl
)
{
void
__iomem
*
mmio_base
;
...
...
@@ -79,7 +97,10 @@ int skl_init_dsp(struct skl *skl)
ret
=
skl_sst_dsp_init
(
bus
->
dev
,
mmio_base
,
irq
,
loader_ops
,
&
skl
->
skl_sst
);
if
(
ret
<
0
)
return
ret
;
skl_dsp_enable_notification
(
skl
->
skl_sst
,
false
);
dev_dbg
(
bus
->
dev
,
"dsp registration status=%d
\n
"
,
ret
);
return
ret
;
...
...
@@ -122,6 +143,7 @@ int skl_suspend_dsp(struct skl *skl)
int
skl_resume_dsp
(
struct
skl
*
skl
)
{
struct
skl_sst
*
ctx
=
skl
->
skl_sst
;
int
ret
;
/* if ppcap is not supported return 0 */
if
(
!
skl
->
ebus
.
ppcap
)
...
...
@@ -131,7 +153,12 @@ int skl_resume_dsp(struct skl *skl)
snd_hdac_ext_bus_ppcap_enable
(
&
skl
->
ebus
,
true
);
snd_hdac_ext_bus_ppcap_int_enable
(
&
skl
->
ebus
,
true
);
return
skl_dsp_wake
(
ctx
->
dsp
);
ret
=
skl_dsp_wake
(
ctx
->
dsp
);
if
(
ret
<
0
)
return
ret
;
skl_dsp_enable_notification
(
skl
->
skl_sst
,
false
);
return
ret
;
}
enum
skl_bitdepth
skl_get_bit_depth
(
int
params
)
...
...
@@ -294,6 +321,7 @@ static void skl_copy_copier_caps(struct skl_module_cfg *mconfig,
(
mconfig
->
formats_config
.
caps_size
)
/
4
;
}
#define SKL_NON_GATEWAY_CPR_NODE_ID 0xFFFFFFFF
/*
* Calculate the gatewat settings required for copier module, type of
* gateway and index of gateway to use
...
...
@@ -303,6 +331,7 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
struct
skl_cpr_cfg
*
cpr_mconfig
)
{
union
skl_connector_node_id
node_id
=
{
0
};
union
skl_ssp_dma_node
ssp_node
=
{
0
};
struct
skl_pipe_params
*
params
=
mconfig
->
pipe
->
p_params
;
switch
(
mconfig
->
dev_type
)
{
...
...
@@ -320,9 +349,9 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
(
SKL_CONN_SOURCE
==
mconfig
->
hw_conn_type
)
?
SKL_DMA_I2S_LINK_OUTPUT_CLASS
:
SKL_DMA_I2S_LINK_INPUT_CLASS
;
node_id
.
node
.
vindex
=
params
->
host_dma_id
+
(
mconfig
->
time_slot
<<
1
)
+
(
mconfig
->
vbus_id
<<
3
)
;
ssp_node
.
dma_node
.
time_slot_index
=
mconfig
->
time_slot
;
ssp_node
.
dma_node
.
i2s_instance
=
mconfig
->
vbus_id
;
node_id
.
node
.
vindex
=
ssp_node
.
val
;
break
;
case
SKL_DEVICE_DMIC
:
...
...
@@ -339,13 +368,18 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
node_id
.
node
.
vindex
=
params
->
link_dma_id
;
break
;
default
:
case
SKL_DEVICE_HDAHOST
:
node_id
.
node
.
dma_type
=
(
SKL_CONN_SOURCE
==
mconfig
->
hw_conn_type
)
?
SKL_DMA_HDA_HOST_OUTPUT_CLASS
:
SKL_DMA_HDA_HOST_INPUT_CLASS
;
node_id
.
node
.
vindex
=
params
->
host_dma_id
;
break
;
default:
cpr_mconfig
->
gtw_cfg
.
node_id
=
SKL_NON_GATEWAY_CPR_NODE_ID
;
cpr_mconfig
->
cpr_feature_mask
=
0
;
return
;
}
cpr_mconfig
->
gtw_cfg
.
node_id
=
node_id
.
val
;
...
...
sound/soc/intel/skylake/skl-nhlt.c
浏览文件 @
8707344e
...
...
@@ -25,7 +25,7 @@ static u8 OSC_UUID[16] = {0x6E, 0x88, 0x9F, 0xA6, 0xEB, 0x6C, 0x94, 0x45,
#define DSDT_NHLT_PATH "\\_SB.PCI0.HDAS"
void
__iomem
*
skl_nhlt_init
(
struct
device
*
dev
)
void
*
skl_nhlt_init
(
struct
device
*
dev
)
{
acpi_handle
handle
;
union
acpi_object
*
obj
;
...
...
@@ -40,17 +40,17 @@ void __iomem *skl_nhlt_init(struct device *dev)
if
(
obj
&&
obj
->
type
==
ACPI_TYPE_BUFFER
)
{
nhlt_ptr
=
(
struct
nhlt_resource_desc
*
)
obj
->
buffer
.
pointer
;
return
ioremap_cache
(
nhlt_ptr
->
min_addr
,
nhlt_ptr
->
length
);
return
memremap
(
nhlt_ptr
->
min_addr
,
nhlt_ptr
->
length
,
MEMREMAP_WB
);
}
dev_err
(
dev
,
"device specific method to extract NHLT blob failed
\n
"
);
return
NULL
;
}
void
skl_nhlt_free
(
void
__iomem
*
addr
)
void
skl_nhlt_free
(
void
*
addr
)
{
iounmap
(
addr
);
addr
=
NULL
;
memunmap
(
addr
);
}
static
struct
nhlt_specific_cfg
*
skl_get_specific_cfg
(
...
...
sound/soc/intel/skylake/skl-pcm.c
浏览文件 @
8707344e
...
...
@@ -24,6 +24,7 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include "skl.h"
#include "skl-topology.h"
#define HDA_MONO 1
#define HDA_STEREO 2
...
...
@@ -115,7 +116,7 @@ static int skl_pcm_open(struct snd_pcm_substream *substream,
dev_dbg
(
dai
->
dev
,
"%s: %s
\n
"
,
__func__
,
dai
->
name
);
ret
=
pm_runtime_get_sync
(
dai
->
dev
);
if
(
ret
)
if
(
ret
<
0
)
return
ret
;
stream
=
snd_hdac_ext_stream_assign
(
ebus
,
substream
,
...
...
@@ -214,6 +215,8 @@ static int skl_pcm_hw_params(struct snd_pcm_substream *substream,
struct
hdac_ext_bus
*
ebus
=
dev_get_drvdata
(
dai
->
dev
);
struct
hdac_ext_stream
*
stream
=
get_hdac_ext_stream
(
substream
);
struct
snd_pcm_runtime
*
runtime
=
substream
->
runtime
;
struct
skl_pipe_params
p_params
=
{
0
};
struct
skl_module_cfg
*
m_cfg
;
int
ret
,
dma_id
;
dev_dbg
(
dai
->
dev
,
"%s: %s
\n
"
,
__func__
,
dai
->
name
);
...
...
@@ -228,6 +231,16 @@ static int skl_pcm_hw_params(struct snd_pcm_substream *substream,
dma_id
=
hdac_stream
(
stream
)
->
stream_tag
-
1
;
dev_dbg
(
dai
->
dev
,
"dma_id=%d
\n
"
,
dma_id
);
p_params
.
s_fmt
=
snd_pcm_format_width
(
params_format
(
params
));
p_params
.
ch
=
params_channels
(
params
);
p_params
.
s_freq
=
params_rate
(
params
);
p_params
.
host_dma_id
=
dma_id
;
p_params
.
stream
=
substream
->
stream
;
m_cfg
=
skl_tplg_fe_get_cpr_module
(
dai
,
p_params
.
stream
);
if
(
m_cfg
)
skl_tplg_update_pipe_params
(
dai
->
dev
,
m_cfg
,
&
p_params
);
return
0
;
}
...
...
@@ -268,6 +281,46 @@ static int skl_pcm_hw_free(struct snd_pcm_substream *substream,
return
skl_substream_free_pages
(
ebus_to_hbus
(
ebus
),
substream
);
}
static
int
skl_be_hw_params
(
struct
snd_pcm_substream
*
substream
,
struct
snd_pcm_hw_params
*
params
,
struct
snd_soc_dai
*
dai
)
{
struct
skl_pipe_params
p_params
=
{
0
};
p_params
.
s_fmt
=
snd_pcm_format_width
(
params_format
(
params
));
p_params
.
ch
=
params_channels
(
params
);
p_params
.
s_freq
=
params_rate
(
params
);
p_params
.
stream
=
substream
->
stream
;
skl_tplg_be_update_params
(
dai
,
&
p_params
);
return
0
;
}
static
int
skl_pcm_trigger
(
struct
snd_pcm_substream
*
substream
,
int
cmd
,
struct
snd_soc_dai
*
dai
)
{
struct
skl
*
skl
=
get_skl_ctx
(
dai
->
dev
);
struct
skl_sst
*
ctx
=
skl
->
skl_sst
;
struct
skl_module_cfg
*
mconfig
;
mconfig
=
skl_tplg_fe_get_cpr_module
(
dai
,
substream
->
stream
);
if
(
!
mconfig
)
return
-
EIO
;
switch
(
cmd
)
{
case
SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
case
SNDRV_PCM_TRIGGER_RESUME
:
return
skl_run_pipe
(
ctx
,
mconfig
->
pipe
);
case
SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
case
SNDRV_PCM_TRIGGER_SUSPEND
:
return
skl_stop_pipe
(
ctx
,
mconfig
->
pipe
);
default:
return
0
;
}
}
static
int
skl_link_hw_params
(
struct
snd_pcm_substream
*
substream
,
struct
snd_pcm_hw_params
*
params
,
struct
snd_soc_dai
*
dai
)
...
...
@@ -277,9 +330,8 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
struct
snd_soc_pcm_runtime
*
rtd
=
snd_pcm_substream_chip
(
substream
);
struct
skl_dma_params
*
dma_params
;
struct
snd_soc_dai
*
codec_dai
=
rtd
->
codec_dai
;
int
dma_id
;
struct
skl_pipe_params
p_params
=
{
0
}
;
pr_debug
(
"%s
\n
"
,
__func__
);
link_dev
=
snd_hdac_ext_stream_assign
(
ebus
,
substream
,
HDAC_EXT_STREAM_TYPE_LINK
);
if
(
!
link_dev
)
...
...
@@ -293,7 +345,14 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
if
(
dma_params
)
dma_params
->
stream_tag
=
hdac_stream
(
link_dev
)
->
stream_tag
;
snd_soc_dai_set_dma_data
(
codec_dai
,
substream
,
(
void
*
)
dma_params
);
dma_id
=
hdac_stream
(
link_dev
)
->
stream_tag
-
1
;
p_params
.
s_fmt
=
snd_pcm_format_width
(
params_format
(
params
));
p_params
.
ch
=
params_channels
(
params
);
p_params
.
s_freq
=
params_rate
(
params
);
p_params
.
stream
=
substream
->
stream
;
p_params
.
link_dma_id
=
hdac_stream
(
link_dev
)
->
stream_tag
-
1
;
skl_tplg_be_update_params
(
dai
,
&
p_params
);
return
0
;
}
...
...
@@ -308,27 +367,12 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream,
unsigned
int
format_val
=
0
;
struct
skl_dma_params
*
dma_params
;
struct
snd_soc_dai
*
codec_dai
=
rtd
->
codec_dai
;
struct
snd_pcm_hw_params
*
params
;
struct
snd_interval
*
channels
,
*
rate
;
struct
hdac_ext_link
*
link
;
dev_dbg
(
dai
->
dev
,
"%s: %s
\n
"
,
__func__
,
dai
->
name
);
if
(
link_dev
->
link_prepared
)
{
dev_dbg
(
dai
->
dev
,
"already stream is prepared - returning
\n
"
);
return
0
;
}
params
=
devm_kzalloc
(
dai
->
dev
,
sizeof
(
*
params
),
GFP_KERNEL
);
if
(
params
==
NULL
)
return
-
ENOMEM
;
channels
=
hw_param_interval
(
params
,
SNDRV_PCM_HW_PARAM_CHANNELS
);
channels
->
min
=
channels
->
max
=
substream
->
runtime
->
channels
;
rate
=
hw_param_interval
(
params
,
SNDRV_PCM_HW_PARAM_RATE
);
rate
->
min
=
rate
->
max
=
substream
->
runtime
->
rate
;
snd_mask_set
(
&
params
->
masks
[
SNDRV_PCM_HW_PARAM_FORMAT
-
SNDRV_PCM_HW_PARAM_FIRST_MASK
],
substream
->
runtime
->
format
);
dma_params
=
(
struct
skl_dma_params
*
)
snd_soc_dai_get_dma_data
(
codec_dai
,
substream
);
...
...
@@ -399,13 +443,13 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream,
return
0
;
}
static
int
skl_
hda_
be_startup
(
struct
snd_pcm_substream
*
substream
,
static
int
skl_be_startup
(
struct
snd_pcm_substream
*
substream
,
struct
snd_soc_dai
*
dai
)
{
return
pm_runtime_get_sync
(
dai
->
dev
);
}
static
void
skl_
hda_
be_shutdown
(
struct
snd_pcm_substream
*
substream
,
static
void
skl_be_shutdown
(
struct
snd_pcm_substream
*
substream
,
struct
snd_soc_dai
*
dai
)
{
pm_runtime_mark_last_busy
(
dai
->
dev
);
...
...
@@ -418,20 +462,28 @@ static struct snd_soc_dai_ops skl_pcm_dai_ops = {
.
prepare
=
skl_pcm_prepare
,
.
hw_params
=
skl_pcm_hw_params
,
.
hw_free
=
skl_pcm_hw_free
,
.
trigger
=
skl_pcm_trigger
,
};
static
struct
snd_soc_dai_ops
skl_dmic_dai_ops
=
{
.
startup
=
skl_hda_be_startup
,
.
shutdown
=
skl_hda_be_shutdown
,
.
startup
=
skl_be_startup
,
.
hw_params
=
skl_be_hw_params
,
.
shutdown
=
skl_be_shutdown
,
};
static
struct
snd_soc_dai_ops
skl_be_ssp_dai_ops
=
{
.
startup
=
skl_be_startup
,
.
hw_params
=
skl_be_hw_params
,
.
shutdown
=
skl_be_shutdown
,
};
static
struct
snd_soc_dai_ops
skl_link_dai_ops
=
{
.
startup
=
skl_
hda_
be_startup
,
.
startup
=
skl_be_startup
,
.
prepare
=
skl_link_pcm_prepare
,
.
hw_params
=
skl_link_hw_params
,
.
hw_free
=
skl_link_hw_free
,
.
trigger
=
skl_link_pcm_trigger
,
.
shutdown
=
skl_
hda_
be_shutdown
,
.
shutdown
=
skl_be_shutdown
,
};
static
struct
snd_soc_dai_driver
skl_platform_dai
[]
=
{
...
...
@@ -487,6 +539,24 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
},
},
/* BE CPU Dais */
{
.
name
=
"SSP0 Pin"
,
.
ops
=
&
skl_be_ssp_dai_ops
,
.
playback
=
{
.
stream_name
=
"ssp0 Tx"
,
.
channels_min
=
HDA_STEREO
,
.
channels_max
=
HDA_STEREO
,
.
rates
=
SNDRV_PCM_RATE_48000
,
.
formats
=
SNDRV_PCM_FMTBIT_S16_LE
,
},
.
capture
=
{
.
stream_name
=
"ssp0 Rx"
,
.
channels_min
=
HDA_STEREO
,
.
channels_max
=
HDA_STEREO
,
.
rates
=
SNDRV_PCM_RATE_48000
,
.
formats
=
SNDRV_PCM_FMTBIT_S16_LE
,
},
},
{
.
name
=
"iDisp Pin"
,
.
ops
=
&
skl_link_dai_ops
,
...
...
@@ -544,7 +614,7 @@ static int skl_platform_open(struct snd_pcm_substream *substream)
return
0
;
}
static
int
skl_
pcm
_trigger
(
struct
snd_pcm_substream
*
substream
,
static
int
skl_
coupled
_trigger
(
struct
snd_pcm_substream
*
substream
,
int
cmd
)
{
struct
hdac_ext_bus
*
ebus
=
get_bus_ctx
(
substream
);
...
...
@@ -618,7 +688,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream,
return
0
;
}
static
int
skl_d
sp
_trigger
(
struct
snd_pcm_substream
*
substream
,
static
int
skl_d
ecoupled
_trigger
(
struct
snd_pcm_substream
*
substream
,
int
cmd
)
{
struct
hdac_ext_bus
*
ebus
=
get_bus_ctx
(
substream
);
...
...
@@ -675,9 +745,9 @@ static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream,
struct
hdac_ext_bus
*
ebus
=
get_bus_ctx
(
substream
);
if
(
ebus
->
ppcap
)
return
skl_d
sp
_trigger
(
substream
,
cmd
);
return
skl_d
ecoupled
_trigger
(
substream
,
cmd
);
else
return
skl_
pcm
_trigger
(
substream
,
cmd
);
return
skl_
coupled
_trigger
(
substream
,
cmd
);
}
/* calculate runtime delay from LPIB */
...
...
@@ -844,7 +914,17 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd)
return
retval
;
}
static
int
skl_platform_soc_probe
(
struct
snd_soc_platform
*
platform
)
{
struct
hdac_ext_bus
*
ebus
=
dev_get_drvdata
(
platform
->
dev
);
if
(
ebus
->
ppcap
)
return
skl_tplg_init
(
platform
,
ebus
);
return
0
;
}
static
struct
snd_soc_platform_driver
skl_platform_drv
=
{
.
probe
=
skl_platform_soc_probe
,
.
ops
=
&
skl_platform_ops
,
.
pcm_new
=
skl_pcm_new
,
.
pcm_free
=
skl_pcm_free
,
...
...
@@ -857,6 +937,11 @@ static const struct snd_soc_component_driver skl_component = {
int
skl_platform_register
(
struct
device
*
dev
)
{
int
ret
;
struct
hdac_ext_bus
*
ebus
=
dev_get_drvdata
(
dev
);
struct
skl
*
skl
=
ebus_to_skl
(
ebus
);
INIT_LIST_HEAD
(
&
skl
->
ppl_list
);
INIT_LIST_HEAD
(
&
skl
->
dapm_path_list
);
ret
=
snd_soc_register_platform
(
dev
,
&
skl_platform_drv
);
if
(
ret
)
{
...
...
sound/soc/intel/skylake/skl-sst-dsp.c
浏览文件 @
8707344e
...
...
@@ -175,7 +175,7 @@ static int skl_dsp_core_power_down(struct sst_dsp *ctx)
/* poll with timeout to check if operation successful */
return
sst_dsp_register_poll
(
ctx
,
SKL_ADSP_REG_ADSPCS
,
SKL_ADSPCS_
S
PA_MASK
,
SKL_ADSPCS_
C
PA_MASK
,
0
,
SKL_DSP_PD_TO
,
"Power down"
);
...
...
@@ -262,6 +262,11 @@ irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id)
val
=
sst_dsp_shim_read_unlocked
(
ctx
,
SKL_ADSP_REG_ADSPIS
);
ctx
->
intr_status
=
val
;
if
(
val
==
0xffffffff
)
{
spin_unlock
(
&
ctx
->
spinlock
);
return
IRQ_NONE
;
}
if
(
val
&
SKL_ADSPIS_IPC
)
{
skl_ipc_int_disable
(
ctx
);
result
=
IRQ_WAKE_THREAD
;
...
...
sound/soc/intel/skylake/skl-sst-ipc.c
浏览文件 @
8707344e
...
...
@@ -464,6 +464,18 @@ void skl_ipc_op_int_enable(struct sst_dsp *ctx)
SKL_ADSP_REG_HIPCCTL_BUSY
,
SKL_ADSP_REG_HIPCCTL_BUSY
);
}
void
skl_ipc_op_int_disable
(
struct
sst_dsp
*
ctx
)
{
/* disable IPC DONE interrupt */
sst_dsp_shim_update_bits_unlocked
(
ctx
,
SKL_ADSP_REG_HIPCCTL
,
SKL_ADSP_REG_HIPCCTL_DONE
,
0
);
/* Disable IPC BUSY interrupt */
sst_dsp_shim_update_bits_unlocked
(
ctx
,
SKL_ADSP_REG_HIPCCTL
,
SKL_ADSP_REG_HIPCCTL_BUSY
,
0
);
}
bool
skl_ipc_int_status
(
struct
sst_dsp
*
ctx
)
{
return
sst_dsp_shim_read_unlocked
(
ctx
,
...
...
sound/soc/intel/skylake/skl-sst-ipc.h
浏览文件 @
8707344e
...
...
@@ -116,6 +116,7 @@ int skl_ipc_set_large_config(struct sst_generic_ipc *ipc,
void
skl_ipc_int_enable
(
struct
sst_dsp
*
dsp
);
void
skl_ipc_op_int_enable
(
struct
sst_dsp
*
ctx
);
void
skl_ipc_op_int_disable
(
struct
sst_dsp
*
ctx
);
void
skl_ipc_int_disable
(
struct
sst_dsp
*
dsp
);
bool
skl_ipc_int_status
(
struct
sst_dsp
*
dsp
);
...
...
sound/soc/intel/skylake/skl-sst.c
浏览文件 @
8707344e
...
...
@@ -70,15 +70,31 @@ static int skl_transfer_firmware(struct sst_dsp *ctx,
static
int
skl_load_base_firmware
(
struct
sst_dsp
*
ctx
)
{
int
ret
=
0
,
i
;
const
struct
firmware
*
fw
=
NULL
;
struct
skl_sst
*
skl
=
ctx
->
thread_context
;
u32
reg
;
ret
=
request_firmware
(
&
fw
,
"dsp_fw_release.bin"
,
ctx
->
dev
);
skl
->
boot_complete
=
false
;
init_waitqueue_head
(
&
skl
->
boot_wait
);
if
(
ctx
->
fw
==
NULL
)
{
ret
=
request_firmware
(
&
ctx
->
fw
,
"dsp_fw_release.bin"
,
ctx
->
dev
);
if
(
ret
<
0
)
{
dev_err
(
ctx
->
dev
,
"Request firmware failed %d
\n
"
,
ret
);
skl_dsp_disable_core
(
ctx
);
return
-
EIO
;
}
}
ret
=
skl_dsp_boot
(
ctx
);
if
(
ret
<
0
)
{
dev_err
(
ctx
->
dev
,
"Request firmware failed %d
\n
"
,
ret
);
skl_dsp_disable_core
(
ctx
);
return
-
EIO
;
dev_err
(
ctx
->
dev
,
"Boot dsp core failed ret: %d"
,
ret
);
goto
skl_load_base_firmware_failed
;
}
ret
=
skl_cldma_prepare
(
ctx
);
if
(
ret
<
0
)
{
dev_err
(
ctx
->
dev
,
"CL dma prepare failed : %d"
,
ret
);
goto
skl_load_base_firmware_failed
;
}
/* enable Interrupt */
...
...
@@ -102,7 +118,7 @@ static int skl_load_base_firmware(struct sst_dsp *ctx)
goto
skl_load_base_firmware_failed
;
}
ret
=
skl_transfer_firmware
(
ctx
,
fw
->
data
,
fw
->
size
);
ret
=
skl_transfer_firmware
(
ctx
,
ctx
->
fw
->
data
,
ctx
->
fw
->
size
);
if
(
ret
<
0
)
{
dev_err
(
ctx
->
dev
,
"Transfer firmware failed%d
\n
"
,
ret
);
goto
skl_load_base_firmware_failed
;
...
...
@@ -118,13 +134,12 @@ static int skl_load_base_firmware(struct sst_dsp *ctx)
dev_dbg
(
ctx
->
dev
,
"Download firmware successful%d
\n
"
,
ret
);
skl_dsp_set_state_locked
(
ctx
,
SKL_DSP_RUNNING
);
}
release_firmware
(
fw
);
return
0
;
skl_load_base_firmware_failed:
skl_dsp_disable_core
(
ctx
);
release_firmware
(
fw
);
release_firmware
(
ctx
->
fw
);
ctx
->
fw
=
NULL
;
return
ret
;
}
...
...
@@ -172,6 +187,12 @@ static int skl_set_dsp_D3(struct sst_dsp *ctx)
}
skl_dsp_set_state_locked
(
ctx
,
SKL_DSP_RESET
);
/* disable Interrupt */
ctx
->
cl_dev
.
ops
.
cl_cleanup_controller
(
ctx
);
skl_cldma_int_disable
(
ctx
);
skl_ipc_op_int_disable
(
ctx
);
skl_ipc_int_disable
(
ctx
);
return
ret
;
}
...
...
@@ -235,22 +256,6 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
if
(
ret
)
return
ret
;
skl
->
boot_complete
=
false
;
init_waitqueue_head
(
&
skl
->
boot_wait
);
ret
=
skl_dsp_boot
(
sst
);
if
(
ret
<
0
)
{
dev_err
(
skl
->
dev
,
"Boot dsp core failed ret: %d"
,
ret
);
goto
free_ipc
;
}
ret
=
skl_cldma_prepare
(
sst
);
if
(
ret
<
0
)
{
dev_err
(
dev
,
"CL dma prepare failed : %d"
,
ret
);
goto
free_ipc
;
}
ret
=
sst
->
fw_ops
.
load_fw
(
sst
);
if
(
ret
<
0
)
{
dev_err
(
dev
,
"Load base fw failed : %d"
,
ret
);
...
...
@@ -262,7 +267,6 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
return
0
;
free_ipc:
skl_ipc_free
(
&
skl
->
ipc
);
return
ret
;
}
...
...
sound/soc/intel/skylake/skl-topology.c
0 → 100644
浏览文件 @
8707344e
/*
* skl-topology.c - Implements Platform component ALSA controls/widget
* handlers.
*
* Copyright (C) 2014-2015 Intel Corp
* Author: Jeeja KP <jeeja.kp@intel.com>
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as 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 <linux/slab.h>
#include <linux/types.h>
#include <linux/firmware.h>
#include <sound/soc.h>
#include <sound/soc-topology.h>
#include "skl-sst-dsp.h"
#include "skl-sst-ipc.h"
#include "skl-topology.h"
#include "skl.h"
#include "skl-tplg-interface.h"
#define SKL_CH_FIXUP_MASK (1 << 0)
#define SKL_RATE_FIXUP_MASK (1 << 1)
#define SKL_FMT_FIXUP_MASK (1 << 2)
/*
* SKL DSP driver modelling uses only few DAPM widgets so for rest we will
* ignore. This helpers checks if the SKL driver handles this widget type
*/
static
int
is_skl_dsp_widget_type
(
struct
snd_soc_dapm_widget
*
w
)
{
switch
(
w
->
id
)
{
case
snd_soc_dapm_dai_link
:
case
snd_soc_dapm_dai_in
:
case
snd_soc_dapm_aif_in
:
case
snd_soc_dapm_aif_out
:
case
snd_soc_dapm_dai_out
:
case
snd_soc_dapm_switch
:
return
false
;
default:
return
true
;
}
}
/*
* Each pipelines needs memory to be allocated. Check if we have free memory
* from available pool. Then only add this to pool
* This is freed when pipe is deleted
* Note: DSP does actual memory management we only keep track for complete
* pool
*/
static
bool
skl_tplg_alloc_pipe_mem
(
struct
skl
*
skl
,
struct
skl_module_cfg
*
mconfig
)
{
struct
skl_sst
*
ctx
=
skl
->
skl_sst
;
if
(
skl
->
resource
.
mem
+
mconfig
->
pipe
->
memory_pages
>
skl
->
resource
.
max_mem
)
{
dev_err
(
ctx
->
dev
,
"%s: module_id %d instance %d
\n
"
,
__func__
,
mconfig
->
id
.
module_id
,
mconfig
->
id
.
instance_id
);
dev_err
(
ctx
->
dev
,
"exceeds ppl memory available %d mem %d
\n
"
,
skl
->
resource
.
max_mem
,
skl
->
resource
.
mem
);
return
false
;
}
skl
->
resource
.
mem
+=
mconfig
->
pipe
->
memory_pages
;
return
true
;
}
/*
* Pipeline needs needs DSP CPU resources for computation, this is
* quantified in MCPS (Million Clocks Per Second) required for module/pipe
*
* Each pipelines needs mcps to be allocated. Check if we have mcps for this
* pipe. This adds the mcps to driver counter
* This is removed on pipeline delete
*/
static
bool
skl_tplg_alloc_pipe_mcps
(
struct
skl
*
skl
,
struct
skl_module_cfg
*
mconfig
)
{
struct
skl_sst
*
ctx
=
skl
->
skl_sst
;
if
(
skl
->
resource
.
mcps
+
mconfig
->
mcps
>
skl
->
resource
.
max_mcps
)
{
dev_err
(
ctx
->
dev
,
"%s: module_id %d instance %d
\n
"
,
__func__
,
mconfig
->
id
.
module_id
,
mconfig
->
id
.
instance_id
);
dev_err
(
ctx
->
dev
,
"exceeds ppl memory available %d > mem %d
\n
"
,
skl
->
resource
.
max_mcps
,
skl
->
resource
.
mcps
);
return
false
;
}
skl
->
resource
.
mcps
+=
mconfig
->
mcps
;
return
true
;
}
/*
* Free the mcps when tearing down
*/
static
void
skl_tplg_free_pipe_mcps
(
struct
skl
*
skl
,
struct
skl_module_cfg
*
mconfig
)
{
skl
->
resource
.
mcps
-=
mconfig
->
mcps
;
}
/*
* Free the memory when tearing down
*/
static
void
skl_tplg_free_pipe_mem
(
struct
skl
*
skl
,
struct
skl_module_cfg
*
mconfig
)
{
skl
->
resource
.
mem
-=
mconfig
->
pipe
->
memory_pages
;
}
static
void
skl_dump_mconfig
(
struct
skl_sst
*
ctx
,
struct
skl_module_cfg
*
mcfg
)
{
dev_dbg
(
ctx
->
dev
,
"Dumping config
\n
"
);
dev_dbg
(
ctx
->
dev
,
"Input Format:
\n
"
);
dev_dbg
(
ctx
->
dev
,
"channels = %d
\n
"
,
mcfg
->
in_fmt
.
channels
);
dev_dbg
(
ctx
->
dev
,
"s_freq = %d
\n
"
,
mcfg
->
in_fmt
.
s_freq
);
dev_dbg
(
ctx
->
dev
,
"ch_cfg = %d
\n
"
,
mcfg
->
in_fmt
.
ch_cfg
);
dev_dbg
(
ctx
->
dev
,
"valid bit depth = %d
\n
"
,
mcfg
->
in_fmt
.
valid_bit_depth
);
dev_dbg
(
ctx
->
dev
,
"Output Format:
\n
"
);
dev_dbg
(
ctx
->
dev
,
"channels = %d
\n
"
,
mcfg
->
out_fmt
.
channels
);
dev_dbg
(
ctx
->
dev
,
"s_freq = %d
\n
"
,
mcfg
->
out_fmt
.
s_freq
);
dev_dbg
(
ctx
->
dev
,
"valid bit depth = %d
\n
"
,
mcfg
->
out_fmt
.
valid_bit_depth
);
dev_dbg
(
ctx
->
dev
,
"ch_cfg = %d
\n
"
,
mcfg
->
out_fmt
.
ch_cfg
);
}
static
void
skl_tplg_update_params
(
struct
skl_module_fmt
*
fmt
,
struct
skl_pipe_params
*
params
,
int
fixup
)
{
if
(
fixup
&
SKL_RATE_FIXUP_MASK
)
fmt
->
s_freq
=
params
->
s_freq
;
if
(
fixup
&
SKL_CH_FIXUP_MASK
)
fmt
->
channels
=
params
->
ch
;
if
(
fixup
&
SKL_FMT_FIXUP_MASK
)
fmt
->
valid_bit_depth
=
params
->
s_fmt
;
}
/*
* A pipeline may have modules which impact the pcm parameters, like SRC,
* channel converter, format converter.
* We need to calculate the output params by applying the 'fixup'
* Topology will tell driver which type of fixup is to be applied by
* supplying the fixup mask, so based on that we calculate the output
*
* Now In FE the pcm hw_params is source/target format. Same is applicable
* for BE with its hw_params invoked.
* here based on FE, BE pipeline and direction we calculate the input and
* outfix and then apply that for a module
*/
static
void
skl_tplg_update_params_fixup
(
struct
skl_module_cfg
*
m_cfg
,
struct
skl_pipe_params
*
params
,
bool
is_fe
)
{
int
in_fixup
,
out_fixup
;
struct
skl_module_fmt
*
in_fmt
,
*
out_fmt
;
in_fmt
=
&
m_cfg
->
in_fmt
;
out_fmt
=
&
m_cfg
->
out_fmt
;
if
(
params
->
stream
==
SNDRV_PCM_STREAM_PLAYBACK
)
{
if
(
is_fe
)
{
in_fixup
=
m_cfg
->
params_fixup
;
out_fixup
=
(
~
m_cfg
->
converter
)
&
m_cfg
->
params_fixup
;
}
else
{
out_fixup
=
m_cfg
->
params_fixup
;
in_fixup
=
(
~
m_cfg
->
converter
)
&
m_cfg
->
params_fixup
;
}
}
else
{
if
(
is_fe
)
{
out_fixup
=
m_cfg
->
params_fixup
;
in_fixup
=
(
~
m_cfg
->
converter
)
&
m_cfg
->
params_fixup
;
}
else
{
in_fixup
=
m_cfg
->
params_fixup
;
out_fixup
=
(
~
m_cfg
->
converter
)
&
m_cfg
->
params_fixup
;
}
}
skl_tplg_update_params
(
in_fmt
,
params
,
in_fixup
);
skl_tplg_update_params
(
out_fmt
,
params
,
out_fixup
);
}
/*
* A module needs input and output buffers, which are dependent upon pcm
* params, so once we have calculate params, we need buffer calculation as
* well.
*/
static
void
skl_tplg_update_buffer_size
(
struct
skl_sst
*
ctx
,
struct
skl_module_cfg
*
mcfg
)
{
int
multiplier
=
1
;
if
(
mcfg
->
m_type
==
SKL_MODULE_TYPE_SRCINT
)
multiplier
=
5
;
mcfg
->
ibs
=
(
mcfg
->
in_fmt
.
s_freq
/
1000
)
*
(
mcfg
->
in_fmt
.
channels
)
*
(
mcfg
->
in_fmt
.
bit_depth
>>
3
)
*
multiplier
;
mcfg
->
obs
=
(
mcfg
->
out_fmt
.
s_freq
/
1000
)
*
(
mcfg
->
out_fmt
.
channels
)
*
(
mcfg
->
out_fmt
.
bit_depth
>>
3
)
*
multiplier
;
}
static
void
skl_tplg_update_module_params
(
struct
snd_soc_dapm_widget
*
w
,
struct
skl_sst
*
ctx
)
{
struct
skl_module_cfg
*
m_cfg
=
w
->
priv
;
struct
skl_pipe_params
*
params
=
m_cfg
->
pipe
->
p_params
;
int
p_conn_type
=
m_cfg
->
pipe
->
conn_type
;
bool
is_fe
;
if
(
!
m_cfg
->
params_fixup
)
return
;
dev_dbg
(
ctx
->
dev
,
"Mconfig for widget=%s BEFORE updation
\n
"
,
w
->
name
);
skl_dump_mconfig
(
ctx
,
m_cfg
);
if
(
p_conn_type
==
SKL_PIPE_CONN_TYPE_FE
)
is_fe
=
true
;
else
is_fe
=
false
;
skl_tplg_update_params_fixup
(
m_cfg
,
params
,
is_fe
);
skl_tplg_update_buffer_size
(
ctx
,
m_cfg
);
dev_dbg
(
ctx
->
dev
,
"Mconfig for widget=%s AFTER updation
\n
"
,
w
->
name
);
skl_dump_mconfig
(
ctx
,
m_cfg
);
}
/*
* A pipe can have multiple modules, each of them will be a DAPM widget as
* well. While managing a pipeline we need to get the list of all the
* widgets in a pipelines, so this helper - skl_tplg_get_pipe_widget() helps
* to get the SKL type widgets in that pipeline
*/
static
int
skl_tplg_alloc_pipe_widget
(
struct
device
*
dev
,
struct
snd_soc_dapm_widget
*
w
,
struct
skl_pipe
*
pipe
)
{
struct
skl_module_cfg
*
src_module
=
NULL
;
struct
snd_soc_dapm_path
*
p
=
NULL
;
struct
skl_pipe_module
*
p_module
=
NULL
;
p_module
=
devm_kzalloc
(
dev
,
sizeof
(
*
p_module
),
GFP_KERNEL
);
if
(
!
p_module
)
return
-
ENOMEM
;
p_module
->
w
=
w
;
list_add_tail
(
&
p_module
->
node
,
&
pipe
->
w_list
);
snd_soc_dapm_widget_for_each_sink_path
(
w
,
p
)
{
if
((
p
->
sink
->
priv
==
NULL
)
&&
(
!
is_skl_dsp_widget_type
(
w
)))
continue
;
if
((
p
->
sink
->
priv
!=
NULL
)
&&
p
->
connect
&&
is_skl_dsp_widget_type
(
p
->
sink
))
{
src_module
=
p
->
sink
->
priv
;
if
(
pipe
->
ppl_id
==
src_module
->
pipe
->
ppl_id
)
skl_tplg_alloc_pipe_widget
(
dev
,
p
->
sink
,
pipe
);
}
}
return
0
;
}
/*
* Inside a pipe instance, we can have various modules. These modules need
* to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by
* skl_init_module() routine, so invoke that for all modules in a pipeline
*/
static
int
skl_tplg_init_pipe_modules
(
struct
skl
*
skl
,
struct
skl_pipe
*
pipe
)
{
struct
skl_pipe_module
*
w_module
;
struct
snd_soc_dapm_widget
*
w
;
struct
skl_module_cfg
*
mconfig
;
struct
skl_sst
*
ctx
=
skl
->
skl_sst
;
int
ret
=
0
;
list_for_each_entry
(
w_module
,
&
pipe
->
w_list
,
node
)
{
w
=
w_module
->
w
;
mconfig
=
w
->
priv
;
/* check resource available */
if
(
!
skl_tplg_alloc_pipe_mcps
(
skl
,
mconfig
))
return
-
ENOMEM
;
/*
* apply fix/conversion to module params based on
* FE/BE params
*/
skl_tplg_update_module_params
(
w
,
ctx
);
ret
=
skl_init_module
(
ctx
,
mconfig
,
NULL
);
if
(
ret
<
0
)
return
ret
;
}
return
0
;
}
/*
* Mixer module represents a pipeline. So in the Pre-PMU event of mixer we
* need create the pipeline. So we do following:
* - check the resources
* - Create the pipeline
* - Initialize the modules in pipeline
* - finally bind all modules together
*/
static
int
skl_tplg_mixer_dapm_pre_pmu_event
(
struct
snd_soc_dapm_widget
*
w
,
struct
skl
*
skl
)
{
int
ret
;
struct
skl_module_cfg
*
mconfig
=
w
->
priv
;
struct
skl_pipe_module
*
w_module
;
struct
skl_pipe
*
s_pipe
=
mconfig
->
pipe
;
struct
skl_module_cfg
*
src_module
=
NULL
,
*
dst_module
;
struct
skl_sst
*
ctx
=
skl
->
skl_sst
;
/* check resource available */
if
(
!
skl_tplg_alloc_pipe_mcps
(
skl
,
mconfig
))
return
-
EBUSY
;
if
(
!
skl_tplg_alloc_pipe_mem
(
skl
,
mconfig
))
return
-
ENOMEM
;
/*
* Create a list of modules for pipe.
* This list contains modules from source to sink
*/
ret
=
skl_create_pipeline
(
ctx
,
mconfig
->
pipe
);
if
(
ret
<
0
)
return
ret
;
/*
* we create a w_list of all widgets in that pipe. This list is not
* freed on PMD event as widgets within a pipe are static. This
* saves us cycles to get widgets in pipe every time.
*
* So if we have already initialized all the widgets of a pipeline
* we skip, so check for list_empty and create the list if empty
*/
if
(
list_empty
(
&
s_pipe
->
w_list
))
{
ret
=
skl_tplg_alloc_pipe_widget
(
ctx
->
dev
,
w
,
s_pipe
);
if
(
ret
<
0
)
return
ret
;
}
/* Init all pipe modules from source to sink */
ret
=
skl_tplg_init_pipe_modules
(
skl
,
s_pipe
);
if
(
ret
<
0
)
return
ret
;
/* Bind modules from source to sink */
list_for_each_entry
(
w_module
,
&
s_pipe
->
w_list
,
node
)
{
dst_module
=
w_module
->
w
->
priv
;
if
(
src_module
==
NULL
)
{
src_module
=
dst_module
;
continue
;
}
ret
=
skl_bind_modules
(
ctx
,
src_module
,
dst_module
);
if
(
ret
<
0
)
return
ret
;
src_module
=
dst_module
;
}
return
0
;
}
/*
* A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA
* we need to do following:
* - Bind to sink pipeline
* Since the sink pipes can be running and we don't get mixer event on
* connect for already running mixer, we need to find the sink pipes
* here and bind to them. This way dynamic connect works.
* - Start sink pipeline, if not running
* - Then run current pipe
*/
static
int
skl_tplg_pga_dapm_pre_pmu_event
(
struct
snd_soc_dapm_widget
*
w
,
struct
skl
*
skl
)
{
struct
snd_soc_dapm_path
*
p
;
struct
skl_dapm_path_list
*
path_list
;
struct
snd_soc_dapm_widget
*
source
,
*
sink
;
struct
skl_module_cfg
*
src_mconfig
,
*
sink_mconfig
;
struct
skl_sst
*
ctx
=
skl
->
skl_sst
;
int
ret
=
0
;
source
=
w
;
src_mconfig
=
source
->
priv
;
/*
* find which sink it is connected to, bind with the sink,
* if sink is not started, start sink pipe first, then start
* this pipe
*/
snd_soc_dapm_widget_for_each_source_path
(
w
,
p
)
{
if
(
!
p
->
connect
)
continue
;
dev_dbg
(
ctx
->
dev
,
"%s: src widget=%s
\n
"
,
__func__
,
w
->
name
);
dev_dbg
(
ctx
->
dev
,
"%s: sink widget=%s
\n
"
,
__func__
,
p
->
sink
->
name
);
/*
* here we will check widgets in sink pipelines, so that
* can be any widgets type and we are only interested if
* they are ones used for SKL so check that first
*/
if
((
p
->
sink
->
priv
!=
NULL
)
&&
is_skl_dsp_widget_type
(
p
->
sink
))
{
sink
=
p
->
sink
;
src_mconfig
=
source
->
priv
;
sink_mconfig
=
sink
->
priv
;
/* Bind source to sink, mixin is always source */
ret
=
skl_bind_modules
(
ctx
,
src_mconfig
,
sink_mconfig
);
if
(
ret
)
return
ret
;
/* Start sinks pipe first */
if
(
sink_mconfig
->
pipe
->
state
!=
SKL_PIPE_STARTED
)
{
ret
=
skl_run_pipe
(
ctx
,
sink_mconfig
->
pipe
);
if
(
ret
)
return
ret
;
}
path_list
=
kzalloc
(
sizeof
(
struct
skl_dapm_path_list
),
GFP_KERNEL
);
if
(
path_list
==
NULL
)
return
-
ENOMEM
;
/* Add connected path to one global list */
path_list
->
dapm_path
=
p
;
list_add_tail
(
&
path_list
->
node
,
&
skl
->
dapm_path_list
);
break
;
}
}
/* Start source pipe last after starting all sinks */
ret
=
skl_run_pipe
(
ctx
,
src_mconfig
->
pipe
);
if
(
ret
)
return
ret
;
return
0
;
}
/*
* in the Post-PMU event of mixer we need to do following:
* - Check if this pipe is running
* - if not, then
* - bind this pipeline to its source pipeline
* if source pipe is already running, this means it is a dynamic
* connection and we need to bind only to that pipe
* - start this pipeline
*/
static
int
skl_tplg_mixer_dapm_post_pmu_event
(
struct
snd_soc_dapm_widget
*
w
,
struct
skl
*
skl
)
{
int
ret
=
0
;
struct
snd_soc_dapm_path
*
p
;
struct
snd_soc_dapm_widget
*
source
,
*
sink
;
struct
skl_module_cfg
*
src_mconfig
,
*
sink_mconfig
;
struct
skl_sst
*
ctx
=
skl
->
skl_sst
;
int
src_pipe_started
=
0
;
sink
=
w
;
sink_mconfig
=
sink
->
priv
;
/*
* If source pipe is already started, that means source is driving
* one more sink before this sink got connected, Since source is
* started, bind this sink to source and start this pipe.
*/
snd_soc_dapm_widget_for_each_sink_path
(
w
,
p
)
{
if
(
!
p
->
connect
)
continue
;
dev_dbg
(
ctx
->
dev
,
"sink widget=%s
\n
"
,
w
->
name
);
dev_dbg
(
ctx
->
dev
,
"src widget=%s
\n
"
,
p
->
source
->
name
);
/*
* here we will check widgets in sink pipelines, so that
* can be any widgets type and we are only interested if
* they are ones used for SKL so check that first
*/
if
((
p
->
source
->
priv
!=
NULL
)
&&
is_skl_dsp_widget_type
(
p
->
source
))
{
source
=
p
->
source
;
src_mconfig
=
source
->
priv
;
sink_mconfig
=
sink
->
priv
;
src_pipe_started
=
1
;
/*
* check pipe state, then no need to bind or start
* the pipe
*/
if
(
src_mconfig
->
pipe
->
state
!=
SKL_PIPE_STARTED
)
src_pipe_started
=
0
;
}
}
if
(
src_pipe_started
)
{
ret
=
skl_bind_modules
(
ctx
,
src_mconfig
,
sink_mconfig
);
if
(
ret
)
return
ret
;
ret
=
skl_run_pipe
(
ctx
,
sink_mconfig
->
pipe
);
}
return
ret
;
}
/*
* in the Pre-PMD event of mixer we need to do following:
* - Stop the pipe
* - find the source connections and remove that from dapm_path_list
* - unbind with source pipelines if still connected
*/
static
int
skl_tplg_mixer_dapm_pre_pmd_event
(
struct
snd_soc_dapm_widget
*
w
,
struct
skl
*
skl
)
{
struct
snd_soc_dapm_widget
*
source
,
*
sink
;
struct
skl_module_cfg
*
src_mconfig
,
*
sink_mconfig
;
int
ret
=
0
,
path_found
=
0
;
struct
skl_dapm_path_list
*
path_list
,
*
tmp_list
;
struct
skl_sst
*
ctx
=
skl
->
skl_sst
;
sink
=
w
;
sink_mconfig
=
sink
->
priv
;
/* Stop the pipe */
ret
=
skl_stop_pipe
(
ctx
,
sink_mconfig
->
pipe
);
if
(
ret
)
return
ret
;
/*
* This list, dapm_path_list handling here does not need any locks
* as we are under dapm lock while handling widget events.
* List can be manipulated safely only under dapm widgets handler
* routines
*/
list_for_each_entry_safe
(
path_list
,
tmp_list
,
&
skl
->
dapm_path_list
,
node
)
{
if
(
path_list
->
dapm_path
->
sink
==
sink
)
{
dev_dbg
(
ctx
->
dev
,
"Path found = %s
\n
"
,
path_list
->
dapm_path
->
name
);
source
=
path_list
->
dapm_path
->
source
;
src_mconfig
=
source
->
priv
;
path_found
=
1
;
list_del
(
&
path_list
->
node
);
kfree
(
path_list
);
break
;
}
}
/*
* If path_found == 1, that means pmd for source pipe has
* not occurred, source is connected to some other sink.
* so its responsibility of sink to unbind itself from source.
*/
if
(
path_found
)
{
ret
=
skl_stop_pipe
(
ctx
,
src_mconfig
->
pipe
);
if
(
ret
<
0
)
return
ret
;
ret
=
skl_unbind_modules
(
ctx
,
src_mconfig
,
sink_mconfig
);
}
return
ret
;
}
/*
* in the Post-PMD event of mixer we need to do following:
* - Free the mcps used
* - Free the mem used
* - Unbind the modules within the pipeline
* - Delete the pipeline (modules are not required to be explicitly
* deleted, pipeline delete is enough here
*/
static
int
skl_tplg_mixer_dapm_post_pmd_event
(
struct
snd_soc_dapm_widget
*
w
,
struct
skl
*
skl
)
{
struct
skl_module_cfg
*
mconfig
=
w
->
priv
;
struct
skl_pipe_module
*
w_module
;
struct
skl_module_cfg
*
src_module
=
NULL
,
*
dst_module
;
struct
skl_sst
*
ctx
=
skl
->
skl_sst
;
struct
skl_pipe
*
s_pipe
=
mconfig
->
pipe
;
int
ret
=
0
;
skl_tplg_free_pipe_mcps
(
skl
,
mconfig
);
list_for_each_entry
(
w_module
,
&
s_pipe
->
w_list
,
node
)
{
dst_module
=
w_module
->
w
->
priv
;
if
(
src_module
==
NULL
)
{
src_module
=
dst_module
;
continue
;
}
ret
=
skl_unbind_modules
(
ctx
,
src_module
,
dst_module
);
if
(
ret
<
0
)
return
ret
;
src_module
=
dst_module
;
}
ret
=
skl_delete_pipe
(
ctx
,
mconfig
->
pipe
);
skl_tplg_free_pipe_mem
(
skl
,
mconfig
);
return
ret
;
}
/*
* in the Post-PMD event of PGA we need to do following:
* - Free the mcps used
* - Stop the pipeline
* - In source pipe is connected, unbind with source pipelines
*/
static
int
skl_tplg_pga_dapm_post_pmd_event
(
struct
snd_soc_dapm_widget
*
w
,
struct
skl
*
skl
)
{
struct
snd_soc_dapm_widget
*
source
,
*
sink
;
struct
skl_module_cfg
*
src_mconfig
,
*
sink_mconfig
;
int
ret
=
0
,
path_found
=
0
;
struct
skl_dapm_path_list
*
path_list
,
*
tmp_path_list
;
struct
skl_sst
*
ctx
=
skl
->
skl_sst
;
source
=
w
;
src_mconfig
=
source
->
priv
;
skl_tplg_free_pipe_mcps
(
skl
,
src_mconfig
);
/* Stop the pipe since this is a mixin module */
ret
=
skl_stop_pipe
(
ctx
,
src_mconfig
->
pipe
);
if
(
ret
)
return
ret
;
list_for_each_entry_safe
(
path_list
,
tmp_path_list
,
&
skl
->
dapm_path_list
,
node
)
{
if
(
path_list
->
dapm_path
->
source
==
source
)
{
dev_dbg
(
ctx
->
dev
,
"Path found = %s
\n
"
,
path_list
->
dapm_path
->
name
);
sink
=
path_list
->
dapm_path
->
sink
;
sink_mconfig
=
sink
->
priv
;
path_found
=
1
;
list_del
(
&
path_list
->
node
);
kfree
(
path_list
);
break
;
}
}
/*
* This is a connector and if path is found that means
* unbind between source and sink has not happened yet
*/
if
(
path_found
)
{
ret
=
skl_stop_pipe
(
ctx
,
src_mconfig
->
pipe
);
if
(
ret
<
0
)
return
ret
;
ret
=
skl_unbind_modules
(
ctx
,
src_mconfig
,
sink_mconfig
);
}
return
ret
;
}
/*
* In modelling, we assume there will be ONLY one mixer in a pipeline. If
* mixer is not required then it is treated as static mixer aka vmixer with
* a hard path to source module
* So we don't need to check if source is started or not as hard path puts
* dependency on each other
*/
static
int
skl_tplg_vmixer_event
(
struct
snd_soc_dapm_widget
*
w
,
struct
snd_kcontrol
*
k
,
int
event
)
{
struct
snd_soc_dapm_context
*
dapm
=
w
->
dapm
;
struct
skl
*
skl
=
get_skl_ctx
(
dapm
->
dev
);
switch
(
event
)
{
case
SND_SOC_DAPM_PRE_PMU
:
return
skl_tplg_mixer_dapm_pre_pmu_event
(
w
,
skl
);
case
SND_SOC_DAPM_POST_PMD
:
return
skl_tplg_mixer_dapm_post_pmd_event
(
w
,
skl
);
}
return
0
;
}
/*
* In modelling, we assume there will be ONLY one mixer in a pipeline. If a
* second one is required that is created as another pipe entity.
* The mixer is responsible for pipe management and represent a pipeline
* instance
*/
static
int
skl_tplg_mixer_event
(
struct
snd_soc_dapm_widget
*
w
,
struct
snd_kcontrol
*
k
,
int
event
)
{
struct
snd_soc_dapm_context
*
dapm
=
w
->
dapm
;
struct
skl
*
skl
=
get_skl_ctx
(
dapm
->
dev
);
switch
(
event
)
{
case
SND_SOC_DAPM_PRE_PMU
:
return
skl_tplg_mixer_dapm_pre_pmu_event
(
w
,
skl
);
case
SND_SOC_DAPM_POST_PMU
:
return
skl_tplg_mixer_dapm_post_pmu_event
(
w
,
skl
);
case
SND_SOC_DAPM_PRE_PMD
:
return
skl_tplg_mixer_dapm_pre_pmd_event
(
w
,
skl
);
case
SND_SOC_DAPM_POST_PMD
:
return
skl_tplg_mixer_dapm_post_pmd_event
(
w
,
skl
);
}
return
0
;
}
/*
* In modelling, we assumed rest of the modules in pipeline are PGA. But we
* are interested in last PGA (leaf PGA) in a pipeline to disconnect with
* the sink when it is running (two FE to one BE or one FE to two BE)
* scenarios
*/
static
int
skl_tplg_pga_event
(
struct
snd_soc_dapm_widget
*
w
,
struct
snd_kcontrol
*
k
,
int
event
)
{
struct
snd_soc_dapm_context
*
dapm
=
w
->
dapm
;
struct
skl
*
skl
=
get_skl_ctx
(
dapm
->
dev
);
switch
(
event
)
{
case
SND_SOC_DAPM_PRE_PMU
:
return
skl_tplg_pga_dapm_pre_pmu_event
(
w
,
skl
);
case
SND_SOC_DAPM_POST_PMD
:
return
skl_tplg_pga_dapm_post_pmd_event
(
w
,
skl
);
}
return
0
;
}
/*
* The FE params are passed by hw_params of the DAI.
* On hw_params, the params are stored in Gateway module of the FE and we
* need to calculate the format in DSP module configuration, that
* conversion is done here
*/
int
skl_tplg_update_pipe_params
(
struct
device
*
dev
,
struct
skl_module_cfg
*
mconfig
,
struct
skl_pipe_params
*
params
)
{
struct
skl_pipe
*
pipe
=
mconfig
->
pipe
;
struct
skl_module_fmt
*
format
=
NULL
;
memcpy
(
pipe
->
p_params
,
params
,
sizeof
(
*
params
));
if
(
params
->
stream
==
SNDRV_PCM_STREAM_PLAYBACK
)
format
=
&
mconfig
->
in_fmt
;
else
format
=
&
mconfig
->
out_fmt
;
/* set the hw_params */
format
->
s_freq
=
params
->
s_freq
;
format
->
channels
=
params
->
ch
;
format
->
valid_bit_depth
=
skl_get_bit_depth
(
params
->
s_fmt
);
/*
* 16 bit is 16 bit container whereas 24 bit is in 32 bit
* container so update bit depth accordingly
*/
switch
(
format
->
valid_bit_depth
)
{
case
SKL_DEPTH_16BIT
:
format
->
bit_depth
=
format
->
valid_bit_depth
;
break
;
case
SKL_DEPTH_24BIT
:
format
->
bit_depth
=
SKL_DEPTH_32BIT
;
break
;
default:
dev_err
(
dev
,
"Invalid bit depth %x for pipe
\n
"
,
format
->
valid_bit_depth
);
return
-
EINVAL
;
}
if
(
params
->
stream
==
SNDRV_PCM_STREAM_PLAYBACK
)
{
mconfig
->
ibs
=
(
format
->
s_freq
/
1000
)
*
(
format
->
channels
)
*
(
format
->
bit_depth
>>
3
);
}
else
{
mconfig
->
obs
=
(
format
->
s_freq
/
1000
)
*
(
format
->
channels
)
*
(
format
->
bit_depth
>>
3
);
}
return
0
;
}
/*
* Query the module config for the FE DAI
* This is used to find the hw_params set for that DAI and apply to FE
* pipeline
*/
struct
skl_module_cfg
*
skl_tplg_fe_get_cpr_module
(
struct
snd_soc_dai
*
dai
,
int
stream
)
{
struct
snd_soc_dapm_widget
*
w
;
struct
snd_soc_dapm_path
*
p
=
NULL
;
if
(
stream
==
SNDRV_PCM_STREAM_PLAYBACK
)
{
w
=
dai
->
playback_widget
;
snd_soc_dapm_widget_for_each_sink_path
(
w
,
p
)
{
if
(
p
->
connect
&&
p
->
sink
->
power
&&
is_skl_dsp_widget_type
(
p
->
sink
))
continue
;
if
(
p
->
sink
->
priv
)
{
dev_dbg
(
dai
->
dev
,
"set params for %s
\n
"
,
p
->
sink
->
name
);
return
p
->
sink
->
priv
;
}
}
}
else
{
w
=
dai
->
capture_widget
;
snd_soc_dapm_widget_for_each_source_path
(
w
,
p
)
{
if
(
p
->
connect
&&
p
->
source
->
power
&&
is_skl_dsp_widget_type
(
p
->
source
))
continue
;
if
(
p
->
source
->
priv
)
{
dev_dbg
(
dai
->
dev
,
"set params for %s
\n
"
,
p
->
source
->
name
);
return
p
->
source
->
priv
;
}
}
}
return
NULL
;
}
static
u8
skl_tplg_be_link_type
(
int
dev_type
)
{
int
ret
;
switch
(
dev_type
)
{
case
SKL_DEVICE_BT
:
ret
=
NHLT_LINK_SSP
;
break
;
case
SKL_DEVICE_DMIC
:
ret
=
NHLT_LINK_DMIC
;
break
;
case
SKL_DEVICE_I2S
:
ret
=
NHLT_LINK_SSP
;
break
;
case
SKL_DEVICE_HDALINK
:
ret
=
NHLT_LINK_HDA
;
break
;
default:
ret
=
NHLT_LINK_INVALID
;
break
;
}
return
ret
;
}
/*
* Fill the BE gateway parameters
* The BE gateway expects a blob of parameters which are kept in the ACPI
* NHLT blob, so query the blob for interface type (i2s/pdm) and instance.
* The port can have multiple settings so pick based on the PCM
* parameters
*/
static
int
skl_tplg_be_fill_pipe_params
(
struct
snd_soc_dai
*
dai
,
struct
skl_module_cfg
*
mconfig
,
struct
skl_pipe_params
*
params
)
{
struct
skl_pipe
*
pipe
=
mconfig
->
pipe
;
struct
nhlt_specific_cfg
*
cfg
;
struct
skl
*
skl
=
get_skl_ctx
(
dai
->
dev
);
int
link_type
=
skl_tplg_be_link_type
(
mconfig
->
dev_type
);
memcpy
(
pipe
->
p_params
,
params
,
sizeof
(
*
params
));
/* update the blob based on virtual bus_id*/
cfg
=
skl_get_ep_blob
(
skl
,
mconfig
->
vbus_id
,
link_type
,
params
->
s_fmt
,
params
->
ch
,
params
->
s_freq
,
params
->
stream
);
if
(
cfg
)
{
mconfig
->
formats_config
.
caps_size
=
cfg
->
size
;
mconfig
->
formats_config
.
caps
=
(
u32
*
)
&
cfg
->
caps
;
}
else
{
dev_err
(
dai
->
dev
,
"Blob NULL for id %x type %d dirn %d
\n
"
,
mconfig
->
vbus_id
,
link_type
,
params
->
stream
);
dev_err
(
dai
->
dev
,
"PCM: ch %d, freq %d, fmt %d
\n
"
,
params
->
ch
,
params
->
s_freq
,
params
->
s_fmt
);
return
-
EINVAL
;
}
return
0
;
}
static
int
skl_tplg_be_set_src_pipe_params
(
struct
snd_soc_dai
*
dai
,
struct
snd_soc_dapm_widget
*
w
,
struct
skl_pipe_params
*
params
)
{
struct
snd_soc_dapm_path
*
p
;
int
ret
=
-
EIO
;
snd_soc_dapm_widget_for_each_source_path
(
w
,
p
)
{
if
(
p
->
connect
&&
is_skl_dsp_widget_type
(
p
->
source
)
&&
p
->
source
->
priv
)
{
if
(
!
p
->
source
->
power
)
{
ret
=
skl_tplg_be_fill_pipe_params
(
dai
,
p
->
source
->
priv
,
params
);
if
(
ret
<
0
)
return
ret
;
}
else
{
return
-
EBUSY
;
}
}
else
{
ret
=
skl_tplg_be_set_src_pipe_params
(
dai
,
p
->
source
,
params
);
if
(
ret
<
0
)
return
ret
;
}
}
return
ret
;
}
static
int
skl_tplg_be_set_sink_pipe_params
(
struct
snd_soc_dai
*
dai
,
struct
snd_soc_dapm_widget
*
w
,
struct
skl_pipe_params
*
params
)
{
struct
snd_soc_dapm_path
*
p
=
NULL
;
int
ret
=
-
EIO
;
snd_soc_dapm_widget_for_each_sink_path
(
w
,
p
)
{
if
(
p
->
connect
&&
is_skl_dsp_widget_type
(
p
->
sink
)
&&
p
->
sink
->
priv
)
{
if
(
!
p
->
sink
->
power
)
{
ret
=
skl_tplg_be_fill_pipe_params
(
dai
,
p
->
sink
->
priv
,
params
);
if
(
ret
<
0
)
return
ret
;
}
else
{
return
-
EBUSY
;
}
}
else
{
ret
=
skl_tplg_be_set_sink_pipe_params
(
dai
,
p
->
sink
,
params
);
if
(
ret
<
0
)
return
ret
;
}
}
return
ret
;
}
/*
* BE hw_params can be a source parameters (capture) or sink parameters
* (playback). Based on sink and source we need to either find the source
* list or the sink list and set the pipeline parameters
*/
int
skl_tplg_be_update_params
(
struct
snd_soc_dai
*
dai
,
struct
skl_pipe_params
*
params
)
{
struct
snd_soc_dapm_widget
*
w
;
if
(
params
->
stream
==
SNDRV_PCM_STREAM_PLAYBACK
)
{
w
=
dai
->
playback_widget
;
return
skl_tplg_be_set_src_pipe_params
(
dai
,
w
,
params
);
}
else
{
w
=
dai
->
capture_widget
;
return
skl_tplg_be_set_sink_pipe_params
(
dai
,
w
,
params
);
}
return
0
;
}
static
const
struct
snd_soc_tplg_widget_events
skl_tplg_widget_ops
[]
=
{
{
SKL_MIXER_EVENT
,
skl_tplg_mixer_event
},
{
SKL_VMIXER_EVENT
,
skl_tplg_vmixer_event
},
{
SKL_PGA_EVENT
,
skl_tplg_pga_event
},
};
/*
* The topology binary passes the pin info for a module so initialize the pin
* info passed into module instance
*/
static
void
skl_fill_module_pin_info
(
struct
skl_dfw_module_pin
*
dfw_pin
,
struct
skl_module_pin
*
m_pin
,
bool
is_dynamic
,
int
max_pin
)
{
int
i
;
for
(
i
=
0
;
i
<
max_pin
;
i
++
)
{
m_pin
[
i
].
id
.
module_id
=
dfw_pin
[
i
].
module_id
;
m_pin
[
i
].
id
.
instance_id
=
dfw_pin
[
i
].
instance_id
;
m_pin
[
i
].
in_use
=
false
;
m_pin
[
i
].
is_dynamic
=
is_dynamic
;
}
}
/*
* Add pipeline from topology binary into driver pipeline list
*
* If already added we return that instance
* Otherwise we create a new instance and add into driver list
*/
static
struct
skl_pipe
*
skl_tplg_add_pipe
(
struct
device
*
dev
,
struct
skl
*
skl
,
struct
skl_dfw_pipe
*
dfw_pipe
)
{
struct
skl_pipeline
*
ppl
;
struct
skl_pipe
*
pipe
;
struct
skl_pipe_params
*
params
;
list_for_each_entry
(
ppl
,
&
skl
->
ppl_list
,
node
)
{
if
(
ppl
->
pipe
->
ppl_id
==
dfw_pipe
->
pipe_id
)
return
ppl
->
pipe
;
}
ppl
=
devm_kzalloc
(
dev
,
sizeof
(
*
ppl
),
GFP_KERNEL
);
if
(
!
ppl
)
return
NULL
;
pipe
=
devm_kzalloc
(
dev
,
sizeof
(
*
pipe
),
GFP_KERNEL
);
if
(
!
pipe
)
return
NULL
;
params
=
devm_kzalloc
(
dev
,
sizeof
(
*
params
),
GFP_KERNEL
);
if
(
!
params
)
return
NULL
;
pipe
->
ppl_id
=
dfw_pipe
->
pipe_id
;
pipe
->
memory_pages
=
dfw_pipe
->
memory_pages
;
pipe
->
pipe_priority
=
dfw_pipe
->
pipe_priority
;
pipe
->
conn_type
=
dfw_pipe
->
conn_type
;
pipe
->
state
=
SKL_PIPE_INVALID
;
pipe
->
p_params
=
params
;
INIT_LIST_HEAD
(
&
pipe
->
w_list
);
ppl
->
pipe
=
pipe
;
list_add
(
&
ppl
->
node
,
&
skl
->
ppl_list
);
return
ppl
->
pipe
;
}
/*
* Topology core widget load callback
*
* This is used to save the private data for each widget which gives
* information to the driver about module and pipeline parameters which DSP
* FW expects like ids, resource values, formats etc
*/
static
int
skl_tplg_widget_load
(
struct
snd_soc_component
*
cmpnt
,
struct
snd_soc_dapm_widget
*
w
,
struct
snd_soc_tplg_dapm_widget
*
tplg_w
)
{
int
ret
;
struct
hdac_ext_bus
*
ebus
=
snd_soc_component_get_drvdata
(
cmpnt
);
struct
skl
*
skl
=
ebus_to_skl
(
ebus
);
struct
hdac_bus
*
bus
=
ebus_to_hbus
(
ebus
);
struct
skl_module_cfg
*
mconfig
;
struct
skl_pipe
*
pipe
;
struct
skl_dfw_module
*
dfw_config
=
(
struct
skl_dfw_module
*
)
tplg_w
->
priv
.
data
;
if
(
!
tplg_w
->
priv
.
size
)
goto
bind_event
;
mconfig
=
devm_kzalloc
(
bus
->
dev
,
sizeof
(
*
mconfig
),
GFP_KERNEL
);
if
(
!
mconfig
)
return
-
ENOMEM
;
w
->
priv
=
mconfig
;
mconfig
->
id
.
module_id
=
dfw_config
->
module_id
;
mconfig
->
id
.
instance_id
=
dfw_config
->
instance_id
;
mconfig
->
mcps
=
dfw_config
->
max_mcps
;
mconfig
->
ibs
=
dfw_config
->
ibs
;
mconfig
->
obs
=
dfw_config
->
obs
;
mconfig
->
core_id
=
dfw_config
->
core_id
;
mconfig
->
max_in_queue
=
dfw_config
->
max_in_queue
;
mconfig
->
max_out_queue
=
dfw_config
->
max_out_queue
;
mconfig
->
is_loadable
=
dfw_config
->
is_loadable
;
mconfig
->
in_fmt
.
channels
=
dfw_config
->
in_fmt
.
channels
;
mconfig
->
in_fmt
.
s_freq
=
dfw_config
->
in_fmt
.
freq
;
mconfig
->
in_fmt
.
bit_depth
=
dfw_config
->
in_fmt
.
bit_depth
;
mconfig
->
in_fmt
.
valid_bit_depth
=
dfw_config
->
in_fmt
.
valid_bit_depth
;
mconfig
->
in_fmt
.
ch_cfg
=
dfw_config
->
in_fmt
.
ch_cfg
;
mconfig
->
out_fmt
.
channels
=
dfw_config
->
out_fmt
.
channels
;
mconfig
->
out_fmt
.
s_freq
=
dfw_config
->
out_fmt
.
freq
;
mconfig
->
out_fmt
.
bit_depth
=
dfw_config
->
out_fmt
.
bit_depth
;
mconfig
->
out_fmt
.
valid_bit_depth
=
dfw_config
->
out_fmt
.
valid_bit_depth
;
mconfig
->
out_fmt
.
ch_cfg
=
dfw_config
->
out_fmt
.
ch_cfg
;
mconfig
->
params_fixup
=
dfw_config
->
params_fixup
;
mconfig
->
converter
=
dfw_config
->
converter
;
mconfig
->
m_type
=
dfw_config
->
module_type
;
mconfig
->
vbus_id
=
dfw_config
->
vbus_id
;
pipe
=
skl_tplg_add_pipe
(
bus
->
dev
,
skl
,
&
dfw_config
->
pipe
);
if
(
pipe
)
mconfig
->
pipe
=
pipe
;
mconfig
->
dev_type
=
dfw_config
->
dev_type
;
mconfig
->
hw_conn_type
=
dfw_config
->
hw_conn_type
;
mconfig
->
time_slot
=
dfw_config
->
time_slot
;
mconfig
->
formats_config
.
caps_size
=
dfw_config
->
caps
.
caps_size
;
mconfig
->
m_in_pin
=
devm_kzalloc
(
bus
->
dev
,
(
mconfig
->
max_in_queue
)
*
sizeof
(
*
mconfig
->
m_in_pin
),
GFP_KERNEL
);
if
(
!
mconfig
->
m_in_pin
)
return
-
ENOMEM
;
mconfig
->
m_out_pin
=
devm_kzalloc
(
bus
->
dev
,
(
mconfig
->
max_out_queue
)
*
sizeof
(
*
mconfig
->
m_out_pin
),
GFP_KERNEL
);
if
(
!
mconfig
->
m_out_pin
)
return
-
ENOMEM
;
skl_fill_module_pin_info
(
dfw_config
->
in_pin
,
mconfig
->
m_in_pin
,
dfw_config
->
is_dynamic_in_pin
,
mconfig
->
max_in_queue
);
skl_fill_module_pin_info
(
dfw_config
->
out_pin
,
mconfig
->
m_out_pin
,
dfw_config
->
is_dynamic_out_pin
,
mconfig
->
max_out_queue
);
if
(
mconfig
->
formats_config
.
caps_size
==
0
)
goto
bind_event
;
mconfig
->
formats_config
.
caps
=
(
u32
*
)
devm_kzalloc
(
bus
->
dev
,
mconfig
->
formats_config
.
caps_size
,
GFP_KERNEL
);
if
(
mconfig
->
formats_config
.
caps
==
NULL
)
return
-
ENOMEM
;
memcpy
(
mconfig
->
formats_config
.
caps
,
dfw_config
->
caps
.
caps
,
dfw_config
->
caps
.
caps_size
);
bind_event:
if
(
tplg_w
->
event_type
==
0
)
{
dev_dbg
(
bus
->
dev
,
"ASoC: No event handler required
\n
"
);
return
0
;
}
ret
=
snd_soc_tplg_widget_bind_event
(
w
,
skl_tplg_widget_ops
,
ARRAY_SIZE
(
skl_tplg_widget_ops
),
tplg_w
->
event_type
);
if
(
ret
)
{
dev_err
(
bus
->
dev
,
"%s: No matching event handlers found for %d
\n
"
,
__func__
,
tplg_w
->
event_type
);
return
-
EINVAL
;
}
return
0
;
}
static
struct
snd_soc_tplg_ops
skl_tplg_ops
=
{
.
widget_load
=
skl_tplg_widget_load
,
};
/* This will be read from topology manifest, currently defined here */
#define SKL_MAX_MCPS 30000000
#define SKL_FW_MAX_MEM 1000000
/*
* SKL topology init routine
*/
int
skl_tplg_init
(
struct
snd_soc_platform
*
platform
,
struct
hdac_ext_bus
*
ebus
)
{
int
ret
;
const
struct
firmware
*
fw
;
struct
hdac_bus
*
bus
=
ebus_to_hbus
(
ebus
);
struct
skl
*
skl
=
ebus_to_skl
(
ebus
);
ret
=
request_firmware
(
&
fw
,
"dfw_sst.bin"
,
bus
->
dev
);
if
(
ret
<
0
)
{
dev_err
(
bus
->
dev
,
"tplg fw %s load failed with %d
\n
"
,
"dfw_sst.bin"
,
ret
);
return
ret
;
}
/*
* The complete tplg for SKL is loaded as index 0, we don't use
* any other index
*/
ret
=
snd_soc_tplg_component_load
(
&
platform
->
component
,
&
skl_tplg_ops
,
fw
,
0
);
if
(
ret
<
0
)
{
dev_err
(
bus
->
dev
,
"tplg component load failed%d
\n
"
,
ret
);
return
-
EINVAL
;
}
skl
->
resource
.
max_mcps
=
SKL_MAX_MCPS
;
skl
->
resource
.
max_mem
=
SKL_FW_MAX_MEM
;
return
0
;
}
sound/soc/intel/skylake/skl-topology.h
浏览文件 @
8707344e
...
...
@@ -129,6 +129,11 @@ struct skl_src_module_cfg {
enum
skl_s_freq
src_cfg
;
}
__packed
;
struct
notification_mask
{
u32
notify
;
u32
enable
;
}
__packed
;
struct
skl_up_down_mixer_cfg
{
struct
skl_base_cfg
base_cfg
;
enum
skl_ch_cfg
out_ch_cfg
;
...
...
@@ -153,8 +158,7 @@ enum skl_dma_type {
union
skl_ssp_dma_node
{
u8
val
;
struct
{
u8
dual_mono
:
1
;
u8
time_slot
:
3
;
u8
time_slot_index
:
4
;
u8
i2s_instance
:
4
;
}
dma_node
;
};
...
...
@@ -263,6 +267,34 @@ struct skl_module_cfg {
struct
skl_specific_cfg
formats_config
;
};
struct
skl_pipeline
{
struct
skl_pipe
*
pipe
;
struct
list_head
node
;
};
struct
skl_dapm_path_list
{
struct
snd_soc_dapm_path
*
dapm_path
;
struct
list_head
node
;
};
static
inline
struct
skl
*
get_skl_ctx
(
struct
device
*
dev
)
{
struct
hdac_ext_bus
*
ebus
=
dev_get_drvdata
(
dev
);
return
ebus_to_skl
(
ebus
);
}
int
skl_tplg_be_update_params
(
struct
snd_soc_dai
*
dai
,
struct
skl_pipe_params
*
params
);
void
skl_tplg_set_be_dmic_config
(
struct
snd_soc_dai
*
dai
,
struct
skl_pipe_params
*
params
,
int
stream
);
int
skl_tplg_init
(
struct
snd_soc_platform
*
platform
,
struct
hdac_ext_bus
*
ebus
);
struct
skl_module_cfg
*
skl_tplg_fe_get_cpr_module
(
struct
snd_soc_dai
*
dai
,
int
stream
);
int
skl_tplg_update_pipe_params
(
struct
device
*
dev
,
struct
skl_module_cfg
*
mconfig
,
struct
skl_pipe_params
*
params
);
int
skl_create_pipeline
(
struct
skl_sst
*
ctx
,
struct
skl_pipe
*
pipe
);
int
skl_run_pipe
(
struct
skl_sst
*
ctx
,
struct
skl_pipe
*
pipe
);
...
...
sound/soc/intel/skylake/skl-tplg-interface.h
浏览文件 @
8707344e
...
...
@@ -19,6 +19,29 @@
#ifndef __HDA_TPLG_INTERFACE_H__
#define __HDA_TPLG_INTERFACE_H__
/*
* Default types range from 0~12. type can range from 0 to 0xff
* SST types start at higher to avoid any overlapping in future
*/
#define SOC_CONTROL_TYPE_HDA_SST_ALGO_PARAMS 0x100
#define SOC_CONTROL_TYPE_HDA_SST_MUX 0x101
#define SOC_CONTROL_TYPE_HDA_SST_MIX 0x101
#define SOC_CONTROL_TYPE_HDA_SST_BYTE 0x103
#define HDA_SST_CFG_MAX 900
/* size of copier cfg*/
#define MAX_IN_QUEUE 8
#define MAX_OUT_QUEUE 8
/* Event types goes here */
/* Reserve event type 0 for no event handlers */
enum
skl_event_types
{
SKL_EVENT_NONE
=
0
,
SKL_MIXER_EVENT
,
SKL_MUX_EVENT
,
SKL_VMIXER_EVENT
,
SKL_PGA_EVENT
};
/**
* enum skl_ch_cfg - channel configuration
*
...
...
@@ -83,6 +106,66 @@ enum skl_dev_type {
SKL_DEVICE_I2S
=
0x2
,
SKL_DEVICE_SLIMBUS
=
0x3
,
SKL_DEVICE_HDALINK
=
0x4
,
SKL_DEVICE_HDAHOST
=
0x5
,
SKL_DEVICE_NONE
};
struct
skl_dfw_module_pin
{
u16
module_id
;
u16
instance_id
;
}
__packed
;
struct
skl_dfw_module_fmt
{
u32
channels
;
u32
freq
;
u32
bit_depth
;
u32
valid_bit_depth
;
u32
ch_cfg
;
}
__packed
;
struct
skl_dfw_module_caps
{
u32
caps_size
;
u32
caps
[
HDA_SST_CFG_MAX
];
};
struct
skl_dfw_pipe
{
u8
pipe_id
;
u8
pipe_priority
;
u16
conn_type
;
u32
memory_pages
;
}
__packed
;
struct
skl_dfw_module
{
u16
module_id
;
u16
instance_id
;
u32
max_mcps
;
u8
core_id
;
u8
max_in_queue
;
u8
max_out_queue
;
u8
is_loadable
;
u8
conn_type
;
u8
dev_type
;
u8
hw_conn_type
;
u8
time_slot
;
u32
obs
;
u32
ibs
;
u32
params_fixup
;
u32
converter
;
u32
module_type
;
u32
vbus_id
;
u8
is_dynamic_in_pin
;
u8
is_dynamic_out_pin
;
struct
skl_dfw_pipe
pipe
;
struct
skl_dfw_module_fmt
in_fmt
;
struct
skl_dfw_module_fmt
out_fmt
;
struct
skl_dfw_module_pin
in_pin
[
MAX_IN_QUEUE
];
struct
skl_dfw_module_pin
out_pin
[
MAX_OUT_QUEUE
];
struct
skl_dfw_module_caps
caps
;
}
__packed
;
struct
skl_dfw_algo_data
{
u32
max
;
char
*
params
;
}
__packed
;
#endif
sound/soc/intel/skylake/skl.c
浏览文件 @
8707344e
...
...
@@ -166,12 +166,20 @@ static int skl_runtime_suspend(struct device *dev)
struct
pci_dev
*
pci
=
to_pci_dev
(
dev
);
struct
hdac_ext_bus
*
ebus
=
pci_get_drvdata
(
pci
);
struct
hdac_bus
*
bus
=
ebus_to_hbus
(
ebus
);
struct
skl
*
skl
=
ebus_to_skl
(
ebus
);
int
ret
;
dev_dbg
(
bus
->
dev
,
"in %s
\n
"
,
__func__
);
/* enable controller wake up event */
snd_hdac_chip_updatew
(
bus
,
WAKEEN
,
0
,
STATESTS_INT_MASK
);
snd_hdac_ext_bus_link_power_down_all
(
ebus
);
ret
=
skl_suspend_dsp
(
skl
);
if
(
ret
<
0
)
return
ret
;
snd_hdac_bus_stop_chip
(
bus
);
snd_hdac_bus_enter_link_reset
(
bus
);
...
...
@@ -183,7 +191,7 @@ static int skl_runtime_resume(struct device *dev)
struct
pci_dev
*
pci
=
to_pci_dev
(
dev
);
struct
hdac_ext_bus
*
ebus
=
pci_get_drvdata
(
pci
);
struct
hdac_bus
*
bus
=
ebus_to_hbus
(
ebus
);
struct
skl
*
hda
=
ebus_to_skl
(
ebus
);
struct
skl
*
skl
=
ebus_to_skl
(
ebus
);
int
status
;
dev_dbg
(
bus
->
dev
,
"in %s
\n
"
,
__func__
);
...
...
@@ -191,12 +199,12 @@ static int skl_runtime_resume(struct device *dev)
/* Read STATESTS before controller reset */
status
=
snd_hdac_chip_readw
(
bus
,
STATESTS
);
skl_init_pci
(
hda
);
skl_init_pci
(
skl
);
snd_hdac_bus_init_chip
(
bus
,
true
);
/* disable controller Wake Up event */
snd_hdac_chip_updatew
(
bus
,
WAKEEN
,
STATESTS_INT_MASK
,
0
);
return
0
;
return
skl_resume_dsp
(
skl
)
;
}
#endif
/* CONFIG_PM */
...
...
@@ -453,21 +461,28 @@ static int skl_probe(struct pci_dev *pci,
if
(
err
<
0
)
goto
out_free
;
skl
->
nhlt
=
skl_nhlt_init
(
bus
->
dev
);
if
(
skl
->
nhlt
==
NULL
)
goto
out_free
;
pci_set_drvdata
(
skl
->
pci
,
ebus
);
/* check if dsp is there */
if
(
ebus
->
ppcap
)
{
/* TODO register with dsp IPC */
dev_dbg
(
bus
->
dev
,
"Register dsp
\n
"
);
err
=
skl_init_dsp
(
skl
);
if
(
err
<
0
)
{
dev_dbg
(
bus
->
dev
,
"error failed to register dsp
\n
"
);
goto
out_free
;
}
}
if
(
ebus
->
mlcap
)
snd_hdac_ext_bus_get_ml_capabilities
(
ebus
);
/* create device for soc dmic */
err
=
skl_dmic_device_register
(
skl
);
if
(
err
<
0
)
goto
out_free
;
goto
out_
dsp_
free
;
/* register platform dai and controls */
err
=
skl_platform_register
(
bus
->
dev
);
...
...
@@ -491,6 +506,8 @@ static int skl_probe(struct pci_dev *pci,
skl_platform_unregister
(
bus
->
dev
);
out_dmic_free:
skl_dmic_device_unregister
(
skl
);
out_dsp_free:
skl_free_dsp
(
skl
);
out_free:
skl
->
init_failed
=
1
;
skl_free
(
ebus
);
...
...
@@ -507,6 +524,7 @@ static void skl_remove(struct pci_dev *pci)
pm_runtime_get_noresume
(
&
pci
->
dev
);
pci_dev_put
(
pci
);
skl_platform_unregister
(
&
pci
->
dev
);
skl_free_dsp
(
skl
);
skl_dmic_device_unregister
(
skl
);
skl_free
(
ebus
);
dev_set_drvdata
(
&
pci
->
dev
,
NULL
);
...
...
sound/soc/intel/skylake/skl.h
浏览文件 @
8707344e
...
...
@@ -48,6 +48,13 @@
#define AZX_REG_VS_SDXEFIFOS_XBASE 0x1094
#define AZX_REG_VS_SDXEFIFOS_XINTERVAL 0x20
struct
skl_dsp_resource
{
u32
max_mcps
;
u32
max_mem
;
u32
mcps
;
u32
mem
;
};
struct
skl
{
struct
hdac_ext_bus
ebus
;
struct
pci_dev
*
pci
;
...
...
@@ -55,8 +62,12 @@ struct skl {
unsigned
int
init_failed
:
1
;
/* delayed init failed */
struct
platform_device
*
dmic_dev
;
void
__iomem
*
nhlt
;
/* nhlt ptr */
void
*
nhlt
;
/* nhlt ptr */
struct
skl_sst
*
skl_sst
;
/* sst skl ctx */
struct
skl_dsp_resource
resource
;
struct
list_head
ppl_list
;
struct
list_head
dapm_path_list
;
};
#define skl_to_ebus(s) (&(s)->ebus)
...
...
@@ -72,8 +83,8 @@ struct skl_dma_params {
int
skl_platform_unregister
(
struct
device
*
dev
);
int
skl_platform_register
(
struct
device
*
dev
);
void
__iomem
*
skl_nhlt_init
(
struct
device
*
dev
);
void
skl_nhlt_free
(
void
__iomem
*
addr
);
void
*
skl_nhlt_init
(
struct
device
*
dev
);
void
skl_nhlt_free
(
void
*
addr
);
struct
nhlt_specific_cfg
*
skl_get_ep_blob
(
struct
skl
*
skl
,
u32
instance
,
u8
link_type
,
u8
s_fmt
,
u8
no_ch
,
u32
s_rate
,
u8
dirn
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录