18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Omnitek Scatter-Gather DMA Controller
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
68c2ecf20Sopenharmony_ci *  All rights reserved.
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/string.h>
108c2ecf20Sopenharmony_ci#include <linux/io.h>
118c2ecf20Sopenharmony_ci#include <linux/pci_regs.h>
128c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "cobalt-driver.h"
158c2ecf20Sopenharmony_ci#include "cobalt-omnitek.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/* descriptor */
188c2ecf20Sopenharmony_ci#define END_OF_CHAIN		(1 << 1)
198c2ecf20Sopenharmony_ci#define INTERRUPT_ENABLE	(1 << 2)
208c2ecf20Sopenharmony_ci#define WRITE_TO_PCI		(1 << 3)
218c2ecf20Sopenharmony_ci#define READ_FROM_PCI		(0 << 3)
228c2ecf20Sopenharmony_ci#define DESCRIPTOR_FLAG_MSK	(END_OF_CHAIN | INTERRUPT_ENABLE | WRITE_TO_PCI)
238c2ecf20Sopenharmony_ci#define NEXT_ADRS_MSK		0xffffffe0
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/* control/status register */
268c2ecf20Sopenharmony_ci#define ENABLE                  (1 << 0)
278c2ecf20Sopenharmony_ci#define START                   (1 << 1)
288c2ecf20Sopenharmony_ci#define ABORT                   (1 << 2)
298c2ecf20Sopenharmony_ci#define DONE                    (1 << 4)
308c2ecf20Sopenharmony_ci#define SG_INTERRUPT            (1 << 5)
318c2ecf20Sopenharmony_ci#define EVENT_INTERRUPT         (1 << 6)
328c2ecf20Sopenharmony_ci#define SCATTER_GATHER_MODE     (1 << 8)
338c2ecf20Sopenharmony_ci#define DISABLE_VIDEO_RESYNC    (1 << 9)
348c2ecf20Sopenharmony_ci#define EVENT_INTERRUPT_ENABLE  (1 << 10)
358c2ecf20Sopenharmony_ci#define DIRECTIONAL_MSK         (3 << 16)
368c2ecf20Sopenharmony_ci#define INPUT_ONLY              (0 << 16)
378c2ecf20Sopenharmony_ci#define OUTPUT_ONLY             (1 << 16)
388c2ecf20Sopenharmony_ci#define BIDIRECTIONAL           (2 << 16)
398c2ecf20Sopenharmony_ci#define DMA_TYPE_MEMORY         (0 << 18)
408c2ecf20Sopenharmony_ci#define DMA_TYPE_FIFO		(1 << 18)
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#define BASE			(cobalt->bar0)
438c2ecf20Sopenharmony_ci#define CAPABILITY_HEADER	(BASE)
448c2ecf20Sopenharmony_ci#define CAPABILITY_REGISTER	(BASE + 0x04)
458c2ecf20Sopenharmony_ci#define PCI_64BIT		(1 << 8)
468c2ecf20Sopenharmony_ci#define LOCAL_64BIT		(1 << 9)
478c2ecf20Sopenharmony_ci#define INTERRUPT_STATUS	(BASE + 0x08)
488c2ecf20Sopenharmony_ci#define PCI(c)			(BASE + 0x40 + ((c) * 0x40))
498c2ecf20Sopenharmony_ci#define SIZE(c)			(BASE + 0x58 + ((c) * 0x40))
508c2ecf20Sopenharmony_ci#define DESCRIPTOR(c)		(BASE + 0x50 + ((c) * 0x40))
518c2ecf20Sopenharmony_ci#define CS_REG(c)		(BASE + 0x60 + ((c) * 0x40))
528c2ecf20Sopenharmony_ci#define BYTES_TRANSFERRED(c)	(BASE + 0x64 + ((c) * 0x40))
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic char *get_dma_direction(u32 status)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	switch (status & DIRECTIONAL_MSK) {
588c2ecf20Sopenharmony_ci	case INPUT_ONLY: return "Input";
598c2ecf20Sopenharmony_ci	case OUTPUT_ONLY: return "Output";
608c2ecf20Sopenharmony_ci	case BIDIRECTIONAL: return "Bidirectional";
618c2ecf20Sopenharmony_ci	}
628c2ecf20Sopenharmony_ci	return "";
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic void show_dma_capability(struct cobalt *cobalt)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	u32 header = ioread32(CAPABILITY_HEADER);
688c2ecf20Sopenharmony_ci	u32 capa = ioread32(CAPABILITY_REGISTER);
698c2ecf20Sopenharmony_ci	u32 i;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	cobalt_info("Omnitek DMA capability: ID 0x%02x Version 0x%02x Next 0x%x Size 0x%x\n",
728c2ecf20Sopenharmony_ci		    header & 0xff, (header >> 8) & 0xff,
738c2ecf20Sopenharmony_ci		    (header >> 16) & 0xffff, (capa >> 24) & 0xff);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	switch ((capa >> 8) & 0x3) {
768c2ecf20Sopenharmony_ci	case 0:
778c2ecf20Sopenharmony_ci		cobalt_info("Omnitek DMA: 32 bits PCIe and Local\n");
788c2ecf20Sopenharmony_ci		break;
798c2ecf20Sopenharmony_ci	case 1:
808c2ecf20Sopenharmony_ci		cobalt_info("Omnitek DMA: 64 bits PCIe, 32 bits Local\n");
818c2ecf20Sopenharmony_ci		break;
828c2ecf20Sopenharmony_ci	case 3:
838c2ecf20Sopenharmony_ci		cobalt_info("Omnitek DMA: 64 bits PCIe and Local\n");
848c2ecf20Sopenharmony_ci		break;
858c2ecf20Sopenharmony_ci	}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	for (i = 0;  i < (capa & 0xf);  i++) {
888c2ecf20Sopenharmony_ci		u32 status = ioread32(CS_REG(i));
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci		cobalt_info("Omnitek DMA channel #%d: %s %s\n", i,
918c2ecf20Sopenharmony_ci			    status & DMA_TYPE_FIFO ? "FIFO" : "MEMORY",
928c2ecf20Sopenharmony_ci			    get_dma_direction(status));
938c2ecf20Sopenharmony_ci	}
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_civoid omni_sg_dma_start(struct cobalt_stream *s, struct sg_dma_desc_info *desc)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	struct cobalt *cobalt = s->cobalt;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	iowrite32((u32)((u64)desc->bus >> 32), DESCRIPTOR(s->dma_channel) + 4);
1018c2ecf20Sopenharmony_ci	iowrite32((u32)desc->bus & NEXT_ADRS_MSK, DESCRIPTOR(s->dma_channel));
1028c2ecf20Sopenharmony_ci	iowrite32(ENABLE | SCATTER_GATHER_MODE | START, CS_REG(s->dma_channel));
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cibool is_dma_done(struct cobalt_stream *s)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	struct cobalt *cobalt = s->cobalt;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	if (ioread32(CS_REG(s->dma_channel)) & DONE)
1108c2ecf20Sopenharmony_ci		return true;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	return false;
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_civoid omni_sg_dma_abort_channel(struct cobalt_stream *s)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	struct cobalt *cobalt = s->cobalt;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	if (!is_dma_done(s))
1208c2ecf20Sopenharmony_ci		iowrite32(ABORT, CS_REG(s->dma_channel));
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ciint omni_sg_dma_init(struct cobalt *cobalt)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	u32 capa = ioread32(CAPABILITY_REGISTER);
1268c2ecf20Sopenharmony_ci	int i;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	cobalt->first_fifo_channel = 0;
1298c2ecf20Sopenharmony_ci	cobalt->dma_channels = capa & 0xf;
1308c2ecf20Sopenharmony_ci	if (capa & PCI_64BIT)
1318c2ecf20Sopenharmony_ci		cobalt->pci_32_bit = false;
1328c2ecf20Sopenharmony_ci	else
1338c2ecf20Sopenharmony_ci		cobalt->pci_32_bit = true;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	for (i = 0; i < cobalt->dma_channels; i++) {
1368c2ecf20Sopenharmony_ci		u32 status = ioread32(CS_REG(i));
1378c2ecf20Sopenharmony_ci		u32 ctrl = ioread32(CS_REG(i));
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci		if (!(ctrl & DONE))
1408c2ecf20Sopenharmony_ci			iowrite32(ABORT, CS_REG(i));
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci		if (!(status & DMA_TYPE_FIFO))
1438c2ecf20Sopenharmony_ci			cobalt->first_fifo_channel++;
1448c2ecf20Sopenharmony_ci	}
1458c2ecf20Sopenharmony_ci	show_dma_capability(cobalt);
1468c2ecf20Sopenharmony_ci	return 0;
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ciint descriptor_list_create(struct cobalt *cobalt,
1508c2ecf20Sopenharmony_ci		struct scatterlist *scatter_list, bool to_pci, unsigned sglen,
1518c2ecf20Sopenharmony_ci		unsigned size, unsigned width, unsigned stride,
1528c2ecf20Sopenharmony_ci		struct sg_dma_desc_info *desc)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	struct sg_dma_descriptor *d = (struct sg_dma_descriptor *)desc->virt;
1558c2ecf20Sopenharmony_ci	dma_addr_t next = desc->bus;
1568c2ecf20Sopenharmony_ci	unsigned offset = 0;
1578c2ecf20Sopenharmony_ci	unsigned copy_bytes = width;
1588c2ecf20Sopenharmony_ci	unsigned copied = 0;
1598c2ecf20Sopenharmony_ci	bool first = true;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	/* Must be 4-byte aligned */
1628c2ecf20Sopenharmony_ci	WARN_ON(sg_dma_address(scatter_list) & 3);
1638c2ecf20Sopenharmony_ci	WARN_ON(size & 3);
1648c2ecf20Sopenharmony_ci	WARN_ON(next & 3);
1658c2ecf20Sopenharmony_ci	WARN_ON(stride & 3);
1668c2ecf20Sopenharmony_ci	WARN_ON(stride < width);
1678c2ecf20Sopenharmony_ci	if (width >= stride)
1688c2ecf20Sopenharmony_ci		copy_bytes = stride = size;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	while (size) {
1718c2ecf20Sopenharmony_ci		dma_addr_t addr = sg_dma_address(scatter_list) + offset;
1728c2ecf20Sopenharmony_ci		unsigned bytes;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci		if (addr == 0)
1758c2ecf20Sopenharmony_ci			return -EFAULT;
1768c2ecf20Sopenharmony_ci		if (cobalt->pci_32_bit) {
1778c2ecf20Sopenharmony_ci			WARN_ON((u64)addr >> 32);
1788c2ecf20Sopenharmony_ci			if ((u64)addr >> 32)
1798c2ecf20Sopenharmony_ci				return -EFAULT;
1808c2ecf20Sopenharmony_ci		}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci		/* PCIe address */
1838c2ecf20Sopenharmony_ci		d->pci_l = addr & 0xffffffff;
1848c2ecf20Sopenharmony_ci		/* If dma_addr_t is 32 bits, then addr >> 32 is actually the
1858c2ecf20Sopenharmony_ci		   equivalent of addr >> 0 in gcc. So must cast to u64. */
1868c2ecf20Sopenharmony_ci		d->pci_h = (u64)addr >> 32;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci		/* Sync to start of streaming frame */
1898c2ecf20Sopenharmony_ci		d->local = 0;
1908c2ecf20Sopenharmony_ci		d->reserved0 = 0;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci		/* Transfer bytes */
1938c2ecf20Sopenharmony_ci		bytes = min(sg_dma_len(scatter_list) - offset,
1948c2ecf20Sopenharmony_ci				copy_bytes - copied);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci		if (first) {
1978c2ecf20Sopenharmony_ci			if (to_pci)
1988c2ecf20Sopenharmony_ci				d->local = 0x11111111;
1998c2ecf20Sopenharmony_ci			first = false;
2008c2ecf20Sopenharmony_ci			if (sglen == 1) {
2018c2ecf20Sopenharmony_ci				/* Make sure there are always at least two
2028c2ecf20Sopenharmony_ci				 * descriptors */
2038c2ecf20Sopenharmony_ci				d->bytes = (bytes / 2) & ~3;
2048c2ecf20Sopenharmony_ci				d->reserved1 = 0;
2058c2ecf20Sopenharmony_ci				size -= d->bytes;
2068c2ecf20Sopenharmony_ci				copied += d->bytes;
2078c2ecf20Sopenharmony_ci				offset += d->bytes;
2088c2ecf20Sopenharmony_ci				addr += d->bytes;
2098c2ecf20Sopenharmony_ci				next += sizeof(struct sg_dma_descriptor);
2108c2ecf20Sopenharmony_ci				d->next_h = (u32)((u64)next >> 32);
2118c2ecf20Sopenharmony_ci				d->next_l = (u32)next |
2128c2ecf20Sopenharmony_ci					(to_pci ? WRITE_TO_PCI : 0);
2138c2ecf20Sopenharmony_ci				bytes -= d->bytes;
2148c2ecf20Sopenharmony_ci				d++;
2158c2ecf20Sopenharmony_ci				/* PCIe address */
2168c2ecf20Sopenharmony_ci				d->pci_l = addr & 0xffffffff;
2178c2ecf20Sopenharmony_ci				/* If dma_addr_t is 32 bits, then addr >> 32
2188c2ecf20Sopenharmony_ci				 * is actually the equivalent of addr >> 0 in
2198c2ecf20Sopenharmony_ci				 * gcc. So must cast to u64. */
2208c2ecf20Sopenharmony_ci				d->pci_h = (u64)addr >> 32;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci				/* Sync to start of streaming frame */
2238c2ecf20Sopenharmony_ci				d->local = 0;
2248c2ecf20Sopenharmony_ci				d->reserved0 = 0;
2258c2ecf20Sopenharmony_ci			}
2268c2ecf20Sopenharmony_ci		}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci		d->bytes = bytes;
2298c2ecf20Sopenharmony_ci		d->reserved1 = 0;
2308c2ecf20Sopenharmony_ci		size -= bytes;
2318c2ecf20Sopenharmony_ci		copied += bytes;
2328c2ecf20Sopenharmony_ci		offset += bytes;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci		if (copied == copy_bytes) {
2358c2ecf20Sopenharmony_ci			while (copied < stride) {
2368c2ecf20Sopenharmony_ci				bytes = min(sg_dma_len(scatter_list) - offset,
2378c2ecf20Sopenharmony_ci						stride - copied);
2388c2ecf20Sopenharmony_ci				copied += bytes;
2398c2ecf20Sopenharmony_ci				offset += bytes;
2408c2ecf20Sopenharmony_ci				size -= bytes;
2418c2ecf20Sopenharmony_ci				if (sg_dma_len(scatter_list) == offset) {
2428c2ecf20Sopenharmony_ci					offset = 0;
2438c2ecf20Sopenharmony_ci					scatter_list = sg_next(scatter_list);
2448c2ecf20Sopenharmony_ci				}
2458c2ecf20Sopenharmony_ci			}
2468c2ecf20Sopenharmony_ci			copied = 0;
2478c2ecf20Sopenharmony_ci		} else {
2488c2ecf20Sopenharmony_ci			offset = 0;
2498c2ecf20Sopenharmony_ci			scatter_list = sg_next(scatter_list);
2508c2ecf20Sopenharmony_ci		}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci		/* Next descriptor + control bits */
2538c2ecf20Sopenharmony_ci		next += sizeof(struct sg_dma_descriptor);
2548c2ecf20Sopenharmony_ci		if (size == 0) {
2558c2ecf20Sopenharmony_ci			/* Loopback to the first descriptor */
2568c2ecf20Sopenharmony_ci			d->next_h = (u32)((u64)desc->bus >> 32);
2578c2ecf20Sopenharmony_ci			d->next_l = (u32)desc->bus |
2588c2ecf20Sopenharmony_ci				(to_pci ? WRITE_TO_PCI : 0) | INTERRUPT_ENABLE;
2598c2ecf20Sopenharmony_ci			if (!to_pci)
2608c2ecf20Sopenharmony_ci				d->local = 0x22222222;
2618c2ecf20Sopenharmony_ci			desc->last_desc_virt = d;
2628c2ecf20Sopenharmony_ci		} else {
2638c2ecf20Sopenharmony_ci			d->next_h = (u32)((u64)next >> 32);
2648c2ecf20Sopenharmony_ci			d->next_l = (u32)next | (to_pci ? WRITE_TO_PCI : 0);
2658c2ecf20Sopenharmony_ci		}
2668c2ecf20Sopenharmony_ci		d++;
2678c2ecf20Sopenharmony_ci	}
2688c2ecf20Sopenharmony_ci	return 0;
2698c2ecf20Sopenharmony_ci}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_civoid descriptor_list_chain(struct sg_dma_desc_info *this,
2728c2ecf20Sopenharmony_ci			   struct sg_dma_desc_info *next)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	struct sg_dma_descriptor *d = this->last_desc_virt;
2758c2ecf20Sopenharmony_ci	u32 direction = d->next_l & WRITE_TO_PCI;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	if (next == NULL) {
2788c2ecf20Sopenharmony_ci		d->next_h = 0;
2798c2ecf20Sopenharmony_ci		d->next_l = direction | INTERRUPT_ENABLE | END_OF_CHAIN;
2808c2ecf20Sopenharmony_ci	} else {
2818c2ecf20Sopenharmony_ci		d->next_h = (u32)((u64)next->bus >> 32);
2828c2ecf20Sopenharmony_ci		d->next_l = (u32)next->bus | direction | INTERRUPT_ENABLE;
2838c2ecf20Sopenharmony_ci	}
2848c2ecf20Sopenharmony_ci}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_civoid *descriptor_list_allocate(struct sg_dma_desc_info *desc, size_t bytes)
2878c2ecf20Sopenharmony_ci{
2888c2ecf20Sopenharmony_ci	desc->size = bytes;
2898c2ecf20Sopenharmony_ci	desc->virt = dma_alloc_coherent(desc->dev, bytes,
2908c2ecf20Sopenharmony_ci					&desc->bus, GFP_KERNEL);
2918c2ecf20Sopenharmony_ci	return desc->virt;
2928c2ecf20Sopenharmony_ci}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_civoid descriptor_list_free(struct sg_dma_desc_info *desc)
2958c2ecf20Sopenharmony_ci{
2968c2ecf20Sopenharmony_ci	if (desc->virt)
2978c2ecf20Sopenharmony_ci		dma_free_coherent(desc->dev, desc->size,
2988c2ecf20Sopenharmony_ci				  desc->virt, desc->bus);
2998c2ecf20Sopenharmony_ci	desc->virt = NULL;
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_civoid descriptor_list_interrupt_enable(struct sg_dma_desc_info *desc)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	struct sg_dma_descriptor *d = desc->last_desc_virt;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	d->next_l |= INTERRUPT_ENABLE;
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_civoid descriptor_list_interrupt_disable(struct sg_dma_desc_info *desc)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	struct sg_dma_descriptor *d = desc->last_desc_virt;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	d->next_l &= ~INTERRUPT_ENABLE;
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_civoid descriptor_list_loopback(struct sg_dma_desc_info *desc)
3178c2ecf20Sopenharmony_ci{
3188c2ecf20Sopenharmony_ci	struct sg_dma_descriptor *d = desc->last_desc_virt;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	d->next_h = (u32)((u64)desc->bus >> 32);
3218c2ecf20Sopenharmony_ci	d->next_l = (u32)desc->bus | (d->next_l & DESCRIPTOR_FLAG_MSK);
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_civoid descriptor_list_end_of_chain(struct sg_dma_desc_info *desc)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	struct sg_dma_descriptor *d = desc->last_desc_virt;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	d->next_l |= END_OF_CHAIN;
3298c2ecf20Sopenharmony_ci}
330