1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
2 | /* |
3 | * cs_dsp.h -- Cirrus Logic DSP firmware support |
4 | * |
5 | * Based on sound/soc/codecs/wm_adsp.h |
6 | * |
7 | * Copyright 2012 Wolfson Microelectronics plc |
8 | * Copyright (C) 2015-2021 Cirrus Logic, Inc. and |
9 | * Cirrus Logic International Semiconductor Ltd. |
10 | */ |
11 | #ifndef __CS_DSP_H |
12 | #define __CS_DSP_H |
13 | |
14 | #include <linux/bits.h> |
15 | #include <linux/device.h> |
16 | #include <linux/firmware.h> |
17 | #include <linux/list.h> |
18 | #include <linux/regmap.h> |
19 | |
20 | #define CS_ADSP2_REGION_0 BIT(0) |
21 | #define CS_ADSP2_REGION_1 BIT(1) |
22 | #define CS_ADSP2_REGION_2 BIT(2) |
23 | #define CS_ADSP2_REGION_3 BIT(3) |
24 | #define CS_ADSP2_REGION_4 BIT(4) |
25 | #define CS_ADSP2_REGION_5 BIT(5) |
26 | #define CS_ADSP2_REGION_6 BIT(6) |
27 | #define CS_ADSP2_REGION_7 BIT(7) |
28 | #define CS_ADSP2_REGION_8 BIT(8) |
29 | #define CS_ADSP2_REGION_9 BIT(9) |
30 | #define CS_ADSP2_REGION_1_9 (CS_ADSP2_REGION_1 | \ |
31 | CS_ADSP2_REGION_2 | CS_ADSP2_REGION_3 | \ |
32 | CS_ADSP2_REGION_4 | CS_ADSP2_REGION_5 | \ |
33 | CS_ADSP2_REGION_6 | CS_ADSP2_REGION_7 | \ |
34 | CS_ADSP2_REGION_8 | CS_ADSP2_REGION_9) |
35 | #define CS_ADSP2_REGION_ALL (CS_ADSP2_REGION_0 | CS_ADSP2_REGION_1_9) |
36 | |
37 | #define CS_DSP_DATA_WORD_SIZE 3 |
38 | #define CS_DSP_DATA_WORD_BITS (3 * BITS_PER_BYTE) |
39 | |
40 | #define CS_DSP_ACKED_CTL_TIMEOUT_MS 100 |
41 | #define CS_DSP_ACKED_CTL_N_QUICKPOLLS 10 |
42 | #define CS_DSP_ACKED_CTL_MIN_VALUE 0 |
43 | #define CS_DSP_ACKED_CTL_MAX_VALUE 0xFFFFFF |
44 | |
45 | /** |
46 | * struct cs_dsp_region - Describes a logical memory region in DSP address space |
47 | * @type: Memory region type |
48 | * @base: Address of region |
49 | */ |
50 | struct cs_dsp_region { |
51 | int type; |
52 | unsigned int base; |
53 | }; |
54 | |
55 | /** |
56 | * struct cs_dsp_alg_region - Describes a logical algorithm region in DSP address space |
57 | * @list: List node for internal use |
58 | * @alg: Algorithm id |
59 | * @ver: Expected algorithm version |
60 | * @type: Memory region type |
61 | * @base: Address of region |
62 | */ |
63 | struct cs_dsp_alg_region { |
64 | struct list_head list; |
65 | unsigned int alg; |
66 | unsigned int ver; |
67 | int type; |
68 | unsigned int base; |
69 | }; |
70 | |
71 | /** |
72 | * struct cs_dsp_coeff_ctl - Describes a coefficient control |
73 | * @list: List node for internal use |
74 | * @dsp: DSP instance associated with this control |
75 | * @cache: Cached value of the control |
76 | * @fw_name: Name of the firmware |
77 | * @subname: Name of the control parsed from the WMFW |
78 | * @subname_len: Length of subname |
79 | * @offset: Offset of control within alg_region in words |
80 | * @len: Length of the cached value in bytes |
81 | * @type: One of the WMFW_CTL_TYPE_ control types defined in wmfw.h |
82 | * @flags: Bitfield of WMFW_CTL_FLAG_ control flags defined in wmfw.h |
83 | * @set: Flag indicating the value has been written by the user |
84 | * @enabled: Flag indicating whether control is enabled |
85 | * @alg_region: Logical region associated with this control |
86 | * @priv: For use by the client |
87 | */ |
88 | struct cs_dsp_coeff_ctl { |
89 | struct list_head list; |
90 | struct cs_dsp *dsp; |
91 | void *cache; |
92 | const char *fw_name; |
93 | /* Subname is needed to match with firmware */ |
94 | const char *subname; |
95 | unsigned int subname_len; |
96 | unsigned int offset; |
97 | size_t len; |
98 | unsigned int type; |
99 | unsigned int flags; |
100 | unsigned int set:1; |
101 | unsigned int enabled:1; |
102 | struct cs_dsp_alg_region alg_region; |
103 | |
104 | void *priv; |
105 | }; |
106 | |
107 | struct cs_dsp_ops; |
108 | struct cs_dsp_client_ops; |
109 | |
110 | /** |
111 | * struct cs_dsp - Configuration and state of a Cirrus Logic DSP |
112 | * @name: The name of the DSP instance |
113 | * @rev: Revision of the DSP |
114 | * @num: DSP instance number |
115 | * @type: Type of DSP |
116 | * @dev: Driver model representation of the device |
117 | * @regmap: Register map of the device |
118 | * @ops: Function pointers for internal callbacks |
119 | * @client_ops: Function pointers for client callbacks |
120 | * @base: Address of the DSP registers |
121 | * @base_sysinfo: Address of the sysinfo register (Halo only) |
122 | * @sysclk_reg: Address of the sysclk register (ADSP1 only) |
123 | * @sysclk_mask: Mask of frequency bits within sysclk register (ADSP1 only) |
124 | * @sysclk_shift: Shift of frequency bits within sysclk register (ADSP1 only) |
125 | * @alg_regions: List of currently loaded algorithm regions |
126 | * @fw_name: Name of the current firmware |
127 | * @fw_id: ID of the current firmware, obtained from the wmfw |
128 | * @fw_id_version: Version of the firmware, obtained from the wmfw |
129 | * @fw_vendor_id: Vendor of the firmware, obtained from the wmfw |
130 | * @mem: DSP memory region descriptions |
131 | * @num_mems: Number of memory regions in this DSP |
132 | * @fw_ver: Version of the wmfw file format |
133 | * @booted: Flag indicating DSP has been configured |
134 | * @running: Flag indicating DSP is executing firmware |
135 | * @ctl_list: Controls defined within the loaded DSP firmware |
136 | * @lock_regions: Enable MPU traps on specified memory regions |
137 | * @pwr_lock: Lock used to serialize accesses |
138 | * @debugfs_root: Debugfs directory for this DSP instance |
139 | * @wmfw_file_name: Filename of the currently loaded firmware |
140 | * @bin_file_name: Filename of the currently loaded coefficients |
141 | */ |
142 | struct cs_dsp { |
143 | const char *name; |
144 | int rev; |
145 | int num; |
146 | int type; |
147 | struct device *dev; |
148 | struct regmap *regmap; |
149 | |
150 | const struct cs_dsp_ops *ops; |
151 | const struct cs_dsp_client_ops *client_ops; |
152 | |
153 | unsigned int base; |
154 | unsigned int base_sysinfo; |
155 | unsigned int sysclk_reg; |
156 | unsigned int sysclk_mask; |
157 | unsigned int sysclk_shift; |
158 | bool no_core_startstop; |
159 | |
160 | struct list_head alg_regions; |
161 | |
162 | const char *fw_name; |
163 | unsigned int fw_id; |
164 | unsigned int fw_id_version; |
165 | unsigned int fw_vendor_id; |
166 | |
167 | const struct cs_dsp_region *mem; |
168 | int num_mems; |
169 | |
170 | int fw_ver; |
171 | |
172 | bool booted; |
173 | bool running; |
174 | |
175 | struct list_head ctl_list; |
176 | |
177 | struct mutex pwr_lock; |
178 | |
179 | unsigned int lock_regions; |
180 | |
181 | #ifdef CONFIG_DEBUG_FS |
182 | struct dentry *debugfs_root; |
183 | char *wmfw_file_name; |
184 | char *bin_file_name; |
185 | #endif |
186 | }; |
187 | |
188 | /** |
189 | * struct cs_dsp_client_ops - client callbacks |
190 | * @control_add: Called under the pwr_lock when a control is created |
191 | * @control_remove: Called under the pwr_lock when a control is destroyed |
192 | * @pre_run: Called under the pwr_lock by cs_dsp_run() before the core is started |
193 | * @post_run: Called under the pwr_lock by cs_dsp_run() after the core is started |
194 | * @pre_stop: Called under the pwr_lock by cs_dsp_stop() before the core is stopped |
195 | * @post_stop: Called under the pwr_lock by cs_dsp_stop() after the core is stopped |
196 | * @watchdog_expired: Called when a watchdog expiry is detected |
197 | * |
198 | * These callbacks give the cs_dsp client an opportunity to respond to events |
199 | * or to perform actions atomically. |
200 | */ |
201 | struct cs_dsp_client_ops { |
202 | int (*control_add)(struct cs_dsp_coeff_ctl *ctl); |
203 | void (*control_remove)(struct cs_dsp_coeff_ctl *ctl); |
204 | int (*pre_run)(struct cs_dsp *dsp); |
205 | int (*post_run)(struct cs_dsp *dsp); |
206 | void (*pre_stop)(struct cs_dsp *dsp); |
207 | void (*post_stop)(struct cs_dsp *dsp); |
208 | void (*watchdog_expired)(struct cs_dsp *dsp); |
209 | }; |
210 | |
211 | int cs_dsp_adsp1_init(struct cs_dsp *dsp); |
212 | int cs_dsp_adsp2_init(struct cs_dsp *dsp); |
213 | int cs_dsp_halo_init(struct cs_dsp *dsp); |
214 | |
215 | int cs_dsp_adsp1_power_up(struct cs_dsp *dsp, |
216 | const struct firmware *wmfw_firmware, char *wmfw_filename, |
217 | const struct firmware *coeff_firmware, char *coeff_filename, |
218 | const char *fw_name); |
219 | void cs_dsp_adsp1_power_down(struct cs_dsp *dsp); |
220 | int cs_dsp_power_up(struct cs_dsp *dsp, |
221 | const struct firmware *wmfw_firmware, char *wmfw_filename, |
222 | const struct firmware *coeff_firmware, char *coeff_filename, |
223 | const char *fw_name); |
224 | void cs_dsp_power_down(struct cs_dsp *dsp); |
225 | int cs_dsp_run(struct cs_dsp *dsp); |
226 | void cs_dsp_stop(struct cs_dsp *dsp); |
227 | |
228 | void cs_dsp_remove(struct cs_dsp *dsp); |
229 | |
230 | int cs_dsp_set_dspclk(struct cs_dsp *dsp, unsigned int freq); |
231 | void cs_dsp_adsp2_bus_error(struct cs_dsp *dsp); |
232 | void cs_dsp_halo_bus_error(struct cs_dsp *dsp); |
233 | void cs_dsp_halo_wdt_expire(struct cs_dsp *dsp); |
234 | |
235 | void cs_dsp_init_debugfs(struct cs_dsp *dsp, struct dentry *debugfs_root); |
236 | void cs_dsp_cleanup_debugfs(struct cs_dsp *dsp); |
237 | |
238 | int cs_dsp_coeff_write_acked_control(struct cs_dsp_coeff_ctl *ctl, unsigned int event_id); |
239 | int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl, unsigned int off, |
240 | const void *buf, size_t len); |
241 | int cs_dsp_coeff_read_ctrl(struct cs_dsp_coeff_ctl *ctl, unsigned int off, |
242 | void *buf, size_t len); |
243 | struct cs_dsp_coeff_ctl *cs_dsp_get_ctl(struct cs_dsp *dsp, const char *name, int type, |
244 | unsigned int alg); |
245 | |
246 | int cs_dsp_read_raw_data_block(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr, |
247 | unsigned int num_words, __be32 *data); |
248 | int cs_dsp_read_data_word(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr, u32 *data); |
249 | int cs_dsp_write_data_word(struct cs_dsp *dsp, int mem_type, unsigned int mem_addr, u32 data); |
250 | void cs_dsp_remove_padding(u32 *buf, int nwords); |
251 | |
252 | struct cs_dsp_alg_region *cs_dsp_find_alg_region(struct cs_dsp *dsp, |
253 | int type, unsigned int id); |
254 | |
255 | const char *cs_dsp_mem_region_name(unsigned int type); |
256 | |
257 | /** |
258 | * struct cs_dsp_chunk - Describes a buffer holding data formatted for the DSP |
259 | * @data: Pointer to underlying buffer memory |
260 | * @max: Pointer to end of the buffer memory |
261 | * @bytes: Number of bytes read/written into the memory chunk |
262 | * @cache: Temporary holding data as it is formatted |
263 | * @cachebits: Number of bits of data currently in cache |
264 | */ |
265 | struct cs_dsp_chunk { |
266 | u8 *data; |
267 | u8 *max; |
268 | int bytes; |
269 | |
270 | u32 cache; |
271 | int cachebits; |
272 | }; |
273 | |
274 | /** |
275 | * cs_dsp_chunk() - Create a DSP memory chunk |
276 | * @data: Pointer to the buffer that will be used to store data |
277 | * @size: Size of the buffer in bytes |
278 | * |
279 | * Return: A cs_dsp_chunk structure |
280 | */ |
281 | static inline struct cs_dsp_chunk cs_dsp_chunk(void *data, int size) |
282 | { |
283 | struct cs_dsp_chunk ch = { |
284 | .data = data, |
285 | .max = data + size, |
286 | }; |
287 | |
288 | return ch; |
289 | } |
290 | |
291 | /** |
292 | * cs_dsp_chunk_end() - Check if a DSP memory chunk is full |
293 | * @ch: Pointer to the chunk structure |
294 | * |
295 | * Return: True if the whole buffer has been read/written |
296 | */ |
297 | static inline bool cs_dsp_chunk_end(struct cs_dsp_chunk *ch) |
298 | { |
299 | return ch->data == ch->max; |
300 | } |
301 | |
302 | /** |
303 | * cs_dsp_chunk_bytes() - Number of bytes written/read from a DSP memory chunk |
304 | * @ch: Pointer to the chunk structure |
305 | * |
306 | * Return: Number of bytes read/written to the buffer |
307 | */ |
308 | static inline int cs_dsp_chunk_bytes(struct cs_dsp_chunk *ch) |
309 | { |
310 | return ch->bytes; |
311 | } |
312 | |
313 | /** |
314 | * cs_dsp_chunk_valid_addr() - Check if an address is in a DSP memory chunk |
315 | * @ch: Pointer to the chunk structure |
316 | * |
317 | * Return: True if the given address is within the buffer |
318 | */ |
319 | static inline bool cs_dsp_chunk_valid_addr(struct cs_dsp_chunk *ch, void *addr) |
320 | { |
321 | return (u8 *)addr >= ch->data && (u8 *)addr < ch->max; |
322 | } |
323 | |
324 | int cs_dsp_chunk_write(struct cs_dsp_chunk *ch, int nbits, u32 val); |
325 | int cs_dsp_chunk_flush(struct cs_dsp_chunk *ch); |
326 | int cs_dsp_chunk_read(struct cs_dsp_chunk *ch, int nbits); |
327 | |
328 | #endif |
329 | |