int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id) { struct rsnd_mod *mod_from; struct rsnd_mod *mod_to; struct rsnd_priv *priv = rsnd_io_to_priv(io); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); int is_play = rsnd_io_is_play(io); /* * DMA failed. try to PIO mode * see * rsnd_ssi_fallback() * rsnd_rdai_continuance_probe() */ if (!dmac) return -EAGAIN; rsnd_dma_of_path(dma, io, is_play, &mod_from, &mod_to); dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1); dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0); /* for Gen2 */ if (mod_from && mod_to) dma->ops = &rsnd_dmapp_ops; else dma->ops = &rsnd_dmaen_ops; /* for Gen1, overwrite */ if (rsnd_is_gen1(priv)) dma->ops = &rsnd_dmaen_ops; return dma->ops->init(io, dma, id, mod_from, mod_to); }
static u32 rsnd_dmapp_read(struct rsnd_dma *dma, u32 reg) { struct rsnd_mod *mod = rsnd_mod_get(dma); struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); return ioread32(rsnd_dmapp_addr(dmac, dma, reg)); }
static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg) { struct rsnd_mod *mod = rsnd_mod_get(dma); struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); struct device *dev = rsnd_priv_to_dev(priv); dev_dbg(dev, "w %p : %08x\n", rsnd_dmapp_addr(dmac, dma, reg), data); iowrite32(data, rsnd_dmapp_addr(dmac, dma, reg)); }
void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma) { struct rsnd_mod *mod = rsnd_dma_to_mod(dma); struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); if (!dmac) return; dma->ops->quit(io, dma); }
static int rsnd_dmapp_attach(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); struct rsnd_priv *priv = rsnd_io_to_priv(io); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); struct device *dev = rsnd_priv_to_dev(priv); dmapp->dmapp_id = dmac->dmapp_num; dmapp->chcr = rsnd_dmapp_get_chcr(io, mod_from, mod_to) | PDMACHCR_DE; dmac->dmapp_num++; dev_dbg(dev, "id/src/dst/chcr = %d/%pad/%pad/%08x\n", dmapp->dmapp_id, &dma->src_addr, &dma->dst_addr, dmapp->chcr); return 0; }
static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { struct rsnd_mod *mod = rsnd_mod_get(dma); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); struct rsnd_priv *priv = rsnd_io_to_priv(io); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); struct device *dev = rsnd_priv_to_dev(priv); struct dma_slave_config cfg = {}; int is_play = rsnd_io_is_play(io); int ret; if (dmaen->chan) { dev_err(dev, "it already has dma channel\n"); return -EIO; } if (dev->of_node) { dmaen->chan = rsnd_dmaen_request_channel(io, mod_from, mod_to); } else { dma_cap_mask_t mask; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); dmaen->chan = dma_request_channel(mask, shdma_chan_filter, (void *)(uintptr_t)id); } if (IS_ERR_OR_NULL(dmaen->chan)) { dmaen->chan = NULL; dev_err(dev, "can't get dma channel\n"); goto rsnd_dma_channel_err; } cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; cfg.src_addr = dma->src_addr; cfg.dst_addr = dma->dst_addr; cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; dev_dbg(dev, "%s[%d] %pad -> %pad\n", rsnd_mod_name(mod), rsnd_mod_id(mod), &cfg.src_addr, &cfg.dst_addr); ret = dmaengine_slave_config(dmaen->chan, &cfg); if (ret < 0) goto rsnd_dma_attach_err; dmac->dmaen_num++; return 0; rsnd_dma_attach_err: rsnd_dmaen_remove(mod, io, priv); rsnd_dma_channel_err: /* * DMA failed. try to PIO mode * see * rsnd_ssi_fallback() * rsnd_rdai_continuance_probe() */ return -EAGAIN; }