diff --git a/sound/soc/intel/skylake/skl-i2s.h b/sound/soc/intel/skylake/skl-i2s.h index dcf819bc688f3d7f05e9594be8a7ee61ddd648d7..ad0a1bbca13cbea7ff622439663124e033218706 100644 --- a/sound/soc/intel/skylake/skl-i2s.h +++ b/sound/soc/intel/skylake/skl-i2s.h @@ -27,6 +27,12 @@ #define SKL_SHIFT(x) (ffs(x) - 1) #define SKL_MCLK_DIV_RATIO_MASK GENMASK(11, 0) +#define is_legacy_blob(x) (x.signature != 0xEE) +#define ext_to_legacy_blob(i2s_config_blob_ext) \ + ((struct skl_i2s_config_blob_legacy *) i2s_config_blob_ext) + +#define get_clk_src(mclk, mask) \ + ((mclk.mdivctrl & mask) >> SKL_SHIFT(mask)) struct skl_i2s_config { u32 ssc0; u32 ssc1; @@ -45,6 +51,24 @@ struct skl_i2s_config_mclk { u32 mdivr; }; +struct skl_i2s_config_mclk_ext { + u32 mdivctrl; + u32 mdivr_count; + u32 mdivr[0]; +} __packed; + +struct skl_i2s_config_blob_signature { + u32 minor_ver : 8; + u32 major_ver : 8; + u32 resvdz : 8; + u32 signature : 8; +} __packed; + +struct skl_i2s_config_blob_header { + struct skl_i2s_config_blob_signature sig; + u32 size; +}; + /** * struct skl_i2s_config_blob_legacy - Structure defines I2S Gateway * configuration legacy blob @@ -61,4 +85,11 @@ struct skl_i2s_config_blob_legacy { struct skl_i2s_config_mclk mclk; }; +struct skl_i2s_config_blob_ext { + u32 gtw_attr; + struct skl_i2s_config_blob_header hdr; + u32 tdm_ts_group[SKL_I2S_MAX_TIME_SLOTS]; + struct skl_i2s_config i2s_cfg; + struct skl_i2s_config_mclk_ext mclk; +} __packed; #endif /* __SOUND_SOC_SKL_I2S_H */ diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index 3b1d2b828c1b6425c06614cce20293265c3c35ed..b9b140275be09908e93e1936a7d9d86772387106 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -28,6 +28,7 @@ static guid_t osc_guid = GUID_INIT(0xA69F886E, 0x6CEB, 0x4594, 0xA4, 0x1F, 0x7B, 0x5D, 0xCE, 0x24, 0xC5, 0x53); + struct nhlt_acpi_table *skl_nhlt_init(struct device *dev) { acpi_handle handle; @@ -287,6 +288,7 @@ void skl_nhlt_remove_sysfs(struct skl *skl) static void skl_get_ssp_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks, struct nhlt_fmt *fmt, u8 id) { + struct skl_i2s_config_blob_ext *i2s_config_ext; struct skl_i2s_config_blob_legacy *i2s_config; struct skl_clk_parent_src *parent; struct skl_ssp_clk *sclk, *sclkfs; @@ -347,12 +349,18 @@ static void skl_get_ssp_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks, /* Fill rate and parent for sclk/sclkfs */ if (!present) { - /* MCLK Divider Source Select */ - i2s_config = (struct skl_i2s_config_blob_legacy *) + i2s_config_ext = (struct skl_i2s_config_blob_ext *) fmt->fmt_config[0].config.caps; - clk_src = ((i2s_config->mclk.mdivctrl) - & SKL_MNDSS_DIV_CLK_SRC_MASK) >> - SKL_SHIFT(SKL_MNDSS_DIV_CLK_SRC_MASK); + + /* MCLK Divider Source Select */ + if (is_legacy_blob(i2s_config_ext->hdr.sig)) { + i2s_config = ext_to_legacy_blob(i2s_config_ext); + clk_src = get_clk_src(i2s_config->mclk, + SKL_MNDSS_DIV_CLK_SRC_MASK); + } else { + clk_src = get_clk_src(i2s_config_ext->mclk, + SKL_MNDSS_DIV_CLK_SRC_MASK); + } parent = skl_get_parent_clk(clk_src); @@ -378,6 +386,7 @@ static void skl_get_ssp_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks, static void skl_get_mclk(struct skl *skl, struct skl_ssp_clk *mclk, struct nhlt_fmt *fmt, u8 id) { + struct skl_i2s_config_blob_ext *i2s_config_ext; struct skl_i2s_config_blob_legacy *i2s_config; struct nhlt_specific_cfg *fmt_cfg; struct skl_clk_parent_src *parent; @@ -385,13 +394,21 @@ static void skl_get_mclk(struct skl *skl, struct skl_ssp_clk *mclk, u8 clk_src; fmt_cfg = &fmt->fmt_config[0].config; - i2s_config = (struct skl_i2s_config_blob_legacy *)fmt_cfg->caps; - - /* MCLK Divider Source Select */ - clk_src = ((i2s_config->mclk.mdivctrl) & SKL_MCLK_DIV_CLK_SRC_MASK) >> - SKL_SHIFT(SKL_MCLK_DIV_CLK_SRC_MASK); - - clkdiv = i2s_config->mclk.mdivr & SKL_MCLK_DIV_RATIO_MASK; + i2s_config_ext = (struct skl_i2s_config_blob_ext *)fmt_cfg->caps; + + /* MCLK Divider Source Select and divider */ + if (is_legacy_blob(i2s_config_ext->hdr.sig)) { + i2s_config = ext_to_legacy_blob(i2s_config_ext); + clk_src = get_clk_src(i2s_config->mclk, + SKL_MCLK_DIV_CLK_SRC_MASK); + clkdiv = i2s_config->mclk.mdivr & + SKL_MCLK_DIV_RATIO_MASK; + } else { + clk_src = get_clk_src(i2s_config_ext->mclk, + SKL_MCLK_DIV_CLK_SRC_MASK); + clkdiv = i2s_config_ext->mclk.mdivr[0] & + SKL_MCLK_DIV_RATIO_MASK; + } /* bypass divider */ div_ratio = 1;