cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

hdac_component.c (9971B)


      1// SPDX-License-Identifier: GPL-2.0
      2// hdac_component.c - routines for sync between HD-A core and DRM driver
      3
      4#include <linux/init.h>
      5#include <linux/module.h>
      6#include <linux/pci.h>
      7#include <linux/component.h>
      8#include <sound/core.h>
      9#include <sound/hdaudio.h>
     10#include <sound/hda_component.h>
     11#include <sound/hda_register.h>
     12
     13static void hdac_acomp_release(struct device *dev, void *res)
     14{
     15}
     16
     17static struct drm_audio_component *hdac_get_acomp(struct device *dev)
     18{
     19	return devres_find(dev, hdac_acomp_release, NULL, NULL);
     20}
     21
     22/**
     23 * snd_hdac_set_codec_wakeup - Enable / disable HDMI/DP codec wakeup
     24 * @bus: HDA core bus
     25 * @enable: enable or disable the wakeup
     26 *
     27 * This function is supposed to be used only by a HD-audio controller
     28 * driver that needs the interaction with graphics driver.
     29 *
     30 * This function should be called during the chip reset, also called at
     31 * resume for updating STATESTS register read.
     32 *
     33 * Returns zero for success or a negative error code.
     34 */
     35int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable)
     36{
     37	struct drm_audio_component *acomp = bus->audio_component;
     38
     39	if (!acomp || !acomp->ops)
     40		return -ENODEV;
     41
     42	if (!acomp->ops->codec_wake_override)
     43		return 0;
     44
     45	dev_dbg(bus->dev, "%s codec wakeup\n",
     46		enable ? "enable" : "disable");
     47
     48	acomp->ops->codec_wake_override(acomp->dev, enable);
     49
     50	return 0;
     51}
     52EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup);
     53
     54/**
     55 * snd_hdac_display_power - Power up / down the power refcount
     56 * @bus: HDA core bus
     57 * @idx: HDA codec address, pass HDA_CODEC_IDX_CONTROLLER for controller
     58 * @enable: power up or down
     59 *
     60 * This function is used by either HD-audio controller or codec driver that
     61 * needs the interaction with graphics driver.
     62 *
     63 * This function updates the power status, and calls the get_power() and
     64 * put_power() ops accordingly, toggling the codec wakeup, too.
     65 */
     66void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable)
     67{
     68	struct drm_audio_component *acomp = bus->audio_component;
     69
     70	dev_dbg(bus->dev, "display power %s\n",
     71		enable ? "enable" : "disable");
     72
     73	mutex_lock(&bus->lock);
     74	if (enable)
     75		set_bit(idx, &bus->display_power_status);
     76	else
     77		clear_bit(idx, &bus->display_power_status);
     78
     79	if (!acomp || !acomp->ops)
     80		goto unlock;
     81
     82	if (bus->display_power_status) {
     83		if (!bus->display_power_active) {
     84			unsigned long cookie = -1;
     85
     86			if (acomp->ops->get_power)
     87				cookie = acomp->ops->get_power(acomp->dev);
     88
     89			snd_hdac_set_codec_wakeup(bus, true);
     90			snd_hdac_set_codec_wakeup(bus, false);
     91			bus->display_power_active = cookie;
     92		}
     93	} else {
     94		if (bus->display_power_active) {
     95			unsigned long cookie = bus->display_power_active;
     96
     97			if (acomp->ops->put_power)
     98				acomp->ops->put_power(acomp->dev, cookie);
     99
    100			bus->display_power_active = 0;
    101		}
    102	}
    103 unlock:
    104	mutex_unlock(&bus->lock);
    105}
    106EXPORT_SYMBOL_GPL(snd_hdac_display_power);
    107
    108/**
    109 * snd_hdac_sync_audio_rate - Set N/CTS based on the sample rate
    110 * @codec: HDA codec
    111 * @nid: the pin widget NID
    112 * @dev_id: device identifier
    113 * @rate: the sample rate to set
    114 *
    115 * This function is supposed to be used only by a HD-audio controller
    116 * driver that needs the interaction with graphics driver.
    117 *
    118 * This function sets N/CTS value based on the given sample rate.
    119 * Returns zero for success, or a negative error code.
    120 */
    121int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
    122			     int dev_id, int rate)
    123{
    124	struct hdac_bus *bus = codec->bus;
    125	struct drm_audio_component *acomp = bus->audio_component;
    126	int port, pipe;
    127
    128	if (!acomp || !acomp->ops || !acomp->ops->sync_audio_rate)
    129		return -ENODEV;
    130	port = nid;
    131	if (acomp->audio_ops && acomp->audio_ops->pin2port) {
    132		port = acomp->audio_ops->pin2port(codec, nid);
    133		if (port < 0)
    134			return -EINVAL;
    135	}
    136	pipe = dev_id;
    137	return acomp->ops->sync_audio_rate(acomp->dev, port, pipe, rate);
    138}
    139EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);
    140
    141/**
    142 * snd_hdac_acomp_get_eld - Get the audio state and ELD via component
    143 * @codec: HDA codec
    144 * @nid: the pin widget NID
    145 * @dev_id: device identifier
    146 * @audio_enabled: the pointer to store the current audio state
    147 * @buffer: the buffer pointer to store ELD bytes
    148 * @max_bytes: the max bytes to be stored on @buffer
    149 *
    150 * This function is supposed to be used only by a HD-audio controller
    151 * driver that needs the interaction with graphics driver.
    152 *
    153 * This function queries the current state of the audio on the given
    154 * digital port and fetches the ELD bytes onto the given buffer.
    155 * It returns the number of bytes for the total ELD data, zero for
    156 * invalid ELD, or a negative error code.
    157 *
    158 * The return size is the total bytes required for the whole ELD bytes,
    159 * thus it may be over @max_bytes.  If it's over @max_bytes, it implies
    160 * that only a part of ELD bytes have been fetched.
    161 */
    162int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id,
    163			   bool *audio_enabled, char *buffer, int max_bytes)
    164{
    165	struct hdac_bus *bus = codec->bus;
    166	struct drm_audio_component *acomp = bus->audio_component;
    167	int port, pipe;
    168
    169	if (!acomp || !acomp->ops || !acomp->ops->get_eld)
    170		return -ENODEV;
    171
    172	port = nid;
    173	if (acomp->audio_ops && acomp->audio_ops->pin2port) {
    174		port = acomp->audio_ops->pin2port(codec, nid);
    175		if (port < 0)
    176			return -EINVAL;
    177	}
    178	pipe = dev_id;
    179	return acomp->ops->get_eld(acomp->dev, port, pipe, audio_enabled,
    180				   buffer, max_bytes);
    181}
    182EXPORT_SYMBOL_GPL(snd_hdac_acomp_get_eld);
    183
    184static int hdac_component_master_bind(struct device *dev)
    185{
    186	struct drm_audio_component *acomp = hdac_get_acomp(dev);
    187	int ret;
    188
    189	if (WARN_ON(!acomp))
    190		return -EINVAL;
    191
    192	ret = component_bind_all(dev, acomp);
    193	if (ret < 0)
    194		return ret;
    195
    196	if (WARN_ON(!(acomp->dev && acomp->ops))) {
    197		ret = -EINVAL;
    198		goto out_unbind;
    199	}
    200
    201	/* pin the module to avoid dynamic unbinding, but only if given */
    202	if (!try_module_get(acomp->ops->owner)) {
    203		ret = -ENODEV;
    204		goto out_unbind;
    205	}
    206
    207	if (acomp->audio_ops && acomp->audio_ops->master_bind) {
    208		ret = acomp->audio_ops->master_bind(dev, acomp);
    209		if (ret < 0)
    210			goto module_put;
    211	}
    212
    213	complete_all(&acomp->master_bind_complete);
    214	return 0;
    215
    216 module_put:
    217	module_put(acomp->ops->owner);
    218out_unbind:
    219	component_unbind_all(dev, acomp);
    220	complete_all(&acomp->master_bind_complete);
    221
    222	return ret;
    223}
    224
    225static void hdac_component_master_unbind(struct device *dev)
    226{
    227	struct drm_audio_component *acomp = hdac_get_acomp(dev);
    228
    229	if (acomp->audio_ops && acomp->audio_ops->master_unbind)
    230		acomp->audio_ops->master_unbind(dev, acomp);
    231	module_put(acomp->ops->owner);
    232	component_unbind_all(dev, acomp);
    233	WARN_ON(acomp->ops || acomp->dev);
    234}
    235
    236static const struct component_master_ops hdac_component_master_ops = {
    237	.bind = hdac_component_master_bind,
    238	.unbind = hdac_component_master_unbind,
    239};
    240
    241/**
    242 * snd_hdac_acomp_register_notifier - Register audio component ops
    243 * @bus: HDA core bus
    244 * @aops: audio component ops
    245 *
    246 * This function is supposed to be used only by a HD-audio controller
    247 * driver that needs the interaction with graphics driver.
    248 *
    249 * This function sets the given ops to be called by the graphics driver.
    250 *
    251 * Returns zero for success or a negative error code.
    252 */
    253int snd_hdac_acomp_register_notifier(struct hdac_bus *bus,
    254				    const struct drm_audio_component_audio_ops *aops)
    255{
    256	if (!bus->audio_component)
    257		return -ENODEV;
    258
    259	bus->audio_component->audio_ops = aops;
    260	return 0;
    261}
    262EXPORT_SYMBOL_GPL(snd_hdac_acomp_register_notifier);
    263
    264/**
    265 * snd_hdac_acomp_init - Initialize audio component
    266 * @bus: HDA core bus
    267 * @aops: audio component ops
    268 * @match_master: match function for finding components
    269 * @extra_size: Extra bytes to allocate
    270 *
    271 * This function is supposed to be used only by a HD-audio controller
    272 * driver that needs the interaction with graphics driver.
    273 *
    274 * This function initializes and sets up the audio component to communicate
    275 * with graphics driver.
    276 *
    277 * Unlike snd_hdac_i915_init(), this function doesn't synchronize with the
    278 * binding with the DRM component.  Each caller needs to sync via master_bind
    279 * audio_ops.
    280 *
    281 * Returns zero for success or a negative error code.
    282 */
    283int snd_hdac_acomp_init(struct hdac_bus *bus,
    284			const struct drm_audio_component_audio_ops *aops,
    285			int (*match_master)(struct device *, int, void *),
    286			size_t extra_size)
    287{
    288	struct component_match *match = NULL;
    289	struct device *dev = bus->dev;
    290	struct drm_audio_component *acomp;
    291	int ret;
    292
    293	if (WARN_ON(hdac_get_acomp(dev)))
    294		return -EBUSY;
    295
    296	acomp = devres_alloc(hdac_acomp_release, sizeof(*acomp) + extra_size,
    297			     GFP_KERNEL);
    298	if (!acomp)
    299		return -ENOMEM;
    300	acomp->audio_ops = aops;
    301	init_completion(&acomp->master_bind_complete);
    302	bus->audio_component = acomp;
    303	devres_add(dev, acomp);
    304
    305	component_match_add_typed(dev, &match, match_master, bus);
    306	ret = component_master_add_with_match(dev, &hdac_component_master_ops,
    307					      match);
    308	if (ret < 0)
    309		goto out_err;
    310
    311	return 0;
    312
    313out_err:
    314	bus->audio_component = NULL;
    315	devres_destroy(dev, hdac_acomp_release, NULL, NULL);
    316	dev_info(dev, "failed to add audio component master (%d)\n", ret);
    317
    318	return ret;
    319}
    320EXPORT_SYMBOL_GPL(snd_hdac_acomp_init);
    321
    322/**
    323 * snd_hdac_acomp_exit - Finalize audio component
    324 * @bus: HDA core bus
    325 *
    326 * This function is supposed to be used only by a HD-audio controller
    327 * driver that needs the interaction with graphics driver.
    328 *
    329 * This function releases the audio component that has been used.
    330 *
    331 * Returns zero for success or a negative error code.
    332 */
    333int snd_hdac_acomp_exit(struct hdac_bus *bus)
    334{
    335	struct device *dev = bus->dev;
    336	struct drm_audio_component *acomp = bus->audio_component;
    337
    338	if (!acomp)
    339		return 0;
    340
    341	if (WARN_ON(bus->display_power_active) && acomp->ops)
    342		acomp->ops->put_power(acomp->dev, bus->display_power_active);
    343
    344	bus->display_power_active = 0;
    345	bus->display_power_status = 0;
    346
    347	component_master_del(dev, &hdac_component_master_ops);
    348
    349	bus->audio_component = NULL;
    350	devres_destroy(dev, hdac_acomp_release, NULL, NULL);
    351
    352	return 0;
    353}
    354EXPORT_SYMBOL_GPL(snd_hdac_acomp_exit);