mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-30 00:21:06 +00:00
6744c0d652
Add sound support for link, using the HDA codec implementation. Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
137 lines
3.3 KiB
C
137 lines
3.3 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Intel HDA audio (Azalia) for ivybridge
|
|
*
|
|
* Originally from coreboot file bd82x6x/azalia.c
|
|
*
|
|
* Copyright (C) 2008 Advanced Micro Devices, Inc.
|
|
* Copyright (C) 2008-2009 coresystems GmbH
|
|
* Copyright (C) 2011 The ChromiumOS Authors.
|
|
* Copyright 2018 Google LLC
|
|
*/
|
|
|
|
#define LOG_CATEGORY UCLASS_SOUND
|
|
|
|
#include <common.h>
|
|
#include <dm.h>
|
|
#include <hda_codec.h>
|
|
#include <pch.h>
|
|
#include <sound.h>
|
|
|
|
static int bd82x6x_azalia_probe(struct udevice *dev)
|
|
{
|
|
struct pci_child_platdata *plat;
|
|
struct hda_codec_priv *priv;
|
|
struct udevice *pch;
|
|
u32 codec_mask;
|
|
int conf;
|
|
int ret;
|
|
|
|
/* Only init after relocation */
|
|
if (!(gd->flags & GD_FLG_RELOC))
|
|
return 0;
|
|
|
|
ret = hda_codec_init(dev);
|
|
if (ret) {
|
|
log_debug("Cannot set up HDA codec (err=%d)\n", ret);
|
|
return ret;
|
|
}
|
|
priv = dev_get_priv(dev);
|
|
|
|
ret = uclass_first_device_err(UCLASS_PCH, &pch);
|
|
log_debug("PCH %p %s\n", pch, pch->name);
|
|
if (ret)
|
|
return ret;
|
|
|
|
conf = pch_ioctl(pch, PCH_REQ_HDA_CONFIG, NULL, 0);
|
|
log_debug("conf = %x\n", conf);
|
|
if (conf >= 0) {
|
|
dm_pci_clrset_config32(dev, 0x120, 7 << 24 | 0xfe,
|
|
1 << 24 | /* 2 << 24 for server */
|
|
conf);
|
|
|
|
dm_pci_clrset_config16(dev, 0x78, 0, 1 << 1);
|
|
} else {
|
|
log_debug("V1CTL disabled\n");
|
|
}
|
|
dm_pci_clrset_config32(dev, 0x114, 0xfe, 0);
|
|
|
|
/* Set VCi enable bit */
|
|
dm_pci_clrset_config32(dev, 0x120, 0, 1U << 31);
|
|
|
|
/* Enable HDMI codec */
|
|
dm_pci_clrset_config32(dev, 0xc4, 0, 1 << 1);
|
|
dm_pci_clrset_config8(dev, 0x43, 0, 1 << 6);
|
|
|
|
/* Additional programming steps */
|
|
dm_pci_clrset_config32(dev, 0xc4, 0, 1 << 13);
|
|
dm_pci_clrset_config32(dev, 0xc4, 0, 1 << 10);
|
|
dm_pci_clrset_config32(dev, 0xd0, 1U << 31, 0);
|
|
|
|
/* Additional step on Panther Point */
|
|
plat = dev_get_parent_platdata(dev);
|
|
if (plat->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_HDA)
|
|
dm_pci_clrset_config32(dev, 0xc4, 0, 1 << 17);
|
|
|
|
dm_pci_write_config8(dev, 0x3c, 0xa); /* unused? */
|
|
|
|
/* Audio Control: Select Azalia mode */
|
|
dm_pci_clrset_config8(dev, 0x40, 0, 1);
|
|
dm_pci_clrset_config8(dev, 0x4d, 1 << 7, 0); /* Docking not supported */
|
|
codec_mask = hda_codec_detect(priv->regs);
|
|
log_debug("codec_mask = %02x\n", codec_mask);
|
|
|
|
if (codec_mask) {
|
|
ret = hda_codecs_init(dev, priv->regs, codec_mask);
|
|
if (ret) {
|
|
log_err("Codec init failed (err=%d)\n", ret);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
/* Enable dynamic clock gating */
|
|
dm_pci_clrset_config8(dev, 0x43, 7, BIT(2) | BIT(0));
|
|
|
|
ret = hda_codec_finish_init(dev);
|
|
if (ret) {
|
|
log_debug("Cannot set up HDA codec (err=%d)\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int bd82x6x_azalia_setup(struct udevice *dev)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int bd82x6x_azalia_start_beep(struct udevice *dev, int frequency_hz)
|
|
{
|
|
return hda_codec_start_beep(dev, frequency_hz);
|
|
}
|
|
|
|
int bd82x6x_azalia_stop_beep(struct udevice *dev)
|
|
{
|
|
return hda_codec_stop_beep(dev);
|
|
}
|
|
|
|
static const struct sound_ops bd82x6x_azalia_ops = {
|
|
.setup = bd82x6x_azalia_setup,
|
|
.start_beep = bd82x6x_azalia_start_beep,
|
|
.stop_beep = bd82x6x_azalia_stop_beep,
|
|
};
|
|
|
|
static const struct udevice_id bd82x6x_azalia_ids[] = {
|
|
{ .compatible = "intel,hd-audio" },
|
|
{ }
|
|
};
|
|
|
|
U_BOOT_DRIVER(bd82x6x_azalia_drv) = {
|
|
.name = "bd82x6x-hda",
|
|
.id = UCLASS_SOUND,
|
|
.of_match = bd82x6x_azalia_ids,
|
|
.probe = bd82x6x_azalia_probe,
|
|
.ops = &bd82x6x_azalia_ops,
|
|
.priv_auto_alloc_size = sizeof(struct hda_codec_priv),
|
|
};
|