| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988 |
- // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
- //
- // This file is provided under a dual BSD/GPLv2 license. When using or
- // redistributing this file, you may do so under either license.
- //
- // Copyright(c) 2022 Intel Corporation
- //
- //
- #include <linux/bitfield.h>
- #include <linux/cleanup.h>
- #include <uapi/sound/sof/tokens.h>
- #include <sound/pcm_params.h>
- #include <sound/sof/ext_manifest4.h>
- #include <sound/intel-nhlt.h>
- #include "sof-priv.h"
- #include "sof-audio.h"
- #include "ipc4-priv.h"
- #include "ipc4-topology.h"
- #include "ops.h"
- /*
- * The ignore_cpc flag can be used to ignore the CPC value for all modules by
- * using 0 instead.
- * The CPC is sent to the firmware along with the SOF_IPC4_MOD_INIT_INSTANCE
- * message and it is used for clock scaling.
- * 0 as CPC value will instruct the firmware to use maximum frequency, thus
- * deactivating the clock scaling.
- */
- static bool ignore_cpc;
- module_param_named(ipc4_ignore_cpc, ignore_cpc, bool, 0444);
- MODULE_PARM_DESC(ipc4_ignore_cpc,
- "Ignore CPC values. This option will disable clock scaling in firmware.");
- #define SOF_IPC4_GAIN_PARAM_ID 0
- #define SOF_IPC4_TPLG_ABI_SIZE 6
- static DEFINE_IDA(alh_group_ida);
- static DEFINE_IDA(pipeline_ida);
- struct sof_comp_domains {
- const char *name;
- enum sof_comp_domain domain;
- };
- static const struct sof_comp_domains sof_domains[] = {
- { "LL", SOF_COMP_DOMAIN_LL, },
- { "DP", SOF_COMP_DOMAIN_DP, }
- };
- static enum sof_comp_domain find_domain(const char *name)
- {
- int i;
- for (i = 0; i < ARRAY_SIZE(sof_domains); i++) {
- if (strcmp(name, sof_domains[i].name) == 0)
- return sof_domains[i].domain;
- }
- /* No valid value found, fall back to manifest value */
- return SOF_COMP_DOMAIN_UNSET;
- }
- static int get_token_comp_domain(void *elem, void *object, u32 offset)
- {
- u32 *val = (u32 *)((u8 *)object + offset);
- *val = find_domain((const char *)elem);
- return 0;
- }
- static const struct sof_topology_token ipc4_sched_tokens[] = {
- {SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_pipeline, lp_mode)},
- {SOF_TKN_SCHED_USE_CHAIN_DMA, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
- offsetof(struct sof_ipc4_pipeline, use_chain_dma)},
- {SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_pipeline, core_id)},
- {SOF_TKN_SCHED_PRIORITY, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_pipeline, priority)},
- {SOF_TKN_SCHED_DIRECTION, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_pipeline, direction)},
- {SOF_TKN_SCHED_DIRECTION, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
- offsetof(struct sof_ipc4_pipeline, direction_valid)},
- };
- static const struct sof_topology_token pipeline_tokens[] = {
- {SOF_TKN_SCHED_DYNAMIC_PIPELINE, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
- offsetof(struct snd_sof_widget, dynamic_pipeline_widget)},
- };
- static const struct sof_topology_token ipc4_comp_tokens[] = {
- {SOF_TKN_COMP_IS_PAGES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_base_module_cfg, is_pages)},
- };
- static const struct sof_topology_token ipc4_in_audio_format_tokens[] = {
- {SOF_TKN_CAVS_AUDIO_FORMAT_IN_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_pin_format, audio_fmt.sampling_frequency)},
- {SOF_TKN_CAVS_AUDIO_FORMAT_IN_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_pin_format, audio_fmt.bit_depth)},
- {SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_map)},
- {SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_cfg)},
- {SOF_TKN_CAVS_AUDIO_FORMAT_IN_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
- get_token_u32, offsetof(struct sof_ipc4_pin_format,
- audio_fmt.interleaving_style)},
- {SOF_TKN_CAVS_AUDIO_FORMAT_IN_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_pin_format, audio_fmt.fmt_cfg)},
- {SOF_TKN_CAVS_AUDIO_FORMAT_INPUT_PIN_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_pin_format, pin_index)},
- {SOF_TKN_CAVS_AUDIO_FORMAT_IBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_pin_format, buffer_size)},
- };
- static const struct sof_topology_token ipc4_out_audio_format_tokens[] = {
- {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_pin_format, audio_fmt.sampling_frequency)},
- {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_pin_format, audio_fmt.bit_depth)},
- {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_map)},
- {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_cfg)},
- {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
- get_token_u32, offsetof(struct sof_ipc4_pin_format,
- audio_fmt.interleaving_style)},
- {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_pin_format, audio_fmt.fmt_cfg)},
- {SOF_TKN_CAVS_AUDIO_FORMAT_OUTPUT_PIN_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_pin_format, pin_index)},
- {SOF_TKN_CAVS_AUDIO_FORMAT_OBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_pin_format, buffer_size)},
- };
- static const struct sof_topology_token ipc4_copier_deep_buffer_tokens[] = {
- {SOF_TKN_INTEL_COPIER_DEEP_BUFFER_DMA_MS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0},
- };
- static const struct sof_topology_token ipc4_copier_tokens[] = {
- {SOF_TKN_INTEL_COPIER_NODE_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0},
- };
- static const struct sof_topology_token ipc4_audio_fmt_num_tokens[] = {
- {SOF_TKN_COMP_NUM_INPUT_AUDIO_FORMATS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_available_audio_format, num_input_formats)},
- {SOF_TKN_COMP_NUM_OUTPUT_AUDIO_FORMATS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_available_audio_format, num_output_formats)},
- };
- static const struct sof_topology_token dai_tokens[] = {
- {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type,
- offsetof(struct sof_ipc4_copier, dai_type)},
- {SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_copier, dai_index)},
- };
- /* Component extended tokens */
- static const struct sof_topology_token comp_ext_tokens[] = {
- {SOF_TKN_COMP_UUID, SND_SOC_TPLG_TUPLE_TYPE_UUID, get_token_uuid,
- offsetof(struct snd_sof_widget, uuid)},
- {SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct snd_sof_widget, core)},
- {SOF_TKN_COMP_SCHED_DOMAIN, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_domain,
- offsetof(struct snd_sof_widget, comp_domain)},
- {SOF_TKN_COMP_DOMAIN_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct snd_sof_widget, dp_domain_id)},
- {SOF_TKN_COMP_HEAP_BYTES_REQUIREMENT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct snd_sof_widget, dp_heap_bytes)},
- {SOF_TKN_COMP_STACK_BYTES_REQUIREMENT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct snd_sof_widget, dp_stack_bytes)},
- };
- static const struct sof_topology_token gain_tokens[] = {
- {SOF_TKN_GAIN_RAMP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
- get_token_u32, offsetof(struct sof_ipc4_gain_params, curve_type)},
- {SOF_TKN_GAIN_RAMP_DURATION,
- SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_gain_params, curve_duration_l)},
- {SOF_TKN_GAIN_VAL, SND_SOC_TPLG_TUPLE_TYPE_WORD,
- get_token_u32, offsetof(struct sof_ipc4_gain_params, init_val)},
- };
- /* SRC */
- static const struct sof_topology_token src_tokens[] = {
- {SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_src_data, sink_rate)},
- };
- /* ASRC */
- static const struct sof_topology_token asrc_tokens[] = {
- {SOF_TKN_ASRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_asrc_data, out_freq)},
- {SOF_TKN_ASRC_OPERATION_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct sof_ipc4_asrc_data, asrc_mode)},
- };
- static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = {
- [SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)},
- [SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)},
- [SOF_SCHED_TOKENS] = {"Scheduler tokens", ipc4_sched_tokens,
- ARRAY_SIZE(ipc4_sched_tokens)},
- [SOF_COMP_EXT_TOKENS] = {"Comp extended tokens", comp_ext_tokens,
- ARRAY_SIZE(comp_ext_tokens)},
- [SOF_COMP_TOKENS] = {"IPC4 Component tokens",
- ipc4_comp_tokens, ARRAY_SIZE(ipc4_comp_tokens)},
- [SOF_IN_AUDIO_FORMAT_TOKENS] = {"IPC4 Input Audio format tokens",
- ipc4_in_audio_format_tokens, ARRAY_SIZE(ipc4_in_audio_format_tokens)},
- [SOF_OUT_AUDIO_FORMAT_TOKENS] = {"IPC4 Output Audio format tokens",
- ipc4_out_audio_format_tokens, ARRAY_SIZE(ipc4_out_audio_format_tokens)},
- [SOF_COPIER_DEEP_BUFFER_TOKENS] = {"IPC4 Copier deep buffer tokens",
- ipc4_copier_deep_buffer_tokens, ARRAY_SIZE(ipc4_copier_deep_buffer_tokens)},
- [SOF_COPIER_TOKENS] = {"IPC4 Copier tokens", ipc4_copier_tokens,
- ARRAY_SIZE(ipc4_copier_tokens)},
- [SOF_AUDIO_FMT_NUM_TOKENS] = {"IPC4 Audio format number tokens",
- ipc4_audio_fmt_num_tokens, ARRAY_SIZE(ipc4_audio_fmt_num_tokens)},
- [SOF_GAIN_TOKENS] = {"Gain tokens", gain_tokens, ARRAY_SIZE(gain_tokens)},
- [SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)},
- [SOF_ASRC_TOKENS] = {"ASRC tokens", asrc_tokens, ARRAY_SIZE(asrc_tokens)},
- };
- struct snd_sof_widget *sof_ipc4_find_swidget_by_ids(struct snd_sof_dev *sdev,
- u32 module_id, int instance_id)
- {
- struct snd_sof_widget *swidget;
- list_for_each_entry(swidget, &sdev->widget_list, list) {
- struct sof_ipc4_fw_module *fw_module = swidget->module_info;
- /* Only active module instances have valid instance_id */
- if (!swidget->use_count)
- continue;
- if (fw_module && fw_module->man4_module_entry.id == module_id &&
- swidget->instance_id == instance_id)
- return swidget;
- }
- return NULL;
- }
- static void sof_ipc4_dbg_audio_format(struct device *dev, struct sof_ipc4_pin_format *pin_fmt,
- int num_formats)
- {
- int i;
- for (i = 0; i < num_formats; i++) {
- struct sof_ipc4_audio_format *fmt = &pin_fmt[i].audio_fmt;
- dev_dbg(dev,
- "Pin #%d: %uHz, %ubit, %luch (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x) buffer size %d\n",
- pin_fmt[i].pin_index, fmt->sampling_frequency, fmt->bit_depth,
- SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg),
- fmt->ch_map, fmt->ch_cfg, fmt->interleaving_style, fmt->fmt_cfg,
- pin_fmt[i].buffer_size);
- }
- }
- static void
- sof_ipc4_dbg_module_audio_format(struct device *dev,
- struct snd_sof_widget *swidget,
- struct sof_ipc4_available_audio_format *available_fmt,
- int in_fmt_index, int out_fmt_index)
- {
- struct sof_ipc4_audio_format *in_fmt, *out_fmt;
- u32 out_rate, out_channels, out_valid_bits;
- u32 in_rate, in_channels, in_valid_bits;
- struct sof_ipc4_pin_format *pin_fmt;
- if (!available_fmt->num_input_formats &&
- !available_fmt->num_output_formats)
- return;
- /* Only input or output is supported by the module */
- if (!available_fmt->num_input_formats) {
- if (available_fmt->num_output_formats == 1)
- dev_dbg(dev, "Output audio format for %s:\n",
- swidget->widget->name);
- else
- dev_dbg(dev,
- "Output audio format (format index: %d) for %s:\n",
- out_fmt_index, swidget->widget->name);
- pin_fmt = &available_fmt->output_pin_fmts[out_fmt_index];
- sof_ipc4_dbg_audio_format(dev, pin_fmt, 1);
- return;
- } else if (!available_fmt->num_output_formats) {
- if (available_fmt->num_input_formats == 1)
- dev_dbg(dev, "Input audio format for %s:\n",
- swidget->widget->name);
- else
- dev_dbg(dev,
- "Input audio format (format index: %d) for %s:\n",
- out_fmt_index, swidget->widget->name);
- pin_fmt = &available_fmt->input_pin_fmts[in_fmt_index];
- sof_ipc4_dbg_audio_format(dev, pin_fmt, 1);
- return;
- }
- in_fmt = &available_fmt->input_pin_fmts[in_fmt_index].audio_fmt;
- out_fmt = &available_fmt->output_pin_fmts[out_fmt_index].audio_fmt;
- in_rate = in_fmt->sampling_frequency;
- in_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
- in_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
- out_rate = out_fmt->sampling_frequency;
- out_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(out_fmt->fmt_cfg);
- out_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(out_fmt->fmt_cfg);
- if (!(in_valid_bits != out_valid_bits || in_rate != out_rate ||
- in_channels != out_channels)) {
- /* There is no change in format */
- if (available_fmt->num_input_formats == 1 &&
- available_fmt->num_output_formats == 1)
- dev_dbg(dev, "Audio format for %s:\n",
- swidget->widget->name);
- else
- dev_dbg(dev,
- "Audio format (in/out format index: %d/%d) for %s:\n",
- in_fmt_index, out_fmt_index, swidget->widget->name);
- pin_fmt = &available_fmt->input_pin_fmts[in_fmt_index];
- sof_ipc4_dbg_audio_format(dev, pin_fmt, 1);
- return;
- }
- /* The format is changed by the module */
- if (available_fmt->num_input_formats == 1)
- dev_dbg(dev, "Input audio format for %s:\n",
- swidget->widget->name);
- else
- dev_dbg(dev, "Input audio format (format index: %d) for %s:\n",
- in_fmt_index, swidget->widget->name);
- pin_fmt = &available_fmt->input_pin_fmts[in_fmt_index];
- sof_ipc4_dbg_audio_format(dev, pin_fmt, 1);
- if (available_fmt->num_output_formats == 1)
- dev_dbg(dev, "Output audio format for %s:\n",
- swidget->widget->name);
- else
- dev_dbg(dev, "Output audio format (format index: %d) for %s:\n",
- out_fmt_index, swidget->widget->name);
- pin_fmt = &available_fmt->output_pin_fmts[out_fmt_index];
- sof_ipc4_dbg_audio_format(dev, pin_fmt, 1);
- }
- static const struct sof_ipc4_audio_format *
- sof_ipc4_get_input_pin_audio_fmt(struct snd_sof_widget *swidget, int pin_index)
- {
- struct sof_ipc4_base_module_cfg_ext *base_cfg_ext;
- struct sof_ipc4_process *process;
- int i;
- if (swidget->id != snd_soc_dapm_effect) {
- struct sof_ipc4_base_module_cfg *base = swidget->private;
- /* For non-process modules, base module config format is used for all input pins */
- return &base->audio_fmt;
- }
- process = swidget->private;
- /*
- * For process modules without base config extension, base module config
- * format is used for all input pins
- */
- if (process->init_config != SOF_IPC4_MODULE_INIT_CONFIG_TYPE_BASE_CFG_WITH_EXT)
- return &process->base_config.audio_fmt;
- base_cfg_ext = process->base_config_ext;
- /*
- * If there are multiple input formats available for a pin, the first available format
- * is chosen.
- */
- for (i = 0; i < base_cfg_ext->num_input_pin_fmts; i++) {
- struct sof_ipc4_pin_format *pin_format = &base_cfg_ext->pin_formats[i];
- if (pin_format->pin_index == pin_index)
- return &pin_format->audio_fmt;
- }
- return NULL;
- }
- /**
- * sof_ipc4_get_audio_fmt - get available audio formats from swidget->tuples
- * @scomp: pointer to pointer to SOC component
- * @swidget: pointer to struct snd_sof_widget containing tuples
- * @available_fmt: pointer to struct sof_ipc4_available_audio_format being filling in
- * @module_base_cfg: Pointer to the base_config in the module init IPC payload
- *
- * Return: 0 if successful
- */
- static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp,
- struct snd_sof_widget *swidget,
- struct sof_ipc4_available_audio_format *available_fmt,
- struct sof_ipc4_base_module_cfg *module_base_cfg)
- {
- struct sof_ipc4_pin_format *in_format = NULL;
- struct sof_ipc4_pin_format *out_format;
- int ret;
- ret = sof_update_ipc_object(scomp, available_fmt,
- SOF_AUDIO_FMT_NUM_TOKENS, swidget->tuples,
- swidget->num_tuples, sizeof(*available_fmt), 1);
- if (ret) {
- dev_err(scomp->dev, "Failed to parse audio format token count\n");
- return ret;
- }
- if (!available_fmt->num_input_formats && !available_fmt->num_output_formats) {
- dev_err(scomp->dev, "No input/output pin formats set in topology\n");
- return -EINVAL;
- }
- dev_dbg(scomp->dev,
- "Number of input audio formats: %d. Number of output audio formats: %d\n",
- available_fmt->num_input_formats, available_fmt->num_output_formats);
- /* set is_pages in the module's base_config */
- ret = sof_update_ipc_object(scomp, module_base_cfg, SOF_COMP_TOKENS, swidget->tuples,
- swidget->num_tuples, sizeof(*module_base_cfg), 1);
- if (ret) {
- dev_err(scomp->dev, "parse comp tokens for %s failed, error: %d\n",
- swidget->widget->name, ret);
- return ret;
- }
- dev_dbg(scomp->dev, "widget %s: is_pages: %d\n", swidget->widget->name,
- module_base_cfg->is_pages);
- if (available_fmt->num_input_formats) {
- in_format = kzalloc_objs(*in_format,
- available_fmt->num_input_formats);
- if (!in_format)
- return -ENOMEM;
- available_fmt->input_pin_fmts = in_format;
- ret = sof_update_ipc_object(scomp, in_format,
- SOF_IN_AUDIO_FORMAT_TOKENS, swidget->tuples,
- swidget->num_tuples, sizeof(*in_format),
- available_fmt->num_input_formats);
- if (ret) {
- dev_err(scomp->dev, "parse input audio fmt tokens failed %d\n", ret);
- goto err_in;
- }
- dev_dbg(scomp->dev, "Input audio formats for %s\n", swidget->widget->name);
- sof_ipc4_dbg_audio_format(scomp->dev, in_format,
- available_fmt->num_input_formats);
- }
- if (available_fmt->num_output_formats) {
- out_format = kzalloc_objs(*out_format,
- available_fmt->num_output_formats);
- if (!out_format) {
- ret = -ENOMEM;
- goto err_in;
- }
- ret = sof_update_ipc_object(scomp, out_format,
- SOF_OUT_AUDIO_FORMAT_TOKENS, swidget->tuples,
- swidget->num_tuples, sizeof(*out_format),
- available_fmt->num_output_formats);
- if (ret) {
- dev_err(scomp->dev, "parse output audio fmt tokens failed\n");
- goto err_out;
- }
- available_fmt->output_pin_fmts = out_format;
- dev_dbg(scomp->dev, "Output audio formats for %s\n", swidget->widget->name);
- sof_ipc4_dbg_audio_format(scomp->dev, out_format,
- available_fmt->num_output_formats);
- }
- return 0;
- err_out:
- kfree(out_format);
- err_in:
- kfree(in_format);
- available_fmt->input_pin_fmts = NULL;
- return ret;
- }
- /* release the memory allocated in sof_ipc4_get_audio_fmt */
- static void sof_ipc4_free_audio_fmt(struct sof_ipc4_available_audio_format *available_fmt)
- {
- kfree(available_fmt->output_pin_fmts);
- available_fmt->output_pin_fmts = NULL;
- kfree(available_fmt->input_pin_fmts);
- available_fmt->input_pin_fmts = NULL;
- }
- static void sof_ipc4_widget_free_comp_pipeline(struct snd_sof_widget *swidget)
- {
- kfree(swidget->private);
- }
- static int sof_ipc4_widget_set_module_info(struct snd_sof_widget *swidget)
- {
- struct snd_soc_component *scomp = swidget->scomp;
- struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
- swidget->module_info = sof_ipc4_find_module_by_uuid(sdev, &swidget->uuid);
- if (swidget->module_info)
- return 0;
- dev_err(sdev->dev, "failed to find module info for widget %s with UUID %pUL\n",
- swidget->widget->name, &swidget->uuid);
- return -EINVAL;
- }
- static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_ipc4_msg *msg)
- {
- struct sof_ipc4_fw_module *fw_module;
- uint32_t type;
- int ret;
- ret = sof_ipc4_widget_set_module_info(swidget);
- if (ret)
- return ret;
- fw_module = swidget->module_info;
- msg->primary = fw_module->man4_module_entry.id;
- msg->primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_INIT_INSTANCE);
- msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
- msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
- msg->extension = SOF_IPC4_MOD_EXT_CORE_ID(swidget->core);
- switch (swidget->comp_domain) {
- case SOF_COMP_DOMAIN_LL:
- type = 0;
- break;
- case SOF_COMP_DOMAIN_DP:
- type = 1;
- break;
- default:
- type = (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_DP) ? 1 : 0;
- break;
- }
- msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(type);
- return 0;
- }
- static void sof_ipc4_widget_update_kcontrol_module_id(struct snd_sof_widget *swidget)
- {
- struct snd_soc_component *scomp = swidget->scomp;
- struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
- struct sof_ipc4_fw_module *fw_module = swidget->module_info;
- struct snd_sof_control *scontrol;
- /* update module ID for all kcontrols for this widget */
- list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
- if (scontrol->comp_id == swidget->comp_id) {
- struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
- struct sof_ipc4_msg *msg = &cdata->msg;
- msg->primary |= fw_module->man4_module_entry.id;
- }
- }
- }
- static int
- sof_ipc4_update_card_components_string(struct snd_sof_widget *swidget,
- struct snd_sof_pcm *spcm, int dir)
- {
- struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
- struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
- struct snd_soc_component *scomp = spcm->scomp;
- struct snd_soc_card *card = scomp->card;
- const char *pt_marker = "iec61937-pcm";
- /*
- * Update the card's components list with iec61937-pcm and a list of PCM
- * ids where ChainDMA is enabled.
- * These PCMs can be used for bytestream passthrough.
- */
- if (!pipeline->use_chain_dma)
- return 0;
- if (card->components) {
- const char *tmp = card->components;
- if (strstr(card->components, pt_marker))
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
- "%s,%d",
- card->components,
- spcm->pcm.pcm_id);
- else
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
- "%s %s:%d",
- card->components,
- pt_marker,
- spcm->pcm.pcm_id);
- devm_kfree(card->dev, tmp);
- } else {
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
- "%s:%d", pt_marker,
- spcm->pcm.pcm_id);
- }
- if (!card->components)
- return -ENOMEM;
- return 0;
- }
- static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget)
- {
- struct sof_ipc4_available_audio_format *available_fmt;
- struct snd_soc_component *scomp = swidget->scomp;
- struct sof_ipc4_copier *ipc4_copier;
- struct snd_sof_pcm *spcm;
- int node_type = 0;
- int ret, dir;
- ipc4_copier = kzalloc_obj(*ipc4_copier);
- if (!ipc4_copier)
- return -ENOMEM;
- swidget->private = ipc4_copier;
- available_fmt = &ipc4_copier->available_fmt;
- dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
- ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt,
- &ipc4_copier->data.base_config);
- if (ret)
- goto free_copier;
- /*
- * This callback is used by host copier and module-to-module copier,
- * and only host copier needs to set gtw_cfg.
- */
- if (!WIDGET_IS_AIF(swidget->id))
- goto skip_gtw_cfg;
- ret = sof_update_ipc_object(scomp, &node_type,
- SOF_COPIER_TOKENS, swidget->tuples,
- swidget->num_tuples, sizeof(node_type), 1);
- if (ret) {
- dev_err(scomp->dev, "parse host copier node type token failed %d\n",
- ret);
- goto free_available_fmt;
- }
- dev_dbg(scomp->dev, "host copier '%s' node_type %u\n", swidget->widget->name, node_type);
- spcm = snd_sof_find_spcm_comp(scomp, swidget->comp_id, &dir);
- if (!spcm)
- goto skip_gtw_cfg;
- ret = sof_ipc4_update_card_components_string(swidget, spcm, dir);
- if (ret)
- goto free_available_fmt;
- if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
- struct snd_sof_pcm_stream *sps = &spcm->stream[dir];
- sof_update_ipc_object(scomp, &sps->dsp_max_burst_size_in_ms,
- SOF_COPIER_DEEP_BUFFER_TOKENS,
- swidget->tuples,
- swidget->num_tuples, sizeof(u32), 1);
- /* Set default DMA buffer size if it is not specified in topology */
- if (!sps->dsp_max_burst_size_in_ms) {
- struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
- struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
- sps->dsp_max_burst_size_in_ms = pipeline->use_chain_dma ?
- SOF_IPC4_CHAIN_DMA_BUFFER_SIZE : SOF_IPC4_MIN_DMA_BUFFER_SIZE;
- }
- } else {
- /* Capture data is copied from DSP to host in 1ms bursts */
- spcm->stream[dir].dsp_max_burst_size_in_ms = 1;
- }
- skip_gtw_cfg:
- ipc4_copier->gtw_attr = kzalloc_obj(*ipc4_copier->gtw_attr);
- if (!ipc4_copier->gtw_attr) {
- ret = -ENOMEM;
- goto free_available_fmt;
- }
- ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr;
- ipc4_copier->data.gtw_cfg.config_length =
- sizeof(struct sof_ipc4_gtw_attributes) >> 2;
- switch (swidget->id) {
- case snd_soc_dapm_aif_in:
- case snd_soc_dapm_aif_out:
- ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type);
- break;
- case snd_soc_dapm_buffer:
- ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_INVALID_NODE_ID;
- ipc4_copier->ipc_config_size = 0;
- break;
- default:
- dev_err(scomp->dev, "invalid widget type %d\n", swidget->id);
- ret = -EINVAL;
- goto free_gtw_attr;
- }
- /* set up module info and message header */
- ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg);
- if (ret)
- goto free_gtw_attr;
- return 0;
- free_gtw_attr:
- kfree(ipc4_copier->gtw_attr);
- free_available_fmt:
- sof_ipc4_free_audio_fmt(available_fmt);
- free_copier:
- kfree(ipc4_copier);
- swidget->private = NULL;
- return ret;
- }
- static void sof_ipc4_widget_free_comp_pcm(struct snd_sof_widget *swidget)
- {
- struct sof_ipc4_copier *ipc4_copier = swidget->private;
- struct sof_ipc4_available_audio_format *available_fmt;
- if (!ipc4_copier)
- return;
- available_fmt = &ipc4_copier->available_fmt;
- kfree(available_fmt->output_pin_fmts);
- kfree(ipc4_copier->gtw_attr);
- kfree(ipc4_copier);
- swidget->private = NULL;
- }
- static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
- {
- struct sof_ipc4_available_audio_format *available_fmt;
- struct snd_soc_component *scomp = swidget->scomp;
- struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
- struct snd_sof_dai *dai = swidget->private;
- struct sof_ipc4_copier *ipc4_copier;
- struct snd_sof_widget *pipe_widget;
- struct sof_ipc4_pipeline *pipeline;
- int node_type = 0;
- int ret;
- ipc4_copier = kzalloc_obj(*ipc4_copier);
- if (!ipc4_copier)
- return -ENOMEM;
- available_fmt = &ipc4_copier->available_fmt;
- dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
- ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt,
- &ipc4_copier->data.base_config);
- if (ret)
- goto free_copier;
- ret = sof_update_ipc_object(scomp, &node_type,
- SOF_COPIER_TOKENS, swidget->tuples,
- swidget->num_tuples, sizeof(node_type), 1);
- if (ret) {
- dev_err(scomp->dev, "parse dai node type failed %d\n", ret);
- goto free_available_fmt;
- }
- ret = sof_update_ipc_object(scomp, ipc4_copier,
- SOF_DAI_TOKENS, swidget->tuples,
- swidget->num_tuples, sizeof(u32), 1);
- if (ret) {
- dev_err(scomp->dev, "parse dai copier node token failed %d\n", ret);
- goto free_available_fmt;
- }
- dev_dbg(scomp->dev, "dai %s node_type %u dai_type %u dai_index %d\n", swidget->widget->name,
- node_type, ipc4_copier->dai_type, ipc4_copier->dai_index);
- dai->type = ipc4_copier->dai_type;
- ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type);
- pipe_widget = swidget->spipe->pipe_widget;
- pipeline = pipe_widget->private;
- if (pipeline->use_chain_dma &&
- !snd_sof_is_chain_dma_supported(sdev, ipc4_copier->dai_type)) {
- dev_err(scomp->dev, "Bad DAI type '%d', Chain DMA is not supported\n",
- ipc4_copier->dai_type);
- ret = -ENODEV;
- goto free_available_fmt;
- }
- switch (ipc4_copier->dai_type) {
- case SOF_DAI_INTEL_ALH:
- {
- struct sof_ipc4_alh_configuration_blob *blob;
- struct snd_soc_dapm_path *p;
- struct snd_sof_widget *w;
- int src_num = 0;
- snd_soc_dapm_widget_for_each_source_path(swidget->widget, p)
- src_num++;
- if (swidget->id == snd_soc_dapm_dai_in && src_num == 0) {
- /*
- * The blob will not be used if the ALH copier is playback direction
- * and doesn't connect to any source.
- * It is fine to call kfree(ipc4_copier->copier_config) since
- * ipc4_copier->copier_config is null.
- */
- break;
- }
- blob = kzalloc_obj(*blob);
- if (!blob) {
- ret = -ENOMEM;
- goto free_available_fmt;
- }
- list_for_each_entry(w, &sdev->widget_list, list) {
- struct snd_sof_dai *alh_dai;
- if (!WIDGET_IS_DAI(w->id) || !w->widget->sname ||
- strcmp(w->widget->sname, swidget->widget->sname))
- continue;
- alh_dai = w->private;
- if (alh_dai->type != SOF_DAI_INTEL_ALH)
- continue;
- blob->alh_cfg.device_count++;
- }
- ipc4_copier->copier_config = (uint32_t *)blob;
- /* set data.gtw_cfg.config_length based on device_count */
- ipc4_copier->data.gtw_cfg.config_length = (sizeof(blob->gw_attr) +
- sizeof(blob->alh_cfg.device_count) +
- sizeof(*blob->alh_cfg.mapping) *
- blob->alh_cfg.device_count) >> 2;
- break;
- }
- case SOF_DAI_INTEL_SSP:
- /* set SSP DAI index as the node_id */
- ipc4_copier->data.gtw_cfg.node_id |=
- SOF_IPC4_NODE_INDEX_INTEL_SSP(ipc4_copier->dai_index);
- break;
- case SOF_DAI_INTEL_DMIC:
- /* set DMIC DAI index as the node_id */
- ipc4_copier->data.gtw_cfg.node_id |=
- SOF_IPC4_NODE_INDEX_INTEL_DMIC(ipc4_copier->dai_index);
- break;
- default:
- ipc4_copier->gtw_attr = kzalloc_obj(*ipc4_copier->gtw_attr);
- if (!ipc4_copier->gtw_attr) {
- ret = -ENOMEM;
- goto free_available_fmt;
- }
- ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr;
- ipc4_copier->data.gtw_cfg.config_length =
- sizeof(struct sof_ipc4_gtw_attributes) >> 2;
- break;
- }
- dai->scomp = scomp;
- dai->private = ipc4_copier;
- /* set up module info and message header */
- ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg);
- if (ret)
- goto free_copier_config;
- return 0;
- free_copier_config:
- kfree(ipc4_copier->copier_config);
- free_available_fmt:
- sof_ipc4_free_audio_fmt(available_fmt);
- free_copier:
- kfree(ipc4_copier);
- dai->private = NULL;
- dai->scomp = NULL;
- return ret;
- }
- static void sof_ipc4_widget_free_comp_dai(struct snd_sof_widget *swidget)
- {
- struct sof_ipc4_available_audio_format *available_fmt;
- struct snd_sof_dai *dai = swidget->private;
- struct sof_ipc4_copier *ipc4_copier;
- if (!dai)
- return;
- if (!dai->private) {
- kfree(dai);
- swidget->private = NULL;
- return;
- }
- ipc4_copier = dai->private;
- available_fmt = &ipc4_copier->available_fmt;
- kfree(available_fmt->output_pin_fmts);
- if (ipc4_copier->dai_type != SOF_DAI_INTEL_SSP &&
- ipc4_copier->dai_type != SOF_DAI_INTEL_DMIC)
- kfree(ipc4_copier->copier_config);
- kfree(dai->private);
- kfree(dai);
- swidget->private = NULL;
- }
- static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
- {
- struct snd_soc_component *scomp = swidget->scomp;
- struct sof_ipc4_pipeline *pipeline;
- struct snd_sof_pipeline *spipe = swidget->spipe;
- int ret;
- pipeline = kzalloc_obj(*pipeline);
- if (!pipeline)
- return -ENOMEM;
- ret = sof_update_ipc_object(scomp, pipeline, SOF_SCHED_TOKENS, swidget->tuples,
- swidget->num_tuples, sizeof(*pipeline), 1);
- if (ret) {
- dev_err(scomp->dev, "parsing scheduler tokens failed\n");
- goto err;
- }
- swidget->core = pipeline->core_id;
- spipe->core_mask |= BIT(pipeline->core_id);
- if (pipeline->direction_valid) {
- spipe->direction = pipeline->direction;
- spipe->direction_valid = true;
- }
- if (pipeline->use_chain_dma) {
- dev_dbg(scomp->dev, "Set up chain DMA for %s\n", swidget->widget->name);
- swidget->private = pipeline;
- return 0;
- }
- /* parse one set of pipeline tokens */
- ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples,
- swidget->num_tuples, sizeof(*swidget), 1);
- if (ret) {
- dev_err(scomp->dev, "parsing pipeline tokens failed\n");
- goto err;
- }
- dev_dbg(scomp->dev, "pipeline '%s': id %d, pri %d, core_id %u, lp mode %d direction %d\n",
- swidget->widget->name, swidget->pipeline_id,
- pipeline->priority, pipeline->core_id, pipeline->lp_mode, pipeline->direction);
- swidget->private = pipeline;
- pipeline->msg.primary = SOF_IPC4_GLB_PIPE_PRIORITY(pipeline->priority);
- pipeline->msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_CREATE_PIPELINE);
- pipeline->msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
- pipeline->msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
- pipeline->msg.extension = pipeline->lp_mode;
- pipeline->msg.extension |= SOF_IPC4_GLB_PIPE_EXT_CORE_ID(pipeline->core_id);
- pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
- return 0;
- err:
- kfree(pipeline);
- return ret;
- }
- static int sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget *swidget)
- {
- struct snd_soc_component *scomp = swidget->scomp;
- struct sof_ipc4_gain *gain;
- int ret;
- gain = kzalloc_obj(*gain);
- if (!gain)
- return -ENOMEM;
- swidget->private = gain;
- gain->data.params.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
- gain->data.params.init_val = SOF_IPC4_VOL_ZERO_DB;
- ret = sof_ipc4_get_audio_fmt(scomp, swidget, &gain->available_fmt, &gain->data.base_config);
- if (ret)
- goto err;
- ret = sof_update_ipc_object(scomp, &gain->data.params, SOF_GAIN_TOKENS,
- swidget->tuples, swidget->num_tuples, sizeof(gain->data), 1);
- if (ret) {
- dev_err(scomp->dev, "Parsing gain tokens failed\n");
- goto err;
- }
- dev_dbg(scomp->dev,
- "pga widget %s: ramp type: %d, ramp duration %d, initial gain value: %#x\n",
- swidget->widget->name, gain->data.params.curve_type,
- gain->data.params.curve_duration_l, gain->data.params.init_val);
- ret = sof_ipc4_widget_setup_msg(swidget, &gain->msg);
- if (ret)
- goto err;
- sof_ipc4_widget_update_kcontrol_module_id(swidget);
- return 0;
- err:
- sof_ipc4_free_audio_fmt(&gain->available_fmt);
- kfree(gain);
- swidget->private = NULL;
- return ret;
- }
- static void sof_ipc4_widget_free_comp_pga(struct snd_sof_widget *swidget)
- {
- struct sof_ipc4_gain *gain = swidget->private;
- if (!gain)
- return;
- sof_ipc4_free_audio_fmt(&gain->available_fmt);
- kfree(swidget->private);
- swidget->private = NULL;
- }
- static int sof_ipc4_widget_setup_comp_mixer(struct snd_sof_widget *swidget)
- {
- struct snd_soc_component *scomp = swidget->scomp;
- struct sof_ipc4_mixer *mixer;
- int ret;
- dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
- mixer = kzalloc_obj(*mixer);
- if (!mixer)
- return -ENOMEM;
- swidget->private = mixer;
- ret = sof_ipc4_get_audio_fmt(scomp, swidget, &mixer->available_fmt,
- &mixer->base_config);
- if (ret)
- goto err;
- ret = sof_ipc4_widget_setup_msg(swidget, &mixer->msg);
- if (ret)
- goto err;
- return 0;
- err:
- sof_ipc4_free_audio_fmt(&mixer->available_fmt);
- kfree(mixer);
- swidget->private = NULL;
- return ret;
- }
- static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget)
- {
- struct snd_soc_component *scomp = swidget->scomp;
- struct snd_sof_pipeline *spipe = swidget->spipe;
- struct sof_ipc4_src *src;
- int ret;
- dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
- src = kzalloc_obj(*src);
- if (!src)
- return -ENOMEM;
- swidget->private = src;
- ret = sof_ipc4_get_audio_fmt(scomp, swidget, &src->available_fmt,
- &src->data.base_config);
- if (ret)
- goto err;
- ret = sof_update_ipc_object(scomp, &src->data, SOF_SRC_TOKENS, swidget->tuples,
- swidget->num_tuples, sizeof(*src), 1);
- if (ret) {
- dev_err(scomp->dev, "Parsing SRC tokens failed\n");
- goto err;
- }
- spipe->core_mask |= BIT(swidget->core);
- dev_dbg(scomp->dev, "SRC sink rate %d\n", src->data.sink_rate);
- ret = sof_ipc4_widget_setup_msg(swidget, &src->msg);
- if (ret)
- goto err;
- return 0;
- err:
- sof_ipc4_free_audio_fmt(&src->available_fmt);
- kfree(src);
- swidget->private = NULL;
- return ret;
- }
- static int sof_ipc4_widget_setup_comp_asrc(struct snd_sof_widget *swidget)
- {
- struct snd_soc_component *scomp = swidget->scomp;
- struct snd_sof_pipeline *spipe = swidget->spipe;
- struct sof_ipc4_asrc *asrc;
- int ret;
- dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
- asrc = kzalloc_obj(*asrc);
- if (!asrc)
- return -ENOMEM;
- swidget->private = asrc;
- ret = sof_ipc4_get_audio_fmt(scomp, swidget, &asrc->available_fmt,
- &asrc->data.base_config);
- if (ret)
- goto err;
- ret = sof_update_ipc_object(scomp, &asrc->data, SOF_ASRC_TOKENS, swidget->tuples,
- swidget->num_tuples, sizeof(*asrc), 1);
- if (ret) {
- dev_err(scomp->dev, "Parsing ASRC tokens failed\n");
- goto err;
- }
- spipe->core_mask |= BIT(swidget->core);
- dev_dbg(scomp->dev, "ASRC sink rate %d, mode 0x%08x\n",
- asrc->data.out_freq, asrc->data.asrc_mode);
- ret = sof_ipc4_widget_setup_msg(swidget, &asrc->msg);
- if (ret)
- goto err;
- return 0;
- err:
- sof_ipc4_free_audio_fmt(&asrc->available_fmt);
- kfree(asrc);
- swidget->private = NULL;
- return ret;
- }
- static void sof_ipc4_widget_free_comp_src(struct snd_sof_widget *swidget)
- {
- struct sof_ipc4_src *src = swidget->private;
- if (!src)
- return;
- sof_ipc4_free_audio_fmt(&src->available_fmt);
- kfree(swidget->private);
- swidget->private = NULL;
- }
- static void sof_ipc4_widget_free_comp_asrc(struct snd_sof_widget *swidget)
- {
- struct sof_ipc4_asrc *asrc = swidget->private;
- if (!asrc)
- return;
- sof_ipc4_free_audio_fmt(&asrc->available_fmt);
- kfree(swidget->private);
- swidget->private = NULL;
- }
- static void sof_ipc4_widget_free_comp_mixer(struct snd_sof_widget *swidget)
- {
- struct sof_ipc4_mixer *mixer = swidget->private;
- if (!mixer)
- return;
- sof_ipc4_free_audio_fmt(&mixer->available_fmt);
- kfree(swidget->private);
- swidget->private = NULL;
- }
- /*
- * Add the process modules support. The process modules are defined as snd_soc_dapm_effect modules.
- */
- static int sof_ipc4_widget_setup_comp_process(struct snd_sof_widget *swidget)
- {
- struct snd_soc_component *scomp = swidget->scomp;
- struct sof_ipc4_fw_module *fw_module;
- struct snd_sof_pipeline *spipe = swidget->spipe;
- struct sof_ipc4_process *process;
- void *cfg;
- int ret;
- process = kzalloc_obj(*process);
- if (!process)
- return -ENOMEM;
- swidget->private = process;
- ret = sof_ipc4_get_audio_fmt(scomp, swidget, &process->available_fmt,
- &process->base_config);
- if (ret)
- goto err;
- ret = sof_ipc4_widget_setup_msg(swidget, &process->msg);
- if (ret)
- goto err;
- /* parse process init module payload config type from module info */
- fw_module = swidget->module_info;
- process->init_config = FIELD_GET(SOF_IPC4_MODULE_INIT_CONFIG_MASK,
- fw_module->man4_module_entry.type);
- process->ipc_config_size = sizeof(struct sof_ipc4_base_module_cfg);
- /* allocate memory for base config extension if needed */
- if (process->init_config == SOF_IPC4_MODULE_INIT_CONFIG_TYPE_BASE_CFG_WITH_EXT) {
- struct sof_ipc4_base_module_cfg_ext *base_cfg_ext;
- u32 ext_size = struct_size(base_cfg_ext, pin_formats,
- size_add(swidget->num_input_pins,
- swidget->num_output_pins));
- base_cfg_ext = kzalloc(ext_size, GFP_KERNEL);
- if (!base_cfg_ext) {
- ret = -ENOMEM;
- goto free_available_fmt;
- }
- base_cfg_ext->num_input_pin_fmts = swidget->num_input_pins;
- base_cfg_ext->num_output_pin_fmts = swidget->num_output_pins;
- process->base_config_ext = base_cfg_ext;
- process->base_config_ext_size = ext_size;
- process->ipc_config_size += ext_size;
- }
- cfg = kzalloc(process->ipc_config_size, GFP_KERNEL);
- if (!cfg) {
- ret = -ENOMEM;
- goto free_base_cfg_ext;
- }
- process->ipc_config_data = cfg;
- sof_ipc4_widget_update_kcontrol_module_id(swidget);
- /* set pipeline core mask to keep track of the core the module is scheduled to run on */
- spipe->core_mask |= BIT(swidget->core);
- return 0;
- free_base_cfg_ext:
- kfree(process->base_config_ext);
- process->base_config_ext = NULL;
- free_available_fmt:
- sof_ipc4_free_audio_fmt(&process->available_fmt);
- err:
- kfree(process);
- swidget->private = NULL;
- return ret;
- }
- static void sof_ipc4_widget_free_comp_process(struct snd_sof_widget *swidget)
- {
- struct sof_ipc4_process *process = swidget->private;
- if (!process)
- return;
- kfree(process->ipc_config_data);
- kfree(process->base_config_ext);
- sof_ipc4_free_audio_fmt(&process->available_fmt);
- kfree(swidget->private);
- swidget->private = NULL;
- }
- static void
- sof_ipc4_update_resource_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
- struct sof_ipc4_base_module_cfg *base_config)
- {
- struct sof_ipc4_fw_module *fw_module = swidget->module_info;
- struct snd_sof_widget *pipe_widget;
- struct sof_ipc4_pipeline *pipeline;
- int task_mem, queue_mem;
- int ibs, bss, total;
- ibs = base_config->ibs;
- bss = base_config->is_pages;
- task_mem = SOF_IPC4_PIPELINE_OBJECT_SIZE;
- task_mem += SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE + bss;
- if (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_LL) {
- task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_LL_TASK_OBJECT_SIZE);
- task_mem += SOF_IPC4_FW_MAX_QUEUE_COUNT * SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE;
- task_mem += SOF_IPC4_LL_TASK_LIST_ITEM_SIZE;
- } else {
- task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_DP_TASK_OBJECT_SIZE);
- task_mem += SOF_IPC4_DP_TASK_LIST_SIZE;
- }
- ibs = SOF_IPC4_FW_ROUNDUP(ibs);
- queue_mem = SOF_IPC4_FW_MAX_QUEUE_COUNT * (SOF_IPC4_DATA_QUEUE_OBJECT_SIZE + ibs);
- total = SOF_IPC4_FW_PAGE(task_mem + queue_mem);
- pipe_widget = swidget->spipe->pipe_widget;
- pipeline = pipe_widget->private;
- pipeline->mem_usage += total;
- /* Update base_config->cpc from the module manifest */
- sof_ipc4_update_cpc_from_manifest(sdev, fw_module, base_config);
- if (ignore_cpc) {
- dev_dbg(sdev->dev, "%s: ibs / obs: %u / %u, forcing cpc to 0 from %u\n",
- swidget->widget->name, base_config->ibs, base_config->obs,
- base_config->cpc);
- base_config->cpc = 0;
- } else {
- dev_dbg(sdev->dev, "%s: ibs / obs / cpc: %u / %u / %u\n",
- swidget->widget->name, base_config->ibs, base_config->obs,
- base_config->cpc);
- }
- }
- static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev,
- struct snd_sof_widget *swidget)
- {
- struct sof_ipc4_fw_module *fw_module = swidget->module_info;
- int max_instances = fw_module->man4_module_entry.instance_max_count;
- swidget->instance_id = ida_alloc_max(&fw_module->m_ida, max_instances, GFP_KERNEL);
- if (swidget->instance_id < 0) {
- dev_err(sdev->dev, "failed to assign instance id for widget %s",
- swidget->widget->name);
- return swidget->instance_id;
- }
- return 0;
- }
- static u32 sof_ipc4_fmt_cfg_to_type(u32 fmt_cfg)
- {
- /* Fetch the sample type from the fmt for 8 and 32 bit formats */
- u32 __bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt_cfg);
- if (__bits == 8 || __bits == 32)
- return SOF_IPC4_AUDIO_FORMAT_CFG_SAMPLE_TYPE(fmt_cfg);
- /*
- * Return LSB integer type for 20 and 24 formats as the firmware is
- * handling the LSB/MSB alignment internally, for the kernel this
- * should not be taken into account, we treat them as LSB to match with
- * the format we support on the PCM side.
- */
- return SOF_IPC4_TYPE_LSB_INTEGER;
- }
- /* update hw_params based on the audio stream format */
- static int sof_ipc4_update_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params,
- struct sof_ipc4_audio_format *fmt, u32 param_to_update)
- {
- struct snd_interval *i;
- if (param_to_update & BIT(SNDRV_PCM_HW_PARAM_FORMAT)) {
- int valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
- int type = sof_ipc4_fmt_cfg_to_type(fmt->fmt_cfg);
- snd_pcm_format_t snd_fmt;
- struct snd_mask *m;
- switch (valid_bits) {
- case 8:
- switch (type) {
- case SOF_IPC4_TYPE_A_LAW:
- snd_fmt = SNDRV_PCM_FORMAT_A_LAW;
- break;
- case SOF_IPC4_TYPE_MU_LAW:
- snd_fmt = SNDRV_PCM_FORMAT_MU_LAW;
- break;
- case SOF_IPC4_TYPE_UNSIGNED_INTEGER:
- snd_fmt = SNDRV_PCM_FORMAT_U8;
- break;
- default:
- dev_err(sdev->dev, "Unsupported PCM 8-bit IPC4 type %d\n", type);
- return -EINVAL;
- }
- break;
- case 16:
- snd_fmt = SNDRV_PCM_FORMAT_S16_LE;
- break;
- case 24:
- snd_fmt = SNDRV_PCM_FORMAT_S24_LE;
- break;
- case 32:
- switch (type) {
- case SOF_IPC4_TYPE_LSB_INTEGER:
- snd_fmt = SNDRV_PCM_FORMAT_S32_LE;
- break;
- case SOF_IPC4_TYPE_FLOAT:
- snd_fmt = SNDRV_PCM_FORMAT_FLOAT_LE;
- break;
- default:
- dev_err(sdev->dev, "Unsupported PCM 32-bit IPC4 type %d\n", type);
- return -EINVAL;
- }
- break;
- default:
- dev_err(sdev->dev, "invalid PCM valid_bits %d\n", valid_bits);
- return -EINVAL;
- }
- m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
- snd_mask_none(m);
- snd_mask_set_format(m, snd_fmt);
- }
- if (param_to_update & BIT(SNDRV_PCM_HW_PARAM_RATE)) {
- unsigned int rate = fmt->sampling_frequency;
- i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
- i->min = rate;
- i->max = rate;
- }
- if (param_to_update & BIT(SNDRV_PCM_HW_PARAM_CHANNELS)) {
- unsigned int channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
- i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
- i->min = channels;
- i->max = channels;
- }
- return 0;
- }
- static bool sof_ipc4_is_single_format(struct snd_sof_dev *sdev,
- struct sof_ipc4_pin_format *pin_fmts, u32 pin_fmts_size)
- {
- struct sof_ipc4_audio_format *fmt;
- u32 rate, channels, valid_bits;
- int i;
- fmt = &pin_fmts[0].audio_fmt;
- rate = fmt->sampling_frequency;
- channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
- valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
- /* check if all output formats in topology are the same */
- for (i = 1; i < pin_fmts_size; i++) {
- u32 _rate, _channels, _valid_bits;
- fmt = &pin_fmts[i].audio_fmt;
- _rate = fmt->sampling_frequency;
- _channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
- _valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
- if (_rate != rate || _channels != channels || _valid_bits != valid_bits)
- return false;
- }
- return true;
- }
- static int sof_ipc4_init_output_audio_fmt(struct snd_sof_dev *sdev,
- struct snd_sof_widget *swidget,
- struct sof_ipc4_base_module_cfg *base_config,
- struct sof_ipc4_available_audio_format *available_fmt,
- u32 out_ref_rate, u32 out_ref_channels,
- u32 out_ref_valid_bits, u32 out_ref_type)
- {
- struct sof_ipc4_pin_format *pin_fmts = available_fmt->output_pin_fmts;
- u32 pin_fmts_size = available_fmt->num_output_formats;
- bool single_format;
- int i = 0;
- if (!pin_fmts_size) {
- dev_err(sdev->dev, "no output formats for %s\n",
- swidget->widget->name);
- return -EINVAL;
- }
- single_format = sof_ipc4_is_single_format(sdev, pin_fmts, pin_fmts_size);
- /* pick the first format if there's only one available or if all formats are the same */
- if (single_format)
- goto out_fmt;
- /*
- * if there are multiple output formats, then choose the output format that matches
- * the reference params
- */
- for (i = 0; i < pin_fmts_size; i++) {
- struct sof_ipc4_audio_format *fmt = &pin_fmts[i].audio_fmt;
- u32 _out_rate, _out_channels, _out_valid_bits, _out_type;
- _out_rate = fmt->sampling_frequency;
- _out_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
- _out_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
- _out_type = sof_ipc4_fmt_cfg_to_type(fmt->fmt_cfg);
- if (_out_rate == out_ref_rate && _out_channels == out_ref_channels &&
- _out_valid_bits == out_ref_valid_bits && _out_type == out_ref_type)
- goto out_fmt;
- }
- dev_err(sdev->dev,
- "%s: Unsupported audio format: %uHz, %ubit, %u channels, type: %d\n",
- __func__, out_ref_rate, out_ref_valid_bits, out_ref_channels,
- out_ref_type);
- return -EINVAL;
- out_fmt:
- base_config->obs = pin_fmts[i].buffer_size;
- return i;
- }
- static int sof_ipc4_get_valid_bits(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params)
- {
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_U8:
- case SNDRV_PCM_FORMAT_MU_LAW:
- case SNDRV_PCM_FORMAT_A_LAW:
- return 8;
- case SNDRV_PCM_FORMAT_S16_LE:
- return 16;
- case SNDRV_PCM_FORMAT_S24_LE:
- return 24;
- case SNDRV_PCM_FORMAT_S32_LE:
- return 32;
- case SNDRV_PCM_FORMAT_FLOAT_LE:
- return 32;
- default:
- dev_err(sdev->dev, "invalid pcm frame format %d\n", params_format(params));
- return -EINVAL;
- }
- }
- static int sof_ipc4_get_sample_type(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params)
- {
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_A_LAW:
- return SOF_IPC4_TYPE_A_LAW;
- case SNDRV_PCM_FORMAT_MU_LAW:
- return SOF_IPC4_TYPE_MU_LAW;
- case SNDRV_PCM_FORMAT_U8:
- return SOF_IPC4_TYPE_UNSIGNED_INTEGER;
- case SNDRV_PCM_FORMAT_S16_LE:
- case SNDRV_PCM_FORMAT_S24_LE:
- case SNDRV_PCM_FORMAT_S32_LE:
- case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
- return SOF_IPC4_TYPE_LSB_INTEGER;
- case SNDRV_PCM_FORMAT_FLOAT_LE:
- return SOF_IPC4_TYPE_FLOAT;
- default:
- dev_err(sdev->dev, "invalid pcm sample type %d\n", params_format(params));
- return -EINVAL;
- }
- }
- static int sof_ipc4_init_input_audio_fmt(struct snd_sof_dev *sdev,
- struct snd_sof_widget *swidget,
- struct sof_ipc4_base_module_cfg *base_config,
- struct snd_pcm_hw_params *params,
- struct sof_ipc4_available_audio_format *available_fmt)
- {
- struct sof_ipc4_pin_format *pin_fmts = available_fmt->input_pin_fmts;
- u32 pin_fmts_size = available_fmt->num_input_formats;
- u32 valid_bits;
- u32 channels;
- u32 rate;
- u32 type;
- bool single_format;
- int sample_valid_bits;
- int sample_type;
- int i = 0;
- if (!pin_fmts_size) {
- dev_err(sdev->dev, "no input formats for %s\n", swidget->widget->name);
- return -EINVAL;
- }
- single_format = sof_ipc4_is_single_format(sdev, pin_fmts, pin_fmts_size);
- if (single_format)
- goto in_fmt;
- sample_valid_bits = sof_ipc4_get_valid_bits(sdev, params);
- if (sample_valid_bits < 0)
- return sample_valid_bits;
- sample_type = sof_ipc4_get_sample_type(sdev, params);
- if (sample_type < 0)
- return sample_type;
- /*
- * Search supported input audio formats with pin index 0 to match rate, channels and
- * sample_valid_bits from reference params
- */
- for (i = 0; i < pin_fmts_size; i++) {
- struct sof_ipc4_audio_format *fmt = &pin_fmts[i].audio_fmt;
- if (pin_fmts[i].pin_index)
- continue;
- rate = fmt->sampling_frequency;
- channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
- valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
- type = sof_ipc4_fmt_cfg_to_type(fmt->fmt_cfg);
- if (params_rate(params) == rate && params_channels(params) == channels &&
- sample_valid_bits == valid_bits && sample_type == type)
- break;
- }
- if (i == pin_fmts_size) {
- dev_err(sdev->dev,
- "%s: Unsupported audio format: %uHz, %ubit, %u channels, type: %d\n",
- __func__, params_rate(params), sample_valid_bits,
- params_channels(params), sample_type);
- return -EINVAL;
- }
- in_fmt:
- /* copy input format */
- memcpy(&base_config->audio_fmt, &pin_fmts[i].audio_fmt,
- sizeof(struct sof_ipc4_audio_format));
- /* set base_cfg ibs/obs */
- base_config->ibs = pin_fmts[i].buffer_size;
- return i;
- }
- static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
- {
- struct sof_ipc4_copier *ipc4_copier = NULL;
- struct snd_sof_widget *pipe_widget;
- struct sof_ipc4_pipeline *pipeline;
- /* reset pipeline memory usage */
- pipe_widget = swidget->spipe->pipe_widget;
- pipeline = pipe_widget->private;
- pipeline->mem_usage = 0;
- if (WIDGET_IS_AIF(swidget->id) || swidget->id == snd_soc_dapm_buffer) {
- if (pipeline->use_chain_dma) {
- pipeline->msg.primary = 0;
- pipeline->msg.extension = 0;
- }
- ipc4_copier = swidget->private;
- } else if (WIDGET_IS_DAI(swidget->id)) {
- struct snd_sof_dai *dai = swidget->private;
- ipc4_copier = dai->private;
- if (pipeline->use_chain_dma) {
- /*
- * Preserve the DMA Link ID and clear other bits since
- * the DMA Link ID is only configured once during
- * dai_config, other fields are expected to be 0 for
- * re-configuration
- */
- pipeline->msg.primary &= SOF_IPC4_GLB_CHAIN_DMA_LINK_ID_MASK;
- pipeline->msg.extension = 0;
- }
- if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
- struct sof_ipc4_alh_configuration_blob *blob;
- unsigned int group_id;
- blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
- if (blob->alh_cfg.device_count > 1) {
- group_id = SOF_IPC4_NODE_INDEX(ipc4_copier->data.gtw_cfg.node_id) -
- ALH_MULTI_GTW_BASE;
- ida_free(&alh_group_ida, group_id);
- }
- }
- }
- if (ipc4_copier) {
- kfree(ipc4_copier->ipc_config_data);
- ipc4_copier->ipc_config_data = NULL;
- ipc4_copier->ipc_config_size = 0;
- }
- }
- #if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_INTEL_NHLT)
- static int snd_sof_get_hw_config_params(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
- int *sample_rate, int *channel_count, int *bit_depth)
- {
- struct snd_soc_tplg_hw_config *hw_config;
- struct snd_sof_dai_link *slink;
- bool dai_link_found = false;
- bool hw_cfg_found = false;
- int i;
- /* get current hw_config from link */
- list_for_each_entry(slink, &sdev->dai_link_list, list) {
- if (!strcmp(slink->link->name, dai->name)) {
- dai_link_found = true;
- break;
- }
- }
- if (!dai_link_found) {
- dev_err(sdev->dev, "%s: no DAI link found for DAI %s\n", __func__, dai->name);
- return -EINVAL;
- }
- for (i = 0; i < slink->num_hw_configs; i++) {
- hw_config = &slink->hw_configs[i];
- if (dai->current_config == le32_to_cpu(hw_config->id)) {
- hw_cfg_found = true;
- break;
- }
- }
- if (!hw_cfg_found) {
- dev_err(sdev->dev, "%s: no matching hw_config found for DAI %s\n", __func__,
- dai->name);
- return -EINVAL;
- }
- *bit_depth = le32_to_cpu(hw_config->tdm_slot_width);
- *channel_count = le32_to_cpu(hw_config->tdm_slots);
- *sample_rate = le32_to_cpu(hw_config->fsync_rate);
- dev_dbg(sdev->dev, "sample rate: %d sample width: %d channels: %d\n",
- *sample_rate, *bit_depth, *channel_count);
- return 0;
- }
- static int
- snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
- bool single_bitdepth,
- struct snd_pcm_hw_params *params, u32 dai_index,
- u32 linktype, u8 dir, u32 **dst, u32 *len)
- {
- struct sof_ipc4_fw_data *ipc4_data = sdev->private;
- struct nhlt_specific_cfg *cfg;
- int sample_rate, channel_count;
- bool format_change = false;
- int bit_depth, ret;
- u32 nhlt_type;
- int dev_type = 0;
- /* convert to NHLT type */
- switch (linktype) {
- case SOF_DAI_INTEL_DMIC:
- nhlt_type = NHLT_LINK_DMIC;
- channel_count = params_channels(params);
- sample_rate = params_rate(params);
- bit_depth = params_width(params);
- /* Prefer 32-bit blob if copier supports multiple formats */
- if (bit_depth <= 16 && !single_bitdepth) {
- dev_dbg(sdev->dev, "Looking for 32-bit blob first for DMIC\n");
- format_change = true;
- bit_depth = 32;
- }
- break;
- case SOF_DAI_INTEL_SSP:
- nhlt_type = NHLT_LINK_SSP;
- ret = snd_sof_get_hw_config_params(sdev, dai, &sample_rate, &channel_count,
- &bit_depth);
- if (ret < 0)
- return ret;
- /*
- * We need to know the type of the external device attached to a SSP
- * port to retrieve the blob from NHLT. However, device type is not
- * specified in topology.
- * Query the type for the port and then pass that information back
- * to the blob lookup function.
- */
- dev_type = intel_nhlt_ssp_device_type(sdev->dev, ipc4_data->nhlt,
- dai_index);
- if (dev_type < 0)
- return dev_type;
- break;
- default:
- return 0;
- }
- dev_dbg(sdev->dev, "dai index %d nhlt type %d direction %d dev type %d\n",
- dai_index, nhlt_type, dir, dev_type);
- /* find NHLT blob with matching params */
- cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt, dai_index, nhlt_type,
- bit_depth, bit_depth, channel_count, sample_rate,
- dir, dev_type);
- if (!cfg) {
- bool get_new_blob = false;
- if (format_change) {
- /*
- * The 32-bit blob was not found in NHLT table, try to
- * look for 16-bit for DMIC or based on the params for
- * SSP
- */
- if (linktype == SOF_DAI_INTEL_DMIC) {
- bit_depth = 16;
- if (params_width(params) == 16)
- format_change = false;
- } else {
- bit_depth = params_width(params);
- format_change = false;
- }
- get_new_blob = true;
- } else if (linktype == SOF_DAI_INTEL_DMIC && !single_bitdepth) {
- /*
- * The requested 32-bit blob (no format change for the
- * blob request) was not found in NHLT table, try to
- * look for 16-bit blob if the copier supports multiple
- * formats
- */
- bit_depth = 16;
- format_change = true;
- get_new_blob = true;
- }
- if (get_new_blob) {
- cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt,
- dai_index, nhlt_type,
- bit_depth, bit_depth,
- channel_count, sample_rate,
- dir, dev_type);
- if (cfg)
- goto out;
- }
- dev_err(sdev->dev,
- "no matching blob for sample rate: %d sample width: %d channels: %d\n",
- sample_rate, bit_depth, channel_count);
- return -EINVAL;
- }
- out:
- /* config length should be in dwords */
- *len = cfg->size >> 2;
- *dst = (u32 *)cfg->caps;
- if (format_change || params_format(params) == SNDRV_PCM_FORMAT_FLOAT_LE) {
- /*
- * Update the params to reflect that different blob was loaded
- * instead of the requested bit depth (16 -> 32 or 32 -> 16).
- * This information is going to be used by the caller to find
- * matching copier format on the dai side.
- */
- struct snd_mask *m;
- m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
- snd_mask_none(m);
- if (bit_depth == 16)
- snd_mask_set_format(m, SNDRV_PCM_FORMAT_S16_LE);
- else
- snd_mask_set_format(m, SNDRV_PCM_FORMAT_S32_LE);
- }
- return 0;
- }
- #else
- static int
- snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
- bool single_bitdepth,
- struct snd_pcm_hw_params *params, u32 dai_index,
- u32 linktype, u8 dir, u32 **dst, u32 *len)
- {
- return 0;
- }
- #endif
- bool sof_ipc4_copier_is_single_bitdepth(struct snd_sof_dev *sdev,
- struct sof_ipc4_pin_format *pin_fmts,
- u32 pin_fmts_size)
- {
- struct sof_ipc4_audio_format *fmt;
- u32 valid_bits;
- int i;
- fmt = &pin_fmts[0].audio_fmt;
- valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
- /* check if all formats in topology are the same */
- for (i = 1; i < pin_fmts_size; i++) {
- u32 _valid_bits;
- fmt = &pin_fmts[i].audio_fmt;
- _valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
- if (_valid_bits != valid_bits)
- return false;
- }
- return true;
- }
- static int
- sof_ipc4_adjust_params_to_dai_format(struct snd_sof_dev *sdev,
- struct snd_pcm_hw_params *params,
- struct sof_ipc4_pin_format *pin_fmts,
- u32 pin_fmts_size)
- {
- u32 params_mask = BIT(SNDRV_PCM_HW_PARAM_RATE) |
- BIT(SNDRV_PCM_HW_PARAM_CHANNELS) |
- BIT(SNDRV_PCM_HW_PARAM_FORMAT);
- struct sof_ipc4_audio_format *fmt;
- u32 rate, channels, valid_bits;
- int i;
- fmt = &pin_fmts[0].audio_fmt;
- rate = fmt->sampling_frequency;
- channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
- valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
- /* check if parameters in topology defined formats are the same */
- for (i = 1; i < pin_fmts_size; i++) {
- u32 val;
- fmt = &pin_fmts[i].audio_fmt;
- if (params_mask & BIT(SNDRV_PCM_HW_PARAM_RATE)) {
- val = fmt->sampling_frequency;
- if (val != rate)
- params_mask &= ~BIT(SNDRV_PCM_HW_PARAM_RATE);
- }
- if (params_mask & BIT(SNDRV_PCM_HW_PARAM_CHANNELS)) {
- val = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
- if (val != channels)
- params_mask &= ~BIT(SNDRV_PCM_HW_PARAM_CHANNELS);
- }
- if (params_mask & BIT(SNDRV_PCM_HW_PARAM_FORMAT)) {
- val = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
- if (val != valid_bits)
- params_mask &= ~BIT(SNDRV_PCM_HW_PARAM_FORMAT);
- }
- }
- if (params_mask)
- return sof_ipc4_update_hw_params(sdev, params,
- &pin_fmts[0].audio_fmt,
- params_mask);
- return 0;
- }
- static int
- sof_ipc4_prepare_dai_copier(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
- struct snd_pcm_hw_params *params, int dir)
- {
- struct sof_ipc4_available_audio_format *available_fmt;
- struct snd_pcm_hw_params dai_params = *params;
- struct sof_ipc4_copier_data *copier_data;
- struct sof_ipc4_pin_format *pin_fmts;
- struct sof_ipc4_copier *ipc4_copier;
- bool single_bitdepth;
- u32 num_pin_fmts;
- int ret;
- ipc4_copier = dai->private;
- copier_data = &ipc4_copier->data;
- available_fmt = &ipc4_copier->available_fmt;
- /*
- * Fixup the params based on the format parameters of the DAI. If any
- * of the RATE, CHANNELS, bit depth is static among the formats then
- * narrow the params to only allow that specific parameter value.
- */
- if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
- pin_fmts = available_fmt->output_pin_fmts;
- num_pin_fmts = available_fmt->num_output_formats;
- } else {
- pin_fmts = available_fmt->input_pin_fmts;
- num_pin_fmts = available_fmt->num_input_formats;
- }
- ret = sof_ipc4_adjust_params_to_dai_format(sdev, &dai_params, pin_fmts,
- num_pin_fmts);
- if (ret)
- return ret;
- single_bitdepth = sof_ipc4_copier_is_single_bitdepth(sdev, pin_fmts,
- num_pin_fmts);
- ret = snd_sof_get_nhlt_endpoint_data(sdev, dai, single_bitdepth,
- &dai_params,
- ipc4_copier->dai_index,
- ipc4_copier->dai_type, dir,
- &ipc4_copier->copier_config,
- &copier_data->gtw_cfg.config_length);
- /* Update the params to reflect the changes made in this function */
- if (!ret)
- *params = dai_params;
- return ret;
- }
- static void sof_ipc4_host_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
- struct snd_sof_platform_stream_params *platform_params)
- {
- struct sof_ipc4_copier *ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
- struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
- struct sof_ipc4_copier_data *copier_data = &ipc4_copier->data;
- struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
- u32 host_dma_id = platform_params->stream_tag - 1;
- if (pipeline->use_chain_dma) {
- pipeline->msg.primary &= ~SOF_IPC4_GLB_CHAIN_DMA_HOST_ID_MASK;
- pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_HOST_ID(host_dma_id);
- return;
- }
- copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
- copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(host_dma_id);
- }
- static int
- sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
- struct snd_pcm_hw_params *fe_params,
- struct snd_sof_platform_stream_params *platform_params,
- struct snd_pcm_hw_params *pipeline_params, int dir)
- {
- struct sof_ipc4_available_audio_format *available_fmt;
- struct snd_soc_component *scomp = swidget->scomp;
- struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
- struct sof_ipc4_copier_data *copier_data;
- int input_fmt_index, output_fmt_index;
- struct sof_ipc4_copier *ipc4_copier;
- struct snd_pcm_hw_params *ref_params __free(kfree) = NULL;
- struct snd_sof_dai *dai;
- u32 gtw_cfg_config_length;
- u32 dma_config_tlv_size = 0;
- void **ipc_config_data;
- int *ipc_config_size;
- u32 **data;
- int ipc_size, ret, out_ref_valid_bits;
- u32 out_ref_rate, out_ref_channels, out_ref_type;
- u32 deep_buffer_dma_ms = 0;
- bool single_output_bitdepth;
- int i;
- switch (swidget->id) {
- case snd_soc_dapm_aif_in:
- case snd_soc_dapm_aif_out:
- {
- struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
- struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
- struct sof_ipc4_gtw_attributes *gtw_attr;
- dev_dbg(sdev->dev,
- "Host copier %s, type %d, ChainDMA: %s, stream_tag: %d\n",
- swidget->widget->name, swidget->id,
- str_yes_no(pipeline->use_chain_dma),
- platform_params->stream_tag);
- /* parse the deep buffer dma size */
- ret = sof_update_ipc_object(scomp, &deep_buffer_dma_ms,
- SOF_COPIER_DEEP_BUFFER_TOKENS, swidget->tuples,
- swidget->num_tuples, sizeof(u32), 1);
- if (ret) {
- dev_err(scomp->dev, "Failed to parse deep buffer dma size for %s\n",
- swidget->widget->name);
- return ret;
- }
- ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
- gtw_attr = ipc4_copier->gtw_attr;
- copier_data = &ipc4_copier->data;
- available_fmt = &ipc4_copier->available_fmt;
- if (pipeline->use_chain_dma) {
- u32 host_dma_id;
- u32 fifo_size;
- host_dma_id = platform_params->stream_tag - 1;
- pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_HOST_ID(host_dma_id);
- if (params_format(fe_params) == SNDRV_PCM_FORMAT_S16_LE)
- pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_SCS_MASK;
- /* Set SCS bit for 8 and 16 bit formats */
- if (params_physical_width(fe_params) <= 16)
- pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_SCS_MASK;
- /*
- * Despite its name the bitfield 'fifo_size' is used to define DMA buffer
- * size. The expression calculates 2ms buffer size.
- */
- fifo_size = DIV_ROUND_UP((SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS *
- params_rate(fe_params) *
- params_channels(fe_params) *
- params_physical_width(fe_params)), 8000);
- pipeline->msg.extension |= SOF_IPC4_GLB_EXT_CHAIN_DMA_FIFO_SIZE(fifo_size);
- /*
- * Chain DMA does not support stream timestamping, but it
- * can use the host side registers for delay calculation.
- */
- copier_data->gtw_cfg.node_id = SOF_IPC4_CHAIN_DMA_NODE_ID;
- return 0;
- }
- /*
- * Use the input_pin_fmts to match pcm params for playback and the output_pin_fmts
- * for capture.
- */
- if (dir == SNDRV_PCM_STREAM_PLAYBACK)
- ref_params = kmemdup(fe_params, sizeof(*ref_params), GFP_KERNEL);
- else
- ref_params = kmemdup(pipeline_params, sizeof(*ref_params), GFP_KERNEL);
- if (!ref_params)
- return -ENOMEM;
- copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
- copier_data->gtw_cfg.node_id |=
- SOF_IPC4_NODE_INDEX(platform_params->stream_tag - 1);
- /* set gateway attributes */
- gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
- break;
- }
- case snd_soc_dapm_dai_in:
- case snd_soc_dapm_dai_out:
- {
- struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
- struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
- dev_dbg(sdev->dev, "Dai copier %s, type %d, ChainDMA: %s\n",
- swidget->widget->name, swidget->id,
- str_yes_no(pipeline->use_chain_dma));
- if (pipeline->use_chain_dma)
- return 0;
- dai = swidget->private;
- ipc4_copier = (struct sof_ipc4_copier *)dai->private;
- copier_data = &ipc4_copier->data;
- available_fmt = &ipc4_copier->available_fmt;
- /*
- * Use the fe_params as a base for the copier configuration.
- * The ref_params might get updated to reflect what format is
- * supported by the copier on the DAI side.
- *
- * In case of capture the ref_params returned will be used to
- * find the input configuration of the copier.
- */
- ref_params = kmemdup(fe_params, sizeof(*ref_params), GFP_KERNEL);
- if (!ref_params)
- return -ENOMEM;
- ret = sof_ipc4_prepare_dai_copier(sdev, dai, ref_params, dir);
- if (ret < 0)
- return ret;
- /*
- * For playback the pipeline_params needs to be used to find the
- * input configuration of the copier.
- */
- if (dir == SNDRV_PCM_STREAM_PLAYBACK)
- memcpy(ref_params, pipeline_params, sizeof(*ref_params));
- break;
- }
- case snd_soc_dapm_buffer:
- {
- dev_dbg(sdev->dev, "Module copier %s, type %d\n",
- swidget->widget->name, swidget->id);
- ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
- copier_data = &ipc4_copier->data;
- available_fmt = &ipc4_copier->available_fmt;
- ref_params = kmemdup(pipeline_params, sizeof(*ref_params), GFP_KERNEL);
- if (!ref_params)
- return -ENOMEM;
- break;
- }
- default:
- dev_err(sdev->dev, "unsupported type %d for copier %s",
- swidget->id, swidget->widget->name);
- return -EINVAL;
- }
- /* set input and output audio formats */
- input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget,
- &copier_data->base_config,
- ref_params, available_fmt);
- if (input_fmt_index < 0)
- return input_fmt_index;
- /* set the reference params for output format selection */
- single_output_bitdepth = sof_ipc4_copier_is_single_bitdepth(sdev,
- available_fmt->output_pin_fmts,
- available_fmt->num_output_formats);
- switch (swidget->id) {
- case snd_soc_dapm_aif_in:
- case snd_soc_dapm_dai_out:
- case snd_soc_dapm_buffer:
- {
- struct sof_ipc4_audio_format *in_fmt;
- in_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt;
- out_ref_rate = in_fmt->sampling_frequency;
- out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
- out_ref_type = sof_ipc4_fmt_cfg_to_type(in_fmt->fmt_cfg);
- if (!single_output_bitdepth)
- out_ref_valid_bits =
- SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
- break;
- }
- case snd_soc_dapm_aif_out:
- case snd_soc_dapm_dai_in:
- out_ref_rate = params_rate(fe_params);
- out_ref_channels = params_channels(fe_params);
- ret = sof_ipc4_get_sample_type(sdev, fe_params);
- if (ret < 0)
- return ret;
- out_ref_type = (u32)ret;
- if (!single_output_bitdepth) {
- out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params);
- if (out_ref_valid_bits < 0)
- return out_ref_valid_bits;
- }
- break;
- default:
- /*
- * Unsupported type should be caught by the former switch default
- * case, this should never happen in reality.
- */
- return -EINVAL;
- }
- /*
- * if the output format is the same across all available output formats, choose
- * that as the reference.
- */
- if (single_output_bitdepth) {
- struct sof_ipc4_audio_format *out_fmt;
- out_fmt = &available_fmt->output_pin_fmts[0].audio_fmt;
- out_ref_valid_bits =
- SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(out_fmt->fmt_cfg);
- out_ref_type = sof_ipc4_fmt_cfg_to_type(out_fmt->fmt_cfg);
- }
- output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget,
- &copier_data->base_config,
- available_fmt, out_ref_rate,
- out_ref_channels, out_ref_valid_bits,
- out_ref_type);
- if (output_fmt_index < 0)
- return output_fmt_index;
- /*
- * Set the output format. Current topology defines pin 0 input and output formats in pairs.
- * This assumes that the pin 0 formats are defined before all other pins.
- * So pick the output audio format with the same index as the chosen
- * input format. This logic will need to be updated when the format definitions
- * in topology change.
- */
- memcpy(&copier_data->out_format,
- &available_fmt->output_pin_fmts[output_fmt_index].audio_fmt,
- sizeof(struct sof_ipc4_audio_format));
- switch (swidget->id) {
- case snd_soc_dapm_dai_in:
- case snd_soc_dapm_dai_out:
- {
- /*
- * Only SOF_DAI_INTEL_ALH needs copier_data to set blob.
- * That's why only ALH dai's blob is set after sof_ipc4_init_input_audio_fmt
- */
- if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
- struct sof_ipc4_alh_configuration_blob *blob;
- struct sof_ipc4_dma_config *dma_config;
- struct sof_ipc4_copier_data *alh_data;
- struct sof_ipc4_copier *alh_copier;
- struct snd_sof_widget *w;
- u32 ch_count = 0;
- u32 ch_mask = 0;
- u32 ch_map;
- u32 step;
- u32 mask;
- blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
- blob->gw_attr.lp_buffer_alloc = 0;
- /* Get channel_mask from ch_map */
- ch_map = copier_data->base_config.audio_fmt.ch_map;
- for (i = 0; ch_map; i++) {
- if ((ch_map & 0xf) != 0xf) {
- ch_mask |= BIT(i);
- ch_count++;
- }
- ch_map >>= 4;
- }
- if (swidget->id == snd_soc_dapm_dai_in && ch_count == out_ref_channels) {
- /*
- * For playback DAI widgets where the channel number is equal to
- * the output reference channels, set the step = 0 to ensure all
- * the ch_mask is applied to all alh mappings.
- */
- mask = ch_mask;
- step = 0;
- } else {
- step = ch_count / blob->alh_cfg.device_count;
- mask = GENMASK(step - 1, 0);
- }
- /*
- * Set each gtw_cfg.node_id to blob->alh_cfg.mapping[]
- * for all widgets with the same stream name
- */
- i = 0;
- list_for_each_entry(w, &sdev->widget_list, list) {
- u32 node_type;
- if (!WIDGET_IS_DAI(w->id) || !w->widget->sname ||
- strcmp(w->widget->sname, swidget->widget->sname))
- continue;
- dai = w->private;
- if (dai->type != SOF_DAI_INTEL_ALH)
- continue;
- alh_copier = (struct sof_ipc4_copier *)dai->private;
- alh_data = &alh_copier->data;
- node_type = SOF_IPC4_GET_NODE_TYPE(alh_data->gtw_cfg.node_id);
- blob->alh_cfg.mapping[i].device = SOF_IPC4_NODE_TYPE(node_type);
- blob->alh_cfg.mapping[i].device |=
- SOF_IPC4_NODE_INDEX(alh_copier->dai_index);
- /*
- * The mapping[i] device in ALH blob should be the same as the
- * dma_config_tlv[i] mapping device if a dma_config_tlv is present.
- * The device id will be used for DMA tlv mapping purposes.
- */
- if (ipc4_copier->dma_config_tlv[i].length) {
- dma_config = &ipc4_copier->dma_config_tlv[i].dma_config;
- blob->alh_cfg.mapping[i].device =
- dma_config->dma_stream_channel_map.mapping[0].device;
- }
- /*
- * Set the same channel mask if the widget channel count is the same
- * as the FE channels for playback as the audio data is duplicated
- * for all speakers in this case. Otherwise, split the channels
- * among the aggregated DAIs. For example, with 4 channels on 2
- * aggregated DAIs, the channel_mask should be 0x3 and 0xc for the
- * two DAI's.
- * The channel masks used depend on the cpu_dais used in the
- * dailink at the machine driver level, which actually comes from
- * the tables in soc_acpi files depending on the _ADR and devID
- * registers for each codec.
- */
- blob->alh_cfg.mapping[i].channel_mask = mask << (step * i);
- i++;
- }
- if (blob->alh_cfg.device_count > 1) {
- int group_id;
- group_id = ida_alloc_max(&alh_group_ida, ALH_MULTI_GTW_COUNT - 1,
- GFP_KERNEL);
- if (group_id < 0)
- return group_id;
- /* add multi-gateway base */
- group_id += ALH_MULTI_GTW_BASE;
- copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
- copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(group_id);
- }
- }
- }
- }
- /* modify the input params for the next widget */
- ret = sof_ipc4_update_hw_params(sdev, pipeline_params,
- &copier_data->out_format,
- BIT(SNDRV_PCM_HW_PARAM_FORMAT) |
- BIT(SNDRV_PCM_HW_PARAM_CHANNELS) |
- BIT(SNDRV_PCM_HW_PARAM_RATE));
- if (ret)
- return ret;
- /*
- * Set the gateway dma_buffer_size to 2ms buffer size to meet the FW expectation. In the
- * deep buffer case, set the dma_buffer_size depending on the deep_buffer_dma_ms set
- * in topology.
- */
- switch (swidget->id) {
- case snd_soc_dapm_dai_in:
- copier_data->gtw_cfg.dma_buffer_size =
- SOF_IPC4_MIN_DMA_BUFFER_SIZE * copier_data->base_config.ibs;
- break;
- case snd_soc_dapm_aif_in:
- copier_data->gtw_cfg.dma_buffer_size =
- max((u32)SOF_IPC4_MIN_DMA_BUFFER_SIZE, deep_buffer_dma_ms) *
- copier_data->base_config.ibs;
- dev_dbg(sdev->dev, "copier %s, dma buffer%s: %u ms (%u bytes)",
- swidget->widget->name,
- deep_buffer_dma_ms ? " (using Deep Buffer)" : "",
- max((u32)SOF_IPC4_MIN_DMA_BUFFER_SIZE, deep_buffer_dma_ms),
- copier_data->gtw_cfg.dma_buffer_size);
- break;
- case snd_soc_dapm_dai_out:
- case snd_soc_dapm_aif_out:
- copier_data->gtw_cfg.dma_buffer_size =
- SOF_IPC4_MIN_DMA_BUFFER_SIZE * copier_data->base_config.obs;
- break;
- default:
- break;
- }
- data = &ipc4_copier->copier_config;
- ipc_config_size = &ipc4_copier->ipc_config_size;
- ipc_config_data = &ipc4_copier->ipc_config_data;
- /* config_length is DWORD based */
- gtw_cfg_config_length = copier_data->gtw_cfg.config_length * 4;
- ipc_size = sizeof(*copier_data) + gtw_cfg_config_length;
- dma_config_tlv_size = 0;
- for (i = 0; i < SOF_IPC4_DMA_DEVICE_MAX_COUNT; i++) {
- if (ipc4_copier->dma_config_tlv[i].type != SOF_IPC4_GTW_DMA_CONFIG_ID)
- continue;
- dma_config_tlv_size += ipc4_copier->dma_config_tlv[i].length;
- dma_config_tlv_size +=
- ipc4_copier->dma_config_tlv[i].dma_config.dma_priv_config_size;
- dma_config_tlv_size += (sizeof(ipc4_copier->dma_config_tlv[i]) -
- sizeof(ipc4_copier->dma_config_tlv[i].dma_config));
- }
- if (dma_config_tlv_size) {
- ipc_size += dma_config_tlv_size;
- /* we also need to increase the size at the gtw level */
- copier_data->gtw_cfg.config_length += dma_config_tlv_size / 4;
- }
- dev_dbg(sdev->dev, "copier %s, IPC size is %d", swidget->widget->name, ipc_size);
- *ipc_config_data = kzalloc(ipc_size, GFP_KERNEL);
- if (!*ipc_config_data)
- return -ENOMEM;
- *ipc_config_size = ipc_size;
- sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt,
- input_fmt_index, output_fmt_index);
- /* update pipeline memory usage */
- sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config);
- /* copy IPC data */
- memcpy(*ipc_config_data, (void *)copier_data, sizeof(*copier_data));
- if (gtw_cfg_config_length)
- memcpy(*ipc_config_data + sizeof(*copier_data),
- *data, gtw_cfg_config_length);
- /* add DMA Config TLV, if configured */
- if (dma_config_tlv_size)
- memcpy(*ipc_config_data + sizeof(*copier_data) +
- gtw_cfg_config_length,
- &ipc4_copier->dma_config_tlv, dma_config_tlv_size);
- /*
- * Restore gateway config length now that IPC payload is prepared. This avoids
- * counting the DMA CONFIG TLV multiple times
- */
- copier_data->gtw_cfg.config_length = gtw_cfg_config_length / 4;
- return 0;
- }
- static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget,
- struct snd_pcm_hw_params *fe_params,
- struct snd_sof_platform_stream_params *platform_params,
- struct snd_pcm_hw_params *pipeline_params, int dir)
- {
- struct snd_soc_component *scomp = swidget->scomp;
- struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
- struct sof_ipc4_gain *gain = swidget->private;
- struct sof_ipc4_available_audio_format *available_fmt = &gain->available_fmt;
- struct sof_ipc4_audio_format *in_fmt;
- u32 out_ref_rate, out_ref_channels, out_ref_valid_bits, out_ref_type;
- int input_fmt_index, output_fmt_index;
- input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget,
- &gain->data.base_config,
- pipeline_params,
- available_fmt);
- if (input_fmt_index < 0)
- return input_fmt_index;
- in_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt;
- out_ref_rate = in_fmt->sampling_frequency;
- out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
- out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
- out_ref_type = sof_ipc4_fmt_cfg_to_type(in_fmt->fmt_cfg);
- output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget,
- &gain->data.base_config,
- available_fmt,
- out_ref_rate,
- out_ref_channels,
- out_ref_valid_bits,
- out_ref_type);
- if (output_fmt_index < 0)
- return output_fmt_index;
- sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt,
- input_fmt_index, output_fmt_index);
- /* update pipeline memory usage */
- sof_ipc4_update_resource_usage(sdev, swidget, &gain->data.base_config);
- return 0;
- }
- static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget,
- struct snd_pcm_hw_params *fe_params,
- struct snd_sof_platform_stream_params *platform_params,
- struct snd_pcm_hw_params *pipeline_params, int dir)
- {
- struct snd_soc_component *scomp = swidget->scomp;
- struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
- struct sof_ipc4_mixer *mixer = swidget->private;
- struct sof_ipc4_available_audio_format *available_fmt = &mixer->available_fmt;
- struct sof_ipc4_audio_format *in_fmt;
- u32 out_ref_rate, out_ref_channels, out_ref_valid_bits, out_ref_type;
- int input_fmt_index, output_fmt_index;
- input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget,
- &mixer->base_config,
- pipeline_params,
- available_fmt);
- if (input_fmt_index < 0)
- return input_fmt_index;
- in_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt;
- out_ref_rate = in_fmt->sampling_frequency;
- out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
- out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
- out_ref_type = sof_ipc4_fmt_cfg_to_type(in_fmt->fmt_cfg);
- output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget,
- &mixer->base_config,
- available_fmt,
- out_ref_rate,
- out_ref_channels,
- out_ref_valid_bits,
- out_ref_type);
- if (output_fmt_index < 0)
- return output_fmt_index;
- sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt,
- input_fmt_index, output_fmt_index);
- /* update pipeline memory usage */
- sof_ipc4_update_resource_usage(sdev, swidget, &mixer->base_config);
- return 0;
- }
- static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget,
- struct snd_pcm_hw_params *fe_params,
- struct snd_sof_platform_stream_params *platform_params,
- struct snd_pcm_hw_params *pipeline_params, int dir)
- {
- struct snd_soc_component *scomp = swidget->scomp;
- struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
- struct sof_ipc4_src *src = swidget->private;
- struct sof_ipc4_available_audio_format *available_fmt = &src->available_fmt;
- struct sof_ipc4_audio_format *out_audio_fmt;
- struct sof_ipc4_audio_format *in_audio_fmt;
- u32 out_ref_rate, out_ref_channels, out_ref_valid_bits, out_ref_type;
- int output_fmt_index, input_fmt_index;
- input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget,
- &src->data.base_config,
- pipeline_params,
- available_fmt);
- if (input_fmt_index < 0)
- return input_fmt_index;
- /*
- * For playback, the SRC sink rate will be configured based on the requested output
- * format, which is restricted to only deal with DAI's with a single format for now.
- */
- if (dir == SNDRV_PCM_STREAM_PLAYBACK && available_fmt->num_output_formats > 1) {
- dev_err(sdev->dev, "Invalid number of output formats: %d for SRC %s\n",
- available_fmt->num_output_formats, swidget->widget->name);
- return -EINVAL;
- }
- /*
- * SRC does not perform format conversion, so the output channels and valid bit depth must
- * be the same as that of the input.
- */
- in_audio_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt;
- out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_audio_fmt->fmt_cfg);
- out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_audio_fmt->fmt_cfg);
- out_ref_type = sof_ipc4_fmt_cfg_to_type(in_audio_fmt->fmt_cfg);
- /*
- * For capture, the SRC module should convert the rate to match the rate requested by the
- * PCM hw_params. Set the reference params based on the fe_params unconditionally as it
- * will be ignored for playback anyway.
- */
- out_ref_rate = params_rate(fe_params);
- output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget,
- &src->data.base_config,
- available_fmt,
- out_ref_rate,
- out_ref_channels,
- out_ref_valid_bits,
- out_ref_type);
- if (output_fmt_index < 0)
- return output_fmt_index;
- sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt,
- input_fmt_index, output_fmt_index);
- /* update pipeline memory usage */
- sof_ipc4_update_resource_usage(sdev, swidget, &src->data.base_config);
- out_audio_fmt = &available_fmt->output_pin_fmts[output_fmt_index].audio_fmt;
- src->data.sink_rate = out_audio_fmt->sampling_frequency;
- /* update pipeline_params for sink widgets */
- return sof_ipc4_update_hw_params(sdev, pipeline_params, out_audio_fmt,
- BIT(SNDRV_PCM_HW_PARAM_FORMAT) |
- BIT(SNDRV_PCM_HW_PARAM_CHANNELS) |
- BIT(SNDRV_PCM_HW_PARAM_RATE));
- }
- static int
- sof_ipc4_process_set_pin_formats(struct snd_sof_widget *swidget, int pin_type)
- {
- struct sof_ipc4_process *process = swidget->private;
- struct sof_ipc4_base_module_cfg_ext *base_cfg_ext = process->base_config_ext;
- struct sof_ipc4_available_audio_format *available_fmt = &process->available_fmt;
- struct sof_ipc4_pin_format *pin_format, *format_list_to_search;
- struct snd_soc_component *scomp = swidget->scomp;
- int num_pins, format_list_count;
- int pin_format_offset = 0;
- int i, j;
- /* set number of pins, offset of pin format and format list to search based on pin type */
- if (pin_type == SOF_PIN_TYPE_INPUT) {
- num_pins = swidget->num_input_pins;
- format_list_to_search = available_fmt->input_pin_fmts;
- format_list_count = available_fmt->num_input_formats;
- } else {
- num_pins = swidget->num_output_pins;
- pin_format_offset = swidget->num_input_pins;
- format_list_to_search = available_fmt->output_pin_fmts;
- format_list_count = available_fmt->num_output_formats;
- }
- for (i = pin_format_offset; i < num_pins + pin_format_offset; i++) {
- pin_format = &base_cfg_ext->pin_formats[i];
- /* Pin 0 audio formats are derived from the base config input/output format */
- if (i == pin_format_offset) {
- if (pin_type == SOF_PIN_TYPE_INPUT) {
- pin_format->buffer_size = process->base_config.ibs;
- pin_format->audio_fmt = process->base_config.audio_fmt;
- } else {
- pin_format->buffer_size = process->base_config.obs;
- pin_format->audio_fmt = process->output_format;
- }
- continue;
- }
- /*
- * For all other pins, find the pin formats from those set in topology. If there
- * is more than one format specified for a pin, this will pick the first available
- * one.
- */
- for (j = 0; j < format_list_count; j++) {
- struct sof_ipc4_pin_format *pin_format_item = &format_list_to_search[j];
- if (pin_format_item->pin_index == i - pin_format_offset) {
- *pin_format = *pin_format_item;
- break;
- }
- }
- if (j == format_list_count) {
- dev_err(scomp->dev, "%s pin %d format not found for %s\n",
- (pin_type == SOF_PIN_TYPE_INPUT) ? "input" : "output",
- i - pin_format_offset, swidget->widget->name);
- return -EINVAL;
- }
- }
- return 0;
- }
- static int sof_ipc4_process_add_base_cfg_extn(struct snd_sof_widget *swidget)
- {
- int ret, i;
- /* copy input and output pin formats */
- for (i = 0; i <= SOF_PIN_TYPE_OUTPUT; i++) {
- ret = sof_ipc4_process_set_pin_formats(swidget, i);
- if (ret < 0)
- return ret;
- }
- return 0;
- }
- static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget,
- struct snd_pcm_hw_params *fe_params,
- struct snd_sof_platform_stream_params *platform_params,
- struct snd_pcm_hw_params *pipeline_params, int dir)
- {
- struct snd_soc_component *scomp = swidget->scomp;
- struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
- struct sof_ipc4_process *process = swidget->private;
- struct sof_ipc4_available_audio_format *available_fmt = &process->available_fmt;
- void *cfg = process->ipc_config_data;
- int output_fmt_index = 0;
- int input_fmt_index = 0;
- int ret;
- if (available_fmt->num_input_formats) {
- input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget,
- &process->base_config,
- pipeline_params,
- available_fmt);
- if (input_fmt_index < 0)
- return input_fmt_index;
- }
- /* Configure output audio format only if the module supports output */
- if (available_fmt->num_output_formats) {
- struct sof_ipc4_audio_format *in_fmt;
- struct sof_ipc4_pin_format *pin_fmt;
- u32 out_ref_rate, out_ref_channels;
- int out_ref_valid_bits, out_ref_type;
- if (available_fmt->num_input_formats) {
- in_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt;
- out_ref_rate = in_fmt->sampling_frequency;
- out_ref_channels =
- SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
- out_ref_valid_bits =
- SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
- out_ref_type = sof_ipc4_fmt_cfg_to_type(in_fmt->fmt_cfg);
- } else {
- /* for modules without input formats, use FE params as reference */
- out_ref_rate = params_rate(fe_params);
- out_ref_channels = params_channels(fe_params);
- ret = sof_ipc4_get_sample_type(sdev, fe_params);
- if (ret < 0)
- return ret;
- out_ref_type = (u32)ret;
- out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params);
- if (out_ref_valid_bits < 0)
- return out_ref_valid_bits;
- }
- output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget,
- &process->base_config,
- available_fmt,
- out_ref_rate,
- out_ref_channels,
- out_ref_valid_bits,
- out_ref_type);
- if (output_fmt_index < 0)
- return output_fmt_index;
- pin_fmt = &available_fmt->output_pin_fmts[output_fmt_index];
- /* copy Pin output format for Pin 0 only */
- if (pin_fmt->pin_index == 0) {
- memcpy(&process->output_format, &pin_fmt->audio_fmt,
- sizeof(struct sof_ipc4_audio_format));
- /* modify the pipeline params with the output format */
- ret = sof_ipc4_update_hw_params(sdev, pipeline_params,
- &process->output_format,
- BIT(SNDRV_PCM_HW_PARAM_FORMAT) |
- BIT(SNDRV_PCM_HW_PARAM_CHANNELS) |
- BIT(SNDRV_PCM_HW_PARAM_RATE));
- if (ret)
- return ret;
- }
- /* set base cfg to match the first output format if there are no input formats */
- if (!available_fmt->num_input_formats) {
- struct sof_ipc4_audio_format *out_fmt;
- out_fmt = &available_fmt->output_pin_fmts[0].audio_fmt;
- /* copy output format */
- memcpy(&process->base_config.audio_fmt, out_fmt, sizeof(*out_fmt));
- }
- }
- sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt,
- input_fmt_index, output_fmt_index);
- /* update pipeline memory usage */
- sof_ipc4_update_resource_usage(sdev, swidget, &process->base_config);
- /* ipc_config_data is composed of the base_config followed by an optional extension */
- memcpy(cfg, &process->base_config, sizeof(struct sof_ipc4_base_module_cfg));
- cfg += sizeof(struct sof_ipc4_base_module_cfg);
- if (process->init_config == SOF_IPC4_MODULE_INIT_CONFIG_TYPE_BASE_CFG_WITH_EXT) {
- struct sof_ipc4_base_module_cfg_ext *base_cfg_ext = process->base_config_ext;
- ret = sof_ipc4_process_add_base_cfg_extn(swidget);
- if (ret < 0)
- return ret;
- memcpy(cfg, base_cfg_ext, process->base_config_ext_size);
- }
- return 0;
- }
- static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
- {
- struct sof_ipc4_control_data *control_data;
- struct sof_ipc4_msg *msg;
- int i;
- scontrol->size = struct_size(control_data, chanv, scontrol->num_channels);
- /* scontrol->ipc_control_data will be freed in sof_control_unload */
- scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL);
- if (!scontrol->ipc_control_data)
- return -ENOMEM;
- control_data = scontrol->ipc_control_data;
- control_data->index = scontrol->index;
- msg = &control_data->msg;
- msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET);
- msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
- msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
- /* volume controls with range 0-1 (off/on) are switch controls */
- if (scontrol->max == 1)
- msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_SWITCH_CONTROL_PARAM_ID);
- else
- msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_GAIN_PARAM_ID);
- for (i = 0; i < scontrol->num_channels; i++) {
- control_data->chanv[i].channel = i;
- /*
- * Default, initial values:
- * - 0dB for volume controls
- * - off (0) for switch controls - value already zero after
- * memory allocation
- */
- if (scontrol->max > 1)
- control_data->chanv[i].value = SOF_IPC4_VOL_ZERO_DB;
- }
- return 0;
- }
- static int sof_ipc4_control_load_enum(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
- {
- struct sof_ipc4_control_data *control_data;
- struct sof_ipc4_msg *msg;
- int i;
- scontrol->size = struct_size(control_data, chanv, scontrol->num_channels);
- /* scontrol->ipc_control_data will be freed in sof_control_unload */
- scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL);
- if (!scontrol->ipc_control_data)
- return -ENOMEM;
- control_data = scontrol->ipc_control_data;
- control_data->index = scontrol->index;
- msg = &control_data->msg;
- msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET);
- msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
- msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
- msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_ENUM_CONTROL_PARAM_ID);
- /* Default, initial value for enums: first enum entry is selected (0) */
- for (i = 0; i < scontrol->num_channels; i++)
- control_data->chanv[i].channel = i;
- return 0;
- }
- static int sof_ipc4_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
- {
- struct sof_ipc4_control_data *control_data;
- struct sof_ipc4_msg *msg;
- int ret;
- /*
- * The max_size is coming from topology and indicates the maximum size
- * of sof_abi_hdr plus the payload, which excludes the local only
- * 'struct sof_ipc4_control_data'
- */
- if (scontrol->max_size < sizeof(struct sof_abi_hdr)) {
- dev_err(sdev->dev,
- "insufficient maximum size for a bytes control %s: %zu.\n",
- scontrol->name, scontrol->max_size);
- return -EINVAL;
- }
- if (scontrol->priv_size > scontrol->max_size) {
- dev_err(sdev->dev,
- "bytes control %s initial data size %zu exceeds max %zu.\n",
- scontrol->name, scontrol->priv_size, scontrol->max_size);
- return -EINVAL;
- }
- if (scontrol->priv_size && scontrol->priv_size < sizeof(struct sof_abi_hdr)) {
- dev_err(sdev->dev,
- "bytes control %s initial data size %zu is insufficient.\n",
- scontrol->name, scontrol->priv_size);
- return -EINVAL;
- }
- /*
- * The used size behind the cdata pointer, which can be smaller than
- * the maximum size
- */
- scontrol->size = sizeof(*control_data) + scontrol->priv_size;
- /* Allocate the cdata: local struct size + maximum payload size */
- scontrol->ipc_control_data = kzalloc(sizeof(*control_data) + scontrol->max_size,
- GFP_KERNEL);
- if (!scontrol->ipc_control_data)
- return -ENOMEM;
- control_data = scontrol->ipc_control_data;
- control_data->index = scontrol->index;
- if (scontrol->priv_size > 0) {
- memcpy(control_data->data, scontrol->priv, scontrol->priv_size);
- kfree(scontrol->priv);
- scontrol->priv = NULL;
- if (control_data->data->magic != SOF_IPC4_ABI_MAGIC) {
- dev_err(sdev->dev, "Wrong ABI magic (%#x) for control: %s\n",
- control_data->data->magic, scontrol->name);
- ret = -EINVAL;
- goto err;
- }
- /* TODO: check the ABI version */
- if (control_data->data->size + sizeof(struct sof_abi_hdr) !=
- scontrol->priv_size) {
- dev_err(sdev->dev, "Control %s conflict in bytes %zu vs. priv size %zu.\n",
- scontrol->name,
- control_data->data->size + sizeof(struct sof_abi_hdr),
- scontrol->priv_size);
- ret = -EINVAL;
- goto err;
- }
- }
- msg = &control_data->msg;
- msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET);
- msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
- msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
- msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(control_data->data->type);
- return 0;
- err:
- kfree(scontrol->ipc_control_data);
- scontrol->ipc_control_data = NULL;
- return ret;
- }
- static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
- {
- switch (scontrol->info_type) {
- case SND_SOC_TPLG_CTL_VOLSW:
- case SND_SOC_TPLG_CTL_VOLSW_SX:
- case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
- return sof_ipc4_control_load_volume(sdev, scontrol);
- case SND_SOC_TPLG_CTL_BYTES:
- return sof_ipc4_control_load_bytes(sdev, scontrol);
- case SND_SOC_TPLG_CTL_ENUM:
- case SND_SOC_TPLG_CTL_ENUM_VALUE:
- return sof_ipc4_control_load_enum(sdev, scontrol);
- default:
- break;
- }
- return 0;
- }
- static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev,
- struct snd_sof_widget *swidget,
- struct sof_ipc4_msg *msg,
- void *ipc_data, u32 ipc_size,
- void **new_data)
- {
- struct sof_ipc4_mod_init_ext_dp_memory_data *dp_mem_data;
- struct sof_ipc4_module_init_ext_init *ext_init;
- struct sof_ipc4_module_init_ext_object *hdr;
- int new_size;
- u32 *payload;
- u32 ext_pos;
- /* For the moment the only reason for adding init_ext_init payload is DP
- * memory data. If both stack and heap size are 0 (= use default), then
- * there is no need for init_ext_init payload.
- */
- if (swidget->comp_domain != SOF_COMP_DOMAIN_DP) {
- msg->extension &= ~SOF_IPC4_MOD_EXT_EXTENDED_INIT_MASK;
- return 0;
- }
- payload = kzalloc(sdev->ipc->max_payload_size, GFP_KERNEL);
- if (!payload)
- return -ENOMEM;
- /* Add ext_init first and set objects array flag to 1 */
- ext_init = (struct sof_ipc4_module_init_ext_init *)payload;
- ext_init->word0 |= SOF_IPC4_MOD_INIT_EXT_OBJ_ARRAY_MASK;
- ext_pos = DIV_ROUND_UP(sizeof(*ext_init), sizeof(u32));
- /* Add object array objects after ext_init */
- /* Add dp_memory_data if comp_domain indicates DP */
- if (swidget->comp_domain == SOF_COMP_DOMAIN_DP) {
- hdr = (struct sof_ipc4_module_init_ext_object *)&payload[ext_pos];
- hdr->header = SOF_IPC4_MOD_INIT_EXT_OBJ_LAST_MASK |
- SOF_IPC4_MOD_INIT_EXT_OBJ_ID(SOF_IPC4_MOD_INIT_DATA_ID_DP_DATA) |
- SOF_IPC4_MOD_INIT_EXT_OBJ_WORDS(DIV_ROUND_UP(sizeof(*dp_mem_data),
- sizeof(u32)));
- ext_pos += DIV_ROUND_UP(sizeof(*hdr), sizeof(u32));
- dp_mem_data = (struct sof_ipc4_mod_init_ext_dp_memory_data *)&payload[ext_pos];
- dp_mem_data->domain_id = swidget->dp_domain_id;
- dp_mem_data->stack_bytes = swidget->dp_stack_bytes;
- dp_mem_data->heap_bytes = swidget->dp_heap_bytes;
- ext_pos += DIV_ROUND_UP(sizeof(*dp_mem_data), sizeof(u32));
- }
- /* If another array object is added, remember clear previous OBJ_LAST bit */
- /* Calculate final size and check that it fits to max payload size */
- new_size = ext_pos * sizeof(u32) + ipc_size;
- if (new_size > sdev->ipc->max_payload_size) {
- dev_err(sdev->dev, "Max ipc payload size %zu exceeded: %u",
- sdev->ipc->max_payload_size, new_size);
- kfree(payload);
- return -EINVAL;
- }
- *new_data = payload;
- /* Copy module specific ipc_payload to end */
- memcpy(&payload[ext_pos], ipc_data, ipc_size);
- /* Update msg extension bits according to the payload changes */
- msg->extension |= SOF_IPC4_MOD_EXT_EXTENDED_INIT_MASK;
- msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK;
- msg->extension |= SOF_IPC4_MOD_EXT_PARAM_SIZE(DIV_ROUND_UP(new_size, sizeof(u32)));
- return new_size;
- }
- static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
- {
- struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
- struct sof_ipc4_fw_data *ipc4_data = sdev->private;
- struct sof_ipc4_pipeline *pipeline;
- struct sof_ipc4_msg *msg;
- void *ipc_data = NULL;
- void *ext_data = NULL;
- u32 ipc_size = 0;
- int ret;
- switch (swidget->id) {
- case snd_soc_dapm_scheduler:
- pipeline = swidget->private;
- if (pipeline->use_chain_dma) {
- dev_warn(sdev->dev, "use_chain_dma set for scheduler %s",
- swidget->widget->name);
- return 0;
- }
- dev_dbg(sdev->dev, "pipeline: %d memory pages: %d\n", swidget->pipeline_id,
- pipeline->mem_usage);
- msg = &pipeline->msg;
- msg->primary |= pipeline->mem_usage;
- swidget->instance_id = ida_alloc_max(&pipeline_ida, ipc4_data->max_num_pipelines,
- GFP_KERNEL);
- if (swidget->instance_id < 0) {
- dev_err(sdev->dev, "failed to assign pipeline id for %s: %d\n",
- swidget->widget->name, swidget->instance_id);
- return swidget->instance_id;
- }
- msg->primary &= ~SOF_IPC4_GLB_PIPE_INSTANCE_MASK;
- msg->primary |= SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id);
- break;
- case snd_soc_dapm_aif_in:
- case snd_soc_dapm_aif_out:
- case snd_soc_dapm_buffer:
- {
- struct sof_ipc4_copier *ipc4_copier = swidget->private;
- pipeline = pipe_widget->private;
- if (pipeline->use_chain_dma)
- return 0;
- ipc_size = ipc4_copier->ipc_config_size;
- ipc_data = ipc4_copier->ipc_config_data;
- msg = &ipc4_copier->msg;
- break;
- }
- case snd_soc_dapm_dai_in:
- case snd_soc_dapm_dai_out:
- {
- struct snd_sof_dai *dai = swidget->private;
- struct sof_ipc4_copier *ipc4_copier = dai->private;
- pipeline = pipe_widget->private;
- if (pipeline->use_chain_dma)
- return 0;
- ipc_size = ipc4_copier->ipc_config_size;
- ipc_data = ipc4_copier->ipc_config_data;
- msg = &ipc4_copier->msg;
- break;
- }
- case snd_soc_dapm_pga:
- {
- struct sof_ipc4_gain *gain = swidget->private;
- ipc_size = sizeof(gain->data);
- ipc_data = &gain->data;
- msg = &gain->msg;
- break;
- }
- case snd_soc_dapm_mixer:
- {
- struct sof_ipc4_mixer *mixer = swidget->private;
- ipc_size = sizeof(mixer->base_config);
- ipc_data = &mixer->base_config;
- msg = &mixer->msg;
- break;
- }
- case snd_soc_dapm_src:
- {
- struct sof_ipc4_src *src = swidget->private;
- ipc_size = sizeof(src->data);
- ipc_data = &src->data;
- msg = &src->msg;
- break;
- }
- case snd_soc_dapm_asrc:
- {
- struct sof_ipc4_asrc *asrc = swidget->private;
- ipc_size = sizeof(asrc->data);
- ipc_data = &asrc->data;
- msg = &asrc->msg;
- break;
- }
- case snd_soc_dapm_effect:
- {
- struct sof_ipc4_process *process = swidget->private;
- if (!process->ipc_config_size) {
- dev_err(sdev->dev, "module %s has no config data!\n",
- swidget->widget->name);
- return -EINVAL;
- }
- ipc_size = process->ipc_config_size;
- ipc_data = process->ipc_config_data;
- msg = &process->msg;
- break;
- }
- default:
- dev_err(sdev->dev, "widget type %d not supported", swidget->id);
- return -EINVAL;
- }
- if (swidget->id != snd_soc_dapm_scheduler) {
- int module_id = msg->primary & SOF_IPC4_MOD_ID_MASK;
- ret = sof_ipc4_widget_assign_instance_id(sdev, swidget);
- if (ret < 0) {
- dev_err(sdev->dev, "failed to assign instance id for %s\n",
- swidget->widget->name);
- return ret;
- }
- msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK;
- msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id);
- msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK;
- msg->extension |= SOF_IPC4_MOD_EXT_PARAM_SIZE(ipc_size >> 2);
- msg->extension &= ~SOF_IPC4_MOD_EXT_PPL_ID_MASK;
- msg->extension |= SOF_IPC4_MOD_EXT_PPL_ID(pipe_widget->instance_id);
- dev_dbg(sdev->dev, "Create widget %s (pipe %d) - ID %d, instance %d, core %d\n",
- swidget->widget->name, swidget->pipeline_id, module_id,
- swidget->instance_id, swidget->core);
- ret = sof_ipc4_widget_setup_msg_payload(sdev, swidget, msg, ipc_data, ipc_size,
- &ext_data);
- if (ret < 0)
- goto fail;
- if (ret > 0) {
- ipc_size = ret;
- ipc_data = ext_data;
- }
- } else {
- dev_dbg(sdev->dev, "Create pipeline %s (pipe %d) - instance %d, core %d\n",
- swidget->widget->name, swidget->pipeline_id,
- swidget->instance_id, swidget->core);
- }
- msg->data_size = ipc_size;
- msg->data_ptr = ipc_data;
- ret = sof_ipc_tx_message_no_reply(sdev->ipc, msg, ipc_size);
- fail:
- if (ret < 0) {
- dev_err(sdev->dev, "failed to create module %s\n", swidget->widget->name);
- if (swidget->id != snd_soc_dapm_scheduler) {
- struct sof_ipc4_fw_module *fw_module = swidget->module_info;
- ida_free(&fw_module->m_ida, swidget->instance_id);
- } else {
- ida_free(&pipeline_ida, swidget->instance_id);
- }
- }
- kfree(ext_data);
- return ret;
- }
- static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
- {
- struct sof_ipc4_fw_module *fw_module = swidget->module_info;
- struct sof_ipc4_fw_data *ipc4_data = sdev->private;
- int ret = 0;
- guard(mutex)(&ipc4_data->pipeline_state_mutex);
- /* freeing a pipeline frees all the widgets associated with it */
- if (swidget->id == snd_soc_dapm_scheduler) {
- struct sof_ipc4_pipeline *pipeline = swidget->private;
- struct sof_ipc4_msg msg = {{ 0 }};
- u32 header;
- if (pipeline->use_chain_dma) {
- dev_warn(sdev->dev, "use_chain_dma set for scheduler %s",
- swidget->widget->name);
- return 0;
- }
- header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id);
- header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_DELETE_PIPELINE);
- header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
- header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
- msg.primary = header;
- ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0);
- if (ret < 0)
- dev_err(sdev->dev, "failed to free pipeline widget %s\n",
- swidget->widget->name);
- pipeline->mem_usage = 0;
- pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
- ida_free(&pipeline_ida, swidget->instance_id);
- swidget->instance_id = -EINVAL;
- } else {
- struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
- struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
- if (!pipeline->use_chain_dma)
- ida_free(&fw_module->m_ida, swidget->instance_id);
- }
- return ret;
- }
- static int sof_ipc4_get_queue_id(struct snd_sof_widget *src_widget,
- struct snd_sof_widget *sink_widget, bool pin_type)
- {
- struct snd_sof_widget *current_swidget;
- struct snd_soc_component *scomp;
- struct ida *queue_ida;
- const char *buddy_name;
- char **pin_binding;
- u32 num_pins;
- int i;
- if (pin_type == SOF_PIN_TYPE_OUTPUT) {
- current_swidget = src_widget;
- pin_binding = src_widget->output_pin_binding;
- queue_ida = &src_widget->output_queue_ida;
- num_pins = src_widget->num_output_pins;
- buddy_name = sink_widget->widget->name;
- } else {
- current_swidget = sink_widget;
- pin_binding = sink_widget->input_pin_binding;
- queue_ida = &sink_widget->input_queue_ida;
- num_pins = sink_widget->num_input_pins;
- buddy_name = src_widget->widget->name;
- }
- scomp = current_swidget->scomp;
- if (num_pins < 1) {
- dev_err(scomp->dev, "invalid %s num_pins: %d for queue allocation for %s\n",
- (pin_type == SOF_PIN_TYPE_OUTPUT ? "output" : "input"),
- num_pins, current_swidget->widget->name);
- return -EINVAL;
- }
- /* If there is only one input/output pin, queue id must be 0 */
- if (num_pins == 1)
- return 0;
- /* Allocate queue ID from pin binding array if it is defined in topology. */
- if (pin_binding) {
- for (i = 0; i < num_pins; i++) {
- if (!strcmp(pin_binding[i], buddy_name))
- return i;
- }
- /*
- * Fail if no queue ID found from pin binding array, so that we don't
- * mixed use pin binding array and ida for queue ID allocation.
- */
- dev_err(scomp->dev, "no %s queue id found from pin binding array for %s\n",
- (pin_type == SOF_PIN_TYPE_OUTPUT ? "output" : "input"),
- current_swidget->widget->name);
- return -EINVAL;
- }
- /* If no pin binding array specified in topology, use ida to allocate one */
- return ida_alloc_max(queue_ida, num_pins, GFP_KERNEL);
- }
- static void sof_ipc4_put_queue_id(struct snd_sof_widget *swidget, int queue_id,
- bool pin_type)
- {
- struct ida *queue_ida;
- char **pin_binding;
- int num_pins;
- if (pin_type == SOF_PIN_TYPE_OUTPUT) {
- pin_binding = swidget->output_pin_binding;
- queue_ida = &swidget->output_queue_ida;
- num_pins = swidget->num_output_pins;
- } else {
- pin_binding = swidget->input_pin_binding;
- queue_ida = &swidget->input_queue_ida;
- num_pins = swidget->num_input_pins;
- }
- /* Nothing to free if queue ID is not allocated with ida. */
- if (num_pins == 1 || pin_binding)
- return;
- ida_free(queue_ida, queue_id);
- }
- static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev,
- struct snd_sof_widget *src_widget,
- struct snd_sof_widget *sink_widget,
- struct snd_sof_route *sroute)
- {
- struct sof_ipc4_copier_config_set_sink_format format;
- const struct sof_ipc_ops *iops = sdev->ipc->ops;
- struct sof_ipc4_base_module_cfg *src_config;
- const struct sof_ipc4_audio_format *pin_fmt;
- struct sof_ipc4_fw_module *fw_module;
- struct sof_ipc4_msg msg = {{ 0 }};
- if (WIDGET_IS_DAI(src_widget->id)) {
- struct snd_sof_dai *dai = src_widget->private;
- src_config = dai->private;
- } else {
- src_config = src_widget->private;
- }
- fw_module = src_widget->module_info;
- format.sink_id = sroute->src_queue_id;
- memcpy(&format.source_fmt, &src_config->audio_fmt, sizeof(format.source_fmt));
- pin_fmt = sof_ipc4_get_input_pin_audio_fmt(sink_widget, sroute->dst_queue_id);
- if (!pin_fmt) {
- dev_err(sdev->dev,
- "Failed to get input audio format of %s:%d for output of %s:%d\n",
- sink_widget->widget->name, sroute->dst_queue_id,
- src_widget->widget->name, sroute->src_queue_id);
- return -EINVAL;
- }
- memcpy(&format.sink_fmt, pin_fmt, sizeof(format.sink_fmt));
- msg.data_size = sizeof(format);
- msg.data_ptr = &format;
- msg.primary = fw_module->man4_module_entry.id;
- msg.primary |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
- msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
- msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
- msg.extension =
- SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_COPIER_MODULE_CFG_PARAM_SET_SINK_FORMAT);
- return iops->set_get_data(sdev, &msg, msg.data_size, true);
- }
- static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
- {
- struct snd_sof_widget *src_widget = sroute->src_widget;
- struct snd_sof_widget *sink_widget = sroute->sink_widget;
- struct snd_sof_widget *src_pipe_widget = src_widget->spipe->pipe_widget;
- struct snd_sof_widget *sink_pipe_widget = sink_widget->spipe->pipe_widget;
- struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;
- struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
- struct sof_ipc4_pipeline *src_pipeline = src_pipe_widget->private;
- struct sof_ipc4_pipeline *sink_pipeline = sink_pipe_widget->private;
- struct sof_ipc4_msg msg = {{ 0 }};
- u32 header, extension;
- int ret;
- /* no route set up if chain DMA is used */
- if (src_pipeline->use_chain_dma || sink_pipeline->use_chain_dma) {
- if (!src_pipeline->use_chain_dma || !sink_pipeline->use_chain_dma) {
- dev_err(sdev->dev,
- "use_chain_dma must be set for both src %s and sink %s pipelines\n",
- src_widget->widget->name, sink_widget->widget->name);
- return -EINVAL;
- }
- return 0;
- }
- if (!src_fw_module || !sink_fw_module) {
- dev_err(sdev->dev,
- "cannot bind %s -> %s, no firmware module for: %s%s\n",
- src_widget->widget->name, sink_widget->widget->name,
- src_fw_module ? "" : " source",
- sink_fw_module ? "" : " sink");
- return -ENODEV;
- }
- sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
- SOF_PIN_TYPE_OUTPUT);
- if (sroute->src_queue_id < 0) {
- dev_err(sdev->dev,
- "failed to get src_queue_id ID from source widget %s\n",
- src_widget->widget->name);
- return sroute->src_queue_id;
- }
- sroute->dst_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget,
- SOF_PIN_TYPE_INPUT);
- if (sroute->dst_queue_id < 0) {
- dev_err(sdev->dev,
- "failed to get dst_queue_id ID from sink widget %s\n",
- sink_widget->widget->name);
- sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id,
- SOF_PIN_TYPE_OUTPUT);
- return sroute->dst_queue_id;
- }
- /* Pin 0 format is already set during copier module init */
- if (sroute->src_queue_id > 0 && WIDGET_IS_COPIER(src_widget->id)) {
- ret = sof_ipc4_set_copier_sink_format(sdev, src_widget,
- sink_widget, sroute);
- if (ret < 0) {
- dev_err(sdev->dev,
- "failed to set sink format for source %s:%d\n",
- src_widget->widget->name, sroute->src_queue_id);
- goto out;
- }
- }
- dev_dbg(sdev->dev, "bind %s:%d -> %s:%d\n",
- src_widget->widget->name, sroute->src_queue_id,
- sink_widget->widget->name, sroute->dst_queue_id);
- header = src_fw_module->man4_module_entry.id;
- header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
- header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_BIND);
- header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
- header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
- extension = sink_fw_module->man4_module_entry.id;
- extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id);
- extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id);
- extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id);
- msg.primary = header;
- msg.extension = extension;
- ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0);
- if (ret < 0) {
- dev_err(sdev->dev, "failed to bind modules %s:%d -> %s:%d\n",
- src_widget->widget->name, sroute->src_queue_id,
- sink_widget->widget->name, sroute->dst_queue_id);
- goto out;
- }
- return ret;
- out:
- sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_OUTPUT);
- sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_INPUT);
- return ret;
- }
- static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
- {
- struct snd_sof_widget *src_widget = sroute->src_widget;
- struct snd_sof_widget *sink_widget = sroute->sink_widget;
- struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;
- struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
- struct sof_ipc4_msg msg = {{ 0 }};
- struct snd_sof_widget *src_pipe_widget = src_widget->spipe->pipe_widget;
- struct snd_sof_widget *sink_pipe_widget = sink_widget->spipe->pipe_widget;
- struct sof_ipc4_pipeline *src_pipeline = src_pipe_widget->private;
- struct sof_ipc4_pipeline *sink_pipeline = sink_pipe_widget->private;
- u32 header, extension;
- int ret = 0;
- /* no route is set up if chain DMA is used */
- if (src_pipeline->use_chain_dma || sink_pipeline->use_chain_dma)
- return 0;
- dev_dbg(sdev->dev, "unbind modules %s:%d -> %s:%d\n",
- src_widget->widget->name, sroute->src_queue_id,
- sink_widget->widget->name, sroute->dst_queue_id);
- /*
- * routes belonging to the same pipeline will be disconnected by the FW when the pipeline
- * is freed. So avoid sending this IPC which will be ignored by the FW anyway.
- */
- if (src_widget->spipe->pipe_widget == sink_widget->spipe->pipe_widget)
- goto out;
- header = src_fw_module->man4_module_entry.id;
- header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
- header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_UNBIND);
- header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
- header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
- extension = sink_fw_module->man4_module_entry.id;
- extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id);
- extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id);
- extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id);
- msg.primary = header;
- msg.extension = extension;
- ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0);
- if (ret < 0)
- dev_err(sdev->dev, "failed to unbind modules %s:%d -> %s:%d\n",
- src_widget->widget->name, sroute->src_queue_id,
- sink_widget->widget->name, sroute->dst_queue_id);
- out:
- sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_INPUT);
- sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_OUTPUT);
- return ret;
- }
- static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
- unsigned int flags, struct snd_sof_dai_config_data *data)
- {
- struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
- struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
- struct snd_sof_dai *dai = swidget->private;
- struct sof_ipc4_gtw_attributes *gtw_attr;
- struct sof_ipc4_copier_data *copier_data;
- struct sof_ipc4_copier *ipc4_copier;
- if (!dai || !dai->private) {
- dev_err(sdev->dev, "Invalid DAI or DAI private data for %s\n",
- swidget->widget->name);
- return -EINVAL;
- }
- ipc4_copier = (struct sof_ipc4_copier *)dai->private;
- copier_data = &ipc4_copier->data;
- if (!data)
- return 0;
- if (pipeline->use_chain_dma) {
- /*
- * Only configure the DMA Link ID for ChainDMA when this op is
- * invoked with SOF_DAI_CONFIG_FLAGS_HW_PARAMS
- */
- if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) {
- pipeline->msg.primary &= ~SOF_IPC4_GLB_CHAIN_DMA_LINK_ID_MASK;
- pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_LINK_ID(data->dai_data);
- }
- return 0;
- }
- switch (ipc4_copier->dai_type) {
- case SOF_DAI_INTEL_HDA:
- gtw_attr = ipc4_copier->gtw_attr;
- gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
- if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) {
- copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
- copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_data);
- }
- break;
- case SOF_DAI_INTEL_ALH:
- /*
- * Do not clear the node ID when this op is invoked with
- * SOF_DAI_CONFIG_FLAGS_HW_FREE. It is needed to free the group_ida during
- * unprepare. The node_id for multi-gateway DAI's will be overwritten with the
- * group_id during copier's ipc_prepare op.
- */
- if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) {
- struct sof_ipc4_alh_configuration_blob *blob;
- blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
- ipc4_copier->dai_index = data->dai_node_id;
- /*
- * no need to set the node_id for aggregated DAI's. These will be assigned
- * a group_id during widget ipc_prepare
- */
- if (blob->alh_cfg.device_count == 1) {
- copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
- copier_data->gtw_cfg.node_id |=
- SOF_IPC4_NODE_INDEX(data->dai_node_id);
- }
- }
- break;
- case SOF_DAI_INTEL_DMIC:
- case SOF_DAI_INTEL_SSP:
- /* nothing to do for SSP/DMIC */
- break;
- default:
- dev_err(sdev->dev, "%s: unsupported dai type %d\n", __func__,
- ipc4_copier->dai_type);
- return -EINVAL;
- }
- return 0;
- }
- static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index,
- struct snd_soc_tplg_manifest *man)
- {
- struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
- struct sof_ipc4_fw_data *ipc4_data = sdev->private;
- struct sof_manifest_tlv *manifest_tlv;
- struct sof_manifest *manifest;
- u32 size = le32_to_cpu(man->priv.size);
- u8 *man_ptr = man->priv.data;
- u32 len_check;
- int i;
- if (!size || size < SOF_IPC4_TPLG_ABI_SIZE) {
- dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n",
- __func__, size);
- return -EINVAL;
- }
- manifest = (struct sof_manifest *)man_ptr;
- dev_info(scomp->dev,
- "Topology: ABI %d:%d:%d Kernel ABI %u:%u:%u\n",
- le16_to_cpu(manifest->abi_major), le16_to_cpu(manifest->abi_minor),
- le16_to_cpu(manifest->abi_patch),
- SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
- /* TODO: Add ABI compatibility check */
- /* no more data after the ABI version */
- if (size <= SOF_IPC4_TPLG_ABI_SIZE)
- return 0;
- manifest_tlv = manifest->items;
- len_check = sizeof(struct sof_manifest);
- for (i = 0; i < le16_to_cpu(manifest->count); i++) {
- len_check += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size);
- if (len_check > size)
- return -EINVAL;
- switch (le32_to_cpu(manifest_tlv->type)) {
- case SOF_MANIFEST_DATA_TYPE_NHLT:
- /* no NHLT in BIOS, so use the one from topology manifest */
- if (ipc4_data->nhlt)
- break;
- ipc4_data->nhlt = devm_kmemdup(sdev->dev, manifest_tlv->data,
- le32_to_cpu(manifest_tlv->size), GFP_KERNEL);
- if (!ipc4_data->nhlt)
- return -ENOMEM;
- break;
- default:
- dev_warn(scomp->dev, "Skipping unknown manifest data type %d\n",
- manifest_tlv->type);
- break;
- }
- man_ptr += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size);
- manifest_tlv = (struct sof_manifest_tlv *)man_ptr;
- }
- return 0;
- }
- static int sof_ipc4_dai_get_param(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int param_type)
- {
- struct sof_ipc4_copier *ipc4_copier = dai->private;
- struct snd_soc_tplg_hw_config *hw_config;
- struct snd_sof_dai_link *slink;
- bool dai_link_found = false;
- bool hw_cfg_found = false;
- int i;
- if (!ipc4_copier)
- return 0;
- list_for_each_entry(slink, &sdev->dai_link_list, list) {
- if (!strcmp(slink->link->name, dai->name)) {
- dai_link_found = true;
- break;
- }
- }
- if (!dai_link_found) {
- dev_err(sdev->dev, "no DAI link found for DAI %s\n", dai->name);
- return -EINVAL;
- }
- for (i = 0; i < slink->num_hw_configs; i++) {
- hw_config = &slink->hw_configs[i];
- if (dai->current_config == le32_to_cpu(hw_config->id)) {
- hw_cfg_found = true;
- break;
- }
- }
- if (!hw_cfg_found) {
- dev_err(sdev->dev, "no matching hw_config found for DAI %s\n", dai->name);
- return -EINVAL;
- }
- switch (ipc4_copier->dai_type) {
- case SOF_DAI_INTEL_SSP:
- switch (param_type) {
- case SOF_DAI_PARAM_INTEL_SSP_MCLK:
- return le32_to_cpu(hw_config->mclk_rate);
- case SOF_DAI_PARAM_INTEL_SSP_BCLK:
- return le32_to_cpu(hw_config->bclk_rate);
- case SOF_DAI_PARAM_INTEL_SSP_TDM_SLOTS:
- return le32_to_cpu(hw_config->tdm_slots);
- default:
- dev_err(sdev->dev, "invalid SSP param %d\n", param_type);
- break;
- }
- break;
- default:
- dev_err(sdev->dev, "DAI type %d not supported yet!\n", ipc4_copier->dai_type);
- break;
- }
- return -EINVAL;
- }
- static int sof_ipc4_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify)
- {
- /*
- * This function is called during system suspend, we need to make sure
- * that all streams have been freed up.
- * Freeing might have been skipped when xrun happened just at the start
- * of the suspend and it sent a SNDRV_PCM_TRIGGER_STOP to the active
- * stream. This will call sof_pcm_stream_free() with
- * free_widget_list = false which will leave the kernel and firmware out
- * of sync during suspend/resume.
- *
- * This will also make sure that paused streams handled correctly.
- */
- return sof_pcm_free_all_streams(sdev);
- }
- static int sof_ipc4_link_setup(struct snd_sof_dev *sdev, struct snd_soc_dai_link *link)
- {
- if (link->no_pcm)
- return 0;
- /*
- * set default trigger order for all links. Exceptions to
- * the rule will be handled in sof_pcm_dai_link_fixup()
- * For playback, the sequence is the following: start BE,
- * start FE, stop FE, stop BE; for Capture the sequence is
- * inverted start FE, start BE, stop BE, stop FE
- */
- link->trigger[SNDRV_PCM_STREAM_PLAYBACK] = SND_SOC_DPCM_TRIGGER_POST;
- link->trigger[SNDRV_PCM_STREAM_CAPTURE] = SND_SOC_DPCM_TRIGGER_PRE;
- return 0;
- }
- /* Tokens needed for different copier variants (aif, dai and buffer) */
- static enum sof_tokens copier_token_list[] = {
- SOF_COMP_TOKENS,
- SOF_COPIER_TOKENS,
- SOF_AUDIO_FMT_NUM_TOKENS,
- SOF_IN_AUDIO_FORMAT_TOKENS,
- SOF_OUT_AUDIO_FORMAT_TOKENS,
- SOF_COMP_EXT_TOKENS,
- SOF_COPIER_DEEP_BUFFER_TOKENS, /* for AIF copier */
- SOF_DAI_TOKENS, /* for DAI copier */
- };
- static enum sof_tokens pipeline_token_list[] = {
- SOF_SCHED_TOKENS,
- SOF_PIPELINE_TOKENS,
- };
- static enum sof_tokens pga_token_list[] = {
- SOF_COMP_TOKENS,
- SOF_GAIN_TOKENS,
- SOF_AUDIO_FMT_NUM_TOKENS,
- SOF_IN_AUDIO_FORMAT_TOKENS,
- SOF_OUT_AUDIO_FORMAT_TOKENS,
- SOF_COMP_EXT_TOKENS,
- };
- static enum sof_tokens mixer_token_list[] = {
- SOF_COMP_TOKENS,
- SOF_AUDIO_FMT_NUM_TOKENS,
- SOF_IN_AUDIO_FORMAT_TOKENS,
- SOF_OUT_AUDIO_FORMAT_TOKENS,
- SOF_COMP_EXT_TOKENS,
- };
- static enum sof_tokens src_token_list[] = {
- SOF_COMP_TOKENS,
- SOF_SRC_TOKENS,
- SOF_AUDIO_FMT_NUM_TOKENS,
- SOF_IN_AUDIO_FORMAT_TOKENS,
- SOF_OUT_AUDIO_FORMAT_TOKENS,
- SOF_COMP_EXT_TOKENS,
- };
- static enum sof_tokens asrc_token_list[] = {
- SOF_COMP_TOKENS,
- SOF_ASRC_TOKENS,
- SOF_AUDIO_FMT_NUM_TOKENS,
- SOF_IN_AUDIO_FORMAT_TOKENS,
- SOF_OUT_AUDIO_FORMAT_TOKENS,
- SOF_COMP_EXT_TOKENS,
- };
- static enum sof_tokens process_token_list[] = {
- SOF_COMP_TOKENS,
- SOF_AUDIO_FMT_NUM_TOKENS,
- SOF_IN_AUDIO_FORMAT_TOKENS,
- SOF_OUT_AUDIO_FORMAT_TOKENS,
- SOF_COMP_EXT_TOKENS,
- };
- static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = {
- [snd_soc_dapm_aif_in] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
- copier_token_list, ARRAY_SIZE(copier_token_list),
- NULL, sof_ipc4_prepare_copier_module,
- sof_ipc4_unprepare_copier_module},
- [snd_soc_dapm_aif_out] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
- copier_token_list, ARRAY_SIZE(copier_token_list),
- NULL, sof_ipc4_prepare_copier_module,
- sof_ipc4_unprepare_copier_module},
- [snd_soc_dapm_dai_in] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai,
- copier_token_list, ARRAY_SIZE(copier_token_list), NULL,
- sof_ipc4_prepare_copier_module,
- sof_ipc4_unprepare_copier_module},
- [snd_soc_dapm_dai_out] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai,
- copier_token_list, ARRAY_SIZE(copier_token_list), NULL,
- sof_ipc4_prepare_copier_module,
- sof_ipc4_unprepare_copier_module},
- [snd_soc_dapm_buffer] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
- copier_token_list, ARRAY_SIZE(copier_token_list),
- NULL, sof_ipc4_prepare_copier_module,
- sof_ipc4_unprepare_copier_module},
- [snd_soc_dapm_scheduler] = {sof_ipc4_widget_setup_comp_pipeline,
- sof_ipc4_widget_free_comp_pipeline,
- pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL,
- NULL, NULL},
- [snd_soc_dapm_pga] = {sof_ipc4_widget_setup_comp_pga, sof_ipc4_widget_free_comp_pga,
- pga_token_list, ARRAY_SIZE(pga_token_list), NULL,
- sof_ipc4_prepare_gain_module,
- NULL},
- [snd_soc_dapm_mixer] = {sof_ipc4_widget_setup_comp_mixer, sof_ipc4_widget_free_comp_mixer,
- mixer_token_list, ARRAY_SIZE(mixer_token_list),
- NULL, sof_ipc4_prepare_mixer_module,
- NULL},
- [snd_soc_dapm_src] = {sof_ipc4_widget_setup_comp_src, sof_ipc4_widget_free_comp_src,
- src_token_list, ARRAY_SIZE(src_token_list),
- NULL, sof_ipc4_prepare_src_module,
- NULL},
- [snd_soc_dapm_asrc] = {sof_ipc4_widget_setup_comp_asrc, sof_ipc4_widget_free_comp_asrc,
- asrc_token_list, ARRAY_SIZE(asrc_token_list),
- NULL, sof_ipc4_prepare_src_module, /* Common prepare with SRC */
- NULL},
- [snd_soc_dapm_effect] = {sof_ipc4_widget_setup_comp_process,
- sof_ipc4_widget_free_comp_process,
- process_token_list, ARRAY_SIZE(process_token_list),
- NULL, sof_ipc4_prepare_process_module,
- NULL},
- };
- const struct sof_ipc_tplg_ops ipc4_tplg_ops = {
- .widget = tplg_ipc4_widget_ops,
- .token_list = ipc4_token_list,
- .control_setup = sof_ipc4_control_setup,
- .control = &tplg_ipc4_control_ops,
- .widget_setup = sof_ipc4_widget_setup,
- .widget_free = sof_ipc4_widget_free,
- .route_setup = sof_ipc4_route_setup,
- .route_free = sof_ipc4_route_free,
- .dai_config = sof_ipc4_dai_config,
- .parse_manifest = sof_ipc4_parse_manifest,
- .dai_get_param = sof_ipc4_dai_get_param,
- .tear_down_all_pipelines = sof_ipc4_tear_down_all_pipelines,
- .link_setup = sof_ipc4_link_setup,
- .host_config = sof_ipc4_host_config,
- };
|