Loading include/sound/hdaudio.h +26 −0 Original line number Diff line number Diff line Loading @@ -495,6 +495,13 @@ static inline u16 snd_hdac_reg_readw(struct hdac_bus *bus, void __iomem *addr) snd_hdac_chip_writeb(chip, reg, \ (snd_hdac_chip_readb(chip, reg) & ~(mask)) | (val)) /* update register macro */ #define snd_hdac_updatel(addr, reg, mask, val) \ writel(((readl(addr + reg) & ~(mask)) | (val)), addr + reg) #define snd_hdac_updatew(addr, reg, mask, val) \ writew(((readw(addr + reg) & ~(mask)) | (val)), addr + reg) /* * HD-audio stream */ Loading @@ -511,6 +518,13 @@ struct hdac_stream { void __iomem *sd_addr; /* stream descriptor pointer */ void __iomem *spib_addr; /* software position in buffers stream pointer */ void __iomem *fifo_addr; /* software position Max fifos stream pointer */ void __iomem *dpibr_addr; /* DMA position in buffer resume pointer */ u32 dpib; /* DMA position in buffer */ u32 lpib; /* Linear position in buffer */ u32 sd_int_sta_mask; /* stream int status mask */ /* pcm support */ Loading Loading @@ -575,6 +589,18 @@ void snd_hdac_stream_timecounter_init(struct hdac_stream *azx_dev, int snd_hdac_get_stream_stripe_ctl(struct hdac_bus *bus, struct snd_pcm_substream *substream); void snd_hdac_stream_spbcap_enable(struct hdac_bus *chip, bool enable, int index); int snd_hdac_stream_set_spib(struct hdac_bus *bus, struct hdac_stream *azx_dev, u32 value); int snd_hdac_stream_get_spbmaxfifo(struct hdac_bus *bus, struct hdac_stream *azx_dev); void snd_hdac_stream_drsm_enable(struct hdac_bus *bus, bool enable, int index); int snd_hdac_stream_set_dpibr(struct hdac_bus *bus, struct hdac_stream *azx_dev, u32 value); int snd_hdac_stream_set_lpib(struct hdac_stream *azx_dev, u32 value); /* * macros for easy use */ Loading include/sound/hdaudio_ext.h +16 −50 Original line number Diff line number Diff line Loading @@ -23,12 +23,9 @@ void snd_hdac_ext_bus_device_remove(struct hdac_bus *bus); void snd_hdac_ext_bus_ppcap_enable(struct hdac_bus *chip, bool enable); void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_bus *chip, bool enable); void snd_hdac_ext_stream_spbcap_enable(struct hdac_bus *chip, bool enable, int index); int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus); struct hdac_ext_link *snd_hdac_ext_bus_link_at(struct hdac_bus *bus, int addr); struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_bus *bus, struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_addr(struct hdac_bus *bus, int addr); struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_name(struct hdac_bus *bus, const char *codec_name); enum hdac_ext_stream_type { Loading @@ -43,11 +40,6 @@ enum hdac_ext_stream_type { * @hstream: hdac_stream * @pphc_addr: processing pipe host stream pointer * @pplc_addr: processing pipe link stream pointer * @spib_addr: software position in buffers stream pointer * @fifo_addr: software position Max fifos stream pointer * @dpibr_addr: DMA position in buffer resume pointer * @dpib: DMA position in buffer * @lpib: Linear position in buffer * @decoupled: stream host and link is decoupled * @link_locked: link is locked * @link_prepared: link is prepared Loading @@ -59,13 +51,6 @@ struct hdac_ext_stream { void __iomem *pphc_addr; void __iomem *pplc_addr; void __iomem *spib_addr; void __iomem *fifo_addr; void __iomem *dpibr_addr; u32 dpib; u32 lpib; bool decoupled:1; bool link_locked:1; bool link_prepared; Loading @@ -80,7 +65,7 @@ struct hdac_ext_stream { int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx, int num_stream, int dir); void snd_hdac_ext_stream_free_all(struct hdac_bus *bus); void snd_hdac_link_free_all(struct hdac_bus *bus); void snd_hdac_ext_link_free_all(struct hdac_bus *bus); struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream, int type); Loading @@ -90,20 +75,10 @@ void snd_hdac_ext_stream_decouple_locked(struct hdac_bus *bus, void snd_hdac_ext_stream_decouple(struct hdac_bus *bus, struct hdac_ext_stream *azx_dev, bool decouple); int snd_hdac_ext_stream_set_spib(struct hdac_bus *bus, struct hdac_ext_stream *hext_stream, u32 value); int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_bus *bus, struct hdac_ext_stream *hext_stream); void snd_hdac_ext_stream_drsm_enable(struct hdac_bus *bus, bool enable, int index); int snd_hdac_ext_stream_set_dpibr(struct hdac_bus *bus, struct hdac_ext_stream *hext_stream, u32 value); int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *hext_stream, u32 value); void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *hext_stream); void snd_hdac_ext_link_stream_clear(struct hdac_ext_stream *hext_stream); void snd_hdac_ext_link_stream_reset(struct hdac_ext_stream *hext_stream); int snd_hdac_ext_link_stream_setup(struct hdac_ext_stream *hext_stream, int fmt); void snd_hdac_ext_stream_start(struct hdac_ext_stream *hext_stream); void snd_hdac_ext_stream_clear(struct hdac_ext_stream *hext_stream); void snd_hdac_ext_stream_reset(struct hdac_ext_stream *hext_stream); int snd_hdac_ext_stream_setup(struct hdac_ext_stream *hext_stream, int fmt); struct hdac_ext_link { struct hdac_bus *bus; Loading @@ -117,29 +92,20 @@ struct hdac_ext_link { struct list_head list; }; int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link); int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link); int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *hlink); int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *hlink); int snd_hdac_ext_bus_link_power_up_all(struct hdac_bus *bus); int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus); void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link, void snd_hdac_ext_bus_link_set_stream_id(struct hdac_ext_link *hlink, int stream); void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link, void snd_hdac_ext_bus_link_clear_stream_id(struct hdac_ext_link *hlink, int stream); int snd_hdac_ext_bus_link_get(struct hdac_bus *bus, struct hdac_ext_link *link); int snd_hdac_ext_bus_link_put(struct hdac_bus *bus, struct hdac_ext_link *link); int snd_hdac_ext_bus_link_get(struct hdac_bus *bus, struct hdac_ext_link *hlink); int snd_hdac_ext_bus_link_put(struct hdac_bus *bus, struct hdac_ext_link *hlink); void snd_hdac_ext_bus_link_power(struct hdac_device *codec, bool enable); /* update register macro */ #define snd_hdac_updatel(addr, reg, mask, val) \ writel(((readl(addr + reg) & ~(mask)) | (val)), \ addr + reg) #define snd_hdac_updatew(addr, reg, mask, val) \ writew(((readw(addr + reg) & ~(mask)) | (val)), \ addr + reg) #define snd_hdac_adsp_writeb(chip, reg, value) \ snd_hdac_reg_writeb(chip, (chip)->dsp_ba + (reg), value) #define snd_hdac_adsp_readb(chip, reg) \ Loading sound/hda/ext/hdac_ext_controller.c +67 −49 Original line number Diff line number Diff line Loading @@ -108,49 +108,47 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus) EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_ml_capabilities); /** * snd_hdac_link_free_all- free hdac extended link objects * snd_hdac_ext_link_free_all- free hdac extended link objects * * @bus: the pointer to HDAC bus object */ void snd_hdac_link_free_all(struct hdac_bus *bus) void snd_hdac_ext_link_free_all(struct hdac_bus *bus) { struct hdac_ext_link *l; struct hdac_ext_link *hlink; while (!list_empty(&bus->hlink_list)) { l = list_first_entry(&bus->hlink_list, struct hdac_ext_link, list); list_del(&l->list); kfree(l); hlink = list_first_entry(&bus->hlink_list, struct hdac_ext_link, list); list_del(&hlink->list); kfree(hlink); } } EXPORT_SYMBOL_GPL(snd_hdac_link_free_all); EXPORT_SYMBOL_GPL(snd_hdac_ext_link_free_all); /** * snd_hdac_ext_bus_link_at - get link at specified address * @bus: link's parent bus device * snd_hdac_ext_bus_get_hlink_by_addr - get hlink at specified address * @bus: hlink's parent bus device * @addr: codec device address * * Returns link object or NULL if matching link is not found. * Returns hlink object or NULL if matching hlink is not found. */ struct hdac_ext_link *snd_hdac_ext_bus_link_at(struct hdac_bus *bus, int addr) struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_addr(struct hdac_bus *bus, int addr) { struct hdac_ext_link *hlink; int i; list_for_each_entry(hlink, &bus->hlink_list, list) for (i = 0; i < HDA_MAX_CODECS; i++) if (hlink->lsdiid & (0x1 << addr)) return hlink; return NULL; } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_at); EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_hlink_by_addr); /** * snd_hdac_ext_bus_get_link - get link based on codec name * snd_hdac_ext_bus_get_hlink_by_name - get hlink based on codec name * @bus: the pointer to HDAC bus object * @codec_name: codec name */ struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_bus *bus, struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_name(struct hdac_bus *bus, const char *codec_name) { int bus_idx, addr; Loading @@ -162,11 +160,11 @@ struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_bus *bus, if (addr < 0 || addr > 31) return NULL; return snd_hdac_ext_bus_link_at(bus, addr); return snd_hdac_ext_bus_get_hlink_by_addr(bus, addr); } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_link); EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_hlink_by_name); static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable) static int check_hdac_link_power_active(struct hdac_ext_link *hlink, bool enable) { int timeout; u32 val; Loading @@ -176,7 +174,7 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable) timeout = 150; do { val = readl(link->ml_addr + AZX_REG_ML_LCTL); val = readl(hlink->ml_addr + AZX_REG_ML_LCTL); if (enable) { if (((val & mask) >> AZX_ML_LCTL_CPA_SHIFT)) return 0; Loading @@ -192,26 +190,26 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable) /** * snd_hdac_ext_bus_link_power_up -power up hda link * @link: HD-audio extended link * @hlink: HD-audio extended link */ int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link) int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *hlink) { snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL, snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, AZX_ML_LCTL_SPA, AZX_ML_LCTL_SPA); return check_hdac_link_power_active(link, true); return check_hdac_link_power_active(hlink, true); } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_up); /** * snd_hdac_ext_bus_link_power_down -power down hda link * @link: HD-audio extended link * @hlink: HD-audio extended link */ int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link) int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *hlink) { snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL, AZX_ML_LCTL_SPA, 0); snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, AZX_ML_LCTL_SPA, 0); return check_hdac_link_power_active(link, false); return check_hdac_link_power_active(hlink, false); } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down); Loading @@ -225,9 +223,7 @@ int snd_hdac_ext_bus_link_power_up_all(struct hdac_bus *bus) int ret; list_for_each_entry(hlink, &bus->hlink_list, list) { snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, AZX_ML_LCTL_SPA, AZX_ML_LCTL_SPA); ret = check_hdac_link_power_active(hlink, true); ret = snd_hdac_ext_bus_link_power_up(hlink); if (ret < 0) return ret; } Loading @@ -246,9 +242,7 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus) int ret; list_for_each_entry(hlink, &bus->hlink_list, list) { snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, AZX_ML_LCTL_SPA, 0); ret = check_hdac_link_power_active(hlink, false); ret = snd_hdac_ext_bus_link_power_down(hlink); if (ret < 0) return ret; } Loading @@ -257,8 +251,32 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus) } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down_all); /** * snd_hdac_ext_bus_link_set_stream_id - maps stream id to link output * @link: HD-audio ext link to set up * @stream: stream id */ void snd_hdac_ext_bus_link_set_stream_id(struct hdac_ext_link *link, int stream) { snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 1 << stream); } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_set_stream_id); /** * snd_hdac_ext_bus_link_clear_stream_id - maps stream id to link output * @link: HD-audio ext link to set up * @stream: stream id */ void snd_hdac_ext_bus_link_clear_stream_id(struct hdac_ext_link *link, int stream) { snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 0); } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_clear_stream_id); int snd_hdac_ext_bus_link_get(struct hdac_bus *bus, struct hdac_ext_link *link) struct hdac_ext_link *hlink) { unsigned long codec_mask; int ret = 0; Loading @@ -269,18 +287,18 @@ int snd_hdac_ext_bus_link_get(struct hdac_bus *bus, * if we move from 0 to 1, count will be 1 so power up this link * as well, also check the dma status and trigger that */ if (++link->ref_count == 1) { if (++hlink->ref_count == 1) { if (!bus->cmd_dma_state) { snd_hdac_bus_init_cmd_io(bus); bus->cmd_dma_state = true; } ret = snd_hdac_ext_bus_link_power_up(link); ret = snd_hdac_ext_bus_link_power_up(hlink); /* * clear the register to invalidate all the output streams */ snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, snd_hdac_updatew(hlink->ml_addr, AZX_REG_ML_LOSIDV, AZX_ML_LOSIDV_STREAM_MASK, 0); /* * wait for 521usec for codec to report status Loading @@ -300,10 +318,10 @@ int snd_hdac_ext_bus_link_get(struct hdac_bus *bus, EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_get); int snd_hdac_ext_bus_link_put(struct hdac_bus *bus, struct hdac_ext_link *link) struct hdac_ext_link *hlink) { int ret = 0; struct hdac_ext_link *hlink; struct hdac_ext_link *hlink_tmp; bool link_up = false; mutex_lock(&bus->lock); Loading @@ -312,15 +330,15 @@ int snd_hdac_ext_bus_link_put(struct hdac_bus *bus, * if we move from 1 to 0, count will be 0 * so power down this link as well */ if (--link->ref_count == 0) { ret = snd_hdac_ext_bus_link_power_down(link); if (--hlink->ref_count == 0) { ret = snd_hdac_ext_bus_link_power_down(hlink); /* * now check if all links are off, if so turn off * cmd dma as well */ list_for_each_entry(hlink, &bus->hlink_list, list) { if (hlink->ref_count) { list_for_each_entry(hlink_tmp, &bus->hlink_list, list) { if (hlink_tmp->ref_count) { link_up = true; break; } Loading @@ -341,7 +359,7 @@ static void hdac_ext_codec_link_up(struct hdac_device *codec) { const char *devname = dev_name(&codec->dev); struct hdac_ext_link *hlink = snd_hdac_ext_bus_get_link(codec->bus, devname); snd_hdac_ext_bus_get_hlink_by_name(codec->bus, devname); if (hlink) snd_hdac_ext_bus_link_get(codec->bus, hlink); Loading @@ -351,7 +369,7 @@ static void hdac_ext_codec_link_down(struct hdac_device *codec) { const char *devname = dev_name(&codec->dev); struct hdac_ext_link *hlink = snd_hdac_ext_bus_get_link(codec->bus, devname); snd_hdac_ext_bus_get_hlink_by_name(codec->bus, devname); if (hlink) snd_hdac_ext_bus_link_put(codec->bus, hlink); Loading sound/hda/ext/hdac_ext_stream.c +20 −183 Original line number Diff line number Diff line Loading @@ -39,20 +39,6 @@ static void snd_hdac_ext_stream_init(struct hdac_bus *bus, AZX_PPLC_INTERVAL * idx; } if (bus->spbcap) { hext_stream->spib_addr = bus->spbcap + AZX_SPB_BASE + AZX_SPB_INTERVAL * idx + AZX_SPB_SPIB; hext_stream->fifo_addr = bus->spbcap + AZX_SPB_BASE + AZX_SPB_INTERVAL * idx + AZX_SPB_MAXFIFO; } if (bus->drsmcap) hext_stream->dpibr_addr = bus->drsmcap + AZX_DRSM_BASE + AZX_DRSM_INTERVAL * idx; hext_stream->decoupled = false; snd_hdac_stream_init(bus, &hext_stream->hstream, idx, direction, tag); } Loading Loading @@ -140,36 +126,36 @@ void snd_hdac_ext_stream_decouple(struct hdac_bus *bus, EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_decouple); /** * snd_hdac_ext_link_stream_start - start a stream * snd_hdac_ext_stream_start - start a stream * @hext_stream: HD-audio ext core stream to start */ void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *hext_stream) void snd_hdac_ext_stream_start(struct hdac_ext_stream *hext_stream) { snd_hdac_updatel(hext_stream->pplc_addr, AZX_REG_PPLCCTL, AZX_PPLCCTL_RUN, AZX_PPLCCTL_RUN); } EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_start); EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_start); /** * snd_hdac_ext_link_stream_clear - stop a stream DMA * snd_hdac_ext_stream_clear - stop a stream DMA * @hext_stream: HD-audio ext core stream to stop */ void snd_hdac_ext_link_stream_clear(struct hdac_ext_stream *hext_stream) void snd_hdac_ext_stream_clear(struct hdac_ext_stream *hext_stream) { snd_hdac_updatel(hext_stream->pplc_addr, AZX_REG_PPLCCTL, AZX_PPLCCTL_RUN, 0); } EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_clear); EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_clear); /** * snd_hdac_ext_link_stream_reset - reset a stream * snd_hdac_ext_stream_reset - reset a stream * @hext_stream: HD-audio ext core stream to reset */ void snd_hdac_ext_link_stream_reset(struct hdac_ext_stream *hext_stream) void snd_hdac_ext_stream_reset(struct hdac_ext_stream *hext_stream) { unsigned char val; int timeout; snd_hdac_ext_link_stream_clear(hext_stream); snd_hdac_ext_stream_clear(hext_stream); snd_hdac_updatel(hext_stream->pplc_addr, AZX_REG_PPLCCTL, AZX_PPLCCTL_STRST, AZX_PPLCCTL_STRST); Loading @@ -196,20 +182,20 @@ void snd_hdac_ext_link_stream_reset(struct hdac_ext_stream *hext_stream) } while (--timeout); } EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_reset); EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_reset); /** * snd_hdac_ext_link_stream_setup - set up the SD for streaming * snd_hdac_ext_stream_setup - set up the SD for streaming * @hext_stream: HD-audio ext core stream to set up * @fmt: stream format */ int snd_hdac_ext_link_stream_setup(struct hdac_ext_stream *hext_stream, int fmt) int snd_hdac_ext_stream_setup(struct hdac_ext_stream *hext_stream, int fmt) { struct hdac_stream *hstream = &hext_stream->hstream; unsigned int val; /* make sure the run bit is zero for SD */ snd_hdac_ext_link_stream_clear(hext_stream); snd_hdac_ext_stream_clear(hext_stream); /* program the stream_tag */ val = readl(hext_stream->pplc_addr + AZX_REG_PPLCCTL); val = (val & ~AZX_PPLCCTL_STRM_MASK) | Loading @@ -221,34 +207,10 @@ int snd_hdac_ext_link_stream_setup(struct hdac_ext_stream *hext_stream, int fmt) return 0; } EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_setup); /** * snd_hdac_ext_link_set_stream_id - maps stream id to link output * @link: HD-audio ext link to set up * @stream: stream id */ void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link, int stream) { snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 1 << stream); } EXPORT_SYMBOL_GPL(snd_hdac_ext_link_set_stream_id); /** * snd_hdac_ext_link_clear_stream_id - maps stream id to link output * @link: HD-audio ext link to set up * @stream: stream id */ void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link, int stream) { snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 0); } EXPORT_SYMBOL_GPL(snd_hdac_ext_link_clear_stream_id); EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_setup); static struct hdac_ext_stream * hdac_ext_link_stream_assign(struct hdac_bus *bus, hdac_ext_link_dma_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream) { struct hdac_ext_stream *res = NULL; Loading Loading @@ -284,7 +246,7 @@ hdac_ext_link_stream_assign(struct hdac_bus *bus, } static struct hdac_ext_stream * hdac_ext_host_stream_assign(struct hdac_bus *bus, hdac_ext_host_dma_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream) { struct hdac_ext_stream *res = NULL; Loading Loading @@ -353,10 +315,10 @@ struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_bus *bus, return hext_stream; case HDAC_EXT_STREAM_TYPE_HOST: return hdac_ext_host_stream_assign(bus, substream); return hdac_ext_host_dma_stream_assign(bus, substream); case HDAC_EXT_STREAM_TYPE_LINK: return hdac_ext_link_stream_assign(bus, substream); return hdac_ext_link_dma_stream_assign(bus, substream); default: return NULL; Loading Loading @@ -405,128 +367,3 @@ void snd_hdac_ext_stream_release(struct hdac_ext_stream *hext_stream, int type) } EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_release); /** * snd_hdac_ext_stream_spbcap_enable - enable SPIB for a stream * @bus: HD-audio core bus * @enable: flag to enable/disable SPIB * @index: stream index for which SPIB need to be enabled */ void snd_hdac_ext_stream_spbcap_enable(struct hdac_bus *bus, bool enable, int index) { u32 mask = 0; if (!bus->spbcap) { dev_err(bus->dev, "Address of SPB capability is NULL\n"); return; } mask |= (1 << index); if (enable) snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, mask); else snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, 0); } EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_spbcap_enable); /** * snd_hdac_ext_stream_set_spib - sets the spib value of a stream * @bus: HD-audio core bus * @hext_stream: hdac_ext_stream * @value: spib value to set */ int snd_hdac_ext_stream_set_spib(struct hdac_bus *bus, struct hdac_ext_stream *hext_stream, u32 value) { if (!bus->spbcap) { dev_err(bus->dev, "Address of SPB capability is NULL\n"); return -EINVAL; } writel(value, hext_stream->spib_addr); return 0; } EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_spib); /** * snd_hdac_ext_stream_get_spbmaxfifo - gets the spib value of a stream * @bus: HD-audio core bus * @hext_stream: hdac_ext_stream * * Return maxfifo for the stream */ int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_bus *bus, struct hdac_ext_stream *hext_stream) { if (!bus->spbcap) { dev_err(bus->dev, "Address of SPB capability is NULL\n"); return -EINVAL; } return readl(hext_stream->fifo_addr); } EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_get_spbmaxfifo); /** * snd_hdac_ext_stream_drsm_enable - enable DMA resume for a stream * @bus: HD-audio core bus * @enable: flag to enable/disable DRSM * @index: stream index for which DRSM need to be enabled */ void snd_hdac_ext_stream_drsm_enable(struct hdac_bus *bus, bool enable, int index) { u32 mask = 0; if (!bus->drsmcap) { dev_err(bus->dev, "Address of DRSM capability is NULL\n"); return; } mask |= (1 << index); if (enable) snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, mask); else snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, 0); } EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_drsm_enable); /** * snd_hdac_ext_stream_set_dpibr - sets the dpibr value of a stream * @bus: HD-audio core bus * @hext_stream: hdac_ext_stream * @value: dpib value to set */ int snd_hdac_ext_stream_set_dpibr(struct hdac_bus *bus, struct hdac_ext_stream *hext_stream, u32 value) { if (!bus->drsmcap) { dev_err(bus->dev, "Address of DRSM capability is NULL\n"); return -EINVAL; } writel(value, hext_stream->dpibr_addr); return 0; } EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_dpibr); /** * snd_hdac_ext_stream_set_lpib - sets the lpib value of a stream * @hext_stream: hdac_ext_stream * @value: lpib value to set */ int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *hext_stream, u32 value) { snd_hdac_stream_writel(&hext_stream->hstream, SD_LPIB, value); return 0; } EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_lpib); sound/hda/hdac_stream.c +136 −0 Original line number Diff line number Diff line Loading @@ -103,6 +103,20 @@ void snd_hdac_stream_init(struct hdac_bus *bus, struct hdac_stream *azx_dev, azx_dev->stream_tag = tag; snd_hdac_dsp_lock_init(azx_dev); list_add_tail(&azx_dev->list, &bus->stream_list); if (bus->spbcap) { azx_dev->spib_addr = bus->spbcap + AZX_SPB_BASE + AZX_SPB_INTERVAL * idx + AZX_SPB_SPIB; azx_dev->fifo_addr = bus->spbcap + AZX_SPB_BASE + AZX_SPB_INTERVAL * idx + AZX_SPB_MAXFIFO; } if (bus->drsmcap) azx_dev->dpibr_addr = bus->drsmcap + AZX_DRSM_BASE + AZX_DRSM_INTERVAL * idx; } EXPORT_SYMBOL_GPL(snd_hdac_stream_init); Loading Loading @@ -718,6 +732,128 @@ void snd_hdac_stream_sync(struct hdac_stream *azx_dev, bool start, } EXPORT_SYMBOL_GPL(snd_hdac_stream_sync); /** * snd_hdac_stream_spbcap_enable - enable SPIB for a stream * @bus: HD-audio core bus * @enable: flag to enable/disable SPIB * @index: stream index for which SPIB need to be enabled */ void snd_hdac_stream_spbcap_enable(struct hdac_bus *bus, bool enable, int index) { u32 mask = 0; if (!bus->spbcap) { dev_err(bus->dev, "Address of SPB capability is NULL\n"); return; } mask |= (1 << index); if (enable) snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, mask); else snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, 0); } EXPORT_SYMBOL_GPL(snd_hdac_stream_spbcap_enable); /** * snd_hdac_stream_set_spib - sets the spib value of a stream * @bus: HD-audio core bus * @azx_dev: hdac_stream * @value: spib value to set */ int snd_hdac_stream_set_spib(struct hdac_bus *bus, struct hdac_stream *azx_dev, u32 value) { if (!bus->spbcap) { dev_err(bus->dev, "Address of SPB capability is NULL\n"); return -EINVAL; } writel(value, azx_dev->spib_addr); return 0; } EXPORT_SYMBOL_GPL(snd_hdac_stream_set_spib); /** * snd_hdac_stream_get_spbmaxfifo - gets the spib value of a stream * @bus: HD-audio core bus * @azx_dev: hdac_stream * * Return maxfifo for the stream */ int snd_hdac_stream_get_spbmaxfifo(struct hdac_bus *bus, struct hdac_stream *azx_dev) { if (!bus->spbcap) { dev_err(bus->dev, "Address of SPB capability is NULL\n"); return -EINVAL; } return readl(azx_dev->fifo_addr); } EXPORT_SYMBOL_GPL(snd_hdac_stream_get_spbmaxfifo); /** * snd_hdac_stream_drsm_enable - enable DMA resume for a stream * @bus: HD-audio core bus * @enable: flag to enable/disable DRSM * @index: stream index for which DRSM need to be enabled */ void snd_hdac_stream_drsm_enable(struct hdac_bus *bus, bool enable, int index) { u32 mask = 0; if (!bus->drsmcap) { dev_err(bus->dev, "Address of DRSM capability is NULL\n"); return; } mask |= (1 << index); if (enable) snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, mask); else snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, 0); } EXPORT_SYMBOL_GPL(snd_hdac_stream_drsm_enable); /** * snd_hdac_stream_set_dpibr - sets the dpibr value of a stream * @bus: HD-audio core bus * @azx_dev: hdac_stream * @value: dpib value to set */ int snd_hdac_stream_set_dpibr(struct hdac_bus *bus, struct hdac_stream *azx_dev, u32 value) { if (!bus->drsmcap) { dev_err(bus->dev, "Address of DRSM capability is NULL\n"); return -EINVAL; } writel(value, azx_dev->dpibr_addr); return 0; } EXPORT_SYMBOL_GPL(snd_hdac_stream_set_dpibr); /** * snd_hdac_stream_set_lpib - sets the lpib value of a stream * @azx_dev: hdac_stream * @value: lpib value to set */ int snd_hdac_stream_set_lpib(struct hdac_stream *azx_dev, u32 value) { snd_hdac_stream_writel(azx_dev, SD_LPIB, value); return 0; } EXPORT_SYMBOL_GPL(snd_hdac_stream_set_lpib); #ifdef CONFIG_SND_HDA_DSP_LOADER /** * snd_hdac_dsp_prepare - prepare for DSP loading Loading Loading
include/sound/hdaudio.h +26 −0 Original line number Diff line number Diff line Loading @@ -495,6 +495,13 @@ static inline u16 snd_hdac_reg_readw(struct hdac_bus *bus, void __iomem *addr) snd_hdac_chip_writeb(chip, reg, \ (snd_hdac_chip_readb(chip, reg) & ~(mask)) | (val)) /* update register macro */ #define snd_hdac_updatel(addr, reg, mask, val) \ writel(((readl(addr + reg) & ~(mask)) | (val)), addr + reg) #define snd_hdac_updatew(addr, reg, mask, val) \ writew(((readw(addr + reg) & ~(mask)) | (val)), addr + reg) /* * HD-audio stream */ Loading @@ -511,6 +518,13 @@ struct hdac_stream { void __iomem *sd_addr; /* stream descriptor pointer */ void __iomem *spib_addr; /* software position in buffers stream pointer */ void __iomem *fifo_addr; /* software position Max fifos stream pointer */ void __iomem *dpibr_addr; /* DMA position in buffer resume pointer */ u32 dpib; /* DMA position in buffer */ u32 lpib; /* Linear position in buffer */ u32 sd_int_sta_mask; /* stream int status mask */ /* pcm support */ Loading Loading @@ -575,6 +589,18 @@ void snd_hdac_stream_timecounter_init(struct hdac_stream *azx_dev, int snd_hdac_get_stream_stripe_ctl(struct hdac_bus *bus, struct snd_pcm_substream *substream); void snd_hdac_stream_spbcap_enable(struct hdac_bus *chip, bool enable, int index); int snd_hdac_stream_set_spib(struct hdac_bus *bus, struct hdac_stream *azx_dev, u32 value); int snd_hdac_stream_get_spbmaxfifo(struct hdac_bus *bus, struct hdac_stream *azx_dev); void snd_hdac_stream_drsm_enable(struct hdac_bus *bus, bool enable, int index); int snd_hdac_stream_set_dpibr(struct hdac_bus *bus, struct hdac_stream *azx_dev, u32 value); int snd_hdac_stream_set_lpib(struct hdac_stream *azx_dev, u32 value); /* * macros for easy use */ Loading
include/sound/hdaudio_ext.h +16 −50 Original line number Diff line number Diff line Loading @@ -23,12 +23,9 @@ void snd_hdac_ext_bus_device_remove(struct hdac_bus *bus); void snd_hdac_ext_bus_ppcap_enable(struct hdac_bus *chip, bool enable); void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_bus *chip, bool enable); void snd_hdac_ext_stream_spbcap_enable(struct hdac_bus *chip, bool enable, int index); int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus); struct hdac_ext_link *snd_hdac_ext_bus_link_at(struct hdac_bus *bus, int addr); struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_bus *bus, struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_addr(struct hdac_bus *bus, int addr); struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_name(struct hdac_bus *bus, const char *codec_name); enum hdac_ext_stream_type { Loading @@ -43,11 +40,6 @@ enum hdac_ext_stream_type { * @hstream: hdac_stream * @pphc_addr: processing pipe host stream pointer * @pplc_addr: processing pipe link stream pointer * @spib_addr: software position in buffers stream pointer * @fifo_addr: software position Max fifos stream pointer * @dpibr_addr: DMA position in buffer resume pointer * @dpib: DMA position in buffer * @lpib: Linear position in buffer * @decoupled: stream host and link is decoupled * @link_locked: link is locked * @link_prepared: link is prepared Loading @@ -59,13 +51,6 @@ struct hdac_ext_stream { void __iomem *pphc_addr; void __iomem *pplc_addr; void __iomem *spib_addr; void __iomem *fifo_addr; void __iomem *dpibr_addr; u32 dpib; u32 lpib; bool decoupled:1; bool link_locked:1; bool link_prepared; Loading @@ -80,7 +65,7 @@ struct hdac_ext_stream { int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx, int num_stream, int dir); void snd_hdac_ext_stream_free_all(struct hdac_bus *bus); void snd_hdac_link_free_all(struct hdac_bus *bus); void snd_hdac_ext_link_free_all(struct hdac_bus *bus); struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream, int type); Loading @@ -90,20 +75,10 @@ void snd_hdac_ext_stream_decouple_locked(struct hdac_bus *bus, void snd_hdac_ext_stream_decouple(struct hdac_bus *bus, struct hdac_ext_stream *azx_dev, bool decouple); int snd_hdac_ext_stream_set_spib(struct hdac_bus *bus, struct hdac_ext_stream *hext_stream, u32 value); int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_bus *bus, struct hdac_ext_stream *hext_stream); void snd_hdac_ext_stream_drsm_enable(struct hdac_bus *bus, bool enable, int index); int snd_hdac_ext_stream_set_dpibr(struct hdac_bus *bus, struct hdac_ext_stream *hext_stream, u32 value); int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *hext_stream, u32 value); void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *hext_stream); void snd_hdac_ext_link_stream_clear(struct hdac_ext_stream *hext_stream); void snd_hdac_ext_link_stream_reset(struct hdac_ext_stream *hext_stream); int snd_hdac_ext_link_stream_setup(struct hdac_ext_stream *hext_stream, int fmt); void snd_hdac_ext_stream_start(struct hdac_ext_stream *hext_stream); void snd_hdac_ext_stream_clear(struct hdac_ext_stream *hext_stream); void snd_hdac_ext_stream_reset(struct hdac_ext_stream *hext_stream); int snd_hdac_ext_stream_setup(struct hdac_ext_stream *hext_stream, int fmt); struct hdac_ext_link { struct hdac_bus *bus; Loading @@ -117,29 +92,20 @@ struct hdac_ext_link { struct list_head list; }; int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link); int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link); int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *hlink); int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *hlink); int snd_hdac_ext_bus_link_power_up_all(struct hdac_bus *bus); int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus); void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link, void snd_hdac_ext_bus_link_set_stream_id(struct hdac_ext_link *hlink, int stream); void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link, void snd_hdac_ext_bus_link_clear_stream_id(struct hdac_ext_link *hlink, int stream); int snd_hdac_ext_bus_link_get(struct hdac_bus *bus, struct hdac_ext_link *link); int snd_hdac_ext_bus_link_put(struct hdac_bus *bus, struct hdac_ext_link *link); int snd_hdac_ext_bus_link_get(struct hdac_bus *bus, struct hdac_ext_link *hlink); int snd_hdac_ext_bus_link_put(struct hdac_bus *bus, struct hdac_ext_link *hlink); void snd_hdac_ext_bus_link_power(struct hdac_device *codec, bool enable); /* update register macro */ #define snd_hdac_updatel(addr, reg, mask, val) \ writel(((readl(addr + reg) & ~(mask)) | (val)), \ addr + reg) #define snd_hdac_updatew(addr, reg, mask, val) \ writew(((readw(addr + reg) & ~(mask)) | (val)), \ addr + reg) #define snd_hdac_adsp_writeb(chip, reg, value) \ snd_hdac_reg_writeb(chip, (chip)->dsp_ba + (reg), value) #define snd_hdac_adsp_readb(chip, reg) \ Loading
sound/hda/ext/hdac_ext_controller.c +67 −49 Original line number Diff line number Diff line Loading @@ -108,49 +108,47 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus) EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_ml_capabilities); /** * snd_hdac_link_free_all- free hdac extended link objects * snd_hdac_ext_link_free_all- free hdac extended link objects * * @bus: the pointer to HDAC bus object */ void snd_hdac_link_free_all(struct hdac_bus *bus) void snd_hdac_ext_link_free_all(struct hdac_bus *bus) { struct hdac_ext_link *l; struct hdac_ext_link *hlink; while (!list_empty(&bus->hlink_list)) { l = list_first_entry(&bus->hlink_list, struct hdac_ext_link, list); list_del(&l->list); kfree(l); hlink = list_first_entry(&bus->hlink_list, struct hdac_ext_link, list); list_del(&hlink->list); kfree(hlink); } } EXPORT_SYMBOL_GPL(snd_hdac_link_free_all); EXPORT_SYMBOL_GPL(snd_hdac_ext_link_free_all); /** * snd_hdac_ext_bus_link_at - get link at specified address * @bus: link's parent bus device * snd_hdac_ext_bus_get_hlink_by_addr - get hlink at specified address * @bus: hlink's parent bus device * @addr: codec device address * * Returns link object or NULL if matching link is not found. * Returns hlink object or NULL if matching hlink is not found. */ struct hdac_ext_link *snd_hdac_ext_bus_link_at(struct hdac_bus *bus, int addr) struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_addr(struct hdac_bus *bus, int addr) { struct hdac_ext_link *hlink; int i; list_for_each_entry(hlink, &bus->hlink_list, list) for (i = 0; i < HDA_MAX_CODECS; i++) if (hlink->lsdiid & (0x1 << addr)) return hlink; return NULL; } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_at); EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_hlink_by_addr); /** * snd_hdac_ext_bus_get_link - get link based on codec name * snd_hdac_ext_bus_get_hlink_by_name - get hlink based on codec name * @bus: the pointer to HDAC bus object * @codec_name: codec name */ struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_bus *bus, struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_name(struct hdac_bus *bus, const char *codec_name) { int bus_idx, addr; Loading @@ -162,11 +160,11 @@ struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_bus *bus, if (addr < 0 || addr > 31) return NULL; return snd_hdac_ext_bus_link_at(bus, addr); return snd_hdac_ext_bus_get_hlink_by_addr(bus, addr); } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_link); EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_hlink_by_name); static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable) static int check_hdac_link_power_active(struct hdac_ext_link *hlink, bool enable) { int timeout; u32 val; Loading @@ -176,7 +174,7 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable) timeout = 150; do { val = readl(link->ml_addr + AZX_REG_ML_LCTL); val = readl(hlink->ml_addr + AZX_REG_ML_LCTL); if (enable) { if (((val & mask) >> AZX_ML_LCTL_CPA_SHIFT)) return 0; Loading @@ -192,26 +190,26 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable) /** * snd_hdac_ext_bus_link_power_up -power up hda link * @link: HD-audio extended link * @hlink: HD-audio extended link */ int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link) int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *hlink) { snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL, snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, AZX_ML_LCTL_SPA, AZX_ML_LCTL_SPA); return check_hdac_link_power_active(link, true); return check_hdac_link_power_active(hlink, true); } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_up); /** * snd_hdac_ext_bus_link_power_down -power down hda link * @link: HD-audio extended link * @hlink: HD-audio extended link */ int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link) int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *hlink) { snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL, AZX_ML_LCTL_SPA, 0); snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, AZX_ML_LCTL_SPA, 0); return check_hdac_link_power_active(link, false); return check_hdac_link_power_active(hlink, false); } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down); Loading @@ -225,9 +223,7 @@ int snd_hdac_ext_bus_link_power_up_all(struct hdac_bus *bus) int ret; list_for_each_entry(hlink, &bus->hlink_list, list) { snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, AZX_ML_LCTL_SPA, AZX_ML_LCTL_SPA); ret = check_hdac_link_power_active(hlink, true); ret = snd_hdac_ext_bus_link_power_up(hlink); if (ret < 0) return ret; } Loading @@ -246,9 +242,7 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus) int ret; list_for_each_entry(hlink, &bus->hlink_list, list) { snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, AZX_ML_LCTL_SPA, 0); ret = check_hdac_link_power_active(hlink, false); ret = snd_hdac_ext_bus_link_power_down(hlink); if (ret < 0) return ret; } Loading @@ -257,8 +251,32 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus) } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down_all); /** * snd_hdac_ext_bus_link_set_stream_id - maps stream id to link output * @link: HD-audio ext link to set up * @stream: stream id */ void snd_hdac_ext_bus_link_set_stream_id(struct hdac_ext_link *link, int stream) { snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 1 << stream); } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_set_stream_id); /** * snd_hdac_ext_bus_link_clear_stream_id - maps stream id to link output * @link: HD-audio ext link to set up * @stream: stream id */ void snd_hdac_ext_bus_link_clear_stream_id(struct hdac_ext_link *link, int stream) { snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 0); } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_clear_stream_id); int snd_hdac_ext_bus_link_get(struct hdac_bus *bus, struct hdac_ext_link *link) struct hdac_ext_link *hlink) { unsigned long codec_mask; int ret = 0; Loading @@ -269,18 +287,18 @@ int snd_hdac_ext_bus_link_get(struct hdac_bus *bus, * if we move from 0 to 1, count will be 1 so power up this link * as well, also check the dma status and trigger that */ if (++link->ref_count == 1) { if (++hlink->ref_count == 1) { if (!bus->cmd_dma_state) { snd_hdac_bus_init_cmd_io(bus); bus->cmd_dma_state = true; } ret = snd_hdac_ext_bus_link_power_up(link); ret = snd_hdac_ext_bus_link_power_up(hlink); /* * clear the register to invalidate all the output streams */ snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, snd_hdac_updatew(hlink->ml_addr, AZX_REG_ML_LOSIDV, AZX_ML_LOSIDV_STREAM_MASK, 0); /* * wait for 521usec for codec to report status Loading @@ -300,10 +318,10 @@ int snd_hdac_ext_bus_link_get(struct hdac_bus *bus, EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_get); int snd_hdac_ext_bus_link_put(struct hdac_bus *bus, struct hdac_ext_link *link) struct hdac_ext_link *hlink) { int ret = 0; struct hdac_ext_link *hlink; struct hdac_ext_link *hlink_tmp; bool link_up = false; mutex_lock(&bus->lock); Loading @@ -312,15 +330,15 @@ int snd_hdac_ext_bus_link_put(struct hdac_bus *bus, * if we move from 1 to 0, count will be 0 * so power down this link as well */ if (--link->ref_count == 0) { ret = snd_hdac_ext_bus_link_power_down(link); if (--hlink->ref_count == 0) { ret = snd_hdac_ext_bus_link_power_down(hlink); /* * now check if all links are off, if so turn off * cmd dma as well */ list_for_each_entry(hlink, &bus->hlink_list, list) { if (hlink->ref_count) { list_for_each_entry(hlink_tmp, &bus->hlink_list, list) { if (hlink_tmp->ref_count) { link_up = true; break; } Loading @@ -341,7 +359,7 @@ static void hdac_ext_codec_link_up(struct hdac_device *codec) { const char *devname = dev_name(&codec->dev); struct hdac_ext_link *hlink = snd_hdac_ext_bus_get_link(codec->bus, devname); snd_hdac_ext_bus_get_hlink_by_name(codec->bus, devname); if (hlink) snd_hdac_ext_bus_link_get(codec->bus, hlink); Loading @@ -351,7 +369,7 @@ static void hdac_ext_codec_link_down(struct hdac_device *codec) { const char *devname = dev_name(&codec->dev); struct hdac_ext_link *hlink = snd_hdac_ext_bus_get_link(codec->bus, devname); snd_hdac_ext_bus_get_hlink_by_name(codec->bus, devname); if (hlink) snd_hdac_ext_bus_link_put(codec->bus, hlink); Loading
sound/hda/ext/hdac_ext_stream.c +20 −183 Original line number Diff line number Diff line Loading @@ -39,20 +39,6 @@ static void snd_hdac_ext_stream_init(struct hdac_bus *bus, AZX_PPLC_INTERVAL * idx; } if (bus->spbcap) { hext_stream->spib_addr = bus->spbcap + AZX_SPB_BASE + AZX_SPB_INTERVAL * idx + AZX_SPB_SPIB; hext_stream->fifo_addr = bus->spbcap + AZX_SPB_BASE + AZX_SPB_INTERVAL * idx + AZX_SPB_MAXFIFO; } if (bus->drsmcap) hext_stream->dpibr_addr = bus->drsmcap + AZX_DRSM_BASE + AZX_DRSM_INTERVAL * idx; hext_stream->decoupled = false; snd_hdac_stream_init(bus, &hext_stream->hstream, idx, direction, tag); } Loading Loading @@ -140,36 +126,36 @@ void snd_hdac_ext_stream_decouple(struct hdac_bus *bus, EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_decouple); /** * snd_hdac_ext_link_stream_start - start a stream * snd_hdac_ext_stream_start - start a stream * @hext_stream: HD-audio ext core stream to start */ void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *hext_stream) void snd_hdac_ext_stream_start(struct hdac_ext_stream *hext_stream) { snd_hdac_updatel(hext_stream->pplc_addr, AZX_REG_PPLCCTL, AZX_PPLCCTL_RUN, AZX_PPLCCTL_RUN); } EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_start); EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_start); /** * snd_hdac_ext_link_stream_clear - stop a stream DMA * snd_hdac_ext_stream_clear - stop a stream DMA * @hext_stream: HD-audio ext core stream to stop */ void snd_hdac_ext_link_stream_clear(struct hdac_ext_stream *hext_stream) void snd_hdac_ext_stream_clear(struct hdac_ext_stream *hext_stream) { snd_hdac_updatel(hext_stream->pplc_addr, AZX_REG_PPLCCTL, AZX_PPLCCTL_RUN, 0); } EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_clear); EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_clear); /** * snd_hdac_ext_link_stream_reset - reset a stream * snd_hdac_ext_stream_reset - reset a stream * @hext_stream: HD-audio ext core stream to reset */ void snd_hdac_ext_link_stream_reset(struct hdac_ext_stream *hext_stream) void snd_hdac_ext_stream_reset(struct hdac_ext_stream *hext_stream) { unsigned char val; int timeout; snd_hdac_ext_link_stream_clear(hext_stream); snd_hdac_ext_stream_clear(hext_stream); snd_hdac_updatel(hext_stream->pplc_addr, AZX_REG_PPLCCTL, AZX_PPLCCTL_STRST, AZX_PPLCCTL_STRST); Loading @@ -196,20 +182,20 @@ void snd_hdac_ext_link_stream_reset(struct hdac_ext_stream *hext_stream) } while (--timeout); } EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_reset); EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_reset); /** * snd_hdac_ext_link_stream_setup - set up the SD for streaming * snd_hdac_ext_stream_setup - set up the SD for streaming * @hext_stream: HD-audio ext core stream to set up * @fmt: stream format */ int snd_hdac_ext_link_stream_setup(struct hdac_ext_stream *hext_stream, int fmt) int snd_hdac_ext_stream_setup(struct hdac_ext_stream *hext_stream, int fmt) { struct hdac_stream *hstream = &hext_stream->hstream; unsigned int val; /* make sure the run bit is zero for SD */ snd_hdac_ext_link_stream_clear(hext_stream); snd_hdac_ext_stream_clear(hext_stream); /* program the stream_tag */ val = readl(hext_stream->pplc_addr + AZX_REG_PPLCCTL); val = (val & ~AZX_PPLCCTL_STRM_MASK) | Loading @@ -221,34 +207,10 @@ int snd_hdac_ext_link_stream_setup(struct hdac_ext_stream *hext_stream, int fmt) return 0; } EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_setup); /** * snd_hdac_ext_link_set_stream_id - maps stream id to link output * @link: HD-audio ext link to set up * @stream: stream id */ void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link, int stream) { snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 1 << stream); } EXPORT_SYMBOL_GPL(snd_hdac_ext_link_set_stream_id); /** * snd_hdac_ext_link_clear_stream_id - maps stream id to link output * @link: HD-audio ext link to set up * @stream: stream id */ void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link, int stream) { snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 0); } EXPORT_SYMBOL_GPL(snd_hdac_ext_link_clear_stream_id); EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_setup); static struct hdac_ext_stream * hdac_ext_link_stream_assign(struct hdac_bus *bus, hdac_ext_link_dma_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream) { struct hdac_ext_stream *res = NULL; Loading Loading @@ -284,7 +246,7 @@ hdac_ext_link_stream_assign(struct hdac_bus *bus, } static struct hdac_ext_stream * hdac_ext_host_stream_assign(struct hdac_bus *bus, hdac_ext_host_dma_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream) { struct hdac_ext_stream *res = NULL; Loading Loading @@ -353,10 +315,10 @@ struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_bus *bus, return hext_stream; case HDAC_EXT_STREAM_TYPE_HOST: return hdac_ext_host_stream_assign(bus, substream); return hdac_ext_host_dma_stream_assign(bus, substream); case HDAC_EXT_STREAM_TYPE_LINK: return hdac_ext_link_stream_assign(bus, substream); return hdac_ext_link_dma_stream_assign(bus, substream); default: return NULL; Loading Loading @@ -405,128 +367,3 @@ void snd_hdac_ext_stream_release(struct hdac_ext_stream *hext_stream, int type) } EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_release); /** * snd_hdac_ext_stream_spbcap_enable - enable SPIB for a stream * @bus: HD-audio core bus * @enable: flag to enable/disable SPIB * @index: stream index for which SPIB need to be enabled */ void snd_hdac_ext_stream_spbcap_enable(struct hdac_bus *bus, bool enable, int index) { u32 mask = 0; if (!bus->spbcap) { dev_err(bus->dev, "Address of SPB capability is NULL\n"); return; } mask |= (1 << index); if (enable) snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, mask); else snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, 0); } EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_spbcap_enable); /** * snd_hdac_ext_stream_set_spib - sets the spib value of a stream * @bus: HD-audio core bus * @hext_stream: hdac_ext_stream * @value: spib value to set */ int snd_hdac_ext_stream_set_spib(struct hdac_bus *bus, struct hdac_ext_stream *hext_stream, u32 value) { if (!bus->spbcap) { dev_err(bus->dev, "Address of SPB capability is NULL\n"); return -EINVAL; } writel(value, hext_stream->spib_addr); return 0; } EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_spib); /** * snd_hdac_ext_stream_get_spbmaxfifo - gets the spib value of a stream * @bus: HD-audio core bus * @hext_stream: hdac_ext_stream * * Return maxfifo for the stream */ int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_bus *bus, struct hdac_ext_stream *hext_stream) { if (!bus->spbcap) { dev_err(bus->dev, "Address of SPB capability is NULL\n"); return -EINVAL; } return readl(hext_stream->fifo_addr); } EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_get_spbmaxfifo); /** * snd_hdac_ext_stream_drsm_enable - enable DMA resume for a stream * @bus: HD-audio core bus * @enable: flag to enable/disable DRSM * @index: stream index for which DRSM need to be enabled */ void snd_hdac_ext_stream_drsm_enable(struct hdac_bus *bus, bool enable, int index) { u32 mask = 0; if (!bus->drsmcap) { dev_err(bus->dev, "Address of DRSM capability is NULL\n"); return; } mask |= (1 << index); if (enable) snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, mask); else snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, 0); } EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_drsm_enable); /** * snd_hdac_ext_stream_set_dpibr - sets the dpibr value of a stream * @bus: HD-audio core bus * @hext_stream: hdac_ext_stream * @value: dpib value to set */ int snd_hdac_ext_stream_set_dpibr(struct hdac_bus *bus, struct hdac_ext_stream *hext_stream, u32 value) { if (!bus->drsmcap) { dev_err(bus->dev, "Address of DRSM capability is NULL\n"); return -EINVAL; } writel(value, hext_stream->dpibr_addr); return 0; } EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_dpibr); /** * snd_hdac_ext_stream_set_lpib - sets the lpib value of a stream * @hext_stream: hdac_ext_stream * @value: lpib value to set */ int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *hext_stream, u32 value) { snd_hdac_stream_writel(&hext_stream->hstream, SD_LPIB, value); return 0; } EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_lpib);
sound/hda/hdac_stream.c +136 −0 Original line number Diff line number Diff line Loading @@ -103,6 +103,20 @@ void snd_hdac_stream_init(struct hdac_bus *bus, struct hdac_stream *azx_dev, azx_dev->stream_tag = tag; snd_hdac_dsp_lock_init(azx_dev); list_add_tail(&azx_dev->list, &bus->stream_list); if (bus->spbcap) { azx_dev->spib_addr = bus->spbcap + AZX_SPB_BASE + AZX_SPB_INTERVAL * idx + AZX_SPB_SPIB; azx_dev->fifo_addr = bus->spbcap + AZX_SPB_BASE + AZX_SPB_INTERVAL * idx + AZX_SPB_MAXFIFO; } if (bus->drsmcap) azx_dev->dpibr_addr = bus->drsmcap + AZX_DRSM_BASE + AZX_DRSM_INTERVAL * idx; } EXPORT_SYMBOL_GPL(snd_hdac_stream_init); Loading Loading @@ -718,6 +732,128 @@ void snd_hdac_stream_sync(struct hdac_stream *azx_dev, bool start, } EXPORT_SYMBOL_GPL(snd_hdac_stream_sync); /** * snd_hdac_stream_spbcap_enable - enable SPIB for a stream * @bus: HD-audio core bus * @enable: flag to enable/disable SPIB * @index: stream index for which SPIB need to be enabled */ void snd_hdac_stream_spbcap_enable(struct hdac_bus *bus, bool enable, int index) { u32 mask = 0; if (!bus->spbcap) { dev_err(bus->dev, "Address of SPB capability is NULL\n"); return; } mask |= (1 << index); if (enable) snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, mask); else snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, 0); } EXPORT_SYMBOL_GPL(snd_hdac_stream_spbcap_enable); /** * snd_hdac_stream_set_spib - sets the spib value of a stream * @bus: HD-audio core bus * @azx_dev: hdac_stream * @value: spib value to set */ int snd_hdac_stream_set_spib(struct hdac_bus *bus, struct hdac_stream *azx_dev, u32 value) { if (!bus->spbcap) { dev_err(bus->dev, "Address of SPB capability is NULL\n"); return -EINVAL; } writel(value, azx_dev->spib_addr); return 0; } EXPORT_SYMBOL_GPL(snd_hdac_stream_set_spib); /** * snd_hdac_stream_get_spbmaxfifo - gets the spib value of a stream * @bus: HD-audio core bus * @azx_dev: hdac_stream * * Return maxfifo for the stream */ int snd_hdac_stream_get_spbmaxfifo(struct hdac_bus *bus, struct hdac_stream *azx_dev) { if (!bus->spbcap) { dev_err(bus->dev, "Address of SPB capability is NULL\n"); return -EINVAL; } return readl(azx_dev->fifo_addr); } EXPORT_SYMBOL_GPL(snd_hdac_stream_get_spbmaxfifo); /** * snd_hdac_stream_drsm_enable - enable DMA resume for a stream * @bus: HD-audio core bus * @enable: flag to enable/disable DRSM * @index: stream index for which DRSM need to be enabled */ void snd_hdac_stream_drsm_enable(struct hdac_bus *bus, bool enable, int index) { u32 mask = 0; if (!bus->drsmcap) { dev_err(bus->dev, "Address of DRSM capability is NULL\n"); return; } mask |= (1 << index); if (enable) snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, mask); else snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, 0); } EXPORT_SYMBOL_GPL(snd_hdac_stream_drsm_enable); /** * snd_hdac_stream_set_dpibr - sets the dpibr value of a stream * @bus: HD-audio core bus * @azx_dev: hdac_stream * @value: dpib value to set */ int snd_hdac_stream_set_dpibr(struct hdac_bus *bus, struct hdac_stream *azx_dev, u32 value) { if (!bus->drsmcap) { dev_err(bus->dev, "Address of DRSM capability is NULL\n"); return -EINVAL; } writel(value, azx_dev->dpibr_addr); return 0; } EXPORT_SYMBOL_GPL(snd_hdac_stream_set_dpibr); /** * snd_hdac_stream_set_lpib - sets the lpib value of a stream * @azx_dev: hdac_stream * @value: lpib value to set */ int snd_hdac_stream_set_lpib(struct hdac_stream *azx_dev, u32 value) { snd_hdac_stream_writel(azx_dev, SD_LPIB, value); return 0; } EXPORT_SYMBOL_GPL(snd_hdac_stream_set_lpib); #ifdef CONFIG_SND_HDA_DSP_LOADER /** * snd_hdac_dsp_prepare - prepare for DSP loading Loading