summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/chromebook-x86/chromeos/Makefile1
-rw-r--r--board/chromebook-x86/chromeos/hda_codec.c145
-rw-r--r--include/chromeos/hda_codec.h20
-rw-r--r--include/pci_ids.h1
-rw-r--r--lib/vbexport/utility.c16
5 files changed, 179 insertions, 4 deletions
diff --git a/board/chromebook-x86/chromeos/Makefile b/board/chromebook-x86/chromeos/Makefile
index a3eb6ec90f2..c1e8f71ce04 100644
--- a/board/chromebook-x86/chromeos/Makefile
+++ b/board/chromebook-x86/chromeos/Makefile
@@ -40,6 +40,7 @@ LIB = $(obj)libchromeos_board.a
COBJS-$(CONFIG_CHROMEOS) += cros_gpio.o
COBJS-$(CONFIG_CHROMEOS) += power_management.o
+COBJS-$(CONFIG_CHROMEOS) += hda_codec.o
COBJS := $(COBJS-y)
OBJS := $(addprefix $(obj),$(COBJS))
diff --git a/board/chromebook-x86/chromeos/hda_codec.c b/board/chromebook-x86/chromeos/hda_codec.c
new file mode 100644
index 00000000000..21a0db5a566
--- /dev/null
+++ b/board/chromebook-x86/chromeos/hda_codec.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ */
+
+/* Implementation of per-board codec beeping */
+
+#include <chromeos/hda_codec.h>
+#include <common.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#define HDA_CMD_REG 0x5C
+#define HDA_ICII_REG 0x64
+#define HDA_ICII_BUSY (1 << 0)
+#define HDA_ICII_VALID (1 << 1)
+
+/**
+ * Wait 50usec for the codec to indicate it is ready
+ * no response would imply that the codec is non-operative
+ */
+static int wait_for_ready(uint32_t base)
+{
+ /* Use a 50 usec timeout - the Linux kernel uses the
+ * same duration
+ */
+
+ int timeout = 50;
+
+ while (timeout--) {
+ uint32_t reg32 = readl(base + HDA_ICII_REG);
+ asm("" ::: "memory");
+ if (!(reg32 & HDA_ICII_BUSY))
+ return 0;
+ udelay(1);
+ }
+
+ return -1;
+}
+
+/**
+ * Wait 50usec for the codec to indicate that it accepted
+ * the previous command. No response would imply that the code
+ * is non-operative
+ */
+static int wait_for_valid(uint32_t base)
+{
+ uint32_t reg32;
+
+ /* Send the verb to the codec */
+ reg32 = readl(base + HDA_ICII_REG);
+ reg32 |= HDA_ICII_BUSY | HDA_ICII_VALID;
+ writel(reg32, base + HDA_ICII_REG);
+
+ /* Use a 50 usec timeout - the Linux kernel uses the
+ * same duration
+ */
+
+ int timeout = 50;
+ while (timeout--) {
+ reg32 = readl(base + HDA_ICII_REG);
+ if ((reg32 & (HDA_ICII_VALID | HDA_ICII_BUSY)) ==
+ HDA_ICII_VALID)
+ return 0;
+ udelay(1);
+ }
+
+ return -1;
+}
+
+/* Wait for the codec to be ready, write the verb, then wait for the
+ * codec to be valid.
+ */
+int write_one_verb(uint32_t base, uint32_t val)
+{
+ if (wait_for_ready(base) == -1)
+ return -1;
+
+ writel(val, base + HDA_CMD_REG);
+
+ if (wait_for_valid(base) == -1)
+ return -1;
+
+ return 0;
+}
+
+/* Supported sound devices.
+ */
+static struct pci_device_id supported[] = {
+ {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COUGARPOINT_HDA},
+ {}
+};
+
+/* Find the base address to talk tot he HDA codec.
+ */
+static u32 get_hda_base(void)
+{
+ pci_dev_t devbusfn;
+ u32 pci_mem_base;
+
+ devbusfn = pci_find_devices(supported, 0);
+ if (devbusfn < 0) {
+ printf("Audio: Controller not found !\n");
+ return 0;
+ }
+
+ pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_0, &pci_mem_base);
+ pci_mem_base = pci_mem_to_phys(devbusfn, pci_mem_base);
+ return pci_mem_base;
+}
+
+static const u32 beep_cmd[] = {
+ 0x00170500, /* power up codec */
+ 0x00270500, /* power up DAC */
+ 0x00670500, /* power up speaker */
+ 0x00670740, /* enable speaker output */
+ 0x0023B04B, /* set DAC gain */
+ 0x00C70A0C, /* enable beep generator 1 kHz */
+};
+
+void enable_beep(void)
+{
+ uint32_t base;
+ int i;
+
+ base = get_hda_base();
+ for (i = 0; i < sizeof(beep_cmd)/sizeof(beep_cmd[0]); i++) {
+ if (write_one_verb(base, beep_cmd[i]))
+ return;
+ }
+}
+
+void disable_beep(void)
+{
+ uint32_t base;
+
+ base = get_hda_base();
+ write_one_verb(base, 0x00C70A00); /* Disable beep gen */
+}
diff --git a/include/chromeos/hda_codec.h b/include/chromeos/hda_codec.h
new file mode 100644
index 00000000000..e10a0974699
--- /dev/null
+++ b/include/chromeos/hda_codec.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ */
+
+/* HDA codec interface for Chrome OS verified boot */
+
+#ifndef CHROMEOS_HDA_CODEC_H_
+#define CHROMEOS_HDA_CODEC_H_
+
+/* Beep control */
+void enable_beep(void);
+void disable_beep(void);
+
+#endif /* CHROMEOS_PHDA_CODEC_H_ */
diff --git a/include/pci_ids.h b/include/pci_ids.h
index dc5016d0c55..fe49c4b4948 100644
--- a/include/pci_ids.h
+++ b/include/pci_ids.h
@@ -2519,6 +2519,7 @@
#define PCI_DEVICE_ID_INTEL_82845_HB 0x1a30
#define PCI_DEVICE_ID_INTEL_IOAT 0x1a38
#define PCI_DEVICE_ID_INTEL_COUGARPOINT_AHCI_MOBILE 0x1c03
+#define PCI_DEVICE_ID_INTEL_COUGARPOINT_HDA 0x1c20
#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22
#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN 0x1c41
#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX 0x1c5f
diff --git a/lib/vbexport/utility.c b/lib/vbexport/utility.c
index 6bc53caed1c..90a94be76b1 100644
--- a/lib/vbexport/utility.c
+++ b/lib/vbexport/utility.c
@@ -16,6 +16,7 @@
#include <common.h>
#include <malloc.h>
#include <chromeos/common.h>
+#include <chromeos/hda_codec.h>
#include <chromeos/power_management.h>
/* Import the definition of vboot_wrapper interfaces. */
@@ -89,10 +90,17 @@ void VbExSleepMs(uint32_t msec)
VbError_t VbExBeep(uint32_t msec, uint32_t frequency)
{
- /* TODO Implement it later. */
- VbExSleepMs(msec);
- VBDEBUG("Beep!\n");
- return VBERROR_NO_SOUND;
+ if (frequency)
+ enable_beep();
+ else
+ disable_beep();
+
+ if (msec > 0) {
+ VbExSleepMs(msec);
+ disable_beep();
+ }
+
+ return VBERROR_SUCCESS;
}
int Memcmp(const void *src1, const void *src2, size_t n)