1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. |
4 | * |
5 | * @File ctsrc.c |
6 | * |
7 | * @Brief |
8 | * This file contains the implementation of the Sample Rate Convertor |
9 | * resource management object. |
10 | * |
11 | * @Author Liu Chun |
12 | * @Date May 13 2008 |
13 | */ |
14 | |
15 | #include "ctsrc.h" |
16 | #include "cthardware.h" |
17 | #include <linux/slab.h> |
18 | |
19 | #define SRC_RESOURCE_NUM 256 |
20 | #define SRCIMP_RESOURCE_NUM 256 |
21 | |
22 | static unsigned int conj_mask; |
23 | |
24 | static int src_default_config_memrd(struct src *src); |
25 | static int src_default_config_memwr(struct src *src); |
26 | static int src_default_config_arcrw(struct src *src); |
27 | |
28 | static int (*src_default_config[3])(struct src *) = { |
29 | [MEMRD] = src_default_config_memrd, |
30 | [MEMWR] = src_default_config_memwr, |
31 | [ARCRW] = src_default_config_arcrw |
32 | }; |
33 | |
34 | static int src_set_state(struct src *src, unsigned int state) |
35 | { |
36 | struct hw *hw; |
37 | |
38 | hw = src->rsc.hw; |
39 | hw->src_set_state(src->rsc.ctrl_blk, state); |
40 | |
41 | return 0; |
42 | } |
43 | |
44 | static int src_set_bm(struct src *src, unsigned int bm) |
45 | { |
46 | struct hw *hw; |
47 | |
48 | hw = src->rsc.hw; |
49 | hw->src_set_bm(src->rsc.ctrl_blk, bm); |
50 | |
51 | return 0; |
52 | } |
53 | |
54 | static int src_set_sf(struct src *src, unsigned int sf) |
55 | { |
56 | struct hw *hw; |
57 | |
58 | hw = src->rsc.hw; |
59 | hw->src_set_sf(src->rsc.ctrl_blk, sf); |
60 | |
61 | return 0; |
62 | } |
63 | |
64 | static int src_set_pm(struct src *src, unsigned int pm) |
65 | { |
66 | struct hw *hw; |
67 | |
68 | hw = src->rsc.hw; |
69 | hw->src_set_pm(src->rsc.ctrl_blk, pm); |
70 | |
71 | return 0; |
72 | } |
73 | |
74 | static int src_set_rom(struct src *src, unsigned int rom) |
75 | { |
76 | struct hw *hw; |
77 | |
78 | hw = src->rsc.hw; |
79 | hw->src_set_rom(src->rsc.ctrl_blk, rom); |
80 | |
81 | return 0; |
82 | } |
83 | |
84 | static int src_set_vo(struct src *src, unsigned int vo) |
85 | { |
86 | struct hw *hw; |
87 | |
88 | hw = src->rsc.hw; |
89 | hw->src_set_vo(src->rsc.ctrl_blk, vo); |
90 | |
91 | return 0; |
92 | } |
93 | |
94 | static int src_set_st(struct src *src, unsigned int st) |
95 | { |
96 | struct hw *hw; |
97 | |
98 | hw = src->rsc.hw; |
99 | hw->src_set_st(src->rsc.ctrl_blk, st); |
100 | |
101 | return 0; |
102 | } |
103 | |
104 | static int src_set_bp(struct src *src, unsigned int bp) |
105 | { |
106 | struct hw *hw; |
107 | |
108 | hw = src->rsc.hw; |
109 | hw->src_set_bp(src->rsc.ctrl_blk, bp); |
110 | |
111 | return 0; |
112 | } |
113 | |
114 | static int src_set_cisz(struct src *src, unsigned int cisz) |
115 | { |
116 | struct hw *hw; |
117 | |
118 | hw = src->rsc.hw; |
119 | hw->src_set_cisz(src->rsc.ctrl_blk, cisz); |
120 | |
121 | return 0; |
122 | } |
123 | |
124 | static int src_set_ca(struct src *src, unsigned int ca) |
125 | { |
126 | struct hw *hw; |
127 | |
128 | hw = src->rsc.hw; |
129 | hw->src_set_ca(src->rsc.ctrl_blk, ca); |
130 | |
131 | return 0; |
132 | } |
133 | |
134 | static int src_set_sa(struct src *src, unsigned int sa) |
135 | { |
136 | struct hw *hw; |
137 | |
138 | hw = src->rsc.hw; |
139 | hw->src_set_sa(src->rsc.ctrl_blk, sa); |
140 | |
141 | return 0; |
142 | } |
143 | |
144 | static int src_set_la(struct src *src, unsigned int la) |
145 | { |
146 | struct hw *hw; |
147 | |
148 | hw = src->rsc.hw; |
149 | hw->src_set_la(src->rsc.ctrl_blk, la); |
150 | |
151 | return 0; |
152 | } |
153 | |
154 | static int src_set_pitch(struct src *src, unsigned int pitch) |
155 | { |
156 | struct hw *hw; |
157 | |
158 | hw = src->rsc.hw; |
159 | hw->src_set_pitch(src->rsc.ctrl_blk, pitch); |
160 | |
161 | return 0; |
162 | } |
163 | |
164 | static int src_set_clear_zbufs(struct src *src) |
165 | { |
166 | struct hw *hw; |
167 | |
168 | hw = src->rsc.hw; |
169 | hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1); |
170 | |
171 | return 0; |
172 | } |
173 | |
174 | static int src_commit_write(struct src *src) |
175 | { |
176 | struct hw *hw; |
177 | int i; |
178 | unsigned int dirty = 0; |
179 | |
180 | hw = src->rsc.hw; |
181 | src->rsc.ops->master(&src->rsc); |
182 | if (src->rsc.msr > 1) { |
183 | /* Save dirty flags for conjugate resource programming */ |
184 | dirty = hw->src_get_dirty(src->rsc.ctrl_blk) & conj_mask; |
185 | } |
186 | hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), |
187 | src->rsc.ctrl_blk); |
188 | |
189 | /* Program conjugate parameter mixer resources */ |
190 | if (MEMWR == src->mode) |
191 | return 0; |
192 | |
193 | for (i = 1; i < src->rsc.msr; i++) { |
194 | src->rsc.ops->next_conj(&src->rsc); |
195 | hw->src_set_dirty(src->rsc.ctrl_blk, dirty); |
196 | hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), |
197 | src->rsc.ctrl_blk); |
198 | } |
199 | src->rsc.ops->master(&src->rsc); |
200 | |
201 | return 0; |
202 | } |
203 | |
204 | static int src_get_ca(struct src *src) |
205 | { |
206 | struct hw *hw; |
207 | |
208 | hw = src->rsc.hw; |
209 | return hw->src_get_ca(hw, src->rsc.ops->index(&src->rsc), |
210 | src->rsc.ctrl_blk); |
211 | } |
212 | |
213 | static int src_init(struct src *src) |
214 | { |
215 | src_default_config[src->mode](src); |
216 | |
217 | return 0; |
218 | } |
219 | |
220 | static struct src *src_next_interleave(struct src *src) |
221 | { |
222 | return src->intlv; |
223 | } |
224 | |
225 | static int src_default_config_memrd(struct src *src) |
226 | { |
227 | struct hw *hw = src->rsc.hw; |
228 | unsigned int rsr, msr; |
229 | |
230 | hw->src_set_state(src->rsc.ctrl_blk, SRC_STATE_OFF); |
231 | hw->src_set_bm(src->rsc.ctrl_blk, 1); |
232 | for (rsr = 0, msr = src->rsc.msr; msr > 1; msr >>= 1) |
233 | rsr++; |
234 | |
235 | hw->src_set_rsr(src->rsc.ctrl_blk, rsr); |
236 | hw->src_set_sf(src->rsc.ctrl_blk, SRC_SF_S16); |
237 | hw->src_set_wr(src->rsc.ctrl_blk, 0); |
238 | hw->src_set_pm(src->rsc.ctrl_blk, 0); |
239 | hw->src_set_rom(src->rsc.ctrl_blk, 0); |
240 | hw->src_set_vo(src->rsc.ctrl_blk, 0); |
241 | hw->src_set_st(src->rsc.ctrl_blk, 0); |
242 | hw->src_set_ilsz(src->rsc.ctrl_blk, src->multi - 1); |
243 | hw->src_set_cisz(src->rsc.ctrl_blk, 0x80); |
244 | hw->src_set_sa(src->rsc.ctrl_blk, 0x0); |
245 | hw->src_set_la(src->rsc.ctrl_blk, 0x1000); |
246 | hw->src_set_ca(src->rsc.ctrl_blk, 0x80); |
247 | hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000); |
248 | hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1); |
249 | |
250 | src->rsc.ops->master(&src->rsc); |
251 | hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), |
252 | src->rsc.ctrl_blk); |
253 | |
254 | for (msr = 1; msr < src->rsc.msr; msr++) { |
255 | src->rsc.ops->next_conj(&src->rsc); |
256 | hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000); |
257 | hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), |
258 | src->rsc.ctrl_blk); |
259 | } |
260 | src->rsc.ops->master(&src->rsc); |
261 | |
262 | return 0; |
263 | } |
264 | |
265 | static int src_default_config_memwr(struct src *src) |
266 | { |
267 | struct hw *hw = src->rsc.hw; |
268 | |
269 | hw->src_set_state(src->rsc.ctrl_blk, SRC_STATE_OFF); |
270 | hw->src_set_bm(src->rsc.ctrl_blk, 1); |
271 | hw->src_set_rsr(src->rsc.ctrl_blk, 0); |
272 | hw->src_set_sf(src->rsc.ctrl_blk, SRC_SF_S16); |
273 | hw->src_set_wr(src->rsc.ctrl_blk, 1); |
274 | hw->src_set_pm(src->rsc.ctrl_blk, 0); |
275 | hw->src_set_rom(src->rsc.ctrl_blk, 0); |
276 | hw->src_set_vo(src->rsc.ctrl_blk, 0); |
277 | hw->src_set_st(src->rsc.ctrl_blk, 0); |
278 | hw->src_set_ilsz(src->rsc.ctrl_blk, 0); |
279 | hw->src_set_cisz(src->rsc.ctrl_blk, 0x80); |
280 | hw->src_set_sa(src->rsc.ctrl_blk, 0x0); |
281 | hw->src_set_la(src->rsc.ctrl_blk, 0x1000); |
282 | hw->src_set_ca(src->rsc.ctrl_blk, 0x80); |
283 | hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000); |
284 | hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1); |
285 | |
286 | src->rsc.ops->master(&src->rsc); |
287 | hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), |
288 | src->rsc.ctrl_blk); |
289 | |
290 | return 0; |
291 | } |
292 | |
293 | static int src_default_config_arcrw(struct src *src) |
294 | { |
295 | struct hw *hw = src->rsc.hw; |
296 | unsigned int rsr, msr; |
297 | unsigned int dirty; |
298 | |
299 | hw->src_set_state(src->rsc.ctrl_blk, SRC_STATE_OFF); |
300 | hw->src_set_bm(src->rsc.ctrl_blk, 0); |
301 | for (rsr = 0, msr = src->rsc.msr; msr > 1; msr >>= 1) |
302 | rsr++; |
303 | |
304 | hw->src_set_rsr(src->rsc.ctrl_blk, rsr); |
305 | hw->src_set_sf(src->rsc.ctrl_blk, SRC_SF_F32); |
306 | hw->src_set_wr(src->rsc.ctrl_blk, 0); |
307 | hw->src_set_pm(src->rsc.ctrl_blk, 0); |
308 | hw->src_set_rom(src->rsc.ctrl_blk, 0); |
309 | hw->src_set_vo(src->rsc.ctrl_blk, 0); |
310 | hw->src_set_st(src->rsc.ctrl_blk, 0); |
311 | hw->src_set_ilsz(src->rsc.ctrl_blk, 0); |
312 | hw->src_set_cisz(src->rsc.ctrl_blk, 0x80); |
313 | hw->src_set_sa(src->rsc.ctrl_blk, 0x0); |
314 | /*hw->src_set_sa(src->rsc.ctrl_blk, 0x100);*/ |
315 | hw->src_set_la(src->rsc.ctrl_blk, 0x1000); |
316 | /*hw->src_set_la(src->rsc.ctrl_blk, 0x03ffffe0);*/ |
317 | hw->src_set_ca(src->rsc.ctrl_blk, 0x80); |
318 | hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000); |
319 | hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1); |
320 | |
321 | dirty = hw->src_get_dirty(src->rsc.ctrl_blk); |
322 | src->rsc.ops->master(&src->rsc); |
323 | for (msr = 0; msr < src->rsc.msr; msr++) { |
324 | hw->src_set_dirty(src->rsc.ctrl_blk, dirty); |
325 | hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), |
326 | src->rsc.ctrl_blk); |
327 | src->rsc.ops->next_conj(&src->rsc); |
328 | } |
329 | src->rsc.ops->master(&src->rsc); |
330 | |
331 | return 0; |
332 | } |
333 | |
334 | static const struct src_rsc_ops src_rsc_ops = { |
335 | .set_state = src_set_state, |
336 | .set_bm = src_set_bm, |
337 | .set_sf = src_set_sf, |
338 | .set_pm = src_set_pm, |
339 | .set_rom = src_set_rom, |
340 | .set_vo = src_set_vo, |
341 | .set_st = src_set_st, |
342 | .set_bp = src_set_bp, |
343 | .set_cisz = src_set_cisz, |
344 | .set_ca = src_set_ca, |
345 | .set_sa = src_set_sa, |
346 | .set_la = src_set_la, |
347 | .set_pitch = src_set_pitch, |
348 | .set_clr_zbufs = src_set_clear_zbufs, |
349 | .commit_write = src_commit_write, |
350 | .get_ca = src_get_ca, |
351 | .init = src_init, |
352 | .next_interleave = src_next_interleave, |
353 | }; |
354 | |
355 | static int |
356 | src_rsc_init(struct src *src, u32 idx, |
357 | const struct src_desc *desc, struct src_mgr *mgr) |
358 | { |
359 | int err; |
360 | int i, n; |
361 | struct src *p; |
362 | |
363 | n = (MEMRD == desc->mode) ? desc->multi : 1; |
364 | for (i = 0, p = src; i < n; i++, p++) { |
365 | err = rsc_init(rsc: &p->rsc, idx: idx + i, type: SRC, msr: desc->msr, hw: mgr->mgr.hw); |
366 | if (err) |
367 | goto error1; |
368 | |
369 | /* Initialize src specific rsc operations */ |
370 | p->ops = &src_rsc_ops; |
371 | p->multi = (0 == i) ? desc->multi : 1; |
372 | p->mode = desc->mode; |
373 | src_default_config[desc->mode](p); |
374 | mgr->src_enable(mgr, p); |
375 | p->intlv = p + 1; |
376 | } |
377 | (--p)->intlv = NULL; /* Set @intlv of the last SRC to NULL */ |
378 | |
379 | mgr->commit_write(mgr); |
380 | |
381 | return 0; |
382 | |
383 | error1: |
384 | for (i--, p--; i >= 0; i--, p--) { |
385 | mgr->src_disable(mgr, p); |
386 | rsc_uninit(rsc: &p->rsc); |
387 | } |
388 | mgr->commit_write(mgr); |
389 | return err; |
390 | } |
391 | |
392 | static int src_rsc_uninit(struct src *src, struct src_mgr *mgr) |
393 | { |
394 | int i, n; |
395 | struct src *p; |
396 | |
397 | n = (MEMRD == src->mode) ? src->multi : 1; |
398 | for (i = 0, p = src; i < n; i++, p++) { |
399 | mgr->src_disable(mgr, p); |
400 | rsc_uninit(rsc: &p->rsc); |
401 | p->multi = 0; |
402 | p->ops = NULL; |
403 | p->mode = NUM_SRCMODES; |
404 | p->intlv = NULL; |
405 | } |
406 | mgr->commit_write(mgr); |
407 | |
408 | return 0; |
409 | } |
410 | |
411 | static int |
412 | get_src_rsc(struct src_mgr *mgr, const struct src_desc *desc, struct src **rsrc) |
413 | { |
414 | unsigned int idx = SRC_RESOURCE_NUM; |
415 | int err; |
416 | struct src *src; |
417 | unsigned long flags; |
418 | |
419 | *rsrc = NULL; |
420 | |
421 | /* Check whether there are sufficient src resources to meet request. */ |
422 | spin_lock_irqsave(&mgr->mgr_lock, flags); |
423 | if (MEMRD == desc->mode) |
424 | err = mgr_get_resource(mgr: &mgr->mgr, n: desc->multi, ridx: &idx); |
425 | else |
426 | err = mgr_get_resource(mgr: &mgr->mgr, n: 1, ridx: &idx); |
427 | |
428 | spin_unlock_irqrestore(lock: &mgr->mgr_lock, flags); |
429 | if (err) { |
430 | dev_err(mgr->card->dev, |
431 | "Can't meet SRC resource request!\n" ); |
432 | return err; |
433 | } |
434 | |
435 | /* Allocate mem for master src resource */ |
436 | if (MEMRD == desc->mode) |
437 | src = kcalloc(n: desc->multi, size: sizeof(*src), GFP_KERNEL); |
438 | else |
439 | src = kzalloc(size: sizeof(*src), GFP_KERNEL); |
440 | |
441 | if (!src) { |
442 | err = -ENOMEM; |
443 | goto error1; |
444 | } |
445 | |
446 | err = src_rsc_init(src, idx, desc, mgr); |
447 | if (err) |
448 | goto error2; |
449 | |
450 | *rsrc = src; |
451 | |
452 | return 0; |
453 | |
454 | error2: |
455 | kfree(objp: src); |
456 | error1: |
457 | spin_lock_irqsave(&mgr->mgr_lock, flags); |
458 | if (MEMRD == desc->mode) |
459 | mgr_put_resource(mgr: &mgr->mgr, n: desc->multi, idx); |
460 | else |
461 | mgr_put_resource(mgr: &mgr->mgr, n: 1, idx); |
462 | |
463 | spin_unlock_irqrestore(lock: &mgr->mgr_lock, flags); |
464 | return err; |
465 | } |
466 | |
467 | static int put_src_rsc(struct src_mgr *mgr, struct src *src) |
468 | { |
469 | unsigned long flags; |
470 | |
471 | spin_lock_irqsave(&mgr->mgr_lock, flags); |
472 | src->rsc.ops->master(&src->rsc); |
473 | if (MEMRD == src->mode) |
474 | mgr_put_resource(mgr: &mgr->mgr, n: src->multi, |
475 | idx: src->rsc.ops->index(&src->rsc)); |
476 | else |
477 | mgr_put_resource(mgr: &mgr->mgr, n: 1, idx: src->rsc.ops->index(&src->rsc)); |
478 | |
479 | spin_unlock_irqrestore(lock: &mgr->mgr_lock, flags); |
480 | src_rsc_uninit(src, mgr); |
481 | kfree(objp: src); |
482 | |
483 | return 0; |
484 | } |
485 | |
486 | static int src_enable_s(struct src_mgr *mgr, struct src *src) |
487 | { |
488 | struct hw *hw = mgr->mgr.hw; |
489 | int i; |
490 | |
491 | src->rsc.ops->master(&src->rsc); |
492 | for (i = 0; i < src->rsc.msr; i++) { |
493 | hw->src_mgr_enbs_src(mgr->mgr.ctrl_blk, |
494 | src->rsc.ops->index(&src->rsc)); |
495 | src->rsc.ops->next_conj(&src->rsc); |
496 | } |
497 | src->rsc.ops->master(&src->rsc); |
498 | |
499 | return 0; |
500 | } |
501 | |
502 | static int src_enable(struct src_mgr *mgr, struct src *src) |
503 | { |
504 | struct hw *hw = mgr->mgr.hw; |
505 | int i; |
506 | |
507 | src->rsc.ops->master(&src->rsc); |
508 | for (i = 0; i < src->rsc.msr; i++) { |
509 | hw->src_mgr_enb_src(mgr->mgr.ctrl_blk, |
510 | src->rsc.ops->index(&src->rsc)); |
511 | src->rsc.ops->next_conj(&src->rsc); |
512 | } |
513 | src->rsc.ops->master(&src->rsc); |
514 | |
515 | return 0; |
516 | } |
517 | |
518 | static int src_disable(struct src_mgr *mgr, struct src *src) |
519 | { |
520 | struct hw *hw = mgr->mgr.hw; |
521 | int i; |
522 | |
523 | src->rsc.ops->master(&src->rsc); |
524 | for (i = 0; i < src->rsc.msr; i++) { |
525 | hw->src_mgr_dsb_src(mgr->mgr.ctrl_blk, |
526 | src->rsc.ops->index(&src->rsc)); |
527 | src->rsc.ops->next_conj(&src->rsc); |
528 | } |
529 | src->rsc.ops->master(&src->rsc); |
530 | |
531 | return 0; |
532 | } |
533 | |
534 | static int src_mgr_commit_write(struct src_mgr *mgr) |
535 | { |
536 | struct hw *hw = mgr->mgr.hw; |
537 | |
538 | hw->src_mgr_commit_write(hw, mgr->mgr.ctrl_blk); |
539 | |
540 | return 0; |
541 | } |
542 | |
543 | int src_mgr_create(struct hw *hw, void **rsrc_mgr) |
544 | { |
545 | int err, i; |
546 | struct src_mgr *src_mgr; |
547 | |
548 | *rsrc_mgr = NULL; |
549 | src_mgr = kzalloc(size: sizeof(*src_mgr), GFP_KERNEL); |
550 | if (!src_mgr) |
551 | return -ENOMEM; |
552 | |
553 | err = rsc_mgr_init(mgr: &src_mgr->mgr, type: SRC, SRC_RESOURCE_NUM, hw); |
554 | if (err) |
555 | goto error1; |
556 | |
557 | spin_lock_init(&src_mgr->mgr_lock); |
558 | conj_mask = hw->src_dirty_conj_mask(); |
559 | |
560 | src_mgr->get_src = get_src_rsc; |
561 | src_mgr->put_src = put_src_rsc; |
562 | src_mgr->src_enable_s = src_enable_s; |
563 | src_mgr->src_enable = src_enable; |
564 | src_mgr->src_disable = src_disable; |
565 | src_mgr->commit_write = src_mgr_commit_write; |
566 | src_mgr->card = hw->card; |
567 | |
568 | /* Disable all SRC resources. */ |
569 | for (i = 0; i < 256; i++) |
570 | hw->src_mgr_dsb_src(src_mgr->mgr.ctrl_blk, i); |
571 | |
572 | hw->src_mgr_commit_write(hw, src_mgr->mgr.ctrl_blk); |
573 | |
574 | *rsrc_mgr = src_mgr; |
575 | |
576 | return 0; |
577 | |
578 | error1: |
579 | kfree(objp: src_mgr); |
580 | return err; |
581 | } |
582 | |
583 | int src_mgr_destroy(void *ptr) |
584 | { |
585 | struct src_mgr *src_mgr = ptr; |
586 | rsc_mgr_uninit(mgr: &src_mgr->mgr); |
587 | kfree(objp: src_mgr); |
588 | |
589 | return 0; |
590 | } |
591 | |
592 | /* SRCIMP resource manager operations */ |
593 | |
594 | static void srcimp_master(struct rsc *rsc) |
595 | { |
596 | rsc->conj = 0; |
597 | rsc->idx = container_of(rsc, struct srcimp, rsc)->idx[0]; |
598 | } |
599 | |
600 | static void srcimp_next_conj(struct rsc *rsc) |
601 | { |
602 | rsc->conj++; |
603 | } |
604 | |
605 | static int srcimp_index(const struct rsc *rsc) |
606 | { |
607 | return container_of(rsc, struct srcimp, rsc)->idx[rsc->conj]; |
608 | } |
609 | |
610 | static const struct rsc_ops srcimp_basic_rsc_ops = { |
611 | .master = srcimp_master, |
612 | .next_conj = srcimp_next_conj, |
613 | .index = srcimp_index, |
614 | .output_slot = NULL, |
615 | }; |
616 | |
617 | static int srcimp_map(struct srcimp *srcimp, struct src *src, struct rsc *input) |
618 | { |
619 | struct imapper *entry; |
620 | int i; |
621 | |
622 | srcimp->rsc.ops->master(&srcimp->rsc); |
623 | src->rsc.ops->master(&src->rsc); |
624 | input->ops->master(input); |
625 | |
626 | /* Program master and conjugate resources */ |
627 | for (i = 0; i < srcimp->rsc.msr; i++) { |
628 | entry = &srcimp->imappers[i]; |
629 | entry->slot = input->ops->output_slot(input); |
630 | entry->user = src->rsc.ops->index(&src->rsc); |
631 | entry->addr = srcimp->rsc.ops->index(&srcimp->rsc); |
632 | srcimp->mgr->imap_add(srcimp->mgr, entry); |
633 | srcimp->mapped |= (0x1 << i); |
634 | |
635 | srcimp->rsc.ops->next_conj(&srcimp->rsc); |
636 | input->ops->next_conj(input); |
637 | } |
638 | |
639 | srcimp->rsc.ops->master(&srcimp->rsc); |
640 | input->ops->master(input); |
641 | |
642 | return 0; |
643 | } |
644 | |
645 | static int srcimp_unmap(struct srcimp *srcimp) |
646 | { |
647 | int i; |
648 | |
649 | /* Program master and conjugate resources */ |
650 | for (i = 0; i < srcimp->rsc.msr; i++) { |
651 | if (srcimp->mapped & (0x1 << i)) { |
652 | srcimp->mgr->imap_delete(srcimp->mgr, |
653 | &srcimp->imappers[i]); |
654 | srcimp->mapped &= ~(0x1 << i); |
655 | } |
656 | } |
657 | |
658 | return 0; |
659 | } |
660 | |
661 | static const struct srcimp_rsc_ops srcimp_ops = { |
662 | .map = srcimp_map, |
663 | .unmap = srcimp_unmap |
664 | }; |
665 | |
666 | static int srcimp_rsc_init(struct srcimp *srcimp, |
667 | const struct srcimp_desc *desc, |
668 | struct srcimp_mgr *mgr) |
669 | { |
670 | int err; |
671 | |
672 | err = rsc_init(rsc: &srcimp->rsc, idx: srcimp->idx[0], |
673 | type: SRCIMP, msr: desc->msr, hw: mgr->mgr.hw); |
674 | if (err) |
675 | return err; |
676 | |
677 | /* Reserve memory for imapper nodes */ |
678 | srcimp->imappers = kcalloc(n: desc->msr, size: sizeof(struct imapper), |
679 | GFP_KERNEL); |
680 | if (!srcimp->imappers) { |
681 | err = -ENOMEM; |
682 | goto error1; |
683 | } |
684 | |
685 | /* Set srcimp specific operations */ |
686 | srcimp->rsc.ops = &srcimp_basic_rsc_ops; |
687 | srcimp->ops = &srcimp_ops; |
688 | srcimp->mgr = mgr; |
689 | |
690 | srcimp->rsc.ops->master(&srcimp->rsc); |
691 | |
692 | return 0; |
693 | |
694 | error1: |
695 | rsc_uninit(rsc: &srcimp->rsc); |
696 | return err; |
697 | } |
698 | |
699 | static int srcimp_rsc_uninit(struct srcimp *srcimp) |
700 | { |
701 | kfree(objp: srcimp->imappers); |
702 | srcimp->imappers = NULL; |
703 | srcimp->ops = NULL; |
704 | srcimp->mgr = NULL; |
705 | rsc_uninit(rsc: &srcimp->rsc); |
706 | |
707 | return 0; |
708 | } |
709 | |
710 | static int get_srcimp_rsc(struct srcimp_mgr *mgr, |
711 | const struct srcimp_desc *desc, |
712 | struct srcimp **rsrcimp) |
713 | { |
714 | int err, i; |
715 | unsigned int idx; |
716 | struct srcimp *srcimp; |
717 | unsigned long flags; |
718 | |
719 | *rsrcimp = NULL; |
720 | |
721 | /* Allocate mem for SRCIMP resource */ |
722 | srcimp = kzalloc(size: sizeof(*srcimp), GFP_KERNEL); |
723 | if (!srcimp) |
724 | return -ENOMEM; |
725 | |
726 | /* Check whether there are sufficient SRCIMP resources. */ |
727 | err = 0; |
728 | spin_lock_irqsave(&mgr->mgr_lock, flags); |
729 | for (i = 0; i < desc->msr; i++) { |
730 | err = mgr_get_resource(mgr: &mgr->mgr, n: 1, ridx: &idx); |
731 | if (err) |
732 | break; |
733 | |
734 | srcimp->idx[i] = idx; |
735 | } |
736 | spin_unlock_irqrestore(lock: &mgr->mgr_lock, flags); |
737 | if (err) { |
738 | dev_err(mgr->card->dev, |
739 | "Can't meet SRCIMP resource request!\n" ); |
740 | goto error1; |
741 | } |
742 | |
743 | err = srcimp_rsc_init(srcimp, desc, mgr); |
744 | if (err) |
745 | goto error1; |
746 | |
747 | *rsrcimp = srcimp; |
748 | |
749 | return 0; |
750 | |
751 | error1: |
752 | spin_lock_irqsave(&mgr->mgr_lock, flags); |
753 | for (i--; i >= 0; i--) |
754 | mgr_put_resource(mgr: &mgr->mgr, n: 1, idx: srcimp->idx[i]); |
755 | |
756 | spin_unlock_irqrestore(lock: &mgr->mgr_lock, flags); |
757 | kfree(objp: srcimp); |
758 | return err; |
759 | } |
760 | |
761 | static int put_srcimp_rsc(struct srcimp_mgr *mgr, struct srcimp *srcimp) |
762 | { |
763 | unsigned long flags; |
764 | int i; |
765 | |
766 | spin_lock_irqsave(&mgr->mgr_lock, flags); |
767 | for (i = 0; i < srcimp->rsc.msr; i++) |
768 | mgr_put_resource(mgr: &mgr->mgr, n: 1, idx: srcimp->idx[i]); |
769 | |
770 | spin_unlock_irqrestore(lock: &mgr->mgr_lock, flags); |
771 | srcimp_rsc_uninit(srcimp); |
772 | kfree(objp: srcimp); |
773 | |
774 | return 0; |
775 | } |
776 | |
777 | static int srcimp_map_op(void *data, struct imapper *entry) |
778 | { |
779 | struct rsc_mgr *mgr = &((struct srcimp_mgr *)data)->mgr; |
780 | struct hw *hw = mgr->hw; |
781 | |
782 | hw->srcimp_mgr_set_imaparc(mgr->ctrl_blk, entry->slot); |
783 | hw->srcimp_mgr_set_imapuser(mgr->ctrl_blk, entry->user); |
784 | hw->srcimp_mgr_set_imapnxt(mgr->ctrl_blk, entry->next); |
785 | hw->srcimp_mgr_set_imapaddr(mgr->ctrl_blk, entry->addr); |
786 | hw->srcimp_mgr_commit_write(mgr->hw, mgr->ctrl_blk); |
787 | |
788 | return 0; |
789 | } |
790 | |
791 | static int srcimp_imap_add(struct srcimp_mgr *mgr, struct imapper *entry) |
792 | { |
793 | unsigned long flags; |
794 | int err; |
795 | |
796 | spin_lock_irqsave(&mgr->imap_lock, flags); |
797 | if ((0 == entry->addr) && (mgr->init_imap_added)) { |
798 | input_mapper_delete(mappers: &mgr->imappers, |
799 | entry: mgr->init_imap, map_op: srcimp_map_op, data: mgr); |
800 | mgr->init_imap_added = 0; |
801 | } |
802 | err = input_mapper_add(mappers: &mgr->imappers, entry, map_op: srcimp_map_op, data: mgr); |
803 | spin_unlock_irqrestore(lock: &mgr->imap_lock, flags); |
804 | |
805 | return err; |
806 | } |
807 | |
808 | static int srcimp_imap_delete(struct srcimp_mgr *mgr, struct imapper *entry) |
809 | { |
810 | unsigned long flags; |
811 | int err; |
812 | |
813 | spin_lock_irqsave(&mgr->imap_lock, flags); |
814 | err = input_mapper_delete(mappers: &mgr->imappers, entry, map_op: srcimp_map_op, data: mgr); |
815 | if (list_empty(head: &mgr->imappers)) { |
816 | input_mapper_add(mappers: &mgr->imappers, entry: mgr->init_imap, |
817 | map_op: srcimp_map_op, data: mgr); |
818 | mgr->init_imap_added = 1; |
819 | } |
820 | spin_unlock_irqrestore(lock: &mgr->imap_lock, flags); |
821 | |
822 | return err; |
823 | } |
824 | |
825 | int srcimp_mgr_create(struct hw *hw, void **rsrcimp_mgr) |
826 | { |
827 | int err; |
828 | struct srcimp_mgr *srcimp_mgr; |
829 | struct imapper *entry; |
830 | |
831 | *rsrcimp_mgr = NULL; |
832 | srcimp_mgr = kzalloc(size: sizeof(*srcimp_mgr), GFP_KERNEL); |
833 | if (!srcimp_mgr) |
834 | return -ENOMEM; |
835 | |
836 | err = rsc_mgr_init(mgr: &srcimp_mgr->mgr, type: SRCIMP, SRCIMP_RESOURCE_NUM, hw); |
837 | if (err) |
838 | goto error1; |
839 | |
840 | spin_lock_init(&srcimp_mgr->mgr_lock); |
841 | spin_lock_init(&srcimp_mgr->imap_lock); |
842 | INIT_LIST_HEAD(list: &srcimp_mgr->imappers); |
843 | entry = kzalloc(size: sizeof(*entry), GFP_KERNEL); |
844 | if (!entry) { |
845 | err = -ENOMEM; |
846 | goto error2; |
847 | } |
848 | entry->slot = entry->addr = entry->next = entry->user = 0; |
849 | list_add(new: &entry->list, head: &srcimp_mgr->imappers); |
850 | srcimp_mgr->init_imap = entry; |
851 | srcimp_mgr->init_imap_added = 1; |
852 | |
853 | srcimp_mgr->get_srcimp = get_srcimp_rsc; |
854 | srcimp_mgr->put_srcimp = put_srcimp_rsc; |
855 | srcimp_mgr->imap_add = srcimp_imap_add; |
856 | srcimp_mgr->imap_delete = srcimp_imap_delete; |
857 | srcimp_mgr->card = hw->card; |
858 | |
859 | *rsrcimp_mgr = srcimp_mgr; |
860 | |
861 | return 0; |
862 | |
863 | error2: |
864 | rsc_mgr_uninit(mgr: &srcimp_mgr->mgr); |
865 | error1: |
866 | kfree(objp: srcimp_mgr); |
867 | return err; |
868 | } |
869 | |
870 | int srcimp_mgr_destroy(void *ptr) |
871 | { |
872 | struct srcimp_mgr *srcimp_mgr = ptr; |
873 | unsigned long flags; |
874 | |
875 | /* free src input mapper list */ |
876 | spin_lock_irqsave(&srcimp_mgr->imap_lock, flags); |
877 | free_input_mapper_list(mappers: &srcimp_mgr->imappers); |
878 | spin_unlock_irqrestore(lock: &srcimp_mgr->imap_lock, flags); |
879 | |
880 | rsc_mgr_uninit(mgr: &srcimp_mgr->mgr); |
881 | kfree(objp: srcimp_mgr); |
882 | |
883 | return 0; |
884 | } |
885 | |