summaryrefslogtreecommitdiff
path: root/sound/pci/hda
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/Kconfig14
-rw-r--r--sound/pci/hda/hda_codec.h3
-rw-r--r--sound/pci/hda/hda_intel.c613
-rw-r--r--sound/pci/hda/patch_hdmi.c62
4 files changed, 605 insertions, 87 deletions
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index bb7e102d6726..522c4fd958dc 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -84,6 +84,20 @@ config SND_HDA_PATCH_LOADER
This option turns on hwdep and reconfig features automatically.
+config SND_HDA_PLATFORM_DRIVER
+ bool "Build platform driver interface for HD-audio driver"
+ help
+ Say Y here to build a platform driver interface for HD-audio driver.
+ This interface can be used by platforms which have an Azalia
+ controller not installed on a PCI bus.
+
+config SND_HDA_PLATFORM_NVIDIA_TEGRA
+ bool "Build NVIDIA Tegra platform driver interface for HD-audio driver"
+ depends on SND_HDA_PLATFORM_DRIVER
+ help
+ Say Y here to build NVIDIA Tegra platform driver interface for
+ HD-audio driver.
+
config SND_HDA_CODEC_REALTEK
bool "Build Realtek HD-audio codec support"
default y
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 755f2b0f9d8e..8f801ae14a15 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -21,6 +21,8 @@
#ifndef __SOUND_HDA_CODEC_H
#define __SOUND_HDA_CODEC_H
+#include <linux/platform_device.h>
+
#include <sound/info.h>
#include <sound/control.h>
#include <sound/pcm.h>
@@ -617,6 +619,7 @@ struct hda_bus_ops {
struct hda_bus_template {
void *private_data;
struct pci_dev *pci;
+ struct platform_device *pdev;
const char *modelname;
int *power_save;
struct hda_bus_ops ops;
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index f6659751f0c9..973e46706cdb 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -46,6 +46,7 @@
#include <linux/pci.h>
#include <linux/mutex.h>
#include <linux/reboot.h>
+#include <linux/clk.h>
#include <sound/core.h>
#include <sound/initval.h>
#include "hda_codec.h"
@@ -321,6 +322,32 @@ enum {
#define NVIDIA_HDA_OSTRM_COH 0x4c
#define NVIDIA_HDA_ENABLE_COHBIT 0x01
+#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA
+/* Defines for Nvidia Tegra HDA support */
+#define NVIDIA_TEGRA_HDA_BAR0_OFFSET 0x8000
+
+#define NVIDIA_TEGRA_HDA_CFG_CMD_OFFSET 0x1004
+#define NVIDIA_TEGRA_HDA_CFG_BAR0_OFFSET 0x1010
+
+#define NVIDIA_TEGRA_HDA_ENABLE_IO_SPACE (1 << 0)
+#define NVIDIA_TEGRA_HDA_ENABLE_MEM_SPACE (1 << 1)
+#define NVIDIA_TEGRA_HDA_ENABLE_BUS_MASTER (1 << 2)
+#define NVIDIA_TEGRA_HDA_ENABLE_SERR (1 << 8)
+#define NVIDIA_TEGRA_HDA_DISABLE_INTR (1 << 10)
+#define NVIDIA_TEGRA_HDA_BAR0_INIT_PROGRAM 0xFFFFFFFF
+#define NVIDIA_TEGRA_HDA_BAR0_FINAL_PROGRAM (1 << 14)
+
+/* IPFS */
+#define NVIDIA_TEGRA_HDA_IPFS_CONFIG 0x180
+#define NVIDIA_TEGRA_HDA_IPFS_EN_FPCI 0x1
+
+#define NVIDIA_TEGRA_HDA_IPFS_FPCI_BAR0 0x80
+#define NVIDIA_TEGRA_HDA_FPCI_BAR0_START 0x40
+
+#define NVIDIA_TEGRA_HDA_IPFS_INTR_MASK 0x188
+#define NVIDIA_TEGRA_HDA_IPFS_EN_INTR (1 << 16)
+#endif /* CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA */
+
/* Defines for Intel SCH HDA snoop control */
#define INTEL_SCH_HDA_DEVC 0x78
#define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11)
@@ -388,6 +415,9 @@ struct azx_rb {
struct azx {
struct snd_card *card;
struct pci_dev *pci;
+ struct platform_device *pdev;
+ struct device *dev;
+ int irq_id;
int dev_index;
/* chip type specific */
@@ -402,8 +432,18 @@ struct azx {
/* pci resources */
unsigned long addr;
void __iomem *remap_addr;
+#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA
+ void __iomem *remap_config_addr;
+#endif
int irq;
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+ /* platform driver clocks */
+ struct clk **platform_clks;
+ int platform_clk_count;
+ int platform_clk_enable;
+#endif
+
/* locks */
spinlock_t reg_lock;
struct mutex open_mutex;
@@ -460,6 +500,7 @@ enum {
AZX_DRIVER_SIS,
AZX_DRIVER_ULI,
AZX_DRIVER_NVIDIA,
+ AZX_DRIVER_NVIDIA_TEGRA,
AZX_DRIVER_TERA,
AZX_DRIVER_CTX,
AZX_DRIVER_GENERIC,
@@ -505,6 +546,7 @@ static char *driver_short_names[] __devinitdata = {
[AZX_DRIVER_SIS] = "HDA SIS966",
[AZX_DRIVER_ULI] = "HDA ULI M5461",
[AZX_DRIVER_NVIDIA] = "HDA NVidia",
+ [AZX_DRIVER_NVIDIA_TEGRA] = "HDA NVIDIA Tegra",
[AZX_DRIVER_TERA] = "HDA Teradici",
[AZX_DRIVER_CTX] = "HDA Creative",
[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
@@ -513,6 +555,48 @@ static char *driver_short_names[] __devinitdata = {
/*
* macros for easy use
*/
+#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA
+#define MASK_LONG_ALIGN 0x3UL
+#define SHIFT_BYTE 3
+#define SHIFT_BITS(reg) ((reg & MASK_LONG_ALIGN) << SHIFT_BYTE)
+#define ADDR_ALIGN_L(base, reg) (base + (reg & ~MASK_LONG_ALIGN))
+#define MASK(bits) (BIT(bits) - 1)
+#define MASK_REG(reg, bits) (MASK(bits) << SHIFT_BITS(reg))
+
+#define tegra_write(base, reg, val, bits) \
+ writel((readl(ADDR_ALIGN_L(base, reg)) & ~MASK_REG(reg, bits)) | \
+ ((val) << SHIFT_BITS(reg)), ADDR_ALIGN_L(base, reg))
+
+#define tegra_read(base, reg, bits) \
+ ((readl(ADDR_ALIGN_L(base, reg)) >> SHIFT_BITS(reg)) & MASK(bits))
+
+#define azx_writel(chip, reg, value) \
+ writel(value, (chip)->remap_addr + ICH6_REG_##reg)
+#define azx_readl(chip, reg) \
+ readl((chip)->remap_addr + ICH6_REG_##reg)
+#define azx_writew(chip, reg, value) \
+ tegra_write((chip)->remap_addr, ICH6_REG_##reg, value, 16)
+#define azx_readw(chip, reg) \
+ tegra_read((chip)->remap_addr, ICH6_REG_##reg, 16)
+#define azx_writeb(chip, reg, value) \
+ tegra_write((chip)->remap_addr, ICH6_REG_##reg, value, 8)
+#define azx_readb(chip, reg) \
+ tegra_read((chip)->remap_addr, ICH6_REG_##reg, 8)
+
+#define azx_sd_writel(dev, reg, value) \
+ writel(value, (dev)->sd_addr + ICH6_REG_##reg)
+#define azx_sd_readl(dev, reg) \
+ readl((dev)->sd_addr + ICH6_REG_##reg)
+#define azx_sd_writew(dev, reg, value) \
+ tegra_write((dev)->sd_addr, ICH6_REG_##reg, value, 16)
+#define azx_sd_readw(dev, reg) \
+ tegra_read((dev)->sd_addr, ICH6_REG_##reg, 16)
+#define azx_sd_writeb(dev, reg, value) \
+ tegra_write((dev)->sd_addr, ICH6_REG_##reg, value, 8)
+#define azx_sd_readb(dev, reg) \
+ tegra_read((dev)->sd_addr, ICH6_REG_##reg, 8)
+
+#else /* CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA */
#define azx_writel(chip,reg,value) \
writel(value, (chip)->remap_addr + ICH6_REG_##reg)
#define azx_readl(chip,reg) \
@@ -539,6 +623,8 @@ static char *driver_short_names[] __devinitdata = {
#define azx_sd_readb(dev,reg) \
readb((dev)->sd_addr + ICH6_REG_##reg)
+#endif /* CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA */
+
/* for pcm support */
#define get_azx_dev(substream) (substream->runtime->private_data)
@@ -557,7 +643,7 @@ static int azx_alloc_cmd_io(struct azx *chip)
/* single page (at least 4096 bytes) must suffice for both ringbuffes */
err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
- snd_dma_pci_data(chip->pci),
+ chip->dev,
PAGE_SIZE, &chip->rb);
if (err < 0) {
snd_printk(KERN_ERR SFX "cannot allocate CORB/RIRB\n");
@@ -1131,6 +1217,83 @@ static void azx_init_pci(struct azx *chip)
}
}
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+/*
+ * initialize the platform specific registers
+ */
+static void reg_update_bits(void __iomem *base, unsigned int reg,
+ unsigned int mask, unsigned int val)
+{
+ unsigned int data;
+
+ data = readl(base + reg);
+ data &= ~mask;
+ data |= (val & mask);
+ writel(data, base + reg);
+}
+
+static void azx_init_platform(struct azx *chip)
+{
+ switch (chip->driver_type) {
+#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA
+ case AZX_DRIVER_NVIDIA_TEGRA:
+ /*Enable the PCI access */
+ reg_update_bits(chip->remap_config_addr,
+ NVIDIA_TEGRA_HDA_IPFS_CONFIG,
+ NVIDIA_TEGRA_HDA_IPFS_EN_FPCI,
+ NVIDIA_TEGRA_HDA_IPFS_EN_FPCI);
+ /* Enable MEM/IO space and bus master */
+ reg_update_bits(chip->remap_config_addr,
+ NVIDIA_TEGRA_HDA_CFG_CMD_OFFSET, 0x507,
+ NVIDIA_TEGRA_HDA_ENABLE_MEM_SPACE |
+ NVIDIA_TEGRA_HDA_ENABLE_IO_SPACE |
+ NVIDIA_TEGRA_HDA_ENABLE_BUS_MASTER |
+ NVIDIA_TEGRA_HDA_ENABLE_SERR);
+ reg_update_bits(chip->remap_config_addr,
+ NVIDIA_TEGRA_HDA_CFG_BAR0_OFFSET, 0xFFFFFFFF,
+ NVIDIA_TEGRA_HDA_BAR0_INIT_PROGRAM);
+ reg_update_bits(chip->remap_config_addr,
+ NVIDIA_TEGRA_HDA_CFG_BAR0_OFFSET, 0xFFFFFFFF,
+ NVIDIA_TEGRA_HDA_BAR0_FINAL_PROGRAM);
+ reg_update_bits(chip->remap_config_addr,
+ NVIDIA_TEGRA_HDA_IPFS_FPCI_BAR0, 0xFFFFFFFF,
+ NVIDIA_TEGRA_HDA_FPCI_BAR0_START);
+ reg_update_bits(chip->remap_config_addr,
+ NVIDIA_TEGRA_HDA_IPFS_INTR_MASK,
+ NVIDIA_TEGRA_HDA_IPFS_EN_INTR,
+ NVIDIA_TEGRA_HDA_IPFS_EN_INTR);
+ break;
+#endif
+ default:
+ break;
+ }
+
+ return;
+}
+
+static void azx_platform_enable_clocks(struct azx *chip)
+{
+ int i;
+
+ for (i = 0; i < chip->platform_clk_count; i++)
+ clk_enable(chip->platform_clks[i]);
+
+ chip->platform_clk_enable++;
+}
+
+static void azx_platform_disable_clocks(struct azx *chip)
+{
+ int i;
+
+ if (!chip->platform_clk_enable)
+ return;
+
+ for (i = 0; i < chip->platform_clk_count; i++)
+ clk_disable(chip->platform_clks[i]);
+
+ chip->platform_clk_enable--;
+}
+#endif /* CONFIG_SND_HDA_PLATFORM_DRIVER */
static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev);
@@ -1437,6 +1600,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model)
bus_temp.private_data = chip;
bus_temp.modelname = model;
bus_temp.pci = chip->pci;
+ bus_temp.pdev = chip->pdev;
bus_temp.ops.command = azx_send_cmd;
bus_temp.ops.get_response = azx_get_response;
bus_temp.ops.attach_pcm = azx_attach_pcm_stream;
@@ -2126,7 +2290,7 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
if (size > MAX_PREALLOC_SIZE)
size = MAX_PREALLOC_SIZE;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
- snd_dma_pci_data(chip->pci),
+ chip->dev,
size, MAX_PREALLOC_SIZE);
return 0;
}
@@ -2168,17 +2332,19 @@ static int __devinit azx_init_stream(struct azx *chip)
static int azx_acquire_irq(struct azx *chip, int do_disconnect)
{
- if (request_irq(chip->pci->irq, azx_interrupt,
+ if (request_irq(chip->irq_id, azx_interrupt,
chip->msi ? 0 : IRQF_SHARED,
KBUILD_MODNAME, chip)) {
printk(KERN_ERR "hda-intel: unable to grab IRQ %d, "
- "disabling device\n", chip->pci->irq);
+ "disabling device\n", chip->irq_id);
if (do_disconnect)
snd_card_disconnect(chip->card);
return -1;
}
- chip->irq = chip->pci->irq;
- pci_intx(chip->pci, !chip->msi);
+ chip->irq = chip->irq_id;
+ if (chip->pci)
+ pci_intx(chip->pci, !chip->msi);
+
return 0;
}
@@ -2216,11 +2382,19 @@ static void azx_power_notify(struct hda_bus *bus)
break;
}
}
- if (power_on)
+ if (power_on) {
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+ azx_platform_enable_clocks(chip);
+#endif
azx_init_chip(chip, 1);
+ }
else if (chip->running && power_save_controller &&
- !bus->power_keep_link_on)
+ !bus->power_keep_link_on) {
azx_stop_chip(chip);
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+ azx_platform_disable_clocks(chip);
+#endif
+ }
}
#endif /* CONFIG_SND_HDA_POWER_SAVE */
@@ -2240,12 +2414,17 @@ static int snd_hda_codecs_inuse(struct hda_bus *bus)
return 0;
}
-static int azx_suspend(struct pci_dev *pci, pm_message_t state)
+static int azx_suspend(struct azx *chip, pm_message_t state)
{
- struct snd_card *card = pci_get_drvdata(pci);
- struct azx *chip = card->private_data;
+ struct snd_card *card = chip->card;
int i;
+#if defined(CONFIG_SND_HDA_PLATFORM_DRIVER) && \
+ defined(CONFIG_SND_HDA_POWER_SAVE)
+ if (!chip->platform_clk_enable)
+ azx_platform_enable_clocks(chip);
+#endif
+
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
azx_clear_irq_pending(chip);
for (i = 0; i < HDA_MAX_PCMS; i++)
@@ -2257,42 +2436,120 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state)
free_irq(chip->irq, chip);
chip->irq = -1;
}
- if (chip->msi)
- pci_disable_msi(chip->pci);
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, pci_choose_state(pci, state));
+
+ if (chip->pci) {
+ if (chip->msi)
+ pci_disable_msi(chip->pci);
+ pci_disable_device(chip->pci);
+ pci_save_state(chip->pci);
+ pci_set_power_state(chip->pci,
+ pci_choose_state(chip->pci, state));
+ }
+
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+ if (chip->pdev)
+ azx_platform_disable_clocks(chip);
+#endif
+
return 0;
}
-static int azx_resume(struct pci_dev *pci)
+static int azx_resume(struct azx *chip)
{
- struct snd_card *card = pci_get_drvdata(pci);
- struct azx *chip = card->private_data;
+ struct snd_card *card = chip->card;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "hda-intel: pci_enable_device failed, "
- "disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+ if (chip->pdev)
+ azx_platform_enable_clocks(chip);
+#endif
+
+ if (chip->pci) {
+ pci_set_power_state(chip->pci, PCI_D0);
+ pci_restore_state(chip->pci);
+ if (pci_enable_device(chip->pci) < 0) {
+ printk(KERN_ERR "hda-intel: pci_enable_device failed, "
+ "disabling device\n");
+ snd_card_disconnect(card);
+ return -EIO;
+ }
+ pci_set_master(chip->pci);
+ if (chip->msi)
+ if (pci_enable_msi(chip->pci) < 0)
+ chip->msi = 0;
}
- pci_set_master(pci);
- if (chip->msi)
- if (pci_enable_msi(pci) < 0)
- chip->msi = 0;
+
if (azx_acquire_irq(chip, 1) < 0)
return -EIO;
- azx_init_pci(chip);
+
+ if (chip->pci)
+ azx_init_pci(chip);
+
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+ if (chip->pdev)
+ azx_init_platform(chip);
+#endif
if (snd_hda_codecs_inuse(chip->bus))
azx_init_chip(chip, 1);
+#if defined(CONFIG_SND_HDA_PLATFORM_DRIVER) && \
+ defined(CONFIG_SND_HDA_POWER_SAVE)
+ else if (chip->driver_type == AZX_DRIVER_NVIDIA_TEGRA) {
+ struct hda_bus *bus = chip->bus;
+ struct hda_codec *c;
+
+ list_for_each_entry(c, &bus->codec_list, list) {
+ snd_hda_power_up(c);
+ snd_hda_power_down(c);
+ }
+ }
+#endif
snd_hda_resume(chip->bus);
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+
+#if defined(CONFIG_SND_HDA_PLATFORM_DRIVER) && \
+ defined(CONFIG_SND_HDA_POWER_SAVE)
+ if (chip->pdev)
+ azx_platform_disable_clocks(chip);
+#endif
+
return 0;
}
+
+static int azx_suspend_pci(struct pci_dev *pci, pm_message_t state)
+{
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct azx *chip = card->private_data;
+
+ return azx_suspend(chip, state);
+}
+
+static int azx_resume_pci(struct pci_dev *pci)
+{
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct azx *chip = card->private_data;
+
+ return azx_resume(chip);
+}
+
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+static int azx_suspend_platform(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct snd_card *card = dev_get_drvdata(&pdev->dev);
+ struct azx *chip = card->private_data;
+
+ return azx_suspend(chip, state);
+}
+
+static int azx_resume_platform(struct platform_device *pdev)
+{
+ struct snd_card *card = dev_get_drvdata(&pdev->dev);
+ struct azx *chip = card->private_data;
+
+ return azx_resume(chip);
+}
+#endif /* CONFIG_SND_HDA_PLATFORM_DRIVER */
#endif /* CONFIG_PM */
@@ -2302,8 +2559,22 @@ static int azx_resume(struct pci_dev *pci)
static int azx_halt(struct notifier_block *nb, unsigned long event, void *buf)
{
struct azx *chip = container_of(nb, struct azx, reboot_notifier);
+
+#if defined(CONFIG_SND_HDA_PLATFORM_DRIVER) && \
+ defined(CONFIG_SND_HDA_POWER_SAVE)
+ if (chip->pdev)
+ azx_platform_enable_clocks(chip);
+#endif
+
snd_hda_bus_reboot_notify(chip->bus);
azx_stop_chip(chip);
+
+#if defined(CONFIG_SND_HDA_PLATFORM_DRIVER) && \
+ defined(CONFIG_SND_HDA_POWER_SAVE)
+ if (chip->pdev)
+ azx_platform_disable_clocks(chip);
+#endif
+
return NOTIFY_OK;
}
@@ -2335,9 +2606,15 @@ static int azx_free(struct azx *chip)
azx_stop_chip(chip);
}
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+ azx_platform_disable_clocks(chip);
+ for (i = 0; i < chip->platform_clk_count; i++)
+ clk_put(chip->platform_clks[i]);
+#endif
+
if (chip->irq >= 0)
free_irq(chip->irq, (void*)chip);
- if (chip->msi)
+ if (chip->pci && chip->msi)
pci_disable_msi(chip->pci);
if (chip->remap_addr)
iounmap(chip->remap_addr);
@@ -2351,8 +2628,10 @@ static int azx_free(struct azx *chip)
snd_dma_free_pages(&chip->rb);
if (chip->posbuf.area)
snd_dma_free_pages(&chip->posbuf);
- pci_release_regions(chip->pci);
- pci_disable_device(chip->pci);
+ if (chip->pci) {
+ pci_release_regions(chip->pci);
+ pci_disable_device(chip->pci);
+ }
kfree(chip->azx_dev);
kfree(chip);
@@ -2397,13 +2676,15 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
return fix;
}
- q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
- if (q) {
- printk(KERN_INFO
- "hda_intel: position_fix set to %d "
- "for device %04x:%04x\n",
- q->value, q->subvendor, q->subdevice);
- return q->value;
+ if (chip->pci) {
+ q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
+ if (q) {
+ printk(KERN_INFO
+ "hda_intel: position_fix set to %d "
+ "for device %04x:%04x\n",
+ q->value, q->subvendor, q->subdevice);
+ return q->value;
+ }
}
/* Check VIA/ATI HD Audio Controller exist */
@@ -2445,7 +2726,7 @@ static void __devinit check_probe_mask(struct azx *chip, int dev)
const struct snd_pci_quirk *q;
chip->codec_probe_mask = probe_mask[dev];
- if (chip->codec_probe_mask == -1) {
+ if (chip->pci && (chip->codec_probe_mask == -1)) {
q = snd_pci_quirk_lookup(chip->pci, probe_mask_list);
if (q) {
printk(KERN_INFO
@@ -2481,6 +2762,12 @@ static void __devinit check_msi(struct azx *chip)
{
const struct snd_pci_quirk *q;
+ /* Disable MSI if chip is not a pci device */
+ if (!chip->pci) {
+ chip->msi = 0;
+ return;
+ }
+
if (enable_msi >= 0) {
chip->msi = !!enable_msi;
return;
@@ -2502,11 +2789,20 @@ static void __devinit check_msi(struct azx *chip)
}
}
+#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA
+static const char *tegra_clk_names[] __initdata = {
+ "hda",
+ "hda2codec",
+ "hda2hdmi",
+};
+static struct clk *tegra_clks[ARRAY_SIZE(tegra_clk_names)];
+#endif
/*
* constructor
*/
static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
+ struct platform_device *pdev,
int dev, unsigned int driver_caps,
struct azx **rchip)
{
@@ -2519,14 +2815,17 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
*rchip = NULL;
- err = pci_enable_device(pci);
- if (err < 0)
- return err;
+ if (pci) {
+ err = pci_enable_device(pci);
+ if (err < 0)
+ return err;
+ }
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (!chip) {
snd_printk(KERN_ERR SFX "cannot allocate chip\n");
- pci_disable_device(pci);
+ if (pci)
+ pci_disable_device(pci);
return -ENOMEM;
}
@@ -2534,6 +2833,9 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
mutex_init(&chip->open_mutex);
chip->card = card;
chip->pci = pci;
+ chip->pdev = pdev;
+ chip->dev = pci ? snd_dma_pci_data(pci) : &pdev->dev;
+ chip->irq_id = pci ? pci->irq : platform_get_irq(pdev, 0);
chip->irq = -1;
chip->driver_caps = driver_caps;
chip->driver_type = driver_caps & 0xff;
@@ -2569,38 +2871,105 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
}
#endif
- err = pci_request_regions(pci, "ICH HD audio");
- if (err < 0) {
- kfree(chip);
- pci_disable_device(pci);
- return err;
- }
+ if (chip->pci) {
+ err = pci_request_regions(pci, "ICH HD audio");
+ if (err < 0) {
+ kfree(chip);
+ pci_disable_device(pci);
+ return err;
+ }
- chip->addr = pci_resource_start(pci, 0);
- chip->remap_addr = pci_ioremap_bar(pci, 0);
- if (chip->remap_addr == NULL) {
- snd_printk(KERN_ERR SFX "ioremap error\n");
- err = -ENXIO;
- goto errout;
+ chip->addr = pci_resource_start(pci, 0);
+ chip->remap_addr = pci_ioremap_bar(pci, 0);
+ if (chip->remap_addr == NULL) {
+ snd_printk(KERN_ERR SFX "ioremap error\n");
+ err = -ENXIO;
+ goto errout;
+ }
+
+ if (chip->msi)
+ if (pci_enable_msi(pci) < 0)
+ chip->msi = 0;
}
- if (chip->msi)
- if (pci_enable_msi(pci) < 0)
- chip->msi = 0;
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+ if (chip->pdev) {
+ struct resource *res, *region;
+
+ /* Do platform specific initialization */
+ switch (chip->driver_type) {
+#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA
+ case AZX_DRIVER_NVIDIA_TEGRA:
+ chip->platform_clk_count = ARRAY_SIZE(tegra_clk_names);
+ for (i = 0; i < chip->platform_clk_count; i++) {
+ tegra_clks[i] = clk_get(&pdev->dev,
+ tegra_clk_names[i]);
+ if (IS_ERR_OR_NULL(tegra_clks[i])) {
+ err = PTR_ERR(tegra_clks[i]);
+ goto errout;
+ }
+ }
+ chip->platform_clks = tegra_clks;
+ break;
+#endif
+ default:
+ break;
+ }
+
+ azx_platform_enable_clocks(chip);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ err = EINVAL;
+ goto errout;
+ }
+
+ region = devm_request_mem_region(chip->dev, res->start,
+ resource_size(res),
+ pdev->name);
+ if (!region) {
+ snd_printk(KERN_ERR SFX "Mem region already claimed\n");
+ err = -EINVAL;
+ goto errout;
+ }
+
+ chip->addr = res->start;
+ chip->remap_addr = devm_ioremap(chip->dev,
+ res->start,
+ resource_size(res));
+ if (chip->remap_addr == NULL) {
+ snd_printk(KERN_ERR SFX "ioremap error\n");
+ err = -ENXIO;
+ goto errout;
+ }
+
+#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA
+ if (chip->driver_type == AZX_DRIVER_NVIDIA_TEGRA) {
+ chip->remap_config_addr = chip->remap_addr;
+ chip->remap_addr += NVIDIA_TEGRA_HDA_BAR0_OFFSET;
+ chip->addr += NVIDIA_TEGRA_HDA_BAR0_OFFSET;
+ }
+#endif
+
+ azx_init_platform(chip);
+ }
+#endif /* CONFIG_SND_HDA_PLATFORM_DRIVER */
if (azx_acquire_irq(chip, 0) < 0) {
err = -EBUSY;
goto errout;
}
- pci_set_master(pci);
+ if (chip->pci)
+ pci_set_master(pci);
+
synchronize_irq(chip->irq);
gcap = azx_readw(chip, GCAP);
snd_printdd(SFX "chipset global capabilities = 0x%x\n", gcap);
/* disable SB600 64bit support for safety */
- if (chip->pci->vendor == PCI_VENDOR_ID_ATI) {
+ if (chip->pci && chip->pci->vendor == PCI_VENDOR_ID_ATI) {
struct pci_dev *p_smbus;
p_smbus = pci_get_device(PCI_VENDOR_ID_ATI,
PCI_DEVICE_ID_ATI_SBX00_SMBUS,
@@ -2618,12 +2987,15 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
gcap &= ~ICH6_GCAP_64OK;
}
- /* allow 64bit DMA address if supported by H/W */
- if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
- pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64));
- else {
- pci_set_dma_mask(pci, DMA_BIT_MASK(32));
- pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32));
+ if (chip->pci) {
+ /* allow 64bit DMA address if supported by H/W */
+ if ((gcap & ICH6_GCAP_64OK) &&
+ !pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
+ pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64));
+ else {
+ pci_set_dma_mask(pci, DMA_BIT_MASK(32));
+ pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32));
+ }
}
/* read number of streams from GCAP register instead of using
@@ -2663,7 +3035,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
for (i = 0; i < chip->num_streams; i++) {
/* allocate memory for the BDL for each stream */
err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
- snd_dma_pci_data(chip->pci),
+ chip->dev,
BDL_SIZE, &chip->azx_dev[i].bdl);
if (err < 0) {
snd_printk(KERN_ERR SFX "cannot allocate BDL\n");
@@ -2672,7 +3044,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
}
/* allocate memory for the position buffer */
err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
- snd_dma_pci_data(chip->pci),
+ chip->dev,
chip->num_streams * 8, &chip->posbuf);
if (err < 0) {
snd_printk(KERN_ERR SFX "cannot allocate posbuf\n");
@@ -2687,7 +3059,8 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
azx_init_stream(chip);
/* initialize chip */
- azx_init_pci(chip);
+ if (chip->pci)
+ azx_init_pci(chip);
azx_init_chip(chip, (probe_only[dev] & 2) == 0);
/* codec detection */
@@ -2732,11 +3105,13 @@ static void power_down_all_codecs(struct azx *chip)
}
static int __devinit azx_probe(struct pci_dev *pci,
- const struct pci_device_id *pci_id)
+ struct platform_device *pdev,
+ int driver_data)
{
static int dev;
struct snd_card *card;
struct azx *chip;
+ struct device *azx_dev = pci ? &pci->dev : &pdev->dev;
int err;
if (dev >= SNDRV_CARDS)
@@ -2753,9 +3128,9 @@ static int __devinit azx_probe(struct pci_dev *pci,
}
/* set this here since it's referred in snd_hda_load_patch() */
- snd_card_set_dev(card, &pci->dev);
+ snd_card_set_dev(card, azx_dev);
- err = azx_create(card, pci, dev, pci_id->driver_data, &chip);
+ err = azx_create(card, pci, pdev, dev, driver_data, &chip);
if (err < 0)
goto out_free;
card->private_data = chip;
@@ -2797,7 +3172,11 @@ static int __devinit azx_probe(struct pci_dev *pci,
if (err < 0)
goto out_free;
- pci_set_drvdata(pci, card);
+ if (pci)
+ pci_set_drvdata(pci, card);
+ else
+ dev_set_drvdata(&pdev->dev, card);
+
chip->running = 1;
power_down_all_codecs(chip);
azx_notifier_register(chip);
@@ -2809,14 +3188,20 @@ out_free:
return err;
}
-static void __devexit azx_remove(struct pci_dev *pci)
+static int __devinit azx_probe_pci(struct pci_dev *pci,
+ const struct pci_device_id *pci_id)
+{
+ return azx_probe(pci, NULL, pci_id->driver_data);
+}
+
+static void __devexit azx_remove_pci(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
pci_set_drvdata(pci, NULL);
}
/* PCI IDs */
-static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
+static DEFINE_PCI_DEVICE_TABLE(azx_pci_ids) = {
/* CPT */
{ PCI_DEVICE(0x8086, 0x1c20),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP },
@@ -2934,27 +3319,85 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
.driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_HDMI },
{ 0, }
};
-MODULE_DEVICE_TABLE(pci, azx_ids);
+MODULE_DEVICE_TABLE(pci, azx_pci_ids);
/* pci_driver definition */
static struct pci_driver driver = {
.name = KBUILD_MODNAME,
- .id_table = azx_ids,
- .probe = azx_probe,
- .remove = __devexit_p(azx_remove),
+ .id_table = azx_pci_ids,
+ .probe = azx_probe_pci,
+ .remove = __devexit_p(azx_remove_pci),
#ifdef CONFIG_PM
- .suspend = azx_suspend,
- .resume = azx_resume,
+ .suspend = azx_suspend_pci,
+ .resume = azx_resume_pci,
#endif
};
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+static int __devinit azx_probe_platform(struct platform_device *pdev)
+{
+ const struct platform_device_id *pdev_id = platform_get_device_id(pdev);
+
+ return azx_probe(NULL, pdev, pdev_id->driver_data);
+}
+
+static int __devexit azx_remove_platform(struct platform_device *pdev)
+{
+ return snd_card_free(dev_get_drvdata(&pdev->dev));
+}
+
+static const struct platform_device_id azx_platform_ids[] = {
+#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA
+ { "tegra30-hda",
+ .driver_data = AZX_DRIVER_NVIDIA_TEGRA | AZX_DCAPS_RIRB_DELAY },
+#endif
+ { },
+};
+MODULE_DEVICE_TABLE(platform, azx_platform_ids);
+
+/* platform_driver definition */
+static struct platform_driver driver_platform = {
+ .driver = {
+ .name = "hda-platform"
+ },
+ .probe = azx_probe_platform,
+ .remove = __devexit_p(azx_remove_platform),
+ .id_table = azx_platform_ids,
+#ifdef CONFIG_PM
+ .suspend = azx_suspend_platform,
+ .resume = azx_resume_platform,
+#endif
+};
+#endif /* CONFIG_SND_HDA_PLATFORM_DRIVER */
+
static int __init alsa_card_azx_init(void)
{
- return pci_register_driver(&driver);
+ int err = 0;
+
+ err = pci_register_driver(&driver);
+ if (err < 0) {
+ snd_printk(KERN_ERR SFX "Failed to register pci driver\n");
+ return err;
+ }
+
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+ err = platform_driver_register(&driver_platform);
+ if (err < 0) {
+ snd_printk(KERN_ERR SFX "Failed to register platform driver\n");
+ pci_unregister_driver(&driver);
+ return err;
+ }
+#endif
+
+ return 0;
}
static void __exit alsa_card_azx_exit(void)
{
+#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER
+ platform_driver_unregister(&driver_platform);
+#endif
+
pci_unregister_driver(&driver);
}
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index e287015cbbb3..b03efbc17132 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -34,6 +34,11 @@
#include <linux/moduleparam.h>
#include <sound/core.h>
#include <sound/jack.h>
+
+#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA
+#include <mach/hdmi-audio.h>
+#endif
+
#include "hda_codec.h"
#include "hda_local.h"
@@ -865,6 +870,34 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
hinfo->formats = per_cvt->formats;
hinfo->maxbps = per_cvt->maxbps;
+#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA
+ if ((codec->preset->id == 0x10de0020) &&
+ (!eld->eld_valid || !eld->sad_count)) {
+ int err = 0;
+ unsigned long timeout;
+
+ if (!eld->eld_valid) {
+ err = tegra_hdmi_setup_hda_presence();
+ if (err < 0) {
+ snd_printk(KERN_WARNING
+ "HDMI: No HDMI device connected\n");
+ return -ENODEV;
+ }
+ }
+
+ timeout = jiffies + msecs_to_jiffies(5000);
+ for (;;) {
+ if (eld->eld_valid && eld->sad_count)
+ break;
+
+ if (time_after(jiffies, timeout))
+ break;
+
+ mdelay(10);
+ }
+ }
+#endif
+
/* Restrict capabilities by ELD if this isn't disabled */
if (!static_hdmi_pcm && eld->eld_valid) {
snd_hdmi_eld_update_pcm_info(eld, hinfo);
@@ -1057,8 +1090,8 @@ static int hdmi_parse_codec(struct hda_codec *codec)
* HDA link is powered off at hot plug or hw initialization time.
*/
#ifdef CONFIG_SND_HDA_POWER_SAVE
- if (!(snd_hda_param_read(codec, codec->afg, AC_PAR_POWER_STATE) &
- AC_PWRST_EPSS))
+ if ((!(snd_hda_param_read(codec, codec->afg, AC_PAR_POWER_STATE) &
+ AC_PWRST_EPSS)) && (codec->preset->id != 0x10de0020))
codec->bus->power_keep_link_on = 1;
#endif
@@ -1089,6 +1122,21 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
int pin_idx = hinfo_to_pin_index(spec, hinfo);
hda_nid_t pin_nid = spec->pins[pin_idx].pin_nid;
+#if defined(CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA) && defined(CONFIG_TEGRA_DC)
+ if (codec->preset->id == 0x10de0020) {
+ int err = 0;
+ /* Set hdmi:audio freq and source selection*/
+ err = tegra_hdmi_setup_audio_freq_source(
+ substream->runtime->rate, HDA);
+ if ( err < 0 ) {
+ snd_printk(KERN_ERR
+ "Unable to set hdmi audio freq to %d \n",
+ substream->runtime->rate);
+ return err;
+ }
+ }
+#endif
+
hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels);
hdmi_setup_audio_infoframe(codec, pin_idx, substream);
@@ -1189,6 +1237,14 @@ static int generic_hdmi_init(struct hda_codec *codec)
struct hdmi_spec *spec = codec->spec;
int pin_idx;
+ switch (codec->preset->id) {
+ case 0x10de0020:
+ snd_hda_codec_write(codec, 4, 0,
+ AC_VERB_SET_DIGI_CONVERT_1, 0x11);
+ default:
+ break;
+ }
+
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
hda_nid_t pin_nid = per_pin->pin_nid;
@@ -1803,6 +1859,7 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = {
{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_generic_hdmi },
{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_generic_hdmi },
{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_generic_hdmi },
+{ .id = 0x10de0020, .name = "Tegra30 HDMI", .patch = patch_generic_hdmi },
{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_generic_hdmi },
{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_generic_hdmi },
{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_generic_hdmi },
@@ -1848,6 +1905,7 @@ MODULE_ALIAS("snd-hda-codec-id:10de0019");
MODULE_ALIAS("snd-hda-codec-id:10de001a");
MODULE_ALIAS("snd-hda-codec-id:10de001b");
MODULE_ALIAS("snd-hda-codec-id:10de001c");
+MODULE_ALIAS("snd-hda-codec-id:10de0020");
MODULE_ALIAS("snd-hda-codec-id:10de0040");
MODULE_ALIAS("snd-hda-codec-id:10de0041");
MODULE_ALIAS("snd-hda-codec-id:10de0042");