Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
0b0ddfa5
K
Kernel
项目概览
openeuler
/
Kernel
大约 1 年 前同步成功
通知
5
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
Kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
0b0ddfa5
编写于
12月 10, 2012
作者:
M
Mark Brown
浏览文件
操作
浏览文件
下载
差异文件
Merge remote-tracking branch 'asoc/topic/wm0010' into asoc-next
上级
0c0936eb
5d910966
变更
1
显示空白变更内容
内联
并排
Showing
1 changed file
with
248 addition
and
171 deletion
+248
-171
sound/soc/codecs/wm0010.c
sound/soc/codecs/wm0010.c
+248
-171
未找到文件。
sound/soc/codecs/wm0010.c
浏览文件 @
0b0ddfa5
...
...
@@ -31,6 +31,9 @@
#define DEVICE_ID_WM0010 10
/* We only support v1 of the .dfw INFO record */
#define INFO_VERSION 1
enum
dfw_cmd
{
DFW_CMD_FUSE
=
0x01
,
DFW_CMD_CODE_HDR
,
...
...
@@ -46,6 +49,13 @@ struct dfw_binrec {
uint8_t
data
[
0
];
}
__packed
;
struct
dfw_inforec
{
u8
info_version
;
u8
tool_major_version
;
u8
tool_minor_version
;
u8
dsp_target
;
};
struct
dfw_pllrec
{
u8
command
;
u32
length
:
24
;
...
...
@@ -97,7 +107,6 @@ struct wm0010_priv {
enum
wm0010_state
state
;
bool
boot_failed
;
int
boot_done
;
bool
ready
;
bool
pll_running
;
int
max_spi_freq
;
...
...
@@ -234,7 +243,7 @@ static void wm0010_boot_xfer_complete(void *data)
break
;
case
0x55555555
:
if
(
wm0010
->
boot_done
==
0
)
if
(
wm0010
->
state
<
WM0010_STAGE2
)
break
;
dev_err
(
codec
->
dev
,
"%d: ROM bootloader running in stage 2
\n
"
,
i
);
...
...
@@ -321,7 +330,6 @@ static void wm0010_boot_xfer_complete(void *data)
break
;
}
wm0010
->
boot_done
++
;
if
(
xfer
->
done
)
complete
(
xfer
->
done
);
}
...
...
@@ -334,94 +342,198 @@ static void byte_swap_64(u64 *data_in, u64 *data_out, u32 len)
data_out
[
i
]
=
cpu_to_be64
(
le64_to_cpu
(
data_in
[
i
]));
}
static
int
wm0010_
boot
(
struct
snd_soc_codec
*
codec
)
static
int
wm0010_
firmware_load
(
char
*
name
,
struct
snd_soc_codec
*
codec
)
{
struct
spi_device
*
spi
=
to_spi_device
(
codec
->
dev
);
struct
wm0010_priv
*
wm0010
=
snd_soc_codec_get_drvdata
(
codec
);
unsigned
long
flags
;
struct
list_head
xfer_list
;
struct
wm0010_boot_xfer
*
xfer
;
int
ret
;
struct
completion
done
;
const
struct
firmware
*
fw
;
const
struct
dfw_binrec
*
rec
;
struct
spi_message
m
;
struct
spi_transfer
t
;
struct
dfw_pllrec
pll_rec
;
u32
*
img
,
*
p
;
u64
*
img_swap
;
u8
*
out
;
const
struct
dfw_inforec
*
inforec
;
u64
*
img
;
u8
*
out
,
dsp
;
u32
len
,
offset
;
int
i
;
spin_lock_irqsave
(
&
wm0010
->
irq_lock
,
flags
);
if
(
wm0010
->
state
!=
WM0010_POWER_OFF
)
dev_warn
(
wm0010
->
dev
,
"DSP already powered up!
\n
"
);
spin_unlock_irqrestore
(
&
wm0010
->
irq_lock
,
flags
);
INIT_LIST_HEAD
(
&
xfer_list
);
if
(
wm0010
->
sysclk
>
26000000
)
{
dev_err
(
codec
->
dev
,
"Max DSP clock frequency is 26MHz
\n
"
);
ret
=
-
ECANCELED
;
goto
err
;
ret
=
request_firmware
(
&
fw
,
name
,
codec
->
dev
);
if
(
ret
!=
0
)
{
dev_err
(
codec
->
dev
,
"Failed to request application: %d
\n
"
,
ret
);
return
ret
;
}
INIT_LIST_HEAD
(
&
xfer_list
);
rec
=
(
const
struct
dfw_binrec
*
)
fw
->
data
;
inforec
=
(
const
struct
dfw_inforec
*
)
rec
->
data
;
offset
=
0
;
dsp
=
inforec
->
dsp_target
;
wm0010
->
boot_failed
=
false
;
BUG_ON
(
!
list_empty
(
&
xfer_list
));
init_completion
(
&
done
);
mutex_lock
(
&
wm0010
->
lock
);
wm0010
->
pll_running
=
false
;
/* First record should be INFO */
if
(
rec
->
command
!=
DFW_CMD_INFO
)
{
dev_err
(
codec
->
dev
,
"First record not INFO
\r\n
"
);
ret
=
-
EINVAL
;
goto
abort
;
}
dev_dbg
(
codec
->
dev
,
"max_spi_freq: %d
\n
"
,
wm0010
->
max_spi_freq
);
if
(
inforec
->
info_version
!=
INFO_VERSION
)
{
dev_err
(
codec
->
dev
,
"Unsupported version (%02d) of INFO record
\r\n
"
,
inforec
->
info_version
);
ret
=
-
EINVAL
;
goto
abort
;
}
ret
=
regulator_bulk_enable
(
ARRAY_SIZE
(
wm0010
->
core_supplies
),
wm0010
->
core_supplies
);
if
(
ret
!=
0
)
{
dev_err
(
&
spi
->
dev
,
"Failed to enable core supplies: %d
\n
"
,
ret
);
mutex_unlock
(
&
wm0010
->
lock
);
goto
err
;
dev_dbg
(
codec
->
dev
,
"Version v%02d INFO record found
\r\n
"
,
inforec
->
info_version
);
/* Check it's a DSP file */
if
(
dsp
!=
DEVICE_ID_WM0010
)
{
dev_err
(
codec
->
dev
,
"Not a WM0010 firmware file.
\r\n
"
);
ret
=
-
EINVAL
;
goto
abort
;
}
ret
=
regulator_enable
(
wm0010
->
dbvdd
);
/* Skip the info record as we don't need to send it */
offset
+=
((
rec
->
length
)
+
8
);
rec
=
(
void
*
)
&
rec
->
data
[
rec
->
length
];
while
(
offset
<
fw
->
size
)
{
dev_dbg
(
codec
->
dev
,
"Packet: command %d, data length = 0x%x
\r\n
"
,
rec
->
command
,
rec
->
length
);
len
=
rec
->
length
+
8
;
out
=
kzalloc
(
len
,
GFP_KERNEL
);
if
(
!
out
)
{
dev_err
(
codec
->
dev
,
"Failed to allocate RX buffer
\n
"
);
ret
=
-
ENOMEM
;
goto
abort1
;
}
img
=
kzalloc
(
len
,
GFP_KERNEL
);
if
(
!
img
)
{
dev_err
(
codec
->
dev
,
"Failed to allocate image buffer
\n
"
);
ret
=
-
ENOMEM
;
goto
abort1
;
}
byte_swap_64
((
u64
*
)
&
rec
->
command
,
img
,
len
);
xfer
=
kzalloc
(
sizeof
(
*
xfer
),
GFP_KERNEL
);
if
(
!
xfer
)
{
dev_err
(
codec
->
dev
,
"Failed to allocate xfer
\n
"
);
ret
=
-
ENOMEM
;
goto
abort1
;
}
xfer
->
codec
=
codec
;
list_add_tail
(
&
xfer
->
list
,
&
xfer_list
);
spi_message_init
(
&
xfer
->
m
);
xfer
->
m
.
complete
=
wm0010_boot_xfer_complete
;
xfer
->
m
.
context
=
xfer
;
xfer
->
t
.
tx_buf
=
img
;
xfer
->
t
.
rx_buf
=
out
;
xfer
->
t
.
len
=
len
;
xfer
->
t
.
bits_per_word
=
8
;
if
(
!
wm0010
->
pll_running
)
{
xfer
->
t
.
speed_hz
=
wm0010
->
sysclk
/
6
;
}
else
{
xfer
->
t
.
speed_hz
=
wm0010
->
max_spi_freq
;
if
(
wm0010
->
board_max_spi_speed
&&
(
wm0010
->
board_max_spi_speed
<
wm0010
->
max_spi_freq
))
xfer
->
t
.
speed_hz
=
wm0010
->
board_max_spi_speed
;
}
/* Store max usable spi frequency for later use */
wm0010
->
max_spi_freq
=
xfer
->
t
.
speed_hz
;
spi_message_add_tail
(
&
xfer
->
t
,
&
xfer
->
m
);
offset
+=
((
rec
->
length
)
+
8
);
rec
=
(
void
*
)
&
rec
->
data
[
rec
->
length
];
if
(
offset
>=
fw
->
size
)
{
dev_dbg
(
codec
->
dev
,
"All transfers scheduled
\n
"
);
xfer
->
done
=
&
done
;
}
ret
=
spi_async
(
spi
,
&
xfer
->
m
);
if
(
ret
!=
0
)
{
dev_err
(
&
spi
->
dev
,
"Failed to enable DBVDD
: %d
\n
"
,
ret
);
goto
err_core
;
dev_err
(
codec
->
dev
,
"Write failed
: %d
\n
"
,
ret
);
goto
abort1
;
}
/* Release reset */
gpio_set_value_cansleep
(
wm0010
->
gpio_reset
,
!
wm0010
->
gpio_reset_value
);
spin_lock_irqsave
(
&
wm0010
->
irq_lock
,
flags
);
wm0010
->
state
=
WM0010_OUT_OF_RESET
;
spin_unlock_irqrestore
(
&
wm0010
->
irq_lock
,
flags
);
if
(
wm0010
->
boot_failed
)
{
dev_dbg
(
codec
->
dev
,
"Boot fail!
\n
"
);
ret
=
-
EINVAL
;
goto
abort1
;
}
}
wait_for_completion
(
&
done
);
ret
=
0
;
abort1:
while
(
!
list_empty
(
&
xfer_list
))
{
xfer
=
list_first_entry
(
&
xfer_list
,
struct
wm0010_boot_xfer
,
list
);
kfree
(
xfer
->
t
.
rx_buf
);
kfree
(
xfer
->
t
.
tx_buf
);
list_del
(
&
xfer
->
list
);
kfree
(
xfer
);
}
abort:
release_firmware
(
fw
);
return
ret
;
}
static
int
wm0010_stage2_load
(
struct
snd_soc_codec
*
codec
)
{
struct
spi_device
*
spi
=
to_spi_device
(
codec
->
dev
);
struct
wm0010_priv
*
wm0010
=
snd_soc_codec_get_drvdata
(
codec
);
const
struct
firmware
*
fw
;
struct
spi_message
m
;
struct
spi_transfer
t
;
u32
*
img
;
u8
*
out
;
int
i
;
int
ret
=
0
;
/* First the bootloader */
ret
=
request_firmware
(
&
fw
,
"wm0010_stage2.bin"
,
codec
->
dev
);
if
(
ret
!=
0
)
{
dev_err
(
codec
->
dev
,
"Failed to request stage2 loader: %d
\n
"
,
ret
);
goto
abor
t
;
return
re
t
;
}
if
(
!
wait_for_completion_timeout
(
&
wm0010
->
boot_completion
,
msecs_to_jiffies
(
10
)))
dev_err
(
codec
->
dev
,
"Failed to get interrupt from DSP
\n
"
);
spin_lock_irqsave
(
&
wm0010
->
irq_lock
,
flags
);
wm0010
->
state
=
WM0010_BOOTROM
;
spin_unlock_irqrestore
(
&
wm0010
->
irq_lock
,
flags
);
dev_dbg
(
codec
->
dev
,
"Downloading %zu byte stage 2 loader
\n
"
,
fw
->
size
);
/* Copy to local buffer first as vmalloc causes problems for dma */
img
=
kzalloc
(
fw
->
size
,
GFP_KERNEL
);
if
(
!
img
)
{
dev_err
(
codec
->
dev
,
"Failed to allocate image buffer
\n
"
);
goto
abort
;
ret
=
-
ENOMEM
;
goto
abort2
;
}
out
=
kzalloc
(
fw
->
size
,
GFP_KERNEL
);
if
(
!
out
)
{
dev_err
(
codec
->
dev
,
"Failed to allocate output buffer
\n
"
);
goto
abort
;
ret
=
-
ENOMEM
;
goto
abort1
;
}
memcpy
(
img
,
&
fw
->
data
[
0
],
fw
->
size
);
...
...
@@ -447,20 +559,97 @@ static int wm0010_boot(struct snd_soc_codec *codec)
/* Look for errors from the boot ROM */
for
(
i
=
0
;
i
<
fw
->
size
;
i
++
)
{
if
(
out
[
i
]
!=
0x55
)
{
ret
=
-
EBUSY
;
dev_err
(
codec
->
dev
,
"Boot ROM error: %x in %d
\n
"
,
out
[
i
],
i
);
wm0010_mark_boot_failure
(
wm0010
);
ret
=
-
EBUSY
;
goto
abort
;
}
}
release_firmware
(
fw
);
kfree
(
img
);
abort:
kfree
(
out
);
abort1:
kfree
(
img
);
abort2:
release_firmware
(
fw
);
return
ret
;
}
static
int
wm0010_boot
(
struct
snd_soc_codec
*
codec
)
{
struct
spi_device
*
spi
=
to_spi_device
(
codec
->
dev
);
struct
wm0010_priv
*
wm0010
=
snd_soc_codec_get_drvdata
(
codec
);
unsigned
long
flags
;
int
ret
;
const
struct
firmware
*
fw
;
struct
spi_message
m
;
struct
spi_transfer
t
;
struct
dfw_pllrec
pll_rec
;
u32
*
p
,
len
;
u64
*
img_swap
;
u8
*
out
;
int
i
;
spin_lock_irqsave
(
&
wm0010
->
irq_lock
,
flags
);
if
(
wm0010
->
state
!=
WM0010_POWER_OFF
)
dev_warn
(
wm0010
->
dev
,
"DSP already powered up!
\n
"
);
spin_unlock_irqrestore
(
&
wm0010
->
irq_lock
,
flags
);
if
(
wm0010
->
sysclk
>
26000000
)
{
dev_err
(
codec
->
dev
,
"Max DSP clock frequency is 26MHz
\n
"
);
ret
=
-
ECANCELED
;
goto
err
;
}
mutex_lock
(
&
wm0010
->
lock
);
wm0010
->
pll_running
=
false
;
dev_dbg
(
codec
->
dev
,
"max_spi_freq: %d
\n
"
,
wm0010
->
max_spi_freq
);
ret
=
regulator_bulk_enable
(
ARRAY_SIZE
(
wm0010
->
core_supplies
),
wm0010
->
core_supplies
);
if
(
ret
!=
0
)
{
dev_err
(
&
spi
->
dev
,
"Failed to enable core supplies: %d
\n
"
,
ret
);
mutex_unlock
(
&
wm0010
->
lock
);
goto
err
;
}
ret
=
regulator_enable
(
wm0010
->
dbvdd
);
if
(
ret
!=
0
)
{
dev_err
(
&
spi
->
dev
,
"Failed to enable DBVDD: %d
\n
"
,
ret
);
goto
err_core
;
}
/* Release reset */
gpio_set_value_cansleep
(
wm0010
->
gpio_reset
,
!
wm0010
->
gpio_reset_value
);
spin_lock_irqsave
(
&
wm0010
->
irq_lock
,
flags
);
wm0010
->
state
=
WM0010_OUT_OF_RESET
;
spin_unlock_irqrestore
(
&
wm0010
->
irq_lock
,
flags
);
/* First the bootloader */
ret
=
request_firmware
(
&
fw
,
"wm0010_stage2.bin"
,
codec
->
dev
);
if
(
ret
!=
0
)
{
dev_err
(
codec
->
dev
,
"Failed to request stage2 loader: %d
\n
"
,
ret
);
goto
abort
;
}
if
(
!
wait_for_completion_timeout
(
&
wm0010
->
boot_completion
,
msecs_to_jiffies
(
20
)))
dev_err
(
codec
->
dev
,
"Failed to get interrupt from DSP
\n
"
);
spin_lock_irqsave
(
&
wm0010
->
irq_lock
,
flags
);
wm0010
->
state
=
WM0010_BOOTROM
;
spin_unlock_irqrestore
(
&
wm0010
->
irq_lock
,
flags
);
ret
=
wm0010_stage2_load
(
codec
);
if
(
ret
)
goto
abort
;
if
(
!
wait_for_completion_timeout
(
&
wm0010
->
boot_completion
,
msecs_to_jiffies
(
1
0
)))
msecs_to_jiffies
(
2
0
)))
dev_err
(
codec
->
dev
,
"Failed to get interrupt from DSP loader.
\n
"
);
spin_lock_irqsave
(
&
wm0010
->
irq_lock
,
flags
);
...
...
@@ -535,110 +724,10 @@ static int wm0010_boot(struct snd_soc_codec *codec)
}
else
dev_dbg
(
codec
->
dev
,
"Not enabling DSP PLL."
);
ret
=
request_firmware
(
&
fw
,
"wm0010.dfw"
,
codec
->
dev
);
if
(
ret
!=
0
)
{
dev_err
(
codec
->
dev
,
"Failed to request application: %d
\n
"
,
ret
);
goto
abort
;
}
rec
=
(
const
struct
dfw_binrec
*
)
fw
->
data
;
offset
=
0
;
wm0010
->
boot_done
=
0
;
wm0010
->
boot_failed
=
false
;
BUG_ON
(
!
list_empty
(
&
xfer_list
));
init_completion
(
&
done
);
/* First record should be INFO */
if
(
rec
->
command
!=
DFW_CMD_INFO
)
{
dev_err
(
codec
->
dev
,
"First record not INFO
\r\n
"
);
goto
abort
;
}
/* Check it's a 0010 file */
if
(
rec
->
data
[
0
]
!=
DEVICE_ID_WM0010
)
{
dev_err
(
codec
->
dev
,
"Not a WM0010 firmware file.
\r\n
"
);
goto
abort
;
}
/* Skip the info record as we don't need to send it */
offset
+=
((
rec
->
length
)
+
8
);
rec
=
(
void
*
)
&
rec
->
data
[
rec
->
length
];
while
(
offset
<
fw
->
size
)
{
dev_dbg
(
codec
->
dev
,
"Packet: command %d, data length = 0x%x
\r\n
"
,
rec
->
command
,
rec
->
length
);
len
=
rec
->
length
+
8
;
out
=
kzalloc
(
len
,
GFP_KERNEL
);
if
(
!
out
)
{
dev_err
(
codec
->
dev
,
"Failed to allocate RX buffer
\n
"
);
goto
abort
;
}
img_swap
=
kzalloc
(
len
,
GFP_KERNEL
);
if
(
!
img_swap
)
{
dev_err
(
codec
->
dev
,
"Failed to allocate image buffer
\n
"
);
goto
abort
;
}
/* We need to re-order for 0010 */
byte_swap_64
((
u64
*
)
&
rec
->
command
,
img_swap
,
len
);
ret
=
wm0010_firmware_load
(
"wm0010.dfw"
,
codec
);
xfer
=
kzalloc
(
sizeof
(
*
xfer
),
GFP_KERNEL
);
if
(
!
xfer
)
{
dev_err
(
codec
->
dev
,
"Failed to allocate xfer
\n
"
);
if
(
ret
!=
0
)
goto
abort
;
}
xfer
->
codec
=
codec
;
list_add_tail
(
&
xfer
->
list
,
&
xfer_list
);
spi_message_init
(
&
xfer
->
m
);
xfer
->
m
.
complete
=
wm0010_boot_xfer_complete
;
xfer
->
m
.
context
=
xfer
;
xfer
->
t
.
tx_buf
=
img_swap
;
xfer
->
t
.
rx_buf
=
out
;
xfer
->
t
.
len
=
len
;
xfer
->
t
.
bits_per_word
=
8
;
if
(
!
wm0010
->
pll_running
)
{
xfer
->
t
.
speed_hz
=
wm0010
->
sysclk
/
6
;
}
else
{
xfer
->
t
.
speed_hz
=
wm0010
->
max_spi_freq
;
if
(
wm0010
->
board_max_spi_speed
&&
(
wm0010
->
board_max_spi_speed
<
wm0010
->
max_spi_freq
))
xfer
->
t
.
speed_hz
=
wm0010
->
board_max_spi_speed
;
}
/* Store max usable spi frequency for later use */
wm0010
->
max_spi_freq
=
xfer
->
t
.
speed_hz
;
spi_message_add_tail
(
&
xfer
->
t
,
&
xfer
->
m
);
offset
+=
((
rec
->
length
)
+
8
);
rec
=
(
void
*
)
&
rec
->
data
[
rec
->
length
];
if
(
offset
>=
fw
->
size
)
{
dev_dbg
(
codec
->
dev
,
"All transfers scheduled
\n
"
);
xfer
->
done
=
&
done
;
}
ret
=
spi_async
(
spi
,
&
xfer
->
m
);
if
(
ret
!=
0
)
{
dev_err
(
codec
->
dev
,
"Write failed: %d
\n
"
,
ret
);
goto
abort
;
}
if
(
wm0010
->
boot_failed
)
goto
abort
;
}
wait_for_completion
(
&
done
);
spin_lock_irqsave
(
&
wm0010
->
irq_lock
,
flags
);
wm0010
->
state
=
WM0010_FIRMWARE
;
...
...
@@ -646,17 +735,6 @@ static int wm0010_boot(struct snd_soc_codec *codec)
mutex_unlock
(
&
wm0010
->
lock
);
release_firmware
(
fw
);
while
(
!
list_empty
(
&
xfer_list
))
{
xfer
=
list_first_entry
(
&
xfer_list
,
struct
wm0010_boot_xfer
,
list
);
kfree
(
xfer
->
t
.
rx_buf
);
kfree
(
xfer
->
t
.
tx_buf
);
list_del
(
&
xfer
->
list
);
kfree
(
xfer
);
}
return
0
;
abort:
...
...
@@ -784,7 +862,6 @@ static irqreturn_t wm0010_irq(int irq, void *data)
struct
wm0010_priv
*
wm0010
=
data
;
switch
(
wm0010
->
state
)
{
case
WM0010_POWER_OFF
:
case
WM0010_OUT_OF_RESET
:
case
WM0010_BOOTROM
:
case
WM0010_STAGE2
:
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录