diff options
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/hda/Kconfig | 21 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.c | 70 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 5 | ||||
-rw-r--r-- | sound/pci/hda/hda_eld.c | 124 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.c | 857 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 3 | ||||
-rw-r--r-- | sound/pci/hda/patch_hdmi.c | 176 |
7 files changed, 1094 insertions, 162 deletions
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 80a7d44bcf81..ae3135050ef0 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -86,6 +86,27 @@ 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_VPR + bool "Allocate PCM DMA buffer in video protected region" + depends on ARCH_TEGRA_11x_SOC && SND_HDA_PLATFORM_NVIDIA_TEGRA + depends on TEGRA_NVMAP + help + Say Y here to allocate PCM DMA buffer in video protected region + config SND_HDA_CODEC_REALTEK bool "Build Realtek HD-audio codec support" default y diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index aeefec74a061..8f212c6eecb8 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -843,7 +843,7 @@ int snd_hda_bus_new(struct snd_card *card, snprintf(bus->workq_name, sizeof(bus->workq_name), "hd-audio%d", card->number); - bus->workq = create_singlethread_workqueue(bus->workq_name); + bus->workq = create_freezable_workqueue(bus->workq_name); if (!bus->workq) { snd_printk(KERN_ERR "cannot create workqueue %s\n", bus->workq_name); @@ -1424,9 +1424,11 @@ int snd_hda_codec_new(struct hda_bus *bus, #ifdef CONFIG_PM codec->d3_stop_clk = snd_hda_codec_get_supported_ps(codec, fg, AC_PWRST_CLKSTOP); +#ifndef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA if (!codec->d3_stop_clk) bus->power_keep_link_on = 1; #endif +#endif codec->epss = snd_hda_codec_get_supported_ps(codec, fg, AC_PWRST_EPSS); @@ -3267,6 +3269,44 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol, return change; } +int snd_hda_max_pcm_ch_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 0xFFFFFFFF; + return 0; +} + +int snd_hda_hdmi_decode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 0xFFFFFFFF; + return 0; +} + +static int snd_hda_max_pcm_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = codec->max_pcm_channels; + return 0; +} + +static int snd_hda_hdmi_decode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = codec->recv_dec_cap; + return 0; +} + static struct snd_kcontrol_new dig_mixes[] = { { .access = SNDRV_CTL_ELEM_ACCESS_READ, @@ -3296,6 +3336,18 @@ static struct snd_kcontrol_new dig_mixes[] = { .get = snd_hda_spdif_out_switch_get, .put = snd_hda_spdif_out_switch_put, }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "HDA Decode Capability", + .info = snd_hda_hdmi_decode_info, + .get = snd_hda_hdmi_decode_get, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "HDA Maximum PCM Channels", + .info = snd_hda_max_pcm_ch_info, + .get = snd_hda_max_pcm_ch_get, + }, { } /* end */ }; @@ -3772,7 +3824,7 @@ static unsigned int hda_sync_power_state(struct hda_codec *codec, if (time_after_eq(jiffies, end_time)) break; /* wait until the codec reachs to the target state */ - msleep(1); + mdelay(1); } return state; } @@ -3892,6 +3944,9 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec, bool in_wq) codec->power_jiffies = jiffies; spin_unlock(&codec->power_lock); codec->in_pm = 0; +#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA + state |= AC_PWRST_CLK_STOP_OK; +#endif return state; } @@ -5512,11 +5567,18 @@ EXPORT_SYMBOL_HDA(snd_hda_add_imux_item); int snd_hda_suspend(struct hda_bus *bus) { struct hda_codec *codec; + unsigned int state; list_for_each_entry(codec, &bus->codec_list, list) { cancel_delayed_work_sync(&codec->jackpoll_work); - if (hda_codec_is_power_on(codec)) - hda_call_codec_suspend(codec, false); + if (hda_codec_is_power_on(codec)) { + state = hda_call_codec_suspend(codec, false); + codec->pm_down_notified = 0; + if (!bus->power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK)) { + codec->pm_down_notified = 1; + hda_call_pm_notify(bus, false); + } + } } return 0; } diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index c93f9021f452..d2f1953e0363 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> @@ -632,6 +634,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; @@ -902,6 +905,8 @@ struct hda_codec { unsigned int (*power_filter)(struct hda_codec *codec, hda_nid_t nid, unsigned int power_state); + unsigned int recv_dec_cap; + unsigned int max_pcm_channels; /* codec-specific additional proc output */ void (*proc_widget_hook)(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid); diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index d0d7ac1e99d2..daa8f5cc6b7b 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -157,6 +157,22 @@ static unsigned int hdmi_get_eld_data(struct hda_codec *codec, hda_nid_t nid, return val; } +static unsigned char hdmi_get_eld_byte(struct hda_codec *codec, hda_nid_t nid, + int byte_index) +{ + unsigned int val; + + val = hdmi_get_eld_data(codec, nid, byte_index); + + if ((val & AC_ELDD_ELD_VALID) == 0) { + snd_printd(KERN_INFO "HDMI: invalid ELD data byte %d\n", + byte_index); + val = 0; + } + + return val & AC_ELDD_ELD_DATA; +} + #define GRAB_BITS(buf, byte, lowbit, bits) \ ({ \ BUILD_BUG_ON(lowbit > 7); \ @@ -310,6 +326,108 @@ out_fail: return -EINVAL; } +#define GET_BITS(val, lowbit, bits) \ +({ \ + BUILD_BUG_ON(lowbit > 7); \ + BUILD_BUG_ON(bits > 8); \ + BUILD_BUG_ON(bits <= 0); \ + \ + (val >> (lowbit)) & ((1 << (bits)) - 1); \ +}) + +/* update ELD information relevant for getting PCM info */ +int hdmi_update_lpcm_sad_eld (struct hda_codec *codec, hda_nid_t nid, + struct hdmi_eld *e) +{ + int i, j; + u32 val, sad_base; + int size; + struct cea_sad *a; + + size = snd_hdmi_get_eld_size(codec, nid); + if (size == 0) { + /* wfg: workaround for ASUS P5E-VM HDMI board */ + snd_printd(KERN_INFO "HDMI: ELD buf size is 0, force 128\n"); + size = 128; + } + if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) { + snd_printd(KERN_INFO "HDMI: invalid ELD buf size %d\n", size); + return -ERANGE; + } + + val = hdmi_get_eld_byte(codec, nid, 0); + e->info.eld_ver = GET_BITS(val, 3, 5); + if (e->info.eld_ver != ELD_VER_CEA_861D && + e->info.eld_ver != ELD_VER_PARTIAL) { + snd_printd(KERN_INFO "HDMI: Unknown ELD version %d\n", + e->info.eld_ver); + goto out_fail; + } + + val = hdmi_get_eld_byte(codec, nid, 4); + sad_base = GET_BITS(val, 0, 5); + sad_base += ELD_FIXED_BYTES; + + val = hdmi_get_eld_byte(codec, nid, 5); + e->info.sad_count = GET_BITS(val, 4, 4); + + for (i = 0; i < e->info.sad_count; i++, sad_base += 3) { + if ((sad_base + 3) > size) { + snd_printd(KERN_INFO "HDMI: out of range SAD %d\n", i); + goto out_fail; + } + a = &e->info.sad[i]; + + val = hdmi_get_eld_byte(codec, nid, sad_base); + a->format = GET_BITS(val, 3, 4); + a->channels = GET_BITS(val, 0, 3); + a->channels++; + + a->rates = 0; + a->sample_bits = 0; + a->max_bitrate = 0; + + if (a->format != AUDIO_CODING_TYPE_LPCM) + continue; + + val = hdmi_get_eld_byte(codec, nid, sad_base + 1); + val = GET_BITS(val, 0, 7); + for (j = 0; j < 7; j++) + if (val & (1 << j)) + a->rates |= cea_sampling_frequencies[j + 1]; + + val = hdmi_get_eld_byte(codec, nid, sad_base + 2); + val = GET_BITS(val, 0, 3); + for (j = 0; j < 3; j++) + if (val & (1 << j)) + a->sample_bits |= cea_sample_sizes[j + 1]; + } + + e->info.lpcm_sad_ready = 1; + + codec->recv_dec_cap = 0; + codec->max_pcm_channels = 0; + for (i = 0; i < e->info.sad_count; i++) { + if (e->info.sad[i].format == AUDIO_CODING_TYPE_AC3) { + codec->recv_dec_cap |= (1 << AUDIO_CODING_TYPE_AC3); + } else if (e->info.sad[i].format == AUDIO_CODING_TYPE_DTS) { + codec->recv_dec_cap |= (1 << AUDIO_CODING_TYPE_DTS); + } else if (e->info.sad[i].format == AUDIO_CODING_TYPE_EAC3) { + codec->recv_dec_cap |= (1 << AUDIO_CODING_TYPE_EAC3); + } else if (e->info.sad[i].format == AUDIO_CODING_TYPE_LPCM) { + codec->max_pcm_channels = + e->info.sad[i].channels > codec->max_pcm_channels ? + e->info.sad[i].channels : codec->max_pcm_channels; + } + } + + return 0; + +out_fail: + e->info.eld_ver = 0; + return -EINVAL; +} + int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) { return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, @@ -339,6 +457,7 @@ int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid, return -ERANGE; } + /* set ELD buffer */ for (i = 0; i < size; i++) { unsigned int val = hdmi_get_eld_data(codec, nid, i); @@ -368,6 +487,7 @@ int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid, } *eld_size = size; + error: return ret; } @@ -649,9 +769,9 @@ void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e, for (i = 0; i < e->sad_count; i++) { struct cea_sad *a = &e->sad[i]; rates |= a->rates; - if (a->channels > channels_max) - channels_max = a->channels; if (a->format == AUDIO_CODING_TYPE_LPCM) { + if (a->channels > channels_max) + channels_max = a->channels; if (a->sample_bits & AC_SUPPCM_BITS_20) { formats |= SNDRV_PCM_FMTBIT_S32_LE; if (maxbps < 20) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 5f055d7ee85b..30e7fd27471e 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -31,7 +31,7 @@ * CHANGES: * * 2004.12.01 Major rewrite by tiwai, merged the work of pshou - * + * */ #include <linux/delay.h> @@ -50,6 +50,7 @@ #include <linux/clocksource.h> #include <linux/time.h> #include <linux/completion.h> +#include <linux/clk.h> #ifdef CONFIG_X86 /* for snoop control */ @@ -63,6 +64,13 @@ #include <linux/firmware.h> #include "hda_codec.h" +#ifdef CONFIG_SND_HDA_VPR +#include <linux/nvmap.h> +#endif +#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA +#include <linux/tegra-powergate.h> +#include <mach/pm_domains.h> +#endif static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; @@ -195,7 +203,8 @@ MODULE_DESCRIPTION("Intel HDA driver"); #define SFX "hda-intel " #endif -#if defined(CONFIG_PM) && defined(CONFIG_VGA_SWITCHEROO) +#if defined(CONFIG_PM) && defined(CONFIG_VGA_SWITCHEROO) && \ + !defined(CONFIG_SND_HDA_PLATFORM_DRIVER) #ifdef CONFIG_SND_HDA_CODEC_HDMI #define SUPPORT_VGA_SWITCHEROO #endif @@ -371,6 +380,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) @@ -470,6 +505,9 @@ struct azx_pcm { 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 */ @@ -484,8 +522,26 @@ 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 + +#ifdef CONFIG_SND_HDA_VPR + struct dma_buf *dmabuf; + struct dma_buf_attachment *attach; + struct sg_table *sgt; + unsigned char *vaddr; + phys_addr_t paddr; +#endif + /* locks */ spinlock_t reg_lock; struct mutex open_mutex; @@ -567,6 +623,7 @@ enum { AZX_DRIVER_SIS, AZX_DRIVER_ULI, AZX_DRIVER_NVIDIA, + AZX_DRIVER_NVIDIA_TEGRA, AZX_DRIVER_TERA, AZX_DRIVER_CTX, AZX_DRIVER_CTHDA, @@ -615,7 +672,7 @@ enum { /* quirks for Nvidia */ #define AZX_DCAPS_PRESET_NVIDIA \ (AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI |\ - AZX_DCAPS_ALIGN_BUFSIZE | AZX_DCAPS_NO_64BIT) + AZX_DCAPS_ALIGN_BUFSIZE | AZX_DCAPS_NO_64BIT | AZX_DCAPS_PM_RUNTIME) #define AZX_DCAPS_PRESET_CTHDA \ (AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_4K_BDLE_BOUNDARY) @@ -640,6 +697,7 @@ static char *driver_short_names[] = { [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_CTHDA] = "HDA Creative", @@ -649,6 +707,48 @@ static char *driver_short_names[] = { /* * 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) \ @@ -675,6 +775,8 @@ static char *driver_short_names[] = { #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) @@ -733,6 +835,14 @@ static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev, static int azx_acquire_irq(struct azx *chip, int do_disconnect); static int azx_send_cmd(struct hda_bus *bus, unsigned int val); +static inline const char *azx_name(const struct azx *chip) +{ + if (chip->pci) + return pci_name(chip->pci); + else /* for platform bus based devices */ + return dev_name(&chip->pdev->dev); +} + /* * Interface for HD codec */ @@ -746,10 +856,10 @@ 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 "%s: cannot allocate CORB/RIRB\n", pci_name(chip->pci)); + snd_printk(KERN_ERR SFX "%s: cannot allocate CORB/RIRB\n", azx_name(chip)); return err; } mark_pages_wc(chip, &chip->rb, true); @@ -900,7 +1010,7 @@ static void azx_update_rirb(struct azx *chip) } else snd_printk(KERN_ERR SFX "%s: spurious response %#x:%#x, " "last cmd=%#08x\n", - pci_name(chip->pci), + azx_name(chip), res, res_ex, chip->last_cmd[addr]); } @@ -945,7 +1055,7 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, if (!chip->polling_mode && chip->poll_count < 2) { snd_printdd(SFX "%s: azx_get_response timeout, " "polling the codec once: last cmd=0x%08x\n", - pci_name(chip->pci), chip->last_cmd[addr]); + azx_name(chip), chip->last_cmd[addr]); do_poll = 1; chip->poll_count++; goto again; @@ -955,7 +1065,7 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, if (!chip->polling_mode) { snd_printk(KERN_WARNING SFX "%s: azx_get_response timeout, " "switching to polling mode: last cmd=0x%08x\n", - pci_name(chip->pci), chip->last_cmd[addr]); + azx_name(chip), chip->last_cmd[addr]); chip->polling_mode = 1; goto again; } @@ -963,7 +1073,7 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, if (chip->msi) { snd_printk(KERN_WARNING SFX "%s: No response from codec, " "disabling MSI: last cmd=0x%08x\n", - pci_name(chip->pci), chip->last_cmd[addr]); + azx_name(chip), chip->last_cmd[addr]); free_irq(chip->irq, chip); chip->irq = -1; pci_disable_msi(chip->pci); @@ -1030,7 +1140,7 @@ static int azx_single_wait_for_response(struct azx *chip, unsigned int addr) } if (printk_ratelimit()) snd_printd(SFX "%s: get_response timeout: IRS=0x%x\n", - pci_name(chip->pci), azx_readw(chip, IRS)); + azx_name(chip), azx_readw(chip, IRS)); chip->rirb.res[addr] = -1; return -EIO; } @@ -1058,7 +1168,7 @@ static int azx_single_send_cmd(struct hda_bus *bus, u32 val) } if (printk_ratelimit()) snd_printd(SFX "%s: send_cmd timeout: IRS=0x%x, val=0x%x\n", - pci_name(chip->pci), azx_readw(chip, IRS), val); + azx_name(chip), azx_readw(chip, IRS), val); return -EIO; } @@ -1081,14 +1191,20 @@ static unsigned int azx_single_get_response(struct hda_bus *bus, static int azx_send_cmd(struct hda_bus *bus, unsigned int val) { struct azx *chip = bus->private_data; + unsigned int ret = 0; if (chip->disabled) return 0; + + pm_runtime_get_sync(chip->dev); chip->last_cmd[azx_command_addr(val)] = val; if (chip->single_cmd) - return azx_single_send_cmd(bus, val); + ret = azx_single_send_cmd(bus, val); else - return azx_corb_send_cmd(bus, val); + ret = azx_corb_send_cmd(bus, val); + pm_runtime_put(chip->dev); + + return ret; } /* get a response */ @@ -1096,12 +1212,17 @@ static unsigned int azx_get_response(struct hda_bus *bus, unsigned int addr) { struct azx *chip = bus->private_data; + unsigned int ret = 0; if (chip->disabled) - return 0; + return ret; + pm_runtime_get_sync(chip->dev); if (chip->single_cmd) - return azx_single_get_response(bus, addr); + ret = azx_single_get_response(bus, addr); else - return azx_rirb_get_response(bus, addr); + ret = azx_rirb_get_response(bus, addr); + pm_runtime_put(chip->dev); + + return ret; } #ifdef CONFIG_PM @@ -1155,7 +1276,7 @@ static int azx_reset(struct azx *chip, int full_reset) __skip: /* check to see if controller is ready */ if (!azx_readb(chip, GCTL)) { - snd_printd(SFX "%s: azx_reset: controller not ready!\n", pci_name(chip->pci)); + snd_printd(SFX "%s: azx_reset: controller not ready!\n", azx_name(chip)); return -EBUSY; } @@ -1167,7 +1288,7 @@ static int azx_reset(struct azx *chip, int full_reset) /* detect codecs */ if (!chip->codec_mask) { chip->codec_mask = azx_readw(chip, STATESTS); - snd_printdd(SFX "%s: codec_mask = 0x%x\n", pci_name(chip->pci), chip->codec_mask); + snd_printdd(SFX "%s: codec_mask = 0x%x\n", azx_name(chip), chip->codec_mask); } return 0; @@ -1176,7 +1297,7 @@ static int azx_reset(struct azx *chip, int full_reset) /* * Lowlevel interface - */ + */ /* enable interrupts */ static void azx_int_enable(struct azx *chip) @@ -1311,7 +1432,7 @@ static void azx_init_pci(struct azx *chip) * The PCI register TCSEL is defined in the Intel manuals. */ if (!(chip->driver_caps & AZX_DCAPS_NO_TCSEL)) { - snd_printdd(SFX "%s: Clearing TCSEL\n", pci_name(chip->pci)); + snd_printdd(SFX "%s: Clearing TCSEL\n", azx_name(chip)); update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0); } @@ -1319,7 +1440,7 @@ static void azx_init_pci(struct azx *chip) * we need to enable snoop. */ if (chip->driver_caps & AZX_DCAPS_ATI_SNOOP) { - snd_printdd(SFX "%s: Setting ATI snoop: %d\n", pci_name(chip->pci), azx_snoop(chip)); + snd_printdd(SFX "%s: Setting ATI snoop: %d\n", azx_name(chip), azx_snoop(chip)); update_pci_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 0x07, azx_snoop(chip) ? ATI_SB450_HDAUDIO_ENABLE_SNOOP : 0); @@ -1327,7 +1448,7 @@ static void azx_init_pci(struct azx *chip) /* For NVIDIA HDA, enable snoop */ if (chip->driver_caps & AZX_DCAPS_NVIDIA_SNOOP) { - snd_printdd(SFX "%s: Setting Nvidia snoop: %d\n", pci_name(chip->pci), azx_snoop(chip)); + snd_printdd(SFX "%s: Setting Nvidia snoop: %d\n", azx_name(chip), azx_snoop(chip)); update_pci_byte(chip->pci, NVIDIA_HDA_TRANSREG_ADDR, 0x0f, NVIDIA_HDA_ENABLE_COHBITS); @@ -1353,11 +1474,115 @@ static void azx_init_pci(struct azx *chip) INTEL_SCH_HDA_DEVC, &snoop); } snd_printdd(SFX "%s: SCH snoop: %s\n", - pci_name(chip->pci), (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) + azx_name(chip), (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) ? "Disabled" : "Enabled"); } } +#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; + +#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA + tegra_unpowergate_partition(TEGRA_POWERGATE_DISB); +#endif + + for (i = 0; i < chip->platform_clk_count; i++) + clk_enable(chip->platform_clks[i]); + + chip->platform_clk_enable++; + +} + +static void azx_platform_enable_clocks(struct azx *chip) +{ +#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA + pm_runtime_get_sync(chip->dev); +#endif + __azx_platform_enable_clocks(chip); +} + +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]); + +#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA + tegra_powergate_partition(TEGRA_POWERGATE_DISB); +#endif + + chip->platform_clk_enable--; +} + +static void azx_platform_disable_clocks(struct azx *chip) +{ + __azx_platform_disable_clocks(chip); +#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA + pm_runtime_put(chip->dev); +#endif +} + +#endif /* CONFIG_SND_HDA_PLATFORM_DRIVER */ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev); @@ -1373,7 +1598,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) int i, ok; #ifdef CONFIG_PM_RUNTIME - if (chip->pci->dev.power.runtime_status != RPM_ACTIVE) + if (chip->dev->power.runtime_status != RPM_ACTIVE) return IRQ_NONE; #endif @@ -1389,7 +1614,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) spin_unlock(&chip->reg_lock); return IRQ_NONE; } - + for (i = 0; i < chip->num_streams; i++) { azx_dev = &chip->azx_dev[i]; if (status & azx_dev->sd_int_sta_mask) { @@ -1431,7 +1656,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) azx_writeb(chip, STATESTS, 0x04); #endif spin_unlock(&chip->reg_lock); - + return IRQ_HANDLED; } @@ -1514,7 +1739,7 @@ static int azx_setup_periods(struct azx *chip, pos_adj = frames_to_bytes(runtime, pos_adj); if (pos_adj >= period_bytes) { snd_printk(KERN_WARNING SFX "%s: Too big adjustment %d\n", - pci_name(chip->pci), bdl_pos_adj[chip->dev_index]); + azx_name(chip), bdl_pos_adj[chip->dev_index]); pos_adj = 0; } else { ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream), @@ -1542,7 +1767,7 @@ static int azx_setup_periods(struct azx *chip, error: snd_printk(KERN_ERR SFX "%s: Too many BDL entries: buffer=%d, period=%d\n", - pci_name(chip->pci), azx_dev->bufsize, period_bytes); + azx_name(chip), azx_dev->bufsize, period_bytes); return -EINVAL; } @@ -1639,7 +1864,7 @@ static int probe_codec(struct azx *chip, int addr) mutex_unlock(&chip->bus->cmd_mutex); if (res == -1) return -EIO; - snd_printdd(SFX "%s: codec #%d probed OK\n", pci_name(chip->pci), addr); + snd_printdd(SFX "%s: codec #%d probed OK\n", azx_name(chip), addr); return 0; } @@ -1702,6 +1927,7 @@ static int 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; @@ -1721,7 +1947,7 @@ static int azx_codec_create(struct azx *chip, const char *model) return err; if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) { - snd_printd(SFX "%s: Enable delay in RIRB handling\n", pci_name(chip->pci)); + snd_printd(SFX "%s: Enable delay in RIRB handling\n", azx_name(chip)); chip->bus->needs_damn_long_delay = 1; } @@ -1739,7 +1965,7 @@ static int azx_codec_create(struct azx *chip, const char *model) */ snd_printk(KERN_WARNING SFX "%s: Codec #%d probe error; " - "disabling it...\n", pci_name(chip->pci), c); + "disabling it...\n", azx_name(chip), c); chip->codec_mask &= ~(1 << c); /* More badly, accessing to a non-existing * codec often screws up the controller chip, @@ -1760,7 +1986,7 @@ static int azx_codec_create(struct azx *chip, const char *model) */ if (chip->driver_caps & AZX_DCAPS_SYNC_WRITE) { snd_printd(SFX "%s: Enable sync_write for stable communication\n", - pci_name(chip->pci)); + azx_name(chip)); chip->bus->sync_write = 1; chip->bus->allow_bus_reset = 1; } @@ -1778,7 +2004,7 @@ static int azx_codec_create(struct azx *chip, const char *model) } } if (!codecs) { - snd_printk(KERN_ERR SFX "%s: no codecs initialized\n", pci_name(chip->pci)); + snd_printk(KERN_ERR SFX "%s: no codecs initialized\n", azx_name(chip)); return -ENXIO; } return 0; @@ -2137,7 +2363,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) if (!format_val) { snd_printk(KERN_ERR SFX "%s: invalid format_val, rate=%d, ch=%d, format=%d\n", - pci_name(chip->pci), runtime->rate, runtime->channels, runtime->format); + azx_name(chip), runtime->rate, runtime->channels, runtime->format); err = -EINVAL; goto unlock; } @@ -2146,7 +2372,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) period_bytes = snd_pcm_lib_period_bytes(substream); snd_printdd(SFX "%s: azx_pcm_prepare: bufsize=0x%x, format=0x%x\n", - pci_name(chip->pci), bufsize, format_val); + azx_name(chip), bufsize, format_val); if (bufsize != azx_dev->bufsize || period_bytes != azx_dev->period_bytes || @@ -2419,7 +2645,7 @@ static unsigned int azx_get_position(struct azx *chip, snd_printk(KERN_WARNING SFX "%s: Unstable LPIB (%d >= %d); " "disabling LPIB delay counting\n", - pci_name(chip->pci), delay, azx_dev->period_bytes); + azx_name(chip), delay, azx_dev->period_bytes); delay = 0; chip->driver_caps &= ~AZX_DCAPS_COUNT_LPIB_DELAY; } @@ -2584,7 +2810,7 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, list_for_each_entry(apcm, &chip->pcm_list, list) { if (apcm->pcm->device == pcm_dev) { snd_printk(KERN_ERR SFX "%s: PCM %d already exists\n", - pci_name(chip->pci), pcm_dev); + azx_name(chip), pcm_dev); return -EBUSY; } } @@ -2616,9 +2842,61 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024; if (size > MAX_PREALLOC_SIZE) size = MAX_PREALLOC_SIZE; +#ifdef CONFIG_SND_HDA_VPR + for (s = 0; s < 2; s++) { + struct snd_pcm_substream *substream; + for (substream = pcm->streams[s].substream; + substream; substream = substream->next) { + chip->dmabuf = nvmap_alloc_dmabuf(size, 32, + NVMAP_HANDLE_WRITE_COMBINE, NVMAP_HEAP_CARVEOUT_VPR); + if (IS_ERR(chip->dmabuf)) { + err = (int)chip->dmabuf; + goto dmabuf_fail; + } + chip->vaddr = dma_buf_vmap(chip->dmabuf); + if (!chip->vaddr) { + err = -ENOMEM; + goto vmap_fail; + } + chip->attach = dma_buf_attach(chip->dmabuf, chip->dev); + if (IS_ERR(chip->attach)) { + err = (int)chip->attach; + goto attach_fail; + } + chip->sgt = dma_buf_map_attachment(chip->attach, + DMA_BIDIRECTIONAL); + if (IS_ERR(chip->sgt)) { + err = (int)chip->sgt; + goto sgt_fail; + } + chip->paddr = sg_dma_address(chip->sgt->sgl); + snd_printk(KERN_DEBUG SFX + "paddr=%08llx vaddr=%p\n", chip->paddr, chip->vaddr); + substream->dma_buffer.area = chip->vaddr; + substream->dma_buffer.addr = chip->paddr; + substream->dma_buffer.bytes = size; + substream->dma_buffer.dev.dev = chip->dev; + if (substream->dma_buffer.bytes > 0) + substream->buffer_bytes_max = + substream->dma_buffer.bytes; + substream->dma_max = MAX_PREALLOC_SIZE; + continue; +sgt_fail: + dma_buf_detach(chip->dmabuf, chip->attach); +attach_fail: + dma_buf_vunmap(chip->dmabuf, chip->vaddr); +vmap_fail: + dma_buf_put(chip->dmabuf); +dmabuf_fail: + chip->dmabuf = NULL; + return err; + } + } +#else 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); +#endif return 0; } @@ -2659,17 +2937,19 @@ static int 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; } @@ -2682,6 +2962,7 @@ static void azx_stop_chip(struct azx *chip) /* disable interrupts */ azx_int_disable(chip); azx_int_clear(chip); + synchronize_irq(chip->irq_id); /* disable CORB/RIRB */ azx_free_cmd_io(chip); @@ -2822,9 +3103,10 @@ static void azx_power_notify(struct hda_bus *bus, bool power_up) return; if (power_up) - pm_runtime_get_sync(&chip->pci->dev); + pm_runtime_get_sync(chip->dev); else - pm_runtime_put_sync(&chip->pci->dev); + pm_runtime_put_sync(chip->dev); + } static DEFINE_MUTEX(card_list_lock); @@ -2876,7 +3158,6 @@ static int param_set_xint(const char *val, const struct kernel_param *kp) */ static int azx_suspend(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct azx *chip = card->private_data; struct azx_pcm *p; @@ -2884,6 +3165,11 @@ static int azx_suspend(struct device *dev) if (chip->disabled) return 0; +#if defined(CONFIG_SND_HDA_PLATFORM_DRIVER) + if (chip->pdev) + __azx_platform_enable_clocks(chip); +#endif + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); azx_clear_irq_pending(chip); list_for_each_entry(p, &chip->pcm_list, list) @@ -2895,43 +3181,82 @@ static int azx_suspend(struct device *dev) 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_D3hot); + + if (chip->pci) { + struct pci_dev *pci = to_pci_dev(dev); + + if (chip->msi) + pci_disable_msi(chip->pci); + pci_disable_device(pci); + pci_save_state(pci); + pci_set_power_state(pci, PCI_D3hot); + } + +#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER + if (chip->pdev) { + /* Disable all clk references */ + while (chip->platform_clk_enable) + __azx_platform_disable_clocks(chip); + } +#endif + return 0; } static int azx_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct azx *chip = card->private_data; if (chip->disabled) return 0; - 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; + } else if (chip->pdev) { + pm_runtime_disable(chip->dev); + pm_runtime_set_active(chip->dev); + pm_runtime_get_noresume(chip->dev); + pm_runtime_enable(chip->dev); } - 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 azx_init_chip(chip, 1); snd_hda_resume(chip->bus); snd_power_change_state(card, SNDRV_CTL_POWER_D0); + +#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER + if (chip->pdev) + pm_runtime_put(chip->dev); +#endif + return 0; } #endif /* CONFIG_PM_SLEEP || SUPPORT_VGA_SWITCHEROO */ @@ -2942,8 +3267,18 @@ static int azx_runtime_suspend(struct device *dev) struct snd_card *card = dev_get_drvdata(dev); struct azx *chip = card->private_data; + if (!power_save_controller || + !(chip->driver_caps & AZX_DCAPS_PM_RUNTIME)) + return -EAGAIN; + azx_stop_chip(chip); azx_clear_irq_pending(chip); + +#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER + if (chip->pdev) + __azx_platform_disable_clocks(chip); +#endif + return 0; } @@ -2952,7 +3287,15 @@ static int azx_runtime_resume(struct device *dev) struct snd_card *card = dev_get_drvdata(dev); struct azx *chip = card->private_data; - azx_init_pci(chip); + if (chip->pci) + azx_init_pci(chip); + +#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER + if (chip->pdev) { + __azx_platform_enable_clocks(chip); + azx_init_platform(chip); + } +#endif azx_init_chip(chip, 1); return 0; } @@ -2989,8 +3332,20 @@ static const struct dev_pm_ops azx_pm = { 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) + 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) + if (chip->pdev) + azx_platform_disable_clocks(chip); +#endif + return NOTIFY_OK; } @@ -3032,25 +3387,25 @@ static void azx_vs_set_state(struct pci_dev *pci, if (!disabled) { snd_printk(KERN_INFO SFX "%s: Start delayed initialization\n", - pci_name(chip->pci)); + azx_name(chip)); if (azx_first_init(chip) < 0 || azx_probe_continue(chip) < 0) { snd_printk(KERN_ERR SFX "%s: initialization error\n", - pci_name(chip->pci)); + azx_name(chip)); chip->init_failed = true; } } } else { snd_printk(KERN_INFO SFX - "%s: %s via VGA-switcheroo\n", pci_name(chip->pci), + "%s: %s via VGA-switcheroo\n", azx_name(chip), disabled ? "Disabling" : "Enabling"); if (disabled) { azx_suspend(&pci->dev); chip->disabled = true; if (snd_hda_lock_devices(chip->bus)) snd_printk(KERN_WARNING SFX "%s: Cannot lock devices!\n", - pci_name(chip->pci)); + azx_name(chip)); } else { snd_hda_unlock_devices(chip->bus); chip->disabled = false; @@ -3081,7 +3436,7 @@ static void init_vga_switcheroo(struct azx *chip) if (p) { snd_printk(KERN_INFO SFX "%s: Handle VGA-switcheroo audio client\n", - pci_name(chip->pci)); + azx_name(chip)); chip->use_vga_switcheroo = 1; pci_dev_put(p); } @@ -3143,9 +3498,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); @@ -3165,15 +3526,27 @@ static int azx_free(struct azx *chip) mark_pages_wc(chip, &chip->posbuf, false); snd_dma_free_pages(&chip->posbuf); } - if (chip->region_requested) - pci_release_regions(chip->pci); - pci_disable_device(chip->pci); + if (chip->pci) { + if (chip->region_requested) + pci_release_regions(chip->pci); + pci_disable_device(chip->pci); + } kfree(chip->azx_dev); #ifdef CONFIG_SND_HDA_PATCH_LOADER if (chip->fw) release_firmware(chip->fw); #endif kfree(chip); +#ifdef CONFIG_SND_HDA_VPR + if (chip->dmabuf) { + dma_buf_unmap_attachment(chip->attach, chip->sgt, + DMA_BIDIRECTIONAL); + dma_buf_detach(chip->dmabuf, chip->attach); + dma_buf_vunmap(chip->dmabuf, chip->vaddr); + dma_buf_put(chip->dmabuf); + chip->dmabuf = NULL; + } +#endif return 0; } @@ -3258,22 +3631,24 @@ static int 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 */ if (chip->driver_caps & AZX_DCAPS_POSFIX_VIA) { - snd_printd(SFX "%s: Using VIACOMBO position fix\n", pci_name(chip->pci)); + snd_printd(SFX "%s: Using VIACOMBO position fix\n", azx_name(chip)); return POS_FIX_VIACOMBO; } if (chip->driver_caps & AZX_DCAPS_POSFIX_LPIB) { - snd_printd(SFX "%s: Using LPIB position fix\n", pci_name(chip->pci)); + snd_printd(SFX "%s: Using LPIB position fix\n", azx_name(chip)); return POS_FIX_LPIB; } return POS_FIX_AUTO; @@ -3308,7 +3683,7 @@ static void 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 @@ -3349,6 +3724,12 @@ static void 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; @@ -3398,17 +3779,27 @@ static void azx_check_snoop_available(struct azx *chip) if (snoop != chip->snoop) { snd_printk(KERN_INFO SFX "%s: Force to %s mode\n", - pci_name(chip->pci), snoop ? "snoop" : "non-snoop"); + azx_name(chip), snoop ? "snoop" : "non-snoop"); chip->snoop = snoop; } } +#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA +static const char *tegra_clk_names[] = { + "hda", + "hda2codec", + "hda2hdmi", +}; +static struct clk *tegra_clks[ARRAY_SIZE(tegra_clk_names)]; +#endif + /* * constructor */ static int azx_create(struct snd_card *card, struct pci_dev *pci, - int dev, unsigned int driver_caps, - struct azx **rchip) + struct platform_device *pdev, + int dev, unsigned int driver_caps, + struct azx **rchip) { static struct snd_device_ops ops = { .dev_free = azx_dev_free, @@ -3418,14 +3809,25 @@ static int 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; + } else if (pdev) { + err = pm_runtime_set_active(&pdev->dev); + if (err < 0) + return err; + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_enable(&pdev->dev); + } chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (!chip) { - snd_printk(KERN_ERR SFX "%s: Cannot allocate chip\n", pci_name(pci)); - pci_disable_device(pci); + if (pci) { + snd_printk(KERN_ERR SFX "%s: Cannot allocate chip\n", pci_name(pci)); + pci_disable_device(pci); + } else + snd_printk(KERN_ERR SFX "Cannot allocate chip\n"); return -ENOMEM; } @@ -3433,6 +3835,9 @@ static int 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; @@ -3473,12 +3878,13 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); if (err < 0) { snd_printk(KERN_ERR SFX "%s: Error creating device [card]!\n", - pci_name(chip->pci)); + azx_name(chip)); azx_free(chip); return err; } *rchip = chip; + return 0; } @@ -3487,7 +3893,7 @@ static int azx_first_init(struct azx *chip) int dev = chip->dev_index; struct pci_dev *pci = chip->pci; struct snd_card *card = chip->card; - int i, err; + int i, err = 0; unsigned short gcap; #if BITS_PER_LONG != 64 @@ -3500,33 +3906,92 @@ static int azx_first_init(struct azx *chip) } #endif - err = pci_request_regions(pci, "ICH HD audio"); - if (err < 0) - return err; - chip->region_requested = 1; - - 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 "%s: ioremap error\n", pci_name(chip->pci)); - return -ENXIO; + if (chip->pci) { + err = pci_request_regions(pci, "ICH HD audio"); + if (err < 0) + return err; + chip->region_requested = 1; + + 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 "%s: ioremap error\n", azx_name(chip)); + return -ENXIO; + } } - 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(&chip->pdev->dev, + tegra_clk_names[i]); + if (IS_ERR_OR_NULL(tegra_clks[i])) { + return PTR_ERR(tegra_clks[i]); + } + } + chip->platform_clks = tegra_clks; + break; +#endif + default: + break; + } + + azx_platform_enable_clocks(chip); + + res = platform_get_resource(chip->pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + return -EINVAL; + } + + region = devm_request_mem_region(chip->dev, res->start, + resource_size(res), + chip->pdev->name); + if (!region) { + snd_printk(KERN_ERR SFX "Mem region already claimed\n"); + return -EINVAL; + } + + 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"); + return -ENXIO; + } + +#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) return -EBUSY; - pci_set_master(pci); + if (chip->pci) + pci_set_master(pci); + synchronize_irq(chip->irq); gcap = azx_readw(chip, GCAP); - snd_printdd(SFX "%s: chipset global capabilities = 0x%x\n", pci_name(chip->pci), gcap); + snd_printdd(SFX "%s: chipset global capabilities = 0x%x\n", azx_name(chip), 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, @@ -3540,7 +4005,7 @@ static int azx_first_init(struct azx *chip) /* disable 64bit DMA address on some devices */ if (chip->driver_caps & AZX_DCAPS_NO_64BIT) { - snd_printd(SFX "%s: Disabling 64bit DMA\n", pci_name(chip->pci)); + snd_printd(SFX "%s: Disabling 64bit DMA\n", azx_name(chip)); gcap &= ~ICH6_GCAP_64OK; } @@ -3556,12 +4021,15 @@ static int azx_first_init(struct azx *chip) chip->align_buffer_size = 1; } - /* 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 @@ -3595,7 +4063,7 @@ static int azx_first_init(struct azx *chip) chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), GFP_KERNEL); if (!chip->azx_dev) { - snd_printk(KERN_ERR SFX "%s: cannot malloc azx_dev\n", pci_name(chip->pci)); + snd_printk(KERN_ERR SFX "%s: cannot malloc azx_dev\n", azx_name(chip)); return -ENOMEM; } @@ -3603,20 +4071,20 @@ static int azx_first_init(struct azx *chip) dsp_lock_init(&chip->azx_dev[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 "%s: cannot allocate BDL\n", pci_name(chip->pci)); + snd_printk(KERN_ERR SFX "%s: cannot allocate BDL\n", azx_name(chip)); return -ENOMEM; } mark_pages_wc(chip, &chip->azx_dev[i].bdl, true); } /* 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 "%s: cannot allocate posbuf\n", pci_name(chip->pci)); + snd_printk(KERN_ERR SFX "%s: cannot allocate posbuf\n", azx_name(chip)); return -ENOMEM; } mark_pages_wc(chip, &chip->posbuf, true); @@ -3629,12 +4097,18 @@ static int azx_first_init(struct azx *chip) azx_init_stream(chip); /* initialize chip */ - 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 azx_init_chip(chip, (probe_only[dev] & 2) == 0); /* codec detection */ if (!chip->codec_mask) { - snd_printk(KERN_ERR SFX "%s: no codecs found!\n", pci_name(chip->pci)); + snd_printk(KERN_ERR SFX "%s: no codecs found!\n", azx_name(chip)); return -ENODEV; } @@ -3671,7 +4145,7 @@ static void azx_firmware_cb(const struct firmware *fw, void *context) if (!fw) { snd_printk(KERN_ERR SFX "%s: Cannot load firmware, aborting\n", - pci_name(chip->pci)); + azx_name(chip)); goto error; } @@ -3690,12 +4164,14 @@ static void azx_firmware_cb(const struct firmware *fw, void *context) #endif static int 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; bool probe_now; + struct device *azx_dev = pci ? &pci->dev : &pdev->dev; int err; if (dev >= SNDRV_CARDS) @@ -3711,26 +4187,29 @@ static int azx_probe(struct pci_dev *pci, return err; } - 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; - pci_set_drvdata(pci, card); + if (pci) + pci_set_drvdata(pci, card); + else + dev_set_drvdata(&pdev->dev, card); err = register_vga_switcheroo(chip); if (err < 0) { snd_printk(KERN_ERR SFX - "%s: Error registering VGA-switcheroo client\n", pci_name(pci)); + "%s: Error registering VGA-switcheroo client\n", azx_name(chip)); goto out_free; } if (check_hdmi_disabled(pci)) { snd_printk(KERN_INFO SFX "%s: VGA controller is disabled\n", - pci_name(pci)); - snd_printk(KERN_INFO SFX "%s: Delaying initialization\n", pci_name(pci)); + azx_name(chip)); + snd_printk(KERN_INFO SFX "%s: Delaying initialization\n", azx_name(chip)); chip->disabled = true; } @@ -3744,7 +4223,7 @@ static int azx_probe(struct pci_dev *pci, #ifdef CONFIG_SND_HDA_PATCH_LOADER if (patch[dev] && *patch[dev]) { snd_printk(KERN_ERR SFX "%s: Applying patch firmware '%s'\n", - pci_name(pci), patch[dev]); + azx_name(chip), patch[dev]); err = request_firmware_nowait(THIS_MODULE, true, patch[dev], &pci->dev, GFP_KERNEL, card, azx_firmware_cb); @@ -3760,11 +4239,32 @@ static int azx_probe(struct pci_dev *pci, goto out_free; } + if (pci) { + pci_set_drvdata(pci, card); + if (pci_dev_run_wake(pci)) pm_runtime_put_noidle(&pci->dev); + } else if (pdev) { + dev_set_drvdata(&pdev->dev, card); +#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA + tegra_pd_add_device(chip->dev); +#endif + pm_runtime_put(chip->dev); + } + + err = register_vga_switcheroo(chip); + if (err < 0) { + snd_printk(KERN_ERR SFX + "Error registering VGA-switcheroo client\n"); + goto out_free; + } dev++; complete_all(&chip->probe_wait); + + if (pdev) + pm_runtime_put(chip->dev); + return 0; out_free: @@ -3818,6 +4318,11 @@ static int azx_probe_continue(struct azx *chip) if (err < 0) goto out_free; + if (chip->pci) + pci_set_drvdata(chip->pci, chip->card); + else + dev_set_drvdata(&chip->pdev->dev, chip->card); + chip->running = 1; power_down_all_codecs(chip); azx_notifier_register(chip); @@ -3830,7 +4335,13 @@ out_free: return err; } -static void azx_remove(struct pci_dev *pci) +static int 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 azx_remove_pci(struct pci_dev *pci) { struct snd_card *card = pci_get_drvdata(pci); @@ -3843,7 +4354,7 @@ static void azx_remove(struct pci_dev *pci) } /* 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_INTEL_PCH_NOPM }, @@ -4016,17 +4527,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 azx_driver = { .name = KBUILD_MODNAME, - .id_table = azx_ids, - .probe = azx_probe, - .remove = azx_remove, + .id_table = azx_pci_ids, + .probe = azx_probe_pci, + .remove = azx_remove_pci, + .driver = { + .pm = AZX_PM_OPS, + }, +}; + +#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER +static int 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 azx_remove_platform(struct platform_device *pdev) +{ + pm_runtime_get_noresume(&pdev->dev); + 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 | + AZX_DCAPS_PM_RUNTIME }, +#endif + { }, +}; +MODULE_DEVICE_TABLE(platform, azx_platform_ids); + +/* platform_driver definition */ +static struct platform_driver hda_platform_driver = { .driver = { + .name = "hda-platform", .pm = AZX_PM_OPS, }, + .probe = azx_probe_platform, + .remove = azx_remove_platform, + .id_table = azx_platform_ids, }; +#endif /* CONFIG_SND_HDA_PLATFORM_DRIVER */ + +static int __init alsa_card_azx_init(void) +{ + int err = 0; + + err = pci_register_driver(&azx_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(&hda_platform_driver); + if (err < 0) { + snd_printk(KERN_ERR SFX "Failed to register platform driver\n"); + pci_unregister_driver(&azx_driver); + return err; + } +#endif + + return 0; +} + +static void __exit alsa_card_azx_exit(void) +{ +#ifdef CONFIG_SND_HDA_PLATFORM_DRIVER + platform_driver_unregister(&hda_platform_driver); +#endif + + pci_unregister_driver(&azx_driver); +} -module_pci_driver(azx_driver); +module_init(alsa_card_azx_init) +module_exit(alsa_card_azx_exit) diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 2e7493ef8ee0..a88c3810a9b4 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -729,6 +729,7 @@ struct parsed_hdmi_eld { /* * all fields will be cleared before updating ELD */ + bool lpcm_sad_ready; int baseline_len; int eld_ver; int cea_edid_ver; @@ -765,6 +766,8 @@ int snd_hdmi_parse_eld(struct parsed_hdmi_eld *e, void snd_hdmi_show_eld(struct parsed_hdmi_eld *e); void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e, struct hda_pcm_stream *hinfo); +int hdmi_update_lpcm_sad_eld (struct hda_codec *codec, hda_nid_t nid, + struct hdmi_eld *e); #ifdef CONFIG_PROC_FS int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld, diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index ba442d24257a..5790d23d4927 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -36,6 +36,11 @@ #include <sound/jack.h> #include <sound/asoundef.h> #include <sound/tlv.h> + +#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA +#include <mach/hdmi-audio.h> +#endif + #include "hda_codec.h" #include "hda_local.h" #include "hda_jack.h" @@ -985,6 +990,10 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) int pin_nid; int pin_idx; struct hda_jack_tbl *jack; +#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA + struct hdmi_eld *eld; + struct hdmi_spec_per_pin *per_pin; +#endif jack = snd_hda_jack_tbl_get_from_tag(codec, tag); if (!jack) @@ -1002,6 +1011,25 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) return; hdmi_present_sense(get_pin(spec, pin_idx), 1); + +#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA + per_pin = get_pin(spec, pin_idx); + eld = &per_pin->sink_eld; + + if (((codec->preset->id == 0x10de0020) || + (codec->preset->id == 0x10de0022) || + (codec->preset->id == 0x10de0028) || + (codec->preset->id == 0x10de002a))) { + /* + * HDMI sink's ELD info cannot always be retrieved for now, e.g. + * in console or for audio devices. Assume the highest speakers + * configuration, to _not_ prohibit multi-channel audio playback + */ + if (!eld->info.spk_alloc) + eld->info.spk_alloc = 0xffff; + } +#endif + snd_hda_jack_report_sync(codec); } @@ -1148,6 +1176,24 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, per_pin = get_pin(spec, pin_idx); eld = &per_pin->sink_eld; +#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA + if ((((codec->preset->id == 0x10de0020) || + (codec->preset->id == 0x10de0022) || + (codec->preset->id == 0x10de0028) || + (codec->preset->id == 0x10de002a))) && + (!eld->monitor_present || !eld->info.lpcm_sad_ready)) { + if (!eld->monitor_present) { + if (tegra_hdmi_setup_hda_presence() < 0) { + snd_printk(KERN_WARNING + "HDMI: No HDMI device connected\n"); + return -ENODEV; + } + } + if (!eld->info.lpcm_sad_ready) + return -ENODEV; + } +#endif + /* Dynamically assign converter to stream */ for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) { per_cvt = get_cvt(spec, cvt_idx); @@ -1185,7 +1231,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, hinfo->maxbps = per_cvt->maxbps; /* Restrict capabilities by ELD if this isn't disabled */ - if (!static_hdmi_pcm && eld->eld_valid) { + if (!static_hdmi_pcm && (eld->eld_valid || eld->info.lpcm_sad_ready)) { snd_hdmi_eld_update_pcm_info(&eld->info, hinfo); if (hinfo->channels_min > hinfo->channels_max || !hinfo->rates || !hinfo->formats) { @@ -1238,6 +1284,7 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) struct hdmi_eld *eld = &spec->temp_eld; struct hdmi_eld *pin_eld = &per_pin->sink_eld; hda_nid_t pin_nid = per_pin->pin_nid; + /* * Always execute a GetPinSense verb here, even when called from * hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited @@ -1261,16 +1308,29 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) codec->addr, pin_nid, pin_eld->monitor_present, eld->eld_valid); if (eld->eld_valid) { + + if (!pin_eld->info.lpcm_sad_ready) { + memset(&eld->info, 0, sizeof(struct parsed_hdmi_eld)); + hdmi_update_lpcm_sad_eld(codec, pin_nid, eld); + } + if (snd_hdmi_get_eld(codec, pin_nid, eld->eld_buffer, &eld->eld_size) < 0) eld->eld_valid = false; else { - memset(&eld->info, 0, sizeof(struct parsed_hdmi_eld)); if (snd_hdmi_parse_eld(&eld->info, eld->eld_buffer, eld->eld_size) < 0) eld->eld_valid = false; } + if(!eld->eld_valid && !pin_eld->info.lpcm_sad_ready) { + mutex_lock(&pin_eld->lock); + pin_eld->info = eld->info; + memcpy(pin_eld->eld_buffer, eld->eld_buffer, + eld->eld_size); + mutex_unlock(&pin_eld->lock); + } + if (eld->eld_valid) { snd_hdmi_show_eld(&eld->info); update_eld = true; @@ -1324,11 +1384,30 @@ static void hdmi_repoll_eld(struct work_struct *work) { struct hdmi_spec_per_pin *per_pin = container_of(to_delayed_work(work), struct hdmi_spec_per_pin, work); +#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA + struct hda_codec *codec = per_pin->codec; + struct hdmi_eld *eld = &per_pin->sink_eld; +#endif if (per_pin->repoll_count++ > 6) per_pin->repoll_count = 0; hdmi_present_sense(per_pin, per_pin->repoll_count); + +#ifdef CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA + if ((codec->preset->id == 0x10de0020) || + (codec->preset->id == 0x10de0022) || + (codec->preset->id == 0x10de0028) || + (codec->preset->id == 0x10de002a)) { + /* + * HDMI sink's ELD info cannot always be retrieved for now, e.g. + * in console or for audio devices. Assume the highest speakers + * configuration, to _not_ prohibit multi-channel audio playback + */ + if (!eld->info.spk_alloc) + eld->info.spk_alloc = 0xffff; + } +#endif } static void intel_haswell_fixup_connect_list(struct hda_codec *codec, @@ -1447,9 +1526,12 @@ static int hdmi_parse_codec(struct hda_codec *codec) * can be lost and presence sense verb will become inaccurate if the * HDA link is powered off at hot plug or hw initialization time. */ - else if (!(snd_hda_param_read(codec, codec->afg, AC_PAR_POWER_STATE) & - AC_PWRST_EPSS)) - codec->bus->power_keep_link_on = 1; + else if ((!(snd_hda_param_read(codec, codec->afg, AC_PAR_POWER_STATE) & + AC_PWRST_EPSS)) && ((codec->preset->id != 0x10de0020) && + (codec->preset->id != 0x10de0022) && + (codec->preset->id != 0x10de0028) && + (codec->preset->id != 0x10de002a))) + codec->bus->power_keep_link_on = 1; #endif return 0; @@ -1492,6 +1574,30 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, per_pin->channels = substream->runtime->channels; per_pin->setup = true; +#if defined(CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA) && defined(CONFIG_TEGRA_DC) + if ((codec->preset->id == 0x10de0020) || + (codec->preset->id == 0x10de0022) || + (codec->preset->id == 0x10de0028) || + (codec->preset->id == 0x10de002a)) { + int err = 0; + + if (substream->runtime->channels == 2) + tegra_hdmi_audio_null_sample_inject(true); + else + tegra_hdmi_audio_null_sample_inject(false); + + /* 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, per_pin, non_pcm); @@ -1804,6 +1910,17 @@ static int generic_hdmi_init_per_pins(struct hda_codec *codec) struct hdmi_spec *spec = codec->spec; int pin_idx; + switch (codec->preset->id) { + case 0x10de0020: + case 0x10de0022: + case 0x10de0028: + case 0x10de002a: + 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 = get_pin(spec, pin_idx); struct hdmi_eld *eld = &per_pin->sink_eld; @@ -1863,9 +1980,26 @@ static void generic_hdmi_free(struct hda_codec *codec) kfree(spec); } +static int generic_hdmi_suspend(struct hda_codec *codec) +{ + struct hdmi_spec *spec = codec->spec; + int pin_idx; + + for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); + struct hdmi_eld *eld = &per_pin->sink_eld; + + cancel_delayed_work_sync(&per_pin->work); + snd_hda_eld_proc_free(codec, eld); + } + + return 0; +} + static const struct hda_codec_ops generic_hdmi_patch_ops = { .init = generic_hdmi_init, .free = generic_hdmi_free, + .suspend = generic_hdmi_suspend, .build_pcms = generic_hdmi_build_pcms, .build_controls = generic_hdmi_build_controls, .unsol_event = hdmi_unsol_event, @@ -2606,18 +2740,22 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = { { .id = 0x10de0015, .name = "GPU 15 HDMI/DP", .patch = patch_nvhdmi }, { .id = 0x10de0016, .name = "GPU 16 HDMI/DP", .patch = patch_nvhdmi }, /* 17 is known to be absent */ -{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de0051, .name = "GPU 51 HDMI/DP", .patch = patch_nvhdmi }, -{ .id = 0x10de0060, .name = "GPU 60 HDMI/DP", .patch = patch_nvhdmi }, +{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_nvhdmi}, +{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_nvhdmi}, +{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_nvhdmi}, +{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_nvhdmi}, +{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_nvhdmi}, +{ .id = 0x10de0020, .name = "Tegra30 HDMI", .patch = patch_generic_hdmi }, +{ .id = 0x10de0022, .name = "Tegra35 HDMI", .patch = patch_generic_hdmi }, +{ .id = 0x10de002a, .name = "Tegra14x HDMI", .patch = patch_generic_hdmi }, +{ .id = 0x10de0028, .name = "Tegra12x HDMI", .patch = patch_generic_hdmi }, +{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_nvhdmi}, +{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_nvhdmi}, +{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_nvhdmi}, +{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_nvhdmi}, +{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_nvhdmi}, +{ .id = 0x10de0051, .name = "GPU 51 HDMI/DP", .patch = patch_nvhdmi}, +{ .id = 0x10de0060, .name = "GPU 60 HDMI/DP", .patch = patch_nvhdmi}, { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch }, { .id = 0x11069f80, .name = "VX900 HDMI/DP", .patch = patch_via_hdmi }, @@ -2664,6 +2802,10 @@ 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:10de0022"); +MODULE_ALIAS("snd-hda-codec-id:10de0028"); +MODULE_ALIAS("snd-hda-codec-id:10de002a"); MODULE_ALIAS("snd-hda-codec-id:10de0040"); MODULE_ALIAS("snd-hda-codec-id:10de0041"); MODULE_ALIAS("snd-hda-codec-id:10de0042"); |