linux/drivers/media/pci/cobalt/cobalt-omnitek.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  Omnitek Scatter-Gather DMA Controller
   4 *
   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           0xffffffe0
  24
  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        else
 133                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 the
 185                   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 two
 202                                 * 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 >> 32
 218                                 * is actually the equivalent of addr >> 0 in
 219                                 * 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