Path: blob/master/sound/soc/intel/avs/board_selection.c
26583 views
// SPDX-License-Identifier: GPL-2.0-only1//2// Copyright(c) 2021-2022 Intel Corporation3//4// Authors: Cezary Rojewski <[email protected]>5// Amadeusz Slawinski <[email protected]>6//78#include <linux/acpi.h>9#include <linux/module.h>10#include <linux/dmi.h>11#include <linux/pci.h>12#include <acpi/nhlt.h>13#include <linux/platform_device.h>14#include <sound/hda_codec.h>15#include <sound/hda_register.h>16#include <sound/soc-acpi.h>17#include <sound/soc-component.h>18#include "avs.h"19#include "utils.h"2021static char *i2s_test;22module_param(i2s_test, charp, 0444);23MODULE_PARM_DESC(i2s_test, "Use I2S test-board instead of ACPI, i2s_test=ssp0tdm,ssp1tdm,... 0 to ignore port");2425bool obsolete_card_names = IS_ENABLED(CONFIG_SND_SOC_INTEL_AVS_CARDNAME_OBSOLETE);26module_param_named(obsolete_card_names, obsolete_card_names, bool, 0444);27MODULE_PARM_DESC(obsolete_card_names, "Use obsolete card names 0=no, 1=yes");2829static const struct dmi_system_id kbl_dmi_table[] = {30{31.matches = {32DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),33DMI_MATCH(DMI_BOARD_NAME, "Skylake Y LPDDR3 RVP3"),34},35},36{37.matches = {38DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),39DMI_MATCH(DMI_BOARD_NAME, "AmberLake Y"),40},41},42{}43};4445static const struct dmi_system_id kblr_dmi_table[] = {46{47.matches = {48DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),49DMI_MATCH(DMI_BOARD_NAME, "Kabylake R DDR4 RVP"),50},51},52{}53};5455static struct snd_soc_acpi_mach *dmi_match_quirk(void *arg)56{57struct snd_soc_acpi_mach *mach = arg;58const struct dmi_system_id *dmi_id;59struct dmi_system_id *dmi_table;6061if (mach->quirk_data == NULL)62return mach;6364dmi_table = (struct dmi_system_id *)mach->quirk_data;6566dmi_id = dmi_first_match(dmi_table);67if (!dmi_id)68return NULL;6970return mach;71}7273#define AVS_SSP(x) (BIT(x))74#define AVS_SSP_RANGE(a, b) (GENMASK(b, a))7576/* supported I2S board codec configurations */77static struct snd_soc_acpi_mach avs_skl_i2s_machines[] = {78{79.id = "INT343A",80.drv_name = "avs_rt286",81.mach_params = {82.i2s_link_mask = AVS_SSP(0),83},84.tplg_filename = "rt286-tplg.bin",85},86{87.id = "10508825",88.drv_name = "avs_nau8825",89.mach_params = {90.i2s_link_mask = AVS_SSP(1),91},92.tplg_filename = "nau8825-tplg.bin",93},94{95.id = "INT343B",96.drv_name = "avs_ssm4567",97.mach_params = {98.i2s_link_mask = AVS_SSP(0),99},100.tplg_filename = "ssm4567-tplg.bin",101},102{103.id = "MX98357A",104.drv_name = "avs_max98357a",105.mach_params = {106.i2s_link_mask = AVS_SSP(0),107},108.tplg_filename = "max98357a-tplg.bin",109},110{},111};112113static struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = {114{115.id = "INT343A",116.drv_name = "avs_rt286",117.mach_params = {118.i2s_link_mask = AVS_SSP(0),119},120.quirk_data = &kbl_dmi_table,121.machine_quirk = dmi_match_quirk,122.tplg_filename = "rt286-tplg.bin",123},124{125.id = "INT343A",126.drv_name = "avs_rt298",127.mach_params = {128.i2s_link_mask = AVS_SSP(0),129},130.quirk_data = &kblr_dmi_table,131.machine_quirk = dmi_match_quirk,132.tplg_filename = "rt298-tplg.bin",133},134{135.id = "MX98927",136.drv_name = "avs_max98927",137.mach_params = {138.i2s_link_mask = AVS_SSP(0),139},140.tplg_filename = "max98927-tplg.bin",141},142{143.id = "10EC5514",144.drv_name = "avs_rt5514",145.mach_params = {146.i2s_link_mask = AVS_SSP(0),147},148.pdata = (struct avs_mach_pdata[]){ { .tdms = (unsigned long[]){ 0x2 } } },149.tplg_filename = "rt5514-tplg.bin",150},151{152.id = "10EC5663",153.drv_name = "avs_rt5663",154.mach_params = {155.i2s_link_mask = AVS_SSP(1),156},157.tplg_filename = "rt5663-tplg.bin",158},159{160.id = "MX98373",161.drv_name = "avs_max98373",162.mach_params = {163.i2s_link_mask = AVS_SSP(0),164},165.tplg_filename = "max98373-tplg.bin",166},167{168.id = "MX98357A",169.drv_name = "avs_max98357a",170.mach_params = {171.i2s_link_mask = AVS_SSP(0),172},173.tplg_filename = "max98357a-tplg.bin",174},175{176.id = "DLGS7219",177.drv_name = "avs_da7219",178.mach_params = {179.i2s_link_mask = AVS_SSP(1),180},181.tplg_filename = "da7219-tplg.bin",182},183{184.id = "ESSX8336",185.drv_name = "avs_es8336",186.mach_params = {187.i2s_link_mask = AVS_SSP(0),188},189.tplg_filename = "es8336-tplg.bin",190},191{},192};193194static struct snd_soc_acpi_mach avs_apl_i2s_machines[] = {195{196.id = "INT343A",197.drv_name = "avs_rt298",198.mach_params = {199.i2s_link_mask = AVS_SSP(5),200},201.tplg_filename = "rt298-tplg.bin",202},203{204.id = "INT34C3",205.drv_name = "avs_tdf8532",206.mach_params = {207.i2s_link_mask = AVS_SSP_RANGE(0, 5),208},209.pdata = (struct avs_mach_pdata[]){ {210.tdms = (unsigned long[]){ 0x1, 0x1, 0x14, 0x1, 0x1, 0x1 }211} },212.tplg_filename = "tdf8532-tplg.bin",213},214{215.id = "MX98357A",216.drv_name = "avs_max98357a",217.mach_params = {218.i2s_link_mask = AVS_SSP(5),219},220.tplg_filename = "max98357a-tplg.bin",221},222{223.id = "DLGS7219",224.drv_name = "avs_da7219",225.mach_params = {226.i2s_link_mask = AVS_SSP(1),227},228.tplg_filename = "da7219-tplg.bin",229},230{},231};232233static struct snd_soc_acpi_mach avs_gml_i2s_machines[] = {234{235.id = "INT343A",236.drv_name = "avs_rt298",237.mach_params = {238.i2s_link_mask = AVS_SSP(2),239},240.tplg_filename = "rt298-tplg.bin",241},242{},243};244245static struct snd_soc_acpi_mach avs_cnl_i2s_machines[] = {246{247.id = "INT34C2",248.drv_name = "avs_rt274",249.mach_params = {250.i2s_link_mask = AVS_SSP(0),251},252.tplg_filename = "rt274-tplg.bin",253},254{255.id = "10EC5682",256.drv_name = "avs_rt5682",257.mach_params = {258.i2s_link_mask = AVS_SSP(1),259},260.tplg_filename = "rt5682-tplg.bin",261},262{},263};264265static struct snd_soc_acpi_mach avs_icl_i2s_machines[] = {266{267.id = "INT343A",268.drv_name = "avs_rt298",269.mach_params = {270.i2s_link_mask = AVS_SSP(0),271},272.tplg_filename = "rt298-tplg.bin",273},274{275.id = "INT34C2",276.drv_name = "avs_rt274",277.mach_params = {278.i2s_link_mask = AVS_SSP(0),279},280.tplg_filename = "rt274-tplg.bin",281},282{},283};284285static struct snd_soc_acpi_mach avs_tgl_i2s_machines[] = {286{287.id = "INT34C2",288.drv_name = "avs_rt274",289.mach_params = {290.i2s_link_mask = AVS_SSP(0),291},292.tplg_filename = "rt274-tplg.bin",293},294{295.id = "10EC0298",296.drv_name = "avs_rt298",297.mach_params = {298.i2s_link_mask = AVS_SSP(0),299},300.tplg_filename = "rt298-tplg.bin",301},302{303.id = "10EC1308",304.drv_name = "avs_rt1308",305.mach_params = {306.i2s_link_mask = AVS_SSP(1),307},308.tplg_filename = "rt1308-tplg.bin",309},310{311.id = "10EC5640",312.uid = "1",313.drv_name = "avs_rt5640",314.mach_params = {315.i2s_link_mask = AVS_SSP(0),316},317.tplg_filename = "rt5640-tplg.bin",318},319{320.id = "10EC5640",321.uid = "3",322.drv_name = "avs_rt5640",323.mach_params = {324.i2s_link_mask = AVS_SSP(1),325},326.tplg_filename = "rt5640-tplg.bin",327},328{329.id = "10EC5640",330.uid = "2",331.drv_name = "avs_rt5640",332.mach_params = {333.i2s_link_mask = AVS_SSP(2),334},335.tplg_filename = "rt5640-tplg.bin",336},337{338.id = "ESSX8336",339.drv_name = "avs_es8336",340.mach_params = {341.i2s_link_mask = AVS_SSP(0),342},343.tplg_filename = "es8336-tplg.bin",344},345{},346};347348static struct snd_soc_acpi_mach avs_mbl_i2s_machines[] = {349{350.id = "PCM3168A",351.drv_name = "avs_pcm3168a",352.mach_params = {353.i2s_link_mask = AVS_SSP(0) | AVS_SSP(2),354},355.tplg_filename = "pcm3168a-tplg.bin",356},357{}358};359360struct avs_acpi_boards {361int id;362struct snd_soc_acpi_mach *machs;363};364365#define AVS_MACH_ENTRY(_id, _mach) \366{ .id = PCI_DEVICE_ID_INTEL_##_id, .machs = (_mach), }367368/* supported I2S boards per platform */369static const struct avs_acpi_boards i2s_boards[] = {370AVS_MACH_ENTRY(HDA_SKL_LP, avs_skl_i2s_machines),371AVS_MACH_ENTRY(HDA_KBL_LP, avs_kbl_i2s_machines),372AVS_MACH_ENTRY(HDA_APL, avs_apl_i2s_machines),373AVS_MACH_ENTRY(HDA_GML, avs_gml_i2s_machines),374AVS_MACH_ENTRY(HDA_CNL_LP, avs_cnl_i2s_machines),375AVS_MACH_ENTRY(HDA_CNL_H, avs_cnl_i2s_machines),376AVS_MACH_ENTRY(HDA_CML_LP, avs_cnl_i2s_machines),377AVS_MACH_ENTRY(HDA_ICL_LP, avs_icl_i2s_machines),378AVS_MACH_ENTRY(HDA_TGL_LP, avs_tgl_i2s_machines),379AVS_MACH_ENTRY(HDA_EHL_0, avs_tgl_i2s_machines),380AVS_MACH_ENTRY(HDA_ADL_N, avs_mbl_i2s_machines),381AVS_MACH_ENTRY(HDA_ADL_P, avs_tgl_i2s_machines),382AVS_MACH_ENTRY(HDA_RPL_P_0, avs_tgl_i2s_machines),383AVS_MACH_ENTRY(HDA_RPL_M, avs_mbl_i2s_machines),384AVS_MACH_ENTRY(HDA_FCL, avs_tgl_i2s_machines),385{ },386};387388static const struct avs_acpi_boards *avs_get_i2s_boards(struct avs_dev *adev)389{390int id, i;391392id = adev->base.pci->device;393for (i = 0; i < ARRAY_SIZE(i2s_boards); i++)394if (i2s_boards[i].id == id)395return &i2s_boards[i];396return NULL;397}398399/* platform devices owned by AVS audio are removed with this hook */400static void board_pdev_unregister(void *data)401{402platform_device_unregister(data);403}404405static int __maybe_unused avs_register_probe_board(struct avs_dev *adev)406{407struct platform_device *board;408struct snd_soc_acpi_mach mach = {{0}};409int ret;410411ret = avs_probe_platform_register(adev, "probe-platform");412if (ret < 0)413return ret;414415mach.mach_params.platform = "probe-platform";416417board = platform_device_register_data(NULL, "avs_probe_mb", PLATFORM_DEVID_NONE,418(const void *)&mach, sizeof(mach));419if (IS_ERR(board)) {420dev_err(adev->dev, "probe board register failed\n");421return PTR_ERR(board);422}423424ret = devm_add_action(adev->dev, board_pdev_unregister, board);425if (ret < 0) {426platform_device_unregister(board);427return ret;428}429return 0;430}431432static int avs_register_dmic_board(struct avs_dev *adev)433{434struct platform_device *codec, *board;435struct snd_soc_acpi_mach mach = {{0}};436struct avs_mach_pdata *pdata;437int ret;438439if (!acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_PDM, -1, -1, -1)) {440dev_dbg(adev->dev, "no DMIC endpoints present\n");441return 0;442}443444codec = platform_device_register_simple("dmic-codec", PLATFORM_DEVID_NONE, NULL, 0);445if (IS_ERR(codec)) {446dev_err(adev->dev, "dmic codec register failed\n");447return PTR_ERR(codec);448}449450ret = devm_add_action(adev->dev, board_pdev_unregister, codec);451if (ret < 0) {452platform_device_unregister(codec);453return ret;454}455456ret = avs_dmic_platform_register(adev, "dmic-platform");457if (ret < 0)458return ret;459460pdata = devm_kzalloc(adev->dev, sizeof(*pdata), GFP_KERNEL);461if (!pdata)462return -ENOMEM;463pdata->obsolete_card_names = obsolete_card_names;464mach.pdata = pdata;465mach.tplg_filename = "dmic-tplg.bin";466mach.mach_params.platform = "dmic-platform";467468board = platform_device_register_data(NULL, "avs_dmic", PLATFORM_DEVID_NONE,469(const void *)&mach, sizeof(mach));470if (IS_ERR(board)) {471dev_err(adev->dev, "dmic board register failed\n");472return PTR_ERR(board);473}474475ret = devm_add_action(adev->dev, board_pdev_unregister, board);476if (ret < 0) {477platform_device_unregister(board);478return ret;479}480481return 0;482}483484static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach *mach)485{486struct platform_device *board;487struct avs_mach_pdata *pdata;488int num_ssps;489char *name;490int ret;491int uid;492493num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;494if (fls(mach->mach_params.i2s_link_mask) > num_ssps) {495dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",496num_ssps, mach->drv_name,497(unsigned long)__fls(mach->mach_params.i2s_link_mask));498return -ENODEV;499}500501pdata = mach->pdata;502if (!pdata)503pdata = devm_kzalloc(adev->dev, sizeof(*pdata), GFP_KERNEL);504if (!pdata)505return -ENOMEM;506pdata->obsolete_card_names = obsolete_card_names;507mach->pdata = pdata;508509uid = mach->mach_params.i2s_link_mask;510if (avs_mach_singular_ssp(mach))511uid = (uid << AVS_CHANNELS_MAX) + avs_mach_ssp_tdm(mach, avs_mach_ssp_port(mach));512513name = devm_kasprintf(adev->dev, GFP_KERNEL, "%s.%d-platform", mach->drv_name, uid);514if (!name)515return -ENOMEM;516517ret = avs_i2s_platform_register(adev, name, mach->mach_params.i2s_link_mask, pdata->tdms);518if (ret < 0)519return ret;520521mach->mach_params.platform = name;522523board = platform_device_register_data(NULL, mach->drv_name, uid,524(const void *)mach, sizeof(*mach));525if (IS_ERR(board)) {526dev_err(adev->dev, "ssp board register failed\n");527return PTR_ERR(board);528}529530ret = devm_add_action(adev->dev, board_pdev_unregister, board);531if (ret < 0) {532platform_device_unregister(board);533return ret;534}535536return 0;537}538539static int avs_register_i2s_test_board(struct avs_dev *adev, int ssp_port, int tdm_slot)540{541struct snd_soc_acpi_mach *mach;542int tdm_mask = BIT(tdm_slot);543unsigned long *tdm_cfg;544char *tplg_name;545int ret;546547mach = devm_kzalloc(adev->dev, sizeof(*mach), GFP_KERNEL);548tdm_cfg = devm_kcalloc(adev->dev, ssp_port + 1, sizeof(unsigned long), GFP_KERNEL);549tplg_name = devm_kasprintf(adev->dev, GFP_KERNEL, AVS_STRING_FMT("i2s", "-test-tplg.bin",550ssp_port, tdm_slot));551if (!mach || !tdm_cfg || !tplg_name)552return -ENOMEM;553554mach->drv_name = "avs_i2s_test";555mach->mach_params.i2s_link_mask = AVS_SSP(ssp_port);556tdm_cfg[ssp_port] = tdm_mask;557mach->pdata = tdm_cfg;558mach->tplg_filename = tplg_name;559560ret = avs_register_i2s_board(adev, mach);561if (ret < 0) {562dev_warn(adev->dev, "register i2s %s failed: %d\n", mach->drv_name, ret);563return ret;564}565566return 0;567}568569static int avs_register_i2s_test_boards(struct avs_dev *adev)570{571int max_ssps = adev->hw_cfg.i2s_caps.ctrl_count;572int ssp_port, tdm_slot, ret;573unsigned long tdm_slots;574u32 *array, num_elems;575576ret = parse_int_array(i2s_test, strlen(i2s_test), (int **)&array);577if (ret) {578dev_err(adev->dev, "failed to parse i2s_test parameter\n");579return ret;580}581582num_elems = *array;583if (num_elems > max_ssps) {584dev_err(adev->dev, "board supports only %d SSP, %d specified\n",585max_ssps, num_elems);586return -EINVAL;587}588589for (ssp_port = 0; ssp_port < num_elems; ssp_port++) {590tdm_slots = array[1 + ssp_port];591for_each_set_bit(tdm_slot, &tdm_slots, 16) {592ret = avs_register_i2s_test_board(adev, ssp_port, tdm_slot);593if (ret)594return ret;595}596}597598return 0;599}600601static int avs_register_i2s_boards(struct avs_dev *adev)602{603const struct avs_acpi_boards *boards;604struct snd_soc_acpi_mach *mach;605int ret;606607if (!acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_SSP, -1, -1, -1)) {608dev_dbg(adev->dev, "no I2S endpoints present\n");609return 0;610}611612if (i2s_test)613return avs_register_i2s_test_boards(adev);614615boards = avs_get_i2s_boards(adev);616if (!boards) {617dev_dbg(adev->dev, "no I2S endpoints supported\n");618return 0;619}620621for (mach = boards->machs; mach->id[0]; mach++) {622if (!acpi_dev_present(mach->id, mach->uid, -1))623continue;624625if (mach->machine_quirk)626if (!mach->machine_quirk(mach))627continue;628629ret = avs_register_i2s_board(adev, mach);630if (ret < 0)631dev_warn(adev->dev, "register i2s %s failed: %d\n", mach->drv_name, ret);632}633634return 0;635}636637static int avs_register_hda_board(struct avs_dev *adev, struct hda_codec *codec)638{639struct snd_soc_acpi_mach mach = {{0}};640struct platform_device *board;641struct avs_mach_pdata *pdata;642struct hdac_device *hdev = &codec->core;643char *pname;644int ret, id;645646pname = devm_kasprintf(adev->dev, GFP_KERNEL, "%s-platform", dev_name(&hdev->dev));647if (!pname)648return -ENOMEM;649650pdata = devm_kzalloc(adev->dev, sizeof(*pdata), GFP_KERNEL);651if (!pdata)652return -ENOMEM;653pdata->obsolete_card_names = obsolete_card_names;654pdata->codec = codec;655656ret = avs_hda_platform_register(adev, pname);657if (ret < 0)658return ret;659660mach.pdata = pdata;661mach.mach_params.platform = pname;662mach.tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL, "hda-%08x-tplg.bin",663hdev->vendor_id);664if (!mach.tplg_filename)665return -ENOMEM;666667id = adev->base.core.idx * HDA_MAX_CODECS + hdev->addr;668board = platform_device_register_data(NULL, "avs_hdaudio", id, (const void *)&mach,669sizeof(mach));670if (IS_ERR(board)) {671dev_err(adev->dev, "hda board register failed\n");672return PTR_ERR(board);673}674675ret = devm_add_action(adev->dev, board_pdev_unregister, board);676if (ret < 0) {677platform_device_unregister(board);678return ret;679}680681return 0;682}683684static int avs_register_hda_boards(struct avs_dev *adev)685{686struct hdac_bus *bus = &adev->base.core;687struct hdac_device *hdev;688int ret;689690if (!bus->num_codecs) {691dev_dbg(adev->dev, "no HDA endpoints present\n");692return 0;693}694695list_for_each_entry(hdev, &bus->codec_list, list) {696struct hda_codec *codec;697698codec = dev_to_hda_codec(&hdev->dev);699700ret = avs_register_hda_board(adev, codec);701if (ret < 0)702dev_warn(adev->dev, "register hda-%08x failed: %d\n",703codec->core.vendor_id, ret);704}705706return 0;707}708709int avs_register_all_boards(struct avs_dev *adev)710{711int ret;712713#ifdef CONFIG_DEBUG_FS714ret = avs_register_probe_board(adev);715if (ret < 0)716dev_warn(adev->dev, "enumerate PROBE endpoints failed: %d\n", ret);717#endif718719ret = avs_register_dmic_board(adev);720if (ret < 0)721dev_warn(adev->dev, "enumerate DMIC endpoints failed: %d\n",722ret);723724ret = avs_register_i2s_boards(adev);725if (ret < 0)726dev_warn(adev->dev, "enumerate I2S endpoints failed: %d\n",727ret);728729ret = avs_register_hda_boards(adev);730if (ret < 0)731dev_warn(adev->dev, "enumerate HDA endpoints failed: %d\n",732ret);733734return 0;735}736737void avs_unregister_all_boards(struct avs_dev *adev)738{739snd_soc_unregister_component(adev->dev);740}741742743