0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <media/i2c/adv7604.h>
0010
0011 #include "cobalt-driver.h"
0012 #include "cobalt-irq.h"
0013 #include "cobalt-omnitek.h"
0014
0015 static void cobalt_dma_stream_queue_handler(struct cobalt_stream *s)
0016 {
0017 struct cobalt *cobalt = s->cobalt;
0018 int rx = s->video_channel;
0019 struct m00473_freewheel_regmap __iomem *fw =
0020 COBALT_CVI_FREEWHEEL(s->cobalt, rx);
0021 struct m00233_video_measure_regmap __iomem *vmr =
0022 COBALT_CVI_VMR(s->cobalt, rx);
0023 struct m00389_cvi_regmap __iomem *cvi =
0024 COBALT_CVI(s->cobalt, rx);
0025 struct m00479_clk_loss_detector_regmap __iomem *clkloss =
0026 COBALT_CVI_CLK_LOSS(s->cobalt, rx);
0027 struct cobalt_buffer *cb;
0028 bool skip = false;
0029
0030 spin_lock(&s->irqlock);
0031
0032 if (list_empty(&s->bufs)) {
0033 pr_err("no buffers!\n");
0034 spin_unlock(&s->irqlock);
0035 return;
0036 }
0037
0038
0039
0040
0041
0042 cb = list_first_entry(&s->bufs, struct cobalt_buffer, list);
0043 list_del(&cb->list);
0044 spin_unlock(&s->irqlock);
0045
0046 if (s->is_audio || s->is_output)
0047 goto done;
0048
0049 if (s->unstable_frame) {
0050 uint32_t stat = ioread32(&vmr->irq_status);
0051
0052 iowrite32(stat, &vmr->irq_status);
0053 if (!(ioread32(&vmr->status) &
0054 M00233_STATUS_BITMAP_INIT_DONE_MSK)) {
0055 cobalt_dbg(1, "!init_done\n");
0056 if (s->enable_freewheel)
0057 goto restart_fw;
0058 goto done;
0059 }
0060
0061 if (ioread32(&clkloss->status) &
0062 M00479_STATUS_BITMAP_CLOCK_MISSING_MSK) {
0063 iowrite32(0, &clkloss->ctrl);
0064 iowrite32(M00479_CTRL_BITMAP_ENABLE_MSK, &clkloss->ctrl);
0065 cobalt_dbg(1, "no clock\n");
0066 if (s->enable_freewheel)
0067 goto restart_fw;
0068 goto done;
0069 }
0070 if ((stat & (M00233_IRQ_STATUS_BITMAP_VACTIVE_AREA_MSK |
0071 M00233_IRQ_STATUS_BITMAP_HACTIVE_AREA_MSK)) ||
0072 ioread32(&vmr->vactive_area) != s->timings.bt.height ||
0073 ioread32(&vmr->hactive_area) != s->timings.bt.width) {
0074 cobalt_dbg(1, "unstable\n");
0075 if (s->enable_freewheel)
0076 goto restart_fw;
0077 goto done;
0078 }
0079 if (!s->enable_cvi) {
0080 s->enable_cvi = true;
0081 iowrite32(M00389_CONTROL_BITMAP_ENABLE_MSK, &cvi->control);
0082 goto done;
0083 }
0084 if (!(ioread32(&cvi->status) & M00389_STATUS_BITMAP_LOCK_MSK)) {
0085 cobalt_dbg(1, "cvi no lock\n");
0086 if (s->enable_freewheel)
0087 goto restart_fw;
0088 goto done;
0089 }
0090 if (!s->enable_freewheel) {
0091 cobalt_dbg(1, "stable\n");
0092 s->enable_freewheel = true;
0093 iowrite32(0, &fw->ctrl);
0094 goto done;
0095 }
0096 cobalt_dbg(1, "enabled fw\n");
0097 iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK |
0098 M00233_CONTROL_BITMAP_ENABLE_INTERRUPT_MSK,
0099 &vmr->control);
0100 iowrite32(M00473_CTRL_BITMAP_ENABLE_MSK, &fw->ctrl);
0101 s->enable_freewheel = false;
0102 s->unstable_frame = false;
0103 s->skip_first_frames = 2;
0104 skip = true;
0105 goto done;
0106 }
0107 if (ioread32(&fw->status) & M00473_STATUS_BITMAP_FREEWHEEL_MODE_MSK) {
0108 restart_fw:
0109 cobalt_dbg(1, "lost lock\n");
0110 iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK,
0111 &vmr->control);
0112 iowrite32(M00473_CTRL_BITMAP_ENABLE_MSK |
0113 M00473_CTRL_BITMAP_FORCE_FREEWHEEL_MODE_MSK,
0114 &fw->ctrl);
0115 iowrite32(0, &cvi->control);
0116 s->unstable_frame = true;
0117 s->enable_freewheel = false;
0118 s->enable_cvi = false;
0119 }
0120 done:
0121 if (s->skip_first_frames) {
0122 skip = true;
0123 s->skip_first_frames--;
0124 }
0125 cb->vb.vb2_buf.timestamp = ktime_get_ns();
0126
0127
0128 cb->vb.sequence = s->sequence++;
0129 vb2_buffer_done(&cb->vb.vb2_buf,
0130 (skip || s->unstable_frame) ?
0131 VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
0132 }
0133
0134 irqreturn_t cobalt_irq_handler(int irq, void *dev_id)
0135 {
0136 struct cobalt *cobalt = (struct cobalt *)dev_id;
0137 u32 dma_interrupt =
0138 cobalt_read_bar0(cobalt, DMA_INTERRUPT_STATUS_REG) & 0xffff;
0139 u32 mask = cobalt_read_bar1(cobalt, COBALT_SYS_STAT_MASK);
0140 u32 edge = cobalt_read_bar1(cobalt, COBALT_SYS_STAT_EDGE);
0141 int i;
0142
0143
0144 cobalt_write_bar0(cobalt, DMA_INTERRUPT_STATUS_REG, dma_interrupt);
0145 cobalt_write_bar1(cobalt, COBALT_SYS_STAT_MASK, mask & ~edge);
0146 cobalt_write_bar1(cobalt, COBALT_SYS_STAT_EDGE, edge);
0147
0148 for (i = 0; i < COBALT_NUM_STREAMS; i++) {
0149 struct cobalt_stream *s = &cobalt->streams[i];
0150 unsigned dma_fifo_mask = s->dma_fifo_mask;
0151
0152 if (dma_interrupt & (1 << s->dma_channel)) {
0153 cobalt->irq_dma[i]++;
0154
0155
0156 cobalt_dma_stream_queue_handler(s);
0157 if (!s->is_audio) {
0158 edge &= ~dma_fifo_mask;
0159 cobalt_write_bar1(cobalt, COBALT_SYS_STAT_MASK,
0160 mask & ~edge);
0161 }
0162 }
0163 if (s->is_audio)
0164 continue;
0165 if (edge & s->adv_irq_mask)
0166 set_bit(COBALT_STREAM_FL_ADV_IRQ, &s->flags);
0167 if ((edge & mask & dma_fifo_mask) && vb2_is_streaming(&s->q)) {
0168 cobalt_info("full rx FIFO %d\n", i);
0169 cobalt->irq_full_fifo++;
0170 }
0171 }
0172
0173 queue_work(cobalt->irq_work_queues, &cobalt->irq_work_queue);
0174
0175 if (edge & mask & (COBALT_SYSSTAT_VI0_INT1_MSK |
0176 COBALT_SYSSTAT_VI1_INT1_MSK |
0177 COBALT_SYSSTAT_VI2_INT1_MSK |
0178 COBALT_SYSSTAT_VI3_INT1_MSK |
0179 COBALT_SYSSTAT_VIHSMA_INT1_MSK |
0180 COBALT_SYSSTAT_VOHSMA_INT1_MSK))
0181 cobalt->irq_adv1++;
0182 if (edge & mask & (COBALT_SYSSTAT_VI0_INT2_MSK |
0183 COBALT_SYSSTAT_VI1_INT2_MSK |
0184 COBALT_SYSSTAT_VI2_INT2_MSK |
0185 COBALT_SYSSTAT_VI3_INT2_MSK |
0186 COBALT_SYSSTAT_VIHSMA_INT2_MSK))
0187 cobalt->irq_adv2++;
0188 if (edge & mask & COBALT_SYSSTAT_VOHSMA_INT1_MSK)
0189 cobalt->irq_advout++;
0190 if (dma_interrupt)
0191 cobalt->irq_dma_tot++;
0192 if (!(edge & mask) && !dma_interrupt)
0193 cobalt->irq_none++;
0194 dma_interrupt = cobalt_read_bar0(cobalt, DMA_INTERRUPT_STATUS_REG);
0195
0196 return IRQ_HANDLED;
0197 }
0198
0199 void cobalt_irq_work_handler(struct work_struct *work)
0200 {
0201 struct cobalt *cobalt =
0202 container_of(work, struct cobalt, irq_work_queue);
0203 int i;
0204
0205 for (i = 0; i < COBALT_NUM_NODES; i++) {
0206 struct cobalt_stream *s = &cobalt->streams[i];
0207
0208 if (test_and_clear_bit(COBALT_STREAM_FL_ADV_IRQ, &s->flags)) {
0209 u32 mask;
0210
0211 v4l2_subdev_call(cobalt->streams[i].sd, core,
0212 interrupt_service_routine, 0, NULL);
0213 mask = cobalt_read_bar1(cobalt, COBALT_SYS_STAT_MASK);
0214 cobalt_write_bar1(cobalt, COBALT_SYS_STAT_MASK,
0215 mask | s->adv_irq_mask);
0216 }
0217 }
0218 }
0219
0220 void cobalt_irq_log_status(struct cobalt *cobalt)
0221 {
0222 u32 mask;
0223 int i;
0224
0225 cobalt_info("irq: adv1=%u adv2=%u advout=%u none=%u full=%u\n",
0226 cobalt->irq_adv1, cobalt->irq_adv2, cobalt->irq_advout,
0227 cobalt->irq_none, cobalt->irq_full_fifo);
0228 cobalt_info("irq: dma_tot=%u (", cobalt->irq_dma_tot);
0229 for (i = 0; i < COBALT_NUM_STREAMS; i++)
0230 pr_cont("%s%u", i ? "/" : "", cobalt->irq_dma[i]);
0231 pr_cont(")\n");
0232 cobalt->irq_dma_tot = cobalt->irq_adv1 = cobalt->irq_adv2 = 0;
0233 cobalt->irq_advout = cobalt->irq_none = cobalt->irq_full_fifo = 0;
0234 memset(cobalt->irq_dma, 0, sizeof(cobalt->irq_dma));
0235
0236 mask = cobalt_read_bar1(cobalt, COBALT_SYS_STAT_MASK);
0237 cobalt_write_bar1(cobalt, COBALT_SYS_STAT_MASK,
0238 mask |
0239 COBALT_SYSSTAT_VI0_LOST_DATA_MSK |
0240 COBALT_SYSSTAT_VI1_LOST_DATA_MSK |
0241 COBALT_SYSSTAT_VI2_LOST_DATA_MSK |
0242 COBALT_SYSSTAT_VI3_LOST_DATA_MSK |
0243 COBALT_SYSSTAT_VIHSMA_LOST_DATA_MSK |
0244 COBALT_SYSSTAT_VOHSMA_LOST_DATA_MSK |
0245 COBALT_SYSSTAT_AUD_IN_LOST_DATA_MSK |
0246 COBALT_SYSSTAT_AUD_OUT_LOST_DATA_MSK);
0247 }