You need to sign in or sign up before continuing.
Newer
Older
* Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module
*
* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
*/
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/iommu.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/spinlock_types.h>
#include <linux/spinlock.h>
#include <media/media-entity.h>
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
#include "camss-vfe.h"
#include "camss.h"
#define MSM_VFE_NAME "msm_vfe"
#define vfe_line_array(ptr_line) \
((const struct vfe_line (*)[]) &(ptr_line[-(ptr_line->id)]))
#define to_vfe(ptr_line) \
container_of(vfe_line_array(ptr_line), struct vfe_device, line)
/* VFE reset timeout */
#define VFE_RESET_TIMEOUT_MS 50
/* VFE halt timeout */
#define VFE_HALT_TIMEOUT_MS 100
/* Max number of frame drop updates per frame */
#define VFE_FRAME_DROP_UPDATES 5
/* Frame drop value. NOTE: VAL + UPDATES should not exceed 31 */
#define VFE_FRAME_DROP_VAL 20
#define VFE_NEXT_SOF_MS 500
#define SCALER_RATIO_MAX 16
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
static const struct {
u32 code;
u8 bpp;
} vfe_formats[] = {
{
MEDIA_BUS_FMT_UYVY8_2X8,
8,
},
{
MEDIA_BUS_FMT_VYUY8_2X8,
8,
},
{
MEDIA_BUS_FMT_YUYV8_2X8,
8,
},
{
MEDIA_BUS_FMT_YVYU8_2X8,
8,
},
{
MEDIA_BUS_FMT_SBGGR8_1X8,
8,
},
{
MEDIA_BUS_FMT_SGBRG8_1X8,
8,
},
{
MEDIA_BUS_FMT_SGRBG8_1X8,
8,
},
{
MEDIA_BUS_FMT_SRGGB8_1X8,
8,
},
{
MEDIA_BUS_FMT_SBGGR10_1X10,
10,
},
{
MEDIA_BUS_FMT_SGBRG10_1X10,
10,
},
{
MEDIA_BUS_FMT_SGRBG10_1X10,
10,
},
{
MEDIA_BUS_FMT_SRGGB10_1X10,
10,
},
{
MEDIA_BUS_FMT_SBGGR12_1X12,
12,
},
{
MEDIA_BUS_FMT_SGBRG12_1X12,
12,
},
{
MEDIA_BUS_FMT_SGRBG12_1X12,
12,
},
{
MEDIA_BUS_FMT_SRGGB12_1X12,
12,
}
/*
* vfe_get_bpp - map media bus format to bits per pixel
* @code: media bus format code
*
* Return number of bits per pixel
*/
static u8 vfe_get_bpp(u32 code)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(vfe_formats); i++)
if (code == vfe_formats[i].code)
return vfe_formats[i].bpp;
WARN(1, "Unknown format\n");
return vfe_formats[0].bpp;
}
/*
* vfe_reset - Trigger reset on VFE module and wait to complete
* @vfe: VFE device
*
* Return 0 on success or a negative error code otherwise
*/
static int vfe_reset(struct vfe_device *vfe)
{
unsigned long time;
reinit_completion(&vfe->reset_complete);
vfe->ops->global_reset(vfe);
time = wait_for_completion_timeout(&vfe->reset_complete,
msecs_to_jiffies(VFE_RESET_TIMEOUT_MS));
if (!time) {
dev_err(vfe->camss->dev, "VFE reset timeout\n");
return -EIO;
}
return 0;
}
/*
* vfe_halt - Trigger halt on VFE module and wait to complete
* @vfe: VFE device
*
* Return 0 on success or a negative error code otherwise
*/
static int vfe_halt(struct vfe_device *vfe)
{
unsigned long time;
reinit_completion(&vfe->halt_complete);
vfe->ops->halt_request(vfe);
time = wait_for_completion_timeout(&vfe->halt_complete,
msecs_to_jiffies(VFE_HALT_TIMEOUT_MS));
if (!time) {
dev_err(vfe->camss->dev, "VFE halt timeout\n");
return -EIO;
}
return 0;
}
static void vfe_init_outputs(struct vfe_device *vfe)
{
int i;
for (i = 0; i < ARRAY_SIZE(vfe->line); i++) {
struct vfe_output *output = &vfe->line[i].output;
output->state = VFE_OUTPUT_OFF;
output->buf[0] = NULL;
output->buf[1] = NULL;
INIT_LIST_HEAD(&output->pending_bufs);
output->wm_num = 1;
if (vfe->line[i].id == VFE_LINE_PIX)
output->wm_num = 2;
}
}
static void vfe_reset_output_maps(struct vfe_device *vfe)
{
int i;
for (i = 0; i < ARRAY_SIZE(vfe->wm_output_map); i++)
vfe->wm_output_map[i] = VFE_LINE_NONE;
}
static void vfe_output_init_addrs(struct vfe_device *vfe,
struct vfe_output *output, u8 sync)
{
u32 ping_addr;
u32 pong_addr;
unsigned int i;
for (i = 0; i < output->wm_num; i++) {
if (output->buf[0])
ping_addr = output->buf[0]->addr[i];
else
ping_addr = 0;
if (output->buf[1])
pong_addr = output->buf[1]->addr[i];
else
pong_addr = ping_addr;
vfe->ops->wm_set_ping_addr(vfe, output->wm_idx[i], ping_addr);
vfe->ops->wm_set_pong_addr(vfe, output->wm_idx[i], pong_addr);
if (sync)
vfe->ops->bus_reload_wm(vfe, output->wm_idx[i]);
}
static void vfe_output_update_ping_addr(struct vfe_device *vfe,
struct vfe_output *output, u8 sync)
{
u32 addr;
unsigned int i;
for (i = 0; i < output->wm_num; i++) {
if (output->buf[0])
addr = output->buf[0]->addr[i];
else
addr = 0;
vfe->ops->wm_set_ping_addr(vfe, output->wm_idx[i], addr);
if (sync)
vfe->ops->bus_reload_wm(vfe, output->wm_idx[i]);
}
static void vfe_output_update_pong_addr(struct vfe_device *vfe,
struct vfe_output *output, u8 sync)
{
u32 addr;
unsigned int i;
for (i = 0; i < output->wm_num; i++) {
if (output->buf[1])
addr = output->buf[1]->addr[i];
else
addr = 0;
vfe->ops->wm_set_pong_addr(vfe, output->wm_idx[i], addr);
if (sync)
vfe->ops->bus_reload_wm(vfe, output->wm_idx[i]);
}
static int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id)
{
int ret = -EBUSY;
int i;
for (i = 0; i < ARRAY_SIZE(vfe->wm_output_map); i++) {
if (vfe->wm_output_map[i] == VFE_LINE_NONE) {
vfe->wm_output_map[i] = line_id;
ret = i;
break;
}
}
return ret;
}
static int vfe_release_wm(struct vfe_device *vfe, u8 wm)
{
if (wm >= ARRAY_SIZE(vfe->wm_output_map))
return -EINVAL;
vfe->wm_output_map[wm] = VFE_LINE_NONE;
return 0;
}
static void vfe_output_frame_drop(struct vfe_device *vfe,
struct vfe_output *output,
u32 drop_pattern)
{
u8 drop_period;
unsigned int i;
/* We need to toggle update period to be valid on next frame */
output->drop_update_idx++;
output->drop_update_idx %= VFE_FRAME_DROP_UPDATES;
drop_period = VFE_FRAME_DROP_VAL + output->drop_update_idx;
for (i = 0; i < output->wm_num; i++) {
vfe->ops->wm_set_framedrop_period(vfe, output->wm_idx[i],
drop_period);
vfe->ops->wm_set_framedrop_pattern(vfe, output->wm_idx[i],
drop_pattern);
vfe->ops->reg_update(vfe,
container_of(output, struct vfe_line, output)->id);
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
}
static struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output)
{
struct camss_buffer *buffer = NULL;
if (!list_empty(&output->pending_bufs)) {
buffer = list_first_entry(&output->pending_bufs,
struct camss_buffer,
queue);
list_del(&buffer->queue);
}
return buffer;
}
/*
* vfe_buf_add_pending - Add output buffer to list of pending
* @output: VFE output
* @buffer: Video buffer
*/
static void vfe_buf_add_pending(struct vfe_output *output,
struct camss_buffer *buffer)
{
INIT_LIST_HEAD(&buffer->queue);
list_add_tail(&buffer->queue, &output->pending_bufs);
}
/*
* vfe_buf_flush_pending - Flush all pending buffers.
* @output: VFE output
* @state: vb2 buffer state
*/
static void vfe_buf_flush_pending(struct vfe_output *output,
enum vb2_buffer_state state)
{
struct camss_buffer *buf;
struct camss_buffer *t;
list_for_each_entry_safe(buf, t, &output->pending_bufs, queue) {
vb2_buffer_done(&buf->vb.vb2_buf, state);
list_del(&buf->queue);
}
}
static void vfe_buf_update_wm_on_next(struct vfe_device *vfe,
struct vfe_output *output)
{
switch (output->state) {
case VFE_OUTPUT_CONTINUOUS:
vfe_output_frame_drop(vfe, output, 3);
break;
case VFE_OUTPUT_SINGLE:
default:
"Next buf in wrong state! %d\n",
output->state);
break;
}
}
static void vfe_buf_update_wm_on_last(struct vfe_device *vfe,
struct vfe_output *output)
{
switch (output->state) {
case VFE_OUTPUT_CONTINUOUS:
output->state = VFE_OUTPUT_SINGLE;
vfe_output_frame_drop(vfe, output, 1);
break;
case VFE_OUTPUT_SINGLE:
output->state = VFE_OUTPUT_STOPPING;
vfe_output_frame_drop(vfe, output, 0);
break;
default:
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
"Last buff in wrong state! %d\n",
output->state);
break;
}
}
static void vfe_buf_update_wm_on_new(struct vfe_device *vfe,
struct vfe_output *output,
struct camss_buffer *new_buf)
{
int inactive_idx;
switch (output->state) {
case VFE_OUTPUT_SINGLE:
inactive_idx = !output->active_buf;
if (!output->buf[inactive_idx]) {
output->buf[inactive_idx] = new_buf;
if (inactive_idx)
vfe_output_update_pong_addr(vfe, output, 0);
else
vfe_output_update_ping_addr(vfe, output, 0);
vfe_output_frame_drop(vfe, output, 3);
output->state = VFE_OUTPUT_CONTINUOUS;
} else {
vfe_buf_add_pending(output, new_buf);
"Inactive buffer is busy\n");
}
break;
case VFE_OUTPUT_IDLE:
if (!output->buf[0]) {
output->buf[0] = new_buf;
vfe_output_init_addrs(vfe, output, 1);
vfe_output_frame_drop(vfe, output, 1);
output->state = VFE_OUTPUT_SINGLE;
} else {
vfe_buf_add_pending(output, new_buf);
"Output idle with buffer set!\n");
}
break;
case VFE_OUTPUT_CONTINUOUS:
default:
vfe_buf_add_pending(output, new_buf);
break;
}
}
static int vfe_get_output(struct vfe_line *line)
{
struct vfe_device *vfe = to_vfe(line);
struct vfe_output *output;
unsigned long flags;
int wm_idx;
spin_lock_irqsave(&vfe->output_lock, flags);
output = &line->output;
if (output->state != VFE_OUTPUT_OFF) {
dev_err(vfe->camss->dev, "Output is running\n");
goto error;
}
output->state = VFE_OUTPUT_RESERVED;
output->active_buf = 0;
for (i = 0; i < output->wm_num; i++) {
wm_idx = vfe_reserve_wm(vfe, line->id);
if (wm_idx < 0) {
dev_err(vfe->camss->dev, "Can not reserve wm\n");
goto error_get_wm;
}
output->wm_idx[i] = wm_idx;
output->drop_update_idx = 0;
spin_unlock_irqrestore(&vfe->output_lock, flags);
return 0;
error_get_wm:
for (i--; i >= 0; i--)
vfe_release_wm(vfe, output->wm_idx[i]);
output->state = VFE_OUTPUT_OFF;
error:
spin_unlock_irqrestore(&vfe->output_lock, flags);
return -EINVAL;
}
static int vfe_put_output(struct vfe_line *line)
{
struct vfe_device *vfe = to_vfe(line);
struct vfe_output *output = &line->output;
unsigned long flags;
unsigned int i;
spin_lock_irqsave(&vfe->output_lock, flags);
for (i = 0; i < output->wm_num; i++)
vfe_release_wm(vfe, output->wm_idx[i]);
output->state = VFE_OUTPUT_OFF;
spin_unlock_irqrestore(&vfe->output_lock, flags);
return 0;
}
static int vfe_enable_output(struct vfe_line *line)
{
struct vfe_device *vfe = to_vfe(line);
struct vfe_output *output = &line->output;
const struct vfe_hw_ops *ops = vfe->ops;
unsigned int i;
ub_size = ops->get_ub_size(vfe->id);
if (!ub_size)
return -EINVAL;
spin_lock_irqsave(&vfe->output_lock, flags);
ops->reg_update_clear(vfe, line->id);
if (output->state != VFE_OUTPUT_RESERVED) {
dev_err(vfe->camss->dev, "Output is not in reserved state %d\n",
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
output->state);
spin_unlock_irqrestore(&vfe->output_lock, flags);
return -EINVAL;
}
output->state = VFE_OUTPUT_IDLE;
output->buf[0] = vfe_buf_get_pending(output);
output->buf[1] = vfe_buf_get_pending(output);
if (!output->buf[0] && output->buf[1]) {
output->buf[0] = output->buf[1];
output->buf[1] = NULL;
}
if (output->buf[0])
output->state = VFE_OUTPUT_SINGLE;
if (output->buf[1])
output->state = VFE_OUTPUT_CONTINUOUS;
switch (output->state) {
case VFE_OUTPUT_SINGLE:
vfe_output_frame_drop(vfe, output, 1);
break;
case VFE_OUTPUT_CONTINUOUS:
vfe_output_frame_drop(vfe, output, 3);
break;
default:
vfe_output_frame_drop(vfe, output, 0);
break;
}
output->sequence = 0;
output->wait_sof = 0;
output->wait_reg_update = 0;
reinit_completion(&output->sof);
reinit_completion(&output->reg_update);
vfe_output_init_addrs(vfe, output, 0);
if (line->id != VFE_LINE_PIX) {
ops->set_cgc_override(vfe, output->wm_idx[0], 1);
ops->enable_irq_wm_line(vfe, output->wm_idx[0], line->id, 1);
ops->bus_connect_wm_to_rdi(vfe, output->wm_idx[0], line->id);
ops->wm_set_subsample(vfe, output->wm_idx[0]);
ops->set_rdi_cid(vfe, line->id, 0);
ops->wm_set_ub_cfg(vfe, output->wm_idx[0],
(ub_size + 1) * output->wm_idx[0], ub_size);
ops->wm_frame_based(vfe, output->wm_idx[0], 1);
ops->wm_enable(vfe, output->wm_idx[0], 1);
ops->bus_reload_wm(vfe, output->wm_idx[0]);
} else {
ub_size /= output->wm_num;
for (i = 0; i < output->wm_num; i++) {
ops->set_cgc_override(vfe, output->wm_idx[i], 1);
ops->wm_set_subsample(vfe, output->wm_idx[i]);
ops->wm_set_ub_cfg(vfe, output->wm_idx[i],
(ub_size + 1) * output->wm_idx[i],
ub_size);
ops->wm_line_based(vfe, output->wm_idx[i],
&line->video_out.active_fmt.fmt.pix_mp,
i, 1);
ops->wm_enable(vfe, output->wm_idx[i], 1);
ops->bus_reload_wm(vfe, output->wm_idx[i]);
ops->enable_irq_pix_line(vfe, 0, line->id, 1);
ops->set_module_cfg(vfe, 1);
ops->set_camif_cfg(vfe, line);
ops->set_xbar_cfg(vfe, output, 1);
ops->set_demux_cfg(vfe, line);
ops->set_scale_cfg(vfe, line);
ops->set_crop_cfg(vfe, line);
ops->set_clamp_cfg(vfe);
ops->set_camif_cmd(vfe, 1);
ops->reg_update(vfe, line->id);
spin_unlock_irqrestore(&vfe->output_lock, flags);
return 0;
}
static int vfe_disable_output(struct vfe_line *line)
{
struct vfe_device *vfe = to_vfe(line);
struct vfe_output *output = &line->output;
const struct vfe_hw_ops *ops = vfe->ops;
unsigned long time;
unsigned int i;
spin_lock_irqsave(&vfe->output_lock, flags);
output->wait_sof = 1;
spin_unlock_irqrestore(&vfe->output_lock, flags);
time = wait_for_completion_timeout(&output->sof,
msecs_to_jiffies(VFE_NEXT_SOF_MS));
if (!time)
dev_err(vfe->camss->dev, "VFE sof timeout\n");
spin_lock_irqsave(&vfe->output_lock, flags);
for (i = 0; i < output->wm_num; i++)
ops->wm_enable(vfe, output->wm_idx[i], 0);
ops->reg_update(vfe, line->id);
output->wait_reg_update = 1;
spin_unlock_irqrestore(&vfe->output_lock, flags);
time = wait_for_completion_timeout(&output->reg_update,
msecs_to_jiffies(VFE_NEXT_SOF_MS));
if (!time)
dev_err(vfe->camss->dev, "VFE reg update timeout\n");
spin_lock_irqsave(&vfe->output_lock, flags);
if (line->id != VFE_LINE_PIX) {
ops->wm_frame_based(vfe, output->wm_idx[0], 0);
ops->bus_disconnect_wm_from_rdi(vfe, output->wm_idx[0],
line->id);
ops->enable_irq_wm_line(vfe, output->wm_idx[0], line->id, 0);
ops->set_cgc_override(vfe, output->wm_idx[0], 0);
spin_unlock_irqrestore(&vfe->output_lock, flags);
} else {
for (i = 0; i < output->wm_num; i++) {
ops->wm_line_based(vfe, output->wm_idx[i], NULL, i, 0);
ops->set_cgc_override(vfe, output->wm_idx[i], 0);
ops->enable_irq_pix_line(vfe, 0, line->id, 0);
ops->set_module_cfg(vfe, 0);
ops->set_xbar_cfg(vfe, output, 0);
ops->set_camif_cmd(vfe, 0);
spin_unlock_irqrestore(&vfe->output_lock, flags);
ops->camif_wait_for_stop(vfe, vfe->camss->dev);
return 0;
}
/*
* vfe_enable - Enable streaming on VFE line
* @line: VFE line
*
* Return 0 on success or a negative error code otherwise
*/
static int vfe_enable(struct vfe_line *line)
{
struct vfe_device *vfe = to_vfe(line);
int ret;
mutex_lock(&vfe->stream_lock);
if (!vfe->stream_count) {
vfe->ops->enable_irq_common(vfe);
vfe->ops->bus_enable_wr_if(vfe, 1);
vfe->ops->set_qos(vfe);
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
}
vfe->stream_count++;
mutex_unlock(&vfe->stream_lock);
ret = vfe_get_output(line);
if (ret < 0)
goto error_get_output;
ret = vfe_enable_output(line);
if (ret < 0)
goto error_enable_output;
vfe->was_streaming = 1;
return 0;
error_enable_output:
vfe_put_output(line);
error_get_output:
mutex_lock(&vfe->stream_lock);
if (vfe->stream_count == 1)
vfe->ops->bus_enable_wr_if(vfe, 0);
vfe->stream_count--;
mutex_unlock(&vfe->stream_lock);
return ret;
}
/*
* vfe_disable - Disable streaming on VFE line
* @line: VFE line
*
* Return 0 on success or a negative error code otherwise
*/
static int vfe_disable(struct vfe_line *line)
{
struct vfe_device *vfe = to_vfe(line);
vfe_disable_output(line);
vfe_put_output(line);
mutex_lock(&vfe->stream_lock);
if (vfe->stream_count == 1)
vfe->ops->bus_enable_wr_if(vfe, 0);
vfe->stream_count--;
mutex_unlock(&vfe->stream_lock);
return 0;
}
/*
* vfe_isr_sof - Process start of frame interrupt
* @vfe: VFE Device
* @line_id: VFE line
*/
static void vfe_isr_sof(struct vfe_device *vfe, enum vfe_line_id line_id)
{
struct vfe_output *output;
unsigned long flags;
spin_lock_irqsave(&vfe->output_lock, flags);
output = &vfe->line[line_id].output;
if (output->wait_sof) {
output->wait_sof = 0;
complete(&output->sof);
}
spin_unlock_irqrestore(&vfe->output_lock, flags);
}
/*
* vfe_isr_reg_update - Process reg update interrupt
* @vfe: VFE Device
* @line_id: VFE line
*/
static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
{
struct vfe_output *output;
unsigned long flags;
spin_lock_irqsave(&vfe->output_lock, flags);
vfe->ops->reg_update_clear(vfe, line_id);
if (output->wait_reg_update) {
output->wait_reg_update = 0;
complete(&output->reg_update);
spin_unlock_irqrestore(&vfe->output_lock, flags);
return;
}
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
if (output->state == VFE_OUTPUT_STOPPING) {
/* Release last buffer when hw is idle */
if (output->last_buffer) {
vb2_buffer_done(&output->last_buffer->vb.vb2_buf,
VB2_BUF_STATE_DONE);
output->last_buffer = NULL;
}
output->state = VFE_OUTPUT_IDLE;
/* Buffers received in stopping state are queued in */
/* dma pending queue, start next capture here */
output->buf[0] = vfe_buf_get_pending(output);
output->buf[1] = vfe_buf_get_pending(output);
if (!output->buf[0] && output->buf[1]) {
output->buf[0] = output->buf[1];
output->buf[1] = NULL;
}
if (output->buf[0])
output->state = VFE_OUTPUT_SINGLE;
if (output->buf[1])
output->state = VFE_OUTPUT_CONTINUOUS;
switch (output->state) {
case VFE_OUTPUT_SINGLE:
vfe_output_frame_drop(vfe, output, 2);
break;
case VFE_OUTPUT_CONTINUOUS:
vfe_output_frame_drop(vfe, output, 3);
break;
default:
vfe_output_frame_drop(vfe, output, 0);
break;
}
vfe_output_init_addrs(vfe, output, 1);
}
spin_unlock_irqrestore(&vfe->output_lock, flags);
}
/*
* vfe_isr_wm_done - Process write master done interrupt
* @vfe: VFE Device
* @wm: Write master id
*/
static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
{
struct camss_buffer *ready_buf;
struct vfe_output *output;
dma_addr_t *new_addr;
unsigned long flags;
u32 active_index;
u64 ts = ktime_get_ns();
unsigned int i;
active_index = vfe->ops->wm_get_ping_pong_status(vfe, wm);
spin_lock_irqsave(&vfe->output_lock, flags);
if (vfe->wm_output_map[wm] == VFE_LINE_NONE) {
"Received wm done for unmapped index\n");
goto out_unlock;
}
output = &vfe->line[vfe->wm_output_map[wm]].output;
if (output->active_buf == active_index) {
"Active buffer mismatch!\n");
goto out_unlock;
}
output->active_buf = active_index;
ready_buf = output->buf[!active_index];
if (!ready_buf) {
"Missing ready buf %d %d!\n",
!active_index, output->state);
goto out_unlock;
}
ready_buf->vb.vb2_buf.timestamp = ts;
ready_buf->vb.sequence = output->sequence++;
/* Get next buffer */
output->buf[!active_index] = vfe_buf_get_pending(output);
if (!output->buf[!active_index]) {
/* No next buffer - set same address */
new_addr = ready_buf->addr;
vfe_buf_update_wm_on_last(vfe, output);
} else {
new_addr = output->buf[!active_index]->addr;
vfe_buf_update_wm_on_next(vfe, output);
}
if (active_index)
for (i = 0; i < output->wm_num; i++)
vfe->ops->wm_set_ping_addr(vfe, output->wm_idx[i],
new_addr[i]);
for (i = 0; i < output->wm_num; i++)
vfe->ops->wm_set_pong_addr(vfe, output->wm_idx[i],
new_addr[i]);
spin_unlock_irqrestore(&vfe->output_lock, flags);
if (output->state == VFE_OUTPUT_STOPPING)
output->last_buffer = ready_buf;
else
vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
return;
out_unlock:
spin_unlock_irqrestore(&vfe->output_lock, flags);
}
/*
* vfe_isr_wm_done - Process composite image done interrupt
* @vfe: VFE Device
* @comp: Composite image id
*/
static void vfe_isr_comp_done(struct vfe_device *vfe, u8 comp)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(vfe->wm_output_map); i++)
if (vfe->wm_output_map[i] == VFE_LINE_PIX) {
vfe_isr_wm_done(vfe, i);
break;
}
}
static inline void vfe_isr_reset_ack(struct vfe_device *vfe)
complete(&vfe->reset_complete);
}
static inline void vfe_isr_halt_ack(struct vfe_device *vfe)
{
complete(&vfe->halt_complete);
vfe->ops->halt_clear(vfe);
/*
* vfe_set_clock_rates - Calculate and set clock rates on VFE module
* @vfe: VFE device
*
* Return 0 on success or a negative error code otherwise
*/
static int vfe_set_clock_rates(struct vfe_device *vfe)
{
u32 pixel_clock[MSM_VFE_LINE_NUM];
int i, j;
int ret;
for (i = VFE_LINE_RDI0; i <= VFE_LINE_PIX; i++) {
ret = camss_get_pixel_clock(&vfe->line[i].subdev.entity,
&pixel_clock[i]);
if (ret)
pixel_clock[i] = 0;
}
for (i = 0; i < vfe->nclocks; i++) {
struct camss_clock *clock = &vfe->clock[i];
if (!strcmp(clock->name, "vfe0") ||
!strcmp(clock->name, "vfe1")) {
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
u64 min_rate = 0;
long rate;
for (j = VFE_LINE_RDI0; j <= VFE_LINE_PIX; j++) {
u32 tmp;
u8 bpp;
if (j == VFE_LINE_PIX) {
tmp = pixel_clock[j];
} else {
bpp = vfe_get_bpp(vfe->line[j].
fmt[MSM_VFE_PAD_SINK].code);
tmp = pixel_clock[j] * bpp / 64;
}
if (min_rate < tmp)
min_rate = tmp;
}
camss_add_clock_margin(&min_rate);
for (j = 0; j < clock->nfreqs; j++)
if (min_rate < clock->freq[j])
break;
if (j == clock->nfreqs) {
dev_err(dev,
"Pixel clock is too high for VFE");
return -EINVAL;
}