Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/intel/avs/skl.c
26583 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
//
3
// Copyright(c) 2021-2022 Intel Corporation
4
//
5
// Authors: Cezary Rojewski <[email protected]>
6
// Amadeusz Slawinski <[email protected]>
7
//
8
9
#include <linux/devcoredump.h>
10
#include <linux/slab.h>
11
#include <sound/hdaudio_ext.h>
12
#include "avs.h"
13
#include "cldma.h"
14
#include "messages.h"
15
#include "registers.h"
16
17
void avs_skl_ipc_interrupt(struct avs_dev *adev)
18
{
19
const struct avs_spec *spec = adev->spec;
20
u32 hipc_ack, hipc_rsp;
21
22
snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset,
23
AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY, 0);
24
25
hipc_ack = snd_hdac_adsp_readl(adev, spec->hipc->ack_offset);
26
hipc_rsp = snd_hdac_adsp_readl(adev, spec->hipc->rsp_offset);
27
28
/* DSP acked host's request. */
29
if (hipc_ack & spec->hipc->ack_done_mask) {
30
complete(&adev->ipc->done_completion);
31
32
/* Tell DSP it has our attention. */
33
snd_hdac_adsp_updatel(adev, spec->hipc->ack_offset, spec->hipc->ack_done_mask,
34
spec->hipc->ack_done_mask);
35
}
36
37
/* DSP sent new response to process */
38
if (hipc_rsp & spec->hipc->rsp_busy_mask) {
39
union avs_reply_msg msg;
40
41
msg.primary = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCT);
42
msg.ext.val = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCTE);
43
44
avs_dsp_process_response(adev, msg.val);
45
46
/* Tell DSP we accepted its message. */
47
snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCT, SKL_ADSP_HIPCT_BUSY,
48
SKL_ADSP_HIPCT_BUSY);
49
}
50
51
snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset,
52
AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY,
53
AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY);
54
}
55
56
static irqreturn_t avs_skl_dsp_interrupt(struct avs_dev *adev)
57
{
58
u32 adspis = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPIS);
59
irqreturn_t ret = IRQ_NONE;
60
61
if (adspis == UINT_MAX)
62
return ret;
63
64
if (adspis & AVS_ADSP_ADSPIS_CLDMA) {
65
hda_cldma_interrupt(&code_loader);
66
ret = IRQ_HANDLED;
67
}
68
69
if (adspis & AVS_ADSP_ADSPIS_IPC) {
70
avs_skl_ipc_interrupt(adev);
71
ret = IRQ_HANDLED;
72
}
73
74
return ret;
75
}
76
77
static int __maybe_unused
78
avs_skl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
79
u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
80
{
81
struct avs_skl_log_state_info *info;
82
u32 size, num_cores = adev->hw_cfg.dsp_cores;
83
int ret, i;
84
85
if (fls_long(resource_mask) > num_cores)
86
return -EINVAL;
87
size = struct_size(info, logs_core, num_cores);
88
info = kzalloc(size, GFP_KERNEL);
89
if (!info)
90
return -ENOMEM;
91
92
info->core_mask = resource_mask;
93
if (enable)
94
for_each_set_bit(i, &resource_mask, num_cores) {
95
info->logs_core[i].enable = enable;
96
info->logs_core[i].min_priority = *priorities++;
97
}
98
else
99
for_each_set_bit(i, &resource_mask, num_cores)
100
info->logs_core[i].enable = enable;
101
102
ret = avs_ipc_set_enable_logs(adev, (u8 *)info, size);
103
kfree(info);
104
if (ret)
105
return AVS_IPC_RET(ret);
106
107
return 0;
108
}
109
110
int avs_skl_log_buffer_offset(struct avs_dev *adev, u32 core)
111
{
112
return core * avs_log_buffer_size(adev);
113
}
114
115
/* fw DbgLogWp registers */
116
#define FW_REGS_DBG_LOG_WP(core) (0x30 + 0x4 * core)
117
118
static int avs_skl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg)
119
{
120
void __iomem *buf;
121
u16 size, write, offset;
122
123
if (!avs_logging_fw(adev))
124
return 0;
125
126
size = avs_log_buffer_size(adev) / 2;
127
write = readl(avs_sram_addr(adev, AVS_FW_REGS_WINDOW) + FW_REGS_DBG_LOG_WP(msg->log.core));
128
/* determine buffer half */
129
offset = (write < size) ? size : 0;
130
131
/* Address is guaranteed to exist in SRAM2. */
132
buf = avs_log_buffer_addr(adev, msg->log.core) + offset;
133
avs_dump_fw_log_wakeup(adev, buf, size);
134
135
return 0;
136
}
137
138
static int avs_skl_coredump(struct avs_dev *adev, union avs_notify_msg *msg)
139
{
140
u8 *dump;
141
142
dump = vzalloc(AVS_FW_REGS_SIZE);
143
if (!dump)
144
return -ENOMEM;
145
146
memcpy_fromio(dump, avs_sram_addr(adev, AVS_FW_REGS_WINDOW), AVS_FW_REGS_SIZE);
147
dev_coredumpv(adev->dev, dump, AVS_FW_REGS_SIZE, GFP_KERNEL);
148
149
return 0;
150
}
151
152
static bool avs_skl_d0ix_toggle(struct avs_dev *adev, struct avs_ipc_msg *tx, bool wake)
153
{
154
/* unsupported on cAVS 1.5 hw */
155
return false;
156
}
157
158
static int avs_skl_set_d0ix(struct avs_dev *adev, bool enable)
159
{
160
/* unsupported on cAVS 1.5 hw */
161
return 0;
162
}
163
164
const struct avs_dsp_ops avs_skl_dsp_ops = {
165
.power = avs_dsp_core_power,
166
.reset = avs_dsp_core_reset,
167
.stall = avs_dsp_core_stall,
168
.dsp_interrupt = avs_skl_dsp_interrupt,
169
.int_control = avs_dsp_interrupt_control,
170
.load_basefw = avs_cldma_load_basefw,
171
.load_lib = avs_cldma_load_library,
172
.transfer_mods = avs_cldma_transfer_modules,
173
.log_buffer_offset = avs_skl_log_buffer_offset,
174
.log_buffer_status = avs_skl_log_buffer_status,
175
.coredump = avs_skl_coredump,
176
.d0ix_toggle = avs_skl_d0ix_toggle,
177
.set_d0ix = avs_skl_set_d0ix,
178
AVS_SET_ENABLE_LOGS_OP(skl)
179
};
180
181