Merge remote-tracking branch 'asoc/topic/intel' into asoc-next
This commit is contained in:
Коммит
4a2447b483
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* 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
|
|
@ -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 (!ebus->ppcap) {
|
||||
if (!bus->ppcap) {
|
||||
dev_err(bus->dev, "Address of PP capability is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable)
|
||||
snd_hdac_updatel(ebus->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(ebus->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 (!ebus->ppcap) {
|
||||
if (!bus->ppcap) {
|
||||
dev_err(bus->dev, "Address of PP capability is NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable)
|
||||
snd_hdac_updatel(ebus->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(ebus->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(ebus->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 = ebus->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);
|
||||
|
|
|
@ -40,27 +40,27 @@ void snd_hdac_ext_stream_init(struct hdac_ext_bus *ebus,
|
|||
{
|
||||
struct hdac_bus *bus = &ebus->bus;
|
||||
|
||||
if (ebus->ppcap) {
|
||||
stream->pphc_addr = ebus->ppcap + AZX_PPHC_BASE +
|
||||
if (bus->ppcap) {
|
||||
stream->pphc_addr = bus->ppcap + AZX_PPHC_BASE +
|
||||
AZX_PPHC_INTERVAL * idx;
|
||||
|
||||
stream->pplc_addr = ebus->ppcap + AZX_PPLC_BASE +
|
||||
stream->pplc_addr = bus->ppcap + AZX_PPLC_BASE +
|
||||
AZX_PPLC_MULTI * ebus->num_streams +
|
||||
AZX_PPLC_INTERVAL * idx;
|
||||
}
|
||||
|
||||
if (ebus->spbcap) {
|
||||
stream->spib_addr = ebus->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 = ebus->spbcap + AZX_SPB_BASE +
|
||||
stream->fifo_addr = bus->spbcap + AZX_SPB_BASE +
|
||||
AZX_SPB_INTERVAL * idx +
|
||||
AZX_SPB_MAXFIFO;
|
||||
}
|
||||
|
||||
if (ebus->drsmcap)
|
||||
stream->dpibr_addr = ebus->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(ebus->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(ebus->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 (!ebus->ppcap) {
|
||||
if (!hbus->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 (!ebus->ppcap) {
|
||||
if (!hbus->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 (!ebus->spbcap) {
|
||||
if (!bus->spbcap) {
|
||||
dev_err(bus->dev, "Address of SPB capability is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
mask |= (1 << index);
|
||||
|
||||
register_mask = readl(ebus->spbcap + AZX_REG_SPB_SPBFCCTL);
|
||||
register_mask = readl(bus->spbcap + AZX_REG_SPB_SPBFCCTL);
|
||||
|
||||
mask |= register_mask;
|
||||
|
||||
if (enable)
|
||||
snd_hdac_updatel(ebus->spbcap, AZX_REG_SPB_SPBFCCTL, 0, mask);
|
||||
snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, 0, mask);
|
||||
else
|
||||
snd_hdac_updatel(ebus->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 (!ebus->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 (!ebus->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 (!ebus->drsmcap) {
|
||||
if (!bus->drsmcap) {
|
||||
dev_err(bus->dev, "Address of DRSM capability is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
mask |= (1 << index);
|
||||
|
||||
register_mask = readl(ebus->drsmcap + AZX_REG_SPB_SPBFCCTL);
|
||||
register_mask = readl(bus->drsmcap + AZX_REG_SPB_SPBFCCTL);
|
||||
|
||||
mask |= register_mask;
|
||||
|
||||
if (enable)
|
||||
snd_hdac_updatel(ebus->drsmcap, AZX_REG_DRSM_CTL, 0, mask);
|
||||
snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, 0, mask);
|
||||
else
|
||||
snd_hdac_updatel(ebus->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 (!ebus->drsmcap) {
|
||||
if (!bus->drsmcap) {
|
||||
dev_err(bus->dev, "Address of DRSM capability is NULL");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 && \
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* 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
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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, cant susupend, abort\n", i);
|
||||
dev_err(dev, "stream %d is running, can't suspend, abort\n", i);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
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
|
||||
|
|
|
@ -0,0 +1,347 @@
|
|||
/*
|
||||
* 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(¶ms->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");
|
|
@ -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_HDMI1_PB]
|
||||
[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] =
|
||||
{
|
||||
.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,
|
||||
},
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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,
|
||||
.driver_data = (unsigned long *)(BYT_RT5640_IN1_MAP |
|
||||
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, "ASUSTeK COMPUTER INC."),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TAF"),
|
||||
},
|
||||
.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_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)) {
|
||||
|
||||
/*
|
||||
* 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;
|
||||
/* set SSP0 to 16-bit */
|
||||
params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
|
||||
|
||||
/*
|
||||
* Default mode for SSP configuration is TDM 4 slot, override config
|
||||
* with explicit setting to I2S 2ch 16-bit. The word length is set with
|
||||
* dai_set_tdm_slot() since there is no other API exposed
|
||||
*/
|
||||
ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
|
||||
SND_SOC_DAIFMT_I2S |
|
||||
SND_SOC_DAIFMT_NB_IF |
|
||||
SND_SOC_DAIFMT_CBS_CFS
|
||||
);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 16);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* set SSP2 to 24-bit */
|
||||
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -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 },
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
|
@ -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,14 +473,7 @@ 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);
|
||||
|
||||
ret = sst->fw_ops.load_fw(sst);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Load base fw failed: %x", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
skl_dsp_init_core_state(sst);
|
||||
skl->is_first_boot = true;
|
||||
|
||||
if (dsp)
|
||||
*dsp = skl;
|
||||
|
@ -413,6 +482,31 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
|
|||
}
|
||||
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\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
skl_dsp_init_core_state(sst);
|
||||
|
||||
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_init_fw);
|
||||
|
||||
void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
|
||||
{
|
||||
|
|
|
@ -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 -EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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 -EINVAL;
|
||||
ops = skl_get_dsp_ops(skl->pci->device);
|
||||
if (!ops)
|
||||
return -EIO;
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 faileden");
|
||||
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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 *mconfig)
|
||||
{
|
||||
struct uuid_module *module;
|
||||
uuid_le *uuid_mod;
|
||||
|
||||
uuid_mod = (uuid_le *)uuid;
|
||||
uuid_mod = (uuid_le *)mconfig->guid;
|
||||
|
||||
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;
|
||||
mconfig->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);
|
||||
|
||||
|
|
|
@ -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,26 +486,33 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
|
|||
return ret;
|
||||
|
||||
skl->cores.count = 2;
|
||||
|
||||
ret = sst->fw_ops.load_fw(sst);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Load base fw failed : %d", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
skl_dsp_init_core_state(sst);
|
||||
skl->is_first_boot = true;
|
||||
|
||||
if (dsp)
|
||||
*dsp = skl;
|
||||
|
||||
return ret;
|
||||
|
||||
cleanup:
|
||||
skl_sst_dsp_cleanup(dev, 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\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
skl_dsp_init_core_state(sst);
|
||||
ctx->is_first_boot = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(skl_sst_init_fw);
|
||||
|
||||
void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
|
||||
{
|
||||
skl_clear_module_table(ctx->dsp);
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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 {
|
||||
|
|
|
@ -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,78 +149,6 @@ 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 {
|
||||
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;
|
||||
} __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;
|
||||
} __packed;
|
||||
|
||||
struct skl_dfw_algo_data {
|
||||
u32 set_params:2;
|
||||
u32 rsvd:30;
|
||||
|
@ -228,4 +157,26 @@ struct skl_dfw_algo_data {
|
|||
char params[0];
|
||||
} __packed;
|
||||
|
||||
#define LIB_NAME_LENGTH 128
|
||||
#define HDA_MAX_LIB 16
|
||||
|
||||
struct lib_info {
|
||||
char name[LIB_NAME_LENGTH];
|
||||
} __packed;
|
||||
|
||||
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
|
||||
|
|
|
@ -587,7 +587,7 @@ static int skl_first_init(struct hdac_ext_bus *ebus)
|
|||
return -ENXIO;
|
||||
}
|
||||
|
||||
snd_hdac_ext_bus_parse_capabilities(ebus);
|
||||
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 (ebus->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 (ebus->mlcap)
|
||||
if (bus->mlcap)
|
||||
snd_hdac_ext_bus_get_ml_capabilities(ebus);
|
||||
|
||||
/* create device for soc dmic */
|
||||
|
|
|
@ -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 */
|
||||
|
|
Загрузка…
Ссылка в новой задаче