Skip to content

Commit

Permalink
Downstream fixes for Unicam
Browse files Browse the repository at this point in the history
  • Loading branch information
naushir committed Nov 19, 2024
1 parent 83d0d4f commit 26b3a09
Showing 1 changed file with 52 additions and 22 deletions.
74 changes: 52 additions & 22 deletions drivers/media/platform/broadcom/bcm2835-unicam.c
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,8 @@ unicam_find_format_by_fourcc(u32 fourcc, u32 pad)
}

for (i = 0; i < num_formats; ++i) {
if (formats[i].fourcc == fourcc)
if (formats[i].fourcc == fourcc ||
formats[i].unpacked_fourcc == fourcc)
return &formats[i];
}

Expand Down Expand Up @@ -640,9 +641,9 @@ static inline void unicam_reg_write_field(struct unicam_device *unicam, u32 offs
}

static void unicam_wr_dma_addr(struct unicam_node *node,
struct unicam_buffer *buf)
struct unicam_buffer *buf, unsigned int size)
{
dma_addr_t endaddr = buf->dma_addr + buf->size;
dma_addr_t endaddr = buf->dma_addr + size;

if (node->id == UNICAM_IMAGE_NODE) {
unicam_reg_write(node->dev, UNICAM_IBSA0, buf->dma_addr);
Expand Down Expand Up @@ -675,16 +676,21 @@ static void unicam_schedule_next_buffer(struct unicam_node *node)
node->next_frm = buf;
list_del(&buf->list);

unicam_wr_dma_addr(node, buf);
unicam_wr_dma_addr(node, buf, buf->size);
}

static void unicam_schedule_dummy_buffer(struct unicam_node *node)
{
int node_id = is_image_node(node) ? UNICAM_IMAGE_NODE : UNICAM_METADATA_NODE;

dev_dbg(node->dev->dev, "Scheduling dummy buffer for node %d\n", node_id);

unicam_wr_dma_addr(node, &node->dummy_buf);
/*
* Due to a HW bug causing buffer overruns in circular buffer mode under
* certain (not yet fully known) conditions, the dummy buffer allocation
* is set to a a single page size, but the hardware gets programmed with
* a buffer size of 0.
*/
unicam_wr_dma_addr(node, &node->dummy_buf, 0);

node->next_frm = NULL;
}
Expand Down Expand Up @@ -771,10 +777,25 @@ static irqreturn_t unicam_isr(int irq, void *dev)
* as complete, as the HW will reuse that buffer.
*/
if (node->cur_frm && node->cur_frm != node->next_frm) {
/*
* This condition checks if FE + FS for the same
* frame has occurred. In such cases, we cannot
* return out the frame, as no buffer handling
* or timestamping has yet been done as part of
* the FS handler.
*/
if (!node->cur_frm->vb.vb2_buf.timestamp) {
dev_dbg(unicam->dev, "ISR: FE without FS, dropping frame\n");
continue;
}

unicam_process_buffer_complete(node, sequence);
node->cur_frm = node->next_frm;
node->next_frm = NULL;
inc_seq = true;
} else {
node->cur_frm = node->next_frm;
}
node->cur_frm = node->next_frm;
}

/*
Expand Down Expand Up @@ -807,17 +828,32 @@ static irqreturn_t unicam_isr(int irq, void *dev)
continue;

if (node->cur_frm)
node->cur_frm->vb.vb2_buf.timestamp = ts;
node->cur_frm->vb.vb2_buf.timestamp =
ts;
else
dev_dbg(unicam->v4l2_dev.dev,
"ISR: [%d] Dropping frame, buffer not available at FS\n",
dev_dbg(unicam->dev, "ISR: [%d] Dropping frame, buffer not available at FS\n",
i);
/*
* Set the next frame output to go to a dummy frame
* if we have not managed to obtain another frame
* from the queue.
* if no buffer currently queued.
*/
unicam_schedule_dummy_buffer(node);
if (!node->next_frm ||
node->next_frm == node->cur_frm) {
unicam_schedule_dummy_buffer(node);
} else if (unicam->node[i].cur_frm) {
/*
* Repeated FS without FE. Hardware will have
* swapped buffers, but the cur_frm doesn't
* contain valid data. Return cur_frm to the
* queue.
*/
spin_lock(&node->dma_queue_lock);
list_add_tail(&node->cur_frm->list,
&node->dma_queue);
spin_unlock(&node->dma_queue_lock);
node->cur_frm = node->next_frm;
node->next_frm = NULL;
}
}

unicam_queue_event_sof(unicam);
Expand All @@ -843,11 +879,6 @@ static irqreturn_t unicam_isr(int irq, void *dev)
}
}

if (unicam_reg_read(unicam, UNICAM_ICTL) & UNICAM_FCM) {
/* Switch out of trigger mode if selected */
unicam_reg_write_field(unicam, UNICAM_ICTL, 1, UNICAM_TFC);
unicam_reg_write_field(unicam, UNICAM_ICTL, 0, UNICAM_FCM);
}
return IRQ_HANDLED;
}

Expand Down Expand Up @@ -1011,8 +1042,7 @@ static void unicam_start_rx(struct unicam_device *unicam,

unicam_reg_write_field(unicam, UNICAM_ANA, 0, UNICAM_DDL);

/* Always start in trigger frame capture mode (UNICAM_FCM set) */
val = UNICAM_FSIE | UNICAM_FEIE | UNICAM_FCM | UNICAM_IBOB;
val = UNICAM_FSIE | UNICAM_FEIE | UNICAM_IBOB;
line_int_freq = max(fmt->height >> 2, 128);
unicam_set_field(&val, line_int_freq, UNICAM_LCIE_MASK);
unicam_reg_write(unicam, UNICAM_ICTL, val);
Expand Down Expand Up @@ -1101,7 +1131,7 @@ static void unicam_start_rx(struct unicam_device *unicam,

unicam_reg_write(unicam, UNICAM_IBLS,
node->fmt.fmt.pix.bytesperline);
unicam_wr_dma_addr(node, node->cur_frm);
unicam_wr_dma_addr(node, node->cur_frm, node->cur_frm->size);
unicam_set_packing_config(unicam, fmtinfo);

ret = unicam_get_image_vc_dt(unicam, state, &vc, &dt);
Expand Down Expand Up @@ -1139,7 +1169,7 @@ static void unicam_start_metadata(struct unicam_device *unicam)
struct unicam_node *node = &unicam->node[UNICAM_METADATA_NODE];

unicam_enable_ed(unicam);
unicam_wr_dma_addr(node, node->cur_frm);
unicam_wr_dma_addr(node, node->cur_frm, node->cur_frm->size);
unicam_reg_write_field(unicam, UNICAM_DCS, 1, UNICAM_LDP);
}

Expand Down

0 comments on commit 26b3a09

Please sign in to comment.