diff options
-rw-r--r-- | drivers/media/platform/coda/coda-common.c | 102 | ||||
-rw-r--r-- | drivers/media/platform/coda/coda_regs.h | 4 |
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 | ||
774 | static 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 | */ | ||
795 | static 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 | |||
851 | static 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 | |||
857 | static 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 | |||
773 | static int coda_subscribe_event(struct v4l2_fh *fh, | 872 | static 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 |