diff options
Diffstat (limited to 'sound/pci/hda')
-rw-r--r-- | sound/pci/hda/Kconfig | 14 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 3 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.c | 613 | ||||
-rw-r--r-- | sound/pci/hda/patch_hdmi.c | 62 |
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"); |