Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
8707344e
Commit
8707344e
authored
Oct 26, 2015
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branches 'asoc/topic/imx' and 'asoc/topic/intel' into asoc-next
parents
f72362e6
43ac9469
6abca1d7
Changes
22
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
1905 additions
and
88 deletions
+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
No files found.
sound/soc/fsl/imx-spdif.c
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment