aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/platform/coda/coda-common.c102
-rw-r--r--drivers/media/platform/coda/coda_regs.h4
2 files changed, 106 insertions, 0 deletions
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c
index 24737f1a1a1b..a7cab14d10c9 100644
--- a/drivers/media/platform/coda/coda-common.c
+++ b/drivers/media/platform/coda/coda-common.c
@@ -15,6 +15,7 @@
15#include <linux/debugfs.h> 15#include <linux/debugfs.h>
16#include <linux/delay.h> 16#include <linux/delay.h>
17#include <linux/firmware.h> 17#include <linux/firmware.h>
18#include <linux/gcd.h>
18#include <linux/genalloc.h> 19#include <linux/genalloc.h>
19#include <linux/interrupt.h> 20#include <linux/interrupt.h>
20#include <linux/io.h> 21#include <linux/io.h>
@@ -770,6 +771,104 @@ static int coda_decoder_cmd(struct file *file, void *fh,
770 return 0; 771 return 0;
771} 772}
772 773
774static int coda_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
775{
776 struct coda_ctx *ctx = fh_to_ctx(fh);
777 struct v4l2_fract *tpf;
778
779 if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
780 return -EINVAL;
781
782 a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
783 tpf = &a->parm.output.timeperframe;
784 tpf->denominator = ctx->params.framerate & CODA_FRATE_RES_MASK;
785 tpf->numerator = 1 + (ctx->params.framerate >>
786 CODA_FRATE_DIV_OFFSET);
787
788 return 0;
789}
790
791/*
792 * Approximate timeperframe v4l2_fract with values that can be written
793 * into the 16-bit CODA_FRATE_DIV and CODA_FRATE_RES fields.
794 */
795static void coda_approximate_timeperframe(struct v4l2_fract *timeperframe)
796{
797 struct v4l2_fract s = *timeperframe;
798 struct v4l2_fract f0;
799 struct v4l2_fract f1 = { 1, 0 };
800 struct v4l2_fract f2 = { 0, 1 };
801 unsigned int i, div, s_denominator;
802
803 /* Lower bound is 1/65535 */
804 if (s.numerator == 0 || s.denominator / s.numerator > 65535) {
805 timeperframe->numerator = 1;
806 timeperframe->denominator = 65535;
807 return;
808 }
809
810 /* Upper bound is 65536/1, map everything above to infinity */
811 if (s.denominator == 0 || s.numerator / s.denominator > 65536) {
812 timeperframe->numerator = 1;
813 timeperframe->denominator = 0;
814 return;
815 }
816
817 /* Reduce fraction to lowest terms */
818 div = gcd(s.numerator, s.denominator);
819 if (div > 1) {
820 s.numerator /= div;
821 s.denominator /= div;
822 }
823
824 if (s.numerator <= 65536 && s.denominator < 65536) {
825 *timeperframe = s;
826 return;
827 }
828
829 /* Find successive convergents from continued fraction expansion */
830 while (f2.numerator <= 65536 && f2.denominator < 65536) {
831 f0 = f1;
832 f1 = f2;
833
834 /* Stop when f2 exactly equals timeperframe */
835 if (s.numerator == 0)
836 break;
837
838 i = s.denominator / s.numerator;
839
840 f2.numerator = f0.numerator + i * f1.numerator;
841 f2.denominator = f0.denominator + i * f2.denominator;
842
843 s_denominator = s.numerator;
844 s.numerator = s.denominator % s.numerator;
845 s.denominator = s_denominator;
846 }
847
848 *timeperframe = f1;
849}
850
851static uint32_t coda_timeperframe_to_frate(struct v4l2_fract *timeperframe)
852{
853 return ((timeperframe->numerator - 1) << CODA_FRATE_DIV_OFFSET) |
854 timeperframe->denominator;
855}
856
857static int coda_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
858{
859 struct coda_ctx *ctx = fh_to_ctx(fh);
860 struct v4l2_fract *tpf;
861
862 if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
863 return -EINVAL;
864
865 tpf = &a->parm.output.timeperframe;
866 coda_approximate_timeperframe(tpf);
867 ctx->params.framerate = coda_timeperframe_to_frate(tpf);
868
869 return 0;
870}
871
773static int coda_subscribe_event(struct v4l2_fh *fh, 872static int coda_subscribe_event(struct v4l2_fh *fh,
774 const struct v4l2_event_subscription *sub) 873 const struct v4l2_event_subscription *sub)
775{ 874{
@@ -810,6 +909,9 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = {
810 .vidioc_try_decoder_cmd = coda_try_decoder_cmd, 909 .vidioc_try_decoder_cmd = coda_try_decoder_cmd,
811 .vidioc_decoder_cmd = coda_decoder_cmd, 910 .vidioc_decoder_cmd = coda_decoder_cmd,
812 911
912 .vidioc_g_parm = coda_g_parm,
913 .vidioc_s_parm = coda_s_parm,
914
813 .vidioc_subscribe_event = coda_subscribe_event, 915 .vidioc_subscribe_event = coda_subscribe_event,
814 .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 916 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
815}; 917};
diff --git a/drivers/media/platform/coda/coda_regs.h b/drivers/media/platform/coda/coda_regs.h
index 7d026241171b..00e4f5160c1f 100644
--- a/drivers/media/platform/coda/coda_regs.h
+++ b/drivers/media/platform/coda/coda_regs.h
@@ -263,6 +263,10 @@
263#define CODADX6_PICHEIGHT_MASK 0x3ff 263#define CODADX6_PICHEIGHT_MASK 0x3ff
264#define CODA7_PICHEIGHT_MASK 0xffff 264#define CODA7_PICHEIGHT_MASK 0xffff
265#define CODA_CMD_ENC_SEQ_SRC_F_RATE 0x194 265#define CODA_CMD_ENC_SEQ_SRC_F_RATE 0x194
266#define CODA_FRATE_RES_OFFSET 0
267#define CODA_FRATE_RES_MASK 0xffff
268#define CODA_FRATE_DIV_OFFSET 16
269#define CODA_FRATE_DIV_MASK 0xffff
266#define CODA_CMD_ENC_SEQ_MP4_PARA 0x198 270#define CODA_CMD_ENC_SEQ_MP4_PARA 0x198
267#define CODA_MP4PARAM_VERID_OFFSET 6 271#define CODA_MP4PARAM_VERID_OFFSET 6
268#define CODA_MP4PARAM_VERID_MASK 0x01 272#define CODA_MP4PARAM_VERID_MASK 0x01