HDA driver support for Phytium desktop

(cherry picked from commit 61b278c01b)
Signed-off-by: Alex Shi <alexsshi@tencent.com>
This commit is contained in:
Wei Tian 2023-04-20 06:24:33 +00:00 committed by Jianping Liu
parent 9b68c04c3f
commit 9cd366d0b7
8 changed files with 1195 additions and 0 deletions

View File

@ -343,6 +343,7 @@ struct hdac_bus {
int poll_count; int poll_count;
bool cmd_resend:1; /* command resend */
int bdl_pos_adj; /* BDL position adjustment */ int bdl_pos_adj; /* BDL position adjustment */
/* locks */ /* locks */

View File

@ -142,6 +142,9 @@ int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val)
{ {
unsigned int addr = azx_command_addr(val); unsigned int addr = azx_command_addr(val);
unsigned int wp, rp; unsigned int wp, rp;
unsigned long timeout;
unsigned int rirb_wp;
int i = 0;
spin_lock_irq(&bus->reg_lock); spin_lock_irq(&bus->reg_lock);
@ -168,6 +171,41 @@ int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val)
bus->corb.buf[wp] = cpu_to_le32(val); bus->corb.buf[wp] = cpu_to_le32(val);
snd_hdac_chip_writew(bus, CORBWP, wp); snd_hdac_chip_writew(bus, CORBWP, wp);
if (bus->cmd_resend) {
timeout = jiffies + msecs_to_jiffies(1000);
udelay(80);
rirb_wp = snd_hdac_chip_readw(bus, RIRBWP);
while (rirb_wp == bus->rirb.wp) {
udelay(80);
rirb_wp = snd_hdac_chip_readw(bus, RIRBWP);
if (rirb_wp != bus->rirb.wp)
break;
if (i > 5)
break;
if (time_after(jiffies, timeout))
break;
/* add command to corb */
wp = snd_hdac_chip_readw(bus, CORBWP);
if (wp == 0xffff) {
/* something wrong, controller likely turned to D3 */
spin_unlock_irq(&bus->reg_lock);
return -EIO;
}
wp++;
wp %= AZX_MAX_CORB_ENTRIES;
rp = snd_hdac_chip_readw(bus, CORBRP);
if (wp == rp) {
/* oops, it's full */
spin_unlock_irq(&bus->reg_lock);
return -EAGAIN;
}
bus->corb.buf[wp] = cpu_to_le32(val);
snd_hdac_chip_writew(bus, CORBWP, wp);
i++;
}
}
spin_unlock_irq(&bus->reg_lock); spin_unlock_irq(&bus->reg_lock);
return 0; return 0;

View File

@ -87,7 +87,11 @@ void snd_hdac_stream_start(struct hdac_stream *azx_dev, bool fresh_start)
trace_snd_hdac_stream_start(bus, azx_dev); trace_snd_hdac_stream_start(bus, azx_dev);
#ifdef CONFIG_SND_HDA_PHYTIUM
azx_dev->start_wallclk = snd_hdac_chip_readl(bus, WALLCLK) / 15;
#else
azx_dev->start_wallclk = snd_hdac_chip_readl(bus, WALLCLK); azx_dev->start_wallclk = snd_hdac_chip_readl(bus, WALLCLK);
#endif
if (!fresh_start) if (!fresh_start)
azx_dev->start_wallclk -= azx_dev->period_wallclk; azx_dev->start_wallclk -= azx_dev->period_wallclk;
@ -514,7 +518,11 @@ static u64 azx_cc_read(const struct cyclecounter *cc)
{ {
struct hdac_stream *azx_dev = container_of(cc, struct hdac_stream, cc); struct hdac_stream *azx_dev = container_of(cc, struct hdac_stream, cc);
#ifdef CONFIG_SND_HDA_PHYTIUM
return snd_hdac_chip_readl(azx_dev->bus, WALLCLK) / 25;
#else
return snd_hdac_chip_readl(azx_dev->bus, WALLCLK); return snd_hdac_chip_readl(azx_dev->bus, WALLCLK);
#endif
} }
static void azx_timecounter_init(struct hdac_stream *azx_dev, static void azx_timecounter_init(struct hdac_stream *azx_dev,

View File

@ -23,6 +23,23 @@ config SND_HDA_INTEL
To compile this driver as a module, choose M here: the module To compile this driver as a module, choose M here: the module
will be called snd-hda-intel. will be called snd-hda-intel.
config SND_HDA_PHYTIUM
tristate "PHYTIUM HD Audio"
depends on SOUND
select SND_HDA
select SND_HDA_ALIGNED_MMIO
help
Say Y here to support the HDA controller present in PHYTIUM
SoCs
This options enables support for the HD Audio controller
present in some PHYTIUM SoCs, used to communicate audio
to the "High Definition Audio" codec.
To compile this driver as a module, choose M here: the module
will be called snd-hda-phytium.
config SND_HDA_INTEL_DETECT_DMIC config SND_HDA_INTEL_DETECT_DMIC
bool "DMIC detection and probe abort" bool "DMIC detection and probe abort"
depends on SND_HDA_INTEL depends on SND_HDA_INTEL

View File

@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
snd-hda-intel-objs := hda_intel.o snd-hda-intel-objs := hda_intel.o
snd-hda-phytium-objs := hda_phytium.o
snd-hda-tegra-objs := hda_tegra.o snd-hda-tegra-objs := hda_tegra.o
snd-hda-codec-y := hda_bind.o hda_codec.o hda_jack.o hda_auto_parser.o hda_sysfs.o snd-hda-codec-y := hda_bind.o hda_codec.o hda_jack.o hda_auto_parser.o hda_sysfs.o
@ -47,4 +48,5 @@ obj-$(CONFIG_SND_HDA_CODEC_HDMI) += snd-hda-codec-hdmi.o
# otherwise the codec patches won't be hooked before the PCI probe # otherwise the codec patches won't be hooked before the PCI probe
# when built in kernel # when built in kernel
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o
obj-$(CONFIG_SND_HDA_PHYTIUM) += snd-hda-phytium.o
obj-$(CONFIG_SND_HDA_TEGRA) += snd-hda-tegra.o obj-$(CONFIG_SND_HDA_TEGRA) += snd-hda-tegra.o

View File

@ -17,6 +17,7 @@
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "hda_phytium.h"
#ifdef CONFIG_X86 #ifdef CONFIG_X86
/* for art-tsc conversion */ /* for art-tsc conversion */
#include <asm/tsc.h> #include <asm/tsc.h>
@ -160,6 +161,8 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
snd_hda_spdif_out_of_nid(apcm->codec, hinfo->nid); snd_hda_spdif_out_of_nid(apcm->codec, hinfo->nid);
unsigned short ctls = spdif ? spdif->ctls : 0; unsigned short ctls = spdif ? spdif->ctls : 0;
struct hda_ft *hda = container_of(chip, struct hda_ft, chip);
hda->substream = substream;
trace_azx_pcm_prepare(chip, azx_dev); trace_azx_pcm_prepare(chip, azx_dev);
dsp_lock(azx_dev); dsp_lock(azx_dev);
if (dsp_is_locked(azx_dev)) { if (dsp_is_locked(azx_dev)) {

1100
sound/pci/hda/hda_phytium.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,26 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Implementation of primary ALSA driver code base for Phytium HD Audio.
*
* Copyright(c) 2018-2022, Phytium Technology Co., Ltd.
*/
#ifndef __SOUND_HDA_PHYTIUM_H__
#define __SOUND_HDA_PHYTIUM_H__
#include "hda_controller.h"
struct hda_ft {
struct azx chip;
struct snd_pcm_substream *substream;
struct device *dev;
void __iomem *regs;
/* for pending irqs */
struct work_struct irq_pending_work;
/* sync probing */
struct completion probe_wait;
struct work_struct probe_work;
/* card list (for power_save trigger) */
struct list_head list;
/* extra flags */
unsigned int irq_pending_warned:1;
unsigned int probe_continued:1;
};
#endif