162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * @File ctsrc.c 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * @Brief 862306a36Sopenharmony_ci * This file contains the implementation of the Sample Rate Convertor 962306a36Sopenharmony_ci * resource management object. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * @Author Liu Chun 1262306a36Sopenharmony_ci * @Date May 13 2008 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "ctsrc.h" 1662306a36Sopenharmony_ci#include "cthardware.h" 1762306a36Sopenharmony_ci#include <linux/slab.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define SRC_RESOURCE_NUM 256 2062306a36Sopenharmony_ci#define SRCIMP_RESOURCE_NUM 256 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic unsigned int conj_mask; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic int src_default_config_memrd(struct src *src); 2562306a36Sopenharmony_cistatic int src_default_config_memwr(struct src *src); 2662306a36Sopenharmony_cistatic int src_default_config_arcrw(struct src *src); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic int (*src_default_config[3])(struct src *) = { 2962306a36Sopenharmony_ci [MEMRD] = src_default_config_memrd, 3062306a36Sopenharmony_ci [MEMWR] = src_default_config_memwr, 3162306a36Sopenharmony_ci [ARCRW] = src_default_config_arcrw 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic int src_set_state(struct src *src, unsigned int state) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci struct hw *hw; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci hw = src->rsc.hw; 3962306a36Sopenharmony_ci hw->src_set_state(src->rsc.ctrl_blk, state); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci return 0; 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic int src_set_bm(struct src *src, unsigned int bm) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci struct hw *hw; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci hw = src->rsc.hw; 4962306a36Sopenharmony_ci hw->src_set_bm(src->rsc.ctrl_blk, bm); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci return 0; 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic int src_set_sf(struct src *src, unsigned int sf) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci struct hw *hw; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci hw = src->rsc.hw; 5962306a36Sopenharmony_ci hw->src_set_sf(src->rsc.ctrl_blk, sf); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci return 0; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic int src_set_pm(struct src *src, unsigned int pm) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci struct hw *hw; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci hw = src->rsc.hw; 6962306a36Sopenharmony_ci hw->src_set_pm(src->rsc.ctrl_blk, pm); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci return 0; 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic int src_set_rom(struct src *src, unsigned int rom) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci struct hw *hw; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci hw = src->rsc.hw; 7962306a36Sopenharmony_ci hw->src_set_rom(src->rsc.ctrl_blk, rom); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci return 0; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic int src_set_vo(struct src *src, unsigned int vo) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci struct hw *hw; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci hw = src->rsc.hw; 8962306a36Sopenharmony_ci hw->src_set_vo(src->rsc.ctrl_blk, vo); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci return 0; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic int src_set_st(struct src *src, unsigned int st) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci struct hw *hw; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci hw = src->rsc.hw; 9962306a36Sopenharmony_ci hw->src_set_st(src->rsc.ctrl_blk, st); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci return 0; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic int src_set_bp(struct src *src, unsigned int bp) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci struct hw *hw; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci hw = src->rsc.hw; 10962306a36Sopenharmony_ci hw->src_set_bp(src->rsc.ctrl_blk, bp); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci return 0; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic int src_set_cisz(struct src *src, unsigned int cisz) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci struct hw *hw; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci hw = src->rsc.hw; 11962306a36Sopenharmony_ci hw->src_set_cisz(src->rsc.ctrl_blk, cisz); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci return 0; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic int src_set_ca(struct src *src, unsigned int ca) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct hw *hw; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci hw = src->rsc.hw; 12962306a36Sopenharmony_ci hw->src_set_ca(src->rsc.ctrl_blk, ca); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci return 0; 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic int src_set_sa(struct src *src, unsigned int sa) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci struct hw *hw; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci hw = src->rsc.hw; 13962306a36Sopenharmony_ci hw->src_set_sa(src->rsc.ctrl_blk, sa); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci return 0; 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic int src_set_la(struct src *src, unsigned int la) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci struct hw *hw; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci hw = src->rsc.hw; 14962306a36Sopenharmony_ci hw->src_set_la(src->rsc.ctrl_blk, la); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci return 0; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic int src_set_pitch(struct src *src, unsigned int pitch) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci struct hw *hw; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci hw = src->rsc.hw; 15962306a36Sopenharmony_ci hw->src_set_pitch(src->rsc.ctrl_blk, pitch); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci return 0; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic int src_set_clear_zbufs(struct src *src) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci struct hw *hw; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci hw = src->rsc.hw; 16962306a36Sopenharmony_ci hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci return 0; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic int src_commit_write(struct src *src) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci struct hw *hw; 17762306a36Sopenharmony_ci int i; 17862306a36Sopenharmony_ci unsigned int dirty = 0; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci hw = src->rsc.hw; 18162306a36Sopenharmony_ci src->rsc.ops->master(&src->rsc); 18262306a36Sopenharmony_ci if (src->rsc.msr > 1) { 18362306a36Sopenharmony_ci /* Save dirty flags for conjugate resource programming */ 18462306a36Sopenharmony_ci dirty = hw->src_get_dirty(src->rsc.ctrl_blk) & conj_mask; 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), 18762306a36Sopenharmony_ci src->rsc.ctrl_blk); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* Program conjugate parameter mixer resources */ 19062306a36Sopenharmony_ci if (MEMWR == src->mode) 19162306a36Sopenharmony_ci return 0; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci for (i = 1; i < src->rsc.msr; i++) { 19462306a36Sopenharmony_ci src->rsc.ops->next_conj(&src->rsc); 19562306a36Sopenharmony_ci hw->src_set_dirty(src->rsc.ctrl_blk, dirty); 19662306a36Sopenharmony_ci hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), 19762306a36Sopenharmony_ci src->rsc.ctrl_blk); 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci src->rsc.ops->master(&src->rsc); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci return 0; 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic int src_get_ca(struct src *src) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci struct hw *hw; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci hw = src->rsc.hw; 20962306a36Sopenharmony_ci return hw->src_get_ca(hw, src->rsc.ops->index(&src->rsc), 21062306a36Sopenharmony_ci src->rsc.ctrl_blk); 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic int src_init(struct src *src) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci src_default_config[src->mode](src); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci return 0; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic struct src *src_next_interleave(struct src *src) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci return src->intlv; 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic int src_default_config_memrd(struct src *src) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci struct hw *hw = src->rsc.hw; 22862306a36Sopenharmony_ci unsigned int rsr, msr; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci hw->src_set_state(src->rsc.ctrl_blk, SRC_STATE_OFF); 23162306a36Sopenharmony_ci hw->src_set_bm(src->rsc.ctrl_blk, 1); 23262306a36Sopenharmony_ci for (rsr = 0, msr = src->rsc.msr; msr > 1; msr >>= 1) 23362306a36Sopenharmony_ci rsr++; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci hw->src_set_rsr(src->rsc.ctrl_blk, rsr); 23662306a36Sopenharmony_ci hw->src_set_sf(src->rsc.ctrl_blk, SRC_SF_S16); 23762306a36Sopenharmony_ci hw->src_set_wr(src->rsc.ctrl_blk, 0); 23862306a36Sopenharmony_ci hw->src_set_pm(src->rsc.ctrl_blk, 0); 23962306a36Sopenharmony_ci hw->src_set_rom(src->rsc.ctrl_blk, 0); 24062306a36Sopenharmony_ci hw->src_set_vo(src->rsc.ctrl_blk, 0); 24162306a36Sopenharmony_ci hw->src_set_st(src->rsc.ctrl_blk, 0); 24262306a36Sopenharmony_ci hw->src_set_ilsz(src->rsc.ctrl_blk, src->multi - 1); 24362306a36Sopenharmony_ci hw->src_set_cisz(src->rsc.ctrl_blk, 0x80); 24462306a36Sopenharmony_ci hw->src_set_sa(src->rsc.ctrl_blk, 0x0); 24562306a36Sopenharmony_ci hw->src_set_la(src->rsc.ctrl_blk, 0x1000); 24662306a36Sopenharmony_ci hw->src_set_ca(src->rsc.ctrl_blk, 0x80); 24762306a36Sopenharmony_ci hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000); 24862306a36Sopenharmony_ci hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci src->rsc.ops->master(&src->rsc); 25162306a36Sopenharmony_ci hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), 25262306a36Sopenharmony_ci src->rsc.ctrl_blk); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci for (msr = 1; msr < src->rsc.msr; msr++) { 25562306a36Sopenharmony_ci src->rsc.ops->next_conj(&src->rsc); 25662306a36Sopenharmony_ci hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000); 25762306a36Sopenharmony_ci hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), 25862306a36Sopenharmony_ci src->rsc.ctrl_blk); 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci src->rsc.ops->master(&src->rsc); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci return 0; 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic int src_default_config_memwr(struct src *src) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci struct hw *hw = src->rsc.hw; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci hw->src_set_state(src->rsc.ctrl_blk, SRC_STATE_OFF); 27062306a36Sopenharmony_ci hw->src_set_bm(src->rsc.ctrl_blk, 1); 27162306a36Sopenharmony_ci hw->src_set_rsr(src->rsc.ctrl_blk, 0); 27262306a36Sopenharmony_ci hw->src_set_sf(src->rsc.ctrl_blk, SRC_SF_S16); 27362306a36Sopenharmony_ci hw->src_set_wr(src->rsc.ctrl_blk, 1); 27462306a36Sopenharmony_ci hw->src_set_pm(src->rsc.ctrl_blk, 0); 27562306a36Sopenharmony_ci hw->src_set_rom(src->rsc.ctrl_blk, 0); 27662306a36Sopenharmony_ci hw->src_set_vo(src->rsc.ctrl_blk, 0); 27762306a36Sopenharmony_ci hw->src_set_st(src->rsc.ctrl_blk, 0); 27862306a36Sopenharmony_ci hw->src_set_ilsz(src->rsc.ctrl_blk, 0); 27962306a36Sopenharmony_ci hw->src_set_cisz(src->rsc.ctrl_blk, 0x80); 28062306a36Sopenharmony_ci hw->src_set_sa(src->rsc.ctrl_blk, 0x0); 28162306a36Sopenharmony_ci hw->src_set_la(src->rsc.ctrl_blk, 0x1000); 28262306a36Sopenharmony_ci hw->src_set_ca(src->rsc.ctrl_blk, 0x80); 28362306a36Sopenharmony_ci hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000); 28462306a36Sopenharmony_ci hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci src->rsc.ops->master(&src->rsc); 28762306a36Sopenharmony_ci hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), 28862306a36Sopenharmony_ci src->rsc.ctrl_blk); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci return 0; 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic int src_default_config_arcrw(struct src *src) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci struct hw *hw = src->rsc.hw; 29662306a36Sopenharmony_ci unsigned int rsr, msr; 29762306a36Sopenharmony_ci unsigned int dirty; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci hw->src_set_state(src->rsc.ctrl_blk, SRC_STATE_OFF); 30062306a36Sopenharmony_ci hw->src_set_bm(src->rsc.ctrl_blk, 0); 30162306a36Sopenharmony_ci for (rsr = 0, msr = src->rsc.msr; msr > 1; msr >>= 1) 30262306a36Sopenharmony_ci rsr++; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci hw->src_set_rsr(src->rsc.ctrl_blk, rsr); 30562306a36Sopenharmony_ci hw->src_set_sf(src->rsc.ctrl_blk, SRC_SF_F32); 30662306a36Sopenharmony_ci hw->src_set_wr(src->rsc.ctrl_blk, 0); 30762306a36Sopenharmony_ci hw->src_set_pm(src->rsc.ctrl_blk, 0); 30862306a36Sopenharmony_ci hw->src_set_rom(src->rsc.ctrl_blk, 0); 30962306a36Sopenharmony_ci hw->src_set_vo(src->rsc.ctrl_blk, 0); 31062306a36Sopenharmony_ci hw->src_set_st(src->rsc.ctrl_blk, 0); 31162306a36Sopenharmony_ci hw->src_set_ilsz(src->rsc.ctrl_blk, 0); 31262306a36Sopenharmony_ci hw->src_set_cisz(src->rsc.ctrl_blk, 0x80); 31362306a36Sopenharmony_ci hw->src_set_sa(src->rsc.ctrl_blk, 0x0); 31462306a36Sopenharmony_ci /*hw->src_set_sa(src->rsc.ctrl_blk, 0x100);*/ 31562306a36Sopenharmony_ci hw->src_set_la(src->rsc.ctrl_blk, 0x1000); 31662306a36Sopenharmony_ci /*hw->src_set_la(src->rsc.ctrl_blk, 0x03ffffe0);*/ 31762306a36Sopenharmony_ci hw->src_set_ca(src->rsc.ctrl_blk, 0x80); 31862306a36Sopenharmony_ci hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000); 31962306a36Sopenharmony_ci hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci dirty = hw->src_get_dirty(src->rsc.ctrl_blk); 32262306a36Sopenharmony_ci src->rsc.ops->master(&src->rsc); 32362306a36Sopenharmony_ci for (msr = 0; msr < src->rsc.msr; msr++) { 32462306a36Sopenharmony_ci hw->src_set_dirty(src->rsc.ctrl_blk, dirty); 32562306a36Sopenharmony_ci hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), 32662306a36Sopenharmony_ci src->rsc.ctrl_blk); 32762306a36Sopenharmony_ci src->rsc.ops->next_conj(&src->rsc); 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci src->rsc.ops->master(&src->rsc); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci return 0; 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic const struct src_rsc_ops src_rsc_ops = { 33562306a36Sopenharmony_ci .set_state = src_set_state, 33662306a36Sopenharmony_ci .set_bm = src_set_bm, 33762306a36Sopenharmony_ci .set_sf = src_set_sf, 33862306a36Sopenharmony_ci .set_pm = src_set_pm, 33962306a36Sopenharmony_ci .set_rom = src_set_rom, 34062306a36Sopenharmony_ci .set_vo = src_set_vo, 34162306a36Sopenharmony_ci .set_st = src_set_st, 34262306a36Sopenharmony_ci .set_bp = src_set_bp, 34362306a36Sopenharmony_ci .set_cisz = src_set_cisz, 34462306a36Sopenharmony_ci .set_ca = src_set_ca, 34562306a36Sopenharmony_ci .set_sa = src_set_sa, 34662306a36Sopenharmony_ci .set_la = src_set_la, 34762306a36Sopenharmony_ci .set_pitch = src_set_pitch, 34862306a36Sopenharmony_ci .set_clr_zbufs = src_set_clear_zbufs, 34962306a36Sopenharmony_ci .commit_write = src_commit_write, 35062306a36Sopenharmony_ci .get_ca = src_get_ca, 35162306a36Sopenharmony_ci .init = src_init, 35262306a36Sopenharmony_ci .next_interleave = src_next_interleave, 35362306a36Sopenharmony_ci}; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic int 35662306a36Sopenharmony_cisrc_rsc_init(struct src *src, u32 idx, 35762306a36Sopenharmony_ci const struct src_desc *desc, struct src_mgr *mgr) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci int err; 36062306a36Sopenharmony_ci int i, n; 36162306a36Sopenharmony_ci struct src *p; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci n = (MEMRD == desc->mode) ? desc->multi : 1; 36462306a36Sopenharmony_ci for (i = 0, p = src; i < n; i++, p++) { 36562306a36Sopenharmony_ci err = rsc_init(&p->rsc, idx + i, SRC, desc->msr, mgr->mgr.hw); 36662306a36Sopenharmony_ci if (err) 36762306a36Sopenharmony_ci goto error1; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci /* Initialize src specific rsc operations */ 37062306a36Sopenharmony_ci p->ops = &src_rsc_ops; 37162306a36Sopenharmony_ci p->multi = (0 == i) ? desc->multi : 1; 37262306a36Sopenharmony_ci p->mode = desc->mode; 37362306a36Sopenharmony_ci src_default_config[desc->mode](p); 37462306a36Sopenharmony_ci mgr->src_enable(mgr, p); 37562306a36Sopenharmony_ci p->intlv = p + 1; 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci (--p)->intlv = NULL; /* Set @intlv of the last SRC to NULL */ 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci mgr->commit_write(mgr); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci return 0; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cierror1: 38462306a36Sopenharmony_ci for (i--, p--; i >= 0; i--, p--) { 38562306a36Sopenharmony_ci mgr->src_disable(mgr, p); 38662306a36Sopenharmony_ci rsc_uninit(&p->rsc); 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci mgr->commit_write(mgr); 38962306a36Sopenharmony_ci return err; 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cistatic int src_rsc_uninit(struct src *src, struct src_mgr *mgr) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci int i, n; 39562306a36Sopenharmony_ci struct src *p; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci n = (MEMRD == src->mode) ? src->multi : 1; 39862306a36Sopenharmony_ci for (i = 0, p = src; i < n; i++, p++) { 39962306a36Sopenharmony_ci mgr->src_disable(mgr, p); 40062306a36Sopenharmony_ci rsc_uninit(&p->rsc); 40162306a36Sopenharmony_ci p->multi = 0; 40262306a36Sopenharmony_ci p->ops = NULL; 40362306a36Sopenharmony_ci p->mode = NUM_SRCMODES; 40462306a36Sopenharmony_ci p->intlv = NULL; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci mgr->commit_write(mgr); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci return 0; 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic int 41262306a36Sopenharmony_ciget_src_rsc(struct src_mgr *mgr, const struct src_desc *desc, struct src **rsrc) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci unsigned int idx = SRC_RESOURCE_NUM; 41562306a36Sopenharmony_ci int err; 41662306a36Sopenharmony_ci struct src *src; 41762306a36Sopenharmony_ci unsigned long flags; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci *rsrc = NULL; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci /* Check whether there are sufficient src resources to meet request. */ 42262306a36Sopenharmony_ci spin_lock_irqsave(&mgr->mgr_lock, flags); 42362306a36Sopenharmony_ci if (MEMRD == desc->mode) 42462306a36Sopenharmony_ci err = mgr_get_resource(&mgr->mgr, desc->multi, &idx); 42562306a36Sopenharmony_ci else 42662306a36Sopenharmony_ci err = mgr_get_resource(&mgr->mgr, 1, &idx); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci spin_unlock_irqrestore(&mgr->mgr_lock, flags); 42962306a36Sopenharmony_ci if (err) { 43062306a36Sopenharmony_ci dev_err(mgr->card->dev, 43162306a36Sopenharmony_ci "Can't meet SRC resource request!\n"); 43262306a36Sopenharmony_ci return err; 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci /* Allocate mem for master src resource */ 43662306a36Sopenharmony_ci if (MEMRD == desc->mode) 43762306a36Sopenharmony_ci src = kcalloc(desc->multi, sizeof(*src), GFP_KERNEL); 43862306a36Sopenharmony_ci else 43962306a36Sopenharmony_ci src = kzalloc(sizeof(*src), GFP_KERNEL); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci if (!src) { 44262306a36Sopenharmony_ci err = -ENOMEM; 44362306a36Sopenharmony_ci goto error1; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci err = src_rsc_init(src, idx, desc, mgr); 44762306a36Sopenharmony_ci if (err) 44862306a36Sopenharmony_ci goto error2; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci *rsrc = src; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci return 0; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_cierror2: 45562306a36Sopenharmony_ci kfree(src); 45662306a36Sopenharmony_cierror1: 45762306a36Sopenharmony_ci spin_lock_irqsave(&mgr->mgr_lock, flags); 45862306a36Sopenharmony_ci if (MEMRD == desc->mode) 45962306a36Sopenharmony_ci mgr_put_resource(&mgr->mgr, desc->multi, idx); 46062306a36Sopenharmony_ci else 46162306a36Sopenharmony_ci mgr_put_resource(&mgr->mgr, 1, idx); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci spin_unlock_irqrestore(&mgr->mgr_lock, flags); 46462306a36Sopenharmony_ci return err; 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_cistatic int put_src_rsc(struct src_mgr *mgr, struct src *src) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci unsigned long flags; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci spin_lock_irqsave(&mgr->mgr_lock, flags); 47262306a36Sopenharmony_ci src->rsc.ops->master(&src->rsc); 47362306a36Sopenharmony_ci if (MEMRD == src->mode) 47462306a36Sopenharmony_ci mgr_put_resource(&mgr->mgr, src->multi, 47562306a36Sopenharmony_ci src->rsc.ops->index(&src->rsc)); 47662306a36Sopenharmony_ci else 47762306a36Sopenharmony_ci mgr_put_resource(&mgr->mgr, 1, src->rsc.ops->index(&src->rsc)); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci spin_unlock_irqrestore(&mgr->mgr_lock, flags); 48062306a36Sopenharmony_ci src_rsc_uninit(src, mgr); 48162306a36Sopenharmony_ci kfree(src); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci return 0; 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic int src_enable_s(struct src_mgr *mgr, struct src *src) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci struct hw *hw = mgr->mgr.hw; 48962306a36Sopenharmony_ci int i; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci src->rsc.ops->master(&src->rsc); 49262306a36Sopenharmony_ci for (i = 0; i < src->rsc.msr; i++) { 49362306a36Sopenharmony_ci hw->src_mgr_enbs_src(mgr->mgr.ctrl_blk, 49462306a36Sopenharmony_ci src->rsc.ops->index(&src->rsc)); 49562306a36Sopenharmony_ci src->rsc.ops->next_conj(&src->rsc); 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci src->rsc.ops->master(&src->rsc); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci return 0; 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic int src_enable(struct src_mgr *mgr, struct src *src) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci struct hw *hw = mgr->mgr.hw; 50562306a36Sopenharmony_ci int i; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci src->rsc.ops->master(&src->rsc); 50862306a36Sopenharmony_ci for (i = 0; i < src->rsc.msr; i++) { 50962306a36Sopenharmony_ci hw->src_mgr_enb_src(mgr->mgr.ctrl_blk, 51062306a36Sopenharmony_ci src->rsc.ops->index(&src->rsc)); 51162306a36Sopenharmony_ci src->rsc.ops->next_conj(&src->rsc); 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci src->rsc.ops->master(&src->rsc); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci return 0; 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_cistatic int src_disable(struct src_mgr *mgr, struct src *src) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci struct hw *hw = mgr->mgr.hw; 52162306a36Sopenharmony_ci int i; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci src->rsc.ops->master(&src->rsc); 52462306a36Sopenharmony_ci for (i = 0; i < src->rsc.msr; i++) { 52562306a36Sopenharmony_ci hw->src_mgr_dsb_src(mgr->mgr.ctrl_blk, 52662306a36Sopenharmony_ci src->rsc.ops->index(&src->rsc)); 52762306a36Sopenharmony_ci src->rsc.ops->next_conj(&src->rsc); 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci src->rsc.ops->master(&src->rsc); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci return 0; 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_cistatic int src_mgr_commit_write(struct src_mgr *mgr) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci struct hw *hw = mgr->mgr.hw; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci hw->src_mgr_commit_write(hw, mgr->mgr.ctrl_blk); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci return 0; 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ciint src_mgr_create(struct hw *hw, struct src_mgr **rsrc_mgr) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci int err, i; 54662306a36Sopenharmony_ci struct src_mgr *src_mgr; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci *rsrc_mgr = NULL; 54962306a36Sopenharmony_ci src_mgr = kzalloc(sizeof(*src_mgr), GFP_KERNEL); 55062306a36Sopenharmony_ci if (!src_mgr) 55162306a36Sopenharmony_ci return -ENOMEM; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci err = rsc_mgr_init(&src_mgr->mgr, SRC, SRC_RESOURCE_NUM, hw); 55462306a36Sopenharmony_ci if (err) 55562306a36Sopenharmony_ci goto error1; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci spin_lock_init(&src_mgr->mgr_lock); 55862306a36Sopenharmony_ci conj_mask = hw->src_dirty_conj_mask(); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci src_mgr->get_src = get_src_rsc; 56162306a36Sopenharmony_ci src_mgr->put_src = put_src_rsc; 56262306a36Sopenharmony_ci src_mgr->src_enable_s = src_enable_s; 56362306a36Sopenharmony_ci src_mgr->src_enable = src_enable; 56462306a36Sopenharmony_ci src_mgr->src_disable = src_disable; 56562306a36Sopenharmony_ci src_mgr->commit_write = src_mgr_commit_write; 56662306a36Sopenharmony_ci src_mgr->card = hw->card; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci /* Disable all SRC resources. */ 56962306a36Sopenharmony_ci for (i = 0; i < 256; i++) 57062306a36Sopenharmony_ci hw->src_mgr_dsb_src(src_mgr->mgr.ctrl_blk, i); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci hw->src_mgr_commit_write(hw, src_mgr->mgr.ctrl_blk); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci *rsrc_mgr = src_mgr; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci return 0; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_cierror1: 57962306a36Sopenharmony_ci kfree(src_mgr); 58062306a36Sopenharmony_ci return err; 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ciint src_mgr_destroy(struct src_mgr *src_mgr) 58462306a36Sopenharmony_ci{ 58562306a36Sopenharmony_ci rsc_mgr_uninit(&src_mgr->mgr); 58662306a36Sopenharmony_ci kfree(src_mgr); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci return 0; 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci/* SRCIMP resource manager operations */ 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic void srcimp_master(struct rsc *rsc) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci rsc->conj = 0; 59662306a36Sopenharmony_ci rsc->idx = container_of(rsc, struct srcimp, rsc)->idx[0]; 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_cistatic void srcimp_next_conj(struct rsc *rsc) 60062306a36Sopenharmony_ci{ 60162306a36Sopenharmony_ci rsc->conj++; 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cistatic int srcimp_index(const struct rsc *rsc) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci return container_of(rsc, struct srcimp, rsc)->idx[rsc->conj]; 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cistatic const struct rsc_ops srcimp_basic_rsc_ops = { 61062306a36Sopenharmony_ci .master = srcimp_master, 61162306a36Sopenharmony_ci .next_conj = srcimp_next_conj, 61262306a36Sopenharmony_ci .index = srcimp_index, 61362306a36Sopenharmony_ci .output_slot = NULL, 61462306a36Sopenharmony_ci}; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_cistatic int srcimp_map(struct srcimp *srcimp, struct src *src, struct rsc *input) 61762306a36Sopenharmony_ci{ 61862306a36Sopenharmony_ci struct imapper *entry; 61962306a36Sopenharmony_ci int i; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci srcimp->rsc.ops->master(&srcimp->rsc); 62262306a36Sopenharmony_ci src->rsc.ops->master(&src->rsc); 62362306a36Sopenharmony_ci input->ops->master(input); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci /* Program master and conjugate resources */ 62662306a36Sopenharmony_ci for (i = 0; i < srcimp->rsc.msr; i++) { 62762306a36Sopenharmony_ci entry = &srcimp->imappers[i]; 62862306a36Sopenharmony_ci entry->slot = input->ops->output_slot(input); 62962306a36Sopenharmony_ci entry->user = src->rsc.ops->index(&src->rsc); 63062306a36Sopenharmony_ci entry->addr = srcimp->rsc.ops->index(&srcimp->rsc); 63162306a36Sopenharmony_ci srcimp->mgr->imap_add(srcimp->mgr, entry); 63262306a36Sopenharmony_ci srcimp->mapped |= (0x1 << i); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci srcimp->rsc.ops->next_conj(&srcimp->rsc); 63562306a36Sopenharmony_ci input->ops->next_conj(input); 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci srcimp->rsc.ops->master(&srcimp->rsc); 63962306a36Sopenharmony_ci input->ops->master(input); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci return 0; 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_cistatic int srcimp_unmap(struct srcimp *srcimp) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci int i; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci /* Program master and conjugate resources */ 64962306a36Sopenharmony_ci for (i = 0; i < srcimp->rsc.msr; i++) { 65062306a36Sopenharmony_ci if (srcimp->mapped & (0x1 << i)) { 65162306a36Sopenharmony_ci srcimp->mgr->imap_delete(srcimp->mgr, 65262306a36Sopenharmony_ci &srcimp->imappers[i]); 65362306a36Sopenharmony_ci srcimp->mapped &= ~(0x1 << i); 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci return 0; 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_cistatic const struct srcimp_rsc_ops srcimp_ops = { 66162306a36Sopenharmony_ci .map = srcimp_map, 66262306a36Sopenharmony_ci .unmap = srcimp_unmap 66362306a36Sopenharmony_ci}; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_cistatic int srcimp_rsc_init(struct srcimp *srcimp, 66662306a36Sopenharmony_ci const struct srcimp_desc *desc, 66762306a36Sopenharmony_ci struct srcimp_mgr *mgr) 66862306a36Sopenharmony_ci{ 66962306a36Sopenharmony_ci int err; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci err = rsc_init(&srcimp->rsc, srcimp->idx[0], 67262306a36Sopenharmony_ci SRCIMP, desc->msr, mgr->mgr.hw); 67362306a36Sopenharmony_ci if (err) 67462306a36Sopenharmony_ci return err; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci /* Reserve memory for imapper nodes */ 67762306a36Sopenharmony_ci srcimp->imappers = kcalloc(desc->msr, sizeof(struct imapper), 67862306a36Sopenharmony_ci GFP_KERNEL); 67962306a36Sopenharmony_ci if (!srcimp->imappers) { 68062306a36Sopenharmony_ci err = -ENOMEM; 68162306a36Sopenharmony_ci goto error1; 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci /* Set srcimp specific operations */ 68562306a36Sopenharmony_ci srcimp->rsc.ops = &srcimp_basic_rsc_ops; 68662306a36Sopenharmony_ci srcimp->ops = &srcimp_ops; 68762306a36Sopenharmony_ci srcimp->mgr = mgr; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci srcimp->rsc.ops->master(&srcimp->rsc); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci return 0; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_cierror1: 69462306a36Sopenharmony_ci rsc_uninit(&srcimp->rsc); 69562306a36Sopenharmony_ci return err; 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_cistatic int srcimp_rsc_uninit(struct srcimp *srcimp) 69962306a36Sopenharmony_ci{ 70062306a36Sopenharmony_ci kfree(srcimp->imappers); 70162306a36Sopenharmony_ci srcimp->imappers = NULL; 70262306a36Sopenharmony_ci srcimp->ops = NULL; 70362306a36Sopenharmony_ci srcimp->mgr = NULL; 70462306a36Sopenharmony_ci rsc_uninit(&srcimp->rsc); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci return 0; 70762306a36Sopenharmony_ci} 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_cistatic int get_srcimp_rsc(struct srcimp_mgr *mgr, 71062306a36Sopenharmony_ci const struct srcimp_desc *desc, 71162306a36Sopenharmony_ci struct srcimp **rsrcimp) 71262306a36Sopenharmony_ci{ 71362306a36Sopenharmony_ci int err, i; 71462306a36Sopenharmony_ci unsigned int idx; 71562306a36Sopenharmony_ci struct srcimp *srcimp; 71662306a36Sopenharmony_ci unsigned long flags; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci *rsrcimp = NULL; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci /* Allocate mem for SRCIMP resource */ 72162306a36Sopenharmony_ci srcimp = kzalloc(sizeof(*srcimp), GFP_KERNEL); 72262306a36Sopenharmony_ci if (!srcimp) 72362306a36Sopenharmony_ci return -ENOMEM; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci /* Check whether there are sufficient SRCIMP resources. */ 72662306a36Sopenharmony_ci err = 0; 72762306a36Sopenharmony_ci spin_lock_irqsave(&mgr->mgr_lock, flags); 72862306a36Sopenharmony_ci for (i = 0; i < desc->msr; i++) { 72962306a36Sopenharmony_ci err = mgr_get_resource(&mgr->mgr, 1, &idx); 73062306a36Sopenharmony_ci if (err) 73162306a36Sopenharmony_ci break; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci srcimp->idx[i] = idx; 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci spin_unlock_irqrestore(&mgr->mgr_lock, flags); 73662306a36Sopenharmony_ci if (err) { 73762306a36Sopenharmony_ci dev_err(mgr->card->dev, 73862306a36Sopenharmony_ci "Can't meet SRCIMP resource request!\n"); 73962306a36Sopenharmony_ci goto error1; 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci err = srcimp_rsc_init(srcimp, desc, mgr); 74362306a36Sopenharmony_ci if (err) 74462306a36Sopenharmony_ci goto error1; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci *rsrcimp = srcimp; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci return 0; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_cierror1: 75162306a36Sopenharmony_ci spin_lock_irqsave(&mgr->mgr_lock, flags); 75262306a36Sopenharmony_ci for (i--; i >= 0; i--) 75362306a36Sopenharmony_ci mgr_put_resource(&mgr->mgr, 1, srcimp->idx[i]); 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci spin_unlock_irqrestore(&mgr->mgr_lock, flags); 75662306a36Sopenharmony_ci kfree(srcimp); 75762306a36Sopenharmony_ci return err; 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_cistatic int put_srcimp_rsc(struct srcimp_mgr *mgr, struct srcimp *srcimp) 76162306a36Sopenharmony_ci{ 76262306a36Sopenharmony_ci unsigned long flags; 76362306a36Sopenharmony_ci int i; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci spin_lock_irqsave(&mgr->mgr_lock, flags); 76662306a36Sopenharmony_ci for (i = 0; i < srcimp->rsc.msr; i++) 76762306a36Sopenharmony_ci mgr_put_resource(&mgr->mgr, 1, srcimp->idx[i]); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci spin_unlock_irqrestore(&mgr->mgr_lock, flags); 77062306a36Sopenharmony_ci srcimp_rsc_uninit(srcimp); 77162306a36Sopenharmony_ci kfree(srcimp); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci return 0; 77462306a36Sopenharmony_ci} 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_cistatic int srcimp_map_op(void *data, struct imapper *entry) 77762306a36Sopenharmony_ci{ 77862306a36Sopenharmony_ci struct rsc_mgr *mgr = &((struct srcimp_mgr *)data)->mgr; 77962306a36Sopenharmony_ci struct hw *hw = mgr->hw; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci hw->srcimp_mgr_set_imaparc(mgr->ctrl_blk, entry->slot); 78262306a36Sopenharmony_ci hw->srcimp_mgr_set_imapuser(mgr->ctrl_blk, entry->user); 78362306a36Sopenharmony_ci hw->srcimp_mgr_set_imapnxt(mgr->ctrl_blk, entry->next); 78462306a36Sopenharmony_ci hw->srcimp_mgr_set_imapaddr(mgr->ctrl_blk, entry->addr); 78562306a36Sopenharmony_ci hw->srcimp_mgr_commit_write(mgr->hw, mgr->ctrl_blk); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci return 0; 78862306a36Sopenharmony_ci} 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_cistatic int srcimp_imap_add(struct srcimp_mgr *mgr, struct imapper *entry) 79162306a36Sopenharmony_ci{ 79262306a36Sopenharmony_ci unsigned long flags; 79362306a36Sopenharmony_ci int err; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci spin_lock_irqsave(&mgr->imap_lock, flags); 79662306a36Sopenharmony_ci if ((0 == entry->addr) && (mgr->init_imap_added)) { 79762306a36Sopenharmony_ci input_mapper_delete(&mgr->imappers, 79862306a36Sopenharmony_ci mgr->init_imap, srcimp_map_op, mgr); 79962306a36Sopenharmony_ci mgr->init_imap_added = 0; 80062306a36Sopenharmony_ci } 80162306a36Sopenharmony_ci err = input_mapper_add(&mgr->imappers, entry, srcimp_map_op, mgr); 80262306a36Sopenharmony_ci spin_unlock_irqrestore(&mgr->imap_lock, flags); 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci return err; 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_cistatic int srcimp_imap_delete(struct srcimp_mgr *mgr, struct imapper *entry) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci unsigned long flags; 81062306a36Sopenharmony_ci int err; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci spin_lock_irqsave(&mgr->imap_lock, flags); 81362306a36Sopenharmony_ci err = input_mapper_delete(&mgr->imappers, entry, srcimp_map_op, mgr); 81462306a36Sopenharmony_ci if (list_empty(&mgr->imappers)) { 81562306a36Sopenharmony_ci input_mapper_add(&mgr->imappers, mgr->init_imap, 81662306a36Sopenharmony_ci srcimp_map_op, mgr); 81762306a36Sopenharmony_ci mgr->init_imap_added = 1; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci spin_unlock_irqrestore(&mgr->imap_lock, flags); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci return err; 82262306a36Sopenharmony_ci} 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ciint srcimp_mgr_create(struct hw *hw, struct srcimp_mgr **rsrcimp_mgr) 82562306a36Sopenharmony_ci{ 82662306a36Sopenharmony_ci int err; 82762306a36Sopenharmony_ci struct srcimp_mgr *srcimp_mgr; 82862306a36Sopenharmony_ci struct imapper *entry; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci *rsrcimp_mgr = NULL; 83162306a36Sopenharmony_ci srcimp_mgr = kzalloc(sizeof(*srcimp_mgr), GFP_KERNEL); 83262306a36Sopenharmony_ci if (!srcimp_mgr) 83362306a36Sopenharmony_ci return -ENOMEM; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci err = rsc_mgr_init(&srcimp_mgr->mgr, SRCIMP, SRCIMP_RESOURCE_NUM, hw); 83662306a36Sopenharmony_ci if (err) 83762306a36Sopenharmony_ci goto error1; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci spin_lock_init(&srcimp_mgr->mgr_lock); 84062306a36Sopenharmony_ci spin_lock_init(&srcimp_mgr->imap_lock); 84162306a36Sopenharmony_ci INIT_LIST_HEAD(&srcimp_mgr->imappers); 84262306a36Sopenharmony_ci entry = kzalloc(sizeof(*entry), GFP_KERNEL); 84362306a36Sopenharmony_ci if (!entry) { 84462306a36Sopenharmony_ci err = -ENOMEM; 84562306a36Sopenharmony_ci goto error2; 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci entry->slot = entry->addr = entry->next = entry->user = 0; 84862306a36Sopenharmony_ci list_add(&entry->list, &srcimp_mgr->imappers); 84962306a36Sopenharmony_ci srcimp_mgr->init_imap = entry; 85062306a36Sopenharmony_ci srcimp_mgr->init_imap_added = 1; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci srcimp_mgr->get_srcimp = get_srcimp_rsc; 85362306a36Sopenharmony_ci srcimp_mgr->put_srcimp = put_srcimp_rsc; 85462306a36Sopenharmony_ci srcimp_mgr->imap_add = srcimp_imap_add; 85562306a36Sopenharmony_ci srcimp_mgr->imap_delete = srcimp_imap_delete; 85662306a36Sopenharmony_ci srcimp_mgr->card = hw->card; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci *rsrcimp_mgr = srcimp_mgr; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci return 0; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_cierror2: 86362306a36Sopenharmony_ci rsc_mgr_uninit(&srcimp_mgr->mgr); 86462306a36Sopenharmony_cierror1: 86562306a36Sopenharmony_ci kfree(srcimp_mgr); 86662306a36Sopenharmony_ci return err; 86762306a36Sopenharmony_ci} 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ciint srcimp_mgr_destroy(struct srcimp_mgr *srcimp_mgr) 87062306a36Sopenharmony_ci{ 87162306a36Sopenharmony_ci unsigned long flags; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci /* free src input mapper list */ 87462306a36Sopenharmony_ci spin_lock_irqsave(&srcimp_mgr->imap_lock, flags); 87562306a36Sopenharmony_ci free_input_mapper_list(&srcimp_mgr->imappers); 87662306a36Sopenharmony_ci spin_unlock_irqrestore(&srcimp_mgr->imap_lock, flags); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci rsc_mgr_uninit(&srcimp_mgr->mgr); 87962306a36Sopenharmony_ci kfree(srcimp_mgr); 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci return 0; 88262306a36Sopenharmony_ci} 883