On Wed, Apr 9, 2014 at 12:43 AM, Takashi Iwai tiwai@suse.de wrote:
At Tue, 8 Apr 2014 12:15:33 -0700, Dylan Reid wrote:
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index ac17c3f..4f6ee6b 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -20,6 +20,20 @@ config SND_HDA_INTEL To compile this driver as a module, choose M here: the module will be called snd-hda-intel.
+config SND_HDA_TEGRA
tristate "Tegra HD Audio"
select SND_HDA
Does (or should) this be build generically? Or any arch-specific dependency, or maybe at least "depends on OF"?
Thanks Takashi,
Yes I think it should depend on OF and ARCH_TEGRA.
help
Say Y here to support the HDA controller present in Nvidia
Tegra SoCs
This options enables support for the HD Audio controller
present in some Nvidia Tegra SoCs, used to communicate audio
to the HDMI output.
To compile this driver as a module, choose M here: the module
will be called snd-hda-tegra.
if SND_HDA
config SND_HDA_DSP_LOADER diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index d0d0c19..194f3093 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -1,5 +1,6 @@ snd-hda-intel-objs := hda_intel.o snd-hda-controller-objs := hda_controller.o +snd-hda-tegra-objs := hda_tegra.o # for haswell power well snd-hda-intel-$(CONFIG_SND_HDA_I915) += hda_i915.o
@@ -47,3 +48,4 @@ obj-$(CONFIG_SND_HDA_CODEC_HDMI) += snd-hda-codec-hdmi.o # otherwise the codec patches won't be hooked before the PCI probe # when built in kernel obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o +obj-$(CONFIG_SND_HDA_TEGRA) += snd-hda-tegra.o diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c new file mode 100644 index 0000000..c36bbca --- /dev/null +++ b/sound/pci/hda/hda_tegra.c @@ -0,0 +1,695 @@ +/*
- Implementation of primary alsa driver code base for Tegra HDA.
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 2 of the License, or (at your option)
- any later version.
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
- */
+#include <linux/clk.h> +#include <linux/clocksource.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/dma-mapping.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/mutex.h> +#include <linux/reboot.h> +#include <linux/io.h> +#include <linux/pm_runtime.h> +#include <linux/of_device.h> +#include <linux/time.h> +#include <linux/completion.h>
+#include <sound/core.h> +#include <sound/initval.h> +#include <linux/firmware.h> +#include "hda_codec.h" +#include "hda_controller.h" +#include "hda_priv.h"
+#define DRV_NAME "tegra-hda"
+/* 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)
+struct hda_tegra_data {
struct azx chip;
struct platform_device *pdev;
struct clk **platform_clks;
int platform_clk_count;
void __iomem *remap_config_addr;
+};
+static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; +module_param_array(probe_mask, int, NULL, 0444); +MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1).");
+static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; +static int *power_save_addr = &power_save; +module_param(power_save, bint, 0644); +MODULE_PARM_DESC(power_save,
"Automatic power-saving timeout (in seconds, 0 = disable).");
+/*
- DMA page allocation ops.
- */
+static int dma_alloc_pages(struct azx *chip,
int type,
size_t size,
struct snd_dma_buffer *buf)
+{
return snd_dma_alloc_pages(type,
chip->card->dev,
size, buf);
+}
+static void dma_free_pages(struct azx *chip, struct snd_dma_buffer *buf) +{
snd_dma_free_pages(buf);
+}
+static int substream_alloc_pages(struct azx *chip,
struct snd_pcm_substream *substream,
size_t size)
+{
struct azx_dev *azx_dev = get_azx_dev(substream);
azx_dev->bufsize = 0;
azx_dev->period_bytes = 0;
azx_dev->format_val = 0;
return snd_pcm_lib_malloc_pages(substream, size);
+}
+static int substream_free_pages(struct azx *chip,
struct snd_pcm_substream *substream)
+{
return snd_pcm_lib_free_pages(substream);
+}
+/*
- Register access ops. Tegra HDA register access is DWORD only.
- */
+#define MASK_LONG_ALIGN 0x3UL +#define SHIFT_BYTE 3 +#define SHIFT_BITS(addr) \
(((unsigned int)(addr) & MASK_LONG_ALIGN) << SHIFT_BYTE)
+#define ADDR_ALIGN_L(addr) \
(void *)((unsigned int)(addr) & ~MASK_LONG_ALIGN)
+#define MASK(bits) (BIT(bits) - 1) +#define MASK_REG(addr, bits) (MASK(bits) << SHIFT_BITS(addr))
This results in lots of compile warnings on 64bit machines.
Yes it does, thanks for checking, I'll fix that up.
sound/pci/hda/hda_tegra.c: In function ‘tegra_hda_writew’: sound/pci/hda/hda_tegra.c:128:4: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] (((unsigned int)(addr) & MASK_LONG_ALIGN) << SHIFT_BYTE)
thanks,
Takashi