diff options
-rw-r--r-- | board/chromebook-x86/chromeos/Makefile | 1 | ||||
-rw-r--r-- | board/chromebook-x86/chromeos/hda_codec.c | 145 | ||||
-rw-r--r-- | include/chromeos/hda_codec.h | 20 | ||||
-rw-r--r-- | include/pci_ids.h | 1 | ||||
-rw-r--r-- | lib/vbexport/utility.c | 16 |
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) |