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
nexedi
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
Hide 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
,
params_rate
(
params
)
*
50
,
params_rate
(
params
)
*
512
);
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_IN1_MAP
,
.
driver_data
=
(
unsigned
long
*
)(
BYT_RT5640_IN3_MAP
|
BYT_RT5640_MCLK_EN
|
BYT_RT5640_SSP0_AIF1
),
},
{
.
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,34 +531,63 @@ 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
;
/* set SSP2 to 24-bit */
params_set_format
(
params
,
SNDRV_PCM_FORMAT_S24_LE
);
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
;
}
/*
* Default mode for SSP configuration is TDM 4 slot, override config
* with explicit setting to I2S 2ch 24-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
;
}
ret
=
snd_soc_dai_set_tdm_slot
(
rtd
->
cpu_dai
,
0x3
,
0x3
,
2
,
24
);
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
);
/*
* Default mode for SSP configuration is TDM 4 slot, override config
* with explicit setting to I2S 2ch 24-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
,
24
);
if
(
ret
<
0
)
{
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
);
if
(
ret
<
0
)
goto
sst_load_base_firmware_failed
;
/* 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,12 +294,23 @@ 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
;
}
...
...
@@ -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,13 +88,15 @@ static int skl_load_base_firmware(struct sst_dsp *ctx)
}
}
ret
=
snd_skl_parse_uuids
(
ctx
,
SKL_ADSP_FW_BIN_HDR_OFFSET
);
if
(
ret
<
0
)
{
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
;
/* 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
);
release_firmware
(
ctx
->
fw
);
skl_dsp_disable_core
(
ctx
,
SKL_DSP_CORE0_MASK
);
return
ret
;
}
}
/* check for extended manifest */
...
...
@@ -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
;
skl
->
is_first_boot
=
true
;
if
(
dsp
)
*
dsp
=
skl
;
return
ret
;
}
EXPORT_SYMBOL_GPL
(
skl_sst_dsp_init
);
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"
,
ret
);
goto
cleanup
;
dev_err
(
dev
,
"Load base fw failed : %d
\n
"
,
ret
);
return
ret
;
}
skl_dsp_init_core_state
(
sst
);
ctx
->
is_first_boot
=
false
;
if
(
dsp
)
*
dsp
=
skl
;
return
ret
;
cleanup:
skl_sst_dsp_cleanup
(
dev
,
skl
);
return
ret
;
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
void
skl_tplg_fill_fmt
(
struct
skl_module_fmt
*
dst_fmt
,
struct
skl_dfw_module_fmt
*
src_fmt
,
int
pins
)
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_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