Revision d2e3fce9ddafe689c6f7cb355f23560637e30b9d authored by Ville Syrjälä on 10 November 2020, 21:04:47 UTC, committed by Rodrigo Vivi on 19 November 2020, 06:52:25 UTC
EDID can declare the maximum supported bpc up to 16,
and apparently there are displays that do so. Currently
we assume 12 bpc is tha max. Fix the assumption and
toss in a MISSING_CASE() for any other value we don't
expect to see.

This fixes modesets with a display with EDID max bpc > 12.
Previously any modeset would just silently fail on platforms
that didn't otherwise limit this via the max_bpc property.
In particular we don't add the max_bpc property to HDMI
ports on gmch platforms, and thus we would see the raw
max_bpc coming from the EDID.

I suppose we could already adjust this to also allow 16bpc,
but seeing as no current platform supports that there is
little point.

Cc: stable@vger.kernel.org
Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/2632
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20201110210447.27454-1-ville.syrjala@linux.intel.com
Reviewed-by: José Roberto de Souza <jose.souza@intel.com>
(cherry picked from commit 2ca5a7b85b0c2b97ef08afbd7799b022e29f192e)
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
1 parent b5462cc
Raw File
ac97_bus.c
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Linux driver model AC97 bus interface
 *
 * Author:	Nicolas Pitre
 * Created:	Jan 14, 2005
 * Copyright:	(C) MontaVista Software Inc.
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/string.h>
#include <sound/ac97_codec.h>

/*
 * snd_ac97_check_id() - Reads and checks the vendor ID of the device
 * @ac97: The AC97 device to check
 * @id: The ID to compare to
 * @id_mask: Mask that is applied to the device ID before comparing to @id
 *
 * If @id is 0 this function returns true if the read device vendor ID is
 * a valid ID. If @id is non 0 this functions returns true if @id
 * matches the read vendor ID. Otherwise the function returns false.
 */
static bool snd_ac97_check_id(struct snd_ac97 *ac97, unsigned int id,
	unsigned int id_mask)
{
	ac97->id = ac97->bus->ops->read(ac97, AC97_VENDOR_ID1) << 16;
	ac97->id |= ac97->bus->ops->read(ac97, AC97_VENDOR_ID2);

	if (ac97->id == 0x0 || ac97->id == 0xffffffff)
		return false;

	if (id != 0 && id != (ac97->id & id_mask))
		return false;

	return true;
}

/**
 * snd_ac97_reset() - Reset AC'97 device
 * @ac97: The AC'97 device to reset
 * @try_warm: Try a warm reset first
 * @id: Expected device vendor ID
 * @id_mask: Mask that is applied to the device ID before comparing to @id
 *
 * This function resets the AC'97 device. If @try_warm is true the function
 * first performs a warm reset. If the warm reset is successful the function
 * returns 1. Otherwise or if @try_warm is false the function issues cold reset
 * followed by a warm reset. If this is successful the function returns 0,
 * otherwise a negative error code. If @id is 0 any valid device ID will be
 * accepted, otherwise only the ID that matches @id and @id_mask is accepted.
 */
int snd_ac97_reset(struct snd_ac97 *ac97, bool try_warm, unsigned int id,
	unsigned int id_mask)
{
	const struct snd_ac97_bus_ops *ops = ac97->bus->ops;

	if (try_warm && ops->warm_reset) {
		ops->warm_reset(ac97);
		if (snd_ac97_check_id(ac97, id, id_mask))
			return 1;
	}

	if (ops->reset)
		ops->reset(ac97);
	if (ops->warm_reset)
		ops->warm_reset(ac97);

	if (snd_ac97_check_id(ac97, id, id_mask))
		return 0;

	return -ENODEV;
}
EXPORT_SYMBOL_GPL(snd_ac97_reset);

/*
 * Let drivers decide whether they want to support given codec from their
 * probe method. Drivers have direct access to the struct snd_ac97
 * structure and may  decide based on the id field amongst other things.
 */
static int ac97_bus_match(struct device *dev, struct device_driver *drv)
{
	return 1;
}

struct bus_type ac97_bus_type = {
	.name		= "ac97",
	.match		= ac97_bus_match,
};

static int __init ac97_bus_init(void)
{
	return bus_register(&ac97_bus_type);
}

subsys_initcall(ac97_bus_init);

static void __exit ac97_bus_exit(void)
{
	bus_unregister(&ac97_bus_type);
}

module_exit(ac97_bus_exit);

EXPORT_SYMBOL(ac97_bus_type);

MODULE_LICENSE("GPL");
back to top