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
4a2447b4
Commit
4a2447b4
authored
Sep 29, 2016
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'asoc/topic/intel' into asoc-next
parents
00f12dbd
0730bd2e
Changes
38
Show whitespace changes
Inline
Side-by-side
Showing
38 changed files
with
2907 additions
and
485 deletions
+2907
-485
include/sound/hda_register.h
include/sound/hda_register.h
+36
-0
include/sound/hdaudio.h
include/sound/hdaudio.h
+13
-0
include/sound/hdaudio_ext.h
include/sound/hdaudio_ext.h
+0
-12
include/uapi/sound/Kbuild
include/uapi/sound/Kbuild
+1
-0
include/uapi/sound/snd_sst_tokens.h
include/uapi/sound/snd_sst_tokens.h
+214
-0
sound/hda/ext/hdac_ext_controller.c
sound/hda/ext/hdac_ext_controller.c
+8
-83
sound/hda/ext/hdac_ext_stream.c
sound/hda/ext/hdac_ext_stream.c
+23
-23
sound/hda/hdac_controller.c
sound/hda/hdac_controller.c
+75
-0
sound/pci/hda/hda_controller.c
sound/pci/hda/hda_controller.c
+202
-1
sound/pci/hda/hda_controller.h
sound/pci/hda/hda_controller.h
+3
-0
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_intel.c
+17
-0
sound/soc/codecs/rt5640.c
sound/soc/codecs/rt5640.c
+3
-0
sound/soc/codecs/rt5640.h
sound/soc/codecs/rt5640.h
+1
-0
sound/soc/intel/Kconfig
sound/soc/intel/Kconfig
+12
-0
sound/soc/intel/atom/sst-atom-controls.c
sound/soc/intel/atom/sst-atom-controls.c
+28
-4
sound/soc/intel/atom/sst-atom-controls.h
sound/soc/intel/atom/sst-atom-controls.h
+6
-0
sound/soc/intel/atom/sst/sst.c
sound/soc/intel/atom/sst/sst.c
+3
-2
sound/soc/intel/atom/sst/sst_acpi.c
sound/soc/intel/atom/sst/sst_acpi.c
+85
-12
sound/soc/intel/boards/Makefile
sound/soc/intel/boards/Makefile
+2
-0
sound/soc/intel/boards/bdw-rt5677.c
sound/soc/intel/boards/bdw-rt5677.c
+347
-0
sound/soc/intel/boards/bxt_da7219_max98357a.c
sound/soc/intel/boards/bxt_da7219_max98357a.c
+69
-6
sound/soc/intel/boards/bxt_rt298.c
sound/soc/intel/boards/bxt_rt298.c
+7
-7
sound/soc/intel/boards/bytcr_rt5640.c
sound/soc/intel/boards/bytcr_rt5640.c
+458
-49
sound/soc/intel/common/sst-acpi.c
sound/soc/intel/common/sst-acpi.c
+1
-0
sound/soc/intel/skylake/bxt-sst.c
sound/soc/intel/skylake/bxt-sst.c
+106
-12
sound/soc/intel/skylake/skl-messages.c
sound/soc/intel/skylake/skl-messages.c
+40
-27
sound/soc/intel/skylake/skl-pcm.c
sound/soc/intel/skylake/skl-pcm.c
+53
-5
sound/soc/intel/skylake/skl-sst-cldma.c
sound/soc/intel/skylake/skl-sst-cldma.c
+2
-2
sound/soc/intel/skylake/skl-sst-dsp.h
sound/soc/intel/skylake/skl-sst-dsp.h
+15
-3
sound/soc/intel/skylake/skl-sst-ipc.c
sound/soc/intel/skylake/skl-sst-ipc.c
+35
-6
sound/soc/intel/skylake/skl-sst-ipc.h
sound/soc/intel/skylake/skl-sst-ipc.h
+11
-1
sound/soc/intel/skylake/skl-sst-utils.c
sound/soc/intel/skylake/skl-sst-utils.c
+161
-15
sound/soc/intel/skylake/skl-sst.c
sound/soc/intel/skylake/skl-sst.c
+29
-20
sound/soc/intel/skylake/skl-topology.c
sound/soc/intel/skylake/skl-topology.c
+800
-118
sound/soc/intel/skylake/skl-topology.h
sound/soc/intel/skylake/skl-topology.h
+13
-2
sound/soc/intel/skylake/skl-tplg-interface.h
sound/soc/intel/skylake/skl-tplg-interface.h
+23
-72
sound/soc/intel/skylake/skl.c
sound/soc/intel/skylake/skl.c
+3
-3
sound/soc/intel/skylake/skl.h
sound/soc/intel/skylake/skl.h
+2
-0
No files found.
include/sound/hda_register.h
View file @
4a2447b4
...
...
@@ -89,6 +89,19 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
#define AZX_REG_SD_BDLPL 0x18
#define AZX_REG_SD_BDLPU 0x1c
/* GTS registers */
#define AZX_REG_LLCH 0x14
#define AZX_REG_GTS_BASE 0x520
#define AZX_REG_GTSCC (AZX_REG_GTS_BASE + 0x00)
#define AZX_REG_WALFCC (AZX_REG_GTS_BASE + 0x04)
#define AZX_REG_TSCCL (AZX_REG_GTS_BASE + 0x08)
#define AZX_REG_TSCCU (AZX_REG_GTS_BASE + 0x0C)
#define AZX_REG_LLPFOC (AZX_REG_GTS_BASE + 0x14)
#define AZX_REG_LLPCL (AZX_REG_GTS_BASE + 0x18)
#define AZX_REG_LLPCU (AZX_REG_GTS_BASE + 0x1C)
/* Haswell/Broadwell display HD-A controller Extended Mode registers */
#define AZX_REG_HSW_EM4 0x100c
#define AZX_REG_HSW_EM5 0x1010
...
...
@@ -242,6 +255,29 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
/* Interval used to calculate the iterating register offset */
#define AZX_DRSM_INTERVAL 0x08
/* Global time synchronization registers */
#define GTSCC_TSCCD_MASK 0x80000000
#define GTSCC_TSCCD_SHIFT BIT(31)
#define GTSCC_TSCCI_MASK 0x20
#define GTSCC_CDMAS_DMA_DIR_SHIFT 4
#define WALFCC_CIF_MASK 0x1FF
#define WALFCC_FN_SHIFT 9
#define HDA_CLK_CYCLES_PER_FRAME 512
/*
* An error occurs near frame "rollover". The clocks in frame value indicates
* whether this error may have occurred. Here we use the value of 10. Please
* see the errata for the right number [<10]
*/
#define HDA_MAX_CYCLE_VALUE 499
#define HDA_MAX_CYCLE_OFFSET 10
#define HDA_MAX_CYCLE_READ_RETRY 10
#define TSCCU_CCU_SHIFT 32
#define LLPC_CCU_SHIFT 32
/*
* helpers to read the stream position
*/
...
...
include/sound/hdaudio.h
View file @
4a2447b4
...
...
@@ -245,6 +245,12 @@ struct hdac_rb {
/*
* HD-audio bus base driver
*
* @ppcap: pp capabilities pointer
* @spbcap: SPIB capabilities pointer
* @mlcap: MultiLink capabilities pointer
* @gtscap: gts capabilities pointer
* @drsmcap: dma resume capabilities pointer
*/
struct
hdac_bus
{
struct
device
*
dev
;
...
...
@@ -256,6 +262,12 @@ struct hdac_bus {
void
__iomem
*
remap_addr
;
int
irq
;
void
__iomem
*
ppcap
;
void
__iomem
*
spbcap
;
void
__iomem
*
mlcap
;
void
__iomem
*
gtscap
;
void
__iomem
*
drsmcap
;
/* codec linked list */
struct
list_head
codec_list
;
unsigned
int
num_codecs
;
...
...
@@ -335,6 +347,7 @@ static inline void snd_hdac_codec_link_down(struct hdac_device *codec)
int
snd_hdac_bus_send_cmd
(
struct
hdac_bus
*
bus
,
unsigned
int
val
);
int
snd_hdac_bus_get_response
(
struct
hdac_bus
*
bus
,
unsigned
int
addr
,
unsigned
int
*
res
);
int
snd_hdac_bus_parse_capabilities
(
struct
hdac_bus
*
bus
);
int
snd_hdac_link_power
(
struct
hdac_device
*
codec
,
bool
enable
);
bool
snd_hdac_bus_init_chip
(
struct
hdac_bus
*
bus
,
bool
full_reset
);
...
...
include/sound/hdaudio_ext.h
View file @
4a2447b4
...
...
@@ -8,11 +8,6 @@
*
* @bus: hdac bus
* @num_streams: streams supported
* @ppcap: pp capabilities pointer
* @spbcap: SPIB capabilities pointer
* @mlcap: MultiLink capabilities pointer
* @gtscap: gts capabilities pointer
* @drsmcap: dma resume capabilities pointer
* @hlink_list: link list of HDA links
* @lock: lock for link mgmt
* @cmd_dma_state: state of cmd DMAs: CORB and RIRB
...
...
@@ -22,12 +17,6 @@ struct hdac_ext_bus {
int
num_streams
;
int
idx
;
void
__iomem
*
ppcap
;
void
__iomem
*
spbcap
;
void
__iomem
*
mlcap
;
void
__iomem
*
gtscap
;
void
__iomem
*
drsmcap
;
struct
list_head
hlink_list
;
struct
mutex
lock
;
...
...
@@ -54,7 +43,6 @@ void snd_hdac_ext_bus_device_remove(struct hdac_ext_bus *ebus);
#define HDA_CODEC_EXT_ENTRY(_vid, _revid, _name, _drv_data) \
HDA_CODEC_REV_EXT_ENTRY(_vid, _revid, _name, _drv_data)
int
snd_hdac_ext_bus_parse_capabilities
(
struct
hdac_ext_bus
*
sbus
);
void
snd_hdac_ext_bus_ppcap_enable
(
struct
hdac_ext_bus
*
chip
,
bool
enable
);
void
snd_hdac_ext_bus_ppcap_int_enable
(
struct
hdac_ext_bus
*
chip
,
bool
enable
);
...
...
include/uapi/sound/Kbuild
View file @
4a2447b4
...
...
@@ -13,3 +13,4 @@ header-y += sb16_csp.h
header-y += sfnt_info.h
header-y += tlv.h
header-y += usb_stream.h
header-y += snd_sst_tokens.h
include/uapi/sound/snd_sst_tokens.h
0 → 100644
View file @
4a2447b4
/*
* snd_sst_tokens.h - Intel SST tokens definition
*
* Copyright (C) 2016 Intel Corp
* Author: Shreyas NC <shreyas.nc@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.
*/
#ifndef __SND_SST_TOKENS_H__
#define __SND_SST_TOKENS_H__
/**
* %SKL_TKN_UUID: Module UUID
*
* %SKL_TKN_U8_BLOCK_TYPE: Type of the private data block.Can be:
* tuples, bytes, short and words
*
* %SKL_TKN_U8_IN_PIN_TYPE: Input pin type,
* homogenous=0, heterogenous=1
*
* %SKL_TKN_U8_OUT_PIN_TYPE: Output pin type,
* homogenous=0, heterogenous=1
* %SKL_TKN_U8_DYN_IN_PIN: Configure Input pin dynamically
* if true
*
* %SKL_TKN_U8_DYN_OUT_PIN: Configure Output pin dynamically
* if true
*
* %SKL_TKN_U8_IN_QUEUE_COUNT: Store the number of Input pins
*
* %SKL_TKN_U8_OUT_QUEUE_COUNT: Store the number of Output pins
*
* %SKL_TKN_U8_TIME_SLOT: TDM slot number
*
* %SKL_TKN_U8_CORE_ID: Stores module affinity value.Can take
* the values:
* SKL_AFFINITY_CORE_0 = 0,
* SKL_AFFINITY_CORE_1,
* SKL_AFFINITY_CORE_MAX
*
* %SKL_TKN_U8_MOD_TYPE: Module type value.
*
* %SKL_TKN_U8_CONN_TYPE: Module connection type can be a FE,
* BE or NONE as defined :
* SKL_PIPE_CONN_TYPE_NONE = 0,
* SKL_PIPE_CONN_TYPE_FE = 1 (HOST_DMA)
* SKL_PIPE_CONN_TYPE_BE = 2 (LINK_DMA)
*
* %SKL_TKN_U8_DEV_TYPE: Type of device to which the module is
* connected
* Can take the values:
* SKL_DEVICE_BT = 0x0,
* SKL_DEVICE_DMIC = 0x1,
* SKL_DEVICE_I2S = 0x2,
* SKL_DEVICE_SLIMBUS = 0x3,
* SKL_DEVICE_HDALINK = 0x4,
* SKL_DEVICE_HDAHOST = 0x5,
* SKL_DEVICE_NONE
*
* %SKL_TKN_U8_HW_CONN_TYPE: Connection type of the HW to which the
* module is connected
* SKL_CONN_NONE = 0,
* SKL_CONN_SOURCE = 1,
* SKL_CONN_SINK = 2
*
* %SKL_TKN_U16_PIN_INST_ID: Stores the pin instance id
*
* %SKL_TKN_U16_MOD_INST_ID: Stores the mdule instance id
*
* %SKL_TKN_U32_MAX_MCPS: Module max mcps value
*
* %SKL_TKN_U32_MEM_PAGES: Module resource pages
*
* %SKL_TKN_U32_OBS: Stores Output Buffer size
*
* %SKL_TKN_U32_IBS: Stores input buffer size
*
* %SKL_TKN_U32_VBUS_ID: Module VBUS_ID. PDM=0, SSP0=0,
* SSP1=1,SSP2=2,
* SSP3=3, SSP4=4,
* SSP5=5, SSP6=6,INVALID
*
* %SKL_TKN_U32_PARAMS_FIXUP: Module Params fixup mask
* %SKL_TKN_U32_CONVERTER: Module params converter mask
* %SKL_TKN_U32_PIPE_ID: Stores the pipe id
*
* %SKL_TKN_U32_PIPE_CONN_TYPE: Type of the token to which the pipe is
* connected to. It can be
* SKL_PIPE_CONN_TYPE_NONE = 0,
* SKL_PIPE_CONN_TYPE_FE = 1 (HOST_DMA),
* SKL_PIPE_CONN_TYPE_BE = 2 (LINK_DMA),
*
* %SKL_TKN_U32_PIPE_PRIORITY: Pipe priority value
* %SKL_TKN_U32_PIPE_MEM_PGS: Pipe resource pages
*
* %SKL_TKN_U32_DIR_PIN_COUNT: Value for the direction to set input/output
* formats and the pin count.
* The first 4 bits have the direction
* value and the next 4 have
* the pin count value.
* SKL_DIR_IN = 0, SKL_DIR_OUT = 1.
* The input and output formats
* share the same set of tokens
* with the distinction between input
* and output made by reading direction
* token.
*
* %SKL_TKN_U32_FMT_CH: Supported channel count
*
* %SKL_TKN_U32_FMT_FREQ: Supported frequency/sample rate
*
* %SKL_TKN_U32_FMT_BIT_DEPTH: Supported container size
*
* %SKL_TKN_U32_FMT_SAMPLE_SIZE:Number of samples in the container
*
* %SKL_TKN_U32_FMT_CH_CONFIG: Supported channel configurations for the
* input/output.
*
* %SKL_TKN_U32_FMT_INTERLEAVE: Interleaving style which can be per
* channel or per sample. The values can be :
* SKL_INTERLEAVING_PER_CHANNEL = 0,
* SKL_INTERLEAVING_PER_SAMPLE = 1,
*
* %SKL_TKN_U32_FMT_SAMPLE_TYPE:
* Specifies the sample type. Can take the
* values: SKL_SAMPLE_TYPE_INT_MSB = 0,
* SKL_SAMPLE_TYPE_INT_LSB = 1,
* SKL_SAMPLE_TYPE_INT_SIGNED = 2,
* SKL_SAMPLE_TYPE_INT_UNSIGNED = 3,
* SKL_SAMPLE_TYPE_FLOAT = 4
*
* %SKL_TKN_U32_CH_MAP: Channel map values
* %SKL_TKN_U32_MOD_SET_PARAMS: It can take these values:
* SKL_PARAM_DEFAULT, SKL_PARAM_INIT,
* SKL_PARAM_SET, SKL_PARAM_BIND
*
* %SKL_TKN_U32_MOD_PARAM_ID: ID of the module params
*
* %SKL_TKN_U32_CAPS_SET_PARAMS:
* Set params value
*
* %SKL_TKN_U32_CAPS_PARAMS_ID: Params ID
*
* %SKL_TKN_U32_CAPS_SIZE: Caps size
*
* %SKL_TKN_U32_PROC_DOMAIN: Specify processing domain
*
* %SKL_TKN_U32_LIB_COUNT: Specifies the number of libraries
*
* %SKL_TKN_STR_LIB_NAME: Specifies the library name
*
* module_id and loadable flags dont have tokens as these values will be
* read from the DSP FW manifest
*/
enum
SKL_TKNS
{
SKL_TKN_UUID
=
1
,
SKL_TKN_U8_NUM_BLOCKS
,
SKL_TKN_U8_BLOCK_TYPE
,
SKL_TKN_U8_IN_PIN_TYPE
,
SKL_TKN_U8_OUT_PIN_TYPE
,
SKL_TKN_U8_DYN_IN_PIN
,
SKL_TKN_U8_DYN_OUT_PIN
,
SKL_TKN_U8_IN_QUEUE_COUNT
,
SKL_TKN_U8_OUT_QUEUE_COUNT
,
SKL_TKN_U8_TIME_SLOT
,
SKL_TKN_U8_CORE_ID
,
SKL_TKN_U8_MOD_TYPE
,
SKL_TKN_U8_CONN_TYPE
,
SKL_TKN_U8_DEV_TYPE
,
SKL_TKN_U8_HW_CONN_TYPE
,
SKL_TKN_U16_MOD_INST_ID
,
SKL_TKN_U16_BLOCK_SIZE
,
SKL_TKN_U32_MAX_MCPS
,
SKL_TKN_U32_MEM_PAGES
,
SKL_TKN_U32_OBS
,
SKL_TKN_U32_IBS
,
SKL_TKN_U32_VBUS_ID
,
SKL_TKN_U32_PARAMS_FIXUP
,
SKL_TKN_U32_CONVERTER
,
SKL_TKN_U32_PIPE_ID
,
SKL_TKN_U32_PIPE_CONN_TYPE
,
SKL_TKN_U32_PIPE_PRIORITY
,
SKL_TKN_U32_PIPE_MEM_PGS
,
SKL_TKN_U32_DIR_PIN_COUNT
,
SKL_TKN_U32_FMT_CH
,
SKL_TKN_U32_FMT_FREQ
,
SKL_TKN_U32_FMT_BIT_DEPTH
,
SKL_TKN_U32_FMT_SAMPLE_SIZE
,
SKL_TKN_U32_FMT_CH_CONFIG
,
SKL_TKN_U32_FMT_INTERLEAVE
,
SKL_TKN_U32_FMT_SAMPLE_TYPE
,
SKL_TKN_U32_FMT_CH_MAP
,
SKL_TKN_U32_PIN_MOD_ID
,
SKL_TKN_U32_PIN_INST_ID
,
SKL_TKN_U32_MOD_SET_PARAMS
,
SKL_TKN_U32_MOD_PARAM_ID
,
SKL_TKN_U32_CAPS_SET_PARAMS
,
SKL_TKN_U32_CAPS_PARAMS_ID
,
SKL_TKN_U32_CAPS_SIZE
,
SKL_TKN_U32_PROC_DOMAIN
,
SKL_TKN_U32_LIB_COUNT
,
SKL_TKN_STR_LIB_NAME
,
SKL_TKN_MAX
=
SKL_TKN_STR_LIB_NAME
,
};
#endif
sound/hda/ext/hdac_ext_controller.c
View file @
4a2447b4
...
...
@@ -29,81 +29,6 @@
*/
#define HDAC_MAX_CAPS 10
/**
* snd_hdac_ext_bus_parse_capabilities - parse capablity structure
* @ebus: the pointer to extended bus object
*
* Returns 0 if successful, or a negative error code.
*/
int
snd_hdac_ext_bus_parse_capabilities
(
struct
hdac_ext_bus
*
ebus
)
{
unsigned
int
cur_cap
;
unsigned
int
offset
;
struct
hdac_bus
*
bus
=
&
ebus
->
bus
;
unsigned
int
counter
=
0
;
offset
=
snd_hdac_chip_readl
(
bus
,
LLCH
);
/* Lets walk the linked capabilities list */
do
{
cur_cap
=
_snd_hdac_chip_read
(
l
,
bus
,
offset
);
dev_dbg
(
bus
->
dev
,
"Capability version: 0x%x
\n
"
,
((
cur_cap
&
AZX_CAP_HDR_VER_MASK
)
>>
AZX_CAP_HDR_VER_OFF
));
dev_dbg
(
bus
->
dev
,
"HDA capability ID: 0x%x
\n
"
,
(
cur_cap
&
AZX_CAP_HDR_ID_MASK
)
>>
AZX_CAP_HDR_ID_OFF
);
switch
((
cur_cap
&
AZX_CAP_HDR_ID_MASK
)
>>
AZX_CAP_HDR_ID_OFF
)
{
case
AZX_ML_CAP_ID
:
dev_dbg
(
bus
->
dev
,
"Found ML capability
\n
"
);
ebus
->
mlcap
=
bus
->
remap_addr
+
offset
;
break
;
case
AZX_GTS_CAP_ID
:
dev_dbg
(
bus
->
dev
,
"Found GTS capability offset=%x
\n
"
,
offset
);
ebus
->
gtscap
=
bus
->
remap_addr
+
offset
;
break
;
case
AZX_PP_CAP_ID
:
/* PP capability found, the Audio DSP is present */
dev_dbg
(
bus
->
dev
,
"Found PP capability offset=%x
\n
"
,
offset
);
ebus
->
ppcap
=
bus
->
remap_addr
+
offset
;
break
;
case
AZX_SPB_CAP_ID
:
/* SPIB capability found, handler function */
dev_dbg
(
bus
->
dev
,
"Found SPB capability
\n
"
);
ebus
->
spbcap
=
bus
->
remap_addr
+
offset
;
break
;
case
AZX_DRSM_CAP_ID
:
/* DMA resume capability found, handler function */
dev_dbg
(
bus
->
dev
,
"Found DRSM capability
\n
"
);
ebus
->
drsmcap
=
bus
->
remap_addr
+
offset
;
break
;
default:
dev_dbg
(
bus
->
dev
,
"Unknown capability %d
\n
"
,
cur_cap
);
break
;
}
counter
++
;
if
(
counter
>
HDAC_MAX_CAPS
)
{
dev_err
(
bus
->
dev
,
"We exceeded HDAC Ext capablities!!!
\n
"
);
break
;
}
/* read the offset of next capabiity */
offset
=
cur_cap
&
AZX_CAP_HDR_NXT_PTR_MASK
;
}
while
(
offset
);
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_hdac_ext_bus_parse_capabilities
);
/*
* processing pipe helpers - these helpers are useful for dealing with HDA
* new capability of processing pipelines
...
...
@@ -118,15 +43,15 @@ void snd_hdac_ext_bus_ppcap_enable(struct hdac_ext_bus *ebus, bool enable)
{
struct
hdac_bus
*
bus
=
&
ebus
->
bus
;
if
(
!
e
bus
->
ppcap
)
{
if
(
!
bus
->
ppcap
)
{
dev_err
(
bus
->
dev
,
"Address of PP capability is NULL"
);
return
;
}
if
(
enable
)
snd_hdac_updatel
(
e
bus
->
ppcap
,
AZX_REG_PP_PPCTL
,
0
,
AZX_PPCTL_GPROCEN
);
snd_hdac_updatel
(
bus
->
ppcap
,
AZX_REG_PP_PPCTL
,
0
,
AZX_PPCTL_GPROCEN
);
else
snd_hdac_updatel
(
e
bus
->
ppcap
,
AZX_REG_PP_PPCTL
,
AZX_PPCTL_GPROCEN
,
0
);
snd_hdac_updatel
(
bus
->
ppcap
,
AZX_REG_PP_PPCTL
,
AZX_PPCTL_GPROCEN
,
0
);
}
EXPORT_SYMBOL_GPL
(
snd_hdac_ext_bus_ppcap_enable
);
...
...
@@ -139,15 +64,15 @@ void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_ext_bus *ebus, bool enable)
{
struct
hdac_bus
*
bus
=
&
ebus
->
bus
;
if
(
!
e
bus
->
ppcap
)
{
if
(
!
bus
->
ppcap
)
{
dev_err
(
bus
->
dev
,
"Address of PP capability is NULL
\n
"
);
return
;
}
if
(
enable
)
snd_hdac_updatel
(
e
bus
->
ppcap
,
AZX_REG_PP_PPCTL
,
0
,
AZX_PPCTL_PIE
);
snd_hdac_updatel
(
bus
->
ppcap
,
AZX_REG_PP_PPCTL
,
0
,
AZX_PPCTL_PIE
);
else
snd_hdac_updatel
(
e
bus
->
ppcap
,
AZX_REG_PP_PPCTL
,
AZX_PPCTL_PIE
,
0
);
snd_hdac_updatel
(
bus
->
ppcap
,
AZX_REG_PP_PPCTL
,
AZX_PPCTL_PIE
,
0
);
}
EXPORT_SYMBOL_GPL
(
snd_hdac_ext_bus_ppcap_int_enable
);
...
...
@@ -171,7 +96,7 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *ebus)
struct
hdac_ext_link
*
hlink
;
struct
hdac_bus
*
bus
=
&
ebus
->
bus
;
link_count
=
readl
(
e
bus
->
mlcap
+
AZX_REG_ML_MLCD
)
+
1
;
link_count
=
readl
(
bus
->
mlcap
+
AZX_REG_ML_MLCD
)
+
1
;
dev_dbg
(
bus
->
dev
,
"In %s Link count: %d
\n
"
,
__func__
,
link_count
);
...
...
@@ -181,7 +106,7 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *ebus)
return
-
ENOMEM
;
hlink
->
index
=
idx
;
hlink
->
bus
=
bus
;
hlink
->
ml_addr
=
e
bus
->
mlcap
+
AZX_ML_BASE
+
hlink
->
ml_addr
=
bus
->
mlcap
+
AZX_ML_BASE
+
(
AZX_ML_INTERVAL
*
idx
);
hlink
->
lcaps
=
readl
(
hlink
->
ml_addr
+
AZX_REG_ML_LCAP
);
hlink
->
lsdiid
=
readw
(
hlink
->
ml_addr
+
AZX_REG_ML_LSDIID
);
...
...
sound/hda/ext/hdac_ext_stream.c
View file @
4a2447b4
...
...
@@ -40,27 +40,27 @@ void snd_hdac_ext_stream_init(struct hdac_ext_bus *ebus,
{
struct
hdac_bus
*
bus
=
&
ebus
->
bus
;
if
(
e
bus
->
ppcap
)
{
stream
->
pphc_addr
=
e
bus
->
ppcap
+
AZX_PPHC_BASE
+
if
(
bus
->
ppcap
)
{
stream
->
pphc_addr
=
bus
->
ppcap
+
AZX_PPHC_BASE
+
AZX_PPHC_INTERVAL
*
idx
;
stream
->
pplc_addr
=
e
bus
->
ppcap
+
AZX_PPLC_BASE
+
stream
->
pplc_addr
=
bus
->
ppcap
+
AZX_PPLC_BASE
+
AZX_PPLC_MULTI
*
ebus
->
num_streams
+
AZX_PPLC_INTERVAL
*
idx
;
}
if
(
e
bus
->
spbcap
)
{
stream
->
spib_addr
=
e
bus
->
spbcap
+
AZX_SPB_BASE
+
if
(
bus
->
spbcap
)
{
stream
->
spib_addr
=
bus
->
spbcap
+
AZX_SPB_BASE
+
AZX_SPB_INTERVAL
*
idx
+
AZX_SPB_SPIB
;
stream
->
fifo_addr
=
e
bus
->
spbcap
+
AZX_SPB_BASE
+
stream
->
fifo_addr
=
bus
->
spbcap
+
AZX_SPB_BASE
+
AZX_SPB_INTERVAL
*
idx
+
AZX_SPB_MAXFIFO
;
}
if
(
e
bus
->
drsmcap
)
stream
->
dpibr_addr
=
e
bus
->
drsmcap
+
AZX_DRSM_BASE
+
if
(
bus
->
drsmcap
)
stream
->
dpibr_addr
=
bus
->
drsmcap
+
AZX_DRSM_BASE
+
AZX_DRSM_INTERVAL
*
idx
;
stream
->
decoupled
=
false
;
...
...
@@ -131,10 +131,10 @@ void snd_hdac_ext_stream_decouple(struct hdac_ext_bus *ebus,
spin_lock_irq
(
&
bus
->
reg_lock
);
if
(
decouple
)
snd_hdac_updatel
(
e
bus
->
ppcap
,
AZX_REG_PP_PPCTL
,
0
,
snd_hdac_updatel
(
bus
->
ppcap
,
AZX_REG_PP_PPCTL
,
0
,
AZX_PPCTL_PROCEN
(
hstream
->
index
));
else
snd_hdac_updatel
(
e
bus
->
ppcap
,
AZX_REG_PP_PPCTL
,
snd_hdac_updatel
(
bus
->
ppcap
,
AZX_REG_PP_PPCTL
,
AZX_PPCTL_PROCEN
(
hstream
->
index
),
0
);
stream
->
decoupled
=
decouple
;
spin_unlock_irq
(
&
bus
->
reg_lock
);
...
...
@@ -255,7 +255,7 @@ hdac_ext_link_stream_assign(struct hdac_ext_bus *ebus,
struct
hdac_stream
*
stream
=
NULL
;
struct
hdac_bus
*
hbus
=
&
ebus
->
bus
;
if
(
!
e
bus
->
ppcap
)
{
if
(
!
h
bus
->
ppcap
)
{
dev_err
(
hbus
->
dev
,
"stream type not supported
\n
"
);
return
NULL
;
}
...
...
@@ -296,7 +296,7 @@ hdac_ext_host_stream_assign(struct hdac_ext_bus *ebus,
struct
hdac_stream
*
stream
=
NULL
;
struct
hdac_bus
*
hbus
=
&
ebus
->
bus
;
if
(
!
e
bus
->
ppcap
)
{
if
(
!
h
bus
->
ppcap
)
{
dev_err
(
hbus
->
dev
,
"stream type not supported
\n
"
);
return
NULL
;
}
...
...
@@ -423,21 +423,21 @@ void snd_hdac_ext_stream_spbcap_enable(struct hdac_ext_bus *ebus,
u32
register_mask
=
0
;
struct
hdac_bus
*
bus
=
&
ebus
->
bus
;
if
(
!
e
bus
->
spbcap
)
{
if
(
!
bus
->
spbcap
)
{
dev_err
(
bus
->
dev
,
"Address of SPB capability is NULL"
);
return
;
}
mask
|=
(
1
<<
index
);
register_mask
=
readl
(
e
bus
->
spbcap
+
AZX_REG_SPB_SPBFCCTL
);
register_mask
=
readl
(
bus
->
spbcap
+
AZX_REG_SPB_SPBFCCTL
);
mask
|=
register_mask
;
if
(
enable
)
snd_hdac_updatel
(
e
bus
->
spbcap
,
AZX_REG_SPB_SPBFCCTL
,
0
,
mask
);
snd_hdac_updatel
(
bus
->
spbcap
,
AZX_REG_SPB_SPBFCCTL
,
0
,
mask
);
else
snd_hdac_updatel
(
e
bus
->
spbcap
,
AZX_REG_SPB_SPBFCCTL
,
mask
,
0
);
snd_hdac_updatel
(
bus
->
spbcap
,
AZX_REG_SPB_SPBFCCTL
,
mask
,
0
);
}
EXPORT_SYMBOL_GPL
(
snd_hdac_ext_stream_spbcap_enable
);
...
...
@@ -452,7 +452,7 @@ int snd_hdac_ext_stream_set_spib(struct hdac_ext_bus *ebus,
{
struct
hdac_bus
*
bus
=
&
ebus
->
bus
;
if
(
!
e
bus
->
spbcap
)
{
if
(
!
bus
->
spbcap
)
{
dev_err
(
bus
->
dev
,
"Address of SPB capability is NULL"
);
return
-
EINVAL
;
}
...
...
@@ -475,7 +475,7 @@ int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_ext_bus *ebus,
{
struct
hdac_bus
*
bus
=
&
ebus
->
bus
;
if
(
!
e
bus
->
spbcap
)
{
if
(
!
bus
->
spbcap
)
{
dev_err
(
bus
->
dev
,
"Address of SPB capability is NULL"
);
return
-
EINVAL
;
}
...
...
@@ -515,21 +515,21 @@ void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus,
u32
register_mask
=
0
;
struct
hdac_bus
*
bus
=
&
ebus
->
bus
;
if
(
!
e
bus
->
drsmcap
)
{
if
(
!
bus
->
drsmcap
)
{
dev_err
(
bus
->
dev
,
"Address of DRSM capability is NULL"
);
return
;
}
mask
|=
(
1
<<
index
);
register_mask
=
readl
(
e
bus
->
drsmcap
+
AZX_REG_SPB_SPBFCCTL
);
register_mask
=
readl
(
bus
->
drsmcap
+
AZX_REG_SPB_SPBFCCTL
);
mask
|=
register_mask
;
if
(
enable
)
snd_hdac_updatel
(
e
bus
->
drsmcap
,
AZX_REG_DRSM_CTL
,
0
,
mask
);
snd_hdac_updatel
(
bus
->
drsmcap
,
AZX_REG_DRSM_CTL
,
0
,
mask
);
else
snd_hdac_updatel
(
e
bus
->
drsmcap
,
AZX_REG_DRSM_CTL
,
mask
,
0
);
snd_hdac_updatel
(
bus
->
drsmcap
,
AZX_REG_DRSM_CTL
,
mask
,
0
);
}
EXPORT_SYMBOL_GPL
(
snd_hdac_ext_stream_drsm_enable
);
...
...
@@ -544,7 +544,7 @@ int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus,
{
struct
hdac_bus
*
bus
=
&
ebus
->
bus
;
if
(
!
e
bus
->
drsmcap
)
{
if
(
!
bus
->
drsmcap
)
{
dev_err
(
bus
->
dev
,
"Address of DRSM capability is NULL"
);
return
-
EINVAL
;
}
...
...
sound/hda/hdac_controller.c
View file @
4a2447b4
...
...
@@ -255,6 +255,81 @@ int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr,
}
EXPORT_SYMBOL_GPL
(
snd_hdac_bus_get_response
);
#define HDAC_MAX_CAPS 10
/**
* snd_hdac_bus_parse_capabilities - parse capability structure
* @bus: the pointer to bus object
*
* Returns 0 if successful, or a negative error code.
*/
int
snd_hdac_bus_parse_capabilities
(
struct
hdac_bus
*
bus
)
{
unsigned
int
cur_cap
;
unsigned
int
offset
;
unsigned
int
counter
=
0
;
offset
=
snd_hdac_chip_readl
(
bus
,
LLCH
);
/* Lets walk the linked capabilities list */
do
{
cur_cap
=
_snd_hdac_chip_read
(
l
,
bus
,
offset
);
dev_dbg
(
bus
->
dev
,
"Capability version: 0x%x
\n
"
,
(
cur_cap
&
AZX_CAP_HDR_VER_MASK
)
>>
AZX_CAP_HDR_VER_OFF
);
dev_dbg
(
bus
->
dev
,
"HDA capability ID: 0x%x
\n
"
,
(
cur_cap
&
AZX_CAP_HDR_ID_MASK
)
>>
AZX_CAP_HDR_ID_OFF
);
switch
((
cur_cap
&
AZX_CAP_HDR_ID_MASK
)
>>
AZX_CAP_HDR_ID_OFF
)
{
case
AZX_ML_CAP_ID
:
dev_dbg
(
bus
->
dev
,
"Found ML capability
\n
"
);
bus
->
mlcap
=
bus
->
remap_addr
+
offset
;
break
;
case
AZX_GTS_CAP_ID
:
dev_dbg
(
bus
->
dev
,
"Found GTS capability offset=%x
\n
"
,
offset
);
bus
->
gtscap
=
bus
->
remap_addr
+
offset
;
break
;
case
AZX_PP_CAP_ID
:
/* PP capability found, the Audio DSP is present */
dev_dbg
(
bus
->
dev
,
"Found PP capability offset=%x
\n
"
,
offset
);
bus
->
ppcap
=
bus
->
remap_addr
+
offset
;
break
;
case
AZX_SPB_CAP_ID
:
/* SPIB capability found, handler function */
dev_dbg
(
bus
->
dev
,
"Found SPB capability
\n
"
);
bus
->
spbcap
=
bus
->
remap_addr
+
offset
;
break
;
case
AZX_DRSM_CAP_ID
:
/* DMA resume capability found, handler function */
dev_dbg
(
bus
->
dev
,
"Found DRSM capability
\n
"
);
bus
->
drsmcap
=
bus
->
remap_addr
+
offset
;
break
;
default:
dev_dbg
(
bus
->
dev
,
"Unknown capability %d
\n
"
,
cur_cap
);
break
;
}
counter
++
;
if
(
counter
>
HDAC_MAX_CAPS
)
{
dev_err
(
bus
->
dev
,
"We exceeded HDAC capabilities!!!
\n
"
);
break
;
}
/* read the offset of next capability */
offset
=
cur_cap
&
AZX_CAP_HDR_NXT_PTR_MASK
;
}
while
(
offset
);
return
0
;
}
EXPORT_SYMBOL_GPL
(
snd_hdac_bus_parse_capabilities
);
/*
* Lowlevel interface
*/
...
...
sound/pci/hda/hda_controller.c
View file @
4a2447b4
...
...
@@ -27,6 +27,12 @@
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#ifdef CONFIG_X86
/* for art-tsc conversion */
#include <asm/tsc.h>
#endif
#include <sound/core.h>
#include <sound/initval.h>
#include "hda_controller.h"
...
...
@@ -337,12 +343,173 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
azx_get_position
(
chip
,
azx_dev
));
}
/*
* azx_scale64: Scale base by mult/div while not overflowing sanely
*
* Derived from scale64_check_overflow in kernel/time/timekeeping.c
*
* The tmestamps for a 48Khz stream can overflow after (2^64/10^9)/48K which
* is about 384307 ie ~4.5 days.
*
* This scales the calculation so that overflow will happen but after 2^64 /
* 48000 secs, which is pretty large!
*
* In caln below:
* base may overflow, but since there isn’t any additional division
* performed on base it’s OK
* rem can’t overflow because both are 32-bit values
*/
#ifdef CONFIG_X86
static
u64
azx_scale64
(
u64
base
,
u32
num
,
u32
den
)
{
u64
rem
;
rem
=
do_div
(
base
,
den
);
base
*=
num
;
rem
*=
num
;
do_div
(
rem
,
den
);
return
base
+
rem
;
}
static
int
azx_get_sync_time
(
ktime_t
*
device
,
struct
system_counterval_t
*
system
,
void
*
ctx
)
{
struct
snd_pcm_substream
*
substream
=
ctx
;
struct
azx_dev
*
azx_dev
=
get_azx_dev
(
substream
);
struct
azx_pcm
*
apcm
=
snd_pcm_substream_chip
(
substream
);
struct
azx
*
chip
=
apcm
->
chip
;
struct
snd_pcm_runtime
*
runtime
;
u64
ll_counter
,
ll_counter_l
,
ll_counter_h
;
u64
tsc_counter
,
tsc_counter_l
,
tsc_counter_h
;
u32
wallclk_ctr
,
wallclk_cycles
;
bool
direction
;
u32
dma_select
;
u32
timeout
=
200
;
u32
retry_count
=
0
;
runtime
=
substream
->
runtime
;
if
(
substream
->
stream
==
SNDRV_PCM_STREAM_PLAYBACK
)
direction
=
1
;
else
direction
=
0
;
/* 0th stream tag is not used, so DMA ch 0 is for 1st stream tag */
do
{
timeout
=
100
;
dma_select
=
(
direction
<<
GTSCC_CDMAS_DMA_DIR_SHIFT
)
|
(
azx_dev
->
core
.
stream_tag
-
1
);
snd_hdac_chip_writel
(
azx_bus
(
chip
),
GTSCC
,
dma_select
);
/* Enable the capture */
snd_hdac_chip_updatel
(
azx_bus
(
chip
),
GTSCC
,
0
,
GTSCC_TSCCI_MASK
);
while
(
timeout
)
{
if
(
snd_hdac_chip_readl
(
azx_bus
(
chip
),
GTSCC
)
&
GTSCC_TSCCD_MASK
)
break
;
timeout
--
;
}
if
(
!
timeout
)
{
dev_err
(
chip
->
card
->
dev
,
"GTSCC capture Timedout!
\n
"
);
return
-
EIO
;
}
/* Read wall clock counter */
wallclk_ctr
=
snd_hdac_chip_readl
(
azx_bus
(
chip
),
WALFCC
);
/* Read TSC counter */
tsc_counter_l
=
snd_hdac_chip_readl
(
azx_bus
(
chip
),
TSCCL
);
tsc_counter_h
=
snd_hdac_chip_readl
(
azx_bus
(
chip
),
TSCCU
);
/* Read Link counter */
ll_counter_l
=
snd_hdac_chip_readl
(
azx_bus
(
chip
),
LLPCL
);
ll_counter_h
=
snd_hdac_chip_readl
(
azx_bus
(
chip
),
LLPCU
);
/* Ack: registers read done */
snd_hdac_chip_writel
(
azx_bus
(
chip
),
GTSCC
,
GTSCC_TSCCD_SHIFT
);
tsc_counter
=
(
tsc_counter_h
<<
TSCCU_CCU_SHIFT
)
|
tsc_counter_l
;
ll_counter
=
(
ll_counter_h
<<
LLPC_CCU_SHIFT
)
|
ll_counter_l
;
wallclk_cycles
=
wallclk_ctr
&
WALFCC_CIF_MASK
;
/*
* An error occurs near frame "rollover". The clocks in
* frame value indicates whether this error may have
* occurred. Here we use the value of 10 i.e.,
* HDA_MAX_CYCLE_OFFSET
*/
if
(
wallclk_cycles
<
HDA_MAX_CYCLE_VALUE
-
HDA_MAX_CYCLE_OFFSET
&&
wallclk_cycles
>
HDA_MAX_CYCLE_OFFSET
)
break
;
/*
* Sleep before we read again, else we may again get
* value near to MAX_CYCLE. Try to sleep for different
* amount of time so we dont hit the same number again
*/
udelay
(
retry_count
++
);
}
while
(
retry_count
!=
HDA_MAX_CYCLE_READ_RETRY
);
if
(
retry_count
==
HDA_MAX_CYCLE_READ_RETRY
)
{
dev_err_ratelimited
(
chip
->
card
->
dev
,
"Error in WALFCC cycle count
\n
"
);
return
-
EIO
;
}
*
device
=
ns_to_ktime
(
azx_scale64
(
ll_counter
,
NSEC_PER_SEC
,
runtime
->
rate
));
*
device
=
ktime_add_ns
(
*
device
,
(
wallclk_cycles
*
NSEC_PER_SEC
)
/
((
HDA_MAX_CYCLE_VALUE
+
1
)
*
runtime
->
rate
));
*
system
=
convert_art_to_tsc
(
tsc_counter
);
return
0
;
}
#else
static
int
azx_get_sync_time
(
ktime_t
*
device
,
struct
system_counterval_t
*
system
,
void
*
ctx
)
{
return
-
ENXIO
;
}
#endif
static
int
azx_get_crosststamp
(
struct
snd_pcm_substream
*
substream
,
struct
system_device_crosststamp
*
xtstamp
)
{
return
get_device_system_crosststamp
(
azx_get_sync_time
,
substream
,
NULL
,
xtstamp
);
}
static
inline
bool
is_link_time_supported
(
struct
snd_pcm_runtime
*
runtime
,
struct
snd_pcm_audio_tstamp_config
*
ts
)
{
if
(
runtime
->
hw
.
info
&
SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME
)
if
(
ts
->
type_requested
==
SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED
)
return
true
;
return
false
;
}
static
int
azx_get_time_info
(
struct
snd_pcm_substream
*
substream
,
struct
timespec
*
system_ts
,
struct
timespec
*
audio_ts
,
struct
snd_pcm_audio_tstamp_config
*
audio_tstamp_config
,
struct
snd_pcm_audio_tstamp_report
*
audio_tstamp_report
)
{
struct
azx_dev
*
azx_dev
=
get_azx_dev
(
substream
);
struct
snd_pcm_runtime
*
runtime
=
substream
->
runtime
;
struct
system_device_crosststamp
xtstamp
;
int
ret
;
u64
nsec
;
if
((
substream
->
runtime
->
hw
.
info
&
SNDRV_PCM_INFO_HAS_LINK_ATIME
)
&&
...
...
@@ -361,8 +528,37 @@ static int azx_get_time_info(struct snd_pcm_substream *substream,
audio_tstamp_report
->
accuracy_report
=
1
;
/* rest of structure is valid */
audio_tstamp_report
->
accuracy
=
42
;
/* 24 MHz WallClock == 42ns resolution */
}
else
}
else
if
(
is_link_time_supported
(
runtime
,
audio_tstamp_config
))
{
ret
=
azx_get_crosststamp
(
substream
,
&
xtstamp
);
if
(
ret
)
return
ret
;
switch
(
runtime
->
tstamp_type
)
{
case
SNDRV_PCM_TSTAMP_TYPE_MONOTONIC
:
return
-
EINVAL
;
case
SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW
:
*
system_ts
=
ktime_to_timespec
(
xtstamp
.
sys_monoraw
);
break
;
default:
*
system_ts
=
ktime_to_timespec
(
xtstamp
.
sys_realtime
);
break
;
}
*
audio_ts
=
ktime_to_timespec
(
xtstamp
.
device
);
audio_tstamp_report
->
actual_type
=
SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED
;
audio_tstamp_report
->
accuracy_report
=
1
;
/* 24 MHz WallClock == 42ns resolution */
audio_tstamp_report
->
accuracy
=
42
;
}
else
{
audio_tstamp_report
->
actual_type
=
SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT
;
}
return
0
;
}
...
...
@@ -412,6 +608,11 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
goto
unlock
;
}
runtime
->
private_data
=
azx_dev
;
if
(
chip
->
gts_present
)
azx_pcm_hw
.
info
=
azx_pcm_hw
.
info
|
SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME
;
runtime
->
hw
=
azx_pcm_hw
;
runtime
->
hw
.
channels_min
=
hinfo
->
channels_min
;
runtime
->
hw
.
channels_max
=
hinfo
->
channels_max
;
...
...
sound/pci/hda/hda_controller.h
View file @
4a2447b4
...
...
@@ -159,6 +159,9 @@ struct azx {
unsigned
int
region_requested
:
1
;
unsigned
int
disabled
:
1
;
/* disabled by vga_switcheroo */
/* GTS present */
unsigned
int
gts_present
:
1
;
#ifdef CONFIG_SND_HDA_DSP_LOADER
struct
azx_dev
saved_azx_dev
;
#endif
...
...
sound/pci/hda/hda_intel.c
View file @
4a2447b4
...
...
@@ -54,6 +54,7 @@
/* for snoop control */
#include <asm/pgtable.h>
#include <asm/cacheflush.h>
#include <asm/cpufeature.h>
#endif
#include <sound/core.h>
#include <sound/initval.h>
...
...
@@ -1663,6 +1664,22 @@ static int azx_first_init(struct azx *chip)
return
-
ENXIO
;
}
if
(
IS_SKL_PLUS
(
pci
))
snd_hdac_bus_parse_capabilities
(
bus
);
/*
* Some Intel CPUs has always running timer (ART) feature and
* controller may have Global time sync reporting capability, so
* check both of these before declaring synchronized time reporting
* capability SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME
*/
chip
->
gts_present
=
false
;
#ifdef CONFIG_X86
if
(
bus
->
ppcap
&&
boot_cpu_has
(
X86_FEATURE_ART
))
chip
->
gts_present
=
true
;
#endif
if
(
chip
->
msi
)
{
if
(
chip
->
driver_caps
&
AZX_DCAPS_NO_MSI64
)
{
dev_dbg
(
card
->
dev
,
"Disabling 64bit MSI
\n
"
);
...
...
sound/soc/codecs/rt5640.c
View file @
4a2447b4
...
...
@@ -1870,6 +1870,9 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,
case
RT5640_SCLK_S_PLL1
:
reg_val
|=
RT5640_SCLK_SRC_PLL1
;
break
;
case
RT5640_SCLK_S_RCCLK
:
reg_val
|=
RT5640_SCLK_SRC_RCCLK
;
break
;
default:
dev_err
(
codec
->
dev
,
"Invalid clock id (%d)
\n
"
,
clk_id
);
return
-
EINVAL
;
...
...
sound/soc/codecs/rt5640.h
View file @
4a2447b4
...
...
@@ -984,6 +984,7 @@
#define RT5640_SCLK_SRC_SFT 14
#define RT5640_SCLK_SRC_MCLK (0x0 << 14)
#define RT5640_SCLK_SRC_PLL1 (0x1 << 14)
#define RT5640_SCLK_SRC_RCCLK (0x2 << 14)
#define RT5640_PLL1_SRC_MASK (0x3 << 12)
#define RT5640_PLL1_SRC_SFT 12
#define RT5640_PLL1_SRC_MCLK (0x0 << 12)
...
...
sound/soc/intel/Kconfig
View file @
4a2447b4
...
...
@@ -25,6 +25,7 @@ config SND_SST_IPC_ACPI
tristate
select SND_SST_IPC
select SND_SOC_INTEL_SST
select IOSF_MBI
config SND_SOC_INTEL_SST
tristate
...
...
@@ -120,6 +121,17 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH
This adds audio driver for Intel Baytrail platform based boards
with the MAX98090 audio codec.
config SND_SOC_INTEL_BDW_RT5677_MACH
tristate "ASoC Audio driver for Intel Broadwell with RT5677 codec"
depends on X86_INTEL_LPSS && GPIOLIB && I2C && DW_DMAC
depends on DW_DMAC_CORE=y
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_HASWELL
select SND_SOC_RT5677
help
This adds support for Intel Broadwell platform based boards with
the RT5677 audio codec.
config SND_SOC_INTEL_BROADWELL_MACH
tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint"
depends on X86_INTEL_LPSS && I2C && DW_DMAC && \
...
...
sound/soc/intel/atom/sst-atom-controls.c
View file @
4a2447b4
/*
/*
* sst-atom-controls.c - Intel MID Platform driver DPCM ALSA controls for Mrfld
*
* Copyright (C) 2013-14 Intel Corp
...
...
@@ -534,6 +534,7 @@ static const DECLARE_TLV_DB_SCALE(sst_gain_tlv_common, SST_GAIN_MIN_VALUE * 10,
/* Look up table to convert MIXER SW bit regs to SWM inputs */
static
const
uint
swm_mixer_input_ids
[
SST_SWM_INPUT_COUNT
]
=
{
[
SST_IP_MODEM
]
=
SST_SWM_IN_MODEM
,
[
SST_IP_CODEC0
]
=
SST_SWM_IN_CODEC0
,
[
SST_IP_CODEC1
]
=
SST_SWM_IN_CODEC1
,
[
SST_IP_LOOP0
]
=
SST_SWM_IN_SPROT_LOOP
,
...
...
@@ -674,6 +675,7 @@ static int sst_swm_mixer_event(struct snd_soc_dapm_widget *w,
/* SBA mixers - 16 inputs */
#define SST_SBA_DECLARE_MIX_CONTROLS(kctl_name) \
static const struct snd_kcontrol_new kctl_name[] = { \
SOC_DAPM_SINGLE("modem_in Switch", SND_SOC_NOPM, SST_IP_MODEM, 1, 0), \
SOC_DAPM_SINGLE("codec_in0 Switch", SND_SOC_NOPM, SST_IP_CODEC0, 1, 0), \
SOC_DAPM_SINGLE("codec_in1 Switch", SND_SOC_NOPM, SST_IP_CODEC1, 1, 0), \
SOC_DAPM_SINGLE("sprot_loop_in Switch", SND_SOC_NOPM, SST_IP_LOOP0, 1, 0), \
...
...
@@ -684,6 +686,7 @@ static int sst_swm_mixer_event(struct snd_soc_dapm_widget *w,
}
#define SST_SBA_MIXER_GRAPH_MAP(mix_name) \
{ mix_name, "modem_in Switch", "modem_in" }, \
{ mix_name, "codec_in0 Switch", "codec_in0" }, \
{ mix_name, "codec_in1 Switch", "codec_in1" }, \
{ mix_name, "sprot_loop_in Switch", "sprot_loop_in" }, \
...
...
@@ -713,6 +716,7 @@ SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_media_l2_controls);
SST_SBA_DECLARE_MIX_CONTROLS
(
sst_mix_voip_controls
);
SST_SBA_DECLARE_MIX_CONTROLS
(
sst_mix_codec0_controls
);
SST_SBA_DECLARE_MIX_CONTROLS
(
sst_mix_codec1_controls
);
SST_SBA_DECLARE_MIX_CONTROLS
(
sst_mix_modem_controls
);
/*
* sst_handle_vb_timer - Start/Stop the DSP scheduler
...
...
@@ -931,17 +935,26 @@ void sst_fill_ssp_defaults(struct snd_soc_dai *dai)
int
send_ssp_cmd
(
struct
snd_soc_dai
*
dai
,
const
char
*
id
,
bool
enable
)
{
struct
sst_data
*
drv
=
snd_soc_dai_get_drvdata
(
dai
);
const
struct
sst_ssp_config
*
config
;
int
ssp_id
;
dev_info
(
dai
->
dev
,
"Enter: enable=%d port_name=%s
\n
"
,
enable
,
id
);
if
(
strcmp
(
id
,
"ssp0-port"
)
==
0
)
ssp_id
=
SSP_MODEM
;
else
if
(
strcmp
(
id
,
"ssp2-port"
)
==
0
)
ssp_id
=
SSP_CODEC
;
else
{
dev_dbg
(
dai
->
dev
,
"port %s is not supported
\n
"
,
id
);
return
-
1
;
}
SST_FILL_DEFAULT_DESTINATION
(
drv
->
ssp_cmd
.
header
.
dst
);
drv
->
ssp_cmd
.
header
.
command_id
=
SBA_HW_SET_SSP
;
drv
->
ssp_cmd
.
header
.
length
=
sizeof
(
struct
sst_cmd_sba_hw_set_ssp
)
-
sizeof
(
struct
sst_dsp_header
);
config
=
&
sst_ssp_configs
;
dev_dbg
(
dai
->
dev
,
"ssp_id: %u
\n
"
,
config
->
ssp_id
);
drv
->
ssp_cmd
.
selection
=
ssp_id
;
dev_dbg
(
dai
->
dev
,
"ssp_id: %u
\n
"
,
ssp_id
);
if
(
enable
)
drv
->
ssp_cmd
.
switch_state
=
SST_SWITCH_ON
;
...
...
@@ -1047,8 +1060,10 @@ static int sst_set_media_loop(struct snd_soc_dapm_widget *w,
}
static
const
struct
snd_soc_dapm_widget
sst_dapm_widgets
[]
=
{
SST_AIF_IN
(
"modem_in"
,
sst_set_be_modules
),
SST_AIF_IN
(
"codec_in0"
,
sst_set_be_modules
),
SST_AIF_IN
(
"codec_in1"
,
sst_set_be_modules
),
SST_AIF_OUT
(
"modem_out"
,
sst_set_be_modules
),
SST_AIF_OUT
(
"codec_out0"
,
sst_set_be_modules
),
SST_AIF_OUT
(
"codec_out1"
,
sst_set_be_modules
),
...
...
@@ -1103,6 +1118,9 @@ static const struct snd_soc_dapm_widget sst_dapm_widgets[] = {
sst_mix_codec0_controls
,
sst_swm_mixer_event
),
SST_SWM_MIXER
(
"codec_out1 mix 0"
,
SND_SOC_NOPM
,
SST_TASK_SBA
,
SST_SWM_OUT_CODEC1
,
sst_mix_codec1_controls
,
sst_swm_mixer_event
),
SST_SWM_MIXER
(
"modem_out mix 0"
,
SND_SOC_NOPM
,
SST_TASK_SBA
,
SST_SWM_OUT_MODEM
,
sst_mix_modem_controls
,
sst_swm_mixer_event
),
};
static
const
struct
snd_soc_dapm_route
intercon
[]
=
{
...
...
@@ -1148,6 +1166,9 @@ static const struct snd_soc_dapm_route intercon[] = {
SST_SBA_MIXER_GRAPH_MAP
(
"codec_out0 mix 0"
),
{
"codec_out1"
,
NULL
,
"codec_out1 mix 0"
},
SST_SBA_MIXER_GRAPH_MAP
(
"codec_out1 mix 0"
),
{
"modem_out"
,
NULL
,
"modem_out mix 0"
},
SST_SBA_MIXER_GRAPH_MAP
(
"modem_out mix 0"
),
};
static
const
char
*
const
slot_names
[]
=
{
...
...
@@ -1217,6 +1238,9 @@ static const struct snd_kcontrol_new sst_gain_controls[] = {
SST_GAIN
(
"media_loop2_out"
,
SST_PATH_INDEX_MEDIA_LOOP2_OUT
,
SST_TASK_SBA
,
0
,
&
sst_gains
[
13
]),
SST_GAIN
(
"sprot_loop_out"
,
SST_PATH_INDEX_SPROT_LOOP_OUT
,
SST_TASK_SBA
,
0
,
&
sst_gains
[
14
]),
SST_VOLUME
(
"media0_in"
,
SST_PATH_INDEX_MEDIA0_IN
,
SST_TASK_MMX
,
0
,
&
sst_gains
[
15
]),
SST_GAIN
(
"modem_in"
,
SST_PATH_INDEX_MODEM_IN
,
SST_TASK_SBA
,
0
,
&
sst_gains
[
16
]),
SST_GAIN
(
"modem_out"
,
SST_PATH_INDEX_MODEM_OUT
,
SST_TASK_SBA
,
0
,
&
sst_gains
[
17
]),
};
#define SST_GAIN_NUM_CONTROLS 3
...
...
sound/soc/intel/atom/sst-atom-controls.h
View file @
4a2447b4
...
...
@@ -35,6 +35,8 @@ enum {
/* define a bit for each mixer input */
#define SST_MIX_IP(x) (x)
#define SST_IP_MODEM SST_MIX_IP(0)
#define SST_IP_BT SST_MIX_IP(1)
#define SST_IP_CODEC0 SST_MIX_IP(2)
#define SST_IP_CODEC1 SST_MIX_IP(3)
#define SST_IP_LOOP0 SST_MIX_IP(4)
...
...
@@ -63,6 +65,7 @@ enum {
* Audio DSP Path Ids. Specified by the audio DSP FW
*/
enum
sst_path_index
{
SST_PATH_INDEX_MODEM_OUT
=
(
0x00
<<
SST_PATH_ID_SHIFT
),
SST_PATH_INDEX_CODEC_OUT0
=
(
0x02
<<
SST_PATH_ID_SHIFT
),
SST_PATH_INDEX_CODEC_OUT1
=
(
0x03
<<
SST_PATH_ID_SHIFT
),
...
...
@@ -80,6 +83,7 @@ enum sst_path_index {
/* Start of input paths */
SST_PATH_INDEX_MODEM_IN
=
(
0x80
<<
SST_PATH_ID_SHIFT
),
SST_PATH_INDEX_CODEC_IN0
=
(
0x82
<<
SST_PATH_ID_SHIFT
),
SST_PATH_INDEX_CODEC_IN1
=
(
0x83
<<
SST_PATH_ID_SHIFT
),
...
...
@@ -105,6 +109,7 @@ enum sst_path_index {
* path IDs
*/
enum
sst_swm_inputs
{
SST_SWM_IN_MODEM
=
(
SST_PATH_INDEX_MODEM_IN
|
SST_DEFAULT_CELL_NBR
),
SST_SWM_IN_CODEC0
=
(
SST_PATH_INDEX_CODEC_IN0
|
SST_DEFAULT_CELL_NBR
),
SST_SWM_IN_CODEC1
=
(
SST_PATH_INDEX_CODEC_IN1
|
SST_DEFAULT_CELL_NBR
),
SST_SWM_IN_SPROT_LOOP
=
(
SST_PATH_INDEX_SPROT_LOOP_IN
|
SST_DEFAULT_CELL_NBR
),
...
...
@@ -124,6 +129,7 @@ enum sst_swm_inputs {
* path IDs
*/
enum
sst_swm_outputs
{
SST_SWM_OUT_MODEM
=
(
SST_PATH_INDEX_MODEM_OUT
|
SST_DEFAULT_CELL_NBR
),
SST_SWM_OUT_CODEC0
=
(
SST_PATH_INDEX_CODEC_OUT0
|
SST_DEFAULT_CELL_NBR
),
SST_SWM_OUT_CODEC1
=
(
SST_PATH_INDEX_CODEC_OUT1
|
SST_DEFAULT_CELL_NBR
),
SST_SWM_OUT_SPROT_LOOP
=
(
SST_PATH_INDEX_SPROT_LOOP_OUT
|
SST_DEFAULT_CELL_NBR
),
...
...
sound/soc/intel/atom/sst/sst.c
View file @
4a2447b4
...
...
@@ -190,7 +190,8 @@ int sst_driver_ops(struct intel_sst_drv *sst)
default:
dev_err
(
sst
->
dev
,
"SST Driver capablities missing for dev_id: %x"
,
sst
->
dev_id
);
"SST Driver capabilities missing for dev_id: %x"
,
sst
->
dev_id
);
return
-
EINVAL
;
};
}
...
...
@@ -441,7 +442,7 @@ static int intel_sst_suspend(struct device *dev)
struct
stream_info
*
stream
=
&
ctx
->
streams
[
i
];
if
(
stream
->
status
==
STREAM_RUNNING
)
{
dev_err
(
dev
,
"stream %d is running, can
t susu
pend, abort
\n
"
,
i
);
dev_err
(
dev
,
"stream %d is running, can
't sus
pend, abort
\n
"
,
i
);
return
-
EBUSY
;
}
}
...
...
sound/soc/intel/atom/sst/sst_acpi.c
View file @
4a2447b4
...
...
@@ -39,6 +39,8 @@
#include <acpi/platform/aclinux.h>
#include <acpi/actypes.h>
#include <acpi/acpi_bus.h>
#include <asm/cpu_device_id.h>
#include <asm/iosf_mbi.h>
#include "../sst-mfld-platform.h"
#include "../../common/sst-dsp.h"
#include "../../common/sst-acpi.h"
...
...
@@ -113,6 +115,28 @@ static const struct sst_res_info byt_rvp_res_info = {
.
acpi_ipc_irq_index
=
5
,
};
/* BYTCR has different BIOS from BYT */
static
const
struct
sst_res_info
bytcr_res_info
=
{
.
shim_offset
=
0x140000
,
.
shim_size
=
0x000100
,
.
shim_phy_addr
=
SST_BYT_SHIM_PHY_ADDR
,
.
ssp0_offset
=
0xa0000
,
.
ssp0_size
=
0x1000
,
.
dma0_offset
=
0x98000
,
.
dma0_size
=
0x4000
,
.
dma1_offset
=
0x9c000
,
.
dma1_size
=
0x4000
,
.
iram_offset
=
0x0c0000
,
.
iram_size
=
0x14000
,
.
dram_offset
=
0x100000
,
.
dram_size
=
0x28000
,
.
mbox_offset
=
0x144000
,
.
mbox_size
=
0x1000
,
.
acpi_lpe_res_index
=
0
,
.
acpi_ddr_index
=
2
,
.
acpi_ipc_irq_index
=
0
};
static
struct
sst_platform_info
byt_rvp_platform_data
=
{
.
probe_data
=
&
byt_fwparse_info
,
.
ipc_info
=
&
byt_ipc_info
,
...
...
@@ -142,7 +166,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
rsrc
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
ctx
->
pdata
->
res_info
->
acpi_lpe_res_index
);
if
(
!
rsrc
)
{
dev_err
(
ctx
->
dev
,
"Invalid SHIM base from IFWI"
);
dev_err
(
ctx
->
dev
,
"Invalid SHIM base from IFWI
\n
"
);
return
-
EIO
;
}
dev_info
(
ctx
->
dev
,
"LPE base: %#x size:%#x"
,
(
unsigned
int
)
rsrc
->
start
,
...
...
@@ -154,7 +178,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
ctx
->
iram
=
devm_ioremap_nocache
(
ctx
->
dev
,
ctx
->
iram_base
,
ctx
->
pdata
->
res_info
->
iram_size
);
if
(
!
ctx
->
iram
)
{
dev_err
(
ctx
->
dev
,
"unable to map IRAM"
);
dev_err
(
ctx
->
dev
,
"unable to map IRAM
\n
"
);
return
-
EIO
;
}
...
...
@@ -164,7 +188,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
ctx
->
dram
=
devm_ioremap_nocache
(
ctx
->
dev
,
ctx
->
dram_base
,
ctx
->
pdata
->
res_info
->
dram_size
);
if
(
!
ctx
->
dram
)
{
dev_err
(
ctx
->
dev
,
"unable to map DRAM"
);
dev_err
(
ctx
->
dev
,
"unable to map DRAM
\n
"
);
return
-
EIO
;
}
...
...
@@ -173,7 +197,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
ctx
->
shim
=
devm_ioremap_nocache
(
ctx
->
dev
,
ctx
->
shim_phy_add
,
ctx
->
pdata
->
res_info
->
shim_size
);
if
(
!
ctx
->
shim
)
{
dev_err
(
ctx
->
dev
,
"unable to map SHIM"
);
dev_err
(
ctx
->
dev
,
"unable to map SHIM
\n
"
);
return
-
EIO
;
}
...
...
@@ -186,7 +210,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
ctx
->
mailbox
=
devm_ioremap_nocache
(
ctx
->
dev
,
ctx
->
mailbox_add
,
ctx
->
pdata
->
res_info
->
mbox_size
);
if
(
!
ctx
->
mailbox
)
{
dev_err
(
ctx
->
dev
,
"unable to map mailbox"
);
dev_err
(
ctx
->
dev
,
"unable to map mailbox
\n
"
);
return
-
EIO
;
}
...
...
@@ -196,7 +220,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
rsrc
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
ctx
->
pdata
->
res_info
->
acpi_ddr_index
);
if
(
!
rsrc
)
{
dev_err
(
ctx
->
dev
,
"Invalid DDR base from IFWI"
);
dev_err
(
ctx
->
dev
,
"Invalid DDR base from IFWI
\n
"
);
return
-
EIO
;
}
ctx
->
ddr_base
=
rsrc
->
start
;
...
...
@@ -205,7 +229,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
ctx
->
ddr
=
devm_ioremap_nocache
(
ctx
->
dev
,
ctx
->
ddr_base
,
resource_size
(
rsrc
));
if
(
!
ctx
->
ddr
)
{
dev_err
(
ctx
->
dev
,
"unable to map DDR"
);
dev_err
(
ctx
->
dev
,
"unable to map DDR
\n
"
);
return
-
EIO
;
}
...
...
@@ -215,6 +239,46 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
return
0
;
}
static
int
is_byt_cr
(
struct
device
*
dev
,
bool
*
bytcr
)
{
int
status
=
0
;
if
(
IS_ENABLED
(
CONFIG_IOSF_MBI
))
{
static
const
struct
x86_cpu_id
cpu_ids
[]
=
{
{
X86_VENDOR_INTEL
,
6
,
55
},
/* Valleyview, Bay Trail */
{}
};
u32
bios_status
;
if
(
!
x86_match_cpu
(
cpu_ids
)
||
!
iosf_mbi_available
())
{
/* bail silently */
return
status
;
}
status
=
iosf_mbi_read
(
BT_MBI_UNIT_PMC
,
/* 0x04 PUNIT */
MBI_REG_READ
,
/* 0x10 */
0x006
,
/* BIOS_CONFIG */
&
bios_status
);
if
(
status
)
{
dev_err
(
dev
,
"could not read PUNIT BIOS_CONFIG
\n
"
);
}
else
{
/* bits 26:27 mirror PMIC options */
bios_status
=
(
bios_status
>>
26
)
&
3
;
if
((
bios_status
==
1
)
||
(
bios_status
==
3
))
*
bytcr
=
true
;
else
dev_info
(
dev
,
"BYT-CR not detected
\n
"
);
}
}
else
{
dev_info
(
dev
,
"IOSF_MBI not enabled, no BYT-CR detection
\n
"
);
}
return
status
;
}
static
int
sst_acpi_probe
(
struct
platform_device
*
pdev
)
{
struct
device
*
dev
=
&
pdev
->
dev
;
...
...
@@ -226,11 +290,12 @@ static int sst_acpi_probe(struct platform_device *pdev)
struct
platform_device
*
plat_dev
;
struct
sst_platform_info
*
pdata
;
unsigned
int
dev_id
;
bool
bytcr
=
false
;
id
=
acpi_match_device
(
dev
->
driver
->
acpi_match_table
,
dev
);
if
(
!
id
)
return
-
ENODEV
;
dev_dbg
(
dev
,
"for %s"
,
id
->
id
);
dev_dbg
(
dev
,
"for %s
\n
"
,
id
->
id
);
mach
=
(
struct
sst_acpi_mach
*
)
id
->
driver_data
;
mach
=
sst_acpi_find_machine
(
mach
);
...
...
@@ -251,6 +316,18 @@ static int sst_acpi_probe(struct platform_device *pdev)
dev_dbg
(
dev
,
"ACPI device id: %x
\n
"
,
dev_id
);
ret
=
sst_alloc_drv_context
(
&
ctx
,
dev
,
dev_id
);
if
(
ret
<
0
)
return
ret
;
ret
=
is_byt_cr
(
dev
,
&
bytcr
);
if
(
!
((
ret
<
0
)
||
(
bytcr
==
false
)))
{
dev_info
(
dev
,
"Detected Baytrail-CR platform
\n
"
);
/* override resource info */
byt_rvp_platform_data
.
res_info
=
&
bytcr_res_info
;
}
plat_dev
=
platform_device_register_data
(
dev
,
pdata
->
platform
,
-
1
,
NULL
,
0
);
if
(
IS_ERR
(
plat_dev
))
{
...
...
@@ -271,10 +348,6 @@ static int sst_acpi_probe(struct platform_device *pdev)
return
PTR_ERR
(
mdev
);
}
ret
=
sst_alloc_drv_context
(
&
ctx
,
dev
,
dev_id
);
if
(
ret
<
0
)
return
ret
;
/* Fill sst platform data */
ctx
->
pdata
=
pdata
;
strcpy
(
ctx
->
firmware_name
,
mach
->
fw_filename
);
...
...
sound/soc/intel/boards/Makefile
View file @
4a2447b4
snd-soc-sst-haswell-objs
:=
haswell.o
snd-soc-sst-byt-rt5640-mach-objs
:=
byt-rt5640.o
snd-soc-sst-byt-max98090-mach-objs
:=
byt-max98090.o
snd-soc-sst-bdw-rt5677-mach-objs
:=
bdw-rt5677.o
snd-soc-sst-broadwell-objs
:=
broadwell.o
snd-soc-sst-bxt-da7219_max98357a-objs
:=
bxt_da7219_max98357a.o
snd-soc-sst-bxt-rt298-objs
:=
bxt_rt298.o
...
...
@@ -19,6 +20,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o
obj-$(CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH)
+=
snd-soc-sst-bxt-da7219_max98357a.o
obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH)
+=
snd-soc-sst-bxt-rt298.o
obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH)
+=
snd-soc-sst-broadwell.o
obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH)
+=
snd-soc-sst-bdw-rt5677-mach.o
obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH)
+=
snd-soc-sst-bytcr-rt5640.o
obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH)
+=
snd-soc-sst-bytcr-rt5651.o
obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH)
+=
snd-soc-sst-cht-bsw-rt5672.o
...
...
sound/soc/intel/boards/bdw-rt5677.c
0 → 100644
View file @
4a2447b4
/*
* ASoC machine driver for Intel Broadwell platforms with RT5677 codec
*
* Copyright (c) 2014, The Chromium OS Authors. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
#include <sound/jack.h>
#include "../common/sst-dsp.h"
#include "../haswell/sst-haswell-ipc.h"
#include "../../codecs/rt5677.h"
struct
bdw_rt5677_priv
{
struct
gpio_desc
*
gpio_hp_en
;
struct
snd_soc_codec
*
codec
;
};
static
int
bdw_rt5677_event_hp
(
struct
snd_soc_dapm_widget
*
w
,
struct
snd_kcontrol
*
k
,
int
event
)
{
struct
snd_soc_dapm_context
*
dapm
=
w
->
dapm
;
struct
snd_soc_card
*
card
=
dapm
->
card
;
struct
bdw_rt5677_priv
*
bdw_rt5677
=
snd_soc_card_get_drvdata
(
card
);
if
(
SND_SOC_DAPM_EVENT_ON
(
event
))
msleep
(
70
);
gpiod_set_value_cansleep
(
bdw_rt5677
->
gpio_hp_en
,
SND_SOC_DAPM_EVENT_ON
(
event
));
return
0
;
}
static
const
struct
snd_soc_dapm_widget
bdw_rt5677_widgets
[]
=
{
SND_SOC_DAPM_HP
(
"Headphone"
,
bdw_rt5677_event_hp
),
SND_SOC_DAPM_SPK
(
"Speaker"
,
NULL
),
SND_SOC_DAPM_MIC
(
"Headset Mic"
,
NULL
),
SND_SOC_DAPM_MIC
(
"Local DMICs"
,
NULL
),
SND_SOC_DAPM_MIC
(
"Remote DMICs"
,
NULL
),
};
static
const
struct
snd_soc_dapm_route
bdw_rt5677_map
[]
=
{
/* Speakers */
{
"Speaker"
,
NULL
,
"PDM1L"
},
{
"Speaker"
,
NULL
,
"PDM1R"
},
/* Headset jack connectors */
{
"Headphone"
,
NULL
,
"LOUT1"
},
{
"Headphone"
,
NULL
,
"LOUT2"
},
{
"IN1P"
,
NULL
,
"Headset Mic"
},
{
"IN1N"
,
NULL
,
"Headset Mic"
},
/* Digital MICs
* Local DMICs: the two DMICs on the mainboard
* Remote DMICs: the two DMICs on the camera module
*/
{
"DMIC L1"
,
NULL
,
"Remote DMICs"
},
{
"DMIC R1"
,
NULL
,
"Remote DMICs"
},
{
"DMIC L2"
,
NULL
,
"Local DMICs"
},
{
"DMIC R2"
,
NULL
,
"Local DMICs"
},
/* CODEC BE connections */
{
"SSP0 CODEC IN"
,
NULL
,
"AIF1 Capture"
},
{
"AIF1 Playback"
,
NULL
,
"SSP0 CODEC OUT"
},
};
static
const
struct
snd_kcontrol_new
bdw_rt5677_controls
[]
=
{
SOC_DAPM_PIN_SWITCH
(
"Speaker"
),
SOC_DAPM_PIN_SWITCH
(
"Headphone"
),
SOC_DAPM_PIN_SWITCH
(
"Headset Mic"
),
SOC_DAPM_PIN_SWITCH
(
"Local DMICs"
),
SOC_DAPM_PIN_SWITCH
(
"Remote DMICs"
),
};
static
struct
snd_soc_jack
headphone_jack
;
static
struct
snd_soc_jack
mic_jack
;
static
struct
snd_soc_jack_pin
headphone_jack_pin
=
{
.
pin
=
"Headphone"
,
.
mask
=
SND_JACK_HEADPHONE
,
};
static
struct
snd_soc_jack_pin
mic_jack_pin
=
{
.
pin
=
"Headset Mic"
,
.
mask
=
SND_JACK_MICROPHONE
,
};
static
struct
snd_soc_jack_gpio
headphone_jack_gpio
=
{
.
name
=
"plug-det"
,
.
report
=
SND_JACK_HEADPHONE
,
.
debounce_time
=
200
,
};
static
struct
snd_soc_jack_gpio
mic_jack_gpio
=
{
.
name
=
"mic-present"
,
.
report
=
SND_JACK_MICROPHONE
,
.
debounce_time
=
200
,
.
invert
=
1
,
};
static
int
broadwell_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 ADSP will covert the FE rate to 48k, stereo */
rate
->
min
=
rate
->
max
=
48000
;
channels
->
min
=
channels
->
max
=
2
;
/* set SSP0 to 16 bit */
snd_mask_set
(
&
params
->
masks
[
SNDRV_PCM_HW_PARAM_FORMAT
-
SNDRV_PCM_HW_PARAM_FIRST_MASK
],
SNDRV_PCM_FORMAT_S16_LE
);
return
0
;
}
static
int
bdw_rt5677_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
,
RT5677_SCLK_S_MCLK
,
24576000
,
SND_SOC_CLOCK_IN
);
if
(
ret
<
0
)
{
dev_err
(
rtd
->
dev
,
"can't set codec sysclk configuration
\n
"
);
return
ret
;
}
return
ret
;
}
static
struct
snd_soc_ops
bdw_rt5677_ops
=
{
.
hw_params
=
bdw_rt5677_hw_params
,
};
static
int
bdw_rt5677_rtd_init
(
struct
snd_soc_pcm_runtime
*
rtd
)
{
struct
sst_pdata
*
pdata
=
dev_get_platdata
(
rtd
->
platform
->
dev
);
struct
sst_hsw
*
broadwell
=
pdata
->
dsp
;
int
ret
;
/* Set ADSP SSP port settings */
ret
=
sst_hsw_device_set_config
(
broadwell
,
SST_HSW_DEVICE_SSP_0
,
SST_HSW_DEVICE_MCLK_FREQ_24_MHZ
,
SST_HSW_DEVICE_CLOCK_MASTER
,
9
);
if
(
ret
<
0
)
{
dev_err
(
rtd
->
dev
,
"error: failed to set device config
\n
"
);
return
ret
;
}
return
0
;
}
static
int
bdw_rt5677_init
(
struct
snd_soc_pcm_runtime
*
rtd
)
{
struct
bdw_rt5677_priv
*
bdw_rt5677
=
snd_soc_card_get_drvdata
(
rtd
->
card
);
struct
snd_soc_codec
*
codec
=
rtd
->
codec
;
struct
snd_soc_dapm_context
*
dapm
=
snd_soc_codec_get_dapm
(
codec
);
/* Enable codec ASRC function for Stereo DAC/Stereo1 ADC/DMIC/I2S1.
* The ASRC clock source is clk_i2s1_asrc.
*/
rt5677_sel_asrc_clk_src
(
codec
,
RT5677_DA_STEREO_FILTER
|
RT5677_AD_STEREO1_FILTER
|
RT5677_I2S1_SOURCE
,
RT5677_CLK_SEL_I2S1_ASRC
);
/* Request rt5677 GPIO for headphone amp control */
bdw_rt5677
->
gpio_hp_en
=
devm_gpiod_get_index
(
codec
->
dev
,
"headphone-enable"
,
0
,
0
);
if
(
IS_ERR
(
bdw_rt5677
->
gpio_hp_en
))
{
dev_err
(
codec
->
dev
,
"Can't find HP_AMP_SHDN_L gpio
\n
"
);
return
PTR_ERR
(
bdw_rt5677
->
gpio_hp_en
);
}
gpiod_direction_output
(
bdw_rt5677
->
gpio_hp_en
,
0
);
/* Create and initialize headphone jack */
if
(
!
snd_soc_card_jack_new
(
rtd
->
card
,
"Headphone Jack"
,
SND_JACK_HEADPHONE
,
&
headphone_jack
,
&
headphone_jack_pin
,
1
))
{
headphone_jack_gpio
.
gpiod_dev
=
codec
->
dev
;
if
(
snd_soc_jack_add_gpios
(
&
headphone_jack
,
1
,
&
headphone_jack_gpio
))
dev_err
(
codec
->
dev
,
"Can't add headphone jack gpio
\n
"
);
}
else
{
dev_err
(
codec
->
dev
,
"Can't create headphone jack
\n
"
);
}
/* Create and initialize mic jack */
if
(
!
snd_soc_card_jack_new
(
rtd
->
card
,
"Mic Jack"
,
SND_JACK_MICROPHONE
,
&
mic_jack
,
&
mic_jack_pin
,
1
))
{
mic_jack_gpio
.
gpiod_dev
=
codec
->
dev
;
if
(
snd_soc_jack_add_gpios
(
&
mic_jack
,
1
,
&
mic_jack_gpio
))
dev_err
(
codec
->
dev
,
"Can't add mic jack gpio
\n
"
);
}
else
{
dev_err
(
codec
->
dev
,
"Can't create mic jack
\n
"
);
}
bdw_rt5677
->
codec
=
codec
;
snd_soc_dapm_force_enable_pin
(
dapm
,
"MICBIAS1"
);
return
0
;
}
/* broadwell digital audio interface glue - connects codec <--> CPU */
static
struct
snd_soc_dai_link
bdw_rt5677_dais
[]
=
{
/* Front End DAI links */
{
.
name
=
"System PCM"
,
.
stream_name
=
"System Playback/Capture"
,
.
cpu_dai_name
=
"System Pin"
,
.
platform_name
=
"haswell-pcm-audio"
,
.
dynamic
=
1
,
.
codec_name
=
"snd-soc-dummy"
,
.
codec_dai_name
=
"snd-soc-dummy-dai"
,
.
init
=
bdw_rt5677_rtd_init
,
.
trigger
=
{
SND_SOC_DPCM_TRIGGER_POST
,
SND_SOC_DPCM_TRIGGER_POST
},
.
dpcm_capture
=
1
,
.
dpcm_playback
=
1
,
},
/* Back End DAI links */
{
/* SSP0 - Codec */
.
name
=
"Codec"
,
.
id
=
0
,
.
cpu_dai_name
=
"snd-soc-dummy-dai"
,
.
platform_name
=
"snd-soc-dummy"
,
.
no_pcm
=
1
,
.
codec_name
=
"i2c-RT5677CE:00"
,
.
codec_dai_name
=
"rt5677-aif1"
,
.
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
=
broadwell_ssp0_fixup
,
.
ops
=
&
bdw_rt5677_ops
,
.
dpcm_playback
=
1
,
.
dpcm_capture
=
1
,
.
init
=
bdw_rt5677_init
,
},
};
static
int
bdw_rt5677_suspend_pre
(
struct
snd_soc_card
*
card
)
{
struct
bdw_rt5677_priv
*
bdw_rt5677
=
snd_soc_card_get_drvdata
(
card
);
struct
snd_soc_dapm_context
*
dapm
;
if
(
bdw_rt5677
->
codec
)
{
dapm
=
snd_soc_codec_get_dapm
(
bdw_rt5677
->
codec
);
snd_soc_dapm_disable_pin
(
dapm
,
"MICBIAS1"
);
}
return
0
;
}
static
int
bdw_rt5677_resume_post
(
struct
snd_soc_card
*
card
)
{
struct
bdw_rt5677_priv
*
bdw_rt5677
=
snd_soc_card_get_drvdata
(
card
);
struct
snd_soc_dapm_context
*
dapm
;
if
(
bdw_rt5677
->
codec
)
{
dapm
=
snd_soc_codec_get_dapm
(
bdw_rt5677
->
codec
);
snd_soc_dapm_force_enable_pin
(
dapm
,
"MICBIAS1"
);
}
return
0
;
}
/* ASoC machine driver for Broadwell DSP + RT5677 */
static
struct
snd_soc_card
bdw_rt5677_card
=
{
.
name
=
"bdw-rt5677"
,
.
owner
=
THIS_MODULE
,
.
dai_link
=
bdw_rt5677_dais
,
.
num_links
=
ARRAY_SIZE
(
bdw_rt5677_dais
),
.
dapm_widgets
=
bdw_rt5677_widgets
,
.
num_dapm_widgets
=
ARRAY_SIZE
(
bdw_rt5677_widgets
),
.
dapm_routes
=
bdw_rt5677_map
,
.
num_dapm_routes
=
ARRAY_SIZE
(
bdw_rt5677_map
),
.
controls
=
bdw_rt5677_controls
,
.
num_controls
=
ARRAY_SIZE
(
bdw_rt5677_controls
),
.
fully_routed
=
true
,
.
suspend_pre
=
bdw_rt5677_suspend_pre
,
.
resume_post
=
bdw_rt5677_resume_post
,
};
static
int
bdw_rt5677_probe
(
struct
platform_device
*
pdev
)
{
struct
bdw_rt5677_priv
*
bdw_rt5677
;
bdw_rt5677_card
.
dev
=
&
pdev
->
dev
;
/* Allocate driver private struct */
bdw_rt5677
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
struct
bdw_rt5677_priv
),
GFP_KERNEL
);
if
(
!
bdw_rt5677
)
{
dev_err
(
&
pdev
->
dev
,
"Can't allocate bdw_rt5677
\n
"
);
return
-
ENOMEM
;
}
snd_soc_card_set_drvdata
(
&
bdw_rt5677_card
,
bdw_rt5677
);
return
devm_snd_soc_register_card
(
&
pdev
->
dev
,
&
bdw_rt5677_card
);
}
static
struct
platform_driver
bdw_rt5677_audio
=
{
.
probe
=
bdw_rt5677_probe
,
.
driver
=
{
.
name
=
"bdw-rt5677"
,
},
};
module_platform_driver
(
bdw_rt5677_audio
)
/* Module information */
MODULE_AUTHOR
(
"Ben Zhang"
);
MODULE_DESCRIPTION
(
"Intel Broadwell RT5677 machine driver"
);
MODULE_LICENSE
(
"GPL v2"
);
MODULE_ALIAS
(
"platform:bdw-rt5677"
);
sound/soc/intel/boards/bxt_da7219_max98357a.c
View file @
4a2447b4
...
...
@@ -37,6 +37,7 @@ enum {
BXT_DPCM_AUDIO_PB
=
0
,
BXT_DPCM_AUDIO_CP
,
BXT_DPCM_AUDIO_REF_CP
,
BXT_DPCM_AUDIO_DMIC_CP
,
BXT_DPCM_AUDIO_HDMI1_PB
,
BXT_DPCM_AUDIO_HDMI2_PB
,
BXT_DPCM_AUDIO_HDMI3_PB
,
...
...
@@ -252,10 +253,56 @@ static struct snd_soc_ops broxton_da7219_ops = {
.
hw_free
=
broxton_da7219_hw_free
,
};
static
int
broxton_dmic_fixup
(
struct
snd_soc_pcm_runtime
*
rtd
,
struct
snd_pcm_hw_params
*
params
)
{
struct
snd_interval
*
channels
=
hw_param_interval
(
params
,
SNDRV_PCM_HW_PARAM_CHANNELS
);
channels
->
min
=
channels
->
max
=
DUAL_CHANNEL
;
return
0
;
}
static
int
broxton_dmic_startup
(
struct
snd_pcm_substream
*
substream
)
{
struct
snd_pcm_runtime
*
runtime
=
substream
->
runtime
;
runtime
->
hw
.
channels_max
=
DUAL_CHANNEL
;
snd_pcm_hw_constraint_list
(
runtime
,
0
,
SNDRV_PCM_HW_PARAM_CHANNELS
,
&
constraints_channels
);
return
snd_pcm_hw_constraint_list
(
substream
->
runtime
,
0
,
SNDRV_PCM_HW_PARAM_RATE
,
&
constraints_rates
);
}
static
const
struct
snd_soc_ops
broxton_dmic_ops
=
{
.
startup
=
broxton_dmic_startup
,
};
static
const
unsigned
int
rates_16000
[]
=
{
16000
,
};
static
const
struct
snd_pcm_hw_constraint_list
constraints_16000
=
{
.
count
=
ARRAY_SIZE
(
rates_16000
),
.
list
=
rates_16000
,
};
static
int
broxton_refcap_startup
(
struct
snd_pcm_substream
*
substream
)
{
return
snd_pcm_hw_constraint_list
(
substream
->
runtime
,
0
,
SNDRV_PCM_HW_PARAM_RATE
,
&
constraints_16000
);
};
static
struct
snd_soc_ops
broxton_refcap_ops
=
{
.
startup
=
broxton_refcap_startup
,
};
/* broxton digital audio interface glue - connects codec <--> CPU */
static
struct
snd_soc_dai_link
broxton_dais
[]
=
{
/* Front End DAI links */
[
BXT_DPCM_AUDIO_PB
]
[
BXT_DPCM_AUDIO_PB
]
=
{
.
name
=
"Bxt Audio Port"
,
.
stream_name
=
"Audio"
,
...
...
@@ -271,7 +318,7 @@ static struct snd_soc_dai_link broxton_dais[] = {
.
dpcm_playback
=
1
,
.
ops
=
&
broxton_da7219_fe_ops
,
},
[
BXT_DPCM_AUDIO_CP
]
[
BXT_DPCM_AUDIO_CP
]
=
{
.
name
=
"Bxt Audio Capture Port"
,
.
stream_name
=
"Audio Record"
,
...
...
@@ -286,7 +333,7 @@ static struct snd_soc_dai_link broxton_dais[] = {
.
dpcm_capture
=
1
,
.
ops
=
&
broxton_da7219_fe_ops
,
},
[
BXT_DPCM_AUDIO_REF_CP
]
[
BXT_DPCM_AUDIO_REF_CP
]
=
{
.
name
=
"Bxt Audio Reference cap"
,
.
stream_name
=
"Refcap"
,
...
...
@@ -299,8 +346,23 @@ static struct snd_soc_dai_link broxton_dais[] = {
.
ignore_suspend
=
1
,
.
nonatomic
=
1
,
.
dynamic
=
1
,
.
ops
=
&
broxton_refcap_ops
,
},
[
BXT_DPCM_AUDIO_DMIC_CP
]
{
.
name
=
"Bxt Audio DMIC cap"
,
.
stream_name
=
"dmiccap"
,
.
cpu_dai_name
=
"DMIC Pin"
,
.
codec_name
=
"snd-soc-dummy"
,
.
codec_dai_name
=
"snd-soc-dummy-dai"
,
.
platform_name
=
"0000:00:0e.0"
,
.
init
=
NULL
,
.
dpcm_capture
=
1
,
.
nonatomic
=
1
,
.
dynamic
=
1
,
.
ops
=
&
broxton_dmic_ops
,
},
[
BXT_DPCM_AUDIO_HDMI1_PB
]
[
BXT_DPCM_AUDIO_HDMI1_PB
]
=
{
.
name
=
"Bxt HDMI Port1"
,
.
stream_name
=
"Hdmi1"
,
...
...
@@ -313,7 +375,7 @@ static struct snd_soc_dai_link broxton_dais[] = {
.
nonatomic
=
1
,
.
dynamic
=
1
,
},
[
BXT_DPCM_AUDIO_HDMI2_PB
]
[
BXT_DPCM_AUDIO_HDMI2_PB
]
=
{
.
name
=
"Bxt HDMI Port2"
,
.
stream_name
=
"Hdmi2"
,
...
...
@@ -326,7 +388,7 @@ static struct snd_soc_dai_link broxton_dais[] = {
.
nonatomic
=
1
,
.
dynamic
=
1
,
},
[
BXT_DPCM_AUDIO_HDMI3_PB
]
[
BXT_DPCM_AUDIO_HDMI3_PB
]
=
{
.
name
=
"Bxt HDMI Port3"
,
.
stream_name
=
"Hdmi3"
,
...
...
@@ -382,6 +444,7 @@ static struct snd_soc_dai_link broxton_dais[] = {
.
codec_dai_name
=
"dmic-hifi"
,
.
platform_name
=
"0000:00:0e.0"
,
.
ignore_suspend
=
1
,
.
be_hw_params_fixup
=
broxton_dmic_fixup
,
.
dpcm_capture
=
1
,
.
no_pcm
=
1
,
},
...
...
sound/soc/intel/boards/bxt_rt298.c
View file @
4a2447b4
...
...
@@ -271,7 +271,7 @@ static const struct snd_soc_ops broxton_rt286_fe_ops = {
/* broxton digital audio interface glue - connects codec <--> CPU */
static
struct
snd_soc_dai_link
broxton_rt298_dais
[]
=
{
/* Front End DAI links */
[
BXT_DPCM_AUDIO_PB
]
[
BXT_DPCM_AUDIO_PB
]
=
{
.
name
=
"Bxt Audio Port"
,
.
stream_name
=
"Audio"
,
...
...
@@ -286,7 +286,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = {
.
dpcm_playback
=
1
,
.
ops
=
&
broxton_rt286_fe_ops
,
},
[
BXT_DPCM_AUDIO_CP
]
[
BXT_DPCM_AUDIO_CP
]
=
{
.
name
=
"Bxt Audio Capture Port"
,
.
stream_name
=
"Audio Record"
,
...
...
@@ -300,7 +300,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = {
.
dpcm_capture
=
1
,
.
ops
=
&
broxton_rt286_fe_ops
,
},
[
BXT_DPCM_AUDIO_REF_CP
]
[
BXT_DPCM_AUDIO_REF_CP
]
=
{
.
name
=
"Bxt Audio Reference cap"
,
.
stream_name
=
"refcap"
,
...
...
@@ -313,7 +313,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = {
.
nonatomic
=
1
,
.
dynamic
=
1
,
},
[
BXT_DPCM_AUDIO_DMIC_CP
]
[
BXT_DPCM_AUDIO_DMIC_CP
]
=
{
.
name
=
"Bxt Audio DMIC cap"
,
.
stream_name
=
"dmiccap"
,
...
...
@@ -327,7 +327,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = {
.
dynamic
=
1
,
.
ops
=
&
broxton_dmic_ops
,
},
[
BXT_DPCM_AUDIO_HDMI1_PB
]
[
BXT_DPCM_AUDIO_HDMI1_PB
]
=
{
.
name
=
"Bxt HDMI Port1"
,
.
stream_name
=
"Hdmi1"
,
...
...
@@ -340,7 +340,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = {
.
nonatomic
=
1
,
.
dynamic
=
1
,
},
[
BXT_DPCM_AUDIO_HDMI2_PB
]
[
BXT_DPCM_AUDIO_HDMI2_PB
]
=
{
.
name
=
"Bxt HDMI Port2"
,
.
stream_name
=
"Hdmi2"
,
...
...
@@ -353,7 +353,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = {
.
nonatomic
=
1
,
.
dynamic
=
1
,
},
[
BXT_DPCM_AUDIO_HDMI3_PB
]
[
BXT_DPCM_AUDIO_HDMI3_PB
]
=
{
.
name
=
"Bxt HDMI Port3"
,
.
stream_name
=
"Hdmi3"
,
...
...
sound/soc/intel/boards/bytcr_rt5640.c
View file @
4a2447b4
...
...
@@ -24,6 +24,9 @@
#include <linux/device.h>
#include <linux/dmi.h>
#include <linux/slab.h>
#include <asm/cpu_device_id.h>
#include <asm/platform_sst_audio.h>
#include <linux/clk.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
...
...
@@ -31,42 +34,153 @@
#include "../../codecs/rt5640.h"
#include "../atom/sst-atom-controls.h"
#include "../common/sst-acpi.h"
#include "../common/sst-dsp.h"
enum
{
BYT_RT5640_DMIC1_MAP
,
BYT_RT5640_DMIC2_MAP
,
BYT_RT5640_IN1_MAP
,
BYT_RT5640_IN3_MAP
,
};
#define BYT_RT5640_MAP(quirk) ((quirk) & 0xff)
#define BYT_RT5640_DMIC_EN BIT(16)
#define BYT_RT5640_MONO_SPEAKER BIT(17)
#define BYT_RT5640_DIFF_MIC BIT(18)
/* defaut is single-ended */
#define BYT_RT5640_SSP2_AIF2 BIT(19)
/* default is using AIF1 */
#define BYT_RT5640_SSP0_AIF1 BIT(20)
#define BYT_RT5640_SSP0_AIF2 BIT(21)
#define BYT_RT5640_MCLK_EN BIT(22)
#define BYT_RT5640_MCLK_25MHZ BIT(23)
struct
byt_rt5640_private
{
struct
clk
*
mclk
;
};
static
unsigned
long
byt_rt5640_quirk
=
BYT_RT5640_DMIC1_MAP
|
BYT_RT5640_DMIC_EN
;
BYT_RT5640_DMIC_EN
|
BYT_RT5640_MCLK_EN
;
static
void
log_quirks
(
struct
device
*
dev
)
{
if
(
BYT_RT5640_MAP
(
byt_rt5640_quirk
)
==
BYT_RT5640_DMIC1_MAP
)
dev_info
(
dev
,
"quirk DMIC1_MAP enabled"
);
if
(
BYT_RT5640_MAP
(
byt_rt5640_quirk
)
==
BYT_RT5640_DMIC2_MAP
)
dev_info
(
dev
,
"quirk DMIC2_MAP enabled"
);
if
(
BYT_RT5640_MAP
(
byt_rt5640_quirk
)
==
BYT_RT5640_IN1_MAP
)
dev_info
(
dev
,
"quirk IN1_MAP enabled"
);
if
(
BYT_RT5640_MAP
(
byt_rt5640_quirk
)
==
BYT_RT5640_IN3_MAP
)
dev_info
(
dev
,
"quirk IN3_MAP enabled"
);
if
(
byt_rt5640_quirk
&
BYT_RT5640_DMIC_EN
)
dev_info
(
dev
,
"quirk DMIC enabled"
);
if
(
byt_rt5640_quirk
&
BYT_RT5640_MONO_SPEAKER
)
dev_info
(
dev
,
"quirk MONO_SPEAKER enabled"
);
if
(
byt_rt5640_quirk
&
BYT_RT5640_DIFF_MIC
)
dev_info
(
dev
,
"quirk DIFF_MIC enabled"
);
if
(
byt_rt5640_quirk
&
BYT_RT5640_SSP2_AIF2
)
dev_info
(
dev
,
"quirk SSP2_AIF2 enabled"
);
if
(
byt_rt5640_quirk
&
BYT_RT5640_SSP0_AIF1
)
dev_info
(
dev
,
"quirk SSP0_AIF1 enabled"
);
if
(
byt_rt5640_quirk
&
BYT_RT5640_SSP0_AIF2
)
dev_info
(
dev
,
"quirk SSP0_AIF2 enabled"
);
if
(
byt_rt5640_quirk
&
BYT_RT5640_MCLK_EN
)
dev_info
(
dev
,
"quirk MCLK_EN enabled"
);
if
(
byt_rt5640_quirk
&
BYT_RT5640_MCLK_25MHZ
)
dev_info
(
dev
,
"quirk MCLK_25MHZ enabled"
);
}
#define BYT_CODEC_DAI1 "rt5640-aif1"
#define BYT_CODEC_DAI2 "rt5640-aif2"
static
inline
struct
snd_soc_dai
*
byt_get_codec_dai
(
struct
snd_soc_card
*
card
)
{
struct
snd_soc_pcm_runtime
*
rtd
;
list_for_each_entry
(
rtd
,
&
card
->
rtd_list
,
list
)
{
if
(
!
strncmp
(
rtd
->
codec_dai
->
name
,
BYT_CODEC_DAI1
,
strlen
(
BYT_CODEC_DAI1
)))
return
rtd
->
codec_dai
;
if
(
!
strncmp
(
rtd
->
codec_dai
->
name
,
BYT_CODEC_DAI2
,
strlen
(
BYT_CODEC_DAI2
)))
return
rtd
->
codec_dai
;
}
return
NULL
;
}
static
int
platform_clock_control
(
struct
snd_soc_dapm_widget
*
w
,
struct
snd_kcontrol
*
k
,
int
event
)
{
struct
snd_soc_dapm_context
*
dapm
=
w
->
dapm
;
struct
snd_soc_card
*
card
=
dapm
->
card
;
struct
snd_soc_dai
*
codec_dai
;
struct
byt_rt5640_private
*
priv
=
snd_soc_card_get_drvdata
(
card
);
int
ret
;
codec_dai
=
byt_get_codec_dai
(
card
);
if
(
!
codec_dai
)
{
dev_err
(
card
->
dev
,
"Codec dai not found; Unable to set platform clock
\n
"
);
return
-
EIO
;
}
if
(
SND_SOC_DAPM_EVENT_ON
(
event
))
{
if
((
byt_rt5640_quirk
&
BYT_RT5640_MCLK_EN
)
&&
priv
->
mclk
)
{
ret
=
clk_prepare_enable
(
priv
->
mclk
);
if
(
ret
<
0
)
{
dev_err
(
card
->
dev
,
"could not configure MCLK state"
);
return
ret
;
}
}
ret
=
snd_soc_dai_set_sysclk
(
codec_dai
,
RT5640_SCLK_S_PLL1
,
48000
*
512
,
SND_SOC_CLOCK_IN
);
}
else
{
/*
* Set codec clock source to internal clock before
* turning off the platform clock. Codec needs clock
* for Jack detection and button press
*/
ret
=
snd_soc_dai_set_sysclk
(
codec_dai
,
RT5640_SCLK_S_RCCLK
,
0
,
SND_SOC_CLOCK_IN
);
if
(
!
ret
)
{
if
((
byt_rt5640_quirk
&
BYT_RT5640_MCLK_EN
)
&&
priv
->
mclk
)
clk_disable_unprepare
(
priv
->
mclk
);
}
}
if
(
ret
<
0
)
{
dev_err
(
card
->
dev
,
"can't set codec sysclk: %d
\n
"
,
ret
);
return
ret
;
}
return
0
;
}
static
const
struct
snd_soc_dapm_widget
byt_rt5640_widgets
[]
=
{
SND_SOC_DAPM_HP
(
"Headphone"
,
NULL
),
SND_SOC_DAPM_MIC
(
"Headset Mic"
,
NULL
),
SND_SOC_DAPM_MIC
(
"Internal Mic"
,
NULL
),
SND_SOC_DAPM_SPK
(
"Speaker"
,
NULL
),
SND_SOC_DAPM_SUPPLY
(
"Platform Clock"
,
SND_SOC_NOPM
,
0
,
0
,
platform_clock_control
,
SND_SOC_DAPM_PRE_PMU
|
SND_SOC_DAPM_POST_PMD
),
};
static
const
struct
snd_soc_dapm_route
byt_rt5640_audio_map
[]
=
{
{
"AIF1 Playback"
,
NULL
,
"ssp2 Tx"
},
{
"ssp2 Tx"
,
NULL
,
"codec_out0"
},
{
"ssp2 Tx"
,
NULL
,
"codec_out1"
},
{
"codec_in0"
,
NULL
,
"ssp2 Rx"
},
{
"codec_in1"
,
NULL
,
"ssp2 Rx"
},
{
"ssp2 Rx"
,
NULL
,
"AIF1 Capture"
},
{
"Headphone"
,
NULL
,
"Platform Clock"
},
{
"Headset Mic"
,
NULL
,
"Platform Clock"
},
{
"Internal Mic"
,
NULL
,
"Platform Clock"
},
{
"Speaker"
,
NULL
,
"Platform Clock"
},
{
"Headset Mic"
,
NULL
,
"MICBIAS1"
},
{
"IN2P"
,
NULL
,
"Headset Mic"
},
{
"Headphone"
,
NULL
,
"HPOL"
},
{
"Headphone"
,
NULL
,
"HPOR"
},
{
"Speaker"
,
NULL
,
"SPOLP"
},
{
"Speaker"
,
NULL
,
"SPOLN"
},
{
"Speaker"
,
NULL
,
"SPORP"
},
{
"Speaker"
,
NULL
,
"SPORN"
},
};
static
const
struct
snd_soc_dapm_route
byt_rt5640_intmic_dmic1_map
[]
=
{
...
...
@@ -82,6 +196,59 @@ static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = {
{
"IN1P"
,
NULL
,
"Internal Mic"
},
};
static
const
struct
snd_soc_dapm_route
byt_rt5640_intmic_in3_map
[]
=
{
{
"Internal Mic"
,
NULL
,
"MICBIAS1"
},
{
"IN3P"
,
NULL
,
"Internal Mic"
},
};
static
const
struct
snd_soc_dapm_route
byt_rt5640_ssp2_aif1_map
[]
=
{
{
"ssp2 Tx"
,
NULL
,
"codec_out0"
},
{
"ssp2 Tx"
,
NULL
,
"codec_out1"
},
{
"codec_in0"
,
NULL
,
"ssp2 Rx"
},
{
"codec_in1"
,
NULL
,
"ssp2 Rx"
},
{
"AIF1 Playback"
,
NULL
,
"ssp2 Tx"
},
{
"ssp2 Rx"
,
NULL
,
"AIF1 Capture"
},
};
static
const
struct
snd_soc_dapm_route
byt_rt5640_ssp2_aif2_map
[]
=
{
{
"ssp2 Tx"
,
NULL
,
"codec_out0"
},
{
"ssp2 Tx"
,
NULL
,
"codec_out1"
},
{
"codec_in0"
,
NULL
,
"ssp2 Rx"
},
{
"codec_in1"
,
NULL
,
"ssp2 Rx"
},
{
"AIF2 Playback"
,
NULL
,
"ssp2 Tx"
},
{
"ssp2 Rx"
,
NULL
,
"AIF2 Capture"
},
};
static
const
struct
snd_soc_dapm_route
byt_rt5640_ssp0_aif1_map
[]
=
{
{
"ssp0 Tx"
,
NULL
,
"modem_out"
},
{
"modem_in"
,
NULL
,
"ssp0 Rx"
},
{
"AIF1 Playback"
,
NULL
,
"ssp0 Tx"
},
{
"ssp0 Rx"
,
NULL
,
"AIF1 Capture"
},
};
static
const
struct
snd_soc_dapm_route
byt_rt5640_ssp0_aif2_map
[]
=
{
{
"ssp0 Tx"
,
NULL
,
"modem_out"
},
{
"modem_in"
,
NULL
,
"ssp0 Rx"
},
{
"AIF2 Playback"
,
NULL
,
"ssp0 Tx"
},
{
"ssp0 Rx"
,
NULL
,
"AIF2 Capture"
},
};
static
const
struct
snd_soc_dapm_route
byt_rt5640_stereo_spk_map
[]
=
{
{
"Speaker"
,
NULL
,
"SPOLP"
},
{
"Speaker"
,
NULL
,
"SPOLN"
},
{
"Speaker"
,
NULL
,
"SPORP"
},
{
"Speaker"
,
NULL
,
"SPORN"
},
};
static
const
struct
snd_soc_dapm_route
byt_rt5640_mono_spk_map
[]
=
{
{
"Speaker"
,
NULL
,
"SPOLP"
},
{
"Speaker"
,
NULL
,
"SPOLN"
},
};
static
const
struct
snd_kcontrol_new
byt_rt5640_controls
[]
=
{
SOC_DAPM_PIN_SWITCH
(
"Headphone"
),
SOC_DAPM_PIN_SWITCH
(
"Headset Mic"
),
...
...
@@ -96,19 +263,46 @@ static int byt_rt5640_aif1_hw_params(struct snd_pcm_substream *substream,
struct
snd_soc_dai
*
codec_dai
=
rtd
->
codec_dai
;
int
ret
;
snd_soc_dai_set_bclk_ratio
(
codec_dai
,
50
);
ret
=
snd_soc_dai_set_sysclk
(
codec_dai
,
RT5640_SCLK_S_PLL1
,
params_rate
(
params
)
*
512
,
SND_SOC_CLOCK_IN
);
if
(
ret
<
0
)
{
dev_err
(
rtd
->
dev
,
"can't set codec clock %d
\n
"
,
ret
);
return
ret
;
}
ret
=
snd_soc_dai_set_pll
(
codec_dai
,
0
,
RT5640_PLL1_S_BCLK1
,
if
(
!
(
byt_rt5640_quirk
&
BYT_RT5640_MCLK_EN
))
{
/* use bitclock as PLL input */
if
((
byt_rt5640_quirk
&
BYT_RT5640_SSP0_AIF1
)
||
(
byt_rt5640_quirk
&
BYT_RT5640_SSP0_AIF2
))
{
/* 2x16 bit slots on SSP0 */
ret
=
snd_soc_dai_set_pll
(
codec_dai
,
0
,
RT5640_PLL1_S_BCLK1
,
params_rate
(
params
)
*
32
,
params_rate
(
params
)
*
512
);
}
else
{
/* 2x15 bit slots on SSP2 */
ret
=
snd_soc_dai_set_pll
(
codec_dai
,
0
,
RT5640_PLL1_S_BCLK1
,
params_rate
(
params
)
*
50
,
params_rate
(
params
)
*
512
);
}
}
else
{
if
(
byt_rt5640_quirk
&
BYT_RT5640_MCLK_25MHZ
)
{
ret
=
snd_soc_dai_set_pll
(
codec_dai
,
0
,
RT5640_PLL1_S_MCLK
,
25000000
,
params_rate
(
params
)
*
512
);
}
else
{
ret
=
snd_soc_dai_set_pll
(
codec_dai
,
0
,
RT5640_PLL1_S_MCLK
,
19200000
,
params_rate
(
params
)
*
512
);
}
}
if
(
ret
<
0
)
{
dev_err
(
rtd
->
dev
,
"can't set codec pll: %d
\n
"
,
ret
);
return
ret
;
...
...
@@ -127,27 +321,73 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
{
.
callback
=
byt_rt5640_quirk_cb
,
.
matches
=
{
DMI_MATCH
(
DMI_SYS_VENDOR
,
"ASUSTeK COMPUTER INC."
),
DMI_MATCH
(
DMI_PRODUCT_NAME
,
"T100TA"
),
DMI_EXACT_MATCH
(
DMI_SYS_VENDOR
,
"ASUSTeK COMPUTER INC."
),
DMI_EXACT_MATCH
(
DMI_PRODUCT_NAME
,
"T100TA"
),
},
.
driver_data
=
(
unsigned
long
*
)(
BYT_RT5640_IN1_MAP
|
BYT_RT5640_MCLK_EN
),
},
{
.
callback
=
byt_rt5640_quirk_cb
,
.
matches
=
{
DMI_EXACT_MATCH
(
DMI_SYS_VENDOR
,
"ASUSTeK COMPUTER INC."
),
DMI_EXACT_MATCH
(
DMI_PRODUCT_NAME
,
"T100TAF"
),
},
.
driver_data
=
(
unsigned
long
*
)
BYT_RT5640_IN1_MAP
,
.
driver_data
=
(
unsigned
long
*
)(
BYT_RT5640_IN1_MAP
|
BYT_RT5640_MONO_SPEAKER
|
BYT_RT5640_DIFF_MIC
|
BYT_RT5640_SSP0_AIF2
|
BYT_RT5640_MCLK_EN
),
},
{
.
callback
=
byt_rt5640_quirk_cb
,
.
matches
=
{
DMI_MATCH
(
DMI_SYS_VENDOR
,
"DellInc."
),
DMI_MATCH
(
DMI_PRODUCT_NAME
,
"Venue 8 Pro 5830"
),
DMI_
EXACT_
MATCH
(
DMI_SYS_VENDOR
,
"DellInc."
),
DMI_
EXACT_
MATCH
(
DMI_PRODUCT_NAME
,
"Venue 8 Pro 5830"
),
},
.
driver_data
=
(
unsigned
long
*
)(
BYT_RT5640_DMIC2_MAP
|
BYT_RT5640_DMIC_EN
|
BYT_RT5640_MCLK_EN
),
},
{
.
callback
=
byt_rt5640_quirk_cb
,
.
matches
=
{
DMI_EXACT_MATCH
(
DMI_SYS_VENDOR
,
"Hewlett-Packard"
),
DMI_EXACT_MATCH
(
DMI_PRODUCT_NAME
,
"HP ElitePad 1000 G2"
),
},
.
driver_data
=
(
unsigned
long
*
)(
BYT_RT5640_IN1_MAP
|
BYT_RT5640_MCLK_EN
),
},
{
.
callback
=
byt_rt5640_quirk_cb
,
.
matches
=
{
DMI_MATCH
(
DMI_SYS_VENDOR
,
"Circuitco"
),
DMI_MATCH
(
DMI_PRODUCT_NAME
,
"Minnowboard Max B3 PLATFORM"
),
},
.
driver_data
=
(
unsigned
long
*
)(
BYT_RT5640_DMIC1_MAP
|
BYT_RT5640_DMIC_EN
),
},
{
.
callback
=
byt_rt5640_quirk_cb
,
.
matches
=
{
DMI_MATCH
(
DMI_SYS_VENDOR
,
"Hewlett-Packard"
),
DMI_MATCH
(
DMI_PRODUCT_NAME
,
"HP ElitePad 1000 G2"
),
DMI_MATCH
(
DMI_BOARD_VENDOR
,
"TECLAST"
),
DMI_MATCH
(
DMI_BOARD_NAME
,
"tPAD"
),
},
.
driver_data
=
(
unsigned
long
*
)(
BYT_RT5640_IN3_MAP
|
BYT_RT5640_MCLK_EN
|
BYT_RT5640_SSP0_AIF1
),
},
.
driver_data
=
(
unsigned
long
*
)
BYT_RT5640_IN1_MAP
,
{
.
callback
=
byt_rt5640_quirk_cb
,
.
matches
=
{
DMI_MATCH
(
DMI_SYS_VENDOR
,
"Acer"
),
DMI_MATCH
(
DMI_PRODUCT_NAME
,
"Aspire SW5-012"
),
},
.
driver_data
=
(
unsigned
long
*
)(
BYT_RT5640_IN1_MAP
|
BYT_RT5640_MCLK_EN
|
BYT_RT5640_SSP0_AIF1
),
},
{}
};
...
...
@@ -158,13 +398,18 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
struct
snd_soc_codec
*
codec
=
runtime
->
codec
;
struct
snd_soc_card
*
card
=
runtime
->
card
;
const
struct
snd_soc_dapm_route
*
custom_map
;
struct
byt_rt5640_private
*
priv
=
snd_soc_card_get_drvdata
(
card
);
int
num_routes
;
card
->
dapm
.
idle_bias_off
=
true
;
rt5640_sel_asrc_clk_src
(
codec
,
RT5640_DA_STEREO_FILTER
|
RT5640_AD_STEREO_FILTER
,
RT5640_DA_MONO_L_FILTER
|
RT5640_DA_MONO_R_FILTER
|
RT5640_AD_STEREO_FILTER
|
RT5640_AD_MONO_L_FILTER
|
RT5640_AD_MONO_R_FILTER
,
RT5640_CLK_SEL_ASRC
);
ret
=
snd_soc_add_card_controls
(
card
,
byt_rt5640_controls
,
...
...
@@ -179,6 +424,10 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
custom_map
=
byt_rt5640_intmic_in1_map
;
num_routes
=
ARRAY_SIZE
(
byt_rt5640_intmic_in1_map
);
break
;
case
BYT_RT5640_IN3_MAP
:
custom_map
=
byt_rt5640_intmic_in3_map
;
num_routes
=
ARRAY_SIZE
(
byt_rt5640_intmic_in3_map
);
break
;
case
BYT_RT5640_DMIC2_MAP
:
custom_map
=
byt_rt5640_intmic_dmic2_map
;
num_routes
=
ARRAY_SIZE
(
byt_rt5640_intmic_dmic2_map
);
...
...
@@ -192,6 +441,43 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
if
(
ret
)
return
ret
;
if
(
byt_rt5640_quirk
&
BYT_RT5640_SSP2_AIF2
)
{
ret
=
snd_soc_dapm_add_routes
(
&
card
->
dapm
,
byt_rt5640_ssp2_aif2_map
,
ARRAY_SIZE
(
byt_rt5640_ssp2_aif2_map
));
}
else
if
(
byt_rt5640_quirk
&
BYT_RT5640_SSP0_AIF1
)
{
ret
=
snd_soc_dapm_add_routes
(
&
card
->
dapm
,
byt_rt5640_ssp0_aif1_map
,
ARRAY_SIZE
(
byt_rt5640_ssp0_aif1_map
));
}
else
if
(
byt_rt5640_quirk
&
BYT_RT5640_SSP0_AIF2
)
{
ret
=
snd_soc_dapm_add_routes
(
&
card
->
dapm
,
byt_rt5640_ssp0_aif2_map
,
ARRAY_SIZE
(
byt_rt5640_ssp0_aif2_map
));
}
else
{
ret
=
snd_soc_dapm_add_routes
(
&
card
->
dapm
,
byt_rt5640_ssp2_aif1_map
,
ARRAY_SIZE
(
byt_rt5640_ssp2_aif1_map
));
}
if
(
ret
)
return
ret
;
if
(
byt_rt5640_quirk
&
BYT_RT5640_MONO_SPEAKER
)
{
ret
=
snd_soc_dapm_add_routes
(
&
card
->
dapm
,
byt_rt5640_mono_spk_map
,
ARRAY_SIZE
(
byt_rt5640_mono_spk_map
));
}
else
{
ret
=
snd_soc_dapm_add_routes
(
&
card
->
dapm
,
byt_rt5640_stereo_spk_map
,
ARRAY_SIZE
(
byt_rt5640_stereo_spk_map
));
}
if
(
ret
)
return
ret
;
if
(
byt_rt5640_quirk
&
BYT_RT5640_DIFF_MIC
)
{
snd_soc_update_bits
(
codec
,
RT5640_IN1_IN2
,
RT5640_IN_DF1
,
RT5640_IN_DF1
);
}
if
(
byt_rt5640_quirk
&
BYT_RT5640_DMIC_EN
)
{
ret
=
rt5640_dmic_enable
(
codec
,
0
,
0
);
if
(
ret
)
...
...
@@ -201,6 +487,30 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
snd_soc_dapm_ignore_suspend
(
&
card
->
dapm
,
"Headphone"
);
snd_soc_dapm_ignore_suspend
(
&
card
->
dapm
,
"Speaker"
);
if
((
byt_rt5640_quirk
&
BYT_RT5640_MCLK_EN
)
&&
priv
->
mclk
)
{
/*
* The firmware might enable the clock at
* boot (this information may or may not
* be reflected in the enable clock register).
* To change the rate we must disable the clock
* first to cover these cases. Due to common
* clock framework restrictions that do not allow
* to disable a clock that has not been enabled,
* we need to enable the clock first.
*/
ret
=
clk_prepare_enable
(
priv
->
mclk
);
if
(
!
ret
)
clk_disable_unprepare
(
priv
->
mclk
);
if
(
byt_rt5640_quirk
&
BYT_RT5640_MCLK_25MHZ
)
ret
=
clk_set_rate
(
priv
->
mclk
,
25000000
);
else
ret
=
clk_set_rate
(
priv
->
mclk
,
19200000
);
if
(
ret
)
dev_err
(
card
->
dev
,
"unable to set MCLK rate
\n
"
);
}
return
ret
;
}
...
...
@@ -221,10 +531,39 @@ static int byt_rt5640_codec_fixup(struct snd_soc_pcm_runtime *rtd,
SNDRV_PCM_HW_PARAM_CHANNELS
);
int
ret
;
/* The DSP will covert the FE rate to 48k, stereo
, 24bits
*/
/* The DSP will covert the FE rate to 48k, stereo */
rate
->
min
=
rate
->
max
=
48000
;
channels
->
min
=
channels
->
max
=
2
;
if
((
byt_rt5640_quirk
&
BYT_RT5640_SSP0_AIF1
)
||
(
byt_rt5640_quirk
&
BYT_RT5640_SSP0_AIF2
))
{
/* set SSP0 to 16-bit */
params_set_format
(
params
,
SNDRV_PCM_FORMAT_S16_LE
);
/*
* Default mode for SSP configuration is TDM 4 slot, override config
* with explicit setting to I2S 2ch 16-bit. The word length is set with
* dai_set_tdm_slot() since there is no other API exposed
*/
ret
=
snd_soc_dai_set_fmt
(
rtd
->
cpu_dai
,
SND_SOC_DAIFMT_I2S
|
SND_SOC_DAIFMT_NB_IF
|
SND_SOC_DAIFMT_CBS_CFS
);
if
(
ret
<
0
)
{
dev_err
(
rtd
->
dev
,
"can't set format to I2S, err %d
\n
"
,
ret
);
return
ret
;
}
ret
=
snd_soc_dai_set_tdm_slot
(
rtd
->
cpu_dai
,
0x3
,
0x3
,
2
,
16
);
if
(
ret
<
0
)
{
dev_err
(
rtd
->
dev
,
"can't set I2S config, err %d
\n
"
,
ret
);
return
ret
;
}
}
else
{
/* set SSP2 to 24-bit */
params_set_format
(
params
,
SNDRV_PCM_FORMAT_S24_LE
);
...
...
@@ -248,7 +587,7 @@ static int byt_rt5640_codec_fixup(struct snd_soc_pcm_runtime *rtd,
dev_err
(
rtd
->
dev
,
"can't set I2S config, err %d
\n
"
,
ret
);
return
ret
;
}
}
return
0
;
}
...
...
@@ -305,10 +644,10 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = {
{
.
name
=
"SSP2-Codec"
,
.
id
=
1
,
.
cpu_dai_name
=
"ssp2-port"
,
.
cpu_dai_name
=
"ssp2-port"
,
/* overwritten for ssp0 routing */
.
platform_name
=
"sst-mfld-platform"
,
.
no_pcm
=
1
,
.
codec_dai_name
=
"rt5640-aif1"
,
.
codec_dai_name
=
"rt5640-aif1"
,
/* changed w/ quirk */
.
codec_name
=
"i2c-10EC5640:00"
,
/* overwritten with HID */
.
dai_fmt
=
SND_SOC_DAIFMT_I2S
|
SND_SOC_DAIFMT_NB_NF
|
SND_SOC_DAIFMT_CBS_CFS
,
...
...
@@ -335,6 +674,21 @@ static struct snd_soc_card byt_rt5640_card = {
};
static
char
byt_rt5640_codec_name
[
16
];
/* i2c-<HID>:00 with HID being 8 chars */
static
char
byt_rt5640_codec_aif_name
[
12
];
/* = "rt5640-aif[1|2]" */
static
char
byt_rt5640_cpu_dai_name
[
10
];
/* = "ssp[0|2]-port" */
static
bool
is_valleyview
(
void
)
{
static
const
struct
x86_cpu_id
cpu_ids
[]
=
{
{
X86_VENDOR_INTEL
,
6
,
55
},
/* Valleyview, Bay Trail */
{}
};
if
(
!
x86_match_cpu
(
cpu_ids
))
return
false
;
return
true
;
}
static
int
snd_byt_rt5640_mc_probe
(
struct
platform_device
*
pdev
)
{
...
...
@@ -343,10 +697,16 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
const
char
*
i2c_name
=
NULL
;
int
i
;
int
dai_index
;
struct
byt_rt5640_private
*
priv
;
priv
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
priv
),
GFP_ATOMIC
);
if
(
!
priv
)
return
-
ENOMEM
;
/* register the soc card */
byt_rt5640_card
.
dev
=
&
pdev
->
dev
;
mach
=
byt_rt5640_card
.
dev
->
platform_data
;
snd_soc_card_set_drvdata
(
&
byt_rt5640_card
,
priv
);
/* fix index of codec dai */
dai_index
=
MERR_DPCM_COMPR
+
1
;
...
...
@@ -366,8 +726,57 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
byt_rt5640_dais
[
dai_index
].
codec_name
=
byt_rt5640_codec_name
;
}
/*
* swap SSP0 if bytcr is detected
* (will be overridden if DMI quirk is detected)
*/
if
(
is_valleyview
())
{
struct
sst_platform_info
*
p_info
=
mach
->
pdata
;
const
struct
sst_res_info
*
res_info
=
p_info
->
res_info
;
/* TODO: use CHAN package info from BIOS to detect AIF1/AIF2 */
if
(
res_info
->
acpi_ipc_irq_index
==
0
)
{
byt_rt5640_quirk
|=
BYT_RT5640_SSP0_AIF2
;
}
}
/* check quirks before creating card */
dmi_check_system
(
byt_rt5640_quirk_table
);
log_quirks
(
&
pdev
->
dev
);
if
((
byt_rt5640_quirk
&
BYT_RT5640_SSP2_AIF2
)
||
(
byt_rt5640_quirk
&
BYT_RT5640_SSP0_AIF2
))
{
/* fixup codec aif name */
snprintf
(
byt_rt5640_codec_aif_name
,
sizeof
(
byt_rt5640_codec_aif_name
),
"%s"
,
"rt5640-aif2"
);
byt_rt5640_dais
[
dai_index
].
codec_dai_name
=
byt_rt5640_codec_aif_name
;
}
if
((
byt_rt5640_quirk
&
BYT_RT5640_SSP0_AIF1
)
||
(
byt_rt5640_quirk
&
BYT_RT5640_SSP0_AIF2
))
{
/* fixup cpu dai name name */
snprintf
(
byt_rt5640_cpu_dai_name
,
sizeof
(
byt_rt5640_cpu_dai_name
),
"%s"
,
"ssp0-port"
);
byt_rt5640_dais
[
dai_index
].
cpu_dai_name
=
byt_rt5640_cpu_dai_name
;
}
if
((
byt_rt5640_quirk
&
BYT_RT5640_MCLK_EN
)
&&
(
is_valleyview
()))
{
priv
->
mclk
=
devm_clk_get
(
&
pdev
->
dev
,
"pmc_plt_clk_3"
);
if
(
IS_ERR
(
priv
->
mclk
))
{
dev_err
(
&
pdev
->
dev
,
"Failed to get MCLK from pmc_plt_clk_3: %ld
\n
"
,
PTR_ERR
(
priv
->
mclk
));
return
PTR_ERR
(
priv
->
mclk
);
}
}
ret_val
=
devm_snd_soc_register_card
(
&
pdev
->
dev
,
&
byt_rt5640_card
);
...
...
sound/soc/intel/common/sst-acpi.c
View file @
4a2447b4
...
...
@@ -199,6 +199,7 @@ static struct sst_acpi_desc sst_acpi_haswell_desc = {
static
struct
sst_acpi_mach
broadwell_machines
[]
=
{
{
"INT343A"
,
"broadwell-audio"
,
"intel/IntcSST2.bin"
,
NULL
,
NULL
,
NULL
},
{
"RT5677CE"
,
"bdw-rt5677"
,
"intel/IntcSST2.bin"
,
NULL
,
NULL
,
NULL
},
{}
};
...
...
sound/soc/intel/skylake/bxt-sst.c
View file @
4a2447b4
...
...
@@ -23,6 +23,7 @@
#include "../common/sst-dsp.h"
#include "../common/sst-dsp-priv.h"
#include "skl-sst-ipc.h"
#include "skl-tplg-interface.h"
#define BXT_BASEFW_TIMEOUT 3000
#define BXT_INIT_TIMEOUT 500
...
...
@@ -40,11 +41,73 @@
#define BXT_INSTANCE_ID 0
#define BXT_BASE_FW_MODULE_ID 0
#define BXT_ADSP_FW_BIN_HDR_OFFSET 0x2000
static
unsigned
int
bxt_get_errorcode
(
struct
sst_dsp
*
ctx
)
{
return
sst_dsp_shim_read
(
ctx
,
BXT_ADSP_ERROR_CODE
);
}
static
int
bxt_load_library
(
struct
sst_dsp
*
ctx
,
struct
skl_dfw_manifest
*
minfo
)
{
struct
snd_dma_buffer
dmab
;
struct
skl_sst
*
skl
=
ctx
->
thread_context
;
const
struct
firmware
*
fw
=
NULL
;
struct
firmware
stripped_fw
;
int
ret
=
0
,
i
,
dma_id
,
stream_tag
;
/* library indices start from 1 to N. 0 represents base FW */
for
(
i
=
1
;
i
<
minfo
->
lib_count
;
i
++
)
{
ret
=
request_firmware
(
&
fw
,
minfo
->
lib
[
i
].
name
,
ctx
->
dev
);
if
(
ret
<
0
)
{
dev_err
(
ctx
->
dev
,
"Request lib %s failed:%d
\n
"
,
minfo
->
lib
[
i
].
name
,
ret
);
return
ret
;
}
if
(
skl
->
is_first_boot
)
{
ret
=
snd_skl_parse_uuids
(
ctx
,
fw
,
BXT_ADSP_FW_BIN_HDR_OFFSET
,
i
);
if
(
ret
<
0
)
goto
load_library_failed
;
}
stripped_fw
.
data
=
fw
->
data
;
stripped_fw
.
size
=
fw
->
size
;
skl_dsp_strip_extended_manifest
(
&
stripped_fw
);
stream_tag
=
ctx
->
dsp_ops
.
prepare
(
ctx
->
dev
,
0x40
,
stripped_fw
.
size
,
&
dmab
);
if
(
stream_tag
<=
0
)
{
dev_err
(
ctx
->
dev
,
"Lib prepare DMA err: %x
\n
"
,
stream_tag
);
ret
=
stream_tag
;
goto
load_library_failed
;
}
dma_id
=
stream_tag
-
1
;
memcpy
(
dmab
.
area
,
stripped_fw
.
data
,
stripped_fw
.
size
);
ctx
->
dsp_ops
.
trigger
(
ctx
->
dev
,
true
,
stream_tag
);
ret
=
skl_sst_ipc_load_library
(
&
skl
->
ipc
,
dma_id
,
i
);
if
(
ret
<
0
)
dev_err
(
ctx
->
dev
,
"IPC Load Lib for %s fail: %d
\n
"
,
minfo
->
lib
[
i
].
name
,
ret
);
ctx
->
dsp_ops
.
trigger
(
ctx
->
dev
,
false
,
stream_tag
);
ctx
->
dsp_ops
.
cleanup
(
ctx
->
dev
,
&
dmab
,
stream_tag
);
release_firmware
(
fw
);
fw
=
NULL
;
}
return
ret
;
load_library_failed:
release_firmware
(
fw
);
return
ret
;
}
/*
* First boot sequence has some extra steps. Core 0 waits for power
* status on core 1, so power up core 1 also momentarily, keep it in
...
...
@@ -157,8 +220,6 @@ static int sst_transfer_fw_host_dma(struct sst_dsp *ctx)
return
ret
;
}
#define BXT_ADSP_FW_BIN_HDR_OFFSET 0x2000
static
int
bxt_load_base_firmware
(
struct
sst_dsp
*
ctx
)
{
struct
firmware
stripped_fw
;
...
...
@@ -175,9 +236,12 @@ static int bxt_load_base_firmware(struct sst_dsp *ctx)
if
(
ctx
->
fw
==
NULL
)
goto
sst_load_base_firmware_failed
;
ret
=
snd_skl_parse_uuids
(
ctx
,
BXT_ADSP_FW_BIN_HDR_OFFSET
);
/* prase uuids on first boot */
if
(
skl
->
is_first_boot
)
{
ret
=
snd_skl_parse_uuids
(
ctx
,
ctx
->
fw
,
BXT_ADSP_FW_BIN_HDR_OFFSET
,
0
);
if
(
ret
<
0
)
goto
sst_load_base_firmware_failed
;
}
stripped_fw
.
data
=
ctx
->
fw
->
data
;
stripped_fw
.
size
=
ctx
->
fw
->
size
;
...
...
@@ -230,15 +294,26 @@ static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
int
ret
;
struct
skl_ipc_dxstate_info
dx
;
unsigned
int
core_mask
=
SKL_DSP_CORE_MASK
(
core_id
);
struct
skl_dfw_manifest
*
minfo
=
&
skl
->
manifest
;
if
(
skl
->
fw_loaded
==
false
)
{
skl
->
boot_complete
=
false
;
ret
=
bxt_load_base_firmware
(
ctx
);
if
(
ret
<
0
)
if
(
ret
<
0
)
{
dev_err
(
ctx
->
dev
,
"reload fw failed: %d
\n
"
,
ret
);
return
ret
;
}
if
(
minfo
->
lib_count
>
1
)
{
ret
=
bxt_load_library
(
ctx
,
minfo
);
if
(
ret
<
0
)
{
dev_err
(
ctx
->
dev
,
"reload libs failed: %d
\n
"
,
ret
);
return
ret
;
}
}
return
ret
;
}
/* If core 0 is being turned on, turn on core 1 as well */
if
(
core_id
==
SKL_DSP_CORE0_ID
)
ret
=
skl_dsp_core_power_up
(
ctx
,
core_mask
|
...
...
@@ -329,7 +404,7 @@ static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id)
ret
=
skl_dsp_disable_core
(
ctx
,
core_mask
);
if
(
ret
<
0
)
{
dev_err
(
ctx
->
dev
,
"Failed to disable core %d"
,
ret
);
dev_err
(
ctx
->
dev
,
"Failed to disable core %d
\n
"
,
ret
);
return
ret
;
}
skl
->
cores
.
state
[
core_id
]
=
SKL_DSP_RESET
;
...
...
@@ -341,6 +416,7 @@ static struct skl_dsp_fw_ops bxt_fw_ops = {
.
set_state_D3
=
bxt_set_dsp_D3
,
.
load_fw
=
bxt_load_base_firmware
,
.
get_fw_errcode
=
bxt_get_errorcode
,
.
load_library
=
bxt_load_library
,
};
static
struct
sst_ops
skl_ops
=
{
...
...
@@ -397,22 +473,40 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
skl
->
cores
.
count
=
2
;
skl
->
boot_complete
=
false
;
init_waitqueue_head
(
&
skl
->
boot_wait
);
skl
->
is_first_boot
=
true
;
if
(
dsp
)
*
dsp
=
skl
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
bxt_sst_dsp_init
);
int
bxt_sst_init_fw
(
struct
device
*
dev
,
struct
skl_sst
*
ctx
)
{
int
ret
;
struct
sst_dsp
*
sst
=
ctx
->
dsp
;
ret
=
sst
->
fw_ops
.
load_fw
(
sst
);
if
(
ret
<
0
)
{
dev_err
(
dev
,
"Load base fw failed: %x"
,
ret
);
dev_err
(
dev
,
"Load base fw failed: %x
\n
"
,
ret
);
return
ret
;
}
skl_dsp_init_core_state
(
sst
);
if
(
dsp
)
*
dsp
=
skl
;
if
(
ctx
->
manifest
.
lib_count
>
1
)
{
ret
=
sst
->
fw_ops
.
load_library
(
sst
,
&
ctx
->
manifest
);
if
(
ret
<
0
)
{
dev_err
(
dev
,
"Load Library failed : %x
\n
"
,
ret
);
return
ret
;
}
}
ctx
->
is_first_boot
=
false
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
bxt_sst_dsp_init
);
EXPORT_SYMBOL_GPL
(
bxt_sst_init_fw
);
void
bxt_sst_dsp_cleanup
(
struct
device
*
dev
,
struct
skl_sst
*
ctx
)
{
...
...
sound/soc/intel/skylake/skl-messages.c
View file @
4a2447b4
...
...
@@ -203,32 +203,35 @@ static const struct skl_dsp_ops dsp_ops[] = {
.
id
=
0x9d70
,
.
loader_ops
=
skl_get_loader_ops
,
.
init
=
skl_sst_dsp_init
,
.
init_fw
=
skl_sst_init_fw
,
.
cleanup
=
skl_sst_dsp_cleanup
},
{
.
id
=
0x9d71
,
.
loader_ops
=
skl_get_loader_ops
,
.
init
=
skl_sst_dsp_init
,
.
init_fw
=
skl_sst_init_fw
,
.
cleanup
=
skl_sst_dsp_cleanup
},
{
.
id
=
0x5a98
,
.
loader_ops
=
bxt_get_loader_ops
,
.
init
=
bxt_sst_dsp_init
,
.
init_fw
=
bxt_sst_init_fw
,
.
cleanup
=
bxt_sst_dsp_cleanup
},
};
static
int
skl_get_dsp_ops
(
int
pci_id
)
const
struct
skl_dsp_ops
*
skl_get_dsp_ops
(
int
pci_id
)
{
int
i
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
dsp_ops
);
i
++
)
{
if
(
dsp_ops
[
i
].
id
==
pci_id
)
return
i
;
return
&
dsp_ops
[
i
]
;
}
return
-
EINVA
L
;
return
NUL
L
;
}
int
skl_init_dsp
(
struct
skl
*
skl
)
...
...
@@ -238,7 +241,8 @@ int skl_init_dsp(struct skl *skl)
struct
hdac_bus
*
bus
=
ebus_to_hbus
(
ebus
);
struct
skl_dsp_loader_ops
loader_ops
;
int
irq
=
bus
->
irq
;
int
ret
,
index
;
const
struct
skl_dsp_ops
*
ops
;
int
ret
;
/* enable ppcap interrupt */
snd_hdac_ext_bus_ppcap_enable
(
&
skl
->
ebus
,
true
);
...
...
@@ -251,18 +255,18 @@ int skl_init_dsp(struct skl *skl)
return
-
ENXIO
;
}
index
=
skl_get_dsp_ops
(
skl
->
pci
->
device
);
if
(
index
<
0
)
return
-
EI
NVAL
;
ops
=
skl_get_dsp_ops
(
skl
->
pci
->
device
);
if
(
!
ops
)
return
-
EI
O
;
loader_ops
=
dsp_ops
[
index
].
loader_ops
();
ret
=
dsp_ops
[
index
].
init
(
bus
->
dev
,
mmio_base
,
irq
,
skl
->
fw_name
,
loader_ops
,
&
skl
->
skl_sst
);
loader_ops
=
ops
->
loader_ops
();
ret
=
ops
->
init
(
bus
->
dev
,
mmio_base
,
irq
,
skl
->
fw_name
,
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
;
...
...
@@ -273,16 +277,16 @@ int skl_free_dsp(struct skl *skl)
struct
hdac_ext_bus
*
ebus
=
&
skl
->
ebus
;
struct
hdac_bus
*
bus
=
ebus_to_hbus
(
ebus
);
struct
skl_sst
*
ctx
=
skl
->
skl_sst
;
int
index
;
const
struct
skl_dsp_ops
*
ops
;
/* disable ppcap interrupt */
snd_hdac_ext_bus_ppcap_int_enable
(
&
skl
->
ebus
,
false
);
index
=
skl_get_dsp_ops
(
skl
->
pci
->
device
);
if
(
index
<
0
)
ops
=
skl_get_dsp_ops
(
skl
->
pci
->
device
);
if
(
!
ops
)
return
-
EIO
;
dsp_ops
[
index
].
cleanup
(
bus
->
dev
,
ctx
);
ops
->
cleanup
(
bus
->
dev
,
ctx
);
if
(
ctx
->
dsp
->
addr
.
lpe
)
iounmap
(
ctx
->
dsp
->
addr
.
lpe
);
...
...
@@ -296,7 +300,7 @@ int skl_suspend_dsp(struct skl *skl)
int
ret
;
/* if ppcap is not supported return 0 */
if
(
!
skl
->
ebus
.
ppcap
)
if
(
!
skl
->
ebus
.
bus
.
ppcap
)
return
0
;
ret
=
skl_dsp_sleep
(
ctx
->
dsp
);
...
...
@@ -316,13 +320,17 @@ int skl_resume_dsp(struct skl *skl)
int
ret
;
/* if ppcap is not supported return 0 */
if
(
!
skl
->
ebus
.
ppcap
)
if
(
!
skl
->
ebus
.
bus
.
ppcap
)
return
0
;
/* enable ppcap interrupt */
snd_hdac_ext_bus_ppcap_enable
(
&
skl
->
ebus
,
true
);
snd_hdac_ext_bus_ppcap_int_enable
(
&
skl
->
ebus
,
true
);
/* check if DSP 1st boot is done */
if
(
skl
->
skl_sst
->
is_first_boot
==
true
)
return
0
;
ret
=
skl_dsp_wake
(
ctx
->
dsp
);
if
(
ret
<
0
)
return
ret
;
...
...
@@ -672,6 +680,7 @@ static u16 skl_get_module_param_size(struct skl_sst *ctx,
return
param_size
;
case
SKL_MODULE_TYPE_BASE_OUTFMT
:
case
SKL_MODULE_TYPE_KPB
:
return
sizeof
(
struct
skl_base_outfmt_cfg
);
default:
...
...
@@ -725,6 +734,7 @@ static int skl_set_module_format(struct skl_sst *ctx,
break
;
case
SKL_MODULE_TYPE_BASE_OUTFMT
:
case
SKL_MODULE_TYPE_KPB
:
skl_set_base_outfmt_format
(
ctx
,
module_config
,
*
param_data
);
break
;
...
...
@@ -779,6 +789,7 @@ static int skl_alloc_queue(struct skl_module_pin *mpin,
mpin
[
i
].
in_use
=
true
;
mpin
[
i
].
id
.
module_id
=
id
.
module_id
;
mpin
[
i
].
id
.
instance_id
=
id
.
instance_id
;
mpin
[
i
].
id
.
pvt_id
=
id
.
pvt_id
;
mpin
[
i
].
tgt_mcfg
=
tgt_cfg
;
return
i
;
}
...
...
@@ -802,6 +813,7 @@ static void skl_free_queue(struct skl_module_pin *mpin, int q_index)
mpin
[
q_index
].
in_use
=
false
;
mpin
[
q_index
].
id
.
module_id
=
0
;
mpin
[
q_index
].
id
.
instance_id
=
0
;
mpin
[
q_index
].
id
.
pvt_id
=
0
;
}
mpin
[
q_index
].
pin_state
=
SKL_PIN_UNBIND
;
mpin
[
q_index
].
tgt_mcfg
=
NULL
;
...
...
@@ -842,7 +854,7 @@ int skl_init_module(struct skl_sst *ctx,
struct
skl_ipc_init_instance_msg
msg
;
dev_dbg
(
ctx
->
dev
,
"%s: module_id = %d instance=%d
\n
"
,
__func__
,
mconfig
->
id
.
module_id
,
mconfig
->
id
.
instance
_id
);
mconfig
->
id
.
module_id
,
mconfig
->
id
.
pvt
_id
);
if
(
mconfig
->
pipe
->
state
!=
SKL_PIPE_CREATED
)
{
dev_err
(
ctx
->
dev
,
"Pipe not created state= %d pipe_id= %d
\n
"
,
...
...
@@ -858,10 +870,11 @@ int skl_init_module(struct skl_sst *ctx,
}
msg
.
module_id
=
mconfig
->
id
.
module_id
;
msg
.
instance_id
=
mconfig
->
id
.
instance
_id
;
msg
.
instance_id
=
mconfig
->
id
.
pvt
_id
;
msg
.
ppl_instance_id
=
mconfig
->
pipe
->
ppl_id
;
msg
.
param_data_size
=
module_config_size
;
msg
.
core_id
=
mconfig
->
core_id
;
msg
.
domain
=
mconfig
->
domain
;
ret
=
skl_ipc_init_instance
(
&
ctx
->
ipc
,
&
msg
,
param_data
);
if
(
ret
<
0
)
{
...
...
@@ -878,9 +891,9 @@ static void skl_dump_bind_info(struct skl_sst *ctx, struct skl_module_cfg
*
src_module
,
struct
skl_module_cfg
*
dst_module
)
{
dev_dbg
(
ctx
->
dev
,
"%s: src module_id = %d src_instance=%d
\n
"
,
__func__
,
src_module
->
id
.
module_id
,
src_module
->
id
.
instance
_id
);
__func__
,
src_module
->
id
.
module_id
,
src_module
->
id
.
pvt
_id
);
dev_dbg
(
ctx
->
dev
,
"%s: dst_module=%d dst_instacne=%d
\n
"
,
__func__
,
dst_module
->
id
.
module_id
,
dst_module
->
id
.
instance
_id
);
dst_module
->
id
.
module_id
,
dst_module
->
id
.
pvt
_id
);
dev_dbg
(
ctx
->
dev
,
"src_module state = %d dst module state = %d
\n
"
,
src_module
->
m_state
,
dst_module
->
m_state
);
...
...
@@ -927,9 +940,9 @@ int skl_unbind_modules(struct skl_sst *ctx,
return
0
;
msg
.
module_id
=
src_mcfg
->
id
.
module_id
;
msg
.
instance_id
=
src_mcfg
->
id
.
instance
_id
;
msg
.
instance_id
=
src_mcfg
->
id
.
pvt
_id
;
msg
.
dst_module_id
=
dst_mcfg
->
id
.
module_id
;
msg
.
dst_instance_id
=
dst_mcfg
->
id
.
instance
_id
;
msg
.
dst_instance_id
=
dst_mcfg
->
id
.
pvt
_id
;
msg
.
bind
=
false
;
ret
=
skl_ipc_bind_unbind
(
&
ctx
->
ipc
,
&
msg
);
...
...
@@ -988,9 +1001,9 @@ int skl_bind_modules(struct skl_sst *ctx,
msg
.
src_queue
,
msg
.
dst_queue
);
msg
.
module_id
=
src_mcfg
->
id
.
module_id
;
msg
.
instance_id
=
src_mcfg
->
id
.
instance
_id
;
msg
.
instance_id
=
src_mcfg
->
id
.
pvt
_id
;
msg
.
dst_module_id
=
dst_mcfg
->
id
.
module_id
;
msg
.
dst_instance_id
=
dst_mcfg
->
id
.
instance
_id
;
msg
.
dst_instance_id
=
dst_mcfg
->
id
.
pvt
_id
;
msg
.
bind
=
true
;
ret
=
skl_ipc_bind_unbind
(
&
ctx
->
ipc
,
&
msg
);
...
...
@@ -1168,7 +1181,7 @@ int skl_set_module_params(struct skl_sst *ctx, u32 *params, int size,
struct
skl_ipc_large_config_msg
msg
;
msg
.
module_id
=
mcfg
->
id
.
module_id
;
msg
.
instance_id
=
mcfg
->
id
.
instance
_id
;
msg
.
instance_id
=
mcfg
->
id
.
pvt
_id
;
msg
.
param_data_size
=
size
;
msg
.
large_param_id
=
param_id
;
...
...
@@ -1181,7 +1194,7 @@ int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size,
struct
skl_ipc_large_config_msg
msg
;
msg
.
module_id
=
mcfg
->
id
.
module_id
;
msg
.
instance_id
=
mcfg
->
id
.
instance
_id
;
msg
.
instance_id
=
mcfg
->
id
.
pvt
_id
;
msg
.
param_data_size
=
size
;
msg
.
large_param_id
=
param_id
;
...
...
sound/soc/intel/skylake/skl-pcm.c
View file @
4a2447b4
...
...
@@ -106,7 +106,7 @@ static void skl_set_pcm_constrains(struct hdac_ext_bus *ebus,
static
enum
hdac_ext_stream_type
skl_get_host_stream_type
(
struct
hdac_ext_bus
*
ebus
)
{
if
(
ebus
->
ppcap
)
if
(
(
ebus_to_hbus
(
ebus
))
->
ppcap
)
return
HDAC_EXT_STREAM_TYPE_HOST
;
else
return
HDAC_EXT_STREAM_TYPE_COUPLED
;
...
...
@@ -188,7 +188,7 @@ static int skl_get_format(struct snd_pcm_substream *substream,
struct
hdac_ext_bus
*
ebus
=
dev_get_drvdata
(
dai
->
dev
);
int
format_val
=
0
;
if
(
ebus
->
ppcap
)
{
if
(
(
ebus_to_hbus
(
ebus
))
->
ppcap
)
{
struct
snd_pcm_runtime
*
runtime
=
substream
->
runtime
;
format_val
=
snd_hdac_calc_stream_format
(
runtime
->
rate
,
...
...
@@ -648,7 +648,8 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.
channels_min
=
HDA_MONO
,
.
channels_max
=
HDA_STEREO
,
.
rates
=
SNDRV_PCM_RATE_48000
|
SNDRV_PCM_RATE_16000
|
SNDRV_PCM_RATE_8000
,
.
formats
=
SNDRV_PCM_FMTBIT_S16_LE
|
SNDRV_PCM_FMTBIT_S24_LE
,
.
formats
=
SNDRV_PCM_FMTBIT_S16_LE
|
SNDRV_PCM_FMTBIT_S24_LE
|
SNDRV_PCM_FMTBIT_S32_LE
,
},
.
capture
=
{
.
stream_name
=
"System Capture"
,
...
...
@@ -1020,7 +1021,7 @@ static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream,
{
struct
hdac_ext_bus
*
ebus
=
get_bus_ctx
(
substream
);
if
(
!
ebus
->
ppcap
)
if
(
!
(
ebus_to_hbus
(
ebus
))
->
ppcap
)
return
skl_coupled_trigger
(
substream
,
cmd
);
return
0
;
...
...
@@ -1138,20 +1139,67 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd)
return
retval
;
}
static
int
skl_populate_modules
(
struct
skl
*
skl
)
{
struct
skl_pipeline
*
p
;
struct
skl_pipe_module
*
m
;
struct
snd_soc_dapm_widget
*
w
;
struct
skl_module_cfg
*
mconfig
;
int
ret
;
list_for_each_entry
(
p
,
&
skl
->
ppl_list
,
node
)
{
list_for_each_entry
(
m
,
&
p
->
pipe
->
w_list
,
node
)
{
w
=
m
->
w
;
mconfig
=
w
->
priv
;
ret
=
snd_skl_get_module_info
(
skl
->
skl_sst
,
mconfig
);
if
(
ret
<
0
)
{
dev_err
(
skl
->
skl_sst
->
dev
,
"query module info failed:%d
\n
"
,
ret
);
goto
err
;
}
}
}
err:
return
ret
;
}
static
int
skl_platform_soc_probe
(
struct
snd_soc_platform
*
platform
)
{
struct
hdac_ext_bus
*
ebus
=
dev_get_drvdata
(
platform
->
dev
);
struct
skl
*
skl
=
ebus_to_skl
(
ebus
);
const
struct
skl_dsp_ops
*
ops
;
int
ret
;
if
(
ebus
->
ppcap
)
{
pm_runtime_get_sync
(
platform
->
dev
);
if
((
ebus_to_hbus
(
ebus
))
->
ppcap
)
{
ret
=
skl_tplg_init
(
platform
,
ebus
);
if
(
ret
<
0
)
{
dev_err
(
platform
->
dev
,
"Failed to init topology!
\n
"
);
return
ret
;
}
skl
->
platform
=
platform
;
/* load the firmwares, since all is set */
ops
=
skl_get_dsp_ops
(
skl
->
pci
->
device
);
if
(
!
ops
)
return
-
EIO
;
if
(
skl
->
skl_sst
->
is_first_boot
==
false
)
{
dev_err
(
platform
->
dev
,
"DSP reports first boot done!!!
\n
"
);
return
-
EIO
;
}
ret
=
ops
->
init_fw
(
platform
->
dev
,
skl
->
skl_sst
);
if
(
ret
<
0
)
{
dev_err
(
platform
->
dev
,
"Failed to boot first fw: %d
\n
"
,
ret
);
return
ret
;
}
skl_populate_modules
(
skl
);
}
pm_runtime_mark_last_busy
(
platform
->
dev
);
pm_runtime_put_autosuspend
(
platform
->
dev
);
return
0
;
}
...
...
sound/soc/intel/skylake/skl-sst-cldma.c
View file @
4a2447b4
...
...
@@ -341,14 +341,14 @@ int skl_cldma_prepare(struct sst_dsp *ctx)
ret
=
ctx
->
dsp_ops
.
alloc_dma_buf
(
ctx
->
dev
,
&
ctx
->
cl_dev
.
dmab_data
,
ctx
->
cl_dev
.
bufsize
);
if
(
ret
<
0
)
{
dev_err
(
ctx
->
dev
,
"Alloc buffer for base fw failed: %x"
,
ret
);
dev_err
(
ctx
->
dev
,
"Alloc buffer for base fw failed: %x
\n
"
,
ret
);
return
ret
;
}
/* Setup Code loader BDL */
ret
=
ctx
->
dsp_ops
.
alloc_dma_buf
(
ctx
->
dev
,
&
ctx
->
cl_dev
.
dmab_bdl
,
PAGE_SIZE
);
if
(
ret
<
0
)
{
dev_err
(
ctx
->
dev
,
"Alloc buffer for blde failed: %x"
,
ret
);
dev_err
(
ctx
->
dev
,
"Alloc buffer for blde failed: %x
\n
"
,
ret
);
ctx
->
dsp_ops
.
free_dma_buf
(
ctx
->
dev
,
&
ctx
->
cl_dev
.
dmab_data
);
return
ret
;
}
...
...
sound/soc/intel/skylake/skl-sst-dsp.h
View file @
4a2447b4
...
...
@@ -20,6 +20,7 @@
#include <sound/memalloc.h>
#include "skl-sst-cldma.h"
#include "skl-tplg-interface.h"
#include "skl-topology.h"
struct
sst_dsp
;
struct
skl_sst
;
...
...
@@ -133,6 +134,8 @@ enum skl_dsp_states {
struct
skl_dsp_fw_ops
{
int
(
*
load_fw
)(
struct
sst_dsp
*
ctx
);
/* FW module parser/loader */
int
(
*
load_library
)(
struct
sst_dsp
*
ctx
,
struct
skl_dfw_manifest
*
minfo
);
int
(
*
parse_fw
)(
struct
sst_dsp
*
ctx
);
int
(
*
set_state_D0
)(
struct
sst_dsp
*
ctx
,
unsigned
int
core_id
);
int
(
*
set_state_D3
)(
struct
sst_dsp
*
ctx
,
unsigned
int
core_id
);
...
...
@@ -203,12 +206,21 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
int
bxt_sst_dsp_init
(
struct
device
*
dev
,
void
__iomem
*
mmio_base
,
int
irq
,
const
char
*
fw_name
,
struct
skl_dsp_loader_ops
dsp_ops
,
struct
skl_sst
**
dsp
);
int
skl_sst_init_fw
(
struct
device
*
dev
,
struct
skl_sst
*
ctx
);
int
bxt_sst_init_fw
(
struct
device
*
dev
,
struct
skl_sst
*
ctx
);
void
skl_sst_dsp_cleanup
(
struct
device
*
dev
,
struct
skl_sst
*
ctx
);
void
bxt_sst_dsp_cleanup
(
struct
device
*
dev
,
struct
skl_sst
*
ctx
);
int
snd_skl_get_module_info
(
struct
skl_sst
*
ctx
,
u8
*
uuid
,
struct
skl_dfw_module
*
dfw_config
);
int
snd_skl_parse_uuids
(
struct
sst_dsp
*
ctx
,
unsigned
int
offset
);
int
snd_skl_get_module_info
(
struct
skl_sst
*
ctx
,
struct
skl_module_cfg
*
mconfig
);
int
snd_skl_parse_uuids
(
struct
sst_dsp
*
ctx
,
const
struct
firmware
*
fw
,
unsigned
int
offset
,
int
index
);
int
skl_get_pvt_id
(
struct
skl_sst
*
ctx
,
struct
skl_module_cfg
*
mconfig
);
int
skl_put_pvt_id
(
struct
skl_sst
*
ctx
,
struct
skl_module_cfg
*
mconfig
);
int
skl_get_pvt_instance_id_map
(
struct
skl_sst
*
ctx
,
int
module_id
,
int
instance_id
);
void
skl_freeup_uuid_list
(
struct
skl_sst
*
ctx
);
int
skl_dsp_strip_extended_manifest
(
struct
firmware
*
fw
);
...
...
sound/soc/intel/skylake/skl-sst-ipc.c
View file @
4a2447b4
...
...
@@ -114,6 +114,11 @@
#define IPC_CORE_ID(x) (((x) & IPC_CORE_ID_MASK) \
<< IPC_CORE_ID_SHIFT)
#define IPC_DOMAIN_SHIFT 28
#define IPC_DOMAIN_MASK 0x1
#define IPC_DOMAIN(x) (((x) & IPC_DOMAIN_MASK) \
<< IPC_DOMAIN_SHIFT)
/* Bind/Unbind message extension register */
#define IPC_DST_MOD_ID_SHIFT 0
#define IPC_DST_MOD_ID(x) (((x) & IPC_MOD_ID_MASK) \
...
...
@@ -190,6 +195,7 @@ enum skl_ipc_glb_type {
IPC_GLB_GET_PPL_CONTEXT_SIZE
=
21
,
IPC_GLB_SAVE_PPL
=
22
,
IPC_GLB_RESTORE_PPL
=
23
,
IPC_GLB_LOAD_LIBRARY
=
24
,
IPC_GLB_NOTIFY
=
26
,
IPC_GLB_MAX_IPC_MSG_NUMBER
=
31
/* Maximum message number */
};
...
...
@@ -338,7 +344,7 @@ static int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
break
;
default:
dev_err
(
ipc
->
dev
,
"ipc: Unhandled error msg=%x"
,
dev_err
(
ipc
->
dev
,
"ipc: Unhandled error msg=%x
\n
"
,
header
.
primary
);
break
;
}
...
...
@@ -379,13 +385,13 @@ static void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
break
;
default:
dev_err
(
ipc
->
dev
,
"Unknown ipc reply: 0x%x"
,
reply
);
dev_err
(
ipc
->
dev
,
"Unknown ipc reply: 0x%x
\n
"
,
reply
);
msg
->
errno
=
-
EINVAL
;
break
;
}
if
(
reply
!=
IPC_GLB_REPLY_SUCCESS
)
{
dev_err
(
ipc
->
dev
,
"ipc FW reply: reply=%d"
,
reply
);
dev_err
(
ipc
->
dev
,
"ipc FW reply: reply=%d
\n
"
,
reply
);
dev_err
(
ipc
->
dev
,
"FW Error Code: %u
\n
"
,
ipc
->
dsp
->
fw_ops
.
get_fw_errcode
(
ipc
->
dsp
));
}
...
...
@@ -434,9 +440,9 @@ irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context)
hipcte
=
sst_dsp_shim_read_unlocked
(
dsp
,
SKL_ADSP_REG_HIPCTE
);
header
.
primary
=
hipct
;
header
.
extension
=
hipcte
;
dev_dbg
(
dsp
->
dev
,
"IPC irq: Firmware respond primary:%x"
,
dev_dbg
(
dsp
->
dev
,
"IPC irq: Firmware respond primary:%x
\n
"
,
header
.
primary
);
dev_dbg
(
dsp
->
dev
,
"IPC irq: Firmware respond extension:%x"
,
dev_dbg
(
dsp
->
dev
,
"IPC irq: Firmware respond extension:%x
\n
"
,
header
.
extension
);
if
(
IPC_GLB_NOTIFY_RSP_TYPE
(
header
.
primary
))
{
...
...
@@ -704,6 +710,7 @@ int skl_ipc_init_instance(struct sst_generic_ipc *ipc,
header
.
extension
=
IPC_CORE_ID
(
msg
->
core_id
);
header
.
extension
|=
IPC_PPL_INSTANCE_ID
(
msg
->
ppl_instance_id
);
header
.
extension
|=
IPC_PARAM_BLOCK_SIZE
(
param_block_size
);
header
.
extension
|=
IPC_DOMAIN
(
msg
->
domain
);
dev_dbg
(
ipc
->
dev
,
"In %s primary =%x ext=%x
\n
"
,
__func__
,
header
.
primary
,
header
.
extension
);
...
...
@@ -742,7 +749,7 @@ int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc,
header
.
extension
);
ret
=
sst_ipc_tx_message_wait
(
ipc
,
*
ipc_header
,
NULL
,
0
,
NULL
,
0
);
if
(
ret
<
0
)
{
dev_err
(
ipc
->
dev
,
"ipc: bind/unbind failed
e
n"
);
dev_err
(
ipc
->
dev
,
"ipc: bind/unbind failed
\
n
"
);
return
ret
;
}
...
...
@@ -902,3 +909,25 @@ int skl_ipc_get_large_config(struct sst_generic_ipc *ipc,
return
ret
;
}
EXPORT_SYMBOL_GPL
(
skl_ipc_get_large_config
);
int
skl_sst_ipc_load_library
(
struct
sst_generic_ipc
*
ipc
,
u8
dma_id
,
u8
table_id
)
{
struct
skl_ipc_header
header
=
{
0
};
u64
*
ipc_header
=
(
u64
*
)(
&
header
);
int
ret
=
0
;
header
.
primary
=
IPC_MSG_TARGET
(
IPC_FW_GEN_MSG
);
header
.
primary
|=
IPC_MSG_DIR
(
IPC_MSG_REQUEST
);
header
.
primary
|=
IPC_GLB_TYPE
(
IPC_GLB_LOAD_LIBRARY
);
header
.
primary
|=
IPC_MOD_INSTANCE_ID
(
table_id
);
header
.
primary
|=
IPC_MOD_ID
(
dma_id
);
ret
=
sst_ipc_tx_message_wait
(
ipc
,
*
ipc_header
,
NULL
,
0
,
NULL
,
0
);
if
(
ret
<
0
)
dev_err
(
ipc
->
dev
,
"ipc: load lib failed
\n
"
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
skl_sst_ipc_load_library
);
sound/soc/intel/skylake/skl-sst-ipc.h
View file @
4a2447b4
...
...
@@ -66,7 +66,7 @@ struct skl_sst {
/* callback for miscbdge */
void
(
*
enable_miscbdcge
)(
struct
device
*
dev
,
bool
enable
);
/*
Is CGCTL.MISCBDCGE disabled
*/
/*
Is CGCTL.MISCBDCGE disabled
*/
bool
miscbdcg_disabled
;
/* Populate module information */
...
...
@@ -75,8 +75,14 @@ struct skl_sst {
/* Is firmware loaded */
bool
fw_loaded
;
/* first boot ? */
bool
is_first_boot
;
/* multi-core */
struct
skl_dsp_cores
cores
;
/* tplg manifest */
struct
skl_dfw_manifest
manifest
;
};
struct
skl_ipc_init_instance_msg
{
...
...
@@ -85,6 +91,7 @@ struct skl_ipc_init_instance_msg {
u16
param_data_size
;
u8
ppl_instance_id
;
u8
core_id
;
u8
domain
;
};
struct
skl_ipc_bind_unbind_msg
{
...
...
@@ -145,6 +152,9 @@ int skl_ipc_set_large_config(struct sst_generic_ipc *ipc,
int
skl_ipc_get_large_config
(
struct
sst_generic_ipc
*
ipc
,
struct
skl_ipc_large_config_msg
*
msg
,
u32
*
param
);
int
skl_sst_ipc_load_library
(
struct
sst_generic_ipc
*
ipc
,
u8
dma_id
,
u8
table_id
);
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
);
...
...
sound/soc/intel/skylake/skl-sst-utils.c
View file @
4a2447b4
...
...
@@ -28,11 +28,6 @@
/* FW Extended Manifest Header id = $AE1 */
#define SKL_EXT_MANIFEST_HEADER_MAGIC 0x31454124
struct
skl_dfw_module_mod
{
char
name
[
100
];
struct
skl_dfw_module
skl_dfw_mod
;
};
struct
UUID
{
u8
id
[
16
];
};
...
...
@@ -99,10 +94,15 @@ struct adsp_fw_hdr {
u32
load_offset
;
}
__packed
;
#define MAX_INSTANCE_BUFF 2
struct
uuid_module
{
uuid_le
uuid
;
int
id
;
int
is_loadable
;
int
max_instance
;
u64
pvt_id
[
MAX_INSTANCE_BUFF
];
int
*
instance_id
;
struct
list_head
list
;
};
...
...
@@ -115,13 +115,13 @@ struct skl_ext_manifest_hdr {
u32
entries
;
};
int
snd_skl_get_module_info
(
struct
skl_sst
*
ctx
,
u8
*
uuid
,
struct
skl_dfw_module
*
dfw_
config
)
int
snd_skl_get_module_info
(
struct
skl_sst
*
ctx
,
struct
skl_module_cfg
*
m
config
)
{
struct
uuid_module
*
module
;
uuid_le
*
uuid_mod
;
uuid_mod
=
(
uuid_le
*
)
u
uid
;
uuid_mod
=
(
uuid_le
*
)
mconfig
->
g
uid
;
if
(
list_empty
(
&
ctx
->
uuid_list
))
{
dev_err
(
ctx
->
dev
,
"Module list is empty
\n
"
);
...
...
@@ -130,8 +130,8 @@ int snd_skl_get_module_info(struct skl_sst *ctx, u8 *uuid,
list_for_each_entry
(
module
,
&
ctx
->
uuid_list
,
list
)
{
if
(
uuid_le_cmp
(
*
uuid_mod
,
module
->
uuid
)
==
0
)
{
dfw_config
->
module_id
=
module
->
id
;
dfw_
config
->
is_loadable
=
module
->
is_loadable
;
mconfig
->
id
.
module_id
=
module
->
id
;
m
config
->
is_loadable
=
module
->
is_loadable
;
return
0
;
}
...
...
@@ -141,15 +141,154 @@ int snd_skl_get_module_info(struct skl_sst *ctx, u8 *uuid,
}
EXPORT_SYMBOL_GPL
(
snd_skl_get_module_info
);
static
int
skl_get_pvtid_map
(
struct
uuid_module
*
module
,
int
instance_id
)
{
int
pvt_id
;
for
(
pvt_id
=
0
;
pvt_id
<
module
->
max_instance
;
pvt_id
++
)
{
if
(
module
->
instance_id
[
pvt_id
]
==
instance_id
)
return
pvt_id
;
}
return
-
EINVAL
;
}
int
skl_get_pvt_instance_id_map
(
struct
skl_sst
*
ctx
,
int
module_id
,
int
instance_id
)
{
struct
uuid_module
*
module
;
list_for_each_entry
(
module
,
&
ctx
->
uuid_list
,
list
)
{
if
(
module
->
id
==
module_id
)
return
skl_get_pvtid_map
(
module
,
instance_id
);
}
return
-
EINVAL
;
}
EXPORT_SYMBOL_GPL
(
skl_get_pvt_instance_id_map
);
static
inline
int
skl_getid_32
(
struct
uuid_module
*
module
,
u64
*
val
,
int
word1_mask
,
int
word2_mask
)
{
int
index
,
max_inst
,
pvt_id
;
u32
mask_val
;
max_inst
=
module
->
max_instance
;
mask_val
=
(
u32
)(
*
val
>>
word1_mask
);
if
(
mask_val
!=
0xffffffff
)
{
index
=
ffz
(
mask_val
);
pvt_id
=
index
+
word1_mask
+
word2_mask
;
if
(
pvt_id
<=
(
max_inst
-
1
))
{
*
val
|=
1
<<
(
index
+
word1_mask
);
return
pvt_id
;
}
}
return
-
EINVAL
;
}
static
inline
int
skl_pvtid_128
(
struct
uuid_module
*
module
)
{
int
j
,
i
,
word1_mask
,
word2_mask
=
0
,
pvt_id
;
for
(
j
=
0
;
j
<
MAX_INSTANCE_BUFF
;
j
++
)
{
word1_mask
=
0
;
for
(
i
=
0
;
i
<
2
;
i
++
)
{
pvt_id
=
skl_getid_32
(
module
,
&
module
->
pvt_id
[
j
],
word1_mask
,
word2_mask
);
if
(
pvt_id
>=
0
)
return
pvt_id
;
word1_mask
+=
32
;
if
((
word1_mask
+
word2_mask
)
>=
module
->
max_instance
)
return
-
EINVAL
;
}
word2_mask
+=
64
;
if
(
word2_mask
>=
module
->
max_instance
)
return
-
EINVAL
;
}
return
-
EINVAL
;
}
/**
* skl_get_pvt_id: generate a private id for use as module id
*
* @ctx: driver context
* @mconfig: module configuration data
*
* This generates a 128 bit private unique id for a module TYPE so that
* module instance is unique
*/
int
skl_get_pvt_id
(
struct
skl_sst
*
ctx
,
struct
skl_module_cfg
*
mconfig
)
{
struct
uuid_module
*
module
;
uuid_le
*
uuid_mod
;
int
pvt_id
;
uuid_mod
=
(
uuid_le
*
)
mconfig
->
guid
;
list_for_each_entry
(
module
,
&
ctx
->
uuid_list
,
list
)
{
if
(
uuid_le_cmp
(
*
uuid_mod
,
module
->
uuid
)
==
0
)
{
pvt_id
=
skl_pvtid_128
(
module
);
if
(
pvt_id
>=
0
)
{
module
->
instance_id
[
pvt_id
]
=
mconfig
->
id
.
instance_id
;
return
pvt_id
;
}
}
}
return
-
EINVAL
;
}
EXPORT_SYMBOL_GPL
(
skl_get_pvt_id
);
/**
* skl_put_pvt_id: free up the private id allocated
*
* @ctx: driver context
* @mconfig: module configuration data
*
* This frees a 128 bit private unique id previously generated
*/
int
skl_put_pvt_id
(
struct
skl_sst
*
ctx
,
struct
skl_module_cfg
*
mconfig
)
{
int
i
;
uuid_le
*
uuid_mod
;
struct
uuid_module
*
module
;
uuid_mod
=
(
uuid_le
*
)
mconfig
->
guid
;
list_for_each_entry
(
module
,
&
ctx
->
uuid_list
,
list
)
{
if
(
uuid_le_cmp
(
*
uuid_mod
,
module
->
uuid
)
==
0
)
{
if
(
mconfig
->
id
.
pvt_id
!=
0
)
i
=
(
mconfig
->
id
.
pvt_id
)
/
64
;
else
i
=
0
;
module
->
pvt_id
[
i
]
&=
~
(
1
<<
(
mconfig
->
id
.
pvt_id
));
mconfig
->
id
.
pvt_id
=
-
1
;
return
0
;
}
}
return
-
EINVAL
;
}
EXPORT_SYMBOL_GPL
(
skl_put_pvt_id
);
/*
* Parse the firmware binary to get the UUID, module id
* and loadable flags
*/
int
snd_skl_parse_uuids
(
struct
sst_dsp
*
ctx
,
unsigned
int
offset
)
int
snd_skl_parse_uuids
(
struct
sst_dsp
*
ctx
,
const
struct
firmware
*
fw
,
unsigned
int
offset
,
int
index
)
{
struct
adsp_fw_hdr
*
adsp_hdr
;
struct
adsp_module_entry
*
mod_entry
;
int
i
,
num_entry
;
int
i
,
num_entry
,
size
;
uuid_le
*
uuid_bin
;
const
char
*
buf
;
struct
skl_sst
*
skl
=
ctx
->
thread_context
;
...
...
@@ -158,8 +297,8 @@ int snd_skl_parse_uuids(struct sst_dsp *ctx, unsigned int offset)
unsigned
int
safe_file
;
/* Get the FW pointer to derive ADSP header */
stripped_fw
.
data
=
ctx
->
fw
->
data
;
stripped_fw
.
size
=
ctx
->
fw
->
size
;
stripped_fw
.
data
=
fw
->
data
;
stripped_fw
.
size
=
fw
->
size
;
skl_dsp_strip_extended_manifest
(
&
stripped_fw
);
...
...
@@ -210,8 +349,15 @@ int snd_skl_parse_uuids(struct sst_dsp *ctx, unsigned int offset)
uuid_bin
=
(
uuid_le
*
)
mod_entry
->
uuid
.
id
;
memcpy
(
&
module
->
uuid
,
uuid_bin
,
sizeof
(
module
->
uuid
));
module
->
id
=
i
;
module
->
id
=
(
i
|
(
index
<<
12
))
;
module
->
is_loadable
=
mod_entry
->
type
.
load_type
;
module
->
max_instance
=
mod_entry
->
instance_max_count
;
size
=
sizeof
(
int
)
*
mod_entry
->
instance_max_count
;
module
->
instance_id
=
devm_kzalloc
(
ctx
->
dev
,
size
,
GFP_KERNEL
);
if
(
!
module
->
instance_id
)
{
kfree
(
module
);
return
-
ENOMEM
;
}
list_add_tail
(
&
module
->
list
,
&
skl
->
uuid_list
);
...
...
sound/soc/intel/skylake/skl-sst.c
View file @
4a2447b4
...
...
@@ -88,14 +88,16 @@ static int skl_load_base_firmware(struct sst_dsp *ctx)
}
}
ret
=
snd_skl_parse_uuids
(
ctx
,
SKL_ADSP_FW_BIN_HDR_OFFSET
);
/* prase uuids on first boot */
if
(
skl
->
is_first_boot
)
{
ret
=
snd_skl_parse_uuids
(
ctx
,
ctx
->
fw
,
SKL_ADSP_FW_BIN_HDR_OFFSET
,
0
);
if
(
ret
<
0
)
{
dev_err
(
ctx
->
dev
,
"UUID parsing err: %d
\n
"
,
ret
);
dev_err
(
ctx
->
dev
,
"UUID parsing err: %d
\n
"
,
ret
);
release_firmware
(
ctx
->
fw
);
skl_dsp_disable_core
(
ctx
,
SKL_DSP_CORE0_MASK
);
return
ret
;
}
}
/* check for extended manifest */
stripped_fw
.
data
=
ctx
->
fw
->
data
;
...
...
@@ -105,13 +107,13 @@ static int skl_load_base_firmware(struct sst_dsp *ctx)
ret
=
skl_dsp_boot
(
ctx
);
if
(
ret
<
0
)
{
dev_err
(
ctx
->
dev
,
"Boot dsp core failed ret: %d"
,
ret
);
dev_err
(
ctx
->
dev
,
"Boot dsp core failed ret: %d
\n
"
,
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
);
dev_err
(
ctx
->
dev
,
"CL dma prepare failed : %d
\n
"
,
ret
);
goto
skl_load_base_firmware_failed
;
}
...
...
@@ -484,25 +486,32 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
return
ret
;
skl
->
cores
.
count
=
2
;
ret
=
sst
->
fw_ops
.
load_fw
(
sst
);
if
(
ret
<
0
)
{
dev_err
(
dev
,
"Load base fw failed : %d"
,
ret
);
goto
cleanup
;
}
skl_dsp_init_core_state
(
sst
);
skl
->
is_first_boot
=
true
;
if
(
dsp
)
*
dsp
=
skl
;
return
ret
;
}
EXPORT_SYMBOL_GPL
(
skl_sst_dsp_init
);
cleanup:
skl_sst_dsp_cleanup
(
dev
,
skl
);
int
skl_sst_init_fw
(
struct
device
*
dev
,
struct
skl_sst
*
ctx
)
{
int
ret
;
struct
sst_dsp
*
sst
=
ctx
->
dsp
;
ret
=
sst
->
fw_ops
.
load_fw
(
sst
);
if
(
ret
<
0
)
{
dev_err
(
dev
,
"Load base fw failed : %d
\n
"
,
ret
);
return
ret
;
}
skl_dsp_init_core_state
(
sst
);
ctx
->
is_first_boot
=
false
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
skl_sst_
dsp_init
);
EXPORT_SYMBOL_GPL
(
skl_sst_
init_fw
);
void
skl_sst_dsp_cleanup
(
struct
device
*
dev
,
struct
skl_sst
*
ctx
)
{
...
...
sound/soc/intel/skylake/skl-topology.c
View file @
4a2447b4
...
...
@@ -21,6 +21,7 @@
#include <linux/firmware.h>
#include <sound/soc.h>
#include <sound/soc-topology.h>
#include <uapi/sound/snd_sst_tokens.h>
#include "skl-sst-dsp.h"
#include "skl-sst-ipc.h"
#include "skl-topology.h"
...
...
@@ -32,6 +33,8 @@
#define SKL_CH_FIXUP_MASK (1 << 0)
#define SKL_RATE_FIXUP_MASK (1 << 1)
#define SKL_FMT_FIXUP_MASK (1 << 2)
#define SKL_IN_DIR_BIT_MASK BIT(0)
#define SKL_PIN_COUNT_MASK GENMASK(7, 4)
/*
* SKL DSP driver modelling uses only few DAPM widgets so for rest we will
...
...
@@ -473,6 +476,14 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
w
=
w_module
->
w
;
mconfig
=
w
->
priv
;
/* check if module ids are populated */
if
(
mconfig
->
id
.
module_id
<
0
)
{
dev_err
(
skl
->
skl_sst
->
dev
,
"module %pUL id not populated
\n
"
,
(
uuid_le
*
)
mconfig
->
guid
);
return
-
EIO
;
}
/* check resource available */
if
(
!
skl_is_pipe_mcps_avail
(
skl
,
mconfig
))
return
-
ENOMEM
;
...
...
@@ -494,12 +505,15 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
* FE/BE params
*/
skl_tplg_update_module_params
(
w
,
ctx
);
mconfig
->
id
.
pvt_id
=
skl_get_pvt_id
(
ctx
,
mconfig
);
if
(
mconfig
->
id
.
pvt_id
<
0
)
return
ret
;
skl_tplg_set_module_init_data
(
w
);
ret
=
skl_init_module
(
ctx
,
mconfig
);
if
(
ret
<
0
)
if
(
ret
<
0
)
{
skl_put_pvt_id
(
ctx
,
mconfig
);
return
ret
;
}
skl_tplg_alloc_pipe_mcps
(
skl
,
mconfig
);
ret
=
skl_tplg_set_module_params
(
w
,
ctx
);
if
(
ret
<
0
)
...
...
@@ -512,6 +526,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
static
int
skl_tplg_unload_pipe_modules
(
struct
skl_sst
*
ctx
,
struct
skl_pipe
*
pipe
)
{
int
ret
;
struct
skl_pipe_module
*
w_module
=
NULL
;
struct
skl_module_cfg
*
mconfig
=
NULL
;
...
...
@@ -519,9 +534,13 @@ static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
mconfig
=
w_module
->
w
->
priv
;
if
(
mconfig
->
is_loadable
&&
ctx
->
dsp
->
fw_ops
.
unload_mod
&&
mconfig
->
m_state
>
SKL_MODULE_UNINIT
)
ret
urn
ctx
->
dsp
->
fw_ops
.
unload_mod
(
ctx
->
dsp
,
mconfig
->
m_state
>
SKL_MODULE_UNINIT
)
{
ret
=
ctx
->
dsp
->
fw_ops
.
unload_mod
(
ctx
->
dsp
,
mconfig
->
id
.
module_id
);
if
(
ret
<
0
)
return
-
EIO
;
}
skl_put_pvt_id
(
ctx
,
mconfig
);
}
/* no modules to unload in this path, so return */
...
...
@@ -588,6 +607,26 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
return
0
;
}
static
int
skl_fill_sink_instance_id
(
struct
skl_sst
*
ctx
,
struct
skl_algo_data
*
alg_data
)
{
struct
skl_kpb_params
*
params
=
(
struct
skl_kpb_params
*
)
alg_data
->
params
;
struct
skl_mod_inst_map
*
inst
;
int
i
,
pvt_id
;
inst
=
params
->
map
;
for
(
i
=
0
;
i
<
params
->
num_modules
;
i
++
)
{
pvt_id
=
skl_get_pvt_instance_id_map
(
ctx
,
inst
->
mod_id
,
inst
->
inst_id
);
if
(
pvt_id
<
0
)
return
-
EINVAL
;
inst
->
inst_id
=
pvt_id
;
inst
++
;
}
return
0
;
}
/*
* Some modules require params to be set after the module is bound to
* all pins connected.
...
...
@@ -636,6 +675,8 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w,
bc
=
(
struct
skl_algo_data
*
)
sb
->
dobj
.
private
;
if
(
bc
->
set_params
==
SKL_PARAM_BIND
)
{
if
(
mconfig
->
m_type
==
SKL_MODULE_TYPE_KPB
)
skl_fill_sink_instance_id
(
ctx
,
bc
);
ret
=
skl_set_module_params
(
ctx
,
(
u32
*
)
bc
->
params
,
bc
->
max
,
bc
->
param_id
,
mconfig
);
...
...
@@ -1460,85 +1501,570 @@ static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = {
skl_tplg_tlv_control_set
},
};
/*
* 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
)
static
int
skl_tplg_fill_pipe_tkn
(
struct
device
*
dev
,
struct
skl_pipe
*
pipe
,
u32
tkn
,
u32
tkn_val
)
{
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
;
m_pin
[
i
].
pin_state
=
SKL_PIN_UNBIND
;
switch
(
tkn
)
{
case
SKL_TKN_U32_PIPE_CONN_TYPE
:
pipe
->
conn_type
=
tkn_val
;
break
;
case
SKL_TKN_U32_PIPE_PRIORITY
:
pipe
->
pipe_priority
=
tkn_val
;
break
;
case
SKL_TKN_U32_PIPE_MEM_PGS
:
pipe
->
memory_pages
=
tkn_val
;
break
;
default:
dev_err
(
dev
,
"Token not handled %d
\n
"
,
tkn
);
return
-
EINVAL
;
}
return
0
;
}
/*
* 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
* Add pipeline by parsing the relevant tokens
* Return an existing pipe if the pipe already exists.
*/
static
struct
skl_pipe
*
skl_tplg_add_pipe
(
struct
device
*
dev
,
struct
skl
*
skl
,
struct
skl_dfw_pipe
*
dfw_pipe
)
static
int
skl_tplg_add_pipe
(
struct
device
*
dev
,
struct
skl_module_cfg
*
mconfig
,
struct
skl
*
skl
,
struct
snd_soc_tplg_vendor_value_elem
*
tkn_elem
)
{
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
;
if
(
ppl
->
pipe
->
ppl_id
==
tkn_elem
->
value
)
{
mconfig
->
pipe
=
ppl
->
pipe
;
return
EEXIST
;
}
}
ppl
=
devm_kzalloc
(
dev
,
sizeof
(
*
ppl
),
GFP_KERNEL
);
if
(
!
ppl
)
return
NULL
;
return
-
ENOMEM
;
pipe
=
devm_kzalloc
(
dev
,
sizeof
(
*
pipe
),
GFP_KERNEL
);
if
(
!
pipe
)
return
NULL
;
return
-
ENOMEM
;
params
=
devm_kzalloc
(
dev
,
sizeof
(
*
params
),
GFP_KERNEL
);
if
(
!
params
)
return
NULL
;
return
-
ENOMEM
;
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
;
pipe
->
ppl_id
=
tkn_elem
->
value
;
INIT_LIST_HEAD
(
&
pipe
->
w_list
);
ppl
->
pipe
=
pipe
;
list_add
(
&
ppl
->
node
,
&
skl
->
ppl_list
);
return
ppl
->
pipe
;
mconfig
->
pipe
=
pipe
;
mconfig
->
pipe
->
state
=
SKL_PIPE_INVALID
;
return
0
;
}
static
int
skl_tplg_fill_pin
(
struct
device
*
dev
,
u32
tkn
,
struct
skl_module_pin
*
m_pin
,
int
pin_index
,
u32
value
)
{
switch
(
tkn
)
{
case
SKL_TKN_U32_PIN_MOD_ID
:
m_pin
[
pin_index
].
id
.
module_id
=
value
;
break
;
case
SKL_TKN_U32_PIN_INST_ID
:
m_pin
[
pin_index
].
id
.
instance_id
=
value
;
break
;
default:
dev_err
(
dev
,
"%d Not a pin token
\n
"
,
value
);
return
-
EINVAL
;
}
return
0
;
}
/*
* Parse for pin config specific tokens to fill up the
* module private data
*/
static
int
skl_tplg_fill_pins_info
(
struct
device
*
dev
,
struct
skl_module_cfg
*
mconfig
,
struct
snd_soc_tplg_vendor_value_elem
*
tkn_elem
,
int
dir
,
int
pin_count
)
{
int
ret
;
struct
skl_module_pin
*
m_pin
;
switch
(
dir
)
{
case
SKL_DIR_IN
:
m_pin
=
mconfig
->
m_in_pin
;
break
;
case
SKL_DIR_OUT
:
m_pin
=
mconfig
->
m_out_pin
;
break
;
default:
dev_err
(
dev
,
"Invalid direction value
\n
"
);
return
-
EINVAL
;
}
ret
=
skl_tplg_fill_pin
(
dev
,
tkn_elem
->
token
,
m_pin
,
pin_count
,
tkn_elem
->
value
);
if
(
ret
<
0
)
return
ret
;
m_pin
[
pin_count
].
in_use
=
false
;
m_pin
[
pin_count
].
pin_state
=
SKL_PIN_UNBIND
;
return
0
;
}
/*
* Fill up input/output module config format based
* on the direction
*/
static
int
skl_tplg_fill_fmt
(
struct
device
*
dev
,
struct
skl_module_cfg
*
mconfig
,
u32
tkn
,
u32
value
,
u32
dir
,
u32
pin_count
)
{
struct
skl_module_fmt
*
dst_fmt
;
switch
(
dir
)
{
case
SKL_DIR_IN
:
dst_fmt
=
mconfig
->
in_fmt
;
dst_fmt
+=
pin_count
;
break
;
case
SKL_DIR_OUT
:
dst_fmt
=
mconfig
->
out_fmt
;
dst_fmt
+=
pin_count
;
break
;
default:
dev_err
(
dev
,
"Invalid direction value
\n
"
);
return
-
EINVAL
;
}
switch
(
tkn
)
{
case
SKL_TKN_U32_FMT_CH
:
dst_fmt
->
channels
=
value
;
break
;
case
SKL_TKN_U32_FMT_FREQ
:
dst_fmt
->
s_freq
=
value
;
break
;
case
SKL_TKN_U32_FMT_BIT_DEPTH
:
dst_fmt
->
bit_depth
=
value
;
break
;
case
SKL_TKN_U32_FMT_SAMPLE_SIZE
:
dst_fmt
->
valid_bit_depth
=
value
;
break
;
case
SKL_TKN_U32_FMT_CH_CONFIG
:
dst_fmt
->
ch_cfg
=
value
;
break
;
case
SKL_TKN_U32_FMT_INTERLEAVE
:
dst_fmt
->
interleaving_style
=
value
;
break
;
case
SKL_TKN_U32_FMT_SAMPLE_TYPE
:
dst_fmt
->
sample_type
=
value
;
break
;
case
SKL_TKN_U32_FMT_CH_MAP
:
dst_fmt
->
ch_map
=
value
;
break
;
default:
dev_err
(
dev
,
"Invalid token %d
\n
"
,
tkn
);
return
-
EINVAL
;
}
return
0
;
}
static
int
skl_tplg_get_uuid
(
struct
device
*
dev
,
struct
skl_module_cfg
*
mconfig
,
struct
snd_soc_tplg_vendor_uuid_elem
*
uuid_tkn
)
{
if
(
uuid_tkn
->
token
==
SKL_TKN_UUID
)
memcpy
(
&
mconfig
->
guid
,
&
uuid_tkn
->
uuid
,
16
);
else
{
dev_err
(
dev
,
"Not an UUID token tkn %d
\n
"
,
uuid_tkn
->
token
);
return
-
EINVAL
;
}
return
0
;
}
static
void
skl_tplg_fill_fmt
(
struct
skl_module_fmt
*
dst_fmt
,
struct
skl_dfw_module_fmt
*
src_fmt
,
int
pins
)
static
void
skl_tplg_fill_pin_dynamic_val
(
struct
skl_module_pin
*
mpin
,
u32
pin_count
,
u32
value
)
{
int
i
;
for
(
i
=
0
;
i
<
pins
;
i
++
)
{
dst_fmt
[
i
].
channels
=
src_fmt
[
i
].
channels
;
dst_fmt
[
i
].
s_freq
=
src_fmt
[
i
].
freq
;
dst_fmt
[
i
].
bit_depth
=
src_fmt
[
i
].
bit_depth
;
dst_fmt
[
i
].
valid_bit_depth
=
src_fmt
[
i
].
valid_bit_depth
;
dst_fmt
[
i
].
ch_cfg
=
src_fmt
[
i
].
ch_cfg
;
dst_fmt
[
i
].
ch_map
=
src_fmt
[
i
].
ch_map
;
dst_fmt
[
i
].
interleaving_style
=
src_fmt
[
i
].
interleaving_style
;
dst_fmt
[
i
].
sample_type
=
src_fmt
[
i
].
sample_type
;
for
(
i
=
0
;
i
<
pin_count
;
i
++
)
mpin
[
i
].
is_dynamic
=
value
;
}
/*
* Parse tokens to fill up the module private data
*/
static
int
skl_tplg_get_token
(
struct
device
*
dev
,
struct
snd_soc_tplg_vendor_value_elem
*
tkn_elem
,
struct
skl
*
skl
,
struct
skl_module_cfg
*
mconfig
)
{
int
tkn_count
=
0
;
int
ret
;
static
int
is_pipe_exists
;
static
int
pin_index
,
dir
;
if
(
tkn_elem
->
token
>
SKL_TKN_MAX
)
return
-
EINVAL
;
switch
(
tkn_elem
->
token
)
{
case
SKL_TKN_U8_IN_QUEUE_COUNT
:
mconfig
->
max_in_queue
=
tkn_elem
->
value
;
mconfig
->
m_in_pin
=
devm_kzalloc
(
dev
,
mconfig
->
max_in_queue
*
sizeof
(
*
mconfig
->
m_in_pin
),
GFP_KERNEL
);
if
(
!
mconfig
->
m_in_pin
)
return
-
ENOMEM
;
break
;
case
SKL_TKN_U8_OUT_QUEUE_COUNT
:
mconfig
->
max_out_queue
=
tkn_elem
->
value
;
mconfig
->
m_out_pin
=
devm_kzalloc
(
dev
,
mconfig
->
max_out_queue
*
sizeof
(
*
mconfig
->
m_out_pin
),
GFP_KERNEL
);
if
(
!
mconfig
->
m_out_pin
)
return
-
ENOMEM
;
break
;
case
SKL_TKN_U8_DYN_IN_PIN
:
if
(
!
mconfig
->
m_in_pin
)
return
-
ENOMEM
;
skl_tplg_fill_pin_dynamic_val
(
mconfig
->
m_in_pin
,
mconfig
->
max_in_queue
,
tkn_elem
->
value
);
break
;
case
SKL_TKN_U8_DYN_OUT_PIN
:
if
(
!
mconfig
->
m_out_pin
)
return
-
ENOMEM
;
skl_tplg_fill_pin_dynamic_val
(
mconfig
->
m_out_pin
,
mconfig
->
max_out_queue
,
tkn_elem
->
value
);
break
;
case
SKL_TKN_U8_TIME_SLOT
:
mconfig
->
time_slot
=
tkn_elem
->
value
;
break
;
case
SKL_TKN_U8_CORE_ID
:
mconfig
->
core_id
=
tkn_elem
->
value
;
case
SKL_TKN_U8_MOD_TYPE
:
mconfig
->
m_type
=
tkn_elem
->
value
;
break
;
case
SKL_TKN_U8_DEV_TYPE
:
mconfig
->
dev_type
=
tkn_elem
->
value
;
break
;
case
SKL_TKN_U8_HW_CONN_TYPE
:
mconfig
->
hw_conn_type
=
tkn_elem
->
value
;
break
;
case
SKL_TKN_U16_MOD_INST_ID
:
mconfig
->
id
.
instance_id
=
tkn_elem
->
value
;
break
;
case
SKL_TKN_U32_MEM_PAGES
:
mconfig
->
mem_pages
=
tkn_elem
->
value
;
break
;
case
SKL_TKN_U32_MAX_MCPS
:
mconfig
->
mcps
=
tkn_elem
->
value
;
break
;
case
SKL_TKN_U32_OBS
:
mconfig
->
obs
=
tkn_elem
->
value
;
break
;
case
SKL_TKN_U32_IBS
:
mconfig
->
ibs
=
tkn_elem
->
value
;
break
;
case
SKL_TKN_U32_VBUS_ID
:
mconfig
->
vbus_id
=
tkn_elem
->
value
;
break
;
case
SKL_TKN_U32_PARAMS_FIXUP
:
mconfig
->
params_fixup
=
tkn_elem
->
value
;
break
;
case
SKL_TKN_U32_CONVERTER
:
mconfig
->
converter
=
tkn_elem
->
value
;
break
;
case
SKL_TKN_U32_PIPE_ID
:
ret
=
skl_tplg_add_pipe
(
dev
,
mconfig
,
skl
,
tkn_elem
);
if
(
ret
<
0
)
return
is_pipe_exists
;
if
(
ret
==
EEXIST
)
is_pipe_exists
=
1
;
break
;
case
SKL_TKN_U32_PIPE_CONN_TYPE
:
case
SKL_TKN_U32_PIPE_PRIORITY
:
case
SKL_TKN_U32_PIPE_MEM_PGS
:
if
(
is_pipe_exists
)
{
ret
=
skl_tplg_fill_pipe_tkn
(
dev
,
mconfig
->
pipe
,
tkn_elem
->
token
,
tkn_elem
->
value
);
if
(
ret
<
0
)
return
ret
;
}
break
;
/*
* SKL_TKN_U32_DIR_PIN_COUNT token has the value for both
* direction and the pin count. The first four bits represent
* direction and next four the pin count.
*/
case
SKL_TKN_U32_DIR_PIN_COUNT
:
dir
=
tkn_elem
->
value
&
SKL_IN_DIR_BIT_MASK
;
pin_index
=
(
tkn_elem
->
value
&
SKL_PIN_COUNT_MASK
)
>>
4
;
break
;
case
SKL_TKN_U32_FMT_CH
:
case
SKL_TKN_U32_FMT_FREQ
:
case
SKL_TKN_U32_FMT_BIT_DEPTH
:
case
SKL_TKN_U32_FMT_SAMPLE_SIZE
:
case
SKL_TKN_U32_FMT_CH_CONFIG
:
case
SKL_TKN_U32_FMT_INTERLEAVE
:
case
SKL_TKN_U32_FMT_SAMPLE_TYPE
:
case
SKL_TKN_U32_FMT_CH_MAP
:
ret
=
skl_tplg_fill_fmt
(
dev
,
mconfig
,
tkn_elem
->
token
,
tkn_elem
->
value
,
dir
,
pin_index
);
if
(
ret
<
0
)
return
ret
;
break
;
case
SKL_TKN_U32_PIN_MOD_ID
:
case
SKL_TKN_U32_PIN_INST_ID
:
ret
=
skl_tplg_fill_pins_info
(
dev
,
mconfig
,
tkn_elem
,
dir
,
pin_index
);
if
(
ret
<
0
)
return
ret
;
break
;
case
SKL_TKN_U32_CAPS_SIZE
:
mconfig
->
formats_config
.
caps_size
=
tkn_elem
->
value
;
break
;
case
SKL_TKN_U32_PROC_DOMAIN
:
mconfig
->
domain
=
tkn_elem
->
value
;
break
;
case
SKL_TKN_U8_IN_PIN_TYPE
:
case
SKL_TKN_U8_OUT_PIN_TYPE
:
case
SKL_TKN_U8_CONN_TYPE
:
break
;
default:
dev_err
(
dev
,
"Token %d not handled
\n
"
,
tkn_elem
->
token
);
return
-
EINVAL
;
}
tkn_count
++
;
return
tkn_count
;
}
/*
* Parse the vendor array for specific tokens to construct
* module private data
*/
static
int
skl_tplg_get_tokens
(
struct
device
*
dev
,
char
*
pvt_data
,
struct
skl
*
skl
,
struct
skl_module_cfg
*
mconfig
,
int
block_size
)
{
struct
snd_soc_tplg_vendor_array
*
array
;
struct
snd_soc_tplg_vendor_value_elem
*
tkn_elem
;
int
tkn_count
=
0
,
ret
;
int
off
=
0
,
tuple_size
=
0
;
if
(
block_size
<=
0
)
return
-
EINVAL
;
while
(
tuple_size
<
block_size
)
{
array
=
(
struct
snd_soc_tplg_vendor_array
*
)(
pvt_data
+
off
);
off
+=
array
->
size
;
switch
(
array
->
type
)
{
case
SND_SOC_TPLG_TUPLE_TYPE_STRING
:
dev_warn
(
dev
,
"no string tokens expected for skl tplg
\n
"
);
continue
;
case
SND_SOC_TPLG_TUPLE_TYPE_UUID
:
ret
=
skl_tplg_get_uuid
(
dev
,
mconfig
,
array
->
uuid
);
if
(
ret
<
0
)
return
ret
;
tuple_size
+=
sizeof
(
*
array
->
uuid
);
continue
;
default:
tkn_elem
=
array
->
value
;
tkn_count
=
0
;
break
;
}
while
(
tkn_count
<=
(
array
->
num_elems
-
1
))
{
ret
=
skl_tplg_get_token
(
dev
,
tkn_elem
,
skl
,
mconfig
);
if
(
ret
<
0
)
return
ret
;
tkn_count
=
tkn_count
+
ret
;
tkn_elem
++
;
}
tuple_size
+=
tkn_count
*
sizeof
(
*
tkn_elem
);
}
return
0
;
}
/*
* Every data block is preceded by a descriptor to read the number
* of data blocks, they type of the block and it's size
*/
static
int
skl_tplg_get_desc_blocks
(
struct
device
*
dev
,
struct
snd_soc_tplg_vendor_array
*
array
)
{
struct
snd_soc_tplg_vendor_value_elem
*
tkn_elem
;
tkn_elem
=
array
->
value
;
switch
(
tkn_elem
->
token
)
{
case
SKL_TKN_U8_NUM_BLOCKS
:
case
SKL_TKN_U8_BLOCK_TYPE
:
case
SKL_TKN_U16_BLOCK_SIZE
:
return
tkn_elem
->
value
;
default:
dev_err
(
dev
,
"Invalid descriptor token %d
\n
"
,
tkn_elem
->
token
);
break
;
}
return
-
EINVAL
;
}
/*
* Parse the private data for the token and corresponding value.
* The private data can have multiple data blocks. So, a data block
* is preceded by a descriptor for number of blocks and a descriptor
* for the type and size of the suceeding data block.
*/
static
int
skl_tplg_get_pvt_data
(
struct
snd_soc_tplg_dapm_widget
*
tplg_w
,
struct
skl
*
skl
,
struct
device
*
dev
,
struct
skl_module_cfg
*
mconfig
)
{
struct
snd_soc_tplg_vendor_array
*
array
;
int
num_blocks
,
block_size
=
0
,
block_type
,
off
=
0
;
char
*
data
;
int
ret
;
/* Read the NUM_DATA_BLOCKS descriptor */
array
=
(
struct
snd_soc_tplg_vendor_array
*
)
tplg_w
->
priv
.
data
;
ret
=
skl_tplg_get_desc_blocks
(
dev
,
array
);
if
(
ret
<
0
)
return
ret
;
num_blocks
=
ret
;
off
+=
array
->
size
;
array
=
(
struct
snd_soc_tplg_vendor_array
*
)(
tplg_w
->
priv
.
data
+
off
);
/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
while
(
num_blocks
>
0
)
{
ret
=
skl_tplg_get_desc_blocks
(
dev
,
array
);
if
(
ret
<
0
)
return
ret
;
block_type
=
ret
;
off
+=
array
->
size
;
array
=
(
struct
snd_soc_tplg_vendor_array
*
)
(
tplg_w
->
priv
.
data
+
off
);
ret
=
skl_tplg_get_desc_blocks
(
dev
,
array
);
if
(
ret
<
0
)
return
ret
;
block_size
=
ret
;
off
+=
array
->
size
;
array
=
(
struct
snd_soc_tplg_vendor_array
*
)
(
tplg_w
->
priv
.
data
+
off
);
data
=
(
tplg_w
->
priv
.
data
+
off
);
if
(
block_type
==
SKL_TYPE_TUPLE
)
{
ret
=
skl_tplg_get_tokens
(
dev
,
data
,
skl
,
mconfig
,
block_size
);
if
(
ret
<
0
)
return
ret
;
--
num_blocks
;
}
else
{
if
(
mconfig
->
formats_config
.
caps_size
>
0
)
memcpy
(
mconfig
->
formats_config
.
caps
,
data
,
mconfig
->
formats_config
.
caps_size
);
--
num_blocks
;
}
}
return
0
;
}
static
void
skl_clear_pin_config
(
struct
snd_soc_platform
*
platform
,
...
...
@@ -1606,9 +2132,6 @@ static int skl_tplg_widget_load(struct snd_soc_component *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
;
...
...
@@ -1619,76 +2142,17 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
return
-
ENOMEM
;
w
->
priv
=
mconfig
;
memcpy
(
&
mconfig
->
guid
,
&
dfw_config
->
uuid
,
16
);
ret
=
snd_skl_get_module_info
(
skl
->
skl_sst
,
mconfig
->
guid
,
dfw_config
);
/*
* module binary can be loaded later, so set it to query when
* module is load for a use case
*/
mconfig
->
id
.
module_id
=
-
1
;
/* Parse private data for tuples */
ret
=
skl_tplg_get_pvt_data
(
tplg_w
,
skl
,
bus
->
dev
,
mconfig
);
if
(
ret
<
0
)
return
ret
;
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
;
skl_tplg_fill_fmt
(
mconfig
->
in_fmt
,
dfw_config
->
in_fmt
,
MODULE_MAX_IN_PINS
);
skl_tplg_fill_fmt
(
mconfig
->
out_fmt
,
dfw_config
->
out_fmt
,
MODULE_MAX_OUT_PINS
);
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
;
mconfig
->
mem_pages
=
dfw_config
->
mem_pages
;
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
);
mconfig
->
formats_config
.
param_id
=
dfw_config
->
caps
.
param_id
;
mconfig
->
formats_config
.
set_params
=
dfw_config
->
caps
.
set_params
;
bind_event:
if
(
tplg_w
->
event_type
==
0
)
{
dev_dbg
(
bus
->
dev
,
"ASoC: No event handler required
\n
"
);
...
...
@@ -1767,11 +2231,229 @@ static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
return
0
;
}
static
int
skl_tplg_fill_str_mfest_tkn
(
struct
device
*
dev
,
struct
snd_soc_tplg_vendor_string_elem
*
str_elem
,
struct
skl_dfw_manifest
*
minfo
)
{
int
tkn_count
=
0
;
static
int
ref_count
;
switch
(
str_elem
->
token
)
{
case
SKL_TKN_STR_LIB_NAME
:
if
(
ref_count
>
minfo
->
lib_count
-
1
)
{
ref_count
=
0
;
return
-
EINVAL
;
}
strncpy
(
minfo
->
lib
[
ref_count
].
name
,
str_elem
->
string
,
ARRAY_SIZE
(
minfo
->
lib
[
ref_count
].
name
));
ref_count
++
;
tkn_count
++
;
break
;
default:
dev_err
(
dev
,
"Not a string token %d
\n
"
,
str_elem
->
token
);
break
;
}
return
tkn_count
;
}
static
int
skl_tplg_get_str_tkn
(
struct
device
*
dev
,
struct
snd_soc_tplg_vendor_array
*
array
,
struct
skl_dfw_manifest
*
minfo
)
{
int
tkn_count
=
0
,
ret
;
struct
snd_soc_tplg_vendor_string_elem
*
str_elem
;
str_elem
=
(
struct
snd_soc_tplg_vendor_string_elem
*
)
array
->
value
;
while
(
tkn_count
<
array
->
num_elems
)
{
ret
=
skl_tplg_fill_str_mfest_tkn
(
dev
,
str_elem
,
minfo
);
str_elem
++
;
if
(
ret
<
0
)
return
ret
;
tkn_count
=
tkn_count
+
ret
;
}
return
tkn_count
;
}
static
int
skl_tplg_get_int_tkn
(
struct
device
*
dev
,
struct
snd_soc_tplg_vendor_value_elem
*
tkn_elem
,
struct
skl_dfw_manifest
*
minfo
)
{
int
tkn_count
=
0
;
switch
(
tkn_elem
->
token
)
{
case
SKL_TKN_U32_LIB_COUNT
:
minfo
->
lib_count
=
tkn_elem
->
value
;
tkn_count
++
;
break
;
default:
dev_err
(
dev
,
"Not a manifest token %d
\n
"
,
tkn_elem
->
token
);
return
-
EINVAL
;
}
return
tkn_count
;
}
/*
* Fill the manifest structure by parsing the tokens based on the
* type.
*/
static
int
skl_tplg_get_manifest_tkn
(
struct
device
*
dev
,
char
*
pvt_data
,
struct
skl_dfw_manifest
*
minfo
,
int
block_size
)
{
int
tkn_count
=
0
,
ret
;
int
off
=
0
,
tuple_size
=
0
;
struct
snd_soc_tplg_vendor_array
*
array
;
struct
snd_soc_tplg_vendor_value_elem
*
tkn_elem
;
if
(
block_size
<=
0
)
return
-
EINVAL
;
while
(
tuple_size
<
block_size
)
{
array
=
(
struct
snd_soc_tplg_vendor_array
*
)(
pvt_data
+
off
);
off
+=
array
->
size
;
switch
(
array
->
type
)
{
case
SND_SOC_TPLG_TUPLE_TYPE_STRING
:
ret
=
skl_tplg_get_str_tkn
(
dev
,
array
,
minfo
);
if
(
ret
<
0
)
return
ret
;
tkn_count
+=
ret
;
tuple_size
+=
tkn_count
*
sizeof
(
struct
snd_soc_tplg_vendor_string_elem
);
continue
;
case
SND_SOC_TPLG_TUPLE_TYPE_UUID
:
dev_warn
(
dev
,
"no uuid tokens for skl tplf manifest
\n
"
);
continue
;
default:
tkn_elem
=
array
->
value
;
tkn_count
=
0
;
break
;
}
while
(
tkn_count
<=
array
->
num_elems
-
1
)
{
ret
=
skl_tplg_get_int_tkn
(
dev
,
tkn_elem
,
minfo
);
if
(
ret
<
0
)
return
ret
;
tkn_count
=
tkn_count
+
ret
;
tkn_elem
++
;
tuple_size
+=
tkn_count
*
sizeof
(
struct
snd_soc_tplg_vendor_value_elem
);
break
;
}
tkn_count
=
0
;
}
return
0
;
}
/*
* Parse manifest private data for tokens. The private data block is
* preceded by descriptors for type and size of data block.
*/
static
int
skl_tplg_get_manifest_data
(
struct
snd_soc_tplg_manifest
*
manifest
,
struct
device
*
dev
,
struct
skl_dfw_manifest
*
minfo
)
{
struct
snd_soc_tplg_vendor_array
*
array
;
int
num_blocks
,
block_size
=
0
,
block_type
,
off
=
0
;
char
*
data
;
int
ret
;
/* Read the NUM_DATA_BLOCKS descriptor */
array
=
(
struct
snd_soc_tplg_vendor_array
*
)
manifest
->
priv
.
data
;
ret
=
skl_tplg_get_desc_blocks
(
dev
,
array
);
if
(
ret
<
0
)
return
ret
;
num_blocks
=
ret
;
off
+=
array
->
size
;
array
=
(
struct
snd_soc_tplg_vendor_array
*
)
(
manifest
->
priv
.
data
+
off
);
/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
while
(
num_blocks
>
0
)
{
ret
=
skl_tplg_get_desc_blocks
(
dev
,
array
);
if
(
ret
<
0
)
return
ret
;
block_type
=
ret
;
off
+=
array
->
size
;
array
=
(
struct
snd_soc_tplg_vendor_array
*
)
(
manifest
->
priv
.
data
+
off
);
ret
=
skl_tplg_get_desc_blocks
(
dev
,
array
);
if
(
ret
<
0
)
return
ret
;
block_size
=
ret
;
off
+=
array
->
size
;
array
=
(
struct
snd_soc_tplg_vendor_array
*
)
(
manifest
->
priv
.
data
+
off
);
data
=
(
manifest
->
priv
.
data
+
off
);
if
(
block_type
==
SKL_TYPE_TUPLE
)
{
ret
=
skl_tplg_get_manifest_tkn
(
dev
,
data
,
minfo
,
block_size
);
if
(
ret
<
0
)
return
ret
;
--
num_blocks
;
}
else
{
return
-
EINVAL
;
}
}
return
0
;
}
static
int
skl_manifest_load
(
struct
snd_soc_component
*
cmpnt
,
struct
snd_soc_tplg_manifest
*
manifest
)
{
struct
skl_dfw_manifest
*
minfo
;
struct
hdac_ext_bus
*
ebus
=
snd_soc_component_get_drvdata
(
cmpnt
);
struct
hdac_bus
*
bus
=
ebus_to_hbus
(
ebus
);
struct
skl
*
skl
=
ebus_to_skl
(
ebus
);
int
ret
=
0
;
/* proceed only if we have private data defined */
if
(
manifest
->
priv
.
size
==
0
)
return
0
;
minfo
=
&
skl
->
skl_sst
->
manifest
;
skl_tplg_get_manifest_data
(
manifest
,
bus
->
dev
,
minfo
);
if
(
minfo
->
lib_count
>
HDA_MAX_LIB
)
{
dev_err
(
bus
->
dev
,
"Exceeding max Library count. Got:%d
\n
"
,
minfo
->
lib_count
);
ret
=
-
EINVAL
;
}
return
ret
;
}
static
struct
snd_soc_tplg_ops
skl_tplg_ops
=
{
.
widget_load
=
skl_tplg_widget_load
,
.
control_load
=
skl_tplg_control_load
,
.
bytes_ext_ops
=
skl_tlv_ops
,
.
bytes_ext_ops_count
=
ARRAY_SIZE
(
skl_tlv_ops
),
.
manifest
=
skl_manifest_load
,
};
/*
...
...
sound/soc/intel/skylake/skl-topology.h
View file @
4a2447b4
...
...
@@ -133,7 +133,7 @@ struct skl_i2s_config_blob {
struct
skl_dma_control
{
u32
node_id
;
u32
config_length
;
u32
config_data
[
1
];
u32
config_data
[
0
];
}
__packed
;
struct
skl_cpr_cfg
{
...
...
@@ -215,9 +215,20 @@ struct skl_module_fmt {
struct
skl_module_cfg
;
struct
skl_mod_inst_map
{
u16
mod_id
;
u16
inst_id
;
};
struct
skl_kpb_params
{
u32
num_modules
;
struct
skl_mod_inst_map
map
[
0
];
};
struct
skl_module_inst_id
{
u32
module_id
;
int
module_id
;
u32
instance_id
;
int
pvt_id
;
};
enum
skl_module_pin_state
{
...
...
sound/soc/intel/skylake/skl-tplg-interface.h
View file @
4a2447b4
...
...
@@ -80,7 +80,8 @@ enum skl_module_type {
SKL_MODULE_TYPE_UPDWMIX
,
SKL_MODULE_TYPE_SRCINT
,
SKL_MODULE_TYPE_ALGO
,
SKL_MODULE_TYPE_BASE_OUTFMT
SKL_MODULE_TYPE_BASE_OUTFMT
,
SKL_MODULE_TYPE_KPB
,
};
enum
skl_core_affinity
{
...
...
@@ -148,84 +149,34 @@ enum skl_module_param_type {
SKL_PARAM_BIND
};
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
;
u32
interleaving_style
;
u32
sample_type
;
u32
ch_map
;
}
__packed
;
struct
skl_dfw_module_caps
{
struct
skl_dfw_algo_data
{
u32
set_params
:
2
;
u32
rsvd
:
30
;
u32
param_id
;
u32
caps_size
;
u32
caps
[
HDA_SST_CFG_MAX
];
};
struct
skl_dfw_pipe
{
u8
pipe_id
;
u8
pipe_priority
;
u16
conn_type
:
4
;
u16
rsvd
:
4
;
u16
memory_pages
:
8
;
u32
max
;
char
params
[
0
];
}
__packed
;
struct
skl_dfw_module
{
u8
uuid
[
16
];
u16
module_id
;
u16
instance_id
;
u32
max_mcps
;
u32
mem_pages
;
u32
obs
;
u32
ibs
;
u32
vbus_id
;
u32
max_in_queue
:
8
;
u32
max_out_queue
:
8
;
u32
time_slot
:
8
;
u32
core_id
:
4
;
u32
rsvd1
:
4
;
u32
module_type
:
8
;
u32
conn_type
:
4
;
u32
dev_type
:
4
;
u32
hw_conn_type
:
4
;
u32
rsvd2
:
12
;
u32
params_fixup
:
8
;
u32
converter
:
8
;
u32
input_pin_type
:
1
;
u32
output_pin_type
:
1
;
u32
is_dynamic_in_pin
:
1
;
u32
is_dynamic_out_pin
:
1
;
u32
is_loadable
:
1
;
u32
rsvd3
:
11
;
struct
skl_dfw_pipe
pipe
;
struct
skl_dfw_module_fmt
in_fmt
[
MAX_IN_QUEUE
];
struct
skl_dfw_module_fmt
out_fmt
[
MAX_OUT_QUEUE
];
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
;
#define LIB_NAME_LENGTH 128
#define HDA_MAX_LIB 16
struct
lib_info
{
char
name
[
LIB_NAME_LENGTH
];
}
__packed
;
struct
skl_dfw_algo_data
{
u32
set_params
:
2
;
u32
rsvd
:
30
;
u32
param_id
;
u32
max
;
char
params
[
0
];
struct
skl_dfw_manifest
{
u32
lib_count
;
struct
lib_info
lib
[
HDA_MAX_LIB
];
}
__packed
;
enum
skl_tkn_dir
{
SKL_DIR_IN
,
SKL_DIR_OUT
};
enum
skl_tuple_type
{
SKL_TYPE_TUPLE
,
SKL_TYPE_DATA
};
#endif
sound/soc/intel/skylake/skl.c
View file @
4a2447b4
...
...
@@ -587,7 +587,7 @@ static int skl_first_init(struct hdac_ext_bus *ebus)
return
-
ENXIO
;
}
snd_hdac_
ext_bus_parse_capabilities
(
e
bus
);
snd_hdac_
bus_parse_capabilities
(
bus
);
if
(
skl_acquire_irq
(
ebus
,
0
)
<
0
)
return
-
EBUSY
;
...
...
@@ -684,7 +684,7 @@ static int skl_probe(struct pci_dev *pci,
skl_dmic_data
.
dmic_num
=
skl_get_dmic_geo
(
skl
);
/* check if dsp is there */
if
(
e
bus
->
ppcap
)
{
if
(
bus
->
ppcap
)
{
err
=
skl_machine_device_register
(
skl
,
(
void
*
)
pci_id
->
driver_data
);
if
(
err
<
0
)
...
...
@@ -698,7 +698,7 @@ static int skl_probe(struct pci_dev *pci,
skl
->
skl_sst
->
enable_miscbdcge
=
skl_enable_miscbdcge
;
}
if
(
e
bus
->
mlcap
)
if
(
bus
->
mlcap
)
snd_hdac_ext_bus_get_ml_capabilities
(
ebus
);
/* create device for soc dmic */
...
...
sound/soc/intel/skylake/skl.h
View file @
4a2447b4
...
...
@@ -105,6 +105,7 @@ struct skl_dsp_ops {
int
irq
,
const
char
*
fw_name
,
struct
skl_dsp_loader_ops
loader_ops
,
struct
skl_sst
**
skl_sst
);
int
(
*
init_fw
)(
struct
device
*
dev
,
struct
skl_sst
*
ctx
);
void
(
*
cleanup
)(
struct
device
*
dev
,
struct
skl_sst
*
ctx
);
};
...
...
@@ -123,4 +124,5 @@ int skl_free_dsp(struct skl *skl);
int
skl_suspend_dsp
(
struct
skl
*
skl
);
int
skl_resume_dsp
(
struct
skl
*
skl
);
void
skl_cleanup_resources
(
struct
skl
*
skl
);
const
struct
skl_dsp_ops
*
skl_get_dsp_ops
(
int
pci_id
);
#endif
/* __SOUND_SOC_SKL_H */
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