diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c index f7bd6e2db..3772307bd 100644 --- a/sound/hda/hdac_controller.c +++ b/sound/hda/hdac_controller.c @@ -10,6 +10,7 @@ #include #include #include "local.h" +#include /* clear CORB read pointer properly */ static void azx_clear_corbrp(struct hdac_bus *bus) @@ -143,6 +144,11 @@ int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val) { unsigned int addr = azx_command_addr(val); unsigned int wp, rp; +#ifdef CONFIG_SND_HDA_PHYTIUM + unsigned long timeout; + unsigned int rirb_wp; + int i = 0; +#endif spin_lock_irq(&bus->reg_lock); @@ -169,6 +175,43 @@ int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val) bus->corb.buf[wp] = cpu_to_le32(val); snd_hdac_chip_writew(bus, CORBWP, wp); +#ifdef CONFIG_SND_HDA_PHYTIUM + if (cpu_is_phytium()) { + 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++; + } + } +#endif spin_unlock_irq(&bus->reg_lock); return 0; diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index aa7955fdf..5c35ee427 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c @@ -12,6 +12,7 @@ #include #include #include "trace.h" +#include /** * snd_hdac_get_stream_stripe_ctl - get stripe control value @@ -87,7 +88,12 @@ void snd_hdac_stream_start(struct hdac_stream *azx_dev, bool fresh_start) trace_snd_hdac_stream_start(bus, azx_dev); - azx_dev->start_wallclk = snd_hdac_chip_readl(bus, WALLCLK); + if (cpu_is_phytium()) { + azx_dev->start_wallclk = snd_hdac_chip_readl(bus, WALLCLK) / 15; + } else { + azx_dev->start_wallclk = snd_hdac_chip_readl(bus, WALLCLK); + } + if (!fresh_start) azx_dev->start_wallclk -= azx_dev->period_wallclk; @@ -520,7 +526,11 @@ static u64 azx_cc_read(const struct cyclecounter *cc) { struct hdac_stream *azx_dev = container_of(cc, struct hdac_stream, cc); - return snd_hdac_chip_readl(azx_dev->bus, WALLCLK); + if (cpu_is_phytium()) { + return snd_hdac_chip_readl(azx_dev->bus, WALLCLK) / 25; + } else { + return snd_hdac_chip_readl(azx_dev->bus, WALLCLK); + } } static void azx_timecounter_init(struct hdac_stream *azx_dev,