]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ALSA: hda/core: add addr_offset field for bus address translation
authorJoakim Zhang <joakim.zhang@cixtech.com>
Fri, 5 Dec 2025 15:46:20 +0000 (23:46 +0800)
committerTakashi Iwai <tiwai@suse.de>
Sun, 7 Dec 2025 12:13:20 +0000 (13:13 +0100)
Add bus addr_offset field for dma address translation,
for some SoCs such as CIX SKY1 which is ARM64 Arch, HOST
and HDAC has different memory view, so need to do dma address
translation between HOST and HDAC.

Signed-off-by: Joakim Zhang <joakim.zhang@cixtech.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/20251205154621.3019640-3-joakim.zhang@cixtech.com
include/sound/hdaudio.h
sound/hda/core/bus.c
sound/hda/core/controller.c
sound/hda/core/stream.c

index 4e0c1d8af09f762feea857d51d717ffe844759cb..f11bfc6b9f428a3410db9c3409f6a65fe8860340 100644 (file)
@@ -380,6 +380,9 @@ struct hdac_bus {
 
        /* factor used to derive STRIPE control value */
        unsigned int sdo_limit;
+
+       /* address offset between host and hadc */
+       dma_addr_t addr_offset;
 };
 
 int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
index 9b196c915f37837011f26fa27d85d518958be675..81498f1e413e2add2012c875ebfe26ee847554f3 100644 (file)
@@ -47,6 +47,7 @@ int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
        INIT_LIST_HEAD(&bus->hlink_list);
        init_waitqueue_head(&bus->rirb_wq);
        bus->irq = -1;
+       bus->addr_offset = 0;
 
        /*
         * Default value of '8' is as per the HD audio specification (Rev 1.0a).
index a7c00ad801170c673518cc9bc311a755a6eee159..69e11d62bbfa7a5351f1f6e198c92cfb5677df72 100644 (file)
@@ -48,8 +48,8 @@ void snd_hdac_bus_init_cmd_io(struct hdac_bus *bus)
        /* CORB set up */
        bus->corb.addr = bus->rb.addr;
        bus->corb.buf = (__le32 *)bus->rb.area;
-       snd_hdac_chip_writel(bus, CORBLBASE, (u32)bus->corb.addr);
-       snd_hdac_chip_writel(bus, CORBUBASE, upper_32_bits(bus->corb.addr));
+       snd_hdac_chip_writel(bus, CORBLBASE, (u32)(bus->corb.addr + bus->addr_offset));
+       snd_hdac_chip_writel(bus, CORBUBASE, upper_32_bits(bus->corb.addr + bus->addr_offset));
 
        /* set the corb size to 256 entries (ULI requires explicitly) */
        snd_hdac_chip_writeb(bus, CORBSIZE, 0x02);
@@ -70,8 +70,8 @@ void snd_hdac_bus_init_cmd_io(struct hdac_bus *bus)
        bus->rirb.buf = (__le32 *)(bus->rb.area + 2048);
        bus->rirb.wp = bus->rirb.rp = 0;
        memset(bus->rirb.cmds, 0, sizeof(bus->rirb.cmds));
-       snd_hdac_chip_writel(bus, RIRBLBASE, (u32)bus->rirb.addr);
-       snd_hdac_chip_writel(bus, RIRBUBASE, upper_32_bits(bus->rirb.addr));
+       snd_hdac_chip_writel(bus, RIRBLBASE, (u32)(bus->rirb.addr + bus->addr_offset));
+       snd_hdac_chip_writel(bus, RIRBUBASE, upper_32_bits(bus->rirb.addr + bus->addr_offset));
 
        /* set the rirb size to 256 entries (ULI requires explicitly) */
        snd_hdac_chip_writeb(bus, RIRBSIZE, 0x02);
@@ -625,8 +625,8 @@ bool snd_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset)
 
        /* program the position buffer */
        if (bus->use_posbuf && bus->posbuf.addr) {
-               snd_hdac_chip_writel(bus, DPLBASE, (u32)bus->posbuf.addr);
-               snd_hdac_chip_writel(bus, DPUBASE, upper_32_bits(bus->posbuf.addr));
+               snd_hdac_chip_writel(bus, DPLBASE, (u32)(bus->posbuf.addr + bus->addr_offset));
+               snd_hdac_chip_writel(bus, DPUBASE, upper_32_bits(bus->posbuf.addr + bus->addr_offset));
        }
 
        bus->chip_init = true;
index 579ec544ef4a48c96268f4324aff4441417a5903..b471a038b3140dca765d99a5dd23808e67509bfa 100644 (file)
@@ -288,16 +288,16 @@ int snd_hdac_stream_setup(struct hdac_stream *azx_dev, bool code_loading)
 
        /* program the BDL address */
        /* lower BDL address */
-       snd_hdac_stream_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr);
+       snd_hdac_stream_writel(azx_dev, SD_BDLPL, (u32)(azx_dev->bdl.addr + bus->addr_offset));
        /* upper BDL address */
        snd_hdac_stream_writel(azx_dev, SD_BDLPU,
-                              upper_32_bits(azx_dev->bdl.addr));
+                              upper_32_bits(azx_dev->bdl.addr + bus->addr_offset));
 
        /* enable the position buffer */
        if (bus->use_posbuf && bus->posbuf.addr) {
                if (!(snd_hdac_chip_readl(bus, DPLBASE) & AZX_DPLBASE_ENABLE))
                        snd_hdac_chip_writel(bus, DPLBASE,
-                               (u32)bus->posbuf.addr | AZX_DPLBASE_ENABLE);
+                               (u32)(bus->posbuf.addr + bus->addr_offset) | AZX_DPLBASE_ENABLE);
        }
 
        /* set the interrupt enable bits in the descriptor control register */
@@ -464,8 +464,8 @@ static int setup_bdle(struct hdac_bus *bus,
 
                addr = snd_sgbuf_get_addr(dmab, ofs);
                /* program the address field of the BDL entry */
-               bdl[0] = cpu_to_le32((u32)addr);
-               bdl[1] = cpu_to_le32(upper_32_bits(addr));
+               bdl[0] = cpu_to_le32((u32)(addr + bus->addr_offset));
+               bdl[1] = cpu_to_le32(upper_32_bits(addr + bus->addr_offset));
                /* program the size field of the BDL entry */
                chunk = snd_sgbuf_get_chunk_size(dmab, ofs, size);
                /* one BDLE cannot cross 4K boundary on CTHDA chips */