162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2015 VanguardiaSur - www.vanguardiasur.com.ar
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2015 Industrial Research Institute for Automation
662306a36Sopenharmony_ci * and Measurements PIAP
762306a36Sopenharmony_ci * Written by Krzysztof Ha?asa
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/mutex.h>
1162306a36Sopenharmony_ci#include <linux/pci.h>
1262306a36Sopenharmony_ci#include <linux/timer.h>
1362306a36Sopenharmony_ci#include <linux/videodev2.h>
1462306a36Sopenharmony_ci#include <media/v4l2-common.h>
1562306a36Sopenharmony_ci#include <media/v4l2-ctrls.h>
1662306a36Sopenharmony_ci#include <media/v4l2-device.h>
1762306a36Sopenharmony_ci#include <media/v4l2-ioctl.h>
1862306a36Sopenharmony_ci#include <media/videobuf2-v4l2.h>
1962306a36Sopenharmony_ci#include <sound/pcm.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include "tw686x-regs.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define TYPE_MAX_CHANNELS	0x0f
2462306a36Sopenharmony_ci#define TYPE_SECOND_GEN		0x10
2562306a36Sopenharmony_ci#define TW686X_DEF_PHASE_REF	0x1518
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define TW686X_AUDIO_PAGE_MAX		16
2862306a36Sopenharmony_ci#define TW686X_AUDIO_PERIODS_MIN	2
2962306a36Sopenharmony_ci#define TW686X_AUDIO_PERIODS_MAX	TW686X_AUDIO_PAGE_MAX
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define TW686X_DMA_MODE_MEMCPY		0
3262306a36Sopenharmony_ci#define TW686X_DMA_MODE_CONTIG		1
3362306a36Sopenharmony_ci#define TW686X_DMA_MODE_SG		2
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistruct tw686x_format {
3662306a36Sopenharmony_ci	char *name;
3762306a36Sopenharmony_ci	unsigned int fourcc;
3862306a36Sopenharmony_ci	unsigned int depth;
3962306a36Sopenharmony_ci	unsigned int mode;
4062306a36Sopenharmony_ci};
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistruct tw686x_dma_desc {
4362306a36Sopenharmony_ci	dma_addr_t phys;
4462306a36Sopenharmony_ci	void *virt;
4562306a36Sopenharmony_ci	unsigned int size;
4662306a36Sopenharmony_ci};
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistruct tw686x_sg_desc {
4962306a36Sopenharmony_ci	/* 3 MSBits for flags, 13 LSBits for length */
5062306a36Sopenharmony_ci	__le32 flags_length;
5162306a36Sopenharmony_ci	__le32 phys;
5262306a36Sopenharmony_ci};
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistruct tw686x_audio_buf {
5562306a36Sopenharmony_ci	dma_addr_t dma;
5662306a36Sopenharmony_ci	void *virt;
5762306a36Sopenharmony_ci	struct list_head list;
5862306a36Sopenharmony_ci};
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistruct tw686x_v4l2_buf {
6162306a36Sopenharmony_ci	struct vb2_v4l2_buffer vb;
6262306a36Sopenharmony_ci	struct list_head list;
6362306a36Sopenharmony_ci};
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistruct tw686x_audio_channel {
6662306a36Sopenharmony_ci	struct tw686x_dev *dev;
6762306a36Sopenharmony_ci	struct snd_pcm_substream *ss;
6862306a36Sopenharmony_ci	unsigned int ch;
6962306a36Sopenharmony_ci	struct tw686x_audio_buf *curr_bufs[2];
7062306a36Sopenharmony_ci	struct tw686x_dma_desc dma_descs[2];
7162306a36Sopenharmony_ci	dma_addr_t ptr;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	struct tw686x_audio_buf buf[TW686X_AUDIO_PAGE_MAX];
7462306a36Sopenharmony_ci	struct list_head buf_list;
7562306a36Sopenharmony_ci	spinlock_t lock;
7662306a36Sopenharmony_ci};
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistruct tw686x_video_channel {
7962306a36Sopenharmony_ci	struct tw686x_dev *dev;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	struct vb2_queue vidq;
8262306a36Sopenharmony_ci	struct list_head vidq_queued;
8362306a36Sopenharmony_ci	struct video_device *device;
8462306a36Sopenharmony_ci	struct tw686x_v4l2_buf *curr_bufs[2];
8562306a36Sopenharmony_ci	struct tw686x_dma_desc dma_descs[2];
8662306a36Sopenharmony_ci	struct tw686x_sg_desc *sg_descs[2];
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	struct v4l2_ctrl_handler ctrl_handler;
8962306a36Sopenharmony_ci	const struct tw686x_format *format;
9062306a36Sopenharmony_ci	struct mutex vb_mutex;
9162306a36Sopenharmony_ci	spinlock_t qlock;
9262306a36Sopenharmony_ci	v4l2_std_id video_standard;
9362306a36Sopenharmony_ci	unsigned int width, height;
9462306a36Sopenharmony_ci	unsigned int h_halve, v_halve;
9562306a36Sopenharmony_ci	unsigned int ch;
9662306a36Sopenharmony_ci	unsigned int num;
9762306a36Sopenharmony_ci	unsigned int fps;
9862306a36Sopenharmony_ci	unsigned int input;
9962306a36Sopenharmony_ci	unsigned int sequence;
10062306a36Sopenharmony_ci	unsigned int pb;
10162306a36Sopenharmony_ci	bool no_signal;
10262306a36Sopenharmony_ci};
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistruct tw686x_dma_ops {
10562306a36Sopenharmony_ci	int (*setup)(struct tw686x_dev *dev);
10662306a36Sopenharmony_ci	int (*alloc)(struct tw686x_video_channel *vc, unsigned int pb);
10762306a36Sopenharmony_ci	void (*free)(struct tw686x_video_channel *vc, unsigned int pb);
10862306a36Sopenharmony_ci	void (*buf_refill)(struct tw686x_video_channel *vc, unsigned int pb);
10962306a36Sopenharmony_ci	const struct vb2_mem_ops *mem_ops;
11062306a36Sopenharmony_ci	enum v4l2_field field;
11162306a36Sopenharmony_ci	u32 hw_dma_mode;
11262306a36Sopenharmony_ci};
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci/* struct tw686x_dev - global device status */
11562306a36Sopenharmony_cistruct tw686x_dev {
11662306a36Sopenharmony_ci	/*
11762306a36Sopenharmony_ci	 * spinlock controlling access to the shared device registers
11862306a36Sopenharmony_ci	 * (DMA enable/disable)
11962306a36Sopenharmony_ci	 */
12062306a36Sopenharmony_ci	spinlock_t lock;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	struct v4l2_device v4l2_dev;
12362306a36Sopenharmony_ci	struct snd_card *snd_card;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	char name[32];
12662306a36Sopenharmony_ci	unsigned int type;
12762306a36Sopenharmony_ci	unsigned int dma_mode;
12862306a36Sopenharmony_ci	struct pci_dev *pci_dev;
12962306a36Sopenharmony_ci	__u32 __iomem *mmio;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	const struct tw686x_dma_ops *dma_ops;
13262306a36Sopenharmony_ci	struct tw686x_video_channel *video_channels;
13362306a36Sopenharmony_ci	struct tw686x_audio_channel *audio_channels;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	/* Per-device audio parameters */
13662306a36Sopenharmony_ci	int audio_rate;
13762306a36Sopenharmony_ci	int period_size;
13862306a36Sopenharmony_ci	int audio_enabled;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	struct timer_list dma_delay_timer;
14162306a36Sopenharmony_ci	u32 pending_dma_en; /* must be protected by lock */
14262306a36Sopenharmony_ci	u32 pending_dma_cmd; /* must be protected by lock */
14362306a36Sopenharmony_ci};
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic inline uint32_t reg_read(struct tw686x_dev *dev, unsigned int reg)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	return readl(dev->mmio + reg);
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic inline void reg_write(struct tw686x_dev *dev, unsigned int reg,
15162306a36Sopenharmony_ci			     uint32_t value)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	writel(value, dev->mmio + reg);
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic inline unsigned int max_channels(struct tw686x_dev *dev)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	return dev->type & TYPE_MAX_CHANNELS; /* 4 or 8 channels */
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic inline unsigned is_second_gen(struct tw686x_dev *dev)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	/* each channel has its own DMA SG table */
16462306a36Sopenharmony_ci	return dev->type & TYPE_SECOND_GEN;
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_civoid tw686x_enable_channel(struct tw686x_dev *dev, unsigned int channel);
16862306a36Sopenharmony_civoid tw686x_disable_channel(struct tw686x_dev *dev, unsigned int channel);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ciint tw686x_video_init(struct tw686x_dev *dev);
17162306a36Sopenharmony_civoid tw686x_video_free(struct tw686x_dev *dev);
17262306a36Sopenharmony_civoid tw686x_video_irq(struct tw686x_dev *dev, unsigned long requests,
17362306a36Sopenharmony_ci		      unsigned int pb_status, unsigned int fifo_status,
17462306a36Sopenharmony_ci		      unsigned int *reset_ch);
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ciint tw686x_audio_init(struct tw686x_dev *dev);
17762306a36Sopenharmony_civoid tw686x_audio_free(struct tw686x_dev *dev);
17862306a36Sopenharmony_civoid tw686x_audio_irq(struct tw686x_dev *dev, unsigned long requests,
17962306a36Sopenharmony_ci		      unsigned int pb_status);
180