1*c087a94bSLad Prabhakar // SPDX-License-Identifier: GPL-2.0 2*c087a94bSLad Prabhakar // 3*c087a94bSLad Prabhakar // Renesas R-Car Audio DMAC support 4*c087a94bSLad Prabhakar // 5*c087a94bSLad Prabhakar // Copyright (C) 2015 Renesas Electronics Corp. 6*c087a94bSLad Prabhakar // Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 7*c087a94bSLad Prabhakar 8*c087a94bSLad Prabhakar #include <linux/delay.h> 9*c087a94bSLad Prabhakar #include <linux/of_dma.h> 10*c087a94bSLad Prabhakar #include <sound/dmaengine_pcm.h> 11*c087a94bSLad Prabhakar #include "rsnd.h" 12*c087a94bSLad Prabhakar 13*c087a94bSLad Prabhakar /* 14*c087a94bSLad Prabhakar * Audio DMAC peri peri register 15*c087a94bSLad Prabhakar */ 16*c087a94bSLad Prabhakar #define PDMASAR 0x00 17*c087a94bSLad Prabhakar #define PDMADAR 0x04 18*c087a94bSLad Prabhakar #define PDMACHCR 0x0c 19*c087a94bSLad Prabhakar 20*c087a94bSLad Prabhakar /* PDMACHCR */ 21*c087a94bSLad Prabhakar #define PDMACHCR_DE (1 << 0) 22*c087a94bSLad Prabhakar 23*c087a94bSLad Prabhakar 24*c087a94bSLad Prabhakar struct rsnd_dmaen { 25*c087a94bSLad Prabhakar struct dma_chan *chan; 26*c087a94bSLad Prabhakar }; 27*c087a94bSLad Prabhakar 28*c087a94bSLad Prabhakar struct rsnd_dmapp { 29*c087a94bSLad Prabhakar int dmapp_id; 30*c087a94bSLad Prabhakar u32 chcr; 31*c087a94bSLad Prabhakar }; 32*c087a94bSLad Prabhakar 33*c087a94bSLad Prabhakar struct rsnd_dma { 34*c087a94bSLad Prabhakar struct rsnd_mod mod; 35*c087a94bSLad Prabhakar struct rsnd_mod *mod_from; 36*c087a94bSLad Prabhakar struct rsnd_mod *mod_to; 37*c087a94bSLad Prabhakar dma_addr_t src_addr; 38*c087a94bSLad Prabhakar dma_addr_t dst_addr; 39*c087a94bSLad Prabhakar union { 40*c087a94bSLad Prabhakar struct rsnd_dmaen en; 41*c087a94bSLad Prabhakar struct rsnd_dmapp pp; 42*c087a94bSLad Prabhakar } dma; 43*c087a94bSLad Prabhakar }; 44*c087a94bSLad Prabhakar 45*c087a94bSLad Prabhakar struct rsnd_dma_ctrl { 46*c087a94bSLad Prabhakar void __iomem *ppbase; 47*c087a94bSLad Prabhakar phys_addr_t ppres; 48*c087a94bSLad Prabhakar int dmaen_num; 49*c087a94bSLad Prabhakar int dmapp_num; 50*c087a94bSLad Prabhakar }; 51*c087a94bSLad Prabhakar 52*c087a94bSLad Prabhakar #define rsnd_priv_to_dmac(p) ((struct rsnd_dma_ctrl *)(p)->dma) 53*c087a94bSLad Prabhakar #define rsnd_mod_to_dma(_mod) container_of((_mod), struct rsnd_dma, mod) 54*c087a94bSLad Prabhakar #define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en) 55*c087a94bSLad Prabhakar #define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp) 56*c087a94bSLad Prabhakar 57*c087a94bSLad Prabhakar /* for DEBUG */ 58*c087a94bSLad Prabhakar static struct rsnd_mod_ops mem_ops = { 59*c087a94bSLad Prabhakar .name = "mem", 60*c087a94bSLad Prabhakar }; 61*c087a94bSLad Prabhakar 62*c087a94bSLad Prabhakar static struct rsnd_mod mem = { 63*c087a94bSLad Prabhakar }; 64*c087a94bSLad Prabhakar 65*c087a94bSLad Prabhakar /* 66*c087a94bSLad Prabhakar * Audio DMAC 67*c087a94bSLad Prabhakar */ 68*c087a94bSLad Prabhakar static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io, 69*c087a94bSLad Prabhakar struct rsnd_mod *mod_from, 70*c087a94bSLad Prabhakar struct rsnd_mod *mod_to) 71*c087a94bSLad Prabhakar { 72*c087a94bSLad Prabhakar if ((!mod_from && !mod_to) || 73*c087a94bSLad Prabhakar (mod_from && mod_to)) 74*c087a94bSLad Prabhakar return NULL; 75*c087a94bSLad Prabhakar 76*c087a94bSLad Prabhakar if (mod_from) 77*c087a94bSLad Prabhakar return rsnd_mod_dma_req(io, mod_from); 78*c087a94bSLad Prabhakar else 79*c087a94bSLad Prabhakar return rsnd_mod_dma_req(io, mod_to); 80*c087a94bSLad Prabhakar } 81*c087a94bSLad Prabhakar 82*c087a94bSLad Prabhakar static int rsnd_dmaen_stop(struct rsnd_mod *mod, 83*c087a94bSLad Prabhakar struct rsnd_dai_stream *io, 84*c087a94bSLad Prabhakar struct rsnd_priv *priv) 85*c087a94bSLad Prabhakar { 86*c087a94bSLad Prabhakar return snd_dmaengine_pcm_trigger(io->substream, SNDRV_PCM_TRIGGER_STOP); 87*c087a94bSLad Prabhakar } 88*c087a94bSLad Prabhakar 89*c087a94bSLad Prabhakar static int rsnd_dmaen_cleanup(struct rsnd_mod *mod, 90*c087a94bSLad Prabhakar struct rsnd_dai_stream *io, 91*c087a94bSLad Prabhakar struct rsnd_priv *priv) 92*c087a94bSLad Prabhakar { 93*c087a94bSLad Prabhakar struct rsnd_dma *dma = rsnd_mod_to_dma(mod); 94*c087a94bSLad Prabhakar struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); 95*c087a94bSLad Prabhakar 96*c087a94bSLad Prabhakar /* 97*c087a94bSLad Prabhakar * DMAEngine release uses mutex lock. 98*c087a94bSLad Prabhakar * Thus, it shouldn't be called under spinlock. 99*c087a94bSLad Prabhakar * Let's call it under prepare 100*c087a94bSLad Prabhakar */ 101*c087a94bSLad Prabhakar if (dmaen->chan) 102*c087a94bSLad Prabhakar snd_dmaengine_pcm_close_release_chan(io->substream); 103*c087a94bSLad Prabhakar 104*c087a94bSLad Prabhakar dmaen->chan = NULL; 105*c087a94bSLad Prabhakar 106*c087a94bSLad Prabhakar return 0; 107*c087a94bSLad Prabhakar } 108*c087a94bSLad Prabhakar 109*c087a94bSLad Prabhakar static int rsnd_dmaen_prepare(struct rsnd_mod *mod, 110*c087a94bSLad Prabhakar struct rsnd_dai_stream *io, 111*c087a94bSLad Prabhakar struct rsnd_priv *priv) 112*c087a94bSLad Prabhakar { 113*c087a94bSLad Prabhakar struct rsnd_dma *dma = rsnd_mod_to_dma(mod); 114*c087a94bSLad Prabhakar struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); 115*c087a94bSLad Prabhakar struct device *dev = rsnd_priv_to_dev(priv); 116*c087a94bSLad Prabhakar 117*c087a94bSLad Prabhakar /* maybe suspended */ 118*c087a94bSLad Prabhakar if (dmaen->chan) 119*c087a94bSLad Prabhakar return 0; 120*c087a94bSLad Prabhakar 121*c087a94bSLad Prabhakar /* 122*c087a94bSLad Prabhakar * DMAEngine request uses mutex lock. 123*c087a94bSLad Prabhakar * Thus, it shouldn't be called under spinlock. 124*c087a94bSLad Prabhakar * Let's call it under prepare 125*c087a94bSLad Prabhakar */ 126*c087a94bSLad Prabhakar dmaen->chan = rsnd_dmaen_request_channel(io, 127*c087a94bSLad Prabhakar dma->mod_from, 128*c087a94bSLad Prabhakar dma->mod_to); 129*c087a94bSLad Prabhakar if (IS_ERR_OR_NULL(dmaen->chan)) { 130*c087a94bSLad Prabhakar dmaen->chan = NULL; 131*c087a94bSLad Prabhakar dev_err(dev, "can't get dma channel\n"); 132*c087a94bSLad Prabhakar return -EIO; 133*c087a94bSLad Prabhakar } 134*c087a94bSLad Prabhakar 135*c087a94bSLad Prabhakar return snd_dmaengine_pcm_open(io->substream, dmaen->chan); 136*c087a94bSLad Prabhakar } 137*c087a94bSLad Prabhakar 138*c087a94bSLad Prabhakar static int rsnd_dmaen_start(struct rsnd_mod *mod, 139*c087a94bSLad Prabhakar struct rsnd_dai_stream *io, 140*c087a94bSLad Prabhakar struct rsnd_priv *priv) 141*c087a94bSLad Prabhakar { 142*c087a94bSLad Prabhakar struct rsnd_dma *dma = rsnd_mod_to_dma(mod); 143*c087a94bSLad Prabhakar struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); 144*c087a94bSLad Prabhakar struct device *dev = rsnd_priv_to_dev(priv); 145*c087a94bSLad Prabhakar struct dma_slave_config cfg = {}; 146*c087a94bSLad Prabhakar enum dma_slave_buswidth buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; 147*c087a94bSLad Prabhakar int ret; 148*c087a94bSLad Prabhakar 149*c087a94bSLad Prabhakar /* 150*c087a94bSLad Prabhakar * in case of monaural data writing or reading through Audio-DMAC 151*c087a94bSLad Prabhakar * data is always in Left Justified format, so both src and dst 152*c087a94bSLad Prabhakar * DMA Bus width need to be set equal to physical data width. 153*c087a94bSLad Prabhakar */ 154*c087a94bSLad Prabhakar if (rsnd_runtime_channel_original(io) == 1) { 155*c087a94bSLad Prabhakar struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); 156*c087a94bSLad Prabhakar int bits = snd_pcm_format_physical_width(runtime->format); 157*c087a94bSLad Prabhakar 158*c087a94bSLad Prabhakar switch (bits) { 159*c087a94bSLad Prabhakar case 8: 160*c087a94bSLad Prabhakar buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE; 161*c087a94bSLad Prabhakar break; 162*c087a94bSLad Prabhakar case 16: 163*c087a94bSLad Prabhakar buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; 164*c087a94bSLad Prabhakar break; 165*c087a94bSLad Prabhakar case 32: 166*c087a94bSLad Prabhakar buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; 167*c087a94bSLad Prabhakar break; 168*c087a94bSLad Prabhakar default: 169*c087a94bSLad Prabhakar dev_err(dev, "invalid format width %d\n", bits); 170*c087a94bSLad Prabhakar return -EINVAL; 171*c087a94bSLad Prabhakar } 172*c087a94bSLad Prabhakar } 173*c087a94bSLad Prabhakar 174*c087a94bSLad Prabhakar cfg.direction = snd_pcm_substream_to_dma_direction(io->substream); 175*c087a94bSLad Prabhakar cfg.src_addr = dma->src_addr; 176*c087a94bSLad Prabhakar cfg.dst_addr = dma->dst_addr; 177*c087a94bSLad Prabhakar cfg.src_addr_width = buswidth; 178*c087a94bSLad Prabhakar cfg.dst_addr_width = buswidth; 179*c087a94bSLad Prabhakar 180*c087a94bSLad Prabhakar dev_dbg(dev, "%s %pad -> %pad\n", 181*c087a94bSLad Prabhakar rsnd_mod_name(mod), 182*c087a94bSLad Prabhakar &cfg.src_addr, &cfg.dst_addr); 183*c087a94bSLad Prabhakar 184*c087a94bSLad Prabhakar ret = dmaengine_slave_config(dmaen->chan, &cfg); 185*c087a94bSLad Prabhakar if (ret < 0) 186*c087a94bSLad Prabhakar return ret; 187*c087a94bSLad Prabhakar 188*c087a94bSLad Prabhakar return snd_dmaengine_pcm_trigger(io->substream, SNDRV_PCM_TRIGGER_START); 189*c087a94bSLad Prabhakar } 190*c087a94bSLad Prabhakar 191*c087a94bSLad Prabhakar struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *name, 192*c087a94bSLad Prabhakar struct rsnd_mod *mod, char *x) 193*c087a94bSLad Prabhakar { 194*c087a94bSLad Prabhakar struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 195*c087a94bSLad Prabhakar struct device *dev = rsnd_priv_to_dev(priv); 196*c087a94bSLad Prabhakar struct dma_chan *chan = NULL; 197*c087a94bSLad Prabhakar struct device_node *np; 198*c087a94bSLad Prabhakar int i = 0; 199*c087a94bSLad Prabhakar 200*c087a94bSLad Prabhakar for_each_child_of_node(of_node, np) { 201*c087a94bSLad Prabhakar i = rsnd_node_fixed_index(dev, np, name, i); 202*c087a94bSLad Prabhakar if (i < 0) { 203*c087a94bSLad Prabhakar chan = NULL; 204*c087a94bSLad Prabhakar of_node_put(np); 205*c087a94bSLad Prabhakar break; 206*c087a94bSLad Prabhakar } 207*c087a94bSLad Prabhakar 208*c087a94bSLad Prabhakar if (i == rsnd_mod_id_raw(mod) && (!chan)) 209*c087a94bSLad Prabhakar chan = of_dma_request_slave_channel(np, x); 210*c087a94bSLad Prabhakar i++; 211*c087a94bSLad Prabhakar } 212*c087a94bSLad Prabhakar 213*c087a94bSLad Prabhakar /* It should call of_node_put(), since, it is rsnd_xxx_of_node() */ 214*c087a94bSLad Prabhakar of_node_put(of_node); 215*c087a94bSLad Prabhakar 216*c087a94bSLad Prabhakar return chan; 217*c087a94bSLad Prabhakar } 218*c087a94bSLad Prabhakar 219*c087a94bSLad Prabhakar static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, 220*c087a94bSLad Prabhakar struct rsnd_dma *dma, 221*c087a94bSLad Prabhakar struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) 222*c087a94bSLad Prabhakar { 223*c087a94bSLad Prabhakar struct rsnd_priv *priv = rsnd_io_to_priv(io); 224*c087a94bSLad Prabhakar struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); 225*c087a94bSLad Prabhakar struct dma_chan *chan; 226*c087a94bSLad Prabhakar 227*c087a94bSLad Prabhakar /* try to get DMAEngine channel */ 228*c087a94bSLad Prabhakar chan = rsnd_dmaen_request_channel(io, mod_from, mod_to); 229*c087a94bSLad Prabhakar if (IS_ERR_OR_NULL(chan)) { 230*c087a94bSLad Prabhakar /* Let's follow when -EPROBE_DEFER case */ 231*c087a94bSLad Prabhakar if (PTR_ERR(chan) == -EPROBE_DEFER) 232*c087a94bSLad Prabhakar return PTR_ERR(chan); 233*c087a94bSLad Prabhakar 234*c087a94bSLad Prabhakar /* 235*c087a94bSLad Prabhakar * DMA failed. try to PIO mode 236*c087a94bSLad Prabhakar * see 237*c087a94bSLad Prabhakar * rsnd_ssi_fallback() 238*c087a94bSLad Prabhakar * rsnd_rdai_continuance_probe() 239*c087a94bSLad Prabhakar */ 240*c087a94bSLad Prabhakar return -EAGAIN; 241*c087a94bSLad Prabhakar } 242*c087a94bSLad Prabhakar 243*c087a94bSLad Prabhakar /* 244*c087a94bSLad Prabhakar * use it for IPMMU if needed 245*c087a94bSLad Prabhakar * see 246*c087a94bSLad Prabhakar * rsnd_preallocate_pages() 247*c087a94bSLad Prabhakar */ 248*c087a94bSLad Prabhakar io->dmac_dev = chan->device->dev; 249*c087a94bSLad Prabhakar 250*c087a94bSLad Prabhakar dma_release_channel(chan); 251*c087a94bSLad Prabhakar 252*c087a94bSLad Prabhakar dmac->dmaen_num++; 253*c087a94bSLad Prabhakar 254*c087a94bSLad Prabhakar return 0; 255*c087a94bSLad Prabhakar } 256*c087a94bSLad Prabhakar 257*c087a94bSLad Prabhakar static int rsnd_dmaen_pointer(struct rsnd_mod *mod, 258*c087a94bSLad Prabhakar struct rsnd_dai_stream *io, 259*c087a94bSLad Prabhakar snd_pcm_uframes_t *pointer) 260*c087a94bSLad Prabhakar { 261*c087a94bSLad Prabhakar *pointer = snd_dmaengine_pcm_pointer(io->substream); 262*c087a94bSLad Prabhakar 263*c087a94bSLad Prabhakar return 0; 264*c087a94bSLad Prabhakar } 265*c087a94bSLad Prabhakar 266*c087a94bSLad Prabhakar static struct rsnd_mod_ops rsnd_dmaen_ops = { 267*c087a94bSLad Prabhakar .name = "audmac", 268*c087a94bSLad Prabhakar .prepare = rsnd_dmaen_prepare, 269*c087a94bSLad Prabhakar .cleanup = rsnd_dmaen_cleanup, 270*c087a94bSLad Prabhakar .start = rsnd_dmaen_start, 271*c087a94bSLad Prabhakar .stop = rsnd_dmaen_stop, 272*c087a94bSLad Prabhakar .pointer = rsnd_dmaen_pointer, 273*c087a94bSLad Prabhakar .get_status = rsnd_mod_get_status, 274*c087a94bSLad Prabhakar }; 275*c087a94bSLad Prabhakar 276*c087a94bSLad Prabhakar /* 277*c087a94bSLad Prabhakar * Audio DMAC peri peri 278*c087a94bSLad Prabhakar */ 279*c087a94bSLad Prabhakar static const u8 gen2_id_table_ssiu[] = { 280*c087a94bSLad Prabhakar /* SSI00 ~ SSI07 */ 281*c087a94bSLad Prabhakar 0x00, 0x01, 0x02, 0x03, 0x39, 0x3a, 0x3b, 0x3c, 282*c087a94bSLad Prabhakar /* SSI10 ~ SSI17 */ 283*c087a94bSLad Prabhakar 0x04, 0x05, 0x06, 0x07, 0x3d, 0x3e, 0x3f, 0x40, 284*c087a94bSLad Prabhakar /* SSI20 ~ SSI27 */ 285*c087a94bSLad Prabhakar 0x08, 0x09, 0x0a, 0x0b, 0x41, 0x42, 0x43, 0x44, 286*c087a94bSLad Prabhakar /* SSI30 ~ SSI37 */ 287*c087a94bSLad Prabhakar 0x0c, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 288*c087a94bSLad Prabhakar /* SSI40 ~ SSI47 */ 289*c087a94bSLad Prabhakar 0x0d, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 290*c087a94bSLad Prabhakar /* SSI5 */ 291*c087a94bSLad Prabhakar 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 292*c087a94bSLad Prabhakar /* SSI6 */ 293*c087a94bSLad Prabhakar 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 294*c087a94bSLad Prabhakar /* SSI7 */ 295*c087a94bSLad Prabhakar 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 296*c087a94bSLad Prabhakar /* SSI8 */ 297*c087a94bSLad Prabhakar 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 298*c087a94bSLad Prabhakar /* SSI90 ~ SSI97 */ 299*c087a94bSLad Prabhakar 0x12, 0x13, 0x14, 0x15, 0x53, 0x54, 0x55, 0x56, 300*c087a94bSLad Prabhakar }; 301*c087a94bSLad Prabhakar static const u8 gen2_id_table_scu[] = { 302*c087a94bSLad Prabhakar 0x2d, /* SCU_SRCI0 */ 303*c087a94bSLad Prabhakar 0x2e, /* SCU_SRCI1 */ 304*c087a94bSLad Prabhakar 0x2f, /* SCU_SRCI2 */ 305*c087a94bSLad Prabhakar 0x30, /* SCU_SRCI3 */ 306*c087a94bSLad Prabhakar 0x31, /* SCU_SRCI4 */ 307*c087a94bSLad Prabhakar 0x32, /* SCU_SRCI5 */ 308*c087a94bSLad Prabhakar 0x33, /* SCU_SRCI6 */ 309*c087a94bSLad Prabhakar 0x34, /* SCU_SRCI7 */ 310*c087a94bSLad Prabhakar 0x35, /* SCU_SRCI8 */ 311*c087a94bSLad Prabhakar 0x36, /* SCU_SRCI9 */ 312*c087a94bSLad Prabhakar }; 313*c087a94bSLad Prabhakar static const u8 gen2_id_table_cmd[] = { 314*c087a94bSLad Prabhakar 0x37, /* SCU_CMD0 */ 315*c087a94bSLad Prabhakar 0x38, /* SCU_CMD1 */ 316*c087a94bSLad Prabhakar }; 317*c087a94bSLad Prabhakar 318*c087a94bSLad Prabhakar static u32 rsnd_dmapp_get_id(struct rsnd_dai_stream *io, 319*c087a94bSLad Prabhakar struct rsnd_mod *mod) 320*c087a94bSLad Prabhakar { 321*c087a94bSLad Prabhakar struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); 322*c087a94bSLad Prabhakar struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); 323*c087a94bSLad Prabhakar struct rsnd_mod *src = rsnd_io_to_mod_src(io); 324*c087a94bSLad Prabhakar struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); 325*c087a94bSLad Prabhakar const u8 *entry = NULL; 326*c087a94bSLad Prabhakar int id = 255; 327*c087a94bSLad Prabhakar int size = 0; 328*c087a94bSLad Prabhakar 329*c087a94bSLad Prabhakar if ((mod == ssi) || 330*c087a94bSLad Prabhakar (mod == ssiu)) { 331*c087a94bSLad Prabhakar int busif = rsnd_mod_id_sub(ssiu); 332*c087a94bSLad Prabhakar 333*c087a94bSLad Prabhakar entry = gen2_id_table_ssiu; 334*c087a94bSLad Prabhakar size = ARRAY_SIZE(gen2_id_table_ssiu); 335*c087a94bSLad Prabhakar id = (rsnd_mod_id(mod) * 8) + busif; 336*c087a94bSLad Prabhakar } else if (mod == src) { 337*c087a94bSLad Prabhakar entry = gen2_id_table_scu; 338*c087a94bSLad Prabhakar size = ARRAY_SIZE(gen2_id_table_scu); 339*c087a94bSLad Prabhakar id = rsnd_mod_id(mod); 340*c087a94bSLad Prabhakar } else if (mod == dvc) { 341*c087a94bSLad Prabhakar entry = gen2_id_table_cmd; 342*c087a94bSLad Prabhakar size = ARRAY_SIZE(gen2_id_table_cmd); 343*c087a94bSLad Prabhakar id = rsnd_mod_id(mod); 344*c087a94bSLad Prabhakar } 345*c087a94bSLad Prabhakar 346*c087a94bSLad Prabhakar if ((!entry) || (size <= id)) { 347*c087a94bSLad Prabhakar struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io)); 348*c087a94bSLad Prabhakar 349*c087a94bSLad Prabhakar dev_err(dev, "unknown connection (%s)\n", rsnd_mod_name(mod)); 350*c087a94bSLad Prabhakar 351*c087a94bSLad Prabhakar /* use non-prohibited SRS number as error */ 352*c087a94bSLad Prabhakar return 0x00; /* SSI00 */ 353*c087a94bSLad Prabhakar } 354*c087a94bSLad Prabhakar 355*c087a94bSLad Prabhakar return entry[id]; 356*c087a94bSLad Prabhakar } 357*c087a94bSLad Prabhakar 358*c087a94bSLad Prabhakar static u32 rsnd_dmapp_get_chcr(struct rsnd_dai_stream *io, 359*c087a94bSLad Prabhakar struct rsnd_mod *mod_from, 360*c087a94bSLad Prabhakar struct rsnd_mod *mod_to) 361*c087a94bSLad Prabhakar { 362*c087a94bSLad Prabhakar return (rsnd_dmapp_get_id(io, mod_from) << 24) + 363*c087a94bSLad Prabhakar (rsnd_dmapp_get_id(io, mod_to) << 16); 364*c087a94bSLad Prabhakar } 365*c087a94bSLad Prabhakar 366*c087a94bSLad Prabhakar #define rsnd_dmapp_addr(dmac, dma, reg) \ 367*c087a94bSLad Prabhakar (dmac->ppbase + 0x20 + reg + \ 368*c087a94bSLad Prabhakar (0x10 * rsnd_dma_to_dmapp(dma)->dmapp_id)) 369*c087a94bSLad Prabhakar static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg) 370*c087a94bSLad Prabhakar { 371*c087a94bSLad Prabhakar struct rsnd_mod *mod = rsnd_mod_get(dma); 372*c087a94bSLad Prabhakar struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 373*c087a94bSLad Prabhakar struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); 374*c087a94bSLad Prabhakar struct device *dev = rsnd_priv_to_dev(priv); 375*c087a94bSLad Prabhakar 376*c087a94bSLad Prabhakar dev_dbg(dev, "w 0x%px : %08x\n", rsnd_dmapp_addr(dmac, dma, reg), data); 377*c087a94bSLad Prabhakar 378*c087a94bSLad Prabhakar iowrite32(data, rsnd_dmapp_addr(dmac, dma, reg)); 379*c087a94bSLad Prabhakar } 380*c087a94bSLad Prabhakar 381*c087a94bSLad Prabhakar static u32 rsnd_dmapp_read(struct rsnd_dma *dma, u32 reg) 382*c087a94bSLad Prabhakar { 383*c087a94bSLad Prabhakar struct rsnd_mod *mod = rsnd_mod_get(dma); 384*c087a94bSLad Prabhakar struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 385*c087a94bSLad Prabhakar struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); 386*c087a94bSLad Prabhakar 387*c087a94bSLad Prabhakar return ioread32(rsnd_dmapp_addr(dmac, dma, reg)); 388*c087a94bSLad Prabhakar } 389*c087a94bSLad Prabhakar 390*c087a94bSLad Prabhakar static void rsnd_dmapp_bset(struct rsnd_dma *dma, u32 data, u32 mask, u32 reg) 391*c087a94bSLad Prabhakar { 392*c087a94bSLad Prabhakar struct rsnd_mod *mod = rsnd_mod_get(dma); 393*c087a94bSLad Prabhakar struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 394*c087a94bSLad Prabhakar struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); 395*c087a94bSLad Prabhakar void __iomem *addr = rsnd_dmapp_addr(dmac, dma, reg); 396*c087a94bSLad Prabhakar u32 val = ioread32(addr); 397*c087a94bSLad Prabhakar 398*c087a94bSLad Prabhakar val &= ~mask; 399*c087a94bSLad Prabhakar val |= (data & mask); 400*c087a94bSLad Prabhakar 401*c087a94bSLad Prabhakar iowrite32(val, addr); 402*c087a94bSLad Prabhakar } 403*c087a94bSLad Prabhakar 404*c087a94bSLad Prabhakar static int rsnd_dmapp_stop(struct rsnd_mod *mod, 405*c087a94bSLad Prabhakar struct rsnd_dai_stream *io, 406*c087a94bSLad Prabhakar struct rsnd_priv *priv) 407*c087a94bSLad Prabhakar { 408*c087a94bSLad Prabhakar struct rsnd_dma *dma = rsnd_mod_to_dma(mod); 409*c087a94bSLad Prabhakar int i; 410*c087a94bSLad Prabhakar 411*c087a94bSLad Prabhakar rsnd_dmapp_bset(dma, 0, PDMACHCR_DE, PDMACHCR); 412*c087a94bSLad Prabhakar 413*c087a94bSLad Prabhakar for (i = 0; i < 1024; i++) { 414*c087a94bSLad Prabhakar if (0 == (rsnd_dmapp_read(dma, PDMACHCR) & PDMACHCR_DE)) 415*c087a94bSLad Prabhakar return 0; 416*c087a94bSLad Prabhakar udelay(1); 417*c087a94bSLad Prabhakar } 418*c087a94bSLad Prabhakar 419*c087a94bSLad Prabhakar return -EIO; 420*c087a94bSLad Prabhakar } 421*c087a94bSLad Prabhakar 422*c087a94bSLad Prabhakar static int rsnd_dmapp_start(struct rsnd_mod *mod, 423*c087a94bSLad Prabhakar struct rsnd_dai_stream *io, 424*c087a94bSLad Prabhakar struct rsnd_priv *priv) 425*c087a94bSLad Prabhakar { 426*c087a94bSLad Prabhakar struct rsnd_dma *dma = rsnd_mod_to_dma(mod); 427*c087a94bSLad Prabhakar struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); 428*c087a94bSLad Prabhakar 429*c087a94bSLad Prabhakar rsnd_dmapp_write(dma, dma->src_addr, PDMASAR); 430*c087a94bSLad Prabhakar rsnd_dmapp_write(dma, dma->dst_addr, PDMADAR); 431*c087a94bSLad Prabhakar rsnd_dmapp_write(dma, dmapp->chcr, PDMACHCR); 432*c087a94bSLad Prabhakar 433*c087a94bSLad Prabhakar return 0; 434*c087a94bSLad Prabhakar } 435*c087a94bSLad Prabhakar 436*c087a94bSLad Prabhakar static int rsnd_dmapp_attach(struct rsnd_dai_stream *io, 437*c087a94bSLad Prabhakar struct rsnd_dma *dma, 438*c087a94bSLad Prabhakar struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) 439*c087a94bSLad Prabhakar { 440*c087a94bSLad Prabhakar struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); 441*c087a94bSLad Prabhakar struct rsnd_priv *priv = rsnd_io_to_priv(io); 442*c087a94bSLad Prabhakar struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); 443*c087a94bSLad Prabhakar struct device *dev = rsnd_priv_to_dev(priv); 444*c087a94bSLad Prabhakar 445*c087a94bSLad Prabhakar dmapp->dmapp_id = dmac->dmapp_num; 446*c087a94bSLad Prabhakar dmapp->chcr = rsnd_dmapp_get_chcr(io, mod_from, mod_to) | PDMACHCR_DE; 447*c087a94bSLad Prabhakar 448*c087a94bSLad Prabhakar dmac->dmapp_num++; 449*c087a94bSLad Prabhakar 450*c087a94bSLad Prabhakar dev_dbg(dev, "id/src/dst/chcr = %d/%pad/%pad/%08x\n", 451*c087a94bSLad Prabhakar dmapp->dmapp_id, &dma->src_addr, &dma->dst_addr, dmapp->chcr); 452*c087a94bSLad Prabhakar 453*c087a94bSLad Prabhakar return 0; 454*c087a94bSLad Prabhakar } 455*c087a94bSLad Prabhakar 456*c087a94bSLad Prabhakar #ifdef CONFIG_DEBUG_FS 457*c087a94bSLad Prabhakar static void rsnd_dmapp_debug_info(struct seq_file *m, 458*c087a94bSLad Prabhakar struct rsnd_dai_stream *io, 459*c087a94bSLad Prabhakar struct rsnd_mod *mod) 460*c087a94bSLad Prabhakar { 461*c087a94bSLad Prabhakar struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 462*c087a94bSLad Prabhakar struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); 463*c087a94bSLad Prabhakar struct rsnd_dma *dma = rsnd_mod_to_dma(mod); 464*c087a94bSLad Prabhakar struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); 465*c087a94bSLad Prabhakar 466*c087a94bSLad Prabhakar rsnd_debugfs_reg_show(m, dmac->ppres, dmac->ppbase, 467*c087a94bSLad Prabhakar 0x20 + 0x10 * dmapp->dmapp_id, 0x10); 468*c087a94bSLad Prabhakar } 469*c087a94bSLad Prabhakar #define DEBUG_INFO .debug_info = rsnd_dmapp_debug_info 470*c087a94bSLad Prabhakar #else 471*c087a94bSLad Prabhakar #define DEBUG_INFO 472*c087a94bSLad Prabhakar #endif 473*c087a94bSLad Prabhakar 474*c087a94bSLad Prabhakar static struct rsnd_mod_ops rsnd_dmapp_ops = { 475*c087a94bSLad Prabhakar .name = "audmac-pp", 476*c087a94bSLad Prabhakar .start = rsnd_dmapp_start, 477*c087a94bSLad Prabhakar .stop = rsnd_dmapp_stop, 478*c087a94bSLad Prabhakar .quit = rsnd_dmapp_stop, 479*c087a94bSLad Prabhakar .get_status = rsnd_mod_get_status, 480*c087a94bSLad Prabhakar DEBUG_INFO 481*c087a94bSLad Prabhakar }; 482*c087a94bSLad Prabhakar 483*c087a94bSLad Prabhakar /* 484*c087a94bSLad Prabhakar * Common DMAC Interface 485*c087a94bSLad Prabhakar */ 486*c087a94bSLad Prabhakar 487*c087a94bSLad Prabhakar /* 488*c087a94bSLad Prabhakar * DMA read/write register offset 489*c087a94bSLad Prabhakar * 490*c087a94bSLad Prabhakar * RSND_xxx_I_N for Audio DMAC input 491*c087a94bSLad Prabhakar * RSND_xxx_O_N for Audio DMAC output 492*c087a94bSLad Prabhakar * RSND_xxx_I_P for Audio DMAC peri peri input 493*c087a94bSLad Prabhakar * RSND_xxx_O_P for Audio DMAC peri peri output 494*c087a94bSLad Prabhakar * 495*c087a94bSLad Prabhakar * ex) R-Car H2 case 496*c087a94bSLad Prabhakar * mod / DMAC in / DMAC out / DMAC PP in / DMAC pp out 497*c087a94bSLad Prabhakar * SSI : 0xec541000 / 0xec241008 / 0xec24100c 498*c087a94bSLad Prabhakar * SSIU: 0xec541000 / 0xec100000 / 0xec100000 / 0xec400000 / 0xec400000 499*c087a94bSLad Prabhakar * SCU : 0xec500000 / 0xec000000 / 0xec004000 / 0xec300000 / 0xec304000 500*c087a94bSLad Prabhakar * CMD : 0xec500000 / / 0xec008000 0xec308000 501*c087a94bSLad Prabhakar */ 502*c087a94bSLad Prabhakar #define RDMA_SSI_I_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0x8) 503*c087a94bSLad Prabhakar #define RDMA_SSI_O_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0xc) 504*c087a94bSLad Prabhakar 505*c087a94bSLad Prabhakar #define RDMA_SSIU_I_N(addr, i, j) (addr ##_reg - 0x00441000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400) - (0x4000 * ((i) / 9) * ((j) / 4))) 506*c087a94bSLad Prabhakar #define RDMA_SSIU_O_N(addr, i, j) RDMA_SSIU_I_N(addr, i, j) 507*c087a94bSLad Prabhakar 508*c087a94bSLad Prabhakar #define RDMA_SSIU_I_P(addr, i, j) (addr ##_reg - 0x00141000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400) - (0x4000 * ((i) / 9) * ((j) / 4))) 509*c087a94bSLad Prabhakar #define RDMA_SSIU_O_P(addr, i, j) RDMA_SSIU_I_P(addr, i, j) 510*c087a94bSLad Prabhakar 511*c087a94bSLad Prabhakar #define RDMA_SRC_I_N(addr, i) (addr ##_reg - 0x00500000 + (0x400 * i)) 512*c087a94bSLad Prabhakar #define RDMA_SRC_O_N(addr, i) (addr ##_reg - 0x004fc000 + (0x400 * i)) 513*c087a94bSLad Prabhakar 514*c087a94bSLad Prabhakar #define RDMA_SRC_I_P(addr, i) (addr ##_reg - 0x00200000 + (0x400 * i)) 515*c087a94bSLad Prabhakar #define RDMA_SRC_O_P(addr, i) (addr ##_reg - 0x001fc000 + (0x400 * i)) 516*c087a94bSLad Prabhakar 517*c087a94bSLad Prabhakar #define RDMA_CMD_O_N(addr, i) (addr ##_reg - 0x004f8000 + (0x400 * i)) 518*c087a94bSLad Prabhakar #define RDMA_CMD_O_P(addr, i) (addr ##_reg - 0x001f8000 + (0x400 * i)) 519*c087a94bSLad Prabhakar 520*c087a94bSLad Prabhakar static dma_addr_t 521*c087a94bSLad Prabhakar rsnd_gen2_dma_addr(struct rsnd_dai_stream *io, 522*c087a94bSLad Prabhakar struct rsnd_mod *mod, 523*c087a94bSLad Prabhakar int is_play, int is_from) 524*c087a94bSLad Prabhakar { 525*c087a94bSLad Prabhakar struct rsnd_priv *priv = rsnd_io_to_priv(io); 526*c087a94bSLad Prabhakar struct device *dev = rsnd_priv_to_dev(priv); 527*c087a94bSLad Prabhakar phys_addr_t ssi_reg = rsnd_gen_get_phy_addr(priv, RSND_BASE_SSI); 528*c087a94bSLad Prabhakar phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_BASE_SCU); 529*c087a94bSLad Prabhakar int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod) || 530*c087a94bSLad Prabhakar !!(rsnd_io_to_mod_ssiu(io) == mod); 531*c087a94bSLad Prabhakar int use_src = !!rsnd_io_to_mod_src(io); 532*c087a94bSLad Prabhakar int use_cmd = !!rsnd_io_to_mod_dvc(io) || 533*c087a94bSLad Prabhakar !!rsnd_io_to_mod_mix(io) || 534*c087a94bSLad Prabhakar !!rsnd_io_to_mod_ctu(io); 535*c087a94bSLad Prabhakar int id = rsnd_mod_id(mod); 536*c087a94bSLad Prabhakar int busif = rsnd_mod_id_sub(rsnd_io_to_mod_ssiu(io)); 537*c087a94bSLad Prabhakar struct dma_addr { 538*c087a94bSLad Prabhakar dma_addr_t out_addr; 539*c087a94bSLad Prabhakar dma_addr_t in_addr; 540*c087a94bSLad Prabhakar } dma_addrs[3][2][3] = { 541*c087a94bSLad Prabhakar /* SRC */ 542*c087a94bSLad Prabhakar /* Capture */ 543*c087a94bSLad Prabhakar {{{ 0, 0 }, 544*c087a94bSLad Prabhakar { RDMA_SRC_O_N(src, id), RDMA_SRC_I_P(src, id) }, 545*c087a94bSLad Prabhakar { RDMA_CMD_O_N(src, id), RDMA_SRC_I_P(src, id) } }, 546*c087a94bSLad Prabhakar /* Playback */ 547*c087a94bSLad Prabhakar {{ 0, 0, }, 548*c087a94bSLad Prabhakar { RDMA_SRC_O_P(src, id), RDMA_SRC_I_N(src, id) }, 549*c087a94bSLad Prabhakar { RDMA_CMD_O_P(src, id), RDMA_SRC_I_N(src, id) } } 550*c087a94bSLad Prabhakar }, 551*c087a94bSLad Prabhakar /* SSI */ 552*c087a94bSLad Prabhakar /* Capture */ 553*c087a94bSLad Prabhakar {{{ RDMA_SSI_O_N(ssi, id), 0 }, 554*c087a94bSLad Prabhakar { RDMA_SSIU_O_P(ssi, id, busif), 0 }, 555*c087a94bSLad Prabhakar { RDMA_SSIU_O_P(ssi, id, busif), 0 } }, 556*c087a94bSLad Prabhakar /* Playback */ 557*c087a94bSLad Prabhakar {{ 0, RDMA_SSI_I_N(ssi, id) }, 558*c087a94bSLad Prabhakar { 0, RDMA_SSIU_I_P(ssi, id, busif) }, 559*c087a94bSLad Prabhakar { 0, RDMA_SSIU_I_P(ssi, id, busif) } } 560*c087a94bSLad Prabhakar }, 561*c087a94bSLad Prabhakar /* SSIU */ 562*c087a94bSLad Prabhakar /* Capture */ 563*c087a94bSLad Prabhakar {{{ RDMA_SSIU_O_N(ssi, id, busif), 0 }, 564*c087a94bSLad Prabhakar { RDMA_SSIU_O_P(ssi, id, busif), 0 }, 565*c087a94bSLad Prabhakar { RDMA_SSIU_O_P(ssi, id, busif), 0 } }, 566*c087a94bSLad Prabhakar /* Playback */ 567*c087a94bSLad Prabhakar {{ 0, RDMA_SSIU_I_N(ssi, id, busif) }, 568*c087a94bSLad Prabhakar { 0, RDMA_SSIU_I_P(ssi, id, busif) }, 569*c087a94bSLad Prabhakar { 0, RDMA_SSIU_I_P(ssi, id, busif) } } }, 570*c087a94bSLad Prabhakar }; 571*c087a94bSLad Prabhakar 572*c087a94bSLad Prabhakar /* 573*c087a94bSLad Prabhakar * FIXME 574*c087a94bSLad Prabhakar * 575*c087a94bSLad Prabhakar * We can't support SSI9-4/5/6/7, because its address is 576*c087a94bSLad Prabhakar * out of calculation rule 577*c087a94bSLad Prabhakar */ 578*c087a94bSLad Prabhakar if ((id == 9) && (busif >= 4)) 579*c087a94bSLad Prabhakar dev_err(dev, "This driver doesn't support SSI%d-%d, so far", 580*c087a94bSLad Prabhakar id, busif); 581*c087a94bSLad Prabhakar 582*c087a94bSLad Prabhakar /* it shouldn't happen */ 583*c087a94bSLad Prabhakar if (use_cmd && !use_src) 584*c087a94bSLad Prabhakar dev_err(dev, "DVC is selected without SRC\n"); 585*c087a94bSLad Prabhakar 586*c087a94bSLad Prabhakar /* use SSIU or SSI ? */ 587*c087a94bSLad Prabhakar if (is_ssi && rsnd_ssi_use_busif(io)) 588*c087a94bSLad Prabhakar is_ssi++; 589*c087a94bSLad Prabhakar 590*c087a94bSLad Prabhakar return (is_from) ? 591*c087a94bSLad Prabhakar dma_addrs[is_ssi][is_play][use_src + use_cmd].out_addr : 592*c087a94bSLad Prabhakar dma_addrs[is_ssi][is_play][use_src + use_cmd].in_addr; 593*c087a94bSLad Prabhakar } 594*c087a94bSLad Prabhakar 595*c087a94bSLad Prabhakar /* 596*c087a94bSLad Prabhakar * Gen4 DMA read/write register offset 597*c087a94bSLad Prabhakar * 598*c087a94bSLad Prabhakar * ex) R-Car V4H case 599*c087a94bSLad Prabhakar * mod / SYS-DMAC in / SYS-DMAC out 600*c087a94bSLad Prabhakar * SSI_SDMC: 0xec400000 / 0xec400000 / 0xec400000 601*c087a94bSLad Prabhakar */ 602*c087a94bSLad Prabhakar #define RDMA_SSI_SDMC(addr, i) (addr + (0x8000 * i)) 603*c087a94bSLad Prabhakar static dma_addr_t 604*c087a94bSLad Prabhakar rsnd_gen4_dma_addr(struct rsnd_dai_stream *io, struct rsnd_mod *mod, 605*c087a94bSLad Prabhakar int is_play, int is_from) 606*c087a94bSLad Prabhakar { 607*c087a94bSLad Prabhakar struct rsnd_priv *priv = rsnd_io_to_priv(io); 608*c087a94bSLad Prabhakar phys_addr_t addr = rsnd_gen_get_phy_addr(priv, RSND_BASE_SDMC); 609*c087a94bSLad Prabhakar int id = rsnd_mod_id(mod); 610*c087a94bSLad Prabhakar int busif = rsnd_mod_id_sub(mod); 611*c087a94bSLad Prabhakar 612*c087a94bSLad Prabhakar /* 613*c087a94bSLad Prabhakar * SSI0 only is supported 614*c087a94bSLad Prabhakar */ 615*c087a94bSLad Prabhakar if (id != 0) { 616*c087a94bSLad Prabhakar struct device *dev = rsnd_priv_to_dev(priv); 617*c087a94bSLad Prabhakar 618*c087a94bSLad Prabhakar dev_err(dev, "This driver doesn't support non SSI0"); 619*c087a94bSLad Prabhakar return -EINVAL; 620*c087a94bSLad Prabhakar } 621*c087a94bSLad Prabhakar 622*c087a94bSLad Prabhakar return RDMA_SSI_SDMC(addr, busif); 623*c087a94bSLad Prabhakar } 624*c087a94bSLad Prabhakar 625*c087a94bSLad Prabhakar static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io, 626*c087a94bSLad Prabhakar struct rsnd_mod *mod, 627*c087a94bSLad Prabhakar int is_play, int is_from) 628*c087a94bSLad Prabhakar { 629*c087a94bSLad Prabhakar struct rsnd_priv *priv = rsnd_io_to_priv(io); 630*c087a94bSLad Prabhakar 631*c087a94bSLad Prabhakar if (!mod) 632*c087a94bSLad Prabhakar return 0; 633*c087a94bSLad Prabhakar 634*c087a94bSLad Prabhakar /* 635*c087a94bSLad Prabhakar * gen1 uses default DMA addr 636*c087a94bSLad Prabhakar */ 637*c087a94bSLad Prabhakar if (rsnd_is_gen1(priv)) 638*c087a94bSLad Prabhakar return 0; 639*c087a94bSLad Prabhakar else if (rsnd_is_gen4(priv)) 640*c087a94bSLad Prabhakar return rsnd_gen4_dma_addr(io, mod, is_play, is_from); 641*c087a94bSLad Prabhakar else 642*c087a94bSLad Prabhakar return rsnd_gen2_dma_addr(io, mod, is_play, is_from); 643*c087a94bSLad Prabhakar } 644*c087a94bSLad Prabhakar 645*c087a94bSLad Prabhakar #define MOD_MAX (RSND_MOD_MAX + 1) /* +Memory */ 646*c087a94bSLad Prabhakar static void rsnd_dma_of_path(struct rsnd_mod *this, 647*c087a94bSLad Prabhakar struct rsnd_dai_stream *io, 648*c087a94bSLad Prabhakar int is_play, 649*c087a94bSLad Prabhakar struct rsnd_mod **mod_from, 650*c087a94bSLad Prabhakar struct rsnd_mod **mod_to) 651*c087a94bSLad Prabhakar { 652*c087a94bSLad Prabhakar struct rsnd_mod *ssi; 653*c087a94bSLad Prabhakar struct rsnd_mod *src = rsnd_io_to_mod_src(io); 654*c087a94bSLad Prabhakar struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io); 655*c087a94bSLad Prabhakar struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); 656*c087a94bSLad Prabhakar struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); 657*c087a94bSLad Prabhakar struct rsnd_mod *mod[MOD_MAX]; 658*c087a94bSLad Prabhakar struct rsnd_mod *mod_start, *mod_end; 659*c087a94bSLad Prabhakar struct rsnd_priv *priv = rsnd_mod_to_priv(this); 660*c087a94bSLad Prabhakar struct device *dev = rsnd_priv_to_dev(priv); 661*c087a94bSLad Prabhakar int nr, i, idx; 662*c087a94bSLad Prabhakar 663*c087a94bSLad Prabhakar /* 664*c087a94bSLad Prabhakar * It should use "rcar_sound,ssiu" on DT. 665*c087a94bSLad Prabhakar * But, we need to keep compatibility for old version. 666*c087a94bSLad Prabhakar * 667*c087a94bSLad Prabhakar * If it has "rcar_sound.ssiu", it will be used. 668*c087a94bSLad Prabhakar * If not, "rcar_sound.ssi" will be used. 669*c087a94bSLad Prabhakar * see 670*c087a94bSLad Prabhakar * rsnd_ssiu_dma_req() 671*c087a94bSLad Prabhakar * rsnd_ssi_dma_req() 672*c087a94bSLad Prabhakar */ 673*c087a94bSLad Prabhakar if (rsnd_ssiu_of_node(priv)) { 674*c087a94bSLad Prabhakar struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); 675*c087a94bSLad Prabhakar 676*c087a94bSLad Prabhakar /* use SSIU */ 677*c087a94bSLad Prabhakar ssi = ssiu; 678*c087a94bSLad Prabhakar if (this == rsnd_io_to_mod_ssi(io)) 679*c087a94bSLad Prabhakar this = ssiu; 680*c087a94bSLad Prabhakar } else { 681*c087a94bSLad Prabhakar /* keep compatible, use SSI */ 682*c087a94bSLad Prabhakar ssi = rsnd_io_to_mod_ssi(io); 683*c087a94bSLad Prabhakar } 684*c087a94bSLad Prabhakar 685*c087a94bSLad Prabhakar if (!ssi) 686*c087a94bSLad Prabhakar return; 687*c087a94bSLad Prabhakar 688*c087a94bSLad Prabhakar nr = 0; 689*c087a94bSLad Prabhakar for (i = 0; i < MOD_MAX; i++) { 690*c087a94bSLad Prabhakar mod[i] = NULL; 691*c087a94bSLad Prabhakar nr += !!rsnd_io_to_mod(io, i); 692*c087a94bSLad Prabhakar } 693*c087a94bSLad Prabhakar 694*c087a94bSLad Prabhakar /* 695*c087a94bSLad Prabhakar * [S] -*-> [E] 696*c087a94bSLad Prabhakar * [S] -*-> SRC -o-> [E] 697*c087a94bSLad Prabhakar * [S] -*-> SRC -> DVC -o-> [E] 698*c087a94bSLad Prabhakar * [S] -*-> SRC -> CTU -> MIX -> DVC -o-> [E] 699*c087a94bSLad Prabhakar * 700*c087a94bSLad Prabhakar * playback [S] = mem 701*c087a94bSLad Prabhakar * [E] = SSI 702*c087a94bSLad Prabhakar * 703*c087a94bSLad Prabhakar * capture [S] = SSI 704*c087a94bSLad Prabhakar * [E] = mem 705*c087a94bSLad Prabhakar * 706*c087a94bSLad Prabhakar * -*-> Audio DMAC 707*c087a94bSLad Prabhakar * -o-> Audio DMAC peri peri 708*c087a94bSLad Prabhakar */ 709*c087a94bSLad Prabhakar mod_start = (is_play) ? NULL : ssi; 710*c087a94bSLad Prabhakar mod_end = (is_play) ? ssi : NULL; 711*c087a94bSLad Prabhakar 712*c087a94bSLad Prabhakar idx = 0; 713*c087a94bSLad Prabhakar mod[idx++] = mod_start; 714*c087a94bSLad Prabhakar for (i = 1; i < nr; i++) { 715*c087a94bSLad Prabhakar if (src) { 716*c087a94bSLad Prabhakar mod[idx++] = src; 717*c087a94bSLad Prabhakar src = NULL; 718*c087a94bSLad Prabhakar } else if (ctu) { 719*c087a94bSLad Prabhakar mod[idx++] = ctu; 720*c087a94bSLad Prabhakar ctu = NULL; 721*c087a94bSLad Prabhakar } else if (mix) { 722*c087a94bSLad Prabhakar mod[idx++] = mix; 723*c087a94bSLad Prabhakar mix = NULL; 724*c087a94bSLad Prabhakar } else if (dvc) { 725*c087a94bSLad Prabhakar mod[idx++] = dvc; 726*c087a94bSLad Prabhakar dvc = NULL; 727*c087a94bSLad Prabhakar } 728*c087a94bSLad Prabhakar } 729*c087a94bSLad Prabhakar mod[idx] = mod_end; 730*c087a94bSLad Prabhakar 731*c087a94bSLad Prabhakar /* 732*c087a94bSLad Prabhakar * | SSI | SRC | 733*c087a94bSLad Prabhakar * -------------+-----+-----+ 734*c087a94bSLad Prabhakar * is_play | o | * | 735*c087a94bSLad Prabhakar * !is_play | * | o | 736*c087a94bSLad Prabhakar */ 737*c087a94bSLad Prabhakar if ((this == ssi) == (is_play)) { 738*c087a94bSLad Prabhakar *mod_from = mod[idx - 1]; 739*c087a94bSLad Prabhakar *mod_to = mod[idx]; 740*c087a94bSLad Prabhakar } else { 741*c087a94bSLad Prabhakar *mod_from = mod[0]; 742*c087a94bSLad Prabhakar *mod_to = mod[1]; 743*c087a94bSLad Prabhakar } 744*c087a94bSLad Prabhakar 745*c087a94bSLad Prabhakar dev_dbg(dev, "module connection (this is %s)\n", rsnd_mod_name(this)); 746*c087a94bSLad Prabhakar for (i = 0; i <= idx; i++) { 747*c087a94bSLad Prabhakar dev_dbg(dev, " %s%s\n", 748*c087a94bSLad Prabhakar rsnd_mod_name(mod[i] ? mod[i] : &mem), 749*c087a94bSLad Prabhakar (mod[i] == *mod_from) ? " from" : 750*c087a94bSLad Prabhakar (mod[i] == *mod_to) ? " to" : ""); 751*c087a94bSLad Prabhakar } 752*c087a94bSLad Prabhakar } 753*c087a94bSLad Prabhakar 754*c087a94bSLad Prabhakar static int rsnd_dma_alloc(struct rsnd_dai_stream *io, struct rsnd_mod *mod, 755*c087a94bSLad Prabhakar struct rsnd_mod **dma_mod) 756*c087a94bSLad Prabhakar { 757*c087a94bSLad Prabhakar struct rsnd_mod *mod_from = NULL; 758*c087a94bSLad Prabhakar struct rsnd_mod *mod_to = NULL; 759*c087a94bSLad Prabhakar struct rsnd_priv *priv = rsnd_io_to_priv(io); 760*c087a94bSLad Prabhakar struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); 761*c087a94bSLad Prabhakar struct device *dev = rsnd_priv_to_dev(priv); 762*c087a94bSLad Prabhakar struct rsnd_dma *dma; 763*c087a94bSLad Prabhakar struct rsnd_mod_ops *ops; 764*c087a94bSLad Prabhakar enum rsnd_mod_type type; 765*c087a94bSLad Prabhakar int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, 766*c087a94bSLad Prabhakar struct rsnd_mod *mod_from, struct rsnd_mod *mod_to); 767*c087a94bSLad Prabhakar int is_play = rsnd_io_is_play(io); 768*c087a94bSLad Prabhakar int ret, dma_id; 769*c087a94bSLad Prabhakar 770*c087a94bSLad Prabhakar /* 771*c087a94bSLad Prabhakar * DMA failed. try to PIO mode 772*c087a94bSLad Prabhakar * see 773*c087a94bSLad Prabhakar * rsnd_ssi_fallback() 774*c087a94bSLad Prabhakar * rsnd_rdai_continuance_probe() 775*c087a94bSLad Prabhakar */ 776*c087a94bSLad Prabhakar if (!dmac) 777*c087a94bSLad Prabhakar return -EAGAIN; 778*c087a94bSLad Prabhakar 779*c087a94bSLad Prabhakar rsnd_dma_of_path(mod, io, is_play, &mod_from, &mod_to); 780*c087a94bSLad Prabhakar 781*c087a94bSLad Prabhakar /* for Gen2 or later */ 782*c087a94bSLad Prabhakar if (mod_from && mod_to) { 783*c087a94bSLad Prabhakar ops = &rsnd_dmapp_ops; 784*c087a94bSLad Prabhakar attach = rsnd_dmapp_attach; 785*c087a94bSLad Prabhakar dma_id = dmac->dmapp_num; 786*c087a94bSLad Prabhakar type = RSND_MOD_AUDMAPP; 787*c087a94bSLad Prabhakar } else { 788*c087a94bSLad Prabhakar ops = &rsnd_dmaen_ops; 789*c087a94bSLad Prabhakar attach = rsnd_dmaen_attach; 790*c087a94bSLad Prabhakar dma_id = dmac->dmaen_num; 791*c087a94bSLad Prabhakar type = RSND_MOD_AUDMA; 792*c087a94bSLad Prabhakar } 793*c087a94bSLad Prabhakar 794*c087a94bSLad Prabhakar /* for Gen1, overwrite */ 795*c087a94bSLad Prabhakar if (rsnd_is_gen1(priv)) { 796*c087a94bSLad Prabhakar ops = &rsnd_dmaen_ops; 797*c087a94bSLad Prabhakar attach = rsnd_dmaen_attach; 798*c087a94bSLad Prabhakar dma_id = dmac->dmaen_num; 799*c087a94bSLad Prabhakar type = RSND_MOD_AUDMA; 800*c087a94bSLad Prabhakar } 801*c087a94bSLad Prabhakar 802*c087a94bSLad Prabhakar dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); 803*c087a94bSLad Prabhakar if (!dma) 804*c087a94bSLad Prabhakar return -ENOMEM; 805*c087a94bSLad Prabhakar 806*c087a94bSLad Prabhakar *dma_mod = rsnd_mod_get(dma); 807*c087a94bSLad Prabhakar 808*c087a94bSLad Prabhakar ret = rsnd_mod_init(priv, *dma_mod, ops, NULL, 809*c087a94bSLad Prabhakar type, dma_id); 810*c087a94bSLad Prabhakar if (ret < 0) 811*c087a94bSLad Prabhakar return ret; 812*c087a94bSLad Prabhakar 813*c087a94bSLad Prabhakar dev_dbg(dev, "%s %s -> %s\n", 814*c087a94bSLad Prabhakar rsnd_mod_name(*dma_mod), 815*c087a94bSLad Prabhakar rsnd_mod_name(mod_from ? mod_from : &mem), 816*c087a94bSLad Prabhakar rsnd_mod_name(mod_to ? mod_to : &mem)); 817*c087a94bSLad Prabhakar 818*c087a94bSLad Prabhakar ret = attach(io, dma, mod_from, mod_to); 819*c087a94bSLad Prabhakar if (ret < 0) 820*c087a94bSLad Prabhakar return ret; 821*c087a94bSLad Prabhakar 822*c087a94bSLad Prabhakar dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1); 823*c087a94bSLad Prabhakar dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0); 824*c087a94bSLad Prabhakar dma->mod_from = mod_from; 825*c087a94bSLad Prabhakar dma->mod_to = mod_to; 826*c087a94bSLad Prabhakar 827*c087a94bSLad Prabhakar return 0; 828*c087a94bSLad Prabhakar } 829*c087a94bSLad Prabhakar 830*c087a94bSLad Prabhakar int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, 831*c087a94bSLad Prabhakar struct rsnd_mod **dma_mod) 832*c087a94bSLad Prabhakar { 833*c087a94bSLad Prabhakar if (!(*dma_mod)) { 834*c087a94bSLad Prabhakar int ret = rsnd_dma_alloc(io, mod, dma_mod); 835*c087a94bSLad Prabhakar 836*c087a94bSLad Prabhakar if (ret < 0) 837*c087a94bSLad Prabhakar return ret; 838*c087a94bSLad Prabhakar } 839*c087a94bSLad Prabhakar 840*c087a94bSLad Prabhakar return rsnd_dai_connect(*dma_mod, io, (*dma_mod)->type); 841*c087a94bSLad Prabhakar } 842*c087a94bSLad Prabhakar 843*c087a94bSLad Prabhakar int rsnd_dma_probe(struct rsnd_priv *priv) 844*c087a94bSLad Prabhakar { 845*c087a94bSLad Prabhakar struct platform_device *pdev = rsnd_priv_to_pdev(priv); 846*c087a94bSLad Prabhakar struct device *dev = rsnd_priv_to_dev(priv); 847*c087a94bSLad Prabhakar struct rsnd_dma_ctrl *dmac; 848*c087a94bSLad Prabhakar struct resource *res; 849*c087a94bSLad Prabhakar 850*c087a94bSLad Prabhakar /* 851*c087a94bSLad Prabhakar * for Gen1 852*c087a94bSLad Prabhakar */ 853*c087a94bSLad Prabhakar if (rsnd_is_gen1(priv)) 854*c087a94bSLad Prabhakar return 0; 855*c087a94bSLad Prabhakar 856*c087a94bSLad Prabhakar /* 857*c087a94bSLad Prabhakar * for Gen2 or later 858*c087a94bSLad Prabhakar */ 859*c087a94bSLad Prabhakar dmac = devm_kzalloc(dev, sizeof(*dmac), GFP_KERNEL); 860*c087a94bSLad Prabhakar if (!dmac) { 861*c087a94bSLad Prabhakar dev_err(dev, "dma allocate failed\n"); 862*c087a94bSLad Prabhakar return 0; /* it will be PIO mode */ 863*c087a94bSLad Prabhakar } 864*c087a94bSLad Prabhakar 865*c087a94bSLad Prabhakar /* for Gen4 doesn't have DMA-pp */ 866*c087a94bSLad Prabhakar if (rsnd_is_gen4(priv)) 867*c087a94bSLad Prabhakar goto audmapp_end; 868*c087a94bSLad Prabhakar 869*c087a94bSLad Prabhakar res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "audmapp"); 870*c087a94bSLad Prabhakar if (!res) { 871*c087a94bSLad Prabhakar dev_err(dev, "lack of audmapp in DT\n"); 872*c087a94bSLad Prabhakar return 0; /* it will be PIO mode */ 873*c087a94bSLad Prabhakar } 874*c087a94bSLad Prabhakar 875*c087a94bSLad Prabhakar dmac->dmapp_num = 0; 876*c087a94bSLad Prabhakar dmac->ppres = res->start; 877*c087a94bSLad Prabhakar dmac->ppbase = devm_ioremap_resource(dev, res); 878*c087a94bSLad Prabhakar if (IS_ERR(dmac->ppbase)) 879*c087a94bSLad Prabhakar return PTR_ERR(dmac->ppbase); 880*c087a94bSLad Prabhakar audmapp_end: 881*c087a94bSLad Prabhakar priv->dma = dmac; 882*c087a94bSLad Prabhakar 883*c087a94bSLad Prabhakar /* dummy mem mod for debug */ 884*c087a94bSLad Prabhakar return rsnd_mod_init(NULL, &mem, &mem_ops, NULL, 0, 0); 885*c087a94bSLad Prabhakar } 886