blob: 476d092f1906995dd8dc48cd472a2509b51f5f31 [file] [log] [blame]
Angel Ponsf94ac9a2020-04-05 15:46:48 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2/* This file is part of the coreboot project. */
Duncan Lauriec88c54c2014-04-30 16:36:13 -07003
4#include <console/console.h>
5#include <device/device.h>
Jonathan A. Kollaschec505ad22015-07-07 12:57:46 -05006#include <device/azalia_device.h>
Duncan Lauriec88c54c2014-04-30 16:36:13 -07007#include <device/pci.h>
8#include <device/pci_ids.h>
9#include <device/pci_ops.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020010#include <device/mmio.h>
Duncan Lauriec88c54c2014-04-30 16:36:13 -070011#include <soc/intel/common/hda_verb.h>
Julius Werner4ee4bd52014-10-20 13:46:39 -070012#include <soc/pch.h>
13#include <soc/ramstage.h>
14#include <soc/rcba.h>
Duncan Lauriec88c54c2014-04-30 16:36:13 -070015
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080016static void codecs_init(u8 *base, u32 codec_mask)
Duncan Lauriec88c54c2014-04-30 16:36:13 -070017{
18 int i;
19
20 /* Can support up to 4 codecs */
21 for (i = 3; i >= 0; i--) {
22 if (codec_mask & (1 << i))
23 hda_codec_init(base, i,
24 cim_verb_data_size,
25 cim_verb_data);
26 }
27
Jonathan A. Kollaschec505ad22015-07-07 12:57:46 -050028 if (pc_beep_verbs_size)
Duncan Lauriec88c54c2014-04-30 16:36:13 -070029 hda_codec_write(base, pc_beep_verbs_size, pc_beep_verbs);
30}
31
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080032static void hda_pch_init(struct device *dev, u8 *base)
Duncan Lauriec88c54c2014-04-30 16:36:13 -070033{
34 u8 reg8;
35 u16 reg16;
36 u32 reg32;
37
38 if (RCBA32(0x2030) & (1 << 31)) {
39 reg32 = pci_read_config32(dev, 0x120);
40 reg32 &= 0xf8ffff01;
41 reg32 |= (1 << 25);
42 reg32 |= RCBA32(0x2030) & 0xfe;
43 pci_write_config32(dev, 0x120, reg32);
44 } else
45 printk(BIOS_DEBUG, "HDA: V1CTL disabled.\n");
46
47 reg32 = pci_read_config32(dev, 0x114);
48 reg32 &= ~0xfe;
49 pci_write_config32(dev, 0x114, reg32);
50
51 // Set VCi enable bit
52 if (pci_read_config32(dev, 0x120) & ((1 << 24) |
53 (1 << 25) | (1 << 26))) {
54 reg32 = pci_read_config32(dev, 0x120);
55 reg32 &= ~(1 << 31);
56 pci_write_config32(dev, 0x120, reg32);
57 }
58
Duncan Lauriec88c54c2014-04-30 16:36:13 -070059 /* Additional programming steps */
60 reg32 = pci_read_config32(dev, 0xc4);
61 reg32 |= (1 << 24);
62 pci_write_config32(dev, 0xc4, reg32);
63
64 reg8 = pci_read_config8(dev, 0x40); // Audio Control
65 reg8 |= 1; // Select HDA mode
66 pci_write_config8(dev, 0x40, reg8);
67
68 reg8 = pci_read_config8(dev, 0x4d); // Docking Status
69 reg8 &= ~(1 << 7); // Docking not supported
70 pci_write_config8(dev, 0x4d, reg8);
71
72 reg16 = read32(base + 0x0012);
73 reg16 |= (1 << 0);
74 write32(base + 0x0012, reg16);
75
76 /* disable Auto Voltage Detector */
77 reg8 = pci_read_config8(dev, 0x42);
78 reg8 |= (1 << 2);
79 pci_write_config8(dev, 0x42, reg8);
80}
81
82static void hda_init(struct device *dev)
83{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080084 u8 *base;
Duncan Lauriec88c54c2014-04-30 16:36:13 -070085 struct resource *res;
86 u32 codec_mask;
87 u32 reg32;
88
89 /* Find base address */
90 res = find_resource(dev, PCI_BASE_ADDRESS_0);
91 if (!res)
92 return;
93
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080094 base = res2mmio(res, 0, 0);
95 printk(BIOS_DEBUG, "HDA: base = %p\n", base);
Duncan Lauriec88c54c2014-04-30 16:36:13 -070096
97 /* Set Bus Master */
98 reg32 = pci_read_config32(dev, PCI_COMMAND);
99 pci_write_config32(dev, PCI_COMMAND, reg32 | PCI_COMMAND_MASTER);
100
101 hda_pch_init(dev, base);
102
103 codec_mask = hda_codec_detect(base);
104
105 if (codec_mask) {
106 printk(BIOS_DEBUG, "HDA: codec_mask = %02x\n", codec_mask);
107 codecs_init(base, codec_mask);
108 }
109}
110
Duncan Laurie61680272014-05-05 12:42:35 -0500111static void hda_enable(struct device *dev)
112{
113 u32 reg32;
Duncan Laurie446fb8e2014-08-08 09:59:43 -0700114 u8 reg8;
115
116 reg8 = pci_read_config8(dev, 0x43);
117 reg8 |= 0x6f;
118 pci_write_config8(dev, 0x43, reg8);
Duncan Laurie61680272014-05-05 12:42:35 -0500119
120 if (!dev->enabled) {
121 /* Route I/O buffers to ADSP function */
Duncan Laurie446fb8e2014-08-08 09:59:43 -0700122 reg8 = pci_read_config8(dev, 0x42);
123 reg8 |= (1 << 7) | (1 << 6);
124 pci_write_config8(dev, 0x42, reg8);
Duncan Laurie61680272014-05-05 12:42:35 -0500125
126 printk(BIOS_INFO, "HDA disabled, I/O buffers routed to ADSP\n");
127
128 /* Ensure memory, io, and bus master are all disabled */
129 reg32 = pci_read_config32(dev, PCI_COMMAND);
130 reg32 &= ~(PCI_COMMAND_MASTER |
131 PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
132 pci_write_config32(dev, PCI_COMMAND, reg32);
133
134 /* Disable this device */
135 pch_disable_devfn(dev);
136 }
137}
138
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700139static struct device_operations hda_ops = {
140 .read_resources = &pci_dev_read_resources,
141 .set_resources = &pci_dev_set_resources,
142 .enable_resources = &pci_dev_enable_resources,
143 .init = &hda_init,
Duncan Laurie61680272014-05-05 12:42:35 -0500144 .enable = &hda_enable,
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700145 .ops_pci = &broadwell_pci_ops,
146};
147
148static const unsigned short pci_device_ids[] = {
149 0x9c20, /* LynxPoint-LP */
150 0x9ca0, /* WildcatPoint */
151 0
152};
153
154static const struct pci_driver pch_hda __pci_driver = {
155 .ops = &hda_ops,
156 .vendor = PCI_VENDOR_ID_INTEL,
157 .devices = pci_device_ids,
158};