Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
raspberrypi-kernel
提交
c1a7c40c
R
raspberrypi-kernel
项目概览
openeuler
/
raspberrypi-kernel
通知
13
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
raspberrypi-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
c1a7c40c
编写于
2月 03, 2017
作者:
T
Takashi Iwai
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'topic/intel-lpe-audio' into for-next
Lots of cleanups and refactoring of Intel LPE audio driver.
上级
374a5040
91b0cb0c
变更
8
展开全部
隐藏空白更改
内联
并排
Showing
8 changed file
with
1034 addition
and
2679 deletion
+1034
-2679
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_reg.h
+3
-0
drivers/gpu/drm/i915/intel_lpe_audio.c
drivers/gpu/drm/i915/intel_lpe_audio.c
+5
-0
sound/x86/Makefile
sound/x86/Makefile
+1
-3
sound/x86/intel_hdmi_audio.c
sound/x86/intel_hdmi_audio.c
+951
-950
sound/x86/intel_hdmi_audio.h
sound/x86/intel_hdmi_audio.h
+20
-97
sound/x86/intel_hdmi_audio_if.c
sound/x86/intel_hdmi_audio_if.c
+0
-548
sound/x86/intel_hdmi_lpe_audio.c
sound/x86/intel_hdmi_lpe_audio.c
+0
-665
sound/x86/intel_hdmi_lpe_audio.h
sound/x86/intel_hdmi_lpe_audio.h
+54
-416
未找到文件。
drivers/gpu/drm/i915/i915_reg.h
浏览文件 @
c1a7c40c
...
...
@@ -2062,6 +2062,9 @@ enum skl_disp_power_wells {
#define I915_HDMI_LPE_AUDIO_SIZE 0x1000
/* DisplayPort Audio w/ LPE */
#define VLV_AUD_CHICKEN_BIT_REG _MMIO(VLV_DISPLAY_BASE + 0x62F38)
#define VLV_CHICKEN_BIT_DBG_ENABLE (1 << 0)
#define _VLV_AUD_PORT_EN_B_DBG (VLV_DISPLAY_BASE + 0x62F20)
#define _VLV_AUD_PORT_EN_C_DBG (VLV_DISPLAY_BASE + 0x62F30)
#define _VLV_AUD_PORT_EN_D_DBG (VLV_DISPLAY_BASE + 0x62F34)
...
...
drivers/gpu/drm/i915/intel_lpe_audio.c
浏览文件 @
c1a7c40c
...
...
@@ -248,6 +248,11 @@ static int lpe_audio_setup(struct drm_i915_private *dev_priv)
goto
err_free_irq
;
}
/* enable chicken bit; at least this is required for Dell Wyse 3040
* with DP outputs (but only sometimes by some reason!)
*/
I915_WRITE
(
VLV_AUD_CHICKEN_BIT_REG
,
VLV_CHICKEN_BIT_DBG_ENABLE
);
return
0
;
err_free_irq:
irq_free_desc
(
dev_priv
->
lpe_audio
.
irq
);
...
...
sound/x86/Makefile
浏览文件 @
c1a7c40c
snd-hdmi-lpe-audio-objs
+=
\
intel_hdmi_audio.o
\
intel_hdmi_audio_if.o
\
intel_hdmi_lpe_audio.o
intel_hdmi_audio.o
obj-$(CONFIG_HDMI_LPE_AUDIO)
+=
snd-hdmi-lpe-audio.o
sound/x86/intel_hdmi_audio.c
浏览文件 @
c1a7c40c
此差异已折叠。
点击以展开。
sound/x86/intel_hdmi_audio.h
浏览文件 @
c1a7c40c
...
...
@@ -30,19 +30,11 @@
#ifndef _INTEL_HDMI_AUDIO_H_
#define _INTEL_HDMI_AUDIO_H_
#include <linux/types.h>
#include <sound/initval.h>
#include <linux/version.h>
#include <linux/pm_runtime.h>
#include <sound/asoundef.h>
#include <sound/control.h>
#include <sound/pcm.h>
#include "intel_hdmi_lpe_audio.h"
#define PCM_INDEX 0
#define MAX_PB_STREAMS 1
#define MAX_CAP_STREAMS 0
#define HDMI_AUDIO_DRIVER "hdmi-audio"
#define HDMI_INFO_FRAME_WORD1 0x000a0184
#define DP_INFO_FRAME_WORD1 0x00441b84
...
...
@@ -64,21 +56,18 @@
#define SMPL_WIDTH_16BITS 0x1
#define SMPL_WIDTH_24BITS 0x5
#define CHANNEL_ALLOCATION 0x1F
#define MASK_BYTE0 0x000000FF
#define VALID_DIP_WORDS 3
#define LAYOUT0 0
#define LAYOUT1 1
#define SWAP_LFE_CENTER 0x00fac4c8
#define AUD_CONFIG_CH_MASK
_V2
0x70
#define AUD_CONFIG_CH_MASK 0x70
struct
pcm_stream_info
{
int
str_id
;
void
*
had_substream
;
void
(
*
period_elapsed
)(
void
*
had_substream
);
u32
buffer_ptr
;
struct
snd_pcm_substream
*
substream
;
u64
buffer_rendered
;
u32
ring_buf_size
;
int
sfreq
;
int
substream_refcount
;
bool
running
;
};
struct
ring_buf_info
{
...
...
@@ -87,113 +76,47 @@ struct ring_buf_info {
u8
is_valid
;
};
struct
had_stream_pvt
{
enum
had_stream_status
stream_status
;
int
stream_ops
;
ssize_t
dbg_cum_bytes
;
};
struct
had_pvt_data
{
enum
had_status_stream
stream_type
;
};
struct
had_callback_ops
{
had_event_call_back
intel_had_event_call_back
;
};
/**
/*
* struct snd_intelhad - intelhad driver structure
*
* @card: ptr to hold card details
* @card_index: sound card index
* @card_id: detected sound card id
* @reg_ops: register operations to program registers
* @query_ops: caps call backs for get/set operations
* @drv_status: driver status
* @connected: the monitor connection status
* @buf_info: ring buffer info
* @stream_info: stream information
* @e
eld: holds E
ELD info
* @e
ld: holds
ELD info
* @curr_buf: pointer to hold current active ring buf
* @valid_buf_cnt: ring buffer count for stream
* @had_spinlock: driver lock
* @aes_bits: IEC958 status bits
* @buff_done: id of current buffer done intr
* @dev: platoform device handle
* @kctl: holds kctl ptrs used for channel map
* @chmap: holds channel map info
* @audio_reg_base: hdmi audio register base offset
* @hw_silence: flag indicates SoC support for HW silence/Keep alive
* @ops: holds ops functions based on platform
* @underrun_count: PCM stream underrun counter
*/
struct
snd_intelhad
{
struct
snd_card
*
card
;
int
card_index
;
char
*
card_id
;
struct
hdmi_audio_registers_ops
reg_ops
;
struct
hdmi_audio_query_set_ops
query_ops
;
enum
had_drv_status
drv_status
;
bool
connected
;
struct
ring_buf_info
buf_info
[
HAD_NUM_OF_RING_BUFS
];
struct
pcm_stream_info
stream_info
;
un
ion
otm_hdmi_eld_t
eeld
;
un
signed
char
eld
[
HDMI_MAX_ELD_BYTES
]
;
bool
dp_output
;
enum
intel_had_aud_buf_type
curr_buf
;
int
valid_buf_cnt
;
unsigned
int
aes_bits
;
int
flag_underrun
;
struct
had_pvt_data
*
private_data
;
spinlock_t
had_spinlock
;
enum
intel_had_aud_buf_type
buff_done
;
struct
device
*
dev
;
struct
snd_kcontrol
*
kctl
;
struct
snd_pcm_chmap
*
chmap
;
unsigned
int
*
audio_reg_base
;
unsigned
int
audio_cfg_offset
;
bool
hw_silence
;
struct
had_ops
*
ops
;
int
underrun_count
;
int
tmds_clock_speed
;
int
link_rate
;
/* internal stuff */
int
irq
;
void
__iomem
*
mmio_start
;
unsigned
int
had_config_offset
;
struct
work_struct
hdmi_audio_wq
;
struct
mutex
mutex
;
/* for protecting chmap and eld */
};
struct
had_ops
{
void
(
*
enable_audio
)(
struct
snd_pcm_substream
*
substream
,
u8
enable
);
void
(
*
reset_audio
)(
u8
reset
);
int
(
*
prog_n
)(
u32
aud_samp_freq
,
u32
*
n_param
,
struct
snd_intelhad
*
intelhaddata
);
void
(
*
prog_cts
)(
u32
aud_samp_freq
,
u32
tmds
,
u32
link_rate
,
u32
n_param
,
struct
snd_intelhad
*
intelhaddata
);
int
(
*
audio_ctrl
)(
struct
snd_pcm_substream
*
substream
,
struct
snd_intelhad
*
intelhaddata
);
void
(
*
prog_dip
)(
struct
snd_pcm_substream
*
substream
,
struct
snd_intelhad
*
intelhaddata
);
void
(
*
handle_underrun
)(
struct
snd_intelhad
*
intelhaddata
);
};
int
had_event_handler
(
enum
had_event_type
event_type
,
void
*
data
);
int
hdmi_audio_query
(
void
*
drv_data
,
struct
hdmi_audio_event
event
);
int
hdmi_audio_suspend
(
void
*
drv_data
,
struct
hdmi_audio_event
event
);
int
hdmi_audio_resume
(
void
*
drv_data
);
int
hdmi_audio_mode_change
(
struct
snd_pcm_substream
*
substream
);
extern
struct
snd_pcm_ops
snd_intelhad_playback_ops
;
int
snd_intelhad_init_audio_ctrl
(
struct
snd_pcm_substream
*
substream
,
struct
snd_intelhad
*
intelhaddata
,
int
flag_silence
);
int
snd_intelhad_prog_buffer
(
struct
snd_intelhad
*
intelhaddata
,
int
start
,
int
end
);
int
snd_intelhad_invd_buffer
(
int
start
,
int
end
);
int
snd_intelhad_read_len
(
struct
snd_intelhad
*
intelhaddata
);
void
had_build_channel_allocation_map
(
struct
snd_intelhad
*
intelhaddata
);
/* Register access functions */
int
had_get_hwstate
(
struct
snd_intelhad
*
intelhaddata
);
int
had_get_caps
(
enum
had_caps_list
query_element
,
void
*
capabilties
);
int
had_set_caps
(
enum
had_caps_list
set_element
,
void
*
capabilties
);
int
had_read_register
(
u32
reg_addr
,
u32
*
data
);
int
had_write_register
(
u32
reg_addr
,
u32
data
);
int
had_read_modify
(
u32
reg_addr
,
u32
data
,
u32
mask
);
int
hdmi_audio_probe
(
void
*
devptr
);
int
hdmi_audio_remove
(
void
*
pdev
);
#endif
/* _INTEL_HDMI_AUDIO_ */
sound/x86/intel_hdmi_audio_if.c
已删除
100644 → 0
浏览文件 @
374a5040
/*
* intel_hdmi_audio_if.c - Intel HDMI audio driver for MID
*
* Copyright (C) 2016 Intel Corp
* Authors: Sailaja Bandarupalli <sailaja.bandarupalli@intel.com>
* Ramesh Babu K V <ramesh.babu@intel.com>
* Vaibhav Agarwal <vaibhav.agarwal@intel.com>
* Jerome Anand <jerome.anand@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 published by
* the Free Software Foundation; version 2 of the License.
*
* 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.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* ALSA driver for Intel MID HDMI audio controller. This file contains
* interface functions exposed to HDMI Display driver and code to register
* with ALSA framework..
*/
#define pr_fmt(fmt) "had: " fmt
#include <linux/io.h>
#include <linux/jiffies.h>
#include <linux/slab.h>
#include <sound/pcm.h>
#include <sound/core.h>
#include "intel_hdmi_audio.h"
#include "intel_hdmi_lpe_audio.h"
/**
* hdmi_audio_query - hdmi audio query function
*
*@haddata: pointer to HAD private data
*@event: audio event for which this method is invoked
*
* This function is called by client driver to query the
* hdmi audio.
*/
int
hdmi_audio_query
(
void
*
haddata
,
struct
hdmi_audio_event
event
)
{
struct
snd_pcm_substream
*
substream
=
NULL
;
struct
had_pvt_data
*
had_stream
;
unsigned
long
flag_irqs
;
struct
snd_intelhad
*
intelhaddata
=
(
struct
snd_intelhad
*
)
haddata
;
if
(
intelhaddata
->
stream_info
.
had_substream
)
substream
=
intelhaddata
->
stream_info
.
had_substream
;
had_stream
=
intelhaddata
->
private_data
;
switch
(
event
.
type
)
{
case
HAD_EVENT_QUERY_IS_AUDIO_BUSY
:
spin_lock_irqsave
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
if
((
had_stream
->
stream_type
==
HAD_RUNNING_STREAM
)
||
substream
)
{
spin_unlock_irqrestore
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
pr_debug
(
"Audio stream active
\n
"
);
return
-
EBUSY
;
}
spin_unlock_irqrestore
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
break
;
case
HAD_EVENT_QUERY_IS_AUDIO_SUSPENDED
:
spin_lock_irqsave
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
if
(
intelhaddata
->
drv_status
==
HAD_DRV_SUSPENDED
)
{
spin_unlock_irqrestore
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
pr_debug
(
"Audio is suspended
\n
"
);
return
1
;
}
spin_unlock_irqrestore
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
break
;
default:
pr_debug
(
"error un-handled event !!
\n
"
);
return
-
EINVAL
;
break
;
}
return
0
;
}
/**
* hdmi_audio_suspend - power management suspend function
*
*@haddata: pointer to HAD private data
*@event: pm event for which this method is invoked
*
* This function is called by client driver to suspend the
* hdmi audio.
*/
int
hdmi_audio_suspend
(
void
*
haddata
,
struct
hdmi_audio_event
event
)
{
int
caps
,
retval
=
0
;
struct
had_pvt_data
*
had_stream
;
unsigned
long
flag_irqs
;
struct
snd_pcm_substream
*
substream
;
struct
snd_intelhad
*
intelhaddata
=
(
struct
snd_intelhad
*
)
haddata
;
pr_debug
(
"Enter:%s
\n
"
,
__func__
);
had_stream
=
intelhaddata
->
private_data
;
substream
=
intelhaddata
->
stream_info
.
had_substream
;
if
(
intelhaddata
->
dev
->
power
.
runtime_status
!=
RPM_SUSPENDED
)
{
pr_err
(
"audio stream is active
\n
"
);
return
-
EAGAIN
;
}
spin_lock_irqsave
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
if
(
intelhaddata
->
drv_status
==
HAD_DRV_DISCONNECTED
)
{
spin_unlock_irqrestore
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
pr_debug
(
"had not connected
\n
"
);
return
retval
;
}
if
(
intelhaddata
->
drv_status
==
HAD_DRV_SUSPENDED
)
{
spin_unlock_irqrestore
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
pr_debug
(
"had already suspended
\n
"
);
return
retval
;
}
intelhaddata
->
drv_status
=
HAD_DRV_SUSPENDED
;
pr_debug
(
"%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_SUSPENDED
\n
"
,
__func__
,
__LINE__
);
spin_unlock_irqrestore
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
/*
* ToDo: Need to disable UNDERRUN interrupts as well
* caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE;
*/
caps
=
HDMI_AUDIO_BUFFER_DONE
;
had_set_caps
(
HAD_SET_DISABLE_AUDIO_INT
,
&
caps
);
had_set_caps
(
HAD_SET_DISABLE_AUDIO
,
NULL
);
pr_debug
(
"Exit:%s"
,
__func__
);
return
retval
;
}
/**
* hdmi_audio_resume - power management resume function
*
*@haddata: pointer to HAD private data
*
* This function is called by client driver to resume the
* hdmi audio.
*/
int
hdmi_audio_resume
(
void
*
haddata
)
{
int
caps
,
retval
=
0
;
struct
snd_intelhad
*
intelhaddata
=
(
struct
snd_intelhad
*
)
haddata
;
unsigned
long
flag_irqs
;
pr_debug
(
"Enter:%s
\n
"
,
__func__
);
spin_lock_irqsave
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
if
(
intelhaddata
->
drv_status
==
HAD_DRV_DISCONNECTED
)
{
spin_unlock_irqrestore
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
pr_debug
(
"had not connected
\n
"
);
return
0
;
}
if
(
intelhaddata
->
drv_status
!=
HAD_DRV_SUSPENDED
)
{
spin_unlock_irqrestore
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
pr_err
(
"had is not in suspended state
\n
"
);
return
0
;
}
if
(
had_get_hwstate
(
intelhaddata
))
{
spin_unlock_irqrestore
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
pr_err
(
"Failed to resume. Device not accessible
\n
"
);
return
-
ENODEV
;
}
intelhaddata
->
drv_status
=
HAD_DRV_CONNECTED
;
pr_debug
(
"%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED
\n
"
,
__func__
,
__LINE__
);
spin_unlock_irqrestore
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
/*
* ToDo: Need to enable UNDERRUN interrupts as well
* caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE;
*/
caps
=
HDMI_AUDIO_BUFFER_DONE
;
retval
=
had_set_caps
(
HAD_SET_ENABLE_AUDIO_INT
,
&
caps
);
retval
=
had_set_caps
(
HAD_SET_ENABLE_AUDIO
,
NULL
);
pr_debug
(
"Exit:%s"
,
__func__
);
return
retval
;
}
static
inline
int
had_chk_intrmiss
(
struct
snd_intelhad
*
intelhaddata
,
enum
intel_had_aud_buf_type
buf_id
)
{
int
i
,
intr_count
=
0
;
enum
intel_had_aud_buf_type
buff_done
;
u32
buf_size
,
buf_addr
;
struct
had_pvt_data
*
had_stream
;
unsigned
long
flag_irqs
;
had_stream
=
intelhaddata
->
private_data
;
buff_done
=
buf_id
;
intr_count
=
snd_intelhad_read_len
(
intelhaddata
);
if
(
intr_count
>
1
)
{
/* In case of active playback */
pr_err
(
"Driver detected %d missed buffer done interrupt(s)!!!!
\n
"
,
(
intr_count
-
1
));
if
(
intr_count
>
3
)
return
intr_count
;
buf_id
+=
(
intr_count
-
1
);
/* Reprogram registers*/
for
(
i
=
buff_done
;
i
<
buf_id
;
i
++
)
{
int
j
=
i
%
4
;
buf_size
=
intelhaddata
->
buf_info
[
j
].
buf_size
;
buf_addr
=
intelhaddata
->
buf_info
[
j
].
buf_addr
;
had_write_register
(
AUD_BUF_A_LENGTH
+
(
j
*
HAD_REG_WIDTH
),
buf_size
);
had_write_register
(
AUD_BUF_A_ADDR
+
(
j
*
HAD_REG_WIDTH
),
(
buf_addr
|
BIT
(
0
)
|
BIT
(
1
)));
}
buf_id
=
buf_id
%
4
;
spin_lock_irqsave
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
intelhaddata
->
buff_done
=
buf_id
;
spin_unlock_irqrestore
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
}
return
intr_count
;
}
int
had_process_buffer_done
(
struct
snd_intelhad
*
intelhaddata
)
{
u32
len
=
1
;
enum
intel_had_aud_buf_type
buf_id
;
enum
intel_had_aud_buf_type
buff_done
;
struct
pcm_stream_info
*
stream
;
u32
buf_size
;
struct
had_pvt_data
*
had_stream
;
int
intr_count
;
enum
had_status_stream
stream_type
;
unsigned
long
flag_irqs
;
had_stream
=
intelhaddata
->
private_data
;
stream
=
&
intelhaddata
->
stream_info
;
intr_count
=
1
;
spin_lock_irqsave
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
if
(
intelhaddata
->
drv_status
==
HAD_DRV_DISCONNECTED
)
{
spin_unlock_irqrestore
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
pr_err
(
"%s:Device already disconnected
\n
"
,
__func__
);
return
0
;
}
buf_id
=
intelhaddata
->
curr_buf
;
intelhaddata
->
buff_done
=
buf_id
;
buff_done
=
intelhaddata
->
buff_done
;
buf_size
=
intelhaddata
->
buf_info
[
buf_id
].
buf_size
;
stream_type
=
had_stream
->
stream_type
;
pr_debug
(
"Enter:%s buf_id=%d
\n
"
,
__func__
,
buf_id
);
/* Every debug statement has an implication
* of ~5msec. Thus, avoid having >3 debug statements
* for each buffer_done handling.
*/
/* Check for any intr_miss in case of active playback */
if
(
had_stream
->
stream_type
==
HAD_RUNNING_STREAM
)
{
spin_unlock_irqrestore
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
intr_count
=
had_chk_intrmiss
(
intelhaddata
,
buf_id
);
if
(
!
intr_count
||
(
intr_count
>
3
))
{
pr_err
(
"HAD SW state in non-recoverable!!! mode
\n
"
);
pr_err
(
"Already played stale data
\n
"
);
return
0
;
}
buf_id
+=
(
intr_count
-
1
);
buf_id
=
buf_id
%
4
;
spin_lock_irqsave
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
}
intelhaddata
->
buf_info
[
buf_id
].
is_valid
=
true
;
if
(
intelhaddata
->
valid_buf_cnt
-
1
==
buf_id
)
{
if
(
had_stream
->
stream_type
>=
HAD_RUNNING_STREAM
)
intelhaddata
->
curr_buf
=
HAD_BUF_TYPE_A
;
}
else
intelhaddata
->
curr_buf
=
buf_id
+
1
;
spin_unlock_irqrestore
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
if
(
had_get_hwstate
(
intelhaddata
))
{
pr_err
(
"HDMI cable plugged-out
\n
"
);
return
0
;
}
/*Reprogram the registers with addr and length*/
had_write_register
(
AUD_BUF_A_LENGTH
+
(
buf_id
*
HAD_REG_WIDTH
),
buf_size
);
had_write_register
(
AUD_BUF_A_ADDR
+
(
buf_id
*
HAD_REG_WIDTH
),
intelhaddata
->
buf_info
[
buf_id
].
buf_addr
|
BIT
(
0
)
|
BIT
(
1
));
had_read_register
(
AUD_BUF_A_LENGTH
+
(
buf_id
*
HAD_REG_WIDTH
),
&
len
);
pr_debug
(
"%s:Enabled buf[%d]
\n
"
,
__func__
,
buf_id
);
/* In case of actual data,
* report buffer_done to above ALSA layer
*/
buf_size
=
intelhaddata
->
buf_info
[
buf_id
].
buf_size
;
if
(
stream_type
>=
HAD_RUNNING_STREAM
)
{
intelhaddata
->
stream_info
.
buffer_rendered
+=
(
intr_count
*
buf_size
);
stream
->
period_elapsed
(
stream
->
had_substream
);
}
return
0
;
}
int
had_process_buffer_underrun
(
struct
snd_intelhad
*
intelhaddata
)
{
enum
intel_had_aud_buf_type
buf_id
;
struct
pcm_stream_info
*
stream
;
struct
had_pvt_data
*
had_stream
;
enum
had_status_stream
stream_type
;
unsigned
long
flag_irqs
;
int
drv_status
;
had_stream
=
intelhaddata
->
private_data
;
stream
=
&
intelhaddata
->
stream_info
;
spin_lock_irqsave
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
buf_id
=
intelhaddata
->
curr_buf
;
stream_type
=
had_stream
->
stream_type
;
intelhaddata
->
buff_done
=
buf_id
;
drv_status
=
intelhaddata
->
drv_status
;
if
(
stream_type
==
HAD_RUNNING_STREAM
)
intelhaddata
->
curr_buf
=
HAD_BUF_TYPE_A
;
spin_unlock_irqrestore
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
pr_debug
(
"Enter:%s buf_id=%d, stream_type=%d
\n
"
,
__func__
,
buf_id
,
stream_type
);
intelhaddata
->
ops
->
handle_underrun
(
intelhaddata
);
if
(
drv_status
==
HAD_DRV_DISCONNECTED
)
{
pr_err
(
"%s:Device already disconnected
\n
"
,
__func__
);
return
0
;
}
if
(
stream_type
==
HAD_RUNNING_STREAM
)
{
/* Report UNDERRUN error to above layers */
intelhaddata
->
flag_underrun
=
1
;
stream
->
period_elapsed
(
stream
->
had_substream
);
}
return
0
;
}
int
had_process_hot_plug
(
struct
snd_intelhad
*
intelhaddata
)
{
enum
intel_had_aud_buf_type
buf_id
;
struct
snd_pcm_substream
*
substream
;
struct
had_pvt_data
*
had_stream
;
unsigned
long
flag_irqs
;
pr_debug
(
"Enter:%s
\n
"
,
__func__
);
substream
=
intelhaddata
->
stream_info
.
had_substream
;
had_stream
=
intelhaddata
->
private_data
;
spin_lock_irqsave
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
if
(
intelhaddata
->
drv_status
==
HAD_DRV_CONNECTED
)
{
pr_debug
(
"Device already connected
\n
"
);
spin_unlock_irqrestore
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
return
0
;
}
buf_id
=
intelhaddata
->
curr_buf
;
intelhaddata
->
buff_done
=
buf_id
;
intelhaddata
->
drv_status
=
HAD_DRV_CONNECTED
;
pr_debug
(
"%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED
\n
"
,
__func__
,
__LINE__
);
spin_unlock_irqrestore
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
pr_debug
(
"Processing HOT_PLUG, buf_id = %d
\n
"
,
buf_id
);
/* Query display driver for audio register base */
if
(
intelhaddata
->
reg_ops
.
hdmi_audio_get_register_base
(
&
intelhaddata
->
audio_reg_base
,
&
intelhaddata
->
audio_cfg_offset
))
{
pr_err
(
"Unable to get audio reg base from Display driver
\n
"
);
goto
err
;
}
if
(
intelhaddata
->
audio_reg_base
==
NULL
)
{
pr_err
(
"audio reg base value is NULL
\n
"
);
goto
err
;
}
pr_debug
(
"%s audio_reg_base = 0x%p
\n
"
,
__func__
,
intelhaddata
->
audio_reg_base
);
/* Safety check */
if
(
substream
)
{
pr_debug
(
"There should not be active PB from ALSA
\n
"
);
pr_debug
(
"Signifies, cable is plugged-in even before
\n
"
);
pr_debug
(
"processing snd_pcm_disconnect
\n
"
);
/* Set runtime->state to hw_params done */
snd_pcm_stop
(
substream
,
SNDRV_PCM_STATE_SETUP
);
}
had_build_channel_allocation_map
(
intelhaddata
);
return
0
;
err:
pm_runtime_disable
(
intelhaddata
->
dev
);
intelhaddata
->
dev
=
NULL
;
return
0
;
}
int
had_process_hot_unplug
(
struct
snd_intelhad
*
intelhaddata
)
{
int
caps
,
retval
=
0
;
enum
intel_had_aud_buf_type
buf_id
;
struct
had_pvt_data
*
had_stream
;
unsigned
long
flag_irqs
;
pr_debug
(
"Enter:%s
\n
"
,
__func__
);
had_stream
=
intelhaddata
->
private_data
;
buf_id
=
intelhaddata
->
curr_buf
;
spin_lock_irqsave
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
if
(
intelhaddata
->
drv_status
==
HAD_DRV_DISCONNECTED
)
{
pr_debug
(
"Device already disconnected
\n
"
);
spin_unlock_irqrestore
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
return
retval
;
}
else
{
/* Disable Audio */
caps
=
HDMI_AUDIO_BUFFER_DONE
;
retval
=
had_set_caps
(
HAD_SET_DISABLE_AUDIO_INT
,
&
caps
);
retval
=
had_set_caps
(
HAD_SET_DISABLE_AUDIO
,
NULL
);
intelhaddata
->
ops
->
enable_audio
(
intelhaddata
->
stream_info
.
had_substream
,
0
);
}
intelhaddata
->
drv_status
=
HAD_DRV_DISCONNECTED
;
pr_debug
(
"%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED
\n
"
,
__func__
,
__LINE__
);
/* Report to above ALSA layer */
if
(
intelhaddata
->
stream_info
.
had_substream
!=
NULL
)
{
spin_unlock_irqrestore
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
pr_debug
(
"%s: unlock -> sending pcm_stop -> lock
\n
"
,
__func__
);
snd_pcm_stop
(
intelhaddata
->
stream_info
.
had_substream
,
SNDRV_PCM_STATE_DISCONNECTED
);
spin_lock_irqsave
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
}
had_stream
->
stream_type
=
HAD_INIT
;
spin_unlock_irqrestore
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
kfree
(
intelhaddata
->
chmap
->
chmap
);
intelhaddata
->
chmap
->
chmap
=
NULL
;
intelhaddata
->
audio_reg_base
=
NULL
;
pr_debug
(
"%s: unlocked -> returned
\n
"
,
__func__
);
return
retval
;
}
/**
* had_event_handler - Call back function to handle events
*
* @event_type: Event type to handle
* @data: data related to the event_type
*
* This function is invoked to handle HDMI events from client driver.
*/
int
had_event_handler
(
enum
had_event_type
event_type
,
void
*
data
)
{
int
retval
=
0
;
struct
snd_intelhad
*
intelhaddata
=
data
;
enum
intel_had_aud_buf_type
buf_id
;
struct
snd_pcm_substream
*
substream
;
struct
had_pvt_data
*
had_stream
;
unsigned
long
flag_irqs
;
buf_id
=
intelhaddata
->
curr_buf
;
had_stream
=
intelhaddata
->
private_data
;
/* Switching to a function can drop atomicity even in INTR context.
* Thus, a big lock is acquired to maintain atomicity.
* This can be optimized later.
* Currently, only buffer_done/_underrun executes in INTR context.
* Also, locking is implemented separately to avoid real contention
* of data(struct intelhaddata) between IRQ/SOFT_IRQ/PROCESS context.
*/
substream
=
intelhaddata
->
stream_info
.
had_substream
;
switch
(
event_type
)
{
case
HAD_EVENT_AUDIO_BUFFER_DONE
:
retval
=
had_process_buffer_done
(
intelhaddata
);
break
;
case
HAD_EVENT_AUDIO_BUFFER_UNDERRUN
:
retval
=
had_process_buffer_underrun
(
intelhaddata
);
break
;
case
HAD_EVENT_HOT_PLUG
:
retval
=
had_process_hot_plug
(
intelhaddata
);
break
;
case
HAD_EVENT_HOT_UNPLUG
:
retval
=
had_process_hot_unplug
(
intelhaddata
);
break
;
case
HAD_EVENT_MODE_CHANGING
:
pr_debug
(
" called _event_handler with _MODE_CHANGE event
\n
"
);
/* Process only if stream is active & cable Plugged-in */
spin_lock_irqsave
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
if
(
intelhaddata
->
drv_status
>=
HAD_DRV_DISCONNECTED
)
{
spin_unlock_irqrestore
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
break
;
}
spin_unlock_irqrestore
(
&
intelhaddata
->
had_spinlock
,
flag_irqs
);
if
((
had_stream
->
stream_type
==
HAD_RUNNING_STREAM
)
&&
substream
)
retval
=
hdmi_audio_mode_change
(
substream
);
break
;
default:
pr_debug
(
"error un-handled event !!
\n
"
);
retval
=
-
EINVAL
;
break
;
}
return
retval
;
}
sound/x86/intel_hdmi_lpe_audio.c
已删除
100644 → 0
浏览文件 @
374a5040
/*
* intel_hdmi_lpe_audio.c - Intel HDMI LPE audio driver for Atom platforms
*
* Copyright (C) 2016 Intel Corp
* Authors:
* Jerome Anand <jerome.anand@intel.com>
* Aravind Siddappaji <aravindx.siddappaji@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 published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <linux/platform_device.h>
#include <linux/irqreturn.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/initval.h>
#include <sound/control.h>
#include <sound/initval.h>
#include <drm/intel_lpe_audio.h>
#include "intel_hdmi_lpe_audio.h"
#include "intel_hdmi_audio.h"
/* globals*/
static
struct
platform_device
*
hlpe_pdev
;
static
int
hlpe_state
;
static
union
otm_hdmi_eld_t
hlpe_eld
;
struct
hdmi_lpe_audio_ctx
{
int
irq
;
void
__iomem
*
mmio_start
;
had_event_call_back
had_event_callbacks
;
struct
snd_intel_had_interface
*
had_interface
;
void
*
had_pvt_data
;
int
tmds_clock_speed
;
bool
dp_output
;
int
link_rate
;
unsigned
int
had_config_offset
;
int
hdmi_audio_interrupt_mask
;
struct
work_struct
hdmi_audio_wq
;
};
static
void
hdmi_set_eld
(
void
*
eld
)
{
int
size
;
BUILD_BUG_ON
(
sizeof
(
hlpe_eld
)
>
HDMI_MAX_ELD_BYTES
);
size
=
sizeof
(
hlpe_eld
);
memcpy
((
void
*
)
&
hlpe_eld
,
eld
,
size
);
}
static
int
hdmi_get_eld
(
void
*
eld
)
{
u8
*
eld_data
=
(
u8
*
)
&
hlpe_eld
;
memcpy
(
eld
,
(
void
*
)
&
hlpe_eld
,
sizeof
(
hlpe_eld
));
print_hex_dump_bytes
(
"eld: "
,
DUMP_PREFIX_NONE
,
eld_data
,
sizeof
(
hlpe_eld
));
return
0
;
}
static
struct
hdmi_lpe_audio_ctx
*
get_hdmi_context
(
void
)
{
struct
hdmi_lpe_audio_ctx
*
ctx
;
ctx
=
platform_get_drvdata
(
hlpe_pdev
);
return
ctx
;
}
/*
* return whether HDMI audio device is busy.
*/
bool
mid_hdmi_audio_is_busy
(
void
*
ddev
)
{
struct
hdmi_lpe_audio_ctx
*
ctx
;
int
hdmi_audio_busy
=
0
;
struct
hdmi_audio_event
hdmi_audio_event
;
dev_dbg
(
&
hlpe_pdev
->
dev
,
"%s: Enter"
,
__func__
);
ctx
=
platform_get_drvdata
(
hlpe_pdev
);
if
(
hlpe_state
==
hdmi_connector_status_disconnected
)
{
/* HDMI is not connected, assuming audio device is idle. */
return
false
;
}
if
(
ctx
->
had_interface
)
{
hdmi_audio_event
.
type
=
HAD_EVENT_QUERY_IS_AUDIO_BUSY
;
hdmi_audio_busy
=
ctx
->
had_interface
->
query
(
ctx
->
had_pvt_data
,
hdmi_audio_event
);
return
hdmi_audio_busy
!=
0
;
}
return
false
;
}
/*
* return true if HDMI audio device is suspended/ disconnected
*/
bool
mid_hdmi_audio_suspend
(
void
*
ddev
)
{
struct
hdmi_lpe_audio_ctx
*
ctx
;
struct
hdmi_audio_event
hdmi_audio_event
;
int
ret
=
0
;
ctx
=
platform_get_drvdata
(
hlpe_pdev
);
if
(
hlpe_state
==
hdmi_connector_status_disconnected
)
{
/* HDMI is not connected, assuming audio device
* is suspended already.
*/
return
true
;
}
dev_dbg
(
&
hlpe_pdev
->
dev
,
"%s: hlpe_state %d"
,
__func__
,
hlpe_state
);
if
(
ctx
->
had_interface
)
{
hdmi_audio_event
.
type
=
0
;
ret
=
ctx
->
had_interface
->
suspend
(
ctx
->
had_pvt_data
,
hdmi_audio_event
);
return
(
ret
==
0
)
?
true
:
false
;
}
return
true
;
}
void
mid_hdmi_audio_resume
(
void
*
ddev
)
{
struct
hdmi_lpe_audio_ctx
*
ctx
;
ctx
=
platform_get_drvdata
(
hlpe_pdev
);
if
(
hlpe_state
==
hdmi_connector_status_disconnected
)
{
/* HDMI is not connected, there is no need
* to resume audio device.
*/
return
;
}
dev_dbg
(
&
hlpe_pdev
->
dev
,
"%s: hlpe_state %d"
,
__func__
,
hlpe_state
);
if
(
ctx
->
had_interface
)
ctx
->
had_interface
->
resume
(
ctx
->
had_pvt_data
);
}
void
mid_hdmi_audio_signal_event
(
enum
had_event_type
event
)
{
struct
hdmi_lpe_audio_ctx
*
ctx
;
dev_dbg
(
&
hlpe_pdev
->
dev
,
"%s: Enter
\n
"
,
__func__
);
ctx
=
platform_get_drvdata
(
hlpe_pdev
);
/* The handler is protected in the respective
* event handlers to avoid races
*/
if
(
ctx
->
had_event_callbacks
)
(
*
ctx
->
had_event_callbacks
)(
event
,
ctx
->
had_pvt_data
);
}
/**
* used to write into display controller HDMI audio registers.
*/
static
int
hdmi_audio_write
(
u32
reg
,
u32
val
)
{
struct
hdmi_lpe_audio_ctx
*
ctx
;
ctx
=
platform_get_drvdata
(
hlpe_pdev
);
dev_dbg
(
&
hlpe_pdev
->
dev
,
"%s: reg[0x%x] = 0x%x
\n
"
,
__func__
,
reg
,
val
);
if
(
ctx
->
dp_output
)
{
if
((
reg
==
AUDIO_HDMI_CONFIG_A
)
||
(
reg
==
AUDIO_HDMI_CONFIG_B
)
||
(
reg
==
AUDIO_HDMI_CONFIG_C
))
{
if
(
val
&
AUD_CONFIG_VALID_BIT
)
val
=
val
|
AUD_CONFIG_DP_MODE
|
AUD_CONFIG_BLOCK_BIT
;
}
}
iowrite32
(
val
,
(
ctx
->
mmio_start
+
reg
));
return
0
;
}
/**
* used to get the register value read from
* display controller HDMI audio registers.
*/
static
int
hdmi_audio_read
(
u32
reg
,
u32
*
val
)
{
struct
hdmi_lpe_audio_ctx
*
ctx
;
ctx
=
platform_get_drvdata
(
hlpe_pdev
);
*
val
=
ioread32
(
ctx
->
mmio_start
+
reg
);
dev_dbg
(
&
hlpe_pdev
->
dev
,
"%s: reg[0x%x] = 0x%x
\n
"
,
__func__
,
reg
,
*
val
);
return
0
;
}
/**
* used to update the masked bits in display controller HDMI
* audio registers.
*/
static
int
hdmi_audio_rmw
(
u32
reg
,
u32
val
,
u32
mask
)
{
struct
hdmi_lpe_audio_ctx
*
ctx
;
u32
val_tmp
=
0
;
ctx
=
platform_get_drvdata
(
hlpe_pdev
);
val_tmp
=
(
val
&
mask
)
|
((
ioread32
(
ctx
->
mmio_start
+
reg
))
&
~
mask
);
if
(
ctx
->
dp_output
)
{
if
((
reg
==
AUDIO_HDMI_CONFIG_A
)
||
(
reg
==
AUDIO_HDMI_CONFIG_B
)
||
(
reg
==
AUDIO_HDMI_CONFIG_C
))
{
if
(
val_tmp
&
AUD_CONFIG_VALID_BIT
)
val_tmp
=
val_tmp
|
AUD_CONFIG_DP_MODE
|
AUD_CONFIG_BLOCK_BIT
;
}
}
iowrite32
(
val_tmp
,
(
ctx
->
mmio_start
+
reg
));
dev_dbg
(
&
hlpe_pdev
->
dev
,
"%s: reg[0x%x] = 0x%x
\n
"
,
__func__
,
reg
,
val_tmp
);
return
0
;
}
/**
* used to return the HDMI audio capabilities.
* e.g. resolution, frame rate.
*/
static
int
hdmi_audio_get_caps
(
enum
had_caps_list
get_element
,
void
*
capabilities
)
{
struct
hdmi_lpe_audio_ctx
*
ctx
;
int
ret
=
0
;
ctx
=
get_hdmi_context
();
dev_dbg
(
&
hlpe_pdev
->
dev
,
"%s: Enter
\n
"
,
__func__
);
switch
(
get_element
)
{
case
HAD_GET_ELD
:
ret
=
hdmi_get_eld
(
capabilities
);
break
;
case
HAD_GET_DISPLAY_RATE
:
/* ToDo: Verify if sampling freq logic is correct */
*
(
u32
*
)
capabilities
=
ctx
->
tmds_clock_speed
;
dev_dbg
(
&
hlpe_pdev
->
dev
,
"%s: tmds_clock_speed = 0x%x
\n
"
,
__func__
,
ctx
->
tmds_clock_speed
);
break
;
case
HAD_GET_LINK_RATE
:
/* ToDo: Verify if sampling freq logic is correct */
*
(
u32
*
)
capabilities
=
ctx
->
link_rate
;
dev_dbg
(
&
hlpe_pdev
->
dev
,
"%s: link rate = 0x%x
\n
"
,
__func__
,
ctx
->
link_rate
);
break
;
case
HAD_GET_DP_OUTPUT
:
*
(
u32
*
)
capabilities
=
ctx
->
dp_output
;
dev_dbg
(
&
hlpe_pdev
->
dev
,
"%s: dp_output = %d
\n
"
,
__func__
,
ctx
->
dp_output
);
break
;
default:
break
;
}
return
ret
;
}
/**
* used to get the current hdmi base address
*/
int
hdmi_audio_get_register_base
(
u32
**
reg_base
,
u32
*
config_offset
)
{
struct
hdmi_lpe_audio_ctx
*
ctx
;
ctx
=
platform_get_drvdata
(
hlpe_pdev
);
*
reg_base
=
(
u32
*
)(
ctx
->
mmio_start
);
*
config_offset
=
ctx
->
had_config_offset
;
dev_dbg
(
&
hlpe_pdev
->
dev
,
"%s: reg_base = 0x%p, cfg_off = 0x%x
\n
"
,
__func__
,
*
reg_base
,
*
config_offset
);
return
0
;
}
/**
* used to set the HDMI audio capabilities.
* e.g. Audio INT.
*/
int
hdmi_audio_set_caps
(
enum
had_caps_list
set_element
,
void
*
capabilties
)
{
struct
hdmi_lpe_audio_ctx
*
ctx
;
ctx
=
platform_get_drvdata
(
hlpe_pdev
);
dev_dbg
(
&
hlpe_pdev
->
dev
,
"%s: cap_id = 0x%x
\n
"
,
__func__
,
set_element
);
switch
(
set_element
)
{
case
HAD_SET_ENABLE_AUDIO_INT
:
{
u32
status_reg
;
hdmi_audio_read
(
AUD_HDMI_STATUS_v2
+
ctx
->
had_config_offset
,
&
status_reg
);
status_reg
|=
HDMI_AUDIO_BUFFER_DONE
|
HDMI_AUDIO_UNDERRUN
;
hdmi_audio_write
(
AUD_HDMI_STATUS_v2
+
ctx
->
had_config_offset
,
status_reg
);
hdmi_audio_read
(
AUD_HDMI_STATUS_v2
+
ctx
->
had_config_offset
,
&
status_reg
);
}
break
;
default:
break
;
}
return
0
;
}
static
struct
hdmi_audio_registers_ops
hdmi_audio_reg_ops
=
{
.
hdmi_audio_get_register_base
=
hdmi_audio_get_register_base
,
.
hdmi_audio_read_register
=
hdmi_audio_read
,
.
hdmi_audio_write_register
=
hdmi_audio_write
,
.
hdmi_audio_read_modify
=
hdmi_audio_rmw
,
};
static
struct
hdmi_audio_query_set_ops
hdmi_audio_get_set_ops
=
{
.
hdmi_audio_get_caps
=
hdmi_audio_get_caps
,
.
hdmi_audio_set_caps
=
hdmi_audio_set_caps
,
};
int
mid_hdmi_audio_setup
(
had_event_call_back
audio_callbacks
,
struct
hdmi_audio_registers_ops
*
reg_ops
,
struct
hdmi_audio_query_set_ops
*
query_ops
)
{
struct
hdmi_lpe_audio_ctx
*
ctx
;
ctx
=
platform_get_drvdata
(
hlpe_pdev
);
dev_dbg
(
&
hlpe_pdev
->
dev
,
"%s: called
\n
"
,
__func__
);
reg_ops
->
hdmi_audio_get_register_base
=
(
hdmi_audio_reg_ops
.
hdmi_audio_get_register_base
);
reg_ops
->
hdmi_audio_read_register
=
(
hdmi_audio_reg_ops
.
hdmi_audio_read_register
);
reg_ops
->
hdmi_audio_write_register
=
(
hdmi_audio_reg_ops
.
hdmi_audio_write_register
);
reg_ops
->
hdmi_audio_read_modify
=
(
hdmi_audio_reg_ops
.
hdmi_audio_read_modify
);
query_ops
->
hdmi_audio_get_caps
=
hdmi_audio_get_set_ops
.
hdmi_audio_get_caps
;
query_ops
->
hdmi_audio_set_caps
=
hdmi_audio_get_set_ops
.
hdmi_audio_set_caps
;
ctx
->
had_event_callbacks
=
audio_callbacks
;
return
0
;
}
static
void
_had_wq
(
struct
work_struct
*
work
)
{
mid_hdmi_audio_signal_event
(
HAD_EVENT_HOT_PLUG
);
}
int
mid_hdmi_audio_register
(
struct
snd_intel_had_interface
*
driver
,
void
*
had_data
)
{
struct
hdmi_lpe_audio_ctx
*
ctx
;
ctx
=
platform_get_drvdata
(
hlpe_pdev
);
dev_dbg
(
&
hlpe_pdev
->
dev
,
"%s: called
\n
"
,
__func__
);
ctx
->
had_pvt_data
=
had_data
;
ctx
->
had_interface
=
driver
;
/* The Audio driver is loading now and we need to notify
* it if there is an HDMI device attached
*/
INIT_WORK
(
&
ctx
->
hdmi_audio_wq
,
_had_wq
);
dev_dbg
(
&
hlpe_pdev
->
dev
,
"%s: Scheduling HDMI audio work queue
\n
"
,
__func__
);
schedule_work
(
&
ctx
->
hdmi_audio_wq
);
return
0
;
}
static
irqreturn_t
display_pipe_interrupt_handler
(
int
irq
,
void
*
dev_id
)
{
u32
audio_stat
,
audio_reg
;
struct
hdmi_lpe_audio_ctx
*
ctx
;
dev_dbg
(
&
hlpe_pdev
->
dev
,
"%s: Enter
\n
"
,
__func__
);
ctx
=
platform_get_drvdata
(
hlpe_pdev
);
audio_reg
=
ctx
->
had_config_offset
+
AUD_HDMI_STATUS_v2
;
hdmi_audio_read
(
audio_reg
,
&
audio_stat
);
if
(
audio_stat
&
HDMI_AUDIO_UNDERRUN
)
{
hdmi_audio_write
(
audio_reg
,
HDMI_AUDIO_UNDERRUN
);
mid_hdmi_audio_signal_event
(
HAD_EVENT_AUDIO_BUFFER_UNDERRUN
);
}
if
(
audio_stat
&
HDMI_AUDIO_BUFFER_DONE
)
{
hdmi_audio_write
(
audio_reg
,
HDMI_AUDIO_BUFFER_DONE
);
mid_hdmi_audio_signal_event
(
HAD_EVENT_AUDIO_BUFFER_DONE
);
}
return
IRQ_HANDLED
;
}
static
void
notify_audio_lpe
(
struct
platform_device
*
pdev
)
{
struct
hdmi_lpe_audio_ctx
*
ctx
=
platform_get_drvdata
(
pdev
);
struct
intel_hdmi_lpe_audio_pdata
*
pdata
=
pdev
->
dev
.
platform_data
;
if
(
pdata
->
hdmi_connected
!=
true
)
{
dev_dbg
(
&
pdev
->
dev
,
"%s: Event: HAD_NOTIFY_HOT_UNPLUG
\n
"
,
__func__
);
if
(
hlpe_state
==
hdmi_connector_status_connected
)
{
hlpe_state
=
hdmi_connector_status_disconnected
;
mid_hdmi_audio_signal_event
(
HAD_EVENT_HOT_UNPLUG
);
}
else
dev_dbg
(
&
pdev
->
dev
,
"%s: Already Unplugged!
\n
"
,
__func__
);
}
else
{
struct
intel_hdmi_lpe_audio_eld
*
eld
=
&
pdata
->
eld
;
switch
(
eld
->
pipe_id
)
{
case
0
:
ctx
->
had_config_offset
=
AUDIO_HDMI_CONFIG_A
;
break
;
case
1
:
ctx
->
had_config_offset
=
AUDIO_HDMI_CONFIG_B
;
break
;
case
2
:
ctx
->
had_config_offset
=
AUDIO_HDMI_CONFIG_C
;
break
;
default:
dev_dbg
(
&
pdev
->
dev
,
"Invalid pipe %d
\n
"
,
eld
->
pipe_id
);
break
;
}
hdmi_set_eld
(
eld
->
eld_data
);
mid_hdmi_audio_signal_event
(
HAD_EVENT_HOT_PLUG
);
hlpe_state
=
hdmi_connector_status_connected
;
dev_dbg
(
&
pdev
->
dev
,
"%s: HAD_NOTIFY_ELD : port = %d, tmds = %d
\n
"
,
__func__
,
eld
->
port_id
,
pdata
->
tmds_clock_speed
);
if
(
pdata
->
tmds_clock_speed
)
{
ctx
->
tmds_clock_speed
=
pdata
->
tmds_clock_speed
;
ctx
->
dp_output
=
pdata
->
dp_output
;
ctx
->
link_rate
=
pdata
->
link_rate
;
mid_hdmi_audio_signal_event
(
HAD_EVENT_MODE_CHANGING
);
}
}
}
/**
* hdmi_lpe_audio_probe - start bridge with i915
*
* This function is called when the i915 driver creates the
* hdmi-lpe-audio platform device. Card creation is deferred until a
* hot plug event is received
*/
static
int
hdmi_lpe_audio_probe
(
struct
platform_device
*
pdev
)
{
struct
hdmi_lpe_audio_ctx
*
ctx
;
struct
intel_hdmi_lpe_audio_pdata
*
pdata
;
int
irq
;
struct
resource
*
res_mmio
;
void
__iomem
*
mmio_start
;
int
ret
=
0
;
unsigned
long
flag_irq
;
static
const
struct
pci_device_id
cherryview_ids
[]
=
{
{
PCI_DEVICE
(
0x8086
,
0x22b0
)},
{
PCI_DEVICE
(
0x8086
,
0x22b1
)},
{
PCI_DEVICE
(
0x8086
,
0x22b2
)},
{
PCI_DEVICE
(
0x8086
,
0x22b3
)},
{}
};
dev_dbg
(
&
hlpe_pdev
->
dev
,
"Enter %s
\n
"
,
__func__
);
/*TBD:remove globals*/
hlpe_pdev
=
pdev
;
hlpe_state
=
hdmi_connector_status_disconnected
;
/* get resources */
irq
=
platform_get_irq
(
pdev
,
0
);
if
(
irq
<
0
)
{
dev_err
(
&
hlpe_pdev
->
dev
,
"Could not get irq resource
\n
"
);
return
-
ENODEV
;
}
res_mmio
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
if
(
!
res_mmio
)
{
dev_err
(
&
hlpe_pdev
->
dev
,
"Could not get IO_MEM resources
\n
"
);
return
-
ENXIO
;
}
dev_dbg
(
&
hlpe_pdev
->
dev
,
"%s: mmio_start = 0x%x, mmio_end = 0x%x
\n
"
,
__func__
,
(
unsigned
int
)
res_mmio
->
start
,
(
unsigned
int
)
res_mmio
->
end
);
mmio_start
=
ioremap_nocache
(
res_mmio
->
start
,
(
size_t
)(
resource_size
(
res_mmio
)));
if
(
!
mmio_start
)
{
dev_err
(
&
hlpe_pdev
->
dev
,
"Could not get ioremap
\n
"
);
return
-
EACCES
;
}
/* setup interrupt handler */
ret
=
request_irq
(
irq
,
display_pipe_interrupt_handler
,
0
,
pdev
->
name
,
NULL
);
if
(
ret
<
0
)
{
dev_err
(
&
hlpe_pdev
->
dev
,
"request_irq failed
\n
"
);
iounmap
(
mmio_start
);
return
-
ENODEV
;
}
/* alloc and save context */
ctx
=
kzalloc
(
sizeof
(
*
ctx
),
GFP_KERNEL
);
if
(
ctx
==
NULL
)
{
free_irq
(
irq
,
NULL
);
iounmap
(
mmio_start
);
return
-
ENOMEM
;
}
ctx
->
irq
=
irq
;
dev_dbg
(
&
hlpe_pdev
->
dev
,
"hdmi lpe audio: irq num = %d
\n
"
,
irq
);
ctx
->
mmio_start
=
mmio_start
;
ctx
->
tmds_clock_speed
=
DIS_SAMPLE_RATE_148_5
;
if
(
pci_dev_present
(
cherryview_ids
))
dev_dbg
(
&
hlpe_pdev
->
dev
,
"%s: Cherrytrail LPE - Detected
\n
"
,
__func__
);
else
dev_dbg
(
&
hlpe_pdev
->
dev
,
"%s: Baytrail LPE - Assume
\n
"
,
__func__
);
/* assume pipe A as default */
ctx
->
had_config_offset
=
AUDIO_HDMI_CONFIG_A
;
pdata
=
pdev
->
dev
.
platform_data
;
if
(
pdata
==
NULL
)
{
dev_err
(
&
hlpe_pdev
->
dev
,
"%s: quit: pdata not allocated by i915!!
\n
"
,
__func__
);
kfree
(
ctx
);
free_irq
(
irq
,
NULL
);
iounmap
(
mmio_start
);
return
-
ENOMEM
;
}
platform_set_drvdata
(
pdev
,
ctx
);
ret
=
hdmi_audio_probe
((
void
*
)
pdev
);
dev_dbg
(
&
hlpe_pdev
->
dev
,
"hdmi lpe audio: setting pin eld notify callback
\n
"
);
spin_lock_irqsave
(
&
pdata
->
lpe_audio_slock
,
flag_irq
);
pdata
->
notify_audio_lpe
=
notify_audio_lpe
;
if
(
pdata
->
notify_pending
)
{
dev_dbg
(
&
hlpe_pdev
->
dev
,
"%s: handle pending notification
\n
"
,
__func__
);
notify_audio_lpe
(
pdev
);
pdata
->
notify_pending
=
false
;
}
spin_unlock_irqrestore
(
&
pdata
->
lpe_audio_slock
,
flag_irq
);
return
ret
;
}
/**
* hdmi_lpe_audio_remove - stop bridge with i915
*
* This function is called when the platform device is destroyed. The sound
* card should have been removed on hot plug event.
*/
static
int
hdmi_lpe_audio_remove
(
struct
platform_device
*
pdev
)
{
struct
hdmi_lpe_audio_ctx
*
ctx
;
dev_dbg
(
&
hlpe_pdev
->
dev
,
"Enter %s
\n
"
,
__func__
);
hdmi_audio_remove
(
pdev
);
/* get context, release resources */
ctx
=
platform_get_drvdata
(
pdev
);
iounmap
(
ctx
->
mmio_start
);
free_irq
(
ctx
->
irq
,
NULL
);
kfree
(
ctx
);
return
0
;
}
static
int
hdmi_lpe_audio_suspend
(
struct
platform_device
*
pt_dev
,
pm_message_t
state
)
{
dev_dbg
(
&
hlpe_pdev
->
dev
,
"Enter %s
\n
"
,
__func__
);
mid_hdmi_audio_suspend
(
NULL
);
return
0
;
}
static
int
hdmi_lpe_audio_resume
(
struct
platform_device
*
pt_dev
)
{
dev_dbg
(
&
hlpe_pdev
->
dev
,
"Enter %s
\n
"
,
__func__
);
mid_hdmi_audio_resume
(
NULL
);
return
0
;
}
static
struct
platform_driver
hdmi_lpe_audio_driver
=
{
.
driver
=
{
.
name
=
"hdmi-lpe-audio"
,
},
.
probe
=
hdmi_lpe_audio_probe
,
.
remove
=
hdmi_lpe_audio_remove
,
.
suspend
=
hdmi_lpe_audio_suspend
,
.
resume
=
hdmi_lpe_audio_resume
};
module_platform_driver
(
hdmi_lpe_audio_driver
);
MODULE_LICENSE
(
"GPL v2"
);
MODULE_ALIAS
(
"platform:hdmi_lpe_audio"
);
sound/x86/intel_hdmi_lpe_audio.h
浏览文件 @
c1a7c40c
...
...
@@ -23,19 +23,6 @@
#ifndef __INTEL_HDMI_LPE_AUDIO_H
#define __INTEL_HDMI_LPE_AUDIO_H
#include <linux/types.h>
#include <sound/initval.h>
#include <linux/version.h>
#include <linux/pm_runtime.h>
#include <sound/asoundef.h>
#include <sound/control.h>
#include <sound/pcm.h>
#define AUD_CONFIG_VALID_BIT (1<<9)
#define AUD_CONFIG_DP_MODE (1<<15)
#define AUD_CONFIG_BLOCK_BIT (1<<7)
#define HMDI_LPE_AUDIO_DRIVER_NAME "intel-hdmi-lpe-audio"
#define HAD_MAX_DEVICES 1
#define HAD_MIN_CHANNEL 2
#define HAD_MAX_CHANNEL 8
...
...
@@ -95,164 +82,6 @@
/* Naud Value */
#define DP_NAUD_VAL 32768
/* _AUD_CONFIG register MASK */
#define AUD_CONFIG_MASK_UNDERRUN 0xC0000000
#define AUD_CONFIG_MASK_SRDBG 0x00000002
#define AUD_CONFIG_MASK_FUNCRST 0x00000001
#define MAX_CNT 0xFF
#define HAD_SUSPEND_DELAY 1000
#define OTM_HDMI_ELD_SIZE 128
union
otm_hdmi_eld_t
{
unsigned
char
eld_data
[
OTM_HDMI_ELD_SIZE
];
struct
{
/* Byte[0] = ELD Version Number */
union
{
unsigned
char
byte0
;
struct
{
unsigned
char
reserved
:
3
;
/* Reserf */
unsigned
char
eld_ver
:
5
;
/* ELD Version Number */
/* 00000b - reserved
* 00001b - first rev, obsoleted
* 00010b - version 2, supporting CEA version
* 861D or below
* 00011b:11111b - reserved
* for future
*/
};
};
/* Byte[1] = Vendor Version Field */
union
{
unsigned
char
vendor_version
;
struct
{
unsigned
char
reserved1
:
3
;
unsigned
char
veld_ver
:
5
;
/* Version number of the ELD
* extension. This value is
* provisioned and unique to
* each vendor.
*/
};
};
/* Byte[2] = Baseline Length field */
unsigned
char
baseline_eld_length
;
/* Length of the Baseline structure
* divided by Four.
*/
/* Byte [3] = Reserved for future use */
unsigned
char
byte3
;
/* Starting of the BaseLine EELD structure
* Byte[4] = Monitor Name Length
*/
union
{
unsigned
char
byte4
;
struct
{
unsigned
char
mnl
:
5
;
unsigned
char
cea_edid_rev_id
:
3
;
};
};
/* Byte[5] = Capabilities */
union
{
unsigned
char
capabilities
;
struct
{
unsigned
char
hdcp
:
1
;
/* HDCP support */
unsigned
char
ai_support
:
1
;
/* AI support */
unsigned
char
connection_type
:
2
;
/* Connection type
* 00 - HDMI
* 01 - DP
* 10 -11 Reserved
* for future
* connection types
*/
unsigned
char
sadc
:
4
;
/* Indicates number of 3 bytes
* Short Audio Descriptors.
*/
};
};
/* Byte[6] = Audio Synch Delay */
unsigned
char
audio_synch_delay
;
/* Amount of time reported by the
* sink that the video trails audio
* in milliseconds.
*/
/* Byte[7] = Speaker Allocation Block */
union
{
unsigned
char
speaker_allocation_block
;
struct
{
unsigned
char
flr
:
1
;
/*Front Left and Right channels*/
unsigned
char
lfe
:
1
;
/*Low Frequency Effect channel*/
unsigned
char
fc
:
1
;
/*Center transmission channel*/
unsigned
char
rlr
:
1
;
/*Rear Left and Right channels*/
unsigned
char
rc
:
1
;
/*Rear Center channel*/
unsigned
char
flrc
:
1
;
/*Front left and Right of Center
*transmission channels
*/
unsigned
char
rlrc
:
1
;
/*Rear left and Right of Center
*transmission channels
*/
unsigned
char
reserved3
:
1
;
/* Reserved */
};
};
/* Byte[8 - 15] - 8 Byte port identification value */
unsigned
char
port_id_value
[
8
];
/* Byte[16 - 17] - 2 Byte Manufacturer ID */
unsigned
char
manufacturer_id
[
2
];
/* Byte[18 - 19] - 2 Byte Product ID */
unsigned
char
product_id
[
2
];
/* Byte [20-83] - 64 Bytes of BaseLine Data */
unsigned
char
mn_sand_sads
[
64
];
/* This will include
* - ASCII string of Monitor name
* - List of 3 byte SADs
* - Zero padding
*/
/* Vendor ELD Block should continue here!
* No Vendor ELD block defined as of now.
*/
}
__packed
;
};
/**
* enum had_status - Audio stream states
*
* @STREAM_INIT: Stream initialized
* @STREAM_RUNNING: Stream running
* @STREAM_PAUSED: Stream paused
* @STREAM_DROPPED: Stream dropped
*/
enum
had_stream_status
{
STREAM_INIT
=
0
,
STREAM_RUNNING
=
1
,
STREAM_PAUSED
=
2
,
STREAM_DROPPED
=
3
};
/**
* enum had_status_stream - HAD stream states
*/
enum
had_status_stream
{
HAD_INIT
=
0
,
HAD_RUNNING_STREAM
,
};
enum
had_drv_status
{
HAD_DRV_CONNECTED
,
HAD_DRV_RUNNING
,
HAD_DRV_DISCONNECTED
,
HAD_DRV_SUSPENDED
,
HAD_DRV_ERR
,
};
/* enum intel_had_aud_buf_type - HDMI controller ring buffer types */
enum
intel_had_aud_buf_type
{
HAD_BUF_TYPE_A
=
0
,
...
...
@@ -261,22 +90,15 @@ enum intel_had_aud_buf_type {
HAD_BUF_TYPE_D
=
3
,
};
enum
num_aud_ch
{
CH_STEREO
=
0
,
CH_THREE_FOUR
=
1
,
CH_FIVE_SIX
=
2
,
CH_SEVEN_EIGHT
=
3
};
/* HDMI Controller register offsets - audio domain common */
/* Base address for below regs = 0x65000 */
enum
hdmi_ctrl_reg_offset_common
{
AUDIO_HDMI_CONFIG_A
=
0x000
,
AUDIO_HDMI_CONFIG_A
=
0x000
,
AUDIO_HDMI_CONFIG_B
=
0x800
,
AUDIO_HDMI_CONFIG_C
=
0x900
,
};
/* HDMI controller register offsets */
enum
hdmi_ctrl_reg_offset
_v1
{
enum
hdmi_ctrl_reg_offset
{
AUD_CONFIG
=
0x0
,
AUD_CH_STATUS_0
=
0x08
,
AUD_CH_STATUS_1
=
0x0C
,
...
...
@@ -294,18 +116,8 @@ enum hdmi_ctrl_reg_offset_v1 {
AUD_BUF_D_ADDR
=
0x58
,
AUD_BUF_D_LENGTH
=
0x5c
,
AUD_CNTL_ST
=
0x60
,
AUD_HDMI_STATUS
=
0x68
,
AUD_HDMIW_INFOFR
=
0x114
,
};
/*
* Delta changes in HDMI controller register offsets
* compare to v1 version
*/
enum
hdmi_ctrl_reg_offset_v2
{
AUD_HDMI_STATUS_v2
=
0x64
,
AUD_HDMIW_INFOFR_v2
=
0x68
,
AUD_HDMI_STATUS
=
0x64
,
/* v2 */
AUD_HDMIW_INFOFR
=
0x68
,
/* v2 */
};
/*
...
...
@@ -350,27 +162,8 @@ struct channel_map_table {
int
spk_mask
;
/* speaker position bit mask */
};
/**
* union aud_cfg - Audio configuration
*
* @cfg_regx: individual register bits
* @cfg_regval: full register value
*
*/
/* Audio configuration */
union
aud_cfg
{
struct
{
u32
aud_en
:
1
;
u32
layout
:
1
;
u32
fmt
:
2
;
u32
num_ch
:
2
;
u32
rsvd0
:
1
;
u32
set
:
1
;
u32
flat
:
1
;
u32
val_bit
:
1
;
u32
user_bit
:
1
;
u32
underrun
:
1
;
u32
rsvd1
:
20
;
}
cfg_regx
;
struct
{
u32
aud_en
:
1
;
u32
layout
:
1
;
...
...
@@ -386,17 +179,15 @@ union aud_cfg {
u32
bogus_sample
:
1
;
u32
dp_modei
:
1
;
u32
rsvd
:
16
;
}
cfg_regx_v2
;
u32
cfg_
regval
;
}
regx
;
u32
regval
;
};
/**
* union aud_ch_status_0 - Audio Channel Status 0 Attributes
*
* @status_0_regx:individual register bits
* @status_0_regval:full register value
*
*/
#define AUD_CONFIG_BLOCK_BIT (1 << 7)
#define AUD_CONFIG_VALID_BIT (1 << 9)
#define AUD_CONFIG_DP_MODE (1 << 15)
/* Audio Channel Status 0 Attributes */
union
aud_ch_status_0
{
struct
{
u32
ch_status
:
1
;
...
...
@@ -410,99 +201,53 @@ union aud_ch_status_0 {
u32
samp_freq
:
4
;
u32
clk_acc
:
2
;
u32
rsvd
:
2
;
}
status_0_
regx
;
u32
status_0_
regval
;
}
regx
;
u32
regval
;
};
/**
* union aud_ch_status_1 - Audio Channel Status 1 Attributes
*
* @status_1_regx: individual register bits
* @status_1_regval: full register value
*
*/
/* Audio Channel Status 1 Attributes */
union
aud_ch_status_1
{
struct
{
u32
max_wrd_len
:
1
;
u32
wrd_len
:
3
;
u32
rsvd
:
28
;
}
status_1_
regx
;
u32
status_1_
regval
;
}
regx
;
u32
regval
;
};
/**
* union aud_hdmi_cts - CTS register
*
* @cts_regx: individual register bits
* @cts_regval: full register value
*
*/
/* CTS register */
union
aud_hdmi_cts
{
struct
{
u32
cts_val
:
20
;
u32
en_cts_prog
:
1
;
u32
rsvd
:
11
;
}
cts_regx
;
struct
{
u32
cts_val
:
24
;
u32
en_cts_prog
:
1
;
u32
rsvd
:
7
;
}
cts_regx_v2
;
u32
cts_
regval
;
}
regx
;
u32
regval
;
};
/**
* union aud_hdmi_n_enable - N register
*
* @n_regx: individual register bits
* @n_regval: full register value
*
*/
/* N register */
union
aud_hdmi_n_enable
{
struct
{
u32
n_val
:
20
;
u32
en_n_prog
:
1
;
u32
rsvd
:
11
;
}
n_regx
;
struct
{
u32
n_val
:
24
;
u32
en_n_prog
:
1
;
u32
rsvd
:
7
;
}
n_regx_v2
;
u32
n_
regval
;
}
regx
;
u32
regval
;
};
/**
* union aud_buf_config - Audio Buffer configurations
*
* @buf_cfg_regx: individual register bits
* @buf_cfgval: full register value
*
*/
/* Audio Buffer configurations */
union
aud_buf_config
{
struct
{
u32
fifo_width
:
8
;
u32
rsvd0
:
8
;
u32
aud_delay
:
8
;
u32
rsvd1
:
8
;
}
buf_cfg_regx
;
struct
{
u32
audio_fifo_watermark
:
8
;
u32
dma_fifo_watermark
:
3
;
u32
rsvd0
:
5
;
u32
aud_delay
:
8
;
u32
rsvd1
:
8
;
}
buf_cfg_regx_v2
;
u32
buf_cf
gval
;
}
regx
;
u32
re
gval
;
};
/**
* union aud_buf_ch_swap - Audio Sample Swapping offset
*
* @buf_ch_swap_regx: individual register bits
* @buf_ch_swap_val: full register value
*
*/
/* Audio Sample Swapping offset */
union
aud_buf_ch_swap
{
struct
{
u32
first_0
:
3
;
...
...
@@ -514,49 +259,31 @@ union aud_buf_ch_swap {
u32
first_3
:
3
;
u32
second_3
:
3
;
u32
rsvd
:
8
;
}
buf_ch_swap_
regx
;
u32
buf_ch_swap_
val
;
}
regx
;
u32
reg
val
;
};
/**
* union aud_buf_addr - Address for Audio Buffer
*
* @buf_addr_regx: individual register bits
* @buf_addr_val: full register value
*
*/
/* Address for Audio Buffer */
union
aud_buf_addr
{
struct
{
u32
valid
:
1
;
u32
intr_en
:
1
;
u32
rsvd
:
4
;
u32
addr
:
26
;
}
buf_addr_
regx
;
u32
buf_addr_
val
;
}
regx
;
u32
reg
val
;
};
/**
* union aud_buf_len - Length of Audio Buffer
*
* @buf_len_regx: individual register bits
* @buf_len_val: full register value
*
*/
/* Length of Audio Buffer */
union
aud_buf_len
{
struct
{
u32
buf_len
:
20
;
u32
rsvd
:
12
;
}
buf_len_
regx
;
u32
buf_len_
val
;
}
regx
;
u32
reg
val
;
};
/**
* union aud_ctrl_st - Audio Control State Register offset
*
* @ctrl_regx: individual register bits
* @ctrl_val: full register value
*
*/
/* Audio Control State Register offset */
union
aud_ctrl_st
{
struct
{
u32
ram_addr
:
4
;
...
...
@@ -569,34 +296,22 @@ union aud_ctrl_st {
u32
dip_idx
:
3
;
u32
dip_en_sta
:
4
;
u32
rsvd
:
7
;
}
ctrl_
regx
;
u32
ctrl_
val
;
}
regx
;
u32
reg
val
;
};
/**
* union aud_info_frame1 - Audio HDMI Widget Data Island Packet offset
*
* @fr1_regx: individual register bits
* @fr1_val: full register value
*
*/
/* Audio HDMI Widget Data Island Packet offset */
union
aud_info_frame1
{
struct
{
u32
pkt_type
:
8
;
u32
ver_num
:
8
;
u32
len
:
5
;
u32
rsvd
:
11
;
}
fr1_
regx
;
u32
fr1_
val
;
}
regx
;
u32
reg
val
;
};
/**
* union aud_info_frame2 - DIP frame 2
*
* @fr2_regx: individual register bits
* @fr2_val: full register value
*
*/
/* DIP frame 2 */
union
aud_info_frame2
{
struct
{
u32
chksum
:
8
;
...
...
@@ -607,17 +322,11 @@ union aud_info_frame2 {
u32
smpl_freq
:
3
;
u32
rsvd1
:
3
;
u32
format
:
8
;
}
fr2_
regx
;
u32
fr2_
val
;
}
regx
;
u32
reg
val
;
};
/**
* union aud_info_frame3 - DIP frame 3
*
* @fr3_regx: individual register bits
* @fr3_val: full register value
*
*/
/* DIP frame 3 */
union
aud_info_frame3
{
struct
{
u32
chnl_alloc
:
8
;
...
...
@@ -625,88 +334,17 @@ union aud_info_frame3 {
u32
lsv
:
4
;
u32
dm_inh
:
1
;
u32
rsvd1
:
16
;
}
fr3_regx
;
u32
fr3_val
;
};
enum
hdmi_connector_status
{
hdmi_connector_status_connected
=
1
,
hdmi_connector_status_disconnected
=
2
,
hdmi_connector_status_unknown
=
3
,
};
#define HDMI_AUDIO_UNDERRUN (1UL<<31)
#define HDMI_AUDIO_BUFFER_DONE (1UL<<29)
#define PORT_ENABLE (1 << 31)
#define SDVO_AUDIO_ENABLE (1 << 6)
enum
had_caps_list
{
HAD_GET_ELD
=
1
,
HAD_GET_DISPLAY_RATE
,
HAD_GET_DP_OUTPUT
,
HAD_GET_LINK_RATE
,
HAD_SET_ENABLE_AUDIO
,
HAD_SET_DISABLE_AUDIO
,
HAD_SET_ENABLE_AUDIO_INT
,
HAD_SET_DISABLE_AUDIO_INT
,
};
enum
had_event_type
{
HAD_EVENT_HOT_PLUG
=
1
,
HAD_EVENT_HOT_UNPLUG
,
HAD_EVENT_MODE_CHANGING
,
HAD_EVENT_AUDIO_BUFFER_DONE
,
HAD_EVENT_AUDIO_BUFFER_UNDERRUN
,
HAD_EVENT_QUERY_IS_AUDIO_BUSY
,
HAD_EVENT_QUERY_IS_AUDIO_SUSPENDED
,
};
/*
* HDMI Display Controller Audio Interface
*
*/
typedef
int
(
*
had_event_call_back
)
(
enum
had_event_type
event_type
,
void
*
ctxt_info
);
struct
hdmi_audio_registers_ops
{
int
(
*
hdmi_audio_get_register_base
)(
u32
**
reg_base
,
u32
*
config_offset
);
int
(
*
hdmi_audio_read_register
)(
u32
reg_addr
,
u32
*
data
);
int
(
*
hdmi_audio_write_register
)(
u32
reg_addr
,
u32
data
);
int
(
*
hdmi_audio_read_modify
)(
u32
reg_addr
,
u32
data
,
u32
mask
);
}
regx
;
u32
regval
;
};
struct
hdmi_audio_query_set_ops
{
int
(
*
hdmi_audio_get_caps
)(
enum
had_caps_list
query_element
,
void
*
capabilties
);
int
(
*
hdmi_audio_set_caps
)(
enum
had_caps_list
set_element
,
void
*
capabilties
);
};
/* AUD_HDMI_STATUS bits */
#define HDMI_AUDIO_UNDERRUN (1U << 31)
#define HDMI_AUDIO_BUFFER_DONE (1U << 29)
struct
hdmi_audio_event
{
int
type
;
};
struct
snd_intel_had_interface
{
const
char
*
name
;
int
(
*
query
)(
void
*
had_data
,
struct
hdmi_audio_event
event
);
int
(
*
suspend
)(
void
*
had_data
,
struct
hdmi_audio_event
event
);
int
(
*
resume
)(
void
*
had_data
);
};
bool
mid_hdmi_audio_is_busy
(
void
*
dev
);
bool
mid_hdmi_audio_suspend
(
void
*
dev
);
void
mid_hdmi_audio_resume
(
void
*
dev
);
void
mid_hdmi_audio_signal_event
(
enum
had_event_type
event
);
int
mid_hdmi_audio_setup
(
had_event_call_back
audio_callbacks
,
struct
hdmi_audio_registers_ops
*
reg_ops
,
struct
hdmi_audio_query_set_ops
*
query_ops
);
int
mid_hdmi_audio_register
(
struct
snd_intel_had_interface
*
driver
,
void
*
had_data
);
/* AUD_HDMI_STATUS register mask */
#define AUD_CONFIG_MASK_UNDERRUN 0xC0000000
#define AUD_CONFIG_MASK_SRDBG 0x00000002
#define AUD_CONFIG_MASK_FUNCRST 0x00000001
#endif
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录