blob: 3fd87dcfbc93498c9011536fcf7194132001c14a [file] [log] [blame]
Duncan Lauriec88c54c2014-04-30 16:36:13 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2008 Advanced Micro Devices, Inc.
5 * Copyright (C) 2008-2009 coresystems GmbH
6 * Copyright (C) 2014 Google Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
Duncan Lauriec88c54c2014-04-30 16:36:13 -070016 */
17
18#include <console/console.h>
19#include <device/device.h>
Jonathan A. Kollaschec505ad22015-07-07 12:57:46 -050020#include <device/azalia_device.h>
Duncan Lauriec88c54c2014-04-30 16:36:13 -070021#include <device/pci.h>
22#include <device/pci_ids.h>
23#include <device/pci_ops.h>
24#include <arch/io.h>
25#include <delay.h>
26#include <soc/intel/common/hda_verb.h>
Julius Werner4ee4bd52014-10-20 13:46:39 -070027#include <soc/pch.h>
28#include <soc/ramstage.h>
29#include <soc/rcba.h>
Duncan Lauriec88c54c2014-04-30 16:36:13 -070030
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080031static void codecs_init(u8 *base, u32 codec_mask)
Duncan Lauriec88c54c2014-04-30 16:36:13 -070032{
33 int i;
34
35 /* Can support up to 4 codecs */
36 for (i = 3; i >= 0; i--) {
37 if (codec_mask & (1 << i))
38 hda_codec_init(base, i,
39 cim_verb_data_size,
40 cim_verb_data);
41 }
42
Jonathan A. Kollaschec505ad22015-07-07 12:57:46 -050043 if (pc_beep_verbs_size)
Duncan Lauriec88c54c2014-04-30 16:36:13 -070044 hda_codec_write(base, pc_beep_verbs_size, pc_beep_verbs);
45}
46
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080047static void hda_pch_init(struct device *dev, u8 *base)
Duncan Lauriec88c54c2014-04-30 16:36:13 -070048{
49 u8 reg8;
50 u16 reg16;
51 u32 reg32;
52
53 if (RCBA32(0x2030) & (1 << 31)) {
54 reg32 = pci_read_config32(dev, 0x120);
55 reg32 &= 0xf8ffff01;
56 reg32 |= (1 << 25);
57 reg32 |= RCBA32(0x2030) & 0xfe;
58 pci_write_config32(dev, 0x120, reg32);
59 } else
60 printk(BIOS_DEBUG, "HDA: V1CTL disabled.\n");
61
62 reg32 = pci_read_config32(dev, 0x114);
63 reg32 &= ~0xfe;
64 pci_write_config32(dev, 0x114, reg32);
65
66 // Set VCi enable bit
67 if (pci_read_config32(dev, 0x120) & ((1 << 24) |
68 (1 << 25) | (1 << 26))) {
69 reg32 = pci_read_config32(dev, 0x120);
70 reg32 &= ~(1 << 31);
71 pci_write_config32(dev, 0x120, reg32);
72 }
73
Duncan Lauriec88c54c2014-04-30 16:36:13 -070074 /* Additional programming steps */
75 reg32 = pci_read_config32(dev, 0xc4);
76 reg32 |= (1 << 24);
77 pci_write_config32(dev, 0xc4, reg32);
78
79 reg8 = pci_read_config8(dev, 0x40); // Audio Control
80 reg8 |= 1; // Select HDA mode
81 pci_write_config8(dev, 0x40, reg8);
82
83 reg8 = pci_read_config8(dev, 0x4d); // Docking Status
84 reg8 &= ~(1 << 7); // Docking not supported
85 pci_write_config8(dev, 0x4d, reg8);
86
87 reg16 = read32(base + 0x0012);
88 reg16 |= (1 << 0);
89 write32(base + 0x0012, reg16);
90
91 /* disable Auto Voltage Detector */
92 reg8 = pci_read_config8(dev, 0x42);
93 reg8 |= (1 << 2);
94 pci_write_config8(dev, 0x42, reg8);
95}
96
97static void hda_init(struct device *dev)
98{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080099 u8 *base;
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700100 struct resource *res;
101 u32 codec_mask;
102 u32 reg32;
103
104 /* Find base address */
105 res = find_resource(dev, PCI_BASE_ADDRESS_0);
106 if (!res)
107 return;
108
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800109 base = res2mmio(res, 0, 0);
110 printk(BIOS_DEBUG, "HDA: base = %p\n", base);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700111
112 /* Set Bus Master */
113 reg32 = pci_read_config32(dev, PCI_COMMAND);
114 pci_write_config32(dev, PCI_COMMAND, reg32 | PCI_COMMAND_MASTER);
115
116 hda_pch_init(dev, base);
117
118 codec_mask = hda_codec_detect(base);
119
120 if (codec_mask) {
121 printk(BIOS_DEBUG, "HDA: codec_mask = %02x\n", codec_mask);
122 codecs_init(base, codec_mask);
123 }
124}
125
Duncan Laurie61680272014-05-05 12:42:35 -0500126static void hda_enable(struct device *dev)
127{
128 u32 reg32;
Duncan Laurie446fb8e2014-08-08 09:59:43 -0700129 u8 reg8;
130
131 reg8 = pci_read_config8(dev, 0x43);
132 reg8 |= 0x6f;
133 pci_write_config8(dev, 0x43, reg8);
Duncan Laurie61680272014-05-05 12:42:35 -0500134
135 if (!dev->enabled) {
136 /* Route I/O buffers to ADSP function */
Duncan Laurie446fb8e2014-08-08 09:59:43 -0700137 reg8 = pci_read_config8(dev, 0x42);
138 reg8 |= (1 << 7) | (1 << 6);
139 pci_write_config8(dev, 0x42, reg8);
Duncan Laurie61680272014-05-05 12:42:35 -0500140
141 printk(BIOS_INFO, "HDA disabled, I/O buffers routed to ADSP\n");
142
143 /* Ensure memory, io, and bus master are all disabled */
144 reg32 = pci_read_config32(dev, PCI_COMMAND);
145 reg32 &= ~(PCI_COMMAND_MASTER |
146 PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
147 pci_write_config32(dev, PCI_COMMAND, reg32);
148
149 /* Disable this device */
150 pch_disable_devfn(dev);
151 }
152}
153
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700154static struct device_operations hda_ops = {
155 .read_resources = &pci_dev_read_resources,
156 .set_resources = &pci_dev_set_resources,
157 .enable_resources = &pci_dev_enable_resources,
158 .init = &hda_init,
Duncan Laurie61680272014-05-05 12:42:35 -0500159 .enable = &hda_enable,
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700160 .ops_pci = &broadwell_pci_ops,
161};
162
163static const unsigned short pci_device_ids[] = {
164 0x9c20, /* LynxPoint-LP */
165 0x9ca0, /* WildcatPoint */
166 0
167};
168
169static const struct pci_driver pch_hda __pci_driver = {
170 .ops = &hda_ops,
171 .vendor = PCI_VENDOR_ID_INTEL,
172 .devices = pci_device_ids,
173};