Ezequiel Garcia | 704a84c | 2016-03-02 11:30:16 -0300 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2015 VanguardiaSur - www.vanguardiasur.com.ar |
| 3 | * |
| 4 | * Copyright (C) 2015 Industrial Research Institute for Automation |
| 5 | * and Measurements PIAP |
| 6 | * Written by Krzysztof Ha?asa |
| 7 | * |
| 8 | * This program is free software; you can redistribute it and/or modify it |
| 9 | * under the terms of version 2 of the GNU General Public License |
| 10 | * as published by the Free Software Foundation. |
| 11 | */ |
| 12 | |
| 13 | #include <linux/mutex.h> |
| 14 | #include <linux/pci.h> |
| 15 | #include <linux/timer.h> |
| 16 | #include <linux/videodev2.h> |
| 17 | #include <media/v4l2-common.h> |
| 18 | #include <media/v4l2-ctrls.h> |
| 19 | #include <media/v4l2-device.h> |
| 20 | #include <media/v4l2-ioctl.h> |
| 21 | #include <media/videobuf2-v4l2.h> |
| 22 | #include <sound/pcm.h> |
| 23 | |
| 24 | #include "tw686x-regs.h" |
| 25 | |
| 26 | #define TYPE_MAX_CHANNELS 0x0f |
| 27 | #define TYPE_SECOND_GEN 0x10 |
| 28 | #define TW686X_DEF_PHASE_REF 0x1518 |
| 29 | |
Ezequiel Garcia | 704a84c | 2016-03-02 11:30:16 -0300 | [diff] [blame] | 30 | #define TW686X_AUDIO_PAGE_MAX 16 |
| 31 | #define TW686X_AUDIO_PERIODS_MIN 2 |
| 32 | #define TW686X_AUDIO_PERIODS_MAX TW686X_AUDIO_PAGE_MAX |
| 33 | |
Ezequiel Garcia | f8afaa8 | 2016-06-04 20:47:15 -0300 | [diff] [blame] | 34 | #define TW686X_DMA_MODE_MEMCPY 0 |
Ezequiel Garcia | 11a1697 | 2016-06-04 20:47:16 -0300 | [diff] [blame] | 35 | #define TW686X_DMA_MODE_CONTIG 1 |
Ezequiel Garcia | 34e2acc | 2016-06-04 20:47:17 -0300 | [diff] [blame] | 36 | #define TW686X_DMA_MODE_SG 2 |
Ezequiel Garcia | f8afaa8 | 2016-06-04 20:47:15 -0300 | [diff] [blame] | 37 | |
Ezequiel Garcia | 704a84c | 2016-03-02 11:30:16 -0300 | [diff] [blame] | 38 | struct tw686x_format { |
| 39 | char *name; |
| 40 | unsigned int fourcc; |
| 41 | unsigned int depth; |
| 42 | unsigned int mode; |
| 43 | }; |
| 44 | |
| 45 | struct tw686x_dma_desc { |
| 46 | dma_addr_t phys; |
| 47 | void *virt; |
| 48 | unsigned int size; |
| 49 | }; |
| 50 | |
Ezequiel Garcia | 34e2acc | 2016-06-04 20:47:17 -0300 | [diff] [blame] | 51 | struct tw686x_sg_desc { |
| 52 | /* 3 MSBits for flags, 13 LSBits for length */ |
| 53 | __le32 flags_length; |
| 54 | __le32 phys; |
| 55 | }; |
| 56 | |
Ezequiel Garcia | 704a84c | 2016-03-02 11:30:16 -0300 | [diff] [blame] | 57 | struct tw686x_audio_buf { |
| 58 | dma_addr_t dma; |
| 59 | void *virt; |
| 60 | struct list_head list; |
| 61 | }; |
| 62 | |
| 63 | struct tw686x_v4l2_buf { |
| 64 | struct vb2_v4l2_buffer vb; |
| 65 | struct list_head list; |
| 66 | }; |
| 67 | |
| 68 | struct tw686x_audio_channel { |
| 69 | struct tw686x_dev *dev; |
| 70 | struct snd_pcm_substream *ss; |
| 71 | unsigned int ch; |
| 72 | struct tw686x_audio_buf *curr_bufs[2]; |
| 73 | struct tw686x_dma_desc dma_descs[2]; |
| 74 | dma_addr_t ptr; |
| 75 | |
| 76 | struct tw686x_audio_buf buf[TW686X_AUDIO_PAGE_MAX]; |
| 77 | struct list_head buf_list; |
| 78 | spinlock_t lock; |
| 79 | }; |
| 80 | |
| 81 | struct tw686x_video_channel { |
| 82 | struct tw686x_dev *dev; |
| 83 | |
| 84 | struct vb2_queue vidq; |
| 85 | struct list_head vidq_queued; |
| 86 | struct video_device *device; |
| 87 | struct tw686x_v4l2_buf *curr_bufs[2]; |
| 88 | struct tw686x_dma_desc dma_descs[2]; |
Ezequiel Garcia | 34e2acc | 2016-06-04 20:47:17 -0300 | [diff] [blame] | 89 | struct tw686x_sg_desc *sg_descs[2]; |
Ezequiel Garcia | 704a84c | 2016-03-02 11:30:16 -0300 | [diff] [blame] | 90 | |
| 91 | struct v4l2_ctrl_handler ctrl_handler; |
| 92 | const struct tw686x_format *format; |
| 93 | struct mutex vb_mutex; |
| 94 | spinlock_t qlock; |
| 95 | v4l2_std_id video_standard; |
| 96 | unsigned int width, height; |
| 97 | unsigned int h_halve, v_halve; |
| 98 | unsigned int ch; |
| 99 | unsigned int num; |
| 100 | unsigned int fps; |
| 101 | unsigned int input; |
| 102 | unsigned int sequence; |
| 103 | unsigned int pb; |
| 104 | bool no_signal; |
| 105 | }; |
| 106 | |
Ezequiel Garcia | f8afaa8 | 2016-06-04 20:47:15 -0300 | [diff] [blame] | 107 | struct tw686x_dma_ops { |
| 108 | int (*setup)(struct tw686x_dev *dev); |
Ezequiel Garcia | f8afaa8 | 2016-06-04 20:47:15 -0300 | [diff] [blame] | 109 | int (*alloc)(struct tw686x_video_channel *vc, unsigned int pb); |
| 110 | void (*free)(struct tw686x_video_channel *vc, unsigned int pb); |
| 111 | void (*buf_refill)(struct tw686x_video_channel *vc, unsigned int pb); |
| 112 | const struct vb2_mem_ops *mem_ops; |
| 113 | enum v4l2_field field; |
| 114 | u32 hw_dma_mode; |
| 115 | }; |
| 116 | |
Ezequiel Garcia | 704a84c | 2016-03-02 11:30:16 -0300 | [diff] [blame] | 117 | /** |
| 118 | * struct tw686x_dev - global device status |
| 119 | * @lock: spinlock controlling access to the |
| 120 | * shared device registers (DMA enable/disable). |
| 121 | */ |
| 122 | struct tw686x_dev { |
| 123 | spinlock_t lock; |
| 124 | |
| 125 | struct v4l2_device v4l2_dev; |
| 126 | struct snd_card *snd_card; |
| 127 | |
| 128 | char name[32]; |
| 129 | unsigned int type; |
Ezequiel Garcia | f8afaa8 | 2016-06-04 20:47:15 -0300 | [diff] [blame] | 130 | unsigned int dma_mode; |
Ezequiel Garcia | 704a84c | 2016-03-02 11:30:16 -0300 | [diff] [blame] | 131 | struct pci_dev *pci_dev; |
| 132 | __u32 __iomem *mmio; |
| 133 | |
Ezequiel Garcia | f8afaa8 | 2016-06-04 20:47:15 -0300 | [diff] [blame] | 134 | const struct tw686x_dma_ops *dma_ops; |
Ezequiel Garcia | 704a84c | 2016-03-02 11:30:16 -0300 | [diff] [blame] | 135 | struct tw686x_video_channel *video_channels; |
| 136 | struct tw686x_audio_channel *audio_channels; |
| 137 | |
Ezequiel Garcia | 447d7c3 | 2016-06-04 20:47:19 -0300 | [diff] [blame] | 138 | /* Per-device audio parameters */ |
| 139 | int audio_rate; |
| 140 | int period_size; |
Ezequiel Garcia | 6deab6f | 2016-06-04 20:47:20 -0300 | [diff] [blame] | 141 | int audio_enabled; |
Ezequiel Garcia | 704a84c | 2016-03-02 11:30:16 -0300 | [diff] [blame] | 142 | |
| 143 | struct timer_list dma_delay_timer; |
| 144 | u32 pending_dma_en; /* must be protected by lock */ |
| 145 | u32 pending_dma_cmd; /* must be protected by lock */ |
| 146 | }; |
| 147 | |
| 148 | static inline uint32_t reg_read(struct tw686x_dev *dev, unsigned int reg) |
| 149 | { |
| 150 | return readl(dev->mmio + reg); |
| 151 | } |
| 152 | |
| 153 | static inline void reg_write(struct tw686x_dev *dev, unsigned int reg, |
| 154 | uint32_t value) |
| 155 | { |
| 156 | writel(value, dev->mmio + reg); |
| 157 | } |
| 158 | |
| 159 | static inline unsigned int max_channels(struct tw686x_dev *dev) |
| 160 | { |
| 161 | return dev->type & TYPE_MAX_CHANNELS; /* 4 or 8 channels */ |
| 162 | } |
| 163 | |
Ezequiel Garcia | 34e2acc | 2016-06-04 20:47:17 -0300 | [diff] [blame] | 164 | static inline unsigned is_second_gen(struct tw686x_dev *dev) |
| 165 | { |
| 166 | /* each channel has its own DMA SG table */ |
| 167 | return dev->type & TYPE_SECOND_GEN; |
| 168 | } |
| 169 | |
Ezequiel Garcia | 704a84c | 2016-03-02 11:30:16 -0300 | [diff] [blame] | 170 | void tw686x_enable_channel(struct tw686x_dev *dev, unsigned int channel); |
| 171 | void tw686x_disable_channel(struct tw686x_dev *dev, unsigned int channel); |
| 172 | |
| 173 | int tw686x_video_init(struct tw686x_dev *dev); |
| 174 | void tw686x_video_free(struct tw686x_dev *dev); |
| 175 | void tw686x_video_irq(struct tw686x_dev *dev, unsigned long requests, |
| 176 | unsigned int pb_status, unsigned int fifo_status, |
| 177 | unsigned int *reset_ch); |
| 178 | |
| 179 | int tw686x_audio_init(struct tw686x_dev *dev); |
| 180 | void tw686x_audio_free(struct tw686x_dev *dev); |
| 181 | void tw686x_audio_irq(struct tw686x_dev *dev, unsigned long requests, |
| 182 | unsigned int pb_status); |