xref: /OK3568_Linux_fs/kernel/drivers/media/pci/cobalt/cobalt-irq.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  cobalt interrupt handling
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *  Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
6*4882a593Smuzhiyun  *  All rights reserved.
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <media/i2c/adv7604.h>
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include "cobalt-driver.h"
12*4882a593Smuzhiyun #include "cobalt-irq.h"
13*4882a593Smuzhiyun #include "cobalt-omnitek.h"
14*4882a593Smuzhiyun 
cobalt_dma_stream_queue_handler(struct cobalt_stream * s)15*4882a593Smuzhiyun static void cobalt_dma_stream_queue_handler(struct cobalt_stream *s)
16*4882a593Smuzhiyun {
17*4882a593Smuzhiyun 	struct cobalt *cobalt = s->cobalt;
18*4882a593Smuzhiyun 	int rx = s->video_channel;
19*4882a593Smuzhiyun 	struct m00473_freewheel_regmap __iomem *fw =
20*4882a593Smuzhiyun 		COBALT_CVI_FREEWHEEL(s->cobalt, rx);
21*4882a593Smuzhiyun 	struct m00233_video_measure_regmap __iomem *vmr =
22*4882a593Smuzhiyun 		COBALT_CVI_VMR(s->cobalt, rx);
23*4882a593Smuzhiyun 	struct m00389_cvi_regmap __iomem *cvi =
24*4882a593Smuzhiyun 		COBALT_CVI(s->cobalt, rx);
25*4882a593Smuzhiyun 	struct m00479_clk_loss_detector_regmap __iomem *clkloss =
26*4882a593Smuzhiyun 		COBALT_CVI_CLK_LOSS(s->cobalt, rx);
27*4882a593Smuzhiyun 	struct cobalt_buffer *cb;
28*4882a593Smuzhiyun 	bool skip = false;
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun 	spin_lock(&s->irqlock);
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun 	if (list_empty(&s->bufs)) {
33*4882a593Smuzhiyun 		pr_err("no buffers!\n");
34*4882a593Smuzhiyun 		spin_unlock(&s->irqlock);
35*4882a593Smuzhiyun 		return;
36*4882a593Smuzhiyun 	}
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun 	/* Give the fresh filled up buffer to the user.
39*4882a593Smuzhiyun 	 * Note that the interrupt is only sent if the DMA can continue
40*4882a593Smuzhiyun 	 * with a new buffer, so it is always safe to return this buffer
41*4882a593Smuzhiyun 	 * to userspace. */
42*4882a593Smuzhiyun 	cb = list_first_entry(&s->bufs, struct cobalt_buffer, list);
43*4882a593Smuzhiyun 	list_del(&cb->list);
44*4882a593Smuzhiyun 	spin_unlock(&s->irqlock);
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	if (s->is_audio || s->is_output)
47*4882a593Smuzhiyun 		goto done;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	if (s->unstable_frame) {
50*4882a593Smuzhiyun 		uint32_t stat = ioread32(&vmr->irq_status);
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 		iowrite32(stat, &vmr->irq_status);
53*4882a593Smuzhiyun 		if (!(ioread32(&vmr->status) &
54*4882a593Smuzhiyun 		      M00233_STATUS_BITMAP_INIT_DONE_MSK)) {
55*4882a593Smuzhiyun 			cobalt_dbg(1, "!init_done\n");
56*4882a593Smuzhiyun 			if (s->enable_freewheel)
57*4882a593Smuzhiyun 				goto restart_fw;
58*4882a593Smuzhiyun 			goto done;
59*4882a593Smuzhiyun 		}
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 		if (ioread32(&clkloss->status) &
62*4882a593Smuzhiyun 		    M00479_STATUS_BITMAP_CLOCK_MISSING_MSK) {
63*4882a593Smuzhiyun 			iowrite32(0, &clkloss->ctrl);
64*4882a593Smuzhiyun 			iowrite32(M00479_CTRL_BITMAP_ENABLE_MSK, &clkloss->ctrl);
65*4882a593Smuzhiyun 			cobalt_dbg(1, "no clock\n");
66*4882a593Smuzhiyun 			if (s->enable_freewheel)
67*4882a593Smuzhiyun 				goto restart_fw;
68*4882a593Smuzhiyun 			goto done;
69*4882a593Smuzhiyun 		}
70*4882a593Smuzhiyun 		if ((stat & (M00233_IRQ_STATUS_BITMAP_VACTIVE_AREA_MSK |
71*4882a593Smuzhiyun 			     M00233_IRQ_STATUS_BITMAP_HACTIVE_AREA_MSK)) ||
72*4882a593Smuzhiyun 				ioread32(&vmr->vactive_area) != s->timings.bt.height ||
73*4882a593Smuzhiyun 				ioread32(&vmr->hactive_area) != s->timings.bt.width) {
74*4882a593Smuzhiyun 			cobalt_dbg(1, "unstable\n");
75*4882a593Smuzhiyun 			if (s->enable_freewheel)
76*4882a593Smuzhiyun 				goto restart_fw;
77*4882a593Smuzhiyun 			goto done;
78*4882a593Smuzhiyun 		}
79*4882a593Smuzhiyun 		if (!s->enable_cvi) {
80*4882a593Smuzhiyun 			s->enable_cvi = true;
81*4882a593Smuzhiyun 			iowrite32(M00389_CONTROL_BITMAP_ENABLE_MSK, &cvi->control);
82*4882a593Smuzhiyun 			goto done;
83*4882a593Smuzhiyun 		}
84*4882a593Smuzhiyun 		if (!(ioread32(&cvi->status) & M00389_STATUS_BITMAP_LOCK_MSK)) {
85*4882a593Smuzhiyun 			cobalt_dbg(1, "cvi no lock\n");
86*4882a593Smuzhiyun 			if (s->enable_freewheel)
87*4882a593Smuzhiyun 				goto restart_fw;
88*4882a593Smuzhiyun 			goto done;
89*4882a593Smuzhiyun 		}
90*4882a593Smuzhiyun 		if (!s->enable_freewheel) {
91*4882a593Smuzhiyun 			cobalt_dbg(1, "stable\n");
92*4882a593Smuzhiyun 			s->enable_freewheel = true;
93*4882a593Smuzhiyun 			iowrite32(0, &fw->ctrl);
94*4882a593Smuzhiyun 			goto done;
95*4882a593Smuzhiyun 		}
96*4882a593Smuzhiyun 		cobalt_dbg(1, "enabled fw\n");
97*4882a593Smuzhiyun 		iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK |
98*4882a593Smuzhiyun 			  M00233_CONTROL_BITMAP_ENABLE_INTERRUPT_MSK,
99*4882a593Smuzhiyun 			  &vmr->control);
100*4882a593Smuzhiyun 		iowrite32(M00473_CTRL_BITMAP_ENABLE_MSK, &fw->ctrl);
101*4882a593Smuzhiyun 		s->enable_freewheel = false;
102*4882a593Smuzhiyun 		s->unstable_frame = false;
103*4882a593Smuzhiyun 		s->skip_first_frames = 2;
104*4882a593Smuzhiyun 		skip = true;
105*4882a593Smuzhiyun 		goto done;
106*4882a593Smuzhiyun 	}
107*4882a593Smuzhiyun 	if (ioread32(&fw->status) & M00473_STATUS_BITMAP_FREEWHEEL_MODE_MSK) {
108*4882a593Smuzhiyun restart_fw:
109*4882a593Smuzhiyun 		cobalt_dbg(1, "lost lock\n");
110*4882a593Smuzhiyun 		iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK,
111*4882a593Smuzhiyun 			  &vmr->control);
112*4882a593Smuzhiyun 		iowrite32(M00473_CTRL_BITMAP_ENABLE_MSK |
113*4882a593Smuzhiyun 			  M00473_CTRL_BITMAP_FORCE_FREEWHEEL_MODE_MSK,
114*4882a593Smuzhiyun 			  &fw->ctrl);
115*4882a593Smuzhiyun 		iowrite32(0, &cvi->control);
116*4882a593Smuzhiyun 		s->unstable_frame = true;
117*4882a593Smuzhiyun 		s->enable_freewheel = false;
118*4882a593Smuzhiyun 		s->enable_cvi = false;
119*4882a593Smuzhiyun 	}
120*4882a593Smuzhiyun done:
121*4882a593Smuzhiyun 	if (s->skip_first_frames) {
122*4882a593Smuzhiyun 		skip = true;
123*4882a593Smuzhiyun 		s->skip_first_frames--;
124*4882a593Smuzhiyun 	}
125*4882a593Smuzhiyun 	cb->vb.vb2_buf.timestamp = ktime_get_ns();
126*4882a593Smuzhiyun 	/* TODO: the sequence number should be read from the FPGA so we
127*4882a593Smuzhiyun 	   also know about dropped frames. */
128*4882a593Smuzhiyun 	cb->vb.sequence = s->sequence++;
129*4882a593Smuzhiyun 	vb2_buffer_done(&cb->vb.vb2_buf,
130*4882a593Smuzhiyun 			(skip || s->unstable_frame) ?
131*4882a593Smuzhiyun 			VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun 
cobalt_irq_handler(int irq,void * dev_id)134*4882a593Smuzhiyun irqreturn_t cobalt_irq_handler(int irq, void *dev_id)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun 	struct cobalt *cobalt = (struct cobalt *)dev_id;
137*4882a593Smuzhiyun 	u32 dma_interrupt =
138*4882a593Smuzhiyun 		cobalt_read_bar0(cobalt, DMA_INTERRUPT_STATUS_REG) & 0xffff;
139*4882a593Smuzhiyun 	u32 mask = cobalt_read_bar1(cobalt, COBALT_SYS_STAT_MASK);
140*4882a593Smuzhiyun 	u32 edge = cobalt_read_bar1(cobalt, COBALT_SYS_STAT_EDGE);
141*4882a593Smuzhiyun 	int i;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	/* Clear DMA interrupt */
144*4882a593Smuzhiyun 	cobalt_write_bar0(cobalt, DMA_INTERRUPT_STATUS_REG, dma_interrupt);
145*4882a593Smuzhiyun 	cobalt_write_bar1(cobalt, COBALT_SYS_STAT_MASK, mask & ~edge);
146*4882a593Smuzhiyun 	cobalt_write_bar1(cobalt, COBALT_SYS_STAT_EDGE, edge);
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	for (i = 0; i < COBALT_NUM_STREAMS; i++) {
149*4882a593Smuzhiyun 		struct cobalt_stream *s = &cobalt->streams[i];
150*4882a593Smuzhiyun 		unsigned dma_fifo_mask = s->dma_fifo_mask;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 		if (dma_interrupt & (1 << s->dma_channel)) {
153*4882a593Smuzhiyun 			cobalt->irq_dma[i]++;
154*4882a593Smuzhiyun 			/* Give fresh buffer to user and chain newly
155*4882a593Smuzhiyun 			 * queued buffers */
156*4882a593Smuzhiyun 			cobalt_dma_stream_queue_handler(s);
157*4882a593Smuzhiyun 			if (!s->is_audio) {
158*4882a593Smuzhiyun 				edge &= ~dma_fifo_mask;
159*4882a593Smuzhiyun 				cobalt_write_bar1(cobalt, COBALT_SYS_STAT_MASK,
160*4882a593Smuzhiyun 						  mask & ~edge);
161*4882a593Smuzhiyun 			}
162*4882a593Smuzhiyun 		}
163*4882a593Smuzhiyun 		if (s->is_audio)
164*4882a593Smuzhiyun 			continue;
165*4882a593Smuzhiyun 		if (edge & s->adv_irq_mask)
166*4882a593Smuzhiyun 			set_bit(COBALT_STREAM_FL_ADV_IRQ, &s->flags);
167*4882a593Smuzhiyun 		if ((edge & mask & dma_fifo_mask) && vb2_is_streaming(&s->q)) {
168*4882a593Smuzhiyun 			cobalt_info("full rx FIFO %d\n", i);
169*4882a593Smuzhiyun 			cobalt->irq_full_fifo++;
170*4882a593Smuzhiyun 		}
171*4882a593Smuzhiyun 	}
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	queue_work(cobalt->irq_work_queues, &cobalt->irq_work_queue);
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	if (edge & mask & (COBALT_SYSSTAT_VI0_INT1_MSK |
176*4882a593Smuzhiyun 			   COBALT_SYSSTAT_VI1_INT1_MSK |
177*4882a593Smuzhiyun 			   COBALT_SYSSTAT_VI2_INT1_MSK |
178*4882a593Smuzhiyun 			   COBALT_SYSSTAT_VI3_INT1_MSK |
179*4882a593Smuzhiyun 			   COBALT_SYSSTAT_VIHSMA_INT1_MSK |
180*4882a593Smuzhiyun 			   COBALT_SYSSTAT_VOHSMA_INT1_MSK))
181*4882a593Smuzhiyun 		cobalt->irq_adv1++;
182*4882a593Smuzhiyun 	if (edge & mask & (COBALT_SYSSTAT_VI0_INT2_MSK |
183*4882a593Smuzhiyun 			   COBALT_SYSSTAT_VI1_INT2_MSK |
184*4882a593Smuzhiyun 			   COBALT_SYSSTAT_VI2_INT2_MSK |
185*4882a593Smuzhiyun 			   COBALT_SYSSTAT_VI3_INT2_MSK |
186*4882a593Smuzhiyun 			   COBALT_SYSSTAT_VIHSMA_INT2_MSK))
187*4882a593Smuzhiyun 		cobalt->irq_adv2++;
188*4882a593Smuzhiyun 	if (edge & mask & COBALT_SYSSTAT_VOHSMA_INT1_MSK)
189*4882a593Smuzhiyun 		cobalt->irq_advout++;
190*4882a593Smuzhiyun 	if (dma_interrupt)
191*4882a593Smuzhiyun 		cobalt->irq_dma_tot++;
192*4882a593Smuzhiyun 	if (!(edge & mask) && !dma_interrupt)
193*4882a593Smuzhiyun 		cobalt->irq_none++;
194*4882a593Smuzhiyun 	dma_interrupt = cobalt_read_bar0(cobalt, DMA_INTERRUPT_STATUS_REG);
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	return IRQ_HANDLED;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun 
cobalt_irq_work_handler(struct work_struct * work)199*4882a593Smuzhiyun void cobalt_irq_work_handler(struct work_struct *work)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun 	struct cobalt *cobalt =
202*4882a593Smuzhiyun 		container_of(work, struct cobalt, irq_work_queue);
203*4882a593Smuzhiyun 	int i;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	for (i = 0; i < COBALT_NUM_NODES; i++) {
206*4882a593Smuzhiyun 		struct cobalt_stream *s = &cobalt->streams[i];
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 		if (test_and_clear_bit(COBALT_STREAM_FL_ADV_IRQ, &s->flags)) {
209*4882a593Smuzhiyun 			u32 mask;
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 			v4l2_subdev_call(cobalt->streams[i].sd, core,
212*4882a593Smuzhiyun 					interrupt_service_routine, 0, NULL);
213*4882a593Smuzhiyun 			mask = cobalt_read_bar1(cobalt, COBALT_SYS_STAT_MASK);
214*4882a593Smuzhiyun 			cobalt_write_bar1(cobalt, COBALT_SYS_STAT_MASK,
215*4882a593Smuzhiyun 				mask | s->adv_irq_mask);
216*4882a593Smuzhiyun 		}
217*4882a593Smuzhiyun 	}
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun 
cobalt_irq_log_status(struct cobalt * cobalt)220*4882a593Smuzhiyun void cobalt_irq_log_status(struct cobalt *cobalt)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun 	u32 mask;
223*4882a593Smuzhiyun 	int i;
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	cobalt_info("irq: adv1=%u adv2=%u advout=%u none=%u full=%u\n",
226*4882a593Smuzhiyun 		    cobalt->irq_adv1, cobalt->irq_adv2, cobalt->irq_advout,
227*4882a593Smuzhiyun 		    cobalt->irq_none, cobalt->irq_full_fifo);
228*4882a593Smuzhiyun 	cobalt_info("irq: dma_tot=%u (", cobalt->irq_dma_tot);
229*4882a593Smuzhiyun 	for (i = 0; i < COBALT_NUM_STREAMS; i++)
230*4882a593Smuzhiyun 		pr_cont("%s%u", i ? "/" : "", cobalt->irq_dma[i]);
231*4882a593Smuzhiyun 	pr_cont(")\n");
232*4882a593Smuzhiyun 	cobalt->irq_dma_tot = cobalt->irq_adv1 = cobalt->irq_adv2 = 0;
233*4882a593Smuzhiyun 	cobalt->irq_advout = cobalt->irq_none = cobalt->irq_full_fifo = 0;
234*4882a593Smuzhiyun 	memset(cobalt->irq_dma, 0, sizeof(cobalt->irq_dma));
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	mask = cobalt_read_bar1(cobalt, COBALT_SYS_STAT_MASK);
237*4882a593Smuzhiyun 	cobalt_write_bar1(cobalt, COBALT_SYS_STAT_MASK,
238*4882a593Smuzhiyun 			mask |
239*4882a593Smuzhiyun 			COBALT_SYSSTAT_VI0_LOST_DATA_MSK |
240*4882a593Smuzhiyun 			COBALT_SYSSTAT_VI1_LOST_DATA_MSK |
241*4882a593Smuzhiyun 			COBALT_SYSSTAT_VI2_LOST_DATA_MSK |
242*4882a593Smuzhiyun 			COBALT_SYSSTAT_VI3_LOST_DATA_MSK |
243*4882a593Smuzhiyun 			COBALT_SYSSTAT_VIHSMA_LOST_DATA_MSK |
244*4882a593Smuzhiyun 			COBALT_SYSSTAT_VOHSMA_LOST_DATA_MSK |
245*4882a593Smuzhiyun 			COBALT_SYSSTAT_AUD_IN_LOST_DATA_MSK |
246*4882a593Smuzhiyun 			COBALT_SYSSTAT_AUD_OUT_LOST_DATA_MSK);
247*4882a593Smuzhiyun }
248