brintos

brintos / linux-shallow public Read only

0
0
Text · 8.2 KiB · 01b82a2 Raw
330 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *  Omnitek Scatter-Gather DMA Controller4 *5 *  Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.6 *  All rights reserved.7 */8 9#include <linux/string.h>10#include <linux/io.h>11#include <linux/pci_regs.h>12#include <linux/spinlock.h>13 14#include "cobalt-driver.h"15#include "cobalt-omnitek.h"16 17/* descriptor */18#define END_OF_CHAIN		(1 << 1)19#define INTERRUPT_ENABLE	(1 << 2)20#define WRITE_TO_PCI		(1 << 3)21#define READ_FROM_PCI		(0 << 3)22#define DESCRIPTOR_FLAG_MSK	(END_OF_CHAIN | INTERRUPT_ENABLE | WRITE_TO_PCI)23#define NEXT_ADRS_MSK		0xffffffe024 25/* control/status register */26#define ENABLE                  (1 << 0)27#define START                   (1 << 1)28#define ABORT                   (1 << 2)29#define DONE                    (1 << 4)30#define SG_INTERRUPT            (1 << 5)31#define EVENT_INTERRUPT         (1 << 6)32#define SCATTER_GATHER_MODE     (1 << 8)33#define DISABLE_VIDEO_RESYNC    (1 << 9)34#define EVENT_INTERRUPT_ENABLE  (1 << 10)35#define DIRECTIONAL_MSK         (3 << 16)36#define INPUT_ONLY              (0 << 16)37#define OUTPUT_ONLY             (1 << 16)38#define BIDIRECTIONAL           (2 << 16)39#define DMA_TYPE_MEMORY         (0 << 18)40#define DMA_TYPE_FIFO		(1 << 18)41 42#define BASE			(cobalt->bar0)43#define CAPABILITY_HEADER	(BASE)44#define CAPABILITY_REGISTER	(BASE + 0x04)45#define PCI_64BIT		(1 << 8)46#define LOCAL_64BIT		(1 << 9)47#define INTERRUPT_STATUS	(BASE + 0x08)48#define PCI(c)			(BASE + 0x40 + ((c) * 0x40))49#define SIZE(c)			(BASE + 0x58 + ((c) * 0x40))50#define DESCRIPTOR(c)		(BASE + 0x50 + ((c) * 0x40))51#define CS_REG(c)		(BASE + 0x60 + ((c) * 0x40))52#define BYTES_TRANSFERRED(c)	(BASE + 0x64 + ((c) * 0x40))53 54 55static char *get_dma_direction(u32 status)56{57	switch (status & DIRECTIONAL_MSK) {58	case INPUT_ONLY: return "Input";59	case OUTPUT_ONLY: return "Output";60	case BIDIRECTIONAL: return "Bidirectional";61	}62	return "";63}64 65static void show_dma_capability(struct cobalt *cobalt)66{67	u32 header = ioread32(CAPABILITY_HEADER);68	u32 capa = ioread32(CAPABILITY_REGISTER);69	u32 i;70 71	cobalt_info("Omnitek DMA capability: ID 0x%02x Version 0x%02x Next 0x%x Size 0x%x\n",72		    header & 0xff, (header >> 8) & 0xff,73		    (header >> 16) & 0xffff, (capa >> 24) & 0xff);74 75	switch ((capa >> 8) & 0x3) {76	case 0:77		cobalt_info("Omnitek DMA: 32 bits PCIe and Local\n");78		break;79	case 1:80		cobalt_info("Omnitek DMA: 64 bits PCIe, 32 bits Local\n");81		break;82	case 3:83		cobalt_info("Omnitek DMA: 64 bits PCIe and Local\n");84		break;85	}86 87	for (i = 0;  i < (capa & 0xf);  i++) {88		u32 status = ioread32(CS_REG(i));89 90		cobalt_info("Omnitek DMA channel #%d: %s %s\n", i,91			    status & DMA_TYPE_FIFO ? "FIFO" : "MEMORY",92			    get_dma_direction(status));93	}94}95 96void omni_sg_dma_start(struct cobalt_stream *s, struct sg_dma_desc_info *desc)97{98	struct cobalt *cobalt = s->cobalt;99 100	iowrite32((u32)((u64)desc->bus >> 32), DESCRIPTOR(s->dma_channel) + 4);101	iowrite32((u32)desc->bus & NEXT_ADRS_MSK, DESCRIPTOR(s->dma_channel));102	iowrite32(ENABLE | SCATTER_GATHER_MODE | START, CS_REG(s->dma_channel));103}104 105bool is_dma_done(struct cobalt_stream *s)106{107	struct cobalt *cobalt = s->cobalt;108 109	if (ioread32(CS_REG(s->dma_channel)) & DONE)110		return true;111 112	return false;113}114 115void omni_sg_dma_abort_channel(struct cobalt_stream *s)116{117	struct cobalt *cobalt = s->cobalt;118 119	if (!is_dma_done(s))120		iowrite32(ABORT, CS_REG(s->dma_channel));121}122 123int omni_sg_dma_init(struct cobalt *cobalt)124{125	u32 capa = ioread32(CAPABILITY_REGISTER);126	int i;127 128	cobalt->first_fifo_channel = 0;129	cobalt->dma_channels = capa & 0xf;130	if (capa & PCI_64BIT)131		cobalt->pci_32_bit = false;132	else133		cobalt->pci_32_bit = true;134 135	for (i = 0; i < cobalt->dma_channels; i++) {136		u32 status = ioread32(CS_REG(i));137		u32 ctrl = ioread32(CS_REG(i));138 139		if (!(ctrl & DONE))140			iowrite32(ABORT, CS_REG(i));141 142		if (!(status & DMA_TYPE_FIFO))143			cobalt->first_fifo_channel++;144	}145	show_dma_capability(cobalt);146	return 0;147}148 149int descriptor_list_create(struct cobalt *cobalt,150		struct scatterlist *scatter_list, bool to_pci, unsigned sglen,151		unsigned size, unsigned width, unsigned stride,152		struct sg_dma_desc_info *desc)153{154	struct sg_dma_descriptor *d = (struct sg_dma_descriptor *)desc->virt;155	dma_addr_t next = desc->bus;156	unsigned offset = 0;157	unsigned copy_bytes = width;158	unsigned copied = 0;159	bool first = true;160 161	/* Must be 4-byte aligned */162	WARN_ON(sg_dma_address(scatter_list) & 3);163	WARN_ON(size & 3);164	WARN_ON(next & 3);165	WARN_ON(stride & 3);166	WARN_ON(stride < width);167	if (width >= stride)168		copy_bytes = stride = size;169 170	while (size) {171		dma_addr_t addr = sg_dma_address(scatter_list) + offset;172		unsigned bytes;173 174		if (addr == 0)175			return -EFAULT;176		if (cobalt->pci_32_bit) {177			WARN_ON((u64)addr >> 32);178			if ((u64)addr >> 32)179				return -EFAULT;180		}181 182		/* PCIe address */183		d->pci_l = addr & 0xffffffff;184		/* If dma_addr_t is 32 bits, then addr >> 32 is actually the185		   equivalent of addr >> 0 in gcc. So must cast to u64. */186		d->pci_h = (u64)addr >> 32;187 188		/* Sync to start of streaming frame */189		d->local = 0;190		d->reserved0 = 0;191 192		/* Transfer bytes */193		bytes = min(sg_dma_len(scatter_list) - offset,194				copy_bytes - copied);195 196		if (first) {197			if (to_pci)198				d->local = 0x11111111;199			first = false;200			if (sglen == 1) {201				/* Make sure there are always at least two202				 * descriptors */203				d->bytes = (bytes / 2) & ~3;204				d->reserved1 = 0;205				size -= d->bytes;206				copied += d->bytes;207				offset += d->bytes;208				addr += d->bytes;209				next += sizeof(struct sg_dma_descriptor);210				d->next_h = (u32)((u64)next >> 32);211				d->next_l = (u32)next |212					(to_pci ? WRITE_TO_PCI : 0);213				bytes -= d->bytes;214				d++;215				/* PCIe address */216				d->pci_l = addr & 0xffffffff;217				/* If dma_addr_t is 32 bits, then addr >> 32218				 * is actually the equivalent of addr >> 0 in219				 * gcc. So must cast to u64. */220				d->pci_h = (u64)addr >> 32;221 222				/* Sync to start of streaming frame */223				d->local = 0;224				d->reserved0 = 0;225			}226		}227 228		d->bytes = bytes;229		d->reserved1 = 0;230		size -= bytes;231		copied += bytes;232		offset += bytes;233 234		if (copied == copy_bytes) {235			while (copied < stride) {236				bytes = min(sg_dma_len(scatter_list) - offset,237						stride - copied);238				copied += bytes;239				offset += bytes;240				size -= bytes;241				if (sg_dma_len(scatter_list) == offset) {242					offset = 0;243					scatter_list = sg_next(scatter_list);244				}245			}246			copied = 0;247		} else {248			offset = 0;249			scatter_list = sg_next(scatter_list);250		}251 252		/* Next descriptor + control bits */253		next += sizeof(struct sg_dma_descriptor);254		if (size == 0) {255			/* Loopback to the first descriptor */256			d->next_h = (u32)((u64)desc->bus >> 32);257			d->next_l = (u32)desc->bus |258				(to_pci ? WRITE_TO_PCI : 0) | INTERRUPT_ENABLE;259			if (!to_pci)260				d->local = 0x22222222;261			desc->last_desc_virt = d;262		} else {263			d->next_h = (u32)((u64)next >> 32);264			d->next_l = (u32)next | (to_pci ? WRITE_TO_PCI : 0);265		}266		d++;267	}268	return 0;269}270 271void descriptor_list_chain(struct sg_dma_desc_info *this,272			   struct sg_dma_desc_info *next)273{274	struct sg_dma_descriptor *d = this->last_desc_virt;275	u32 direction = d->next_l & WRITE_TO_PCI;276 277	if (next == NULL) {278		d->next_h = 0;279		d->next_l = direction | INTERRUPT_ENABLE | END_OF_CHAIN;280	} else {281		d->next_h = (u32)((u64)next->bus >> 32);282		d->next_l = (u32)next->bus | direction | INTERRUPT_ENABLE;283	}284}285 286void *descriptor_list_allocate(struct sg_dma_desc_info *desc, size_t bytes)287{288	desc->size = bytes;289	desc->virt = dma_alloc_coherent(desc->dev, bytes,290					&desc->bus, GFP_KERNEL);291	return desc->virt;292}293 294void descriptor_list_free(struct sg_dma_desc_info *desc)295{296	if (desc->virt)297		dma_free_coherent(desc->dev, desc->size,298				  desc->virt, desc->bus);299	desc->virt = NULL;300}301 302void descriptor_list_interrupt_enable(struct sg_dma_desc_info *desc)303{304	struct sg_dma_descriptor *d = desc->last_desc_virt;305 306	d->next_l |= INTERRUPT_ENABLE;307}308 309void descriptor_list_interrupt_disable(struct sg_dma_desc_info *desc)310{311	struct sg_dma_descriptor *d = desc->last_desc_virt;312 313	d->next_l &= ~INTERRUPT_ENABLE;314}315 316void descriptor_list_loopback(struct sg_dma_desc_info *desc)317{318	struct sg_dma_descriptor *d = desc->last_desc_virt;319 320	d->next_h = (u32)((u64)desc->bus >> 32);321	d->next_l = (u32)desc->bus | (d->next_l & DESCRIPTOR_FLAG_MSK);322}323 324void descriptor_list_end_of_chain(struct sg_dma_desc_info *desc)325{326	struct sg_dma_descriptor *d = desc->last_desc_virt;327 328	d->next_l |= END_OF_CHAIN;329}330