Loading include/sound/hda_i915.h +2 −3 Original line number Diff line number Diff line Loading @@ -9,7 +9,7 @@ #ifdef CONFIG_SND_HDA_I915 int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable); int snd_hdac_display_power(struct hdac_bus *bus, bool enable); int snd_hdac_get_display_clk(struct hdac_bus *bus); void snd_hdac_i915_set_bclk(struct hdac_bus *bus); int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate); int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, bool *audio_enabled, char *buffer, int max_bytes); Loading @@ -25,9 +25,8 @@ static inline int snd_hdac_display_power(struct hdac_bus *bus, bool enable) { return 0; } static inline int snd_hdac_get_display_clk(struct hdac_bus *bus) static inline void snd_hdac_i915_set_bclk(struct hdac_bus *bus) { return 0; } static inline int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate) Loading include/sound/hda_regmap.h +2 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ int snd_hdac_regmap_add_vendor_verb(struct hdac_device *codec, unsigned int verb); int snd_hdac_regmap_read_raw(struct hdac_device *codec, unsigned int reg, unsigned int *val); int snd_hdac_regmap_read_raw_uncached(struct hdac_device *codec, unsigned int reg, unsigned int *val); int snd_hdac_regmap_write_raw(struct hdac_device *codec, unsigned int reg, unsigned int val); int snd_hdac_regmap_update_raw(struct hdac_device *codec, unsigned int reg, Loading sound/hda/hdac_device.c +4 −6 Original line number Diff line number Diff line Loading @@ -299,13 +299,11 @@ EXPORT_SYMBOL_GPL(_snd_hdac_read_parm); int snd_hdac_read_parm_uncached(struct hdac_device *codec, hda_nid_t nid, int parm) { int val; unsigned int cmd, val; if (codec->regmap) regcache_cache_bypass(codec->regmap, true); val = snd_hdac_read_parm(codec, nid, parm); if (codec->regmap) regcache_cache_bypass(codec->regmap, false); cmd = snd_hdac_regmap_encode_verb(nid, AC_VERB_PARAMETERS) | parm; if (snd_hdac_regmap_read_raw_uncached(codec, cmd, &val) < 0) return -1; return val; } EXPORT_SYMBOL_GPL(snd_hdac_read_parm_uncached); Loading sound/hda/hdac_i915.c +50 −10 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <sound/core.h> #include <sound/hdaudio.h> #include <sound/hda_i915.h> #include <sound/hda_register.h> static struct i915_audio_component *hdac_acomp; Loading Loading @@ -97,26 +98,65 @@ int snd_hdac_display_power(struct hdac_bus *bus, bool enable) } EXPORT_SYMBOL_GPL(snd_hdac_display_power); #define CONTROLLER_IN_GPU(pci) (((pci)->device == 0x0a0c) || \ ((pci)->device == 0x0c0c) || \ ((pci)->device == 0x0d0c) || \ ((pci)->device == 0x160c)) /** * snd_hdac_get_display_clk - Get CDCLK in kHz * snd_hdac_i915_set_bclk - Reprogram BCLK for HSW/BDW * @bus: HDA core bus * * This function is supposed to be used only by a HD-audio controller * driver that needs the interaction with i915 graphics. * Intel HSW/BDW display HDA controller is in GPU. Both its power and link BCLK * depends on GPU. Two Extended Mode registers EM4 (M value) and EM5 (N Value) * are used to convert CDClk (Core Display Clock) to 24MHz BCLK: * BCLK = CDCLK * M / N * The values will be lost when the display power well is disabled and need to * be restored to avoid abnormal playback speed. * * This function queries CDCLK value in kHz from the graphics driver and * returns the value. A negative code is returned in error. * Call this function at initializing and changing power well, as well as * at ELD notifier for the hotplug. */ int snd_hdac_get_display_clk(struct hdac_bus *bus) void snd_hdac_i915_set_bclk(struct hdac_bus *bus) { struct i915_audio_component *acomp = bus->audio_component; struct pci_dev *pci = to_pci_dev(bus->dev); int cdclk_freq; unsigned int bclk_m, bclk_n; if (!acomp || !acomp->ops || !acomp->ops->get_cdclk_freq) return; /* only for i915 binding */ if (!CONTROLLER_IN_GPU(pci)) return; /* only HSW/BDW */ cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev); switch (cdclk_freq) { case 337500: bclk_m = 16; bclk_n = 225; break; if (!acomp || !acomp->ops) return -ENODEV; case 450000: default: /* default CDCLK 450MHz */ bclk_m = 4; bclk_n = 75; break; case 540000: bclk_m = 4; bclk_n = 90; break; case 675000: bclk_m = 8; bclk_n = 225; break; } return acomp->ops->get_cdclk_freq(acomp->dev); snd_hdac_chip_writew(bus, HSW_EM4, bclk_m); snd_hdac_chip_writew(bus, HSW_EM5, bclk_n); } EXPORT_SYMBOL_GPL(snd_hdac_get_display_clk); EXPORT_SYMBOL_GPL(snd_hdac_i915_set_bclk); /* There is a fixed mapping between audio pin node and display port. * on SNB, IVY, HSW, BSW, SKL, BXT, KBL: Loading sound/hda/hdac_regmap.c +28 −12 Original line number Diff line number Diff line Loading @@ -453,14 +453,30 @@ int snd_hdac_regmap_write_raw(struct hdac_device *codec, unsigned int reg, EXPORT_SYMBOL_GPL(snd_hdac_regmap_write_raw); static int reg_raw_read(struct hdac_device *codec, unsigned int reg, unsigned int *val) unsigned int *val, bool uncached) { if (!codec->regmap) if (uncached || !codec->regmap) return hda_reg_read(codec, reg, val); else return regmap_read(codec->regmap, reg, val); } static int __snd_hdac_regmap_read_raw(struct hdac_device *codec, unsigned int reg, unsigned int *val, bool uncached) { int err; err = reg_raw_read(codec, reg, val, uncached); if (err == -EAGAIN) { err = snd_hdac_power_up_pm(codec); if (!err) err = reg_raw_read(codec, reg, val, uncached); snd_hdac_power_down_pm(codec); } return err; } /** * snd_hdac_regmap_read_raw - read a pseudo register with power mgmt * @codec: the codec object Loading @@ -472,19 +488,19 @@ static int reg_raw_read(struct hdac_device *codec, unsigned int reg, int snd_hdac_regmap_read_raw(struct hdac_device *codec, unsigned int reg, unsigned int *val) { int err; err = reg_raw_read(codec, reg, val); if (err == -EAGAIN) { err = snd_hdac_power_up_pm(codec); if (!err) err = reg_raw_read(codec, reg, val); snd_hdac_power_down_pm(codec); } return err; return __snd_hdac_regmap_read_raw(codec, reg, val, false); } EXPORT_SYMBOL_GPL(snd_hdac_regmap_read_raw); /* Works like snd_hdac_regmap_read_raw(), but this doesn't read from the * cache but always via hda verbs. */ int snd_hdac_regmap_read_raw_uncached(struct hdac_device *codec, unsigned int reg, unsigned int *val) { return __snd_hdac_regmap_read_raw(codec, reg, val, true); } /** * snd_hdac_regmap_update_raw - update a pseudo register with power mgmt * @codec: the codec object Loading Loading
include/sound/hda_i915.h +2 −3 Original line number Diff line number Diff line Loading @@ -9,7 +9,7 @@ #ifdef CONFIG_SND_HDA_I915 int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable); int snd_hdac_display_power(struct hdac_bus *bus, bool enable); int snd_hdac_get_display_clk(struct hdac_bus *bus); void snd_hdac_i915_set_bclk(struct hdac_bus *bus); int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate); int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, bool *audio_enabled, char *buffer, int max_bytes); Loading @@ -25,9 +25,8 @@ static inline int snd_hdac_display_power(struct hdac_bus *bus, bool enable) { return 0; } static inline int snd_hdac_get_display_clk(struct hdac_bus *bus) static inline void snd_hdac_i915_set_bclk(struct hdac_bus *bus) { return 0; } static inline int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate) Loading
include/sound/hda_regmap.h +2 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ int snd_hdac_regmap_add_vendor_verb(struct hdac_device *codec, unsigned int verb); int snd_hdac_regmap_read_raw(struct hdac_device *codec, unsigned int reg, unsigned int *val); int snd_hdac_regmap_read_raw_uncached(struct hdac_device *codec, unsigned int reg, unsigned int *val); int snd_hdac_regmap_write_raw(struct hdac_device *codec, unsigned int reg, unsigned int val); int snd_hdac_regmap_update_raw(struct hdac_device *codec, unsigned int reg, Loading
sound/hda/hdac_device.c +4 −6 Original line number Diff line number Diff line Loading @@ -299,13 +299,11 @@ EXPORT_SYMBOL_GPL(_snd_hdac_read_parm); int snd_hdac_read_parm_uncached(struct hdac_device *codec, hda_nid_t nid, int parm) { int val; unsigned int cmd, val; if (codec->regmap) regcache_cache_bypass(codec->regmap, true); val = snd_hdac_read_parm(codec, nid, parm); if (codec->regmap) regcache_cache_bypass(codec->regmap, false); cmd = snd_hdac_regmap_encode_verb(nid, AC_VERB_PARAMETERS) | parm; if (snd_hdac_regmap_read_raw_uncached(codec, cmd, &val) < 0) return -1; return val; } EXPORT_SYMBOL_GPL(snd_hdac_read_parm_uncached); Loading
sound/hda/hdac_i915.c +50 −10 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <sound/core.h> #include <sound/hdaudio.h> #include <sound/hda_i915.h> #include <sound/hda_register.h> static struct i915_audio_component *hdac_acomp; Loading Loading @@ -97,26 +98,65 @@ int snd_hdac_display_power(struct hdac_bus *bus, bool enable) } EXPORT_SYMBOL_GPL(snd_hdac_display_power); #define CONTROLLER_IN_GPU(pci) (((pci)->device == 0x0a0c) || \ ((pci)->device == 0x0c0c) || \ ((pci)->device == 0x0d0c) || \ ((pci)->device == 0x160c)) /** * snd_hdac_get_display_clk - Get CDCLK in kHz * snd_hdac_i915_set_bclk - Reprogram BCLK for HSW/BDW * @bus: HDA core bus * * This function is supposed to be used only by a HD-audio controller * driver that needs the interaction with i915 graphics. * Intel HSW/BDW display HDA controller is in GPU. Both its power and link BCLK * depends on GPU. Two Extended Mode registers EM4 (M value) and EM5 (N Value) * are used to convert CDClk (Core Display Clock) to 24MHz BCLK: * BCLK = CDCLK * M / N * The values will be lost when the display power well is disabled and need to * be restored to avoid abnormal playback speed. * * This function queries CDCLK value in kHz from the graphics driver and * returns the value. A negative code is returned in error. * Call this function at initializing and changing power well, as well as * at ELD notifier for the hotplug. */ int snd_hdac_get_display_clk(struct hdac_bus *bus) void snd_hdac_i915_set_bclk(struct hdac_bus *bus) { struct i915_audio_component *acomp = bus->audio_component; struct pci_dev *pci = to_pci_dev(bus->dev); int cdclk_freq; unsigned int bclk_m, bclk_n; if (!acomp || !acomp->ops || !acomp->ops->get_cdclk_freq) return; /* only for i915 binding */ if (!CONTROLLER_IN_GPU(pci)) return; /* only HSW/BDW */ cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev); switch (cdclk_freq) { case 337500: bclk_m = 16; bclk_n = 225; break; if (!acomp || !acomp->ops) return -ENODEV; case 450000: default: /* default CDCLK 450MHz */ bclk_m = 4; bclk_n = 75; break; case 540000: bclk_m = 4; bclk_n = 90; break; case 675000: bclk_m = 8; bclk_n = 225; break; } return acomp->ops->get_cdclk_freq(acomp->dev); snd_hdac_chip_writew(bus, HSW_EM4, bclk_m); snd_hdac_chip_writew(bus, HSW_EM5, bclk_n); } EXPORT_SYMBOL_GPL(snd_hdac_get_display_clk); EXPORT_SYMBOL_GPL(snd_hdac_i915_set_bclk); /* There is a fixed mapping between audio pin node and display port. * on SNB, IVY, HSW, BSW, SKL, BXT, KBL: Loading
sound/hda/hdac_regmap.c +28 −12 Original line number Diff line number Diff line Loading @@ -453,14 +453,30 @@ int snd_hdac_regmap_write_raw(struct hdac_device *codec, unsigned int reg, EXPORT_SYMBOL_GPL(snd_hdac_regmap_write_raw); static int reg_raw_read(struct hdac_device *codec, unsigned int reg, unsigned int *val) unsigned int *val, bool uncached) { if (!codec->regmap) if (uncached || !codec->regmap) return hda_reg_read(codec, reg, val); else return regmap_read(codec->regmap, reg, val); } static int __snd_hdac_regmap_read_raw(struct hdac_device *codec, unsigned int reg, unsigned int *val, bool uncached) { int err; err = reg_raw_read(codec, reg, val, uncached); if (err == -EAGAIN) { err = snd_hdac_power_up_pm(codec); if (!err) err = reg_raw_read(codec, reg, val, uncached); snd_hdac_power_down_pm(codec); } return err; } /** * snd_hdac_regmap_read_raw - read a pseudo register with power mgmt * @codec: the codec object Loading @@ -472,19 +488,19 @@ static int reg_raw_read(struct hdac_device *codec, unsigned int reg, int snd_hdac_regmap_read_raw(struct hdac_device *codec, unsigned int reg, unsigned int *val) { int err; err = reg_raw_read(codec, reg, val); if (err == -EAGAIN) { err = snd_hdac_power_up_pm(codec); if (!err) err = reg_raw_read(codec, reg, val); snd_hdac_power_down_pm(codec); } return err; return __snd_hdac_regmap_read_raw(codec, reg, val, false); } EXPORT_SYMBOL_GPL(snd_hdac_regmap_read_raw); /* Works like snd_hdac_regmap_read_raw(), but this doesn't read from the * cache but always via hda verbs. */ int snd_hdac_regmap_read_raw_uncached(struct hdac_device *codec, unsigned int reg, unsigned int *val) { return __snd_hdac_regmap_read_raw(codec, reg, val, true); } /** * snd_hdac_regmap_update_raw - update a pseudo register with power mgmt * @codec: the codec object Loading