From 8dbcc3fa387c16abfc88a628cf528c439c91b332 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 30 Oct 2020 17:55:22 +0100 Subject: media: v4l2: prepare compat-ioctl rework The v4l2-compat-ioctl32() currently takes an extra round trip through user space pointers when converting the data structure formats. In particular, this involves using the compat_alloc_user_space() and copy_in_user() helpers that often lead to worse compat handlers compared to using in_compat_syscall() checks when copying the data. The native implementation already gained a simpler method to deal with the conversion for the time32 conversion. Hook into the same places to provide a location for reading and writing user space data from inside of the generic video_usercopy() helper. Hans Verkuil rewrote the video_get_user() function here to simplify the zeroing of the extra input fields and fixed a couple of bugs in the original implementation. [hverkuil: fix: CHECK: Please don't use multiple blank lines] Co-developed-by: Hans Verkuil Signed-off-by: Hans Verkuil Signed-off-by: Arnd Bergmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 53 +++++++++ drivers/media/v4l2-core/v4l2-ioctl.c | 159 +++++++++++++++----------- include/media/v4l2-ioctl.h | 10 ++ 3 files changed, 155 insertions(+), 67 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index a99e82ec9ab6..7c939d5c5232 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -1414,6 +1414,59 @@ static int put_v4l2_edid32(struct v4l2_edid __user *p64, #define VIDIOC_G_OUTPUT32 _IOR ('V', 46, s32) #define VIDIOC_S_OUTPUT32 _IOWR('V', 47, s32) +unsigned int v4l2_compat_translate_cmd(unsigned int cmd) +{ + switch (cmd) { + } + return cmd; +} + +int v4l2_compat_get_user(void __user *arg, void *parg, unsigned int cmd) +{ + switch (cmd) { + } + return 0; +} + +int v4l2_compat_put_user(void __user *arg, void *parg, unsigned int cmd) +{ + switch (cmd) { + } + return 0; +} + +int v4l2_compat_get_array_args(struct file *file, void *mbuf, + void __user *user_ptr, size_t array_size, + unsigned int cmd, void *arg) +{ + int err = 0; + + switch (cmd) { + default: + if (copy_from_user(mbuf, user_ptr, array_size)) + err = -EFAULT; + break; + } + + return err; +} + +int v4l2_compat_put_array_args(struct file *file, void __user *user_ptr, + void *mbuf, size_t array_size, + unsigned int cmd, void *arg) +{ + int err = 0; + + switch (cmd) { + default: + if (copy_to_user(user_ptr, mbuf, array_size)) + err = -EFAULT; + break; + } + + return err; +} + /** * alloc_userspace() - Allocates a 64-bits userspace pointer compatible * for calling the native 64-bits version of an ioctl. diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index eeff398fbdcc..b8be61a09776 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -8,6 +8,7 @@ * Mauro Carvalho Chehab (version 2) */ +#include #include #include #include @@ -3104,14 +3105,18 @@ static unsigned int video_translate_cmd(unsigned int cmd) return VIDIOC_PREPARE_BUF; #endif } + if (in_compat_syscall()) + return v4l2_compat_translate_cmd(cmd); return cmd; } -static int video_get_user(void __user *arg, void *parg, unsigned int cmd, +static int video_get_user(void __user *arg, void *parg, + unsigned int real_cmd, unsigned int cmd, bool *always_copy) { - unsigned int n = _IOC_SIZE(cmd); + unsigned int n = _IOC_SIZE(real_cmd); + int err = 0; if (!(_IOC_DIR(cmd) & _IOC_WRITE)) { /* read-only ioctl */ @@ -3119,73 +3124,82 @@ static int video_get_user(void __user *arg, void *parg, unsigned int cmd, return 0; } - switch (cmd) { -#ifdef CONFIG_COMPAT_32BIT_TIME - case VIDIOC_QUERYBUF_TIME32: - case VIDIOC_QBUF_TIME32: - case VIDIOC_DQBUF_TIME32: - case VIDIOC_PREPARE_BUF_TIME32: { - struct v4l2_buffer_time32 vb32; - struct v4l2_buffer *vb = parg; - - if (copy_from_user(&vb32, arg, sizeof(vb32))) - return -EFAULT; - - *vb = (struct v4l2_buffer) { - .index = vb32.index, - .type = vb32.type, - .bytesused = vb32.bytesused, - .flags = vb32.flags, - .field = vb32.field, - .timestamp.tv_sec = vb32.timestamp.tv_sec, - .timestamp.tv_usec = vb32.timestamp.tv_usec, - .timecode = vb32.timecode, - .sequence = vb32.sequence, - .memory = vb32.memory, - .m.userptr = vb32.m.userptr, - .length = vb32.length, - .request_fd = vb32.request_fd, - }; - - if (cmd == VIDIOC_QUERYBUF_TIME32) - vb->request_fd = 0; + /* + * In some cases, only a few fields are used as input, + * i.e. when the app sets "index" and then the driver + * fills in the rest of the structure for the thing + * with that index. We only need to copy up the first + * non-input field. + */ + if (v4l2_is_known_ioctl(real_cmd)) { + u32 flags = v4l2_ioctls[_IOC_NR(real_cmd)].flags; - break; + if (flags & INFO_FL_CLEAR_MASK) + n = (flags & INFO_FL_CLEAR_MASK) >> 16; + *always_copy = flags & INFO_FL_ALWAYS_COPY; } -#endif - default: - /* - * In some cases, only a few fields are used as input, - * i.e. when the app sets "index" and then the driver - * fills in the rest of the structure for the thing - * with that index. We only need to copy up the first - * non-input field. - */ - if (v4l2_is_known_ioctl(cmd)) { - u32 flags = v4l2_ioctls[_IOC_NR(cmd)].flags; - - if (flags & INFO_FL_CLEAR_MASK) - n = (flags & INFO_FL_CLEAR_MASK) >> 16; - *always_copy = flags & INFO_FL_ALWAYS_COPY; - } + if (cmd == real_cmd) { if (copy_from_user(parg, (void __user *)arg, n)) - return -EFAULT; - - /* zero out anything we don't copy from userspace */ - if (n < _IOC_SIZE(cmd)) - memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n); - break; + err = -EFAULT; + } else if (in_compat_syscall()) { + err = v4l2_compat_get_user(arg, parg, cmd); + } else { + switch (cmd) { +#ifdef CONFIG_COMPAT_32BIT_TIME + case VIDIOC_QUERYBUF_TIME32: + case VIDIOC_QBUF_TIME32: + case VIDIOC_DQBUF_TIME32: + case VIDIOC_PREPARE_BUF_TIME32: { + struct v4l2_buffer_time32 vb32; + struct v4l2_buffer *vb = parg; + + if (copy_from_user(&vb32, arg, sizeof(vb32))) + return -EFAULT; + + *vb = (struct v4l2_buffer) { + .index = vb32.index, + .type = vb32.type, + .bytesused = vb32.bytesused, + .flags = vb32.flags, + .field = vb32.field, + .timestamp.tv_sec = vb32.timestamp.tv_sec, + .timestamp.tv_usec = vb32.timestamp.tv_usec, + .timecode = vb32.timecode, + .sequence = vb32.sequence, + .memory = vb32.memory, + .m.userptr = vb32.m.userptr, + .length = vb32.length, + .request_fd = vb32.request_fd, + }; + break; + } +#endif + } } - return 0; + /* zero out anything we don't copy from userspace */ + if (!err && n < _IOC_SIZE(real_cmd)) + memset((u8 *)parg + n, 0, _IOC_SIZE(real_cmd) - n); + return err; } -static int video_put_user(void __user *arg, void *parg, unsigned int cmd) +static int video_put_user(void __user *arg, void *parg, + unsigned int real_cmd, unsigned int cmd) { if (!(_IOC_DIR(cmd) & _IOC_READ)) return 0; + if (cmd == real_cmd) { + /* Copy results into user buffer */ + if (copy_to_user(arg, parg, _IOC_SIZE(cmd))) + return -EFAULT; + return 0; + } + + if (in_compat_syscall()) + return v4l2_compat_put_user(arg, parg, cmd); + switch (cmd) { #ifdef CONFIG_COMPAT_32BIT_TIME case VIDIOC_DQEVENT_TIME32: { @@ -3236,11 +3250,6 @@ static int video_put_user(void __user *arg, void *parg, unsigned int cmd) break; } #endif - default: - /* Copy results into user buffer */ - if (copy_to_user(arg, parg, _IOC_SIZE(cmd))) - return -EFAULT; - break; } return 0; @@ -3274,8 +3283,8 @@ video_usercopy(struct file *file, unsigned int orig_cmd, unsigned long arg, parg = mbuf; } - err = video_get_user((void __user *)arg, parg, orig_cmd, - &always_copy); + err = video_get_user((void __user *)arg, parg, cmd, + orig_cmd, &always_copy); if (err) goto out; } @@ -3297,7 +3306,14 @@ video_usercopy(struct file *file, unsigned int orig_cmd, unsigned long arg, if (NULL == mbuf) goto out_array_args; err = -EFAULT; - if (copy_from_user(mbuf, user_ptr, array_size)) + if (in_compat_syscall()) + err = v4l2_compat_get_array_args(file, mbuf, user_ptr, + array_size, orig_cmd, + parg); + else + err = copy_from_user(mbuf, user_ptr, array_size) ? + -EFAULT : 0; + if (err) goto out_array_args; *kernel_ptr = mbuf; } @@ -3318,8 +3334,17 @@ video_usercopy(struct file *file, unsigned int orig_cmd, unsigned long arg, if (has_array_args) { *kernel_ptr = (void __force *)user_ptr; - if (copy_to_user(user_ptr, mbuf, array_size)) + if (in_compat_syscall()) { + int put_err; + + put_err = v4l2_compat_put_array_args(file, user_ptr, mbuf, + array_size, orig_cmd, + parg); + if (put_err) + err = put_err; + } else if (copy_to_user(user_ptr, mbuf, array_size)) { err = -EFAULT; + } goto out_array_args; } /* @@ -3330,7 +3355,7 @@ video_usercopy(struct file *file, unsigned int orig_cmd, unsigned long arg, goto out; out_array_args: - if (video_put_user((void __user *)arg, parg, orig_cmd)) + if (video_put_user((void __user *)arg, parg, cmd, orig_cmd)) err = -EFAULT; out: kvfree(mbuf); diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index 86878fba332b..edb733f21604 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -686,6 +686,16 @@ long int v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg); #endif +unsigned int v4l2_compat_translate_cmd(unsigned int cmd); +int v4l2_compat_get_user(void __user *arg, void *parg, unsigned int cmd); +int v4l2_compat_put_user(void __user *arg, void *parg, unsigned int cmd); +int v4l2_compat_get_array_args(struct file *file, void *mbuf, + void __user *user_ptr, size_t array_size, + unsigned int cmd, void *arg); +int v4l2_compat_put_array_args(struct file *file, void __user *user_ptr, + void *mbuf, size_t array_size, + unsigned int cmd, void *arg); + /** * typedef v4l2_kioctl - Typedef used to pass an ioctl handler. * -- cgit v1.2.3 From 3b8bc8912adf293291bfbf1be2c7214014f6c313 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 30 Oct 2020 17:55:23 +0100 Subject: media: v4l2: remove unneeded compat ioctl handlers These seven commands are all compatible and do not need any conversion handlers. The existing ones just copy 32-bit integers around, and those are always compatible. Signed-off-by: Arnd Bergmann Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 42 --------------------------- 1 file changed, 42 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 7c939d5c5232..a76f6ac5b1eb 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -1406,14 +1406,6 @@ static int put_v4l2_edid32(struct v4l2_edid __user *p64, #define VIDIOC_PREPARE_BUF32 _IOWR('V', 93, struct v4l2_buffer32) #define VIDIOC_PREPARE_BUF32_TIME32 _IOWR('V', 93, struct v4l2_buffer32_time32) -#define VIDIOC_OVERLAY32 _IOW ('V', 14, s32) -#define VIDIOC_STREAMON32 _IOW ('V', 18, s32) -#define VIDIOC_STREAMOFF32 _IOW ('V', 19, s32) -#define VIDIOC_G_INPUT32 _IOR ('V', 38, s32) -#define VIDIOC_S_INPUT32 _IOWR('V', 39, s32) -#define VIDIOC_G_OUTPUT32 _IOR ('V', 46, s32) -#define VIDIOC_S_OUTPUT32 _IOWR('V', 47, s32) - unsigned int v4l2_compat_translate_cmd(unsigned int cmd) { switch (cmd) { @@ -1544,13 +1536,6 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_DQEVENT32: ncmd = VIDIOC_DQEVENT; break; case VIDIOC_DQEVENT32_TIME32: ncmd = VIDIOC_DQEVENT_TIME32; break; #endif - case VIDIOC_OVERLAY32: ncmd = VIDIOC_OVERLAY; break; - case VIDIOC_STREAMON32: ncmd = VIDIOC_STREAMON; break; - case VIDIOC_STREAMOFF32: ncmd = VIDIOC_STREAMOFF; break; - case VIDIOC_G_INPUT32: ncmd = VIDIOC_G_INPUT; break; - case VIDIOC_S_INPUT32: ncmd = VIDIOC_S_INPUT; break; - case VIDIOC_G_OUTPUT32: ncmd = VIDIOC_G_OUTPUT; break; - case VIDIOC_S_OUTPUT32: ncmd = VIDIOC_S_OUTPUT; break; case VIDIOC_CREATE_BUFS32: ncmd = VIDIOC_CREATE_BUFS; break; case VIDIOC_PREPARE_BUF32: ncmd = VIDIOC_PREPARE_BUF; break; case VIDIOC_PREPARE_BUF32_TIME32: ncmd = VIDIOC_PREPARE_BUF_TIME32; break; @@ -1565,24 +1550,6 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar * argument into it. */ switch (cmd) { - case VIDIOC_OVERLAY32: - case VIDIOC_STREAMON32: - case VIDIOC_STREAMOFF32: - case VIDIOC_S_INPUT32: - case VIDIOC_S_OUTPUT32: - err = alloc_userspace(sizeof(unsigned int), 0, &new_p64); - if (!err && assign_in_user((unsigned int __user *)new_p64, - (compat_uint_t __user *)p32)) - err = -EFAULT; - compatible_arg = 0; - break; - - case VIDIOC_G_INPUT32: - case VIDIOC_G_OUTPUT32: - err = alloc_userspace(sizeof(unsigned int), 0, &new_p64); - compatible_arg = 0; - break; - case VIDIOC_G_EDID32: case VIDIOC_S_EDID32: err = alloc_userspace(sizeof(struct v4l2_edid), 0, &new_p64); @@ -1755,15 +1722,6 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar * the original 32 bits structure. */ switch (cmd) { - case VIDIOC_S_INPUT32: - case VIDIOC_S_OUTPUT32: - case VIDIOC_G_INPUT32: - case VIDIOC_G_OUTPUT32: - if (assign_in_user((compat_uint_t __user *)p32, - ((unsigned int __user *)new_p64))) - err = -EFAULT; - break; - case VIDIOC_G_FBUF32: err = put_v4l2_framebuffer32(new_p64, p32); break; -- cgit v1.2.3 From 6c9361e739a549742a39d8372f37add56e343604 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 30 Oct 2020 17:55:24 +0100 Subject: media: v4l2: move v4l2_ext_controls conversion The v4l2_ext_controls ioctl handlers use an indirect pointer to an incompatible data structure, making the conversion particularly tricky. Moving the compat implementation to use the new v4l2_compat_get_user()/v4l2_compat_put_user() helpers makes it noticeably simpler. In v4l2_compat_get_array_args()/v4l2_compat_put_array_args(), the 'file' argument needs to get passed to determine the exact format, which is a bit unfortunate, as no other conversion needs these. [hverkuil: fix: WARNING: Missing a blank line after declarations] [hverkuil: fix: CHECK: Please don't use multiple blank lines] Signed-off-by: Arnd Bergmann Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 236 ++++++++++---------------- 1 file changed, 90 insertions(+), 146 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index a76f6ac5b1eb..7bec9a848fbf 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -1124,142 +1124,44 @@ static inline bool ctrl_is_pointer(struct file *file, u32 id) (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD); } -static int bufsize_v4l2_ext_controls(struct v4l2_ext_controls32 __user *p32, - u32 *size) -{ - u32 count; - - if (!access_ok(p32, sizeof(*p32)) || - get_user(count, &p32->count)) - return -EFAULT; - if (count > V4L2_CID_MAX_CTRLS) - return -EINVAL; - *size = count * sizeof(struct v4l2_ext_control); - return 0; -} - -static int get_v4l2_ext_controls32(struct file *file, - struct v4l2_ext_controls __user *p64, - struct v4l2_ext_controls32 __user *p32, - void __user *aux_buf, u32 aux_space) +static int get_v4l2_ext_controls32(struct v4l2_ext_controls *p64, + struct v4l2_ext_controls32 __user *p32) { - struct v4l2_ext_control32 __user *ucontrols; - struct v4l2_ext_control __user *kcontrols; - u32 count; - u32 n; - compat_caddr_t p; - - if (!access_ok(p32, sizeof(*p32)) || - assign_in_user(&p64->which, &p32->which) || - get_user(count, &p32->count) || - put_user(count, &p64->count) || - assign_in_user(&p64->error_idx, &p32->error_idx) || - assign_in_user(&p64->request_fd, &p32->request_fd) || - copy_in_user(p64->reserved, p32->reserved, sizeof(p64->reserved))) - return -EFAULT; + struct v4l2_ext_controls32 ec32; - if (count == 0) - return put_user(NULL, &p64->controls); - if (count > V4L2_CID_MAX_CTRLS) - return -EINVAL; - if (get_user(p, &p32->controls)) - return -EFAULT; - ucontrols = compat_ptr(p); - if (!access_ok(ucontrols, count * sizeof(*ucontrols))) - return -EFAULT; - if (aux_space < count * sizeof(*kcontrols)) + if (copy_from_user(&ec32, p32, sizeof(ec32))) return -EFAULT; - kcontrols = aux_buf; - if (put_user_force(kcontrols, &p64->controls)) - return -EFAULT; - - for (n = 0; n < count; n++) { - u32 id; - - if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols))) - return -EFAULT; - - if (get_user(id, &kcontrols->id)) - return -EFAULT; - if (ctrl_is_pointer(file, id)) { - void __user *s; + *p64 = (struct v4l2_ext_controls) { + .which = ec32.which, + .count = ec32.count, + .error_idx = ec32.error_idx, + .request_fd = ec32.request_fd, + .reserved[0] = ec32.reserved[0], + .controls = (void __force *)compat_ptr(ec32.controls), + }; - if (get_user(p, &ucontrols->string)) - return -EFAULT; - s = compat_ptr(p); - if (put_user(s, &kcontrols->string)) - return -EFAULT; - } - ucontrols++; - kcontrols++; - } return 0; } -static int put_v4l2_ext_controls32(struct file *file, - struct v4l2_ext_controls __user *p64, +static int put_v4l2_ext_controls32(struct v4l2_ext_controls *p64, struct v4l2_ext_controls32 __user *p32) { - struct v4l2_ext_control32 __user *ucontrols; - struct v4l2_ext_control *kcontrols; - u32 count; - u32 n; - compat_caddr_t p; - - /* - * We need to define kcontrols without __user, even though it does - * point to data in userspace here. The reason is that v4l2-ioctl.c - * copies it from userspace to kernelspace, so its definition in - * videodev2.h doesn't have a __user markup. Defining kcontrols - * with __user causes smatch warnings, so instead declare it - * without __user and cast it as a userspace pointer where needed. - */ - if (!access_ok(p32, sizeof(*p32)) || - assign_in_user(&p32->which, &p64->which) || - get_user(count, &p64->count) || - put_user(count, &p32->count) || - assign_in_user(&p32->error_idx, &p64->error_idx) || - assign_in_user(&p32->request_fd, &p64->request_fd) || - copy_in_user(p32->reserved, p64->reserved, sizeof(p32->reserved)) || - get_user(kcontrols, &p64->controls)) - return -EFAULT; + struct v4l2_ext_controls32 ec32; + + memset(&ec32, 0, sizeof(ec32)); + ec32 = (struct v4l2_ext_controls32) { + .which = p64->which, + .count = p64->count, + .error_idx = p64->error_idx, + .request_fd = p64->request_fd, + .reserved[0] = p64->reserved[0], + .controls = (uintptr_t)p64->controls, + }; - if (!count || count > (U32_MAX/sizeof(*ucontrols))) - return 0; - if (get_user(p, &p32->controls)) - return -EFAULT; - ucontrols = compat_ptr(p); - if (!access_ok(ucontrols, count * sizeof(*ucontrols))) + if (copy_to_user(p32, &ec32, sizeof(ec32))) return -EFAULT; - for (n = 0; n < count; n++) { - unsigned int size = sizeof(*ucontrols); - u32 id; - - if (get_user_cast(id, &kcontrols->id) || - put_user(id, &ucontrols->id) || - assign_in_user_cast(&ucontrols->size, &kcontrols->size) || - copy_in_user(&ucontrols->reserved2, - (void __user *)&kcontrols->reserved2, - sizeof(ucontrols->reserved2))) - return -EFAULT; - - /* - * Do not modify the pointer when copying a pointer control. - * The contents of the pointer was changed, not the pointer - * itself. - */ - if (ctrl_is_pointer(file, id)) - size -= sizeof(ucontrols->value64); - - if (copy_in_user(ucontrols, - (void __user *)kcontrols, size)) - return -EFAULT; - - ucontrols++; - kcontrols++; - } return 0; } @@ -1409,6 +1311,12 @@ static int put_v4l2_edid32(struct v4l2_edid __user *p64, unsigned int v4l2_compat_translate_cmd(unsigned int cmd) { switch (cmd) { + case VIDIOC_G_EXT_CTRLS32: + return VIDIOC_G_EXT_CTRLS; + case VIDIOC_S_EXT_CTRLS32: + return VIDIOC_S_EXT_CTRLS; + case VIDIOC_TRY_EXT_CTRLS32: + return VIDIOC_TRY_EXT_CTRLS; } return cmd; } @@ -1416,6 +1324,10 @@ unsigned int v4l2_compat_translate_cmd(unsigned int cmd) int v4l2_compat_get_user(void __user *arg, void *parg, unsigned int cmd) { switch (cmd) { + case VIDIOC_G_EXT_CTRLS32: + case VIDIOC_S_EXT_CTRLS32: + case VIDIOC_TRY_EXT_CTRLS32: + return get_v4l2_ext_controls32(parg, arg); } return 0; } @@ -1423,6 +1335,10 @@ int v4l2_compat_get_user(void __user *arg, void *parg, unsigned int cmd) int v4l2_compat_put_user(void __user *arg, void *parg, unsigned int cmd) { switch (cmd) { + case VIDIOC_G_EXT_CTRLS32: + case VIDIOC_S_EXT_CTRLS32: + case VIDIOC_TRY_EXT_CTRLS32: + return put_v4l2_ext_controls32(parg, arg); } return 0; } @@ -1434,6 +1350,30 @@ int v4l2_compat_get_array_args(struct file *file, void *mbuf, int err = 0; switch (cmd) { + case VIDIOC_G_EXT_CTRLS32: + case VIDIOC_S_EXT_CTRLS32: + case VIDIOC_TRY_EXT_CTRLS32: { + struct v4l2_ext_controls *ecs64 = arg; + struct v4l2_ext_control *ec64 = mbuf; + struct v4l2_ext_control32 __user *ec32 = user_ptr; + int n; + + for (n = 0; n < ecs64->count; n++) { + if (copy_from_user(ec64, ec32, sizeof(*ec32))) + return -EFAULT; + + if (ctrl_is_pointer(file, ec64->id)) { + compat_uptr_t p; + + if (get_user(p, &ec32->string)) + return -EFAULT; + ec64->string = compat_ptr(p); + } + ec32++; + ec64++; + } + break; + } default: if (copy_from_user(mbuf, user_ptr, array_size)) err = -EFAULT; @@ -1450,6 +1390,33 @@ int v4l2_compat_put_array_args(struct file *file, void __user *user_ptr, int err = 0; switch (cmd) { + case VIDIOC_G_EXT_CTRLS32: + case VIDIOC_S_EXT_CTRLS32: + case VIDIOC_TRY_EXT_CTRLS32: { + struct v4l2_ext_controls *ecs64 = arg; + struct v4l2_ext_control *ec64 = mbuf; + struct v4l2_ext_control32 __user *ec32 = user_ptr; + int n; + + for (n = 0; n < ecs64->count; n++) { + unsigned int size = sizeof(*ec32); + /* + * Do not modify the pointer when copying a pointer + * control. The contents of the pointer was changed, + * not the pointer itself. + * The structures are otherwise compatible. + */ + if (ctrl_is_pointer(file, ec64->id)) + size -= sizeof(ec32->value64); + + if (copy_to_user(ec32, ec64, size)) + return -EFAULT; + + ec32++; + ec64++; + } + break; + } default: if (copy_to_user(user_ptr, mbuf, array_size)) err = -EFAULT; @@ -1529,9 +1496,6 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_ENUMSTD32: ncmd = VIDIOC_ENUMSTD; break; case VIDIOC_ENUMINPUT32: ncmd = VIDIOC_ENUMINPUT; break; case VIDIOC_TRY_FMT32: ncmd = VIDIOC_TRY_FMT; break; - case VIDIOC_G_EXT_CTRLS32: ncmd = VIDIOC_G_EXT_CTRLS; break; - case VIDIOC_S_EXT_CTRLS32: ncmd = VIDIOC_S_EXT_CTRLS; break; - case VIDIOC_TRY_EXT_CTRLS32: ncmd = VIDIOC_TRY_EXT_CTRLS; break; #ifdef CONFIG_X86_64 case VIDIOC_DQEVENT32: ncmd = VIDIOC_DQEVENT; break; case VIDIOC_DQEVENT32_TIME32: ncmd = VIDIOC_DQEVENT_TIME32; break; @@ -1647,20 +1611,6 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar compatible_arg = 0; break; - case VIDIOC_G_EXT_CTRLS32: - case VIDIOC_S_EXT_CTRLS32: - case VIDIOC_TRY_EXT_CTRLS32: - err = bufsize_v4l2_ext_controls(p32, &aux_space); - if (!err) - err = alloc_userspace(sizeof(struct v4l2_ext_controls), - aux_space, &new_p64); - if (!err) { - aux_buf = new_p64 + sizeof(struct v4l2_ext_controls); - err = get_v4l2_ext_controls32(file, new_p64, p32, - aux_buf, aux_space); - } - compatible_arg = 0; - break; #ifdef CONFIG_X86_64 case VIDIOC_DQEVENT32: err = alloc_userspace(sizeof(struct v4l2_event), 0, &new_p64); @@ -1703,12 +1653,6 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar * the blocks to maximum allowed value. */ switch (cmd) { - case VIDIOC_G_EXT_CTRLS32: - case VIDIOC_S_EXT_CTRLS32: - case VIDIOC_TRY_EXT_CTRLS32: - if (put_v4l2_ext_controls32(file, new_p64, p32)) - err = -EFAULT; - break; case VIDIOC_S_EDID32: if (put_v4l2_edid32(new_p64, p32)) err = -EFAULT; -- cgit v1.2.3 From 00af58fd9a20556a25deb85f32085f82c697c178 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 30 Oct 2020 17:55:25 +0100 Subject: media: v4l2: move compat handling for v4l2_buffer The ioctl commands based on v4l2_buffer have two sets of compat calls, one for native time32 structures, and one for compat structures on 64-bit architectures. Change the compat version to use the same approach as the other simpler one, for both versions of the structure. In an earlier version of the patch, I unified the v4l2_buffer_time32 and v4l2_buffer32_time32 compatibility handling into a single implementation, but that relied on having it all in one file, rather than having the in_compat_syscall() version in v4l2-compat-ioctl32.c. [hverkuil: fix various trivial checkpatch issues] Signed-off-by: Arnd Bergmann Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 724 ++++++++++---------------- 1 file changed, 270 insertions(+), 454 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 7bec9a848fbf..d154179fb6d2 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -521,480 +521,250 @@ struct v4l2_buffer32_time32 { __s32 request_fd; }; -static int get_v4l2_plane32(struct v4l2_plane __user *p64, +static int get_v4l2_plane32(struct v4l2_plane *p64, struct v4l2_plane32 __user *p32, enum v4l2_memory memory) { - compat_ulong_t p; + struct v4l2_plane32 plane32; + typeof(p64->m) m = {}; - if (copy_in_user(p64, p32, 2 * sizeof(__u32)) || - copy_in_user(&p64->data_offset, &p32->data_offset, - sizeof(p64->data_offset))) + if (copy_from_user(&plane32, p32, sizeof(plane32))) return -EFAULT; switch (memory) { case V4L2_MEMORY_MMAP: case V4L2_MEMORY_OVERLAY: - if (copy_in_user(&p64->m.mem_offset, &p32->m.mem_offset, - sizeof(p32->m.mem_offset))) - return -EFAULT; + m.mem_offset = plane32.m.mem_offset; break; case V4L2_MEMORY_USERPTR: - if (get_user(p, &p32->m.userptr) || - put_user((unsigned long)compat_ptr(p), &p64->m.userptr)) - return -EFAULT; + m.userptr = (unsigned long)compat_ptr(plane32.m.userptr); break; case V4L2_MEMORY_DMABUF: - if (copy_in_user(&p64->m.fd, &p32->m.fd, sizeof(p32->m.fd))) - return -EFAULT; + m.fd = plane32.m.fd; break; } + memset(p64, 0, sizeof(*p64)); + *p64 = (struct v4l2_plane) { + .bytesused = plane32.bytesused, + .length = plane32.length, + .m = m, + .data_offset = plane32.data_offset, + }; + return 0; } -static int put_v4l2_plane32(struct v4l2_plane __user *p64, +static int put_v4l2_plane32(struct v4l2_plane *p64, struct v4l2_plane32 __user *p32, enum v4l2_memory memory) { - unsigned long p; + struct v4l2_plane32 plane32; - if (copy_in_user(p32, p64, 2 * sizeof(__u32)) || - copy_in_user(&p32->data_offset, &p64->data_offset, - sizeof(p64->data_offset))) - return -EFAULT; + memset(&plane32, 0, sizeof(plane32)); + plane32 = (struct v4l2_plane32) { + .bytesused = p64->bytesused, + .length = p64->length, + .data_offset = p64->data_offset, + }; switch (memory) { case V4L2_MEMORY_MMAP: case V4L2_MEMORY_OVERLAY: - if (copy_in_user(&p32->m.mem_offset, &p64->m.mem_offset, - sizeof(p64->m.mem_offset))) - return -EFAULT; + plane32.m.mem_offset = p64->m.mem_offset; break; case V4L2_MEMORY_USERPTR: - if (get_user(p, &p64->m.userptr) || - put_user((compat_ulong_t)ptr_to_compat((void __user *)p), - &p32->m.userptr)) - return -EFAULT; + plane32.m.userptr = (uintptr_t)(p64->m.userptr); break; case V4L2_MEMORY_DMABUF: - if (copy_in_user(&p32->m.fd, &p64->m.fd, sizeof(p64->m.fd))) - return -EFAULT; + plane32.m.fd = p64->m.fd; break; } - return 0; -} - -static int bufsize_v4l2_buffer(struct v4l2_buffer32 __user *p32, u32 *size) -{ - u32 type; - u32 length; - - if (!access_ok(p32, sizeof(*p32)) || - get_user(type, &p32->type) || - get_user(length, &p32->length)) + if (copy_to_user(p32, &plane32, sizeof(plane32))) return -EFAULT; - if (V4L2_TYPE_IS_MULTIPLANAR(type)) { - if (length > VIDEO_MAX_PLANES) - return -EINVAL; - - /* - * We don't really care if userspace decides to kill itself - * by passing a very big length value - */ - *size = length * sizeof(struct v4l2_plane); - } else { - *size = 0; - } return 0; } -static int bufsize_v4l2_buffer_time32(struct v4l2_buffer32_time32 __user *p32, u32 *size) +static int get_v4l2_buffer32(struct v4l2_buffer *vb, + struct v4l2_buffer32 __user *arg) { - u32 type; - u32 length; + struct v4l2_buffer32 vb32; - if (!access_ok(p32, sizeof(*p32)) || - get_user(type, &p32->type) || - get_user(length, &p32->length)) + if (copy_from_user(&vb32, arg, sizeof(vb32))) return -EFAULT; - if (V4L2_TYPE_IS_MULTIPLANAR(type)) { - if (length > VIDEO_MAX_PLANES) - return -EINVAL; + memset(vb, 0, sizeof(*vb)); + *vb = (struct v4l2_buffer) { + .index = vb32.index, + .type = vb32.type, + .bytesused = vb32.bytesused, + .flags = vb32.flags, + .field = vb32.field, + .timestamp.tv_sec = vb32.timestamp.tv_sec, + .timestamp.tv_usec = vb32.timestamp.tv_usec, + .timecode = vb32.timecode, + .sequence = vb32.sequence, + .memory = vb32.memory, + .m.offset = vb32.m.offset, + .length = vb32.length, + .request_fd = vb32.request_fd, + }; - /* - * We don't really care if userspace decides to kill itself - * by passing a very big length value - */ - *size = length * sizeof(struct v4l2_plane); - } else { - *size = 0; + switch (vb->memory) { + case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: + vb->m.offset = vb32.m.offset; + break; + case V4L2_MEMORY_USERPTR: + vb->m.userptr = (unsigned long)compat_ptr(vb32.m.userptr); + break; + case V4L2_MEMORY_DMABUF: + vb->m.fd = vb32.m.fd; + break; } - return 0; -} - -static int get_v4l2_buffer32(struct v4l2_buffer __user *p64, - struct v4l2_buffer32 __user *p32, - void __user *aux_buf, u32 aux_space) -{ - u32 type; - u32 length; - s32 request_fd; - enum v4l2_memory memory; - struct v4l2_plane32 __user *uplane32; - struct v4l2_plane __user *uplane; - compat_caddr_t p; - int ret; - - if (!access_ok(p32, sizeof(*p32)) || - assign_in_user(&p64->index, &p32->index) || - get_user(type, &p32->type) || - put_user(type, &p64->type) || - assign_in_user(&p64->flags, &p32->flags) || - get_user(memory, &p32->memory) || - put_user(memory, &p64->memory) || - get_user(length, &p32->length) || - put_user(length, &p64->length) || - get_user(request_fd, &p32->request_fd) || - put_user(request_fd, &p64->request_fd)) - return -EFAULT; - - if (V4L2_TYPE_IS_OUTPUT(type)) - if (assign_in_user(&p64->bytesused, &p32->bytesused) || - assign_in_user(&p64->field, &p32->field) || - assign_in_user(&p64->timestamp.tv_sec, - &p32->timestamp.tv_sec) || - assign_in_user(&p64->timestamp.tv_usec, - &p32->timestamp.tv_usec)) - return -EFAULT; - - if (V4L2_TYPE_IS_MULTIPLANAR(type)) { - u32 num_planes = length; - - if (num_planes == 0) { - /* - * num_planes == 0 is legal, e.g. when userspace doesn't - * need planes array on DQBUF - */ - return put_user(NULL, &p64->m.planes); - } - if (num_planes > VIDEO_MAX_PLANES) - return -EINVAL; - - if (get_user(p, &p32->m.planes)) - return -EFAULT; - - uplane32 = compat_ptr(p); - if (!access_ok(uplane32, - num_planes * sizeof(*uplane32))) - return -EFAULT; - - /* - * We don't really care if userspace decides to kill itself - * by passing a very big num_planes value - */ - if (aux_space < num_planes * sizeof(*uplane)) - return -EFAULT; - - uplane = aux_buf; - if (put_user_force(uplane, &p64->m.planes)) - return -EFAULT; - - while (num_planes--) { - ret = get_v4l2_plane32(uplane, uplane32, memory); - if (ret) - return ret; - uplane++; - uplane32++; - } - } else { - switch (memory) { - case V4L2_MEMORY_MMAP: - case V4L2_MEMORY_OVERLAY: - if (assign_in_user(&p64->m.offset, &p32->m.offset)) - return -EFAULT; - break; - case V4L2_MEMORY_USERPTR: { - compat_ulong_t userptr; - if (get_user(userptr, &p32->m.userptr) || - put_user((unsigned long)compat_ptr(userptr), - &p64->m.userptr)) - return -EFAULT; - break; - } - case V4L2_MEMORY_DMABUF: - if (assign_in_user(&p64->m.fd, &p32->m.fd)) - return -EFAULT; - break; - } - } + if (V4L2_TYPE_IS_MULTIPLANAR(vb->type)) + vb->m.planes = (void __force *) + compat_ptr(vb32.m.planes); return 0; } -static int get_v4l2_buffer32_time32(struct v4l2_buffer_time32 __user *p64, - struct v4l2_buffer32_time32 __user *p32, - void __user *aux_buf, u32 aux_space) +#ifdef CONFIG_COMPAT_32BIT_TIME +static int get_v4l2_buffer32_time32(struct v4l2_buffer *vb, + struct v4l2_buffer32_time32 __user *arg) { - u32 type; - u32 length; - s32 request_fd; - enum v4l2_memory memory; - struct v4l2_plane32 __user *uplane32; - struct v4l2_plane __user *uplane; - compat_caddr_t p; - int ret; + struct v4l2_buffer32_time32 vb32; - if (!access_ok(p32, sizeof(*p32)) || - assign_in_user(&p64->index, &p32->index) || - get_user(type, &p32->type) || - put_user(type, &p64->type) || - assign_in_user(&p64->flags, &p32->flags) || - get_user(memory, &p32->memory) || - put_user(memory, &p64->memory) || - get_user(length, &p32->length) || - put_user(length, &p64->length) || - get_user(request_fd, &p32->request_fd) || - put_user(request_fd, &p64->request_fd)) + if (copy_from_user(&vb32, arg, sizeof(vb32))) return -EFAULT; - if (V4L2_TYPE_IS_OUTPUT(type)) - if (assign_in_user(&p64->bytesused, &p32->bytesused) || - assign_in_user(&p64->field, &p32->field) || - assign_in_user(&p64->timestamp.tv_sec, - &p32->timestamp.tv_sec) || - assign_in_user(&p64->timestamp.tv_usec, - &p32->timestamp.tv_usec)) - return -EFAULT; - - if (V4L2_TYPE_IS_MULTIPLANAR(type)) { - u32 num_planes = length; - - if (num_planes == 0) { - /* - * num_planes == 0 is legal, e.g. when userspace doesn't - * need planes array on DQBUF - */ - return put_user(NULL, &p64->m.planes); - } - if (num_planes > VIDEO_MAX_PLANES) - return -EINVAL; - - if (get_user(p, &p32->m.planes)) - return -EFAULT; - - uplane32 = compat_ptr(p); - if (!access_ok(uplane32, - num_planes * sizeof(*uplane32))) - return -EFAULT; - - /* - * We don't really care if userspace decides to kill itself - * by passing a very big num_planes value - */ - if (aux_space < num_planes * sizeof(*uplane)) - return -EFAULT; - - uplane = aux_buf; - if (put_user_force(uplane, &p64->m.planes)) - return -EFAULT; - - while (num_planes--) { - ret = get_v4l2_plane32(uplane, uplane32, memory); - if (ret) - return ret; - uplane++; - uplane32++; - } - } else { - switch (memory) { - case V4L2_MEMORY_MMAP: - case V4L2_MEMORY_OVERLAY: - if (assign_in_user(&p64->m.offset, &p32->m.offset)) - return -EFAULT; - break; - case V4L2_MEMORY_USERPTR: { - compat_ulong_t userptr; - - if (get_user(userptr, &p32->m.userptr) || - put_user((unsigned long)compat_ptr(userptr), - &p64->m.userptr)) - return -EFAULT; - break; - } - case V4L2_MEMORY_DMABUF: - if (assign_in_user(&p64->m.fd, &p32->m.fd)) - return -EFAULT; - break; - } + *vb = (struct v4l2_buffer) { + .index = vb32.index, + .type = vb32.type, + .bytesused = vb32.bytesused, + .flags = vb32.flags, + .field = vb32.field, + .timestamp.tv_sec = vb32.timestamp.tv_sec, + .timestamp.tv_usec = vb32.timestamp.tv_usec, + .timecode = vb32.timecode, + .sequence = vb32.sequence, + .memory = vb32.memory, + .m.offset = vb32.m.offset, + .length = vb32.length, + .request_fd = vb32.request_fd, + }; + switch (vb->memory) { + case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: + vb->m.offset = vb32.m.offset; + break; + case V4L2_MEMORY_USERPTR: + vb->m.userptr = (unsigned long)compat_ptr(vb32.m.userptr); + break; + case V4L2_MEMORY_DMABUF: + vb->m.fd = vb32.m.fd; + break; } + if (V4L2_TYPE_IS_MULTIPLANAR(vb->type)) + vb->m.planes = (void __force *) + compat_ptr(vb32.m.planes); + return 0; } +#endif -static int put_v4l2_buffer32(struct v4l2_buffer __user *p64, - struct v4l2_buffer32 __user *p32) +static int put_v4l2_buffer32(struct v4l2_buffer *vb, + struct v4l2_buffer32 __user *arg) { - u32 type; - u32 length; - enum v4l2_memory memory; - struct v4l2_plane32 __user *uplane32; - struct v4l2_plane *uplane; - compat_caddr_t p; - int ret; + struct v4l2_buffer32 vb32; + + memset(&vb32, 0, sizeof(vb32)); + vb32 = (struct v4l2_buffer32) { + .index = vb->index, + .type = vb->type, + .bytesused = vb->bytesused, + .flags = vb->flags, + .field = vb->field, + .timestamp.tv_sec = vb->timestamp.tv_sec, + .timestamp.tv_usec = vb->timestamp.tv_usec, + .timecode = vb->timecode, + .sequence = vb->sequence, + .memory = vb->memory, + .m.offset = vb->m.offset, + .length = vb->length, + .request_fd = vb->request_fd, + }; - if (!access_ok(p32, sizeof(*p32)) || - assign_in_user(&p32->index, &p64->index) || - get_user(type, &p64->type) || - put_user(type, &p32->type) || - assign_in_user(&p32->flags, &p64->flags) || - get_user(memory, &p64->memory) || - put_user(memory, &p32->memory)) - return -EFAULT; + switch (vb->memory) { + case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: + vb32.m.offset = vb->m.offset; + break; + case V4L2_MEMORY_USERPTR: + vb32.m.userptr = (uintptr_t)(vb->m.userptr); + break; + case V4L2_MEMORY_DMABUF: + vb32.m.fd = vb->m.fd; + break; + } - if (assign_in_user(&p32->bytesused, &p64->bytesused) || - assign_in_user(&p32->field, &p64->field) || - assign_in_user(&p32->timestamp.tv_sec, &p64->timestamp.tv_sec) || - assign_in_user(&p32->timestamp.tv_usec, &p64->timestamp.tv_usec) || - copy_in_user(&p32->timecode, &p64->timecode, sizeof(p64->timecode)) || - assign_in_user(&p32->sequence, &p64->sequence) || - assign_in_user(&p32->reserved2, &p64->reserved2) || - assign_in_user(&p32->request_fd, &p64->request_fd) || - get_user(length, &p64->length) || - put_user(length, &p32->length)) - return -EFAULT; + if (V4L2_TYPE_IS_MULTIPLANAR(vb->type)) + vb32.m.planes = (uintptr_t)vb->m.planes; - if (V4L2_TYPE_IS_MULTIPLANAR(type)) { - u32 num_planes = length; - - if (num_planes == 0) - return 0; - /* We need to define uplane without __user, even though - * it does point to data in userspace here. The reason is - * that v4l2-ioctl.c copies it from userspace to kernelspace, - * so its definition in videodev2.h doesn't have a - * __user markup. Defining uplane with __user causes - * smatch warnings, so instead declare it without __user - * and cast it as a userspace pointer to put_v4l2_plane32(). - */ - if (get_user(uplane, &p64->m.planes)) - return -EFAULT; - if (get_user(p, &p32->m.planes)) - return -EFAULT; - uplane32 = compat_ptr(p); - - while (num_planes--) { - ret = put_v4l2_plane32((void __user *)uplane, - uplane32, memory); - if (ret) - return ret; - ++uplane; - ++uplane32; - } - } else { - switch (memory) { - case V4L2_MEMORY_MMAP: - case V4L2_MEMORY_OVERLAY: - if (assign_in_user(&p32->m.offset, &p64->m.offset)) - return -EFAULT; - break; - case V4L2_MEMORY_USERPTR: - if (assign_in_user(&p32->m.userptr, &p64->m.userptr)) - return -EFAULT; - break; - case V4L2_MEMORY_DMABUF: - if (assign_in_user(&p32->m.fd, &p64->m.fd)) - return -EFAULT; - break; - } - } + if (copy_to_user(arg, &vb32, sizeof(vb32))) + return -EFAULT; return 0; } -static int put_v4l2_buffer32_time32(struct v4l2_buffer_time32 __user *p64, - struct v4l2_buffer32_time32 __user *p32) +#ifdef CONFIG_COMPAT_32BIT_TIME +static int put_v4l2_buffer32_time32(struct v4l2_buffer *vb, + struct v4l2_buffer32_time32 __user *arg) { - u32 type; - u32 length; - enum v4l2_memory memory; - struct v4l2_plane32 __user *uplane32; - struct v4l2_plane *uplane; - compat_caddr_t p; - int ret; + struct v4l2_buffer32_time32 vb32; + + memset(&vb32, 0, sizeof(vb32)); + vb32 = (struct v4l2_buffer32_time32) { + .index = vb->index, + .type = vb->type, + .bytesused = vb->bytesused, + .flags = vb->flags, + .field = vb->field, + .timestamp.tv_sec = vb->timestamp.tv_sec, + .timestamp.tv_usec = vb->timestamp.tv_usec, + .timecode = vb->timecode, + .sequence = vb->sequence, + .memory = vb->memory, + .m.offset = vb->m.offset, + .length = vb->length, + .request_fd = vb->request_fd, + }; + switch (vb->memory) { + case V4L2_MEMORY_MMAP: + case V4L2_MEMORY_OVERLAY: + vb32.m.offset = vb->m.offset; + break; + case V4L2_MEMORY_USERPTR: + vb32.m.userptr = (uintptr_t)(vb->m.userptr); + break; + case V4L2_MEMORY_DMABUF: + vb32.m.fd = vb->m.fd; + break; + } - if (!access_ok(p32, sizeof(*p32)) || - assign_in_user(&p32->index, &p64->index) || - get_user(type, &p64->type) || - put_user(type, &p32->type) || - assign_in_user(&p32->flags, &p64->flags) || - get_user(memory, &p64->memory) || - put_user(memory, &p32->memory)) - return -EFAULT; + if (V4L2_TYPE_IS_MULTIPLANAR(vb->type)) + vb32.m.planes = (uintptr_t)vb->m.planes; - if (assign_in_user(&p32->bytesused, &p64->bytesused) || - assign_in_user(&p32->field, &p64->field) || - assign_in_user(&p32->timestamp.tv_sec, &p64->timestamp.tv_sec) || - assign_in_user(&p32->timestamp.tv_usec, &p64->timestamp.tv_usec) || - copy_in_user(&p32->timecode, &p64->timecode, sizeof(p64->timecode)) || - assign_in_user(&p32->sequence, &p64->sequence) || - assign_in_user(&p32->reserved2, &p64->reserved2) || - assign_in_user(&p32->request_fd, &p64->request_fd) || - get_user(length, &p64->length) || - put_user(length, &p32->length)) + if (copy_to_user(arg, &vb32, sizeof(vb32))) return -EFAULT; - if (V4L2_TYPE_IS_MULTIPLANAR(type)) { - u32 num_planes = length; - - if (num_planes == 0) - return 0; - /* We need to define uplane without __user, even though - * it does point to data in userspace here. The reason is - * that v4l2-ioctl.c copies it from userspace to kernelspace, - * so its definition in videodev2.h doesn't have a - * __user markup. Defining uplane with __user causes - * smatch warnings, so instead declare it without __user - * and cast it as a userspace pointer to put_v4l2_plane32(). - */ - if (get_user(uplane, &p64->m.planes)) - return -EFAULT; - if (get_user(p, &p32->m.planes)) - return -EFAULT; - uplane32 = compat_ptr(p); - - while (num_planes--) { - ret = put_v4l2_plane32((void __user *)uplane, - uplane32, memory); - if (ret) - return ret; - ++uplane; - ++uplane32; - } - } else { - switch (memory) { - case V4L2_MEMORY_MMAP: - case V4L2_MEMORY_OVERLAY: - if (assign_in_user(&p32->m.offset, &p64->m.offset)) - return -EFAULT; - break; - case V4L2_MEMORY_USERPTR: - if (assign_in_user(&p32->m.userptr, &p64->m.userptr)) - return -EFAULT; - break; - case V4L2_MEMORY_DMABUF: - if (assign_in_user(&p32->m.fd, &p64->m.fd)) - return -EFAULT; - break; - } - } - return 0; } +#endif struct v4l2_framebuffer32 { __u32 capability; @@ -1311,12 +1081,30 @@ static int put_v4l2_edid32(struct v4l2_edid __user *p64, unsigned int v4l2_compat_translate_cmd(unsigned int cmd) { switch (cmd) { +#ifdef CONFIG_COMPAT_32BIT_TIME + case VIDIOC_QUERYBUF32_TIME32: + return VIDIOC_QUERYBUF; + case VIDIOC_QBUF32_TIME32: + return VIDIOC_QBUF; + case VIDIOC_DQBUF32_TIME32: + return VIDIOC_DQBUF; + case VIDIOC_PREPARE_BUF32_TIME32: + return VIDIOC_PREPARE_BUF; +#endif + case VIDIOC_QUERYBUF32: + return VIDIOC_QUERYBUF; + case VIDIOC_QBUF32: + return VIDIOC_QBUF; + case VIDIOC_DQBUF32: + return VIDIOC_DQBUF; case VIDIOC_G_EXT_CTRLS32: return VIDIOC_G_EXT_CTRLS; case VIDIOC_S_EXT_CTRLS32: return VIDIOC_S_EXT_CTRLS; case VIDIOC_TRY_EXT_CTRLS32: return VIDIOC_TRY_EXT_CTRLS; + case VIDIOC_PREPARE_BUF32: + return VIDIOC_PREPARE_BUF; } return cmd; } @@ -1324,6 +1112,19 @@ unsigned int v4l2_compat_translate_cmd(unsigned int cmd) int v4l2_compat_get_user(void __user *arg, void *parg, unsigned int cmd) { switch (cmd) { +#ifdef CONFIG_COMPAT_32BIT_TIME + case VIDIOC_QUERYBUF32_TIME32: + case VIDIOC_QBUF32_TIME32: + case VIDIOC_DQBUF32_TIME32: + case VIDIOC_PREPARE_BUF32_TIME32: + return get_v4l2_buffer32_time32(parg, arg); +#endif + case VIDIOC_QUERYBUF32: + case VIDIOC_QBUF32: + case VIDIOC_DQBUF32: + case VIDIOC_PREPARE_BUF32: + return get_v4l2_buffer32(parg, arg); + case VIDIOC_G_EXT_CTRLS32: case VIDIOC_S_EXT_CTRLS32: case VIDIOC_TRY_EXT_CTRLS32: @@ -1335,6 +1136,19 @@ int v4l2_compat_get_user(void __user *arg, void *parg, unsigned int cmd) int v4l2_compat_put_user(void __user *arg, void *parg, unsigned int cmd) { switch (cmd) { +#ifdef CONFIG_COMPAT_32BIT_TIME + case VIDIOC_QUERYBUF32_TIME32: + case VIDIOC_QBUF32_TIME32: + case VIDIOC_DQBUF32_TIME32: + case VIDIOC_PREPARE_BUF32_TIME32: + return put_v4l2_buffer32_time32(parg, arg); +#endif + case VIDIOC_QUERYBUF32: + case VIDIOC_QBUF32: + case VIDIOC_DQBUF32: + case VIDIOC_PREPARE_BUF32: + return put_v4l2_buffer32(parg, arg); + case VIDIOC_G_EXT_CTRLS32: case VIDIOC_S_EXT_CTRLS32: case VIDIOC_TRY_EXT_CTRLS32: @@ -1350,6 +1164,34 @@ int v4l2_compat_get_array_args(struct file *file, void *mbuf, int err = 0; switch (cmd) { + case VIDIOC_QUERYBUF32_TIME32: + case VIDIOC_QBUF32_TIME32: + case VIDIOC_DQBUF32_TIME32: + case VIDIOC_PREPARE_BUF32_TIME32: + case VIDIOC_QUERYBUF32: + case VIDIOC_QBUF32: + case VIDIOC_DQBUF32: + case VIDIOC_PREPARE_BUF32: { + struct v4l2_buffer *b64 = arg; + struct v4l2_plane *p64 = mbuf; + struct v4l2_plane32 __user *p32 = user_ptr; + + if (V4L2_TYPE_IS_MULTIPLANAR(b64->type)) { + u32 num_planes = b64->length; + + if (num_planes == 0) + return 0; + + while (num_planes--) { + err = get_v4l2_plane32(p64, p32, b64->memory); + if (err) + return err; + ++p64; + ++p32; + } + } + break; + } case VIDIOC_G_EXT_CTRLS32: case VIDIOC_S_EXT_CTRLS32: case VIDIOC_TRY_EXT_CTRLS32: { @@ -1390,6 +1232,34 @@ int v4l2_compat_put_array_args(struct file *file, void __user *user_ptr, int err = 0; switch (cmd) { + case VIDIOC_QUERYBUF32_TIME32: + case VIDIOC_QBUF32_TIME32: + case VIDIOC_DQBUF32_TIME32: + case VIDIOC_PREPARE_BUF32_TIME32: + case VIDIOC_QUERYBUF32: + case VIDIOC_QBUF32: + case VIDIOC_DQBUF32: + case VIDIOC_PREPARE_BUF32: { + struct v4l2_buffer *b64 = arg; + struct v4l2_plane *p64 = mbuf; + struct v4l2_plane32 __user *p32 = user_ptr; + + if (V4L2_TYPE_IS_MULTIPLANAR(b64->type)) { + u32 num_planes = b64->length; + + if (num_planes == 0) + return 0; + + while (num_planes--) { + err = put_v4l2_plane32(p64, p32, b64->memory); + if (err) + return err; + ++p64; + ++p32; + } + } + break; + } case VIDIOC_G_EXT_CTRLS32: case VIDIOC_S_EXT_CTRLS32: case VIDIOC_TRY_EXT_CTRLS32: { @@ -1485,14 +1355,8 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar switch (cmd) { case VIDIOC_G_FMT32: ncmd = VIDIOC_G_FMT; break; case VIDIOC_S_FMT32: ncmd = VIDIOC_S_FMT; break; - case VIDIOC_QUERYBUF32: ncmd = VIDIOC_QUERYBUF; break; - case VIDIOC_QUERYBUF32_TIME32: ncmd = VIDIOC_QUERYBUF_TIME32; break; case VIDIOC_G_FBUF32: ncmd = VIDIOC_G_FBUF; break; case VIDIOC_S_FBUF32: ncmd = VIDIOC_S_FBUF; break; - case VIDIOC_QBUF32: ncmd = VIDIOC_QBUF; break; - case VIDIOC_QBUF32_TIME32: ncmd = VIDIOC_QBUF_TIME32; break; - case VIDIOC_DQBUF32: ncmd = VIDIOC_DQBUF; break; - case VIDIOC_DQBUF32_TIME32: ncmd = VIDIOC_DQBUF_TIME32; break; case VIDIOC_ENUMSTD32: ncmd = VIDIOC_ENUMSTD; break; case VIDIOC_ENUMINPUT32: ncmd = VIDIOC_ENUMINPUT; break; case VIDIOC_TRY_FMT32: ncmd = VIDIOC_TRY_FMT; break; @@ -1501,8 +1365,6 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_DQEVENT32_TIME32: ncmd = VIDIOC_DQEVENT_TIME32; break; #endif case VIDIOC_CREATE_BUFS32: ncmd = VIDIOC_CREATE_BUFS; break; - case VIDIOC_PREPARE_BUF32: ncmd = VIDIOC_PREPARE_BUF; break; - case VIDIOC_PREPARE_BUF32_TIME32: ncmd = VIDIOC_PREPARE_BUF_TIME32; break; case VIDIOC_G_EDID32: ncmd = VIDIOC_G_EDID; break; case VIDIOC_S_EDID32: ncmd = VIDIOC_S_EDID; break; default: ncmd = cmd; break; @@ -1550,38 +1412,6 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar compatible_arg = 0; break; - case VIDIOC_PREPARE_BUF32: - case VIDIOC_QUERYBUF32: - case VIDIOC_QBUF32: - case VIDIOC_DQBUF32: - err = bufsize_v4l2_buffer(p32, &aux_space); - if (!err) - err = alloc_userspace(sizeof(struct v4l2_buffer), - aux_space, &new_p64); - if (!err) { - aux_buf = new_p64 + sizeof(struct v4l2_buffer); - err = get_v4l2_buffer32(new_p64, p32, - aux_buf, aux_space); - } - compatible_arg = 0; - break; - - case VIDIOC_PREPARE_BUF32_TIME32: - case VIDIOC_QUERYBUF32_TIME32: - case VIDIOC_QBUF32_TIME32: - case VIDIOC_DQBUF32_TIME32: - err = bufsize_v4l2_buffer_time32(p32, &aux_space); - if (!err) - err = alloc_userspace(sizeof(struct v4l2_buffer), - aux_space, &new_p64); - if (!err) { - aux_buf = new_p64 + sizeof(struct v4l2_buffer); - err = get_v4l2_buffer32_time32(new_p64, p32, - aux_buf, aux_space); - } - compatible_arg = 0; - break; - case VIDIOC_S_FBUF32: err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0, &new_p64); @@ -1694,20 +1524,6 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar err = put_v4l2_create32(new_p64, p32); break; - case VIDIOC_PREPARE_BUF32: - case VIDIOC_QUERYBUF32: - case VIDIOC_QBUF32: - case VIDIOC_DQBUF32: - err = put_v4l2_buffer32(new_p64, p32); - break; - - case VIDIOC_PREPARE_BUF32_TIME32: - case VIDIOC_QUERYBUF32_TIME32: - case VIDIOC_QBUF32_TIME32: - case VIDIOC_DQBUF32_TIME32: - err = put_v4l2_buffer32_time32(new_p64, p32); - break; - case VIDIOC_ENUMSTD32: err = put_v4l2_standard32(new_p64, p32); break; -- cgit v1.2.3 From 3f65c6f67e8813448d7e3cfd3470b0f8c15bfaea Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 30 Oct 2020 17:55:26 +0100 Subject: media: v4l2: allocate v4l2_clip objects early The v4l2_format based ioctls can have an indirect pointer to an array of v4l2_clip structures for overlay mode, depending on the 'type' member. There are only five drivers that use the overlay mode and copy the data through the __user pointer. Change the five drivers to use memcpy() instead, and copy the data in common code using the check_array_args() helpers. This allows for a subsequent patch that use the same mechanism for compat ioctl handlers. Note that there is another pointer for a 'bitmap' that is only used in the 'vivid' driver and nowhere else. There is no easy way to use the same trick without adding complexity to the common code, so this remains a __user pointer. [hverkuil: fix: CHECK: spaces preferred around that '*' (ctx:VxV)] [hverkuil: fix: CHECK: Alignment should match open parenthesis] Signed-off-by: Arnd Bergmann Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146/saa7146_video.c | 6 ++---- drivers/media/pci/bt8xx/bttv-driver.c | 8 ++------ drivers/media/pci/saa7134/saa7134-video.c | 19 +++++++------------ drivers/media/test-drivers/vivid/vivid-vid-cap.c | 18 +++++++----------- drivers/media/test-drivers/vivid/vivid-vid-out.c | 18 +++++++----------- drivers/media/v4l2-core/v4l2-ioctl.c | 23 ++++++++++++++++++++++- include/uapi/linux/videodev2.h | 2 +- 7 files changed, 48 insertions(+), 46 deletions(-) diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c index ccd15b4d4920..7b8795eca589 100644 --- a/drivers/media/common/saa7146/saa7146_video.c +++ b/drivers/media/common/saa7146/saa7146_video.c @@ -771,10 +771,8 @@ static int vidioc_s_fmt_vid_overlay(struct file *file, void *__fh, struct v4l2_f vv->ov.nclips = f->fmt.win.clipcount; if (vv->ov.nclips > 16) vv->ov.nclips = 16; - if (copy_from_user(vv->ov.clips, f->fmt.win.clips, - sizeof(struct v4l2_clip) * vv->ov.nclips)) { - return -EFAULT; - } + memcpy(vv->ov.clips, f->fmt.win.clips, + sizeof(struct v4l2_clip) * vv->ov.nclips); /* vv->ov.fh is used to indicate that we have valid overlay information, too */ vv->ov.fh = fh; diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 8824dd0fb331..ef2ead36b70e 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -2143,12 +2143,8 @@ static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv, clips = kmalloc(size,GFP_KERNEL); if (NULL == clips) return -ENOMEM; - if (n > 0) { - if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) { - kfree(clips); - return -EFAULT; - } - } + if (n > 0) + memcpy(clips, win->clips, sizeof(struct v4l2_clip) * n); /* clip against screen */ if (NULL != btv->fbuf.base) diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 9a6a6b68f8e3..94c1c10d0fea 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -1265,9 +1265,7 @@ static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_dev *dev = video_drvdata(file); - struct v4l2_clip __user *clips = f->fmt.win.clips; u32 clipcount = f->fmt.win.clipcount; - int err = 0; int i; if (saa7134_no_overlay > 0) { @@ -1275,20 +1273,18 @@ static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv, return -EINVAL; } f->fmt.win = dev->win; - f->fmt.win.clips = clips; - if (clips == NULL) + if (!f->fmt.win.clips) clipcount = 0; if (dev->nclips < clipcount) clipcount = dev->nclips; f->fmt.win.clipcount = clipcount; - for (i = 0; !err && i < clipcount; i++) { - if (copy_to_user(&f->fmt.win.clips[i].c, &dev->clips[i].c, - sizeof(struct v4l2_rect))) - err = -EFAULT; + for (i = 0; i < clipcount; i++) { + memcpy(&f->fmt.win.clips[i].c, &dev->clips[i].c, + sizeof(struct v4l2_rect)); } - return err; + return 0; } static int saa7134_try_fmt_vid_cap(struct file *file, void *priv, @@ -1396,9 +1392,8 @@ static int saa7134_s_fmt_vid_overlay(struct file *file, void *priv, dev->win = f->fmt.win; dev->nclips = f->fmt.win.clipcount; - if (copy_from_user(dev->clips, f->fmt.win.clips, - sizeof(struct v4l2_clip) * dev->nclips)) - return -EFAULT; + memcpy(dev->clips, f->fmt.win.clips, + sizeof(struct v4l2_clip) * dev->nclips); if (priv == dev->overlay_owner) { spin_lock_irqsave(&dev->slock, flags); diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.c b/drivers/media/test-drivers/vivid/vivid-vid-cap.c index eadf28ab1e39..b9caa4b26209 100644 --- a/drivers/media/test-drivers/vivid/vivid-vid-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.c @@ -1107,11 +1107,9 @@ int vidioc_g_fmt_vid_overlay(struct file *file, void *priv, ((compose->width + 7) / 8) * compose->height)) return -EFAULT; } - if (clipcount && win->clips) { - if (copy_to_user(win->clips, dev->clips_cap, - clipcount * sizeof(dev->clips_cap[0]))) - return -EFAULT; - } + if (clipcount && win->clips) + memcpy(win->clips, dev->clips_cap, + clipcount * sizeof(dev->clips_cap[0])); return 0; } @@ -1141,9 +1139,8 @@ int vidioc_try_fmt_vid_overlay(struct file *file, void *priv, if (win->clipcount > MAX_CLIPS) win->clipcount = MAX_CLIPS; if (win->clipcount) { - if (copy_from_user(dev->try_clips_cap, win->clips, - win->clipcount * sizeof(dev->clips_cap[0]))) - return -EFAULT; + memcpy(dev->try_clips_cap, win->clips, + win->clipcount * sizeof(dev->clips_cap[0])); for (i = 0; i < win->clipcount; i++) { struct v4l2_rect *r = &dev->try_clips_cap[i].c; @@ -1166,9 +1163,8 @@ int vidioc_try_fmt_vid_overlay(struct file *file, void *priv, return -EINVAL; } } - if (copy_to_user(win->clips, dev->try_clips_cap, - win->clipcount * sizeof(dev->clips_cap[0]))) - return -EFAULT; + memcpy(win->clips, dev->try_clips_cap, + win->clipcount * sizeof(dev->clips_cap[0])); } return 0; } diff --git a/drivers/media/test-drivers/vivid/vivid-vid-out.c b/drivers/media/test-drivers/vivid/vivid-vid-out.c index ee3446e3217c..ac1e981e8342 100644 --- a/drivers/media/test-drivers/vivid/vivid-vid-out.c +++ b/drivers/media/test-drivers/vivid/vivid-vid-out.c @@ -857,11 +857,9 @@ int vidioc_g_fmt_vid_out_overlay(struct file *file, void *priv, ((dev->compose_out.width + 7) / 8) * dev->compose_out.height)) return -EFAULT; } - if (clipcount && win->clips) { - if (copy_to_user(win->clips, dev->clips_out, - clipcount * sizeof(dev->clips_out[0]))) - return -EFAULT; - } + if (clipcount && win->clips) + memcpy(win->clips, dev->clips_out, + clipcount * sizeof(dev->clips_out[0])); return 0; } @@ -891,9 +889,8 @@ int vidioc_try_fmt_vid_out_overlay(struct file *file, void *priv, if (win->clipcount > MAX_CLIPS) win->clipcount = MAX_CLIPS; if (win->clipcount) { - if (copy_from_user(dev->try_clips_out, win->clips, - win->clipcount * sizeof(dev->clips_out[0]))) - return -EFAULT; + memcpy(dev->try_clips_out, win->clips, + win->clipcount * sizeof(dev->clips_out[0])); for (i = 0; i < win->clipcount; i++) { struct v4l2_rect *r = &dev->try_clips_out[i].c; @@ -916,9 +913,8 @@ int vidioc_try_fmt_vid_out_overlay(struct file *file, void *priv, return -EINVAL; } } - if (copy_to_user(win->clips, dev->try_clips_out, - win->clipcount * sizeof(dev->clips_out[0]))) - return -EFAULT; + memcpy(win->clips, dev->try_clips_out, + win->clipcount * sizeof(dev->clips_out[0])); } return 0; } diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index b8be61a09776..f0f6906a879d 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1582,7 +1582,7 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops, switch (p->type) { case V4L2_BUF_TYPE_VIDEO_OVERLAY: case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: { - struct v4l2_clip __user *clips = p->fmt.win.clips; + struct v4l2_clip *clips = p->fmt.win.clips; u32 clipcount = p->fmt.win.clipcount; void __user *bitmap = p->fmt.win.bitmap; @@ -3084,6 +3084,27 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, } break; } + case VIDIOC_G_FMT: + case VIDIOC_S_FMT: + case VIDIOC_TRY_FMT: { + struct v4l2_format *fmt = parg; + + if (fmt->type != V4L2_BUF_TYPE_VIDEO_OVERLAY && + fmt->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY) + break; + if (fmt->fmt.win.clipcount > 2048) + return -EINVAL; + if (!fmt->fmt.win.clipcount) + break; + + *user_ptr = (void __user *)fmt->fmt.win.clips; + *kernel_ptr = (void **)&fmt->fmt.win.clips; + *array_size = sizeof(struct v4l2_clip) + * fmt->fmt.win.clipcount; + + ret = 1; + break; + } } return ret; diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 534eaa4d39bc..b10f102bbf6f 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1185,7 +1185,7 @@ struct v4l2_window { struct v4l2_rect w; __u32 field; /* enum v4l2_field */ __u32 chromakey; - struct v4l2_clip __user *clips; + struct v4l2_clip *clips; __u32 clipcount; void __user *bitmap; __u8 global_alpha; -- cgit v1.2.3 From 566f960d3c5e1f63482298b60a80de4d3cd75d68 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 30 Oct 2020 17:55:27 +0100 Subject: media: v4l2: convert v4l2_format compat ioctls Now that the 'clips' array is accessed by common code in the native ioctl handler, the same can be done for the compat version, greatly simplifying the compat code for these four ioctl commands. [hverkuil: fix: CHECK: Alignment should match open parenthesis] Signed-off-by: Arnd Bergmann Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 346 +++++++++++--------------- 1 file changed, 139 insertions(+), 207 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index d154179fb6d2..fe681aa7c109 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -150,77 +150,54 @@ struct v4l2_window32 { __u8 global_alpha; }; -static int get_v4l2_window32(struct v4l2_window __user *p64, - struct v4l2_window32 __user *p32, - void __user *aux_buf, u32 aux_space) +static int get_v4l2_window32(struct v4l2_window *p64, + struct v4l2_window32 __user *p32) { - struct v4l2_clip32 __user *uclips; - struct v4l2_clip __user *kclips; - compat_caddr_t p; - u32 clipcount; + struct v4l2_window32 w32; - if (!access_ok(p32, sizeof(*p32)) || - copy_in_user(&p64->w, &p32->w, sizeof(p32->w)) || - assign_in_user(&p64->field, &p32->field) || - assign_in_user(&p64->chromakey, &p32->chromakey) || - assign_in_user(&p64->global_alpha, &p32->global_alpha) || - get_user(clipcount, &p32->clipcount) || - put_user(clipcount, &p64->clipcount)) + if (copy_from_user(&w32, p32, sizeof(w32))) return -EFAULT; - if (clipcount > 2048) - return -EINVAL; - if (!clipcount) - return put_user(NULL, &p64->clips); - if (get_user(p, &p32->clips)) - return -EFAULT; - uclips = compat_ptr(p); - if (aux_space < clipcount * sizeof(*kclips)) - return -EFAULT; - kclips = aux_buf; - if (put_user(kclips, &p64->clips)) - return -EFAULT; + *p64 = (struct v4l2_window) { + .w = w32.w, + .field = w32.field, + .chromakey = w32.chromakey, + .clips = (void __force *)compat_ptr(w32.clips), + .clipcount = w32.clipcount, + .bitmap = compat_ptr(w32.bitmap), + .global_alpha = w32.global_alpha, + }; + + if (p64->clipcount > 2048) + return -EINVAL; + if (!p64->clipcount) + p64->clips = NULL; - while (clipcount--) { - if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c))) - return -EFAULT; - if (put_user(clipcount ? kclips + 1 : NULL, &kclips->next)) - return -EFAULT; - uclips++; - kclips++; - } return 0; } -static int put_v4l2_window32(struct v4l2_window __user *p64, +static int put_v4l2_window32(struct v4l2_window *p64, struct v4l2_window32 __user *p32) { - struct v4l2_clip __user *kclips; - struct v4l2_clip32 __user *uclips; - compat_caddr_t p; - u32 clipcount; - - if (copy_in_user(&p32->w, &p64->w, sizeof(p64->w)) || - assign_in_user(&p32->field, &p64->field) || - assign_in_user(&p32->chromakey, &p64->chromakey) || - assign_in_user(&p32->global_alpha, &p64->global_alpha) || - get_user(clipcount, &p64->clipcount) || - put_user(clipcount, &p32->clipcount)) - return -EFAULT; - if (!clipcount) - return 0; + struct v4l2_window32 w32; + + memset(&w32, 0, sizeof(w32)); + w32 = (struct v4l2_window32) { + .w = p64->w, + .field = p64->field, + .chromakey = p64->chromakey, + .clips = (uintptr_t)p64->clips, + .clipcount = p64->clipcount, + .bitmap = ptr_to_compat(p64->bitmap), + .global_alpha = p64->global_alpha, + }; - if (get_user(kclips, &p64->clips)) - return -EFAULT; - if (get_user(p, &p32->clips)) + /* copy everything except the clips pointer */ + if (copy_to_user(p32, &w32, offsetof(struct v4l2_window32, clips)) || + copy_to_user(&p32->clipcount, &w32.clipcount, + sizeof(w32) - offsetof(struct v4l2_window32, clipcount))) return -EFAULT; - uclips = compat_ptr(p); - while (clipcount--) { - if (copy_in_user(&uclips->c, &kclips->c, sizeof(uclips->c))) - return -EFAULT; - uclips++; - kclips++; - } + return 0; } @@ -257,169 +234,99 @@ struct v4l2_create_buffers32 { __u32 reserved[7]; }; -static int __bufsize_v4l2_format(struct v4l2_format32 __user *p32, u32 *size) -{ - u32 type; - - if (get_user(type, &p32->type)) - return -EFAULT; - - switch (type) { - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: { - u32 clipcount; - - if (get_user(clipcount, &p32->fmt.win.clipcount)) - return -EFAULT; - if (clipcount > 2048) - return -EINVAL; - *size = clipcount * sizeof(struct v4l2_clip); - return 0; - } - default: - *size = 0; - return 0; - } -} - -static int bufsize_v4l2_format(struct v4l2_format32 __user *p32, u32 *size) -{ - if (!access_ok(p32, sizeof(*p32))) - return -EFAULT; - return __bufsize_v4l2_format(p32, size); -} - -static int __get_v4l2_format32(struct v4l2_format __user *p64, - struct v4l2_format32 __user *p32, - void __user *aux_buf, u32 aux_space) +static int get_v4l2_format32(struct v4l2_format *p64, + struct v4l2_format32 __user *p32) { - u32 type; - - if (get_user(type, &p32->type) || put_user(type, &p64->type)) + if (get_user(p64->type, &p32->type)) return -EFAULT; - switch (type) { + switch (p64->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return copy_in_user(&p64->fmt.pix, &p32->fmt.pix, - sizeof(p64->fmt.pix)) ? -EFAULT : 0; + return copy_from_user(&p64->fmt.pix, &p32->fmt.pix, + sizeof(p64->fmt.pix)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return copy_in_user(&p64->fmt.pix_mp, &p32->fmt.pix_mp, - sizeof(p64->fmt.pix_mp)) ? -EFAULT : 0; + return copy_from_user(&p64->fmt.pix_mp, &p32->fmt.pix_mp, + sizeof(p64->fmt.pix_mp)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_OVERLAY: case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - return get_v4l2_window32(&p64->fmt.win, &p32->fmt.win, - aux_buf, aux_space); + return get_v4l2_window32(&p64->fmt.win, &p32->fmt.win); case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: - return copy_in_user(&p64->fmt.vbi, &p32->fmt.vbi, - sizeof(p64->fmt.vbi)) ? -EFAULT : 0; + return copy_from_user(&p64->fmt.vbi, &p32->fmt.vbi, + sizeof(p64->fmt.vbi)) ? -EFAULT : 0; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - return copy_in_user(&p64->fmt.sliced, &p32->fmt.sliced, - sizeof(p64->fmt.sliced)) ? -EFAULT : 0; + return copy_from_user(&p64->fmt.sliced, &p32->fmt.sliced, + sizeof(p64->fmt.sliced)) ? -EFAULT : 0; case V4L2_BUF_TYPE_SDR_CAPTURE: case V4L2_BUF_TYPE_SDR_OUTPUT: - return copy_in_user(&p64->fmt.sdr, &p32->fmt.sdr, - sizeof(p64->fmt.sdr)) ? -EFAULT : 0; + return copy_from_user(&p64->fmt.sdr, &p32->fmt.sdr, + sizeof(p64->fmt.sdr)) ? -EFAULT : 0; case V4L2_BUF_TYPE_META_CAPTURE: case V4L2_BUF_TYPE_META_OUTPUT: - return copy_in_user(&p64->fmt.meta, &p32->fmt.meta, - sizeof(p64->fmt.meta)) ? -EFAULT : 0; + return copy_from_user(&p64->fmt.meta, &p32->fmt.meta, + sizeof(p64->fmt.meta)) ? -EFAULT : 0; default: return -EINVAL; } } -static int get_v4l2_format32(struct v4l2_format __user *p64, - struct v4l2_format32 __user *p32, - void __user *aux_buf, u32 aux_space) -{ - if (!access_ok(p32, sizeof(*p32))) - return -EFAULT; - return __get_v4l2_format32(p64, p32, aux_buf, aux_space); -} - -static int bufsize_v4l2_create(struct v4l2_create_buffers32 __user *p32, - u32 *size) -{ - if (!access_ok(p32, sizeof(*p32))) - return -EFAULT; - return __bufsize_v4l2_format(&p32->format, size); -} - -static int get_v4l2_create32(struct v4l2_create_buffers __user *p64, - struct v4l2_create_buffers32 __user *p32, - void __user *aux_buf, u32 aux_space) +static int get_v4l2_create32(struct v4l2_create_buffers *p64, + struct v4l2_create_buffers32 __user *p32) { - if (!access_ok(p32, sizeof(*p32)) || - copy_in_user(p64, p32, - offsetof(struct v4l2_create_buffers32, format))) + if (copy_from_user(p64, p32, + offsetof(struct v4l2_create_buffers32, format))) return -EFAULT; - return __get_v4l2_format32(&p64->format, &p32->format, - aux_buf, aux_space); + return get_v4l2_format32(&p64->format, &p32->format); } -static int __put_v4l2_format32(struct v4l2_format __user *p64, - struct v4l2_format32 __user *p32) +static int put_v4l2_format32(struct v4l2_format *p64, + struct v4l2_format32 __user *p32) { - u32 type; - - if (get_user(type, &p64->type)) - return -EFAULT; - - switch (type) { + switch (p64->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return copy_in_user(&p32->fmt.pix, &p64->fmt.pix, + return copy_to_user(&p32->fmt.pix, &p64->fmt.pix, sizeof(p64->fmt.pix)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return copy_in_user(&p32->fmt.pix_mp, &p64->fmt.pix_mp, + return copy_to_user(&p32->fmt.pix_mp, &p64->fmt.pix_mp, sizeof(p64->fmt.pix_mp)) ? -EFAULT : 0; case V4L2_BUF_TYPE_VIDEO_OVERLAY: case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: return put_v4l2_window32(&p64->fmt.win, &p32->fmt.win); case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: - return copy_in_user(&p32->fmt.vbi, &p64->fmt.vbi, + return copy_to_user(&p32->fmt.vbi, &p64->fmt.vbi, sizeof(p64->fmt.vbi)) ? -EFAULT : 0; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - return copy_in_user(&p32->fmt.sliced, &p64->fmt.sliced, + return copy_to_user(&p32->fmt.sliced, &p64->fmt.sliced, sizeof(p64->fmt.sliced)) ? -EFAULT : 0; case V4L2_BUF_TYPE_SDR_CAPTURE: case V4L2_BUF_TYPE_SDR_OUTPUT: - return copy_in_user(&p32->fmt.sdr, &p64->fmt.sdr, + return copy_to_user(&p32->fmt.sdr, &p64->fmt.sdr, sizeof(p64->fmt.sdr)) ? -EFAULT : 0; case V4L2_BUF_TYPE_META_CAPTURE: case V4L2_BUF_TYPE_META_OUTPUT: - return copy_in_user(&p32->fmt.meta, &p64->fmt.meta, + return copy_to_user(&p32->fmt.meta, &p64->fmt.meta, sizeof(p64->fmt.meta)) ? -EFAULT : 0; default: return -EINVAL; } } -static int put_v4l2_format32(struct v4l2_format __user *p64, - struct v4l2_format32 __user *p32) -{ - if (!access_ok(p32, sizeof(*p32))) - return -EFAULT; - return __put_v4l2_format32(p64, p32); -} - -static int put_v4l2_create32(struct v4l2_create_buffers __user *p64, +static int put_v4l2_create32(struct v4l2_create_buffers *p64, struct v4l2_create_buffers32 __user *p32) { - if (!access_ok(p32, sizeof(*p32)) || - copy_in_user(p32, p64, + if (copy_to_user(p32, p64, offsetof(struct v4l2_create_buffers32, format)) || - assign_in_user(&p32->capabilities, &p64->capabilities) || - copy_in_user(p32->reserved, p64->reserved, sizeof(p64->reserved))) + put_user(p64->capabilities, &p32->capabilities) || + copy_to_user(p32->reserved, p64->reserved, sizeof(p64->reserved))) return -EFAULT; - return __put_v4l2_format32(&p64->format, &p32->format); + return put_v4l2_format32(&p64->format, &p32->format); } struct v4l2_standard32 { @@ -1081,6 +988,12 @@ static int put_v4l2_edid32(struct v4l2_edid __user *p64, unsigned int v4l2_compat_translate_cmd(unsigned int cmd) { switch (cmd) { + case VIDIOC_G_FMT32: + return VIDIOC_G_FMT; + case VIDIOC_S_FMT32: + return VIDIOC_S_FMT; + case VIDIOC_TRY_FMT32: + return VIDIOC_TRY_FMT; #ifdef CONFIG_COMPAT_32BIT_TIME case VIDIOC_QUERYBUF32_TIME32: return VIDIOC_QUERYBUF; @@ -1097,6 +1010,8 @@ unsigned int v4l2_compat_translate_cmd(unsigned int cmd) return VIDIOC_QBUF; case VIDIOC_DQBUF32: return VIDIOC_DQBUF; + case VIDIOC_CREATE_BUFS32: + return VIDIOC_CREATE_BUFS; case VIDIOC_G_EXT_CTRLS32: return VIDIOC_G_EXT_CTRLS; case VIDIOC_S_EXT_CTRLS32: @@ -1112,6 +1027,10 @@ unsigned int v4l2_compat_translate_cmd(unsigned int cmd) int v4l2_compat_get_user(void __user *arg, void *parg, unsigned int cmd) { switch (cmd) { + case VIDIOC_G_FMT32: + case VIDIOC_S_FMT32: + case VIDIOC_TRY_FMT32: + return get_v4l2_format32(parg, arg); #ifdef CONFIG_COMPAT_32BIT_TIME case VIDIOC_QUERYBUF32_TIME32: case VIDIOC_QBUF32_TIME32: @@ -1129,6 +1048,9 @@ int v4l2_compat_get_user(void __user *arg, void *parg, unsigned int cmd) case VIDIOC_S_EXT_CTRLS32: case VIDIOC_TRY_EXT_CTRLS32: return get_v4l2_ext_controls32(parg, arg); + + case VIDIOC_CREATE_BUFS32: + return get_v4l2_create32(parg, arg); } return 0; } @@ -1136,6 +1058,10 @@ int v4l2_compat_get_user(void __user *arg, void *parg, unsigned int cmd) int v4l2_compat_put_user(void __user *arg, void *parg, unsigned int cmd) { switch (cmd) { + case VIDIOC_G_FMT32: + case VIDIOC_S_FMT32: + case VIDIOC_TRY_FMT32: + return put_v4l2_format32(parg, arg); #ifdef CONFIG_COMPAT_32BIT_TIME case VIDIOC_QUERYBUF32_TIME32: case VIDIOC_QBUF32_TIME32: @@ -1153,6 +1079,9 @@ int v4l2_compat_put_user(void __user *arg, void *parg, unsigned int cmd) case VIDIOC_S_EXT_CTRLS32: case VIDIOC_TRY_EXT_CTRLS32: return put_v4l2_ext_controls32(parg, arg); + + case VIDIOC_CREATE_BUFS32: + return put_v4l2_create32(parg, arg); } return 0; } @@ -1164,6 +1093,29 @@ int v4l2_compat_get_array_args(struct file *file, void *mbuf, int err = 0; switch (cmd) { + case VIDIOC_G_FMT32: + case VIDIOC_S_FMT32: + case VIDIOC_TRY_FMT32: { + struct v4l2_format *f64 = arg; + struct v4l2_clip *c64 = mbuf; + struct v4l2_clip32 __user *c32 = user_ptr; + u32 clipcount = f64->fmt.win.clipcount; + + if ((f64->type != V4L2_BUF_TYPE_VIDEO_OVERLAY && + f64->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY) || + clipcount == 0) + return 0; + if (clipcount > 2048) + return -EINVAL; + while (clipcount--) { + if (copy_from_user(c64, c32, sizeof(c64->c))) + return -EFAULT; + c64->next = NULL; + c64++; + c32++; + } + break; + } case VIDIOC_QUERYBUF32_TIME32: case VIDIOC_QBUF32_TIME32: case VIDIOC_DQBUF32_TIME32: @@ -1232,6 +1184,28 @@ int v4l2_compat_put_array_args(struct file *file, void __user *user_ptr, int err = 0; switch (cmd) { + case VIDIOC_G_FMT32: + case VIDIOC_S_FMT32: + case VIDIOC_TRY_FMT32: { + struct v4l2_format *f64 = arg; + struct v4l2_clip *c64 = mbuf; + struct v4l2_clip32 __user *c32 = user_ptr; + u32 clipcount = f64->fmt.win.clipcount; + + if ((f64->type != V4L2_BUF_TYPE_VIDEO_OVERLAY && + f64->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY) || + clipcount == 0) + return 0; + if (clipcount > 2048) + return -EINVAL; + while (clipcount--) { + if (copy_to_user(c32, c64, sizeof(c64->c))) + return -EFAULT; + c64++; + c32++; + } + break; + } case VIDIOC_QUERYBUF32_TIME32: case VIDIOC_QBUF32_TIME32: case VIDIOC_DQBUF32_TIME32: @@ -1353,18 +1327,14 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar * 1. When struct size is different, converts the command. */ switch (cmd) { - case VIDIOC_G_FMT32: ncmd = VIDIOC_G_FMT; break; - case VIDIOC_S_FMT32: ncmd = VIDIOC_S_FMT; break; case VIDIOC_G_FBUF32: ncmd = VIDIOC_G_FBUF; break; case VIDIOC_S_FBUF32: ncmd = VIDIOC_S_FBUF; break; case VIDIOC_ENUMSTD32: ncmd = VIDIOC_ENUMSTD; break; case VIDIOC_ENUMINPUT32: ncmd = VIDIOC_ENUMINPUT; break; - case VIDIOC_TRY_FMT32: ncmd = VIDIOC_TRY_FMT; break; #ifdef CONFIG_X86_64 case VIDIOC_DQEVENT32: ncmd = VIDIOC_DQEVENT; break; case VIDIOC_DQEVENT32_TIME32: ncmd = VIDIOC_DQEVENT_TIME32; break; #endif - case VIDIOC_CREATE_BUFS32: ncmd = VIDIOC_CREATE_BUFS; break; case VIDIOC_G_EDID32: ncmd = VIDIOC_G_EDID; break; case VIDIOC_S_EDID32: ncmd = VIDIOC_S_EDID; break; default: ncmd = cmd; break; @@ -1384,34 +1354,6 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar compatible_arg = 0; break; - case VIDIOC_G_FMT32: - case VIDIOC_S_FMT32: - case VIDIOC_TRY_FMT32: - err = bufsize_v4l2_format(p32, &aux_space); - if (!err) - err = alloc_userspace(sizeof(struct v4l2_format), - aux_space, &new_p64); - if (!err) { - aux_buf = new_p64 + sizeof(struct v4l2_format); - err = get_v4l2_format32(new_p64, p32, - aux_buf, aux_space); - } - compatible_arg = 0; - break; - - case VIDIOC_CREATE_BUFS32: - err = bufsize_v4l2_create(p32, &aux_space); - if (!err) - err = alloc_userspace(sizeof(struct v4l2_create_buffers), - aux_space, &new_p64); - if (!err) { - aux_buf = new_p64 + sizeof(struct v4l2_create_buffers); - err = get_v4l2_create32(new_p64, p32, - aux_buf, aux_space); - } - compatible_arg = 0; - break; - case VIDIOC_S_FBUF32: err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0, &new_p64); @@ -1514,16 +1456,6 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar err = put_v4l2_edid32(new_p64, p32); break; - case VIDIOC_G_FMT32: - case VIDIOC_S_FMT32: - case VIDIOC_TRY_FMT32: - err = put_v4l2_format32(new_p64, p32); - break; - - case VIDIOC_CREATE_BUFS32: - err = put_v4l2_create32(new_p64, p32); - break; - case VIDIOC_ENUMSTD32: err = put_v4l2_standard32(new_p64, p32); break; -- cgit v1.2.3 From 50085270a162d628dc60ecbc8cab9f33618555dc Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 30 Oct 2020 17:55:28 +0100 Subject: media: v4l2: remaining compat handlers There are eight remaining ioctl commands handled by copying incompatible data structures in v4l2_compat_ioctl32(), all of them fairly simple. Change them to instead go through the native ioctl infrastructure and only special-case the data copy. Signed-off-by: Arnd Bergmann Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 283 ++++++++++---------------- 1 file changed, 109 insertions(+), 174 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index fe681aa7c109..b51fa680b4cf 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -338,27 +338,23 @@ struct v4l2_standard32 { __u32 reserved[4]; }; -static int get_v4l2_standard32(struct v4l2_standard __user *p64, +static int get_v4l2_standard32(struct v4l2_standard *p64, struct v4l2_standard32 __user *p32) { /* other fields are not set by the user, nor used by the driver */ - if (!access_ok(p32, sizeof(*p32)) || - assign_in_user(&p64->index, &p32->index)) - return -EFAULT; - return 0; + return get_user(p64->index, &p32->index); } -static int put_v4l2_standard32(struct v4l2_standard __user *p64, +static int put_v4l2_standard32(struct v4l2_standard *p64, struct v4l2_standard32 __user *p32) { - if (!access_ok(p32, sizeof(*p32)) || - assign_in_user(&p32->index, &p64->index) || - assign_in_user(&p32->id, &p64->id) || - copy_in_user(p32->name, p64->name, sizeof(p32->name)) || - copy_in_user(&p32->frameperiod, &p64->frameperiod, + if (put_user(p64->index, &p32->index) || + put_user(p64->id, &p32->id) || + copy_to_user(p32->name, p64->name, sizeof(p32->name)) || + copy_to_user(&p32->frameperiod, &p64->frameperiod, sizeof(p32->frameperiod)) || - assign_in_user(&p32->framelines, &p64->framelines) || - copy_in_user(p32->reserved, p64->reserved, sizeof(p32->reserved))) + put_user(p64->framelines, &p32->framelines) || + copy_to_user(p32->reserved, p64->reserved, sizeof(p32->reserved))) return -EFAULT; return 0; } @@ -689,33 +685,30 @@ struct v4l2_framebuffer32 { } fmt; }; -static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *p64, +static int get_v4l2_framebuffer32(struct v4l2_framebuffer *p64, struct v4l2_framebuffer32 __user *p32) { compat_caddr_t tmp; - if (!access_ok(p32, sizeof(*p32)) || - get_user(tmp, &p32->base) || - put_user_force(compat_ptr(tmp), &p64->base) || - assign_in_user(&p64->capability, &p32->capability) || - assign_in_user(&p64->flags, &p32->flags) || - copy_in_user(&p64->fmt, &p32->fmt, sizeof(p64->fmt))) + if (get_user(tmp, &p32->base) || + get_user(p64->capability, &p32->capability) || + get_user(p64->flags, &p32->flags) || + copy_from_user(&p64->fmt, &p32->fmt, sizeof(p64->fmt))) return -EFAULT; + p64->base = (void __force *)compat_ptr(tmp); + return 0; } -static int put_v4l2_framebuffer32(struct v4l2_framebuffer __user *p64, +static int put_v4l2_framebuffer32(struct v4l2_framebuffer *p64, struct v4l2_framebuffer32 __user *p32) { - void *base; - - if (!access_ok(p32, sizeof(*p32)) || - get_user(base, &p64->base) || - put_user(ptr_to_compat((void __user *)base), &p32->base) || - assign_in_user(&p32->capability, &p64->capability) || - assign_in_user(&p32->flags, &p64->flags) || - copy_in_user(&p32->fmt, &p64->fmt, sizeof(p64->fmt))) + if (put_user((uintptr_t)p64->base, &p32->base) || + put_user(p64->capability, &p32->capability) || + put_user(p64->flags, &p32->flags) || + copy_to_user(&p32->fmt, &p64->fmt, sizeof(p64->fmt))) return -EFAULT; + return 0; } @@ -735,18 +728,18 @@ struct v4l2_input32 { * The 64-bit v4l2_input struct has extra padding at the end of the struct. * Otherwise it is identical to the 32-bit version. */ -static inline int get_v4l2_input32(struct v4l2_input __user *p64, +static inline int get_v4l2_input32(struct v4l2_input *p64, struct v4l2_input32 __user *p32) { - if (copy_in_user(p64, p32, sizeof(*p32))) + if (copy_from_user(p64, p32, sizeof(*p32))) return -EFAULT; return 0; } -static inline int put_v4l2_input32(struct v4l2_input __user *p64, +static inline int put_v4l2_input32(struct v4l2_input *p64, struct v4l2_input32 __user *p32) { - if (copy_in_user(p32, p64, sizeof(*p32))) + if (copy_to_user(p32, p64, sizeof(*p32))) return -EFAULT; return 0; } @@ -880,38 +873,38 @@ struct v4l2_event32_time32 { __u32 reserved[8]; }; -static int put_v4l2_event32(struct v4l2_event __user *p64, +static int put_v4l2_event32(struct v4l2_event *p64, struct v4l2_event32 __user *p32) { - if (!access_ok(p32, sizeof(*p32)) || - assign_in_user(&p32->type, &p64->type) || - copy_in_user(&p32->u, &p64->u, sizeof(p64->u)) || - assign_in_user(&p32->pending, &p64->pending) || - assign_in_user(&p32->sequence, &p64->sequence) || - assign_in_user(&p32->timestamp.tv_sec, &p64->timestamp.tv_sec) || - assign_in_user(&p32->timestamp.tv_nsec, &p64->timestamp.tv_nsec) || - assign_in_user(&p32->id, &p64->id) || - copy_in_user(p32->reserved, p64->reserved, sizeof(p32->reserved))) + if (put_user(p64->type, &p32->type) || + copy_to_user(&p32->u, &p64->u, sizeof(p64->u)) || + put_user(p64->pending, &p32->pending) || + put_user(p64->sequence, &p32->sequence) || + put_user(p64->timestamp.tv_sec, &p32->timestamp.tv_sec) || + put_user(p64->timestamp.tv_nsec, &p32->timestamp.tv_nsec) || + put_user(p64->id, &p32->id) || + copy_to_user(p32->reserved, p64->reserved, sizeof(p32->reserved))) return -EFAULT; return 0; } -static int put_v4l2_event32_time32(struct v4l2_event_time32 __user *p64, +#ifdef CONFIG_COMPAT_32BIT_TIME +static int put_v4l2_event32_time32(struct v4l2_event *p64, struct v4l2_event32_time32 __user *p32) { - if (!access_ok(p32, sizeof(*p32)) || - assign_in_user(&p32->type, &p64->type) || - copy_in_user(&p32->u, &p64->u, sizeof(p64->u)) || - assign_in_user(&p32->pending, &p64->pending) || - assign_in_user(&p32->sequence, &p64->sequence) || - assign_in_user(&p32->timestamp.tv_sec, &p64->timestamp.tv_sec) || - assign_in_user(&p32->timestamp.tv_nsec, &p64->timestamp.tv_nsec) || - assign_in_user(&p32->id, &p64->id) || - copy_in_user(p32->reserved, p64->reserved, sizeof(p32->reserved))) + if (put_user(p64->type, &p32->type) || + copy_to_user(&p32->u, &p64->u, sizeof(p64->u)) || + put_user(p64->pending, &p32->pending) || + put_user(p64->sequence, &p32->sequence) || + put_user(p64->timestamp.tv_sec, &p32->timestamp.tv_sec) || + put_user(p64->timestamp.tv_nsec, &p32->timestamp.tv_nsec) || + put_user(p64->id, &p32->id) || + copy_to_user(p32->reserved, p64->reserved, sizeof(p32->reserved))) return -EFAULT; return 0; } #endif +#endif struct v4l2_edid32 { __u32 pad; @@ -921,34 +914,23 @@ struct v4l2_edid32 { compat_caddr_t edid; }; -static int get_v4l2_edid32(struct v4l2_edid __user *p64, +static int get_v4l2_edid32(struct v4l2_edid *p64, struct v4l2_edid32 __user *p32) { - compat_uptr_t tmp; - - if (!access_ok(p32, sizeof(*p32)) || - assign_in_user(&p64->pad, &p32->pad) || - assign_in_user(&p64->start_block, &p32->start_block) || - assign_in_user_cast(&p64->blocks, &p32->blocks) || - get_user(tmp, &p32->edid) || - put_user_force(compat_ptr(tmp), &p64->edid) || - copy_in_user(p64->reserved, p32->reserved, sizeof(p64->reserved))) + compat_uptr_t edid; + + if (copy_from_user(p64, p32, offsetof(struct v4l2_edid32, edid)) || + get_user(edid, &p32->edid)) return -EFAULT; + + p64->edid = (void __force *)compat_ptr(edid); return 0; } -static int put_v4l2_edid32(struct v4l2_edid __user *p64, +static int put_v4l2_edid32(struct v4l2_edid *p64, struct v4l2_edid32 __user *p32) { - void *edid; - - if (!access_ok(p32, sizeof(*p32)) || - assign_in_user(&p32->pad, &p64->pad) || - assign_in_user(&p32->start_block, &p64->start_block) || - assign_in_user(&p32->blocks, &p64->blocks) || - get_user(edid, &p64->edid) || - put_user(ptr_to_compat((void __user *)edid), &p32->edid) || - copy_in_user(p32->reserved, p64->reserved, sizeof(p32->reserved))) + if (copy_to_user(p32, p64, offsetof(struct v4l2_edid32, edid))) return -EFAULT; return 0; } @@ -994,6 +976,10 @@ unsigned int v4l2_compat_translate_cmd(unsigned int cmd) return VIDIOC_S_FMT; case VIDIOC_TRY_FMT32: return VIDIOC_TRY_FMT; + case VIDIOC_G_FBUF32: + return VIDIOC_G_FBUF; + case VIDIOC_S_FBUF32: + return VIDIOC_S_FBUF; #ifdef CONFIG_COMPAT_32BIT_TIME case VIDIOC_QUERYBUF32_TIME32: return VIDIOC_QUERYBUF; @@ -1020,6 +1006,22 @@ unsigned int v4l2_compat_translate_cmd(unsigned int cmd) return VIDIOC_TRY_EXT_CTRLS; case VIDIOC_PREPARE_BUF32: return VIDIOC_PREPARE_BUF; + case VIDIOC_ENUMSTD32: + return VIDIOC_ENUMSTD; + case VIDIOC_ENUMINPUT32: + return VIDIOC_ENUMINPUT; + case VIDIOC_G_EDID32: + return VIDIOC_G_EDID; + case VIDIOC_S_EDID32: + return VIDIOC_S_EDID; +#ifdef CONFIG_X86_64 + case VIDIOC_DQEVENT32: + return VIDIOC_DQEVENT; +#ifdef CONFIG_COMPAT_32BIT_TIME + case VIDIOC_DQEVENT32_TIME32: + return VIDIOC_DQEVENT; +#endif +#endif } return cmd; } @@ -1031,6 +1033,9 @@ int v4l2_compat_get_user(void __user *arg, void *parg, unsigned int cmd) case VIDIOC_S_FMT32: case VIDIOC_TRY_FMT32: return get_v4l2_format32(parg, arg); + + case VIDIOC_S_FBUF32: + return get_v4l2_framebuffer32(parg, arg); #ifdef CONFIG_COMPAT_32BIT_TIME case VIDIOC_QUERYBUF32_TIME32: case VIDIOC_QBUF32_TIME32: @@ -1051,6 +1056,16 @@ int v4l2_compat_get_user(void __user *arg, void *parg, unsigned int cmd) case VIDIOC_CREATE_BUFS32: return get_v4l2_create32(parg, arg); + + case VIDIOC_ENUMSTD32: + return get_v4l2_standard32(parg, arg); + + case VIDIOC_ENUMINPUT32: + return get_v4l2_input32(parg, arg); + + case VIDIOC_G_EDID32: + case VIDIOC_S_EDID32: + return get_v4l2_edid32(parg, arg); } return 0; } @@ -1062,6 +1077,9 @@ int v4l2_compat_put_user(void __user *arg, void *parg, unsigned int cmd) case VIDIOC_S_FMT32: case VIDIOC_TRY_FMT32: return put_v4l2_format32(parg, arg); + + case VIDIOC_G_FBUF32: + return put_v4l2_framebuffer32(parg, arg); #ifdef CONFIG_COMPAT_32BIT_TIME case VIDIOC_QUERYBUF32_TIME32: case VIDIOC_QBUF32_TIME32: @@ -1082,6 +1100,24 @@ int v4l2_compat_put_user(void __user *arg, void *parg, unsigned int cmd) case VIDIOC_CREATE_BUFS32: return put_v4l2_create32(parg, arg); + + case VIDIOC_ENUMSTD32: + return put_v4l2_standard32(parg, arg); + + case VIDIOC_ENUMINPUT32: + return put_v4l2_input32(parg, arg); + + case VIDIOC_G_EDID32: + case VIDIOC_S_EDID32: + return put_v4l2_edid32(parg, arg); +#ifdef CONFIG_X86_64 + case VIDIOC_DQEVENT32: + return put_v4l2_event32(parg, arg); +#ifdef CONFIG_COMPAT_32BIT_TIME + case VIDIOC_DQEVENT32_TIME32: + return put_v4l2_event32_time32(parg, arg); +#endif +#endif } return 0; } @@ -1327,16 +1363,6 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar * 1. When struct size is different, converts the command. */ switch (cmd) { - case VIDIOC_G_FBUF32: ncmd = VIDIOC_G_FBUF; break; - case VIDIOC_S_FBUF32: ncmd = VIDIOC_S_FBUF; break; - case VIDIOC_ENUMSTD32: ncmd = VIDIOC_ENUMSTD; break; - case VIDIOC_ENUMINPUT32: ncmd = VIDIOC_ENUMINPUT; break; -#ifdef CONFIG_X86_64 - case VIDIOC_DQEVENT32: ncmd = VIDIOC_DQEVENT; break; - case VIDIOC_DQEVENT32_TIME32: ncmd = VIDIOC_DQEVENT_TIME32; break; -#endif - case VIDIOC_G_EDID32: ncmd = VIDIOC_G_EDID; break; - case VIDIOC_S_EDID32: ncmd = VIDIOC_S_EDID; break; default: ncmd = cmd; break; } @@ -1346,53 +1372,6 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar * argument into it. */ switch (cmd) { - case VIDIOC_G_EDID32: - case VIDIOC_S_EDID32: - err = alloc_userspace(sizeof(struct v4l2_edid), 0, &new_p64); - if (!err) - err = get_v4l2_edid32(new_p64, p32); - compatible_arg = 0; - break; - - case VIDIOC_S_FBUF32: - err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0, - &new_p64); - if (!err) - err = get_v4l2_framebuffer32(new_p64, p32); - compatible_arg = 0; - break; - - case VIDIOC_G_FBUF32: - err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0, - &new_p64); - compatible_arg = 0; - break; - - case VIDIOC_ENUMSTD32: - err = alloc_userspace(sizeof(struct v4l2_standard), 0, - &new_p64); - if (!err) - err = get_v4l2_standard32(new_p64, p32); - compatible_arg = 0; - break; - - case VIDIOC_ENUMINPUT32: - err = alloc_userspace(sizeof(struct v4l2_input), 0, &new_p64); - if (!err) - err = get_v4l2_input32(new_p64, p32); - compatible_arg = 0; - break; - -#ifdef CONFIG_X86_64 - case VIDIOC_DQEVENT32: - err = alloc_userspace(sizeof(struct v4l2_event), 0, &new_p64); - compatible_arg = 0; - break; - case VIDIOC_DQEVENT32_TIME32: - err = alloc_userspace(sizeof(struct v4l2_event_time32), 0, &new_p64); - compatible_arg = 0; - break; -#endif } if (err) return err; @@ -1414,55 +1393,11 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar if (err == -ENOTTY) return err; - /* - * 4. Special case: even after an error we need to put the - * results back for some ioctls. - * - * In the case of EXT_CTRLS, the error_idx will contain information - * on which control failed. - * - * In the case of S_EDID, the driver can return E2BIG and set - * the blocks to maximum allowed value. - */ - switch (cmd) { - case VIDIOC_S_EDID32: - if (put_v4l2_edid32(new_p64, p32)) - err = -EFAULT; - break; - } - if (err) - return err; - /* * 5. Copy the data returned at the 64 bits userspace pointer to * the original 32 bits structure. */ switch (cmd) { - case VIDIOC_G_FBUF32: - err = put_v4l2_framebuffer32(new_p64, p32); - break; - -#ifdef CONFIG_X86_64 - case VIDIOC_DQEVENT32: - err = put_v4l2_event32(new_p64, p32); - break; - - case VIDIOC_DQEVENT32_TIME32: - err = put_v4l2_event32_time32(new_p64, p32); - break; -#endif - - case VIDIOC_G_EDID32: - err = put_v4l2_edid32(new_p64, p32); - break; - - case VIDIOC_ENUMSTD32: - err = put_v4l2_standard32(new_p64, p32); - break; - - case VIDIOC_ENUMINPUT32: - err = put_v4l2_input32(new_p64, p32); - break; } return err; } -- cgit v1.2.3 From 6df26dc6b9b7bf6b25acc20eee6877e13f040a81 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 30 Oct 2020 17:55:29 +0100 Subject: media: v4l2: remove remaining compat_ioctl There are no remaining conversions in v4l2_compat_ioctl32(), so all the infrastructure for it can be removed, with the only remaining bit being the compat_ioctl32() callback into drivers that implement their own incompatible data structures. Signed-off-by: Arnd Bergmann Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 196 +------------------------- 1 file changed, 2 insertions(+), 194 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index b51fa680b4cf..58d29284db13 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -23,103 +23,6 @@ #include #include -/** - * assign_in_user() - Copy from one __user var to another one - * - * @to: __user var where data will be stored - * @from: __user var where data will be retrieved. - * - * As this code very often needs to allocate userspace memory, it is easier - * to have a macro that will do both get_user() and put_user() at once. - * - * This function complements the macros defined at asm-generic/uaccess.h. - * It uses the same argument order as copy_in_user() - */ -#define assign_in_user(to, from) \ -({ \ - typeof(*from) __assign_tmp; \ - \ - get_user(__assign_tmp, from) || put_user(__assign_tmp, to); \ -}) - -/** - * get_user_cast() - Stores at a kernelspace local var the contents from a - * pointer with userspace data that is not tagged with __user. - * - * @__x: var where data will be stored - * @__ptr: var where data will be retrieved. - * - * Sometimes we need to declare a pointer without __user because it - * comes from a pointer struct field that will be retrieved from userspace - * by the 64-bit native ioctl handler. This function ensures that the - * @__ptr will be cast to __user before calling get_user() in order to - * avoid warnings with static code analyzers like smatch. - */ -#define get_user_cast(__x, __ptr) \ -({ \ - get_user(__x, (typeof(*__ptr) __user *)(__ptr)); \ -}) - -/** - * put_user_force() - Stores the contents of a kernelspace local var - * into a userspace pointer, removing any __user cast. - * - * @__x: var where data will be stored - * @__ptr: var where data will be retrieved. - * - * Sometimes we need to remove the __user attribute from some data, - * by passing the __force macro. This function ensures that the - * @__ptr will be cast with __force before calling put_user(), in order to - * avoid warnings with static code analyzers like smatch. - */ -#define put_user_force(__x, __ptr) \ -({ \ - put_user((typeof(*__x) __force *)(__x), __ptr); \ -}) - -/** - * assign_in_user_cast() - Copy from one __user var to another one - * - * @to: __user var where data will be stored - * @from: var where data will be retrieved that needs to be cast to __user. - * - * As this code very often needs to allocate userspace memory, it is easier - * to have a macro that will do both get_user_cast() and put_user() at once. - * - * This function should be used instead of assign_in_user() when the @from - * variable was not declared as __user. See get_user_cast() for more details. - * - * This function complements the macros defined at asm-generic/uaccess.h. - * It uses the same argument order as copy_in_user() - */ -#define assign_in_user_cast(to, from) \ -({ \ - typeof(*from) __assign_tmp; \ - \ - get_user_cast(__assign_tmp, from) || put_user(__assign_tmp, to);\ -}) - -/** - * native_ioctl - Ancillary function that calls the native 64 bits ioctl - * handler. - * - * @file: pointer to &struct file with the file handler - * @cmd: ioctl to be called - * @arg: arguments passed from/to the ioctl handler - * - * This function calls the native ioctl handler at v4l2-dev, e. g. v4l2_ioctl() - */ -static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - long ret = -ENOIOCTLCMD; - - if (file->f_op->unlocked_ioctl) - ret = file->f_op->unlocked_ioctl(file, cmd, arg); - - return ret; -} - - /* * Per-ioctl data copy handlers. * @@ -1306,102 +1209,6 @@ int v4l2_compat_put_array_args(struct file *file, void __user *user_ptr, return err; } -/** - * alloc_userspace() - Allocates a 64-bits userspace pointer compatible - * for calling the native 64-bits version of an ioctl. - * - * @size: size of the structure itself to be allocated. - * @aux_space: extra size needed to store "extra" data, e.g. space for - * other __user data that is pointed to fields inside the - * structure. - * @new_p64: pointer to a pointer to be filled with the allocated struct. - * - * Return: - * - * if it can't allocate memory, either -ENOMEM or -EFAULT will be returned. - * Zero otherwise. - */ -static int alloc_userspace(unsigned int size, u32 aux_space, - void __user **new_p64) -{ - *new_p64 = compat_alloc_user_space(size + aux_space); - if (!*new_p64) - return -ENOMEM; - if (clear_user(*new_p64, size)) - return -EFAULT; - return 0; -} - -/** - * do_video_ioctl() - Ancillary function with handles a compat32 ioctl call - * - * @file: pointer to &struct file with the file handler - * @cmd: ioctl to be called - * @arg: arguments passed from/to the ioctl handler - * - * This function is called when a 32 bits application calls a V4L2 ioctl - * and the Kernel is compiled with 64 bits. - * - * This function is called by v4l2_compat_ioctl32() when the function is - * not private to some specific driver. - * - * It converts a 32-bits struct into a 64 bits one, calls the native 64-bits - * ioctl handler and fills back the 32-bits struct with the results of the - * native call. - */ -static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - void __user *p32 = compat_ptr(arg); - void __user *new_p64 = NULL; - void __user *aux_buf; - u32 aux_space; - int compatible_arg = 1; - long err = 0; - unsigned int ncmd; - - /* - * 1. When struct size is different, converts the command. - */ - switch (cmd) { - default: ncmd = cmd; break; - } - - /* - * 2. Allocates a 64-bits userspace pointer to store the - * values of the ioctl and copy data from the 32-bits __user - * argument into it. - */ - switch (cmd) { - } - if (err) - return err; - - /* - * 3. Calls the native 64-bits ioctl handler. - * - * For the functions where a conversion was not needed, - * compatible_arg is true, and it will call it with the arguments - * provided by userspace and stored at @p32 var. - * - * Otherwise, it will pass the newly allocated @new_p64 argument. - */ - if (compatible_arg) - err = native_ioctl(file, ncmd, (unsigned long)p32); - else - err = native_ioctl(file, ncmd, (unsigned long)new_p64); - - if (err == -ENOTTY) - return err; - - /* - * 5. Copy the data returned at the 64 bits userspace pointer to - * the original 32 bits structure. - */ - switch (cmd) { - } - return err; -} - /** * v4l2_compat_ioctl32() - Handles a compat32 ioctl call * @@ -1425,7 +1232,8 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) return ret; if (_IOC_TYPE(cmd) == 'V' && _IOC_NR(cmd) < BASE_VIDIOC_PRIVATE) - ret = do_video_ioctl(file, cmd, arg); + ret = file->f_op->unlocked_ioctl(file, cmd, + (unsigned long)compat_ptr(arg)); else if (vdev->fops->compat_ioctl32) ret = vdev->fops->compat_ioctl32(file, cmd, arg); -- cgit v1.2.3 From 67120129f95d90cc1b8875ed4f9bfaa21b914356 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 29 Sep 2020 15:14:24 +0200 Subject: media: coda: use semicolons rather than commas to separate statements Replace commas with semicolons. Commas introduce unnecessary variability in the code structure and are hard to see. What is done is essentially described by the following Coccinelle semantic patch (http://coccinelle.lip6.fr/): // @@ expression e1,e2; @@ e1 -, +; e2 ... when any // Signed-off-by: Julia Lawall Reviewed-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 87a2c706f747..547ad34b1424 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -2861,7 +2861,7 @@ static int coda_register_device(struct coda_dev *dev, int i) strscpy(vfd->name, dev->devtype->vdevs[i]->name, sizeof(vfd->name)); vfd->fops = &coda_fops; vfd->ioctl_ops = &coda_ioctl_ops; - vfd->release = video_device_release_empty, + vfd->release = video_device_release_empty; vfd->lock = &dev->dev_mutex; vfd->v4l2_dev = &dev->v4l2_dev; vfd->vfl_dir = VFL_DIR_M2M; -- cgit v1.2.3 From 973c960de6a278ab34ef214bd6c600a48bff1aa3 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 29 Sep 2020 15:14:25 +0200 Subject: media: em28xx-audio: use semicolons rather than commas to separate statements Replace commas with semicolons. Commas introduce unnecessary variability in the code structure and are hard to see. What is done is essentially described by the following Coccinelle semantic patch (http://coccinelle.lip6.fr/): // @@ expression e1,e2; @@ e1 -, +; e2 ... when any // Signed-off-by: Julia Lawall Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-audio.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index dc968fd5ace9..4d5ab1433b44 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -583,9 +583,9 @@ static int em28xx_cvol_new(struct snd_card *card, struct em28xx *dev, struct snd_kcontrol_new tmp; memset(&tmp, 0, sizeof(tmp)); - tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER, - tmp.private_value = id, - tmp.name = ctl_name, + tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + tmp.private_value = id; + tmp.name = ctl_name; /* Add Mute Control */ sprintf(ctl_name, "%s Switch", name); @@ -600,16 +600,16 @@ static int em28xx_cvol_new(struct snd_card *card, struct em28xx *dev, ctl_name, id); memset(&tmp, 0, sizeof(tmp)); - tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER, - tmp.private_value = id, - tmp.name = ctl_name, + tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + tmp.private_value = id; + tmp.name = ctl_name; /* Add Volume Control */ sprintf(ctl_name, "%s Volume", name); tmp.get = em28xx_vol_get; tmp.put = em28xx_vol_put; tmp.info = em28xx_vol_info; - tmp.tlv.p = em28xx_db_scale, + tmp.tlv.p = em28xx_db_scale; kctl = snd_ctl_new1(&tmp, dev); err = snd_ctl_add(card, kctl); if (err < 0) -- cgit v1.2.3 From 829393f700fb5cbc92be0beec23dada5e70d434e Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 29 Sep 2020 15:14:26 +0200 Subject: media: rtl28xxu: use semicolons rather than commas to separate statements Replace commas with semicolons. Commas introduce unnecessary variability in the code structure and are hard to see. What is done is essentially described by the following Coccinelle semantic patch (http://coccinelle.lip6.fr/): // @@ expression e1,e2; @@ e1 -, +; e2 ... when any // Signed-off-by: Julia Lawall Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index 91460e4d0c30..3952cc534b4a 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -955,7 +955,7 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) struct mn88472_config mn88472_config = {}; mn88472_config.fe = &adap->fe[1]; - mn88472_config.i2c_wr_max = 22, + mn88472_config.i2c_wr_max = 22; strscpy(info.type, "mn88472", I2C_NAME_SIZE); mn88472_config.xtal = 20500000; mn88472_config.ts_mode = SERIAL_TS_MODE; @@ -980,7 +980,7 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) struct mn88473_config mn88473_config = {}; mn88473_config.fe = &adap->fe[1]; - mn88473_config.i2c_wr_max = 22, + mn88473_config.i2c_wr_max = 22; strscpy(info.type, "mn88473", I2C_NAME_SIZE); info.addr = 0x18; info.platform_data = &mn88473_config; -- cgit v1.2.3 From 2fad4168fbeb5d9fa09e91a0488e0737e911f506 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 29 Sep 2020 15:14:27 +0200 Subject: media: saa7134: use semicolons rather than commas to separate statements Replace commas with semicolons. Commas introduce unnecessary variability in the code structure and are hard to see. What is done is essentially described by the following Coccinelle semantic patch (http://coccinelle.lip6.fr/): // @@ expression e1,e2; @@ e1 -, +; e2 ... when any // Signed-off-by: Julia Lawall Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/saa7134-video.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 94c1c10d0fea..c24716f4ce23 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -868,8 +868,11 @@ static int buffer_activate(struct saa7134_dev *dev, lines_uv = dev->height >> dev->fmt->vshift; base2 = base + bpl * dev->height; base3 = base2 + bpl_uv * lines_uv; - if (dev->fmt->uvswap) - tmp = base2, base2 = base3, base3 = tmp; + if (dev->fmt->uvswap) { + tmp = base2; + base2 = base3; + base3 = tmp; + } video_dbg("uv: bpl=%ld lines=%ld base2/3=%ld/%ld\n", bpl_uv,lines_uv,base2,base3); if (V4L2_FIELD_HAS_BOTH(dev->field)) { -- cgit v1.2.3 From 3a3c72d69b0dacea3f106449b287eb1552a6a7ac Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 29 Sep 2020 15:14:28 +0200 Subject: media: m88ds3103: use semicolons rather than commas to separate statements Replace commas with semicolons. Commas introduce unnecessary variability in the code structure and are hard to see. What is done is essentially described by the following Coccinelle semantic patch (http://coccinelle.lip6.fr/): // @@ expression e1,e2; @@ e1 -, +; e2 ... when any // Signed-off-by: Julia Lawall Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/m88ds3103.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c index ad6d9d564a87..cfa4cdde99d8 100644 --- a/drivers/media/dvb-frontends/m88ds3103.c +++ b/drivers/media/dvb-frontends/m88ds3103.c @@ -1793,9 +1793,9 @@ static int m88ds3103_probe(struct i2c_client *client, dev->config.lnb_en_pol = pdata->lnb_en_pol; dev->cfg = &dev->config; /* create regmap */ - dev->regmap_config.reg_bits = 8, - dev->regmap_config.val_bits = 8, - dev->regmap_config.lock_arg = dev, + dev->regmap_config.reg_bits = 8; + dev->regmap_config.val_bits = 8; + dev->regmap_config.lock_arg = dev; dev->regmap = devm_regmap_init_i2c(client, &dev->regmap_config); if (IS_ERR(dev->regmap)) { ret = PTR_ERR(dev->regmap); -- cgit v1.2.3 From c87dbeb8b195ff85c4b50e699249ff7ef61b797e Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 29 Sep 2020 15:14:29 +0200 Subject: media: gspca: ov534-ov772x: use semicolons rather than commas to separate statements Replace commas with semicolons. Commas introduce unnecessary variability in the code structure and are hard to see. What is done is essentially described by the following Coccinelle semantic patch (http://coccinelle.lip6.fr/): // @@ expression e1,e2; @@ e1 -, +; e2 ... when any // Signed-off-by: Julia Lawall Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/ov534.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c index 9a11158f38da..8b6a57f170d0 100644 --- a/drivers/media/usb/gspca/ov534.c +++ b/drivers/media/usb/gspca/ov534.c @@ -1220,9 +1220,9 @@ static int sd_init_controls(struct gspca_dev *gspca_dev) int hflip_def; if (sd->sensor == SENSOR_OV767x) { - saturation_min = 0, - saturation_max = 6, - saturation_def = 3, + saturation_min = 0; + saturation_max = 6; + saturation_def = 3; brightness_min = -127; brightness_max = 127; brightness_def = 0; @@ -1233,9 +1233,9 @@ static int sd_init_controls(struct gspca_dev *gspca_dev) exposure_def = 0x13; hflip_def = 1; } else { - saturation_min = 0, - saturation_max = 255, - saturation_def = 64, + saturation_min = 0; + saturation_max = 255; + saturation_def = 64; brightness_min = 0; brightness_max = 255; brightness_def = 0; -- cgit v1.2.3 From f5071fd5360444ad52b70078203a42eb73427ebe Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 29 Sep 2020 15:14:30 +0200 Subject: media: s3c-camif: use semicolons rather than commas to separate statements Replace commas with semicolons. Commas introduce unnecessary variability in the code structure and are hard to see. What is done is essentially described by the following Coccinelle semantic patch (http://coccinelle.lip6.fr/): // @@ expression e1,e2; @@ e1 -, +; e2 ... when any // Signed-off-by: Julia Lawall Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s3c-camif/camif-core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/s3c-camif/camif-core.c b/drivers/media/platform/s3c-camif/camif-core.c index 422fd549e9c8..4c3c00d59c92 100644 --- a/drivers/media/platform/s3c-camif/camif-core.c +++ b/drivers/media/platform/s3c-camif/camif-core.c @@ -131,11 +131,13 @@ static int camif_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift) while (sh--) { unsigned int tmp = 1 << sh; if (src >= tar * tmp) { - *shift = sh, *ratio = tmp; + *shift = sh; + *ratio = tmp; return 0; } } - *shift = 0, *ratio = 1; + *shift = 0; + *ratio = 1; return 0; } -- cgit v1.2.3 From 835fd614cbb535af5c7f6a05886fdbf422256c2a Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 29 Sep 2020 15:14:31 +0200 Subject: media: sun4i-csi: use semicolons rather than commas to separate statements Replace commas with semicolons. Commas introduce unnecessary variability in the code structure and are hard to see. What is done is essentially described by the following Coccinelle semantic patch (http://coccinelle.lip6.fr/): // @@ expression e1,e2; @@ e1 -, +; e2 ... when any // Signed-off-by: Julia Lawall Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c index 8f4e254b6a41..1a2f65d83a6c 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c @@ -363,7 +363,7 @@ int sun4i_csi_v4l2_register(struct sun4i_csi *csi) vdev->lock = &csi->lock; /* Set a default format */ - csi->fmt.pixelformat = sun4i_csi_formats[0].fourcc, + csi->fmt.pixelformat = sun4i_csi_formats[0].fourcc; csi->fmt.width = CSI_DEFAULT_WIDTH; csi->fmt.height = CSI_DEFAULT_HEIGHT; _sun4i_csi_try_fmt(csi, &csi->fmt); -- cgit v1.2.3 From e4b0e7d618984eb924ea31c7b009c297a79b7f32 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 29 Sep 2020 15:14:32 +0200 Subject: media: pvrusb2: use semicolons rather than commas to separate statements Replace commas with semicolons. Commas introduce unnecessary variability in the code structure and are hard to see. What is done is essentially described by the following Coccinelle semantic patch (http://coccinelle.lip6.fr/): // @@ expression e1,e2; @@ e1 -, +; e2 ... when any // Signed-off-by: Julia Lawall Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/pvrusb2/pvrusb2-devattr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/pvrusb2/pvrusb2-devattr.c b/drivers/media/usb/pvrusb2/pvrusb2-devattr.c index 1fcf63218885..d1b984ec757d 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-devattr.c @@ -594,7 +594,7 @@ static int pvr2_lgdt3306a_attach(struct pvr2_dvb_adapter *adap) lgdt3306a_config.mpeg_mode = LGDT3306A_MPEG_PARALLEL; lgdt3306a_config.tpclk_edge = LGDT3306A_TPCLK_FALLING_EDGE; lgdt3306a_config.tpvalid_polarity = LGDT3306A_TP_VALID_LOW; - lgdt3306a_config.xtalMHz = 25, /* demod clock MHz; 24/25 supported */ + lgdt3306a_config.xtalMHz = 25; /* demod clock MHz; 24/25 supported */ adap->i2c_client_demod[0] = dvb_module_probe("lgdt3306a", NULL, &adap->channel.hdw->i2c_adap, -- cgit v1.2.3 From fa71ae71ebaa91af45b78033ddd22fa214b8a4a1 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 29 Sep 2020 15:14:34 +0200 Subject: media: ts2020: use semicolons rather than commas to separate statements Replace commas with semicolons. Commas introduce unnecessary variability in the code structure and are hard to see. What is done is essentially described by the following Coccinelle semantic patch (http://coccinelle.lip6.fr/): // @@ expression e1,e2; @@ e1 -, +; e2 ... when any // Signed-off-by: Julia Lawall Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/ts2020.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb-frontends/ts2020.c b/drivers/media/dvb-frontends/ts2020.c index 234607b02edb..3e383912bcfd 100644 --- a/drivers/media/dvb-frontends/ts2020.c +++ b/drivers/media/dvb-frontends/ts2020.c @@ -569,11 +569,11 @@ static int ts2020_probe(struct i2c_client *client, /* create regmap */ mutex_init(&dev->regmap_mutex); - dev->regmap_config.reg_bits = 8, - dev->regmap_config.val_bits = 8, - dev->regmap_config.lock = ts2020_regmap_lock, - dev->regmap_config.unlock = ts2020_regmap_unlock, - dev->regmap_config.lock_arg = dev, + dev->regmap_config.reg_bits = 8; + dev->regmap_config.val_bits = 8; + dev->regmap_config.lock = ts2020_regmap_lock; + dev->regmap_config.unlock = ts2020_regmap_unlock; + dev->regmap_config.lock_arg = dev; dev->regmap = regmap_init_i2c(client, &dev->regmap_config); if (IS_ERR(dev->regmap)) { ret = PTR_ERR(dev->regmap); -- cgit v1.2.3 From 130e820d20dfb58bf2c929397589c6128533e48b Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 29 Sep 2020 15:14:35 +0200 Subject: media: msp3400: use semicolons rather than commas to separate statements Replace commas with semicolons. Commas introduce unnecessary variability in the code structure and are hard to see. What is done is essentially described by the following Coccinelle semantic patch (http://coccinelle.lip6.fr/): // @@ expression e1,e2; @@ e1 -, +; e2 ... when any // Signed-off-by: Julia Lawall Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/msp3400-kthreads.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/msp3400-kthreads.c b/drivers/media/i2c/msp3400-kthreads.c index 52e506f86de5..ecabc0e1d32e 100644 --- a/drivers/media/i2c/msp3400-kthreads.c +++ b/drivers/media/i2c/msp3400-kthreads.c @@ -549,8 +549,10 @@ restart: val = msp_read_dsp(client, 0x1b); if (val > 32767) val -= 65536; - if (val1 < val) - val1 = val, max1 = i; + if (val1 < val) { + val1 = val; + max1 = i; + } dev_dbg_lvl(&client->dev, 1, msp_debug, "carrier1 val: %5d / %s\n", val, cd[i].name); } @@ -586,8 +588,10 @@ restart: val = msp_read_dsp(client, 0x1b); if (val > 32767) val -= 65536; - if (val2 < val) - val2 = val, max2 = i; + if (val2 < val) { + val2 = val; + max2 = i; + } dev_dbg_lvl(&client->dev, 1, msp_debug, "carrier2 val: %5d / %s\n", val, cd[i].name); } -- cgit v1.2.3 From 0fcd8d890f625253663b477a37406c5ae8576f9d Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 29 Sep 2020 15:14:36 +0200 Subject: media: radio-sf16fmr2: use semicolons rather than commas to separate statements Replace commas with semicolons. Commas introduce unnecessary variability in the code structure and are hard to see. What is done is essentially described by the following Coccinelle semantic patch (http://coccinelle.lip6.fr/): // @@ expression e1,e2; @@ e1 -, +; e2 ... when any // Signed-off-by: Julia Lawall Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-sf16fmr2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index bd323e640f1a..0388894cfe41 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c @@ -215,7 +215,7 @@ static int fmr2_probe(struct fmr2 *fmr2, struct device *pdev, int io) return -EBUSY; strscpy(fmr2->v4l2_dev.name, "radio-sf16fmr2", - sizeof(fmr2->v4l2_dev.name)), + sizeof(fmr2->v4l2_dev.name)); fmr2->io = io; if (!request_region(fmr2->io, 2, fmr2->v4l2_dev.name)) { -- cgit v1.2.3 From ef0d21e492ced54743c7548d3f377130771cfcd5 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 29 Sep 2020 15:14:37 +0200 Subject: media: mt2060: use semicolons rather than commas to separate statements Replace commas with semicolons. Commas introduce unnecessary variability in the code structure and are hard to see. What is done is essentially described by the following Coccinelle semantic patch (http://coccinelle.lip6.fr/): // @@ expression e1,e2; @@ e1 -, +; e2 ... when any // Signed-off-by: Julia Lawall Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/mt2060.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/tuners/mt2060.c b/drivers/media/tuners/mt2060.c index 0e7ac2b49990..204e6186bf71 100644 --- a/drivers/media/tuners/mt2060.c +++ b/drivers/media/tuners/mt2060.c @@ -215,7 +215,7 @@ static int mt2060_set_params(struct dvb_frontend *fe) f_lo2 = f_lo1 - freq - IF2; // From the Comtech datasheet, the step used is 50kHz. The tuner chip could be more precise f_lo2 = ((f_lo2 + 25) / 50) * 50; - priv->frequency = (f_lo1 - f_lo2 - IF2) * 1000, + priv->frequency = (f_lo1 - f_lo2 - IF2) * 1000; #ifdef MT2060_SPURCHECK // LO-related spurs detection and correction -- cgit v1.2.3 From c2cf441779b24cc45179cded868a8175c0397479 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 29 Sep 2020 15:14:38 +0200 Subject: media: au0828: use semicolons rather than commas to separate statements Replace commas with semicolons. Commas introduce unnecessary variability in the code structure and are hard to see. What is done is essentially described by the following Coccinelle semantic patch (http://coccinelle.lip6.fr/): // @@ expression e1,e2; @@ e1 -, +; e2 ... when any // Signed-off-by: Julia Lawall Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index aa5bc6a2ae20..5c4bac5a4ec7 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -248,7 +248,7 @@ static int au0828_init_isoc(struct au0828_dev *dev, int max_packets, memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size); pipe = usb_rcvisocpipe(dev->usbdev, - dev->isoc_in_endpointaddr), + dev->isoc_in_endpointaddr); usb_fill_int_urb(urb, dev->usbdev, pipe, dev->isoc_ctl.transfer_buffer[i], sb_size, -- cgit v1.2.3 From e095406a4010ff648ea6e0316f02de370163225b Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 29 Sep 2020 15:14:39 +0200 Subject: media: dvbsky: use semicolons rather than commas to separate statements Replace commas with semicolons. Commas introduce unnecessary variability in the code structure and are hard to see. What is done is essentially described by the following Coccinelle semantic patch (http://coccinelle.lip6.fr/): // @@ expression e1,e2; @@ e1 -, +; e2 ... when any // Signed-off-by: Julia Lawall Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/dvbsky.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c index 0d9657f7f29d..689829f1b52a 100644 --- a/drivers/media/usb/dvb-usb-v2/dvbsky.c +++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c @@ -287,8 +287,8 @@ static int dvbsky_s960_attach(struct dvb_usb_adapter *adap) m88ds3103_pdata.ts_clk = 16000; m88ds3103_pdata.ts_clk_pol = 0; m88ds3103_pdata.agc = 0x99; - m88ds3103_pdata.lnb_hv_pol = 1, - m88ds3103_pdata.lnb_en_pol = 1, + m88ds3103_pdata.lnb_hv_pol = 1; + m88ds3103_pdata.lnb_en_pol = 1; state->i2c_client_demod = dvb_module_probe("m88ds3103", NULL, &d->i2c_adap, @@ -383,15 +383,15 @@ static int dvbsky_s960c_attach(struct dvb_usb_adapter *adap) struct sp2_config sp2_config = {}; /* attach demod */ - m88ds3103_pdata.clk = 27000000, - m88ds3103_pdata.i2c_wr_max = 33, - m88ds3103_pdata.clk_out = 0, - m88ds3103_pdata.ts_mode = M88DS3103_TS_CI, - m88ds3103_pdata.ts_clk = 10000, - m88ds3103_pdata.ts_clk_pol = 1, - m88ds3103_pdata.agc = 0x99, - m88ds3103_pdata.lnb_hv_pol = 0, - m88ds3103_pdata.lnb_en_pol = 1, + m88ds3103_pdata.clk = 27000000; + m88ds3103_pdata.i2c_wr_max = 33; + m88ds3103_pdata.clk_out = 0; + m88ds3103_pdata.ts_mode = M88DS3103_TS_CI; + m88ds3103_pdata.ts_clk = 10000; + m88ds3103_pdata.ts_clk_pol = 1; + m88ds3103_pdata.agc = 0x99; + m88ds3103_pdata.lnb_hv_pol = 0; + m88ds3103_pdata.lnb_en_pol = 1; state->i2c_client_demod = dvb_module_probe("m88ds3103", NULL, &d->i2c_adap, -- cgit v1.2.3 From 7214f42cfcd64b4abc690e5b98cb5a151185e39f Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 29 Sep 2020 15:14:40 +0200 Subject: media: dib0700: use semicolons rather than commas to separate statements Replace commas with semicolons. Commas introduce unnecessary variability in the code structure and are hard to see. What is done is essentially described by the following Coccinelle semantic patch (http://coccinelle.lip6.fr/): // @@ expression e1,e2; @@ e1 -, +; e2 ... when any // Signed-off-by: Julia Lawall Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/dib0700_devices.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index d3288c107906..710c1afe3e85 100644 --- a/drivers/media/usb/dvb-usb/dib0700_devices.c +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c @@ -3074,8 +3074,8 @@ static int nim7090_tuner_attach(struct dvb_usb_adapter *adap) struct dib0700_adapter_state *st = adap->priv; struct i2c_adapter *tun_i2c = st->dib7000p_ops.get_i2c_tuner(adap->fe_adap[0].fe); - nim7090_dib0090_config.reset = st->dib7000p_ops.tuner_sleep, - nim7090_dib0090_config.sleep = st->dib7000p_ops.tuner_sleep, + nim7090_dib0090_config.reset = st->dib7000p_ops.tuner_sleep; + nim7090_dib0090_config.sleep = st->dib7000p_ops.tuner_sleep; nim7090_dib0090_config.get_adc_power = st->dib7000p_ops.get_adc_power; if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &nim7090_dib0090_config) == NULL) -- cgit v1.2.3 From 107b2c9caf6d709f29fc29aa1170a39a11e0a1c7 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 29 Sep 2020 15:14:41 +0200 Subject: media: rtl2832: use semicolons rather than commas to separate statements Replace commas with semicolons. Commas introduce unnecessary variability in the code structure and are hard to see. What is done is essentially described by the following Coccinelle semantic patch (http://coccinelle.lip6.fr/): // @@ expression e1,e2; @@ e1 -, +; e2 ... when any // Signed-off-by: Julia Lawall Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/rtl2832.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index e5bffaaeed38..01dcc7f1b9b2 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c @@ -1056,13 +1056,13 @@ static int rtl2832_probe(struct i2c_client *client, dev->sleeping = true; INIT_DELAYED_WORK(&dev->i2c_gate_work, rtl2832_i2c_gate_work); /* create regmap */ - dev->regmap_config.reg_bits = 8, - dev->regmap_config.val_bits = 8, - dev->regmap_config.volatile_reg = rtl2832_volatile_reg, - dev->regmap_config.max_register = 5 * 0x100, - dev->regmap_config.ranges = regmap_range_cfg, - dev->regmap_config.num_ranges = ARRAY_SIZE(regmap_range_cfg), - dev->regmap_config.cache_type = REGCACHE_NONE, + dev->regmap_config.reg_bits = 8; + dev->regmap_config.val_bits = 8; + dev->regmap_config.volatile_reg = rtl2832_volatile_reg; + dev->regmap_config.max_register = 5 * 0x100; + dev->regmap_config.ranges = regmap_range_cfg; + dev->regmap_config.num_ranges = ARRAY_SIZE(regmap_range_cfg); + dev->regmap_config.cache_type = REGCACHE_NONE; dev->regmap = regmap_init_i2c(client, &dev->regmap_config); if (IS_ERR(dev->regmap)) { ret = PTR_ERR(dev->regmap); -- cgit v1.2.3 From abeb97ec2ea2aaed37d242a4ea93d76fa8cc4b13 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 29 Sep 2020 15:14:42 +0200 Subject: media: exynos4-is: use semicolons rather than commas to separate statements Replace commas with semicolons. Commas introduce unnecessary variability in the code structure and are hard to see. What is done is essentially described by the following Coccinelle semantic patch (http://coccinelle.lip6.fr/): // @@ expression e1,e2; @@ e1 -, +; e2 ... when any // Signed-off-by: Julia Lawall Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c index 08d1f39a914c..db6e548fe08e 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.c +++ b/drivers/media/platform/exynos4-is/fimc-core.c @@ -214,11 +214,13 @@ static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift) while (sh--) { u32 tmp = 1 << sh; if (src >= tar * tmp) { - *shift = sh, *ratio = tmp; + *shift = sh; + *ratio = tmp; return 0; } } - *shift = 0, *ratio = 1; + *shift = 0; + *ratio = 1; return 0; } -- cgit v1.2.3 From 8b88e2cddb9d24305b5e62730e65c54616abec94 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 29 Sep 2020 15:14:43 +0200 Subject: media: bttv: use semicolons rather than commas to separate statements Replace commas with semicolons. Commas introduce unnecessary variability in the code structure and are hard to see. What is done is essentially described by the following Coccinelle semantic patch (http://coccinelle.lip6.fr/): // @@ expression e1,e2; @@ e1 -, +; e2 ... when any // Signed-off-by: Julia Lawall Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-cards.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c index 16148802dabb..ca20b806e82d 100644 --- a/drivers/media/pci/bt8xx/bttv-cards.c +++ b/drivers/media/pci/bt8xx/bttv-cards.c @@ -3934,8 +3934,10 @@ static void osprey_eeprom(struct bttv *btv, const u8 ee[256]) if (checksum != ee[21]) return; cardid = BTTV_BOARD_OSPREY1x0_848; - for (i = 12; i < 21; i++) - serial *= 10, serial += ee[i] - '0'; + for (i = 12; i < 21; i++) { + serial *= 10; + serial += ee[i] - '0'; + } } } else { unsigned short type; -- cgit v1.2.3 From 336934dbecd88ba218de07b054a24c1ac0285ee4 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 11 Sep 2020 13:27:07 +0200 Subject: media: marvell-ccic: Fix -Wunused-function warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If CONFIG_PM is n, gcc warns: drivers/media/platform/marvell-ccic/mmp-driver.c:324:12: warning: ‘mmpcam_runtime_suspend’ defined but not used [-Wunused-function] static int mmpcam_runtime_suspend(struct device *dev) ^~~~~~~~~~~~~~~~~~~~~~ drivers/media/platform/marvell-ccic/mmp-driver.c:310:12: warning: ‘mmpcam_runtime_resume’ defined but not used [-Wunused-function] static int mmpcam_runtime_resume(struct device *dev) ^~~~~~~~~~~~~~~~~~~~~ Mark them as __maybe_unused to fix this. Reported-by: Hulk Robot Signed-off-by: YueHaibing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/marvell-ccic/mmp-driver.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c index cd902b180669..032fdddbbecc 100644 --- a/drivers/media/platform/marvell-ccic/mmp-driver.c +++ b/drivers/media/platform/marvell-ccic/mmp-driver.c @@ -307,7 +307,7 @@ static int mmpcam_platform_remove(struct platform_device *pdev) * Suspend/resume support. */ -static int mmpcam_runtime_resume(struct device *dev) +static int __maybe_unused mmpcam_runtime_resume(struct device *dev) { struct mmp_camera *cam = dev_get_drvdata(dev); struct mcam_camera *mcam = &cam->mcam; @@ -321,7 +321,7 @@ static int mmpcam_runtime_resume(struct device *dev) return 0; } -static int mmpcam_runtime_suspend(struct device *dev) +static int __maybe_unused mmpcam_runtime_suspend(struct device *dev) { struct mmp_camera *cam = dev_get_drvdata(dev); struct mcam_camera *mcam = &cam->mcam; -- cgit v1.2.3 From acc4de3d7f4710764f20e32633bc5fe0334f0cd9 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Sun, 13 Sep 2020 14:17:56 +0200 Subject: media: rcar-vin: Remove redundant compatible values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mandatory compatible value 'renesas,rcar-gen2-vin' was added to all Gen2 DTS files in 2017, remove the redundant device specific values from the driver. Signed-off-by: Niklas Söderlund Reviewed-by: Geert Uytterhoeven Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-core.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 34d003e0e9b9..1c52678a4d0f 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -1267,22 +1267,6 @@ static const struct of_device_id rvin_of_id_table[] = { .compatible = "renesas,vin-r8a7779", .data = &rcar_info_h1, }, - { - .compatible = "renesas,vin-r8a7790", - .data = &rcar_info_gen2, - }, - { - .compatible = "renesas,vin-r8a7791", - .data = &rcar_info_gen2, - }, - { - .compatible = "renesas,vin-r8a7793", - .data = &rcar_info_gen2, - }, - { - .compatible = "renesas,vin-r8a7794", - .data = &rcar_info_gen2, - }, { .compatible = "renesas,rcar-gen2-vin", .data = &rcar_info_gen2, -- cgit v1.2.3 From adbf7c06330ec0c01cef324c384b24c88254ae65 Mon Sep 17 00:00:00 2001 From: Dafna Hirschfeld Date: Mon, 28 Sep 2020 17:28:09 +0200 Subject: media: staging: rkisp1: remove TODO item to document quantization handling The quantization handling is already documented in the file rkisp1.rst so this item can be removed. Fixes: 6616726907418 (media: staging: rkisp1: allow quantization setting by userspace on the isp source pad) Signed-off-by: Dafna Hirschfeld Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/rkisp1/TODO | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/staging/media/rkisp1/TODO b/drivers/staging/media/rkisp1/TODO index e7c8398fc2ce..d9360607fbfb 100644 --- a/drivers/staging/media/rkisp1/TODO +++ b/drivers/staging/media/rkisp1/TODO @@ -1,6 +1,5 @@ * Fix pad format size for statistics and parameters entities. * Fix checkpatch errors. -* Add uapi docs. Remember to add documentation of how quantization is handled. * streaming paths (mainpath and selfpath) check if the other path is streaming in several places of the code, review this, specially that it doesn't seem it supports streaming from both paths at the same time. -- cgit v1.2.3 From 020c7b6d3cd45ef0e464961b12632a1419eaf098 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 28 Sep 2020 22:14:33 +0200 Subject: media: uapi: h264: Add documentation to the interface header In preparation for making the interface public, document all the structures. Special care is taken to annotate those fields that depart from the H264 syntax. This commit only adds documentation and doesn't affect functionality in any way. Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/media/h264-ctrls.h | 195 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 185 insertions(+), 10 deletions(-) diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h index ec4799154438..893e21354a9b 100644 --- a/include/media/h264-ctrls.h +++ b/include/media/h264-ctrls.h @@ -46,11 +46,38 @@ #define V4L2_CTRL_TYPE_H264_DECODE_PARAMS 0x0114 #define V4L2_CTRL_TYPE_H264_PRED_WEIGHTS 0x0115 +/** + * enum v4l2_mpeg_video_h264_decode_mode - Decoding mode + * + * @V4L2_MPEG_VIDEO_H264_DECODE_MODE_SLICE_BASED: indicates that decoding + * is performed one slice at a time. In this mode, + * V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS must contain the parsed slice + * parameters and the OUTPUT buffer must contain a single slice. + * V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF feature is used + * in order to support multislice frames. + * @V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED: indicates that + * decoding is performed per frame. The OUTPUT buffer must contain + * all slices and also both fields. This mode is typically supported + * by device drivers that are able to parse the slice(s) header(s) + * in hardware. When this mode is selected, + * V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS is not used. + */ enum v4l2_mpeg_video_h264_decode_mode { V4L2_MPEG_VIDEO_H264_DECODE_MODE_SLICE_BASED, V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED, }; +/** + * enum v4l2_mpeg_video_h264_start_code - Start code + * + * @V4L2_MPEG_VIDEO_H264_START_CODE_NONE: slices are passed + * to the driver without any start code. + * @V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B: slices are passed + * to the driver with an Annex B start code prefix + * (legal start codes can be 3-bytes 0x000001 or 4-bytes 0x00000001). + * This mode is typically supported by device drivers that parse + * the start code in hardware. + */ enum v4l2_mpeg_video_h264_start_code { V4L2_MPEG_VIDEO_H264_START_CODE_NONE, V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B, @@ -71,6 +98,31 @@ enum v4l2_mpeg_video_h264_start_code { #define V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD 0x20 #define V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE 0x40 +/** + * struct v4l2_ctrl_h264_sps - H264 sequence parameter set + * + * All the members on this sequence parameter set structure match the + * sequence parameter set syntax as specified by the H264 specification. + * + * @profile_idc: see H264 specification. + * @constraint_set_flags: see H264 specification. + * @level_idc: see H264 specification. + * @seq_parameter_set_id: see H264 specification. + * @chroma_format_idc: see H264 specification. + * @bit_depth_luma_minus8: see H264 specification. + * @bit_depth_chroma_minus8: see H264 specification. + * @log2_max_frame_num_minus4: see H264 specification. + * @pic_order_cnt_type: see H264 specification. + * @log2_max_pic_order_cnt_lsb_minus4: see H264 specification. + * @max_num_ref_frames: see H264 specification. + * @num_ref_frames_in_pic_order_cnt_cycle: see H264 specification. + * @offset_for_ref_frame: see H264 specification. + * @offset_for_non_ref_pic: see H264 specification. + * @offset_for_top_to_bottom_field: see H264 specification. + * @pic_width_in_mbs_minus1: see H264 specification. + * @pic_height_in_map_units_minus1: see H264 specification. + * @flags: see V4L2_H264_SPS_FLAG_{}. + */ struct v4l2_ctrl_h264_sps { __u8 profile_idc; __u8 constraint_set_flags; @@ -101,6 +153,31 @@ struct v4l2_ctrl_h264_sps { #define V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE 0x0040 #define V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT 0x0080 +/** + * struct v4l2_ctrl_h264_pps - H264 picture parameter set + * + * Except where noted, all the members on this picture parameter set + * structure match the sequence parameter set syntax as specified + * by the H264 specification. + * + * In particular, V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT flag + * has a specific meaning. This flag should be set if a non-flat + * scaling matrix applies to the picture. In this case, applications + * are expected to use V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX, + * to pass the values of the non-flat matrices. + * + * @pic_parameter_set_id: see H264 specification. + * @seq_parameter_set_id: see H264 specification. + * @num_slice_groups_minus1: see H264 specification. + * @num_ref_idx_l0_default_active_minus1: see H264 specification. + * @num_ref_idx_l1_default_active_minus1: see H264 specification. + * @weighted_bipred_idc: see H264 specification. + * @pic_init_qp_minus26: see H264 specification. + * @pic_init_qs_minus26: see H264 specification. + * @chroma_qp_index_offset: see H264 specification. + * @second_chroma_qp_index_offset: see H264 specification. + * @flags: see V4L2_H264_PPS_FLAG_{}. + */ struct v4l2_ctrl_h264_pps { __u8 pic_parameter_set_id; __u8 seq_parameter_set_id; @@ -115,6 +192,23 @@ struct v4l2_ctrl_h264_pps { __u16 flags; }; +/** + * struct v4l2_ctrl_h264_scaling_matrix - H264 scaling matrices + * + * @scaling_list_4x4: scaling matrix after applying the inverse + * scanning process. Expected list order is Intra Y, Intra Cb, + * Intra Cr, Inter Y, Inter Cb, Inter Cr. The values on each + * scaling list are expected in raster scan order. + * @scaling_list_8x8: scaling matrix after applying the inverse + * scanning process. Expected list order is Intra Y, Inter Y, + * Intra Cb, Inter Cb, Intra Cr, Inter Cr. The values on each + * scaling list are expected in raster scan order. + * + * Note that the list order is different for the 4x4 and 8x8 + * matrices as per the H264 specification, see table 7-2 "Assignment + * of mnemonic names to scaling list indices and specification of + * fall-back rule". + */ struct v4l2_ctrl_h264_scaling_matrix { __u8 scaling_list_4x4[6][16]; __u8 scaling_list_8x8[6][64]; @@ -134,6 +228,16 @@ struct v4l2_h264_weight_factors { ((pps)->weighted_bipred_idc == 1 && \ (slice)->slice_type == V4L2_H264_SLICE_TYPE_B)) +/** + * struct v4l2_ctrl_h264_pred_weights - Prediction weight table + * + * Prediction weight table, which matches the syntax specified + * by the H264 specification. + * + * @luma_log2_weight_denom: see H264 specification. + * @chroma_log2_weight_denom: see H264 specification. + * @weight_factors: luma and chroma weight factors. + */ struct v4l2_ctrl_h264_pred_weights { __u16 luma_log2_weight_denom; __u16 chroma_log2_weight_denom; @@ -153,19 +257,55 @@ struct v4l2_ctrl_h264_pred_weights { #define V4L2_H264_BOTTOM_FIELD_REF 0x2 #define V4L2_H264_FRAME_REF 0x3 +/** + * struct v4l2_h264_reference - H264 picture reference + * + * @fields: indicates how the picture is referenced. + * Valid values are V4L2_H264_{}_REF. + * @index: index into v4l2_ctrl_h264_decode_params.dpb[]. + */ struct v4l2_h264_reference { __u8 fields; - - /* Index into v4l2_ctrl_h264_decode_params.dpb[] */ __u8 index; }; +/** + * struct v4l2_ctrl_h264_slice_params - H264 slice parameters + * + * This structure holds the H264 syntax elements that are specified + * as non-invariant for the slices in a given frame. + * + * Slice invariant syntax elements are contained in struct + * v4l2_ctrl_h264_decode_params. This is done to reduce the API surface + * on frame-based decoders, where slice header parsing is done by the + * hardware. + * + * Slice invariant syntax elements are specified in specification section + * "7.4.3 Slice header semantics". + * + * Except where noted, the members on this struct match the slice header syntax. + * + * @header_bit_size: offset in bits to slice_data() from the beginning of this slice. + * @first_mb_in_slice: see H264 specification. + * @slice_type: see H264 specification. + * @colour_plane_id: see H264 specification. + * @redundant_pic_cnt: see H264 specification. + * @cabac_init_idc: see H264 specification. + * @slice_qp_delta: see H264 specification. + * @slice_qs_delta: see H264 specification. + * @disable_deblocking_filter_idc: see H264 specification. + * @slice_alpha_c0_offset_div2: see H264 specification. + * @slice_beta_offset_div2: see H264 specification. + * @num_ref_idx_l0_active_minus1: see H264 specification. + * @num_ref_idx_l1_active_minus1: see H264 specification. + * @reserved: padding field. Should be zeroed by applications. + * @ref_pic_list0: reference picture list 0 after applying the per-slice modifications. + * @ref_pic_list1: reference picture list 1 after applying the per-slice modifications. + * @flags: see V4L2_H264_SLICE_FLAG_{}. + */ struct v4l2_ctrl_h264_slice_params { - /* Offset in bits to slice_data() from the beginning of this slice. */ __u32 header_bit_size; - __u32 first_mb_in_slice; - __u8 slice_type; __u8 colour_plane_id; __u8 redundant_pic_cnt; @@ -191,22 +331,59 @@ struct v4l2_ctrl_h264_slice_params { #define V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM 0x04 #define V4L2_H264_DPB_ENTRY_FLAG_FIELD 0x08 +/** + * struct v4l2_h264_dpb_entry - H264 decoded picture buffer entry + * + * @reference_ts: timestamp of the V4L2 capture buffer to use as reference. + * The timestamp refers to the timestamp field in struct v4l2_buffer. + * Use v4l2_timeval_to_ns() to convert the struct timeval to a __u64. + * @pic_num: matches PicNum variable assigned during the reference + * picture lists construction process. + * @frame_num: frame identifier which matches frame_num syntax element. + * @fields: indicates how the DPB entry is referenced. Valid values are + * V4L2_H264_{}_REF. + * @reserved: padding field. Should be zeroed by applications. + * @top_field_order_cnt: matches TopFieldOrderCnt picture value. + * @bottom_field_order_cnt: matches BottomFieldOrderCnt picture value. + * Note that picture field is indicated by v4l2_buffer.field. + * @flags: see V4L2_H264_DPB_ENTRY_FLAG_{}. + */ struct v4l2_h264_dpb_entry { __u64 reference_ts; __u32 pic_num; __u16 frame_num; __u8 fields; __u8 reserved[5]; - /* Note that field is indicated by v4l2_buffer.field */ __s32 top_field_order_cnt; __s32 bottom_field_order_cnt; - __u32 flags; /* V4L2_H264_DPB_ENTRY_FLAG_* */ + __u32 flags; }; #define V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC 0x01 #define V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC 0x02 #define V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD 0x04 +/** + * struct v4l2_ctrl_h264_decode_params - H264 decoding parameters + * + * @dpb: decoded picture buffer. + * @nal_ref_idc: slice header syntax element. + * @frame_num: slice header syntax element. + * @top_field_order_cnt: matches TopFieldOrderCnt picture value. + * @bottom_field_order_cnt: matches BottomFieldOrderCnt picture value. + * Note that picture field is indicated by v4l2_buffer.field. + * @idr_pic_id: slice header syntax element. + * @pic_order_cnt_lsb: slice header syntax element. + * @delta_pic_order_cnt_bottom: slice header syntax element. + * @delta_pic_order_cnt0: slice header syntax element. + * @delta_pic_order_cnt1: slice header syntax element. + * @dec_ref_pic_marking_bit_size: size in bits of dec_ref_pic_marking() + * syntax element. + * @pic_order_cnt_bit_size: size in bits of pic order count syntax. + * @slice_group_change_cycle: slice header syntax element. + * @reserved: padding field. Should be zeroed by applications. + * @flags: see V4L2_H264_DECODE_PARAM_FLAG_{}. + */ struct v4l2_ctrl_h264_decode_params { struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]; __u16 nal_ref_idc; @@ -218,14 +395,12 @@ struct v4l2_ctrl_h264_decode_params { __s32 delta_pic_order_cnt_bottom; __s32 delta_pic_order_cnt0; __s32 delta_pic_order_cnt1; - /* Size in bits of dec_ref_pic_marking() syntax element. */ __u32 dec_ref_pic_marking_bit_size; - /* Size in bits of pic order count syntax. */ __u32 pic_order_cnt_bit_size; __u32 slice_group_change_cycle; __u32 reserved; - __u32 flags; /* V4L2_H264_DECODE_PARAM_FLAG_* */ + __u32 flags; }; #endif -- cgit v1.2.3 From e7531d5625ed1ec50299059949d5782d9459b8e5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 1 Oct 2020 12:13:42 +0200 Subject: media: Fix V4L2_COLORSPACE_470_SYSTEM_BG description The description of the V4L2_COLORSPACE_470_SYSTEM_BG stated that it was superseded by SMPTE 170M. That is incorrect. The probably root cause of this is that the HDMI standard does not support this colorspace and, unless otherwise signaled, will fall back to SMPTE 170M for SDTV. However, EBU Tech. 3321 states that sources should signal Rec. 709 as the colorimetry when using HDMI since the difference between Rec. 709 and Tech. 3213 are negligible. Update the text accordingly. Also drop a spurious " at the end of the Tech 3213 title in the bibliography. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/v4l/biblio.rst | 12 +++++++++++- .../userspace-api/media/v4l/colorspaces-details.rst | 5 +++-- include/uapi/linux/videodev2.h | 4 +--- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Documentation/userspace-api/media/v4l/biblio.rst b/Documentation/userspace-api/media/v4l/biblio.rst index 7869b6f6ff72..64d241daf63c 100644 --- a/Documentation/userspace-api/media/v4l/biblio.rst +++ b/Documentation/userspace-api/media/v4l/biblio.rst @@ -270,7 +270,17 @@ EBU Tech 3213 ============= -:title: E.B.U. Standard for Chromaticity Tolerances for Studio Monitors" +:title: E.B.U. Standard for Chromaticity Tolerances for Studio Monitors + +:author: European Broadcast Union (http://www.ebu.ch) + +.. _tech3321: + +EBU Tech 3321 +============= + + +:title: E.B.U. guidelines for Consumer Flat Panel Displays (FPDs) :author: European Broadcast Union (http://www.ebu.ch) diff --git a/Documentation/userspace-api/media/v4l/colorspaces-details.rst b/Documentation/userspace-api/media/v4l/colorspaces-details.rst index 014e7c9fc655..126f66482a0d 100644 --- a/Documentation/userspace-api/media/v4l/colorspaces-details.rst +++ b/Documentation/userspace-api/media/v4l/colorspaces-details.rst @@ -674,8 +674,9 @@ Colorspace EBU Tech. 3213 (V4L2_COLORSPACE_470_SYSTEM_BG) ========================================================= The :ref:`tech3213` standard defines the colorspace used by PAL/SECAM -in 1975. In practice this colorspace is obsolete and SMPTE 170M should -be used instead. The default transfer function is +in 1975. Note that this colorspace is not supported by the HDMI interface. +Instead :ref:`tech3321` recommends that Rec. 709 is used instead for HDMI. +The default transfer function is ``V4L2_XFER_FUNC_709``. The default Y'CbCr encoding is ``V4L2_YCBCR_ENC_601``. The default Y'CbCr quantization is limited range. The chromaticities of the primary colors and the white reference diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index b10f102bbf6f..927075fa9099 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -221,9 +221,7 @@ enum v4l2_colorspace { V4L2_COLORSPACE_470_SYSTEM_M = 5, /* - * EBU Tech 3213 PAL/SECAM colorspace. This only makes sense when - * dealing with really old PAL/SECAM recordings. Superseded by - * SMPTE 170M. + * EBU Tech 3213 PAL/SECAM colorspace. */ V4L2_COLORSPACE_470_SYSTEM_BG = 6, -- cgit v1.2.3 From 5e3a81d42e1d50ec66d47186da25d833750ba4e3 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 2 Oct 2020 12:16:20 +0200 Subject: media: zoran: fix spelling mistake and make error message more meaningful There is a spelling mistake in a pci_err error message. Fix this and make the error message a little more meaningful. Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/zoran/zoran_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/zoran/zoran_driver.c b/drivers/staging/media/zoran/zoran_driver.c index 808196ea5b81..d9f8b21edf6a 100644 --- a/drivers/staging/media/zoran/zoran_driver.c +++ b/drivers/staging/media/zoran/zoran_driver.c @@ -666,7 +666,7 @@ static int zoran_g_selection(struct file *file, void *__fh, struct v4l2_selectio if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - pci_err(zr->pci_dev, "%s invalid combinaison\n", __func__); + pci_err(zr->pci_dev, "%s invalid selection type combination\n", __func__); return -EINVAL; } -- cgit v1.2.3 From 6e8c09bb8d60a0b905295e9e2c999b39953c5bf3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 2 Oct 2020 16:48:03 +0200 Subject: media: vivid: fix (partially) timing issues The vivid driver is a bit flaky w.r.t. the kthread timing, esp. when running inside a virtual machine. This is caused by calling schedule_timeout_uninterruptible(1) which can actually take more than one jiffie. A while loop with schedule() turns out to be a lot more precise. Also, if mutex_trylock() fails, then just call schedule() instead of schedule_timeout_uninterruptible(1). There is no need to wait until the next jiffer, just schedule(), then try to get the lock again. This is still not precise enough, it is still relatively easy to get missed frames. This really should be converted to use a proper timer, but for now this solves the worst problems. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/test-drivers/vivid/vivid-kthread-cap.c | 6 ++++-- drivers/media/test-drivers/vivid/vivid-kthread-out.c | 6 ++++-- drivers/media/test-drivers/vivid/vivid-kthread-touch.c | 6 ++++-- drivers/media/test-drivers/vivid/vivid-sdr-cap.c | 6 ++++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/media/test-drivers/vivid/vivid-kthread-cap.c b/drivers/media/test-drivers/vivid/vivid-kthread-cap.c index 01a9d671b947..67fb3c00f9ad 100644 --- a/drivers/media/test-drivers/vivid/vivid-kthread-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-kthread-cap.c @@ -819,7 +819,7 @@ static int vivid_thread_vid_cap(void *data) break; if (!mutex_trylock(&dev->mutex)) { - schedule_timeout_uninterruptible(1); + schedule(); continue; } @@ -888,7 +888,9 @@ static int vivid_thread_vid_cap(void *data) next_jiffies_since_start = jiffies_since_start; wait_jiffies = next_jiffies_since_start - jiffies_since_start; - schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1); + while (jiffies - cur_jiffies < wait_jiffies && + !kthread_should_stop()) + schedule(); } dprintk(dev, 1, "Video Capture Thread End\n"); return 0; diff --git a/drivers/media/test-drivers/vivid/vivid-kthread-out.c b/drivers/media/test-drivers/vivid/vivid-kthread-out.c index 6780687978f9..79c57d14ac4e 100644 --- a/drivers/media/test-drivers/vivid/vivid-kthread-out.c +++ b/drivers/media/test-drivers/vivid/vivid-kthread-out.c @@ -167,7 +167,7 @@ static int vivid_thread_vid_out(void *data) break; if (!mutex_trylock(&dev->mutex)) { - schedule_timeout_uninterruptible(1); + schedule(); continue; } @@ -233,7 +233,9 @@ static int vivid_thread_vid_out(void *data) next_jiffies_since_start = jiffies_since_start; wait_jiffies = next_jiffies_since_start - jiffies_since_start; - schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1); + while (jiffies - cur_jiffies < wait_jiffies && + !kthread_should_stop()) + schedule(); } dprintk(dev, 1, "Video Output Thread End\n"); return 0; diff --git a/drivers/media/test-drivers/vivid/vivid-kthread-touch.c b/drivers/media/test-drivers/vivid/vivid-kthread-touch.c index 674507b5ccb5..38fdfee79498 100644 --- a/drivers/media/test-drivers/vivid/vivid-kthread-touch.c +++ b/drivers/media/test-drivers/vivid/vivid-kthread-touch.c @@ -69,7 +69,7 @@ static int vivid_thread_touch_cap(void *data) break; if (!mutex_trylock(&dev->mutex)) { - schedule_timeout_uninterruptible(1); + schedule(); continue; } cur_jiffies = jiffies; @@ -128,7 +128,9 @@ static int vivid_thread_touch_cap(void *data) next_jiffies_since_start = jiffies_since_start; wait_jiffies = next_jiffies_since_start - jiffies_since_start; - schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1); + while (jiffies - cur_jiffies < wait_jiffies && + !kthread_should_stop()) + schedule(); } dprintk(dev, 1, "Touch Capture Thread End\n"); return 0; diff --git a/drivers/media/test-drivers/vivid/vivid-sdr-cap.c b/drivers/media/test-drivers/vivid/vivid-sdr-cap.c index 2b7522e16efc..a1e52708b7ca 100644 --- a/drivers/media/test-drivers/vivid/vivid-sdr-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-sdr-cap.c @@ -142,7 +142,7 @@ static int vivid_thread_sdr_cap(void *data) break; if (!mutex_trylock(&dev->mutex)) { - schedule_timeout_uninterruptible(1); + schedule(); continue; } @@ -201,7 +201,9 @@ static int vivid_thread_sdr_cap(void *data) next_jiffies_since_start = jiffies_since_start; wait_jiffies = next_jiffies_since_start - jiffies_since_start; - schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1); + while (jiffies - cur_jiffies < wait_jiffies && + !kthread_should_stop()) + schedule(); } dprintk(dev, 1, "SDR Capture Thread End\n"); return 0; -- cgit v1.2.3 From 35d1a7bbe45626a9bada329c42353e402030bc83 Mon Sep 17 00:00:00 2001 From: Dafna Hirschfeld Date: Fri, 2 Oct 2020 20:42:17 +0200 Subject: media: staging: rkisp1: validate links before powering and streaming In function rkisp1_vb2_start_streaming, the call to media_pipeline_start should be the first thing in order to validate the links and prevents their state from being modified before power up and streaming. Adjust stop streaming to the same logic, call media_pipeline_stop after we disable streaming on the entities in the topology. Signed-off-by: Helen Koike Signed-off-by: Dafna Hirschfeld Reviewed-by: Tomasz Figa Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/rkisp1/rkisp1-capture.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/staging/media/rkisp1/rkisp1-capture.c b/drivers/staging/media/rkisp1/rkisp1-capture.c index b6f497ce3e95..9b4a12e13f13 100644 --- a/drivers/staging/media/rkisp1/rkisp1-capture.c +++ b/drivers/staging/media/rkisp1/rkisp1-capture.c @@ -921,7 +921,6 @@ static void rkisp1_vb2_stop_streaming(struct vb2_queue *queue) mutex_lock(&cap->rkisp1->stream_lock); rkisp1_stream_stop(cap); - media_pipeline_stop(&node->vdev.entity); ret = rkisp1_pipeline_sink_walk(&node->vdev.entity, NULL, rkisp1_pipeline_disable_cb); if (ret) @@ -937,6 +936,8 @@ static void rkisp1_vb2_stop_streaming(struct vb2_queue *queue) rkisp1_dummy_buf_destroy(cap); + media_pipeline_stop(&node->vdev.entity); + mutex_unlock(&cap->rkisp1->stream_lock); } @@ -986,9 +987,15 @@ rkisp1_vb2_start_streaming(struct vb2_queue *queue, unsigned int count) mutex_lock(&cap->rkisp1->stream_lock); + ret = media_pipeline_start(entity, &cap->rkisp1->pipe); + if (ret) { + dev_err(cap->rkisp1->dev, "start pipeline failed %d\n", ret); + goto err_ret_buffers; + } + ret = rkisp1_dummy_buf_create(cap); if (ret) - goto err_ret_buffers; + goto err_pipeline_stop; ret = pm_runtime_get_sync(cap->rkisp1->dev); if (ret < 0) { @@ -1009,18 +1016,10 @@ rkisp1_vb2_start_streaming(struct vb2_queue *queue, unsigned int count) if (ret) goto err_stop_stream; - ret = media_pipeline_start(entity, &cap->rkisp1->pipe); - if (ret) { - dev_err(cap->rkisp1->dev, "start pipeline failed %d\n", ret); - goto err_pipe_disable; - } - mutex_unlock(&cap->rkisp1->stream_lock); return 0; -err_pipe_disable: - rkisp1_pipeline_sink_walk(entity, NULL, rkisp1_pipeline_disable_cb); err_stop_stream: rkisp1_stream_stop(cap); v4l2_pipeline_pm_put(entity); @@ -1028,6 +1027,8 @@ err_pipe_pm_put: pm_runtime_put(cap->rkisp1->dev); err_destroy_dummy: rkisp1_dummy_buf_destroy(cap); +err_pipeline_stop: + media_pipeline_stop(entity); err_ret_buffers: rkisp1_return_all_buffers(cap, VB2_BUF_STATE_QUEUED); mutex_unlock(&cap->rkisp1->stream_lock); -- cgit v1.2.3 From dd48134061bb0ae2c53f40d78f7672055be06b53 Mon Sep 17 00:00:00 2001 From: Dafna Hirschfeld Date: Fri, 2 Oct 2020 20:42:18 +0200 Subject: media: staging: rkisp1: params: in stop_streaming, use list_splice_init to move the buffers Currently the code uses 'list_cut_position' to move the buffers to a temporary list. Replace it with 'list_splice_init'. This is nicer since we don't need to access params.prev. Also, replace INIT_LIST_HEAD with the simpler LIST_HEAD. Signed-off-by: Dafna Hirschfeld Acked-by: Helen Koike Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/rkisp1/rkisp1-params.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/staging/media/rkisp1/rkisp1-params.c b/drivers/staging/media/rkisp1/rkisp1-params.c index 986d293201e6..cb9f3332a9a0 100644 --- a/drivers/staging/media/rkisp1/rkisp1-params.c +++ b/drivers/staging/media/rkisp1/rkisp1-params.c @@ -1462,9 +1462,7 @@ static void rkisp1_params_vb2_stop_streaming(struct vb2_queue *vq) { struct rkisp1_params *params = vq->drv_priv; struct rkisp1_buffer *buf; - struct list_head tmp_list; - - INIT_LIST_HEAD(&tmp_list); + LIST_HEAD(tmp_list); /* * we first move the buffers into a local list 'tmp_list' @@ -1473,7 +1471,7 @@ static void rkisp1_params_vb2_stop_streaming(struct vb2_queue *vq) */ spin_lock_irq(¶ms->config_lock); params->is_streaming = false; - list_cut_position(&tmp_list, ¶ms->params, params->params.prev); + list_splice_init(¶ms->params, &tmp_list); spin_unlock_irq(¶ms->config_lock); list_for_each_entry(buf, &tmp_list, queue) -- cgit v1.2.3 From 60fcc5beb80cbdaeb0ced74428d9a2c731e6c57c Mon Sep 17 00:00:00 2001 From: Dafna Hirschfeld Date: Fri, 2 Oct 2020 20:42:19 +0200 Subject: media: staging: rkisp1: initialize buffer lists only on probe The buffer lists of stats and params entities are initialized in queue_setup callback with 'INIT_LIST_HEAD'. It is enough to initialize the lists only upon registration. For the stats entity the list is already initialize upon registration. Signed-off-by: Dafna Hirschfeld Acked-by: Helen Koike Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/rkisp1/rkisp1-params.c | 4 +--- drivers/staging/media/rkisp1/rkisp1-stats.c | 4 ---- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/staging/media/rkisp1/rkisp1-params.c b/drivers/staging/media/rkisp1/rkisp1-params.c index cb9f3332a9a0..aa758f8c2264 100644 --- a/drivers/staging/media/rkisp1/rkisp1-params.c +++ b/drivers/staging/media/rkisp1/rkisp1-params.c @@ -1420,8 +1420,6 @@ static int rkisp1_params_vb2_queue_setup(struct vb2_queue *vq, unsigned int sizes[], struct device *alloc_devs[]) { - struct rkisp1_params *params = vq->drv_priv; - *num_buffers = clamp_t(u32, *num_buffers, RKISP1_ISP_PARAMS_REQ_BUFS_MIN, RKISP1_ISP_PARAMS_REQ_BUFS_MAX); @@ -1430,7 +1428,6 @@ static int rkisp1_params_vb2_queue_setup(struct vb2_queue *vq, sizes[0] = sizeof(struct rkisp1_params_cfg); - INIT_LIST_HEAD(¶ms->params); return 0; } @@ -1545,6 +1542,7 @@ int rkisp1_params_register(struct rkisp1_device *rkisp1) params->rkisp1 = rkisp1; mutex_init(&node->vlock); + INIT_LIST_HEAD(¶ms->params); spin_lock_init(¶ms->config_lock); strscpy(vdev->name, RKISP1_PARAMS_DEV_NAME, sizeof(vdev->name)); diff --git a/drivers/staging/media/rkisp1/rkisp1-stats.c b/drivers/staging/media/rkisp1/rkisp1-stats.c index 51c64f75fe29..c58ae52b8a98 100644 --- a/drivers/staging/media/rkisp1/rkisp1-stats.c +++ b/drivers/staging/media/rkisp1/rkisp1-stats.c @@ -94,8 +94,6 @@ static int rkisp1_stats_vb2_queue_setup(struct vb2_queue *vq, unsigned int sizes[], struct device *alloc_devs[]) { - struct rkisp1_stats *stats = vq->drv_priv; - *num_planes = 1; *num_buffers = clamp_t(u32, *num_buffers, RKISP1_ISP_STATS_REQ_BUFS_MIN, @@ -103,8 +101,6 @@ static int rkisp1_stats_vb2_queue_setup(struct vb2_queue *vq, sizes[0] = sizeof(struct rkisp1_stat_buffer); - INIT_LIST_HEAD(&stats->stat); - return 0; } -- cgit v1.2.3 From 3fcd2d42a071f858a9e6050db4f87c13eeded953 Mon Sep 17 00:00:00 2001 From: Dafna Hirschfeld Date: Fri, 2 Oct 2020 20:42:20 +0200 Subject: media: staging: rkisp1: remove the 'is_streaming' field from stats and params The params and stats entities have a field 'is_streaming'. This field is not needed since the entities can have available buffers only if they stream and therefore it is enough to check if there are buffers available. As a result, their start_stream callbacks can be removed since they only set the 'is_streaming' field. Signed-off-by: Dafna Hirschfeld Acked-by: Helen Koike Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/rkisp1/rkisp1-common.h | 12 ++++-------- drivers/staging/media/rkisp1/rkisp1-params.c | 21 +-------------------- drivers/staging/media/rkisp1/rkisp1-stats.c | 17 ----------------- 3 files changed, 5 insertions(+), 45 deletions(-) diff --git a/drivers/staging/media/rkisp1/rkisp1-common.h b/drivers/staging/media/rkisp1/rkisp1-common.h index 45abacdbb664..692333c66f9d 100644 --- a/drivers/staging/media/rkisp1/rkisp1-common.h +++ b/drivers/staging/media/rkisp1/rkisp1-common.h @@ -240,19 +240,17 @@ struct rkisp1_capture { * * @vnode: video node * @rkisp1: pointer to the rkisp1 device - * @lock: locks the buffer list 'stat' and 'is_streaming' + * @lock: locks the buffer list 'stat' * @stat: queue of rkisp1_buffer * @vdev_fmt: v4l2_format of the metadata format - * @is_streaming: device is streaming */ struct rkisp1_stats { struct rkisp1_vdev_node vnode; struct rkisp1_device *rkisp1; - spinlock_t lock; /* locks the buffers list 'stats' and 'is_streaming' */ + spinlock_t lock; /* locks the buffers list 'stats' */ struct list_head stat; struct v4l2_format vdev_fmt; - bool is_streaming; }; /* @@ -260,10 +258,9 @@ struct rkisp1_stats { * * @vnode: video node * @rkisp1: pointer to the rkisp1 device - * @config_lock: locks the buffer list 'params' and 'is_streaming' + * @config_lock: locks the buffer list 'params' * @params: queue of rkisp1_buffer * @vdev_fmt: v4l2_format of the metadata format - * @is_streaming: device is streaming * @quantization: the quantization configured on the isp's src pad * @raw_type: the bayer pattern on the isp video sink pad */ @@ -271,10 +268,9 @@ struct rkisp1_params { struct rkisp1_vdev_node vnode; struct rkisp1_device *rkisp1; - spinlock_t config_lock; /* locks the buffers list 'params' and 'is_streaming' */ + spinlock_t config_lock; /* locks the buffers list 'params' */ struct list_head params; struct v4l2_format vdev_fmt; - bool is_streaming; enum v4l2_quantization quantization; enum rkisp1_fmt_raw_pat_type raw_type; diff --git a/drivers/staging/media/rkisp1/rkisp1-params.c b/drivers/staging/media/rkisp1/rkisp1-params.c index aa758f8c2264..3afbc24ca05e 100644 --- a/drivers/staging/media/rkisp1/rkisp1-params.c +++ b/drivers/staging/media/rkisp1/rkisp1-params.c @@ -1224,10 +1224,6 @@ void rkisp1_params_isr(struct rkisp1_device *rkisp1) struct rkisp1_params *params = &rkisp1->params; spin_lock(¶ms->config_lock); - if (!params->is_streaming) { - spin_unlock(¶ms->config_lock); - return; - } rkisp1_params_apply_params_cfg(params, frame_sequence); spin_unlock(¶ms->config_lock); @@ -1303,8 +1299,7 @@ static void rkisp1_params_config_parameter(struct rkisp1_params *params) spin_lock_irq(¶ms->config_lock); /* apply the first buffer if there is one already */ - if (params->is_streaming) - rkisp1_params_apply_params_cfg(params, 0); + rkisp1_params_apply_params_cfg(params, 0); spin_unlock_irq(¶ms->config_lock); } @@ -1467,7 +1462,6 @@ static void rkisp1_params_vb2_stop_streaming(struct vb2_queue *vq) * without holding the lock */ spin_lock_irq(¶ms->config_lock); - params->is_streaming = false; list_splice_init(¶ms->params, &tmp_list); spin_unlock_irq(¶ms->config_lock); @@ -1475,25 +1469,12 @@ static void rkisp1_params_vb2_stop_streaming(struct vb2_queue *vq) vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); } -static int -rkisp1_params_vb2_start_streaming(struct vb2_queue *queue, unsigned int count) -{ - struct rkisp1_params *params = queue->drv_priv; - - spin_lock_irq(¶ms->config_lock); - params->is_streaming = true; - spin_unlock_irq(¶ms->config_lock); - - return 0; -} - static struct vb2_ops rkisp1_params_vb2_ops = { .queue_setup = rkisp1_params_vb2_queue_setup, .wait_prepare = vb2_ops_wait_prepare, .wait_finish = vb2_ops_wait_finish, .buf_queue = rkisp1_params_vb2_buf_queue, .buf_prepare = rkisp1_params_vb2_buf_prepare, - .start_streaming = rkisp1_params_vb2_start_streaming, .stop_streaming = rkisp1_params_vb2_stop_streaming, }; diff --git a/drivers/staging/media/rkisp1/rkisp1-stats.c b/drivers/staging/media/rkisp1/rkisp1-stats.c index c58ae52b8a98..3ddab8fa8f2d 100644 --- a/drivers/staging/media/rkisp1/rkisp1-stats.c +++ b/drivers/staging/media/rkisp1/rkisp1-stats.c @@ -136,7 +136,6 @@ static void rkisp1_stats_vb2_stop_streaming(struct vb2_queue *vq) unsigned int i; spin_lock_irq(&stats->lock); - stats->is_streaming = false; for (i = 0; i < RKISP1_ISP_STATS_REQ_BUFS_MAX; i++) { if (list_empty(&stats->stat)) break; @@ -148,18 +147,6 @@ static void rkisp1_stats_vb2_stop_streaming(struct vb2_queue *vq) spin_unlock_irq(&stats->lock); } -static int -rkisp1_stats_vb2_start_streaming(struct vb2_queue *queue, unsigned int count) -{ - struct rkisp1_stats *stats = queue->drv_priv; - - spin_lock_irq(&stats->lock); - stats->is_streaming = true; - spin_unlock_irq(&stats->lock); - - return 0; -} - static const struct vb2_ops rkisp1_stats_vb2_ops = { .queue_setup = rkisp1_stats_vb2_queue_setup, .buf_queue = rkisp1_stats_vb2_buf_queue, @@ -167,7 +154,6 @@ static const struct vb2_ops rkisp1_stats_vb2_ops = { .wait_prepare = vb2_ops_wait_prepare, .wait_finish = vb2_ops_wait_finish, .stop_streaming = rkisp1_stats_vb2_stop_streaming, - .start_streaming = rkisp1_stats_vb2_start_streaming, }; static int @@ -355,12 +341,9 @@ void rkisp1_stats_isr(struct rkisp1_stats *stats, u32 isp_ris) if (isp_mis_tmp & RKISP1_STATS_MEAS_MASK) rkisp1->debug.stats_error++; - if (!stats->is_streaming) - goto unlock; if (isp_ris & RKISP1_STATS_MEAS_MASK) rkisp1_stats_send_measurement(stats, isp_ris); -unlock: spin_unlock(&stats->lock); } -- cgit v1.2.3 From cdda99d70d73d08ef7a9bcac0a5a347fba8442b0 Mon Sep 17 00:00:00 2001 From: Dafna Hirschfeld Date: Mon, 19 Oct 2020 22:59:54 +0200 Subject: media: staging: rkisp1: params: remove unnecessary "!!" There are several 'if' conditions of the form: if (!!(module_ens & SOME_FLAG)) Those can be replaced with: if (module_ens & SOME_FLAG) Signed-off-by: Dafna Hirschfeld Acked-by: Helen Koike Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/rkisp1/rkisp1-params.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/staging/media/rkisp1/rkisp1-params.c b/drivers/staging/media/rkisp1/rkisp1-params.c index 3afbc24ca05e..5d7ec9a136f1 100644 --- a/drivers/staging/media/rkisp1/rkisp1-params.c +++ b/drivers/staging/media/rkisp1/rkisp1-params.c @@ -896,7 +896,7 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, &new_params->others.dpcc_config); if (module_en_update & RKISP1_CIF_ISP_MODULE_DPCC) { - if (!!(module_ens & RKISP1_CIF_ISP_MODULE_DPCC)) + if (module_ens & RKISP1_CIF_ISP_MODULE_DPCC) rkisp1_param_set_bits(params, RKISP1_CIF_ISP_DPCC_MODE, RKISP1_CIF_ISP_DPCC_ENA); @@ -915,7 +915,7 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, &new_params->others.bls_config); if (module_en_update & RKISP1_CIF_ISP_MODULE_BLS) { - if (!!(module_ens & RKISP1_CIF_ISP_MODULE_BLS)) + if (module_ens & RKISP1_CIF_ISP_MODULE_BLS) rkisp1_param_set_bits(params, RKISP1_CIF_ISP_BLS_CTRL, RKISP1_CIF_ISP_BLS_ENA); @@ -934,7 +934,7 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, &new_params->others.sdg_config); if (module_en_update & RKISP1_CIF_ISP_MODULE_SDG) { - if (!!(module_ens & RKISP1_CIF_ISP_MODULE_SDG)) + if (module_ens & RKISP1_CIF_ISP_MODULE_SDG) rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_GAMMA_IN_ENA); @@ -953,7 +953,7 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, &new_params->others.lsc_config); if (module_en_update & RKISP1_CIF_ISP_MODULE_LSC) { - if (!!(module_ens & RKISP1_CIF_ISP_MODULE_LSC)) + if (module_ens & RKISP1_CIF_ISP_MODULE_LSC) rkisp1_param_set_bits(params, RKISP1_CIF_ISP_LSC_CTRL, RKISP1_CIF_ISP_LSC_CTRL_ENA); @@ -972,7 +972,7 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, &new_params->others.awb_gain_config); if (module_en_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN) { - if (!!(module_ens & RKISP1_CIF_ISP_MODULE_AWB_GAIN)) + if (module_ens & RKISP1_CIF_ISP_MODULE_AWB_GAIN) rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); @@ -991,7 +991,7 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, &new_params->others.bdm_config); if (module_en_update & RKISP1_CIF_ISP_MODULE_BDM) { - if (!!(module_ens & RKISP1_CIF_ISP_MODULE_BDM)) + if (module_ens & RKISP1_CIF_ISP_MODULE_BDM) rkisp1_param_set_bits(params, RKISP1_CIF_ISP_DEMOSAIC, RKISP1_CIF_ISP_DEMOSAIC_BYPASS); @@ -1010,7 +1010,7 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, &new_params->others.flt_config); if (module_en_update & RKISP1_CIF_ISP_MODULE_FLT) { - if (!!(module_ens & RKISP1_CIF_ISP_MODULE_FLT)) + if (module_ens & RKISP1_CIF_ISP_MODULE_FLT) rkisp1_param_set_bits(params, RKISP1_CIF_ISP_FILT_MODE, RKISP1_CIF_ISP_FLT_ENA); @@ -1041,7 +1041,7 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, &new_params->others.goc_config); if (module_en_update & RKISP1_CIF_ISP_MODULE_GOC) { - if (!!(module_ens & RKISP1_CIF_ISP_MODULE_GOC)) + if (module_ens & RKISP1_CIF_ISP_MODULE_GOC) rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); @@ -1061,7 +1061,7 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, } if (module_en_update & RKISP1_CIF_ISP_MODULE_CPROC) { - if (!!(module_ens & RKISP1_CIF_ISP_MODULE_CPROC)) + if (module_ens & RKISP1_CIF_ISP_MODULE_CPROC) rkisp1_param_set_bits(params, RKISP1_CIF_C_PROC_CTRL, RKISP1_CIF_C_PROC_CTR_ENABLE); @@ -1092,7 +1092,7 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, &new_params->others.dpf_config); if (module_en_update & RKISP1_CIF_ISP_MODULE_DPF) { - if (!!(module_ens & RKISP1_CIF_ISP_MODULE_DPF)) + if (module_ens & RKISP1_CIF_ISP_MODULE_DPF) rkisp1_param_set_bits(params, RKISP1_CIF_ISP_DPF_MODE, RKISP1_CIF_ISP_DPF_MODE_EN); @@ -1141,7 +1141,7 @@ static void rkisp1_isp_isr_meas_config(struct rkisp1_params *params, &new_params->meas.afc_config); if (module_en_update & RKISP1_CIF_ISP_MODULE_AFC) { - if (!!(module_ens & RKISP1_CIF_ISP_MODULE_AFC)) + if (module_ens & RKISP1_CIF_ISP_MODULE_AFC) rkisp1_param_set_bits(params, RKISP1_CIF_ISP_AFM_CTRL, RKISP1_CIF_ISP_AFM_ENA); @@ -1173,7 +1173,7 @@ static void rkisp1_isp_isr_meas_config(struct rkisp1_params *params, &new_params->meas.aec_config); if (module_en_update & RKISP1_CIF_ISP_MODULE_AEC) { - if (!!(module_ens & RKISP1_CIF_ISP_MODULE_AEC)) + if (module_ens & RKISP1_CIF_ISP_MODULE_AEC) rkisp1_param_set_bits(params, RKISP1_CIF_ISP_EXP_CTRL, RKISP1_CIF_ISP_EXP_ENA); -- cgit v1.2.3 From db1733ce23bd375d760466cec7e159a491ed2153 Mon Sep 17 00:00:00 2001 From: Dafna Hirschfeld Date: Mon, 19 Oct 2020 22:59:55 +0200 Subject: media: staging: rkisp1: params: remove unnecessary parentheses There are several 'if' expression where double parentheses is used when one is enough. Remove the extra parentheses. Signed-off-by: Dafna Hirschfeld Acked-by: Helen Koike Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/rkisp1/rkisp1-params.c | 32 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/staging/media/rkisp1/rkisp1-params.c b/drivers/staging/media/rkisp1/rkisp1-params.c index 5d7ec9a136f1..298c16736b1c 100644 --- a/drivers/staging/media/rkisp1/rkisp1-params.c +++ b/drivers/staging/media/rkisp1/rkisp1-params.c @@ -891,7 +891,7 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, if ((module_en_update & RKISP1_CIF_ISP_MODULE_DPCC) || (module_cfg_update & RKISP1_CIF_ISP_MODULE_DPCC)) { /*update dpc config */ - if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_DPCC)) + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_DPCC) rkisp1_dpcc_config(params, &new_params->others.dpcc_config); @@ -910,7 +910,7 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, if ((module_en_update & RKISP1_CIF_ISP_MODULE_BLS) || (module_cfg_update & RKISP1_CIF_ISP_MODULE_BLS)) { /* update bls config */ - if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_BLS)) + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_BLS) rkisp1_bls_config(params, &new_params->others.bls_config); @@ -929,7 +929,7 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, if ((module_en_update & RKISP1_CIF_ISP_MODULE_SDG) || (module_cfg_update & RKISP1_CIF_ISP_MODULE_SDG)) { /* update sdg config */ - if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_SDG)) + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_SDG) rkisp1_sdg_config(params, &new_params->others.sdg_config); @@ -948,7 +948,7 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, if ((module_en_update & RKISP1_CIF_ISP_MODULE_LSC) || (module_cfg_update & RKISP1_CIF_ISP_MODULE_LSC)) { /* update lsc config */ - if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_LSC)) + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_LSC) rkisp1_lsc_config(params, &new_params->others.lsc_config); @@ -967,7 +967,7 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, if ((module_en_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN) || (module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN)) { /* update awb gains */ - if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN)) + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN) rkisp1_awb_gain_config(params, &new_params->others.awb_gain_config); @@ -986,7 +986,7 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, if ((module_en_update & RKISP1_CIF_ISP_MODULE_BDM) || (module_cfg_update & RKISP1_CIF_ISP_MODULE_BDM)) { /* update bdm config */ - if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_BDM)) + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_BDM) rkisp1_bdm_config(params, &new_params->others.bdm_config); @@ -1005,7 +1005,7 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, if ((module_en_update & RKISP1_CIF_ISP_MODULE_FLT) || (module_cfg_update & RKISP1_CIF_ISP_MODULE_FLT)) { /* update filter config */ - if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_FLT)) + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_FLT) rkisp1_flt_config(params, &new_params->others.flt_config); @@ -1024,7 +1024,7 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, if ((module_en_update & RKISP1_CIF_ISP_MODULE_CTK) || (module_cfg_update & RKISP1_CIF_ISP_MODULE_CTK)) { /* update ctk config */ - if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_CTK)) + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_CTK) rkisp1_ctk_config(params, &new_params->others.ctk_config); @@ -1036,7 +1036,7 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, if ((module_en_update & RKISP1_CIF_ISP_MODULE_GOC) || (module_cfg_update & RKISP1_CIF_ISP_MODULE_GOC)) { /* update goc config */ - if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_GOC)) + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_GOC) rkisp1_goc_config(params, &new_params->others.goc_config); @@ -1055,7 +1055,7 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, if ((module_en_update & RKISP1_CIF_ISP_MODULE_CPROC) || (module_cfg_update & RKISP1_CIF_ISP_MODULE_CPROC)) { /* update cproc config */ - if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_CPROC)) { + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_CPROC) { rkisp1_cproc_config(params, &new_params->others.cproc_config); } @@ -1075,7 +1075,7 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, if ((module_en_update & RKISP1_CIF_ISP_MODULE_IE) || (module_cfg_update & RKISP1_CIF_ISP_MODULE_IE)) { /* update ie config */ - if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_IE)) + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_IE) rkisp1_ie_config(params, &new_params->others.ie_config); @@ -1087,7 +1087,7 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, if ((module_en_update & RKISP1_CIF_ISP_MODULE_DPF) || (module_cfg_update & RKISP1_CIF_ISP_MODULE_DPF)) { /* update dpf config */ - if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_DPF)) + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_DPF) rkisp1_dpf_config(params, &new_params->others.dpf_config); @@ -1123,7 +1123,7 @@ static void rkisp1_isp_isr_meas_config(struct rkisp1_params *params, if ((module_en_update & RKISP1_CIF_ISP_MODULE_AWB) || (module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB)) { /* update awb config */ - if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB)) + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB) rkisp1_awb_meas_config(params, &new_params->meas.awb_meas_config); @@ -1136,7 +1136,7 @@ static void rkisp1_isp_isr_meas_config(struct rkisp1_params *params, if ((module_en_update & RKISP1_CIF_ISP_MODULE_AFC) || (module_cfg_update & RKISP1_CIF_ISP_MODULE_AFC)) { /* update afc config */ - if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_AFC)) + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AFC) rkisp1_afm_config(params, &new_params->meas.afc_config); @@ -1155,7 +1155,7 @@ static void rkisp1_isp_isr_meas_config(struct rkisp1_params *params, if ((module_en_update & RKISP1_CIF_ISP_MODULE_HST) || (module_cfg_update & RKISP1_CIF_ISP_MODULE_HST)) { /* update hst config */ - if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_HST)) + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_HST) rkisp1_hst_config(params, &new_params->meas.hst_config); @@ -1168,7 +1168,7 @@ static void rkisp1_isp_isr_meas_config(struct rkisp1_params *params, if ((module_en_update & RKISP1_CIF_ISP_MODULE_AEC) || (module_cfg_update & RKISP1_CIF_ISP_MODULE_AEC)) { /* update aec config */ - if ((module_cfg_update & RKISP1_CIF_ISP_MODULE_AEC)) + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AEC) rkisp1_aec_config(params, &new_params->meas.aec_config); -- cgit v1.2.3 From d6a032ab1cf92dab67486c0f4a55375aa2799729 Mon Sep 17 00:00:00 2001 From: Dafna Hirschfeld Date: Tue, 20 Oct 2020 15:25:14 +0200 Subject: media: staging: rkisp1: uapi: add "WITH Linux-syscall-note" Add "WITH Linux-syscall-note" to the uapi header SPDX comment. Signed-off-by: Dafna Hirschfeld Acked-by: Helen Koike Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/rkisp1/uapi/rkisp1-config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/rkisp1/uapi/rkisp1-config.h b/drivers/staging/media/rkisp1/uapi/rkisp1-config.h index 432cb6be55b4..8d906cc7da8f 100644 --- a/drivers/staging/media/rkisp1/uapi/rkisp1-config.h +++ b/drivers/staging/media/rkisp1/uapi/rkisp1-config.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ +/* SPDX-License-Identifier: ((GPL-2.0+ WITH Linux-syscall-note) OR MIT) */ /* * Rockchip ISP1 userspace API * Copyright (C) 2017 Rockchip Electronics Co., Ltd. -- cgit v1.2.3 From f4aefc581af4286ff3bfaea44084c5e5d9aa57c8 Mon Sep 17 00:00:00 2001 From: Dafna Hirschfeld Date: Mon, 26 Oct 2020 17:28:48 +0100 Subject: media: staging: rkisp1: capture: set default quantization on 'set_fmt' On 's/try_fmt' ioctl, set the quantization field to V4L2_QUANTIZATION_DEFAULT. This fixes the compliance errors: fail: v4l2-test-formats.cpp(357): quantization >= 0xff fail: v4l2-test-formats.cpp(473): testColorspace(!node->is_io_mc, pix_mp.pixelformat, pix_mp.colorspace, pix_mp.ycbcr_enc, pix_mp.quantization) test VIDIOC_TRY_FMT: FAIL fail: v4l2-test-formats.cpp(357): quantization >= 0xff fail: v4l2-test-formats.cpp(473): testColorspace(!node->is_io_mc, pix_mp.pixelformat, pix_mp.colorspace, pix_mp.ycbcr_enc, pix_mp.quantization) test VIDIOC_S_FMT: FAIL Signed-off-by: Dafna Hirschfeld Acked-by: Helen Koike Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/rkisp1/rkisp1-capture.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/media/rkisp1/rkisp1-capture.c b/drivers/staging/media/rkisp1/rkisp1-capture.c index 9b4a12e13f13..1c0f79284162 100644 --- a/drivers/staging/media/rkisp1/rkisp1-capture.c +++ b/drivers/staging/media/rkisp1/rkisp1-capture.c @@ -1133,6 +1133,7 @@ static void rkisp1_try_fmt(const struct rkisp1_capture *cap, pixm->field = V4L2_FIELD_NONE; pixm->colorspace = V4L2_COLORSPACE_DEFAULT; pixm->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + pixm->quantization = V4L2_QUANTIZATION_DEFAULT; info = rkisp1_fill_pixfmt(pixm, cap->id); -- cgit v1.2.3 From d51b5d9a277b8555346829d3783ab73d8ad90ada Mon Sep 17 00:00:00 2001 From: Helen Koike Date: Mon, 19 Oct 2020 18:04:34 +0200 Subject: media: staging: rkisp1: cap: refactor enable/disable stream to allow multistreaming Allow streaming from self picture path and main picture path at the same time. Take care for s_stream() callbacks to not be called twice. When starting a stream, s_stream(true) shouldn't be called for the isp and the sensor if the other stream is already enabled (since it was already called). When stopping a stream, s_stream(false) shouldn't be called for isp and the sensor if the other stream is still enabled. Remove the callback function scheme for navigating through the topology, simplifying the code, improving readability. Remove multistreaming item from the TODO list. Signed-off-by: Helen Koike Reviewed-by: Dafna Hirschfeld Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/rkisp1/TODO | 3 - drivers/staging/media/rkisp1/rkisp1-capture.c | 219 +++++++++++++------------- 2 files changed, 110 insertions(+), 112 deletions(-) diff --git a/drivers/staging/media/rkisp1/TODO b/drivers/staging/media/rkisp1/TODO index d9360607fbfb..75aae98242d0 100644 --- a/drivers/staging/media/rkisp1/TODO +++ b/drivers/staging/media/rkisp1/TODO @@ -1,8 +1,5 @@ * Fix pad format size for statistics and parameters entities. * Fix checkpatch errors. -* streaming paths (mainpath and selfpath) check if the other path is streaming -in several places of the code, review this, specially that it doesn't seem it -supports streaming from both paths at the same time. NOTES: * All v4l2-compliance test must pass. diff --git a/drivers/staging/media/rkisp1/rkisp1-capture.c b/drivers/staging/media/rkisp1/rkisp1-capture.c index 1c0f79284162..a7a013204177 100644 --- a/drivers/staging/media/rkisp1/rkisp1-capture.c +++ b/drivers/staging/media/rkisp1/rkisp1-capture.c @@ -830,71 +830,43 @@ static void rkisp1_return_all_buffers(struct rkisp1_capture *cap, } /* - * rkisp1_pipeline_sink_walk - Walk through the pipeline and call cb - * @from: entity at which to start pipeline walk - * @until: entity at which to stop pipeline walk - * - * Walk the entities chain starting at the pipeline video node and stop - * all subdevices in the chain. - * - * If the until argument isn't NULL, stop the pipeline walk when reaching the - * until entity. This is used to disable a partially started pipeline due to a - * subdev start error. + * Most of registers inside rockchip ISP1 have shadow register since + * they must be not be changed during processing a frame. + * Usually, each sub-module updates its shadow register after + * processing the last pixel of a frame. */ -static int rkisp1_pipeline_sink_walk(struct media_entity *from, - struct media_entity *until, - int (*cb)(struct media_entity *from, - struct media_entity *curr)) +static void rkisp1_cap_stream_enable(struct rkisp1_capture *cap) { - struct media_entity *entity = from; - struct media_pad *pad; - unsigned int i; - int ret; - - while (1) { - pad = NULL; - /* Find remote source pad */ - for (i = 0; i < entity->num_pads; i++) { - struct media_pad *spad = &entity->pads[i]; - - if (!(spad->flags & MEDIA_PAD_FL_SINK)) - continue; - pad = media_entity_remote_pad(spad); - if (pad && is_media_entity_v4l2_subdev(pad->entity)) - break; - } - if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) - break; + struct rkisp1_device *rkisp1 = cap->rkisp1; + struct rkisp1_capture *other = &rkisp1->capture_devs[cap->id ^ 1]; - entity = pad->entity; - if (entity == until) - break; + cap->ops->set_data_path(cap); + cap->ops->config(cap); - ret = cb(from, entity); - if (ret) - return ret; + /* Setup a buffer for the next frame */ + spin_lock_irq(&cap->buf.lock); + rkisp1_set_next_buf(cap); + cap->ops->enable(cap); + /* It's safe to config ACTIVE and SHADOW regs for the + * first stream. While when the second is starting, do NOT + * force update because it also update the first one. + * + * The latter case would drop one more buf(that is 2) since + * there's not buf in shadow when the second FE received. This's + * also required because the second FE maybe corrupt especially + * when run at 120fps. + */ + if (!other->is_streaming) { + /* force cfg update */ + rkisp1_write(rkisp1, + RKISP1_CIF_MI_INIT_SOFT_UPD, RKISP1_CIF_MI_INIT); + rkisp1_set_next_buf(cap); } - - return 0; -} - -static int rkisp1_pipeline_disable_cb(struct media_entity *from, - struct media_entity *curr) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(curr); - - return v4l2_subdev_call(sd, video, s_stream, false); -} - -static int rkisp1_pipeline_enable_cb(struct media_entity *from, - struct media_entity *curr) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(curr); - - return v4l2_subdev_call(sd, video, s_stream, true); + spin_unlock_irq(&cap->buf.lock); + cap->is_streaming = true; } -static void rkisp1_stream_stop(struct rkisp1_capture *cap) +static void rkisp1_cap_stream_disable(struct rkisp1_capture *cap) { int ret; @@ -911,6 +883,82 @@ static void rkisp1_stream_stop(struct rkisp1_capture *cap) } } +/* + * rkisp1_pipeline_stream_disable - disable nodes in the pipeline + * + * Call s_stream(false) in the reverse order from + * rkisp1_pipeline_stream_enable() and disable the DMA engine. + * Should be called before media_pipeline_stop() + */ +static void rkisp1_pipeline_stream_disable(struct rkisp1_capture *cap) + __must_hold(&cap->rkisp1->stream_lock) +{ + struct rkisp1_device *rkisp1 = cap->rkisp1; + + /* + * If the other capture is streaming, isp and sensor nodes shouldn't + * be disabled, skip them. + */ + if (rkisp1->pipe.streaming_count < 2) { + v4l2_subdev_call(rkisp1->active_sensor->sd, video, s_stream, + false); + v4l2_subdev_call(&rkisp1->isp.sd, video, s_stream, false); + } + + v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video, s_stream, + false); + + rkisp1_cap_stream_disable(cap); +} + +/* + * rkisp1_pipeline_stream_enable - enable nodes in the pipeline + * + * Enable the DMA Engine and call s_stream(true) through the pipeline. + * Should be called after media_pipeline_start() + */ +static int rkisp1_pipeline_stream_enable(struct rkisp1_capture *cap) + __must_hold(&cap->rkisp1->stream_lock) +{ + struct rkisp1_device *rkisp1 = cap->rkisp1; + int ret; + + rkisp1_cap_stream_enable(cap); + + ret = v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video, + s_stream, true); + if (ret) + goto err_disable_cap; + + /* + * If the other capture is streaming, isp and sensor nodes are already + * enabled, skip them. + */ + if (rkisp1->pipe.streaming_count > 1) + return 0; + + ret = v4l2_subdev_call(&rkisp1->isp.sd, video, s_stream, true); + if (ret) + goto err_disable_rsz; + + ret = v4l2_subdev_call(rkisp1->active_sensor->sd, video, s_stream, + true); + if (ret) + goto err_disable_isp; + + return 0; + +err_disable_isp: + v4l2_subdev_call(&rkisp1->isp.sd, video, s_stream, false); +err_disable_rsz: + v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video, s_stream, + false); +err_disable_cap: + rkisp1_cap_stream_disable(cap); + + return ret; +} + static void rkisp1_vb2_stop_streaming(struct vb2_queue *queue) { struct rkisp1_capture *cap = queue->drv_priv; @@ -920,12 +968,7 @@ static void rkisp1_vb2_stop_streaming(struct vb2_queue *queue) mutex_lock(&cap->rkisp1->stream_lock); - rkisp1_stream_stop(cap); - ret = rkisp1_pipeline_sink_walk(&node->vdev.entity, NULL, - rkisp1_pipeline_disable_cb); - if (ret) - dev_err(rkisp1->dev, - "pipeline stream-off failed error:%d\n", ret); + rkisp1_pipeline_stream_disable(cap); rkisp1_return_all_buffers(cap, VB2_BUF_STATE_ERROR); @@ -941,43 +984,6 @@ static void rkisp1_vb2_stop_streaming(struct vb2_queue *queue) mutex_unlock(&cap->rkisp1->stream_lock); } -/* - * Most of registers inside rockchip ISP1 have shadow register since - * they must be not be changed during processing a frame. - * Usually, each sub-module updates its shadow register after - * processing the last pixel of a frame. - */ -static void rkisp1_stream_start(struct rkisp1_capture *cap) -{ - struct rkisp1_device *rkisp1 = cap->rkisp1; - struct rkisp1_capture *other = &rkisp1->capture_devs[cap->id ^ 1]; - - cap->ops->set_data_path(cap); - cap->ops->config(cap); - - /* Setup a buffer for the next frame */ - spin_lock_irq(&cap->buf.lock); - rkisp1_set_next_buf(cap); - cap->ops->enable(cap); - /* It's safe to config ACTIVE and SHADOW regs for the - * first stream. While when the second is starting, do NOT - * force update because it also update the first one. - * - * The latter case would drop one more buf(that is 2) since - * there's not buf in shadow when the second FE received. This's - * also required because the second FE maybe corrupt especially - * when run at 120fps. - */ - if (!other->is_streaming) { - /* force cfg update */ - rkisp1_write(rkisp1, - RKISP1_CIF_MI_INIT_SOFT_UPD, RKISP1_CIF_MI_INIT); - rkisp1_set_next_buf(cap); - } - spin_unlock_irq(&cap->buf.lock); - cap->is_streaming = true; -} - static int rkisp1_vb2_start_streaming(struct vb2_queue *queue, unsigned int count) { @@ -1008,20 +1014,15 @@ rkisp1_vb2_start_streaming(struct vb2_queue *queue, unsigned int count) goto err_pipe_pm_put; } - rkisp1_stream_start(cap); - - /* start sub-devices */ - ret = rkisp1_pipeline_sink_walk(entity, NULL, - rkisp1_pipeline_enable_cb); + ret = rkisp1_pipeline_stream_enable(cap); if (ret) - goto err_stop_stream; + goto err_v4l2_pm_put; mutex_unlock(&cap->rkisp1->stream_lock); return 0; -err_stop_stream: - rkisp1_stream_stop(cap); +err_v4l2_pm_put: v4l2_pipeline_pm_put(entity); err_pipe_pm_put: pm_runtime_put(cap->rkisp1->dev); -- cgit v1.2.3 From 185ca93444b31b2e9a39ffd2332b63172f191e2b Mon Sep 17 00:00:00 2001 From: Helen Koike Date: Tue, 20 Oct 2020 21:38:42 +0200 Subject: media: staging: dt-bindings: rkisp1: add missing required nodes Add missing required nodes in json-schema yaml file for Rockchip ISP1 dt-bindings. Signed-off-by: Helen Koike Acked-by: Rob Herring Reviewed-by: Tomasz Figa Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../Documentation/devicetree/bindings/media/rockchip-isp1.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml b/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml index af246b71eac6..a77b6ec500c9 100644 --- a/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml +++ b/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml @@ -94,11 +94,19 @@ properties: remote-endpoint: true + required: + - reg + - "#address-cells" + - "#size-cells" + required: + - "#address-cells" + - "#size-cells" - port@0 required: - compatible + - reg - interrupts - clocks - clock-names -- cgit v1.2.3 From d55575f8f757f62174a3ab5dc55df699cb7a752b Mon Sep 17 00:00:00 2001 From: Helen Koike Date: Tue, 20 Oct 2020 21:38:43 +0200 Subject: media: staging: dt-bindings: rkisp1: drop i2c unit address Add missing required items in Rockchip ISP1 dt-bindings example for a complete i2c node. Drop unit address to Fix error: /example-0/parent/i2c@ff160000: node has a unit name, but no reg or ranges property Remove unecessary fields for the example. Signed-off-by: Helen Koike Acked-by: Rob Herring Reviewed-by: Tomasz Figa Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml b/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml index a77b6ec500c9..4c31cfaee270 100644 --- a/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml +++ b/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml @@ -168,8 +168,7 @@ examples: }; }; - i2c7: i2c@ff160000 { - clock-frequency = <400000>; + i2c7: i2c { #address-cells = <1>; #size-cells = <0>; -- cgit v1.2.3 From a493baf1c44ab3428518b1567f85d65faec1fe16 Mon Sep 17 00:00:00 2001 From: Helen Koike Date: Tue, 20 Oct 2020 21:38:44 +0200 Subject: media: staging: dt-bindings: rkisp1: re-order properties Organize properties order in dt-bindings to move it out of staging. On top: compatible, reg and interrupts. Then alphabetical order, then properties starting with '#'. Signed-off-by: Helen Koike Acked-by: Rob Herring Reviewed-by: Tomasz Figa Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/rockchip-isp1.yaml | 32 +++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml b/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml index 4c31cfaee270..79ebacab83cf 100644 --- a/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml +++ b/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml @@ -23,19 +23,6 @@ properties: interrupts: maxItems: 1 - iommus: - maxItems: 1 - - power-domains: - maxItems: 1 - - phys: - maxItems: 1 - description: phandle for the PHY port - - phy-names: - const: dphy - clocks: items: - description: ISP clock @@ -52,6 +39,19 @@ properties: - const: hclk_isp - const: hclk_isp_wrap + iommus: + maxItems: 1 + + phys: + maxItems: 1 + description: phandle for the PHY port + + phy-names: + const: dphy + + power-domains: + maxItems: 1 + # See ./video-interfaces.txt for details ports: type: object @@ -110,10 +110,10 @@ required: - interrupts - clocks - clock-names - - power-domains - iommus - phys - phy-names + - power-domains - ports additionalProperties: false @@ -139,19 +139,19 @@ examples: clock-names = "clk_isp", "aclk_isp", "aclk_isp_wrap", "hclk_isp", "hclk_isp_wrap"; - power-domains = <&power RK3399_PD_ISP0>; iommus = <&isp0_mmu>; phys = <&dphy>; phy-names = "dphy"; + power-domains = <&power RK3399_PD_ISP0>; ports { #address-cells = <1>; #size-cells = <0>; port@0 { + reg = <0>; #address-cells = <1>; #size-cells = <0>; - reg = <0>; mipi_in_wcam: endpoint@0 { reg = <0>; -- cgit v1.2.3 From 4b69709aa0a26972e56d497bc16e9b2e424b3a01 Mon Sep 17 00:00:00 2001 From: Helen Koike Date: Tue, 20 Oct 2020 21:38:45 +0200 Subject: media: staging: dt-bindings: rkisp1: drop parent unit address Fix the following error found with make ARCH=arm64 dt_binding_check: Documentation/devicetree/bindings/media/rockchip-isp1.example.dts:24.27-101.11: Warning (unit_address_vs_reg): /example-0/parent@0: node has a unit name, but no reg or ranges property Reported-by: Johan Jonker Signed-off-by: Helen Koike Acked-by: Rob Herring Reviewed-by: Tomasz Figa Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml b/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml index 79ebacab83cf..62a6b9c95949 100644 --- a/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml +++ b/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml @@ -125,7 +125,7 @@ examples: #include #include - parent0: parent@0 { + parent0: parent { #address-cells = <2>; #size-cells = <2>; -- cgit v1.2.3 From 099d801bcd1e493b4de71e488c94e2dd0451eaa4 Mon Sep 17 00:00:00 2001 From: Helen Koike Date: Tue, 20 Oct 2020 21:38:46 +0200 Subject: media: staging: rkisp1: remove unecessary clocks aclk_isp_wrap is a child of aclk_isp, and hclk_isp_wrap is a child of hclk_isp, thus we can remove parents from the list. Also, for the isp0, we only need the ISP clock, ACLK and HCLK. In the future we'll need a pixel clock for RK3288 and RK3399, and a JPEG clock for RK3288. So with the goal to cleanup the dt-bindings and remove it from staging, simplify clock names to isp, aclk and hclk. Assigned clocks are meant to refer to the full path in the clock tree, i.e. the leaf in the tree. For instance, in RK3399, the clock responsible for ACLK (ISP AXI CLOCK) is aclk_isp0_wrapper. For reference, this is the isp clock topology on RK3399: xin24m pll_npll npll clk_isp1 clk_isp0 pll_cpll cpll aclk_isp1 aclk_isp1_noc hclk_isp1 aclk_isp1_wrapper hclk_isp1_noc aclk_isp0 hclk_isp1_wrapper aclk_isp0_wrapper aclk_isp0_noc hclk_isp0 hclk_isp0_wrapper hclk_isp0_noc pclkin_isp1_wrapper Signed-off-by: Helen Koike Reviewed-by: Tomasz Figa Reviewed-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/rockchip-isp1.yaml | 44 +++++++++++++++------- drivers/staging/media/rkisp1/rkisp1-dev.c | 8 ++-- 2 files changed, 33 insertions(+), 19 deletions(-) diff --git a/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml b/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml index 62a6b9c95949..2004c054ed1a 100644 --- a/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml +++ b/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml @@ -24,20 +24,24 @@ properties: maxItems: 1 clocks: + minItems: 3 items: + # isp0 and isp1 - description: ISP clock - - description: ISP AXI clock clock - - description: ISP AXI clock wrapper clock - - description: ISP AHB clock clock - - description: ISP AHB wrapper clock + - description: ISP AXI clock + - description: ISP AHB clock + # only for isp1 + - description: ISP Pixel clock clock-names: + minItems: 3 items: - - const: clk_isp - - const: aclk_isp - - const: aclk_isp_wrap - - const: hclk_isp - - const: hclk_isp_wrap + # isp0 and isp1 + - const: isp + - const: aclk + - const: hclk + # only for isp1 + - const: pclk_isp iommus: maxItems: 1 @@ -116,6 +120,20 @@ required: - power-domains - ports +if: + properties: + compatible: + contains: + const: rockchip,rk3399-cif-isp +then: + properties: + clocks: + minItems: 3 + maxItems: 4 + clock-names: + minItems: 3 + maxItems: 4 + additionalProperties: false examples: @@ -134,11 +152,9 @@ examples: reg = <0x0 0xff910000 0x0 0x4000>; interrupts = ; clocks = <&cru SCLK_ISP0>, - <&cru ACLK_ISP0>, <&cru ACLK_ISP0_WRAPPER>, - <&cru HCLK_ISP0>, <&cru HCLK_ISP0_WRAPPER>; - clock-names = "clk_isp", - "aclk_isp", "aclk_isp_wrap", - "hclk_isp", "hclk_isp_wrap"; + <&cru ACLK_ISP0_WRAPPER>, + <&cru HCLK_ISP0_WRAPPER>; + clock-names = "isp", "aclk", "hclk"; iommus = <&isp0_mmu>; phys = <&dphy>; phy-names = "dphy"; diff --git a/drivers/staging/media/rkisp1/rkisp1-dev.c b/drivers/staging/media/rkisp1/rkisp1-dev.c index 91584695804b..90d654346556 100644 --- a/drivers/staging/media/rkisp1/rkisp1-dev.c +++ b/drivers/staging/media/rkisp1/rkisp1-dev.c @@ -405,11 +405,9 @@ static irqreturn_t rkisp1_isr(int irq, void *ctx) } static const char * const rk3399_isp_clks[] = { - "clk_isp", - "aclk_isp", - "hclk_isp", - "aclk_isp_wrap", - "hclk_isp_wrap", + "isp", + "aclk", + "hclk", }; static const struct rkisp1_match_data rk3399_isp_clk_data = { -- cgit v1.2.3 From 121ca877c1e870a6580a3bcb53de79e1a678f5f8 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 9 Sep 2020 16:24:07 +0200 Subject: media: rkvdec: Remove redundant platform_get_irq error message platform_get_irq() will call dev_err() itself on failure, so there is no need for the driver to also do this. This is detected by coccinelle. Signed-off-by: YueHaibing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/rkvdec/rkvdec.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c index d25c4a37e2af..552e0bd12ecf 100644 --- a/drivers/staging/media/rkvdec/rkvdec.c +++ b/drivers/staging/media/rkvdec/rkvdec.c @@ -1038,10 +1038,8 @@ static int rkvdec_probe(struct platform_device *pdev) vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); irq = platform_get_irq(pdev, 0); - if (irq <= 0) { - dev_err(&pdev->dev, "Could not get vdec IRQ\n"); + if (irq <= 0) return -ENXIO; - } ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, rkvdec_irq_handler, IRQF_ONESHOT, -- cgit v1.2.3 From 1671d4ea7794495ad52599932f8821e81530dace Mon Sep 17 00:00:00 2001 From: Liu Shixin Date: Wed, 16 Sep 2020 04:50:24 +0200 Subject: media: saa7164: convert to use DEFINE_SEQ_ATTRIBUTE macro Use DEFINE_SEQ_ATTRIBUTE macro to simplify the code. Signed-off-by: Liu Shixin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7164/saa7164-core.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c index 6c08b77bfd47..f3a4e575a782 100644 --- a/drivers/media/pci/saa7164/saa7164-core.c +++ b/drivers/media/pci/saa7164/saa7164-core.c @@ -1139,32 +1139,21 @@ static int saa7164_seq_show(struct seq_file *m, void *v) return 0; } -static const struct seq_operations saa7164_seq_ops = { +static const struct seq_operations saa7164_sops = { .start = saa7164_seq_start, .next = saa7164_seq_next, .stop = saa7164_seq_stop, .show = saa7164_seq_show, }; -static int saa7164_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &saa7164_seq_ops); -} - -static const struct file_operations saa7164_operations = { - .owner = THIS_MODULE, - .open = saa7164_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; +DEFINE_SEQ_ATTRIBUTE(saa7164); static struct dentry *saa7614_dentry; static void __init saa7164_debugfs_create(void) { saa7614_dentry = debugfs_create_file("saa7164", 0444, NULL, NULL, - &saa7164_operations); + &saa7164_fops); } static void __exit saa7164_debugfs_remove(void) -- cgit v1.2.3 From af0321a5be3e5647441eb6b79355beaa592df97a Mon Sep 17 00:00:00 2001 From: Evgeny Novikov Date: Tue, 6 Oct 2020 19:21:22 +0200 Subject: media: zr364xx: propagate errors from zr364xx_start_readpipe() zr364xx_start_readpipe() can fail but callers do not care about that. This can result in various negative consequences. The patch adds missed error handling. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Evgeny Novikov Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/zr364xx/zr364xx.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index 8c670934d920..d65d3c2a034e 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -1327,6 +1327,7 @@ static int zr364xx_board_init(struct zr364xx_camera *cam) { struct zr364xx_pipeinfo *pipe = cam->pipe; unsigned long i; + int err; DBG("board init: %p\n", cam); memset(pipe, 0, sizeof(*pipe)); @@ -1359,9 +1360,8 @@ static int zr364xx_board_init(struct zr364xx_camera *cam) if (i == 0) { printk(KERN_INFO KBUILD_MODNAME ": out of memory. Aborting\n"); - kfree(cam->pipe->transfer_buffer); - cam->pipe->transfer_buffer = NULL; - return -ENOMEM; + err = -ENOMEM; + goto err_free; } else cam->buffer.dwFrames = i; @@ -1376,9 +1376,17 @@ static int zr364xx_board_init(struct zr364xx_camera *cam) /*** end create system buffers ***/ /* start read pipe */ - zr364xx_start_readpipe(cam); + err = zr364xx_start_readpipe(cam); + if (err) + goto err_free; + DBG(": board initialized\n"); return 0; + +err_free: + kfree(cam->pipe->transfer_buffer); + cam->pipe->transfer_buffer = NULL; + return err; } static int zr364xx_probe(struct usb_interface *intf, @@ -1575,10 +1583,19 @@ static int zr364xx_resume(struct usb_interface *intf) if (!cam->was_streaming) return 0; - zr364xx_start_readpipe(cam); + res = zr364xx_start_readpipe(cam); + if (res) + return res; + res = zr364xx_prepare(cam); - if (!res) - zr364xx_start_acquire(cam); + if (res) + goto err_prepare; + + zr364xx_start_acquire(cam); + return 0; + +err_prepare: + zr364xx_stop_readpipe(cam); return res; } #endif -- cgit v1.2.3 From f23e5f407ffa400a9958a6ef8c8db7c63b99f28e Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Wed, 7 Oct 2020 12:35:39 +0200 Subject: media: coda: Remove redundant ctx->initialized setting The ctx->initialized flag is set in __coda_decoder_seq_init, so it's redundant to set it in coda_dec_seq_init_work. Remove the redundant set, which allows to simplify the implementation quite a bit. This change shouldn't affect functionality as it's just cosmetics. Signed-off-by: Ezequiel Garcia Reviewed-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index bf75927bac4e..aa0a47c34413 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -2005,21 +2005,13 @@ static void coda_dec_seq_init_work(struct work_struct *work) struct coda_ctx *ctx = container_of(work, struct coda_ctx, seq_init_work); struct coda_dev *dev = ctx->dev; - int ret; mutex_lock(&ctx->buffer_mutex); mutex_lock(&dev->coda_mutex); - if (ctx->initialized == 1) - goto out; - - ret = __coda_decoder_seq_init(ctx); - if (ret < 0) - goto out; - - ctx->initialized = 1; + if (!ctx->initialized) + __coda_decoder_seq_init(ctx); -out: mutex_unlock(&dev->coda_mutex); mutex_unlock(&ctx->buffer_mutex); } -- cgit v1.2.3 From ba928bbd0782d152170ff04f0a1091c0055213bc Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Wed, 7 Oct 2020 12:35:40 +0200 Subject: media: coda: Simplify H.264 small buffer padding logic The H.264 small buffer padding is done under the (ctx->qsequence == 0 && payload < 512) condition. Given this is the exact same condition immediately above, we can move it right there, making the code slightly clearer. This change shouldn't affect functionality as it's just cosmetics. Signed-off-by: Ezequiel Garcia Reviewed-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index aa0a47c34413..659fcf77b0ed 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -293,12 +293,11 @@ static bool coda_bitstream_try_queue(struct coda_ctx *ctx, coda_dbg(1, ctx, "could not parse header, sequence initialization might fail\n"); } - } - /* Add padding before the first buffer, if it is too small */ - if (ctx->qsequence == 0 && payload < 512 && - ctx->codec->src_fourcc == V4L2_PIX_FMT_H264) - coda_h264_bitstream_pad(ctx, 512 - payload); + /* Add padding before the first buffer, if it is too small */ + if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264) + coda_h264_bitstream_pad(ctx, 512 - payload); + } ret = coda_bitstream_queue(ctx, vaddr, payload); if (ret < 0) { -- cgit v1.2.3 From a22955e81a11d695c6d20486826abf09f5295e93 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Wed, 7 Oct 2020 12:35:41 +0200 Subject: media: coda: Clarify device registered log Instead of printing just the device type, let's use the device name, which makes the message more useful. With this commit, the messages shown when the driver is registered are: coda 2040000.vpu: Firmware code revision: 570363 coda 2040000.vpu: Initialized CODA960. coda 2040000.vpu: Firmware version: 3.1.1 coda 2040000.vpu: coda-jpeg-encoder registered as video0 coda 2040000.vpu: coda-jpeg-decoder registered as video1 coda 2040000.vpu: coda-video-encoder registered as video2 coda 2040000.vpu: coda-video-decoder registered as video3 Signed-off-by: Ezequiel Garcia Acked-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 547ad34b1424..588617653b68 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -172,7 +172,7 @@ struct coda_video_device { }; static const struct coda_video_device coda_bit_encoder = { - .name = "coda-encoder", + .name = "coda-video-encoder", .type = CODA_INST_ENCODER, .ops = &coda_bit_encode_ops, .src_formats = { @@ -202,7 +202,7 @@ static const struct coda_video_device coda_bit_jpeg_encoder = { }; static const struct coda_video_device coda_bit_decoder = { - .name = "coda-decoder", + .name = "coda-video-decoder", .type = CODA_INST_DECODER, .ops = &coda_bit_decode_ops, .src_formats = { @@ -2851,12 +2851,12 @@ err_clk_per: static int coda_register_device(struct coda_dev *dev, int i) { struct video_device *vfd = &dev->vfd[i]; - enum coda_inst_type type; + const char *name; int ret; if (i >= dev->devtype->num_vdevs) return -EINVAL; - type = dev->devtype->vdevs[i]->type; + name = dev->devtype->vdevs[i]->name; strscpy(vfd->name, dev->devtype->vdevs[i]->name, sizeof(vfd->name)); vfd->fops = &coda_fops; @@ -2876,8 +2876,7 @@ static int coda_register_device(struct coda_dev *dev, int i) ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); if (!ret) v4l2_info(&dev->v4l2_dev, "%s registered as %s\n", - type == CODA_INST_ENCODER ? "encoder" : "decoder", - video_device_node_name(vfd)); + name, video_device_node_name(vfd)); return ret; } -- cgit v1.2.3 From aef47f6c585a807a68803f46cd5c01d67e2ba2b7 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Wed, 7 Oct 2020 12:35:42 +0200 Subject: media: coda: Clarify interrupt registered name Make interrupt naming more consistent by using a common pattern for video and jpeg interrupts. With this commit, interrupts are shown as: 29: 0 0 GPC 12 Level coda-video 30: 0 0 GPC 3 Level coda-jpeg Signed-off-by: Ezequiel Garcia Acked-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 588617653b68..f9e66247e92a 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -3153,7 +3153,7 @@ static int coda_probe(struct platform_device *pdev) return irq; ret = devm_request_irq(&pdev->dev, irq, coda_irq_handler, 0, - dev_name(&pdev->dev), dev); + CODA_NAME "-video", dev); if (ret < 0) { dev_err(&pdev->dev, "failed to request irq: %d\n", ret); return ret; @@ -3167,7 +3167,7 @@ static int coda_probe(struct platform_device *pdev) ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, coda9_jpeg_irq_handler, - IRQF_ONESHOT, CODA_NAME " jpeg", + IRQF_ONESHOT, CODA_NAME "-jpeg", dev); if (ret < 0) { dev_err(&pdev->dev, "failed to request jpeg irq\n"); -- cgit v1.2.3 From e5c0cd26d54e2e52792de2be3c32c9627168a06e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 8 Oct 2020 17:22:49 +0200 Subject: media: cec-core.rst/cec-ioc-g-mode.rst: fix typos in monitor-all description cec-core.rst was missing 'are', and cec-ioc-g-mode.rst was missing a comma. In both cases this made the description of the Monitor All functionality hard to read. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/driver-api/media/cec-core.rst | 2 +- Documentation/userspace-api/media/cec/cec-ioc-g-mode.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/driver-api/media/cec-core.rst b/Documentation/driver-api/media/cec-core.rst index bc42982ac21e..9c6aff3b0ddf 100644 --- a/Documentation/driver-api/media/cec-core.rst +++ b/Documentation/driver-api/media/cec-core.rst @@ -143,7 +143,7 @@ To enable/disable the 'monitor all' mode:: int (*adap_monitor_all_enable)(struct cec_adapter *adap, bool enable); If enabled, then the adapter should be put in a mode to also monitor messages -that not for us. Not all hardware supports this and this function is only +that are not for us. Not all hardware supports this and this function is only called if the CEC_CAP_MONITOR_ALL capability is set. This callback is optional (some hardware may always be in 'monitor all' mode). diff --git a/Documentation/userspace-api/media/cec/cec-ioc-g-mode.rst b/Documentation/userspace-api/media/cec/cec-ioc-g-mode.rst index d3387b1fa7c5..663bdef8d6da 100644 --- a/Documentation/userspace-api/media/cec/cec-ioc-g-mode.rst +++ b/Documentation/userspace-api/media/cec/cec-ioc-g-mode.rst @@ -188,7 +188,7 @@ Available follower modes are: in combination with :ref:`CEC_MODE_NO_INITIATOR `, otherwise the ``EINVAL`` error code will be returned. In 'monitor all' mode all messages this CEC device transmits and all messages it receives, including - directed messages for other CEC devices will be reported. This is + directed messages for other CEC devices, will be reported. This is very useful for debugging, but not all devices support this. This mode requires that the :ref:`CEC_CAP_MONITOR_ALL ` capability is set, otherwise the ``EINVAL`` error code is returned. This is only allowed if -- cgit v1.2.3 From a08ad6339e0441ca12533969ed94a87e3655426e Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 8 Oct 2020 23:12:23 +0200 Subject: media: tm6000: Fix sizeof() mismatches The are two instances of sizeof() being used incorrectly. The sizeof(void *) is incorrect because urb_buffer is a char ** pointer, fix this by using sizeof(*dev->urb_buffer). The sizeof(dma_addr_t *) is incorrect, it should be sizeof(*dev->urb_dma), which is a dma_addr_t and not a dma_addr_t *. This errors did not cause any issues because it just so happens the sizes are the same. Addresses-Coverity: ("Sizeof not portable (SIZEOF_MISMATCH)") Fixes: 16427faf2867 ("[media] tm6000: Add parameter to keep urb bufs allocated") Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/tm6000/tm6000-video.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index bfba06ea60e9..2df736c029d6 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -461,11 +461,12 @@ static int tm6000_alloc_urb_buffers(struct tm6000_core *dev) if (dev->urb_buffer) return 0; - dev->urb_buffer = kmalloc_array(num_bufs, sizeof(void *), GFP_KERNEL); + dev->urb_buffer = kmalloc_array(num_bufs, sizeof(*dev->urb_buffer), + GFP_KERNEL); if (!dev->urb_buffer) return -ENOMEM; - dev->urb_dma = kmalloc_array(num_bufs, sizeof(dma_addr_t *), + dev->urb_dma = kmalloc_array(num_bufs, sizeof(*dev->urb_dma), GFP_KERNEL); if (!dev->urb_dma) return -ENOMEM; -- cgit v1.2.3 From 41cbf0aecbf888376f4f5dc8b13af48b6a3795fa Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 9 Oct 2020 00:55:53 +0200 Subject: media: pxa_camera: Use fallthrough pseudo-keyword In order to enable -Wimplicit-fallthrough for Clang[1], replace the existing /* fall through */ comments with the new pseudo-keyword macro fallthrough[2]. [1] https://git.kernel.org/linus/e2079e93f562c7f7a030eb7642017ee5eabaaa10 [2] https://www.kernel.org/doc/html/v5.7/process/deprecated.html?highlight=fallthrough#implicit-switch-case-fall-through Signed-off-by: Gustavo A. R. Silva Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/pxa_camera.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c index e47520fcb93c..b664ce7558a1 100644 --- a/drivers/media/platform/pxa_camera.c +++ b/drivers/media/platform/pxa_camera.c @@ -1256,7 +1256,7 @@ static void pxa_camera_setup_cicr(struct pxa_camera_dev *pcdev, * transformation. Note that UYVY is the only format that * should be used if pxa framebuffer Overlay2 is used. */ - /* fall through */ + fallthrough; case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_VYUY: case V4L2_PIX_FMT_YUYV: @@ -1667,7 +1667,7 @@ static int pxa_camera_get_formats(struct v4l2_device *v4l2_dev, "Providing format %s using code %d\n", pxa_camera_formats[0].name, code.code); } - /* fall through */ + fallthrough; case MEDIA_BUS_FMT_VYUY8_2X8: case MEDIA_BUS_FMT_YUYV8_2X8: case MEDIA_BUS_FMT_YVYU8_2X8: -- cgit v1.2.3 From 01c7a8167d497469f4da392c3c009ebf3169bf43 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Fri, 9 Oct 2020 06:16:21 +0200 Subject: media: MAINTAINERS: rectify ZR36067 VIDEO FOR LINUX DRIVER section Commit 754f0f1ba8d9 ("media: MAINTAINERS: change maintainer of the zoran driver") added a new section in MAINTAINERS with an invalid file entry and at the wrong place for alphabetic ordering. Hence, ./scripts/get_maintainer.pl --self-test=patterns complains: warning: no file matches F: Documentation/media/v4l-drivers/zoran.rst Point the file entry to the right location and move the section to the right place in MAINTAINERS. Signed-off-by: Lukas Bulwahn Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index e73636b75f29..aa8ee8f69bc6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -19419,6 +19419,13 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/zonefs.git F: Documentation/filesystems/zonefs.rst F: fs/zonefs/ +ZPOOL COMPRESSED PAGE STORAGE API +M: Dan Streetman +L: linux-mm@kvack.org +S: Maintained +F: include/linux/zpool.h +F: mm/zpool.c + ZR36067 VIDEO FOR LINUX DRIVER M: Corentin Labbe L: mjpeg-users@lists.sourceforge.net @@ -19429,13 +19436,6 @@ Q: https://patchwork.linuxtv.org/project/linux-media/list/ F: Documentation/driver-api/media/drivers/zoran.rst F: drivers/staging/media/zoran/ -ZPOOL COMPRESSED PAGE STORAGE API -M: Dan Streetman -L: linux-mm@kvack.org -S: Maintained -F: include/linux/zpool.h -F: mm/zpool.c - ZRAM COMPRESSED RAM BLOCK DEVICE DRVIER M: Minchan Kim M: Nitin Gupta -- cgit v1.2.3 From e91c255733d9bbb4978a372f44fb5ed689ccdbd1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 9 Oct 2020 11:16:16 +0200 Subject: media: cec-core: first mark device unregistered, then wake up fhs If a CEC device node is unregistered, then it should be marked as unregistered before waking up any filehandles that are waiting for an event. This ensures that there is no race condition where an application can call CEC_DQEVENT and have the ioctl return 0 instead of ENODEV. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/core/cec-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/cec/core/cec-core.c b/drivers/media/cec/core/cec-core.c index ece236291f35..551689d371a7 100644 --- a/drivers/media/cec/core/cec-core.c +++ b/drivers/media/cec/core/cec-core.c @@ -166,12 +166,12 @@ static void cec_devnode_unregister(struct cec_adapter *adap) mutex_unlock(&devnode->lock); return; } + devnode->registered = false; + devnode->unregistered = true; list_for_each_entry(fh, &devnode->fhs, list) wake_up_interruptible(&fh->wait); - devnode->registered = false; - devnode->unregistered = true; mutex_unlock(&devnode->lock); mutex_lock(&adap->lock); -- cgit v1.2.3 From f28a81a3b64270da3588174feff4628c36e0ff4e Mon Sep 17 00:00:00 2001 From: Yu Kuai Date: Fri, 9 Oct 2020 14:37:58 +0200 Subject: media: platform: add missing put_device() call in mtk_jpeg_clk_init() if of_find_device_by_node() succeeds, mtk_jpeg_clk_init() doesn't have a corresponding put_device(). Thus add put_device() to fix the exception handling for this function implementation. Fixes: 648372a87cee ("media: platform: Change the call functions of getting/enable/disable the jpeg's clock") Signed-off-by: Yu Kuai Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c index 227245ccaedc..106543391c46 100644 --- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c @@ -1306,6 +1306,7 @@ static int mtk_jpeg_clk_init(struct mtk_jpeg_dev *jpeg) jpeg->variant->clks); if (ret) { dev_err(&pdev->dev, "failed to get jpeg clock:%d\n", ret); + put_device(&pdev->dev); return ret; } -- cgit v1.2.3 From 5d4fa2c50125c9cda9e380d89268757cc5fa743d Mon Sep 17 00:00:00 2001 From: Yu Kuai Date: Fri, 9 Oct 2020 14:38:01 +0200 Subject: media: mtk-vcodec: add missing put_device() call in mtk_vcodec_init_dec_pm() if of_find_device_by_node() succeed, mtk_vcodec_init_dec_pm() doesn't have a corresponding put_device(). Thus add jump target to fix the exception handling for this function implementation. Fixes: 590577a4e525 ("[media] vcodec: mediatek: Add Mediatek V4L2 Video Decoder Driver") Signed-off-by: Yu Kuai Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c index 36dfe3fc056a..f6a6b42865fb 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c @@ -47,11 +47,14 @@ int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *mtkdev) dec_clk->clk_info = devm_kcalloc(&pdev->dev, dec_clk->clk_num, sizeof(*clk_info), GFP_KERNEL); - if (!dec_clk->clk_info) - return -ENOMEM; + if (!dec_clk->clk_info) { + ret = -ENOMEM; + goto put_device; + } } else { mtk_v4l2_err("Failed to get vdec clock count"); - return -EINVAL; + ret = -EINVAL; + goto put_device; } for (i = 0; i < dec_clk->clk_num; i++) { @@ -60,19 +63,22 @@ int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *mtkdev) "clock-names", i, &clk_info->clk_name); if (ret) { mtk_v4l2_err("Failed to get clock name id = %d", i); - return ret; + goto put_device; } clk_info->vcodec_clk = devm_clk_get(&pdev->dev, clk_info->clk_name); if (IS_ERR(clk_info->vcodec_clk)) { mtk_v4l2_err("devm_clk_get (%d)%s fail", i, clk_info->clk_name); - return PTR_ERR(clk_info->vcodec_clk); + ret = PTR_ERR(clk_info->vcodec_clk); + goto put_device; } } pm_runtime_enable(&pdev->dev); - + return 0; +put_device: + put_device(pm->larbvdec); return ret; } -- cgit v1.2.3 From 27c3943683f74e35e1d390ceb2e3639eff616ad6 Mon Sep 17 00:00:00 2001 From: Yu Kuai Date: Fri, 9 Oct 2020 14:38:02 +0200 Subject: media: mtk-vcodec: add missing put_device() call in mtk_vcodec_release_dec_pm() mtk_vcodec_release_dec_pm() will be called in two places: a. mtk_vcodec_init_dec_pm() succeed while mtk_vcodec_probe() return error. b. mtk_vcodec_dec_remove(). In both cases put_device() call is needed, since of_find_device_by_node() was called in mtk_vcodec_init_dec_pm() previously. Thus add put_devices() call in mtk_vcodec_release_dec_pm() Fixes: 590577a4e525 ("[media] vcodec: mediatek: Add Mediatek V4L2 Video Decoder Driver") Signed-off-by: Yu Kuai Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c index f6a6b42865fb..ddee7046ce42 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c @@ -85,6 +85,7 @@ put_device: void mtk_vcodec_release_dec_pm(struct mtk_vcodec_dev *dev) { pm_runtime_disable(dev->pm.dev); + put_device(dev->pm.larbvdec); } void mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm) -- cgit v1.2.3 From 4affafd7bec7c65da31777f18bd20420f1aeb5f8 Mon Sep 17 00:00:00 2001 From: Yu Kuai Date: Fri, 9 Oct 2020 14:38:03 +0200 Subject: media: mtk-vcodec: add missing put_device() call in mtk_vcodec_init_enc_pm() if of_find_device_by_node() succeed, mtk_vcodec_init_enc_pm() doesn't have a corresponding put_device(). Thus add jump target to fix the exception handling for this function implementation. Fixes: 4e855a6efa54 ("[media] vcodec: mediatek: Add Mediatek V4L2 Video Encoder Driver") Signed-off-by: Yu Kuai Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c | 26 ++++++++++++++++------ 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c index ee22902aaa71..1a047c25679f 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c @@ -47,14 +47,16 @@ int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *mtkdev) node = of_parse_phandle(dev->of_node, "mediatek,larb", 1); if (!node) { mtk_v4l2_err("no mediatek,larb found"); - return -ENODEV; + ret = -ENODEV; + goto put_larbvenc; } pdev = of_find_device_by_node(node); of_node_put(node); if (!pdev) { mtk_v4l2_err("no mediatek,larb device found"); - return -ENODEV; + ret = -ENODEV; + goto put_larbvenc; } pm->larbvenclt = &pdev->dev; @@ -67,11 +69,14 @@ int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *mtkdev) enc_clk->clk_info = devm_kcalloc(&pdev->dev, enc_clk->clk_num, sizeof(*clk_info), GFP_KERNEL); - if (!enc_clk->clk_info) - return -ENOMEM; + if (!enc_clk->clk_info) { + ret = -ENOMEM; + goto put_larbvenclt; + } } else { mtk_v4l2_err("Failed to get venc clock count"); - return -EINVAL; + ret = -EINVAL; + goto put_larbvenclt; } for (i = 0; i < enc_clk->clk_num; i++) { @@ -80,17 +85,24 @@ int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *mtkdev) "clock-names", i, &clk_info->clk_name); if (ret) { mtk_v4l2_err("venc failed to get clk name %d", i); - return ret; + goto put_larbvenclt; } clk_info->vcodec_clk = devm_clk_get(&pdev->dev, clk_info->clk_name); if (IS_ERR(clk_info->vcodec_clk)) { mtk_v4l2_err("venc devm_clk_get (%d)%s fail", i, clk_info->clk_name); - return PTR_ERR(clk_info->vcodec_clk); + ret = PTR_ERR(clk_info->vcodec_clk); + goto put_larbvenclt; } } + return 0; + +put_larbvenclt: + put_device(pm->larbvenclt); +put_larbvenc: + put_device(pm->larbvenc); return ret; } -- cgit v1.2.3 From d940d2f46bfec6e206609cf44c6bd612a81d117e Mon Sep 17 00:00:00 2001 From: Yu Kuai Date: Fri, 9 Oct 2020 14:38:04 +0200 Subject: media: mtk-vcodec: add missing put_device() call in mtk_vcodec_release_enc_pm() mtk_vcodec_release_enc_pm() will be called in two places: a. mtk_vcodec_init_enc_pm() succeed while mtk_vcodec_probe() return error. b. mtk_vcodec_enc_remove(). In both cases put_device() call is needed, since of_find_device_by_node() was called in mtk_vcodec_init_enc_pm() previously. Thus add put_devices() call in mtk_vcodec_release_enc_pm() Signed-off-by: Yu Kuai Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c index 1a047c25679f..3b7c54d6aa8f 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c @@ -108,6 +108,8 @@ put_larbvenc: void mtk_vcodec_release_enc_pm(struct mtk_vcodec_dev *mtkdev) { + put_device(mtkdev->pm.larbvenclt); + put_device(mtkdev->pm.larbvenc); } -- cgit v1.2.3 From 9bb83e8fe252f15ad30430e80eb7f9da66cacbb9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 13 Oct 2020 16:26:17 +0200 Subject: media: Bulk remove BUG_ON(in_interrupt()) None of these BUG_ON()'s is justified. BUG_ON() should only be used when there is really no way to survive. If at all these could be replaced by lockdep_assert_preemption_enabled() to cover all invalid caller context and not just those covered by in_interrupt(). But all functions which are invoked from those places contain already debug mechanisms to catch wrong context, so having these extra checks is not having any advantage. Signed-off-by: Thomas Gleixner Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146/saa7146_fops.c | 2 -- drivers/media/pci/bt8xx/bttv-risc.c | 1 - drivers/media/pci/cx23885/cx23885-core.c | 1 - drivers/media/pci/cx25821/cx25821-core.c | 1 - drivers/media/platform/fsl-viu.c | 2 -- drivers/media/usb/tm6000/tm6000-video.c | 2 -- drivers/media/usb/zr364xx/zr364xx.c | 2 -- 7 files changed, 11 deletions(-) diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c index d6531874faa6..e936c56b0378 100644 --- a/drivers/media/common/saa7146/saa7146_fops.c +++ b/drivers/media/common/saa7146/saa7146_fops.c @@ -55,8 +55,6 @@ void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q, struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); DEB_EE("dev:%p, buf:%p\n", dev, buf); - BUG_ON(in_interrupt()); - videobuf_waiton(q, &buf->vb, 0, 0); videobuf_dma_unmap(q->dev, dma); videobuf_dma_free(dma); diff --git a/drivers/media/pci/bt8xx/bttv-risc.c b/drivers/media/pci/bt8xx/bttv-risc.c index 4af72826b006..32fa4a7fe76f 100644 --- a/drivers/media/pci/bt8xx/bttv-risc.c +++ b/drivers/media/pci/bt8xx/bttv-risc.c @@ -572,7 +572,6 @@ bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf { struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - BUG_ON(in_interrupt()); videobuf_waiton(q, &buf->vb, 0, 0); videobuf_dma_unmap(q->dev, dma); videobuf_dma_free(dma); diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 4b0c53f61fb7..16eb4ab0e73e 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -1322,7 +1322,6 @@ void cx23885_free_buffer(struct cx23885_dev *dev, struct cx23885_buffer *buf) { struct cx23885_riscmem *risc = &buf->risc; - BUG_ON(in_interrupt()); pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma); } diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index 55018d9e439f..6f8ffab8840f 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -1198,7 +1198,6 @@ EXPORT_SYMBOL(cx25821_risc_databuffer_audio); void cx25821_free_buffer(struct cx25821_dev *dev, struct cx25821_buffer *buf) { - BUG_ON(in_interrupt()); if (WARN_ON(buf->risc.size == 0)) return; pci_free_consistent(dev->pci, diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c index 4f2a0f992905..ff625301e777 100644 --- a/drivers/media/platform/fsl-viu.c +++ b/drivers/media/platform/fsl-viu.c @@ -381,8 +381,6 @@ static void free_buffer(struct videobuf_queue *vq, struct viu_buf *buf) struct videobuf_buffer *vb = &buf->vb; void *vaddr = NULL; - BUG_ON(in_interrupt()); - videobuf_waiton(vq, &buf->vb, 0, 0); if (vq->int_ops && vq->int_ops->vaddr) diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index 2df736c029d6..3f650ede0c3d 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -693,8 +693,6 @@ static void free_buffer(struct videobuf_queue *vq, struct tm6000_buffer *buf) struct tm6000_core *dev = fh->dev; unsigned long flags; - BUG_ON(in_interrupt()); - /* We used to wait for the buffer to finish here, but this didn't work because, as we were keeping the state as VIDEOBUF_QUEUED, videobuf_queue_cancel marked it as finished for us. diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index d65d3c2a034e..1e1c6b4d1874 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -357,8 +357,6 @@ static void free_buffer(struct videobuf_queue *vq, struct zr364xx_buffer *buf) { _DBG("%s\n", __func__); - BUG_ON(in_interrupt()); - videobuf_vmalloc_free(&buf->vb); buf->vb.state = VIDEOBUF_NEEDS_INIT; } -- cgit v1.2.3 From 994388f228c66e7c8f7f4dd5e4c9d61d548b316c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 13 Oct 2020 16:26:19 +0200 Subject: media: au0828: Consolidate dmesg output The memory allocations in au0828_init_isoc() happen all in task context with GFP_KERNEL. Therefore a printk() trying to deduce whether this is called from task or interrupt context is pretty useless. Convert it to au0828_isocdbg() as the other one in that function and for completeness sake add one for the URB allocation as well. Signed-off-by: Thomas Gleixner Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-video.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 5c4bac5a4ec7..c0f118563c7d 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -231,6 +231,7 @@ static int au0828_init_isoc(struct au0828_dev *dev, int max_packets, for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { urb = usb_alloc_urb(max_packets, GFP_KERNEL); if (!urb) { + au0828_isocdbg("cannot allocate URB\n"); au0828_uninit_isoc(dev); return -ENOMEM; } @@ -239,9 +240,7 @@ static int au0828_init_isoc(struct au0828_dev *dev, int max_packets, dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->usbdev, sb_size, GFP_KERNEL, &urb->transfer_dma); if (!dev->isoc_ctl.transfer_buffer[i]) { - printk("unable to allocate %i bytes for transfer buffer %i%s\n", - sb_size, i, - in_interrupt() ? " while in int" : ""); + au0828_isocdbg("cannot allocate transfer buffer\n"); au0828_uninit_isoc(dev); return -ENOMEM; } -- cgit v1.2.3 From 8b77d1f99e6403a457c2482a88539726276ec01a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 14 Oct 2020 17:38:04 +0200 Subject: media: cx231xx: Consolidate dmesg output The memory allocations in cx231xx_init_*() happen all in task context with GFP_KERNEL. Therefore a dev_err() trying to deduce whether this is called from task or interrupt context is pretty useless. Remove these historical leftovers. Signed-off-by: Thomas Gleixner Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-core.c | 10 ++++------ drivers/media/usb/cx231xx/cx231xx-vbi.c | 5 ++--- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c index 05d91caaed0c..727e6268567f 100644 --- a/drivers/media/usb/cx231xx/cx231xx-core.c +++ b/drivers/media/usb/cx231xx/cx231xx-core.c @@ -1061,9 +1061,8 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets, &urb->transfer_dma); if (!dev->video_mode.isoc_ctl.transfer_buffer[i]) { dev_err(dev->dev, - "unable to allocate %i bytes for transfer buffer %i%s\n", - sb_size, i, - in_interrupt() ? " while in int" : ""); + "unable to allocate %i bytes for transfer buffer %i\n", + sb_size, i); cx231xx_uninit_isoc(dev); return -ENOMEM; } @@ -1197,9 +1196,8 @@ int cx231xx_init_bulk(struct cx231xx *dev, int max_packets, &urb->transfer_dma); if (!dev->video_mode.bulk_ctl.transfer_buffer[i]) { dev_err(dev->dev, - "unable to allocate %i bytes for transfer buffer %i%s\n", - sb_size, i, - in_interrupt() ? " while in int" : ""); + "unable to allocate %i bytes for transfer buffer %i\n", + sb_size, i); cx231xx_uninit_bulk(dev); return -ENOMEM; } diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c index d2f143a096d1..fdc8b7f7b0c1 100644 --- a/drivers/media/usb/cx231xx/cx231xx-vbi.c +++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c @@ -408,9 +408,8 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets, kzalloc(sb_size, GFP_KERNEL); if (!dev->vbi_mode.bulk_ctl.transfer_buffer[i]) { dev_err(dev->dev, - "unable to allocate %i bytes for transfer buffer %i%s\n", - sb_size, i, - in_interrupt() ? " while in int" : ""); + "unable to allocate %i bytes for transfer buffer %i\n", + sb_size, i); cx231xx_uninit_vbi_isoc(dev); return -ENOMEM; } -- cgit v1.2.3 From 90ed57851eef0d60320cf2c24536de9ab3183e0f Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Fri, 16 Oct 2020 01:14:04 +0200 Subject: media: rcar-vin: Use scratch buffer when not in running state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In its early stages the VIN driver did not use an internal scratch buffer. This leads to a unnecessary complex start and stop behavior, specially for TB/BT. The driver now always allocates a scratch buffer to deal with buffer under-runs, use the scratch buffer to also simplify starting and stopping. When capture is starting use the scratch buffer instead of a user-space buffers while syncing the driver with the hardware state. This allows the driver to know that no user-space buffer is given to the hardware before the running state is reached. When capture is stopping use the scratch buffer instead of leaving the user-space buffers in place and add a check that all user-space buffers are processed by the hardware before transitioning from the stopping to stopped state. This allows the driver to know all user-space buffers given to the hardware are fully processed. This change in itself does not improve the driver much but it paves the way for future simplifications and enhancements. One direct improvement of this change is that TB/BT buffers returned to user-space while stopping will always contain both fields, that was not guaranteed before. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-dma.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c index 692dea300b0d..ca90bde8d29f 100644 --- a/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/rcar-vin/rcar-dma.c @@ -905,7 +905,7 @@ static void rvin_fill_hw_slot(struct rvin_dev *vin, int slot) vin->format.sizeimage / 2; break; } - } else if (list_empty(&vin->buf_list)) { + } else if (vin->state != RUNNING || list_empty(&vin->buf_list)) { vin->buf_hw[slot].buffer = NULL; vin->buf_hw[slot].type = FULL; phys_addr = vin->scratch_phys; @@ -998,12 +998,6 @@ static irqreturn_t rvin_irq(int irq, void *data) goto done; } - /* Nothing to do if capture status is 'STOPPING' */ - if (vin->state == STOPPING) { - vin_dbg(vin, "IRQ while state stopping\n"); - goto done; - } - /* Prepare for capture and update state */ vnms = rvin_read(vin, VNMS_REG); slot = (vnms & VNMS_FBS_MASK) >> VNMS_FBS_SHIFT; @@ -1313,14 +1307,32 @@ out: static void rvin_stop_streaming(struct vb2_queue *vq) { struct rvin_dev *vin = vb2_get_drv_priv(vq); + unsigned int i, retries; unsigned long flags; - int retries = 0; + bool buffersFreed; spin_lock_irqsave(&vin->qlock, flags); vin->state = STOPPING; + /* Wait until only scratch buffer is used, max 3 interrupts. */ + retries = 0; + while (retries++ < RVIN_RETRIES) { + buffersFreed = true; + for (i = 0; i < HW_BUFFER_NUM; i++) + if (vin->buf_hw[i].buffer) + buffersFreed = false; + + if (buffersFreed) + break; + + spin_unlock_irqrestore(&vin->qlock, flags); + msleep(RVIN_TIMEOUT_MS); + spin_lock_irqsave(&vin->qlock, flags); + } + /* Wait for streaming to stop */ + retries = 0; while (retries++ < RVIN_RETRIES) { rvin_capture_stop(vin); @@ -1336,7 +1348,7 @@ static void rvin_stop_streaming(struct vb2_queue *vq) spin_lock_irqsave(&vin->qlock, flags); } - if (vin->state != STOPPED) { + if (!buffersFreed || vin->state != STOPPED) { /* * If this happens something have gone horribly wrong. * Set state to stopped to prevent the interrupt handler -- cgit v1.2.3 From b83a18cca8924a11eb3317354de30a5a4220aec9 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Fri, 16 Oct 2020 01:14:05 +0200 Subject: media: rcar-vin: Remove handling of user-space buffers when stopping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When returning buffers to user-space it's no longer needed to examine the buffers given to hardware as recent changes guarantees the only buffer present in the hardware registers when the driver is not in the running state is the scratch buffer. Remove the special case and rename the function to better describe it now only deals with buffers queued to the driver but not yet recorded in the hardware registers. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-dma.c | 31 +++++++----------------------- 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c index ca90bde8d29f..680160f9f851 100644 --- a/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/rcar-vin/rcar-dma.c @@ -1051,27 +1051,10 @@ done: } /* Need to hold qlock before calling */ -static void return_all_buffers(struct rvin_dev *vin, - enum vb2_buffer_state state) +static void return_unused_buffers(struct rvin_dev *vin, + enum vb2_buffer_state state) { struct rvin_buffer *buf, *node; - struct vb2_v4l2_buffer *freed[HW_BUFFER_NUM]; - unsigned int i, n; - - for (i = 0; i < HW_BUFFER_NUM; i++) { - freed[i] = vin->buf_hw[i].buffer; - vin->buf_hw[i].buffer = NULL; - - for (n = 0; n < i; n++) { - if (freed[i] == freed[n]) { - freed[i] = NULL; - break; - } - } - - if (freed[i]) - vb2_buffer_done(&freed[i]->vb2_buf, state); - } list_for_each_entry_safe(buf, node, &vin->buf_list, list) { vb2_buffer_done(&buf->vb.vb2_buf, state); @@ -1271,7 +1254,7 @@ static int rvin_start_streaming(struct vb2_queue *vq, unsigned int count) &vin->scratch_phys, GFP_KERNEL); if (!vin->scratch) { spin_lock_irqsave(&vin->qlock, flags); - return_all_buffers(vin, VB2_BUF_STATE_QUEUED); + return_unused_buffers(vin, VB2_BUF_STATE_QUEUED); spin_unlock_irqrestore(&vin->qlock, flags); vin_err(vin, "Failed to allocate scratch buffer\n"); return -ENOMEM; @@ -1280,7 +1263,7 @@ static int rvin_start_streaming(struct vb2_queue *vq, unsigned int count) ret = rvin_set_stream(vin, 1); if (ret) { spin_lock_irqsave(&vin->qlock, flags); - return_all_buffers(vin, VB2_BUF_STATE_QUEUED); + return_unused_buffers(vin, VB2_BUF_STATE_QUEUED); spin_unlock_irqrestore(&vin->qlock, flags); goto out; } @@ -1291,7 +1274,7 @@ static int rvin_start_streaming(struct vb2_queue *vq, unsigned int count) ret = rvin_capture_start(vin); if (ret) { - return_all_buffers(vin, VB2_BUF_STATE_QUEUED); + return_unused_buffers(vin, VB2_BUF_STATE_QUEUED); rvin_set_stream(vin, 0); } @@ -1358,8 +1341,8 @@ static void rvin_stop_streaming(struct vb2_queue *vq) vin->state = STOPPED; } - /* Release all active buffers */ - return_all_buffers(vin, VB2_BUF_STATE_ERROR); + /* Return all unused buffers. */ + return_unused_buffers(vin, VB2_BUF_STATE_ERROR); spin_unlock_irqrestore(&vin->qlock, flags); -- cgit v1.2.3 From 43e36a222a33bf9a0ea33f2e3eb1d7881f965ff8 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Fri, 16 Oct 2020 01:14:06 +0200 Subject: media: rcar-vin: Cache the CSI-2 channel selection value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation of suspend/resume support cache the chsel value when written to the register so it can be restored on resume if needed. Signed-off-by: Niklas Söderlund Reviewed-by: Laurent Pinchart Reviewed-by: Jacopo Mondi Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-dma.c | 2 ++ drivers/media/platform/rcar-vin/rcar-vin.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c index 680160f9f851..f65deac4c2db 100644 --- a/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/rcar-vin/rcar-dma.c @@ -1456,6 +1456,8 @@ int rvin_set_channel_routing(struct rvin_dev *vin, u8 chsel) vin_dbg(vin, "Set IFMD 0x%x\n", ifmd); + vin->chsel = chsel; + /* Restore VNMC. */ rvin_write(vin, vnmc, VNMC_REG); diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h index 8396e0e45478..2fef23470e3d 100644 --- a/drivers/media/platform/rcar-vin/rcar-vin.h +++ b/drivers/media/platform/rcar-vin/rcar-vin.h @@ -189,6 +189,7 @@ struct rvin_info { * @state: keeps track of operation state * * @is_csi: flag to mark the VIN as using a CSI-2 subdevice + * @chsel Cached value of the current CSI-2 channel selection * * @mbus_code: media bus format code * @format: active V4L2 pixel format @@ -232,6 +233,7 @@ struct rvin_dev { enum rvin_dma_state state; bool is_csi; + unsigned int chsel; u32 mbus_code; struct v4l2_pix_format format; -- cgit v1.2.3 From 63a71dd813e207b3df6adf45757e864aa7f3364e Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Fri, 16 Oct 2020 01:14:07 +0200 Subject: media: rcar-vin: Break out hardware start and stop to new methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To support suspend and resume the ability to start and stop the hardware needs to be available internally in the driver. Currently this code is in the start and stop callbacks of the vb2_ops struct. In these callbacks the code is intertwined with buffer allocation and freeing. Prepare for suspend and resume support by breaking out the hardware start/stop code into new methods. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-dma.c | 78 +++++++++++++++++------------- drivers/media/platform/rcar-vin/rcar-vin.h | 3 ++ 2 files changed, 48 insertions(+), 33 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c index f65deac4c2db..5a5f0e500747 100644 --- a/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/rcar-vin/rcar-dma.c @@ -1050,16 +1050,20 @@ done: return IRQ_RETVAL(handled); } -/* Need to hold qlock before calling */ static void return_unused_buffers(struct rvin_dev *vin, enum vb2_buffer_state state) { struct rvin_buffer *buf, *node; + unsigned long flags; + + spin_lock_irqsave(&vin->qlock, flags); list_for_each_entry_safe(buf, node, &vin->buf_list, list) { vb2_buffer_done(&buf->vb.vb2_buf, state); list_del(&buf->list); } + + spin_unlock_irqrestore(&vin->qlock, flags); } static int rvin_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, @@ -1243,53 +1247,55 @@ static int rvin_set_stream(struct rvin_dev *vin, int on) return ret; } -static int rvin_start_streaming(struct vb2_queue *vq, unsigned int count) +int rvin_start_streaming(struct rvin_dev *vin) { - struct rvin_dev *vin = vb2_get_drv_priv(vq); unsigned long flags; int ret; - /* Allocate scratch buffer. */ - vin->scratch = dma_alloc_coherent(vin->dev, vin->format.sizeimage, - &vin->scratch_phys, GFP_KERNEL); - if (!vin->scratch) { - spin_lock_irqsave(&vin->qlock, flags); - return_unused_buffers(vin, VB2_BUF_STATE_QUEUED); - spin_unlock_irqrestore(&vin->qlock, flags); - vin_err(vin, "Failed to allocate scratch buffer\n"); - return -ENOMEM; - } - ret = rvin_set_stream(vin, 1); - if (ret) { - spin_lock_irqsave(&vin->qlock, flags); - return_unused_buffers(vin, VB2_BUF_STATE_QUEUED); - spin_unlock_irqrestore(&vin->qlock, flags); - goto out; - } + if (ret) + return ret; spin_lock_irqsave(&vin->qlock, flags); vin->sequence = 0; ret = rvin_capture_start(vin); - if (ret) { - return_unused_buffers(vin, VB2_BUF_STATE_QUEUED); + if (ret) rvin_set_stream(vin, 0); - } spin_unlock_irqrestore(&vin->qlock, flags); -out: - if (ret) - dma_free_coherent(vin->dev, vin->format.sizeimage, vin->scratch, - vin->scratch_phys); return ret; } -static void rvin_stop_streaming(struct vb2_queue *vq) +static int rvin_start_streaming_vq(struct vb2_queue *vq, unsigned int count) { struct rvin_dev *vin = vb2_get_drv_priv(vq); + int ret = -ENOMEM; + + /* Allocate scratch buffer. */ + vin->scratch = dma_alloc_coherent(vin->dev, vin->format.sizeimage, + &vin->scratch_phys, GFP_KERNEL); + if (!vin->scratch) + goto err_scratch; + + ret = rvin_start_streaming(vin); + if (ret) + goto err_start; + + return 0; +err_start: + dma_free_coherent(vin->dev, vin->format.sizeimage, vin->scratch, + vin->scratch_phys); +err_scratch: + return_unused_buffers(vin, VB2_BUF_STATE_QUEUED); + + return ret; +} + +void rvin_stop_streaming(struct rvin_dev *vin) +{ unsigned int i, retries; unsigned long flags; bool buffersFreed; @@ -1341,27 +1347,33 @@ static void rvin_stop_streaming(struct vb2_queue *vq) vin->state = STOPPED; } - /* Return all unused buffers. */ - return_unused_buffers(vin, VB2_BUF_STATE_ERROR); - spin_unlock_irqrestore(&vin->qlock, flags); rvin_set_stream(vin, 0); /* disable interrupts */ rvin_disable_interrupts(vin); +} + +static void rvin_stop_streaming_vq(struct vb2_queue *vq) +{ + struct rvin_dev *vin = vb2_get_drv_priv(vq); + + rvin_stop_streaming(vin); /* Free scratch buffer. */ dma_free_coherent(vin->dev, vin->format.sizeimage, vin->scratch, vin->scratch_phys); + + return_unused_buffers(vin, VB2_BUF_STATE_ERROR); } static const struct vb2_ops rvin_qops = { .queue_setup = rvin_queue_setup, .buf_prepare = rvin_buffer_prepare, .buf_queue = rvin_buffer_queue, - .start_streaming = rvin_start_streaming, - .stop_streaming = rvin_stop_streaming, + .start_streaming = rvin_start_streaming_vq, + .stop_streaming = rvin_stop_streaming_vq, .wait_prepare = vb2_ops_wait_prepare, .wait_finish = vb2_ops_wait_finish, }; diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h index 2fef23470e3d..4ec8584709c8 100644 --- a/drivers/media/platform/rcar-vin/rcar-vin.h +++ b/drivers/media/platform/rcar-vin/rcar-vin.h @@ -299,4 +299,7 @@ void rvin_crop_scale_comp(struct rvin_dev *vin); int rvin_set_channel_routing(struct rvin_dev *vin, u8 chsel); void rvin_set_alpha(struct rvin_dev *vin, unsigned int alpha); +int rvin_start_streaming(struct rvin_dev *vin); +void rvin_stop_streaming(struct rvin_dev *vin); + #endif -- cgit v1.2.3 From bea2b6a4e14102fbc03eae0393eed9814521289f Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Fri, 16 Oct 2020 01:14:08 +0200 Subject: media: rcar-vin: Add support for suspend and resume MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for suspend and resume by stopping and starting the video pipeline while still retaining all buffers given to the driver by user-space and internally allocated ones, this gives the application a seamless experience. Buffers are never returned to user-space unprocessed so user-space don't notice when suspending. When resuming the driver restarts the capture session using the internal scratch buffer, this happens before user-space is unfrozen, this leads to speedy response times once the application resumes its execution. As the entire pipeline is stopped on suspend all subdevices in use are also stopped, and if they enter a shutdown state when not streaming (such as the R-Car CSI-2 driver) they too will be suspended and resumed in sync with the VIN driver. To be able to do keep track of which VINs should be resumed a new internal state SUSPENDED is added to recode this. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-core.c | 51 +++++++++++++++++++++++++++++ drivers/media/platform/rcar-vin/rcar-vin.h | 10 +++--- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 1c52678a4d0f..518813456194 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -918,6 +918,54 @@ static int rvin_mc_init(struct rvin_dev *vin) return ret; } +/* ----------------------------------------------------------------------------- + * Suspend / Resume + */ + +static int __maybe_unused rvin_suspend(struct device *dev) +{ + struct rvin_dev *vin = dev_get_drvdata(dev); + + if (vin->state != RUNNING) + return 0; + + rvin_stop_streaming(vin); + + vin->state = SUSPENDED; + + return 0; +} + +static int __maybe_unused rvin_resume(struct device *dev) +{ + struct rvin_dev *vin = dev_get_drvdata(dev); + + if (vin->state != SUSPENDED) + return 0; + + /* + * Restore group master CHSEL setting. + * + * This needs to be done by every VIN resuming not only the master + * as we don't know if and in which order the master VINs will + * be resumed. + */ + if (vin->info->use_mc) { + unsigned int master_id = rvin_group_id_to_master(vin->id); + struct rvin_dev *master = vin->group->vin[master_id]; + int ret; + + if (WARN_ON(!master)) + return -ENODEV; + + ret = rvin_set_channel_routing(master, master->chsel); + if (ret) + return ret; + } + + return rvin_start_streaming(vin); +} + /* ----------------------------------------------------------------------------- * Platform Device Driver */ @@ -1405,9 +1453,12 @@ static int rcar_vin_remove(struct platform_device *pdev) return 0; } +static SIMPLE_DEV_PM_OPS(rvin_pm_ops, rvin_suspend, rvin_resume); + static struct platform_driver rcar_vin_driver = { .driver = { .name = "rcar-vin", + .pm = &rvin_pm_ops, .of_match_table = rvin_of_id_table, }, .probe = rcar_vin_probe, diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h index 4ec8584709c8..4539bd53d9d4 100644 --- a/drivers/media/platform/rcar-vin/rcar-vin.h +++ b/drivers/media/platform/rcar-vin/rcar-vin.h @@ -49,16 +49,18 @@ enum rvin_csi_id { }; /** - * STOPPED - No operation in progress - * STARTING - Capture starting up - * RUNNING - Operation in progress have buffers - * STOPPING - Stopping operation + * STOPPED - No operation in progress + * STARTING - Capture starting up + * RUNNING - Operation in progress have buffers + * STOPPING - Stopping operation + * SUSPENDED - Capture is suspended */ enum rvin_dma_state { STOPPED = 0, STARTING, RUNNING, STOPPING, + SUSPENDED, }; /** -- cgit v1.2.3 From c7b2c0ccd064a9866b08935e48aa132fdcf2d48f Mon Sep 17 00:00:00 2001 From: Deepak R Varma Date: Fri, 16 Oct 2020 19:40:33 +0200 Subject: media: staging: media: imx: remove commented code The virtual channel is always treated as 0 once the stream enters CSI's. Commented code in the "#if 0" can be safely removed as it will not serve any purpose in future. Issue reported by checkpatch script. Signed-off-by: Deepak R Varma Acked-by: Steve Longerbeam Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx-media-csi.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index 21ebf7769696..9320e3974d86 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -1131,13 +1131,6 @@ static int csi_link_validate(struct v4l2_subdev *sd, * enters the CSI's however, they are treated internally * in the IPU as virtual channel 0. */ -#if 0 - mutex_unlock(&priv->lock); - vc_num = imx_media_find_mipi_csi2_channel(&priv->sd.entity); - if (vc_num < 0) - return vc_num; - mutex_lock(&priv->lock); -#endif ipu_csi_set_mipi_datatype(priv->csi, vc_num, &priv->format_mbus[CSI_SINK_PAD]); } -- cgit v1.2.3 From b14e7b66b08d604689e14dcd5b82855b46201699 Mon Sep 17 00:00:00 2001 From: Deepak R Varma Date: Fri, 16 Oct 2020 19:46:06 +0200 Subject: media: staging: media: imx: remove unnecessary variable use Use of variable vc_num is unnecessary here as it is used only once. Instead, the value can directly be used in place of the variable. Signed-off-by: Deepak R Varma Acked-by: Steve Longerbeam Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx-media-csi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index 9320e3974d86..db77fef07654 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -1123,7 +1123,6 @@ static int csi_link_validate(struct v4l2_subdev *sd, priv->upstream_ep = upstream_ep; is_csi2 = !is_parallel_bus(&upstream_ep); if (is_csi2) { - int vc_num = 0; /* * NOTE! It seems the virtual channels from the mipi csi-2 * receiver are used only for routing by the video mux's, @@ -1131,7 +1130,7 @@ static int csi_link_validate(struct v4l2_subdev *sd, * enters the CSI's however, they are treated internally * in the IPU as virtual channel 0. */ - ipu_csi_set_mipi_datatype(priv->csi, vc_num, + ipu_csi_set_mipi_datatype(priv->csi, 0, &priv->format_mbus[CSI_SINK_PAD]); } -- cgit v1.2.3 From 7fd85371e53c745d8e896dc89d7d37885fb6f47b Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Mon, 19 Oct 2020 18:29:17 +0200 Subject: media: remove unneeded break A break is not needed if it is preceded by a return Signed-off-by: Tom Rix Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drx39xyj/drxj.c | 7 ------- drivers/media/dvb-frontends/drxd_hard.c | 1 - drivers/media/dvb-frontends/nxt200x.c | 16 ---------------- drivers/media/dvb-frontends/si21xx.c | 2 -- drivers/media/tuners/mt2063.c | 1 - 5 files changed, 27 deletions(-) diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index 237b9d04c076..37b32d9b398d 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -2325,7 +2325,6 @@ hi_command(struct i2c_device_addr *dev_addr, const struct drxj_hi_cmd *cmd, u16 default: return -EINVAL; - break; } /* Write command */ @@ -3594,7 +3593,6 @@ static int ctrl_set_uio_cfg(struct drx_demod_instance *demod, struct drxuio_cfg break; default: return -EINVAL; - break; } /* switch ( uio_cfg->mode ) */ break; /*====================================================================*/ @@ -3618,7 +3616,6 @@ static int ctrl_set_uio_cfg(struct drx_demod_instance *demod, struct drxuio_cfg break; default: return -EINVAL; - break; } /* switch ( uio_cfg->mode ) */ break; /*====================================================================*/ @@ -3642,7 +3639,6 @@ static int ctrl_set_uio_cfg(struct drx_demod_instance *demod, struct drxuio_cfg case DRX_UIO_MODE_FIRMWARE0: default: return -EINVAL; - break; } /* switch ( uio_cfg->mode ) */ break; /*====================================================================*/ @@ -10953,7 +10949,6 @@ ctrl_set_standard(struct drx_demod_instance *demod, enum drx_standard *standard) default: ext_attr->standard = DRX_STANDARD_UNKNOWN; return -EINVAL; - break; } return 0; @@ -11074,7 +11069,6 @@ ctrl_power_mode(struct drx_demod_instance *demod, enum drx_power_mode *mode) default: /* Unknow sleep mode */ return -EINVAL; - break; } /* Check if device needs to be powered up */ @@ -11896,7 +11890,6 @@ static int drx_ctrl_u_code(struct drx_demod_instance *demod, } default: return -EINVAL; - break; } mc_data += mc_block_nr_bytes; diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c index 45f982863904..a7eb81df88c2 100644 --- a/drivers/media/dvb-frontends/drxd_hard.c +++ b/drivers/media/dvb-frontends/drxd_hard.c @@ -1622,7 +1622,6 @@ static int CorrectSysClockDeviation(struct drxd_state *state) break; default: return -1; - break; } /* Compute new sysclock value diff --git a/drivers/media/dvb-frontends/nxt200x.c b/drivers/media/dvb-frontends/nxt200x.c index 35b83b1dd82c..200b6dbc75f8 100644 --- a/drivers/media/dvb-frontends/nxt200x.c +++ b/drivers/media/dvb-frontends/nxt200x.c @@ -168,7 +168,6 @@ static int nxt200x_writereg_multibyte (struct nxt200x_state* state, u8 reg, u8* break; default: return -EINVAL; - break; } /* set multi register length */ @@ -190,7 +189,6 @@ static int nxt200x_writereg_multibyte (struct nxt200x_state* state, u8 reg, u8* break; default: return -EINVAL; - break; } pr_warn("Error writing multireg register 0x%02X\n", reg); @@ -216,7 +214,6 @@ static int nxt200x_readreg_multibyte (struct nxt200x_state* state, u8 reg, u8* d /* read the actual data */ nxt200x_readbytes(state, reg, data, len); return 0; - break; case NXT2004: /* probably not right, but gives correct values */ attr = 0x02; @@ -239,10 +236,8 @@ static int nxt200x_readreg_multibyte (struct nxt200x_state* state, u8 reg, u8* d nxt200x_readbytes(state, 0x36 + i, &data[i], 1); } return 0; - break; default: return -EINVAL; - break; } } @@ -374,7 +369,6 @@ static int nxt200x_writetuner (struct nxt200x_state* state, u8* data) break; default: return -EINVAL; - break; } return 0; } @@ -555,7 +549,6 @@ static int nxt200x_setup_frontend_parameters(struct dvb_frontend *fe) break; default: return -EINVAL; - break; } if (fe->ops.tuner_ops.calc_regs) { @@ -580,7 +573,6 @@ static int nxt200x_setup_frontend_parameters(struct dvb_frontend *fe) break; default: return -EINVAL; - break; } nxt200x_writebytes(state, 0x42, buf, 1); @@ -594,7 +586,6 @@ static int nxt200x_setup_frontend_parameters(struct dvb_frontend *fe) break; default: return -EINVAL; - break; } nxt200x_writebytes(state, 0x57, buf, 1); @@ -610,7 +601,6 @@ static int nxt200x_setup_frontend_parameters(struct dvb_frontend *fe) break; default: return -EINVAL; - break; } /* write sdmx input */ @@ -626,7 +616,6 @@ static int nxt200x_setup_frontend_parameters(struct dvb_frontend *fe) break; default: return -EINVAL; - break; } buf[1] = 0x00; switch (state->demod_chip) { @@ -638,7 +627,6 @@ static int nxt200x_setup_frontend_parameters(struct dvb_frontend *fe) break; default: return -EINVAL; - break; } /* write adc power lpf fc */ @@ -664,7 +652,6 @@ static int nxt200x_setup_frontend_parameters(struct dvb_frontend *fe) break; default: return -EINVAL; - break; } /* write kg1 */ @@ -720,7 +707,6 @@ static int nxt200x_setup_frontend_parameters(struct dvb_frontend *fe) break; default: return -EINVAL; - break; } nxt200x_writebytes(state, 0x30, buf, 1); @@ -742,7 +728,6 @@ static int nxt200x_setup_frontend_parameters(struct dvb_frontend *fe) break; default: return -EINVAL; - break; } /* write agc control reg */ @@ -1114,7 +1099,6 @@ static int nxt200x_init(struct dvb_frontend* fe) break; default: return -EINVAL; - break; } state->initialised = 1; } diff --git a/drivers/media/dvb-frontends/si21xx.c b/drivers/media/dvb-frontends/si21xx.c index a116eff417f2..e31eb2c5cc4c 100644 --- a/drivers/media/dvb-frontends/si21xx.c +++ b/drivers/media/dvb-frontends/si21xx.c @@ -464,10 +464,8 @@ static int si21xx_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage volt) switch (volt) { case SEC_VOLTAGE_18: return si21_writereg(state, LNB_CTRL_REG_1, val | 0x40); - break; case SEC_VOLTAGE_13: return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x40)); - break; default: return -EINVAL; } diff --git a/drivers/media/tuners/mt2063.c b/drivers/media/tuners/mt2063.c index 2240d214dfac..d105431a2e2d 100644 --- a/drivers/media/tuners/mt2063.c +++ b/drivers/media/tuners/mt2063.c @@ -1849,7 +1849,6 @@ static int mt2063_init(struct dvb_frontend *fe) default: return -ENODEV; - break; } while (status >= 0 && *def) { -- cgit v1.2.3 From 1342f51ec248324bec6149721e2aac1e4770c794 Mon Sep 17 00:00:00 2001 From: Robert Foss Date: Mon, 19 Oct 2020 20:56:20 +0200 Subject: media: MAINTAINERS: camss: Add Robert Foss as co-maintainer I would like to contribute some of my time to co-maintain the CAMSS driver. I'm currently working to extend CAMSS to new hardware platforms. Signed-off-by: Robert Foss Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index aa8ee8f69bc6..6955a91472af 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14466,6 +14466,7 @@ W: https://wireless.wiki.kernel.org/en/users/Drivers/ath9k F: drivers/net/wireless/ath/ath9k/ QUALCOMM CAMERA SUBSYSTEM DRIVER +M: Robert Foss M: Todor Tomov L: linux-media@vger.kernel.org S: Maintained -- cgit v1.2.3 From 57a975565c970d6dd84bc73712857decb5cae8eb Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 20 Oct 2020 16:46:55 +0200 Subject: media: staging: rkisp1: rsz: make const array static, makes object smaller Don't populate the const array dev_names on the stack but instead it static. Makes the object code smaller by 15 bytes. Before: text data bss dec hex filename 17091 2648 64 19803 4d5b media/rkisp1/rkisp1-resizer.o After: text data bss dec hex filename 17012 2712 64 19788 4d4c media/rkisp1/rkisp1-resizer.o (gcc version 10.2.0) Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/rkisp1/rkisp1-resizer.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/rkisp1/rkisp1-resizer.c b/drivers/staging/media/rkisp1/rkisp1-resizer.c index 1687d82e6c68..7ca5b47c5bf5 100644 --- a/drivers/staging/media/rkisp1/rkisp1-resizer.c +++ b/drivers/staging/media/rkisp1/rkisp1-resizer.c @@ -763,8 +763,10 @@ static void rkisp1_rsz_unregister(struct rkisp1_resizer *rsz) static int rkisp1_rsz_register(struct rkisp1_resizer *rsz) { - const char * const dev_names[] = {RKISP1_RSZ_MP_DEV_NAME, - RKISP1_RSZ_SP_DEV_NAME}; + static const char * const dev_names[] = { + RKISP1_RSZ_MP_DEV_NAME, + RKISP1_RSZ_SP_DEV_NAME + }; struct media_pad *pads = rsz->pads; struct v4l2_subdev *sd = &rsz->sd; int ret; -- cgit v1.2.3 From 69baf338fc16a4d55c78da8874ce3f06feb38c78 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Thu, 17 Sep 2020 18:08:47 +0200 Subject: media: v4l2-fwnode: Return -EINVAL for invalid bus-type Return -EINVAL if invalid bus-type is detected while parsing endpoints. Fixes: 26c1126c9b56 ("media: v4l: fwnode: Use media bus type for bus parser selection") Signed-off-by: Lad Prabhakar Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-fwnode.c | 6 +++++- include/media/v4l2-mediabus.h | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index d7bbe33840cb..dfc53d11053f 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -93,7 +93,7 @@ v4l2_fwnode_bus_type_to_mbus(enum v4l2_fwnode_bus_type type) const struct v4l2_fwnode_bus_conv *conv = get_v4l2_fwnode_bus_conv_by_fwnode_bus(type); - return conv ? conv->mbus_type : V4L2_MBUS_UNKNOWN; + return conv ? conv->mbus_type : V4L2_MBUS_INVALID; } static const char * @@ -436,6 +436,10 @@ static int __v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode, v4l2_fwnode_mbus_type_to_string(vep->bus_type), vep->bus_type); mbus_type = v4l2_fwnode_bus_type_to_mbus(bus_type); + if (mbus_type == V4L2_MBUS_INVALID) { + pr_debug("unsupported bus type %u\n", bus_type); + return -EINVAL; + } if (vep->bus_type != V4L2_MBUS_UNKNOWN) { if (mbus_type != V4L2_MBUS_UNKNOWN && diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h index 59b1de197114..c20e2dc6d432 100644 --- a/include/media/v4l2-mediabus.h +++ b/include/media/v4l2-mediabus.h @@ -103,6 +103,7 @@ * @V4L2_MBUS_CCP2: CCP2 (Compact Camera Port 2) * @V4L2_MBUS_CSI2_DPHY: MIPI CSI-2 serial interface, with D-PHY * @V4L2_MBUS_CSI2_CPHY: MIPI CSI-2 serial interface, with C-PHY + * @V4L2_MBUS_INVALID: invalid bus type (keep as last) */ enum v4l2_mbus_type { V4L2_MBUS_UNKNOWN, @@ -112,6 +113,7 @@ enum v4l2_mbus_type { V4L2_MBUS_CCP2, V4L2_MBUS_CSI2_DPHY, V4L2_MBUS_CSI2_CPHY, + V4L2_MBUS_INVALID, }; /** -- cgit v1.2.3 From 37bb22ed9c72f56096bf8917d496922220869ed3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 21 Sep 2020 18:23:19 +0200 Subject: media: i2c: imx219: simplify getting state container The pointer to 'struct v4l2_subdev' is stored in drvdata via v4l2_i2c_subdev_init() so there is no point of a dance like: struct i2c_client *client = to_i2c_client(struct device *dev) struct v4l2_subdev *sd = i2c_get_clientdata(client); This allows to remove local variable 'client' and few pointer dereferences. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx219.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 1cee45e35355..d5349d1ca485 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -1114,22 +1114,21 @@ err_unlock: /* Power/clock management functions */ static int imx219_power_on(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct imx219 *imx219 = to_imx219(sd); int ret; ret = regulator_bulk_enable(IMX219_NUM_SUPPLIES, imx219->supplies); if (ret) { - dev_err(&client->dev, "%s: failed to enable regulators\n", + dev_err(dev, "%s: failed to enable regulators\n", __func__); return ret; } ret = clk_prepare_enable(imx219->xclk); if (ret) { - dev_err(&client->dev, "%s: failed to enable clock\n", + dev_err(dev, "%s: failed to enable clock\n", __func__); goto reg_off; } @@ -1148,8 +1147,7 @@ reg_off: static int imx219_power_off(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct imx219 *imx219 = to_imx219(sd); gpiod_set_value_cansleep(imx219->reset_gpio, 0); @@ -1161,8 +1159,7 @@ static int imx219_power_off(struct device *dev) static int __maybe_unused imx219_suspend(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct imx219 *imx219 = to_imx219(sd); if (imx219->streaming) @@ -1173,8 +1170,7 @@ static int __maybe_unused imx219_suspend(struct device *dev) static int __maybe_unused imx219_resume(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct imx219 *imx219 = to_imx219(sd); int ret; -- cgit v1.2.3 From b50ce25de76949b3543a42f59c8386d626166765 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 21 Sep 2020 18:23:20 +0200 Subject: media: i2c: imx290: simplify getting state container The pointer to 'struct v4l2_subdev' is stored in drvdata via v4l2_i2c_subdev_init() so there is no point of a dance like: struct i2c_client *client = to_i2c_client(struct device *dev) struct v4l2_subdev *sd = i2c_get_clientdata(client); This allows to remove local variable 'client' and few pointer dereferences. White at it, use 'dev' directly instead of 'imx290->dev'. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx290.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index adcddf3204f7..6319a42057d2 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -842,20 +842,19 @@ exit: static int imx290_power_on(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct imx290 *imx290 = to_imx290(sd); int ret; ret = clk_prepare_enable(imx290->xclk); if (ret) { - dev_err(imx290->dev, "Failed to enable clock\n"); + dev_err(dev, "Failed to enable clock\n"); return ret; } ret = regulator_bulk_enable(IMX290_NUM_SUPPLIES, imx290->supplies); if (ret) { - dev_err(imx290->dev, "Failed to enable regulators\n"); + dev_err(dev, "Failed to enable regulators\n"); clk_disable_unprepare(imx290->xclk); return ret; } @@ -872,8 +871,7 @@ static int imx290_power_on(struct device *dev) static int imx290_power_off(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct imx290 *imx290 = to_imx290(sd); clk_disable_unprepare(imx290->xclk); -- cgit v1.2.3 From 74290ac11b78b6eb36f0aab37bc5ef9e7a08239a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 21 Sep 2020 18:23:21 +0200 Subject: media: i2c: imx319: simplify getting state container The pointer to 'struct v4l2_subdev' is stored in drvdata via v4l2_i2c_subdev_init() so there is no point of a dance like: struct i2c_client *client = to_i2c_client(struct device *dev) struct v4l2_subdev *sd = i2c_get_clientdata(client); This allows to remove local variable 'client' and few pointer dereferences. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx319.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/imx319.c b/drivers/media/i2c/imx319.c index 17c2e4b41221..8b86fc65364e 100644 --- a/drivers/media/i2c/imx319.c +++ b/drivers/media/i2c/imx319.c @@ -2179,8 +2179,7 @@ err_unlock: static int __maybe_unused imx319_suspend(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct imx319 *imx319 = to_imx319(sd); if (imx319->streaming) @@ -2191,8 +2190,7 @@ static int __maybe_unused imx319_suspend(struct device *dev) static int __maybe_unused imx319_resume(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct imx319 *imx319 = to_imx319(sd); int ret; -- cgit v1.2.3 From 5347e1ed7761cf5fb62b03e488a05d90536a1bea Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 21 Sep 2020 18:23:22 +0200 Subject: media: i2c: imx319: silence unused acpi_device_id warning If driver is built without ACPI, the struct acpi_device_id won't be used: drivers/media/i2c/imx319.c:2536:36: warning: 'imx319_acpi_ids' defined but not used [-Wunused-const-variable=] Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx319.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/imx319.c b/drivers/media/i2c/imx319.c index 8b86fc65364e..8473c0bbb35d 100644 --- a/drivers/media/i2c/imx319.c +++ b/drivers/media/i2c/imx319.c @@ -2533,7 +2533,7 @@ static const struct dev_pm_ops imx319_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(imx319_suspend, imx319_resume) }; -static const struct acpi_device_id imx319_acpi_ids[] = { +static const struct acpi_device_id imx319_acpi_ids[] __maybe_unused = { { "SONY319A" }, { /* sentinel */ } }; -- cgit v1.2.3 From be0b9b6399aadc8888996ad8724c96862205a2cb Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 21 Sep 2020 18:23:23 +0200 Subject: media: i2c: imx355: simplify getting state container The pointer to 'struct v4l2_subdev' is stored in drvdata via v4l2_i2c_subdev_init() so there is no point of a dance like: struct i2c_client *client = to_i2c_client(struct device *dev) struct v4l2_subdev *sd = i2c_get_clientdata(client); This allows to remove local variable 'client' and few pointer dereferences. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx355.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c index bed293b60e50..51245e71b411 100644 --- a/drivers/media/i2c/imx355.c +++ b/drivers/media/i2c/imx355.c @@ -1480,8 +1480,7 @@ err_unlock: static int __maybe_unused imx355_suspend(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct imx355 *imx355 = to_imx355(sd); if (imx355->streaming) @@ -1492,8 +1491,7 @@ static int __maybe_unused imx355_suspend(struct device *dev) static int __maybe_unused imx355_resume(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct imx355 *imx355 = to_imx355(sd); int ret; -- cgit v1.2.3 From bbaecc36b7e0d68d18fde9650261d4df703f110d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 21 Sep 2020 18:23:24 +0200 Subject: media: i2c: imx355: silence unused acpi_device_id warning If driver is built without ACPI, the struct acpi_device_id won't be used: drivers/media/i2c/imx355.c:1836:36: warning: 'imx355_acpi_ids' defined but not used [-Wunused-const-variable=] [Sakari Ailus: Added a space before __maybe_unused] Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx355.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c index 51245e71b411..700f7467fb31 100644 --- a/drivers/media/i2c/imx355.c +++ b/drivers/media/i2c/imx355.c @@ -1833,7 +1833,7 @@ static const struct dev_pm_ops imx355_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(imx355_suspend, imx355_resume) }; -static const struct acpi_device_id imx355_acpi_ids[] = { +static const struct acpi_device_id imx355_acpi_ids[] __maybe_unused = { { "SONY355A" }, { /* sentinel */ } }; -- cgit v1.2.3 From 3d5201233ad593edc92e6fb6eb3838e0158df988 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 21 Sep 2020 18:23:25 +0200 Subject: media: i2c: ad5820: simplify getting state container The pointer to 'struct v4l2_subdev' is stored in drvdata via v4l2_i2c_subdev_init() so there is no point of a dance like: struct i2c_client *client = to_i2c_client(struct device *dev) struct v4l2_subdev *sd = i2c_get_clientdata(client); This allows to remove local variable 'client' and few pointer dereferences. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ad5820.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/ad5820.c b/drivers/media/i2c/ad5820.c index 19c74db0649f..2958a4694461 100644 --- a/drivers/media/i2c/ad5820.c +++ b/drivers/media/i2c/ad5820.c @@ -270,8 +270,7 @@ static const struct v4l2_subdev_internal_ops ad5820_internal_ops = { */ static int __maybe_unused ad5820_suspend(struct device *dev) { - struct i2c_client *client = container_of(dev, struct i2c_client, dev); - struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct v4l2_subdev *subdev = dev_get_drvdata(dev); struct ad5820_device *coil = to_ad5820_device(subdev); if (!coil->power_count) @@ -282,8 +281,7 @@ static int __maybe_unused ad5820_suspend(struct device *dev) static int __maybe_unused ad5820_resume(struct device *dev) { - struct i2c_client *client = container_of(dev, struct i2c_client, dev); - struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct v4l2_subdev *subdev = dev_get_drvdata(dev); struct ad5820_device *coil = to_ad5820_device(subdev); if (!coil->power_count) -- cgit v1.2.3 From 22a7c931c6659804aa63ab75933939a1ed2710c5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 21 Sep 2020 18:23:26 +0200 Subject: media: i2c: adp1653: simplify getting state container The pointer to 'struct v4l2_subdev' is stored in drvdata via v4l2_i2c_subdev_init() so there is no point of a dance like: struct i2c_client *client = to_i2c_client(struct device *dev) struct v4l2_subdev *sd = i2c_get_clientdata(client); This allows to remove local variable 'client' and few pointer dereferences. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adp1653.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/adp1653.c b/drivers/media/i2c/adp1653.c index 694125a59f64..522a0b10e415 100644 --- a/drivers/media/i2c/adp1653.c +++ b/drivers/media/i2c/adp1653.c @@ -379,8 +379,7 @@ static const struct v4l2_subdev_internal_ops adp1653_internal_ops = { static int adp1653_suspend(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct v4l2_subdev *subdev = dev_get_drvdata(dev); struct adp1653_flash *flash = to_adp1653_flash(subdev); if (!flash->power_count) @@ -391,8 +390,7 @@ static int adp1653_suspend(struct device *dev) static int adp1653_resume(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct v4l2_subdev *subdev = dev_get_drvdata(dev); struct adp1653_flash *flash = to_adp1653_flash(subdev); if (!flash->power_count) -- cgit v1.2.3 From 17ed3c90dc05c1fd8ccbebaec99d59aea8288b93 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 21 Sep 2020 18:23:27 +0200 Subject: media: i2c: adv7180: simplify getting state container The pointer to 'struct v4l2_subdev' is stored in drvdata via v4l2_i2c_subdev_init() so there is no point of a dance like: struct i2c_client *client = to_i2c_client(struct device *dev) struct v4l2_subdev *sd = i2c_get_clientdata(client); This allows to remove local variable 'client' and few pointer dereferences. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7180.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 4498d14d3429..44bb6fe85644 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -1454,8 +1454,7 @@ MODULE_DEVICE_TABLE(i2c, adv7180_id); #ifdef CONFIG_PM_SLEEP static int adv7180_suspend(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct adv7180_state *state = to_state(sd); return adv7180_set_power(state, false); @@ -1463,8 +1462,7 @@ static int adv7180_suspend(struct device *dev) static int adv7180_resume(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct adv7180_state *state = to_state(sd); int ret; -- cgit v1.2.3 From 334abb57b271ae25a95c0436582e4e7bdb660ce1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 21 Sep 2020 18:23:28 +0200 Subject: media: i2c: ak7375: simplify getting state container The pointer to 'struct v4l2_subdev' is stored in drvdata via v4l2_i2c_subdev_init() so there is no point of a dance like: struct i2c_client *client = to_i2c_client(struct device *dev) struct v4l2_subdev *sd = i2c_get_clientdata(client); This allows to remove local variable 'client' and few pointer dereferences. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ak7375.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/ak7375.c b/drivers/media/i2c/ak7375.c index 7b14b11605ca..e1f94ee0f48f 100644 --- a/drivers/media/i2c/ak7375.c +++ b/drivers/media/i2c/ak7375.c @@ -196,9 +196,7 @@ static int ak7375_remove(struct i2c_client *client) */ static int __maybe_unused ak7375_vcm_suspend(struct device *dev) { - - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct ak7375_device *ak7375_dev = sd_to_ak7375_vcm(sd); int ret, val; @@ -233,8 +231,7 @@ static int __maybe_unused ak7375_vcm_suspend(struct device *dev) */ static int __maybe_unused ak7375_vcm_resume(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct ak7375_device *ak7375_dev = sd_to_ak7375_vcm(sd); int ret, val; -- cgit v1.2.3 From 92172a3105d2ce32dcdc0a4b0b28d449faceb82a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 21 Sep 2020 18:23:29 +0200 Subject: media: i2c: dw9768: simplify getting state container The pointer to 'struct v4l2_subdev' is stored in drvdata via v4l2_i2c_subdev_init() so there is no point of a dance like: struct i2c_client *client = to_i2c_client(struct device *dev) struct v4l2_subdev *sd = i2c_get_clientdata(client); This allows to remove local variable 'client' and few pointer dereferences. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/dw9768.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/dw9768.c b/drivers/media/i2c/dw9768.c index 45cdd924b565..8b8cb4b077b5 100644 --- a/drivers/media/i2c/dw9768.c +++ b/drivers/media/i2c/dw9768.c @@ -315,8 +315,7 @@ static int dw9768_release(struct dw9768 *dw9768) static int dw9768_runtime_suspend(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct dw9768 *dw9768 = sd_to_dw9768(sd); dw9768_release(dw9768); @@ -328,8 +327,7 @@ static int dw9768_runtime_suspend(struct device *dev) static int dw9768_runtime_resume(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct dw9768 *dw9768 = sd_to_dw9768(sd); int ret; -- cgit v1.2.3 From f6d549174f234d757405ebde1973031c6bb95177 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 21 Sep 2020 18:23:30 +0200 Subject: media: i2c: et8ek8: simplify getting state container The pointer to 'struct v4l2_subdev' is stored in drvdata via v4l2_i2c_subdev_init() so there is no point of a dance like: struct i2c_client *client = to_i2c_client(struct device *dev) struct v4l2_subdev *sd = i2c_get_clientdata(client); This allows to remove local variable 'client' and few pointer dereferences. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/et8ek8/et8ek8_driver.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/et8ek8/et8ek8_driver.c b/drivers/media/i2c/et8ek8/et8ek8_driver.c index 256acf73d5ea..122af761c8e3 100644 --- a/drivers/media/i2c/et8ek8/et8ek8_driver.c +++ b/drivers/media/i2c/et8ek8/et8ek8_driver.c @@ -1237,7 +1237,7 @@ static ssize_t et8ek8_priv_mem_read(struct device *dev, struct device_attribute *attr, char *buf) { - struct v4l2_subdev *subdev = i2c_get_clientdata(to_i2c_client(dev)); + struct v4l2_subdev *subdev = dev_get_drvdata(dev); struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev); #if PAGE_SIZE < ET8EK8_PRIV_MEM_SIZE @@ -1374,8 +1374,7 @@ static const struct v4l2_subdev_internal_ops et8ek8_internal_ops = { */ static int __maybe_unused et8ek8_suspend(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct v4l2_subdev *subdev = dev_get_drvdata(dev); struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev); if (!sensor->power_count) @@ -1386,8 +1385,7 @@ static int __maybe_unused et8ek8_suspend(struct device *dev) static int __maybe_unused et8ek8_resume(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct v4l2_subdev *subdev = dev_get_drvdata(dev); struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev); if (!sensor->power_count) -- cgit v1.2.3 From 34b3c34d104c70fc9bad1e34be7bfff33661ffdf Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 21 Sep 2020 18:23:31 +0200 Subject: media: i2c: hi556: simplify getting state container The pointer to 'struct v4l2_subdev' is stored in drvdata via v4l2_i2c_subdev_init() so there is no point of a dance like: struct i2c_client *client = to_i2c_client(struct device *dev) struct v4l2_subdev *sd = i2c_get_clientdata(client); This allows to remove local variable 'client' and few pointer dereferences. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/hi556.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/hi556.c b/drivers/media/i2c/hi556.c index c66cd1446c0f..c74736845d7a 100644 --- a/drivers/media/i2c/hi556.c +++ b/drivers/media/i2c/hi556.c @@ -839,8 +839,7 @@ static int hi556_set_stream(struct v4l2_subdev *sd, int enable) static int __maybe_unused hi556_suspend(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct hi556 *hi556 = to_hi556(sd); mutex_lock(&hi556->mutex); @@ -854,8 +853,7 @@ static int __maybe_unused hi556_suspend(struct device *dev) static int __maybe_unused hi556_resume(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct hi556 *hi556 = to_hi556(sd); int ret; -- cgit v1.2.3 From 00dd015d176a860a30c280d9d598122797955923 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 21 Sep 2020 18:23:32 +0200 Subject: media: i2c: ov13858: simplify getting state container The pointer to 'struct v4l2_subdev' is stored in drvdata via v4l2_i2c_subdev_init() so there is no point of a dance like: struct i2c_client *client = to_i2c_client(struct device *dev) struct v4l2_subdev *sd = i2c_get_clientdata(client); This allows to remove local variable 'client' and few pointer dereferences. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov13858.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c index 236ad2c816b7..2f3be7a80cef 100644 --- a/drivers/media/i2c/ov13858.c +++ b/drivers/media/i2c/ov13858.c @@ -1505,8 +1505,7 @@ err_unlock: static int __maybe_unused ov13858_suspend(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct ov13858 *ov13858 = to_ov13858(sd); if (ov13858->streaming) @@ -1517,8 +1516,7 @@ static int __maybe_unused ov13858_suspend(struct device *dev) static int __maybe_unused ov13858_resume(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct ov13858 *ov13858 = to_ov13858(sd); int ret; -- cgit v1.2.3 From 7519296da44f5eb15a092f7d92de6c101de2461a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 21 Sep 2020 18:23:33 +0200 Subject: media: i2c: ov2680: simplify getting state container The pointer to 'struct v4l2_subdev' is stored in drvdata via v4l2_i2c_subdev_init() so there is no point of a dance like: struct i2c_client *client = to_i2c_client(struct device *dev) struct v4l2_subdev *sd = i2c_get_clientdata(client); This allows to remove local variable 'client' and few pointer dereferences. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov2680.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/ov2680.c b/drivers/media/i2c/ov2680.c index 59cdbc33658c..178dfe985a25 100644 --- a/drivers/media/i2c/ov2680.c +++ b/drivers/media/i2c/ov2680.c @@ -1111,8 +1111,7 @@ static int ov2680_remove(struct i2c_client *client) static int __maybe_unused ov2680_suspend(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct ov2680_dev *sensor = to_ov2680_dev(sd); if (sensor->is_streaming) @@ -1123,8 +1122,7 @@ static int __maybe_unused ov2680_suspend(struct device *dev) static int __maybe_unused ov2680_resume(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct ov2680_dev *sensor = to_ov2680_dev(sd); int ret; -- cgit v1.2.3 From dab24a220e03454c79846307dee1b0f496059fe1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 21 Sep 2020 18:23:34 +0200 Subject: media: i2c: ov2685: simplify getting state container The pointer to 'struct v4l2_subdev' is stored in drvdata via v4l2_i2c_subdev_init() so there is no point of a dance like: struct i2c_client *client = to_i2c_client(struct device *dev) struct v4l2_subdev *sd = i2c_get_clientdata(client); This allows to remove local variable 'client' and few pointer dereferences. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov2685.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/ov2685.c b/drivers/media/i2c/ov2685.c index 6814583d9606..49a2dcedb347 100644 --- a/drivers/media/i2c/ov2685.c +++ b/drivers/media/i2c/ov2685.c @@ -506,8 +506,7 @@ static int ov2685_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) static int __maybe_unused ov2685_runtime_resume(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct ov2685 *ov2685 = to_ov2685(sd); return __ov2685_power_on(ov2685); @@ -515,8 +514,7 @@ static int __maybe_unused ov2685_runtime_resume(struct device *dev) static int __maybe_unused ov2685_runtime_suspend(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct ov2685 *ov2685 = to_ov2685(sd); __ov2685_power_off(ov2685); -- cgit v1.2.3 From 5fa6f1fc32ca5d3b1c7524e1ca5581602f0dab7d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 21 Sep 2020 18:23:35 +0200 Subject: media: i2c: ov2740: simplify getting state container The pointer to 'struct v4l2_subdev' is stored in drvdata via v4l2_i2c_subdev_init() so there is no point of a dance like: struct i2c_client *client = to_i2c_client(struct device *dev) struct v4l2_subdev *sd = i2c_get_clientdata(client); This allows to remove local variable 'client' and few pointer dereferences. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov2740.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c index bd0d45b0d43f..0d32b0c0ca11 100644 --- a/drivers/media/i2c/ov2740.c +++ b/drivers/media/i2c/ov2740.c @@ -674,8 +674,7 @@ static int ov2740_set_stream(struct v4l2_subdev *sd, int enable) static int __maybe_unused ov2740_suspend(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct ov2740 *ov2740 = to_ov2740(sd); mutex_lock(&ov2740->mutex); @@ -689,8 +688,7 @@ static int __maybe_unused ov2740_suspend(struct device *dev) static int __maybe_unused ov2740_resume(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct ov2740 *ov2740 = to_ov2740(sd); int ret = 0; -- cgit v1.2.3 From bf3965577aff6c6e88e75ac2897f06a973abea1c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 21 Sep 2020 18:23:36 +0200 Subject: media: i2c: ov5670: simplify getting state container The pointer to 'struct v4l2_subdev' is stored in drvdata via v4l2_i2c_subdev_init() so there is no point of a dance like: struct i2c_client *client = to_i2c_client(struct device *dev) struct v4l2_subdev *sd = i2c_get_clientdata(client); This allows to remove local variable 'client' and few pointer dereferences. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5670.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index f26252e35e08..148fd4e05029 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -2373,8 +2373,7 @@ unlock_and_return: static int __maybe_unused ov5670_suspend(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct ov5670 *ov5670 = to_ov5670(sd); if (ov5670->streaming) @@ -2385,8 +2384,7 @@ static int __maybe_unused ov5670_suspend(struct device *dev) static int __maybe_unused ov5670_resume(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct ov5670 *ov5670 = to_ov5670(sd); int ret; -- cgit v1.2.3 From 1a74712569404be7ac5b0bef9ec5d92fb0dd3cc9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 21 Sep 2020 18:23:37 +0200 Subject: media: i2c: ov5675: simplify getting state container The pointer to 'struct v4l2_subdev' is stored in drvdata via v4l2_i2c_subdev_init() so there is no point of a dance like: struct i2c_client *client = to_i2c_client(struct device *dev) struct v4l2_subdev *sd = i2c_get_clientdata(client); This allows to remove local variable 'client' and few pointer dereferences. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5675.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/ov5675.c b/drivers/media/i2c/ov5675.c index 9540ce8918f0..5e35808037ad 100644 --- a/drivers/media/i2c/ov5675.c +++ b/drivers/media/i2c/ov5675.c @@ -889,8 +889,7 @@ static int ov5675_set_stream(struct v4l2_subdev *sd, int enable) static int __maybe_unused ov5675_suspend(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct ov5675 *ov5675 = to_ov5675(sd); mutex_lock(&ov5675->mutex); @@ -904,8 +903,7 @@ static int __maybe_unused ov5675_suspend(struct device *dev) static int __maybe_unused ov5675_resume(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct ov5675 *ov5675 = to_ov5675(sd); int ret; -- cgit v1.2.3 From 8666b3197bcd2834d851051a5dbb232f4824622a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 21 Sep 2020 18:23:38 +0200 Subject: media: i2c: ov5695: simplify getting state container The pointer to 'struct v4l2_subdev' is stored in drvdata via v4l2_i2c_subdev_init() so there is no point of a dance like: struct i2c_client *client = to_i2c_client(struct device *dev) struct v4l2_subdev *sd = i2c_get_clientdata(client); This allows to remove local variable 'client' and few pointer dereferences. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5695.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/ov5695.c b/drivers/media/i2c/ov5695.c index cc678d9d2e0d..bbccb6f9582f 100644 --- a/drivers/media/i2c/ov5695.c +++ b/drivers/media/i2c/ov5695.c @@ -1033,8 +1033,7 @@ static void __ov5695_power_off(struct ov5695 *ov5695) static int __maybe_unused ov5695_runtime_resume(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct ov5695 *ov5695 = to_ov5695(sd); return __ov5695_power_on(ov5695); @@ -1042,8 +1041,7 @@ static int __maybe_unused ov5695_runtime_resume(struct device *dev) static int __maybe_unused ov5695_runtime_suspend(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct ov5695 *ov5695 = to_ov5695(sd); __ov5695_power_off(ov5695); -- cgit v1.2.3 From fc7586e7c85f87f84d571260b6c4e6fcba92b445 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 21 Sep 2020 18:23:39 +0200 Subject: media: i2c: ov7740: simplify getting state container The pointer to 'struct v4l2_subdev' is stored in drvdata via v4l2_i2c_subdev_init() so there is no point of a dance like: struct i2c_client *client = to_i2c_client(struct device *dev) struct v4l2_subdev *sd = i2c_get_clientdata(client); This allows to remove local variable 'client' and few pointer dereferences. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov7740.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c index 5832461c032d..47a9003d29d6 100644 --- a/drivers/media/i2c/ov7740.c +++ b/drivers/media/i2c/ov7740.c @@ -1176,8 +1176,7 @@ static int ov7740_remove(struct i2c_client *client) static int __maybe_unused ov7740_runtime_suspend(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); ov7740_set_power(ov7740, 0); @@ -1187,8 +1186,7 @@ static int __maybe_unused ov7740_runtime_suspend(struct device *dev) static int __maybe_unused ov7740_runtime_resume(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); return ov7740_set_power(ov7740, 1); -- cgit v1.2.3 From 9a855b73e8ed8bb65cfc322456b6dd32143b0f69 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 21 Sep 2020 18:23:40 +0200 Subject: media: i2c: ov8856: simplify getting state container The pointer to 'struct v4l2_subdev' is stored in drvdata via v4l2_i2c_subdev_init() so there is no point of a dance like: struct i2c_client *client = to_i2c_client(struct device *dev) struct v4l2_subdev *sd = i2c_get_clientdata(client); This allows to remove local variable 'client' and few pointer dereferences. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov8856.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c index 2f4ceaa80593..d8cefd3d4045 100644 --- a/drivers/media/i2c/ov8856.c +++ b/drivers/media/i2c/ov8856.c @@ -1417,8 +1417,7 @@ static void __ov8856_power_off(struct ov8856 *ov8856) static int __maybe_unused ov8856_suspend(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct ov8856 *ov8856 = to_ov8856(sd); mutex_lock(&ov8856->mutex); @@ -1433,8 +1432,7 @@ static int __maybe_unused ov8856_suspend(struct device *dev) static int __maybe_unused ov8856_resume(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct ov8856 *ov8856 = to_ov8856(sd); int ret; -- cgit v1.2.3 From b5783c4d1fbeb2fc2d2fc8f2844e07eb65fb2cd3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 21 Sep 2020 18:23:41 +0200 Subject: media: i2c: smiapp: simplify getting state container The pointer to 'struct v4l2_subdev' is stored in drvdata via v4l2_i2c_subdev_init() so there is no point of a dance like: struct i2c_client *client = to_i2c_client(struct device *dev) struct v4l2_subdev *sd = i2c_get_clientdata(client); This allows to remove local variable 'client' and few pointer dereferences. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 6fc0680a93d0..105ef29152e8 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -1185,8 +1185,7 @@ out: static int smiapp_power_on(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct v4l2_subdev *subdev = dev_get_drvdata(dev); struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); /* * The sub-device related to the I2C device is always the @@ -1199,14 +1198,14 @@ static int smiapp_power_on(struct device *dev) rval = regulator_enable(sensor->vana); if (rval) { - dev_err(&client->dev, "failed to enable vana regulator\n"); + dev_err(dev, "failed to enable vana regulator\n"); return rval; } usleep_range(1000, 1000); rval = clk_prepare_enable(sensor->ext_clk); if (rval < 0) { - dev_dbg(&client->dev, "failed to enable xclk\n"); + dev_dbg(dev, "failed to enable xclk\n"); goto out_xclk_fail; } usleep_range(1000, 1000); @@ -1230,7 +1229,7 @@ static int smiapp_power_on(struct device *dev) if (sensor->hwcfg->i2c_addr_alt) { rval = smiapp_change_cci_addr(sensor); if (rval) { - dev_err(&client->dev, "cci address change error\n"); + dev_err(dev, "cci address change error\n"); goto out_cci_addr_fail; } } @@ -1238,14 +1237,14 @@ static int smiapp_power_on(struct device *dev) rval = smiapp_write(sensor, SMIAPP_REG_U8_SOFTWARE_RESET, SMIAPP_SOFTWARE_RESET); if (rval < 0) { - dev_err(&client->dev, "software reset failed\n"); + dev_err(dev, "software reset failed\n"); goto out_cci_addr_fail; } if (sensor->hwcfg->i2c_addr_alt) { rval = smiapp_change_cci_addr(sensor); if (rval) { - dev_err(&client->dev, "cci address change error\n"); + dev_err(dev, "cci address change error\n"); goto out_cci_addr_fail; } } @@ -1253,7 +1252,7 @@ static int smiapp_power_on(struct device *dev) rval = smiapp_write(sensor, SMIAPP_REG_U16_COMPRESSION_MODE, SMIAPP_COMPRESSION_MODE_SIMPLE_PREDICTOR); if (rval) { - dev_err(&client->dev, "compression mode set failed\n"); + dev_err(dev, "compression mode set failed\n"); goto out_cci_addr_fail; } @@ -1261,28 +1260,28 @@ static int smiapp_power_on(struct device *dev) sensor, SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ, sensor->hwcfg->ext_clk / (1000000 / (1 << 8))); if (rval) { - dev_err(&client->dev, "extclk frequency set failed\n"); + dev_err(dev, "extclk frequency set failed\n"); goto out_cci_addr_fail; } rval = smiapp_write(sensor, SMIAPP_REG_U8_CSI_LANE_MODE, sensor->hwcfg->lanes - 1); if (rval) { - dev_err(&client->dev, "csi lane mode set failed\n"); + dev_err(dev, "csi lane mode set failed\n"); goto out_cci_addr_fail; } rval = smiapp_write(sensor, SMIAPP_REG_U8_FAST_STANDBY_CTRL, SMIAPP_FAST_STANDBY_CTRL_IMMEDIATE); if (rval) { - dev_err(&client->dev, "fast standby set failed\n"); + dev_err(dev, "fast standby set failed\n"); goto out_cci_addr_fail; } rval = smiapp_write(sensor, SMIAPP_REG_U8_CSI_SIGNALLING_MODE, sensor->hwcfg->csi_signalling_mode); if (rval) { - dev_err(&client->dev, "csi signalling mode set failed\n"); + dev_err(dev, "csi signalling mode set failed\n"); goto out_cci_addr_fail; } @@ -1294,7 +1293,7 @@ static int smiapp_power_on(struct device *dev) rval = smiapp_call_quirk(sensor, post_poweron); if (rval) { - dev_err(&client->dev, "post_poweron quirks failed\n"); + dev_err(dev, "post_poweron quirks failed\n"); goto out_cci_addr_fail; } @@ -1312,8 +1311,7 @@ out_xclk_fail: static int smiapp_power_off(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct v4l2_subdev *subdev = dev_get_drvdata(dev); struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); struct smiapp_sensor *sensor = container_of(ssd, struct smiapp_sensor, ssds[0]); -- cgit v1.2.3 From 1c891423d7059f65f45beff408923fe0b34d85e5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 21 Sep 2020 18:23:42 +0200 Subject: media: i2c: tvp5150: simplify getting state container The pointer to 'struct v4l2_subdev' is stored in drvdata via v4l2_i2c_subdev_init() so there is no point of a dance like: struct i2c_client *client = to_i2c_client(struct device *dev) struct v4l2_subdev *sd = i2c_get_clientdata(client); This allows to remove local variable 'client' and few pointer dereferences. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvp5150.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 7d9401219a3a..29f65bb6103d 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -1413,8 +1413,7 @@ static const struct media_entity_operations tvp5150_sd_media_ops = { ****************************************************************************/ static int __maybe_unused tvp5150_runtime_suspend(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct tvp5150 *decoder = to_tvp5150(sd); if (decoder->irq) @@ -1427,8 +1426,7 @@ static int __maybe_unused tvp5150_runtime_suspend(struct device *dev) static int __maybe_unused tvp5150_runtime_resume(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct tvp5150 *decoder = to_tvp5150(sd); if (decoder->irq) -- cgit v1.2.3 From 1d7b18a9ee5513fe45175ccb8a29ae08ad110fb2 Mon Sep 17 00:00:00 2001 From: Bingbu Cao Date: Fri, 25 Sep 2020 03:59:20 +0200 Subject: media: ov2740: change the minimal exposure value to 4 The minimal valid exposure value should be 4 lines instead of 8 for ov2740 mannual exposure control. Signed-off-by: Bingbu Cao Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov2740.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c index 0d32b0c0ca11..64ecb6917dd3 100644 --- a/drivers/media/i2c/ov2740.c +++ b/drivers/media/i2c/ov2740.c @@ -37,7 +37,7 @@ /* Exposure controls from sensor */ #define OV2740_REG_EXPOSURE 0x3500 -#define OV2740_EXPOSURE_MIN 8 +#define OV2740_EXPOSURE_MIN 4 #define OV2740_EXPOSURE_MAX_MARGIN 8 #define OV2740_EXPOSURE_STEP 1 -- cgit v1.2.3 From e0f822f8d9698e47cb6781538bc7490fba638979 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Wed, 30 Sep 2020 03:13:22 +0200 Subject: media: ov2740: select regmap Fix OV2740 build breakage by selecting REGMAP_I2C config: ov2740.c:1011:23: error: variable has incomplete type 'struct regmap_config' struct regmap_config regmap_config = { }; ^ ov2740.c:1011:9: note: forward declaration of 'struct regmap_config' struct regmap_config regmap_config = { }; ^ ov2740.c:1028:11: error: implicit declaration of function 'devm_regmap_init_i2c' regmap = devm_regmap_init_i2c(client, ®map_config); Signed-off-by: Sergey Senozhatsky Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 878f66ef2719..c64326ca331c 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -877,6 +877,7 @@ config VIDEO_OV2740 select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE + select REGMAP_I2C help This is a Video4Linux2 sensor driver for the OmniVision OV2740 camera. -- cgit v1.2.3 From 51a4756519eabb67c8bb94746462b3d4e72213ce Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Wed, 16 Sep 2020 12:46:45 +0200 Subject: media: v4l2-async: Fix trivial documentation typo Fix the incorrect spelling asyncrhronous as asynchronous, which is visible in the public documentation of enum v4l2_async_match_type. Fixes: ab4f5a4afc2d ("[media] v4l2-async: document the remaining stuff") Signed-off-by: Kieran Bingham Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-async.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h index d6e31234826f..0e04b5b2ebb0 100644 --- a/include/media/v4l2-async.h +++ b/include/media/v4l2-async.h @@ -27,7 +27,7 @@ struct v4l2_async_notifier; * @V4L2_ASYNC_MATCH_I2C: Match will check for I2C adapter ID and address * @V4L2_ASYNC_MATCH_FWNODE: Match will use firmware node * - * This enum is used by the asyncrhronous sub-device logic to define the + * This enum is used by the asynchronous sub-device logic to define the * algorithm that will be used to match an asynchronous device. */ enum v4l2_async_match_type { -- cgit v1.2.3 From c87bfb6240598a150efa536d2717ced2f409fe5e Mon Sep 17 00:00:00 2001 From: Sowjanya Komatineni Date: Mon, 21 Sep 2020 23:39:37 +0200 Subject: media: i2c: imx274: Fix Y_OUT_SIZE register setting As per Sony IMX274 Y_OUT_SIZE should be the height of effective image output from the sensor which are the actual total lines sent over MIPI CSI to receiver. So, Y_OUT_SIZE should be same as crop height and this patch fixes it. Signed-off-by: Sowjanya Komatineni Reviewed-by: Thierry Reding Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx274.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c index e6aa9f32b6a8..55869fffe356 100644 --- a/drivers/media/i2c/imx274.c +++ b/drivers/media/i2c/imx274.c @@ -1163,7 +1163,7 @@ static int imx274_apply_trimming(struct stimx274 *imx274) (-imx274->crop.top / 2) : (imx274->crop.top / 2); v_cut = (IMX274_MAX_HEIGHT - imx274->crop.height) / 2; write_v_size = imx274->crop.height + 22; - y_out_size = imx274->crop.height + 14; + y_out_size = imx274->crop.height; err = imx274_write_mbreg(imx274, IMX274_HMAX_REG_LSB, hmax, 2); if (!err) -- cgit v1.2.3 From f4fcf0108b42a997aace451fa1a0801e1c7de0d3 Mon Sep 17 00:00:00 2001 From: Sowjanya Komatineni Date: Mon, 21 Sep 2020 23:39:38 +0200 Subject: media: i2c: imx274: Remove stop stream i2c writes during remove Sensor should already be in standby during remove and there is no need to configure sensor registers for stream stop. Signed-off-by: Sowjanya Komatineni Reviewed-by: Thierry Reding Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx274.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c index 55869fffe356..79b8b5a137d4 100644 --- a/drivers/media/i2c/imx274.c +++ b/drivers/media/i2c/imx274.c @@ -1970,9 +1970,6 @@ static int imx274_remove(struct i2c_client *client) struct v4l2_subdev *sd = i2c_get_clientdata(client); struct stimx274 *imx274 = to_imx274(sd); - /* stop stream */ - imx274_write_table(imx274, imx274_stop); - v4l2_async_unregister_subdev(sd); v4l2_ctrl_handler_free(&imx274->ctrls.handler); media_entity_cleanup(&sd->entity); -- cgit v1.2.3 From ad97bc37426c1eec1464649062352196138d5d0c Mon Sep 17 00:00:00 2001 From: Sowjanya Komatineni Date: Mon, 21 Sep 2020 23:39:39 +0200 Subject: media: i2c: imx274: Add IMX274 power on and off sequence IMX274 has analog 2.8V supply, digital core 1.8V supply, and vddl digital io 1.2V supply which are optional based on camera module design. IMX274 also need external 24Mhz clock and is optional based on camera module design. This patch adds support for IMX274 power on and off to enable and disable these supplies and external clock. Reviewed-by: Luca Ceresoli Signed-off-by: Sowjanya Komatineni Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx274.c | 184 +++++++++++++++++++++++++++++++++------------ 1 file changed, 134 insertions(+), 50 deletions(-) diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c index 79b8b5a137d4..2a6498e037cd 100644 --- a/drivers/media/i2c/imx274.c +++ b/drivers/media/i2c/imx274.c @@ -18,7 +18,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -131,6 +133,15 @@ #define IMX274_TABLE_WAIT_MS 0 #define IMX274_TABLE_END 1 +/* regulator supplies */ +static const char * const imx274_supply_names[] = { + "vddl", /* IF (1.2V) supply */ + "vdig", /* Digital Core (1.8V) supply */ + "vana", /* Analog (2.8V) supply */ +}; + +#define IMX274_NUM_SUPPLIES ARRAY_SIZE(imx274_supply_names) + /* * imx274 I2C operation related structure */ @@ -501,6 +512,8 @@ struct imx274_ctrls { * @frame_rate: V4L2 frame rate structure * @regmap: Pointer to regmap structure * @reset_gpio: Pointer to reset gpio + * @supplies: List of analog and digital supply regulators + * @inck: Pointer to sensor input clock * @lock: Mutex structure * @mode: Parameters for the selected readout mode */ @@ -514,6 +527,8 @@ struct stimx274 { struct v4l2_fract frame_interval; struct regmap *regmap; struct gpio_desc *reset_gpio; + struct regulator_bulk_data supplies[IMX274_NUM_SUPPLIES]; + struct clk *inck; struct mutex lock; /* mutex lock for operations */ const struct imx274_mode *mode; }; @@ -726,6 +741,12 @@ static int imx274_start_stream(struct stimx274 *priv) { int err = 0; + err = __v4l2_ctrl_handler_setup(&priv->ctrls.handler); + if (err) { + dev_err(&priv->client->dev, "Error %d setup controls\n", err); + return err; + } + /* * Refer to "Standby Cancel Sequence when using CSI-2" in * imx274 datasheet, it should wait 10ms or more here. @@ -767,6 +788,66 @@ static void imx274_reset(struct stimx274 *priv, int rst) usleep_range(IMX274_RESET_DELAY1, IMX274_RESET_DELAY2); } +static int imx274_power_on(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct stimx274 *imx274 = to_imx274(sd); + int ret; + + /* keep sensor in reset before power on */ + imx274_reset(imx274, 0); + + ret = clk_prepare_enable(imx274->inck); + if (ret) { + dev_err(&imx274->client->dev, + "Failed to enable input clock: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(IMX274_NUM_SUPPLIES, imx274->supplies); + if (ret) { + dev_err(&imx274->client->dev, + "Failed to enable regulators: %d\n", ret); + goto fail_reg; + } + + udelay(2); + imx274_reset(imx274, 1); + + return 0; + +fail_reg: + clk_disable_unprepare(imx274->inck); + return ret; +} + +static int imx274_power_off(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct stimx274 *imx274 = to_imx274(sd); + + imx274_reset(imx274, 0); + + regulator_bulk_disable(IMX274_NUM_SUPPLIES, imx274->supplies); + + clk_disable_unprepare(imx274->inck); + + return 0; +} + +static int imx274_regulators_get(struct device *dev, struct stimx274 *imx274) +{ + unsigned int i; + + for (i = 0; i < IMX274_NUM_SUPPLIES; i++) + imx274->supplies[i].supply = imx274_supply_names[i]; + + return devm_regulator_bulk_get(dev, IMX274_NUM_SUPPLIES, + imx274->supplies); +} + /** * imx274_s_ctrl - This is used to set the imx274 V4L2 controls * @ctrl: V4L2 control to be set @@ -781,6 +862,9 @@ static int imx274_s_ctrl(struct v4l2_ctrl *ctrl) struct stimx274 *imx274 = to_imx274(sd); int ret = -EINVAL; + if (!pm_runtime_get_if_in_use(&imx274->client->dev)) + return 0; + dev_dbg(&imx274->client->dev, "%s : s_ctrl: %s, value: %d\n", __func__, ctrl->name, ctrl->val); @@ -811,6 +895,8 @@ static int imx274_s_ctrl(struct v4l2_ctrl *ctrl) break; } + pm_runtime_put(&imx274->client->dev); + return ret; } @@ -1271,10 +1357,8 @@ unlock: * * Return: 0 on success, errors otherwise */ -static int imx274_load_default(struct stimx274 *priv) +static void imx274_load_default(struct stimx274 *priv) { - int ret; - /* load default control values */ priv->frame_interval.numerator = 1; priv->frame_interval.denominator = IMX274_DEF_FRAME_RATE; @@ -1282,29 +1366,6 @@ static int imx274_load_default(struct stimx274 *priv) priv->ctrls.gain->val = IMX274_DEF_GAIN; priv->ctrls.vflip->val = 0; priv->ctrls.test_pattern->val = TEST_PATTERN_DISABLED; - - /* update frame rate */ - ret = imx274_set_frame_interval(priv, - priv->frame_interval); - if (ret) - return ret; - - /* update exposure time */ - ret = v4l2_ctrl_s_ctrl(priv->ctrls.exposure, priv->ctrls.exposure->val); - if (ret) - return ret; - - /* update gain */ - ret = v4l2_ctrl_s_ctrl(priv->ctrls.gain, priv->ctrls.gain->val); - if (ret) - return ret; - - /* update vflip */ - ret = v4l2_ctrl_s_ctrl(priv->ctrls.vflip, priv->ctrls.vflip->val); - if (ret) - return ret; - - return 0; } /** @@ -1329,6 +1390,13 @@ static int imx274_s_stream(struct v4l2_subdev *sd, int on) mutex_lock(&imx274->lock); if (on) { + ret = pm_runtime_get_sync(&imx274->client->dev); + if (ret < 0) { + pm_runtime_put_noidle(&imx274->client->dev); + mutex_unlock(&imx274->lock); + return ret; + } + /* load mode registers */ ret = imx274_mode_regs(imx274); if (ret) @@ -1349,12 +1417,6 @@ static int imx274_s_stream(struct v4l2_subdev *sd, int on) if (ret) goto fail; - /* update exposure time */ - ret = __v4l2_ctrl_s_ctrl(imx274->ctrls.exposure, - imx274->ctrls.exposure->val); - if (ret) - goto fail; - /* start stream */ ret = imx274_start_stream(imx274); if (ret) @@ -1364,6 +1426,8 @@ static int imx274_s_stream(struct v4l2_subdev *sd, int on) ret = imx274_write_table(imx274, imx274_stop); if (ret) goto fail; + + pm_runtime_put(&imx274->client->dev); } mutex_unlock(&imx274->lock); @@ -1371,6 +1435,7 @@ static int imx274_s_stream(struct v4l2_subdev *sd, int on) return 0; fail: + pm_runtime_put(&imx274->client->dev); mutex_unlock(&imx274->lock); dev_err(&imx274->client->dev, "s_stream failed\n"); return ret; @@ -1836,6 +1901,17 @@ static int imx274_probe(struct i2c_client *client) mutex_init(&imx274->lock); + imx274->inck = devm_clk_get_optional(&client->dev, "inck"); + if (IS_ERR(imx274->inck)) + return PTR_ERR(imx274->inck); + + ret = imx274_regulators_get(&client->dev, imx274); + if (ret) { + dev_err(&client->dev, + "Failed to get power regulators, err: %d\n", ret); + return ret; + } + /* initialize format */ imx274->mode = &imx274_modes[IMX274_DEFAULT_BINNING]; imx274->crop.width = IMX274_MAX_WIDTH; @@ -1883,15 +1959,20 @@ static int imx274_probe(struct i2c_client *client) goto err_me; } - /* pull sensor out of reset */ - imx274_reset(imx274, 1); + /* power on the sensor */ + ret = imx274_power_on(&client->dev); + if (ret < 0) { + dev_err(&client->dev, + "%s : imx274 power on failed\n", __func__); + goto err_me; + } /* initialize controls */ ret = v4l2_ctrl_handler_init(&imx274->ctrls.handler, 4); if (ret < 0) { dev_err(&client->dev, "%s : ctrl handler init Failed\n", __func__); - goto err_me; + goto err_power_off; } imx274->ctrls.handler.lock = &imx274->lock; @@ -1927,22 +2008,8 @@ static int imx274_probe(struct i2c_client *client) goto err_ctrls; } - /* setup default controls */ - ret = v4l2_ctrl_handler_setup(&imx274->ctrls.handler); - if (ret) { - dev_err(&client->dev, - "Error %d setup default controls\n", ret); - goto err_ctrls; - } - /* load default control values */ - ret = imx274_load_default(imx274); - if (ret) { - dev_err(&client->dev, - "%s : imx274_load_default failed %d\n", - __func__, ret); - goto err_ctrls; - } + imx274_load_default(imx274); /* register subdevice */ ret = v4l2_async_register_subdev(sd); @@ -1953,11 +2020,17 @@ static int imx274_probe(struct i2c_client *client) goto err_ctrls; } + pm_runtime_set_active(&client->dev); + pm_runtime_enable(&client->dev); + pm_runtime_idle(&client->dev); + dev_info(&client->dev, "imx274 : imx274 probe success !\n"); return 0; err_ctrls: v4l2_ctrl_handler_free(&imx274->ctrls.handler); +err_power_off: + imx274_power_off(&client->dev); err_me: media_entity_cleanup(&sd->entity); err_regmap: @@ -1970,16 +2043,27 @@ static int imx274_remove(struct i2c_client *client) struct v4l2_subdev *sd = i2c_get_clientdata(client); struct stimx274 *imx274 = to_imx274(sd); + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + imx274_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); + v4l2_async_unregister_subdev(sd); v4l2_ctrl_handler_free(&imx274->ctrls.handler); + media_entity_cleanup(&sd->entity); mutex_destroy(&imx274->lock); return 0; } +static const struct dev_pm_ops imx274_pm_ops = { + SET_RUNTIME_PM_OPS(imx274_power_off, imx274_power_on, NULL) +}; + static struct i2c_driver imx274_i2c_driver = { .driver = { .name = DRIVER_NAME, + .pm = &imx274_pm_ops, .of_match_table = imx274_of_id_table, }, .probe_new = imx274_probe, -- cgit v1.2.3 From e599fc86717fde6741891c8b1689fe7043734348 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Tue, 15 Sep 2020 11:04:41 +0200 Subject: media: imx274: remove binning enum Binning enum is unused. Remove from driver. Suggested-by: Sakari Ailus Signed-off-by: Eugen Hristev Reviewed-by: Luca Ceresoli Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx274.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c index 2a6498e037cd..abff11528d0d 100644 --- a/drivers/media/i2c/imx274.c +++ b/drivers/media/i2c/imx274.c @@ -67,7 +67,6 @@ */ #define IMX274_MIN_EXPOSURE_TIME (4 * 260 / 72) -#define IMX274_DEFAULT_BINNING IMX274_BINNING_OFF #define IMX274_MAX_WIDTH (3840) #define IMX274_MAX_HEIGHT (2160) #define IMX274_MAX_FRAME_RATE (120) @@ -156,12 +155,6 @@ static const struct regmap_config imx274_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -enum imx274_binning { - IMX274_BINNING_OFF, - IMX274_BINNING_2_1, - IMX274_BINNING_3_1, -}; - /* * Parameters for each imx274 readout mode. * @@ -1913,7 +1906,7 @@ static int imx274_probe(struct i2c_client *client) } /* initialize format */ - imx274->mode = &imx274_modes[IMX274_DEFAULT_BINNING]; + imx274->mode = &imx274_modes[0]; imx274->crop.width = IMX274_MAX_WIDTH; imx274->crop.height = IMX274_MAX_HEIGHT; imx274->format.width = imx274->crop.width / imx274->mode->bin_ratio; -- cgit v1.2.3 From f70ad2aced307948a9a4395471f72528e32307e7 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Tue, 15 Sep 2020 11:04:42 +0200 Subject: media: imx274: add support for sensor mode6, 1280x540 Add support for the mode 6 for the sensor, this mode uses 3/8 subsampling and 3 horizontal binning. Aspect ratio is changed. Split the bin_ratio variable into two parts, one for width and one for height, as the ratio is no longer preserved when doing subsampling in this mode. Signed-off-by: Eugen Hristev Reviewed-by: Luca Ceresoli Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx274.c | 84 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 70 insertions(+), 14 deletions(-) diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c index abff11528d0d..54642d5f2d5b 100644 --- a/drivers/media/i2c/imx274.c +++ b/drivers/media/i2c/imx274.c @@ -162,7 +162,8 @@ static const struct regmap_config imx274_regmap_config = { * implemented modes. * * @init_regs: registers to initialize the mode - * @bin_ratio: downscale factor (e.g. 3 for 3:1 binning) + * @wbin_ratio: width downscale factor (e.g. 3 for 1280; 3 = 3840/1280) + * @hbin_ratio: height downscale factor (e.g. 3 for 720; 3 = 2160/720) * @min_frame_len: Minimum frame length for each mode (see "Frame Rate * Adjustment (CSI-2)" in the datasheet) * @min_SHR: Minimum SHR register value (see "Shutter Setting (CSI-2)" in the @@ -173,7 +174,8 @@ static const struct regmap_config imx274_regmap_config = { */ struct imx274_mode { const struct reg_8 *init_regs; - unsigned int bin_ratio; + u8 wbin_ratio; + u8 hbin_ratio; int min_frame_len; int min_SHR; int max_fps; @@ -336,6 +338,46 @@ static const struct reg_8 imx274_mode5_1280x720_raw10[] = { {IMX274_TABLE_END, 0x00} }; +/* + * Vertical 2/8 subsampling horizontal 3 binning + * imx274 mode6(refer to datasheet) register configuration with + * 1280x540 resolution, raw10 data and mipi four lane output + */ +static const struct reg_8 imx274_mode6_1280x540_raw10[] = { + {0x3004, 0x04}, /* mode setting */ + {0x3005, 0x31}, + {0x3006, 0x00}, + {0x3007, 0x02}, /* mode setting */ + + {0x3018, 0xA2}, /* output XVS, HVS */ + + {0x306B, 0x05}, + {0x30E2, 0x04}, /* mode setting */ + + {0x30EE, 0x01}, + {0x3342, 0x0A}, + {0x3343, 0x00}, + {0x3344, 0x16}, + {0x3345, 0x00}, + {0x33A6, 0x01}, + {0x3528, 0x0E}, + {0x3554, 0x1F}, + {0x3555, 0x01}, + {0x3556, 0x01}, + {0x3557, 0x01}, + {0x3558, 0x01}, + {0x3559, 0x00}, + {0x355A, 0x00}, + {0x35BA, 0x0E}, + {0x366A, 0x1B}, + {0x366B, 0x1A}, + {0x366C, 0x19}, + {0x366D, 0x17}, + {0x3A41, 0x04}, + + {IMX274_TABLE_END, 0x00} +}; + /* * imx274 first step register configuration for * starting stream @@ -449,7 +491,8 @@ static const struct reg_8 imx274_tp_regs[] = { static const struct imx274_mode imx274_modes[] = { { /* mode 1, 4K */ - .bin_ratio = 1, + .wbin_ratio = 1, /* 3840 */ + .hbin_ratio = 1, /* 2160 */ .init_regs = imx274_mode1_3840x2160_raw10, .min_frame_len = 4550, .min_SHR = 12, @@ -458,7 +501,8 @@ static const struct imx274_mode imx274_modes[] = { }, { /* mode 3, 1080p */ - .bin_ratio = 2, + .wbin_ratio = 2, /* 1920 */ + .hbin_ratio = 2, /* 1080 */ .init_regs = imx274_mode3_1920x1080_raw10, .min_frame_len = 2310, .min_SHR = 8, @@ -467,13 +511,24 @@ static const struct imx274_mode imx274_modes[] = { }, { /* mode 5, 720p */ - .bin_ratio = 3, + .wbin_ratio = 3, /* 1280 */ + .hbin_ratio = 3, /* 720 */ .init_regs = imx274_mode5_1280x720_raw10, .min_frame_len = 2310, .min_SHR = 8, .max_fps = 120, .nocpiop = 112, }, + { + /* mode 6, 540p */ + .wbin_ratio = 3, /* 1280 */ + .hbin_ratio = 4, /* 540 */ + .init_regs = imx274_mode6_1280x540_raw10, + .min_frame_len = 2310, + .min_SHR = 4, + .max_fps = 120, + .nocpiop = 112, + }, }; /* @@ -971,12 +1026,13 @@ static int __imx274_change_compose(struct stimx274 *imx274, } for (i = 0; i < ARRAY_SIZE(imx274_modes); i++) { - unsigned int ratio = imx274_modes[i].bin_ratio; + u8 wratio = imx274_modes[i].wbin_ratio; + u8 hratio = imx274_modes[i].hbin_ratio; int goodness = imx274_binning_goodness( imx274, - cur_crop->width / ratio, *width, - cur_crop->height / ratio, *height, + cur_crop->width / wratio, *width, + cur_crop->height / hratio, *height, flags); if (goodness >= best_goodness) { @@ -985,14 +1041,14 @@ static int __imx274_change_compose(struct stimx274 *imx274, } } - *width = cur_crop->width / best_mode->bin_ratio; - *height = cur_crop->height / best_mode->bin_ratio; + *width = cur_crop->width / best_mode->wbin_ratio; + *height = cur_crop->height / best_mode->hbin_ratio; if (which == V4L2_SUBDEV_FORMAT_ACTIVE) imx274->mode = best_mode; - dev_dbg(dev, "%s: selected %u:1 binning\n", - __func__, best_mode->bin_ratio); + dev_dbg(dev, "%s: selected %ux%u binning\n", + __func__, best_mode->wbin_ratio, best_mode->hbin_ratio); tgt_fmt->width = *width; tgt_fmt->height = *height; @@ -1909,8 +1965,8 @@ static int imx274_probe(struct i2c_client *client) imx274->mode = &imx274_modes[0]; imx274->crop.width = IMX274_MAX_WIDTH; imx274->crop.height = IMX274_MAX_HEIGHT; - imx274->format.width = imx274->crop.width / imx274->mode->bin_ratio; - imx274->format.height = imx274->crop.height / imx274->mode->bin_ratio; + imx274->format.width = imx274->crop.width / imx274->mode->wbin_ratio; + imx274->format.height = imx274->crop.height / imx274->mode->hbin_ratio; imx274->format.field = V4L2_FIELD_NONE; imx274->format.code = MEDIA_BUS_FMT_SRGGB10_1X10; imx274->format.colorspace = V4L2_COLORSPACE_SRGB; -- cgit v1.2.3 From 7b177d8f50d99f67b3f082d6eae30bab342a6dd7 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Thu, 10 Sep 2020 18:19:49 +0200 Subject: media: dt-bindings: media: mt9v111: Convert to json-schema Convert the mt9v111 bindings document to json-schema and update the MAINTAINERS file accordingly. Reviewed-by: Laurent Pinchart Signed-off-by: Jacopo Mondi Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/i2c/aptina,mt9v111.txt | 46 ------------- .../bindings/media/i2c/aptina,mt9v111.yaml | 75 ++++++++++++++++++++++ MAINTAINERS | 2 +- 3 files changed, 76 insertions(+), 47 deletions(-) delete mode 100644 Documentation/devicetree/bindings/media/i2c/aptina,mt9v111.txt create mode 100644 Documentation/devicetree/bindings/media/i2c/aptina,mt9v111.yaml diff --git a/Documentation/devicetree/bindings/media/i2c/aptina,mt9v111.txt b/Documentation/devicetree/bindings/media/i2c/aptina,mt9v111.txt deleted file mode 100644 index bd896e9f67d1..000000000000 --- a/Documentation/devicetree/bindings/media/i2c/aptina,mt9v111.txt +++ /dev/null @@ -1,46 +0,0 @@ -* Aptina MT9V111 CMOS sensor ----------------------------- - -The Aptina MT9V111 is a 1/4-Inch VGA-format digital image sensor with a core -based on Aptina MT9V011 sensor and an integrated Image Flow Processor (IFP). - -The sensor has an active pixel array of 640x480 pixels and can output a number -of image resolution and formats controllable through a simple two-wires -interface. - -Required properties: --------------------- - -- compatible: shall be "aptina,mt9v111". -- clocks: reference to the system clock input provider. - -Optional properties: --------------------- - -- enable-gpios: output enable signal, pin name "OE#". Active low. -- standby-gpios: low power state control signal, pin name "STANDBY". - Active high. -- reset-gpios: chip reset signal, pin name "RESET#". Active low. - -The device node must contain one 'port' child node with one 'endpoint' child -sub-node for its digital output video port, in accordance with the video -interface bindings defined in: -Documentation/devicetree/bindings/media/video-interfaces.txt - -Example: --------- - - &i2c1 { - camera@48 { - compatible = "aptina,mt9v111"; - reg = <0x48>; - - clocks = <&camera_clk>; - - port { - mt9v111_out: endpoint { - remote-endpoint = <&ceu_in>; - }; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/media/i2c/aptina,mt9v111.yaml b/Documentation/devicetree/bindings/media/i2c/aptina,mt9v111.yaml new file mode 100644 index 000000000000..ff9546e95d05 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/aptina,mt9v111.yaml @@ -0,0 +1,75 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/aptina,mt9v111.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Aptina MT9V111 CMOS sensor + +maintainers: + - Jacopo Mondi + +description: | + The Aptina MT9V111 is a 1/4-Inch VGA-format digital image sensor with a core + based on Aptina MT9V011 sensor and an integrated Image Flow Processor (IFP). + + The sensor has an active pixel array of 640x480 pixels and can output a number + of image resolutions and formats controllable through a simple two-wires + interface. + +properties: + compatible: + const: aptina,mt9v111 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + enable-gpios: + description: Enable signal, pin name "OE#". Active low. + maxItems: 1 + + standby-gpios: + description: | + Low power state control signal, pin name "STANDBY". Active high. + maxItems: 1 + + reset-gpios: + description: Chip reset signal, pin name "RESET#". Active low. + maxItems: 1 + + port: + type: object + description: | + Output video port. See ../video-interfaces.txt. + +required: + - compatible + - reg + - clocks + - port + +additionalProperties: false + +examples: + - | + i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + camera@48 { + compatible = "aptina,mt9v111"; + reg = <0x48>; + clocks = <&camera_clk>; + + port { + mt9v111_out: endpoint { + remote-endpoint = <&ceu_in>; + }; + }; + }; + }; + +... diff --git a/MAINTAINERS b/MAINTAINERS index 6955a91472af..1e06081c965d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11931,7 +11931,7 @@ M: Jacopo Mondi L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git -F: Documentation/devicetree/bindings/media/i2c/aptina,mt9v111.txt +F: Documentation/devicetree/bindings/media/i2c/aptina,mt9v111.yaml F: drivers/media/i2c/mt9v111.c MULTIFUNCTION DEVICES (MFD) -- cgit v1.2.3 From 8d9b35a2da8e0f03df97196557863ce425992b10 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Thu, 10 Sep 2020 18:20:30 +0200 Subject: media: dt-bindings: media: imx214: Convert to json-schema Convert the imx214 bindings document to json-schema and update the MAINTAINERS file accordingly. Reviewed-by: Laurent Pinchart Signed-off-by: Jacopo Mondi Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/i2c/sony,imx214.txt | 53 -------- .../devicetree/bindings/media/i2c/sony,imx214.yaml | 133 +++++++++++++++++++++ MAINTAINERS | 2 +- 3 files changed, 134 insertions(+), 54 deletions(-) delete mode 100644 Documentation/devicetree/bindings/media/i2c/sony,imx214.txt create mode 100644 Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx214.txt b/Documentation/devicetree/bindings/media/i2c/sony,imx214.txt deleted file mode 100644 index f11f28a5fda4..000000000000 --- a/Documentation/devicetree/bindings/media/i2c/sony,imx214.txt +++ /dev/null @@ -1,53 +0,0 @@ -* Sony 1/3.06-Inch 13.13Mp CMOS Digital Image Sensor - -The Sony imx214 is a 1/3.06-inch CMOS active pixel digital image sensor with -an active array size of 4224H x 3200V. It is programmable through an I2C -interface. -Image data is sent through MIPI CSI-2, through 2 or 4 lanes at a maximum -throughput of 1.2Gbps/lane. - - -Required Properties: -- compatible: Shall be "sony,imx214". -- reg: I2C bus address of the device. Depending on how the sensor is wired, - it shall be <0x10> or <0x1a>; -- enable-gpios: GPIO descriptor for the enable pin. -- vdddo-supply: Chip digital IO regulator (1.8V). -- vdda-supply: Chip analog regulator (2.7V). -- vddd-supply: Chip digital core regulator (1.12V). -- clocks: Reference to the xclk clock. -- clock-frequency: Frequency of the xclk clock. - -Optional Properties: -- flash-leds: See ../video-interfaces.txt -- lens-focus: See ../video-interfaces.txt - -The imx214 device node shall contain one 'port' child node with -an 'endpoint' subnode. For further reading on port node refer to -Documentation/devicetree/bindings/media/video-interfaces.txt. - -Required Properties on endpoint: -- data-lanes: check ../video-interfaces.txt -- link-frequencies: check ../video-interfaces.txt -- remote-endpoint: check ../video-interfaces.txt - -Example: - - camera-sensor@1a { - compatible = "sony,imx214"; - reg = <0x1a>; - vdddo-supply = <&pm8994_lvs1>; - vddd-supply = <&camera_vddd_1v12>; - vdda-supply = <&pm8994_l17>; - lens-focus = <&ad5820>; - enable-gpios = <&msmgpio 25 GPIO_ACTIVE_HIGH>; - clocks = <&mmcc CAMSS_MCLK0_CLK>; - clock-frequency = <24000000>; - port { - imx214_ep: endpoint { - data-lanes = <1 2 3 4>; - link-frequencies = /bits/ 64 <480000000>; - remote-endpoint = <&csiphy0_ep>; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml new file mode 100644 index 000000000000..0f5e25fa4e9d --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml @@ -0,0 +1,133 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/sony,imx214.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sony 1/3.06-Inch 13.13MP CMOS Digital Image Sensor + +maintainers: + - Ricardo Ribalda + +description: | + The Sony IMX214 is a 1/3.06-inch CMOS active pixel digital image sensor with + an active array size of 4224H x 3200V. It is programmable through an I2C + interface. Image data is sent through MIPI CSI-2, through 2 or 4 lanes at a + maximum throughput of 1.2Gbps/lane. + +properties: + compatible: + const: sony,imx214 + + reg: + enum: + - 0x10 + - 0x1a + + clocks: + description: Reference to the xclk clock. + maxItems: 1 + + clock-frequency: + description: Frequency of the xclk clock in Hz. + + enable-gpios: + description: GPIO descriptor for the enable pin. + maxItems: 1 + + vdddo-supply: + description: Chip digital IO regulator (1.8V). + maxItems: 1 + + vdda-supply: + description: Chip analog regulator (2.7V). + maxItems: 1 + + vddd-supply: + description: Chip digital core regulator (1.12V). + maxItems: 1 + + flash-leds: + description: See ../video-interfaces.txt + + lens-focus: + description: See ../video-interfaces.txt + + port: + type: object + description: | + Video output port. See ../video-interfaces.txt. + + properties: + endpoint: + type: object + + properties: + data-lanes: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: See ../video-interfaces.txt + anyOf: + - items: + - const: 1 + - const: 2 + - items: + - const: 1 + - const: 2 + - const: 3 + - const: 4 + + link-frequencies: + $ref: /schemas/types.yaml#/definitions/uint64-array + description: See ../video-interfaces.txt + + required: + - data-lanes + - link-frequencies + + unevaluatedProperties: false + + additionalProperties: false + +required: + - compatible + - reg + - clocks + - clock-frequency + - enable-gpios + - vdddo-supply + - vdda-supply + - vddd-supply + - port + +additionalProperties: false + +examples: + - | + #include + + i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + camera-sensor@1a { + compatible = "sony,imx214"; + reg = <0x1a>; + vdddo-supply = <&pm8994_lvs1>; + vddd-supply = <&camera_vddd_1v12>; + vdda-supply = <&pm8994_l17>; + lens-focus = <&ad5820>; + enable-gpios = <&msmgpio 25 GPIO_ACTIVE_HIGH>; + clocks = <&camera_clk>; + clock-frequency = <24000000>; + + port { + imx214_ep: endpoint { + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <480000000>; + remote-endpoint = <&csiphy0_ep>; + }; + }; + }; + }; + +... diff --git a/MAINTAINERS b/MAINTAINERS index 1e06081c965d..0717a87c1b41 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16298,7 +16298,7 @@ M: Ricardo Ribalda L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git -F: Documentation/devicetree/bindings/media/i2c/sony,imx214.txt +F: Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml F: drivers/media/i2c/imx214.c SONY IMX219 SENSOR DRIVER -- cgit v1.2.3 From 898bd5b5a4c526d8e310c398ec13b41c1b805f59 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Thu, 10 Sep 2020 18:20:53 +0200 Subject: media: dt-bindings: media: ov772x: Convert to json-schema Convert the ov772x binding document to json-schema and update the MAINTAINERS file accordingly. Reviewed-by: Lad Prabhakar Reviewed-by: Laurent Pinchart Signed-off-by: Jacopo Mondi Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/i2c/ov772x.txt | 40 ------------ .../devicetree/bindings/media/i2c/ovti,ov772x.yaml | 74 ++++++++++++++++++++++ MAINTAINERS | 2 +- 3 files changed, 75 insertions(+), 41 deletions(-) delete mode 100644 Documentation/devicetree/bindings/media/i2c/ov772x.txt create mode 100644 Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml diff --git a/Documentation/devicetree/bindings/media/i2c/ov772x.txt b/Documentation/devicetree/bindings/media/i2c/ov772x.txt deleted file mode 100644 index 0b3ede5b8e6a..000000000000 --- a/Documentation/devicetree/bindings/media/i2c/ov772x.txt +++ /dev/null @@ -1,40 +0,0 @@ -* Omnivision OV7720/OV7725 CMOS sensor - -The Omnivision OV7720/OV7725 sensor supports multiple resolutions output, -such as VGA, QVGA, and any size scaling down from CIF to 40x30. It also can -support the YUV422, RGB565/555/444, GRB422 or raw RGB output formats. - -Required Properties: -- compatible: shall be one of - "ovti,ov7720" - "ovti,ov7725" -- clocks: reference to the xclk input clock. - -Optional Properties: -- reset-gpios: reference to the GPIO connected to the RSTB pin which is - active low, if any. -- powerdown-gpios: reference to the GPIO connected to the PWDN pin which is - active high, if any. - -The device node shall contain one 'port' child node with one child 'endpoint' -subnode for its digital output video port, in accordance with the video -interface bindings defined in Documentation/devicetree/bindings/media/ -video-interfaces.txt. - -Example: - -&i2c0 { - ov772x: camera@21 { - compatible = "ovti,ov7725"; - reg = <0x21>; - reset-gpios = <&axi_gpio_0 0 GPIO_ACTIVE_LOW>; - powerdown-gpios = <&axi_gpio_0 1 GPIO_ACTIVE_LOW>; - clocks = <&xclk>; - - port { - ov772x_0: endpoint { - remote-endpoint = <&vcap1_in0>; - }; - }; - }; -}; diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml new file mode 100644 index 000000000000..e7e2d31fcc23 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/ovti,ov772x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Omnivision OV7720/OV7725 CMOS sensor + +maintainers: + - Jacopo Mondi + +description: | + The Omnivision OV7720/OV7725 sensor supports multiple resolutions output, + such as VGA, QVGA, and any size scaling down from CIF to 40x30. It also can + support the YUV422, RGB565/555/444, GRB422 or raw RGB output formats. + +properties: + compatible: + enum: + - ovti,ov7720 + - ovti,ov7725 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + reset-gpios: + description: | + Reference to the GPIO connected to the RSTB pin which is active low. + maxItems: 1 + + powerdown-gpios: + description: | + Reference to the GPIO connected to the PWDN pin which is active high. + maxItems: 1 + + port: + type: object + description: | + Video output port. See ../video-interfaces.txt. + +required: + - compatible + - reg + - clocks + - port + +additionalProperties: false + +examples: + - | + #include + + i2c0 { + #address-cells = <1>; + #size-cells = <0>; + ov772x: camera@21 { + compatible = "ovti,ov7725"; + reg = <0x21>; + reset-gpios = <&axi_gpio_0 0 GPIO_ACTIVE_LOW>; + powerdown-gpios = <&axi_gpio_0 1 GPIO_ACTIVE_LOW>; + clocks = <&xclk>; + + port { + ov772x_0: endpoint { + remote-endpoint = <&vcap1_in0>; + }; + }; + }; + }; + +... diff --git a/MAINTAINERS b/MAINTAINERS index 0717a87c1b41..c6a935e03003 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12958,7 +12958,7 @@ M: Jacopo Mondi L: linux-media@vger.kernel.org S: Odd fixes T: git git://linuxtv.org/media_tree.git -F: Documentation/devicetree/bindings/media/i2c/ov772x.txt +F: Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml F: drivers/media/i2c/ov772x.c F: include/media/i2c/ov772x.h -- cgit v1.2.3 From b2d059460e5eee3b5fe8230f95e372d175aa4dc4 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Thu, 10 Sep 2020 18:20:54 +0200 Subject: media: dt-bindings: media: ov772x: Make bus-type mandatory In order to establish required properties based on the selected bus type, make the 'bus-type' property mandatory. As this change documents an endpoint property, also document the 'remote-endpoint' one now that the 'endpoint' schema has been expanded. Binary compatibility with existing DTB is kept as the driver does not enforce the property to be present, and shall fall-back to default parallel bus configuration, which was the only supported bus type, if the property is not specified. Reviewed-by: Rob Herring Reviewed-by: Laurent Pinchart Reviewed-by: Lad Prabhakar Signed-off-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/i2c/ovti,ov772x.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml index e7e2d31fcc23..b034953b92e9 100644 --- a/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml @@ -41,6 +41,21 @@ properties: description: | Video output port. See ../video-interfaces.txt. + properties: + endpoint: + type: object + + properties: + bus-type: + enum: [5, 6] + + required: + - bus-type + + unevaluatedProperties: false + + additionalProperties: false + required: - compatible - reg @@ -65,6 +80,7 @@ examples: port { ov772x_0: endpoint { + bus-type = <5>; remote-endpoint = <&vcap1_in0>; }; }; -- cgit v1.2.3 From b20d9fac5bf54d5909d8538431bf53d83fbe5509 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Thu, 10 Sep 2020 18:20:55 +0200 Subject: media: dt-bindings: media: ov772x: Document endpoint props Document endpoint properties for the parallel bus type and add them to the example. Specify a few constraints: - If the bus type is BT.656 no hsync or vsync polarities can be specified. - If the bus width is 10 bits, not data-shift can be applied. Reviewed-by: Laurent Pinchart Reviewed-by: Lad Prabhakar Signed-off-by: Jacopo Mondi Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/i2c/ovti,ov772x.yaml | 44 ++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml index b034953b92e9..63b3779d7289 100644 --- a/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml @@ -49,6 +49,45 @@ properties: bus-type: enum: [5, 6] + bus-width: + enum: [8, 10] + default: 10 + + data-shift: + enum: [0, 2] + default: 0 + + hsync-active: + enum: [0, 1] + default: 1 + + vsync-active: + enum: [0, 1] + default: 1 + + pclk-sample: + enum: [0, 1] + default: 1 + + allOf: + - if: + properties: + bus-type: + const: 6 + then: + properties: + hsync-active: false + vsync-active: false + + - if: + properties: + bus-width: + const: 10 + then: + properties: + data-shift: + const: 0 + required: - bus-type @@ -81,6 +120,11 @@ examples: port { ov772x_0: endpoint { bus-type = <5>; + vsync-active = <0>; + hsync-active = <0>; + pclk-sample = <0>; + bus-width = <8>; + data-shift = <0>; remote-endpoint = <&vcap1_in0>; }; }; -- cgit v1.2.3 From d7dc892dd46d8d5c733b39c6631a7f616cc95d94 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 23 Sep 2020 10:21:12 +0200 Subject: media: dt-bindings: convert CODA VPU bindings to yaml Convert to YAML and add generic IP core compatibles "cnm,codadx6", "cnm,codahx4", "cnm,coda7541", and "cnm,coda960" in addition to the SoC specific compatibles. The new generic compatibles are already used in the SoC device trees and replace the free form comments. For example: - compatible : should be "fsl,-src" for i.MX SoCs: (a) "fsl,imx27-vpu" for CodaDx6 present in i.MX27 turns into: properties: compatible: oneOf: - items: - const: fsl,imx27-vpu - const: cnm,codadx6 This allows to properly specify the secondary JPEG unit interrupt that is only present on cnm,coda960. Also add the missing "fsl,imx6dl-vpu", "cnm,coda960" compatible. The AXI bus connection to the internal SRAM is different between i.MX6Q and i.MX6DL, which requires the driver to load a different firmware depending on the SoC. Further, specify the power-domain property for i.MX6 and change the clock order from "ahb", "per" to "per", "ahb". This order is currently used in all SoC device trees. Signed-off-by: Philipp Zabel Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/coda.txt | 31 ------- Documentation/devicetree/bindings/media/coda.yaml | 108 ++++++++++++++++++++++ MAINTAINERS | 2 +- 3 files changed, 109 insertions(+), 32 deletions(-) delete mode 100644 Documentation/devicetree/bindings/media/coda.txt create mode 100644 Documentation/devicetree/bindings/media/coda.yaml diff --git a/Documentation/devicetree/bindings/media/coda.txt b/Documentation/devicetree/bindings/media/coda.txt deleted file mode 100644 index 90eb74cc1993..000000000000 --- a/Documentation/devicetree/bindings/media/coda.txt +++ /dev/null @@ -1,31 +0,0 @@ -Chips&Media Coda multi-standard codec IP -======================================== - -Coda codec IPs are present in i.MX SoCs in various versions, -called VPU (Video Processing Unit). - -Required properties: -- compatible : should be "fsl,-src" for i.MX SoCs: - (a) "fsl,imx27-vpu" for CodaDx6 present in i.MX27 - (b) "fsl,imx51-vpu" for CodaHx4 present in i.MX51 - (c) "fsl,imx53-vpu" for CODA7541 present in i.MX53 - (d) "fsl,imx6q-vpu" for CODA960 present in i.MX6q -- reg: should be register base and length as documented in the - SoC reference manual -- interrupts : Should contain the VPU interrupt. For CODA960, - a second interrupt is needed for the MJPEG unit. -- clocks : Should contain the ahb and per clocks, in the order - determined by the clock-names property. -- clock-names : Should be "ahb", "per" -- iram : phandle pointing to the SRAM device node - -Example: - -vpu: vpu@63ff4000 { - compatible = "fsl,imx53-vpu"; - reg = <0x63ff4000 0x1000>; - interrupts = <9>; - clocks = <&clks 63>, <&clks 63>; - clock-names = "ahb", "per"; - iram = <&ocram>; -}; diff --git a/Documentation/devicetree/bindings/media/coda.yaml b/Documentation/devicetree/bindings/media/coda.yaml new file mode 100644 index 000000000000..7bac0057faf7 --- /dev/null +++ b/Documentation/devicetree/bindings/media/coda.yaml @@ -0,0 +1,108 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/coda.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Chips&Media Coda multi-standard codec IP + +maintainers: + - Philipp Zabel + +description: |- + Coda codec IPs are present in i.MX SoCs in various versions, + called VPU (Video Processing Unit). + +properties: + compatible: + oneOf: + - items: + - const: fsl,imx27-vpu + - const: cnm,codadx6 + - items: + - const: fsl,imx51-vpu + - const: cnm,codahx4 + - items: + - const: fsl,imx53-vpu + - const: cnm,coda7541 + - items: + - enum: + - fsl,imx6dl-vpu + - fsl,imx6q-vpu + - const: cnm,coda960 + + reg: + maxItems: 1 + + clocks: + items: + - description: PER clock + - description: AHB interface clock + + clock-names: + items: + - const: per + - const: ahb + + resets: + maxItems: 1 + + iram: + $ref: /schemas/types.yaml#/definitions/phandle + description: phandle pointing to the SRAM device node + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +allOf: + - if: + properties: + compatible: + contains: + const: cnm,coda960 + then: + properties: + interrupts: + items: + - description: BIT processor interrupt + - description: JPEG unit interrupt + + interrupt-names: + items: + - const: bit + - const: jpeg + else: + properties: + interrupts: + items: + - description: BIT processor interrupt + + - if: + properties: + compatible: + contains: + enum: + - fsl,imx6dl-vpu + - fsl,imx6q-vpu + then: + properties: + power-domains: + $ref: /schemas/types.yaml#/definitions/phandle + description: phandle pointing to the PU power domain + maxItems: 1 + +examples: + - | + vpu: video-codec@63ff4000 { + compatible = "fsl,imx53-vpu", "cnm,coda7541"; + reg = <0x63ff4000 0x1000>; + interrupts = <9>; + clocks = <&clks 63>, <&clks 63>; + clock-names = "per", "ahb"; + iram = <&ocram>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index c6a935e03003..43fb0a939fea 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4354,7 +4354,7 @@ CODA V4L2 MEM2MEM DRIVER M: Philipp Zabel L: linux-media@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/media/coda.txt +F: Documentation/devicetree/bindings/media/coda.yaml F: drivers/media/platform/coda/ CODE OF CONDUCT -- cgit v1.2.3 From 1726b976a6aa58d0182a3094db266072acf6bb66 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 30 Sep 2020 13:49:15 +0200 Subject: media: adv748x: Zero entire struct v4l2_fwnode_endpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The v4l2_fwnode_parse_endpoint() function can make use of defaults in multiple bus types. To use this feature, all callers must zero the rest of the fields of this struct, too. All other drivers appear to do that already apart from this one. Signed-off-by: Sakari Ailus Reviewed-by: Niklas Söderlund Reviewed-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv748x/adv748x-core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c index 1fe7f97c6d52..ae8b7ebf3830 100644 --- a/drivers/media/i2c/adv748x/adv748x-core.c +++ b/drivers/media/i2c/adv748x/adv748x-core.c @@ -589,14 +589,13 @@ static int adv748x_parse_csi2_lanes(struct adv748x_state *state, unsigned int port, struct device_node *ep) { - struct v4l2_fwnode_endpoint vep; + struct v4l2_fwnode_endpoint vep = { .bus_type = V4L2_MBUS_CSI2_DPHY }; unsigned int num_lanes; int ret; if (port != ADV748X_PORT_TXA && port != ADV748X_PORT_TXB) return 0; - vep.bus_type = V4L2_MBUS_CSI2_DPHY; ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &vep); if (ret) return ret; -- cgit v1.2.3 From b3cc73d2bf14e7c6e0376fa9433e708349e9ddfc Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 30 Sep 2020 14:08:03 +0200 Subject: media: v4l2-fwnode: v4l2_fwnode_endpoint_parse caller must init vep argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document that the caller of v4l2_fwnode_endpoint_parse() must init the fields of struct v4l2_fwnode_endpoint (vep argument) fields. It used to be that the fields were zeroed by v4l2_fwnode_endpoint_parse when bus type was set to V4L2_MBUS_UNKNOWN but with recent changes (Fixes: line below) that no longer makes sense. Fixes: bb4bba9232fc ("media: v4l2-fwnode: Make bus configuration a struct") Signed-off-by: Sakari Ailus Reviewed-by: Niklas Söderlund Reviewed-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-fwnode.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h index c09074276543..ed0840f3d5df 100644 --- a/include/media/v4l2-fwnode.h +++ b/include/media/v4l2-fwnode.h @@ -231,6 +231,9 @@ struct v4l2_fwnode_connector { * guessing @vep.bus_type between CSI-2 D-PHY, parallel and BT.656 busses is * supported. NEVER RELY ON GUESSING @vep.bus_type IN NEW DRIVERS! * + * The caller is required to initialise all fields of @vep, either with + * explicitly values, or by zeroing them. + * * The function does not change the V4L2 fwnode endpoint state if it fails. * * NOTE: This function does not parse properties the size of which is variable @@ -273,6 +276,9 @@ void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep); * guessing @vep.bus_type between CSI-2 D-PHY, parallel and BT.656 busses is * supported. NEVER RELY ON GUESSING @vep.bus_type IN NEW DRIVERS! * + * The caller is required to initialise all fields of @vep, either with + * explicitly values, or by zeroing them. + * * The function does not change the V4L2 fwnode endpoint state if it fails. * * v4l2_fwnode_endpoint_alloc_parse() has two important differences to -- cgit v1.2.3 From c2505342ee5b9f6370ea6a90c87a44a0f3c6b5eb Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 30 Sep 2020 14:28:54 +0200 Subject: media: v4l2-fwnode: Don't zero parts of struct v4l2_fwnode_endpoint anymore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't zero parts of the vep argument to v4l2_fwnode_endpoint_parse() anymore as this can no longer be done while still supporting defaults on multiple bus types. Signed-off-by: Sakari Ailus Reviewed-by: Niklas Söderlund Reviewed-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-fwnode.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index dfc53d11053f..44dd04b05e29 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -416,20 +416,8 @@ static int __v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode, enum v4l2_mbus_type mbus_type; int rval; - if (vep->bus_type == V4L2_MBUS_UNKNOWN) { - /* Zero fields from bus union to until the end */ - memset(&vep->bus, 0, - sizeof(*vep) - offsetof(typeof(*vep), bus)); - } - pr_debug("===== begin parsing endpoint %pfw\n", fwnode); - /* - * Zero the fwnode graph endpoint memory in case we don't end up parsing - * the endpoint. - */ - memset(&vep->base, 0, sizeof(vep->base)); - fwnode_property_read_u32(fwnode, "bus-type", &bus_type); pr_debug("fwnode video bus type %s (%u), mbus type %s (%u)\n", v4l2_fwnode_bus_type_to_string(bus_type), bus_type, -- cgit v1.2.3 From 20936f77347d021299301569603b317c110de712 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 30 Sep 2020 16:28:49 +0200 Subject: media: v4l2-fwnode: Rework v4l2_fwnode_endpoint_parse documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rework the documentation of v4l2_fwnode_endpoint_parse for better readability, usefulness and correctness. Signed-off-by: Sakari Ailus Reviewed-by: Niklas Söderlund Reviewed-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-fwnode.h | 62 +++++++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h index ed0840f3d5df..20b30d770944 100644 --- a/include/media/v4l2-fwnode.h +++ b/include/media/v4l2-fwnode.h @@ -219,17 +219,26 @@ struct v4l2_fwnode_connector { * @vep: pointer to the V4L2 fwnode data structure * * This function parses the V4L2 fwnode endpoint specific parameters from the - * firmware. The caller is responsible for assigning @vep.bus_type to a valid - * media bus type. The caller may also set the default configuration for the - * endpoint --- a configuration that shall be in line with the DT binding - * documentation. Should a device support multiple bus types, the caller may - * call this function once the correct type is found --- with a default - * configuration valid for that type. - * - * It is also allowed to set @vep.bus_type to V4L2_MBUS_UNKNOWN. USING THIS - * FEATURE REQUIRES "bus-type" PROPERTY IN DT BINDINGS. For old drivers, - * guessing @vep.bus_type between CSI-2 D-PHY, parallel and BT.656 busses is - * supported. NEVER RELY ON GUESSING @vep.bus_type IN NEW DRIVERS! + * firmware. There are two ways to use this function, either by letting it + * obtain the type of the bus (by setting the @vep.bus_type field to + * V4L2_MBUS_UNKNOWN) or specifying the bus type explicitly to one of the &enum + * v4l2_mbus_type types. + * + * When @vep.bus_type is V4L2_MBUS_UNKNOWN, the function will use the "bus-type" + * property to determine the type when it is available. The caller is + * responsible for validating the contents of @vep.bus_type field after the call + * returns. + * + * As a deprecated functionality to support older DT bindings without "bus-type" + * property for devices that support multiple types, if the "bus-type" property + * does not exist, the function will attempt to guess the type based on the + * endpoint properties available. NEVER RELY ON GUESSING THE BUS TYPE IN NEW + * DRIVERS OR BINDINGS. + * + * It is also possible to set @vep.bus_type corresponding to an actual bus. In + * this case the function will only attempt to parse properties related to this + * bus, and it will return an error if the value of the "bus-type" property + * corresponds to a different bus. * * The caller is required to initialise all fields of @vep, either with * explicitly values, or by zeroing them. @@ -264,17 +273,26 @@ void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep); * @vep: pointer to the V4L2 fwnode data structure * * This function parses the V4L2 fwnode endpoint specific parameters from the - * firmware. The caller is responsible for assigning @vep.bus_type to a valid - * media bus type. The caller may also set the default configuration for the - * endpoint --- a configuration that shall be in line with the DT binding - * documentation. Should a device support multiple bus types, the caller may - * call this function once the correct type is found --- with a default - * configuration valid for that type. - * - * It is also allowed to set @vep.bus_type to V4L2_MBUS_UNKNOWN. USING THIS - * FEATURE REQUIRES "bus-type" PROPERTY IN DT BINDINGS. For old drivers, - * guessing @vep.bus_type between CSI-2 D-PHY, parallel and BT.656 busses is - * supported. NEVER RELY ON GUESSING @vep.bus_type IN NEW DRIVERS! + * firmware. There are two ways to use this function, either by letting it + * obtain the type of the bus (by setting the @vep.bus_type field to + * V4L2_MBUS_UNKNOWN) or specifying the bus type explicitly to one of the &enum + * v4l2_mbus_type types. + * + * When @vep.bus_type is V4L2_MBUS_UNKNOWN, the function will use the "bus-type" + * property to determine the type when it is available. The caller is + * responsible for validating the contents of @vep.bus_type field after the call + * returns. + * + * As a deprecated functionality to support older DT bindings without "bus-type" + * property for devices that support multiple types, if the "bus-type" property + * does not exist, the function will attempt to guess the type based on the + * endpoint properties available. NEVER RELY ON GUESSING THE BUS TYPE IN NEW + * DRIVERS OR BINDINGS. + * + * It is also possible to set @vep.bus_type corresponding to an actual bus. In + * this case the function will only attempt to parse properties related to this + * bus, and it will return an error if the value of the "bus-type" property + * corresponds to a different bus. * * The caller is required to initialise all fields of @vep, either with * explicitly values, or by zeroing them. -- cgit v1.2.3 From 3be682fac66ca5829bb18c623c15147628a2d6f8 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 30 Sep 2020 16:34:43 +0200 Subject: media: v4l2-fwnode: Say it's fine to use v4l2_fwnode_endpoint_parse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Earlier it was expected that there would be more variable size endpoint properties and that most if not all drivers would need them. For that reason it was expected also that v4l2_fwnode_endpoint_parse would no longer be needed. What actually happened that not all drivers require "link-frequencies", the only variable size media endpoint property without a small upper limit. Therefore drivers that do not need that information are fine using v4l2_fwnode_endpoint_parse. So don't tell drivers to use v4l2_fwnode_endpoint_alloc_parse in all cases. Signed-off-by: Sakari Ailus Reviewed-by: Niklas Söderlund Reviewed-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-fwnode.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h index 20b30d770944..be30e066c621 100644 --- a/include/media/v4l2-fwnode.h +++ b/include/media/v4l2-fwnode.h @@ -245,9 +245,9 @@ struct v4l2_fwnode_connector { * * The function does not change the V4L2 fwnode endpoint state if it fails. * - * NOTE: This function does not parse properties the size of which is variable - * without a low fixed limit. Please use v4l2_fwnode_endpoint_alloc_parse() in - * new drivers instead. + * NOTE: This function does not parse "link-frequencies" property as its size is + * not known in advance. Please use v4l2_fwnode_endpoint_alloc_parse() if you + * need properties of variable size. * * Return: %0 on success or a negative error code on failure: * %-ENOMEM on memory allocation failure -- cgit v1.2.3 From 3e51ce5b1e87f4e31cbcf9971d6fd36ab1510466 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Tue, 15 Sep 2020 20:19:42 +0200 Subject: media: dt-bindings: adv7604: Fix documentation for hpd-gpios MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As of [1] the hpd-gpios property is optional, document it as such. 1. commit 269bd1324fbfaa52 ("[media] media: adv7604: improve usage of gpiod API") Signed-off-by: Niklas Söderlund Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/i2c/adv7604.txt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/media/i2c/adv7604.txt b/Documentation/devicetree/bindings/media/i2c/adv7604.txt index b3e688b77a38..8c7cdc7cd7aa 100644 --- a/Documentation/devicetree/bindings/media/i2c/adv7604.txt +++ b/Documentation/devicetree/bindings/media/i2c/adv7604.txt @@ -19,10 +19,6 @@ Required Properties: slave device on the I2C bus. The main address is mandatory, others are optional and revert to defaults if not specified. - - hpd-gpios: References to the GPIOs that control the HDMI hot-plug - detection pins, one per HDMI input. The active flag indicates the GPIO - level that enables hot-plug detection. - The device node must contain one 'port' child node per device input and output port, in accordance with the video interface bindings defined in Documentation/devicetree/bindings/media/video-interfaces.txt. The port nodes @@ -37,6 +33,9 @@ The digital output port node must contain at least one endpoint. Optional Properties: + - hpd-gpios: References to the GPIOs that control the HDMI hot-plug + detection pins, one per HDMI input. The active flag indicates the GPIO + level that enables hot-plug detection. - reset-gpios: Reference to the GPIO connected to the device's reset pin. - default-input: Select which input is selected after reset. - reg-names : Names of maps with programmable addresses. -- cgit v1.2.3 From 450c6b108e2876cbe391f812a52a887805e1c726 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Tue, 15 Sep 2020 20:19:43 +0200 Subject: media: dt-bindings: adv7604: Convert bindings to json-schema MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert ADV7604 video decoder documentation to json-schema. Signed-off-by: Niklas Söderlund Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/i2c/adv7604.txt | 87 ---------- .../devicetree/bindings/media/i2c/adv7604.yaml | 178 +++++++++++++++++++++ 2 files changed, 178 insertions(+), 87 deletions(-) delete mode 100644 Documentation/devicetree/bindings/media/i2c/adv7604.txt create mode 100644 Documentation/devicetree/bindings/media/i2c/adv7604.yaml diff --git a/Documentation/devicetree/bindings/media/i2c/adv7604.txt b/Documentation/devicetree/bindings/media/i2c/adv7604.txt deleted file mode 100644 index 8c7cdc7cd7aa..000000000000 --- a/Documentation/devicetree/bindings/media/i2c/adv7604.txt +++ /dev/null @@ -1,87 +0,0 @@ -* Analog Devices ADV7604/11/12 video decoder with HDMI receiver - -The ADV7604 and ADV7611/12 are multiformat video decoders with an integrated -HDMI receiver. The ADV7604 has four multiplexed HDMI inputs and one analog -input, and the ADV7611 has one HDMI input and no analog input. The 7612 is -similar to the 7611 but has 2 HDMI inputs. - -These device tree bindings support the ADV7611/12 only at the moment. - -Required Properties: - - - compatible: Must contain one of the following - - "adi,adv7611" for the ADV7611 - - "adi,adv7612" for the ADV7612 - - - reg: I2C slave addresses - The ADV76xx has up to thirteen 256-byte maps that can be accessed via the - main I2C ports. Each map has it own I2C address and acts as a standard - slave device on the I2C bus. The main address is mandatory, others are - optional and revert to defaults if not specified. - -The device node must contain one 'port' child node per device input and output -port, in accordance with the video interface bindings defined in -Documentation/devicetree/bindings/media/video-interfaces.txt. The port nodes -are numbered as follows. - - Port ADV7611 ADV7612 ------------------------------------------------------------- - HDMI 0 0, 1 - Digital output 1 2 - -The digital output port node must contain at least one endpoint. - -Optional Properties: - - - hpd-gpios: References to the GPIOs that control the HDMI hot-plug - detection pins, one per HDMI input. The active flag indicates the GPIO - level that enables hot-plug detection. - - reset-gpios: Reference to the GPIO connected to the device's reset pin. - - default-input: Select which input is selected after reset. - - reg-names : Names of maps with programmable addresses. - It can contain any map needing a non-default address. - Possible maps names are : - "main", "avlink", "cec", "infoframe", "esdp", "dpp", "afe", - "rep", "edid", "hdmi", "test", "cp", "vdp" - -Optional Endpoint Properties: - - The following three properties are defined in video-interfaces.txt and are - valid for source endpoints only. - - - hsync-active: Horizontal synchronization polarity. Defaults to active low. - - vsync-active: Vertical synchronization polarity. Defaults to active low. - - pclk-sample: Pixel clock polarity. Defaults to output on the falling edge. - - If none of hsync-active, vsync-active and pclk-sample is specified the - endpoint will use embedded BT.656 synchronization. - -Example: - - hdmi_receiver@4c { - compatible = "adi,adv7611"; - /* - * The edid page will be accessible @ 0x66 on the I2C bus. All - * other maps will retain their default addresses. - */ - reg = <0x4c>, <0x66>; - reg-names = "main", "edid"; - - reset-gpios = <&ioexp 0 GPIO_ACTIVE_LOW>; - hpd-gpios = <&ioexp 2 GPIO_ACTIVE_HIGH>; - - #address-cells = <1>; - #size-cells = <0>; - - default-input = <0>; - - port@0 { - reg = <0>; - }; - port@1 { - reg = <1>; - hdmi_in: endpoint { - remote-endpoint = <&ccdc_in>; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/media/i2c/adv7604.yaml b/Documentation/devicetree/bindings/media/i2c/adv7604.yaml new file mode 100644 index 000000000000..3897af540ddd --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/adv7604.yaml @@ -0,0 +1,178 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/adv7604.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices ADV7604/11/12 video decoder with HDMI receiver + +maintainers: + - Hans Verkuil + +description: + The ADV7604 and ADV7611/12 are multiformat video decoders with an integrated + HDMI receiver. The ADV7604 has four multiplexed HDMI inputs and one analog + input, and the ADV7611 has one HDMI input and no analog input. The 7612 is + similar to the 7611 but has 2 HDMI inputs. + + These device tree bindings support the ADV7611/12 only at the moment. + +properties: + compatible: + items: + - enum: + - adi,adv7611 + - adi,adv7612 + + reg: + minItems: 1 + maxItems: 13 + + reg-names: + minItems: 1 + maxItems: 13 + items: + - const: main + - enum: [ avlink, cec, infoframe, esdp, dpp, afe, rep, edid, hdmi, test, cp, vdp ] + - enum: [ avlink, cec, infoframe, esdp, dpp, afe, rep, edid, hdmi, test, cp, vdp ] + - enum: [ avlink, cec, infoframe, esdp, dpp, afe, rep, edid, hdmi, test, cp, vdp ] + - enum: [ avlink, cec, infoframe, esdp, dpp, afe, rep, edid, hdmi, test, cp, vdp ] + - enum: [ avlink, cec, infoframe, esdp, dpp, afe, rep, edid, hdmi, test, cp, vdp ] + - enum: [ avlink, cec, infoframe, esdp, dpp, afe, rep, edid, hdmi, test, cp, vdp ] + - enum: [ avlink, cec, infoframe, esdp, dpp, afe, rep, edid, hdmi, test, cp, vdp ] + - enum: [ avlink, cec, infoframe, esdp, dpp, afe, rep, edid, hdmi, test, cp, vdp ] + - enum: [ avlink, cec, infoframe, esdp, dpp, afe, rep, edid, hdmi, test, cp, vdp ] + - enum: [ avlink, cec, infoframe, esdp, dpp, afe, rep, edid, hdmi, test, cp, vdp ] + - enum: [ avlink, cec, infoframe, esdp, dpp, afe, rep, edid, hdmi, test, cp, vdp ] + - enum: [ avlink, cec, infoframe, esdp, dpp, afe, rep, edid, hdmi, test, cp, vdp ] + + interrupts: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + hpd-gpios: + minItems: 1 + description: + References to the GPIOs that control the HDMI hot-plug detection pins, + one per HDMI input. The active flag indicates the GPIO level that + enables hot-plug detection. + + default-input: + maxItems: 1 + description: + Select which input is selected after reset. + + ports: + type: object + description: + A node containing input and output port nodes with endpoint definitions + as documented in + Documentation/devicetree/bindings/media/video-interfaces.txt + +required: + - compatible + - reg + +additionalProperties: false + +allOf: + - if: + properties: + compatible: + contains: + const: adi,adv7611 + then: + properties: + ports: + properties: + '#address-cells': + const: 1 + '#size-cells': + const: 0 + port@0: + type: object + description: Input port + port@1: + type: object + description: Output port + + required: + - port@1 + + additionalProperties: false + + required: + - ports + + - if: + properties: + compatible: + contains: + const: adi,adv7612 + then: + properties: + ports: + properties: + '#address-cells': + const: 1 + '#size-cells': + const: 0 + port@2: + type: object + description: Output port + + patternProperties: + "^port@[0-1]$": + type: object + description: Input port + + required: + - port@2 + + additionalProperties: false + + required: + - ports + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + hdmi_receiver@4c { + compatible = "adi,adv7611"; + /* + * The edid page will be accessible @ 0x66 on the I2C bus. All + * other maps will retain their default addresses. + */ + reg = <0x4c>, <0x66>; + reg-names = "main", "edid"; + + reset-gpios = <&ioexp 0 GPIO_ACTIVE_LOW>; + hpd-gpios = <&ioexp 2 GPIO_ACTIVE_HIGH>; + default-input = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + }; + + port@1 { + reg = <1>; + hdmi_in: endpoint { + remote-endpoint = <&ccdc_in>; + }; + }; + }; + + + }; + }; -- cgit v1.2.3 From 5b3ff3be485ec29180368e9a2d61bf6d3dfaf7e6 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Tue, 15 Sep 2020 20:19:44 +0200 Subject: media: MAINTAINERS: Add ADV7604 bindings documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the YAML dt-bindings document for ADV7604. Signed-off-by: Niklas Söderlund Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 43fb0a939fea..811db1d3ca33 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1073,6 +1073,7 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained F: drivers/media/i2c/adv7604* +F: Documentation/devicetree/bindings/media/i2c/adv7604.yaml ANALOG DEVICES INC ADV7842 DRIVER M: Hans Verkuil -- cgit v1.2.3 From 09e73bbd3ee513bb29f327bd6d0e51bcd7b260a7 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Mon, 14 Sep 2020 23:50:10 +0200 Subject: media: rcar-csi2: Switch to using fwnode instead of OF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the fwnode_graph_get_endpoint_by_id() interface instead of of_graph_get_endpoint_by_regs() to fetch the fwnode. This saves translating between a device_node and fwnode_handle. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-csi2.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c index 79f229756805..b84c3882ee3a 100644 --- a/drivers/media/platform/rcar-vin/rcar-csi2.c +++ b/drivers/media/platform/rcar-vin/rcar-csi2.c @@ -876,31 +876,31 @@ static int rcsi2_parse_dt(struct rcar_csi2 *priv) { struct v4l2_async_subdev *asd; struct fwnode_handle *fwnode; - struct device_node *ep; + struct fwnode_handle *ep; struct v4l2_fwnode_endpoint v4l2_ep = { .bus_type = 0 }; int ret; - ep = of_graph_get_endpoint_by_regs(priv->dev->of_node, 0, 0); + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(priv->dev), 0, 0, 0); if (!ep) { dev_err(priv->dev, "Not connected to subdevice\n"); return -EINVAL; } - ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &v4l2_ep); + ret = v4l2_fwnode_endpoint_parse(ep, &v4l2_ep); if (ret) { dev_err(priv->dev, "Could not parse v4l2 endpoint\n"); - of_node_put(ep); + fwnode_handle_put(ep); return -EINVAL; } ret = rcsi2_parse_v4l2(priv, &v4l2_ep); if (ret) { - of_node_put(ep); + fwnode_handle_put(ep); return ret; } - fwnode = fwnode_graph_get_remote_endpoint(of_fwnode_handle(ep)); - of_node_put(ep); + fwnode = fwnode_graph_get_remote_endpoint(ep); + fwnode_handle_put(ep); dev_dbg(priv->dev, "Found '%pOF'\n", to_of_node(fwnode)); -- cgit v1.2.3 From 055e124eec851996567910def94ead0aaac8fa36 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Mon, 14 Sep 2020 23:50:11 +0200 Subject: media: rcar-csi2: Set bus type when parsing fwnode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The only supported bus for the R-Car CSI-2 driver is CSI-2 DPHY, specify this before parsing the fwnode. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-csi2.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c index b84c3882ee3a..945d2eb87233 100644 --- a/drivers/media/platform/rcar-vin/rcar-csi2.c +++ b/drivers/media/platform/rcar-vin/rcar-csi2.c @@ -877,7 +877,9 @@ static int rcsi2_parse_dt(struct rcar_csi2 *priv) struct v4l2_async_subdev *asd; struct fwnode_handle *fwnode; struct fwnode_handle *ep; - struct v4l2_fwnode_endpoint v4l2_ep = { .bus_type = 0 }; + struct v4l2_fwnode_endpoint v4l2_ep = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; int ret; ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(priv->dev), 0, 0, 0); -- cgit v1.2.3 From 8a10b4e3601eaefa4b7c8de9b62a0e15ccd4d99e Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Sat, 3 Oct 2020 00:23:21 +0200 Subject: media: i2c: ov772x: Parse endpoint properties Parse endpoint properties using v4l2_fwnode_endpoint_alloc_parse() to determine the bus type and store it in the driver structure. Set bus_type to V4L2_MBUS_PARALLEL as it's the only supported one Signed-off-by: Lad Prabhakar Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov772x.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c index 2cc6a678069a..afe2446dfb68 100644 --- a/drivers/media/i2c/ov772x.c +++ b/drivers/media/i2c/ov772x.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -434,6 +435,7 @@ struct ov772x_priv { #ifdef CONFIG_MEDIA_CONTROLLER struct media_pad pad; #endif + enum v4l2_mbus_type bus_type; }; /* @@ -1348,6 +1350,34 @@ static const struct v4l2_subdev_ops ov772x_subdev_ops = { .pad = &ov772x_subdev_pad_ops, }; +static int ov772x_parse_dt(struct i2c_client *client, + struct ov772x_priv *priv) +{ + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_PARALLEL + }; + struct fwnode_handle *ep; + int ret; + + ep = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL); + if (!ep) { + dev_err(&client->dev, "Endpoint node not found\n"); + return -EINVAL; + } + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + if (ret) + goto error_fwnode_put; + + priv->bus_type = bus_cfg.bus_type; + v4l2_fwnode_endpoint_free(&bus_cfg); + +error_fwnode_put: + fwnode_handle_put(ep); + + return ret; +} + /* * i2c_driver function */ @@ -1415,6 +1445,10 @@ static int ov772x_probe(struct i2c_client *client) goto error_clk_put; } + ret = ov772x_parse_dt(client, priv); + if (ret) + goto error_clk_put; + ret = ov772x_video_probe(priv); if (ret < 0) goto error_gpio_put; -- cgit v1.2.3 From efcb7dda9b53d4569d08906eedc95aa51d2d5555 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Sat, 3 Oct 2020 00:23:22 +0200 Subject: media: i2c: ov772x: Add support for BT.656 mode Add support to read the bus-type for V4L2_MBUS_BT656 and enable BT.656 mode in the sensor if needed. For backward compatibility with older DTS where the bus-type property was not mandatory, assume V4L2_MBUS_PARALLEL as it was the only supported bus at the time. v4l2_fwnode_endpoint_alloc_parse() will not fail if 'bus-type' is not specified. Signed-off-by: Lad Prabhakar Reviewed-by: Biju Das Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov772x.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c index afe2446dfb68..86e542b77ee5 100644 --- a/drivers/media/i2c/ov772x.c +++ b/drivers/media/i2c/ov772x.c @@ -583,6 +583,14 @@ static int ov772x_s_stream(struct v4l2_subdev *sd, int enable) if (priv->streaming == enable) goto done; + if (priv->bus_type == V4L2_MBUS_BT656) { + ret = regmap_update_bits(priv->regmap, COM7, ITU656_ON_OFF, + enable ? + ITU656_ON_OFF : ~ITU656_ON_OFF); + if (ret) + goto done; + } + ret = regmap_update_bits(priv->regmap, COM2, SOFT_SLEEP_MODE, enable ? 0 : SOFT_SLEEP_MODE); if (ret) @@ -1365,9 +1373,21 @@ static int ov772x_parse_dt(struct i2c_client *client, return -EINVAL; } + /* + * For backward compatibility with older DTS where the + * bus-type property was not mandatory, assume + * V4L2_MBUS_PARALLEL as it was the only supported bus at the + * time. v4l2_fwnode_endpoint_alloc_parse() will not fail if + * 'bus-type' is not specified. + */ ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); - if (ret) - goto error_fwnode_put; + if (ret) { + bus_cfg = (struct v4l2_fwnode_endpoint) + { .bus_type = V4L2_MBUS_BT656 }; + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + if (ret) + goto error_fwnode_put; + } priv->bus_type = bus_cfg.bus_type; v4l2_fwnode_endpoint_free(&bus_cfg); -- cgit v1.2.3 From f5c24ca7bf8c707927668dc76773616a25d0fded Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Sat, 3 Oct 2020 00:23:23 +0200 Subject: media: i2c: ov772x: Add test pattern control Add support for test pattern control supported by the sensor. Signed-off-by: Lad Prabhakar Reviewed-by: Biju Das Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov772x.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c index 86e542b77ee5..d94cf2d39c2a 100644 --- a/drivers/media/i2c/ov772x.c +++ b/drivers/media/i2c/ov772x.c @@ -227,7 +227,7 @@ /* COM3 */ #define SWAP_MASK (SWAP_RGB | SWAP_YUV | SWAP_ML) -#define IMG_MASK (VFLIP_IMG | HFLIP_IMG) +#define IMG_MASK (VFLIP_IMG | HFLIP_IMG | SCOLOR_TEST) #define VFLIP_IMG 0x80 /* Vertical flip image ON/OFF selection */ #define HFLIP_IMG 0x40 /* Horizontal mirror image ON/OFF selection */ @@ -425,6 +425,7 @@ struct ov772x_priv { const struct ov772x_win_size *win; struct v4l2_ctrl *vflip_ctrl; struct v4l2_ctrl *hflip_ctrl; + unsigned int test_pattern; /* band_filter = COM8[5] ? 256 - BDBASE : 0 */ struct v4l2_ctrl *band_filter_ctrl; unsigned int fps; @@ -540,6 +541,11 @@ static const struct ov772x_win_size ov772x_win_sizes[] = { }, }; +static const char * const ov772x_test_pattern_menu[] = { + "Disabled", + "Vertical Color Bar Type 1", +}; + /* * frame rate settings lists */ @@ -810,6 +816,9 @@ static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl) } return ret; + case V4L2_CID_TEST_PATTERN: + priv->test_pattern = ctrl->val; + return 0; } return -EINVAL; @@ -1108,6 +1117,8 @@ static int ov772x_set_params(struct ov772x_priv *priv, val ^= VFLIP_IMG; if (priv->hflip_ctrl->val) val ^= HFLIP_IMG; + if (priv->test_pattern) + val |= SCOLOR_TEST; ret = regmap_update_bits(priv->regmap, COM3, SWAP_MASK | IMG_MASK, val); if (ret < 0) @@ -1444,6 +1455,10 @@ static int ov772x_probe(struct i2c_client *client) priv->band_filter_ctrl = v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, V4L2_CID_BAND_STOP_FILTER, 0, 256, 1, 0); + v4l2_ctrl_new_std_menu_items(&priv->hdl, &ov772x_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov772x_test_pattern_menu) - 1, + 0, 0, ov772x_test_pattern_menu); priv->subdev.ctrl_handler = &priv->hdl; if (priv->hdl.error) { ret = priv->hdl.error; -- cgit v1.2.3 From db8e94e7cf27d8bc101ef5b8ee5c1af77cd5b1c9 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 5 Jul 2016 11:41:15 +0200 Subject: media: v4l: subdev: Improve link format validation debug messages The existing link format validation failure debug message in media-entity.c helped to pinpoint the point of failure but provided no additional information what's wrong. Tell the user exactly why the validation failed. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-subdev.c | 48 ++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index a7d508e74d6b..956dafab43d4 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -792,21 +792,55 @@ int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd, struct v4l2_subdev_format *source_fmt, struct v4l2_subdev_format *sink_fmt) { + bool pass = true; + /* The width, height and code must match. */ - if (source_fmt->format.width != sink_fmt->format.width - || source_fmt->format.height != sink_fmt->format.height - || source_fmt->format.code != sink_fmt->format.code) - return -EPIPE; + if (source_fmt->format.width != sink_fmt->format.width) { + dev_dbg(sd->entity.graph_obj.mdev->dev, + "%s: width does not match (source %u, sink %u)\n", + __func__, + source_fmt->format.width, sink_fmt->format.width); + pass = false; + } + + if (source_fmt->format.height != sink_fmt->format.height) { + dev_dbg(sd->entity.graph_obj.mdev->dev, + "%s: height does not match (source %u, sink %u)\n", + __func__, + source_fmt->format.height, sink_fmt->format.height); + pass = false; + } + + if (source_fmt->format.code != sink_fmt->format.code) { + dev_dbg(sd->entity.graph_obj.mdev->dev, + "%s: media bus code does not match (source 0x%8.8x, sink 0x%8.8x)\n", + __func__, + source_fmt->format.code, sink_fmt->format.code); + pass = false; + } /* The field order must match, or the sink field order must be NONE * to support interlaced hardware connected to bridges that support * progressive formats only. */ if (source_fmt->format.field != sink_fmt->format.field && - sink_fmt->format.field != V4L2_FIELD_NONE) - return -EPIPE; + sink_fmt->format.field != V4L2_FIELD_NONE) { + dev_dbg(sd->entity.graph_obj.mdev->dev, + "%s: field does not match (source %u, sink %u)\n", + __func__, + source_fmt->format.field, sink_fmt->format.field); + pass = false; + } - return 0; + if (pass) + return 0; + + dev_dbg(sd->entity.graph_obj.mdev->dev, + "%s: link was \"%s\":%u -> \"%s\":%u\n", __func__, + link->source->entity->name, link->source->index, + link->sink->entity->name, link->sink->index); + + return -EPIPE; } EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate_default); -- cgit v1.2.3 From 8160e86702e0807bd36d40f82648f9f9820b9d5a Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 8 Oct 2020 21:06:28 +0200 Subject: media: ipu3-cio2: Return actual subdev format Return actual subdev format on ipu3-cio2 subdev pads. The earlier implementation was based on an infinite recursion that exhausted the stack. Reported-by: Tsuchiya Yuto Fixes: c2a6a07afe4a ("media: intel-ipu3: cio2: add new MIPI-CSI2 driver") Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Reviewed-by: Bingbu Cao Reviewed-by: Andy Shevchenko Cc: stable@vger.kernel.org # v4.16 and up Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/intel/ipu3/ipu3-cio2.c | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index 4e598e937dfe..afa472026ba4 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -1232,29 +1232,11 @@ static int cio2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_format *fmt) { struct cio2_queue *q = container_of(sd, struct cio2_queue, subdev); - struct v4l2_subdev_format format; - int ret; - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad); - return 0; - } - - if (fmt->pad == CIO2_PAD_SINK) { - format.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, - &format); - - if (ret) - return ret; - /* update colorspace etc */ - q->subdev_fmt.colorspace = format.format.colorspace; - q->subdev_fmt.ycbcr_enc = format.format.ycbcr_enc; - q->subdev_fmt.quantization = format.format.quantization; - q->subdev_fmt.xfer_func = format.format.xfer_func; - } - - fmt->format = q->subdev_fmt; + else + fmt->format = q->subdev_fmt; return 0; } -- cgit v1.2.3 From 55a6c6b2be3d6670bf5772364d8208bd8dc17da4 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 8 Oct 2020 21:29:38 +0200 Subject: media: ipu3-cio2: Serialise access to pad format Pad format can be accessed from user space. Serialise access to it. Fixes: c2a6a07afe4a ("media: intel-ipu3: cio2: add new MIPI-CSI2 driver") Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Reviewed-by: Bingbu Cao Reviewed-by: Andy Shevchenko Cc: stable@vger.kernel.org # v4.16 and up Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/intel/ipu3/ipu3-cio2.c | 11 +++++++++++ drivers/media/pci/intel/ipu3/ipu3-cio2.h | 1 + 2 files changed, 12 insertions(+) diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index afa472026ba4..b3a08196e08c 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -1233,11 +1233,15 @@ static int cio2_subdev_get_fmt(struct v4l2_subdev *sd, { struct cio2_queue *q = container_of(sd, struct cio2_queue, subdev); + mutex_lock(&q->subdev_lock); + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad); else fmt->format = q->subdev_fmt; + mutex_unlock(&q->subdev_lock); + return 0; } @@ -1261,6 +1265,8 @@ static int cio2_subdev_set_fmt(struct v4l2_subdev *sd, if (fmt->pad == CIO2_PAD_SOURCE) return cio2_subdev_get_fmt(sd, cfg, fmt); + mutex_lock(&q->subdev_lock); + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format; } else { @@ -1271,6 +1277,8 @@ static int cio2_subdev_set_fmt(struct v4l2_subdev *sd, fmt->format = q->subdev_fmt; } + mutex_unlock(&q->subdev_lock); + return 0; } @@ -1529,6 +1537,7 @@ static int cio2_queue_init(struct cio2_device *cio2, struct cio2_queue *q) /* Initialize miscellaneous variables */ mutex_init(&q->lock); + mutex_init(&q->subdev_lock); /* Initialize formats to default values */ fmt = &q->subdev_fmt; @@ -1645,6 +1654,7 @@ fail_vdev_media_entity: fail_subdev_media_entity: cio2_fbpt_exit(q, &cio2->pci_dev->dev); fail_fbpt: + mutex_destroy(&q->subdev_lock); mutex_destroy(&q->lock); return r; @@ -1657,6 +1667,7 @@ static void cio2_queue_exit(struct cio2_device *cio2, struct cio2_queue *q) v4l2_device_unregister_subdev(&q->subdev); media_entity_cleanup(&q->subdev.entity); cio2_fbpt_exit(q, &cio2->pci_dev->dev); + mutex_destroy(&q->subdev_lock); mutex_destroy(&q->lock); } diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.h b/drivers/media/pci/intel/ipu3/ipu3-cio2.h index 549b08f88f0c..146492383aa5 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.h +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.h @@ -335,6 +335,7 @@ struct cio2_queue { /* Subdev, /dev/v4l-subdevX */ struct v4l2_subdev subdev; + struct mutex subdev_lock; /* Serialise acces to subdev_fmt field */ struct media_pad subdev_pads[CIO2_PADS]; struct v4l2_mbus_framefmt subdev_fmt; atomic_t frame_sequence; -- cgit v1.2.3 From a86cf9b29e8b12811cf53c4970eefe0c1d290476 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 8 Oct 2020 21:33:26 +0200 Subject: media: ipu3-cio2: Validate mbus format in setting subdev format Validate media bus code, width and height when setting the subdev format. This effectively reworks how setting subdev format is implemented in the driver. Fixes: c2a6a07afe4a ("media: intel-ipu3: cio2: add new MIPI-CSI2 driver") Signed-off-by: Sakari Ailus Reviewed-by: Andy Shevchenko Reviewed-by: Laurent Pinchart Cc: stable@vger.kernel.org # v4.16 and up Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/intel/ipu3/ipu3-cio2.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index b3a08196e08c..72095f8a4d46 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -1257,6 +1257,9 @@ static int cio2_subdev_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_format *fmt) { struct cio2_queue *q = container_of(sd, struct cio2_queue, subdev); + struct v4l2_mbus_framefmt *mbus; + u32 mbus_code = fmt->format.code; + unsigned int i; /* * Only allow setting sink pad format; @@ -1265,18 +1268,26 @@ static int cio2_subdev_set_fmt(struct v4l2_subdev *sd, if (fmt->pad == CIO2_PAD_SOURCE) return cio2_subdev_get_fmt(sd, cfg, fmt); - mutex_lock(&q->subdev_lock); + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) + mbus = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); + else + mbus = &q->subdev_fmt; - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format; - } else { - /* It's the sink, allow changing frame size */ - q->subdev_fmt.width = fmt->format.width; - q->subdev_fmt.height = fmt->format.height; - q->subdev_fmt.code = fmt->format.code; - fmt->format = q->subdev_fmt; + fmt->format.code = formats[0].mbus_code; + + for (i = 0; i < ARRAY_SIZE(formats); i++) { + if (formats[i].mbus_code == fmt->format.code) { + fmt->format.code = mbus_code; + break; + } } + fmt->format.width = min_t(u32, fmt->format.width, CIO2_IMAGE_MAX_WIDTH); + fmt->format.height = min_t(u32, fmt->format.height, + CIO2_IMAGE_MAX_LENGTH); + + mutex_lock(&q->subdev_lock); + *mbus = fmt->format; mutex_unlock(&q->subdev_lock); return 0; -- cgit v1.2.3 From 219a8b9c04e54872f9a4d566633fb42f08bcbe2a Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 9 Oct 2020 15:56:05 +0200 Subject: media: ipu3-cio2: Make the field on subdev format V4L2_FIELD_NONE The ipu3-cio2 doesn't make use of the field and this is reflected in V4L2 buffers as well as the try format. Do this in active format, too. Fixes: c2a6a07afe4a ("media: intel-ipu3: cio2: add new MIPI-CSI2 driver") Signed-off-by: Sakari Ailus Reviewed-by: Bingbu Cao Reviewed-by: Andy Shevchenko Reviewed-by: Laurent Pinchart Cc: stable@vger.kernel.org # v4.16 and up Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/intel/ipu3/ipu3-cio2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index 72095f8a4d46..87d040e176f7 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -1285,6 +1285,7 @@ static int cio2_subdev_set_fmt(struct v4l2_subdev *sd, fmt->format.width = min_t(u32, fmt->format.width, CIO2_IMAGE_MAX_WIDTH); fmt->format.height = min_t(u32, fmt->format.height, CIO2_IMAGE_MAX_LENGTH); + fmt->format.field = V4L2_FIELD_NONE; mutex_lock(&q->subdev_lock); *mbus = fmt->format; -- cgit v1.2.3 From 44e6d472cef6ad2ef1954bcbca9a91505bca1bfd Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 9 Oct 2020 12:02:41 +0200 Subject: media: ipu3-cio2: Use unsigned values where appropriate Use unsigned values for width, height, bit shifts and registers, effectively for all definitions that are not signed. Signed-off-by: Sakari Ailus Reviewed-by: Andy Shevchenko Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/intel/ipu3/ipu3-cio2.h | 156 +++++++++++++++---------------- 1 file changed, 78 insertions(+), 78 deletions(-) diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.h b/drivers/media/pci/intel/ipu3/ipu3-cio2.h index 146492383aa5..7650d7998a3f 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.h +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.h @@ -13,20 +13,20 @@ #define CIO2_PCI_BAR 0 #define CIO2_DMA_MASK DMA_BIT_MASK(39) -#define CIO2_IMAGE_MAX_WIDTH 4224 -#define CIO2_IMAGE_MAX_LENGTH 3136 +#define CIO2_IMAGE_MAX_WIDTH 4224U +#define CIO2_IMAGE_MAX_LENGTH 3136U /* 32MB = 8xFBPT_entry */ #define CIO2_MAX_LOPS 8 #define CIO2_MAX_BUFFERS (PAGE_SIZE / 16 / CIO2_MAX_LOPS) #define CIO2_LOP_ENTRIES (PAGE_SIZE / sizeof(u32)) -#define CIO2_PAD_SINK 0 -#define CIO2_PAD_SOURCE 1 -#define CIO2_PADS 2 +#define CIO2_PAD_SINK 0U +#define CIO2_PAD_SOURCE 1U +#define CIO2_PADS 2U -#define CIO2_NUM_DMA_CHAN 20 -#define CIO2_NUM_PORTS 4 /* DPHYs */ +#define CIO2_NUM_DMA_CHAN 20U +#define CIO2_NUM_PORTS 4U /* DPHYs */ /* 1 for each sensor */ #define CIO2_QUEUES CIO2_NUM_PORTS @@ -66,12 +66,12 @@ #define CIO2_REG_MIPIBE_FORCE_RAW8 (CIO2_REG_MIPIBE_BASE + 0x20) #define CIO2_REG_MIPIBE_FORCE_RAW8_ENABLE BIT(0) #define CIO2_REG_MIPIBE_FORCE_RAW8_USE_TYPEID BIT(1) -#define CIO2_REG_MIPIBE_FORCE_RAW8_TYPEID_SHIFT 2 +#define CIO2_REG_MIPIBE_FORCE_RAW8_TYPEID_SHIFT 2U #define CIO2_REG_MIPIBE_IRQ_STATUS (CIO2_REG_MIPIBE_BASE + 0x24) #define CIO2_REG_MIPIBE_IRQ_CLEAR (CIO2_REG_MIPIBE_BASE + 0x28) #define CIO2_REG_MIPIBE_GLOBAL_LUT_DISREGARD (CIO2_REG_MIPIBE_BASE + 0x68) -#define CIO2_MIPIBE_GLOBAL_LUT_DISREGARD 1 +#define CIO2_MIPIBE_GLOBAL_LUT_DISREGARD 1U #define CIO2_REG_MIPIBE_PKT_STALL_STATUS (CIO2_REG_MIPIBE_BASE + 0x6c) #define CIO2_REG_MIPIBE_PARSE_GSP_THROUGH_LP_LUT_REG_IDX \ (CIO2_REG_MIPIBE_BASE + 0x70) @@ -79,10 +79,10 @@ (CIO2_REG_MIPIBE_BASE + 0x74 + 4 * (vc)) #define CIO2_REG_MIPIBE_LP_LUT_ENTRY(m) /* m = 0..15 */ \ (CIO2_REG_MIPIBE_BASE + 0x84 + 4 * (m)) -#define CIO2_MIPIBE_LP_LUT_ENTRY_DISREGARD 1 -#define CIO2_MIPIBE_LP_LUT_ENTRY_SID_SHIFT 1 -#define CIO2_MIPIBE_LP_LUT_ENTRY_VC_SHIFT 5 -#define CIO2_MIPIBE_LP_LUT_ENTRY_FORMAT_TYPE_SHIFT 7 +#define CIO2_MIPIBE_LP_LUT_ENTRY_DISREGARD 1U +#define CIO2_MIPIBE_LP_LUT_ENTRY_SID_SHIFT 1U +#define CIO2_MIPIBE_LP_LUT_ENTRY_VC_SHIFT 5U +#define CIO2_MIPIBE_LP_LUT_ENTRY_FORMAT_TYPE_SHIFT 7U /* base register: CIO2_REG_PIPE_BASE(pipe) * CIO2_REG_IRQCTRL_BASE */ /* IRQ registers are 18-bit wide, see cio2_irq_error for bit definitions */ @@ -113,31 +113,31 @@ #define CIO2_CGC_ROSC_DCGE BIT(12) #define CIO2_CGC_XOSC_DCGE BIT(13) #define CIO2_CGC_FLIS_DCGE BIT(14) -#define CIO2_CGC_CLKGATE_HOLDOFF_SHIFT 20 -#define CIO2_CGC_CSI_CLKGATE_HOLDOFF_SHIFT 24 +#define CIO2_CGC_CLKGATE_HOLDOFF_SHIFT 20U +#define CIO2_CGC_CSI_CLKGATE_HOLDOFF_SHIFT 24U #define CIO2_REG_D0I3C 0x1408 #define CIO2_D0I3C_I3 BIT(2) /* Set D0I3 */ #define CIO2_D0I3C_RR BIT(3) /* Restore? */ #define CIO2_REG_SWRESET 0x140c -#define CIO2_SWRESET_SWRESET 1 +#define CIO2_SWRESET_SWRESET 1U #define CIO2_REG_SENSOR_ACTIVE 0x1410 #define CIO2_REG_INT_STS 0x1414 #define CIO2_REG_INT_STS_EXT_OE 0x1418 -#define CIO2_INT_EXT_OE_DMAOE_SHIFT 0 +#define CIO2_INT_EXT_OE_DMAOE_SHIFT 0U #define CIO2_INT_EXT_OE_DMAOE_MASK 0x7ffff -#define CIO2_INT_EXT_OE_OES_SHIFT 24 +#define CIO2_INT_EXT_OE_OES_SHIFT 24U #define CIO2_INT_EXT_OE_OES_MASK (0xf << CIO2_INT_EXT_OE_OES_SHIFT) #define CIO2_REG_INT_EN 0x1420 #define CIO2_REG_INT_EN_IRQ (1 << 24) -#define CIO2_REG_INT_EN_IOS(dma) (1 << (((dma) >> 1) + 12)) +#define CIO2_REG_INT_EN_IOS(dma) (1U << (((dma) >> 1U) + 12U)) /* * Interrupt on completion bit, Eg. DMA 0-3 maps to bit 0-3, * DMA4 & DMA5 map to bit 4 ... DMA18 & DMA19 map to bit 11 Et cetera */ -#define CIO2_INT_IOC(dma) (1 << ((dma) < 4 ? (dma) : ((dma) >> 1) + 2)) +#define CIO2_INT_IOC(dma) (1U << ((dma) < 4U ? (dma) : ((dma) >> 1U) + 2U)) #define CIO2_INT_IOC_SHIFT 0 #define CIO2_INT_IOC_MASK (0x7ff << CIO2_INT_IOC_SHIFT) -#define CIO2_INT_IOS_IOLN(dma) (1 << (((dma) >> 1) + 12)) +#define CIO2_INT_IOS_IOLN(dma) (1U << (((dma) >> 1U) + 12U)) #define CIO2_INT_IOS_IOLN_SHIFT 12 #define CIO2_INT_IOS_IOLN_MASK (0x3ff << CIO2_INT_IOS_IOLN_SHIFT) #define CIO2_INT_IOIE BIT(22) @@ -145,32 +145,32 @@ #define CIO2_INT_IOIRQ BIT(24) #define CIO2_REG_INT_EN_EXT_OE 0x1424 #define CIO2_REG_DMA_DBG 0x1448 -#define CIO2_REG_DMA_DBG_DMA_INDEX_SHIFT 0 +#define CIO2_REG_DMA_DBG_DMA_INDEX_SHIFT 0U #define CIO2_REG_PBM_ARB_CTRL 0x1460 -#define CIO2_PBM_ARB_CTRL_LANES_DIV 0 /* 4-4-2-2 lanes */ -#define CIO2_PBM_ARB_CTRL_LANES_DIV_SHIFT 0 +#define CIO2_PBM_ARB_CTRL_LANES_DIV 0U /* 4-4-2-2 lanes */ +#define CIO2_PBM_ARB_CTRL_LANES_DIV_SHIFT 0U #define CIO2_PBM_ARB_CTRL_LE_EN BIT(7) -#define CIO2_PBM_ARB_CTRL_PLL_POST_SHTDN 2 -#define CIO2_PBM_ARB_CTRL_PLL_POST_SHTDN_SHIFT 8 -#define CIO2_PBM_ARB_CTRL_PLL_AHD_WK_UP 480 -#define CIO2_PBM_ARB_CTRL_PLL_AHD_WK_UP_SHIFT 16 +#define CIO2_PBM_ARB_CTRL_PLL_POST_SHTDN 2U +#define CIO2_PBM_ARB_CTRL_PLL_POST_SHTDN_SHIFT 8U +#define CIO2_PBM_ARB_CTRL_PLL_AHD_WK_UP 480U +#define CIO2_PBM_ARB_CTRL_PLL_AHD_WK_UP_SHIFT 16U #define CIO2_REG_PBM_WMCTRL1 0x1464 -#define CIO2_PBM_WMCTRL1_MIN_2CK_SHIFT 0 -#define CIO2_PBM_WMCTRL1_MID1_2CK_SHIFT 8 -#define CIO2_PBM_WMCTRL1_MID2_2CK_SHIFT 16 +#define CIO2_PBM_WMCTRL1_MIN_2CK_SHIFT 0U +#define CIO2_PBM_WMCTRL1_MID1_2CK_SHIFT 8U +#define CIO2_PBM_WMCTRL1_MID2_2CK_SHIFT 16U #define CIO2_PBM_WMCTRL1_TS_COUNT_DISABLE BIT(31) #define CIO2_PBM_WMCTRL1_MIN_2CK (4 << CIO2_PBM_WMCTRL1_MIN_2CK_SHIFT) #define CIO2_PBM_WMCTRL1_MID1_2CK (16 << CIO2_PBM_WMCTRL1_MID1_2CK_SHIFT) #define CIO2_PBM_WMCTRL1_MID2_2CK (21 << CIO2_PBM_WMCTRL1_MID2_2CK_SHIFT) #define CIO2_REG_PBM_WMCTRL2 0x1468 -#define CIO2_PBM_WMCTRL2_HWM_2CK 40 -#define CIO2_PBM_WMCTRL2_HWM_2CK_SHIFT 0 -#define CIO2_PBM_WMCTRL2_LWM_2CK 22 -#define CIO2_PBM_WMCTRL2_LWM_2CK_SHIFT 8 -#define CIO2_PBM_WMCTRL2_OBFFWM_2CK 2 -#define CIO2_PBM_WMCTRL2_OBFFWM_2CK_SHIFT 16 -#define CIO2_PBM_WMCTRL2_TRANSDYN 1 -#define CIO2_PBM_WMCTRL2_TRANSDYN_SHIFT 24 +#define CIO2_PBM_WMCTRL2_HWM_2CK 40U +#define CIO2_PBM_WMCTRL2_HWM_2CK_SHIFT 0U +#define CIO2_PBM_WMCTRL2_LWM_2CK 22U +#define CIO2_PBM_WMCTRL2_LWM_2CK_SHIFT 8U +#define CIO2_PBM_WMCTRL2_OBFFWM_2CK 2U +#define CIO2_PBM_WMCTRL2_OBFFWM_2CK_SHIFT 16U +#define CIO2_PBM_WMCTRL2_TRANSDYN 1U +#define CIO2_PBM_WMCTRL2_TRANSDYN_SHIFT 24U #define CIO2_PBM_WMCTRL2_DYNWMEN BIT(28) #define CIO2_PBM_WMCTRL2_OBFF_MEM_EN BIT(29) #define CIO2_PBM_WMCTRL2_OBFF_CPU_EN BIT(30) @@ -178,12 +178,12 @@ #define CIO2_REG_PBM_TS_COUNT 0x146c #define CIO2_REG_PBM_FOPN_ABORT 0x1474 /* below n = 0..3 */ -#define CIO2_PBM_FOPN_ABORT(n) (0x1 << 8 * (n)) -#define CIO2_PBM_FOPN_FORCE_ABORT(n) (0x2 << 8 * (n)) -#define CIO2_PBM_FOPN_FRAMEOPEN(n) (0x8 << 8 * (n)) +#define CIO2_PBM_FOPN_ABORT(n) (0x1 << 8U * (n)) +#define CIO2_PBM_FOPN_FORCE_ABORT(n) (0x2 << 8U * (n)) +#define CIO2_PBM_FOPN_FRAMEOPEN(n) (0x8 << 8U * (n)) #define CIO2_REG_LTRCTRL 0x1480 #define CIO2_LTRCTRL_LTRDYNEN BIT(16) -#define CIO2_LTRCTRL_LTRSTABLETIME_SHIFT 8 +#define CIO2_LTRCTRL_LTRSTABLETIME_SHIFT 8U #define CIO2_LTRCTRL_LTRSTABLETIME_MASK 0xff #define CIO2_LTRCTRL_LTRSEL1S3 BIT(7) #define CIO2_LTRCTRL_LTRSEL1S2 BIT(6) @@ -195,28 +195,28 @@ #define CIO2_LTRCTRL_LTRSEL2S0 BIT(0) #define CIO2_REG_LTRVAL23 0x1484 #define CIO2_REG_LTRVAL01 0x1488 -#define CIO2_LTRVAL02_VAL_SHIFT 0 -#define CIO2_LTRVAL02_SCALE_SHIFT 10 -#define CIO2_LTRVAL13_VAL_SHIFT 16 -#define CIO2_LTRVAL13_SCALE_SHIFT 26 +#define CIO2_LTRVAL02_VAL_SHIFT 0U +#define CIO2_LTRVAL02_SCALE_SHIFT 10U +#define CIO2_LTRVAL13_VAL_SHIFT 16U +#define CIO2_LTRVAL13_SCALE_SHIFT 26U -#define CIO2_LTRVAL0_VAL 175 +#define CIO2_LTRVAL0_VAL 175U /* Value times 1024 ns */ -#define CIO2_LTRVAL0_SCALE 2 -#define CIO2_LTRVAL1_VAL 90 -#define CIO2_LTRVAL1_SCALE 2 -#define CIO2_LTRVAL2_VAL 90 -#define CIO2_LTRVAL2_SCALE 2 -#define CIO2_LTRVAL3_VAL 90 -#define CIO2_LTRVAL3_SCALE 2 +#define CIO2_LTRVAL0_SCALE 2U +#define CIO2_LTRVAL1_VAL 90U +#define CIO2_LTRVAL1_SCALE 2U +#define CIO2_LTRVAL2_VAL 90U +#define CIO2_LTRVAL2_SCALE 2U +#define CIO2_LTRVAL3_VAL 90U +#define CIO2_LTRVAL3_SCALE 2U #define CIO2_REG_CDMABA(n) (0x1500 + 0x10 * (n)) /* n = 0..19 */ #define CIO2_REG_CDMARI(n) (0x1504 + 0x10 * (n)) -#define CIO2_CDMARI_FBPT_RP_SHIFT 0 +#define CIO2_CDMARI_FBPT_RP_SHIFT 0U #define CIO2_CDMARI_FBPT_RP_MASK 0xff #define CIO2_REG_CDMAC0(n) (0x1508 + 0x10 * (n)) -#define CIO2_CDMAC0_FBPT_LEN_SHIFT 0 -#define CIO2_CDMAC0_FBPT_WIDTH_SHIFT 8 +#define CIO2_CDMAC0_FBPT_LEN_SHIFT 0U +#define CIO2_CDMAC0_FBPT_WIDTH_SHIFT 8U #define CIO2_CDMAC0_FBPT_NS BIT(25) #define CIO2_CDMAC0_DMA_INTR_ON_FS BIT(26) #define CIO2_CDMAC0_DMA_INTR_ON_FE BIT(27) @@ -225,12 +225,12 @@ #define CIO2_CDMAC0_DMA_EN BIT(30) #define CIO2_CDMAC0_DMA_HALTED BIT(31) #define CIO2_REG_CDMAC1(n) (0x150c + 0x10 * (n)) -#define CIO2_CDMAC1_LINENUMINT_SHIFT 0 -#define CIO2_CDMAC1_LINENUMUPDATE_SHIFT 16 +#define CIO2_CDMAC1_LINENUMINT_SHIFT 0U +#define CIO2_CDMAC1_LINENUMUPDATE_SHIFT 16U /* n = 0..3 */ #define CIO2_REG_PXM_PXF_FMT_CFG0(n) (0x1700 + 0x30 * (n)) -#define CIO2_PXM_PXF_FMT_CFG_SID0_SHIFT 0 -#define CIO2_PXM_PXF_FMT_CFG_SID1_SHIFT 16 +#define CIO2_PXM_PXF_FMT_CFG_SID0_SHIFT 0U +#define CIO2_PXM_PXF_FMT_CFG_SID1_SHIFT 16U #define CIO2_PXM_PXF_FMT_CFG_PCK_64B (0 << 0) #define CIO2_PXM_PXF_FMT_CFG_PCK_32B (1 << 0) #define CIO2_PXM_PXF_FMT_CFG_BPP_08 (0 << 2) @@ -249,27 +249,27 @@ #define CIO2_PXM_PXF_FMT_CFG_PSWAP4_2ND_BD (1 << 10) #define CIO2_REG_INT_STS_EXT_IE 0x17e4 #define CIO2_REG_INT_EN_EXT_IE 0x17e8 -#define CIO2_INT_EXT_IE_ECC_RE(n) (0x01 << (8 * (n))) -#define CIO2_INT_EXT_IE_DPHY_NR(n) (0x02 << (8 * (n))) -#define CIO2_INT_EXT_IE_ECC_NR(n) (0x04 << (8 * (n))) -#define CIO2_INT_EXT_IE_CRCERR(n) (0x08 << (8 * (n))) -#define CIO2_INT_EXT_IE_INTERFRAMEDATA(n) (0x10 << (8 * (n))) -#define CIO2_INT_EXT_IE_PKT2SHORT(n) (0x20 << (8 * (n))) -#define CIO2_INT_EXT_IE_PKT2LONG(n) (0x40 << (8 * (n))) -#define CIO2_INT_EXT_IE_IRQ(n) (0x80 << (8 * (n))) +#define CIO2_INT_EXT_IE_ECC_RE(n) (0x01 << (8U * (n))) +#define CIO2_INT_EXT_IE_DPHY_NR(n) (0x02 << (8U * (n))) +#define CIO2_INT_EXT_IE_ECC_NR(n) (0x04 << (8U * (n))) +#define CIO2_INT_EXT_IE_CRCERR(n) (0x08 << (8U * (n))) +#define CIO2_INT_EXT_IE_INTERFRAMEDATA(n) (0x10 << (8U * (n))) +#define CIO2_INT_EXT_IE_PKT2SHORT(n) (0x20 << (8U * (n))) +#define CIO2_INT_EXT_IE_PKT2LONG(n) (0x40 << (8U * (n))) +#define CIO2_INT_EXT_IE_IRQ(n) (0x80 << (8U * (n))) #define CIO2_REG_PXM_FRF_CFG(n) (0x1720 + 0x30 * (n)) #define CIO2_PXM_FRF_CFG_FNSEL BIT(0) #define CIO2_PXM_FRF_CFG_FN_RST BIT(1) #define CIO2_PXM_FRF_CFG_ABORT BIT(2) -#define CIO2_PXM_FRF_CFG_CRC_TH_SHIFT 3 +#define CIO2_PXM_FRF_CFG_CRC_TH_SHIFT 3U #define CIO2_PXM_FRF_CFG_MSK_ECC_DPHY_NR BIT(8) #define CIO2_PXM_FRF_CFG_MSK_ECC_RE BIT(9) #define CIO2_PXM_FRF_CFG_MSK_ECC_DPHY_NE BIT(10) -#define CIO2_PXM_FRF_CFG_EVEN_ODD_MODE_SHIFT 11 +#define CIO2_PXM_FRF_CFG_EVEN_ODD_MODE_SHIFT 11U #define CIO2_PXM_FRF_CFG_MASK_CRC_THRES BIT(13) #define CIO2_PXM_FRF_CFG_MASK_CSI_ACCEPT BIT(14) #define CIO2_PXM_FRF_CFG_CIOHC_FS_MODE BIT(15) -#define CIO2_PXM_FRF_CFG_CIOHC_FRST_FRM_SHIFT 16 +#define CIO2_PXM_FRF_CFG_CIOHC_FRST_FRM_SHIFT 16U #define CIO2_REG_PXM_SID2BID0(n) (0x1724 + 0x30 * (n)) #define CIO2_FB_HPLL_FREQ 0x2 #define CIO2_ISCLK_RATIO 0xc @@ -278,14 +278,14 @@ #define CIO2_INT_EN_EXT_OE_MASK 0x8f0fffff -#define CIO2_CGC_CLKGATE_HOLDOFF 3 -#define CIO2_CGC_CSI_CLKGATE_HOLDOFF 5 +#define CIO2_CGC_CLKGATE_HOLDOFF 3U +#define CIO2_CGC_CSI_CLKGATE_HOLDOFF 5U #define CIO2_PXM_FRF_CFG_CRC_TH 16 #define CIO2_INT_EN_EXT_IE_MASK 0xffffffff -#define CIO2_DMA_CHAN 0 +#define CIO2_DMA_CHAN 0U #define CIO2_CSIRX_DLY_CNT_CLANE_IDX -1 @@ -302,8 +302,8 @@ #define CIO2_CSIRX_DLY_CNT_TERMEN_DEFAULT 0x4 #define CIO2_CSIRX_DLY_CNT_SETTLE_DEFAULT 0x570 -#define CIO2_PMCSR_OFFSET 4 -#define CIO2_PMCSR_D0D3_SHIFT 2 +#define CIO2_PMCSR_OFFSET 4U +#define CIO2_PMCSR_D0D3_SHIFT 2U #define CIO2_PMCSR_D3 0x3 struct cio2_csi2_timing { -- cgit v1.2.3 From 40f072e181550058307a2847e4a1b417b05da293 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 12 Oct 2020 11:34:30 +0200 Subject: media: ipu3-cio2: Remove explicit type from frame size checks Now that the values are unsigned, we can remove the explicit cast to u32. Signed-off-by: Sakari Ailus Reviewed-by: Andy Shevchenko Reviewed-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/intel/ipu3/ipu3-cio2.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index 87d040e176f7..e42177f8c426 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -1282,9 +1282,8 @@ static int cio2_subdev_set_fmt(struct v4l2_subdev *sd, } } - fmt->format.width = min_t(u32, fmt->format.width, CIO2_IMAGE_MAX_WIDTH); - fmt->format.height = min_t(u32, fmt->format.height, - CIO2_IMAGE_MAX_LENGTH); + fmt->format.width = min(fmt->format.width, CIO2_IMAGE_MAX_WIDTH); + fmt->format.height = min(fmt->format.height, CIO2_IMAGE_MAX_LENGTH); fmt->format.field = V4L2_FIELD_NONE; mutex_lock(&q->subdev_lock); -- cgit v1.2.3 From b369132f0a0b1933a5d479d3b6a9441e30553885 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 12 Oct 2020 13:52:46 +0200 Subject: media: ipu3-cio2: Rename CIO2_IMAGE_MAX_LENGTH as CIO2_IMAGE_MAX_HEIGHT CIO2_IMAGE_MAX_LENGTH is the maximum height of the image. Rename it as "CIO2_IMAGE_MAX_HEIGHT" in order to better describe what it is. Suggested-by: Laurent Pinchart Signed-off-by: Sakari Ailus Reviewed-by: Andy Shevchenko Reviewed-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/intel/ipu3/ipu3-cio2.c | 6 +++--- drivers/media/pci/intel/ipu3/ipu3-cio2.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index e42177f8c426..d9baa8bfe54f 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -1094,8 +1094,8 @@ static int cio2_v4l2_try_fmt(struct file *file, void *fh, struct v4l2_format *f) /* Only supports up to 4224x3136 */ if (mpix->width > CIO2_IMAGE_MAX_WIDTH) mpix->width = CIO2_IMAGE_MAX_WIDTH; - if (mpix->height > CIO2_IMAGE_MAX_LENGTH) - mpix->height = CIO2_IMAGE_MAX_LENGTH; + if (mpix->height > CIO2_IMAGE_MAX_HEIGHT) + mpix->height = CIO2_IMAGE_MAX_HEIGHT; mpix->num_planes = 1; mpix->pixelformat = fmt->fourcc; @@ -1283,7 +1283,7 @@ static int cio2_subdev_set_fmt(struct v4l2_subdev *sd, } fmt->format.width = min(fmt->format.width, CIO2_IMAGE_MAX_WIDTH); - fmt->format.height = min(fmt->format.height, CIO2_IMAGE_MAX_LENGTH); + fmt->format.height = min(fmt->format.height, CIO2_IMAGE_MAX_HEIGHT); fmt->format.field = V4L2_FIELD_NONE; mutex_lock(&q->subdev_lock); diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.h b/drivers/media/pci/intel/ipu3/ipu3-cio2.h index 7650d7998a3f..ccf0b85ae36f 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.h +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.h @@ -14,7 +14,7 @@ #define CIO2_DMA_MASK DMA_BIT_MASK(39) #define CIO2_IMAGE_MAX_WIDTH 4224U -#define CIO2_IMAGE_MAX_LENGTH 3136U +#define CIO2_IMAGE_MAX_HEIGHT 3136U /* 32MB = 8xFBPT_entry */ #define CIO2_MAX_LOPS 8 -- cgit v1.2.3 From 61e7f892b5ee1dd10ea8bff805f3c3fe6e535959 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 12 Oct 2020 17:25:28 +0200 Subject: media: ipu3-cio2: Remove traces of returned buffers If starting a video buffer queue fails, the buffers are returned to videobuf2. Remove the reference to the buffer from the driver's queue as well. Fixes: c2a6a07afe4a ("media: intel-ipu3: cio2: add new MIPI-CSI2 driver") Signed-off-by: Sakari Ailus Cc: stable@vger.kernel.org # v4.16 and up Reviewed-by: Andy Shevchenko Reviewed-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/intel/ipu3/ipu3-cio2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index d9baa8bfe54f..51c4dd6a8f9a 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -791,6 +791,7 @@ static void cio2_vb2_return_all_buffers(struct cio2_queue *q, atomic_dec(&q->bufs_queued); vb2_buffer_done(&q->bufs[i]->vbb.vb2_buf, state); + q->bufs[i] = NULL; } } } -- cgit v1.2.3 From 32ea5e057aad9b90504836d444355d3cd86da230 Mon Sep 17 00:00:00 2001 From: Hugues Fruchet Date: Thu, 8 Oct 2020 10:29:16 +0200 Subject: media: ov5640: add support of 160x120 resolution Add support of 160x120 resolution. Signed-off-by: Hugues Fruchet Tested-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5640.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index 8d0254d0e5ea..40d6983fe473 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -98,7 +98,8 @@ #define OV5640_REG_AVG_READOUT 0x56a1 enum ov5640_mode_id { - OV5640_MODE_QCIF_176_144 = 0, + OV5640_MODE_QQVGA_160_120 = 0, + OV5640_MODE_QCIF_176_144, OV5640_MODE_QVGA_320_240, OV5640_MODE_VGA_640_480, OV5640_MODE_NTSC_720_480, @@ -416,6 +417,24 @@ static const struct reg_value ov5640_setting_QVGA_320_240[] = { {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, }; +static const struct reg_value ov5640_setting_QQVGA_160_120[] = { + {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + static const struct reg_value ov5640_setting_QCIF_176_144[] = { {0x3c07, 0x08, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, @@ -552,6 +571,11 @@ static const struct ov5640_mode_info ov5640_mode_init_data = { static const struct ov5640_mode_info ov5640_mode_data[OV5640_NUM_MODES] = { + {OV5640_MODE_QQVGA_160_120, SUBSAMPLING, + 160, 1896, 120, 984, + ov5640_setting_QQVGA_160_120, + ARRAY_SIZE(ov5640_setting_QQVGA_160_120), + OV5640_30_FPS}, {OV5640_MODE_QCIF_176_144, SUBSAMPLING, 176, 1896, 144, 984, ov5640_setting_QCIF_176_144, -- cgit v1.2.3 From b9b327623b45f7e57245638d19c04392b457cab9 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Wed, 7 Oct 2020 18:02:10 +0200 Subject: media: stm32-dcmi: don't print an error on probe deferral Change stm32-dcmi driver to not print an error message when the device probe operation is deferred. Signed-off-by: Etienne Carriere Acked-by: Hugues Fruchet Tested-by: Alexandre TORGUE Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/stm32/stm32-dcmi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index fd1c41cba52f..720534e1aee5 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -1851,7 +1851,9 @@ static int dcmi_probe(struct platform_device *pdev) dcmi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); if (IS_ERR(dcmi->rstc)) { - dev_err(&pdev->dev, "Could not get reset control\n"); + if (PTR_ERR(dcmi->rstc) != -EPROBE_DEFER) + dev_err(&pdev->dev, "Could not get reset control\n"); + return PTR_ERR(dcmi->rstc); } -- cgit v1.2.3 From ab32b2c3636b63b2a3d5ddb04627d6a3219d27d6 Mon Sep 17 00:00:00 2001 From: Hugues Fruchet Date: Wed, 7 Oct 2020 18:05:52 +0200 Subject: media: stm32-dcmi: remove deprecated dmaengine_terminate_all() Replace dmaengine_terminate_all() by dmaengine_terminate_sync() to ensure that all pending dma operations are really finished. This is not ensured by dmaengine_terminate_all() and this API is deprecated, so better to use the _sync() variant. Signed-off-by: Hugues Fruchet Reviewed-by: Philippe CORNU Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/stm32/stm32-dcmi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index 720534e1aee5..c6bb3e4759b0 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -324,7 +324,7 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi, } /* - * Avoid call of dmaengine_terminate_all() between + * Avoid call of dmaengine_terminate_sync() between * dmaengine_prep_slave_single() and dmaengine_submit() * by locking the whole DMA submission sequence */ @@ -438,7 +438,7 @@ static void dcmi_process_jpeg(struct stm32_dcmi *dcmi) } /* Abort DMA operation */ - dmaengine_terminate_all(dcmi->dma_chan); + dmaengine_terminate_sync(dcmi->dma_chan); /* Restart capture */ if (dcmi_restart_capture(dcmi)) @@ -882,7 +882,7 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) /* Stop all pending DMA operations */ mutex_lock(&dcmi->dma_lock); - dmaengine_terminate_all(dcmi->dma_chan); + dmaengine_terminate_sync(dcmi->dma_chan); mutex_unlock(&dcmi->dma_lock); pm_runtime_put(dcmi->dev); -- cgit v1.2.3 From 734f0b0153f91b0bf79aea84593befffc85c3f98 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Wed, 7 Oct 2020 18:08:25 +0200 Subject: media: stm32-dcmi: add 8-bit Bayer formats support Add BA81, GBRG, GRBG, RGGB formats in the list of supported capture formats. Signed-off-by: Alain Volmat Acked-by: Hugues FRUCHET Reviewed-by: Philippe CORNU Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/stm32/stm32-dcmi.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index c6bb3e4759b0..5b988f676bad 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -1574,6 +1574,22 @@ static const struct dcmi_format dcmi_formats[] = { .fourcc = V4L2_PIX_FMT_JPEG, .mbus_code = MEDIA_BUS_FMT_JPEG_1X8, .bpp = 1, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, + .bpp = 1, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, + .bpp = 1, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, + .bpp = 1, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB8, + .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, + .bpp = 1, }, }; -- cgit v1.2.3 From 3abafaf41ab743162cae543932d94575d483ecbb Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Tue, 6 Oct 2020 22:38:17 +0200 Subject: media: ov7670: do not aggregate returns Adding muliple status together loses individual failures. Check each status separately. Clean up some other returns for consistency. Fixed several coding style problems by running the file through checkpatch.pl --fix-inplace Signed-off-by: Tom Rix Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov7670.c | 96 +++++++++++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 40 deletions(-) diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index b42b289faaef..d2df811b1a40 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -561,6 +561,7 @@ static int ov7670_read(struct v4l2_subdev *sd, unsigned char reg, unsigned char *value) { struct ov7670_info *info = to_state(sd); + if (info->use_smbus) return ov7670_read_smbus(sd, reg, value); else @@ -571,6 +572,7 @@ static int ov7670_write(struct v4l2_subdev *sd, unsigned char reg, unsigned char value) { struct ov7670_info *info = to_state(sd); + if (info->use_smbus) return ov7670_write_smbus(sd, reg, value); else @@ -597,6 +599,7 @@ static int ov7670_write_array(struct v4l2_subdev *sd, struct regval_list *vals) { while (vals->reg_num != 0xff || vals->value != 0xff) { int ret = ov7670_write(sd, vals->reg_num, vals->value); + if (ret < 0) return ret; vals++; @@ -921,27 +924,38 @@ static int ov7670_set_hw(struct v4l2_subdev *sd, int hstart, int hstop, { int ret; unsigned char v; -/* - * Horizontal: 11 bits, top 8 live in hstart and hstop. Bottom 3 of - * hstart are in href[2:0], bottom 3 of hstop in href[5:3]. There is - * a mystery "edge offset" value in the top two bits of href. - */ - ret = ov7670_write(sd, REG_HSTART, (hstart >> 3) & 0xff); - ret += ov7670_write(sd, REG_HSTOP, (hstop >> 3) & 0xff); - ret += ov7670_read(sd, REG_HREF, &v); + /* + * Horizontal: 11 bits, top 8 live in hstart and hstop. Bottom 3 of + * hstart are in href[2:0], bottom 3 of hstop in href[5:3]. There is + * a mystery "edge offset" value in the top two bits of href. + */ + ret = ov7670_write(sd, REG_HSTART, (hstart >> 3) & 0xff); + if (ret) + return ret; + ret = ov7670_write(sd, REG_HSTOP, (hstop >> 3) & 0xff); + if (ret) + return ret; + ret = ov7670_read(sd, REG_HREF, &v); + if (ret) + return ret; v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7); msleep(10); - ret += ov7670_write(sd, REG_HREF, v); -/* - * Vertical: similar arrangement, but only 10 bits. - */ - ret += ov7670_write(sd, REG_VSTART, (vstart >> 2) & 0xff); - ret += ov7670_write(sd, REG_VSTOP, (vstop >> 2) & 0xff); - ret += ov7670_read(sd, REG_VREF, &v); + ret = ov7670_write(sd, REG_HREF, v); + if (ret) + return ret; + /* Vertical: similar arrangement, but only 10 bits. */ + ret = ov7670_write(sd, REG_VSTART, (vstart >> 2) & 0xff); + if (ret) + return ret; + ret = ov7670_write(sd, REG_VSTOP, (vstop >> 2) & 0xff); + if (ret) + return ret; + ret = ov7670_read(sd, REG_VREF, &v); + if (ret) + return ret; v = (v & 0xf0) | ((vstop & 0x3) << 2) | (vstart & 0x3); msleep(10); - ret += ov7670_write(sd, REG_VREF, v); - return ret; + return ov7670_write(sd, REG_VREF, v); } @@ -1245,6 +1259,7 @@ static int ov7670_enum_frame_size(struct v4l2_subdev *sd, */ for (i = 0; i < n_win_sizes; i++) { struct ov7670_win_size *win = &info->devtype->win_sizes[i]; + if (info->min_width && win->width < info->min_width) continue; if (info->min_height && win->height < info->min_height) @@ -1285,17 +1300,17 @@ static int ov7670_store_cmatrix(struct v4l2_subdev *sd, raw = 0xff; else raw = (-1 * matrix[i]) & 0xff; - } - else { + } else { if (matrix[i] > 255) raw = 0xff; else raw = matrix[i] & 0xff; } - ret += ov7670_write(sd, REG_CMATRIX_BASE + i, raw); + ret = ov7670_write(sd, REG_CMATRIX_BASE + i, raw); + if (ret) + return ret; } - ret += ov7670_write(sd, REG_CMATRIX_SIGN, signbits); - return ret; + return ov7670_write(sd, REG_CMATRIX_SIGN, signbits); } @@ -1381,11 +1396,9 @@ static int ov7670_s_sat_hue(struct v4l2_subdev *sd, int sat, int hue) { struct ov7670_info *info = to_state(sd); int matrix[CMATRIX_LEN]; - int ret; ov7670_calc_cmatrix(info, matrix, sat, hue); - ret = ov7670_store_cmatrix(sd, matrix); - return ret; + return ov7670_store_cmatrix(sd, matrix); } @@ -1403,14 +1416,12 @@ static unsigned char ov7670_abs_to_sm(unsigned char v) static int ov7670_s_brightness(struct v4l2_subdev *sd, int value) { unsigned char com8 = 0, v; - int ret; ov7670_read(sd, REG_COM8, &com8); com8 &= ~COM8_AEC; ov7670_write(sd, REG_COM8, com8); v = ov7670_abs_to_sm(value); - ret = ov7670_write(sd, REG_BRIGHT, v); - return ret; + return ov7670_write(sd, REG_BRIGHT, v); } static int ov7670_s_contrast(struct v4l2_subdev *sd, int value) @@ -1424,13 +1435,14 @@ static int ov7670_s_hflip(struct v4l2_subdev *sd, int value) int ret; ret = ov7670_read(sd, REG_MVFP, &v); + if (ret) + return ret; if (value) v |= MVFP_MIRROR; else v &= ~MVFP_MIRROR; msleep(10); /* FIXME */ - ret += ov7670_write(sd, REG_MVFP, v); - return ret; + return ov7670_write(sd, REG_MVFP, v); } static int ov7670_s_vflip(struct v4l2_subdev *sd, int value) @@ -1439,13 +1451,14 @@ static int ov7670_s_vflip(struct v4l2_subdev *sd, int value) int ret; ret = ov7670_read(sd, REG_MVFP, &v); + if (ret) + return ret; if (value) v |= MVFP_FLIP; else v &= ~MVFP_FLIP; msleep(10); /* FIXME */ - ret += ov7670_write(sd, REG_MVFP, v); - return ret; + return ov7670_write(sd, REG_MVFP, v); } /* @@ -1460,8 +1473,10 @@ static int ov7670_g_gain(struct v4l2_subdev *sd, __s32 *value) unsigned char gain; ret = ov7670_read(sd, REG_GAIN, &gain); + if (ret) + return ret; *value = gain; - return ret; + return 0; } static int ov7670_s_gain(struct v4l2_subdev *sd, int value) @@ -1470,12 +1485,13 @@ static int ov7670_s_gain(struct v4l2_subdev *sd, int value) unsigned char com8; ret = ov7670_write(sd, REG_GAIN, value & 0xff); + if (ret) + return ret; /* Have to turn off AGC as well */ - if (ret == 0) { - ret = ov7670_read(sd, REG_COM8, &com8); - ret = ov7670_write(sd, REG_COM8, com8 & ~COM8_AGC); - } - return ret; + ret = ov7670_read(sd, REG_COM8, &com8); + if (ret) + return ret; + return ov7670_write(sd, REG_COM8, com8 & ~COM8_AGC); } /* @@ -1680,13 +1696,13 @@ static int ov7670_s_power(struct v4l2_subdev *sd, int on) return 0; if (on) { - ov7670_power_on (sd); + ov7670_power_on(sd); ov7670_init(sd, 0); ov7670_apply_fmt(sd); ov7675_apply_framerate(sd); v4l2_ctrl_handler_setup(&info->hdl); } else { - ov7670_power_off (sd); + ov7670_power_off(sd); } return 0; -- cgit v1.2.3 From 98f9aafa9f411bbc4f352191340b74db0ba908a8 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 13 Oct 2020 14:12:02 +0200 Subject: media: ipu3-cio2: Check receved the size against payload size, not buffer size Compare the received size of the payload size, not the allocated size of the buffer that is page aligned. This way also images that aren't aligned to page size are not warned about. Also wrap a line over 80 characters. Suggested-by: Laurent Pinchart Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Tested-by: Jean-Michel Hautbois Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/intel/ipu3/ipu3-cio2.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index 51c4dd6a8f9a..c557d189200b 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -561,7 +561,9 @@ static void cio2_buffer_done(struct cio2_device *cio2, unsigned int dma_chan) b = q->bufs[q->bufs_first]; if (b) { - unsigned int bytes = entry[1].second_entry.num_of_bytes; + unsigned int received = entry[1].second_entry.num_of_bytes; + unsigned long payload = + vb2_get_plane_payload(&b->vbb.vb2_buf, 0); q->bufs[q->bufs_first] = NULL; atomic_dec(&q->bufs_queued); @@ -571,10 +573,10 @@ static void cio2_buffer_done(struct cio2_device *cio2, unsigned int dma_chan) b->vbb.vb2_buf.timestamp = ns; b->vbb.field = V4L2_FIELD_NONE; b->vbb.sequence = atomic_read(&q->frame_sequence); - if (b->vbb.vb2_buf.planes[0].length != bytes) - dev_warn(dev, "buffer length is %d received %d\n", - b->vbb.vb2_buf.planes[0].length, - bytes); + if (payload != received) + dev_warn(dev, + "payload length is %lu, received %u\n", + payload, received); vb2_buffer_done(&b->vbb.vb2_buf, VB2_BUF_STATE_DONE); } atomic_inc(&q->frame_sequence); -- cgit v1.2.3 From d3ed195bc761a1c5e5f1feae519318a4f91d258c Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 13 Oct 2020 15:11:37 +0200 Subject: media: Documentation: v4l: Fix language Remove extra "is" from sentence explaining V4L2_CID_PIXEL_RATE may be used to tell the pixel rate used by a transmitter driver. Also call V4L2_CID_PIXEL_RATE a control. Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- Documentation/driver-api/media/csi2.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Documentation/driver-api/media/csi2.rst b/Documentation/driver-api/media/csi2.rst index e1b838014906..e3bbc6baf0f0 100644 --- a/Documentation/driver-api/media/csi2.rst +++ b/Documentation/driver-api/media/csi2.rst @@ -28,10 +28,9 @@ interface elements must be present on the sub-device represents the CSI-2 transmitter. The V4L2_CID_LINK_FREQ control is used to tell the receiver driver the -frequency (and not the symbol rate) of the link. The -V4L2_CID_PIXEL_RATE is may be used by the receiver to obtain the pixel -rate the transmitter uses. The -:c:type:`v4l2_subdev_video_ops`->s_stream() callback provides an +frequency (and not the symbol rate) of the link. The V4L2_CID_PIXEL_RATE +control may be used by the receiver to obtain the pixel rate the transmitter +uses. The :c:type:`v4l2_subdev_video_ops`->s_stream() callback provides an ability to start and stop the stream. The value of the V4L2_CID_PIXEL_RATE is calculated as follows:: -- cgit v1.2.3 From 9d0a79e55a626165efb52bb15d714d231fc985e6 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 13 Oct 2020 16:02:27 +0200 Subject: media: Documentation: v4l: Document required controls on camera sensors Raw camera sensors connected to parallel or CSI-2 busses need to implement V4L2_CID_LINK_FREQ control so receiver drivers can configure the hardware accordingly. Document this. Also say V4L2_CID_PIXEL_RATE is recommended for such hardware. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- Documentation/driver-api/media/camera-sensor.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Documentation/driver-api/media/camera-sensor.rst b/Documentation/driver-api/media/camera-sensor.rst index 4d1ae12b9b4d..ffb0cad8137a 100644 --- a/Documentation/driver-api/media/camera-sensor.rst +++ b/Documentation/driver-api/media/camera-sensor.rst @@ -132,3 +132,16 @@ used to obtain device's power state after the power state transition: The function returns a non-zero value if it succeeded getting the power count or runtime PM was disabled, in either of which cases the driver may proceed to access the device. + +Controls +-------- + +For camera sensors that are connected to a bus where transmitter and receiver +require common configuration set by drivers, such as CSI-2 or parallel (BT.601 +or BT.656) bus, the ``V4L2_CID_LINK_FREQ`` control is mandatory on transmitter +drivers. Receiver drivers can use the ``V4L2_CID_LINK_FREQ`` to query the +frequency used on the bus. + +The transmitter drivers should also implement ``V4L2_CID_PIXEL_RATE`` control in +order to tell the maximum pixel rate to the receiver. This is required on raw +camera sensors. -- cgit v1.2.3 From 1b888b3cebef2de3936167e95652830145040b78 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 13 Oct 2020 16:54:00 +0200 Subject: media: v4l: Add a helper for obtaining the link frequency Add a helper for obtaining the link frequency from transmitter drivers. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-common.c | 33 +++++++++++++++++++++++++++++++++ include/media/v4l2-common.h | 21 +++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index 3dc17ebe14fa..78007dba4677 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -441,3 +441,36 @@ int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat, return 0; } EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt); + +s64 v4l2_get_link_rate(struct v4l2_ctrl_handler *handler, unsigned int mul, + unsigned int div) +{ + struct v4l2_ctrl *ctrl; + s64 freq; + + ctrl = v4l2_ctrl_find(handler, V4L2_CID_LINK_FREQ); + if (ctrl) { + struct v4l2_querymenu qm = { .id = V4L2_CID_LINK_FREQ }; + int ret; + + qm.index = v4l2_ctrl_g_ctrl(ctrl); + + ret = v4l2_querymenu(handler, &qm); + if (ret) + return -ENOENT; + + freq = qm.value; + } else { + if (!mul || !div) + return -ENOENT; + + ctrl = v4l2_ctrl_find(handler, V4L2_CID_PIXEL_RATE); + if (!ctrl) + return -ENOENT; + + freq = div_u64(v4l2_ctrl_g_ctrl_int64(ctrl) * mul, div); + } + + return freq > 0 ? freq : -EINVAL; +} +EXPORT_SYMBOL_GPL(v4l2_get_link_rate); diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index a3083529b698..be36cbdcc1bd 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -519,6 +519,27 @@ int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat, int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, u32 pixelformat, u32 width, u32 height); +/** + * v4l2_get_link_rate - Get link rate from transmitter + * + * @handler: The transmitter's control handler + * @mul: The multiplier between pixel rate and link frequency. Bits per pixel on + * D-PHY, samples per clock on parallel. 0 otherwise. + * @div: The divisor between pixel rate and link frequency. Number of data lanes + * times two on D-PHY, 1 on parallel. 0 otherwise. + * + * This function is intended for obtaining the link frequency from the + * transmitter sub-devices. It returns the link rate, either from the + * V4L2_CID_LINK_FREQ control implemented by the transmitter, or value + * calculated based on the V4L2_CID_PIXEL_RATE implemented by the transmitter. + * + * Returns link frequency on success, otherwise a negative error code: + * -ENOENT: Link frequency or pixel rate control not found + * -EINVAL: Invalid link frequency value + */ +s64 v4l2_get_link_rate(struct v4l2_ctrl_handler *handler, unsigned int mul, + unsigned int div); + static inline u64 v4l2_buffer_get_timestamp(const struct v4l2_buffer *buf) { /* -- cgit v1.2.3 From 4b6c129e87a31289f21077090698711f3c3ea459 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 13 Oct 2020 17:01:10 +0200 Subject: media: ipu3-cio2: Use v4l2_get_link_freq helper Use v4l2_get_link_freq helper and add support for sensor drivers implementing only V4L2_CID_PIXEL_RATE. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/intel/ipu3/ipu3-cio2.c | 34 +++++++++++--------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index c557d189200b..d060cfe473d8 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -33,6 +33,7 @@ struct ipu3_cio2_fmt { u32 mbus_code; u32 fourcc; u8 mipicode; + u8 bpp; }; /* @@ -46,18 +47,22 @@ static const struct ipu3_cio2_fmt formats[] = { .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, .fourcc = V4L2_PIX_FMT_IPU3_SGRBG10, .mipicode = 0x2b, + .bpp = 10, }, { .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, .fourcc = V4L2_PIX_FMT_IPU3_SGBRG10, .mipicode = 0x2b, + .bpp = 10, }, { .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, .fourcc = V4L2_PIX_FMT_IPU3_SBGGR10, .mipicode = 0x2b, + .bpp = 10, }, { .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, .fourcc = V4L2_PIX_FMT_IPU3_SRGGB10, .mipicode = 0x2b, + .bpp = 10, }, }; @@ -288,35 +293,20 @@ static s32 cio2_rx_timing(s32 a, s32 b, s64 freq, int def) /* Calculate the the delay value for termination enable of clock lane HS Rx */ static int cio2_csi2_calc_timing(struct cio2_device *cio2, struct cio2_queue *q, - struct cio2_csi2_timing *timing) + struct cio2_csi2_timing *timing, + unsigned int bpp, unsigned int lanes) { struct device *dev = &cio2->pci_dev->dev; - struct v4l2_querymenu qm = { .id = V4L2_CID_LINK_FREQ }; - struct v4l2_ctrl *link_freq; s64 freq; - int r; if (!q->sensor) return -ENODEV; - link_freq = v4l2_ctrl_find(q->sensor->ctrl_handler, V4L2_CID_LINK_FREQ); - if (!link_freq) { - dev_err(dev, "failed to find LINK_FREQ\n"); - return -EPIPE; - } - - qm.index = v4l2_ctrl_g_ctrl(link_freq); - r = v4l2_querymenu(q->sensor->ctrl_handler, &qm); - if (r) { - dev_err(dev, "failed to get menu item\n"); - return r; - } - - if (!qm.value) { - dev_err(dev, "error invalid link_freq\n"); - return -EINVAL; + freq = v4l2_get_link_rate(q->sensor->ctrl_handler, bpp, lanes); + if (freq < 0) { + dev_err(dev, "error %lld, invalid link_freq\n", freq); + return freq; } - freq = qm.value; timing->clk_termen = cio2_rx_timing(CIO2_CSIRX_DLY_CNT_TERMEN_CLANE_A, CIO2_CSIRX_DLY_CNT_TERMEN_CLANE_B, @@ -364,7 +354,7 @@ static int cio2_hw_init(struct cio2_device *cio2, struct cio2_queue *q) lanes = q->csi2.lanes; - r = cio2_csi2_calc_timing(cio2, q, &timing); + r = cio2_csi2_calc_timing(cio2, q, &timing, fmt->bpp, lanes); if (r) return r; -- cgit v1.2.3 From 68579b32e786f9680e7c6b6c7d17e26943bb02b3 Mon Sep 17 00:00:00 2001 From: Hugues Fruchet Date: Tue, 13 Oct 2020 11:02:23 +0200 Subject: media: ov5640: fix support of BT656 bus mode Fix PCLK polarity not being taken into account. Add comments about BT656 register control. Remove useless ov5640_set_stream_bt656() function. Refine comments about MIPI IO register control. Fixes: 4039b03720f7 ("media: i2c: ov5640: Add support for BT656 mode") Signed-off-by: Hugues Fruchet Reviewed-by: Jacopo Mondi Tested-by: Lad Prabhakar Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5640.c | 82 +++++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 37 deletions(-) diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index 40d6983fe473..14f3afa7721a 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -1240,20 +1240,6 @@ static int ov5640_set_autogain(struct ov5640_dev *sensor, bool on) BIT(1), on ? 0 : BIT(1)); } -static int ov5640_set_stream_bt656(struct ov5640_dev *sensor, bool on) -{ - int ret; - - ret = ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, - on ? 0x1 : 0x00); - if (ret) - return ret; - - return ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, on ? - OV5640_REG_SYS_CTRL0_SW_PWUP : - OV5640_REG_SYS_CTRL0_SW_PWDN); -} - static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on) { return ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, on ? @@ -2018,13 +2004,13 @@ static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on) static int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on) { unsigned int flags = sensor->ep.bus.parallel.flags; - u8 pclk_pol = 0; - u8 hsync_pol = 0; - u8 vsync_pol = 0; + bool bt656 = sensor->ep.bus_type == V4L2_MBUS_BT656; + u8 polarities = 0; int ret; if (!on) { /* Reset settings to their default values. */ + ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 0x00); ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58); ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, 0x20); ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 0x00); @@ -2048,7 +2034,35 @@ static int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on) * - VSYNC: active high * - HREF: active low * - PCLK: active low + * + * VSYNC & HREF are not configured if BT656 bus mode is selected */ + + /* + * BT656 embedded synchronization configuration + * + * CCIR656 CTRL00 + * - [7]: SYNC code selection (0: auto generate sync code, + * 1: sync code from regs 0x4732-0x4735) + * - [6]: f value in CCIR656 SYNC code when fixed f value + * - [5]: Fixed f value + * - [4:3]: Blank toggle data options (00: data=1'h040/1'h200, + * 01: data from regs 0x4736-0x4738, 10: always keep 0) + * - [1]: Clip data disable + * - [0]: CCIR656 mode enable + * + * Default CCIR656 SAV/EAV mode with default codes + * SAV=0xff000080 & EAV=0xff00009d is enabled here with settings: + * - CCIR656 mode enable + * - auto generation of sync codes + * - blank toggle data 1'h040/1'h200 + * - clip reserved data (0x00 & 0xff changed to 0x01 & 0xfe) + */ + ret = ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, + bt656 ? 0x01 : 0x00); + if (ret) + return ret; + /* * configure parallel port control lines polarity * @@ -2059,29 +2073,26 @@ static int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on) * datasheet and hardware, 0 is active high * and 1 is active low...) */ - if (sensor->ep.bus_type == V4L2_MBUS_PARALLEL) { - if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) - pclk_pol = 1; + if (!bt656) { if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) - hsync_pol = 1; + polarities |= BIT(1); if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) - vsync_pol = 1; - - ret = ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, - (pclk_pol << 5) | (hsync_pol << 1) | - vsync_pol); - - if (ret) - return ret; + polarities |= BIT(0); } + if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) + polarities |= BIT(5); + + ret = ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, polarities); + if (ret) + return ret; /* - * powerdown MIPI TX/RX PHY & disable MIPI + * powerdown MIPI TX/RX PHY & enable DVP * * MIPI CONTROL 00 - * 4: PWDN PHY TX - * 3: PWDN PHY RX - * 2: MIPI enable + * [4] = 1 : Power down MIPI HS Tx + * [3] = 1 : Power down MIPI LS Rx + * [2] = 0 : DVP enable (MIPI disable) */ ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x18); if (ret) @@ -2098,8 +2109,7 @@ static int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on) * - [3:0]: D[9:6] output enable */ ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, - sensor->ep.bus_type == V4L2_MBUS_PARALLEL ? - 0x7f : 0x1f); + bt656 ? 0x1f : 0x7f); if (ret) return ret; @@ -2949,8 +2959,6 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable) if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY) ret = ov5640_set_stream_mipi(sensor, enable); - else if (sensor->ep.bus_type == V4L2_MBUS_BT656) - ret = ov5640_set_stream_bt656(sensor, enable); else ret = ov5640_set_stream_dvp(sensor, enable); -- cgit v1.2.3 From d30ac9d81a33757467eeb8e78606c7748220fb21 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 28 Oct 2020 11:03:57 +0100 Subject: media: imx258: Remove Jason Chen's e-mail Remove Jason Chen's e-mail address for it no longer works. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx258.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c index ccb55fd1d506..df62c69a48c0 100644 --- a/drivers/media/i2c/imx258.c +++ b/drivers/media/i2c/imx258.c @@ -1305,6 +1305,6 @@ module_i2c_driver(imx258_i2c_driver); MODULE_AUTHOR("Yeh, Andy "); MODULE_AUTHOR("Chiang, Alan"); -MODULE_AUTHOR("Chen, Jason "); +MODULE_AUTHOR("Chen, Jason"); MODULE_DESCRIPTION("Sony IMX258 sensor driver"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 6651dba2bd838f34cf5a1e84229aaa579b1a94fe Mon Sep 17 00:00:00 2001 From: Evgeny Novikov Date: Tue, 14 Jul 2020 19:20:49 +0200 Subject: media: isif: reset global state isif_probe() invokes iounmap() on error handling paths, but it does not reset the global state. So, later it can invoke iounmap() even when ioremap() fails. This is the case also for isif_remove(). The patch resets the global state after invoking iounmap() to avoid this. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Evgeny Novikov Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/isif.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/davinci/isif.c b/drivers/media/platform/davinci/isif.c index c98edb67cfb2..c53cecd072b1 100644 --- a/drivers/media/platform/davinci/isif.c +++ b/drivers/media/platform/davinci/isif.c @@ -1075,10 +1075,14 @@ fail_base_iomap: release_mem_region(res->start, resource_size(res)); i--; fail_nobase_res: - if (isif_cfg.base_addr) + if (isif_cfg.base_addr) { iounmap(isif_cfg.base_addr); - if (isif_cfg.linear_tbl0_addr) + isif_cfg.base_addr = NULL; + } + if (isif_cfg.linear_tbl0_addr) { iounmap(isif_cfg.linear_tbl0_addr); + isif_cfg.linear_tbl0_addr = NULL; + } while (i >= 0) { res = platform_get_resource(pdev, IORESOURCE_MEM, i); @@ -1096,8 +1100,11 @@ static int isif_remove(struct platform_device *pdev) int i = 0; iounmap(isif_cfg.base_addr); + isif_cfg.base_addr = NULL; iounmap(isif_cfg.linear_tbl0_addr); + isif_cfg.linear_tbl0_addr = NULL; iounmap(isif_cfg.linear_tbl1_addr); + isif_cfg.linear_tbl1_addr = NULL; while (i < 3) { res = platform_get_resource(pdev, IORESOURCE_MEM, i); if (res) -- cgit v1.2.3 From 7243f33120dd150150c5999127b3ba9fa567e1ac Mon Sep 17 00:00:00 2001 From: Hsin-Yi Wang Date: Thu, 3 Sep 2020 07:48:33 +0200 Subject: media: mtk-vcodec: remove allocated dma_parms Commit 9495b7e92f71 ("driver core: platform: Initialize dma_parms for platform devices") included dma_parms in platform_device. There's no need to allocate again. Fixes: 13483fc2f20f ("media: mtk-vcodec: set dma max segment size") Suggested-by: Robin Murphy Signed-off-by: Hsin-Yi Wang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c | 9 +-------- drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c | 9 +-------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c index d14bc208ea5e..c7ed09fbafb6 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c @@ -232,14 +232,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev) mtk_v4l2_err("Could not get vdec IPI device"); return -ENODEV; } - if (!pdev->dev.dma_parms) { - pdev->dev.dma_parms = devm_kzalloc(&pdev->dev, - sizeof(*pdev->dev.dma_parms), - GFP_KERNEL); - if (!pdev->dev.dma_parms) - return -ENOMEM; - } - dma_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); + dma_set_max_seg_size(&pdev->dev, UINT_MAX); dev->fw_handler = mtk_vcodec_fw_select(dev, fw_type, VPU_RST_DEC); if (IS_ERR(dev->fw_handler)) diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c index dcfa2c2d4def..a2aa96b03f66 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c @@ -284,14 +284,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev) mtk_v4l2_err("Could not get venc IPI device"); return -ENODEV; } - if (!pdev->dev.dma_parms) { - pdev->dev.dma_parms = devm_kzalloc(&pdev->dev, - sizeof(*pdev->dev.dma_parms), - GFP_KERNEL); - if (!pdev->dev.dma_parms) - return -ENOMEM; - } - dma_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); + dma_set_max_seg_size(&pdev->dev, UINT_MAX); dev->fw_handler = mtk_vcodec_fw_select(dev, fw_type, VPU_RST_ENC); if (IS_ERR(dev->fw_handler)) -- cgit v1.2.3 From 652ce6769349e669e1514093a83dd913cc9b5039 Mon Sep 17 00:00:00 2001 From: Liu Shixin Date: Mon, 21 Sep 2020 10:24:39 +0200 Subject: media: media/pci: simplify the return expression of verify_window_lock Simplify the return expression. Signed-off-by: Liu Shixin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index ef2ead36b70e..956a12e311c0 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -2058,7 +2058,6 @@ verify_window_lock(struct bttv_fh *fh, struct v4l2_window *win, { enum v4l2_field field; unsigned int width_mask; - int rc; if (win->w.width < 48) win->w.width = 48; @@ -2111,13 +2110,10 @@ verify_window_lock(struct bttv_fh *fh, struct v4l2_window *win, win->w.width -= win->w.left & ~width_mask; win->w.left = (win->w.left - width_mask - 1) & width_mask; - rc = limit_scaled_size_lock(fh, &win->w.width, &win->w.height, - field, width_mask, - /* width_bias: round down */ 0, - adjust_size, adjust_crop); - if (0 != rc) - return rc; - return 0; + return limit_scaled_size_lock(fh, &win->w.width, &win->w.height, + field, width_mask, + /* width_bias: round down */ 0, + adjust_size, adjust_crop); } static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv, -- cgit v1.2.3 From 4cbbe2aaa0536b0e7b3dfbd7febc3bc2ec300559 Mon Sep 17 00:00:00 2001 From: Zhang Qilong Date: Mon, 2 Nov 2020 15:28:52 +0100 Subject: media: staging: rkisp1: cap: fix runtime PM imbalance on error pm_runtime_get_sync will increment pm usage counter even it failed. Forgetting to pm_runtime_put_noidle will result in reference imbalance in rkisp1_vb2_start_streaming, so we should fix it. Fixes: 56e3b29f9f6b2 ("media: staging: rkisp1: add streaming paths") Signed-off-by: Zhang Qilong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/rkisp1/rkisp1-capture.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/media/rkisp1/rkisp1-capture.c b/drivers/staging/media/rkisp1/rkisp1-capture.c index a7a013204177..6d2fd27970f2 100644 --- a/drivers/staging/media/rkisp1/rkisp1-capture.c +++ b/drivers/staging/media/rkisp1/rkisp1-capture.c @@ -1005,6 +1005,7 @@ rkisp1_vb2_start_streaming(struct vb2_queue *queue, unsigned int count) ret = pm_runtime_get_sync(cap->rkisp1->dev); if (ret < 0) { + pm_runtime_put_noidle(cap->rkisp1->dev); dev_err(cap->rkisp1->dev, "power up failed %d\n", ret); goto err_destroy_dummy; } -- cgit v1.2.3 From 940727bf22f74cbdef8de327de34c4ae565c89ea Mon Sep 17 00:00:00 2001 From: Zhang Qilong Date: Mon, 2 Nov 2020 15:26:22 +0100 Subject: media: cedrus: fix reference leak in cedrus_start_streaming pm_runtime_get_sync will increment pm usage counter even it failed. Forgetting to pm_runtime_put_noidle will result in reference leak in cedrus_start_streaming. We should fix it. Fixes: d5aecd289babf ("media: cedrus: Implement runtime PM") Signed-off-by: Zhang Qilong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/sunxi/cedrus/cedrus_video.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c index 667b86dde1ee..911f607d9b09 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c @@ -479,8 +479,10 @@ static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count) if (V4L2_TYPE_IS_OUTPUT(vq->type)) { ret = pm_runtime_get_sync(dev->dev); - if (ret < 0) + if (ret < 0) { + pm_runtime_put_noidle(dev->dev); goto err_cleanup; + } if (dev->dec_ops[ctx->current_codec]->start) { ret = dev->dec_ops[ctx->current_codec]->start(ctx); -- cgit v1.2.3 From 6ad253cc3436269fc6bcff03d704c672f368da0a Mon Sep 17 00:00:00 2001 From: Dafna Hirschfeld Date: Fri, 30 Oct 2020 14:46:08 +0100 Subject: media: uapi: add MEDIA_BUS_FMT_METADATA_FIXED media bus format. MEDIA_BUS_FMT_METADATA_FIXED should be used when the same driver handles both sides of the link and the bus format is a fixed metadata format that is not configurable from userspace. The width and height will be set to 0 for this format. Signed-off-by: Dafna Hirschfeld Acked-by: Helen Koike Acked-by: Sakari Ailus Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/subdev-formats.rst | 27 ++++++++++++++++++++++ include/uapi/linux/media-bus-format.h | 8 +++++++ 2 files changed, 35 insertions(+) diff --git a/Documentation/userspace-api/media/v4l/subdev-formats.rst b/Documentation/userspace-api/media/v4l/subdev-formats.rst index c9b7bb3ca089..7f16cbe46e5c 100644 --- a/Documentation/userspace-api/media/v4l/subdev-formats.rst +++ b/Documentation/userspace-api/media/v4l/subdev-formats.rst @@ -7899,3 +7899,30 @@ formats. - 0x5001 - Interleaved raw UYVY and JPEG image format with embedded meta-data used by Samsung S3C73MX camera sensors. + +.. _v4l2-mbus-metadata-fmts: + +Metadata Formats +^^^^^^^^^^^^^^^^ + +This section lists all metadata formats. + +The following table lists the existing metadata formats. + +.. tabularcolumns:: |p{8.0cm}|p{1.4cm}|p{7.7cm}| + +.. flat-table:: Metadata formats + :header-rows: 1 + :stub-columns: 0 + + * - Identifier + - Code + - Comments + * .. _MEDIA-BUS-FMT-METADATA-FIXED: + + - MEDIA_BUS_FMT_METADATA_FIXED + - 0x7001 + - This format should be used when the same driver handles + both sides of the link and the bus format is a fixed + metadata format that is not configurable from userspace. + Width and height will be set to 0 for this format. diff --git a/include/uapi/linux/media-bus-format.h b/include/uapi/linux/media-bus-format.h index 84fa53ffb13f..2ce3d891d344 100644 --- a/include/uapi/linux/media-bus-format.h +++ b/include/uapi/linux/media-bus-format.h @@ -156,4 +156,12 @@ /* HSV - next is 0x6002 */ #define MEDIA_BUS_FMT_AHSV8888_1X32 0x6001 +/* + * This format should be used when the same driver handles + * both sides of the link and the bus format is a fixed + * metadata format that is not configurable from userspace. + * Width and height will be set to 0 for this format. + */ +#define MEDIA_BUS_FMT_METADATA_FIXED 0x7001 + #endif /* __LINUX_MEDIA_BUS_FORMAT_H */ -- cgit v1.2.3 From 8cb7ebe4ebd70b33a6edb30c9984febb9947a407 Mon Sep 17 00:00:00 2001 From: Dafna Hirschfeld Date: Fri, 30 Oct 2020 14:46:09 +0100 Subject: media: staging: rkisp1: isp: set metadata pads to MEDIA_BUS_FMT_METADATA_FIXED Set the code of the metadata pads of the isp entity to MEDIA_BUS_FMT_METADATA_FIXED and set the width and height of their formats to 0. This solves the TODO item: "Fix pad format size for statistics and parameters entities." Signed-off-by: Dafna Hirschfeld Acked-by: Helen Koike Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/rkisp1/TODO | 1 - drivers/staging/media/rkisp1/rkisp1-isp.c | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/staging/media/rkisp1/TODO b/drivers/staging/media/rkisp1/TODO index 75aae98242d0..ca3651fd0833 100644 --- a/drivers/staging/media/rkisp1/TODO +++ b/drivers/staging/media/rkisp1/TODO @@ -1,4 +1,3 @@ -* Fix pad format size for statistics and parameters entities. * Fix checkpatch errors. NOTES: diff --git a/drivers/staging/media/rkisp1/rkisp1-isp.c b/drivers/staging/media/rkisp1/rkisp1-isp.c index a9715b0b7264..48d08ff87da2 100644 --- a/drivers/staging/media/rkisp1/rkisp1-isp.c +++ b/drivers/staging/media/rkisp1/rkisp1-isp.c @@ -574,7 +574,7 @@ static int rkisp1_isp_enum_mbus_code(struct v4l2_subdev *sd, } else { if (code->index > 0) return -EINVAL; - code->code = MEDIA_BUS_FMT_FIXED; + code->code = MEDIA_BUS_FMT_METADATA_FIXED; return 0; } @@ -633,10 +633,10 @@ static int rkisp1_isp_init_config(struct v4l2_subdev *sd, RKISP1_ISP_PAD_SINK_PARAMS); src_fmt = v4l2_subdev_get_try_format(sd, cfg, RKISP1_ISP_PAD_SOURCE_STATS); - sink_fmt->width = RKISP1_DEFAULT_WIDTH; - sink_fmt->height = RKISP1_DEFAULT_HEIGHT; + sink_fmt->width = 0; + sink_fmt->height = 0; sink_fmt->field = V4L2_FIELD_NONE; - sink_fmt->code = MEDIA_BUS_FMT_FIXED; + sink_fmt->code = MEDIA_BUS_FMT_METADATA_FIXED; *src_fmt = *sink_fmt; return 0; -- cgit v1.2.3 From 8297ae5c29fc715d1da2e057852053dd900c99a6 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Tue, 3 Nov 2020 22:32:37 +0100 Subject: media: coda: coda_buffer_meta housekeeping fix It's possible that the VPU was initialized using just one buffer, containing only codec headers. In this case, right after the initialization and after updating the FIFO read pointer, we need to iterate through all the coda_buffer_meta and release any metas that have been already used by the VPU. This issue is affecting indirectly the bitstream buffer fill threshold, which depends on the meta end position of the first queued meta, which is passed to coda_bitstream_can_fetch_past(). Without this fix, it's possible that for certain videos, the bitstream buffer level is not filled properly, resulting in a PIC_RUN timeout. Reported-by: Benjamin Bara Signed-off-by: Ezequiel Garcia Reviewed-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 42 ++++++++++++++++++++++++++++++---- drivers/media/platform/coda/coda.h | 1 + 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 659fcf77b0ed..919b36d753ec 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1836,6 +1836,29 @@ static bool coda_reorder_enable(struct coda_ctx *ctx) return profile > V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; } +static void coda_decoder_drop_used_metas(struct coda_ctx *ctx) +{ + struct coda_buffer_meta *meta, *tmp; + + /* + * All metas that end at or before the RD pointer (fifo out), + * are now consumed by the VPU and should be released. + */ + spin_lock(&ctx->buffer_meta_lock); + list_for_each_entry_safe(meta, tmp, &ctx->buffer_meta_list, list) { + if (ctx->bitstream_fifo.kfifo.out >= meta->end) { + coda_dbg(2, ctx, "releasing meta: seq=%d start=%d end=%d\n", + meta->sequence, meta->start, meta->end); + + list_del(&meta->list); + ctx->num_metas--; + ctx->first_frame_sequence++; + kfree(meta); + } + } + spin_unlock(&ctx->buffer_meta_lock); +} + static int __coda_decoder_seq_init(struct coda_ctx *ctx) { struct coda_q_data *q_data_src, *q_data_dst; @@ -1921,10 +1944,17 @@ static int __coda_decoder_seq_init(struct coda_ctx *ctx) } ctx->sequence_offset = ~0U; ctx->initialized = 1; + ctx->first_frame_sequence = 0; /* Update kfifo out pointer from coda bitstream read pointer */ coda_kfifo_sync_from_device(ctx); + /* + * After updating the read pointer, we need to check if + * any metas are consumed and should be released. + */ + coda_decoder_drop_used_metas(ctx); + if (coda_read(dev, CODA_RET_DEC_SEQ_SUCCESS) == 0) { v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT failed, error code = 0x%x\n", @@ -2395,12 +2425,16 @@ static void coda_finish_decode(struct coda_ctx *ctx) v4l2_err(&dev->v4l2_dev, "decoded frame index out of range: %d\n", decoded_idx); } else { + int sequence; + decoded_frame = &ctx->internal_frames[decoded_idx]; val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM); if (ctx->sequence_offset == -1) ctx->sequence_offset = val; - val -= ctx->sequence_offset; + + sequence = val + ctx->first_frame_sequence + - ctx->sequence_offset; spin_lock(&ctx->buffer_meta_lock); if (!list_empty(&ctx->buffer_meta_list)) { meta = list_first_entry(&ctx->buffer_meta_list, @@ -2415,10 +2449,10 @@ static void coda_finish_decode(struct coda_ctx *ctx) * should be enough to detect most errors and saves us * from doing different things based on the format. */ - if ((val & 0xffff) != (meta->sequence & 0xffff)) { + if ((sequence & 0xffff) != (meta->sequence & 0xffff)) { v4l2_err(&dev->v4l2_dev, "sequence number mismatch (%d(%d) != %d)\n", - val, ctx->sequence_offset, + sequence, ctx->sequence_offset, meta->sequence); } decoded_frame->meta = *meta; @@ -2428,7 +2462,7 @@ static void coda_finish_decode(struct coda_ctx *ctx) v4l2_err(&dev->v4l2_dev, "empty timestamp list!\n"); memset(&decoded_frame->meta, 0, sizeof(struct coda_buffer_meta)); - decoded_frame->meta.sequence = val; + decoded_frame->meta.sequence = sequence; decoded_frame->meta.last = false; ctx->sequence_offset++; } diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index b81f3aca9209..e53f7a65d532 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -259,6 +259,7 @@ struct coda_ctx { struct list_head buffer_meta_list; spinlock_t buffer_meta_lock; int num_metas; + unsigned int first_frame_sequence; struct coda_aux_buf workbuf; int num_internal_frames; int idx; -- cgit v1.2.3 From b2d3bef1aa7858b2ae5e0d01adb214121ba00b9f Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Wed, 4 Nov 2020 18:43:11 +0100 Subject: media: coda: Add a V4L2 user for control error macroblocks count To avoid potentially overflowing the kernel logs in the case of corrupted streams, this commit replaces an error message with a per-stream counter to be read through a driver-specific control. Applications can read the per-stream accumulated error macroblocks count. The old error message is replaced by a rate-limited debug message. Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 10 +++++++--- drivers/media/platform/coda/coda-common.c | 18 ++++++++++++++++++ drivers/media/platform/coda/coda.h | 10 ++++++++++ include/uapi/linux/v4l2-controls.h | 6 ++++++ 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 919b36d753ec..2f42808c43a4 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -2369,9 +2370,12 @@ static void coda_finish_decode(struct coda_ctx *ctx) } err_mb = coda_read(dev, CODA_RET_DEC_PIC_ERR_MB); - if (err_mb > 0) - v4l2_err(&dev->v4l2_dev, - "errors in %d macroblocks\n", err_mb); + if (err_mb > 0) { + if (__ratelimit(&dev->mb_err_rs)) + coda_dbg(1, ctx, "errors in %d macroblocks\n", err_mb); + v4l2_ctrl_s_ctrl(ctx->mb_err_cnt_ctrl, + v4l2_ctrl_g_ctrl(ctx->mb_err_cnt_ctrl) + err_mb); + } if (dev->devtype->product == CODA_HX4 || dev->devtype->product == CODA_7541) { diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index f9e66247e92a..d30eafea701d 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -2062,6 +2063,7 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) if (q_data_dst->fourcc == V4L2_PIX_FMT_JPEG) ctx->params.gop_size = 1; ctx->gopcounter = ctx->params.gop_size - 1; + v4l2_ctrl_s_ctrl(ctx->mb_err_cnt_ctrl, 0); ret = ctx->ops->start_streaming(ctx); if (ctx->inst_type == CODA_INST_DECODER) { @@ -2462,6 +2464,15 @@ static void coda_decode_ctrls(struct coda_ctx *ctx) ctx->mpeg4_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; } +static const struct v4l2_ctrl_config coda_mb_err_cnt_ctrl_config = { + .id = V4L2_CID_CODA_MB_ERR_CNT, + .name = "Macroblocks Error Count", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 0x7fffffff, + .step = 1, +}; + static int coda_ctrls_setup(struct coda_ctx *ctx) { v4l2_ctrl_handler_init(&ctx->ctrls, 2); @@ -2484,6 +2495,12 @@ static int coda_ctrls_setup(struct coda_ctx *ctx) 1, 1, 1, 1); if (ctx->cvd->src_formats[0] == V4L2_PIX_FMT_H264) coda_decode_ctrls(ctx); + + ctx->mb_err_cnt_ctrl = v4l2_ctrl_new_custom(&ctx->ctrls, + &coda_mb_err_cnt_ctrl_config, + NULL); + if (ctx->mb_err_cnt_ctrl) + ctx->mb_err_cnt_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; } if (ctx->ctrls.error) { @@ -3202,6 +3219,7 @@ static int coda_probe(struct platform_device *pdev) if (ret) return ret; + ratelimit_default_init(&dev->mb_err_rs); mutex_init(&dev->dev_mutex); mutex_init(&dev->coda_mutex); ida_init(&dev->ida); diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index e53f7a65d532..dcf35641c603 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -28,6 +29,13 @@ #define CODA_MAX_FRAMEBUFFERS 19 #define FMO_SLICE_SAVE_BUF_SIZE (32) +/* + * This control allows applications to read the per-stream + * (i.e. per-context) Macroblocks Error Count. This value + * is CODA specific. + */ +#define V4L2_CID_CODA_MB_ERR_CNT (V4L2_CID_USER_CODA_BASE + 0) + enum { V4L2_M2M_SRC = 0, V4L2_M2M_DST = 1, @@ -92,6 +100,7 @@ struct coda_dev { struct v4l2_m2m_dev *m2m_dev; struct ida ida; struct dentry *debugfs_root; + struct ratelimit_state mb_err_rs; }; struct coda_codec { @@ -242,6 +251,7 @@ struct coda_ctx { struct v4l2_ctrl *mpeg2_level_ctrl; struct v4l2_ctrl *mpeg4_profile_ctrl; struct v4l2_ctrl *mpeg4_level_ctrl; + struct v4l2_ctrl *mb_err_cnt_ctrl; struct v4l2_fh fh; int gopcounter; int runcounter; diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index a184c4939438..7035f4fb182c 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -198,6 +198,12 @@ enum v4l2_colorfx { */ #define V4L2_CID_USER_ATMEL_ISC_BASE (V4L2_CID_USER_BASE + 0x10c0) +/* + * The base for the CODA driver controls. + * We reserve 16 controls for this driver. + */ +#define V4L2_CID_USER_CODA_BASE (V4L2_CID_USER_BASE + 0x10e0) + /* MPEG-class control IDs */ /* The MPEG controls are applicable to all codec controls * and the 'MPEG' part of the define is historical */ -- cgit v1.2.3 From d41662e52a0321e6263278d9a9791ef4b03b5af7 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Tue, 25 Aug 2020 19:35:21 +0200 Subject: media: dt-bindings: media: allwinner,sun4i-a10-video-engine: Add R40 compatible Allwinner R40 SoC contains video engine. Add compatible for it. Signed-off-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/allwinner,sun4i-a10-video-engine.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-video-engine.yaml b/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-video-engine.yaml index 4cc1a670c986..0d58bbcd24d3 100644 --- a/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-video-engine.yaml +++ b/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-video-engine.yaml @@ -18,6 +18,7 @@ properties: - allwinner,sun7i-a20-video-engine - allwinner,sun8i-a33-video-engine - allwinner,sun8i-h3-video-engine + - allwinner,sun8i-r40-video-engine - allwinner,sun50i-a64-video-engine - allwinner,sun50i-h5-video-engine - allwinner,sun50i-h6-video-engine -- cgit v1.2.3 From f50613c1a83070a5212bbf394559ebd4b09e3f20 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Tue, 25 Aug 2020 19:35:22 +0200 Subject: media: cedrus: Add support for R40 Video engine in R40 is very similar to that in A33 but it runs on lower speed, at least according to OS images released by board designer. Signed-off-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/sunxi/cedrus/cedrus.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index e0e35502e34a..9a102b7c1bb9 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -508,6 +508,11 @@ static const struct cedrus_variant sun8i_h3_cedrus_variant = { .mod_rate = 402000000, }; +static const struct cedrus_variant sun8i_r40_cedrus_variant = { + .capabilities = CEDRUS_CAPABILITY_UNTILED, + .mod_rate = 297000000, +}; + static const struct cedrus_variant sun50i_a64_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_UNTILED | CEDRUS_CAPABILITY_H265_DEC, @@ -548,6 +553,10 @@ static const struct of_device_id cedrus_dt_match[] = { .compatible = "allwinner,sun8i-h3-video-engine", .data = &sun8i_h3_cedrus_variant, }, + { + .compatible = "allwinner,sun8i-r40-video-engine", + .data = &sun8i_r40_cedrus_variant, + }, { .compatible = "allwinner,sun50i-a64-video-engine", .data = &sun50i_a64_cedrus_variant, -- cgit v1.2.3 From 0d72f489995bb8565f6fe30539d4504c88356a9e Mon Sep 17 00:00:00 2001 From: Yu Kuai Date: Wed, 4 Nov 2020 13:41:36 +0100 Subject: media: platform: add missing put_device() call in mtk_jpeg_probe() and mtk_jpeg_remove() if mtk_jpeg_clk_init() succeed, mtk_jpeg_probe() and mtk_jpeg_remove() doesn't have a corresponding put_device(). Thus add a new helper mtk_jpeg_clk_release() to fix it. Fixes: b2f0d2724ba4 ("[media] vcodec: mediatek: Add Mediatek JPEG Decoder Driver") Signed-off-by: Yu Kuai Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c index 106543391c46..88a23bce569d 100644 --- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c @@ -1332,6 +1332,12 @@ static void mtk_jpeg_job_timeout_work(struct work_struct *work) v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx); } + +static inline void mtk_jpeg_clk_release(struct mtk_jpeg_dev *jpeg) +{ + put_device(jpeg->larb); +} + static int mtk_jpeg_probe(struct platform_device *pdev) { struct mtk_jpeg_dev *jpeg; @@ -1436,6 +1442,7 @@ err_m2m_init: v4l2_device_unregister(&jpeg->v4l2_dev); err_dev_register: + mtk_jpeg_clk_release(jpeg); err_clk_init: @@ -1453,6 +1460,7 @@ static int mtk_jpeg_remove(struct platform_device *pdev) video_device_release(jpeg->vdev); v4l2_m2m_release(jpeg->m2m_dev); v4l2_device_unregister(&jpeg->v4l2_dev); + mtk_jpeg_clk_release(jpeg); return 0; } -- cgit v1.2.3 From b064945517ee368bfb6343bf3fb4613d537c4bbb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 23 Oct 2020 16:08:10 +0200 Subject: media: fix kernel-doc markups Some identifiers have different names between their prototypes and the kernel-doc markup. Seome seems to be due to cut-and-paste related issues. Others need to be fixed, as kernel-doc markups should use this format: identifier - description Acked-by: Sakari Ailus # IPU3 and V4L2 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/ascot2e.h | 2 +- drivers/media/dvb-frontends/cxd2820r.h | 2 +- drivers/media/dvb-frontends/drxk.h | 2 +- drivers/media/dvb-frontends/dvb-pll.h | 2 +- drivers/media/dvb-frontends/helene.h | 4 ++-- drivers/media/dvb-frontends/horus3a.h | 2 +- drivers/media/dvb-frontends/ix2505v.h | 4 ++-- drivers/media/dvb-frontends/m88ds3103.h | 2 +- drivers/media/dvb-frontends/mb86a20s.h | 2 +- drivers/media/dvb-frontends/stb6000.h | 2 +- drivers/media/dvb-frontends/tda826x.h | 2 +- drivers/media/dvb-frontends/zl10036.h | 4 ++-- drivers/staging/media/ipu3/include/intel-ipu3.h | 8 ++++---- include/media/dvbdev.h | 2 +- include/media/v4l2-ctrls.h | 2 +- include/media/v4l2-dev.h | 4 ++-- include/media/v4l2-device.h | 2 +- include/media/v4l2-dv-timings.h | 2 +- include/media/v4l2-fwnode.h | 2 +- include/media/v4l2-mediabus.h | 6 +++--- include/media/v4l2-subdev.h | 2 +- include/media/videobuf2-core.h | 2 +- 22 files changed, 31 insertions(+), 31 deletions(-) diff --git a/drivers/media/dvb-frontends/ascot2e.h b/drivers/media/dvb-frontends/ascot2e.h index f886fab1283f..d86b3de85c6a 100644 --- a/drivers/media/dvb-frontends/ascot2e.h +++ b/drivers/media/dvb-frontends/ascot2e.h @@ -33,7 +33,7 @@ struct ascot2e_config { #if IS_REACHABLE(CONFIG_DVB_ASCOT2E) /** - * Attach an ascot2e tuner + * ascot2e_attach - Attach an ascot2e tuner * * @fe: frontend to be attached * @config: pointer to &struct ascot2e_config with tuner configuration. diff --git a/drivers/media/dvb-frontends/cxd2820r.h b/drivers/media/dvb-frontends/cxd2820r.h index a28b8754932b..4aa6cf4fb913 100644 --- a/drivers/media/dvb-frontends/cxd2820r.h +++ b/drivers/media/dvb-frontends/cxd2820r.h @@ -96,7 +96,7 @@ struct cxd2820r_config { #if IS_REACHABLE(CONFIG_DVB_CXD2820R) /** - * Attach a cxd2820r demod + * cxd2820r_attach - Attach a cxd2820r demod * * @config: pointer to &struct cxd2820r_config with demod configuration. * @i2c: i2c adapter to use. diff --git a/drivers/media/dvb-frontends/drxk.h b/drivers/media/dvb-frontends/drxk.h index ee06e89187e4..69fdca00f364 100644 --- a/drivers/media/dvb-frontends/drxk.h +++ b/drivers/media/dvb-frontends/drxk.h @@ -54,7 +54,7 @@ struct drxk_config { #if IS_REACHABLE(CONFIG_DVB_DRXK) /** - * Attach a drxk demod + * drxk_attach - Attach a drxk demod * * @config: pointer to &struct drxk_config with demod configuration. * @i2c: i2c adapter to use. diff --git a/drivers/media/dvb-frontends/dvb-pll.h b/drivers/media/dvb-frontends/dvb-pll.h index 973a66a82e27..71838888743b 100644 --- a/drivers/media/dvb-frontends/dvb-pll.h +++ b/drivers/media/dvb-frontends/dvb-pll.h @@ -38,7 +38,7 @@ struct dvb_pll_config { #if IS_REACHABLE(CONFIG_DVB_PLL) /** - * Attach a dvb-pll to the supplied frontend structure. + * dvb_pll_attach - Attach a dvb-pll to the supplied frontend structure. * * @fe: Frontend to attach to. * @pll_addr: i2c address of the PLL (if used). diff --git a/drivers/media/dvb-frontends/helene.h b/drivers/media/dvb-frontends/helene.h index c026bdcf548d..32e0b1fb268c 100644 --- a/drivers/media/dvb-frontends/helene.h +++ b/drivers/media/dvb-frontends/helene.h @@ -44,7 +44,7 @@ struct helene_config { #if IS_REACHABLE(CONFIG_DVB_HELENE) /** - * Attach a helene tuner (terrestrial and cable standards) + * helene_attach - Attach a helene tuner (terrestrial and cable standards) * * @fe: frontend to be attached * @config: pointer to &struct helene_config with tuner configuration. @@ -57,7 +57,7 @@ extern struct dvb_frontend *helene_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c); /** - * Attach a helene tuner (satellite standards) + * helene_attach_s - Attach a helene tuner (satellite standards) * * @fe: frontend to be attached * @config: pointer to &struct helene_config with tuner configuration. diff --git a/drivers/media/dvb-frontends/horus3a.h b/drivers/media/dvb-frontends/horus3a.h index 366c399e3329..91dbe20169cd 100644 --- a/drivers/media/dvb-frontends/horus3a.h +++ b/drivers/media/dvb-frontends/horus3a.h @@ -33,7 +33,7 @@ struct horus3a_config { #if IS_REACHABLE(CONFIG_DVB_HORUS3A) /** - * Attach a horus3a tuner + * horus3a_attach - Attach a horus3a tuner * * @fe: frontend to be attached * @config: pointer to &struct helene_config with tuner configuration. diff --git a/drivers/media/dvb-frontends/ix2505v.h b/drivers/media/dvb-frontends/ix2505v.h index 671c0e0959f7..175569131365 100644 --- a/drivers/media/dvb-frontends/ix2505v.h +++ b/drivers/media/dvb-frontends/ix2505v.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Driver for Sharp IX2505V (marked B0017) DVB-S silicon tuner * * Copyright (C) 2010 Malcolm Priestley @@ -31,7 +31,7 @@ struct ix2505v_config { #if IS_REACHABLE(CONFIG_DVB_IX2505V) /** - * Attach a ix2505v tuner to the supplied frontend structure. + * ix2505v_attach - Attach a ix2505v tuner to the supplied frontend structure. * * @fe: Frontend to attach to. * @config: pointer to &struct ix2505v_config diff --git a/drivers/media/dvb-frontends/m88ds3103.h b/drivers/media/dvb-frontends/m88ds3103.h index 46b722495e4c..e32b68c0df70 100644 --- a/drivers/media/dvb-frontends/m88ds3103.h +++ b/drivers/media/dvb-frontends/m88ds3103.h @@ -128,7 +128,7 @@ struct m88ds3103_config { #if defined(CONFIG_DVB_M88DS3103) || \ (defined(CONFIG_DVB_M88DS3103_MODULE) && defined(MODULE)) /** - * Attach a m88ds3103 demod + * m88ds3103_attach - Attach a m88ds3103 demod * * @config: pointer to &struct m88ds3103_config with demod configuration. * @i2c: i2c adapter to use. diff --git a/drivers/media/dvb-frontends/mb86a20s.h b/drivers/media/dvb-frontends/mb86a20s.h index 00a6b6e9b5e4..d20d22bf7580 100644 --- a/drivers/media/dvb-frontends/mb86a20s.h +++ b/drivers/media/dvb-frontends/mb86a20s.h @@ -26,7 +26,7 @@ struct mb86a20s_config { #if IS_REACHABLE(CONFIG_DVB_MB86A20S) /** - * Attach a mb86a20s demod + * mb86a20s_attach - Attach a mb86a20s demod * * @config: pointer to &struct mb86a20s_config with demod configuration. * @i2c: i2c adapter to use. diff --git a/drivers/media/dvb-frontends/stb6000.h b/drivers/media/dvb-frontends/stb6000.h index 570a4b1d07d6..38da55af7ea9 100644 --- a/drivers/media/dvb-frontends/stb6000.h +++ b/drivers/media/dvb-frontends/stb6000.h @@ -15,7 +15,7 @@ #if IS_REACHABLE(CONFIG_DVB_STB6000) /** - * Attach a stb6000 tuner to the supplied frontend structure. + * stb6000_attach - Attach a stb6000 tuner to the supplied frontend structure. * * @fe: Frontend to attach to. * @addr: i2c address of the tuner. diff --git a/drivers/media/dvb-frontends/tda826x.h b/drivers/media/dvb-frontends/tda826x.h index bb575a251b04..e1d33edbb8ec 100644 --- a/drivers/media/dvb-frontends/tda826x.h +++ b/drivers/media/dvb-frontends/tda826x.h @@ -14,7 +14,7 @@ #include /** - * Attach a tda826x tuner to the supplied frontend structure. + * tda826x_attach - Attach a tda826x tuner to the supplied frontend structure. * * @fe: Frontend to attach to. * @addr: i2c address of the tuner. diff --git a/drivers/media/dvb-frontends/zl10036.h b/drivers/media/dvb-frontends/zl10036.h index 91eea777eaf1..ad83e6344e7f 100644 --- a/drivers/media/dvb-frontends/zl10036.h +++ b/drivers/media/dvb-frontends/zl10036.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Driver for Zarlink ZL10036 DVB-S silicon tuner * * Copyright (C) 2006 Tino Reichardt @@ -19,7 +19,7 @@ struct zl10036_config { #if IS_REACHABLE(CONFIG_DVB_ZL10036) /** - * Attach a zl10036 tuner to the supplied frontend structure. + * zl10036_attach - Attach a zl10036 tuner to the supplied frontend structure. * * @fe: Frontend to attach to. * @config: zl10036_config structure. diff --git a/drivers/staging/media/ipu3/include/intel-ipu3.h b/drivers/staging/media/ipu3/include/intel-ipu3.h index 3a45c1fe4957..edd8edda0647 100644 --- a/drivers/staging/media/ipu3/include/intel-ipu3.h +++ b/drivers/staging/media/ipu3/include/intel-ipu3.h @@ -418,7 +418,7 @@ struct ipu3_uapi_af_config_s { IPU3_UAPI_AWB_FR_SPARE_FOR_BUBBLES) * IPU3_UAPI_MAX_STRIPES) /** - * struct ipu3_uapi_awb_fr_meta_data - AWB filter response meta data + * struct ipu3_uapi_awb_fr_raw_buffer - AWB filter response meta data * * @meta_data: Statistics output on the grid after convolving with 1D filter. */ @@ -1506,7 +1506,7 @@ struct ipu3_uapi_sharp_cfg { } __packed; /** - * struct struct ipu3_uapi_far_w - Sharpening config for far sub-group + * struct ipu3_uapi_far_w - Sharpening config for far sub-group * * @dir_shrp: Weight of wide direct sharpening, u1.6, range [0, 64], default 64. * @reserved0: reserved @@ -1526,7 +1526,7 @@ struct ipu3_uapi_far_w { } __packed; /** - * struct struct ipu3_uapi_unsharp_cfg - Unsharp config + * struct ipu3_uapi_unsharp_cfg - Unsharp config * * @unsharp_weight: Unsharp mask blending weight. * u1.6, range [0, 64], default 16. @@ -1772,7 +1772,7 @@ struct ipu3_uapi_vss_lut_y { } __packed; /** - * struct ipu3_uapi_yuvp1_iefd_vssnlm_cf - IEFd Vssnlm Lookup table + * struct ipu3_uapi_yuvp1_iefd_vssnlm_cfg - IEFd Vssnlm Lookup table * * @vss_lut_x: vss lookup table. See &ipu3_uapi_vss_lut_x description * @vss_lut_y: vss lookup table. See &ipu3_uapi_vss_lut_y description diff --git a/include/media/dvbdev.h b/include/media/dvbdev.h index e547cbeee431..b04a38be5183 100644 --- a/include/media/dvbdev.h +++ b/include/media/dvbdev.h @@ -321,7 +321,7 @@ int dvb_create_media_graph(struct dvb_adapter *adap, int dvb_generic_open(struct inode *inode, struct file *file); /** - * dvb_generic_close - Digital TV close function, used by DVB devices + * dvb_generic_release - Digital TV close function, used by DVB devices * * @inode: pointer to &struct inode. * @file: pointer to &struct file. diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index cb25f345e9ad..4fbace0fc7e5 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -1292,7 +1292,7 @@ static inline void v4l2_ctrl_request_hdl_put(struct v4l2_ctrl_handler *hdl) } /** - * v4l2_ctrl_request_ctrl_find() - Find a control with the given ID. + * v4l2_ctrl_request_hdl_ctrl_find() - Find a control with the given ID. * * @hdl: The control handler from the request. * @id: The ID of the control to find. diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index ad2d41952442..6a4afd4a7df2 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h @@ -43,8 +43,8 @@ enum vfl_devnode_type { }; /** - * enum vfl_direction - Identifies if a &struct video_device corresponds - * to a receiver, a transmitter or a mem-to-mem device. + * enum vfl_devnode_direction - Identifies if a &struct video_device + * corresponds to a receiver, a transmitter or a mem-to-mem device. * * @VFL_DIR_RX: device is a receiver. * @VFL_DIR_TX: device is a transmitter. diff --git a/include/media/v4l2-device.h b/include/media/v4l2-device.h index 64ec4de948e9..8a8977a33ec1 100644 --- a/include/media/v4l2-device.h +++ b/include/media/v4l2-device.h @@ -174,7 +174,7 @@ int __must_check v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, void v4l2_device_unregister_subdev(struct v4l2_subdev *sd); /** - * __v4l2_device_register_ro_subdev_nodes - Registers device nodes for + * __v4l2_device_register_subdev_nodes - Registers device nodes for * all subdevs of the v4l2 device that are marked with the * %V4L2_SUBDEV_FL_HAS_DEVNODE flag. * diff --git a/include/media/v4l2-dv-timings.h b/include/media/v4l2-dv-timings.h index 2cc0cabc124f..8fa963326bf6 100644 --- a/include/media/v4l2-dv-timings.h +++ b/include/media/v4l2-dv-timings.h @@ -224,7 +224,7 @@ static inline bool can_reduce_fps(struct v4l2_bt_timings *bt) } /** - * struct v4l2_hdmi_rx_colorimetry - describes the HDMI colorimetry information + * struct v4l2_hdmi_colorimetry - describes the HDMI colorimetry information * @colorspace: enum v4l2_colorspace, the colorspace * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding * @quantization: enum v4l2_quantization, colorspace quantization diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h index be30e066c621..4e1f6e1d847e 100644 --- a/include/media/v4l2-fwnode.h +++ b/include/media/v4l2-fwnode.h @@ -538,7 +538,7 @@ v4l2_async_notifier_parse_fwnode_endpoints_by_port(struct device *dev, parse_endpoint_func parse_endpoint); /** - * v4l2_fwnode_reference_parse_sensor_common - parse common references on + * v4l2_async_notifier_parse_fwnode_sensor_common - parse common references on * sensors for async sub-devices * @dev: the device node the properties of which are parsed for references * @notifier: the async notifier where the async subdevs will be added diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h index c20e2dc6d432..841e190aedd9 100644 --- a/include/media/v4l2-mediabus.h +++ b/include/media/v4l2-mediabus.h @@ -147,7 +147,7 @@ v4l2_fill_pix_format(struct v4l2_pix_format *pix_fmt, } /** - * v4l2_fill_pix_format - Ancillary routine that fills a &struct + * v4l2_fill_mbus_format - Ancillary routine that fills a &struct * v4l2_mbus_framefmt from a &struct v4l2_pix_format and a * data format code. * @@ -170,7 +170,7 @@ static inline void v4l2_fill_mbus_format(struct v4l2_mbus_framefmt *mbus_fmt, } /** - * v4l2_fill_pix_format - Ancillary routine that fills a &struct + * v4l2_fill_pix_format_mplane - Ancillary routine that fills a &struct * v4l2_pix_format_mplane fields from a media bus structure. * * @pix_mp_fmt: pointer to &struct v4l2_pix_format_mplane to be filled @@ -190,7 +190,7 @@ v4l2_fill_pix_format_mplane(struct v4l2_pix_format_mplane *pix_mp_fmt, } /** - * v4l2_fill_pix_format - Ancillary routine that fills a &struct + * v4l2_fill_mbus_format_mplane - Ancillary routine that fills a &struct * v4l2_mbus_framefmt from a &struct v4l2_pix_format_mplane. * * @mbus_fmt: pointer to &struct v4l2_mbus_framefmt to be filled diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 1de960bfcab9..d0e9a5bdb08b 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -309,7 +309,7 @@ struct v4l2_subdev_audio_ops { }; /** - * enum v4l2_mbus_frame_desc_entry - media bus frame description flags + * enum v4l2_mbus_frame_desc_flags - media bus frame description flags * * @V4L2_MBUS_FRAME_DESC_FL_LEN_MAX: * Indicates that &struct v4l2_mbus_frame_desc_entry->length field diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index bbb3f26fbde9..61969402a0e3 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -1043,7 +1043,7 @@ __poll_t vb2_core_poll(struct vb2_queue *q, struct file *file, size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count, loff_t *ppos, int nonblock); /** - * vb2_read() - implements write() syscall logic. + * vb2_write() - implements write() syscall logic. * @q: pointer to &struct vb2_queue with videobuf2 queue. * @data: pointed to target userspace buffer * @count: number of bytes to write -- cgit v1.2.3 From 4568ea3fa95d33cc10e8938949ae9a875046e553 Mon Sep 17 00:00:00 2001 From: Stanimir Varbanov Date: Sat, 24 Oct 2020 18:35:09 +0200 Subject: media: venus: venc: Fix default capture format The default codec after driver open is set to be H264 but the instance format for capture is wrongly set to H263. Correct this to H264. For regular applications this is not a big issue because they set the format through S_FMT but for example v4l2-compliance does not. Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/venc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index f8b1484e7dcd..0bf92cc21f3a 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -999,7 +999,7 @@ static int m2m_queue_init(void *priv, struct vb2_queue *src_vq, static void venc_inst_init(struct venus_inst *inst) { - inst->fmt_cap = &venc_formats[2]; + inst->fmt_cap = &venc_formats[3]; inst->fmt_out = &venc_formats[0]; inst->width = 1280; inst->height = ALIGN(720, 32); -- cgit v1.2.3 From de04408fd12d5d3b9fb3724034666a84cccbf190 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 21 Oct 2020 02:09:43 +0200 Subject: media: venus: vdec: return parsed crop information from stream Per the stateful codec specification, VIDIOC_G_SELECTION with a target of V4L2_SEL_TGT_COMPOSE is supposed to return the crop area of capture buffers containing the decoded frame. Until now the driver did not get that information from the firmware and just returned the dimensions of CAPTURE buffers. The firmware unfortunately does not always provide the crop information from the stream ; also make sure to detect when that happens and fallback to providing the coded size in these cases. Signed-off-by: Alexandre Courbot Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/core.h | 1 + drivers/media/platform/qcom/venus/vdec.c | 32 +++++++++++++++++++++++++++----- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index 7b79a33dc9d6..3bc129a4f817 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -361,6 +361,7 @@ struct venus_inst { unsigned int streamon_cap, streamon_out; u32 width; u32 height; + struct v4l2_rect crop; u32 out_width; u32 out_height; u32 colorspace; diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index ea13170a6a2c..8488411204c3 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -325,6 +325,10 @@ static int vdec_s_fmt(struct file *file, void *fh, struct v4l2_format *f) inst->width = format.fmt.pix_mp.width; inst->height = format.fmt.pix_mp.height; + inst->crop.top = 0; + inst->crop.left = 0; + inst->crop.width = inst->width; + inst->crop.height = inst->height; if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) inst->fmt_out = fmt; @@ -343,6 +347,9 @@ vdec_g_selection(struct file *file, void *fh, struct v4l2_selection *s) s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) return -EINVAL; + s->r.top = 0; + s->r.left = 0; + switch (s->target) { case V4L2_SEL_TGT_CROP_BOUNDS: case V4L2_SEL_TGT_CROP_DEFAULT: @@ -363,16 +370,12 @@ vdec_g_selection(struct file *file, void *fh, struct v4l2_selection *s) case V4L2_SEL_TGT_COMPOSE: if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - s->r.width = inst->out_width; - s->r.height = inst->out_height; + s->r = inst->crop; break; default: return -EINVAL; } - s->r.top = 0; - s->r.left = 0; - return 0; } @@ -1309,6 +1312,21 @@ static void vdec_event_change(struct venus_inst *inst, inst->width = format.fmt.pix_mp.width; inst->height = format.fmt.pix_mp.height; + /* + * Some versions of the firmware do not report crop information for + * all codecs. For these cases, set the crop to the coded resolution. + */ + if (ev_data->input_crop.width > 0 && ev_data->input_crop.height > 0) { + inst->crop.left = ev_data->input_crop.left; + inst->crop.top = ev_data->input_crop.top; + inst->crop.width = ev_data->input_crop.width; + inst->crop.height = ev_data->input_crop.height; + } else { + inst->crop.left = 0; + inst->crop.top = 0; + inst->crop.width = ev_data->width; + inst->crop.height = ev_data->height; + } inst->out_width = ev_data->width; inst->out_height = ev_data->height; @@ -1412,6 +1430,10 @@ static void vdec_inst_init(struct venus_inst *inst) inst->fmt_cap = &vdec_formats[0]; inst->width = frame_width_min(inst); inst->height = ALIGN(frame_height_min(inst), 32); + inst->crop.left = 0; + inst->crop.top = 0; + inst->crop.width = inst->width; + inst->crop.height = inst->height; inst->out_width = frame_width_min(inst); inst->out_height = frame_height_min(inst); inst->fps = 30; -- cgit v1.2.3 From 21926d466e3a4f35c2536244d1d56512cc81a0a9 Mon Sep 17 00:00:00 2001 From: Mansur Alisha Shaik Date: Mon, 19 Oct 2020 06:18:11 +0200 Subject: media: venus: core: change clk enable and disable order in resume and suspend Currently video driver is voting after clk enable and un voting before clk disable. This is incorrect, video driver should vote before clk enable and unvote after clk disable. Corrected this by changing the order of clk enable and clk disable. suspend") Fixes: 07f8f22a33a9e ("media: venus: core: remove CNOC voting while device Signed-off-by: Mansur Alisha Shaik Reviewed-by: Stephen Boyd Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/core.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index 6103aaf43987..52a3886c496e 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -355,13 +355,16 @@ static __maybe_unused int venus_runtime_suspend(struct device *dev) if (ret) return ret; + if (pm_ops->core_power) { + ret = pm_ops->core_power(dev, POWER_OFF); + if (ret) + return ret; + } + ret = icc_set_bw(core->cpucfg_path, 0, 0); if (ret) return ret; - if (pm_ops->core_power) - ret = pm_ops->core_power(dev, POWER_OFF); - return ret; } @@ -371,16 +374,16 @@ static __maybe_unused int venus_runtime_resume(struct device *dev) const struct venus_pm_ops *pm_ops = core->pm_ops; int ret; + ret = icc_set_bw(core->cpucfg_path, 0, kbps_to_icc(1000)); + if (ret) + return ret; + if (pm_ops->core_power) { ret = pm_ops->core_power(dev, POWER_ON); if (ret) return ret; } - ret = icc_set_bw(core->cpucfg_path, 0, kbps_to_icc(1000)); - if (ret) - return ret; - return hfi_core_resume(core, false); } -- cgit v1.2.3 From 9e8efdb5787986cc0d0134925cf5c4f001bb3f2e Mon Sep 17 00:00:00 2001 From: Mansur Alisha Shaik Date: Mon, 19 Oct 2020 06:18:12 +0200 Subject: media: venus: core: vote for video-mem path Currently video driver is voting for venus0-ebi path during buffer processing with an average bandwidth of all the instances and unvoting during session release. While video streaming when we try to do XO-SD using the command "echo mem > /sys/power/state command" , device is not entering to suspend state and from interconnect summary seeing votes for venus0-ebi Corrected this by voting for venus0-ebi path in venus_runtime_resume() and unvote during venus_runtime_suspend(). suspend") Fixes: 07f8f22a33a9e ("media: venus: core: remove CNOC voting while device Signed-off-by: Mansur Alisha Shaik Reviewed-by: Stephen Boyd Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/core.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index 52a3886c496e..fa363b8ddc07 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -363,7 +363,18 @@ static __maybe_unused int venus_runtime_suspend(struct device *dev) ret = icc_set_bw(core->cpucfg_path, 0, 0); if (ret) - return ret; + goto err_cpucfg_path; + + ret = icc_set_bw(core->video_path, 0, 0); + if (ret) + goto err_video_path; + + return ret; + +err_video_path: + icc_set_bw(core->cpucfg_path, kbps_to_icc(1000), 0); +err_cpucfg_path: + pm_ops->core_power(dev, POWER_ON); return ret; } @@ -374,6 +385,10 @@ static __maybe_unused int venus_runtime_resume(struct device *dev) const struct venus_pm_ops *pm_ops = core->pm_ops; int ret; + ret = icc_set_bw(core->video_path, 0, kbps_to_icc(1000)); + if (ret) + return ret; + ret = icc_set_bw(core->cpucfg_path, 0, kbps_to_icc(1000)); if (ret) return ret; -- cgit v1.2.3 From e44fb034b03231cd117d6db73fb8048deab6ea41 Mon Sep 17 00:00:00 2001 From: Mansur Alisha Shaik Date: Mon, 19 Oct 2020 06:18:13 +0200 Subject: media: venus: core: vote with average bandwidth and peak bandwidth as zero As per bandwidth table video driver is voting with average bandwidth for "video-mem" and "cpu-cfg" paths as peak bandwidth is zero in bandwidth table. suspend") Fixes: 07f8f22a33a9e ("media: venus: core: remove CNOC voting while device Signed-off-by: Mansur Alisha Shaik Reviewed-by: Stephen Boyd Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index fa363b8ddc07..d5bfd6fff85b 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -385,11 +385,11 @@ static __maybe_unused int venus_runtime_resume(struct device *dev) const struct venus_pm_ops *pm_ops = core->pm_ops; int ret; - ret = icc_set_bw(core->video_path, 0, kbps_to_icc(1000)); + ret = icc_set_bw(core->video_path, kbps_to_icc(20000), 0); if (ret) return ret; - ret = icc_set_bw(core->cpucfg_path, 0, kbps_to_icc(1000)); + ret = icc_set_bw(core->cpucfg_path, kbps_to_icc(1000), 0); if (ret) return ret; -- cgit v1.2.3 From eff5ce02e170125936c43ca96c7dc701a86681ed Mon Sep 17 00:00:00 2001 From: Mansur Alisha Shaik Date: Mon, 19 Oct 2020 06:18:14 +0200 Subject: media: venus: put dummy vote on video-mem path after last session release As per current implementation, video driver is unvoting "videom-mem" path for last video session during vdec_session_release(). While video playback when we try to suspend device, we see video clock warnings since votes are already removed during vdec_session_release(). corrected this by putting dummy vote on "video-mem" after last video session release and unvoting it during suspend. suspend") Fixes: 07f8f22a33a9e ("media: venus: core: remove CNOC voting while device Signed-off-by: Mansur Alisha Shaik Reviewed-by: Stephen Boyd Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/pm_helpers.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c index 57877eacecf0..0ebba8e3bd75 100644 --- a/drivers/media/platform/qcom/venus/pm_helpers.c +++ b/drivers/media/platform/qcom/venus/pm_helpers.c @@ -212,6 +212,16 @@ static int load_scale_bw(struct venus_core *core) } mutex_unlock(&core->lock); + /* + * keep minimum bandwidth vote for "video-mem" path, + * so that clks can be disabled during vdec_session_release(). + * Actual bandwidth drop will be done during device supend + * so that device can power down without any warnings. + */ + + if (!total_avg && !total_peak) + total_avg = kbps_to_icc(1000); + dev_dbg(core->dev, VDBGL "total: avg_bw: %u, peak_bw: %u\n", total_avg, total_peak); -- cgit v1.2.3 From b57cf6a0a8894d5e89848e15e8f5e4cf36124aeb Mon Sep 17 00:00:00 2001 From: Mansur Alisha Shaik Date: Mon, 2 Nov 2020 11:31:37 +0100 Subject: media: venus: fix calculating mbps in calculate_inst_freq() Currently in calculate_inst_freq(), video driver is calculating macro blocks per frame instead of macro blocks per second(mpbs). Which results frequency is always setting to lower frequency (150MHz) as per frequency table for sc7180. Hence the playback is not smooth. Corrected this by correcting the mbps calculation in calculate_inst_freq(). Signed-off-by: Mansur Alisha Shaik Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/pm_helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c index 0ebba8e3bd75..12784e9b1d66 100644 --- a/drivers/media/platform/qcom/venus/pm_helpers.c +++ b/drivers/media/platform/qcom/venus/pm_helpers.c @@ -938,7 +938,7 @@ static unsigned long calculate_inst_freq(struct venus_inst *inst, u32 fps = (u32)inst->fps; u32 mbs_per_sec; - mbs_per_sec = load_per_instance(inst) / fps; + mbs_per_sec = load_per_instance(inst); vpp_freq = mbs_per_sec * inst->clk_data.codec_freq_data->vpp_freq; /* 21 / 20 is overhead factor */ -- cgit v1.2.3 From 9696960f1347f28bde0ab5aeaafe1fbc8d477206 Mon Sep 17 00:00:00 2001 From: Mansur Alisha Shaik Date: Thu, 24 Sep 2020 08:59:44 +0200 Subject: media: venus: core: handle race condititon for core ops For core ops we are having only write protect but there is no read protect, because of this in multithreading and concurrency, one CPU core is reading without wait which is causing the NULL pointer dereferece crash. one such scenario is as show below, where in one CPU core, core->ops becoming NULL and in another CPU core calling core->ops->session_init(). CPU: core-7: Call trace: hfi_session_init+0x180/0x1dc [venus_core] vdec_queue_setup+0x9c/0x364 [venus_dec] vb2_core_reqbufs+0x1e4/0x368 [videobuf2_common] vb2_reqbufs+0x4c/0x64 [videobuf2_v4l2] v4l2_m2m_reqbufs+0x50/0x84 [v4l2_mem2mem] v4l2_m2m_ioctl_reqbufs+0x2c/0x38 [v4l2_mem2mem] v4l_reqbufs+0x4c/0x5c __video_do_ioctl+0x2b0/0x39c CPU: core-0: Call trace: venus_shutdown+0x98/0xfc [venus_core] venus_sys_error_handler+0x64/0x148 [venus_core] process_one_work+0x210/0x3d0 worker_thread+0x248/0x3f4 kthread+0x11c/0x12c Signed-off-by: Mansur Alisha Shaik Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/hfi.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/media/platform/qcom/venus/hfi.c b/drivers/media/platform/qcom/venus/hfi.c index a59022adb14c..638ed5cfe05e 100644 --- a/drivers/media/platform/qcom/venus/hfi.c +++ b/drivers/media/platform/qcom/venus/hfi.c @@ -198,6 +198,18 @@ int hfi_session_init(struct venus_inst *inst, u32 pixfmt) const struct hfi_ops *ops = core->ops; int ret; + /* + * If core shutdown is in progress or if we are in system + * recovery, return an error as during system error recovery + * session_init() can't pass successfully + */ + mutex_lock(&core->lock); + if (!core->ops || core->sys_error) { + mutex_unlock(&core->lock); + return -EIO; + } + mutex_unlock(&core->lock); + if (inst->state != INST_UNINIT) return -EINVAL; -- cgit v1.2.3 From de15e6231e6a3ca58d58d7e2c614a76c940dbb38 Mon Sep 17 00:00:00 2001 From: Mansur Alisha Shaik Date: Thu, 24 Sep 2020 08:59:45 +0200 Subject: media: venus: handle use after free for iommu_map/iommu_unmap In concurrency usecase and reboot scenario we are seeing muliple crashes related to iommu_map/iommu_unamp of core->fw.iommu_domain. In one case we are seeing "Unable to handle kernel NULL pointer dereference at virtual address 0000000000000008" crash, this is because of core->fw.iommu_domain in venus_firmware_deinit() and trying to map in venus_boot() during venus_sys_error_handler() Call trace: __iommu_map+0x4c/0x348 iommu_map+0x5c/0x70 venus_boot+0x184/0x230 [venus_core] venus_sys_error_handler+0xa0/0x14c [venus_core] process_one_work+0x210/0x3d0 worker_thread+0x248/0x3f4 kthread+0x11c/0x12c ret_from_fork+0x10/0x18 In second case we are seeing "Unable to handle kernel paging request at virtual address 006b6b6b6b6b6b9b" crash, this is because of unmapping iommu domain which is already unmapped. Call trace: venus_remove+0xf8/0x108 [venus_core] venus_core_shutdown+0x1c/0x34 [venus_core] platform_drv_shutdown+0x28/0x34 device_shutdown+0x154/0x1fc kernel_restart_prepare+0x40/0x4c kernel_restart+0x1c/0x64 __arm64_sys_reboot+0x190/0x238 el0_svc_common+0xa4/0x154 el0_svc_compat_handler+0x2c/0x38 el0_svc_compat+0x8/0x10 Signed-off-by: Mansur Alisha Shaik Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/firmware.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c index 1db64a854b88..d03e2dd5808c 100644 --- a/drivers/media/platform/qcom/venus/firmware.c +++ b/drivers/media/platform/qcom/venus/firmware.c @@ -171,9 +171,14 @@ static int venus_shutdown_no_tz(struct venus_core *core) iommu = core->fw.iommu_domain; - unmapped = iommu_unmap(iommu, VENUS_FW_START_ADDR, mapped); - if (unmapped != mapped) - dev_err(dev, "failed to unmap firmware\n"); + if (core->fw.mapped_mem_size && iommu) { + unmapped = iommu_unmap(iommu, VENUS_FW_START_ADDR, mapped); + + if (unmapped != mapped) + dev_err(dev, "failed to unmap firmware\n"); + else + core->fw.mapped_mem_size = 0; + } return 0; } @@ -305,7 +310,11 @@ void venus_firmware_deinit(struct venus_core *core) iommu = core->fw.iommu_domain; iommu_detach_device(iommu, core->fw.dev); - iommu_domain_free(iommu); + + if (core->fw.iommu_domain) { + iommu_domain_free(iommu); + core->fw.iommu_domain = NULL; + } platform_device_unregister(to_platform_device(core->fw.dev)); } -- cgit v1.2.3 From 7399139be6b21c7c59323a4fab56cc07cd254529 Mon Sep 17 00:00:00 2001 From: Mansur Alisha Shaik Date: Thu, 24 Sep 2020 08:59:46 +0200 Subject: media: venus: core: add shutdown callback for venus After the SMMU translation is disabled in the arm-smmu shutdown callback during reboot, if any subsystem are still alive then IOVAs they are using will become PAs on bus, which may lead to crash. So implemented shutdown callback, which detach iommu maps. Signed-off-by: Mansur Alisha Shaik Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/core.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index d5bfd6fff85b..bdd293faaad0 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -345,6 +345,14 @@ static int venus_remove(struct platform_device *pdev) return ret; } +static void venus_core_shutdown(struct platform_device *pdev) +{ + struct venus_core *core = platform_get_drvdata(pdev); + + venus_shutdown(core); + venus_firmware_deinit(core); +} + static __maybe_unused int venus_runtime_suspend(struct device *dev) { struct venus_core *core = dev_get_drvdata(dev); @@ -620,6 +628,7 @@ static struct platform_driver qcom_venus_driver = { .of_match_table = venus_dt_match, .pm = &venus_pm_ops, }, + .shutdown = venus_core_shutdown, }; module_platform_driver(qcom_venus_driver); -- cgit v1.2.3 From 72e637fec558c7842d6f1508f480fd77c20afe3a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 30 Oct 2020 12:52:30 +0100 Subject: media: rc: validate that "rc_proto" is reasonable Smatch complains that "rc_proto" comes from the user and it can result in shift wrapping in ir_raw_encode_scancode() drivers/media/rc/rc-ir-raw.c:526 ir_raw_encode_scancode() error: undefined (user controlled) shift '1 << protocol' This is true, but I reviewed the surrounding code and it appears harmless. Anyway, let's verify that "rc_proto" is valid as a kernel hardening measure. Signed-off-by: Dan Carpenter Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/lirc_dev.c | 3 ++- include/uapi/linux/lirc.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 220363b9a868..116daf90c858 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -263,7 +263,8 @@ static ssize_t lirc_transmit(struct file *file, const char __user *buf, goto out_unlock; } - if (scan.flags || scan.keycode || scan.timestamp) { + if (scan.flags || scan.keycode || scan.timestamp || + scan.rc_proto > RC_PROTO_MAX) { ret = -EINVAL; goto out_unlock; } diff --git a/include/uapi/linux/lirc.h b/include/uapi/linux/lirc.h index f99d9dcae667..c1eb960adde3 100644 --- a/include/uapi/linux/lirc.h +++ b/include/uapi/linux/lirc.h @@ -226,6 +226,7 @@ enum rc_proto { RC_PROTO_RCMM24 = 25, RC_PROTO_RCMM32 = 26, RC_PROTO_XBOX_DVD = 27, + RC_PROTO_MAX = RC_PROTO_XBOX_DVD, }; #endif -- cgit v1.2.3 From ee50d6e60d9a8e110e984cdd9e788d93eff540ba Mon Sep 17 00:00:00 2001 From: Qinglang Miao Date: Fri, 30 Oct 2020 02:34:25 +0100 Subject: media: usb: dvb-usb-v2: zd1301: fix missing platform_device_unregister() Add the missing platform_device_unregister() before return from zd1301_frontend_attach in the error handling case when pdev->dev.driver is empty. There's an error handling route named err_platform_device_unregister, so just reuse it. Signed-off-by: Qinglang Miao Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/zd1301.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/dvb-usb-v2/zd1301.c b/drivers/media/usb/dvb-usb-v2/zd1301.c index ba2c1b0d3989..72aa6a9a9ed4 100644 --- a/drivers/media/usb/dvb-usb-v2/zd1301.c +++ b/drivers/media/usb/dvb-usb-v2/zd1301.c @@ -150,7 +150,7 @@ static int zd1301_frontend_attach(struct dvb_usb_adapter *adap) } if (!pdev->dev.driver) { ret = -ENODEV; - goto err; + goto err_platform_device_unregister; } if (!try_module_get(pdev->dev.driver->owner)) { ret = -ENODEV; -- cgit v1.2.3 From 167faadfcf9339088910e9e85a1b711fcbbef8e9 Mon Sep 17 00:00:00 2001 From: Dinghao Liu Date: Mon, 24 Aug 2020 14:27:46 +0200 Subject: media: dvbdev: Fix memleak in dvb_register_device When device_create() fails, dvbdev and dvbdevfops should be freed just like when dvb_register_media_device() fails. Signed-off-by: Dinghao Liu Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvbdev.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c index 959fa2820259..5ff7bedee247 100644 --- a/drivers/media/dvb-core/dvbdev.c +++ b/drivers/media/dvb-core/dvbdev.c @@ -539,6 +539,9 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, if (IS_ERR(clsdev)) { pr_err("%s: failed to create device dvb%d.%s%d (%ld)\n", __func__, adap->num, dnames[type], id, PTR_ERR(clsdev)); + dvb_media_device_free(dvbdev); + kfree(dvbdevfops); + kfree(dvbdev); return PTR_ERR(clsdev); } dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", -- cgit v1.2.3 From 9d28a76d406b118df484ef3fd160c02c6cd1d6e7 Mon Sep 17 00:00:00 2001 From: Helen Koike Date: Sat, 7 Nov 2020 00:02:36 +0100 Subject: media: staging: rkisp1: cap: fix timeout when stopping the stream The dma engine should be stopped first. The driver waits for an interrupt to stop the stream in a known state after a frame. If rkisp1_cap_stream_disable() is called after stopping the rest of the pipeline, then most likely the interrupt won't arrive, we'll get a timeout and debugfs variables mp_stop_timeout or sp_stop_timeout will be incremented. Fixes: 37db540bb9d1f ("media: staging: rkisp1: cap: refactor enable/disable stream to allow multistreaming") Signed-off-by: Helen Koike Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/rkisp1/rkisp1-capture.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/rkisp1/rkisp1-capture.c b/drivers/staging/media/rkisp1/rkisp1-capture.c index 6d2fd27970f2..b81235afd053 100644 --- a/drivers/staging/media/rkisp1/rkisp1-capture.c +++ b/drivers/staging/media/rkisp1/rkisp1-capture.c @@ -895,6 +895,8 @@ static void rkisp1_pipeline_stream_disable(struct rkisp1_capture *cap) { struct rkisp1_device *rkisp1 = cap->rkisp1; + rkisp1_cap_stream_disable(cap); + /* * If the other capture is streaming, isp and sensor nodes shouldn't * be disabled, skip them. @@ -907,8 +909,6 @@ static void rkisp1_pipeline_stream_disable(struct rkisp1_capture *cap) v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video, s_stream, false); - - rkisp1_cap_stream_disable(cap); } /* -- cgit v1.2.3 From df22026aebd863745efd753371f46f6ab28a2617 Mon Sep 17 00:00:00 2001 From: Shunqian Zheng Date: Fri, 6 Nov 2020 13:19:36 +0100 Subject: media: videodev2.h, v4l2-ioctl: add rkisp1 meta buffer format Add the Rockchip ISP1 specific processing parameter format V4L2_META_FMT_RK_ISP1_PARAMS and metadata format V4L2_META_FMT_RK_ISP1_STAT_3A for 3A. Signed-off-by: Shunqian Zheng Signed-off-by: Jacob Chen Signed-off-by: Helen Koike Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ioctl.c | 2 ++ drivers/staging/media/rkisp1/uapi/rkisp1-config.h | 4 ---- include/uapi/linux/videodev2.h | 4 ++++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index f0f6906a879d..3198abdd538c 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1403,6 +1403,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_META_FMT_UVC: descr = "UVC Payload Header Metadata"; break; case V4L2_META_FMT_D4XX: descr = "Intel D4xx UVC Metadata"; break; case V4L2_META_FMT_VIVID: descr = "Vivid Metadata"; break; + case V4L2_META_FMT_RK_ISP1_PARAMS: descr = "Rockchip ISP1 3A Parameters"; break; + case V4L2_META_FMT_RK_ISP1_STAT_3A: descr = "Rockchip ISP1 3A Statistics"; break; default: /* Compressed formats */ diff --git a/drivers/staging/media/rkisp1/uapi/rkisp1-config.h b/drivers/staging/media/rkisp1/uapi/rkisp1-config.h index 8d906cc7da8f..6e449e784260 100644 --- a/drivers/staging/media/rkisp1/uapi/rkisp1-config.h +++ b/drivers/staging/media/rkisp1/uapi/rkisp1-config.h @@ -9,10 +9,6 @@ #include -/* Vendor specific - used for RK_ISP1 camera sub-system */ -#define V4L2_META_FMT_RK_ISP1_PARAMS v4l2_fourcc('R', 'K', '1', 'P') /* Rockchip ISP1 params */ -#define V4L2_META_FMT_RK_ISP1_STAT_3A v4l2_fourcc('R', 'K', '1', 'S') /* Rockchip ISP1 3A statistics */ - /* Defect Pixel Cluster Detection */ #define RKISP1_CIF_ISP_MODULE_DPCC (1U << 0) /* Black Level Subtraction */ diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 927075fa9099..761ac9da3ffd 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -768,6 +768,10 @@ struct v4l2_pix_format { #define V4L2_META_FMT_D4XX v4l2_fourcc('D', '4', 'X', 'X') /* D4XX Payload Header metadata */ #define V4L2_META_FMT_VIVID v4l2_fourcc('V', 'I', 'V', 'D') /* Vivid Metadata */ +/* Vendor specific - used for RK_ISP1 camera sub-system */ +#define V4L2_META_FMT_RK_ISP1_PARAMS v4l2_fourcc('R', 'K', '1', 'P') /* Rockchip ISP1 3A Parameters */ +#define V4L2_META_FMT_RK_ISP1_STAT_3A v4l2_fourcc('R', 'K', '1', 'S') /* Rockchip ISP1 3A Statistics */ + /* priv field value to indicates that subsequent fields are valid. */ #define V4L2_PIX_FMT_PRIV_MAGIC 0xfeedcafe -- cgit v1.2.3 From e6938cc1cb7763a363f62b78147f1f2fb972f49c Mon Sep 17 00:00:00 2001 From: Helen Koike Date: Fri, 6 Nov 2020 13:19:37 +0100 Subject: media: rockchip: rkisp1: destage Rockchip ISP1 driver All the items in the TODO list were addressed, uapi was reviewed, documentation written, checkpatch errors fixed, several bugs fixed. There is no big reason to keep this driver in staging, so move it out. Dt-bindings Verified with: make ARCH=arm64 dt_binding_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/media/rockchip-isp1.yaml Fields of MAINTAINERS file sorted according to output of ./scripts/parse-maintainers.pl --input=MAINTAINERS --output=MAINTAINERS --order [dt-bindings: media: rkisp1: move rockchip-isp1 bindings out of staging] [dt-bindings: media: rkisp1: move rockchip-isp1 bindings out of staging] [hverkuil: fix various checkpatch alignment warnings] Signed-off-by: Helen Koike Acked-by: Rob Herring Reviewed-by: Tomasz Figa Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/rockchip-isp1.yaml | 215 +++ .../userspace-api/media/v4l/pixfmt-meta-rkisp1.rst | 2 +- MAINTAINERS | 5 +- drivers/media/platform/Kconfig | 18 + drivers/media/platform/Makefile | 1 + drivers/media/platform/rockchip/rkisp1/Makefile | 10 + .../platform/rockchip/rkisp1/rkisp1-capture.c | 1431 ++++++++++++++++++ .../media/platform/rockchip/rkisp1/rkisp1-common.c | 37 + .../media/platform/rockchip/rkisp1/rkisp1-common.h | 485 ++++++ .../media/platform/rockchip/rkisp1/rkisp1-dev.c | 581 ++++++++ .../media/platform/rockchip/rkisp1/rkisp1-isp.c | 1160 +++++++++++++++ .../media/platform/rockchip/rkisp1/rkisp1-params.c | 1572 ++++++++++++++++++++ .../media/platform/rockchip/rkisp1/rkisp1-regs.h | 1262 ++++++++++++++++ .../platform/rockchip/rkisp1/rkisp1-resizer.c | 846 +++++++++++ .../media/platform/rockchip/rkisp1/rkisp1-stats.c | 415 ++++++ drivers/staging/media/Kconfig | 2 - drivers/staging/media/Makefile | 1 - .../devicetree/bindings/media/rockchip-isp1.yaml | 215 --- drivers/staging/media/rkisp1/Kconfig | 19 - drivers/staging/media/rkisp1/Makefile | 10 - drivers/staging/media/rkisp1/TODO | 8 - drivers/staging/media/rkisp1/rkisp1-capture.c | 1431 ------------------ drivers/staging/media/rkisp1/rkisp1-common.c | 37 - drivers/staging/media/rkisp1/rkisp1-common.h | 485 ------ drivers/staging/media/rkisp1/rkisp1-dev.c | 580 -------- drivers/staging/media/rkisp1/rkisp1-isp.c | 1161 --------------- drivers/staging/media/rkisp1/rkisp1-params.c | 1572 -------------------- drivers/staging/media/rkisp1/rkisp1-regs.h | 1262 ---------------- drivers/staging/media/rkisp1/rkisp1-resizer.c | 846 ----------- drivers/staging/media/rkisp1/rkisp1-stats.c | 415 ------ drivers/staging/media/rkisp1/uapi/rkisp1-config.h | 884 ----------- include/uapi/linux/rkisp1-config.h | 884 +++++++++++ 32 files changed, 8922 insertions(+), 8930 deletions(-) create mode 100644 Documentation/devicetree/bindings/media/rockchip-isp1.yaml create mode 100644 drivers/media/platform/rockchip/rkisp1/Makefile create mode 100644 drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c create mode 100644 drivers/media/platform/rockchip/rkisp1/rkisp1-common.c create mode 100644 drivers/media/platform/rockchip/rkisp1/rkisp1-common.h create mode 100644 drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c create mode 100644 drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c create mode 100644 drivers/media/platform/rockchip/rkisp1/rkisp1-params.c create mode 100644 drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h create mode 100644 drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c create mode 100644 drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c delete mode 100644 drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml delete mode 100644 drivers/staging/media/rkisp1/Kconfig delete mode 100644 drivers/staging/media/rkisp1/Makefile delete mode 100644 drivers/staging/media/rkisp1/TODO delete mode 100644 drivers/staging/media/rkisp1/rkisp1-capture.c delete mode 100644 drivers/staging/media/rkisp1/rkisp1-common.c delete mode 100644 drivers/staging/media/rkisp1/rkisp1-common.h delete mode 100644 drivers/staging/media/rkisp1/rkisp1-dev.c delete mode 100644 drivers/staging/media/rkisp1/rkisp1-isp.c delete mode 100644 drivers/staging/media/rkisp1/rkisp1-params.c delete mode 100644 drivers/staging/media/rkisp1/rkisp1-regs.h delete mode 100644 drivers/staging/media/rkisp1/rkisp1-resizer.c delete mode 100644 drivers/staging/media/rkisp1/rkisp1-stats.c delete mode 100644 drivers/staging/media/rkisp1/uapi/rkisp1-config.h create mode 100644 include/uapi/linux/rkisp1-config.h diff --git a/Documentation/devicetree/bindings/media/rockchip-isp1.yaml b/Documentation/devicetree/bindings/media/rockchip-isp1.yaml new file mode 100644 index 000000000000..2004c054ed1a --- /dev/null +++ b/Documentation/devicetree/bindings/media/rockchip-isp1.yaml @@ -0,0 +1,215 @@ +# SPDX-License-Identifier: (GPL-2.0+ OR MIT) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/rockchip-isp1.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Rockchip SoC Image Signal Processing unit v1 + +maintainers: + - Helen Koike + +description: | + Rockchip ISP1 is the Camera interface for the Rockchip series of SoCs + which contains image processing, scaling, and compression functions. + +properties: + compatible: + const: rockchip,rk3399-cif-isp + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + minItems: 3 + items: + # isp0 and isp1 + - description: ISP clock + - description: ISP AXI clock + - description: ISP AHB clock + # only for isp1 + - description: ISP Pixel clock + + clock-names: + minItems: 3 + items: + # isp0 and isp1 + - const: isp + - const: aclk + - const: hclk + # only for isp1 + - const: pclk_isp + + iommus: + maxItems: 1 + + phys: + maxItems: 1 + description: phandle for the PHY port + + phy-names: + const: dphy + + power-domains: + maxItems: 1 + + # See ./video-interfaces.txt for details + ports: + type: object + additionalProperties: false + + properties: + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + port@0: + type: object + description: connection point for sensors at MIPI-DPHY RX0 + additionalProperties: false + + properties: + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + reg: + const: 0 + + patternProperties: + endpoint: + type: object + additionalProperties: false + + properties: + reg: + maxItems: 1 + + data-lanes: + minItems: 1 + maxItems: 4 + + remote-endpoint: true + + required: + - reg + - "#address-cells" + - "#size-cells" + + required: + - "#address-cells" + - "#size-cells" + - port@0 + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - iommus + - phys + - phy-names + - power-domains + - ports + +if: + properties: + compatible: + contains: + const: rockchip,rk3399-cif-isp +then: + properties: + clocks: + minItems: 3 + maxItems: 4 + clock-names: + minItems: 3 + maxItems: 4 + +additionalProperties: false + +examples: + - | + + #include + #include + #include + + parent0: parent { + #address-cells = <2>; + #size-cells = <2>; + + isp0: isp0@ff910000 { + compatible = "rockchip,rk3399-cif-isp"; + reg = <0x0 0xff910000 0x0 0x4000>; + interrupts = ; + clocks = <&cru SCLK_ISP0>, + <&cru ACLK_ISP0_WRAPPER>, + <&cru HCLK_ISP0_WRAPPER>; + clock-names = "isp", "aclk", "hclk"; + iommus = <&isp0_mmu>; + phys = <&dphy>; + phy-names = "dphy"; + power-domains = <&power RK3399_PD_ISP0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + mipi_in_wcam: endpoint@0 { + reg = <0>; + remote-endpoint = <&wcam_out>; + data-lanes = <1 2>; + }; + + mipi_in_ucam: endpoint@1 { + reg = <1>; + remote-endpoint = <&ucam_out>; + data-lanes = <1>; + }; + }; + }; + }; + + i2c7: i2c { + #address-cells = <1>; + #size-cells = <0>; + + wcam: camera@36 { + compatible = "ovti,ov5695"; + reg = <0x36>; + + port { + wcam_out: endpoint { + remote-endpoint = <&mipi_in_wcam>; + data-lanes = <1 2>; + }; + }; + }; + + ucam: camera@3c { + compatible = "ovti,ov2685"; + reg = <0x3c>; + + port { + ucam_out: endpoint { + remote-endpoint = <&mipi_in_ucam>; + data-lanes = <1>; + }; + }; + }; + }; + }; diff --git a/Documentation/userspace-api/media/v4l/pixfmt-meta-rkisp1.rst b/Documentation/userspace-api/media/v4l/pixfmt-meta-rkisp1.rst index 7e43837ed260..f3671472d410 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-meta-rkisp1.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-meta-rkisp1.rst @@ -46,4 +46,4 @@ important tuning tools using software control loop. rkisp1 uAPI data types ====================== -.. kernel-doc:: drivers/staging/media/rkisp1/uapi/rkisp1-config.h +.. kernel-doc:: include/uapi/linux/rkisp1-config.h diff --git a/MAINTAINERS b/MAINTAINERS index 811db1d3ca33..352b8eaa21f7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15034,10 +15034,13 @@ ROCKCHIP ISP V1 DRIVER M: Helen Koike M: Dafna Hirschfeld L: linux-media@vger.kernel.org +L: linux-rockchip@lists.infradead.org S: Maintained F: Documentation/admin-guide/media/rkisp1.rst +F: Documentation/devicetree/bindings/media/rockchip-isp1.yaml F: Documentation/userspace-api/media/v4l/pixfmt-meta-rkisp1.rst -F: drivers/staging/media/rkisp1/ +F: drivers/media/platform/rockchip/rkisp1 +F: include/uapi/linux/rkisp1-config.h ROCKCHIP RASTER 2D GRAPHIC ACCELERATION UNIT DRIVER M: Jacob Chen diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index a3cb104956d5..b161f2ba238f 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -147,6 +147,24 @@ config VIDEO_RENESAS_CEU help This is a v4l2 driver for the Renesas CEU Interface +config VIDEO_ROCKCHIP_ISP1 + tristate "Rockchip Image Signal Processing v1 Unit driver" + depends on VIDEO_V4L2 && OF + depends on ARCH_ROCKCHIP || COMPILE_TEST + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + select VIDEOBUF2_DMA_CONTIG + select VIDEOBUF2_VMALLOC + select V4L2_FWNODE + select GENERIC_PHY_MIPI_DPHY + default n + help + Enable this to support the Image Signal Processing (ISP) module + present in RK3399 SoCs. + + To compile this driver as a module, choose M here: the module + will be called rockchip-isp1. + source "drivers/media/platform/exynos4-is/Kconfig" source "drivers/media/platform/am437x/Kconfig" source "drivers/media/platform/xilinx/Kconfig" diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 62b6cdc8c730..b342714228db 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -52,6 +52,7 @@ obj-$(CONFIG_VIDEO_RENESAS_FDP1) += rcar_fdp1.o obj-$(CONFIG_VIDEO_RENESAS_JPU) += rcar_jpu.o obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1/ +obj-$(CONFIG_VIDEO_ROCKCHIP_ISP1) += rockchip/rkisp1/ obj-$(CONFIG_VIDEO_ROCKCHIP_RGA) += rockchip/rga/ obj-y += omap/ diff --git a/drivers/media/platform/rockchip/rkisp1/Makefile b/drivers/media/platform/rockchip/rkisp1/Makefile new file mode 100644 index 000000000000..ab32a77db8f7 --- /dev/null +++ b/drivers/media/platform/rockchip/rkisp1/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_VIDEO_ROCKCHIP_ISP1) += rockchip-isp1.o +rockchip-isp1-objs += rkisp1-capture.o \ + rkisp1-common.o \ + rkisp1-dev.o \ + rkisp1-isp.o \ + rkisp1-resizer.o \ + rkisp1-stats.o \ + rkisp1-params.o diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c new file mode 100644 index 000000000000..b81235afd053 --- /dev/null +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c @@ -0,0 +1,1431 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Rockchip ISP1 Driver - V4l capture device + * + * Copyright (C) 2019 Collabora, Ltd. + * + * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd. + * Copyright (C) 2017 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rkisp1-common.h" + +/* + * NOTE: There are two capture video devices in rkisp1, selfpath and mainpath. + * + * differences between selfpath and mainpath + * available mp sink input: isp + * available sp sink input : isp, dma(TODO) + * available mp sink pad fmts: yuv422, raw + * available sp sink pad fmts: yuv422, yuv420...... + * available mp source fmts: yuv, raw, jpeg(TODO) + * available sp source fmts: yuv, rgb + */ + +#define RKISP1_SP_DEV_NAME RKISP1_DRIVER_NAME "_selfpath" +#define RKISP1_MP_DEV_NAME RKISP1_DRIVER_NAME "_mainpath" + +#define RKISP1_MIN_BUFFERS_NEEDED 3 + +enum rkisp1_plane { + RKISP1_PLANE_Y = 0, + RKISP1_PLANE_CB = 1, + RKISP1_PLANE_CR = 2 +}; + +/* + * @fourcc: pixel format + * @fmt_type: helper filed for pixel format + * @uv_swap: if cb cr swaped, for yuv + * @write_format: defines how YCbCr self picture data is written to memory + * @output_format: defines sp output format + * @mbus: the mbus code on the src resizer pad that matches the pixel format + */ +struct rkisp1_capture_fmt_cfg { + u32 fourcc; + u8 uv_swap; + u32 write_format; + u32 output_format; + u32 mbus; +}; + +struct rkisp1_capture_ops { + void (*config)(struct rkisp1_capture *cap); + void (*stop)(struct rkisp1_capture *cap); + void (*enable)(struct rkisp1_capture *cap); + void (*disable)(struct rkisp1_capture *cap); + void (*set_data_path)(struct rkisp1_capture *cap); + bool (*is_stopped)(struct rkisp1_capture *cap); +}; + +struct rkisp1_capture_config { + const struct rkisp1_capture_fmt_cfg *fmts; + int fmt_size; + struct { + u32 y_size_init; + u32 cb_size_init; + u32 cr_size_init; + u32 y_base_ad_init; + u32 cb_base_ad_init; + u32 cr_base_ad_init; + u32 y_offs_cnt_init; + u32 cb_offs_cnt_init; + u32 cr_offs_cnt_init; + } mi; +}; + +/* + * The supported pixel formats for mainpath. NOTE, pixel formats with identical 'mbus' + * are grouped together. This is assumed and used by the function rkisp1_cap_enum_mbus_codes + */ +static const struct rkisp1_capture_fmt_cfg rkisp1_mp_fmts[] = { + /* yuv422 */ + { + .fourcc = V4L2_PIX_FMT_YUYV, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUVINT, + .mbus = MEDIA_BUS_FMT_YUYV8_2X8, + }, { + .fourcc = V4L2_PIX_FMT_YUV422P, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + .mbus = MEDIA_BUS_FMT_YUYV8_2X8, + }, { + .fourcc = V4L2_PIX_FMT_NV16, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA, + .mbus = MEDIA_BUS_FMT_YUYV8_2X8, + }, { + .fourcc = V4L2_PIX_FMT_NV61, + .uv_swap = 1, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA, + .mbus = MEDIA_BUS_FMT_YUYV8_2X8, + }, { + .fourcc = V4L2_PIX_FMT_YVU422M, + .uv_swap = 1, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + .mbus = MEDIA_BUS_FMT_YUYV8_2X8, + }, + /* yuv400 */ + { + .fourcc = V4L2_PIX_FMT_GREY, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + .mbus = MEDIA_BUS_FMT_YUYV8_2X8, + }, + /* yuv420 */ + { + .fourcc = V4L2_PIX_FMT_NV21, + .uv_swap = 1, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA, + .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, + }, { + .fourcc = V4L2_PIX_FMT_NV12, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA, + .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, + }, { + .fourcc = V4L2_PIX_FMT_NV21M, + .uv_swap = 1, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA, + .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, + }, { + .fourcc = V4L2_PIX_FMT_NV12M, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA, + .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, + }, { + .fourcc = V4L2_PIX_FMT_YUV420, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, + }, { + .fourcc = V4L2_PIX_FMT_YVU420, + .uv_swap = 1, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, + }, + /* raw */ + { + .fourcc = V4L2_PIX_FMT_SRGGB8, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + .mbus = MEDIA_BUS_FMT_SRGGB8_1X8, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + .mbus = MEDIA_BUS_FMT_SGRBG8_1X8, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + .mbus = MEDIA_BUS_FMT_SGBRG8_1X8, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + .mbus = MEDIA_BUS_FMT_SBGGR8_1X8, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB10, + .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, + .mbus = MEDIA_BUS_FMT_SRGGB10_1X10, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG10, + .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, + .mbus = MEDIA_BUS_FMT_SGRBG10_1X10, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG10, + .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, + .mbus = MEDIA_BUS_FMT_SGBRG10_1X10, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR10, + .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, + .mbus = MEDIA_BUS_FMT_SBGGR10_1X10, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB12, + .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, + .mbus = MEDIA_BUS_FMT_SRGGB12_1X12, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG12, + .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, + .mbus = MEDIA_BUS_FMT_SGRBG12_1X12, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG12, + .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, + .mbus = MEDIA_BUS_FMT_SGBRG12_1X12, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR12, + .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, + .mbus = MEDIA_BUS_FMT_SBGGR12_1X12, + }, +}; + +/* + * The supported pixel formats for selfpath. NOTE, pixel formats with identical 'mbus' + * are grouped together. This is assumed and used by the function rkisp1_cap_enum_mbus_codes + */ +static const struct rkisp1_capture_fmt_cfg rkisp1_sp_fmts[] = { + /* yuv422 */ + { + .fourcc = V4L2_PIX_FMT_YUYV, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_SP_WRITE_INT, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422, + .mbus = MEDIA_BUS_FMT_YUYV8_2X8, + }, { + .fourcc = V4L2_PIX_FMT_YUV422P, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_SP_WRITE_PLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422, + .mbus = MEDIA_BUS_FMT_YUYV8_2X8, + }, { + .fourcc = V4L2_PIX_FMT_NV16, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422, + .mbus = MEDIA_BUS_FMT_YUYV8_2X8, + }, { + .fourcc = V4L2_PIX_FMT_NV61, + .uv_swap = 1, + .write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422, + .mbus = MEDIA_BUS_FMT_YUYV8_2X8, + }, { + .fourcc = V4L2_PIX_FMT_YVU422M, + .uv_swap = 1, + .write_format = RKISP1_MI_CTRL_SP_WRITE_PLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422, + .mbus = MEDIA_BUS_FMT_YUYV8_2X8, + }, + /* yuv400 */ + { + .fourcc = V4L2_PIX_FMT_GREY, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_SP_WRITE_PLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV400, + .mbus = MEDIA_BUS_FMT_YUYV8_2X8, + }, + /* rgb */ + { + .fourcc = V4L2_PIX_FMT_XBGR32, + .write_format = RKISP1_MI_CTRL_SP_WRITE_PLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_RGB888, + .mbus = MEDIA_BUS_FMT_YUYV8_2X8, + }, { + .fourcc = V4L2_PIX_FMT_RGB565, + .write_format = RKISP1_MI_CTRL_SP_WRITE_PLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_RGB565, + .mbus = MEDIA_BUS_FMT_YUYV8_2X8, + }, + /* yuv420 */ + { + .fourcc = V4L2_PIX_FMT_NV21, + .uv_swap = 1, + .write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420, + .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, + }, { + .fourcc = V4L2_PIX_FMT_NV12, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420, + .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, + }, { + .fourcc = V4L2_PIX_FMT_NV21M, + .uv_swap = 1, + .write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420, + .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, + }, { + .fourcc = V4L2_PIX_FMT_NV12M, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420, + .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, + }, { + .fourcc = V4L2_PIX_FMT_YUV420, + .uv_swap = 0, + .write_format = RKISP1_MI_CTRL_SP_WRITE_PLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420, + .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, + }, { + .fourcc = V4L2_PIX_FMT_YVU420, + .uv_swap = 1, + .write_format = RKISP1_MI_CTRL_SP_WRITE_PLA, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420, + .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, + }, +}; + +static const struct rkisp1_capture_config rkisp1_capture_config_mp = { + .fmts = rkisp1_mp_fmts, + .fmt_size = ARRAY_SIZE(rkisp1_mp_fmts), + .mi = { + .y_size_init = RKISP1_CIF_MI_MP_Y_SIZE_INIT, + .cb_size_init = RKISP1_CIF_MI_MP_CB_SIZE_INIT, + .cr_size_init = RKISP1_CIF_MI_MP_CR_SIZE_INIT, + .y_base_ad_init = RKISP1_CIF_MI_MP_Y_BASE_AD_INIT, + .cb_base_ad_init = RKISP1_CIF_MI_MP_CB_BASE_AD_INIT, + .cr_base_ad_init = RKISP1_CIF_MI_MP_CR_BASE_AD_INIT, + .y_offs_cnt_init = RKISP1_CIF_MI_MP_Y_OFFS_CNT_INIT, + .cb_offs_cnt_init = RKISP1_CIF_MI_MP_CB_OFFS_CNT_INIT, + .cr_offs_cnt_init = RKISP1_CIF_MI_MP_CR_OFFS_CNT_INIT, + }, +}; + +static const struct rkisp1_capture_config rkisp1_capture_config_sp = { + .fmts = rkisp1_sp_fmts, + .fmt_size = ARRAY_SIZE(rkisp1_sp_fmts), + .mi = { + .y_size_init = RKISP1_CIF_MI_SP_Y_SIZE_INIT, + .cb_size_init = RKISP1_CIF_MI_SP_CB_SIZE_INIT, + .cr_size_init = RKISP1_CIF_MI_SP_CR_SIZE_INIT, + .y_base_ad_init = RKISP1_CIF_MI_SP_Y_BASE_AD_INIT, + .cb_base_ad_init = RKISP1_CIF_MI_SP_CB_BASE_AD_INIT, + .cr_base_ad_init = RKISP1_CIF_MI_SP_CR_BASE_AD_INIT, + .y_offs_cnt_init = RKISP1_CIF_MI_SP_Y_OFFS_CNT_INIT, + .cb_offs_cnt_init = RKISP1_CIF_MI_SP_CB_OFFS_CNT_INIT, + .cr_offs_cnt_init = RKISP1_CIF_MI_SP_CR_OFFS_CNT_INIT, + }, +}; + +static inline struct rkisp1_vdev_node * +rkisp1_vdev_to_node(struct video_device *vdev) +{ + return container_of(vdev, struct rkisp1_vdev_node, vdev); +} + +int rkisp1_cap_enum_mbus_codes(struct rkisp1_capture *cap, + struct v4l2_subdev_mbus_code_enum *code) +{ + const struct rkisp1_capture_fmt_cfg *fmts = cap->config->fmts; + /* + * initialize curr_mbus to non existing mbus code 0 to ensure it is + * different from fmts[0].mbus + */ + u32 curr_mbus = 0; + int i, n = 0; + + for (i = 0; i < cap->config->fmt_size; i++) { + if (fmts[i].mbus == curr_mbus) + continue; + + curr_mbus = fmts[i].mbus; + if (n++ == code->index) { + code->code = curr_mbus; + return 0; + } + } + return -EINVAL; +} + +/* ---------------------------------------------------------------------------- + * Stream operations for self-picture path (sp) and main-picture path (mp) + */ + +static void rkisp1_mi_config_ctrl(struct rkisp1_capture *cap) +{ + u32 mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL); + + mi_ctrl &= ~GENMASK(17, 16); + mi_ctrl |= RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_64; + + mi_ctrl &= ~GENMASK(19, 18); + mi_ctrl |= RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_64; + + mi_ctrl |= RKISP1_CIF_MI_CTRL_INIT_BASE_EN | + RKISP1_CIF_MI_CTRL_INIT_OFFSET_EN; + + rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); +} + +static u32 rkisp1_pixfmt_comp_size(const struct v4l2_pix_format_mplane *pixm, + unsigned int component) +{ + /* + * If packed format, then plane_fmt[0].sizeimage is the sum of all + * components, so we need to calculate just the size of Y component. + * See rkisp1_fill_pixfmt(). + */ + if (!component && pixm->num_planes == 1) + return pixm->plane_fmt[0].bytesperline * pixm->height; + return pixm->plane_fmt[component].sizeimage; +} + +static void rkisp1_irq_frame_end_enable(struct rkisp1_capture *cap) +{ + u32 mi_imsc = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_IMSC); + + mi_imsc |= RKISP1_CIF_MI_FRAME(cap); + rkisp1_write(cap->rkisp1, mi_imsc, RKISP1_CIF_MI_IMSC); +} + +static void rkisp1_mp_config(struct rkisp1_capture *cap) +{ + const struct v4l2_pix_format_mplane *pixm = &cap->pix.fmt; + struct rkisp1_device *rkisp1 = cap->rkisp1; + u32 reg; + + rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y), + cap->config->mi.y_size_init); + rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB), + cap->config->mi.cb_size_init); + rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR), + cap->config->mi.cr_size_init); + + rkisp1_irq_frame_end_enable(cap); + + /* set uv swapping for semiplanar formats */ + if (cap->pix.info->comp_planes == 2) { + reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_XTD_FORMAT_CTRL); + if (cap->pix.cfg->uv_swap) + reg |= RKISP1_CIF_MI_XTD_FMT_CTRL_MP_CB_CR_SWAP; + else + reg &= ~RKISP1_CIF_MI_XTD_FMT_CTRL_MP_CB_CR_SWAP; + rkisp1_write(rkisp1, reg, RKISP1_CIF_MI_XTD_FORMAT_CTRL); + } + + rkisp1_mi_config_ctrl(cap); + + reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_CTRL); + reg &= ~RKISP1_MI_CTRL_MP_FMT_MASK; + reg |= cap->pix.cfg->write_format; + rkisp1_write(rkisp1, reg, RKISP1_CIF_MI_CTRL); + + reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_CTRL); + reg |= RKISP1_CIF_MI_MP_AUTOUPDATE_ENABLE; + rkisp1_write(rkisp1, reg, RKISP1_CIF_MI_CTRL); +} + +static void rkisp1_sp_config(struct rkisp1_capture *cap) +{ + const struct v4l2_pix_format_mplane *pixm = &cap->pix.fmt; + struct rkisp1_device *rkisp1 = cap->rkisp1; + u32 mi_ctrl, reg; + + rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y), + cap->config->mi.y_size_init); + rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB), + cap->config->mi.cb_size_init); + rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR), + cap->config->mi.cr_size_init); + + rkisp1_write(rkisp1, pixm->width, RKISP1_CIF_MI_SP_Y_PIC_WIDTH); + rkisp1_write(rkisp1, pixm->height, RKISP1_CIF_MI_SP_Y_PIC_HEIGHT); + rkisp1_write(rkisp1, cap->sp_y_stride, RKISP1_CIF_MI_SP_Y_LLENGTH); + + rkisp1_irq_frame_end_enable(cap); + + /* set uv swapping for semiplanar formats */ + if (cap->pix.info->comp_planes == 2) { + reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_XTD_FORMAT_CTRL); + if (cap->pix.cfg->uv_swap) + reg |= RKISP1_CIF_MI_XTD_FMT_CTRL_SP_CB_CR_SWAP; + else + reg &= ~RKISP1_CIF_MI_XTD_FMT_CTRL_SP_CB_CR_SWAP; + rkisp1_write(rkisp1, reg, RKISP1_CIF_MI_XTD_FORMAT_CTRL); + } + + rkisp1_mi_config_ctrl(cap); + + mi_ctrl = rkisp1_read(rkisp1, RKISP1_CIF_MI_CTRL); + mi_ctrl &= ~RKISP1_MI_CTRL_SP_FMT_MASK; + mi_ctrl |= cap->pix.cfg->write_format | + RKISP1_MI_CTRL_SP_INPUT_YUV422 | + cap->pix.cfg->output_format | + RKISP1_CIF_MI_SP_AUTOUPDATE_ENABLE; + rkisp1_write(rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); +} + +static void rkisp1_mp_disable(struct rkisp1_capture *cap) +{ + u32 mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL); + + mi_ctrl &= ~(RKISP1_CIF_MI_CTRL_MP_ENABLE | + RKISP1_CIF_MI_CTRL_RAW_ENABLE); + rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); +} + +static void rkisp1_sp_disable(struct rkisp1_capture *cap) +{ + u32 mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL); + + mi_ctrl &= ~RKISP1_CIF_MI_CTRL_SP_ENABLE; + rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); +} + +static void rkisp1_mp_enable(struct rkisp1_capture *cap) +{ + u32 mi_ctrl; + + rkisp1_mp_disable(cap); + + mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL); + if (v4l2_is_format_bayer(cap->pix.info)) + mi_ctrl |= RKISP1_CIF_MI_CTRL_RAW_ENABLE; + /* YUV */ + else + mi_ctrl |= RKISP1_CIF_MI_CTRL_MP_ENABLE; + + rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); +} + +static void rkisp1_sp_enable(struct rkisp1_capture *cap) +{ + u32 mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL); + + mi_ctrl |= RKISP1_CIF_MI_CTRL_SP_ENABLE; + rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); +} + +static void rkisp1_mp_sp_stop(struct rkisp1_capture *cap) +{ + if (!cap->is_streaming) + return; + rkisp1_write(cap->rkisp1, + RKISP1_CIF_MI_FRAME(cap), RKISP1_CIF_MI_ICR); + cap->ops->disable(cap); +} + +static bool rkisp1_mp_is_stopped(struct rkisp1_capture *cap) +{ + u32 en = RKISP1_CIF_MI_CTRL_SHD_MP_IN_ENABLED | + RKISP1_CIF_MI_CTRL_SHD_RAW_OUT_ENABLED; + + return !(rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL_SHD) & en); +} + +static bool rkisp1_sp_is_stopped(struct rkisp1_capture *cap) +{ + return !(rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL_SHD) & + RKISP1_CIF_MI_CTRL_SHD_SP_IN_ENABLED); +} + +static void rkisp1_mp_set_data_path(struct rkisp1_capture *cap) +{ + u32 dpcl = rkisp1_read(cap->rkisp1, RKISP1_CIF_VI_DPCL); + + dpcl = dpcl | RKISP1_CIF_VI_DPCL_CHAN_MODE_MP | + RKISP1_CIF_VI_DPCL_MP_MUX_MRSZ_MI; + rkisp1_write(cap->rkisp1, dpcl, RKISP1_CIF_VI_DPCL); +} + +static void rkisp1_sp_set_data_path(struct rkisp1_capture *cap) +{ + u32 dpcl = rkisp1_read(cap->rkisp1, RKISP1_CIF_VI_DPCL); + + dpcl |= RKISP1_CIF_VI_DPCL_CHAN_MODE_SP; + rkisp1_write(cap->rkisp1, dpcl, RKISP1_CIF_VI_DPCL); +} + +static struct rkisp1_capture_ops rkisp1_capture_ops_mp = { + .config = rkisp1_mp_config, + .enable = rkisp1_mp_enable, + .disable = rkisp1_mp_disable, + .stop = rkisp1_mp_sp_stop, + .set_data_path = rkisp1_mp_set_data_path, + .is_stopped = rkisp1_mp_is_stopped, +}; + +static struct rkisp1_capture_ops rkisp1_capture_ops_sp = { + .config = rkisp1_sp_config, + .enable = rkisp1_sp_enable, + .disable = rkisp1_sp_disable, + .stop = rkisp1_mp_sp_stop, + .set_data_path = rkisp1_sp_set_data_path, + .is_stopped = rkisp1_sp_is_stopped, +}; + +/* ---------------------------------------------------------------------------- + * Frame buffer operations + */ + +static int rkisp1_dummy_buf_create(struct rkisp1_capture *cap) +{ + const struct v4l2_pix_format_mplane *pixm = &cap->pix.fmt; + struct rkisp1_dummy_buffer *dummy_buf = &cap->buf.dummy; + + dummy_buf->size = max3(rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y), + rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB), + rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR)); + + /* The driver never access vaddr, no mapping is required */ + dummy_buf->vaddr = dma_alloc_attrs(cap->rkisp1->dev, + dummy_buf->size, + &dummy_buf->dma_addr, + GFP_KERNEL, + DMA_ATTR_NO_KERNEL_MAPPING); + if (!dummy_buf->vaddr) + return -ENOMEM; + + return 0; +} + +static void rkisp1_dummy_buf_destroy(struct rkisp1_capture *cap) +{ + dma_free_attrs(cap->rkisp1->dev, + cap->buf.dummy.size, cap->buf.dummy.vaddr, + cap->buf.dummy.dma_addr, DMA_ATTR_NO_KERNEL_MAPPING); +} + +static void rkisp1_set_next_buf(struct rkisp1_capture *cap) +{ + cap->buf.curr = cap->buf.next; + cap->buf.next = NULL; + + if (!list_empty(&cap->buf.queue)) { + u32 *buff_addr; + + cap->buf.next = list_first_entry(&cap->buf.queue, struct rkisp1_buffer, queue); + list_del(&cap->buf.next->queue); + + buff_addr = cap->buf.next->buff_addr; + + rkisp1_write(cap->rkisp1, + buff_addr[RKISP1_PLANE_Y], + cap->config->mi.y_base_ad_init); + rkisp1_write(cap->rkisp1, + buff_addr[RKISP1_PLANE_CB], + cap->config->mi.cb_base_ad_init); + rkisp1_write(cap->rkisp1, + buff_addr[RKISP1_PLANE_CR], + cap->config->mi.cr_base_ad_init); + } else { + /* + * Use the dummy space allocated by dma_alloc_coherent to + * throw data if there is no available buffer. + */ + rkisp1_write(cap->rkisp1, + cap->buf.dummy.dma_addr, + cap->config->mi.y_base_ad_init); + rkisp1_write(cap->rkisp1, + cap->buf.dummy.dma_addr, + cap->config->mi.cb_base_ad_init); + rkisp1_write(cap->rkisp1, + cap->buf.dummy.dma_addr, + cap->config->mi.cr_base_ad_init); + } + + /* Set plane offsets */ + rkisp1_write(cap->rkisp1, 0, cap->config->mi.y_offs_cnt_init); + rkisp1_write(cap->rkisp1, 0, cap->config->mi.cb_offs_cnt_init); + rkisp1_write(cap->rkisp1, 0, cap->config->mi.cr_offs_cnt_init); +} + +/* + * This function is called when a frame end comes. The next frame + * is processing and we should set up buffer for next-next frame, + * otherwise it will overflow. + */ +static void rkisp1_handle_buffer(struct rkisp1_capture *cap) +{ + struct rkisp1_isp *isp = &cap->rkisp1->isp; + struct rkisp1_buffer *curr_buf; + + spin_lock(&cap->buf.lock); + curr_buf = cap->buf.curr; + + if (curr_buf) { + curr_buf->vb.sequence = isp->frame_sequence; + curr_buf->vb.vb2_buf.timestamp = ktime_get_boottime_ns(); + curr_buf->vb.field = V4L2_FIELD_NONE; + vb2_buffer_done(&curr_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + } else { + cap->rkisp1->debug.frame_drop[cap->id]++; + } + + rkisp1_set_next_buf(cap); + spin_unlock(&cap->buf.lock); +} + +void rkisp1_capture_isr(struct rkisp1_device *rkisp1) +{ + unsigned int i; + u32 status; + + status = rkisp1_read(rkisp1, RKISP1_CIF_MI_MIS); + rkisp1_write(rkisp1, status, RKISP1_CIF_MI_ICR); + + for (i = 0; i < ARRAY_SIZE(rkisp1->capture_devs); ++i) { + struct rkisp1_capture *cap = &rkisp1->capture_devs[i]; + + if (!(status & RKISP1_CIF_MI_FRAME(cap))) + continue; + if (!cap->is_stopping) { + rkisp1_handle_buffer(cap); + continue; + } + /* + * Make sure stream is actually stopped, whose state + * can be read from the shadow register, before + * wake_up() thread which would immediately free all + * frame buffers. stop() takes effect at the next + * frame end that sync the configurations to shadow + * regs. + */ + if (!cap->ops->is_stopped(cap)) { + cap->ops->stop(cap); + continue; + } + cap->is_stopping = false; + cap->is_streaming = false; + wake_up(&cap->done); + } +} + +/* ---------------------------------------------------------------------------- + * Vb2 operations + */ + +static int rkisp1_vb2_queue_setup(struct vb2_queue *queue, + unsigned int *num_buffers, + unsigned int *num_planes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct rkisp1_capture *cap = queue->drv_priv; + const struct v4l2_pix_format_mplane *pixm = &cap->pix.fmt; + unsigned int i; + + if (*num_planes) { + if (*num_planes != pixm->num_planes) + return -EINVAL; + + for (i = 0; i < pixm->num_planes; i++) + if (sizes[i] < pixm->plane_fmt[i].sizeimage) + return -EINVAL; + } else { + *num_planes = pixm->num_planes; + for (i = 0; i < pixm->num_planes; i++) + sizes[i] = pixm->plane_fmt[i].sizeimage; + } + + return 0; +} + +static void rkisp1_vb2_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct rkisp1_buffer *ispbuf = + container_of(vbuf, struct rkisp1_buffer, vb); + struct rkisp1_capture *cap = vb->vb2_queue->drv_priv; + const struct v4l2_pix_format_mplane *pixm = &cap->pix.fmt; + unsigned int i; + + memset(ispbuf->buff_addr, 0, sizeof(ispbuf->buff_addr)); + for (i = 0; i < pixm->num_planes; i++) + ispbuf->buff_addr[i] = vb2_dma_contig_plane_dma_addr(vb, i); + + /* Convert to non-MPLANE */ + if (pixm->num_planes == 1) { + ispbuf->buff_addr[RKISP1_PLANE_CB] = + ispbuf->buff_addr[RKISP1_PLANE_Y] + + rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y); + ispbuf->buff_addr[RKISP1_PLANE_CR] = + ispbuf->buff_addr[RKISP1_PLANE_CB] + + rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB); + } + + /* + * uv swap can be supported for planar formats by switching + * the address of cb and cr + */ + if (cap->pix.info->comp_planes == 3 && cap->pix.cfg->uv_swap) + swap(ispbuf->buff_addr[RKISP1_PLANE_CR], + ispbuf->buff_addr[RKISP1_PLANE_CB]); + + spin_lock_irq(&cap->buf.lock); + list_add_tail(&ispbuf->queue, &cap->buf.queue); + spin_unlock_irq(&cap->buf.lock); +} + +static int rkisp1_vb2_buf_prepare(struct vb2_buffer *vb) +{ + struct rkisp1_capture *cap = vb->vb2_queue->drv_priv; + unsigned int i; + + for (i = 0; i < cap->pix.fmt.num_planes; i++) { + unsigned long size = cap->pix.fmt.plane_fmt[i].sizeimage; + + if (vb2_plane_size(vb, i) < size) { + dev_err(cap->rkisp1->dev, + "User buffer too small (%ld < %ld)\n", + vb2_plane_size(vb, i), size); + return -EINVAL; + } + vb2_set_plane_payload(vb, i, size); + } + + return 0; +} + +static void rkisp1_return_all_buffers(struct rkisp1_capture *cap, + enum vb2_buffer_state state) +{ + struct rkisp1_buffer *buf; + + spin_lock_irq(&cap->buf.lock); + if (cap->buf.curr) { + vb2_buffer_done(&cap->buf.curr->vb.vb2_buf, state); + cap->buf.curr = NULL; + } + if (cap->buf.next) { + vb2_buffer_done(&cap->buf.next->vb.vb2_buf, state); + cap->buf.next = NULL; + } + while (!list_empty(&cap->buf.queue)) { + buf = list_first_entry(&cap->buf.queue, + struct rkisp1_buffer, queue); + list_del(&buf->queue); + vb2_buffer_done(&buf->vb.vb2_buf, state); + } + spin_unlock_irq(&cap->buf.lock); +} + +/* + * Most of registers inside rockchip ISP1 have shadow register since + * they must be not be changed during processing a frame. + * Usually, each sub-module updates its shadow register after + * processing the last pixel of a frame. + */ +static void rkisp1_cap_stream_enable(struct rkisp1_capture *cap) +{ + struct rkisp1_device *rkisp1 = cap->rkisp1; + struct rkisp1_capture *other = &rkisp1->capture_devs[cap->id ^ 1]; + + cap->ops->set_data_path(cap); + cap->ops->config(cap); + + /* Setup a buffer for the next frame */ + spin_lock_irq(&cap->buf.lock); + rkisp1_set_next_buf(cap); + cap->ops->enable(cap); + /* It's safe to config ACTIVE and SHADOW regs for the + * first stream. While when the second is starting, do NOT + * force update because it also update the first one. + * + * The latter case would drop one more buf(that is 2) since + * there's not buf in shadow when the second FE received. This's + * also required because the second FE maybe corrupt especially + * when run at 120fps. + */ + if (!other->is_streaming) { + /* force cfg update */ + rkisp1_write(rkisp1, + RKISP1_CIF_MI_INIT_SOFT_UPD, RKISP1_CIF_MI_INIT); + rkisp1_set_next_buf(cap); + } + spin_unlock_irq(&cap->buf.lock); + cap->is_streaming = true; +} + +static void rkisp1_cap_stream_disable(struct rkisp1_capture *cap) +{ + int ret; + + /* Stream should stop in interrupt. If it dosn't, stop it by force. */ + cap->is_stopping = true; + ret = wait_event_timeout(cap->done, + !cap->is_streaming, + msecs_to_jiffies(1000)); + if (!ret) { + cap->rkisp1->debug.stop_timeout[cap->id]++; + cap->ops->stop(cap); + cap->is_stopping = false; + cap->is_streaming = false; + } +} + +/* + * rkisp1_pipeline_stream_disable - disable nodes in the pipeline + * + * Call s_stream(false) in the reverse order from + * rkisp1_pipeline_stream_enable() and disable the DMA engine. + * Should be called before media_pipeline_stop() + */ +static void rkisp1_pipeline_stream_disable(struct rkisp1_capture *cap) + __must_hold(&cap->rkisp1->stream_lock) +{ + struct rkisp1_device *rkisp1 = cap->rkisp1; + + rkisp1_cap_stream_disable(cap); + + /* + * If the other capture is streaming, isp and sensor nodes shouldn't + * be disabled, skip them. + */ + if (rkisp1->pipe.streaming_count < 2) { + v4l2_subdev_call(rkisp1->active_sensor->sd, video, s_stream, + false); + v4l2_subdev_call(&rkisp1->isp.sd, video, s_stream, false); + } + + v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video, s_stream, + false); +} + +/* + * rkisp1_pipeline_stream_enable - enable nodes in the pipeline + * + * Enable the DMA Engine and call s_stream(true) through the pipeline. + * Should be called after media_pipeline_start() + */ +static int rkisp1_pipeline_stream_enable(struct rkisp1_capture *cap) + __must_hold(&cap->rkisp1->stream_lock) +{ + struct rkisp1_device *rkisp1 = cap->rkisp1; + int ret; + + rkisp1_cap_stream_enable(cap); + + ret = v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video, + s_stream, true); + if (ret) + goto err_disable_cap; + + /* + * If the other capture is streaming, isp and sensor nodes are already + * enabled, skip them. + */ + if (rkisp1->pipe.streaming_count > 1) + return 0; + + ret = v4l2_subdev_call(&rkisp1->isp.sd, video, s_stream, true); + if (ret) + goto err_disable_rsz; + + ret = v4l2_subdev_call(rkisp1->active_sensor->sd, video, s_stream, + true); + if (ret) + goto err_disable_isp; + + return 0; + +err_disable_isp: + v4l2_subdev_call(&rkisp1->isp.sd, video, s_stream, false); +err_disable_rsz: + v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video, s_stream, + false); +err_disable_cap: + rkisp1_cap_stream_disable(cap); + + return ret; +} + +static void rkisp1_vb2_stop_streaming(struct vb2_queue *queue) +{ + struct rkisp1_capture *cap = queue->drv_priv; + struct rkisp1_vdev_node *node = &cap->vnode; + struct rkisp1_device *rkisp1 = cap->rkisp1; + int ret; + + mutex_lock(&cap->rkisp1->stream_lock); + + rkisp1_pipeline_stream_disable(cap); + + rkisp1_return_all_buffers(cap, VB2_BUF_STATE_ERROR); + + v4l2_pipeline_pm_put(&node->vdev.entity); + ret = pm_runtime_put(rkisp1->dev); + if (ret < 0) + dev_err(rkisp1->dev, "power down failed error:%d\n", ret); + + rkisp1_dummy_buf_destroy(cap); + + media_pipeline_stop(&node->vdev.entity); + + mutex_unlock(&cap->rkisp1->stream_lock); +} + +static int +rkisp1_vb2_start_streaming(struct vb2_queue *queue, unsigned int count) +{ + struct rkisp1_capture *cap = queue->drv_priv; + struct media_entity *entity = &cap->vnode.vdev.entity; + int ret; + + mutex_lock(&cap->rkisp1->stream_lock); + + ret = media_pipeline_start(entity, &cap->rkisp1->pipe); + if (ret) { + dev_err(cap->rkisp1->dev, "start pipeline failed %d\n", ret); + goto err_ret_buffers; + } + + ret = rkisp1_dummy_buf_create(cap); + if (ret) + goto err_pipeline_stop; + + ret = pm_runtime_get_sync(cap->rkisp1->dev); + if (ret < 0) { + pm_runtime_put_noidle(cap->rkisp1->dev); + dev_err(cap->rkisp1->dev, "power up failed %d\n", ret); + goto err_destroy_dummy; + } + ret = v4l2_pipeline_pm_get(entity); + if (ret) { + dev_err(cap->rkisp1->dev, "open cif pipeline failed %d\n", ret); + goto err_pipe_pm_put; + } + + ret = rkisp1_pipeline_stream_enable(cap); + if (ret) + goto err_v4l2_pm_put; + + mutex_unlock(&cap->rkisp1->stream_lock); + + return 0; + +err_v4l2_pm_put: + v4l2_pipeline_pm_put(entity); +err_pipe_pm_put: + pm_runtime_put(cap->rkisp1->dev); +err_destroy_dummy: + rkisp1_dummy_buf_destroy(cap); +err_pipeline_stop: + media_pipeline_stop(entity); +err_ret_buffers: + rkisp1_return_all_buffers(cap, VB2_BUF_STATE_QUEUED); + mutex_unlock(&cap->rkisp1->stream_lock); + + return ret; +} + +static struct vb2_ops rkisp1_vb2_ops = { + .queue_setup = rkisp1_vb2_queue_setup, + .buf_queue = rkisp1_vb2_buf_queue, + .buf_prepare = rkisp1_vb2_buf_prepare, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .stop_streaming = rkisp1_vb2_stop_streaming, + .start_streaming = rkisp1_vb2_start_streaming, +}; + +/* ---------------------------------------------------------------------------- + * IOCTLs operations + */ + +static const struct v4l2_format_info * +rkisp1_fill_pixfmt(struct v4l2_pix_format_mplane *pixm, + enum rkisp1_stream_id id) +{ + struct v4l2_plane_pix_format *plane_y = &pixm->plane_fmt[0]; + const struct v4l2_format_info *info; + unsigned int i; + u32 stride; + + memset(pixm->plane_fmt, 0, sizeof(pixm->plane_fmt)); + info = v4l2_format_info(pixm->pixelformat); + pixm->num_planes = info->mem_planes; + stride = info->bpp[0] * pixm->width; + /* Self path supports custom stride but Main path doesn't */ + if (id == RKISP1_MAINPATH || plane_y->bytesperline < stride) + plane_y->bytesperline = stride; + plane_y->sizeimage = plane_y->bytesperline * pixm->height; + + /* normalize stride to pixels per line */ + stride = DIV_ROUND_UP(plane_y->bytesperline, info->bpp[0]); + + for (i = 1; i < info->comp_planes; i++) { + struct v4l2_plane_pix_format *plane = &pixm->plane_fmt[i]; + + /* bytesperline for other components derive from Y component */ + plane->bytesperline = DIV_ROUND_UP(stride, info->hdiv) * + info->bpp[i]; + plane->sizeimage = plane->bytesperline * + DIV_ROUND_UP(pixm->height, info->vdiv); + } + + /* + * If pixfmt is packed, then plane_fmt[0] should contain the total size + * considering all components. plane_fmt[i] for i > 0 should be ignored + * by userspace as mem_planes == 1, but we are keeping information there + * for convenience. + */ + if (info->mem_planes == 1) + for (i = 1; i < info->comp_planes; i++) + plane_y->sizeimage += pixm->plane_fmt[i].sizeimage; + + return info; +} + +static const struct rkisp1_capture_fmt_cfg * +rkisp1_find_fmt_cfg(const struct rkisp1_capture *cap, const u32 pixelfmt) +{ + unsigned int i; + + for (i = 0; i < cap->config->fmt_size; i++) { + if (cap->config->fmts[i].fourcc == pixelfmt) + return &cap->config->fmts[i]; + } + return NULL; +} + +static void rkisp1_try_fmt(const struct rkisp1_capture *cap, + struct v4l2_pix_format_mplane *pixm, + const struct rkisp1_capture_fmt_cfg **fmt_cfg, + const struct v4l2_format_info **fmt_info) +{ + const struct rkisp1_capture_config *config = cap->config; + const struct rkisp1_capture_fmt_cfg *fmt; + const struct v4l2_format_info *info; + const unsigned int max_widths[] = { RKISP1_RSZ_MP_SRC_MAX_WIDTH, + RKISP1_RSZ_SP_SRC_MAX_WIDTH }; + const unsigned int max_heights[] = { RKISP1_RSZ_MP_SRC_MAX_HEIGHT, + RKISP1_RSZ_SP_SRC_MAX_HEIGHT}; + + fmt = rkisp1_find_fmt_cfg(cap, pixm->pixelformat); + if (!fmt) { + fmt = config->fmts; + pixm->pixelformat = fmt->fourcc; + } + + pixm->width = clamp_t(u32, pixm->width, + RKISP1_RSZ_SRC_MIN_WIDTH, max_widths[cap->id]); + pixm->height = clamp_t(u32, pixm->height, + RKISP1_RSZ_SRC_MIN_HEIGHT, max_heights[cap->id]); + + pixm->field = V4L2_FIELD_NONE; + pixm->colorspace = V4L2_COLORSPACE_DEFAULT; + pixm->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + pixm->quantization = V4L2_QUANTIZATION_DEFAULT; + + info = rkisp1_fill_pixfmt(pixm, cap->id); + + if (fmt_cfg) + *fmt_cfg = fmt; + if (fmt_info) + *fmt_info = info; +} + +static void rkisp1_set_fmt(struct rkisp1_capture *cap, + struct v4l2_pix_format_mplane *pixm) +{ + rkisp1_try_fmt(cap, pixm, &cap->pix.cfg, &cap->pix.info); + cap->pix.fmt = *pixm; + + /* SP supports custom stride in number of pixels of the Y plane */ + if (cap->id == RKISP1_SELFPATH) + cap->sp_y_stride = pixm->plane_fmt[0].bytesperline / + cap->pix.info->bpp[0]; +} + +static int rkisp1_try_fmt_vid_cap_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct rkisp1_capture *cap = video_drvdata(file); + + rkisp1_try_fmt(cap, &f->fmt.pix_mp, NULL, NULL); + + return 0; +} + +static int rkisp1_enum_fmt_vid_cap_mplane(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct rkisp1_capture *cap = video_drvdata(file); + const struct rkisp1_capture_fmt_cfg *fmt = NULL; + unsigned int i, n = 0; + + if (!f->mbus_code) { + if (f->index >= cap->config->fmt_size) + return -EINVAL; + + fmt = &cap->config->fmts[f->index]; + f->pixelformat = fmt->fourcc; + return 0; + } + + for (i = 0; i < cap->config->fmt_size; i++) { + if (cap->config->fmts[i].mbus != f->mbus_code) + continue; + + if (n++ == f->index) { + f->pixelformat = cap->config->fmts[i].fourcc; + return 0; + } + } + return -EINVAL; +} + +static int rkisp1_s_fmt_vid_cap_mplane(struct file *file, + void *priv, struct v4l2_format *f) +{ + struct rkisp1_capture *cap = video_drvdata(file); + struct rkisp1_vdev_node *node = + rkisp1_vdev_to_node(&cap->vnode.vdev); + + if (vb2_is_busy(&node->buf_queue)) + return -EBUSY; + + rkisp1_set_fmt(cap, &f->fmt.pix_mp); + + return 0; +} + +static int rkisp1_g_fmt_vid_cap_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct rkisp1_capture *cap = video_drvdata(file); + + f->fmt.pix_mp = cap->pix.fmt; + + return 0; +} + +static int +rkisp1_querycap(struct file *file, void *priv, struct v4l2_capability *cap) +{ + struct rkisp1_capture *cap_dev = video_drvdata(file); + struct rkisp1_device *rkisp1 = cap_dev->rkisp1; + + strscpy(cap->driver, rkisp1->dev->driver->name, sizeof(cap->driver)); + strscpy(cap->card, rkisp1->dev->driver->name, sizeof(cap->card)); + strscpy(cap->bus_info, RKISP1_BUS_INFO, sizeof(cap->bus_info)); + + return 0; +} + +static const struct v4l2_ioctl_ops rkisp1_v4l2_ioctl_ops = { + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_try_fmt_vid_cap_mplane = rkisp1_try_fmt_vid_cap_mplane, + .vidioc_s_fmt_vid_cap_mplane = rkisp1_s_fmt_vid_cap_mplane, + .vidioc_g_fmt_vid_cap_mplane = rkisp1_g_fmt_vid_cap_mplane, + .vidioc_enum_fmt_vid_cap = rkisp1_enum_fmt_vid_cap_mplane, + .vidioc_querycap = rkisp1_querycap, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static int rkisp1_capture_link_validate(struct media_link *link) +{ + struct video_device *vdev = + media_entity_to_video_device(link->sink->entity); + struct v4l2_subdev *sd = + media_entity_to_v4l2_subdev(link->source->entity); + struct rkisp1_capture *cap = video_get_drvdata(vdev); + const struct rkisp1_capture_fmt_cfg *fmt = + rkisp1_find_fmt_cfg(cap, cap->pix.fmt.pixelformat); + struct v4l2_subdev_format sd_fmt; + int ret; + + sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + sd_fmt.pad = link->source->index; + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt); + if (ret) + return ret; + + if (sd_fmt.format.height != cap->pix.fmt.height || + sd_fmt.format.width != cap->pix.fmt.width || + sd_fmt.format.code != fmt->mbus) + return -EPIPE; + + return 0; +} + +/* ---------------------------------------------------------------------------- + * core functions + */ + +static const struct media_entity_operations rkisp1_media_ops = { + .link_validate = rkisp1_capture_link_validate, +}; + +static const struct v4l2_file_operations rkisp1_fops = { + .open = v4l2_fh_open, + .release = vb2_fop_release, + .unlocked_ioctl = video_ioctl2, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, +}; + +static void rkisp1_unregister_capture(struct rkisp1_capture *cap) +{ + media_entity_cleanup(&cap->vnode.vdev.entity); + vb2_video_unregister_device(&cap->vnode.vdev); +} + +void rkisp1_capture_devs_unregister(struct rkisp1_device *rkisp1) +{ + struct rkisp1_capture *mp = &rkisp1->capture_devs[RKISP1_MAINPATH]; + struct rkisp1_capture *sp = &rkisp1->capture_devs[RKISP1_SELFPATH]; + + rkisp1_unregister_capture(mp); + rkisp1_unregister_capture(sp); +} + +static int rkisp1_register_capture(struct rkisp1_capture *cap) +{ + const char * const dev_names[] = {RKISP1_MP_DEV_NAME, + RKISP1_SP_DEV_NAME}; + struct v4l2_device *v4l2_dev = &cap->rkisp1->v4l2_dev; + struct video_device *vdev = &cap->vnode.vdev; + struct rkisp1_vdev_node *node; + struct vb2_queue *q; + int ret; + + strscpy(vdev->name, dev_names[cap->id], sizeof(vdev->name)); + node = rkisp1_vdev_to_node(vdev); + mutex_init(&node->vlock); + + vdev->ioctl_ops = &rkisp1_v4l2_ioctl_ops; + vdev->release = video_device_release_empty; + vdev->fops = &rkisp1_fops; + vdev->minor = -1; + vdev->v4l2_dev = v4l2_dev; + vdev->lock = &node->vlock; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_STREAMING | V4L2_CAP_IO_MC; + vdev->entity.ops = &rkisp1_media_ops; + video_set_drvdata(vdev, cap); + vdev->vfl_dir = VFL_DIR_RX; + node->pad.flags = MEDIA_PAD_FL_SINK; + + q = &node->buf_queue; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + q->io_modes = VB2_MMAP | VB2_DMABUF; + q->drv_priv = cap; + q->ops = &rkisp1_vb2_ops; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = sizeof(struct rkisp1_buffer); + q->min_buffers_needed = RKISP1_MIN_BUFFERS_NEEDED; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &node->vlock; + q->dev = cap->rkisp1->dev; + ret = vb2_queue_init(q); + if (ret) { + dev_err(cap->rkisp1->dev, + "vb2 queue init failed (err=%d)\n", ret); + return ret; + } + + vdev->queue = q; + + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); + if (ret) { + dev_err(cap->rkisp1->dev, + "failed to register %s, ret=%d\n", vdev->name, ret); + return ret; + } + v4l2_info(v4l2_dev, "registered %s as /dev/video%d\n", vdev->name, + vdev->num); + + ret = media_entity_pads_init(&vdev->entity, 1, &node->pad); + if (ret) { + video_unregister_device(vdev); + return ret; + } + + return 0; +} + +static void +rkisp1_capture_init(struct rkisp1_device *rkisp1, enum rkisp1_stream_id id) +{ + struct rkisp1_capture *cap = &rkisp1->capture_devs[id]; + struct v4l2_pix_format_mplane pixm; + + memset(cap, 0, sizeof(*cap)); + cap->id = id; + cap->rkisp1 = rkisp1; + + INIT_LIST_HEAD(&cap->buf.queue); + init_waitqueue_head(&cap->done); + spin_lock_init(&cap->buf.lock); + if (cap->id == RKISP1_SELFPATH) { + cap->ops = &rkisp1_capture_ops_sp; + cap->config = &rkisp1_capture_config_sp; + } else { + cap->ops = &rkisp1_capture_ops_mp; + cap->config = &rkisp1_capture_config_mp; + } + + cap->is_streaming = false; + + memset(&pixm, 0, sizeof(pixm)); + pixm.pixelformat = V4L2_PIX_FMT_YUYV; + pixm.width = RKISP1_DEFAULT_WIDTH; + pixm.height = RKISP1_DEFAULT_HEIGHT; + rkisp1_set_fmt(cap, &pixm); +} + +int rkisp1_capture_devs_register(struct rkisp1_device *rkisp1) +{ + struct rkisp1_capture *cap; + unsigned int i, j; + int ret; + + for (i = 0; i < ARRAY_SIZE(rkisp1->capture_devs); i++) { + rkisp1_capture_init(rkisp1, i); + cap = &rkisp1->capture_devs[i]; + cap->rkisp1 = rkisp1; + ret = rkisp1_register_capture(cap); + if (ret) + goto err_unreg_capture_devs; + } + + return 0; + +err_unreg_capture_devs: + for (j = 0; j < i; j++) { + cap = &rkisp1->capture_devs[j]; + rkisp1_unregister_capture(cap); + } + + return ret; +} diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.c new file mode 100644 index 000000000000..cf889666e166 --- /dev/null +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Rockchip ISP1 Driver - Common definitions + * + * Copyright (C) 2019 Collabora, Ltd. + */ + +#include + +#include "rkisp1-common.h" + +static const struct v4l2_rect rkisp1_sd_min_crop = { + .width = RKISP1_ISP_MIN_WIDTH, + .height = RKISP1_ISP_MIN_HEIGHT, + .top = 0, + .left = 0, +}; + +void rkisp1_sd_adjust_crop_rect(struct v4l2_rect *crop, + const struct v4l2_rect *bounds) +{ + v4l2_rect_set_min_size(crop, &rkisp1_sd_min_crop); + v4l2_rect_map_inside(crop, bounds); +} + +void rkisp1_sd_adjust_crop(struct v4l2_rect *crop, + const struct v4l2_mbus_framefmt *bounds) +{ + struct v4l2_rect crop_bounds = { + .left = 0, + .top = 0, + .width = bounds->width, + .height = bounds->height, + }; + + rkisp1_sd_adjust_crop_rect(crop, &crop_bounds); +} diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h new file mode 100644 index 000000000000..3a134e97161c --- /dev/null +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h @@ -0,0 +1,485 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ +/* + * Rockchip ISP1 Driver - Common definitions + * + * Copyright (C) 2019 Collabora, Ltd. + * + * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd. + * Copyright (C) 2017 Rockchip Electronics Co., Ltd. + */ + +#ifndef _RKISP1_COMMON_H +#define _RKISP1_COMMON_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rkisp1-regs.h" + +/* + * flags on the 'direction' field in struct 'rkisp1_isp_mbus_info' that indicate + * on which pad the media bus format is supported + */ +#define RKISP1_ISP_SD_SRC BIT(0) +#define RKISP1_ISP_SD_SINK BIT(1) + +/* min and max values for the widths and heights of the entities */ +#define RKISP1_ISP_MAX_WIDTH 4032 +#define RKISP1_ISP_MAX_HEIGHT 3024 +#define RKISP1_ISP_MIN_WIDTH 32 +#define RKISP1_ISP_MIN_HEIGHT 32 + +#define RKISP1_RSZ_MP_SRC_MAX_WIDTH 4416 +#define RKISP1_RSZ_MP_SRC_MAX_HEIGHT 3312 +#define RKISP1_RSZ_SP_SRC_MAX_WIDTH 1920 +#define RKISP1_RSZ_SP_SRC_MAX_HEIGHT 1920 +#define RKISP1_RSZ_SRC_MIN_WIDTH 32 +#define RKISP1_RSZ_SRC_MIN_HEIGHT 16 + +/* the default width and height of all the entities */ +#define RKISP1_DEFAULT_WIDTH 800 +#define RKISP1_DEFAULT_HEIGHT 600 + +#define RKISP1_DRIVER_NAME "rkisp1" +#define RKISP1_BUS_INFO "platform:" RKISP1_DRIVER_NAME + +/* maximum number of clocks */ +#define RKISP1_MAX_BUS_CLK 8 + +/* a bitmask of the ready stats */ +#define RKISP1_STATS_MEAS_MASK (RKISP1_CIF_ISP_AWB_DONE | \ + RKISP1_CIF_ISP_AFM_FIN | \ + RKISP1_CIF_ISP_EXP_END | \ + RKISP1_CIF_ISP_HIST_MEASURE_RDY) + +/* enum for the resizer pads */ +enum rkisp1_rsz_pad { + RKISP1_RSZ_PAD_SINK, + RKISP1_RSZ_PAD_SRC, + RKISP1_RSZ_PAD_MAX +}; + +/* enum for the capture id */ +enum rkisp1_stream_id { + RKISP1_MAINPATH, + RKISP1_SELFPATH, +}; + +/* bayer patterns */ +enum rkisp1_fmt_raw_pat_type { + RKISP1_RAW_RGGB = 0, + RKISP1_RAW_GRBG, + RKISP1_RAW_GBRG, + RKISP1_RAW_BGGR, +}; + +/* enum for the isp pads */ +enum rkisp1_isp_pad { + RKISP1_ISP_PAD_SINK_VIDEO, + RKISP1_ISP_PAD_SINK_PARAMS, + RKISP1_ISP_PAD_SOURCE_VIDEO, + RKISP1_ISP_PAD_SOURCE_STATS, + RKISP1_ISP_PAD_MAX +}; + +/* + * struct rkisp1_sensor_async - A container for the v4l2_async_subdev to add to the notifier + * of the v4l2-async API + * + * @asd: async_subdev variable for the sensor + * @lanes: number of lanes + * @mbus_type: type of bus (currently only CSI2 is supported) + * @mbus_flags: media bus (V4L2_MBUS_*) flags + * @sd: a pointer to v4l2_subdev struct of the sensor + * @pixel_rate_ctrl: pixel rate of the sensor, used to initialize the phy + * @dphy: a pointer to the phy + */ +struct rkisp1_sensor_async { + struct v4l2_async_subdev asd; + unsigned int lanes; + enum v4l2_mbus_type mbus_type; + unsigned int mbus_flags; + struct v4l2_subdev *sd; + struct v4l2_ctrl *pixel_rate_ctrl; + struct phy *dphy; +}; + +/* + * struct rkisp1_isp - ISP subdev entity + * + * @sd: v4l2_subdev variable + * @rkisp1: pointer to rkisp1_device + * @pads: media pads + * @pad_cfg: pads configurations + * @sink_fmt: input format + * @src_fmt: output format + * @ops_lock: ops serialization + * @is_dphy_errctrl_disabled: if dphy errctrl is disabled (avoid endless interrupt) + * @frame_sequence: used to synchronize frame_id between video devices. + */ +struct rkisp1_isp { + struct v4l2_subdev sd; + struct media_pad pads[RKISP1_ISP_PAD_MAX]; + struct v4l2_subdev_pad_config pad_cfg[RKISP1_ISP_PAD_MAX]; + const struct rkisp1_isp_mbus_info *sink_fmt; + const struct rkisp1_isp_mbus_info *src_fmt; + struct mutex ops_lock; /* serialize the subdevice ops */ + bool is_dphy_errctrl_disabled; + __u32 frame_sequence; +}; + +/* + * struct rkisp1_vdev_node - Container for the video nodes: params, stats, mainpath, selfpath + * + * @buf_queue: queue of buffers + * @vlock: lock of the video node + * @vdev: video node + * @pad: media pad + */ +struct rkisp1_vdev_node { + struct vb2_queue buf_queue; + struct mutex vlock; /* ioctl serialization mutex */ + struct video_device vdev; + struct media_pad pad; +}; + +/* + * struct rkisp1_buffer - A container for the vb2 buffers used by the video devices: + * params, stats, mainpath, selfpath + * + * @vb: vb2 buffer + * @queue: entry of the buffer in the queue + * @buff_addr: dma addresses of each plane, used only by the capture devices: selfpath, mainpath + * @vaddr: virtual address for buffers used by params and stats devices + */ +struct rkisp1_buffer { + struct vb2_v4l2_buffer vb; + struct list_head queue; + union { + u32 buff_addr[VIDEO_MAX_PLANES]; + void *vaddr; + }; +}; + +/* + * struct rkisp1_dummy_buffer - A buffer to write the next frame to in case + * there are no vb2 buffers available. + * + * @vaddr: return value of call to dma_alloc_attrs. + * @dma_addr: dma address of the buffer. + * @size: size of the buffer. + */ +struct rkisp1_dummy_buffer { + void *vaddr; + dma_addr_t dma_addr; + u32 size; +}; + +struct rkisp1_device; + +/* + * struct rkisp1_capture - ISP capture video device + * + * @vnode: video node + * @rkisp1: pointer to rkisp1_device + * @id: id of the capture, one of RKISP1_SELFPATH, RKISP1_MAINPATH + * @ops: list of callbacks to configure the capture device. + * @config: a pointer to the list of registers to configure the capture format. + * @is_streaming: device is streaming + * @is_stopping: stop_streaming callback was called and the device is in the process of + * stopping the streaming. + * @done: when stop_streaming callback is called, the device waits for the next irq + * handler to stop the streaming by waiting on the 'done' wait queue. + * If the irq handler is not called, the stream is stopped by the callback + * after timeout. + * @sp_y_stride: the selfpath allows to configure a y stride that is longer than the image width. + * @buf.lock: lock to protect buf.queue + * @buf.queue: queued buffer list + * @buf.dummy: dummy space to store dropped data + * + * rkisp1 uses shadow registers, so it needs two buffers at a time + * @buf.curr: the buffer used for current frame + * @buf.next: the buffer used for next frame + * @pix.cfg: pixel configuration + * @pix.info: a pointer to the v4l2_format_info of the pixel format + * @pix.fmt: buffer format + */ +struct rkisp1_capture { + struct rkisp1_vdev_node vnode; + struct rkisp1_device *rkisp1; + enum rkisp1_stream_id id; + struct rkisp1_capture_ops *ops; + const struct rkisp1_capture_config *config; + bool is_streaming; + bool is_stopping; + wait_queue_head_t done; + unsigned int sp_y_stride; + struct { + /* protects queue, curr and next */ + spinlock_t lock; + struct list_head queue; + struct rkisp1_dummy_buffer dummy; + struct rkisp1_buffer *curr; + struct rkisp1_buffer *next; + } buf; + struct { + const struct rkisp1_capture_fmt_cfg *cfg; + const struct v4l2_format_info *info; + struct v4l2_pix_format_mplane fmt; + } pix; +}; + +/* + * struct rkisp1_stats - ISP Statistics device + * + * @vnode: video node + * @rkisp1: pointer to the rkisp1 device + * @lock: locks the buffer list 'stat' + * @stat: queue of rkisp1_buffer + * @vdev_fmt: v4l2_format of the metadata format + */ +struct rkisp1_stats { + struct rkisp1_vdev_node vnode; + struct rkisp1_device *rkisp1; + + spinlock_t lock; /* locks the buffers list 'stats' */ + struct list_head stat; + struct v4l2_format vdev_fmt; +}; + +/* + * struct rkisp1_params - ISP input parameters device + * + * @vnode: video node + * @rkisp1: pointer to the rkisp1 device + * @config_lock: locks the buffer list 'params' + * @params: queue of rkisp1_buffer + * @vdev_fmt: v4l2_format of the metadata format + * @quantization: the quantization configured on the isp's src pad + * @raw_type: the bayer pattern on the isp video sink pad + */ +struct rkisp1_params { + struct rkisp1_vdev_node vnode; + struct rkisp1_device *rkisp1; + + spinlock_t config_lock; /* locks the buffers list 'params' */ + struct list_head params; + struct v4l2_format vdev_fmt; + + enum v4l2_quantization quantization; + enum rkisp1_fmt_raw_pat_type raw_type; +}; + +/* + * struct rkisp1_resizer - Resizer subdev + * + * @sd: v4l2_subdev variable + * @id: id of the resizer, one of RKISP1_SELFPATH, RKISP1_MAINPATH + * @rkisp1: pointer to the rkisp1 device + * @pads: media pads + * @pad_cfg: configurations for the pads + * @config: the set of registers to configure the resizer + * @pixel_enc: pixel encoding of the resizer + * @ops_lock: a lock for the subdev ops + */ +struct rkisp1_resizer { + struct v4l2_subdev sd; + enum rkisp1_stream_id id; + struct rkisp1_device *rkisp1; + struct media_pad pads[RKISP1_RSZ_PAD_MAX]; + struct v4l2_subdev_pad_config pad_cfg[RKISP1_RSZ_PAD_MAX]; + const struct rkisp1_rsz_config *config; + enum v4l2_pixel_encoding pixel_enc; + struct mutex ops_lock; /* serialize the subdevice ops */ +}; + +/* + * struct rkisp1_debug - Values to be exposed on debugfs. + * The parameters are counters of the number of times the + * event occurred since the driver was loaded. + * + * @data_loss: loss of data occurred within a line, processing failure + * @outform_size_error: size error is generated in outmux submodule + * @img_stabilization_size_error: size error is generated in image stabilization submodule + * @inform_size_err: size error is generated in inform submodule + * @mipi_error: mipi error occurred + * @stats_error: writing to the 'Interrupt clear register' did not clear + * it in the register 'Masked interrupt status' + * @stop_timeout: upon stream stop, the capture waits 1 second for the isr to stop + * the stream. This param is incremented in case of timeout. + * @frame_drop: a frame was ready but the buffer queue was empty so the frame + * was not sent to userspace + */ +struct rkisp1_debug { + struct dentry *debugfs_dir; + unsigned long data_loss; + unsigned long outform_size_error; + unsigned long img_stabilization_size_error; + unsigned long inform_size_error; + unsigned long irq_delay; + unsigned long mipi_error; + unsigned long stats_error; + unsigned long stop_timeout[2]; + unsigned long frame_drop[2]; +}; + +/* + * struct rkisp1_device - ISP platform device + * + * @base_addr: base register address + * @irq: the irq number + * @dev: a pointer to the struct device + * @clk_size: number of clocks + * @clks: array of clocks + * @v4l2_dev: v4l2_device variable + * @media_dev: media_device variable + * @notifier: a notifier to register on the v4l2-async API to be notified on the sensor + * @active_sensor: sensor in-use, set when streaming on + * @isp: ISP sub-device + * @resizer_devs: resizer sub-devices + * @capture_devs: capture devices + * @stats: ISP statistics metadata capture device + * @params: ISP parameters metadata output device + * @pipe: media pipeline + * @stream_lock: serializes {start/stop}_streaming callbacks between the capture devices. + * @debug: debug params to be exposed on debugfs + */ +struct rkisp1_device { + void __iomem *base_addr; + int irq; + struct device *dev; + unsigned int clk_size; + struct clk_bulk_data clks[RKISP1_MAX_BUS_CLK]; + struct v4l2_device v4l2_dev; + struct media_device media_dev; + struct v4l2_async_notifier notifier; + struct rkisp1_sensor_async *active_sensor; + struct rkisp1_isp isp; + struct rkisp1_resizer resizer_devs[2]; + struct rkisp1_capture capture_devs[2]; + struct rkisp1_stats stats; + struct rkisp1_params params; + struct media_pipeline pipe; + struct mutex stream_lock; /* serialize {start/stop}_streaming cb between capture devices */ + struct rkisp1_debug debug; +}; + +/* + * struct rkisp1_isp_mbus_info - ISP media bus info, Translates media bus code to hardware + * format values + * + * @mbus_code: media bus code + * @pixel_enc: pixel encoding + * @mipi_dt: mipi data type + * @yuv_seq: the order of the Y, Cb, Cr values + * @bus_width: bus width + * @bayer_pat: bayer pattern + * @direction: a bitmask of the flags indicating on which pad the format is supported on + */ +struct rkisp1_isp_mbus_info { + u32 mbus_code; + enum v4l2_pixel_encoding pixel_enc; + u32 mipi_dt; + u32 yuv_seq; + u8 bus_width; + enum rkisp1_fmt_raw_pat_type bayer_pat; + unsigned int direction; +}; + +static inline void +rkisp1_write(struct rkisp1_device *rkisp1, u32 val, unsigned int addr) +{ + writel(val, rkisp1->base_addr + addr); +} + +static inline u32 rkisp1_read(struct rkisp1_device *rkisp1, unsigned int addr) +{ + return readl(rkisp1->base_addr + addr); +} + +/* + * rkisp1_cap_enum_mbus_codes - A helper function that return the i'th supported mbus code + * of the capture entity. This is used to enumerate the supported + * mbus codes on the source pad of the resizer. + * + * @cap: the capture entity + * @code: the mbus code, the function reads the code->index and fills the code->code + */ +int rkisp1_cap_enum_mbus_codes(struct rkisp1_capture *cap, + struct v4l2_subdev_mbus_code_enum *code); + +/* + * rkisp1_sd_adjust_crop_rect - adjust a rectangle to fit into another rectangle. + * + * @crop: rectangle to adjust. + * @bounds: rectangle used as bounds. + */ +void rkisp1_sd_adjust_crop_rect(struct v4l2_rect *crop, + const struct v4l2_rect *bounds); + +/* + * rkisp1_sd_adjust_crop - adjust a rectangle to fit into media bus format + * + * @crop: rectangle to adjust. + * @bounds: media bus format used as bounds. + */ +void rkisp1_sd_adjust_crop(struct v4l2_rect *crop, + const struct v4l2_mbus_framefmt *bounds); + +/* + * rkisp1_isp_mbus_info - get the isp info of the media bus code + * + * @mbus_code: the media bus code + */ +const struct rkisp1_isp_mbus_info *rkisp1_isp_mbus_info_get(u32 mbus_code); + +/* rkisp1_params_configure - configure the params when stream starts. + * This function is called by the isp entity upon stream starts. + * The function applies the initial configuration of the parameters. + * + * @params: pointer to rkisp1_params. + * @bayer_pat: the bayer pattern on the isp video sink pad + * @quantization: the quantization configured on the isp's src pad + */ +void rkisp1_params_configure(struct rkisp1_params *params, + enum rkisp1_fmt_raw_pat_type bayer_pat, + enum v4l2_quantization quantization); + +/* rkisp1_params_disable - disable all parameters. + * This function is called by the isp entity upon stream start + * when capturing bayer format. + * + * @params: pointer to rkisp1_params. + */ +void rkisp1_params_disable(struct rkisp1_params *params); + +/* irq handlers */ +void rkisp1_isp_isr(struct rkisp1_device *rkisp1); +void rkisp1_mipi_isr(struct rkisp1_device *rkisp1); +void rkisp1_capture_isr(struct rkisp1_device *rkisp1); +void rkisp1_stats_isr(struct rkisp1_stats *stats, u32 isp_ris); +void rkisp1_params_isr(struct rkisp1_device *rkisp1); + +/* register/unregisters functions of the entities */ +int rkisp1_capture_devs_register(struct rkisp1_device *rkisp1); +void rkisp1_capture_devs_unregister(struct rkisp1_device *rkisp1); + +int rkisp1_isp_register(struct rkisp1_device *rkisp1); +void rkisp1_isp_unregister(struct rkisp1_device *rkisp1); + +int rkisp1_resizer_devs_register(struct rkisp1_device *rkisp1); +void rkisp1_resizer_devs_unregister(struct rkisp1_device *rkisp1); + +int rkisp1_stats_register(struct rkisp1_device *rkisp1); +void rkisp1_stats_unregister(struct rkisp1_device *rkisp1); + +int rkisp1_params_register(struct rkisp1_device *rkisp1); +void rkisp1_params_unregister(struct rkisp1_device *rkisp1); + +#endif /* _RKISP1_COMMON_H */ diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c new file mode 100644 index 000000000000..9af137e4967f --- /dev/null +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c @@ -0,0 +1,581 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Rockchip ISP1 Driver - Base driver + * + * Copyright (C) 2019 Collabora, Ltd. + * + * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd. + * Copyright (C) 2017 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rkisp1-common.h" + +/* + * ISP Details + * ----------- + * + * ISP Comprises with: + * MIPI serial camera interface + * Image Signal Processing + * Many Image Enhancement Blocks + * Crop + * Resizer + * RBG display ready image + * Image Rotation + * + * ISP Block Diagram + * ----------------- + * rkisp1-resizer.c rkisp1-capture.c + * |====================| |=======================| + * rkisp1-isp.c Main Picture Path + * |==========================| |===============================================| + * +-----------+ +--+--+--+--+ +--------+ +--------+ +-----------+ + * | | | | | | | | | | | | | + * +--------+ |\ | | | | | | | -->| Crop |->| RSZ |------------->| | + * | MIPI |--->| \ | | | | | | | | | | | | | | + * +--------+ | | | | |IE|IE|IE|IE| | +--------+ +--------+ | Memory | + * |MUX|--->| ISP |->|0 |1 |2 |3 |---+ | Interface | + * +--------+ | | | | | | | | | | +--------+ +--------+ +--------+ | | + * |Parallel|--->| / | | | | | | | | | | | | | | | | + * +--------+ |/ | | | | | | | -->| Crop |->| RSZ |->| RGB |->| | + * | | | | | | | | | | | | Rotate | | | + * +-----------+ +--+--+--+--+ +--------+ +--------+ +--------+ +-----------+ + * ^ + * +--------+ | |===============================================| + * | DMA |------------------------------------+ Self Picture Path + * +--------+ + * + * rkisp1-stats.c rkisp1-params.c + * |===============| |===============| + * +---------------+ +---------------+ + * | | | | + * | ISP | | ISP | + * | | | | + * +---------------+ +---------------+ + * + * + * Media Topology + * -------------- + * +----------+ +----------+ + * | Sensor 2 | | Sensor X | + * ------------ ... ------------ + * | 0 | | 0 | + * +----------+ +----------+ +-----------+ + * \ | | params | + * \ | | (output) | + * +----------+ \ | +-----------+ + * | Sensor 1 | v v | + * ------------ +------+------+ | + * | 0 |----->| 0 | 1 |<---------+ + * +----------+ |------+------| + * | ISP | + * |------+------| + * +-------------| 2 | 3 |----------+ + * | +------+------+ | + * | | | + * v v v + * +- ---------+ +-----------+ +-----------+ + * | 0 | | 0 | | stats | + * ------------- ------------- | (capture) | + * | Resizer | | Resizer | +-----------+ + * ------------| ------------| + * | 1 | | 1 | + * +-----------+ +-----------+ + * | | + * v v + * +-----------+ +-----------+ + * | selfpath | | mainpath | + * | (capture) | | (capture) | + * +-----------+ +-----------+ + */ + +struct rkisp1_match_data { + const char * const *clks; + unsigned int size; +}; + +/* ---------------------------------------------------------------------------- + * Sensor DT bindings + */ + +static int rkisp1_create_links(struct rkisp1_device *rkisp1) +{ + struct media_entity *source, *sink; + unsigned int flags, source_pad; + struct v4l2_subdev *sd; + unsigned int i; + int ret; + + /* sensor links */ + flags = MEDIA_LNK_FL_ENABLED; + list_for_each_entry(sd, &rkisp1->v4l2_dev.subdevs, list) { + if (sd == &rkisp1->isp.sd || + sd == &rkisp1->resizer_devs[RKISP1_MAINPATH].sd || + sd == &rkisp1->resizer_devs[RKISP1_SELFPATH].sd) + continue; + + ret = media_entity_get_fwnode_pad(&sd->entity, sd->fwnode, + MEDIA_PAD_FL_SOURCE); + if (ret < 0) { + dev_err(rkisp1->dev, "failed to find src pad for %s\n", + sd->name); + return ret; + } + source_pad = ret; + + ret = media_create_pad_link(&sd->entity, source_pad, + &rkisp1->isp.sd.entity, + RKISP1_ISP_PAD_SINK_VIDEO, + flags); + if (ret) + return ret; + + flags = 0; + } + + flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE; + + /* create ISP->RSZ->CAP links */ + for (i = 0; i < 2; i++) { + source = &rkisp1->isp.sd.entity; + sink = &rkisp1->resizer_devs[i].sd.entity; + ret = media_create_pad_link(source, RKISP1_ISP_PAD_SOURCE_VIDEO, + sink, RKISP1_RSZ_PAD_SINK, + MEDIA_LNK_FL_ENABLED); + if (ret) + return ret; + + source = sink; + sink = &rkisp1->capture_devs[i].vnode.vdev.entity; + ret = media_create_pad_link(source, RKISP1_RSZ_PAD_SRC, + sink, 0, flags); + if (ret) + return ret; + } + + /* params links */ + source = &rkisp1->params.vnode.vdev.entity; + sink = &rkisp1->isp.sd.entity; + ret = media_create_pad_link(source, 0, sink, + RKISP1_ISP_PAD_SINK_PARAMS, flags); + if (ret) + return ret; + + /* 3A stats links */ + source = &rkisp1->isp.sd.entity; + sink = &rkisp1->stats.vnode.vdev.entity; + return media_create_pad_link(source, RKISP1_ISP_PAD_SOURCE_STATS, + sink, 0, flags); +} + +static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *sd, + struct v4l2_async_subdev *asd) +{ + struct rkisp1_device *rkisp1 = + container_of(notifier, struct rkisp1_device, notifier); + struct rkisp1_sensor_async *s_asd = + container_of(asd, struct rkisp1_sensor_async, asd); + + s_asd->pixel_rate_ctrl = v4l2_ctrl_find(sd->ctrl_handler, + V4L2_CID_PIXEL_RATE); + s_asd->sd = sd; + s_asd->dphy = devm_phy_get(rkisp1->dev, "dphy"); + if (IS_ERR(s_asd->dphy)) { + if (PTR_ERR(s_asd->dphy) != -EPROBE_DEFER) + dev_err(rkisp1->dev, "Couldn't get the MIPI D-PHY\n"); + return PTR_ERR(s_asd->dphy); + } + + phy_init(s_asd->dphy); + + return 0; +} + +static void rkisp1_subdev_notifier_unbind(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *sd, + struct v4l2_async_subdev *asd) +{ + struct rkisp1_sensor_async *s_asd = + container_of(asd, struct rkisp1_sensor_async, asd); + + phy_exit(s_asd->dphy); +} + +static int rkisp1_subdev_notifier_complete(struct v4l2_async_notifier *notifier) +{ + struct rkisp1_device *rkisp1 = + container_of(notifier, struct rkisp1_device, notifier); + int ret; + + ret = rkisp1_create_links(rkisp1); + if (ret) + return ret; + + ret = v4l2_device_register_subdev_nodes(&rkisp1->v4l2_dev); + if (ret) + return ret; + + dev_dbg(rkisp1->dev, "Async subdev notifier completed\n"); + + return 0; +} + +static const struct v4l2_async_notifier_operations rkisp1_subdev_notifier_ops = { + .bound = rkisp1_subdev_notifier_bound, + .unbind = rkisp1_subdev_notifier_unbind, + .complete = rkisp1_subdev_notifier_complete, +}; + +static int rkisp1_subdev_notifier(struct rkisp1_device *rkisp1) +{ + struct v4l2_async_notifier *ntf = &rkisp1->notifier; + unsigned int next_id = 0; + int ret; + + v4l2_async_notifier_init(ntf); + + while (1) { + struct v4l2_fwnode_endpoint vep = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; + struct rkisp1_sensor_async *rk_asd = NULL; + struct fwnode_handle *ep; + + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(rkisp1->dev), + 0, next_id, + FWNODE_GRAPH_ENDPOINT_NEXT); + if (!ep) + break; + + ret = v4l2_fwnode_endpoint_parse(ep, &vep); + if (ret) + goto err_parse; + + rk_asd = kzalloc(sizeof(*rk_asd), GFP_KERNEL); + if (!rk_asd) { + ret = -ENOMEM; + goto err_parse; + } + + rk_asd->mbus_type = vep.bus_type; + rk_asd->mbus_flags = vep.bus.mipi_csi2.flags; + rk_asd->lanes = vep.bus.mipi_csi2.num_data_lanes; + + ret = v4l2_async_notifier_add_fwnode_remote_subdev(ntf, ep, + &rk_asd->asd); + if (ret) + goto err_parse; + + dev_dbg(rkisp1->dev, "registered ep id %d with %d lanes\n", + vep.base.id, rk_asd->lanes); + + next_id = vep.base.id + 1; + + fwnode_handle_put(ep); + + continue; +err_parse: + fwnode_handle_put(ep); + kfree(rk_asd); + v4l2_async_notifier_cleanup(ntf); + return ret; + } + + if (next_id == 0) + dev_dbg(rkisp1->dev, "no remote subdevice found\n"); + ntf->ops = &rkisp1_subdev_notifier_ops; + ret = v4l2_async_notifier_register(&rkisp1->v4l2_dev, ntf); + if (ret) { + v4l2_async_notifier_cleanup(ntf); + return ret; + } + return 0; +} + +/* ---------------------------------------------------------------------------- + * Power + */ + +static int __maybe_unused rkisp1_runtime_suspend(struct device *dev) +{ + struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); + + clk_bulk_disable_unprepare(rkisp1->clk_size, rkisp1->clks); + return pinctrl_pm_select_sleep_state(dev); +} + +static int __maybe_unused rkisp1_runtime_resume(struct device *dev) +{ + struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); + int ret; + + ret = pinctrl_pm_select_default_state(dev); + if (ret) + return ret; + ret = clk_bulk_prepare_enable(rkisp1->clk_size, rkisp1->clks); + if (ret) + return ret; + + return 0; +} + +static const struct dev_pm_ops rkisp1_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(rkisp1_runtime_suspend, rkisp1_runtime_resume, NULL) +}; + +/* ---------------------------------------------------------------------------- + * Core + */ + +static int rkisp1_entities_register(struct rkisp1_device *rkisp1) +{ + int ret; + + ret = rkisp1_isp_register(rkisp1); + if (ret) + return ret; + + ret = rkisp1_resizer_devs_register(rkisp1); + if (ret) + goto err_unreg_isp_subdev; + + ret = rkisp1_capture_devs_register(rkisp1); + if (ret) + goto err_unreg_resizer_devs; + + ret = rkisp1_stats_register(rkisp1); + if (ret) + goto err_unreg_capture_devs; + + ret = rkisp1_params_register(rkisp1); + if (ret) + goto err_unreg_stats; + + ret = rkisp1_subdev_notifier(rkisp1); + if (ret) { + dev_err(rkisp1->dev, + "Failed to register subdev notifier(%d)\n", ret); + goto err_unreg_params; + } + + return 0; +err_unreg_params: + rkisp1_params_unregister(rkisp1); +err_unreg_stats: + rkisp1_stats_unregister(rkisp1); +err_unreg_capture_devs: + rkisp1_capture_devs_unregister(rkisp1); +err_unreg_resizer_devs: + rkisp1_resizer_devs_unregister(rkisp1); +err_unreg_isp_subdev: + rkisp1_isp_unregister(rkisp1); + return ret; +} + +static irqreturn_t rkisp1_isr(int irq, void *ctx) +{ + struct device *dev = ctx; + struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); + + /* + * Call rkisp1_capture_isr() first to handle the frame that + * potentially completed using the current frame_sequence number before + * it is potentially incremented by rkisp1_isp_isr() in the vertical + * sync. + */ + rkisp1_capture_isr(rkisp1); + rkisp1_isp_isr(rkisp1); + rkisp1_mipi_isr(rkisp1); + + return IRQ_HANDLED; +} + +static const char * const rk3399_isp_clks[] = { + "isp", + "aclk", + "hclk", +}; + +static const struct rkisp1_match_data rk3399_isp_clk_data = { + .clks = rk3399_isp_clks, + .size = ARRAY_SIZE(rk3399_isp_clks), +}; + +static const struct of_device_id rkisp1_of_match[] = { + { + .compatible = "rockchip,rk3399-cif-isp", + .data = &rk3399_isp_clk_data, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, rkisp1_of_match); + +static void rkisp1_debug_init(struct rkisp1_device *rkisp1) +{ + struct rkisp1_debug *debug = &rkisp1->debug; + + debug->debugfs_dir = debugfs_create_dir(RKISP1_DRIVER_NAME, NULL); + if (!debug->debugfs_dir) { + dev_dbg(rkisp1->dev, "failed to create debugfs directory\n"); + return; + } + debugfs_create_ulong("data_loss", 0444, debug->debugfs_dir, + &debug->data_loss); + debugfs_create_ulong("outform_size_err", 0444, debug->debugfs_dir, + &debug->outform_size_error); + debugfs_create_ulong("img_stabilization_size_error", 0444, + debug->debugfs_dir, + &debug->img_stabilization_size_error); + debugfs_create_ulong("inform_size_error", 0444, debug->debugfs_dir, + &debug->inform_size_error); + debugfs_create_ulong("irq_delay", 0444, debug->debugfs_dir, + &debug->irq_delay); + debugfs_create_ulong("mipi_error", 0444, debug->debugfs_dir, + &debug->mipi_error); + debugfs_create_ulong("stats_error", 0444, debug->debugfs_dir, + &debug->stats_error); + debugfs_create_ulong("mp_stop_timeout", 0444, debug->debugfs_dir, + &debug->stop_timeout[RKISP1_MAINPATH]); + debugfs_create_ulong("sp_stop_timeout", 0444, debug->debugfs_dir, + &debug->stop_timeout[RKISP1_SELFPATH]); + debugfs_create_ulong("mp_frame_drop", 0444, debug->debugfs_dir, + &debug->frame_drop[RKISP1_MAINPATH]); + debugfs_create_ulong("sp_frame_drop", 0444, debug->debugfs_dir, + &debug->frame_drop[RKISP1_SELFPATH]); +} + +static int rkisp1_probe(struct platform_device *pdev) +{ + const struct rkisp1_match_data *clk_data; + struct device *dev = &pdev->dev; + struct rkisp1_device *rkisp1; + struct v4l2_device *v4l2_dev; + unsigned int i; + int ret, irq; + + clk_data = of_device_get_match_data(&pdev->dev); + if (!clk_data) + return -ENODEV; + + rkisp1 = devm_kzalloc(dev, sizeof(*rkisp1), GFP_KERNEL); + if (!rkisp1) + return -ENOMEM; + + dev_set_drvdata(dev, rkisp1); + rkisp1->dev = dev; + + mutex_init(&rkisp1->stream_lock); + + rkisp1->base_addr = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(rkisp1->base_addr)) + return PTR_ERR(rkisp1->base_addr); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret = devm_request_irq(dev, irq, rkisp1_isr, IRQF_SHARED, + dev_driver_string(dev), dev); + if (ret) { + dev_err(dev, "request irq failed: %d\n", ret); + return ret; + } + + rkisp1->irq = irq; + + for (i = 0; i < clk_data->size; i++) + rkisp1->clks[i].id = clk_data->clks[i]; + ret = devm_clk_bulk_get(dev, clk_data->size, rkisp1->clks); + if (ret) + return ret; + rkisp1->clk_size = clk_data->size; + + pm_runtime_enable(&pdev->dev); + + strscpy(rkisp1->media_dev.model, RKISP1_DRIVER_NAME, + sizeof(rkisp1->media_dev.model)); + rkisp1->media_dev.dev = &pdev->dev; + strscpy(rkisp1->media_dev.bus_info, RKISP1_BUS_INFO, + sizeof(rkisp1->media_dev.bus_info)); + media_device_init(&rkisp1->media_dev); + + v4l2_dev = &rkisp1->v4l2_dev; + v4l2_dev->mdev = &rkisp1->media_dev; + strscpy(v4l2_dev->name, RKISP1_DRIVER_NAME, sizeof(v4l2_dev->name)); + + ret = v4l2_device_register(rkisp1->dev, &rkisp1->v4l2_dev); + if (ret) + return ret; + + ret = media_device_register(&rkisp1->media_dev); + if (ret) { + dev_err(dev, "Failed to register media device: %d\n", ret); + goto err_unreg_v4l2_dev; + } + + ret = rkisp1_entities_register(rkisp1); + if (ret) + goto err_unreg_media_dev; + + rkisp1_debug_init(rkisp1); + + return 0; + +err_unreg_media_dev: + media_device_unregister(&rkisp1->media_dev); +err_unreg_v4l2_dev: + v4l2_device_unregister(&rkisp1->v4l2_dev); + pm_runtime_disable(&pdev->dev); + return ret; +} + +static int rkisp1_remove(struct platform_device *pdev) +{ + struct rkisp1_device *rkisp1 = platform_get_drvdata(pdev); + + v4l2_async_notifier_unregister(&rkisp1->notifier); + v4l2_async_notifier_cleanup(&rkisp1->notifier); + + rkisp1_params_unregister(rkisp1); + rkisp1_stats_unregister(rkisp1); + rkisp1_capture_devs_unregister(rkisp1); + rkisp1_resizer_devs_unregister(rkisp1); + rkisp1_isp_unregister(rkisp1); + + media_device_unregister(&rkisp1->media_dev); + v4l2_device_unregister(&rkisp1->v4l2_dev); + + pm_runtime_disable(&pdev->dev); + + debugfs_remove_recursive(rkisp1->debug.debugfs_dir); + return 0; +} + +static struct platform_driver rkisp1_drv = { + .driver = { + .name = RKISP1_DRIVER_NAME, + .of_match_table = of_match_ptr(rkisp1_of_match), + .pm = &rkisp1_pm_ops, + }, + .probe = rkisp1_probe, + .remove = rkisp1_remove, +}; + +module_platform_driver(rkisp1_drv); +MODULE_DESCRIPTION("Rockchip ISP1 platform driver"); +MODULE_LICENSE("Dual MIT/GPL"); diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c new file mode 100644 index 000000000000..889982d8ca41 --- /dev/null +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c @@ -0,0 +1,1160 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Rockchip ISP1 Driver - ISP Subdevice + * + * Copyright (C) 2019 Collabora, Ltd. + * + * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd. + * Copyright (C) 2017 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "rkisp1-common.h" + +#define RKISP1_DEF_SINK_PAD_FMT MEDIA_BUS_FMT_SRGGB10_1X10 +#define RKISP1_DEF_SRC_PAD_FMT MEDIA_BUS_FMT_YUYV8_2X8 + +#define RKISP1_ISP_DEV_NAME RKISP1_DRIVER_NAME "_isp" + +/* + * NOTE: MIPI controller and input MUX are also configured in this file. + * This is because ISP Subdev describes not only ISP submodule (input size, + * format, output size, format), but also a virtual route device. + */ + +/* + * There are many variables named with format/frame in below code, + * please see here for their meaning. + * Cropping in the sink pad defines the image region from the sensor. + * Cropping in the source pad defines the region for the Image Stabilizer (IS) + * + * Cropping regions of ISP + * + * +---------------------------------------------------------+ + * | Sensor image | + * | +---------------------------------------------------+ | + * | | CIF_ISP_ACQ (for black level) | | + * | | sink pad format | | + * | | +--------------------------------------------+ | | + * | | | CIF_ISP_OUT | | | + * | | | sink pad crop | | | + * | | | +---------------------------------+ | | | + * | | | | CIF_ISP_IS | | | | + * | | | | source pad crop and format | | | | + * | | | +---------------------------------+ | | | + * | | +--------------------------------------------+ | | + * | +---------------------------------------------------+ | + * +---------------------------------------------------------+ + */ + +static const struct rkisp1_isp_mbus_info rkisp1_isp_formats[] = { + { + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, + .pixel_enc = V4L2_PIXEL_ENC_YUV, + .direction = RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = RKISP1_CIF_CSI2_DT_RAW10, + .bayer_pat = RKISP1_RAW_RGGB, + .bus_width = 10, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = RKISP1_CIF_CSI2_DT_RAW10, + .bayer_pat = RKISP1_RAW_BGGR, + .bus_width = 10, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = RKISP1_CIF_CSI2_DT_RAW10, + .bayer_pat = RKISP1_RAW_GBRG, + .bus_width = 10, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = RKISP1_CIF_CSI2_DT_RAW10, + .bayer_pat = RKISP1_RAW_GRBG, + .bus_width = 10, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = RKISP1_CIF_CSI2_DT_RAW12, + .bayer_pat = RKISP1_RAW_RGGB, + .bus_width = 12, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = RKISP1_CIF_CSI2_DT_RAW12, + .bayer_pat = RKISP1_RAW_BGGR, + .bus_width = 12, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = RKISP1_CIF_CSI2_DT_RAW12, + .bayer_pat = RKISP1_RAW_GBRG, + .bus_width = 12, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = RKISP1_CIF_CSI2_DT_RAW12, + .bayer_pat = RKISP1_RAW_GRBG, + .bus_width = 12, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = RKISP1_CIF_CSI2_DT_RAW8, + .bayer_pat = RKISP1_RAW_RGGB, + .bus_width = 8, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = RKISP1_CIF_CSI2_DT_RAW8, + .bayer_pat = RKISP1_RAW_BGGR, + .bus_width = 8, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = RKISP1_CIF_CSI2_DT_RAW8, + .bayer_pat = RKISP1_RAW_GBRG, + .bus_width = 8, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = RKISP1_CIF_CSI2_DT_RAW8, + .bayer_pat = RKISP1_RAW_GRBG, + .bus_width = 8, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16, + .pixel_enc = V4L2_PIXEL_ENC_YUV, + .mipi_dt = RKISP1_CIF_CSI2_DT_YUV422_8b, + .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_YCBYCR, + .bus_width = 16, + .direction = RKISP1_ISP_SD_SINK, + }, { + .mbus_code = MEDIA_BUS_FMT_YVYU8_1X16, + .pixel_enc = V4L2_PIXEL_ENC_YUV, + .mipi_dt = RKISP1_CIF_CSI2_DT_YUV422_8b, + .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_YCRYCB, + .bus_width = 16, + .direction = RKISP1_ISP_SD_SINK, + }, { + .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16, + .pixel_enc = V4L2_PIXEL_ENC_YUV, + .mipi_dt = RKISP1_CIF_CSI2_DT_YUV422_8b, + .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_CBYCRY, + .bus_width = 16, + .direction = RKISP1_ISP_SD_SINK, + }, { + .mbus_code = MEDIA_BUS_FMT_VYUY8_1X16, + .pixel_enc = V4L2_PIXEL_ENC_YUV, + .mipi_dt = RKISP1_CIF_CSI2_DT_YUV422_8b, + .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_CRYCBY, + .bus_width = 16, + .direction = RKISP1_ISP_SD_SINK, + }, +}; + +/* ---------------------------------------------------------------------------- + * Helpers + */ + +const struct rkisp1_isp_mbus_info *rkisp1_isp_mbus_info_get(u32 mbus_code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(rkisp1_isp_formats); i++) { + const struct rkisp1_isp_mbus_info *fmt = &rkisp1_isp_formats[i]; + + if (fmt->mbus_code == mbus_code) + return fmt; + } + + return NULL; +} + +static struct v4l2_subdev *rkisp1_get_remote_sensor(struct v4l2_subdev *sd) +{ + struct media_pad *local, *remote; + struct media_entity *sensor_me; + + local = &sd->entity.pads[RKISP1_ISP_PAD_SINK_VIDEO]; + remote = media_entity_remote_pad(local); + if (!remote) + return NULL; + + sensor_me = remote->entity; + return media_entity_to_v4l2_subdev(sensor_me); +} + +static struct v4l2_mbus_framefmt * +rkisp1_isp_get_pad_fmt(struct rkisp1_isp *isp, + struct v4l2_subdev_pad_config *cfg, + unsigned int pad, u32 which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_format(&isp->sd, cfg, pad); + else + return v4l2_subdev_get_try_format(&isp->sd, isp->pad_cfg, pad); +} + +static struct v4l2_rect * +rkisp1_isp_get_pad_crop(struct rkisp1_isp *isp, + struct v4l2_subdev_pad_config *cfg, + unsigned int pad, u32 which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_crop(&isp->sd, cfg, pad); + else + return v4l2_subdev_get_try_crop(&isp->sd, isp->pad_cfg, pad); +} + +/* ---------------------------------------------------------------------------- + * Camera Interface registers configurations + */ + +/* + * Image Stabilization. + * This should only be called when configuring CIF + * or at the frame end interrupt + */ +static void rkisp1_config_ism(struct rkisp1_device *rkisp1) +{ + struct v4l2_rect *src_crop = + rkisp1_isp_get_pad_crop(&rkisp1->isp, NULL, + RKISP1_ISP_PAD_SOURCE_VIDEO, + V4L2_SUBDEV_FORMAT_ACTIVE); + u32 val; + + rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_RECENTER); + rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_MAX_DX); + rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_MAX_DY); + rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_DISPLACE); + rkisp1_write(rkisp1, src_crop->left, RKISP1_CIF_ISP_IS_H_OFFS); + rkisp1_write(rkisp1, src_crop->top, RKISP1_CIF_ISP_IS_V_OFFS); + rkisp1_write(rkisp1, src_crop->width, RKISP1_CIF_ISP_IS_H_SIZE); + rkisp1_write(rkisp1, src_crop->height, RKISP1_CIF_ISP_IS_V_SIZE); + + /* IS(Image Stabilization) is always on, working as output crop */ + rkisp1_write(rkisp1, 1, RKISP1_CIF_ISP_IS_CTRL); + val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL); + val |= RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD; + rkisp1_write(rkisp1, val, RKISP1_CIF_ISP_CTRL); +} + +/* + * configure ISP blocks with input format, size...... + */ +static int rkisp1_config_isp(struct rkisp1_device *rkisp1) +{ + u32 isp_ctrl = 0, irq_mask = 0, acq_mult = 0, signal = 0; + const struct rkisp1_isp_mbus_info *src_fmt, *sink_fmt; + struct rkisp1_sensor_async *sensor; + struct v4l2_mbus_framefmt *sink_frm; + struct v4l2_rect *sink_crop; + + sensor = rkisp1->active_sensor; + sink_fmt = rkisp1->isp.sink_fmt; + src_fmt = rkisp1->isp.src_fmt; + sink_frm = rkisp1_isp_get_pad_fmt(&rkisp1->isp, NULL, + RKISP1_ISP_PAD_SINK_VIDEO, + V4L2_SUBDEV_FORMAT_ACTIVE); + sink_crop = rkisp1_isp_get_pad_crop(&rkisp1->isp, NULL, + RKISP1_ISP_PAD_SINK_VIDEO, + V4L2_SUBDEV_FORMAT_ACTIVE); + + if (sink_fmt->pixel_enc == V4L2_PIXEL_ENC_BAYER) { + acq_mult = 1; + if (src_fmt->pixel_enc == V4L2_PIXEL_ENC_BAYER) { + if (sensor->mbus_type == V4L2_MBUS_BT656) + isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT_ITU656; + else + isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT; + } else { + rkisp1_write(rkisp1, RKISP1_CIF_ISP_DEMOSAIC_TH(0xc), + RKISP1_CIF_ISP_DEMOSAIC); + + if (sensor->mbus_type == V4L2_MBUS_BT656) + isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU656; + else + isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU601; + } + } else if (sink_fmt->pixel_enc == V4L2_PIXEL_ENC_YUV) { + acq_mult = 2; + if (sensor->mbus_type == V4L2_MBUS_CSI2_DPHY) { + isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU601; + } else { + if (sensor->mbus_type == V4L2_MBUS_BT656) + isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU656; + else + isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU601; + } + + irq_mask |= RKISP1_CIF_ISP_DATA_LOSS; + } + + /* Set up input acquisition properties */ + if (sensor->mbus_type == V4L2_MBUS_BT656 || + sensor->mbus_type == V4L2_MBUS_PARALLEL) { + if (sensor->mbus_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) + signal = RKISP1_CIF_ISP_ACQ_PROP_POS_EDGE; + } + + if (sensor->mbus_type == V4L2_MBUS_PARALLEL) { + if (sensor->mbus_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) + signal |= RKISP1_CIF_ISP_ACQ_PROP_VSYNC_LOW; + + if (sensor->mbus_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) + signal |= RKISP1_CIF_ISP_ACQ_PROP_HSYNC_LOW; + } + + rkisp1_write(rkisp1, isp_ctrl, RKISP1_CIF_ISP_CTRL); + rkisp1_write(rkisp1, signal | sink_fmt->yuv_seq | + RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT(sink_fmt->bayer_pat) | + RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_ALL, + RKISP1_CIF_ISP_ACQ_PROP); + rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_ACQ_NR_FRAMES); + + /* Acquisition Size */ + rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_ACQ_H_OFFS); + rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_ACQ_V_OFFS); + rkisp1_write(rkisp1, + acq_mult * sink_frm->width, RKISP1_CIF_ISP_ACQ_H_SIZE); + rkisp1_write(rkisp1, sink_frm->height, RKISP1_CIF_ISP_ACQ_V_SIZE); + + /* ISP Out Area */ + rkisp1_write(rkisp1, sink_crop->left, RKISP1_CIF_ISP_OUT_H_OFFS); + rkisp1_write(rkisp1, sink_crop->top, RKISP1_CIF_ISP_OUT_V_OFFS); + rkisp1_write(rkisp1, sink_crop->width, RKISP1_CIF_ISP_OUT_H_SIZE); + rkisp1_write(rkisp1, sink_crop->height, RKISP1_CIF_ISP_OUT_V_SIZE); + + irq_mask |= RKISP1_CIF_ISP_FRAME | RKISP1_CIF_ISP_V_START | + RKISP1_CIF_ISP_PIC_SIZE_ERROR; + rkisp1_write(rkisp1, irq_mask, RKISP1_CIF_ISP_IMSC); + + if (src_fmt->pixel_enc == V4L2_PIXEL_ENC_BAYER) { + rkisp1_params_disable(&rkisp1->params); + } else { + struct v4l2_mbus_framefmt *src_frm; + + src_frm = rkisp1_isp_get_pad_fmt(&rkisp1->isp, NULL, + RKISP1_ISP_PAD_SINK_VIDEO, + V4L2_SUBDEV_FORMAT_ACTIVE); + rkisp1_params_configure(&rkisp1->params, sink_fmt->bayer_pat, + src_frm->quantization); + } + + return 0; +} + +static int rkisp1_config_dvp(struct rkisp1_device *rkisp1) +{ + const struct rkisp1_isp_mbus_info *sink_fmt = rkisp1->isp.sink_fmt; + u32 val, input_sel; + + switch (sink_fmt->bus_width) { + case 8: + input_sel = RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_8B_ZERO; + break; + case 10: + input_sel = RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_ZERO; + break; + case 12: + input_sel = RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_12B; + break; + default: + dev_err(rkisp1->dev, "Invalid bus width\n"); + return -EINVAL; + } + + val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_ACQ_PROP); + rkisp1_write(rkisp1, val | input_sel, RKISP1_CIF_ISP_ACQ_PROP); + + return 0; +} + +static int rkisp1_config_mipi(struct rkisp1_device *rkisp1) +{ + const struct rkisp1_isp_mbus_info *sink_fmt = rkisp1->isp.sink_fmt; + unsigned int lanes = rkisp1->active_sensor->lanes; + u32 mipi_ctrl; + + if (lanes < 1 || lanes > 4) + return -EINVAL; + + mipi_ctrl = RKISP1_CIF_MIPI_CTRL_NUM_LANES(lanes - 1) | + RKISP1_CIF_MIPI_CTRL_SHUTDOWNLANES(0xf) | + RKISP1_CIF_MIPI_CTRL_ERR_SOT_SYNC_HS_SKIP | + RKISP1_CIF_MIPI_CTRL_CLOCKLANE_ENA; + + rkisp1_write(rkisp1, mipi_ctrl, RKISP1_CIF_MIPI_CTRL); + + /* Configure Data Type and Virtual Channel */ + rkisp1_write(rkisp1, + RKISP1_CIF_MIPI_DATA_SEL_DT(sink_fmt->mipi_dt) | + RKISP1_CIF_MIPI_DATA_SEL_VC(0), + RKISP1_CIF_MIPI_IMG_DATA_SEL); + + /* Clear MIPI interrupts */ + rkisp1_write(rkisp1, ~0, RKISP1_CIF_MIPI_ICR); + /* + * Disable RKISP1_CIF_MIPI_ERR_DPHY interrupt here temporary for + * isp bus may be dead when switch isp. + */ + rkisp1_write(rkisp1, + RKISP1_CIF_MIPI_FRAME_END | RKISP1_CIF_MIPI_ERR_CSI | + RKISP1_CIF_MIPI_ERR_DPHY | + RKISP1_CIF_MIPI_SYNC_FIFO_OVFLW(0x03) | + RKISP1_CIF_MIPI_ADD_DATA_OVFLW, + RKISP1_CIF_MIPI_IMSC); + + dev_dbg(rkisp1->dev, "\n MIPI_CTRL 0x%08x\n" + " MIPI_IMG_DATA_SEL 0x%08x\n" + " MIPI_STATUS 0x%08x\n" + " MIPI_IMSC 0x%08x\n", + rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL), + rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMG_DATA_SEL), + rkisp1_read(rkisp1, RKISP1_CIF_MIPI_STATUS), + rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC)); + + return 0; +} + +/* Configure MUX */ +static int rkisp1_config_path(struct rkisp1_device *rkisp1) +{ + struct rkisp1_sensor_async *sensor = rkisp1->active_sensor; + u32 dpcl = rkisp1_read(rkisp1, RKISP1_CIF_VI_DPCL); + int ret = 0; + + if (sensor->mbus_type == V4L2_MBUS_BT656 || + sensor->mbus_type == V4L2_MBUS_PARALLEL) { + ret = rkisp1_config_dvp(rkisp1); + dpcl |= RKISP1_CIF_VI_DPCL_IF_SEL_PARALLEL; + } else if (sensor->mbus_type == V4L2_MBUS_CSI2_DPHY) { + ret = rkisp1_config_mipi(rkisp1); + dpcl |= RKISP1_CIF_VI_DPCL_IF_SEL_MIPI; + } + + rkisp1_write(rkisp1, dpcl, RKISP1_CIF_VI_DPCL); + + return ret; +} + +/* Hardware configure Entry */ +static int rkisp1_config_cif(struct rkisp1_device *rkisp1) +{ + u32 cif_id; + int ret; + + cif_id = rkisp1_read(rkisp1, RKISP1_CIF_VI_ID); + dev_dbg(rkisp1->dev, "CIF_ID 0x%08x\n", cif_id); + + ret = rkisp1_config_isp(rkisp1); + if (ret) + return ret; + ret = rkisp1_config_path(rkisp1); + if (ret) + return ret; + rkisp1_config_ism(rkisp1); + + return 0; +} + +static void rkisp1_isp_stop(struct rkisp1_device *rkisp1) +{ + u32 val; + + /* + * ISP(mi) stop in mi frame end -> Stop ISP(mipi) -> + * Stop ISP(isp) ->wait for ISP isp off + */ + /* stop and clear MI, MIPI, and ISP interrupts */ + rkisp1_write(rkisp1, 0, RKISP1_CIF_MIPI_IMSC); + rkisp1_write(rkisp1, ~0, RKISP1_CIF_MIPI_ICR); + + rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IMSC); + rkisp1_write(rkisp1, ~0, RKISP1_CIF_ISP_ICR); + + rkisp1_write(rkisp1, 0, RKISP1_CIF_MI_IMSC); + rkisp1_write(rkisp1, ~0, RKISP1_CIF_MI_ICR); + val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL); + rkisp1_write(rkisp1, val & (~RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA), + RKISP1_CIF_MIPI_CTRL); + /* stop ISP */ + val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL); + val &= ~(RKISP1_CIF_ISP_CTRL_ISP_INFORM_ENABLE | + RKISP1_CIF_ISP_CTRL_ISP_ENABLE); + rkisp1_write(rkisp1, val, RKISP1_CIF_ISP_CTRL); + + val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL); + rkisp1_write(rkisp1, val | RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD, + RKISP1_CIF_ISP_CTRL); + + readx_poll_timeout(readl, rkisp1->base_addr + RKISP1_CIF_ISP_RIS, + val, val & RKISP1_CIF_ISP_OFF, 20, 100); + rkisp1_write(rkisp1, + RKISP1_CIF_IRCL_MIPI_SW_RST | RKISP1_CIF_IRCL_ISP_SW_RST, + RKISP1_CIF_IRCL); + rkisp1_write(rkisp1, 0x0, RKISP1_CIF_IRCL); +} + +static void rkisp1_config_clk(struct rkisp1_device *rkisp1) +{ + u32 val = RKISP1_CIF_ICCL_ISP_CLK | RKISP1_CIF_ICCL_CP_CLK | + RKISP1_CIF_ICCL_MRSZ_CLK | RKISP1_CIF_ICCL_SRSZ_CLK | + RKISP1_CIF_ICCL_JPEG_CLK | RKISP1_CIF_ICCL_MI_CLK | + RKISP1_CIF_ICCL_IE_CLK | RKISP1_CIF_ICCL_MIPI_CLK | + RKISP1_CIF_ICCL_DCROP_CLK; + + rkisp1_write(rkisp1, val, RKISP1_CIF_ICCL); +} + +static void rkisp1_isp_start(struct rkisp1_device *rkisp1) +{ + struct rkisp1_sensor_async *sensor = rkisp1->active_sensor; + u32 val; + + rkisp1_config_clk(rkisp1); + + /* Activate MIPI */ + if (sensor->mbus_type == V4L2_MBUS_CSI2_DPHY) { + val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL); + rkisp1_write(rkisp1, val | RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA, + RKISP1_CIF_MIPI_CTRL); + } + /* Activate ISP */ + val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL); + val |= RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD | + RKISP1_CIF_ISP_CTRL_ISP_ENABLE | + RKISP1_CIF_ISP_CTRL_ISP_INFORM_ENABLE; + rkisp1_write(rkisp1, val, RKISP1_CIF_ISP_CTRL); + + /* + * CIF spec says to wait for sufficient time after enabling + * the MIPI interface and before starting the sensor output. + */ + usleep_range(1000, 1200); +} + +/* ---------------------------------------------------------------------------- + * Subdev pad operations + */ + +static int rkisp1_isp_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + unsigned int i, dir; + int pos = 0; + + if (code->pad == RKISP1_ISP_PAD_SINK_VIDEO) { + dir = RKISP1_ISP_SD_SINK; + } else if (code->pad == RKISP1_ISP_PAD_SOURCE_VIDEO) { + dir = RKISP1_ISP_SD_SRC; + } else { + if (code->index > 0) + return -EINVAL; + code->code = MEDIA_BUS_FMT_METADATA_FIXED; + return 0; + } + + if (code->index >= ARRAY_SIZE(rkisp1_isp_formats)) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(rkisp1_isp_formats); i++) { + const struct rkisp1_isp_mbus_info *fmt = &rkisp1_isp_formats[i]; + + if (fmt->direction & dir) + pos++; + + if (code->index == pos - 1) { + code->code = fmt->mbus_code; + if (fmt->pixel_enc == V4L2_PIXEL_ENC_YUV && + dir == RKISP1_ISP_SD_SRC) + code->flags = + V4L2_SUBDEV_MBUS_CODE_CSC_QUANTIZATION; + return 0; + } + } + + return -EINVAL; +} + +static int rkisp1_isp_init_config(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg) +{ + struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; + struct v4l2_rect *sink_crop, *src_crop; + + sink_fmt = v4l2_subdev_get_try_format(sd, cfg, + RKISP1_ISP_PAD_SINK_VIDEO); + sink_fmt->width = RKISP1_DEFAULT_WIDTH; + sink_fmt->height = RKISP1_DEFAULT_HEIGHT; + sink_fmt->field = V4L2_FIELD_NONE; + sink_fmt->code = RKISP1_DEF_SINK_PAD_FMT; + + sink_crop = v4l2_subdev_get_try_crop(sd, cfg, + RKISP1_ISP_PAD_SINK_VIDEO); + sink_crop->width = RKISP1_DEFAULT_WIDTH; + sink_crop->height = RKISP1_DEFAULT_HEIGHT; + sink_crop->left = 0; + sink_crop->top = 0; + + src_fmt = v4l2_subdev_get_try_format(sd, cfg, + RKISP1_ISP_PAD_SOURCE_VIDEO); + *src_fmt = *sink_fmt; + src_fmt->code = RKISP1_DEF_SRC_PAD_FMT; + + src_crop = v4l2_subdev_get_try_crop(sd, cfg, + RKISP1_ISP_PAD_SOURCE_VIDEO); + *src_crop = *sink_crop; + + sink_fmt = v4l2_subdev_get_try_format(sd, cfg, + RKISP1_ISP_PAD_SINK_PARAMS); + src_fmt = v4l2_subdev_get_try_format(sd, cfg, + RKISP1_ISP_PAD_SOURCE_STATS); + sink_fmt->width = 0; + sink_fmt->height = 0; + sink_fmt->field = V4L2_FIELD_NONE; + sink_fmt->code = MEDIA_BUS_FMT_METADATA_FIXED; + *src_fmt = *sink_fmt; + + return 0; +} + +static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_mbus_framefmt *format, + unsigned int which) +{ + const struct rkisp1_isp_mbus_info *mbus_info; + struct v4l2_mbus_framefmt *src_fmt; + const struct v4l2_rect *src_crop; + + src_fmt = rkisp1_isp_get_pad_fmt(isp, cfg, + RKISP1_ISP_PAD_SOURCE_VIDEO, which); + src_crop = rkisp1_isp_get_pad_crop(isp, cfg, + RKISP1_ISP_PAD_SOURCE_VIDEO, which); + + src_fmt->code = format->code; + mbus_info = rkisp1_isp_mbus_info_get(src_fmt->code); + if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SRC)) { + src_fmt->code = RKISP1_DEF_SRC_PAD_FMT; + mbus_info = rkisp1_isp_mbus_info_get(src_fmt->code); + } + if (which == V4L2_SUBDEV_FORMAT_ACTIVE) + isp->src_fmt = mbus_info; + src_fmt->width = src_crop->width; + src_fmt->height = src_crop->height; + + /* + * The CSC API is used to allow userspace to force full + * quantization on YUV formats. + */ + if (format->flags & V4L2_MBUS_FRAMEFMT_SET_CSC && + format->quantization == V4L2_QUANTIZATION_FULL_RANGE && + mbus_info->pixel_enc == V4L2_PIXEL_ENC_YUV) + src_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; + else if (mbus_info->pixel_enc == V4L2_PIXEL_ENC_YUV) + src_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; + else + src_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; + + *format = *src_fmt; +} + +static void rkisp1_isp_set_src_crop(struct rkisp1_isp *isp, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_rect *r, unsigned int which) +{ + struct v4l2_mbus_framefmt *src_fmt; + const struct v4l2_rect *sink_crop; + struct v4l2_rect *src_crop; + + src_crop = rkisp1_isp_get_pad_crop(isp, cfg, + RKISP1_ISP_PAD_SOURCE_VIDEO, + which); + sink_crop = rkisp1_isp_get_pad_crop(isp, cfg, + RKISP1_ISP_PAD_SINK_VIDEO, + which); + + src_crop->left = ALIGN(r->left, 2); + src_crop->width = ALIGN(r->width, 2); + src_crop->top = r->top; + src_crop->height = r->height; + rkisp1_sd_adjust_crop_rect(src_crop, sink_crop); + + *r = *src_crop; + + /* Propagate to out format */ + src_fmt = rkisp1_isp_get_pad_fmt(isp, cfg, + RKISP1_ISP_PAD_SOURCE_VIDEO, which); + rkisp1_isp_set_src_fmt(isp, cfg, src_fmt, which); +} + +static void rkisp1_isp_set_sink_crop(struct rkisp1_isp *isp, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_rect *r, unsigned int which) +{ + struct v4l2_rect *sink_crop, *src_crop; + struct v4l2_mbus_framefmt *sink_fmt; + + sink_crop = rkisp1_isp_get_pad_crop(isp, cfg, RKISP1_ISP_PAD_SINK_VIDEO, + which); + sink_fmt = rkisp1_isp_get_pad_fmt(isp, cfg, RKISP1_ISP_PAD_SINK_VIDEO, + which); + + sink_crop->left = ALIGN(r->left, 2); + sink_crop->width = ALIGN(r->width, 2); + sink_crop->top = r->top; + sink_crop->height = r->height; + rkisp1_sd_adjust_crop(sink_crop, sink_fmt); + + *r = *sink_crop; + + /* Propagate to out crop */ + src_crop = rkisp1_isp_get_pad_crop(isp, cfg, + RKISP1_ISP_PAD_SOURCE_VIDEO, which); + rkisp1_isp_set_src_crop(isp, cfg, src_crop, which); +} + +static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_mbus_framefmt *format, + unsigned int which) +{ + const struct rkisp1_isp_mbus_info *mbus_info; + struct v4l2_mbus_framefmt *sink_fmt; + struct v4l2_rect *sink_crop; + + sink_fmt = rkisp1_isp_get_pad_fmt(isp, cfg, RKISP1_ISP_PAD_SINK_VIDEO, + which); + sink_fmt->code = format->code; + mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); + if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SINK)) { + sink_fmt->code = RKISP1_DEF_SINK_PAD_FMT; + mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); + } + if (which == V4L2_SUBDEV_FORMAT_ACTIVE) + isp->sink_fmt = mbus_info; + + sink_fmt->width = clamp_t(u32, format->width, + RKISP1_ISP_MIN_WIDTH, + RKISP1_ISP_MAX_WIDTH); + sink_fmt->height = clamp_t(u32, format->height, + RKISP1_ISP_MIN_HEIGHT, + RKISP1_ISP_MAX_HEIGHT); + + *format = *sink_fmt; + + /* Propagate to in crop */ + sink_crop = rkisp1_isp_get_pad_crop(isp, cfg, RKISP1_ISP_PAD_SINK_VIDEO, + which); + rkisp1_isp_set_sink_crop(isp, cfg, sink_crop, which); +} + +static int rkisp1_isp_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd); + + mutex_lock(&isp->ops_lock); + fmt->format = *rkisp1_isp_get_pad_fmt(isp, cfg, fmt->pad, fmt->which); + mutex_unlock(&isp->ops_lock); + return 0; +} + +static int rkisp1_isp_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd); + + mutex_lock(&isp->ops_lock); + if (fmt->pad == RKISP1_ISP_PAD_SINK_VIDEO) + rkisp1_isp_set_sink_fmt(isp, cfg, &fmt->format, fmt->which); + else if (fmt->pad == RKISP1_ISP_PAD_SOURCE_VIDEO) + rkisp1_isp_set_src_fmt(isp, cfg, &fmt->format, fmt->which); + else + fmt->format = *rkisp1_isp_get_pad_fmt(isp, cfg, fmt->pad, + fmt->which); + + mutex_unlock(&isp->ops_lock); + return 0; +} + +static int rkisp1_isp_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd); + int ret = 0; + + if (sel->pad != RKISP1_ISP_PAD_SOURCE_VIDEO && + sel->pad != RKISP1_ISP_PAD_SINK_VIDEO) + return -EINVAL; + + mutex_lock(&isp->ops_lock); + switch (sel->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + if (sel->pad == RKISP1_ISP_PAD_SINK_VIDEO) { + struct v4l2_mbus_framefmt *fmt; + + fmt = rkisp1_isp_get_pad_fmt(isp, cfg, sel->pad, + sel->which); + sel->r.height = fmt->height; + sel->r.width = fmt->width; + sel->r.left = 0; + sel->r.top = 0; + } else { + sel->r = *rkisp1_isp_get_pad_crop(isp, cfg, + RKISP1_ISP_PAD_SINK_VIDEO, + sel->which); + } + break; + case V4L2_SEL_TGT_CROP: + sel->r = *rkisp1_isp_get_pad_crop(isp, cfg, sel->pad, + sel->which); + break; + default: + ret = -EINVAL; + } + mutex_unlock(&isp->ops_lock); + return ret; +} + +static int rkisp1_isp_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct rkisp1_device *rkisp1 = + container_of(sd->v4l2_dev, struct rkisp1_device, v4l2_dev); + struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd); + int ret = 0; + + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + dev_dbg(rkisp1->dev, "%s: pad: %d sel(%d,%d)/%dx%d\n", __func__, + sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height); + mutex_lock(&isp->ops_lock); + if (sel->pad == RKISP1_ISP_PAD_SINK_VIDEO) + rkisp1_isp_set_sink_crop(isp, cfg, &sel->r, sel->which); + else if (sel->pad == RKISP1_ISP_PAD_SOURCE_VIDEO) + rkisp1_isp_set_src_crop(isp, cfg, &sel->r, sel->which); + else + ret = -EINVAL; + + mutex_unlock(&isp->ops_lock); + return ret; +} + +static int rkisp1_subdev_link_validate(struct media_link *link) +{ + if (link->sink->index == RKISP1_ISP_PAD_SINK_PARAMS) + return 0; + + return v4l2_subdev_link_validate(link); +} + +static const struct v4l2_subdev_pad_ops rkisp1_isp_pad_ops = { + .enum_mbus_code = rkisp1_isp_enum_mbus_code, + .get_selection = rkisp1_isp_get_selection, + .set_selection = rkisp1_isp_set_selection, + .init_cfg = rkisp1_isp_init_config, + .get_fmt = rkisp1_isp_get_fmt, + .set_fmt = rkisp1_isp_set_fmt, + .link_validate = v4l2_subdev_link_validate_default, +}; + +/* ---------------------------------------------------------------------------- + * Stream operations + */ + +static int rkisp1_mipi_csi2_start(struct rkisp1_isp *isp, + struct rkisp1_sensor_async *sensor) +{ + struct rkisp1_device *rkisp1 = + container_of(isp->sd.v4l2_dev, struct rkisp1_device, v4l2_dev); + union phy_configure_opts opts; + struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy; + s64 pixel_clock; + + if (!sensor->pixel_rate_ctrl) { + dev_warn(rkisp1->dev, "No pixel rate control in sensor subdev\n"); + return -EPIPE; + } + + pixel_clock = v4l2_ctrl_g_ctrl_int64(sensor->pixel_rate_ctrl); + if (!pixel_clock) { + dev_err(rkisp1->dev, "Invalid pixel rate value\n"); + return -EINVAL; + } + + phy_mipi_dphy_get_default_config(pixel_clock, isp->sink_fmt->bus_width, + sensor->lanes, cfg); + phy_set_mode(sensor->dphy, PHY_MODE_MIPI_DPHY); + phy_configure(sensor->dphy, &opts); + phy_power_on(sensor->dphy); + + return 0; +} + +static void rkisp1_mipi_csi2_stop(struct rkisp1_sensor_async *sensor) +{ + phy_power_off(sensor->dphy); +} + +static int rkisp1_isp_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct rkisp1_device *rkisp1 = + container_of(sd->v4l2_dev, struct rkisp1_device, v4l2_dev); + struct rkisp1_isp *isp = &rkisp1->isp; + struct v4l2_subdev *sensor_sd; + int ret = 0; + + if (!enable) { + rkisp1_isp_stop(rkisp1); + rkisp1_mipi_csi2_stop(rkisp1->active_sensor); + return 0; + } + + sensor_sd = rkisp1_get_remote_sensor(sd); + if (!sensor_sd) { + dev_warn(rkisp1->dev, "No link between isp and sensor\n"); + return -ENODEV; + } + + rkisp1->active_sensor = container_of(sensor_sd->asd, + struct rkisp1_sensor_async, asd); + + if (rkisp1->active_sensor->mbus_type != V4L2_MBUS_CSI2_DPHY) + return -EINVAL; + + rkisp1->isp.frame_sequence = -1; + mutex_lock(&isp->ops_lock); + ret = rkisp1_config_cif(rkisp1); + if (ret) + goto mutex_unlock; + + ret = rkisp1_mipi_csi2_start(&rkisp1->isp, rkisp1->active_sensor); + if (ret) + goto mutex_unlock; + + rkisp1_isp_start(rkisp1); + +mutex_unlock: + mutex_unlock(&isp->ops_lock); + return ret; +} + +static int rkisp1_isp_subs_evt(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + if (sub->type != V4L2_EVENT_FRAME_SYNC) + return -EINVAL; + + /* V4L2_EVENT_FRAME_SYNC doesn't require an id, so zero should be set */ + if (sub->id != 0) + return -EINVAL; + + return v4l2_event_subscribe(fh, sub, 0, NULL); +} + +static const struct media_entity_operations rkisp1_isp_media_ops = { + .link_validate = rkisp1_subdev_link_validate, +}; + +static const struct v4l2_subdev_video_ops rkisp1_isp_video_ops = { + .s_stream = rkisp1_isp_s_stream, +}; + +static const struct v4l2_subdev_core_ops rkisp1_isp_core_ops = { + .subscribe_event = rkisp1_isp_subs_evt, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + +static const struct v4l2_subdev_ops rkisp1_isp_ops = { + .core = &rkisp1_isp_core_ops, + .video = &rkisp1_isp_video_ops, + .pad = &rkisp1_isp_pad_ops, +}; + +int rkisp1_isp_register(struct rkisp1_device *rkisp1) +{ + struct rkisp1_isp *isp = &rkisp1->isp; + struct media_pad *pads = isp->pads; + struct v4l2_subdev *sd = &isp->sd; + int ret; + + v4l2_subdev_init(sd, &rkisp1_isp_ops); + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; + sd->entity.ops = &rkisp1_isp_media_ops; + sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; + sd->owner = THIS_MODULE; + strscpy(sd->name, RKISP1_ISP_DEV_NAME, sizeof(sd->name)); + + pads[RKISP1_ISP_PAD_SINK_VIDEO].flags = MEDIA_PAD_FL_SINK | + MEDIA_PAD_FL_MUST_CONNECT; + pads[RKISP1_ISP_PAD_SINK_PARAMS].flags = MEDIA_PAD_FL_SINK; + pads[RKISP1_ISP_PAD_SOURCE_VIDEO].flags = MEDIA_PAD_FL_SOURCE; + pads[RKISP1_ISP_PAD_SOURCE_STATS].flags = MEDIA_PAD_FL_SOURCE; + + isp->sink_fmt = rkisp1_isp_mbus_info_get(RKISP1_DEF_SINK_PAD_FMT); + isp->src_fmt = rkisp1_isp_mbus_info_get(RKISP1_DEF_SRC_PAD_FMT); + + mutex_init(&isp->ops_lock); + ret = media_entity_pads_init(&sd->entity, RKISP1_ISP_PAD_MAX, pads); + if (ret) + return ret; + + ret = v4l2_device_register_subdev(&rkisp1->v4l2_dev, sd); + if (ret) { + dev_err(rkisp1->dev, "Failed to register isp subdev\n"); + goto err_cleanup_media_entity; + } + + rkisp1_isp_init_config(sd, rkisp1->isp.pad_cfg); + return 0; + +err_cleanup_media_entity: + media_entity_cleanup(&sd->entity); + + return ret; +} + +void rkisp1_isp_unregister(struct rkisp1_device *rkisp1) +{ + struct v4l2_subdev *sd = &rkisp1->isp.sd; + + v4l2_device_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); +} + +/* ---------------------------------------------------------------------------- + * Interrupt handlers + */ + +void rkisp1_mipi_isr(struct rkisp1_device *rkisp1) +{ + u32 val, status; + + status = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_MIS); + if (!status) + return; + + rkisp1_write(rkisp1, status, RKISP1_CIF_MIPI_ICR); + + /* + * Disable DPHY errctrl interrupt, because this dphy + * erctrl signal is asserted until the next changes + * of line state. This time is may be too long and cpu + * is hold in this interrupt. + */ + if (status & RKISP1_CIF_MIPI_ERR_CTRL(0x0f)) { + val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC); + rkisp1_write(rkisp1, val & ~RKISP1_CIF_MIPI_ERR_CTRL(0x0f), + RKISP1_CIF_MIPI_IMSC); + rkisp1->isp.is_dphy_errctrl_disabled = true; + } + + /* + * Enable DPHY errctrl interrupt again, if mipi have receive + * the whole frame without any error. + */ + if (status == RKISP1_CIF_MIPI_FRAME_END) { + /* + * Enable DPHY errctrl interrupt again, if mipi have receive + * the whole frame without any error. + */ + if (rkisp1->isp.is_dphy_errctrl_disabled) { + val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC); + val |= RKISP1_CIF_MIPI_ERR_CTRL(0x0f); + rkisp1_write(rkisp1, val, RKISP1_CIF_MIPI_IMSC); + rkisp1->isp.is_dphy_errctrl_disabled = false; + } + } else { + rkisp1->debug.mipi_error++; + } +} + +static void rkisp1_isp_queue_event_sof(struct rkisp1_isp *isp) +{ + struct v4l2_event event = { + .type = V4L2_EVENT_FRAME_SYNC, + }; + event.u.frame_sync.frame_sequence = isp->frame_sequence; + + v4l2_event_queue(isp->sd.devnode, &event); +} + +void rkisp1_isp_isr(struct rkisp1_device *rkisp1) +{ + u32 status, isp_err; + + status = rkisp1_read(rkisp1, RKISP1_CIF_ISP_MIS); + if (!status) + return; + + rkisp1_write(rkisp1, status, RKISP1_CIF_ISP_ICR); + + /* Vertical sync signal, starting generating new frame */ + if (status & RKISP1_CIF_ISP_V_START) { + rkisp1->isp.frame_sequence++; + rkisp1_isp_queue_event_sof(&rkisp1->isp); + if (status & RKISP1_CIF_ISP_FRAME) { + WARN_ONCE(1, "irq delay is too long, buffers might not be in sync\n"); + rkisp1->debug.irq_delay++; + } + } + if (status & RKISP1_CIF_ISP_PIC_SIZE_ERROR) { + /* Clear pic_size_error */ + isp_err = rkisp1_read(rkisp1, RKISP1_CIF_ISP_ERR); + if (isp_err & RKISP1_CIF_ISP_ERR_INFORM_SIZE) + rkisp1->debug.inform_size_error++; + if (isp_err & RKISP1_CIF_ISP_ERR_IS_SIZE) + rkisp1->debug.img_stabilization_size_error++; + if (isp_err & RKISP1_CIF_ISP_ERR_OUTFORM_SIZE) + rkisp1->debug.outform_size_error++; + rkisp1_write(rkisp1, isp_err, RKISP1_CIF_ISP_ERR_CLR); + } else if (status & RKISP1_CIF_ISP_DATA_LOSS) { + /* keep track of data_loss in debugfs */ + rkisp1->debug.data_loss++; + } + + if (status & RKISP1_CIF_ISP_FRAME) { + u32 isp_ris; + + /* New frame from the sensor received */ + isp_ris = rkisp1_read(rkisp1, RKISP1_CIF_ISP_RIS); + if (isp_ris & RKISP1_STATS_MEAS_MASK) + rkisp1_stats_isr(&rkisp1->stats, isp_ris); + /* + * Then update changed configs. Some of them involve + * lot of register writes. Do those only one per frame. + * Do the updates in the order of the processing flow. + */ + rkisp1_params_isr(rkisp1); + } +} diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c new file mode 100644 index 000000000000..03f9a81df440 --- /dev/null +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c @@ -0,0 +1,1572 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Rockchip ISP1 Driver - Params subdevice + * + * Copyright (C) 2017 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include /* for ISP params */ + +#include "rkisp1-common.h" + +#define RKISP1_PARAMS_DEV_NAME RKISP1_DRIVER_NAME "_params" + +#define RKISP1_ISP_PARAMS_REQ_BUFS_MIN 2 +#define RKISP1_ISP_PARAMS_REQ_BUFS_MAX 8 + +#define RKISP1_ISP_DPCC_LINE_THRESH(n) \ + (RKISP1_CIF_ISP_DPCC_LINE_THRESH_1 + 0x14 * (n)) +#define RKISP1_ISP_DPCC_LINE_MAD_FAC(n) \ + (RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_1 + 0x14 * (n)) +#define RKISP1_ISP_DPCC_PG_FAC(n) \ + (RKISP1_CIF_ISP_DPCC_PG_FAC_1 + 0x14 * (n)) +#define RKISP1_ISP_DPCC_RND_THRESH(n) \ + (RKISP1_CIF_ISP_DPCC_RND_THRESH_1 + 0x14 * (n)) +#define RKISP1_ISP_DPCC_RG_FAC(n) \ + (RKISP1_CIF_ISP_DPCC_RG_FAC_1 + 0x14 * (n)) +#define RKISP1_ISP_CC_COEFF(n) \ + (RKISP1_CIF_ISP_CC_COEFF_0 + (n) * 4) + +static inline void +rkisp1_param_set_bits(struct rkisp1_params *params, u32 reg, u32 bit_mask) +{ + u32 val; + + val = rkisp1_read(params->rkisp1, reg); + rkisp1_write(params->rkisp1, val | bit_mask, reg); +} + +static inline void +rkisp1_param_clear_bits(struct rkisp1_params *params, u32 reg, u32 bit_mask) +{ + u32 val; + + val = rkisp1_read(params->rkisp1, reg); + rkisp1_write(params->rkisp1, val & ~bit_mask, reg); +} + +/* ISP BP interface function */ +static void rkisp1_dpcc_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_dpcc_config *arg) +{ + unsigned int i; + u32 mode; + + /* avoid to override the old enable value */ + mode = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_DPCC_MODE); + mode &= RKISP1_CIF_ISP_DPCC_ENA; + mode |= arg->mode & ~RKISP1_CIF_ISP_DPCC_ENA; + rkisp1_write(params->rkisp1, mode, RKISP1_CIF_ISP_DPCC_MODE); + rkisp1_write(params->rkisp1, arg->output_mode, + RKISP1_CIF_ISP_DPCC_OUTPUT_MODE); + rkisp1_write(params->rkisp1, arg->set_use, + RKISP1_CIF_ISP_DPCC_SET_USE); + + rkisp1_write(params->rkisp1, arg->methods[0].method, + RKISP1_CIF_ISP_DPCC_METHODS_SET_1); + rkisp1_write(params->rkisp1, arg->methods[1].method, + RKISP1_CIF_ISP_DPCC_METHODS_SET_2); + rkisp1_write(params->rkisp1, arg->methods[2].method, + RKISP1_CIF_ISP_DPCC_METHODS_SET_3); + for (i = 0; i < RKISP1_CIF_ISP_DPCC_METHODS_MAX; i++) { + rkisp1_write(params->rkisp1, arg->methods[i].line_thresh, + RKISP1_ISP_DPCC_LINE_THRESH(i)); + rkisp1_write(params->rkisp1, arg->methods[i].line_mad_fac, + RKISP1_ISP_DPCC_LINE_MAD_FAC(i)); + rkisp1_write(params->rkisp1, arg->methods[i].pg_fac, + RKISP1_ISP_DPCC_PG_FAC(i)); + rkisp1_write(params->rkisp1, arg->methods[i].rnd_thresh, + RKISP1_ISP_DPCC_RND_THRESH(i)); + rkisp1_write(params->rkisp1, arg->methods[i].rg_fac, + RKISP1_ISP_DPCC_RG_FAC(i)); + } + + rkisp1_write(params->rkisp1, arg->rnd_offs, + RKISP1_CIF_ISP_DPCC_RND_OFFS); + rkisp1_write(params->rkisp1, arg->ro_limits, + RKISP1_CIF_ISP_DPCC_RO_LIMITS); +} + +/* ISP black level subtraction interface function */ +static void rkisp1_bls_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_bls_config *arg) +{ + /* avoid to override the old enable value */ + u32 new_control; + + new_control = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_BLS_CTRL); + new_control &= RKISP1_CIF_ISP_BLS_ENA; + /* fixed subtraction values */ + if (!arg->enable_auto) { + const struct rkisp1_cif_isp_bls_fixed_val *pval = + &arg->fixed_val; + + switch (params->raw_type) { + case RKISP1_RAW_BGGR: + rkisp1_write(params->rkisp1, + pval->r, RKISP1_CIF_ISP_BLS_D_FIXED); + rkisp1_write(params->rkisp1, + pval->gr, RKISP1_CIF_ISP_BLS_C_FIXED); + rkisp1_write(params->rkisp1, + pval->gb, RKISP1_CIF_ISP_BLS_B_FIXED); + rkisp1_write(params->rkisp1, + pval->b, RKISP1_CIF_ISP_BLS_A_FIXED); + break; + case RKISP1_RAW_GBRG: + rkisp1_write(params->rkisp1, + pval->r, RKISP1_CIF_ISP_BLS_C_FIXED); + rkisp1_write(params->rkisp1, + pval->gr, RKISP1_CIF_ISP_BLS_D_FIXED); + rkisp1_write(params->rkisp1, + pval->gb, RKISP1_CIF_ISP_BLS_A_FIXED); + rkisp1_write(params->rkisp1, + pval->b, RKISP1_CIF_ISP_BLS_B_FIXED); + break; + case RKISP1_RAW_GRBG: + rkisp1_write(params->rkisp1, + pval->r, RKISP1_CIF_ISP_BLS_B_FIXED); + rkisp1_write(params->rkisp1, + pval->gr, RKISP1_CIF_ISP_BLS_A_FIXED); + rkisp1_write(params->rkisp1, + pval->gb, RKISP1_CIF_ISP_BLS_D_FIXED); + rkisp1_write(params->rkisp1, + pval->b, RKISP1_CIF_ISP_BLS_C_FIXED); + break; + case RKISP1_RAW_RGGB: + rkisp1_write(params->rkisp1, + pval->r, RKISP1_CIF_ISP_BLS_A_FIXED); + rkisp1_write(params->rkisp1, + pval->gr, RKISP1_CIF_ISP_BLS_B_FIXED); + rkisp1_write(params->rkisp1, + pval->gb, RKISP1_CIF_ISP_BLS_C_FIXED); + rkisp1_write(params->rkisp1, + pval->b, RKISP1_CIF_ISP_BLS_D_FIXED); + break; + default: + break; + } + + } else { + if (arg->en_windows & BIT(1)) { + rkisp1_write(params->rkisp1, arg->bls_window2.h_offs, + RKISP1_CIF_ISP_BLS_H2_START); + rkisp1_write(params->rkisp1, arg->bls_window2.h_size, + RKISP1_CIF_ISP_BLS_H2_STOP); + rkisp1_write(params->rkisp1, arg->bls_window2.v_offs, + RKISP1_CIF_ISP_BLS_V2_START); + rkisp1_write(params->rkisp1, arg->bls_window2.v_size, + RKISP1_CIF_ISP_BLS_V2_STOP); + new_control |= RKISP1_CIF_ISP_BLS_WINDOW_2; + } + + if (arg->en_windows & BIT(0)) { + rkisp1_write(params->rkisp1, arg->bls_window1.h_offs, + RKISP1_CIF_ISP_BLS_H1_START); + rkisp1_write(params->rkisp1, arg->bls_window1.h_size, + RKISP1_CIF_ISP_BLS_H1_STOP); + rkisp1_write(params->rkisp1, arg->bls_window1.v_offs, + RKISP1_CIF_ISP_BLS_V1_START); + rkisp1_write(params->rkisp1, arg->bls_window1.v_size, + RKISP1_CIF_ISP_BLS_V1_STOP); + new_control |= RKISP1_CIF_ISP_BLS_WINDOW_1; + } + + rkisp1_write(params->rkisp1, arg->bls_samples, + RKISP1_CIF_ISP_BLS_SAMPLES); + + new_control |= RKISP1_CIF_ISP_BLS_MODE_MEASURED; + } + rkisp1_write(params->rkisp1, new_control, RKISP1_CIF_ISP_BLS_CTRL); +} + +/* ISP LS correction interface function */ +static void +rkisp1_lsc_correct_matrix_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_lsc_config *pconfig) +{ + unsigned int isp_lsc_status, sram_addr, isp_lsc_table_sel, i, j, data; + + isp_lsc_status = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_LSC_STATUS); + + /* RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153 = ( 17 * 18 ) >> 1 */ + sram_addr = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ? + RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_0 : + RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153; + rkisp1_write(params->rkisp1, sram_addr, + RKISP1_CIF_ISP_LSC_R_TABLE_ADDR); + rkisp1_write(params->rkisp1, sram_addr, + RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR); + rkisp1_write(params->rkisp1, sram_addr, + RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR); + rkisp1_write(params->rkisp1, sram_addr, + RKISP1_CIF_ISP_LSC_B_TABLE_ADDR); + + /* program data tables (table size is 9 * 17 = 153) */ + for (i = 0; i < RKISP1_CIF_ISP_LSC_SAMPLES_MAX; i++) { + /* + * 17 sectors with 2 values in one DWORD = 9 + * DWORDs (2nd value of last DWORD unused) + */ + for (j = 0; j < RKISP1_CIF_ISP_LSC_SAMPLES_MAX - 1; j += 2) { + data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->r_data_tbl[i][j], + pconfig->r_data_tbl[i][j + 1]); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_R_TABLE_DATA); + + data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->gr_data_tbl[i][j], + pconfig->gr_data_tbl[i][j + 1]); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_GR_TABLE_DATA); + + data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->gb_data_tbl[i][j], + pconfig->gb_data_tbl[i][j + 1]); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_GB_TABLE_DATA); + + data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->b_data_tbl[i][j], + pconfig->b_data_tbl[i][j + 1]); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_B_TABLE_DATA); + } + data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->r_data_tbl[i][j], 0); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_R_TABLE_DATA); + + data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->gr_data_tbl[i][j], 0); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_GR_TABLE_DATA); + + data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->gb_data_tbl[i][j], 0); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_GB_TABLE_DATA); + + data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->b_data_tbl[i][j], 0); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_B_TABLE_DATA); + } + isp_lsc_table_sel = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ? + RKISP1_CIF_ISP_LSC_TABLE_0 : + RKISP1_CIF_ISP_LSC_TABLE_1; + rkisp1_write(params->rkisp1, isp_lsc_table_sel, + RKISP1_CIF_ISP_LSC_TABLE_SEL); +} + +static void rkisp1_lsc_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_lsc_config *arg) +{ + unsigned int i, data; + u32 lsc_ctrl; + + /* To config must be off , store the current status firstly */ + lsc_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_LSC_CTRL); + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_LSC_CTRL, + RKISP1_CIF_ISP_LSC_CTRL_ENA); + rkisp1_lsc_correct_matrix_config(params, arg); + + for (i = 0; i < RKISP1_CIF_ISP_LSC_SECTORS_TBL_SIZE / 2; i++) { + /* program x size tables */ + data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->x_size_tbl[i * 2], + arg->x_size_tbl[i * 2 + 1]); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_XSIZE_01 + i * 4); + + /* program x grad tables */ + data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->x_grad_tbl[i * 2], + arg->x_grad_tbl[i * 2 + 1]); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_XGRAD_01 + i * 4); + + /* program y size tables */ + data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->y_size_tbl[i * 2], + arg->y_size_tbl[i * 2 + 1]); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_YSIZE_01 + i * 4); + + /* program y grad tables */ + data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->y_grad_tbl[i * 2], + arg->y_grad_tbl[i * 2 + 1]); + rkisp1_write(params->rkisp1, data, + RKISP1_CIF_ISP_LSC_YGRAD_01 + i * 4); + } + + /* restore the lsc ctrl status */ + if (lsc_ctrl & RKISP1_CIF_ISP_LSC_CTRL_ENA) { + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_LSC_CTRL, + RKISP1_CIF_ISP_LSC_CTRL_ENA); + } else { + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_LSC_CTRL, + RKISP1_CIF_ISP_LSC_CTRL_ENA); + } +} + +/* ISP Filtering function */ +static void rkisp1_flt_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_flt_config *arg) +{ + u32 filt_mode; + + rkisp1_write(params->rkisp1, + arg->thresh_bl0, RKISP1_CIF_ISP_FILT_THRESH_BL0); + rkisp1_write(params->rkisp1, + arg->thresh_bl1, RKISP1_CIF_ISP_FILT_THRESH_BL1); + rkisp1_write(params->rkisp1, + arg->thresh_sh0, RKISP1_CIF_ISP_FILT_THRESH_SH0); + rkisp1_write(params->rkisp1, + arg->thresh_sh1, RKISP1_CIF_ISP_FILT_THRESH_SH1); + rkisp1_write(params->rkisp1, arg->fac_bl0, RKISP1_CIF_ISP_FILT_FAC_BL0); + rkisp1_write(params->rkisp1, arg->fac_bl1, RKISP1_CIF_ISP_FILT_FAC_BL1); + rkisp1_write(params->rkisp1, arg->fac_mid, RKISP1_CIF_ISP_FILT_FAC_MID); + rkisp1_write(params->rkisp1, arg->fac_sh0, RKISP1_CIF_ISP_FILT_FAC_SH0); + rkisp1_write(params->rkisp1, arg->fac_sh1, RKISP1_CIF_ISP_FILT_FAC_SH1); + rkisp1_write(params->rkisp1, + arg->lum_weight, RKISP1_CIF_ISP_FILT_LUM_WEIGHT); + + rkisp1_write(params->rkisp1, + (arg->mode ? RKISP1_CIF_ISP_FLT_MODE_DNR : 0) | + RKISP1_CIF_ISP_FLT_CHROMA_V_MODE(arg->chr_v_mode) | + RKISP1_CIF_ISP_FLT_CHROMA_H_MODE(arg->chr_h_mode) | + RKISP1_CIF_ISP_FLT_GREEN_STAGE1(arg->grn_stage1), + RKISP1_CIF_ISP_FILT_MODE); + + /* avoid to override the old enable value */ + filt_mode = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_FILT_MODE); + filt_mode &= RKISP1_CIF_ISP_FLT_ENA; + if (arg->mode) + filt_mode |= RKISP1_CIF_ISP_FLT_MODE_DNR; + filt_mode |= RKISP1_CIF_ISP_FLT_CHROMA_V_MODE(arg->chr_v_mode) | + RKISP1_CIF_ISP_FLT_CHROMA_H_MODE(arg->chr_h_mode) | + RKISP1_CIF_ISP_FLT_GREEN_STAGE1(arg->grn_stage1); + rkisp1_write(params->rkisp1, filt_mode, RKISP1_CIF_ISP_FILT_MODE); +} + +/* ISP demosaic interface function */ +static int rkisp1_bdm_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_bdm_config *arg) +{ + u32 bdm_th; + + /* avoid to override the old enable value */ + bdm_th = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_DEMOSAIC); + bdm_th &= RKISP1_CIF_ISP_DEMOSAIC_BYPASS; + bdm_th |= arg->demosaic_th & ~RKISP1_CIF_ISP_DEMOSAIC_BYPASS; + /* set demosaic threshold */ + rkisp1_write(params->rkisp1, bdm_th, RKISP1_CIF_ISP_DEMOSAIC); + return 0; +} + +/* ISP GAMMA correction interface function */ +static void rkisp1_sdg_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_sdg_config *arg) +{ + unsigned int i; + + rkisp1_write(params->rkisp1, + arg->xa_pnts.gamma_dx0, RKISP1_CIF_ISP_GAMMA_DX_LO); + rkisp1_write(params->rkisp1, + arg->xa_pnts.gamma_dx1, RKISP1_CIF_ISP_GAMMA_DX_HI); + + for (i = 0; i < RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE; i++) { + rkisp1_write(params->rkisp1, arg->curve_r.gamma_y[i], + RKISP1_CIF_ISP_GAMMA_R_Y0 + i * 4); + rkisp1_write(params->rkisp1, arg->curve_g.gamma_y[i], + RKISP1_CIF_ISP_GAMMA_G_Y0 + i * 4); + rkisp1_write(params->rkisp1, arg->curve_b.gamma_y[i], + RKISP1_CIF_ISP_GAMMA_B_Y0 + i * 4); + } +} + +/* ISP GAMMA correction interface function */ +static void rkisp1_goc_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_goc_config *arg) +{ + unsigned int i; + + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); + rkisp1_write(params->rkisp1, arg->mode, RKISP1_CIF_ISP_GAMMA_OUT_MODE); + + for (i = 0; i < RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES; i++) + rkisp1_write(params->rkisp1, arg->gamma_y[i], + RKISP1_CIF_ISP_GAMMA_OUT_Y_0 + i * 4); +} + +/* ISP Cross Talk */ +static void rkisp1_ctk_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_ctk_config *arg) +{ + unsigned int i, j, k = 0; + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + rkisp1_write(params->rkisp1, arg->coeff[i][j], + RKISP1_CIF_ISP_CT_COEFF_0 + 4 * k++); + for (i = 0; i < 3; i++) + rkisp1_write(params->rkisp1, arg->ct_offset[i], + RKISP1_CIF_ISP_CT_OFFSET_R + i * 4); +} + +static void rkisp1_ctk_enable(struct rkisp1_params *params, bool en) +{ + if (en) + return; + + /* Write back the default values. */ + rkisp1_write(params->rkisp1, 0x80, RKISP1_CIF_ISP_CT_COEFF_0); + rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_1); + rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_2); + rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_3); + rkisp1_write(params->rkisp1, 0x80, RKISP1_CIF_ISP_CT_COEFF_4); + rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_5); + rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_6); + rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_7); + rkisp1_write(params->rkisp1, 0x80, RKISP1_CIF_ISP_CT_COEFF_8); + + rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_OFFSET_R); + rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_OFFSET_G); + rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_OFFSET_B); +} + +/* ISP White Balance Mode */ +static void rkisp1_awb_meas_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_awb_meas_config *arg) +{ + u32 reg_val = 0; + /* based on the mode,configure the awb module */ + if (arg->awb_mode == RKISP1_CIF_ISP_AWB_MODE_YCBCR) { + /* Reference Cb and Cr */ + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_AWB_REF_CR_SET(arg->awb_ref_cr) | + arg->awb_ref_cb, RKISP1_CIF_ISP_AWB_REF); + /* Yc Threshold */ + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_AWB_MAX_Y_SET(arg->max_y) | + RKISP1_CIF_ISP_AWB_MIN_Y_SET(arg->min_y) | + RKISP1_CIF_ISP_AWB_MAX_CS_SET(arg->max_csum) | + arg->min_c, RKISP1_CIF_ISP_AWB_THRESH); + } + + reg_val = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP); + if (arg->enable_ymax_cmp) + reg_val |= RKISP1_CIF_ISP_AWB_YMAX_CMP_EN; + else + reg_val &= ~RKISP1_CIF_ISP_AWB_YMAX_CMP_EN; + rkisp1_write(params->rkisp1, reg_val, RKISP1_CIF_ISP_AWB_PROP); + + /* window offset */ + rkisp1_write(params->rkisp1, + arg->awb_wnd.v_offs, RKISP1_CIF_ISP_AWB_WND_V_OFFS); + rkisp1_write(params->rkisp1, + arg->awb_wnd.h_offs, RKISP1_CIF_ISP_AWB_WND_H_OFFS); + /* AWB window size */ + rkisp1_write(params->rkisp1, + arg->awb_wnd.v_size, RKISP1_CIF_ISP_AWB_WND_V_SIZE); + rkisp1_write(params->rkisp1, + arg->awb_wnd.h_size, RKISP1_CIF_ISP_AWB_WND_H_SIZE); + /* Number of frames */ + rkisp1_write(params->rkisp1, + arg->frames, RKISP1_CIF_ISP_AWB_FRAMES); +} + +static void +rkisp1_awb_meas_enable(struct rkisp1_params *params, + const struct rkisp1_cif_isp_awb_meas_config *arg, + bool en) +{ + u32 reg_val = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP); + + /* switch off */ + reg_val &= RKISP1_CIF_ISP_AWB_MODE_MASK_NONE; + + if (en) { + if (arg->awb_mode == RKISP1_CIF_ISP_AWB_MODE_RGB) + reg_val |= RKISP1_CIF_ISP_AWB_MODE_RGB_EN; + else + reg_val |= RKISP1_CIF_ISP_AWB_MODE_YCBCR_EN; + + rkisp1_write(params->rkisp1, reg_val, RKISP1_CIF_ISP_AWB_PROP); + + /* Measurements require AWB block be active. */ + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); + } else { + rkisp1_write(params->rkisp1, + reg_val, RKISP1_CIF_ISP_AWB_PROP); + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); + } +} + +static void +rkisp1_awb_gain_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_awb_gain_config *arg) +{ + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_green_r) | + arg->gain_green_b, RKISP1_CIF_ISP_AWB_GAIN_G); + + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_red) | + arg->gain_blue, RKISP1_CIF_ISP_AWB_GAIN_RB); +} + +static void rkisp1_aec_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_aec_config *arg) +{ + unsigned int block_hsize, block_vsize; + u32 exp_ctrl; + + /* avoid to override the old enable value */ + exp_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_EXP_CTRL); + exp_ctrl &= RKISP1_CIF_ISP_EXP_ENA; + if (arg->autostop) + exp_ctrl |= RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP; + if (arg->mode == RKISP1_CIF_ISP_EXP_MEASURING_MODE_1) + exp_ctrl |= RKISP1_CIF_ISP_EXP_CTRL_MEASMODE_1; + rkisp1_write(params->rkisp1, exp_ctrl, RKISP1_CIF_ISP_EXP_CTRL); + + rkisp1_write(params->rkisp1, + arg->meas_window.h_offs, RKISP1_CIF_ISP_EXP_H_OFFSET); + rkisp1_write(params->rkisp1, + arg->meas_window.v_offs, RKISP1_CIF_ISP_EXP_V_OFFSET); + + block_hsize = arg->meas_window.h_size / + RKISP1_CIF_ISP_EXP_COLUMN_NUM - 1; + block_vsize = arg->meas_window.v_size / + RKISP1_CIF_ISP_EXP_ROW_NUM - 1; + + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_EXP_H_SIZE_SET(block_hsize), + RKISP1_CIF_ISP_EXP_H_SIZE); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_EXP_V_SIZE_SET(block_vsize), + RKISP1_CIF_ISP_EXP_V_SIZE); +} + +static void rkisp1_cproc_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_cproc_config *arg) +{ + struct rkisp1_cif_isp_isp_other_cfg *cur_other_cfg = + container_of(arg, struct rkisp1_cif_isp_isp_other_cfg, cproc_config); + struct rkisp1_cif_isp_ie_config *cur_ie_config = + &cur_other_cfg->ie_config; + u32 effect = cur_ie_config->effect; + u32 quantization = params->quantization; + + rkisp1_write(params->rkisp1, arg->contrast, RKISP1_CIF_C_PROC_CONTRAST); + rkisp1_write(params->rkisp1, arg->hue, RKISP1_CIF_C_PROC_HUE); + rkisp1_write(params->rkisp1, arg->sat, RKISP1_CIF_C_PROC_SATURATION); + rkisp1_write(params->rkisp1, arg->brightness, + RKISP1_CIF_C_PROC_BRIGHTNESS); + + if (quantization != V4L2_QUANTIZATION_FULL_RANGE || + effect != V4L2_COLORFX_NONE) { + rkisp1_param_clear_bits(params, RKISP1_CIF_C_PROC_CTRL, + RKISP1_CIF_C_PROC_YOUT_FULL | + RKISP1_CIF_C_PROC_YIN_FULL | + RKISP1_CIF_C_PROC_COUT_FULL); + } else { + rkisp1_param_set_bits(params, RKISP1_CIF_C_PROC_CTRL, + RKISP1_CIF_C_PROC_YOUT_FULL | + RKISP1_CIF_C_PROC_YIN_FULL | + RKISP1_CIF_C_PROC_COUT_FULL); + } +} + +static void rkisp1_hst_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_hst_config *arg) +{ + unsigned int block_hsize, block_vsize; + static const u32 hist_weight_regs[] = { + RKISP1_CIF_ISP_HIST_WEIGHT_00TO30, + RKISP1_CIF_ISP_HIST_WEIGHT_40TO21, + RKISP1_CIF_ISP_HIST_WEIGHT_31TO12, + RKISP1_CIF_ISP_HIST_WEIGHT_22TO03, + RKISP1_CIF_ISP_HIST_WEIGHT_13TO43, + RKISP1_CIF_ISP_HIST_WEIGHT_04TO34, + RKISP1_CIF_ISP_HIST_WEIGHT_44, + }; + const u8 *weight; + unsigned int i; + u32 hist_prop; + + /* avoid to override the old enable value */ + hist_prop = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_HIST_PROP); + hist_prop &= RKISP1_CIF_ISP_HIST_PROP_MODE_MASK; + hist_prop |= RKISP1_CIF_ISP_HIST_PREDIV_SET(arg->histogram_predivider); + rkisp1_write(params->rkisp1, hist_prop, RKISP1_CIF_ISP_HIST_PROP); + rkisp1_write(params->rkisp1, + arg->meas_window.h_offs, + RKISP1_CIF_ISP_HIST_H_OFFS); + rkisp1_write(params->rkisp1, + arg->meas_window.v_offs, + RKISP1_CIF_ISP_HIST_V_OFFS); + + block_hsize = arg->meas_window.h_size / + RKISP1_CIF_ISP_HIST_COLUMN_NUM - 1; + block_vsize = arg->meas_window.v_size / RKISP1_CIF_ISP_HIST_ROW_NUM - 1; + + rkisp1_write(params->rkisp1, block_hsize, RKISP1_CIF_ISP_HIST_H_SIZE); + rkisp1_write(params->rkisp1, block_vsize, RKISP1_CIF_ISP_HIST_V_SIZE); + + weight = arg->hist_weight; + for (i = 0; i < ARRAY_SIZE(hist_weight_regs); ++i, weight += 4) + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_HIST_WEIGHT_SET(weight[0], + weight[1], + weight[2], + weight[3]), + hist_weight_regs[i]); +} + +static void +rkisp1_hst_enable(struct rkisp1_params *params, + const struct rkisp1_cif_isp_hst_config *arg, bool en) +{ + if (en) { + u32 hist_prop = rkisp1_read(params->rkisp1, + RKISP1_CIF_ISP_HIST_PROP); + + hist_prop &= ~RKISP1_CIF_ISP_HIST_PROP_MODE_MASK; + hist_prop |= arg->mode; + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_HIST_PROP, + hist_prop); + } else { + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_HIST_PROP, + RKISP1_CIF_ISP_HIST_PROP_MODE_MASK); + } +} + +static void rkisp1_afm_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_afc_config *arg) +{ + size_t num_of_win = min_t(size_t, ARRAY_SIZE(arg->afm_win), + arg->num_afm_win); + u32 afm_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AFM_CTRL); + unsigned int i; + + /* Switch off to configure. */ + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_AFM_CTRL, + RKISP1_CIF_ISP_AFM_ENA); + + for (i = 0; i < num_of_win; i++) { + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_AFM_WINDOW_X(arg->afm_win[i].h_offs) | + RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_offs), + RKISP1_CIF_ISP_AFM_LT_A + i * 8); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_AFM_WINDOW_X(arg->afm_win[i].h_size + + arg->afm_win[i].h_offs) | + RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_size + + arg->afm_win[i].v_offs), + RKISP1_CIF_ISP_AFM_RB_A + i * 8); + } + rkisp1_write(params->rkisp1, arg->thres, RKISP1_CIF_ISP_AFM_THRES); + rkisp1_write(params->rkisp1, arg->var_shift, + RKISP1_CIF_ISP_AFM_VAR_SHIFT); + /* restore afm status */ + rkisp1_write(params->rkisp1, afm_ctrl, RKISP1_CIF_ISP_AFM_CTRL); +} + +static void rkisp1_ie_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_ie_config *arg) +{ + u32 eff_ctrl; + + eff_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_IMG_EFF_CTRL); + eff_ctrl &= ~RKISP1_CIF_IMG_EFF_CTRL_MODE_MASK; + + if (params->quantization == V4L2_QUANTIZATION_FULL_RANGE) + eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_YCBCR_FULL; + + switch (arg->effect) { + case V4L2_COLORFX_SEPIA: + eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_SEPIA; + break; + case V4L2_COLORFX_SET_CBCR: + rkisp1_write(params->rkisp1, arg->eff_tint, + RKISP1_CIF_IMG_EFF_TINT); + eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_SEPIA; + break; + /* + * Color selection is similar to water color(AQUA): + * grayscale + selected color w threshold + */ + case V4L2_COLORFX_AQUA: + eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_COLOR_SEL; + rkisp1_write(params->rkisp1, arg->color_sel, + RKISP1_CIF_IMG_EFF_COLOR_SEL); + break; + case V4L2_COLORFX_EMBOSS: + eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_EMBOSS; + rkisp1_write(params->rkisp1, arg->eff_mat_1, + RKISP1_CIF_IMG_EFF_MAT_1); + rkisp1_write(params->rkisp1, arg->eff_mat_2, + RKISP1_CIF_IMG_EFF_MAT_2); + rkisp1_write(params->rkisp1, arg->eff_mat_3, + RKISP1_CIF_IMG_EFF_MAT_3); + break; + case V4L2_COLORFX_SKETCH: + eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_SKETCH; + rkisp1_write(params->rkisp1, arg->eff_mat_3, + RKISP1_CIF_IMG_EFF_MAT_3); + rkisp1_write(params->rkisp1, arg->eff_mat_4, + RKISP1_CIF_IMG_EFF_MAT_4); + rkisp1_write(params->rkisp1, arg->eff_mat_5, + RKISP1_CIF_IMG_EFF_MAT_5); + break; + case V4L2_COLORFX_BW: + eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_BLACKWHITE; + break; + case V4L2_COLORFX_NEGATIVE: + eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_NEGATIVE; + break; + default: + break; + } + + rkisp1_write(params->rkisp1, eff_ctrl, RKISP1_CIF_IMG_EFF_CTRL); +} + +static void rkisp1_ie_enable(struct rkisp1_params *params, bool en) +{ + if (en) { + rkisp1_param_set_bits(params, RKISP1_CIF_ICCL, + RKISP1_CIF_ICCL_IE_CLK); + rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_CTRL_ENABLE, + RKISP1_CIF_IMG_EFF_CTRL); + rkisp1_param_set_bits(params, RKISP1_CIF_IMG_EFF_CTRL, + RKISP1_CIF_IMG_EFF_CTRL_CFG_UPD); + } else { + rkisp1_param_clear_bits(params, RKISP1_CIF_IMG_EFF_CTRL, + RKISP1_CIF_IMG_EFF_CTRL_ENABLE); + rkisp1_param_clear_bits(params, RKISP1_CIF_ICCL, + RKISP1_CIF_ICCL_IE_CLK); + } +} + +static void rkisp1_csm_config(struct rkisp1_params *params, bool full_range) +{ + static const u16 full_range_coeff[] = { + 0x0026, 0x004b, 0x000f, + 0x01ea, 0x01d6, 0x0040, + 0x0040, 0x01ca, 0x01f6 + }; + static const u16 limited_range_coeff[] = { + 0x0021, 0x0040, 0x000d, + 0x01ed, 0x01db, 0x0038, + 0x0038, 0x01d1, 0x01f7, + }; + unsigned int i; + + if (full_range) { + for (i = 0; i < ARRAY_SIZE(full_range_coeff); i++) + rkisp1_write(params->rkisp1, full_range_coeff[i], + RKISP1_CIF_ISP_CC_COEFF_0 + i * 4); + + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA | + RKISP1_CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA); + } else { + for (i = 0; i < ARRAY_SIZE(limited_range_coeff); i++) + rkisp1_write(params->rkisp1, limited_range_coeff[i], + RKISP1_CIF_ISP_CC_COEFF_0 + i * 4); + + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA | + RKISP1_CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA); + } +} + +/* ISP De-noise Pre-Filter(DPF) function */ +static void rkisp1_dpf_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_dpf_config *arg) +{ + unsigned int isp_dpf_mode, spatial_coeff, i; + + switch (arg->gain.mode) { + case RKISP1_CIF_ISP_DPF_GAIN_USAGE_NF_GAINS: + isp_dpf_mode = RKISP1_CIF_ISP_DPF_MODE_USE_NF_GAIN | + RKISP1_CIF_ISP_DPF_MODE_AWB_GAIN_COMP; + break; + case RKISP1_CIF_ISP_DPF_GAIN_USAGE_LSC_GAINS: + isp_dpf_mode = RKISP1_CIF_ISP_DPF_MODE_LSC_GAIN_COMP; + break; + case RKISP1_CIF_ISP_DPF_GAIN_USAGE_NF_LSC_GAINS: + isp_dpf_mode = RKISP1_CIF_ISP_DPF_MODE_USE_NF_GAIN | + RKISP1_CIF_ISP_DPF_MODE_AWB_GAIN_COMP | + RKISP1_CIF_ISP_DPF_MODE_LSC_GAIN_COMP; + break; + case RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_GAINS: + isp_dpf_mode = RKISP1_CIF_ISP_DPF_MODE_AWB_GAIN_COMP; + break; + case RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_LSC_GAINS: + isp_dpf_mode = RKISP1_CIF_ISP_DPF_MODE_LSC_GAIN_COMP | + RKISP1_CIF_ISP_DPF_MODE_AWB_GAIN_COMP; + break; + case RKISP1_CIF_ISP_DPF_GAIN_USAGE_DISABLED: + default: + isp_dpf_mode = 0; + break; + } + + if (arg->nll.scale_mode == RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC) + isp_dpf_mode |= RKISP1_CIF_ISP_DPF_MODE_NLL_SEGMENTATION; + if (arg->rb_flt.fltsize == RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_9x9) + isp_dpf_mode |= RKISP1_CIF_ISP_DPF_MODE_RB_FLTSIZE_9x9; + if (!arg->rb_flt.r_enable) + isp_dpf_mode |= RKISP1_CIF_ISP_DPF_MODE_R_FLT_DIS; + if (!arg->rb_flt.b_enable) + isp_dpf_mode |= RKISP1_CIF_ISP_DPF_MODE_B_FLT_DIS; + if (!arg->g_flt.gb_enable) + isp_dpf_mode |= RKISP1_CIF_ISP_DPF_MODE_GB_FLT_DIS; + if (!arg->g_flt.gr_enable) + isp_dpf_mode |= RKISP1_CIF_ISP_DPF_MODE_GR_FLT_DIS; + + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_DPF_MODE, + isp_dpf_mode); + rkisp1_write(params->rkisp1, arg->gain.nf_b_gain, + RKISP1_CIF_ISP_DPF_NF_GAIN_B); + rkisp1_write(params->rkisp1, arg->gain.nf_r_gain, + RKISP1_CIF_ISP_DPF_NF_GAIN_R); + rkisp1_write(params->rkisp1, arg->gain.nf_gb_gain, + RKISP1_CIF_ISP_DPF_NF_GAIN_GB); + rkisp1_write(params->rkisp1, arg->gain.nf_gr_gain, + RKISP1_CIF_ISP_DPF_NF_GAIN_GR); + + for (i = 0; i < RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS; i++) { + rkisp1_write(params->rkisp1, arg->nll.coeff[i], + RKISP1_CIF_ISP_DPF_NULL_COEFF_0 + i * 4); + } + + spatial_coeff = arg->g_flt.spatial_coeff[0] | + (arg->g_flt.spatial_coeff[1] << 8) | + (arg->g_flt.spatial_coeff[2] << 16) | + (arg->g_flt.spatial_coeff[3] << 24); + rkisp1_write(params->rkisp1, spatial_coeff, + RKISP1_CIF_ISP_DPF_S_WEIGHT_G_1_4); + + spatial_coeff = arg->g_flt.spatial_coeff[4] | + (arg->g_flt.spatial_coeff[5] << 8); + rkisp1_write(params->rkisp1, spatial_coeff, + RKISP1_CIF_ISP_DPF_S_WEIGHT_G_5_6); + + spatial_coeff = arg->rb_flt.spatial_coeff[0] | + (arg->rb_flt.spatial_coeff[1] << 8) | + (arg->rb_flt.spatial_coeff[2] << 16) | + (arg->rb_flt.spatial_coeff[3] << 24); + rkisp1_write(params->rkisp1, spatial_coeff, + RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_1_4); + + spatial_coeff = arg->rb_flt.spatial_coeff[4] | + (arg->rb_flt.spatial_coeff[5] << 8); + rkisp1_write(params->rkisp1, spatial_coeff, + RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_5_6); +} + +static void +rkisp1_dpf_strength_config(struct rkisp1_params *params, + const struct rkisp1_cif_isp_dpf_strength_config *arg) +{ + rkisp1_write(params->rkisp1, arg->b, RKISP1_CIF_ISP_DPF_STRENGTH_B); + rkisp1_write(params->rkisp1, arg->g, RKISP1_CIF_ISP_DPF_STRENGTH_G); + rkisp1_write(params->rkisp1, arg->r, RKISP1_CIF_ISP_DPF_STRENGTH_R); +} + +static void +rkisp1_isp_isr_other_config(struct rkisp1_params *params, + const struct rkisp1_params_cfg *new_params) +{ + unsigned int module_en_update, module_cfg_update, module_ens; + + module_en_update = new_params->module_en_update; + module_cfg_update = new_params->module_cfg_update; + module_ens = new_params->module_ens; + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_DPCC) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_DPCC)) { + /*update dpc config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_DPCC) + rkisp1_dpcc_config(params, + &new_params->others.dpcc_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_DPCC) { + if (module_ens & RKISP1_CIF_ISP_MODULE_DPCC) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_DPCC_MODE, + RKISP1_CIF_ISP_DPCC_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_DPCC_MODE, + RKISP1_CIF_ISP_DPCC_ENA); + } + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_BLS) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_BLS)) { + /* update bls config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_BLS) + rkisp1_bls_config(params, + &new_params->others.bls_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_BLS) { + if (module_ens & RKISP1_CIF_ISP_MODULE_BLS) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_BLS_CTRL, + RKISP1_CIF_ISP_BLS_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_BLS_CTRL, + RKISP1_CIF_ISP_BLS_ENA); + } + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_SDG) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_SDG)) { + /* update sdg config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_SDG) + rkisp1_sdg_config(params, + &new_params->others.sdg_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_SDG) { + if (module_ens & RKISP1_CIF_ISP_MODULE_SDG) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_GAMMA_IN_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_GAMMA_IN_ENA); + } + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_LSC) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_LSC)) { + /* update lsc config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_LSC) + rkisp1_lsc_config(params, + &new_params->others.lsc_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_LSC) { + if (module_ens & RKISP1_CIF_ISP_MODULE_LSC) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_LSC_CTRL, + RKISP1_CIF_ISP_LSC_CTRL_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_LSC_CTRL, + RKISP1_CIF_ISP_LSC_CTRL_ENA); + } + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN)) { + /* update awb gains */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN) + rkisp1_awb_gain_config(params, + &new_params->others.awb_gain_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN) { + if (module_ens & RKISP1_CIF_ISP_MODULE_AWB_GAIN) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); + } + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_BDM) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_BDM)) { + /* update bdm config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_BDM) + rkisp1_bdm_config(params, + &new_params->others.bdm_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_BDM) { + if (module_ens & RKISP1_CIF_ISP_MODULE_BDM) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_DEMOSAIC, + RKISP1_CIF_ISP_DEMOSAIC_BYPASS); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_DEMOSAIC, + RKISP1_CIF_ISP_DEMOSAIC_BYPASS); + } + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_FLT) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_FLT)) { + /* update filter config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_FLT) + rkisp1_flt_config(params, + &new_params->others.flt_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_FLT) { + if (module_ens & RKISP1_CIF_ISP_MODULE_FLT) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_FILT_MODE, + RKISP1_CIF_ISP_FLT_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_FILT_MODE, + RKISP1_CIF_ISP_FLT_ENA); + } + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_CTK) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_CTK)) { + /* update ctk config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_CTK) + rkisp1_ctk_config(params, + &new_params->others.ctk_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_CTK) + rkisp1_ctk_enable(params, + !!(module_ens & RKISP1_CIF_ISP_MODULE_CTK)); + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_GOC) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_GOC)) { + /* update goc config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_GOC) + rkisp1_goc_config(params, + &new_params->others.goc_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_GOC) { + if (module_ens & RKISP1_CIF_ISP_MODULE_GOC) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); + } + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_CPROC) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_CPROC)) { + /* update cproc config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_CPROC) { + rkisp1_cproc_config(params, + &new_params->others.cproc_config); + } + + if (module_en_update & RKISP1_CIF_ISP_MODULE_CPROC) { + if (module_ens & RKISP1_CIF_ISP_MODULE_CPROC) + rkisp1_param_set_bits(params, + RKISP1_CIF_C_PROC_CTRL, + RKISP1_CIF_C_PROC_CTR_ENABLE); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_C_PROC_CTRL, + RKISP1_CIF_C_PROC_CTR_ENABLE); + } + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_IE) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_IE)) { + /* update ie config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_IE) + rkisp1_ie_config(params, + &new_params->others.ie_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_IE) + rkisp1_ie_enable(params, + !!(module_ens & RKISP1_CIF_ISP_MODULE_IE)); + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_DPF) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_DPF)) { + /* update dpf config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_DPF) + rkisp1_dpf_config(params, + &new_params->others.dpf_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_DPF) { + if (module_ens & RKISP1_CIF_ISP_MODULE_DPF) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_DPF_MODE, + RKISP1_CIF_ISP_DPF_MODE_EN); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_DPF_MODE, + RKISP1_CIF_ISP_DPF_MODE_EN); + } + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_DPF_STRENGTH) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_DPF_STRENGTH)) { + /* update dpf strength config */ + rkisp1_dpf_strength_config(params, + &new_params->others.dpf_strength_config); + } +} + +static void rkisp1_isp_isr_meas_config(struct rkisp1_params *params, + struct rkisp1_params_cfg *new_params) +{ + unsigned int module_en_update, module_cfg_update, module_ens; + + module_en_update = new_params->module_en_update; + module_cfg_update = new_params->module_cfg_update; + module_ens = new_params->module_ens; + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_AWB) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB)) { + /* update awb config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB) + rkisp1_awb_meas_config(params, + &new_params->meas.awb_meas_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_AWB) + rkisp1_awb_meas_enable(params, + &new_params->meas.awb_meas_config, + !!(module_ens & RKISP1_CIF_ISP_MODULE_AWB)); + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_AFC) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_AFC)) { + /* update afc config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AFC) + rkisp1_afm_config(params, + &new_params->meas.afc_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_AFC) { + if (module_ens & RKISP1_CIF_ISP_MODULE_AFC) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_AFM_CTRL, + RKISP1_CIF_ISP_AFM_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_AFM_CTRL, + RKISP1_CIF_ISP_AFM_ENA); + } + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_HST) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_HST)) { + /* update hst config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_HST) + rkisp1_hst_config(params, + &new_params->meas.hst_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_HST) + rkisp1_hst_enable(params, + &new_params->meas.hst_config, + !!(module_ens & RKISP1_CIF_ISP_MODULE_HST)); + } + + if ((module_en_update & RKISP1_CIF_ISP_MODULE_AEC) || + (module_cfg_update & RKISP1_CIF_ISP_MODULE_AEC)) { + /* update aec config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AEC) + rkisp1_aec_config(params, + &new_params->meas.aec_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_AEC) { + if (module_ens & RKISP1_CIF_ISP_MODULE_AEC) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_EXP_CTRL, + RKISP1_CIF_ISP_EXP_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_EXP_CTRL, + RKISP1_CIF_ISP_EXP_ENA); + } + } +} + +static void rkisp1_params_apply_params_cfg(struct rkisp1_params *params, + unsigned int frame_sequence) +{ + struct rkisp1_params_cfg *new_params; + struct rkisp1_buffer *cur_buf = NULL; + + if (list_empty(¶ms->params)) + return; + + cur_buf = list_first_entry(¶ms->params, + struct rkisp1_buffer, queue); + + new_params = (struct rkisp1_params_cfg *)(cur_buf->vaddr); + + rkisp1_isp_isr_other_config(params, new_params); + rkisp1_isp_isr_meas_config(params, new_params); + + /* update shadow register immediately */ + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD); + + list_del(&cur_buf->queue); + + cur_buf->vb.sequence = frame_sequence; + vb2_buffer_done(&cur_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); +} + +void rkisp1_params_isr(struct rkisp1_device *rkisp1) +{ + /* + * This isr is called when the ISR finishes processing a frame (RKISP1_CIF_ISP_FRAME). + * Configurations performed here will be applied on the next frame. + * Since frame_sequence is updated on the vertical sync signal, we should use + * frame_sequence + 1 here to indicate to userspace on which frame these parameters + * are being applied. + */ + unsigned int frame_sequence = rkisp1->isp.frame_sequence + 1; + struct rkisp1_params *params = &rkisp1->params; + + spin_lock(¶ms->config_lock); + rkisp1_params_apply_params_cfg(params, frame_sequence); + + spin_unlock(¶ms->config_lock); +} + +static const struct rkisp1_cif_isp_awb_meas_config rkisp1_awb_params_default_config = { + { + 0, 0, RKISP1_DEFAULT_WIDTH, RKISP1_DEFAULT_HEIGHT + }, + RKISP1_CIF_ISP_AWB_MODE_YCBCR, 200, 30, 20, 20, 0, 128, 128 +}; + +static const struct rkisp1_cif_isp_aec_config rkisp1_aec_params_default_config = { + RKISP1_CIF_ISP_EXP_MEASURING_MODE_0, + RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP_0, + { + RKISP1_DEFAULT_WIDTH >> 2, RKISP1_DEFAULT_HEIGHT >> 2, + RKISP1_DEFAULT_WIDTH >> 1, RKISP1_DEFAULT_HEIGHT >> 1 + } +}; + +static const struct rkisp1_cif_isp_hst_config rkisp1_hst_params_default_config = { + RKISP1_CIF_ISP_HISTOGRAM_MODE_RGB_COMBINED, + 3, + { + RKISP1_DEFAULT_WIDTH >> 2, RKISP1_DEFAULT_HEIGHT >> 2, + RKISP1_DEFAULT_WIDTH >> 1, RKISP1_DEFAULT_HEIGHT >> 1 + }, + { + 0, /* To be filled in with 0x01 at runtime. */ + } +}; + +static const struct rkisp1_cif_isp_afc_config rkisp1_afc_params_default_config = { + 1, + { + { + 300, 225, 200, 150 + } + }, + 4, + 14 +}; + +static void rkisp1_params_config_parameter(struct rkisp1_params *params) +{ + struct rkisp1_cif_isp_hst_config hst = rkisp1_hst_params_default_config; + + rkisp1_awb_meas_config(params, &rkisp1_awb_params_default_config); + rkisp1_awb_meas_enable(params, &rkisp1_awb_params_default_config, + true); + + rkisp1_aec_config(params, &rkisp1_aec_params_default_config); + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_EXP_CTRL, + RKISP1_CIF_ISP_EXP_ENA); + + rkisp1_afm_config(params, &rkisp1_afc_params_default_config); + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_AFM_CTRL, + RKISP1_CIF_ISP_AFM_ENA); + + memset(hst.hist_weight, 0x01, sizeof(hst.hist_weight)); + rkisp1_hst_config(params, &hst); + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_HIST_PROP, + ~RKISP1_CIF_ISP_HIST_PROP_MODE_MASK | + rkisp1_hst_params_default_config.mode); + + /* set the range */ + if (params->quantization == V4L2_QUANTIZATION_FULL_RANGE) + rkisp1_csm_config(params, true); + else + rkisp1_csm_config(params, false); + + spin_lock_irq(¶ms->config_lock); + + /* apply the first buffer if there is one already */ + rkisp1_params_apply_params_cfg(params, 0); + + spin_unlock_irq(¶ms->config_lock); +} + +void rkisp1_params_configure(struct rkisp1_params *params, + enum rkisp1_fmt_raw_pat_type bayer_pat, + enum v4l2_quantization quantization) +{ + params->quantization = quantization; + params->raw_type = bayer_pat; + rkisp1_params_config_parameter(params); +} + +/* Not called when the camera active, thus not isr protection. */ +void rkisp1_params_disable(struct rkisp1_params *params) +{ + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_DPCC_MODE, + RKISP1_CIF_ISP_DPCC_ENA); + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_LSC_CTRL, + RKISP1_CIF_ISP_LSC_CTRL_ENA); + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_BLS_CTRL, + RKISP1_CIF_ISP_BLS_ENA); + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_GAMMA_IN_ENA); + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_DEMOSAIC, + RKISP1_CIF_ISP_DEMOSAIC_BYPASS); + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_FILT_MODE, + RKISP1_CIF_ISP_FLT_ENA); + rkisp1_awb_meas_enable(params, NULL, false); + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_EXP_CTRL, + RKISP1_CIF_ISP_EXP_ENA); + rkisp1_ctk_enable(params, false); + rkisp1_param_clear_bits(params, RKISP1_CIF_C_PROC_CTRL, + RKISP1_CIF_C_PROC_CTR_ENABLE); + rkisp1_hst_enable(params, NULL, false); + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_AFM_CTRL, + RKISP1_CIF_ISP_AFM_ENA); + rkisp1_ie_enable(params, false); + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_DPF_MODE, + RKISP1_CIF_ISP_DPF_MODE_EN); +} + +static int rkisp1_params_enum_fmt_meta_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct video_device *video = video_devdata(file); + struct rkisp1_params *params = video_get_drvdata(video); + + if (f->index > 0 || f->type != video->queue->type) + return -EINVAL; + + f->pixelformat = params->vdev_fmt.fmt.meta.dataformat; + + return 0; +} + +static int rkisp1_params_g_fmt_meta_out(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct video_device *video = video_devdata(file); + struct rkisp1_params *params = video_get_drvdata(video); + struct v4l2_meta_format *meta = &f->fmt.meta; + + if (f->type != video->queue->type) + return -EINVAL; + + memset(meta, 0, sizeof(*meta)); + meta->dataformat = params->vdev_fmt.fmt.meta.dataformat; + meta->buffersize = params->vdev_fmt.fmt.meta.buffersize; + + return 0; +} + +static int rkisp1_params_querycap(struct file *file, + void *priv, struct v4l2_capability *cap) +{ + struct video_device *vdev = video_devdata(file); + + strscpy(cap->driver, RKISP1_DRIVER_NAME, sizeof(cap->driver)); + strscpy(cap->card, vdev->name, sizeof(cap->card)); + strscpy(cap->bus_info, RKISP1_BUS_INFO, sizeof(cap->bus_info)); + + return 0; +} + +/* ISP params video device IOCTLs */ +static const struct v4l2_ioctl_ops rkisp1_params_ioctl = { + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_enum_fmt_meta_out = rkisp1_params_enum_fmt_meta_out, + .vidioc_g_fmt_meta_out = rkisp1_params_g_fmt_meta_out, + .vidioc_s_fmt_meta_out = rkisp1_params_g_fmt_meta_out, + .vidioc_try_fmt_meta_out = rkisp1_params_g_fmt_meta_out, + .vidioc_querycap = rkisp1_params_querycap, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static int rkisp1_params_vb2_queue_setup(struct vb2_queue *vq, + unsigned int *num_buffers, + unsigned int *num_planes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + *num_buffers = clamp_t(u32, *num_buffers, + RKISP1_ISP_PARAMS_REQ_BUFS_MIN, + RKISP1_ISP_PARAMS_REQ_BUFS_MAX); + + *num_planes = 1; + + sizes[0] = sizeof(struct rkisp1_params_cfg); + + return 0; +} + +static void rkisp1_params_vb2_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct rkisp1_buffer *params_buf = + container_of(vbuf, struct rkisp1_buffer, vb); + struct vb2_queue *vq = vb->vb2_queue; + struct rkisp1_params *params = vq->drv_priv; + + params_buf->vaddr = vb2_plane_vaddr(vb, 0); + spin_lock_irq(¶ms->config_lock); + list_add_tail(¶ms_buf->queue, ¶ms->params); + spin_unlock_irq(¶ms->config_lock); +} + +static int rkisp1_params_vb2_buf_prepare(struct vb2_buffer *vb) +{ + if (vb2_plane_size(vb, 0) < sizeof(struct rkisp1_params_cfg)) + return -EINVAL; + + vb2_set_plane_payload(vb, 0, sizeof(struct rkisp1_params_cfg)); + + return 0; +} + +static void rkisp1_params_vb2_stop_streaming(struct vb2_queue *vq) +{ + struct rkisp1_params *params = vq->drv_priv; + struct rkisp1_buffer *buf; + LIST_HEAD(tmp_list); + + /* + * we first move the buffers into a local list 'tmp_list' + * and then we can iterate it and call vb2_buffer_done + * without holding the lock + */ + spin_lock_irq(¶ms->config_lock); + list_splice_init(¶ms->params, &tmp_list); + spin_unlock_irq(¶ms->config_lock); + + list_for_each_entry(buf, &tmp_list, queue) + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); +} + +static struct vb2_ops rkisp1_params_vb2_ops = { + .queue_setup = rkisp1_params_vb2_queue_setup, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_queue = rkisp1_params_vb2_buf_queue, + .buf_prepare = rkisp1_params_vb2_buf_prepare, + .stop_streaming = rkisp1_params_vb2_stop_streaming, + +}; + +static struct v4l2_file_operations rkisp1_params_fops = { + .mmap = vb2_fop_mmap, + .unlocked_ioctl = video_ioctl2, + .poll = vb2_fop_poll, + .open = v4l2_fh_open, + .release = vb2_fop_release +}; + +static int rkisp1_params_init_vb2_queue(struct vb2_queue *q, + struct rkisp1_params *params) +{ + struct rkisp1_vdev_node *node; + + node = container_of(q, struct rkisp1_vdev_node, buf_queue); + + q->type = V4L2_BUF_TYPE_META_OUTPUT; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + q->drv_priv = params; + q->ops = &rkisp1_params_vb2_ops; + q->mem_ops = &vb2_vmalloc_memops; + q->buf_struct_size = sizeof(struct rkisp1_buffer); + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &node->vlock; + + return vb2_queue_init(q); +} + +static void rkisp1_init_params(struct rkisp1_params *params) +{ + params->vdev_fmt.fmt.meta.dataformat = + V4L2_META_FMT_RK_ISP1_PARAMS; + params->vdev_fmt.fmt.meta.buffersize = + sizeof(struct rkisp1_params_cfg); +} + +int rkisp1_params_register(struct rkisp1_device *rkisp1) +{ + struct rkisp1_params *params = &rkisp1->params; + struct rkisp1_vdev_node *node = ¶ms->vnode; + struct video_device *vdev = &node->vdev; + int ret; + + params->rkisp1 = rkisp1; + mutex_init(&node->vlock); + INIT_LIST_HEAD(¶ms->params); + spin_lock_init(¶ms->config_lock); + + strscpy(vdev->name, RKISP1_PARAMS_DEV_NAME, sizeof(vdev->name)); + + video_set_drvdata(vdev, params); + vdev->ioctl_ops = &rkisp1_params_ioctl; + vdev->fops = &rkisp1_params_fops; + vdev->release = video_device_release_empty; + /* + * Provide a mutex to v4l2 core. It will be used + * to protect all fops and v4l2 ioctls. + */ + vdev->lock = &node->vlock; + vdev->v4l2_dev = &rkisp1->v4l2_dev; + vdev->queue = &node->buf_queue; + vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_META_OUTPUT; + vdev->vfl_dir = VFL_DIR_TX; + rkisp1_params_init_vb2_queue(vdev->queue, params); + rkisp1_init_params(params); + video_set_drvdata(vdev, params); + + node->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&vdev->entity, 1, &node->pad); + if (ret) + return ret; + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); + if (ret) { + dev_err(rkisp1->dev, + "failed to register %s, ret=%d\n", vdev->name, ret); + goto err_cleanup_media_entity; + } + return 0; +err_cleanup_media_entity: + media_entity_cleanup(&vdev->entity); + return ret; +} + +void rkisp1_params_unregister(struct rkisp1_device *rkisp1) +{ + struct rkisp1_params *params = &rkisp1->params; + struct rkisp1_vdev_node *node = ¶ms->vnode; + struct video_device *vdev = &node->vdev; + + vb2_video_unregister_device(vdev); + media_entity_cleanup(&vdev->entity); +} diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h new file mode 100644 index 000000000000..049f6c3a11df --- /dev/null +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h @@ -0,0 +1,1262 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ +/* + * Rockchip ISP1 Driver - Registers header + * + * Copyright (C) 2017 Rockchip Electronics Co., Ltd. + */ + +#ifndef _RKISP1_REGS_H +#define _RKISP1_REGS_H + +/* ISP_CTRL */ +#define RKISP1_CIF_ISP_CTRL_ISP_ENABLE BIT(0) +#define RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT (0 << 1) +#define RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU656 BIT(1) +#define RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU601 (2 << 1) +#define RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU601 (3 << 1) +#define RKISP1_CIF_ISP_CTRL_ISP_MODE_DATA_MODE (4 << 1) +#define RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU656 (5 << 1) +#define RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT_ITU656 (6 << 1) +#define RKISP1_CIF_ISP_CTRL_ISP_INFORM_ENABLE BIT(4) +#define RKISP1_CIF_ISP_CTRL_ISP_GAMMA_IN_ENA BIT(6) +#define RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA BIT(7) +#define RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD_PERMANENT BIT(8) +#define RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD BIT(9) +#define RKISP1_CIF_ISP_CTRL_ISP_GEN_CFG_UPD BIT(10) +#define RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA BIT(11) +#define RKISP1_CIF_ISP_CTRL_ISP_FLASH_MODE_ENA BIT(12) +#define RKISP1_CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA BIT(13) +#define RKISP1_CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA BIT(14) + +/* ISP_ACQ_PROP */ +#define RKISP1_CIF_ISP_ACQ_PROP_POS_EDGE BIT(0) +#define RKISP1_CIF_ISP_ACQ_PROP_HSYNC_LOW BIT(1) +#define RKISP1_CIF_ISP_ACQ_PROP_VSYNC_LOW BIT(2) +#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_RGGB (0 << 3) +#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_GRBG BIT(3) +#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_GBRG (2 << 3) +#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_BGGR (3 << 3) +#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT(pat) ((pat) << 3) +#define RKISP1_CIF_ISP_ACQ_PROP_YCBYCR (0 << 7) +#define RKISP1_CIF_ISP_ACQ_PROP_YCRYCB BIT(7) +#define RKISP1_CIF_ISP_ACQ_PROP_CBYCRY (2 << 7) +#define RKISP1_CIF_ISP_ACQ_PROP_CRYCBY (3 << 7) +#define RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_ALL (0 << 9) +#define RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_EVEN BIT(9) +#define RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_ODD (2 << 9) +#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_12B (0 << 12) +#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_ZERO BIT(12) +#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_MSB (2 << 12) +#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_8B_ZERO (3 << 12) +#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_8B_MSB (4 << 12) + +/* VI_DPCL */ +#define RKISP1_CIF_VI_DPCL_DMA_JPEG (0 << 0) +#define RKISP1_CIF_VI_DPCL_MP_MUX_MRSZ_MI BIT(0) +#define RKISP1_CIF_VI_DPCL_MP_MUX_MRSZ_JPEG (2 << 0) +#define RKISP1_CIF_VI_DPCL_CHAN_MODE_MP BIT(2) +#define RKISP1_CIF_VI_DPCL_CHAN_MODE_SP (2 << 2) +#define RKISP1_CIF_VI_DPCL_CHAN_MODE_MPSP (3 << 2) +#define RKISP1_CIF_VI_DPCL_DMA_SW_SPMUX (0 << 4) +#define RKISP1_CIF_VI_DPCL_DMA_SW_SI BIT(4) +#define RKISP1_CIF_VI_DPCL_DMA_SW_IE (2 << 4) +#define RKISP1_CIF_VI_DPCL_DMA_SW_JPEG (3 << 4) +#define RKISP1_CIF_VI_DPCL_DMA_SW_ISP (4 << 4) +#define RKISP1_CIF_VI_DPCL_IF_SEL_PARALLEL (0 << 8) +#define RKISP1_CIF_VI_DPCL_IF_SEL_SMIA BIT(8) +#define RKISP1_CIF_VI_DPCL_IF_SEL_MIPI (2 << 8) +#define RKISP1_CIF_VI_DPCL_DMA_IE_MUX_DMA BIT(10) +#define RKISP1_CIF_VI_DPCL_DMA_SP_MUX_DMA BIT(11) + +/* ISP_IMSC - ISP_MIS - ISP_RIS - ISP_ICR - ISP_ISR */ +#define RKISP1_CIF_ISP_OFF BIT(0) +#define RKISP1_CIF_ISP_FRAME BIT(1) +#define RKISP1_CIF_ISP_DATA_LOSS BIT(2) +#define RKISP1_CIF_ISP_PIC_SIZE_ERROR BIT(3) +#define RKISP1_CIF_ISP_AWB_DONE BIT(4) +#define RKISP1_CIF_ISP_FRAME_IN BIT(5) +#define RKISP1_CIF_ISP_V_START BIT(6) +#define RKISP1_CIF_ISP_H_START BIT(7) +#define RKISP1_CIF_ISP_FLASH_ON BIT(8) +#define RKISP1_CIF_ISP_FLASH_OFF BIT(9) +#define RKISP1_CIF_ISP_SHUTTER_ON BIT(10) +#define RKISP1_CIF_ISP_SHUTTER_OFF BIT(11) +#define RKISP1_CIF_ISP_AFM_SUM_OF BIT(12) +#define RKISP1_CIF_ISP_AFM_LUM_OF BIT(13) +#define RKISP1_CIF_ISP_AFM_FIN BIT(14) +#define RKISP1_CIF_ISP_HIST_MEASURE_RDY BIT(15) +#define RKISP1_CIF_ISP_FLASH_CAP BIT(17) +#define RKISP1_CIF_ISP_EXP_END BIT(18) +#define RKISP1_CIF_ISP_VSM_END BIT(19) + +/* ISP_ERR */ +#define RKISP1_CIF_ISP_ERR_INFORM_SIZE BIT(0) +#define RKISP1_CIF_ISP_ERR_IS_SIZE BIT(1) +#define RKISP1_CIF_ISP_ERR_OUTFORM_SIZE BIT(2) + +/* MI_CTRL */ +#define RKISP1_CIF_MI_CTRL_MP_ENABLE BIT(0) +#define RKISP1_CIF_MI_CTRL_SP_ENABLE (2 << 0) +#define RKISP1_CIF_MI_CTRL_JPEG_ENABLE (4 << 0) +#define RKISP1_CIF_MI_CTRL_RAW_ENABLE (8 << 0) +#define RKISP1_CIF_MI_CTRL_HFLIP BIT(4) +#define RKISP1_CIF_MI_CTRL_VFLIP BIT(5) +#define RKISP1_CIF_MI_CTRL_ROT BIT(6) +#define RKISP1_CIF_MI_BYTE_SWAP BIT(7) +#define RKISP1_CIF_MI_SP_Y_FULL_YUV2RGB BIT(8) +#define RKISP1_CIF_MI_SP_CBCR_FULL_YUV2RGB BIT(9) +#define RKISP1_CIF_MI_SP_422NONCOSITEED BIT(10) +#define RKISP1_CIF_MI_MP_PINGPONG_ENABEL BIT(11) +#define RKISP1_CIF_MI_SP_PINGPONG_ENABEL BIT(12) +#define RKISP1_CIF_MI_MP_AUTOUPDATE_ENABLE BIT(13) +#define RKISP1_CIF_MI_SP_AUTOUPDATE_ENABLE BIT(14) +#define RKISP1_CIF_MI_LAST_PIXEL_SIG_ENABLE BIT(15) +#define RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_16 (0 << 16) +#define RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_32 BIT(16) +#define RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_64 (2 << 16) +#define RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_16 (0 << 18) +#define RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_32 BIT(18) +#define RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_64 (2 << 18) +#define RKISP1_CIF_MI_CTRL_INIT_BASE_EN BIT(20) +#define RKISP1_CIF_MI_CTRL_INIT_OFFSET_EN BIT(21) +#define RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8 (0 << 22) +#define RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA BIT(22) +#define RKISP1_MI_CTRL_MP_WRITE_YUVINT (2 << 22) +#define RKISP1_MI_CTRL_MP_WRITE_RAW12 (2 << 22) +#define RKISP1_MI_CTRL_SP_WRITE_PLA (0 << 24) +#define RKISP1_MI_CTRL_SP_WRITE_SPLA BIT(24) +#define RKISP1_MI_CTRL_SP_WRITE_INT (2 << 24) +#define RKISP1_MI_CTRL_SP_INPUT_YUV400 (0 << 26) +#define RKISP1_MI_CTRL_SP_INPUT_YUV420 BIT(26) +#define RKISP1_MI_CTRL_SP_INPUT_YUV422 (2 << 26) +#define RKISP1_MI_CTRL_SP_INPUT_YUV444 (3 << 26) +#define RKISP1_MI_CTRL_SP_OUTPUT_YUV400 (0 << 28) +#define RKISP1_MI_CTRL_SP_OUTPUT_YUV420 BIT(28) +#define RKISP1_MI_CTRL_SP_OUTPUT_YUV422 (2 << 28) +#define RKISP1_MI_CTRL_SP_OUTPUT_YUV444 (3 << 28) +#define RKISP1_MI_CTRL_SP_OUTPUT_RGB565 (4 << 28) +#define RKISP1_MI_CTRL_SP_OUTPUT_RGB666 (5 << 28) +#define RKISP1_MI_CTRL_SP_OUTPUT_RGB888 (6 << 28) + +#define RKISP1_MI_CTRL_MP_FMT_MASK GENMASK(23, 22) +#define RKISP1_MI_CTRL_SP_FMT_MASK GENMASK(30, 24) + +/* MI_INIT */ +#define RKISP1_CIF_MI_INIT_SKIP BIT(2) +#define RKISP1_CIF_MI_INIT_SOFT_UPD BIT(4) + +/* MI_CTRL_SHD */ +#define RKISP1_CIF_MI_CTRL_SHD_MP_IN_ENABLED BIT(0) +#define RKISP1_CIF_MI_CTRL_SHD_SP_IN_ENABLED BIT(1) +#define RKISP1_CIF_MI_CTRL_SHD_JPEG_IN_ENABLED BIT(2) +#define RKISP1_CIF_MI_CTRL_SHD_RAW_IN_ENABLED BIT(3) +#define RKISP1_CIF_MI_CTRL_SHD_MP_OUT_ENABLED BIT(16) +#define RKISP1_CIF_MI_CTRL_SHD_SP_OUT_ENABLED BIT(17) +#define RKISP1_CIF_MI_CTRL_SHD_JPEG_OUT_ENABLED BIT(18) +#define RKISP1_CIF_MI_CTRL_SHD_RAW_OUT_ENABLED BIT(19) + +/* RSZ_CTRL */ +#define RKISP1_CIF_RSZ_CTRL_SCALE_HY_ENABLE BIT(0) +#define RKISP1_CIF_RSZ_CTRL_SCALE_HC_ENABLE BIT(1) +#define RKISP1_CIF_RSZ_CTRL_SCALE_VY_ENABLE BIT(2) +#define RKISP1_CIF_RSZ_CTRL_SCALE_VC_ENABLE BIT(3) +#define RKISP1_CIF_RSZ_CTRL_SCALE_HY_UP BIT(4) +#define RKISP1_CIF_RSZ_CTRL_SCALE_HC_UP BIT(5) +#define RKISP1_CIF_RSZ_CTRL_SCALE_VY_UP BIT(6) +#define RKISP1_CIF_RSZ_CTRL_SCALE_VC_UP BIT(7) +#define RKISP1_CIF_RSZ_CTRL_CFG_UPD BIT(8) +#define RKISP1_CIF_RSZ_CTRL_CFG_UPD_AUTO BIT(9) +#define RKISP1_CIF_RSZ_SCALER_FACTOR BIT(16) + +/* MI_IMSC - MI_MIS - MI_RIS - MI_ICR - MI_ISR */ +#define RKISP1_CIF_MI_FRAME(stream) BIT((stream)->id) +#define RKISP1_CIF_MI_MBLK_LINE BIT(2) +#define RKISP1_CIF_MI_FILL_MP_Y BIT(3) +#define RKISP1_CIF_MI_WRAP_MP_Y BIT(4) +#define RKISP1_CIF_MI_WRAP_MP_CB BIT(5) +#define RKISP1_CIF_MI_WRAP_MP_CR BIT(6) +#define RKISP1_CIF_MI_WRAP_SP_Y BIT(7) +#define RKISP1_CIF_MI_WRAP_SP_CB BIT(8) +#define RKISP1_CIF_MI_WRAP_SP_CR BIT(9) +#define RKISP1_CIF_MI_DMA_READY BIT(11) + +/* MI_STATUS */ +#define RKISP1_CIF_MI_STATUS_MP_Y_FIFO_FULL BIT(0) +#define RKISP1_CIF_MI_STATUS_SP_Y_FIFO_FULL BIT(4) + +/* MI_DMA_CTRL */ +#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_LUM_16 (0 << 0) +#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_LUM_32 BIT(0) +#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_LUM_64 (2 << 0) +#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_CHROM_16 (0 << 2) +#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_CHROM_32 BIT(2) +#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_CHROM_64 (2 << 2) +#define RKISP1_CIF_MI_DMA_CTRL_READ_FMT_PLANAR (0 << 4) +#define RKISP1_CIF_MI_DMA_CTRL_READ_FMT_SPLANAR BIT(4) +#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV400 (0 << 6) +#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV420 BIT(6) +#define RKISP1_CIF_MI_DMA_CTRL_READ_FMT_PACKED (2 << 4) +#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV422 (2 << 6) +#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV444 (3 << 6) +#define RKISP1_CIF_MI_DMA_CTRL_BYTE_SWAP BIT(8) +#define RKISP1_CIF_MI_DMA_CTRL_CONTINUOUS_ENA BIT(9) +#define RKISP1_CIF_MI_DMA_CTRL_RGB_BAYER_NO (0 << 12) +#define RKISP1_CIF_MI_DMA_CTRL_RGB_BAYER_8BIT BIT(12) +#define RKISP1_CIF_MI_DMA_CTRL_RGB_BAYER_16BIT (2 << 12) +/* MI_DMA_START */ +#define RKISP1_CIF_MI_DMA_START_ENABLE BIT(0) +/* MI_XTD_FORMAT_CTRL */ +#define RKISP1_CIF_MI_XTD_FMT_CTRL_MP_CB_CR_SWAP BIT(0) +#define RKISP1_CIF_MI_XTD_FMT_CTRL_SP_CB_CR_SWAP BIT(1) +#define RKISP1_CIF_MI_XTD_FMT_CTRL_DMA_CB_CR_SWAP BIT(2) + +/* CCL */ +#define RKISP1_CIF_CCL_CIF_CLK_DIS BIT(2) +/* ICCL */ +#define RKISP1_CIF_ICCL_ISP_CLK BIT(0) +#define RKISP1_CIF_ICCL_CP_CLK BIT(1) +#define RKISP1_CIF_ICCL_RES_2 BIT(2) +#define RKISP1_CIF_ICCL_MRSZ_CLK BIT(3) +#define RKISP1_CIF_ICCL_SRSZ_CLK BIT(4) +#define RKISP1_CIF_ICCL_JPEG_CLK BIT(5) +#define RKISP1_CIF_ICCL_MI_CLK BIT(6) +#define RKISP1_CIF_ICCL_RES_7 BIT(7) +#define RKISP1_CIF_ICCL_IE_CLK BIT(8) +#define RKISP1_CIF_ICCL_SIMP_CLK BIT(9) +#define RKISP1_CIF_ICCL_SMIA_CLK BIT(10) +#define RKISP1_CIF_ICCL_MIPI_CLK BIT(11) +#define RKISP1_CIF_ICCL_DCROP_CLK BIT(12) +/* IRCL */ +#define RKISP1_CIF_IRCL_ISP_SW_RST BIT(0) +#define RKISP1_CIF_IRCL_CP_SW_RST BIT(1) +#define RKISP1_CIF_IRCL_YCS_SW_RST BIT(2) +#define RKISP1_CIF_IRCL_MRSZ_SW_RST BIT(3) +#define RKISP1_CIF_IRCL_SRSZ_SW_RST BIT(4) +#define RKISP1_CIF_IRCL_JPEG_SW_RST BIT(5) +#define RKISP1_CIF_IRCL_MI_SW_RST BIT(6) +#define RKISP1_CIF_IRCL_CIF_SW_RST BIT(7) +#define RKISP1_CIF_IRCL_IE_SW_RST BIT(8) +#define RKISP1_CIF_IRCL_SI_SW_RST BIT(9) +#define RKISP1_CIF_IRCL_MIPI_SW_RST BIT(11) + +/* C_PROC_CTR */ +#define RKISP1_CIF_C_PROC_CTR_ENABLE BIT(0) +#define RKISP1_CIF_C_PROC_YOUT_FULL BIT(1) +#define RKISP1_CIF_C_PROC_YIN_FULL BIT(2) +#define RKISP1_CIF_C_PROC_COUT_FULL BIT(3) +#define RKISP1_CIF_C_PROC_CTRL_RESERVED 0xFFFFFFFE +#define RKISP1_CIF_C_PROC_CONTRAST_RESERVED 0xFFFFFF00 +#define RKISP1_CIF_C_PROC_BRIGHTNESS_RESERVED 0xFFFFFF00 +#define RKISP1_CIF_C_PROC_HUE_RESERVED 0xFFFFFF00 +#define RKISP1_CIF_C_PROC_SATURATION_RESERVED 0xFFFFFF00 +#define RKISP1_CIF_C_PROC_MACC_RESERVED 0xE000E000 +#define RKISP1_CIF_C_PROC_TONE_RESERVED 0xF000 +/* DUAL_CROP_CTRL */ +#define RKISP1_CIF_DUAL_CROP_MP_MODE_BYPASS (0 << 0) +#define RKISP1_CIF_DUAL_CROP_MP_MODE_YUV BIT(0) +#define RKISP1_CIF_DUAL_CROP_MP_MODE_RAW (2 << 0) +#define RKISP1_CIF_DUAL_CROP_SP_MODE_BYPASS (0 << 2) +#define RKISP1_CIF_DUAL_CROP_SP_MODE_YUV BIT(2) +#define RKISP1_CIF_DUAL_CROP_SP_MODE_RAW (2 << 2) +#define RKISP1_CIF_DUAL_CROP_CFG_UPD_PERMANENT BIT(4) +#define RKISP1_CIF_DUAL_CROP_CFG_UPD BIT(5) +#define RKISP1_CIF_DUAL_CROP_GEN_CFG_UPD BIT(6) + +/* IMG_EFF_CTRL */ +#define RKISP1_CIF_IMG_EFF_CTRL_ENABLE BIT(0) +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_BLACKWHITE (0 << 1) +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_NEGATIVE BIT(1) +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_SEPIA (2 << 1) +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_COLOR_SEL (3 << 1) +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_EMBOSS (4 << 1) +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_SKETCH (5 << 1) +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_SHARPEN (6 << 1) +#define RKISP1_CIF_IMG_EFF_CTRL_CFG_UPD BIT(4) +#define RKISP1_CIF_IMG_EFF_CTRL_YCBCR_FULL BIT(5) + +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_BLACKWHITE_SHIFT 0 +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_NEGATIVE_SHIFT 1 +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_SEPIA_SHIFT 2 +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_COLOR_SEL_SHIFT 3 +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_EMBOSS_SHIFT 4 +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_SKETCH_SHIFT 5 +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_SHARPEN_SHIFT 6 +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_MASK 0xE + +/* IMG_EFF_COLOR_SEL */ +#define RKISP1_CIF_IMG_EFF_COLOR_RGB 0 +#define RKISP1_CIF_IMG_EFF_COLOR_B BIT(0) +#define RKISP1_CIF_IMG_EFF_COLOR_G (2 << 0) +#define RKISP1_CIF_IMG_EFF_COLOR_GB (3 << 0) +#define RKISP1_CIF_IMG_EFF_COLOR_R (4 << 0) +#define RKISP1_CIF_IMG_EFF_COLOR_RB (5 << 0) +#define RKISP1_CIF_IMG_EFF_COLOR_RG (6 << 0) +#define RKISP1_CIF_IMG_EFF_COLOR_RGB2 (7 << 0) + +/* MIPI_CTRL */ +#define RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA BIT(0) +#define RKISP1_CIF_MIPI_CTRL_SHUTDOWNLANES(a) (((a) & 0xF) << 8) +#define RKISP1_CIF_MIPI_CTRL_NUM_LANES(a) (((a) & 0x3) << 12) +#define RKISP1_CIF_MIPI_CTRL_ERR_SOT_HS_SKIP BIT(16) +#define RKISP1_CIF_MIPI_CTRL_ERR_SOT_SYNC_HS_SKIP BIT(17) +#define RKISP1_CIF_MIPI_CTRL_CLOCKLANE_ENA BIT(18) + +/* MIPI_DATA_SEL */ +#define RKISP1_CIF_MIPI_DATA_SEL_VC(a) (((a) & 0x3) << 6) +#define RKISP1_CIF_MIPI_DATA_SEL_DT(a) (((a) & 0x3F) << 0) +/* MIPI DATA_TYPE */ +#define RKISP1_CIF_CSI2_DT_YUV420_8b 0x18 +#define RKISP1_CIF_CSI2_DT_YUV420_10b 0x19 +#define RKISP1_CIF_CSI2_DT_YUV422_8b 0x1E +#define RKISP1_CIF_CSI2_DT_YUV422_10b 0x1F +#define RKISP1_CIF_CSI2_DT_RGB565 0x22 +#define RKISP1_CIF_CSI2_DT_RGB666 0x23 +#define RKISP1_CIF_CSI2_DT_RGB888 0x24 +#define RKISP1_CIF_CSI2_DT_RAW8 0x2A +#define RKISP1_CIF_CSI2_DT_RAW10 0x2B +#define RKISP1_CIF_CSI2_DT_RAW12 0x2C + +/* MIPI_IMSC, MIPI_RIS, MIPI_MIS, MIPI_ICR, MIPI_ISR */ +#define RKISP1_CIF_MIPI_SYNC_FIFO_OVFLW(a) (((a) & 0xF) << 0) +#define RKISP1_CIF_MIPI_ERR_SOT(a) (((a) & 0xF) << 4) +#define RKISP1_CIF_MIPI_ERR_SOT_SYNC(a) (((a) & 0xF) << 8) +#define RKISP1_CIF_MIPI_ERR_EOT_SYNC(a) (((a) & 0xF) << 12) +#define RKISP1_CIF_MIPI_ERR_CTRL(a) (((a) & 0xF) << 16) +#define RKISP1_CIF_MIPI_ERR_PROTOCOL BIT(20) +#define RKISP1_CIF_MIPI_ERR_ECC1 BIT(21) +#define RKISP1_CIF_MIPI_ERR_ECC2 BIT(22) +#define RKISP1_CIF_MIPI_ERR_CS BIT(23) +#define RKISP1_CIF_MIPI_FRAME_END BIT(24) +#define RKISP1_CIF_MIPI_ADD_DATA_OVFLW BIT(25) +#define RKISP1_CIF_MIPI_ADD_DATA_WATER_MARK BIT(26) + +#define RKISP1_CIF_MIPI_ERR_CSI (RKISP1_CIF_MIPI_ERR_PROTOCOL | \ + RKISP1_CIF_MIPI_ERR_ECC1 | \ + RKISP1_CIF_MIPI_ERR_ECC2 | \ + RKISP1_CIF_MIPI_ERR_CS) + +#define RKISP1_CIF_MIPI_ERR_DPHY (RKISP1_CIF_MIPI_ERR_SOT(3) | \ + RKISP1_CIF_MIPI_ERR_SOT_SYNC(3) | \ + RKISP1_CIF_MIPI_ERR_EOT_SYNC(3) | \ + RKISP1_CIF_MIPI_ERR_CTRL(3)) + +/* SUPER_IMPOSE */ +#define RKISP1_CIF_SUPER_IMP_CTRL_NORMAL_MODE BIT(0) +#define RKISP1_CIF_SUPER_IMP_CTRL_REF_IMG_MEM BIT(1) +#define RKISP1_CIF_SUPER_IMP_CTRL_TRANSP_DIS BIT(2) + +/* ISP HISTOGRAM CALCULATION : ISP_HIST_PROP */ +#define RKISP1_CIF_ISP_HIST_PROP_MODE_DIS (0 << 0) +#define RKISP1_CIF_ISP_HIST_PROP_MODE_RGB BIT(0) +#define RKISP1_CIF_ISP_HIST_PROP_MODE_RED (2 << 0) +#define RKISP1_CIF_ISP_HIST_PROP_MODE_GREEN (3 << 0) +#define RKISP1_CIF_ISP_HIST_PROP_MODE_BLUE (4 << 0) +#define RKISP1_CIF_ISP_HIST_PROP_MODE_LUM (5 << 0) +#define RKISP1_CIF_ISP_HIST_PROP_MODE_MASK 0x7 +#define RKISP1_CIF_ISP_HIST_PREDIV_SET(x) (((x) & 0x7F) << 3) +#define RKISP1_CIF_ISP_HIST_WEIGHT_SET(v0, v1, v2, v3) \ + (((v0) & 0x1F) | (((v1) & 0x1F) << 8) |\ + (((v2) & 0x1F) << 16) | \ + (((v3) & 0x1F) << 24)) + +#define RKISP1_CIF_ISP_HIST_WINDOW_OFFSET_RESERVED 0xFFFFF000 +#define RKISP1_CIF_ISP_HIST_WINDOW_SIZE_RESERVED 0xFFFFF800 +#define RKISP1_CIF_ISP_HIST_WEIGHT_RESERVED 0xE0E0E0E0 +#define RKISP1_CIF_ISP_MAX_HIST_PREDIVIDER 0x0000007F +#define RKISP1_CIF_ISP_HIST_ROW_NUM 5 +#define RKISP1_CIF_ISP_HIST_COLUMN_NUM 5 + +/* AUTO FOCUS MEASUREMENT: ISP_AFM_CTRL */ +#define RKISP1_ISP_AFM_CTRL_ENABLE BIT(0) + +/* SHUTTER CONTROL */ +#define RKISP1_CIF_ISP_SH_CTRL_SH_ENA BIT(0) +#define RKISP1_CIF_ISP_SH_CTRL_REP_EN BIT(1) +#define RKISP1_CIF_ISP_SH_CTRL_SRC_SH_TRIG BIT(2) +#define RKISP1_CIF_ISP_SH_CTRL_EDGE_POS BIT(3) +#define RKISP1_CIF_ISP_SH_CTRL_POL_LOW BIT(4) + +/* FLASH MODULE */ +/* ISP_FLASH_CMD */ +#define RKISP1_CIFFLASH_CMD_PRELIGHT_ON BIT(0) +#define RKISP1_CIFFLASH_CMD_FLASH_ON BIT(1) +#define RKISP1_CIFFLASH_CMD_PRE_FLASH_ON BIT(2) +/* ISP_FLASH_CONFIG */ +#define RKISP1_CIFFLASH_CONFIG_PRELIGHT_END BIT(0) +#define RKISP1_CIFFLASH_CONFIG_VSYNC_POS BIT(1) +#define RKISP1_CIFFLASH_CONFIG_PRELIGHT_LOW BIT(2) +#define RKISP1_CIFFLASH_CONFIG_SRC_FL_TRIG BIT(3) +#define RKISP1_CIFFLASH_CONFIG_DELAY(a) (((a) & 0xF) << 4) + +/* Demosaic: ISP_DEMOSAIC */ +#define RKISP1_CIF_ISP_DEMOSAIC_BYPASS BIT(10) +#define RKISP1_CIF_ISP_DEMOSAIC_TH(x) ((x) & 0xFF) + +/* AWB */ +/* ISP_AWB_PROP */ +#define RKISP1_CIF_ISP_AWB_YMAX_CMP_EN BIT(2) +#define RKISP1_CIF_ISP_AWB_YMAX_READ(x) (((x) >> 2) & 1) +#define RKISP1_CIF_ISP_AWB_MODE_RGB_EN ((1 << 31) | (0x2 << 0)) +#define RKISP1_CIF_ISP_AWB_MODE_YCBCR_EN ((0 << 31) | (0x2 << 0)) +#define RKISP1_CIF_ISP_AWB_MODE_MASK_NONE 0xFFFFFFFC +#define RKISP1_CIF_ISP_AWB_MODE_READ(x) ((x) & 3) +/* ISP_AWB_GAIN_RB, ISP_AWB_GAIN_G */ +#define RKISP1_CIF_ISP_AWB_GAIN_R_SET(x) (((x) & 0x3FF) << 16) +#define RKISP1_CIF_ISP_AWB_GAIN_R_READ(x) (((x) >> 16) & 0x3FF) +#define RKISP1_CIF_ISP_AWB_GAIN_B_SET(x) ((x) & 0x3FFF) +#define RKISP1_CIF_ISP_AWB_GAIN_B_READ(x) ((x) & 0x3FFF) +/* ISP_AWB_REF */ +#define RKISP1_CIF_ISP_AWB_REF_CR_SET(x) (((x) & 0xFF) << 8) +#define RKISP1_CIF_ISP_AWB_REF_CR_READ(x) (((x) >> 8) & 0xFF) +#define RKISP1_CIF_ISP_AWB_REF_CB_READ(x) ((x) & 0xFF) +/* ISP_AWB_THRESH */ +#define RKISP1_CIF_ISP_AWB_MAX_CS_SET(x) (((x) & 0xFF) << 8) +#define RKISP1_CIF_ISP_AWB_MAX_CS_READ(x) (((x) >> 8) & 0xFF) +#define RKISP1_CIF_ISP_AWB_MIN_C_READ(x) ((x) & 0xFF) +#define RKISP1_CIF_ISP_AWB_MIN_Y_SET(x) (((x) & 0xFF) << 16) +#define RKISP1_CIF_ISP_AWB_MIN_Y_READ(x) (((x) >> 16) & 0xFF) +#define RKISP1_CIF_ISP_AWB_MAX_Y_SET(x) (((x) & 0xFF) << 24) +#define RKISP1_CIF_ISP_AWB_MAX_Y_READ(x) (((x) >> 24) & 0xFF) +/* ISP_AWB_MEAN */ +#define RKISP1_CIF_ISP_AWB_GET_MEAN_CR_R(x) ((x) & 0xFF) +#define RKISP1_CIF_ISP_AWB_GET_MEAN_CB_B(x) (((x) >> 8) & 0xFF) +#define RKISP1_CIF_ISP_AWB_GET_MEAN_Y_G(x) (((x) >> 16) & 0xFF) +/* ISP_AWB_WHITE_CNT */ +#define RKISP1_CIF_ISP_AWB_GET_PIXEL_CNT(x) ((x) & 0x3FFFFFF) + +#define RKISP1_CIF_ISP_AWB_GAINS_MAX_VAL 0x000003FF +#define RKISP1_CIF_ISP_AWB_WINDOW_OFFSET_MAX 0x00000FFF +#define RKISP1_CIF_ISP_AWB_WINDOW_MAX_SIZE 0x00001FFF +#define RKISP1_CIF_ISP_AWB_CBCR_MAX_REF 0x000000FF +#define RKISP1_CIF_ISP_AWB_THRES_MAX_YC 0x000000FF + +/* AE */ +/* ISP_EXP_CTRL */ +#define RKISP1_CIF_ISP_EXP_ENA BIT(0) +#define RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP BIT(1) +/* + *'1' luminance calculation according to Y=(R+G+B) x 0.332 (85/256) + *'0' luminance calculation according to Y=16+0.25R+0.5G+0.1094B + */ +#define RKISP1_CIF_ISP_EXP_CTRL_MEASMODE_1 BIT(31) + +/* ISP_EXP_H_SIZE */ +#define RKISP1_CIF_ISP_EXP_H_SIZE_SET(x) ((x) & 0x7FF) +#define RKISP1_CIF_ISP_EXP_HEIGHT_MASK 0x000007FF +/* ISP_EXP_V_SIZE : vertical size must be a multiple of 2). */ +#define RKISP1_CIF_ISP_EXP_V_SIZE_SET(x) ((x) & 0x7FE) + +/* ISP_EXP_H_OFFSET */ +#define RKISP1_CIF_ISP_EXP_H_OFFSET_SET(x) ((x) & 0x1FFF) +#define RKISP1_CIF_ISP_EXP_MAX_HOFFS 2424 +/* ISP_EXP_V_OFFSET */ +#define RKISP1_CIF_ISP_EXP_V_OFFSET_SET(x) ((x) & 0x1FFF) +#define RKISP1_CIF_ISP_EXP_MAX_VOFFS 1806 + +#define RKISP1_CIF_ISP_EXP_ROW_NUM 5 +#define RKISP1_CIF_ISP_EXP_COLUMN_NUM 5 +#define RKISP1_CIF_ISP_EXP_NUM_LUMA_REGS \ + (RKISP1_CIF_ISP_EXP_ROW_NUM * RKISP1_CIF_ISP_EXP_COLUMN_NUM) +#define RKISP1_CIF_ISP_EXP_BLOCK_MAX_HSIZE 516 +#define RKISP1_CIF_ISP_EXP_BLOCK_MIN_HSIZE 35 +#define RKISP1_CIF_ISP_EXP_BLOCK_MAX_VSIZE 390 +#define RKISP1_CIF_ISP_EXP_BLOCK_MIN_VSIZE 28 +#define RKISP1_CIF_ISP_EXP_MAX_HSIZE \ + (RKISP1_CIF_ISP_EXP_BLOCK_MAX_HSIZE * RKISP1_CIF_ISP_EXP_COLUMN_NUM + 1) +#define RKISP1_CIF_ISP_EXP_MIN_HSIZE \ + (RKISP1_CIF_ISP_EXP_BLOCK_MIN_HSIZE * RKISP1_CIF_ISP_EXP_COLUMN_NUM + 1) +#define RKISP1_CIF_ISP_EXP_MAX_VSIZE \ + (RKISP1_CIF_ISP_EXP_BLOCK_MAX_VSIZE * RKISP1_CIF_ISP_EXP_ROW_NUM + 1) +#define RKISP1_CIF_ISP_EXP_MIN_VSIZE \ + (RKISP1_CIF_ISP_EXP_BLOCK_MIN_VSIZE * RKISP1_CIF_ISP_EXP_ROW_NUM + 1) + +/* LSC: ISP_LSC_CTRL */ +#define RKISP1_CIF_ISP_LSC_CTRL_ENA BIT(0) +#define RKISP1_CIF_ISP_LSC_SECT_SIZE_RESERVED 0xFC00FC00 +#define RKISP1_CIF_ISP_LSC_GRAD_RESERVED 0xF000F000 +#define RKISP1_CIF_ISP_LSC_SAMPLE_RESERVED 0xF000F000 +#define RKISP1_CIF_ISP_LSC_TABLE_DATA(v0, v1) \ + (((v0) & 0xFFF) | (((v1) & 0xFFF) << 12)) +#define RKISP1_CIF_ISP_LSC_SECT_SIZE(v0, v1) \ + (((v0) & 0xFFF) | (((v1) & 0xFFF) << 16)) +#define RKISP1_CIF_ISP_LSC_GRAD_SIZE(v0, v1) \ + (((v0) & 0xFFF) | (((v1) & 0xFFF) << 16)) + +/* LSC: ISP_LSC_TABLE_SEL */ +#define RKISP1_CIF_ISP_LSC_TABLE_0 0 +#define RKISP1_CIF_ISP_LSC_TABLE_1 1 + +/* LSC: ISP_LSC_STATUS */ +#define RKISP1_CIF_ISP_LSC_ACTIVE_TABLE BIT(1) +#define RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_0 0 +#define RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153 153 + +/* FLT */ +/* ISP_FILT_MODE */ +#define RKISP1_CIF_ISP_FLT_ENA BIT(0) + +/* + * 0: green filter static mode (active filter factor = FILT_FAC_MID) + * 1: dynamic noise reduction/sharpen Default + */ +#define RKISP1_CIF_ISP_FLT_MODE_DNR BIT(1) +#define RKISP1_CIF_ISP_FLT_MODE_MAX 1 +#define RKISP1_CIF_ISP_FLT_CHROMA_V_MODE(x) (((x) & 0x3) << 4) +#define RKISP1_CIF_ISP_FLT_CHROMA_H_MODE(x) (((x) & 0x3) << 6) +#define RKISP1_CIF_ISP_FLT_CHROMA_MODE_MAX 3 +#define RKISP1_CIF_ISP_FLT_GREEN_STAGE1(x) (((x) & 0xF) << 8) +#define RKISP1_CIF_ISP_FLT_GREEN_STAGE1_MAX 8 +#define RKISP1_CIF_ISP_FLT_THREAD_RESERVED 0xFFFFFC00 +#define RKISP1_CIF_ISP_FLT_FAC_RESERVED 0xFFFFFFC0 +#define RKISP1_CIF_ISP_FLT_LUM_WEIGHT_RESERVED 0xFFF80000 + +#define RKISP1_CIF_ISP_CTK_COEFF_RESERVED 0xFFFFF800 +#define RKISP1_CIF_ISP_XTALK_OFFSET_RESERVED 0xFFFFF000 + +/* GOC */ +#define RKISP1_CIF_ISP_GAMMA_OUT_MODE_EQU BIT(0) +#define RKISP1_CIF_ISP_GOC_MODE_MAX 1 +#define RKISP1_CIF_ISP_GOC_RESERVED 0xFFFFF800 +/* ISP_CTRL BIT 11*/ +#define RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA_READ(x) (((x) >> 11) & 1) + +/* DPCC */ +/* ISP_DPCC_MODE */ +#define RKISP1_CIF_ISP_DPCC_ENA BIT(0) +#define RKISP1_CIF_ISP_DPCC_MODE_MAX 0x07 +#define RKISP1_CIF_ISP_DPCC_OUTPUTMODE_MAX 0x0F +#define RKISP1_CIF_ISP_DPCC_SETUSE_MAX 0x0F +#define RKISP1_CIF_ISP_DPCC_METHODS_SET_RESERVED 0xFFFFE000 +#define RKISP1_CIF_ISP_DPCC_LINE_THRESH_RESERVED 0xFFFF0000 +#define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_RESERVED 0xFFFFC0C0 +#define RKISP1_CIF_ISP_DPCC_PG_FAC_RESERVED 0xFFFFC0C0 +#define RKISP1_CIF_ISP_DPCC_RND_THRESH_RESERVED 0xFFFF0000 +#define RKISP1_CIF_ISP_DPCC_RG_FAC_RESERVED 0xFFFFC0C0 +#define RKISP1_CIF_ISP_DPCC_RO_LIMIT_RESERVED 0xFFFFF000 +#define RKISP1_CIF_ISP_DPCC_RND_OFFS_RESERVED 0xFFFFF000 + +/* BLS */ +/* ISP_BLS_CTRL */ +#define RKISP1_CIF_ISP_BLS_ENA BIT(0) +#define RKISP1_CIF_ISP_BLS_MODE_MEASURED BIT(1) +#define RKISP1_CIF_ISP_BLS_MODE_FIXED 0 +#define RKISP1_CIF_ISP_BLS_WINDOW_1 BIT(2) +#define RKISP1_CIF_ISP_BLS_WINDOW_2 (2 << 2) + +/* GAMMA-IN */ +#define RKISP1_CIFISP_DEGAMMA_X_RESERVED \ + ((1 << 31) | (1 << 27) | (1 << 23) | (1 << 19) |\ + (1 << 15) | (1 << 11) | (1 << 7) | (1 << 3)) +#define RKISP1_CIFISP_DEGAMMA_Y_RESERVED 0xFFFFF000 + +/* AFM */ +#define RKISP1_CIF_ISP_AFM_ENA BIT(0) +#define RKISP1_CIF_ISP_AFM_THRES_RESERVED 0xFFFF0000 +#define RKISP1_CIF_ISP_AFM_VAR_SHIFT_RESERVED 0xFFF8FFF8 +#define RKISP1_CIF_ISP_AFM_WINDOW_X_RESERVED 0xE000 +#define RKISP1_CIF_ISP_AFM_WINDOW_Y_RESERVED 0xF000 +#define RKISP1_CIF_ISP_AFM_WINDOW_X_MIN 0x5 +#define RKISP1_CIF_ISP_AFM_WINDOW_Y_MIN 0x2 +#define RKISP1_CIF_ISP_AFM_WINDOW_X(x) (((x) & 0x1FFF) << 16) +#define RKISP1_CIF_ISP_AFM_WINDOW_Y(x) ((x) & 0x1FFF) + +/* DPF */ +#define RKISP1_CIF_ISP_DPF_MODE_EN BIT(0) +#define RKISP1_CIF_ISP_DPF_MODE_B_FLT_DIS BIT(1) +#define RKISP1_CIF_ISP_DPF_MODE_GB_FLT_DIS BIT(2) +#define RKISP1_CIF_ISP_DPF_MODE_GR_FLT_DIS BIT(3) +#define RKISP1_CIF_ISP_DPF_MODE_R_FLT_DIS BIT(4) +#define RKISP1_CIF_ISP_DPF_MODE_RB_FLTSIZE_9x9 BIT(5) +#define RKISP1_CIF_ISP_DPF_MODE_NLL_SEGMENTATION BIT(6) +#define RKISP1_CIF_ISP_DPF_MODE_AWB_GAIN_COMP BIT(7) +#define RKISP1_CIF_ISP_DPF_MODE_LSC_GAIN_COMP BIT(8) +#define RKISP1_CIF_ISP_DPF_MODE_USE_NF_GAIN BIT(9) +#define RKISP1_CIF_ISP_DPF_NF_GAIN_RESERVED 0xFFFFF000 +#define RKISP1_CIF_ISP_DPF_SPATIAL_COEFF_MAX 0x1F +#define RKISP1_CIF_ISP_DPF_NLL_COEFF_N_MAX 0x3FF + +/* =================================================================== */ +/* CIF Registers */ +/* =================================================================== */ +#define RKISP1_CIF_CTRL_BASE 0x00000000 +#define RKISP1_CIF_CCL (RKISP1_CIF_CTRL_BASE + 0x00000000) +#define RKISP1_CIF_VI_ID (RKISP1_CIF_CTRL_BASE + 0x00000008) +#define RKISP1_CIF_ICCL (RKISP1_CIF_CTRL_BASE + 0x00000010) +#define RKISP1_CIF_IRCL (RKISP1_CIF_CTRL_BASE + 0x00000014) +#define RKISP1_CIF_VI_DPCL (RKISP1_CIF_CTRL_BASE + 0x00000018) + +#define RKISP1_CIF_IMG_EFF_BASE 0x00000200 +#define RKISP1_CIF_IMG_EFF_CTRL (RKISP1_CIF_IMG_EFF_BASE + 0x00000000) +#define RKISP1_CIF_IMG_EFF_COLOR_SEL (RKISP1_CIF_IMG_EFF_BASE + 0x00000004) +#define RKISP1_CIF_IMG_EFF_MAT_1 (RKISP1_CIF_IMG_EFF_BASE + 0x00000008) +#define RKISP1_CIF_IMG_EFF_MAT_2 (RKISP1_CIF_IMG_EFF_BASE + 0x0000000C) +#define RKISP1_CIF_IMG_EFF_MAT_3 (RKISP1_CIF_IMG_EFF_BASE + 0x00000010) +#define RKISP1_CIF_IMG_EFF_MAT_4 (RKISP1_CIF_IMG_EFF_BASE + 0x00000014) +#define RKISP1_CIF_IMG_EFF_MAT_5 (RKISP1_CIF_IMG_EFF_BASE + 0x00000018) +#define RKISP1_CIF_IMG_EFF_TINT (RKISP1_CIF_IMG_EFF_BASE + 0x0000001C) +#define RKISP1_CIF_IMG_EFF_CTRL_SHD (RKISP1_CIF_IMG_EFF_BASE + 0x00000020) +#define RKISP1_CIF_IMG_EFF_SHARPEN (RKISP1_CIF_IMG_EFF_BASE + 0x00000024) + +#define RKISP1_CIF_SUPER_IMP_BASE 0x00000300 +#define RKISP1_CIF_SUPER_IMP_CTRL (RKISP1_CIF_SUPER_IMP_BASE + 0x00000000) +#define RKISP1_CIF_SUPER_IMP_OFFSET_X (RKISP1_CIF_SUPER_IMP_BASE + 0x00000004) +#define RKISP1_CIF_SUPER_IMP_OFFSET_Y (RKISP1_CIF_SUPER_IMP_BASE + 0x00000008) +#define RKISP1_CIF_SUPER_IMP_COLOR_Y (RKISP1_CIF_SUPER_IMP_BASE + 0x0000000C) +#define RKISP1_CIF_SUPER_IMP_COLOR_CB (RKISP1_CIF_SUPER_IMP_BASE + 0x00000010) +#define RKISP1_CIF_SUPER_IMP_COLOR_CR (RKISP1_CIF_SUPER_IMP_BASE + 0x00000014) + +#define RKISP1_CIF_ISP_BASE 0x00000400 +#define RKISP1_CIF_ISP_CTRL (RKISP1_CIF_ISP_BASE + 0x00000000) +#define RKISP1_CIF_ISP_ACQ_PROP (RKISP1_CIF_ISP_BASE + 0x00000004) +#define RKISP1_CIF_ISP_ACQ_H_OFFS (RKISP1_CIF_ISP_BASE + 0x00000008) +#define RKISP1_CIF_ISP_ACQ_V_OFFS (RKISP1_CIF_ISP_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_ACQ_H_SIZE (RKISP1_CIF_ISP_BASE + 0x00000010) +#define RKISP1_CIF_ISP_ACQ_V_SIZE (RKISP1_CIF_ISP_BASE + 0x00000014) +#define RKISP1_CIF_ISP_ACQ_NR_FRAMES (RKISP1_CIF_ISP_BASE + 0x00000018) +#define RKISP1_CIF_ISP_GAMMA_DX_LO (RKISP1_CIF_ISP_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_GAMMA_DX_HI (RKISP1_CIF_ISP_BASE + 0x00000020) +#define RKISP1_CIF_ISP_GAMMA_R_Y0 (RKISP1_CIF_ISP_BASE + 0x00000024) +#define RKISP1_CIF_ISP_GAMMA_R_Y1 (RKISP1_CIF_ISP_BASE + 0x00000028) +#define RKISP1_CIF_ISP_GAMMA_R_Y2 (RKISP1_CIF_ISP_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_GAMMA_R_Y3 (RKISP1_CIF_ISP_BASE + 0x00000030) +#define RKISP1_CIF_ISP_GAMMA_R_Y4 (RKISP1_CIF_ISP_BASE + 0x00000034) +#define RKISP1_CIF_ISP_GAMMA_R_Y5 (RKISP1_CIF_ISP_BASE + 0x00000038) +#define RKISP1_CIF_ISP_GAMMA_R_Y6 (RKISP1_CIF_ISP_BASE + 0x0000003C) +#define RKISP1_CIF_ISP_GAMMA_R_Y7 (RKISP1_CIF_ISP_BASE + 0x00000040) +#define RKISP1_CIF_ISP_GAMMA_R_Y8 (RKISP1_CIF_ISP_BASE + 0x00000044) +#define RKISP1_CIF_ISP_GAMMA_R_Y9 (RKISP1_CIF_ISP_BASE + 0x00000048) +#define RKISP1_CIF_ISP_GAMMA_R_Y10 (RKISP1_CIF_ISP_BASE + 0x0000004C) +#define RKISP1_CIF_ISP_GAMMA_R_Y11 (RKISP1_CIF_ISP_BASE + 0x00000050) +#define RKISP1_CIF_ISP_GAMMA_R_Y12 (RKISP1_CIF_ISP_BASE + 0x00000054) +#define RKISP1_CIF_ISP_GAMMA_R_Y13 (RKISP1_CIF_ISP_BASE + 0x00000058) +#define RKISP1_CIF_ISP_GAMMA_R_Y14 (RKISP1_CIF_ISP_BASE + 0x0000005C) +#define RKISP1_CIF_ISP_GAMMA_R_Y15 (RKISP1_CIF_ISP_BASE + 0x00000060) +#define RKISP1_CIF_ISP_GAMMA_R_Y16 (RKISP1_CIF_ISP_BASE + 0x00000064) +#define RKISP1_CIF_ISP_GAMMA_G_Y0 (RKISP1_CIF_ISP_BASE + 0x00000068) +#define RKISP1_CIF_ISP_GAMMA_G_Y1 (RKISP1_CIF_ISP_BASE + 0x0000006C) +#define RKISP1_CIF_ISP_GAMMA_G_Y2 (RKISP1_CIF_ISP_BASE + 0x00000070) +#define RKISP1_CIF_ISP_GAMMA_G_Y3 (RKISP1_CIF_ISP_BASE + 0x00000074) +#define RKISP1_CIF_ISP_GAMMA_G_Y4 (RKISP1_CIF_ISP_BASE + 0x00000078) +#define RKISP1_CIF_ISP_GAMMA_G_Y5 (RKISP1_CIF_ISP_BASE + 0x0000007C) +#define RKISP1_CIF_ISP_GAMMA_G_Y6 (RKISP1_CIF_ISP_BASE + 0x00000080) +#define RKISP1_CIF_ISP_GAMMA_G_Y7 (RKISP1_CIF_ISP_BASE + 0x00000084) +#define RKISP1_CIF_ISP_GAMMA_G_Y8 (RKISP1_CIF_ISP_BASE + 0x00000088) +#define RKISP1_CIF_ISP_GAMMA_G_Y9 (RKISP1_CIF_ISP_BASE + 0x0000008C) +#define RKISP1_CIF_ISP_GAMMA_G_Y10 (RKISP1_CIF_ISP_BASE + 0x00000090) +#define RKISP1_CIF_ISP_GAMMA_G_Y11 (RKISP1_CIF_ISP_BASE + 0x00000094) +#define RKISP1_CIF_ISP_GAMMA_G_Y12 (RKISP1_CIF_ISP_BASE + 0x00000098) +#define RKISP1_CIF_ISP_GAMMA_G_Y13 (RKISP1_CIF_ISP_BASE + 0x0000009C) +#define RKISP1_CIF_ISP_GAMMA_G_Y14 (RKISP1_CIF_ISP_BASE + 0x000000A0) +#define RKISP1_CIF_ISP_GAMMA_G_Y15 (RKISP1_CIF_ISP_BASE + 0x000000A4) +#define RKISP1_CIF_ISP_GAMMA_G_Y16 (RKISP1_CIF_ISP_BASE + 0x000000A8) +#define RKISP1_CIF_ISP_GAMMA_B_Y0 (RKISP1_CIF_ISP_BASE + 0x000000AC) +#define RKISP1_CIF_ISP_GAMMA_B_Y1 (RKISP1_CIF_ISP_BASE + 0x000000B0) +#define RKISP1_CIF_ISP_GAMMA_B_Y2 (RKISP1_CIF_ISP_BASE + 0x000000B4) +#define RKISP1_CIF_ISP_GAMMA_B_Y3 (RKISP1_CIF_ISP_BASE + 0x000000B8) +#define RKISP1_CIF_ISP_GAMMA_B_Y4 (RKISP1_CIF_ISP_BASE + 0x000000BC) +#define RKISP1_CIF_ISP_GAMMA_B_Y5 (RKISP1_CIF_ISP_BASE + 0x000000C0) +#define RKISP1_CIF_ISP_GAMMA_B_Y6 (RKISP1_CIF_ISP_BASE + 0x000000C4) +#define RKISP1_CIF_ISP_GAMMA_B_Y7 (RKISP1_CIF_ISP_BASE + 0x000000C8) +#define RKISP1_CIF_ISP_GAMMA_B_Y8 (RKISP1_CIF_ISP_BASE + 0x000000CC) +#define RKISP1_CIF_ISP_GAMMA_B_Y9 (RKISP1_CIF_ISP_BASE + 0x000000D0) +#define RKISP1_CIF_ISP_GAMMA_B_Y10 (RKISP1_CIF_ISP_BASE + 0x000000D4) +#define RKISP1_CIF_ISP_GAMMA_B_Y11 (RKISP1_CIF_ISP_BASE + 0x000000D8) +#define RKISP1_CIF_ISP_GAMMA_B_Y12 (RKISP1_CIF_ISP_BASE + 0x000000DC) +#define RKISP1_CIF_ISP_GAMMA_B_Y13 (RKISP1_CIF_ISP_BASE + 0x000000E0) +#define RKISP1_CIF_ISP_GAMMA_B_Y14 (RKISP1_CIF_ISP_BASE + 0x000000E4) +#define RKISP1_CIF_ISP_GAMMA_B_Y15 (RKISP1_CIF_ISP_BASE + 0x000000E8) +#define RKISP1_CIF_ISP_GAMMA_B_Y16 (RKISP1_CIF_ISP_BASE + 0x000000EC) +#define RKISP1_CIF_ISP_AWB_PROP (RKISP1_CIF_ISP_BASE + 0x00000110) +#define RKISP1_CIF_ISP_AWB_WND_H_OFFS (RKISP1_CIF_ISP_BASE + 0x00000114) +#define RKISP1_CIF_ISP_AWB_WND_V_OFFS (RKISP1_CIF_ISP_BASE + 0x00000118) +#define RKISP1_CIF_ISP_AWB_WND_H_SIZE (RKISP1_CIF_ISP_BASE + 0x0000011C) +#define RKISP1_CIF_ISP_AWB_WND_V_SIZE (RKISP1_CIF_ISP_BASE + 0x00000120) +#define RKISP1_CIF_ISP_AWB_FRAMES (RKISP1_CIF_ISP_BASE + 0x00000124) +#define RKISP1_CIF_ISP_AWB_REF (RKISP1_CIF_ISP_BASE + 0x00000128) +#define RKISP1_CIF_ISP_AWB_THRESH (RKISP1_CIF_ISP_BASE + 0x0000012C) +#define RKISP1_CIF_ISP_AWB_GAIN_G (RKISP1_CIF_ISP_BASE + 0x00000138) +#define RKISP1_CIF_ISP_AWB_GAIN_RB (RKISP1_CIF_ISP_BASE + 0x0000013C) +#define RKISP1_CIF_ISP_AWB_WHITE_CNT (RKISP1_CIF_ISP_BASE + 0x00000140) +#define RKISP1_CIF_ISP_AWB_MEAN (RKISP1_CIF_ISP_BASE + 0x00000144) +#define RKISP1_CIF_ISP_CC_COEFF_0 (RKISP1_CIF_ISP_BASE + 0x00000170) +#define RKISP1_CIF_ISP_CC_COEFF_1 (RKISP1_CIF_ISP_BASE + 0x00000174) +#define RKISP1_CIF_ISP_CC_COEFF_2 (RKISP1_CIF_ISP_BASE + 0x00000178) +#define RKISP1_CIF_ISP_CC_COEFF_3 (RKISP1_CIF_ISP_BASE + 0x0000017C) +#define RKISP1_CIF_ISP_CC_COEFF_4 (RKISP1_CIF_ISP_BASE + 0x00000180) +#define RKISP1_CIF_ISP_CC_COEFF_5 (RKISP1_CIF_ISP_BASE + 0x00000184) +#define RKISP1_CIF_ISP_CC_COEFF_6 (RKISP1_CIF_ISP_BASE + 0x00000188) +#define RKISP1_CIF_ISP_CC_COEFF_7 (RKISP1_CIF_ISP_BASE + 0x0000018C) +#define RKISP1_CIF_ISP_CC_COEFF_8 (RKISP1_CIF_ISP_BASE + 0x00000190) +#define RKISP1_CIF_ISP_OUT_H_OFFS (RKISP1_CIF_ISP_BASE + 0x00000194) +#define RKISP1_CIF_ISP_OUT_V_OFFS (RKISP1_CIF_ISP_BASE + 0x00000198) +#define RKISP1_CIF_ISP_OUT_H_SIZE (RKISP1_CIF_ISP_BASE + 0x0000019C) +#define RKISP1_CIF_ISP_OUT_V_SIZE (RKISP1_CIF_ISP_BASE + 0x000001A0) +#define RKISP1_CIF_ISP_DEMOSAIC (RKISP1_CIF_ISP_BASE + 0x000001A4) +#define RKISP1_CIF_ISP_FLAGS_SHD (RKISP1_CIF_ISP_BASE + 0x000001A8) +#define RKISP1_CIF_ISP_OUT_H_OFFS_SHD (RKISP1_CIF_ISP_BASE + 0x000001AC) +#define RKISP1_CIF_ISP_OUT_V_OFFS_SHD (RKISP1_CIF_ISP_BASE + 0x000001B0) +#define RKISP1_CIF_ISP_OUT_H_SIZE_SHD (RKISP1_CIF_ISP_BASE + 0x000001B4) +#define RKISP1_CIF_ISP_OUT_V_SIZE_SHD (RKISP1_CIF_ISP_BASE + 0x000001B8) +#define RKISP1_CIF_ISP_IMSC (RKISP1_CIF_ISP_BASE + 0x000001BC) +#define RKISP1_CIF_ISP_RIS (RKISP1_CIF_ISP_BASE + 0x000001C0) +#define RKISP1_CIF_ISP_MIS (RKISP1_CIF_ISP_BASE + 0x000001C4) +#define RKISP1_CIF_ISP_ICR (RKISP1_CIF_ISP_BASE + 0x000001C8) +#define RKISP1_CIF_ISP_ISR (RKISP1_CIF_ISP_BASE + 0x000001CC) +#define RKISP1_CIF_ISP_CT_COEFF_0 (RKISP1_CIF_ISP_BASE + 0x000001D0) +#define RKISP1_CIF_ISP_CT_COEFF_1 (RKISP1_CIF_ISP_BASE + 0x000001D4) +#define RKISP1_CIF_ISP_CT_COEFF_2 (RKISP1_CIF_ISP_BASE + 0x000001D8) +#define RKISP1_CIF_ISP_CT_COEFF_3 (RKISP1_CIF_ISP_BASE + 0x000001DC) +#define RKISP1_CIF_ISP_CT_COEFF_4 (RKISP1_CIF_ISP_BASE + 0x000001E0) +#define RKISP1_CIF_ISP_CT_COEFF_5 (RKISP1_CIF_ISP_BASE + 0x000001E4) +#define RKISP1_CIF_ISP_CT_COEFF_6 (RKISP1_CIF_ISP_BASE + 0x000001E8) +#define RKISP1_CIF_ISP_CT_COEFF_7 (RKISP1_CIF_ISP_BASE + 0x000001EC) +#define RKISP1_CIF_ISP_CT_COEFF_8 (RKISP1_CIF_ISP_BASE + 0x000001F0) +#define RKISP1_CIF_ISP_GAMMA_OUT_MODE (RKISP1_CIF_ISP_BASE + 0x000001F4) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_0 (RKISP1_CIF_ISP_BASE + 0x000001F8) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_1 (RKISP1_CIF_ISP_BASE + 0x000001FC) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_2 (RKISP1_CIF_ISP_BASE + 0x00000200) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_3 (RKISP1_CIF_ISP_BASE + 0x00000204) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_4 (RKISP1_CIF_ISP_BASE + 0x00000208) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_5 (RKISP1_CIF_ISP_BASE + 0x0000020C) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_6 (RKISP1_CIF_ISP_BASE + 0x00000210) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_7 (RKISP1_CIF_ISP_BASE + 0x00000214) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_8 (RKISP1_CIF_ISP_BASE + 0x00000218) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_9 (RKISP1_CIF_ISP_BASE + 0x0000021C) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_10 (RKISP1_CIF_ISP_BASE + 0x00000220) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_11 (RKISP1_CIF_ISP_BASE + 0x00000224) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_12 (RKISP1_CIF_ISP_BASE + 0x00000228) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_13 (RKISP1_CIF_ISP_BASE + 0x0000022C) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_14 (RKISP1_CIF_ISP_BASE + 0x00000230) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_15 (RKISP1_CIF_ISP_BASE + 0x00000234) +#define RKISP1_CIF_ISP_GAMMA_OUT_Y_16 (RKISP1_CIF_ISP_BASE + 0x00000238) +#define RKISP1_CIF_ISP_ERR (RKISP1_CIF_ISP_BASE + 0x0000023C) +#define RKISP1_CIF_ISP_ERR_CLR (RKISP1_CIF_ISP_BASE + 0x00000240) +#define RKISP1_CIF_ISP_FRAME_COUNT (RKISP1_CIF_ISP_BASE + 0x00000244) +#define RKISP1_CIF_ISP_CT_OFFSET_R (RKISP1_CIF_ISP_BASE + 0x00000248) +#define RKISP1_CIF_ISP_CT_OFFSET_G (RKISP1_CIF_ISP_BASE + 0x0000024C) +#define RKISP1_CIF_ISP_CT_OFFSET_B (RKISP1_CIF_ISP_BASE + 0x00000250) + +#define RKISP1_CIF_ISP_FLASH_BASE 0x00000660 +#define RKISP1_CIF_ISP_FLASH_CMD (RKISP1_CIF_ISP_FLASH_BASE + 0x00000000) +#define RKISP1_CIF_ISP_FLASH_CONFIG (RKISP1_CIF_ISP_FLASH_BASE + 0x00000004) +#define RKISP1_CIF_ISP_FLASH_PREDIV (RKISP1_CIF_ISP_FLASH_BASE + 0x00000008) +#define RKISP1_CIF_ISP_FLASH_DELAY (RKISP1_CIF_ISP_FLASH_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_FLASH_TIME (RKISP1_CIF_ISP_FLASH_BASE + 0x00000010) +#define RKISP1_CIF_ISP_FLASH_MAXP (RKISP1_CIF_ISP_FLASH_BASE + 0x00000014) + +#define RKISP1_CIF_ISP_SH_BASE 0x00000680 +#define RKISP1_CIF_ISP_SH_CTRL (RKISP1_CIF_ISP_SH_BASE + 0x00000000) +#define RKISP1_CIF_ISP_SH_PREDIV (RKISP1_CIF_ISP_SH_BASE + 0x00000004) +#define RKISP1_CIF_ISP_SH_DELAY (RKISP1_CIF_ISP_SH_BASE + 0x00000008) +#define RKISP1_CIF_ISP_SH_TIME (RKISP1_CIF_ISP_SH_BASE + 0x0000000C) + +#define RKISP1_CIF_C_PROC_BASE 0x00000800 +#define RKISP1_CIF_C_PROC_CTRL (RKISP1_CIF_C_PROC_BASE + 0x00000000) +#define RKISP1_CIF_C_PROC_CONTRAST (RKISP1_CIF_C_PROC_BASE + 0x00000004) +#define RKISP1_CIF_C_PROC_BRIGHTNESS (RKISP1_CIF_C_PROC_BASE + 0x00000008) +#define RKISP1_CIF_C_PROC_SATURATION (RKISP1_CIF_C_PROC_BASE + 0x0000000C) +#define RKISP1_CIF_C_PROC_HUE (RKISP1_CIF_C_PROC_BASE + 0x00000010) + +#define RKISP1_CIF_DUAL_CROP_BASE 0x00000880 +#define RKISP1_CIF_DUAL_CROP_CTRL (RKISP1_CIF_DUAL_CROP_BASE + 0x00000000) +#define RKISP1_CIF_DUAL_CROP_M_H_OFFS (RKISP1_CIF_DUAL_CROP_BASE + 0x00000004) +#define RKISP1_CIF_DUAL_CROP_M_V_OFFS (RKISP1_CIF_DUAL_CROP_BASE + 0x00000008) +#define RKISP1_CIF_DUAL_CROP_M_H_SIZE (RKISP1_CIF_DUAL_CROP_BASE + 0x0000000C) +#define RKISP1_CIF_DUAL_CROP_M_V_SIZE (RKISP1_CIF_DUAL_CROP_BASE + 0x00000010) +#define RKISP1_CIF_DUAL_CROP_S_H_OFFS (RKISP1_CIF_DUAL_CROP_BASE + 0x00000014) +#define RKISP1_CIF_DUAL_CROP_S_V_OFFS (RKISP1_CIF_DUAL_CROP_BASE + 0x00000018) +#define RKISP1_CIF_DUAL_CROP_S_H_SIZE (RKISP1_CIF_DUAL_CROP_BASE + 0x0000001C) +#define RKISP1_CIF_DUAL_CROP_S_V_SIZE (RKISP1_CIF_DUAL_CROP_BASE + 0x00000020) +#define RKISP1_CIF_DUAL_CROP_M_H_OFFS_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000024) +#define RKISP1_CIF_DUAL_CROP_M_V_OFFS_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000028) +#define RKISP1_CIF_DUAL_CROP_M_H_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x0000002C) +#define RKISP1_CIF_DUAL_CROP_M_V_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000030) +#define RKISP1_CIF_DUAL_CROP_S_H_OFFS_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000034) +#define RKISP1_CIF_DUAL_CROP_S_V_OFFS_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000038) +#define RKISP1_CIF_DUAL_CROP_S_H_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x0000003C) +#define RKISP1_CIF_DUAL_CROP_S_V_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000040) + +#define RKISP1_CIF_MRSZ_BASE 0x00000C00 +#define RKISP1_CIF_MRSZ_CTRL (RKISP1_CIF_MRSZ_BASE + 0x00000000) +#define RKISP1_CIF_MRSZ_SCALE_HY (RKISP1_CIF_MRSZ_BASE + 0x00000004) +#define RKISP1_CIF_MRSZ_SCALE_HCB (RKISP1_CIF_MRSZ_BASE + 0x00000008) +#define RKISP1_CIF_MRSZ_SCALE_HCR (RKISP1_CIF_MRSZ_BASE + 0x0000000C) +#define RKISP1_CIF_MRSZ_SCALE_VY (RKISP1_CIF_MRSZ_BASE + 0x00000010) +#define RKISP1_CIF_MRSZ_SCALE_VC (RKISP1_CIF_MRSZ_BASE + 0x00000014) +#define RKISP1_CIF_MRSZ_PHASE_HY (RKISP1_CIF_MRSZ_BASE + 0x00000018) +#define RKISP1_CIF_MRSZ_PHASE_HC (RKISP1_CIF_MRSZ_BASE + 0x0000001C) +#define RKISP1_CIF_MRSZ_PHASE_VY (RKISP1_CIF_MRSZ_BASE + 0x00000020) +#define RKISP1_CIF_MRSZ_PHASE_VC (RKISP1_CIF_MRSZ_BASE + 0x00000024) +#define RKISP1_CIF_MRSZ_SCALE_LUT_ADDR (RKISP1_CIF_MRSZ_BASE + 0x00000028) +#define RKISP1_CIF_MRSZ_SCALE_LUT (RKISP1_CIF_MRSZ_BASE + 0x0000002C) +#define RKISP1_CIF_MRSZ_CTRL_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000030) +#define RKISP1_CIF_MRSZ_SCALE_HY_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000034) +#define RKISP1_CIF_MRSZ_SCALE_HCB_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000038) +#define RKISP1_CIF_MRSZ_SCALE_HCR_SHD (RKISP1_CIF_MRSZ_BASE + 0x0000003C) +#define RKISP1_CIF_MRSZ_SCALE_VY_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000040) +#define RKISP1_CIF_MRSZ_SCALE_VC_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000044) +#define RKISP1_CIF_MRSZ_PHASE_HY_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000048) +#define RKISP1_CIF_MRSZ_PHASE_HC_SHD (RKISP1_CIF_MRSZ_BASE + 0x0000004C) +#define RKISP1_CIF_MRSZ_PHASE_VY_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000050) +#define RKISP1_CIF_MRSZ_PHASE_VC_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000054) + +#define RKISP1_CIF_SRSZ_BASE 0x00001000 +#define RKISP1_CIF_SRSZ_CTRL (RKISP1_CIF_SRSZ_BASE + 0x00000000) +#define RKISP1_CIF_SRSZ_SCALE_HY (RKISP1_CIF_SRSZ_BASE + 0x00000004) +#define RKISP1_CIF_SRSZ_SCALE_HCB (RKISP1_CIF_SRSZ_BASE + 0x00000008) +#define RKISP1_CIF_SRSZ_SCALE_HCR (RKISP1_CIF_SRSZ_BASE + 0x0000000C) +#define RKISP1_CIF_SRSZ_SCALE_VY (RKISP1_CIF_SRSZ_BASE + 0x00000010) +#define RKISP1_CIF_SRSZ_SCALE_VC (RKISP1_CIF_SRSZ_BASE + 0x00000014) +#define RKISP1_CIF_SRSZ_PHASE_HY (RKISP1_CIF_SRSZ_BASE + 0x00000018) +#define RKISP1_CIF_SRSZ_PHASE_HC (RKISP1_CIF_SRSZ_BASE + 0x0000001C) +#define RKISP1_CIF_SRSZ_PHASE_VY (RKISP1_CIF_SRSZ_BASE + 0x00000020) +#define RKISP1_CIF_SRSZ_PHASE_VC (RKISP1_CIF_SRSZ_BASE + 0x00000024) +#define RKISP1_CIF_SRSZ_SCALE_LUT_ADDR (RKISP1_CIF_SRSZ_BASE + 0x00000028) +#define RKISP1_CIF_SRSZ_SCALE_LUT (RKISP1_CIF_SRSZ_BASE + 0x0000002C) +#define RKISP1_CIF_SRSZ_CTRL_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000030) +#define RKISP1_CIF_SRSZ_SCALE_HY_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000034) +#define RKISP1_CIF_SRSZ_SCALE_HCB_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000038) +#define RKISP1_CIF_SRSZ_SCALE_HCR_SHD (RKISP1_CIF_SRSZ_BASE + 0x0000003C) +#define RKISP1_CIF_SRSZ_SCALE_VY_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000040) +#define RKISP1_CIF_SRSZ_SCALE_VC_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000044) +#define RKISP1_CIF_SRSZ_PHASE_HY_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000048) +#define RKISP1_CIF_SRSZ_PHASE_HC_SHD (RKISP1_CIF_SRSZ_BASE + 0x0000004C) +#define RKISP1_CIF_SRSZ_PHASE_VY_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000050) +#define RKISP1_CIF_SRSZ_PHASE_VC_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000054) + +#define RKISP1_CIF_MI_BASE 0x00001400 +#define RKISP1_CIF_MI_CTRL (RKISP1_CIF_MI_BASE + 0x00000000) +#define RKISP1_CIF_MI_INIT (RKISP1_CIF_MI_BASE + 0x00000004) +#define RKISP1_CIF_MI_MP_Y_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x00000008) +#define RKISP1_CIF_MI_MP_Y_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x0000000C) +#define RKISP1_CIF_MI_MP_Y_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000010) +#define RKISP1_CIF_MI_MP_Y_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x00000014) +#define RKISP1_CIF_MI_MP_Y_IRQ_OFFS_INIT (RKISP1_CIF_MI_BASE + 0x00000018) +#define RKISP1_CIF_MI_MP_CB_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x0000001C) +#define RKISP1_CIF_MI_MP_CB_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x00000020) +#define RKISP1_CIF_MI_MP_CB_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000024) +#define RKISP1_CIF_MI_MP_CB_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x00000028) +#define RKISP1_CIF_MI_MP_CR_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x0000002C) +#define RKISP1_CIF_MI_MP_CR_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x00000030) +#define RKISP1_CIF_MI_MP_CR_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000034) +#define RKISP1_CIF_MI_MP_CR_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x00000038) +#define RKISP1_CIF_MI_SP_Y_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x0000003C) +#define RKISP1_CIF_MI_SP_Y_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x00000040) +#define RKISP1_CIF_MI_SP_Y_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000044) +#define RKISP1_CIF_MI_SP_Y_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x00000048) +#define RKISP1_CIF_MI_SP_Y_LLENGTH (RKISP1_CIF_MI_BASE + 0x0000004C) +#define RKISP1_CIF_MI_SP_CB_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x00000050) +#define RKISP1_CIF_MI_SP_CB_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x00000054) +#define RKISP1_CIF_MI_SP_CB_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000058) +#define RKISP1_CIF_MI_SP_CB_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x0000005C) +#define RKISP1_CIF_MI_SP_CR_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x00000060) +#define RKISP1_CIF_MI_SP_CR_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x00000064) +#define RKISP1_CIF_MI_SP_CR_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000068) +#define RKISP1_CIF_MI_SP_CR_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x0000006C) +#define RKISP1_CIF_MI_BYTE_CNT (RKISP1_CIF_MI_BASE + 0x00000070) +#define RKISP1_CIF_MI_CTRL_SHD (RKISP1_CIF_MI_BASE + 0x00000074) +#define RKISP1_CIF_MI_MP_Y_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x00000078) +#define RKISP1_CIF_MI_MP_Y_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x0000007C) +#define RKISP1_CIF_MI_MP_Y_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x00000080) +#define RKISP1_CIF_MI_MP_Y_IRQ_OFFS_SHD (RKISP1_CIF_MI_BASE + 0x00000084) +#define RKISP1_CIF_MI_MP_CB_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x00000088) +#define RKISP1_CIF_MI_MP_CB_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x0000008C) +#define RKISP1_CIF_MI_MP_CB_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x00000090) +#define RKISP1_CIF_MI_MP_CR_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x00000094) +#define RKISP1_CIF_MI_MP_CR_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x00000098) +#define RKISP1_CIF_MI_MP_CR_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x0000009C) +#define RKISP1_CIF_MI_SP_Y_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x000000A0) +#define RKISP1_CIF_MI_SP_Y_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x000000A4) +#define RKISP1_CIF_MI_SP_Y_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x000000A8) +#define RKISP1_CIF_MI_SP_CB_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x000000B0) +#define RKISP1_CIF_MI_SP_CB_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x000000B4) +#define RKISP1_CIF_MI_SP_CB_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x000000B8) +#define RKISP1_CIF_MI_SP_CR_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x000000BC) +#define RKISP1_CIF_MI_SP_CR_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x000000C0) +#define RKISP1_CIF_MI_SP_CR_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x000000C4) +#define RKISP1_CIF_MI_DMA_Y_PIC_START_AD (RKISP1_CIF_MI_BASE + 0x000000C8) +#define RKISP1_CIF_MI_DMA_Y_PIC_WIDTH (RKISP1_CIF_MI_BASE + 0x000000CC) +#define RKISP1_CIF_MI_DMA_Y_LLENGTH (RKISP1_CIF_MI_BASE + 0x000000D0) +#define RKISP1_CIF_MI_DMA_Y_PIC_SIZE (RKISP1_CIF_MI_BASE + 0x000000D4) +#define RKISP1_CIF_MI_DMA_CB_PIC_START_AD (RKISP1_CIF_MI_BASE + 0x000000D8) +#define RKISP1_CIF_MI_DMA_CR_PIC_START_AD (RKISP1_CIF_MI_BASE + 0x000000E8) +#define RKISP1_CIF_MI_IMSC (RKISP1_CIF_MI_BASE + 0x000000F8) +#define RKISP1_CIF_MI_RIS (RKISP1_CIF_MI_BASE + 0x000000FC) +#define RKISP1_CIF_MI_MIS (RKISP1_CIF_MI_BASE + 0x00000100) +#define RKISP1_CIF_MI_ICR (RKISP1_CIF_MI_BASE + 0x00000104) +#define RKISP1_CIF_MI_ISR (RKISP1_CIF_MI_BASE + 0x00000108) +#define RKISP1_CIF_MI_STATUS (RKISP1_CIF_MI_BASE + 0x0000010C) +#define RKISP1_CIF_MI_STATUS_CLR (RKISP1_CIF_MI_BASE + 0x00000110) +#define RKISP1_CIF_MI_SP_Y_PIC_WIDTH (RKISP1_CIF_MI_BASE + 0x00000114) +#define RKISP1_CIF_MI_SP_Y_PIC_HEIGHT (RKISP1_CIF_MI_BASE + 0x00000118) +#define RKISP1_CIF_MI_SP_Y_PIC_SIZE (RKISP1_CIF_MI_BASE + 0x0000011C) +#define RKISP1_CIF_MI_DMA_CTRL (RKISP1_CIF_MI_BASE + 0x00000120) +#define RKISP1_CIF_MI_DMA_START (RKISP1_CIF_MI_BASE + 0x00000124) +#define RKISP1_CIF_MI_DMA_STATUS (RKISP1_CIF_MI_BASE + 0x00000128) +#define RKISP1_CIF_MI_PIXEL_COUNT (RKISP1_CIF_MI_BASE + 0x0000012C) +#define RKISP1_CIF_MI_MP_Y_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000130) +#define RKISP1_CIF_MI_MP_CB_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000134) +#define RKISP1_CIF_MI_MP_CR_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000138) +#define RKISP1_CIF_MI_SP_Y_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x0000013C) +#define RKISP1_CIF_MI_SP_CB_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000140) +#define RKISP1_CIF_MI_SP_CR_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000144) +#define RKISP1_CIF_MI_XTD_FORMAT_CTRL (RKISP1_CIF_MI_BASE + 0x00000148) + +#define RKISP1_CIF_SMIA_BASE 0x00001A00 +#define RKISP1_CIF_SMIA_CTRL (RKISP1_CIF_SMIA_BASE + 0x00000000) +#define RKISP1_CIF_SMIA_STATUS (RKISP1_CIF_SMIA_BASE + 0x00000004) +#define RKISP1_CIF_SMIA_IMSC (RKISP1_CIF_SMIA_BASE + 0x00000008) +#define RKISP1_CIF_SMIA_RIS (RKISP1_CIF_SMIA_BASE + 0x0000000C) +#define RKISP1_CIF_SMIA_MIS (RKISP1_CIF_SMIA_BASE + 0x00000010) +#define RKISP1_CIF_SMIA_ICR (RKISP1_CIF_SMIA_BASE + 0x00000014) +#define RKISP1_CIF_SMIA_ISR (RKISP1_CIF_SMIA_BASE + 0x00000018) +#define RKISP1_CIF_SMIA_DATA_FORMAT_SEL (RKISP1_CIF_SMIA_BASE + 0x0000001C) +#define RKISP1_CIF_SMIA_SOF_EMB_DATA_LINES (RKISP1_CIF_SMIA_BASE + 0x00000020) +#define RKISP1_CIF_SMIA_EMB_HSTART (RKISP1_CIF_SMIA_BASE + 0x00000024) +#define RKISP1_CIF_SMIA_EMB_HSIZE (RKISP1_CIF_SMIA_BASE + 0x00000028) +#define RKISP1_CIF_SMIA_EMB_VSTART (RKISP1_CIF_SMIA_BASE + 0x0000002c) +#define RKISP1_CIF_SMIA_NUM_LINES (RKISP1_CIF_SMIA_BASE + 0x00000030) +#define RKISP1_CIF_SMIA_EMB_DATA_FIFO (RKISP1_CIF_SMIA_BASE + 0x00000034) +#define RKISP1_CIF_SMIA_EMB_DATA_WATERMARK (RKISP1_CIF_SMIA_BASE + 0x00000038) + +#define RKISP1_CIF_MIPI_BASE 0x00001C00 +#define RKISP1_CIF_MIPI_CTRL (RKISP1_CIF_MIPI_BASE + 0x00000000) +#define RKISP1_CIF_MIPI_STATUS (RKISP1_CIF_MIPI_BASE + 0x00000004) +#define RKISP1_CIF_MIPI_IMSC (RKISP1_CIF_MIPI_BASE + 0x00000008) +#define RKISP1_CIF_MIPI_RIS (RKISP1_CIF_MIPI_BASE + 0x0000000C) +#define RKISP1_CIF_MIPI_MIS (RKISP1_CIF_MIPI_BASE + 0x00000010) +#define RKISP1_CIF_MIPI_ICR (RKISP1_CIF_MIPI_BASE + 0x00000014) +#define RKISP1_CIF_MIPI_ISR (RKISP1_CIF_MIPI_BASE + 0x00000018) +#define RKISP1_CIF_MIPI_CUR_DATA_ID (RKISP1_CIF_MIPI_BASE + 0x0000001C) +#define RKISP1_CIF_MIPI_IMG_DATA_SEL (RKISP1_CIF_MIPI_BASE + 0x00000020) +#define RKISP1_CIF_MIPI_ADD_DATA_SEL_1 (RKISP1_CIF_MIPI_BASE + 0x00000024) +#define RKISP1_CIF_MIPI_ADD_DATA_SEL_2 (RKISP1_CIF_MIPI_BASE + 0x00000028) +#define RKISP1_CIF_MIPI_ADD_DATA_SEL_3 (RKISP1_CIF_MIPI_BASE + 0x0000002C) +#define RKISP1_CIF_MIPI_ADD_DATA_SEL_4 (RKISP1_CIF_MIPI_BASE + 0x00000030) +#define RKISP1_CIF_MIPI_ADD_DATA_FIFO (RKISP1_CIF_MIPI_BASE + 0x00000034) +#define RKISP1_CIF_MIPI_FIFO_FILL_LEVEL (RKISP1_CIF_MIPI_BASE + 0x00000038) +#define RKISP1_CIF_MIPI_COMPRESSED_MODE (RKISP1_CIF_MIPI_BASE + 0x0000003C) +#define RKISP1_CIF_MIPI_FRAME (RKISP1_CIF_MIPI_BASE + 0x00000040) +#define RKISP1_CIF_MIPI_GEN_SHORT_DT (RKISP1_CIF_MIPI_BASE + 0x00000044) +#define RKISP1_CIF_MIPI_GEN_SHORT_8_9 (RKISP1_CIF_MIPI_BASE + 0x00000048) +#define RKISP1_CIF_MIPI_GEN_SHORT_A_B (RKISP1_CIF_MIPI_BASE + 0x0000004C) +#define RKISP1_CIF_MIPI_GEN_SHORT_C_D (RKISP1_CIF_MIPI_BASE + 0x00000050) +#define RKISP1_CIF_MIPI_GEN_SHORT_E_F (RKISP1_CIF_MIPI_BASE + 0x00000054) + +#define RKISP1_CIF_ISP_AFM_BASE 0x00002000 +#define RKISP1_CIF_ISP_AFM_CTRL (RKISP1_CIF_ISP_AFM_BASE + 0x00000000) +#define RKISP1_CIF_ISP_AFM_LT_A (RKISP1_CIF_ISP_AFM_BASE + 0x00000004) +#define RKISP1_CIF_ISP_AFM_RB_A (RKISP1_CIF_ISP_AFM_BASE + 0x00000008) +#define RKISP1_CIF_ISP_AFM_LT_B (RKISP1_CIF_ISP_AFM_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_AFM_RB_B (RKISP1_CIF_ISP_AFM_BASE + 0x00000010) +#define RKISP1_CIF_ISP_AFM_LT_C (RKISP1_CIF_ISP_AFM_BASE + 0x00000014) +#define RKISP1_CIF_ISP_AFM_RB_C (RKISP1_CIF_ISP_AFM_BASE + 0x00000018) +#define RKISP1_CIF_ISP_AFM_THRES (RKISP1_CIF_ISP_AFM_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_AFM_VAR_SHIFT (RKISP1_CIF_ISP_AFM_BASE + 0x00000020) +#define RKISP1_CIF_ISP_AFM_SUM_A (RKISP1_CIF_ISP_AFM_BASE + 0x00000024) +#define RKISP1_CIF_ISP_AFM_SUM_B (RKISP1_CIF_ISP_AFM_BASE + 0x00000028) +#define RKISP1_CIF_ISP_AFM_SUM_C (RKISP1_CIF_ISP_AFM_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_AFM_LUM_A (RKISP1_CIF_ISP_AFM_BASE + 0x00000030) +#define RKISP1_CIF_ISP_AFM_LUM_B (RKISP1_CIF_ISP_AFM_BASE + 0x00000034) +#define RKISP1_CIF_ISP_AFM_LUM_C (RKISP1_CIF_ISP_AFM_BASE + 0x00000038) + +#define RKISP1_CIF_ISP_LSC_BASE 0x00002200 +#define RKISP1_CIF_ISP_LSC_CTRL (RKISP1_CIF_ISP_LSC_BASE + 0x00000000) +#define RKISP1_CIF_ISP_LSC_R_TABLE_ADDR (RKISP1_CIF_ISP_LSC_BASE + 0x00000004) +#define RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR (RKISP1_CIF_ISP_LSC_BASE + 0x00000008) +#define RKISP1_CIF_ISP_LSC_B_TABLE_ADDR (RKISP1_CIF_ISP_LSC_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR (RKISP1_CIF_ISP_LSC_BASE + 0x00000010) +#define RKISP1_CIF_ISP_LSC_R_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x00000014) +#define RKISP1_CIF_ISP_LSC_GR_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x00000018) +#define RKISP1_CIF_ISP_LSC_B_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_LSC_GB_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x00000020) +#define RKISP1_CIF_ISP_LSC_XGRAD_01 (RKISP1_CIF_ISP_LSC_BASE + 0x00000024) +#define RKISP1_CIF_ISP_LSC_XGRAD_23 (RKISP1_CIF_ISP_LSC_BASE + 0x00000028) +#define RKISP1_CIF_ISP_LSC_XGRAD_45 (RKISP1_CIF_ISP_LSC_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_LSC_XGRAD_67 (RKISP1_CIF_ISP_LSC_BASE + 0x00000030) +#define RKISP1_CIF_ISP_LSC_YGRAD_01 (RKISP1_CIF_ISP_LSC_BASE + 0x00000034) +#define RKISP1_CIF_ISP_LSC_YGRAD_23 (RKISP1_CIF_ISP_LSC_BASE + 0x00000038) +#define RKISP1_CIF_ISP_LSC_YGRAD_45 (RKISP1_CIF_ISP_LSC_BASE + 0x0000003C) +#define RKISP1_CIF_ISP_LSC_YGRAD_67 (RKISP1_CIF_ISP_LSC_BASE + 0x00000040) +#define RKISP1_CIF_ISP_LSC_XSIZE_01 (RKISP1_CIF_ISP_LSC_BASE + 0x00000044) +#define RKISP1_CIF_ISP_LSC_XSIZE_23 (RKISP1_CIF_ISP_LSC_BASE + 0x00000048) +#define RKISP1_CIF_ISP_LSC_XSIZE_45 (RKISP1_CIF_ISP_LSC_BASE + 0x0000004C) +#define RKISP1_CIF_ISP_LSC_XSIZE_67 (RKISP1_CIF_ISP_LSC_BASE + 0x00000050) +#define RKISP1_CIF_ISP_LSC_YSIZE_01 (RKISP1_CIF_ISP_LSC_BASE + 0x00000054) +#define RKISP1_CIF_ISP_LSC_YSIZE_23 (RKISP1_CIF_ISP_LSC_BASE + 0x00000058) +#define RKISP1_CIF_ISP_LSC_YSIZE_45 (RKISP1_CIF_ISP_LSC_BASE + 0x0000005C) +#define RKISP1_CIF_ISP_LSC_YSIZE_67 (RKISP1_CIF_ISP_LSC_BASE + 0x00000060) +#define RKISP1_CIF_ISP_LSC_TABLE_SEL (RKISP1_CIF_ISP_LSC_BASE + 0x00000064) +#define RKISP1_CIF_ISP_LSC_STATUS (RKISP1_CIF_ISP_LSC_BASE + 0x00000068) + +#define RKISP1_CIF_ISP_IS_BASE 0x00002300 +#define RKISP1_CIF_ISP_IS_CTRL (RKISP1_CIF_ISP_IS_BASE + 0x00000000) +#define RKISP1_CIF_ISP_IS_RECENTER (RKISP1_CIF_ISP_IS_BASE + 0x00000004) +#define RKISP1_CIF_ISP_IS_H_OFFS (RKISP1_CIF_ISP_IS_BASE + 0x00000008) +#define RKISP1_CIF_ISP_IS_V_OFFS (RKISP1_CIF_ISP_IS_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_IS_H_SIZE (RKISP1_CIF_ISP_IS_BASE + 0x00000010) +#define RKISP1_CIF_ISP_IS_V_SIZE (RKISP1_CIF_ISP_IS_BASE + 0x00000014) +#define RKISP1_CIF_ISP_IS_MAX_DX (RKISP1_CIF_ISP_IS_BASE + 0x00000018) +#define RKISP1_CIF_ISP_IS_MAX_DY (RKISP1_CIF_ISP_IS_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_IS_DISPLACE (RKISP1_CIF_ISP_IS_BASE + 0x00000020) +#define RKISP1_CIF_ISP_IS_H_OFFS_SHD (RKISP1_CIF_ISP_IS_BASE + 0x00000024) +#define RKISP1_CIF_ISP_IS_V_OFFS_SHD (RKISP1_CIF_ISP_IS_BASE + 0x00000028) +#define RKISP1_CIF_ISP_IS_H_SIZE_SHD (RKISP1_CIF_ISP_IS_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_IS_V_SIZE_SHD (RKISP1_CIF_ISP_IS_BASE + 0x00000030) + +#define RKISP1_CIF_ISP_HIST_BASE 0x00002400 + +#define RKISP1_CIF_ISP_HIST_PROP (RKISP1_CIF_ISP_HIST_BASE + 0x00000000) +#define RKISP1_CIF_ISP_HIST_H_OFFS (RKISP1_CIF_ISP_HIST_BASE + 0x00000004) +#define RKISP1_CIF_ISP_HIST_V_OFFS (RKISP1_CIF_ISP_HIST_BASE + 0x00000008) +#define RKISP1_CIF_ISP_HIST_H_SIZE (RKISP1_CIF_ISP_HIST_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_HIST_V_SIZE (RKISP1_CIF_ISP_HIST_BASE + 0x00000010) +#define RKISP1_CIF_ISP_HIST_BIN_0 (RKISP1_CIF_ISP_HIST_BASE + 0x00000014) +#define RKISP1_CIF_ISP_HIST_BIN_1 (RKISP1_CIF_ISP_HIST_BASE + 0x00000018) +#define RKISP1_CIF_ISP_HIST_BIN_2 (RKISP1_CIF_ISP_HIST_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_HIST_BIN_3 (RKISP1_CIF_ISP_HIST_BASE + 0x00000020) +#define RKISP1_CIF_ISP_HIST_BIN_4 (RKISP1_CIF_ISP_HIST_BASE + 0x00000024) +#define RKISP1_CIF_ISP_HIST_BIN_5 (RKISP1_CIF_ISP_HIST_BASE + 0x00000028) +#define RKISP1_CIF_ISP_HIST_BIN_6 (RKISP1_CIF_ISP_HIST_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_HIST_BIN_7 (RKISP1_CIF_ISP_HIST_BASE + 0x00000030) +#define RKISP1_CIF_ISP_HIST_BIN_8 (RKISP1_CIF_ISP_HIST_BASE + 0x00000034) +#define RKISP1_CIF_ISP_HIST_BIN_9 (RKISP1_CIF_ISP_HIST_BASE + 0x00000038) +#define RKISP1_CIF_ISP_HIST_BIN_10 (RKISP1_CIF_ISP_HIST_BASE + 0x0000003C) +#define RKISP1_CIF_ISP_HIST_BIN_11 (RKISP1_CIF_ISP_HIST_BASE + 0x00000040) +#define RKISP1_CIF_ISP_HIST_BIN_12 (RKISP1_CIF_ISP_HIST_BASE + 0x00000044) +#define RKISP1_CIF_ISP_HIST_BIN_13 (RKISP1_CIF_ISP_HIST_BASE + 0x00000048) +#define RKISP1_CIF_ISP_HIST_BIN_14 (RKISP1_CIF_ISP_HIST_BASE + 0x0000004C) +#define RKISP1_CIF_ISP_HIST_BIN_15 (RKISP1_CIF_ISP_HIST_BASE + 0x00000050) +#define RKISP1_CIF_ISP_HIST_WEIGHT_00TO30 (RKISP1_CIF_ISP_HIST_BASE + 0x00000054) +#define RKISP1_CIF_ISP_HIST_WEIGHT_40TO21 (RKISP1_CIF_ISP_HIST_BASE + 0x00000058) +#define RKISP1_CIF_ISP_HIST_WEIGHT_31TO12 (RKISP1_CIF_ISP_HIST_BASE + 0x0000005C) +#define RKISP1_CIF_ISP_HIST_WEIGHT_22TO03 (RKISP1_CIF_ISP_HIST_BASE + 0x00000060) +#define RKISP1_CIF_ISP_HIST_WEIGHT_13TO43 (RKISP1_CIF_ISP_HIST_BASE + 0x00000064) +#define RKISP1_CIF_ISP_HIST_WEIGHT_04TO34 (RKISP1_CIF_ISP_HIST_BASE + 0x00000068) +#define RKISP1_CIF_ISP_HIST_WEIGHT_44 (RKISP1_CIF_ISP_HIST_BASE + 0x0000006C) + +#define RKISP1_CIF_ISP_FILT_BASE 0x00002500 +#define RKISP1_CIF_ISP_FILT_MODE (RKISP1_CIF_ISP_FILT_BASE + 0x00000000) +#define RKISP1_CIF_ISP_FILT_THRESH_BL0 (RKISP1_CIF_ISP_FILT_BASE + 0x00000028) +#define RKISP1_CIF_ISP_FILT_THRESH_BL1 (RKISP1_CIF_ISP_FILT_BASE + 0x0000002c) +#define RKISP1_CIF_ISP_FILT_THRESH_SH0 (RKISP1_CIF_ISP_FILT_BASE + 0x00000030) +#define RKISP1_CIF_ISP_FILT_THRESH_SH1 (RKISP1_CIF_ISP_FILT_BASE + 0x00000034) +#define RKISP1_CIF_ISP_FILT_LUM_WEIGHT (RKISP1_CIF_ISP_FILT_BASE + 0x00000038) +#define RKISP1_CIF_ISP_FILT_FAC_SH1 (RKISP1_CIF_ISP_FILT_BASE + 0x0000003c) +#define RKISP1_CIF_ISP_FILT_FAC_SH0 (RKISP1_CIF_ISP_FILT_BASE + 0x00000040) +#define RKISP1_CIF_ISP_FILT_FAC_MID (RKISP1_CIF_ISP_FILT_BASE + 0x00000044) +#define RKISP1_CIF_ISP_FILT_FAC_BL0 (RKISP1_CIF_ISP_FILT_BASE + 0x00000048) +#define RKISP1_CIF_ISP_FILT_FAC_BL1 (RKISP1_CIF_ISP_FILT_BASE + 0x0000004C) + +#define RKISP1_CIF_ISP_CAC_BASE 0x00002580 +#define RKISP1_CIF_ISP_CAC_CTRL (RKISP1_CIF_ISP_CAC_BASE + 0x00000000) +#define RKISP1_CIF_ISP_CAC_COUNT_START (RKISP1_CIF_ISP_CAC_BASE + 0x00000004) +#define RKISP1_CIF_ISP_CAC_A (RKISP1_CIF_ISP_CAC_BASE + 0x00000008) +#define RKISP1_CIF_ISP_CAC_B (RKISP1_CIF_ISP_CAC_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_CAC_C (RKISP1_CIF_ISP_CAC_BASE + 0x00000010) +#define RKISP1_CIF_ISP_X_NORM (RKISP1_CIF_ISP_CAC_BASE + 0x00000014) +#define RKISP1_CIF_ISP_Y_NORM (RKISP1_CIF_ISP_CAC_BASE + 0x00000018) + +#define RKISP1_CIF_ISP_EXP_BASE 0x00002600 +#define RKISP1_CIF_ISP_EXP_CTRL (RKISP1_CIF_ISP_EXP_BASE + 0x00000000) +#define RKISP1_CIF_ISP_EXP_H_OFFSET (RKISP1_CIF_ISP_EXP_BASE + 0x00000004) +#define RKISP1_CIF_ISP_EXP_V_OFFSET (RKISP1_CIF_ISP_EXP_BASE + 0x00000008) +#define RKISP1_CIF_ISP_EXP_H_SIZE (RKISP1_CIF_ISP_EXP_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_EXP_V_SIZE (RKISP1_CIF_ISP_EXP_BASE + 0x00000010) +#define RKISP1_CIF_ISP_EXP_MEAN_00 (RKISP1_CIF_ISP_EXP_BASE + 0x00000014) +#define RKISP1_CIF_ISP_EXP_MEAN_10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000018) +#define RKISP1_CIF_ISP_EXP_MEAN_20 (RKISP1_CIF_ISP_EXP_BASE + 0x0000001c) +#define RKISP1_CIF_ISP_EXP_MEAN_30 (RKISP1_CIF_ISP_EXP_BASE + 0x00000020) +#define RKISP1_CIF_ISP_EXP_MEAN_40 (RKISP1_CIF_ISP_EXP_BASE + 0x00000024) +#define RKISP1_CIF_ISP_EXP_MEAN_01 (RKISP1_CIF_ISP_EXP_BASE + 0x00000028) +#define RKISP1_CIF_ISP_EXP_MEAN_11 (RKISP1_CIF_ISP_EXP_BASE + 0x0000002c) +#define RKISP1_CIF_ISP_EXP_MEAN_21 (RKISP1_CIF_ISP_EXP_BASE + 0x00000030) +#define RKISP1_CIF_ISP_EXP_MEAN_31 (RKISP1_CIF_ISP_EXP_BASE + 0x00000034) +#define RKISP1_CIF_ISP_EXP_MEAN_41 (RKISP1_CIF_ISP_EXP_BASE + 0x00000038) +#define RKISP1_CIF_ISP_EXP_MEAN_02 (RKISP1_CIF_ISP_EXP_BASE + 0x0000003c) +#define RKISP1_CIF_ISP_EXP_MEAN_12 (RKISP1_CIF_ISP_EXP_BASE + 0x00000040) +#define RKISP1_CIF_ISP_EXP_MEAN_22 (RKISP1_CIF_ISP_EXP_BASE + 0x00000044) +#define RKISP1_CIF_ISP_EXP_MEAN_32 (RKISP1_CIF_ISP_EXP_BASE + 0x00000048) +#define RKISP1_CIF_ISP_EXP_MEAN_42 (RKISP1_CIF_ISP_EXP_BASE + 0x0000004c) +#define RKISP1_CIF_ISP_EXP_MEAN_03 (RKISP1_CIF_ISP_EXP_BASE + 0x00000050) +#define RKISP1_CIF_ISP_EXP_MEAN_13 (RKISP1_CIF_ISP_EXP_BASE + 0x00000054) +#define RKISP1_CIF_ISP_EXP_MEAN_23 (RKISP1_CIF_ISP_EXP_BASE + 0x00000058) +#define RKISP1_CIF_ISP_EXP_MEAN_33 (RKISP1_CIF_ISP_EXP_BASE + 0x0000005c) +#define RKISP1_CIF_ISP_EXP_MEAN_43 (RKISP1_CIF_ISP_EXP_BASE + 0x00000060) +#define RKISP1_CIF_ISP_EXP_MEAN_04 (RKISP1_CIF_ISP_EXP_BASE + 0x00000064) +#define RKISP1_CIF_ISP_EXP_MEAN_14 (RKISP1_CIF_ISP_EXP_BASE + 0x00000068) +#define RKISP1_CIF_ISP_EXP_MEAN_24 (RKISP1_CIF_ISP_EXP_BASE + 0x0000006c) +#define RKISP1_CIF_ISP_EXP_MEAN_34 (RKISP1_CIF_ISP_EXP_BASE + 0x00000070) +#define RKISP1_CIF_ISP_EXP_MEAN_44 (RKISP1_CIF_ISP_EXP_BASE + 0x00000074) + +#define RKISP1_CIF_ISP_BLS_BASE 0x00002700 +#define RKISP1_CIF_ISP_BLS_CTRL (RKISP1_CIF_ISP_BLS_BASE + 0x00000000) +#define RKISP1_CIF_ISP_BLS_SAMPLES (RKISP1_CIF_ISP_BLS_BASE + 0x00000004) +#define RKISP1_CIF_ISP_BLS_H1_START (RKISP1_CIF_ISP_BLS_BASE + 0x00000008) +#define RKISP1_CIF_ISP_BLS_H1_STOP (RKISP1_CIF_ISP_BLS_BASE + 0x0000000c) +#define RKISP1_CIF_ISP_BLS_V1_START (RKISP1_CIF_ISP_BLS_BASE + 0x00000010) +#define RKISP1_CIF_ISP_BLS_V1_STOP (RKISP1_CIF_ISP_BLS_BASE + 0x00000014) +#define RKISP1_CIF_ISP_BLS_H2_START (RKISP1_CIF_ISP_BLS_BASE + 0x00000018) +#define RKISP1_CIF_ISP_BLS_H2_STOP (RKISP1_CIF_ISP_BLS_BASE + 0x0000001c) +#define RKISP1_CIF_ISP_BLS_V2_START (RKISP1_CIF_ISP_BLS_BASE + 0x00000020) +#define RKISP1_CIF_ISP_BLS_V2_STOP (RKISP1_CIF_ISP_BLS_BASE + 0x00000024) +#define RKISP1_CIF_ISP_BLS_A_FIXED (RKISP1_CIF_ISP_BLS_BASE + 0x00000028) +#define RKISP1_CIF_ISP_BLS_B_FIXED (RKISP1_CIF_ISP_BLS_BASE + 0x0000002c) +#define RKISP1_CIF_ISP_BLS_C_FIXED (RKISP1_CIF_ISP_BLS_BASE + 0x00000030) +#define RKISP1_CIF_ISP_BLS_D_FIXED (RKISP1_CIF_ISP_BLS_BASE + 0x00000034) +#define RKISP1_CIF_ISP_BLS_A_MEASURED (RKISP1_CIF_ISP_BLS_BASE + 0x00000038) +#define RKISP1_CIF_ISP_BLS_B_MEASURED (RKISP1_CIF_ISP_BLS_BASE + 0x0000003c) +#define RKISP1_CIF_ISP_BLS_C_MEASURED (RKISP1_CIF_ISP_BLS_BASE + 0x00000040) +#define RKISP1_CIF_ISP_BLS_D_MEASURED (RKISP1_CIF_ISP_BLS_BASE + 0x00000044) + +#define RKISP1_CIF_ISP_DPF_BASE 0x00002800 +#define RKISP1_CIF_ISP_DPF_MODE (RKISP1_CIF_ISP_DPF_BASE + 0x00000000) +#define RKISP1_CIF_ISP_DPF_STRENGTH_R (RKISP1_CIF_ISP_DPF_BASE + 0x00000004) +#define RKISP1_CIF_ISP_DPF_STRENGTH_G (RKISP1_CIF_ISP_DPF_BASE + 0x00000008) +#define RKISP1_CIF_ISP_DPF_STRENGTH_B (RKISP1_CIF_ISP_DPF_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_DPF_S_WEIGHT_G_1_4 (RKISP1_CIF_ISP_DPF_BASE + 0x00000010) +#define RKISP1_CIF_ISP_DPF_S_WEIGHT_G_5_6 (RKISP1_CIF_ISP_DPF_BASE + 0x00000014) +#define RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_1_4 (RKISP1_CIF_ISP_DPF_BASE + 0x00000018) +#define RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_5_6 (RKISP1_CIF_ISP_DPF_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_0 (RKISP1_CIF_ISP_DPF_BASE + 0x00000020) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_1 (RKISP1_CIF_ISP_DPF_BASE + 0x00000024) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_2 (RKISP1_CIF_ISP_DPF_BASE + 0x00000028) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_3 (RKISP1_CIF_ISP_DPF_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_4 (RKISP1_CIF_ISP_DPF_BASE + 0x00000030) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_5 (RKISP1_CIF_ISP_DPF_BASE + 0x00000034) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_6 (RKISP1_CIF_ISP_DPF_BASE + 0x00000038) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_7 (RKISP1_CIF_ISP_DPF_BASE + 0x0000003C) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_8 (RKISP1_CIF_ISP_DPF_BASE + 0x00000040) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_9 (RKISP1_CIF_ISP_DPF_BASE + 0x00000044) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_10 (RKISP1_CIF_ISP_DPF_BASE + 0x00000048) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_11 (RKISP1_CIF_ISP_DPF_BASE + 0x0000004C) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_12 (RKISP1_CIF_ISP_DPF_BASE + 0x00000050) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_13 (RKISP1_CIF_ISP_DPF_BASE + 0x00000054) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_14 (RKISP1_CIF_ISP_DPF_BASE + 0x00000058) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_15 (RKISP1_CIF_ISP_DPF_BASE + 0x0000005C) +#define RKISP1_CIF_ISP_DPF_NULL_COEFF_16 (RKISP1_CIF_ISP_DPF_BASE + 0x00000060) +#define RKISP1_CIF_ISP_DPF_NF_GAIN_R (RKISP1_CIF_ISP_DPF_BASE + 0x00000064) +#define RKISP1_CIF_ISP_DPF_NF_GAIN_GR (RKISP1_CIF_ISP_DPF_BASE + 0x00000068) +#define RKISP1_CIF_ISP_DPF_NF_GAIN_GB (RKISP1_CIF_ISP_DPF_BASE + 0x0000006C) +#define RKISP1_CIF_ISP_DPF_NF_GAIN_B (RKISP1_CIF_ISP_DPF_BASE + 0x00000070) + +#define RKISP1_CIF_ISP_DPCC_BASE 0x00002900 +#define RKISP1_CIF_ISP_DPCC_MODE (RKISP1_CIF_ISP_DPCC_BASE + 0x00000000) +#define RKISP1_CIF_ISP_DPCC_OUTPUT_MODE (RKISP1_CIF_ISP_DPCC_BASE + 0x00000004) +#define RKISP1_CIF_ISP_DPCC_SET_USE (RKISP1_CIF_ISP_DPCC_BASE + 0x00000008) +#define RKISP1_CIF_ISP_DPCC_METHODS_SET_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_DPCC_METHODS_SET_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000010) +#define RKISP1_CIF_ISP_DPCC_METHODS_SET_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000014) +#define RKISP1_CIF_ISP_DPCC_LINE_THRESH_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000018) +#define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_DPCC_PG_FAC_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000020) +#define RKISP1_CIF_ISP_DPCC_RND_THRESH_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000024) +#define RKISP1_CIF_ISP_DPCC_RG_FAC_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000028) +#define RKISP1_CIF_ISP_DPCC_LINE_THRESH_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000030) +#define RKISP1_CIF_ISP_DPCC_PG_FAC_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000034) +#define RKISP1_CIF_ISP_DPCC_RND_THRESH_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000038) +#define RKISP1_CIF_ISP_DPCC_RG_FAC_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000003C) +#define RKISP1_CIF_ISP_DPCC_LINE_THRESH_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000040) +#define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000044) +#define RKISP1_CIF_ISP_DPCC_PG_FAC_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000048) +#define RKISP1_CIF_ISP_DPCC_RND_THRESH_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000004C) +#define RKISP1_CIF_ISP_DPCC_RG_FAC_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000050) +#define RKISP1_CIF_ISP_DPCC_RO_LIMITS (RKISP1_CIF_ISP_DPCC_BASE + 0x00000054) +#define RKISP1_CIF_ISP_DPCC_RND_OFFS (RKISP1_CIF_ISP_DPCC_BASE + 0x00000058) +#define RKISP1_CIF_ISP_DPCC_BPT_CTRL (RKISP1_CIF_ISP_DPCC_BASE + 0x0000005C) +#define RKISP1_CIF_ISP_DPCC_BPT_NUMBER (RKISP1_CIF_ISP_DPCC_BASE + 0x00000060) +#define RKISP1_CIF_ISP_DPCC_BPT_ADDR (RKISP1_CIF_ISP_DPCC_BASE + 0x00000064) +#define RKISP1_CIF_ISP_DPCC_BPT_DATA (RKISP1_CIF_ISP_DPCC_BASE + 0x00000068) + +#define RKISP1_CIF_ISP_WDR_BASE 0x00002A00 +#define RKISP1_CIF_ISP_WDR_CTRL (RKISP1_CIF_ISP_WDR_BASE + 0x00000000) +#define RKISP1_CIF_ISP_WDR_TONECURVE_1 (RKISP1_CIF_ISP_WDR_BASE + 0x00000004) +#define RKISP1_CIF_ISP_WDR_TONECURVE_2 (RKISP1_CIF_ISP_WDR_BASE + 0x00000008) +#define RKISP1_CIF_ISP_WDR_TONECURVE_3 (RKISP1_CIF_ISP_WDR_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_4 (RKISP1_CIF_ISP_WDR_BASE + 0x00000010) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_0 (RKISP1_CIF_ISP_WDR_BASE + 0x00000014) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_1 (RKISP1_CIF_ISP_WDR_BASE + 0x00000018) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_2 (RKISP1_CIF_ISP_WDR_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_3 (RKISP1_CIF_ISP_WDR_BASE + 0x00000020) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_4 (RKISP1_CIF_ISP_WDR_BASE + 0x00000024) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_5 (RKISP1_CIF_ISP_WDR_BASE + 0x00000028) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_6 (RKISP1_CIF_ISP_WDR_BASE + 0x0000002C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_7 (RKISP1_CIF_ISP_WDR_BASE + 0x00000030) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_8 (RKISP1_CIF_ISP_WDR_BASE + 0x00000034) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_9 (RKISP1_CIF_ISP_WDR_BASE + 0x00000038) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_10 (RKISP1_CIF_ISP_WDR_BASE + 0x0000003C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_11 (RKISP1_CIF_ISP_WDR_BASE + 0x00000040) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_12 (RKISP1_CIF_ISP_WDR_BASE + 0x00000044) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_13 (RKISP1_CIF_ISP_WDR_BASE + 0x00000048) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_14 (RKISP1_CIF_ISP_WDR_BASE + 0x0000004C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_15 (RKISP1_CIF_ISP_WDR_BASE + 0x00000050) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_16 (RKISP1_CIF_ISP_WDR_BASE + 0x00000054) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_17 (RKISP1_CIF_ISP_WDR_BASE + 0x00000058) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_18 (RKISP1_CIF_ISP_WDR_BASE + 0x0000005C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_19 (RKISP1_CIF_ISP_WDR_BASE + 0x00000060) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_20 (RKISP1_CIF_ISP_WDR_BASE + 0x00000064) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_21 (RKISP1_CIF_ISP_WDR_BASE + 0x00000068) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_22 (RKISP1_CIF_ISP_WDR_BASE + 0x0000006C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_23 (RKISP1_CIF_ISP_WDR_BASE + 0x00000070) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_24 (RKISP1_CIF_ISP_WDR_BASE + 0x00000074) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_25 (RKISP1_CIF_ISP_WDR_BASE + 0x00000078) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_26 (RKISP1_CIF_ISP_WDR_BASE + 0x0000007C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_27 (RKISP1_CIF_ISP_WDR_BASE + 0x00000080) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_28 (RKISP1_CIF_ISP_WDR_BASE + 0x00000084) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_29 (RKISP1_CIF_ISP_WDR_BASE + 0x00000088) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_30 (RKISP1_CIF_ISP_WDR_BASE + 0x0000008C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_31 (RKISP1_CIF_ISP_WDR_BASE + 0x00000090) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_32 (RKISP1_CIF_ISP_WDR_BASE + 0x00000094) +#define RKISP1_CIF_ISP_WDR_OFFSET (RKISP1_CIF_ISP_WDR_BASE + 0x00000098) +#define RKISP1_CIF_ISP_WDR_DELTAMIN (RKISP1_CIF_ISP_WDR_BASE + 0x0000009C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_1_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000A0) +#define RKISP1_CIF_ISP_WDR_TONECURVE_2_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000A4) +#define RKISP1_CIF_ISP_WDR_TONECURVE_3_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000A8) +#define RKISP1_CIF_ISP_WDR_TONECURVE_4_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000AC) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_0_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000B0) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_1_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000B4) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_2_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000B8) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_3_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000BC) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_4_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000C0) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_5_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000C4) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_6_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000C8) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_7_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000CC) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_8_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000D0) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_9_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000D4) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_10_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000D8) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_11_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000DC) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_12_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000E0) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_13_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000E4) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_14_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000E8) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_15_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000EC) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_16_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000F0) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_17_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000F4) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_18_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000F8) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_19_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000FC) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_20_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000100) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_21_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000104) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_22_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000108) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_23_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x0000010C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_24_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000110) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_25_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000114) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_26_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000118) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_27_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x0000011C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_28_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000120) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_29_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000124) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_30_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000128) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_31_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x0000012C) +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_32_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000130) + +#define RKISP1_CIF_ISP_VSM_BASE 0x00002F00 +#define RKISP1_CIF_ISP_VSM_MODE (RKISP1_CIF_ISP_VSM_BASE + 0x00000000) +#define RKISP1_CIF_ISP_VSM_H_OFFS (RKISP1_CIF_ISP_VSM_BASE + 0x00000004) +#define RKISP1_CIF_ISP_VSM_V_OFFS (RKISP1_CIF_ISP_VSM_BASE + 0x00000008) +#define RKISP1_CIF_ISP_VSM_H_SIZE (RKISP1_CIF_ISP_VSM_BASE + 0x0000000C) +#define RKISP1_CIF_ISP_VSM_V_SIZE (RKISP1_CIF_ISP_VSM_BASE + 0x00000010) +#define RKISP1_CIF_ISP_VSM_H_SEGMENTS (RKISP1_CIF_ISP_VSM_BASE + 0x00000014) +#define RKISP1_CIF_ISP_VSM_V_SEGMENTS (RKISP1_CIF_ISP_VSM_BASE + 0x00000018) +#define RKISP1_CIF_ISP_VSM_DELTA_H (RKISP1_CIF_ISP_VSM_BASE + 0x0000001C) +#define RKISP1_CIF_ISP_VSM_DELTA_V (RKISP1_CIF_ISP_VSM_BASE + 0x00000020) + +#endif /* _RKISP1_REGS_H */ diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c new file mode 100644 index 000000000000..813670ed9577 --- /dev/null +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c @@ -0,0 +1,846 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Rockchip ISP1 Driver - V4l resizer device + * + * Copyright (C) 2019 Collabora, Ltd. + * + * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd. + * Copyright (C) 2017 Rockchip Electronics Co., Ltd. + */ + +#include "rkisp1-common.h" + +#define RKISP1_RSZ_SP_DEV_NAME RKISP1_DRIVER_NAME "_resizer_selfpath" +#define RKISP1_RSZ_MP_DEV_NAME RKISP1_DRIVER_NAME "_resizer_mainpath" + +#define RKISP1_DEF_FMT MEDIA_BUS_FMT_YUYV8_2X8 +#define RKISP1_DEF_PIXEL_ENC V4L2_PIXEL_ENC_YUV + +struct rkisp1_rsz_yuv_mbus_info { + u32 mbus_code; + u32 hdiv; + u32 vdiv; +}; + +static const struct rkisp1_rsz_yuv_mbus_info rkisp1_rsz_yuv_src_formats[] = { + { + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, /* YUV422 */ + .hdiv = 2, + .vdiv = 1, + }, + { + .mbus_code = MEDIA_BUS_FMT_YUYV8_1_5X8, /* YUV420 */ + .hdiv = 2, + .vdiv = 2, + }, +}; + +static const struct rkisp1_rsz_yuv_mbus_info *rkisp1_rsz_get_yuv_mbus_info(u32 mbus_code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(rkisp1_rsz_yuv_src_formats); i++) { + if (rkisp1_rsz_yuv_src_formats[i].mbus_code == mbus_code) + return &rkisp1_rsz_yuv_src_formats[i]; + } + + return NULL; +} + +enum rkisp1_shadow_regs_when { + RKISP1_SHADOW_REGS_SYNC, + RKISP1_SHADOW_REGS_ASYNC, +}; + +struct rkisp1_rsz_config { + /* constrains */ + const int max_rsz_width; + const int max_rsz_height; + const int min_rsz_width; + const int min_rsz_height; + /* registers */ + struct { + u32 ctrl; + u32 ctrl_shd; + u32 scale_hy; + u32 scale_hcr; + u32 scale_hcb; + u32 scale_vy; + u32 scale_vc; + u32 scale_lut; + u32 scale_lut_addr; + u32 scale_hy_shd; + u32 scale_hcr_shd; + u32 scale_hcb_shd; + u32 scale_vy_shd; + u32 scale_vc_shd; + u32 phase_hy; + u32 phase_hc; + u32 phase_vy; + u32 phase_vc; + u32 phase_hy_shd; + u32 phase_hc_shd; + u32 phase_vy_shd; + u32 phase_vc_shd; + } rsz; + struct { + u32 ctrl; + u32 yuvmode_mask; + u32 rawmode_mask; + u32 h_offset; + u32 v_offset; + u32 h_size; + u32 v_size; + } dual_crop; +}; + +static const struct rkisp1_rsz_config rkisp1_rsz_config_mp = { + /* constraints */ + .max_rsz_width = RKISP1_RSZ_MP_SRC_MAX_WIDTH, + .max_rsz_height = RKISP1_RSZ_MP_SRC_MAX_HEIGHT, + .min_rsz_width = RKISP1_RSZ_SRC_MIN_WIDTH, + .min_rsz_height = RKISP1_RSZ_SRC_MIN_HEIGHT, + /* registers */ + .rsz = { + .ctrl = RKISP1_CIF_MRSZ_CTRL, + .scale_hy = RKISP1_CIF_MRSZ_SCALE_HY, + .scale_hcr = RKISP1_CIF_MRSZ_SCALE_HCR, + .scale_hcb = RKISP1_CIF_MRSZ_SCALE_HCB, + .scale_vy = RKISP1_CIF_MRSZ_SCALE_VY, + .scale_vc = RKISP1_CIF_MRSZ_SCALE_VC, + .scale_lut = RKISP1_CIF_MRSZ_SCALE_LUT, + .scale_lut_addr = RKISP1_CIF_MRSZ_SCALE_LUT_ADDR, + .scale_hy_shd = RKISP1_CIF_MRSZ_SCALE_HY_SHD, + .scale_hcr_shd = RKISP1_CIF_MRSZ_SCALE_HCR_SHD, + .scale_hcb_shd = RKISP1_CIF_MRSZ_SCALE_HCB_SHD, + .scale_vy_shd = RKISP1_CIF_MRSZ_SCALE_VY_SHD, + .scale_vc_shd = RKISP1_CIF_MRSZ_SCALE_VC_SHD, + .phase_hy = RKISP1_CIF_MRSZ_PHASE_HY, + .phase_hc = RKISP1_CIF_MRSZ_PHASE_HC, + .phase_vy = RKISP1_CIF_MRSZ_PHASE_VY, + .phase_vc = RKISP1_CIF_MRSZ_PHASE_VC, + .ctrl_shd = RKISP1_CIF_MRSZ_CTRL_SHD, + .phase_hy_shd = RKISP1_CIF_MRSZ_PHASE_HY_SHD, + .phase_hc_shd = RKISP1_CIF_MRSZ_PHASE_HC_SHD, + .phase_vy_shd = RKISP1_CIF_MRSZ_PHASE_VY_SHD, + .phase_vc_shd = RKISP1_CIF_MRSZ_PHASE_VC_SHD, + }, + .dual_crop = { + .ctrl = RKISP1_CIF_DUAL_CROP_CTRL, + .yuvmode_mask = RKISP1_CIF_DUAL_CROP_MP_MODE_YUV, + .rawmode_mask = RKISP1_CIF_DUAL_CROP_MP_MODE_RAW, + .h_offset = RKISP1_CIF_DUAL_CROP_M_H_OFFS, + .v_offset = RKISP1_CIF_DUAL_CROP_M_V_OFFS, + .h_size = RKISP1_CIF_DUAL_CROP_M_H_SIZE, + .v_size = RKISP1_CIF_DUAL_CROP_M_V_SIZE, + }, +}; + +static const struct rkisp1_rsz_config rkisp1_rsz_config_sp = { + /* constraints */ + .max_rsz_width = RKISP1_RSZ_SP_SRC_MAX_WIDTH, + .max_rsz_height = RKISP1_RSZ_SP_SRC_MAX_HEIGHT, + .min_rsz_width = RKISP1_RSZ_SRC_MIN_WIDTH, + .min_rsz_height = RKISP1_RSZ_SRC_MIN_HEIGHT, + /* registers */ + .rsz = { + .ctrl = RKISP1_CIF_SRSZ_CTRL, + .scale_hy = RKISP1_CIF_SRSZ_SCALE_HY, + .scale_hcr = RKISP1_CIF_SRSZ_SCALE_HCR, + .scale_hcb = RKISP1_CIF_SRSZ_SCALE_HCB, + .scale_vy = RKISP1_CIF_SRSZ_SCALE_VY, + .scale_vc = RKISP1_CIF_SRSZ_SCALE_VC, + .scale_lut = RKISP1_CIF_SRSZ_SCALE_LUT, + .scale_lut_addr = RKISP1_CIF_SRSZ_SCALE_LUT_ADDR, + .scale_hy_shd = RKISP1_CIF_SRSZ_SCALE_HY_SHD, + .scale_hcr_shd = RKISP1_CIF_SRSZ_SCALE_HCR_SHD, + .scale_hcb_shd = RKISP1_CIF_SRSZ_SCALE_HCB_SHD, + .scale_vy_shd = RKISP1_CIF_SRSZ_SCALE_VY_SHD, + .scale_vc_shd = RKISP1_CIF_SRSZ_SCALE_VC_SHD, + .phase_hy = RKISP1_CIF_SRSZ_PHASE_HY, + .phase_hc = RKISP1_CIF_SRSZ_PHASE_HC, + .phase_vy = RKISP1_CIF_SRSZ_PHASE_VY, + .phase_vc = RKISP1_CIF_SRSZ_PHASE_VC, + .ctrl_shd = RKISP1_CIF_SRSZ_CTRL_SHD, + .phase_hy_shd = RKISP1_CIF_SRSZ_PHASE_HY_SHD, + .phase_hc_shd = RKISP1_CIF_SRSZ_PHASE_HC_SHD, + .phase_vy_shd = RKISP1_CIF_SRSZ_PHASE_VY_SHD, + .phase_vc_shd = RKISP1_CIF_SRSZ_PHASE_VC_SHD, + }, + .dual_crop = { + .ctrl = RKISP1_CIF_DUAL_CROP_CTRL, + .yuvmode_mask = RKISP1_CIF_DUAL_CROP_SP_MODE_YUV, + .rawmode_mask = RKISP1_CIF_DUAL_CROP_SP_MODE_RAW, + .h_offset = RKISP1_CIF_DUAL_CROP_S_H_OFFS, + .v_offset = RKISP1_CIF_DUAL_CROP_S_V_OFFS, + .h_size = RKISP1_CIF_DUAL_CROP_S_H_SIZE, + .v_size = RKISP1_CIF_DUAL_CROP_S_V_SIZE, + }, +}; + +static struct v4l2_mbus_framefmt * +rkisp1_rsz_get_pad_fmt(struct rkisp1_resizer *rsz, + struct v4l2_subdev_pad_config *cfg, + unsigned int pad, u32 which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_format(&rsz->sd, cfg, pad); + else + return v4l2_subdev_get_try_format(&rsz->sd, rsz->pad_cfg, pad); +} + +static struct v4l2_rect * +rkisp1_rsz_get_pad_crop(struct rkisp1_resizer *rsz, + struct v4l2_subdev_pad_config *cfg, + unsigned int pad, u32 which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_crop(&rsz->sd, cfg, pad); + else + return v4l2_subdev_get_try_crop(&rsz->sd, rsz->pad_cfg, pad); +} + +/* ---------------------------------------------------------------------------- + * Dual crop hw configs + */ + +static void rkisp1_dcrop_disable(struct rkisp1_resizer *rsz, + enum rkisp1_shadow_regs_when when) +{ + u32 dc_ctrl = rkisp1_read(rsz->rkisp1, rsz->config->dual_crop.ctrl); + u32 mask = ~(rsz->config->dual_crop.yuvmode_mask | + rsz->config->dual_crop.rawmode_mask); + + dc_ctrl &= mask; + if (when == RKISP1_SHADOW_REGS_ASYNC) + dc_ctrl |= RKISP1_CIF_DUAL_CROP_GEN_CFG_UPD; + else + dc_ctrl |= RKISP1_CIF_DUAL_CROP_CFG_UPD; + rkisp1_write(rsz->rkisp1, dc_ctrl, rsz->config->dual_crop.ctrl); +} + +/* configure dual-crop unit */ +static void rkisp1_dcrop_config(struct rkisp1_resizer *rsz) +{ + struct rkisp1_device *rkisp1 = rsz->rkisp1; + struct v4l2_mbus_framefmt *sink_fmt; + struct v4l2_rect *sink_crop; + u32 dc_ctrl; + + sink_crop = rkisp1_rsz_get_pad_crop(rsz, NULL, RKISP1_RSZ_PAD_SINK, + V4L2_SUBDEV_FORMAT_ACTIVE); + sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, NULL, RKISP1_RSZ_PAD_SINK, + V4L2_SUBDEV_FORMAT_ACTIVE); + + if (sink_crop->width == sink_fmt->width && + sink_crop->height == sink_fmt->height && + sink_crop->left == 0 && sink_crop->top == 0) { + rkisp1_dcrop_disable(rsz, RKISP1_SHADOW_REGS_SYNC); + dev_dbg(rkisp1->dev, "capture %d crop disabled\n", rsz->id); + return; + } + + dc_ctrl = rkisp1_read(rkisp1, rsz->config->dual_crop.ctrl); + rkisp1_write(rkisp1, sink_crop->left, rsz->config->dual_crop.h_offset); + rkisp1_write(rkisp1, sink_crop->top, rsz->config->dual_crop.v_offset); + rkisp1_write(rkisp1, sink_crop->width, rsz->config->dual_crop.h_size); + rkisp1_write(rkisp1, sink_crop->height, rsz->config->dual_crop.v_size); + dc_ctrl |= rsz->config->dual_crop.yuvmode_mask; + dc_ctrl |= RKISP1_CIF_DUAL_CROP_CFG_UPD; + rkisp1_write(rkisp1, dc_ctrl, rsz->config->dual_crop.ctrl); + + dev_dbg(rkisp1->dev, "stream %d crop: %dx%d -> %dx%d\n", rsz->id, + sink_fmt->width, sink_fmt->height, + sink_crop->width, sink_crop->height); +} + +/* ---------------------------------------------------------------------------- + * Resizer hw configs + */ + +static void rkisp1_rsz_dump_regs(struct rkisp1_resizer *rsz) +{ + dev_dbg(rsz->rkisp1->dev, + "RSZ_CTRL 0x%08x/0x%08x\n" + "RSZ_SCALE_HY %d/%d\n" + "RSZ_SCALE_HCB %d/%d\n" + "RSZ_SCALE_HCR %d/%d\n" + "RSZ_SCALE_VY %d/%d\n" + "RSZ_SCALE_VC %d/%d\n" + "RSZ_PHASE_HY %d/%d\n" + "RSZ_PHASE_HC %d/%d\n" + "RSZ_PHASE_VY %d/%d\n" + "RSZ_PHASE_VC %d/%d\n", + rkisp1_read(rsz->rkisp1, rsz->config->rsz.ctrl), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.ctrl_shd), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hy), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hy_shd), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hcb), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hcb_shd), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hcr), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hcr_shd), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_vy), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_vy_shd), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_vc), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_vc_shd), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_hy), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_hy_shd), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_hc), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_hc_shd), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_vy), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_vy_shd), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_vc), + rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_vc_shd)); +} + +static void rkisp1_rsz_update_shadow(struct rkisp1_resizer *rsz, + enum rkisp1_shadow_regs_when when) +{ + u32 ctrl_cfg = rkisp1_read(rsz->rkisp1, rsz->config->rsz.ctrl); + + if (when == RKISP1_SHADOW_REGS_ASYNC) + ctrl_cfg |= RKISP1_CIF_RSZ_CTRL_CFG_UPD_AUTO; + else + ctrl_cfg |= RKISP1_CIF_RSZ_CTRL_CFG_UPD; + + rkisp1_write(rsz->rkisp1, ctrl_cfg, rsz->config->rsz.ctrl); +} + +static u32 rkisp1_rsz_calc_ratio(u32 len_sink, u32 len_src) +{ + if (len_sink < len_src) + return ((len_sink - 1) * RKISP1_CIF_RSZ_SCALER_FACTOR) / + (len_src - 1); + + return ((len_src - 1) * RKISP1_CIF_RSZ_SCALER_FACTOR) / + (len_sink - 1) + 1; +} + +static void rkisp1_rsz_disable(struct rkisp1_resizer *rsz, + enum rkisp1_shadow_regs_when when) +{ + rkisp1_write(rsz->rkisp1, 0, rsz->config->rsz.ctrl); + + if (when == RKISP1_SHADOW_REGS_SYNC) + rkisp1_rsz_update_shadow(rsz, when); +} + +static void rkisp1_rsz_config_regs(struct rkisp1_resizer *rsz, + struct v4l2_rect *sink_y, + struct v4l2_rect *sink_c, + struct v4l2_rect *src_y, + struct v4l2_rect *src_c, + enum rkisp1_shadow_regs_when when) +{ + struct rkisp1_device *rkisp1 = rsz->rkisp1; + u32 ratio, rsz_ctrl = 0; + unsigned int i; + + /* No phase offset */ + rkisp1_write(rkisp1, 0, rsz->config->rsz.phase_hy); + rkisp1_write(rkisp1, 0, rsz->config->rsz.phase_hc); + rkisp1_write(rkisp1, 0, rsz->config->rsz.phase_vy); + rkisp1_write(rkisp1, 0, rsz->config->rsz.phase_vc); + + /* Linear interpolation */ + for (i = 0; i < 64; i++) { + rkisp1_write(rkisp1, i, rsz->config->rsz.scale_lut_addr); + rkisp1_write(rkisp1, i, rsz->config->rsz.scale_lut); + } + + if (sink_y->width != src_y->width) { + rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_HY_ENABLE; + if (sink_y->width < src_y->width) + rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_HY_UP; + ratio = rkisp1_rsz_calc_ratio(sink_y->width, src_y->width); + rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_hy); + } + + if (sink_c->width != src_c->width) { + rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_HC_ENABLE; + if (sink_c->width < src_c->width) + rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_HC_UP; + ratio = rkisp1_rsz_calc_ratio(sink_c->width, src_c->width); + rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_hcb); + rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_hcr); + } + + if (sink_y->height != src_y->height) { + rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_VY_ENABLE; + if (sink_y->height < src_y->height) + rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_VY_UP; + ratio = rkisp1_rsz_calc_ratio(sink_y->height, src_y->height); + rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_vy); + } + + if (sink_c->height != src_c->height) { + rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_VC_ENABLE; + if (sink_c->height < src_c->height) + rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_VC_UP; + ratio = rkisp1_rsz_calc_ratio(sink_c->height, src_c->height); + rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_vc); + } + + rkisp1_write(rkisp1, rsz_ctrl, rsz->config->rsz.ctrl); + + rkisp1_rsz_update_shadow(rsz, when); +} + +static void rkisp1_rsz_config(struct rkisp1_resizer *rsz, + enum rkisp1_shadow_regs_when when) +{ + const struct rkisp1_rsz_yuv_mbus_info *sink_yuv_info, *src_yuv_info; + struct v4l2_rect sink_y, sink_c, src_y, src_c; + struct v4l2_mbus_framefmt *src_fmt, *sink_fmt; + struct v4l2_rect *sink_crop; + + sink_crop = rkisp1_rsz_get_pad_crop(rsz, NULL, RKISP1_RSZ_PAD_SINK, + V4L2_SUBDEV_FORMAT_ACTIVE); + src_fmt = rkisp1_rsz_get_pad_fmt(rsz, NULL, RKISP1_RSZ_PAD_SRC, + V4L2_SUBDEV_FORMAT_ACTIVE); + src_yuv_info = rkisp1_rsz_get_yuv_mbus_info(src_fmt->code); + sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, NULL, RKISP1_RSZ_PAD_SINK, + V4L2_SUBDEV_FORMAT_ACTIVE); + sink_yuv_info = rkisp1_rsz_get_yuv_mbus_info(sink_fmt->code); + + /* + * The resizer only works on yuv formats, + * so return if it is bayer format. + */ + if (rsz->pixel_enc == V4L2_PIXEL_ENC_BAYER) { + rkisp1_rsz_disable(rsz, when); + return; + } + + sink_y.width = sink_crop->width; + sink_y.height = sink_crop->height; + src_y.width = src_fmt->width; + src_y.height = src_fmt->height; + + sink_c.width = sink_y.width / sink_yuv_info->hdiv; + sink_c.height = sink_y.height / sink_yuv_info->vdiv; + + /* + * The resizer is used not only to change the dimensions of the frame + * but also to change the scale for YUV formats, + * (4:2:2 -> 4:2:0 for example). So the width/height of the CbCr + * streams should be set according to the media bus format in the src pad. + */ + src_c.width = src_y.width / src_yuv_info->hdiv; + src_c.height = src_y.height / src_yuv_info->vdiv; + + if (sink_c.width == src_c.width && sink_c.height == src_c.height) { + rkisp1_rsz_disable(rsz, when); + return; + } + + dev_dbg(rsz->rkisp1->dev, "stream %d rsz/scale: %dx%d -> %dx%d\n", + rsz->id, sink_crop->width, sink_crop->height, + src_fmt->width, src_fmt->height); + dev_dbg(rsz->rkisp1->dev, "chroma scaling %dx%d -> %dx%d\n", + sink_c.width, sink_c.height, src_c.width, src_c.height); + + /* set values in the hw */ + rkisp1_rsz_config_regs(rsz, &sink_y, &sink_c, &src_y, &src_c, when); + + rkisp1_rsz_dump_regs(rsz); +} + +/* ---------------------------------------------------------------------------- + * Subdev pad operations + */ + +static int rkisp1_rsz_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct rkisp1_resizer *rsz = + container_of(sd, struct rkisp1_resizer, sd); + struct v4l2_subdev_pad_config dummy_cfg; + u32 pad = code->pad; + int ret; + + if (code->pad == RKISP1_RSZ_PAD_SRC) { + /* supported mbus codes on the src are the same as in the capture */ + struct rkisp1_capture *cap = &rsz->rkisp1->capture_devs[rsz->id]; + + return rkisp1_cap_enum_mbus_codes(cap, code); + } + + /* + * The selfpath capture doesn't support bayer formats. Therefore the selfpath resizer + * should support only YUV422 on the sink pad + */ + if (rsz->id == RKISP1_SELFPATH) { + if (code->index > 0) + return -EINVAL; + code->code = MEDIA_BUS_FMT_YUYV8_2X8; + return 0; + } + + /* supported mbus codes on the sink pad are the same as isp src pad */ + code->pad = RKISP1_ISP_PAD_SOURCE_VIDEO; + ret = v4l2_subdev_call(&rsz->rkisp1->isp.sd, pad, enum_mbus_code, + &dummy_cfg, code); + + /* restore pad */ + code->pad = pad; + code->flags = 0; + return ret; +} + +static int rkisp1_rsz_init_config(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg) +{ + struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; + struct v4l2_rect *sink_crop; + + sink_fmt = v4l2_subdev_get_try_format(sd, cfg, RKISP1_RSZ_PAD_SRC); + sink_fmt->width = RKISP1_DEFAULT_WIDTH; + sink_fmt->height = RKISP1_DEFAULT_HEIGHT; + sink_fmt->field = V4L2_FIELD_NONE; + sink_fmt->code = RKISP1_DEF_FMT; + + sink_crop = v4l2_subdev_get_try_crop(sd, cfg, RKISP1_RSZ_PAD_SINK); + sink_crop->width = RKISP1_DEFAULT_WIDTH; + sink_crop->height = RKISP1_DEFAULT_HEIGHT; + sink_crop->left = 0; + sink_crop->top = 0; + + src_fmt = v4l2_subdev_get_try_format(sd, cfg, RKISP1_RSZ_PAD_SINK); + *src_fmt = *sink_fmt; + + /* NOTE: there is no crop in the source pad, only in the sink */ + + return 0; +} + +static void rkisp1_rsz_set_src_fmt(struct rkisp1_resizer *rsz, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_mbus_framefmt *format, + unsigned int which) +{ + const struct rkisp1_isp_mbus_info *mbus_info; + struct v4l2_mbus_framefmt *src_fmt; + + src_fmt = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SRC, which); + mbus_info = rkisp1_isp_mbus_info_get(src_fmt->code); + + /* for YUV formats, userspace can change the mbus code on the src pad if it is supported */ + if (mbus_info->pixel_enc == V4L2_PIXEL_ENC_YUV && + rkisp1_rsz_get_yuv_mbus_info(format->code)) + src_fmt->code = format->code; + + src_fmt->width = clamp_t(u32, format->width, + rsz->config->min_rsz_width, + rsz->config->max_rsz_width); + src_fmt->height = clamp_t(u32, format->height, + rsz->config->min_rsz_height, + rsz->config->max_rsz_height); + + *format = *src_fmt; +} + +static void rkisp1_rsz_set_sink_crop(struct rkisp1_resizer *rsz, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_rect *r, + unsigned int which) +{ + const struct rkisp1_isp_mbus_info *mbus_info; + struct v4l2_mbus_framefmt *sink_fmt; + struct v4l2_rect *sink_crop; + + sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SINK, which); + sink_crop = rkisp1_rsz_get_pad_crop(rsz, cfg, RKISP1_RSZ_PAD_SINK, + which); + + /* Not crop for MP bayer raw data */ + mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); + + if (rsz->id == RKISP1_MAINPATH && + mbus_info->pixel_enc == V4L2_PIXEL_ENC_BAYER) { + sink_crop->left = 0; + sink_crop->top = 0; + sink_crop->width = sink_fmt->width; + sink_crop->height = sink_fmt->height; + + *r = *sink_crop; + return; + } + + sink_crop->left = ALIGN(r->left, 2); + sink_crop->width = ALIGN(r->width, 2); + sink_crop->top = r->top; + sink_crop->height = r->height; + rkisp1_sd_adjust_crop(sink_crop, sink_fmt); + + *r = *sink_crop; +} + +static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_mbus_framefmt *format, + unsigned int which) +{ + const struct rkisp1_isp_mbus_info *mbus_info; + struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; + struct v4l2_rect *sink_crop; + + sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SINK, which); + src_fmt = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SRC, which); + sink_crop = rkisp1_rsz_get_pad_crop(rsz, cfg, RKISP1_RSZ_PAD_SINK, + which); + if (rsz->id == RKISP1_SELFPATH) + sink_fmt->code = MEDIA_BUS_FMT_YUYV8_2X8; + else + sink_fmt->code = format->code; + + mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); + if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SRC)) { + sink_fmt->code = RKISP1_DEF_FMT; + mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); + } + if (which == V4L2_SUBDEV_FORMAT_ACTIVE) + rsz->pixel_enc = mbus_info->pixel_enc; + + /* Propagete to source pad */ + src_fmt->code = sink_fmt->code; + + sink_fmt->width = clamp_t(u32, format->width, + RKISP1_ISP_MIN_WIDTH, + RKISP1_ISP_MAX_WIDTH); + sink_fmt->height = clamp_t(u32, format->height, + RKISP1_ISP_MIN_HEIGHT, + RKISP1_ISP_MAX_HEIGHT); + + *format = *sink_fmt; + + /* Update sink crop */ + rkisp1_rsz_set_sink_crop(rsz, cfg, sink_crop, which); +} + +static int rkisp1_rsz_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct rkisp1_resizer *rsz = + container_of(sd, struct rkisp1_resizer, sd); + + mutex_lock(&rsz->ops_lock); + fmt->format = *rkisp1_rsz_get_pad_fmt(rsz, cfg, fmt->pad, fmt->which); + mutex_unlock(&rsz->ops_lock); + return 0; +} + +static int rkisp1_rsz_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct rkisp1_resizer *rsz = + container_of(sd, struct rkisp1_resizer, sd); + + mutex_lock(&rsz->ops_lock); + if (fmt->pad == RKISP1_RSZ_PAD_SINK) + rkisp1_rsz_set_sink_fmt(rsz, cfg, &fmt->format, fmt->which); + else + rkisp1_rsz_set_src_fmt(rsz, cfg, &fmt->format, fmt->which); + + mutex_unlock(&rsz->ops_lock); + return 0; +} + +static int rkisp1_rsz_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct rkisp1_resizer *rsz = + container_of(sd, struct rkisp1_resizer, sd); + struct v4l2_mbus_framefmt *mf_sink; + int ret = 0; + + if (sel->pad == RKISP1_RSZ_PAD_SRC) + return -EINVAL; + + mutex_lock(&rsz->ops_lock); + switch (sel->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + mf_sink = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SINK, + sel->which); + sel->r.height = mf_sink->height; + sel->r.width = mf_sink->width; + sel->r.left = 0; + sel->r.top = 0; + break; + case V4L2_SEL_TGT_CROP: + sel->r = *rkisp1_rsz_get_pad_crop(rsz, cfg, RKISP1_RSZ_PAD_SINK, + sel->which); + break; + default: + ret = -EINVAL; + } + + mutex_unlock(&rsz->ops_lock); + return ret; +} + +static int rkisp1_rsz_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct rkisp1_resizer *rsz = + container_of(sd, struct rkisp1_resizer, sd); + + if (sel->target != V4L2_SEL_TGT_CROP || sel->pad == RKISP1_RSZ_PAD_SRC) + return -EINVAL; + + dev_dbg(rsz->rkisp1->dev, "%s: pad: %d sel(%d,%d)/%dx%d\n", __func__, + sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height); + + mutex_lock(&rsz->ops_lock); + rkisp1_rsz_set_sink_crop(rsz, cfg, &sel->r, sel->which); + mutex_unlock(&rsz->ops_lock); + + return 0; +} + +static const struct media_entity_operations rkisp1_rsz_media_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static const struct v4l2_subdev_pad_ops rkisp1_rsz_pad_ops = { + .enum_mbus_code = rkisp1_rsz_enum_mbus_code, + .get_selection = rkisp1_rsz_get_selection, + .set_selection = rkisp1_rsz_set_selection, + .init_cfg = rkisp1_rsz_init_config, + .get_fmt = rkisp1_rsz_get_fmt, + .set_fmt = rkisp1_rsz_set_fmt, + .link_validate = v4l2_subdev_link_validate_default, +}; + +/* ---------------------------------------------------------------------------- + * Stream operations + */ + +static int rkisp1_rsz_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct rkisp1_resizer *rsz = + container_of(sd, struct rkisp1_resizer, sd); + struct rkisp1_device *rkisp1 = rsz->rkisp1; + struct rkisp1_capture *other = &rkisp1->capture_devs[rsz->id ^ 1]; + enum rkisp1_shadow_regs_when when = RKISP1_SHADOW_REGS_SYNC; + + if (!enable) { + rkisp1_dcrop_disable(rsz, RKISP1_SHADOW_REGS_ASYNC); + rkisp1_rsz_disable(rsz, RKISP1_SHADOW_REGS_ASYNC); + return 0; + } + + if (other->is_streaming) + when = RKISP1_SHADOW_REGS_ASYNC; + + mutex_lock(&rsz->ops_lock); + rkisp1_rsz_config(rsz, when); + rkisp1_dcrop_config(rsz); + + mutex_unlock(&rsz->ops_lock); + return 0; +} + +static const struct v4l2_subdev_video_ops rkisp1_rsz_video_ops = { + .s_stream = rkisp1_rsz_s_stream, +}; + +static const struct v4l2_subdev_ops rkisp1_rsz_ops = { + .video = &rkisp1_rsz_video_ops, + .pad = &rkisp1_rsz_pad_ops, +}; + +static void rkisp1_rsz_unregister(struct rkisp1_resizer *rsz) +{ + v4l2_device_unregister_subdev(&rsz->sd); + media_entity_cleanup(&rsz->sd.entity); +} + +static int rkisp1_rsz_register(struct rkisp1_resizer *rsz) +{ + static const char * const dev_names[] = { + RKISP1_RSZ_MP_DEV_NAME, + RKISP1_RSZ_SP_DEV_NAME + }; + struct media_pad *pads = rsz->pads; + struct v4l2_subdev *sd = &rsz->sd; + int ret; + + if (rsz->id == RKISP1_SELFPATH) + rsz->config = &rkisp1_rsz_config_sp; + else + rsz->config = &rkisp1_rsz_config_mp; + + v4l2_subdev_init(sd, &rkisp1_rsz_ops); + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->entity.ops = &rkisp1_rsz_media_ops; + sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER; + sd->owner = THIS_MODULE; + strscpy(sd->name, dev_names[rsz->id], sizeof(sd->name)); + + pads[RKISP1_RSZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK | + MEDIA_PAD_FL_MUST_CONNECT; + pads[RKISP1_RSZ_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE | + MEDIA_PAD_FL_MUST_CONNECT; + + rsz->pixel_enc = RKISP1_DEF_PIXEL_ENC; + + mutex_init(&rsz->ops_lock); + ret = media_entity_pads_init(&sd->entity, RKISP1_RSZ_PAD_MAX, pads); + if (ret) + return ret; + + ret = v4l2_device_register_subdev(&rsz->rkisp1->v4l2_dev, sd); + if (ret) { + dev_err(sd->dev, "Failed to register resizer subdev\n"); + goto err_cleanup_media_entity; + } + + rkisp1_rsz_init_config(sd, rsz->pad_cfg); + return 0; + +err_cleanup_media_entity: + media_entity_cleanup(&sd->entity); + + return ret; +} + +int rkisp1_resizer_devs_register(struct rkisp1_device *rkisp1) +{ + struct rkisp1_resizer *rsz; + unsigned int i, j; + int ret; + + for (i = 0; i < ARRAY_SIZE(rkisp1->resizer_devs); i++) { + rsz = &rkisp1->resizer_devs[i]; + rsz->rkisp1 = rkisp1; + rsz->id = i; + ret = rkisp1_rsz_register(rsz); + if (ret) + goto err_unreg_resizer_devs; + } + + return 0; + +err_unreg_resizer_devs: + for (j = 0; j < i; j++) { + rsz = &rkisp1->resizer_devs[j]; + rkisp1_rsz_unregister(rsz); + } + + return ret; +} + +void rkisp1_resizer_devs_unregister(struct rkisp1_device *rkisp1) +{ + struct rkisp1_resizer *mp = &rkisp1->resizer_devs[RKISP1_MAINPATH]; + struct rkisp1_resizer *sp = &rkisp1->resizer_devs[RKISP1_SELFPATH]; + + rkisp1_rsz_unregister(mp); + rkisp1_rsz_unregister(sp); +} diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c new file mode 100644 index 000000000000..3ddab8fa8f2d --- /dev/null +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c @@ -0,0 +1,415 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Rockchip ISP1 Driver - Stats subdevice + * + * Copyright (C) 2017 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include /* for ISP statistics */ + +#include "rkisp1-common.h" + +#define RKISP1_STATS_DEV_NAME RKISP1_DRIVER_NAME "_stats" + +#define RKISP1_ISP_STATS_REQ_BUFS_MIN 2 +#define RKISP1_ISP_STATS_REQ_BUFS_MAX 8 + +static int rkisp1_stats_enum_fmt_meta_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct video_device *video = video_devdata(file); + struct rkisp1_stats *stats = video_get_drvdata(video); + + if (f->index > 0 || f->type != video->queue->type) + return -EINVAL; + + f->pixelformat = stats->vdev_fmt.fmt.meta.dataformat; + return 0; +} + +static int rkisp1_stats_g_fmt_meta_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct video_device *video = video_devdata(file); + struct rkisp1_stats *stats = video_get_drvdata(video); + struct v4l2_meta_format *meta = &f->fmt.meta; + + if (f->type != video->queue->type) + return -EINVAL; + + memset(meta, 0, sizeof(*meta)); + meta->dataformat = stats->vdev_fmt.fmt.meta.dataformat; + meta->buffersize = stats->vdev_fmt.fmt.meta.buffersize; + + return 0; +} + +static int rkisp1_stats_querycap(struct file *file, + void *priv, struct v4l2_capability *cap) +{ + struct video_device *vdev = video_devdata(file); + + strscpy(cap->driver, RKISP1_DRIVER_NAME, sizeof(cap->driver)); + strscpy(cap->card, vdev->name, sizeof(cap->card)); + strscpy(cap->bus_info, RKISP1_BUS_INFO, sizeof(cap->bus_info)); + + return 0; +} + +/* ISP video device IOCTLs */ +static const struct v4l2_ioctl_ops rkisp1_stats_ioctl = { + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_enum_fmt_meta_cap = rkisp1_stats_enum_fmt_meta_cap, + .vidioc_g_fmt_meta_cap = rkisp1_stats_g_fmt_meta_cap, + .vidioc_s_fmt_meta_cap = rkisp1_stats_g_fmt_meta_cap, + .vidioc_try_fmt_meta_cap = rkisp1_stats_g_fmt_meta_cap, + .vidioc_querycap = rkisp1_stats_querycap, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static const struct v4l2_file_operations rkisp1_stats_fops = { + .mmap = vb2_fop_mmap, + .unlocked_ioctl = video_ioctl2, + .poll = vb2_fop_poll, + .open = v4l2_fh_open, + .release = vb2_fop_release +}; + +static int rkisp1_stats_vb2_queue_setup(struct vb2_queue *vq, + unsigned int *num_buffers, + unsigned int *num_planes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + *num_planes = 1; + + *num_buffers = clamp_t(u32, *num_buffers, RKISP1_ISP_STATS_REQ_BUFS_MIN, + RKISP1_ISP_STATS_REQ_BUFS_MAX); + + sizes[0] = sizeof(struct rkisp1_stat_buffer); + + return 0; +} + +static void rkisp1_stats_vb2_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct rkisp1_buffer *stats_buf = + container_of(vbuf, struct rkisp1_buffer, vb); + struct vb2_queue *vq = vb->vb2_queue; + struct rkisp1_stats *stats_dev = vq->drv_priv; + + stats_buf->vaddr = vb2_plane_vaddr(vb, 0); + + spin_lock_irq(&stats_dev->lock); + list_add_tail(&stats_buf->queue, &stats_dev->stat); + spin_unlock_irq(&stats_dev->lock); +} + +static int rkisp1_stats_vb2_buf_prepare(struct vb2_buffer *vb) +{ + if (vb2_plane_size(vb, 0) < sizeof(struct rkisp1_stat_buffer)) + return -EINVAL; + + vb2_set_plane_payload(vb, 0, sizeof(struct rkisp1_stat_buffer)); + + return 0; +} + +static void rkisp1_stats_vb2_stop_streaming(struct vb2_queue *vq) +{ + struct rkisp1_stats *stats = vq->drv_priv; + struct rkisp1_buffer *buf; + unsigned int i; + + spin_lock_irq(&stats->lock); + for (i = 0; i < RKISP1_ISP_STATS_REQ_BUFS_MAX; i++) { + if (list_empty(&stats->stat)) + break; + buf = list_first_entry(&stats->stat, + struct rkisp1_buffer, queue); + list_del(&buf->queue); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } + spin_unlock_irq(&stats->lock); +} + +static const struct vb2_ops rkisp1_stats_vb2_ops = { + .queue_setup = rkisp1_stats_vb2_queue_setup, + .buf_queue = rkisp1_stats_vb2_buf_queue, + .buf_prepare = rkisp1_stats_vb2_buf_prepare, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .stop_streaming = rkisp1_stats_vb2_stop_streaming, +}; + +static int +rkisp1_stats_init_vb2_queue(struct vb2_queue *q, struct rkisp1_stats *stats) +{ + struct rkisp1_vdev_node *node; + + node = container_of(q, struct rkisp1_vdev_node, buf_queue); + + q->type = V4L2_BUF_TYPE_META_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + q->drv_priv = stats; + q->ops = &rkisp1_stats_vb2_ops; + q->mem_ops = &vb2_vmalloc_memops; + q->buf_struct_size = sizeof(struct rkisp1_buffer); + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &node->vlock; + + return vb2_queue_init(q); +} + +static void rkisp1_stats_get_awb_meas(struct rkisp1_stats *stats, + struct rkisp1_stat_buffer *pbuf) +{ + /* Protect against concurrent access from ISR? */ + struct rkisp1_device *rkisp1 = stats->rkisp1; + u32 reg_val; + + pbuf->meas_type |= RKISP1_CIF_ISP_STAT_AWB; + reg_val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AWB_WHITE_CNT); + pbuf->params.awb.awb_mean[0].cnt = + RKISP1_CIF_ISP_AWB_GET_PIXEL_CNT(reg_val); + reg_val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AWB_MEAN); + + pbuf->params.awb.awb_mean[0].mean_cr_or_r = + RKISP1_CIF_ISP_AWB_GET_MEAN_CR_R(reg_val); + pbuf->params.awb.awb_mean[0].mean_cb_or_b = + RKISP1_CIF_ISP_AWB_GET_MEAN_CB_B(reg_val); + pbuf->params.awb.awb_mean[0].mean_y_or_g = + RKISP1_CIF_ISP_AWB_GET_MEAN_Y_G(reg_val); +} + +static void rkisp1_stats_get_aec_meas(struct rkisp1_stats *stats, + struct rkisp1_stat_buffer *pbuf) +{ + struct rkisp1_device *rkisp1 = stats->rkisp1; + unsigned int i; + + pbuf->meas_type |= RKISP1_CIF_ISP_STAT_AUTOEXP; + for (i = 0; i < RKISP1_CIF_ISP_AE_MEAN_MAX; i++) + pbuf->params.ae.exp_mean[i] = + (u8)rkisp1_read(rkisp1, + RKISP1_CIF_ISP_EXP_MEAN_00 + i * 4); +} + +static void rkisp1_stats_get_afc_meas(struct rkisp1_stats *stats, + struct rkisp1_stat_buffer *pbuf) +{ + struct rkisp1_device *rkisp1 = stats->rkisp1; + struct rkisp1_cif_isp_af_stat *af; + + pbuf->meas_type |= RKISP1_CIF_ISP_STAT_AFM; + + af = &pbuf->params.af; + af->window[0].sum = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AFM_SUM_A); + af->window[0].lum = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AFM_LUM_A); + af->window[1].sum = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AFM_SUM_B); + af->window[1].lum = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AFM_LUM_B); + af->window[2].sum = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AFM_SUM_C); + af->window[2].lum = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AFM_LUM_C); +} + +static void rkisp1_stats_get_hst_meas(struct rkisp1_stats *stats, + struct rkisp1_stat_buffer *pbuf) +{ + struct rkisp1_device *rkisp1 = stats->rkisp1; + unsigned int i; + + pbuf->meas_type |= RKISP1_CIF_ISP_STAT_HIST; + for (i = 0; i < RKISP1_CIF_ISP_HIST_BIN_N_MAX; i++) + pbuf->params.hist.hist_bins[i] = + (u8)rkisp1_read(rkisp1, + RKISP1_CIF_ISP_HIST_BIN_0 + i * 4); +} + +static void rkisp1_stats_get_bls_meas(struct rkisp1_stats *stats, + struct rkisp1_stat_buffer *pbuf) +{ + struct rkisp1_device *rkisp1 = stats->rkisp1; + const struct rkisp1_isp_mbus_info *in_fmt = rkisp1->isp.sink_fmt; + struct rkisp1_cif_isp_bls_meas_val *bls_val; + + bls_val = &pbuf->params.ae.bls_val; + if (in_fmt->bayer_pat == RKISP1_RAW_BGGR) { + bls_val->meas_b = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_A_MEASURED); + bls_val->meas_gb = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_B_MEASURED); + bls_val->meas_gr = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_C_MEASURED); + bls_val->meas_r = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_D_MEASURED); + } else if (in_fmt->bayer_pat == RKISP1_RAW_GBRG) { + bls_val->meas_gb = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_A_MEASURED); + bls_val->meas_b = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_B_MEASURED); + bls_val->meas_r = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_C_MEASURED); + bls_val->meas_gr = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_D_MEASURED); + } else if (in_fmt->bayer_pat == RKISP1_RAW_GRBG) { + bls_val->meas_gr = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_A_MEASURED); + bls_val->meas_r = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_B_MEASURED); + bls_val->meas_b = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_C_MEASURED); + bls_val->meas_gb = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_D_MEASURED); + } else if (in_fmt->bayer_pat == RKISP1_RAW_RGGB) { + bls_val->meas_r = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_A_MEASURED); + bls_val->meas_gr = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_B_MEASURED); + bls_val->meas_gb = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_C_MEASURED); + bls_val->meas_b = + rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_D_MEASURED); + } +} + +static void +rkisp1_stats_send_measurement(struct rkisp1_stats *stats, u32 isp_ris) +{ + struct rkisp1_stat_buffer *cur_stat_buf; + struct rkisp1_buffer *cur_buf = NULL; + unsigned int frame_sequence = stats->rkisp1->isp.frame_sequence; + u64 timestamp = ktime_get_ns(); + + /* get one empty buffer */ + if (!list_empty(&stats->stat)) { + cur_buf = list_first_entry(&stats->stat, + struct rkisp1_buffer, queue); + list_del(&cur_buf->queue); + } + + if (!cur_buf) + return; + + cur_stat_buf = + (struct rkisp1_stat_buffer *)(cur_buf->vaddr); + + if (isp_ris & RKISP1_CIF_ISP_AWB_DONE) + rkisp1_stats_get_awb_meas(stats, cur_stat_buf); + + if (isp_ris & RKISP1_CIF_ISP_AFM_FIN) + rkisp1_stats_get_afc_meas(stats, cur_stat_buf); + + if (isp_ris & RKISP1_CIF_ISP_EXP_END) { + rkisp1_stats_get_aec_meas(stats, cur_stat_buf); + rkisp1_stats_get_bls_meas(stats, cur_stat_buf); + } + + if (isp_ris & RKISP1_CIF_ISP_HIST_MEASURE_RDY) + rkisp1_stats_get_hst_meas(stats, cur_stat_buf); + + vb2_set_plane_payload(&cur_buf->vb.vb2_buf, 0, + sizeof(struct rkisp1_stat_buffer)); + cur_buf->vb.sequence = frame_sequence; + cur_buf->vb.vb2_buf.timestamp = timestamp; + vb2_buffer_done(&cur_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); +} + +void rkisp1_stats_isr(struct rkisp1_stats *stats, u32 isp_ris) +{ + struct rkisp1_device *rkisp1 = stats->rkisp1; + unsigned int isp_mis_tmp = 0; + + spin_lock(&stats->lock); + + rkisp1_write(rkisp1, RKISP1_STATS_MEAS_MASK, RKISP1_CIF_ISP_ICR); + + isp_mis_tmp = rkisp1_read(rkisp1, RKISP1_CIF_ISP_MIS); + if (isp_mis_tmp & RKISP1_STATS_MEAS_MASK) + rkisp1->debug.stats_error++; + + if (isp_ris & RKISP1_STATS_MEAS_MASK) + rkisp1_stats_send_measurement(stats, isp_ris); + + spin_unlock(&stats->lock); +} + +static void rkisp1_init_stats(struct rkisp1_stats *stats) +{ + stats->vdev_fmt.fmt.meta.dataformat = + V4L2_META_FMT_RK_ISP1_STAT_3A; + stats->vdev_fmt.fmt.meta.buffersize = + sizeof(struct rkisp1_stat_buffer); +} + +int rkisp1_stats_register(struct rkisp1_device *rkisp1) +{ + struct rkisp1_stats *stats = &rkisp1->stats; + struct rkisp1_vdev_node *node = &stats->vnode; + struct video_device *vdev = &node->vdev; + int ret; + + stats->rkisp1 = rkisp1; + mutex_init(&node->vlock); + INIT_LIST_HEAD(&stats->stat); + spin_lock_init(&stats->lock); + + strscpy(vdev->name, RKISP1_STATS_DEV_NAME, sizeof(vdev->name)); + + video_set_drvdata(vdev, stats); + vdev->ioctl_ops = &rkisp1_stats_ioctl; + vdev->fops = &rkisp1_stats_fops; + vdev->release = video_device_release_empty; + vdev->lock = &node->vlock; + vdev->v4l2_dev = &rkisp1->v4l2_dev; + vdev->queue = &node->buf_queue; + vdev->device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING; + vdev->vfl_dir = VFL_DIR_RX; + rkisp1_stats_init_vb2_queue(vdev->queue, stats); + rkisp1_init_stats(stats); + video_set_drvdata(vdev, stats); + + node->pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&vdev->entity, 1, &node->pad); + if (ret) + goto err_mutex_destroy; + + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); + if (ret) { + dev_err(&vdev->dev, + "failed to register %s, ret=%d\n", vdev->name, ret); + goto err_cleanup_media_entity; + } + + return 0; + +err_cleanup_media_entity: + media_entity_cleanup(&vdev->entity); +err_mutex_destroy: + mutex_destroy(&node->vlock); + return ret; +} + +void rkisp1_stats_unregister(struct rkisp1_device *rkisp1) +{ + struct rkisp1_stats *stats = &rkisp1->stats; + struct rkisp1_vdev_node *node = &stats->vnode; + struct video_device *vdev = &node->vdev; + + vb2_video_unregister_device(vdev); + media_entity_cleanup(&vdev->entity); + mutex_destroy(&node->vlock); +} diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index 747c6cf1d795..e8996b1c3b35 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -44,6 +44,4 @@ source "drivers/staging/media/tegra-video/Kconfig" source "drivers/staging/media/ipu3/Kconfig" -source "drivers/staging/media/rkisp1/Kconfig" - endif diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index b59571826ba6..24b5873ff760 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -10,5 +10,4 @@ obj-$(CONFIG_VIDEO_TEGRA) += tegra-video/ obj-$(CONFIG_TEGRA_VDE) += tegra-vde/ obj-$(CONFIG_VIDEO_HANTRO) += hantro/ obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/ -obj-$(CONFIG_VIDEO_ROCKCHIP_ISP1) += rkisp1/ obj-$(CONFIG_VIDEO_ZORAN) += zoran/ diff --git a/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml b/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml deleted file mode 100644 index 2004c054ed1a..000000000000 --- a/drivers/staging/media/rkisp1/Documentation/devicetree/bindings/media/rockchip-isp1.yaml +++ /dev/null @@ -1,215 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0+ OR MIT) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/media/rockchip-isp1.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Rockchip SoC Image Signal Processing unit v1 - -maintainers: - - Helen Koike - -description: | - Rockchip ISP1 is the Camera interface for the Rockchip series of SoCs - which contains image processing, scaling, and compression functions. - -properties: - compatible: - const: rockchip,rk3399-cif-isp - - reg: - maxItems: 1 - - interrupts: - maxItems: 1 - - clocks: - minItems: 3 - items: - # isp0 and isp1 - - description: ISP clock - - description: ISP AXI clock - - description: ISP AHB clock - # only for isp1 - - description: ISP Pixel clock - - clock-names: - minItems: 3 - items: - # isp0 and isp1 - - const: isp - - const: aclk - - const: hclk - # only for isp1 - - const: pclk_isp - - iommus: - maxItems: 1 - - phys: - maxItems: 1 - description: phandle for the PHY port - - phy-names: - const: dphy - - power-domains: - maxItems: 1 - - # See ./video-interfaces.txt for details - ports: - type: object - additionalProperties: false - - properties: - "#address-cells": - const: 1 - - "#size-cells": - const: 0 - - port@0: - type: object - description: connection point for sensors at MIPI-DPHY RX0 - additionalProperties: false - - properties: - "#address-cells": - const: 1 - - "#size-cells": - const: 0 - - reg: - const: 0 - - patternProperties: - endpoint: - type: object - additionalProperties: false - - properties: - reg: - maxItems: 1 - - data-lanes: - minItems: 1 - maxItems: 4 - - remote-endpoint: true - - required: - - reg - - "#address-cells" - - "#size-cells" - - required: - - "#address-cells" - - "#size-cells" - - port@0 - -required: - - compatible - - reg - - interrupts - - clocks - - clock-names - - iommus - - phys - - phy-names - - power-domains - - ports - -if: - properties: - compatible: - contains: - const: rockchip,rk3399-cif-isp -then: - properties: - clocks: - minItems: 3 - maxItems: 4 - clock-names: - minItems: 3 - maxItems: 4 - -additionalProperties: false - -examples: - - | - - #include - #include - #include - - parent0: parent { - #address-cells = <2>; - #size-cells = <2>; - - isp0: isp0@ff910000 { - compatible = "rockchip,rk3399-cif-isp"; - reg = <0x0 0xff910000 0x0 0x4000>; - interrupts = ; - clocks = <&cru SCLK_ISP0>, - <&cru ACLK_ISP0_WRAPPER>, - <&cru HCLK_ISP0_WRAPPER>; - clock-names = "isp", "aclk", "hclk"; - iommus = <&isp0_mmu>; - phys = <&dphy>; - phy-names = "dphy"; - power-domains = <&power RK3399_PD_ISP0>; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - #address-cells = <1>; - #size-cells = <0>; - - mipi_in_wcam: endpoint@0 { - reg = <0>; - remote-endpoint = <&wcam_out>; - data-lanes = <1 2>; - }; - - mipi_in_ucam: endpoint@1 { - reg = <1>; - remote-endpoint = <&ucam_out>; - data-lanes = <1>; - }; - }; - }; - }; - - i2c7: i2c { - #address-cells = <1>; - #size-cells = <0>; - - wcam: camera@36 { - compatible = "ovti,ov5695"; - reg = <0x36>; - - port { - wcam_out: endpoint { - remote-endpoint = <&mipi_in_wcam>; - data-lanes = <1 2>; - }; - }; - }; - - ucam: camera@3c { - compatible = "ovti,ov2685"; - reg = <0x3c>; - - port { - ucam_out: endpoint { - remote-endpoint = <&mipi_in_ucam>; - data-lanes = <1>; - }; - }; - }; - }; - }; diff --git a/drivers/staging/media/rkisp1/Kconfig b/drivers/staging/media/rkisp1/Kconfig deleted file mode 100644 index 41f5def9ea44..000000000000 --- a/drivers/staging/media/rkisp1/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only - -config VIDEO_ROCKCHIP_ISP1 - tristate "Rockchip Image Signal Processing v1 Unit driver" - depends on VIDEO_V4L2 && OF - depends on ARCH_ROCKCHIP || COMPILE_TEST - select MEDIA_CONTROLLER - select VIDEO_V4L2_SUBDEV_API - select VIDEOBUF2_DMA_CONTIG - select VIDEOBUF2_VMALLOC - select V4L2_FWNODE - select GENERIC_PHY_MIPI_DPHY - default n - help - Enable this to support the Image Signal Processing (ISP) module - present in RK3399 SoCs. - - To compile this driver as a module, choose M here: the module - will be called rockchip-isp1. diff --git a/drivers/staging/media/rkisp1/Makefile b/drivers/staging/media/rkisp1/Makefile deleted file mode 100644 index ab32a77db8f7..000000000000 --- a/drivers/staging/media/rkisp1/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -obj-$(CONFIG_VIDEO_ROCKCHIP_ISP1) += rockchip-isp1.o -rockchip-isp1-objs += rkisp1-capture.o \ - rkisp1-common.o \ - rkisp1-dev.o \ - rkisp1-isp.o \ - rkisp1-resizer.o \ - rkisp1-stats.o \ - rkisp1-params.o diff --git a/drivers/staging/media/rkisp1/TODO b/drivers/staging/media/rkisp1/TODO deleted file mode 100644 index ca3651fd0833..000000000000 --- a/drivers/staging/media/rkisp1/TODO +++ /dev/null @@ -1,8 +0,0 @@ -* Fix checkpatch errors. - -NOTES: -* All v4l2-compliance test must pass. -* Stats and params can be tested with libcamera and ChromiumOS stack. - -Please CC patches to Linux Media and -Helen Koike . diff --git a/drivers/staging/media/rkisp1/rkisp1-capture.c b/drivers/staging/media/rkisp1/rkisp1-capture.c deleted file mode 100644 index b81235afd053..000000000000 --- a/drivers/staging/media/rkisp1/rkisp1-capture.c +++ /dev/null @@ -1,1431 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -/* - * Rockchip ISP1 Driver - V4l capture device - * - * Copyright (C) 2019 Collabora, Ltd. - * - * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd. - * Copyright (C) 2017 Rockchip Electronics Co., Ltd. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rkisp1-common.h" - -/* - * NOTE: There are two capture video devices in rkisp1, selfpath and mainpath. - * - * differences between selfpath and mainpath - * available mp sink input: isp - * available sp sink input : isp, dma(TODO) - * available mp sink pad fmts: yuv422, raw - * available sp sink pad fmts: yuv422, yuv420...... - * available mp source fmts: yuv, raw, jpeg(TODO) - * available sp source fmts: yuv, rgb - */ - -#define RKISP1_SP_DEV_NAME RKISP1_DRIVER_NAME "_selfpath" -#define RKISP1_MP_DEV_NAME RKISP1_DRIVER_NAME "_mainpath" - -#define RKISP1_MIN_BUFFERS_NEEDED 3 - -enum rkisp1_plane { - RKISP1_PLANE_Y = 0, - RKISP1_PLANE_CB = 1, - RKISP1_PLANE_CR = 2 -}; - -/* - * @fourcc: pixel format - * @fmt_type: helper filed for pixel format - * @uv_swap: if cb cr swaped, for yuv - * @write_format: defines how YCbCr self picture data is written to memory - * @output_format: defines sp output format - * @mbus: the mbus code on the src resizer pad that matches the pixel format - */ -struct rkisp1_capture_fmt_cfg { - u32 fourcc; - u8 uv_swap; - u32 write_format; - u32 output_format; - u32 mbus; -}; - -struct rkisp1_capture_ops { - void (*config)(struct rkisp1_capture *cap); - void (*stop)(struct rkisp1_capture *cap); - void (*enable)(struct rkisp1_capture *cap); - void (*disable)(struct rkisp1_capture *cap); - void (*set_data_path)(struct rkisp1_capture *cap); - bool (*is_stopped)(struct rkisp1_capture *cap); -}; - -struct rkisp1_capture_config { - const struct rkisp1_capture_fmt_cfg *fmts; - int fmt_size; - struct { - u32 y_size_init; - u32 cb_size_init; - u32 cr_size_init; - u32 y_base_ad_init; - u32 cb_base_ad_init; - u32 cr_base_ad_init; - u32 y_offs_cnt_init; - u32 cb_offs_cnt_init; - u32 cr_offs_cnt_init; - } mi; -}; - -/* - * The supported pixel formats for mainpath. NOTE, pixel formats with identical 'mbus' - * are grouped together. This is assumed and used by the function rkisp1_cap_enum_mbus_codes - */ -static const struct rkisp1_capture_fmt_cfg rkisp1_mp_fmts[] = { - /* yuv422 */ - { - .fourcc = V4L2_PIX_FMT_YUYV, - .uv_swap = 0, - .write_format = RKISP1_MI_CTRL_MP_WRITE_YUVINT, - .mbus = MEDIA_BUS_FMT_YUYV8_2X8, - }, { - .fourcc = V4L2_PIX_FMT_YUV422P, - .uv_swap = 0, - .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, - .mbus = MEDIA_BUS_FMT_YUYV8_2X8, - }, { - .fourcc = V4L2_PIX_FMT_NV16, - .uv_swap = 0, - .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA, - .mbus = MEDIA_BUS_FMT_YUYV8_2X8, - }, { - .fourcc = V4L2_PIX_FMT_NV61, - .uv_swap = 1, - .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA, - .mbus = MEDIA_BUS_FMT_YUYV8_2X8, - }, { - .fourcc = V4L2_PIX_FMT_YVU422M, - .uv_swap = 1, - .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, - .mbus = MEDIA_BUS_FMT_YUYV8_2X8, - }, - /* yuv400 */ - { - .fourcc = V4L2_PIX_FMT_GREY, - .uv_swap = 0, - .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, - .mbus = MEDIA_BUS_FMT_YUYV8_2X8, - }, - /* yuv420 */ - { - .fourcc = V4L2_PIX_FMT_NV21, - .uv_swap = 1, - .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA, - .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, - }, { - .fourcc = V4L2_PIX_FMT_NV12, - .uv_swap = 0, - .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA, - .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, - }, { - .fourcc = V4L2_PIX_FMT_NV21M, - .uv_swap = 1, - .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA, - .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, - }, { - .fourcc = V4L2_PIX_FMT_NV12M, - .uv_swap = 0, - .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA, - .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, - }, { - .fourcc = V4L2_PIX_FMT_YUV420, - .uv_swap = 0, - .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, - .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, - }, { - .fourcc = V4L2_PIX_FMT_YVU420, - .uv_swap = 1, - .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, - .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, - }, - /* raw */ - { - .fourcc = V4L2_PIX_FMT_SRGGB8, - .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, - .mbus = MEDIA_BUS_FMT_SRGGB8_1X8, - }, { - .fourcc = V4L2_PIX_FMT_SGRBG8, - .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, - .mbus = MEDIA_BUS_FMT_SGRBG8_1X8, - }, { - .fourcc = V4L2_PIX_FMT_SGBRG8, - .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, - .mbus = MEDIA_BUS_FMT_SGBRG8_1X8, - }, { - .fourcc = V4L2_PIX_FMT_SBGGR8, - .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, - .mbus = MEDIA_BUS_FMT_SBGGR8_1X8, - }, { - .fourcc = V4L2_PIX_FMT_SRGGB10, - .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, - .mbus = MEDIA_BUS_FMT_SRGGB10_1X10, - }, { - .fourcc = V4L2_PIX_FMT_SGRBG10, - .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, - .mbus = MEDIA_BUS_FMT_SGRBG10_1X10, - }, { - .fourcc = V4L2_PIX_FMT_SGBRG10, - .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, - .mbus = MEDIA_BUS_FMT_SGBRG10_1X10, - }, { - .fourcc = V4L2_PIX_FMT_SBGGR10, - .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, - .mbus = MEDIA_BUS_FMT_SBGGR10_1X10, - }, { - .fourcc = V4L2_PIX_FMT_SRGGB12, - .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, - .mbus = MEDIA_BUS_FMT_SRGGB12_1X12, - }, { - .fourcc = V4L2_PIX_FMT_SGRBG12, - .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, - .mbus = MEDIA_BUS_FMT_SGRBG12_1X12, - }, { - .fourcc = V4L2_PIX_FMT_SGBRG12, - .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, - .mbus = MEDIA_BUS_FMT_SGBRG12_1X12, - }, { - .fourcc = V4L2_PIX_FMT_SBGGR12, - .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, - .mbus = MEDIA_BUS_FMT_SBGGR12_1X12, - }, -}; - -/* - * The supported pixel formats for selfpath. NOTE, pixel formats with identical 'mbus' - * are grouped together. This is assumed and used by the function rkisp1_cap_enum_mbus_codes - */ -static const struct rkisp1_capture_fmt_cfg rkisp1_sp_fmts[] = { - /* yuv422 */ - { - .fourcc = V4L2_PIX_FMT_YUYV, - .uv_swap = 0, - .write_format = RKISP1_MI_CTRL_SP_WRITE_INT, - .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422, - .mbus = MEDIA_BUS_FMT_YUYV8_2X8, - }, { - .fourcc = V4L2_PIX_FMT_YUV422P, - .uv_swap = 0, - .write_format = RKISP1_MI_CTRL_SP_WRITE_PLA, - .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422, - .mbus = MEDIA_BUS_FMT_YUYV8_2X8, - }, { - .fourcc = V4L2_PIX_FMT_NV16, - .uv_swap = 0, - .write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA, - .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422, - .mbus = MEDIA_BUS_FMT_YUYV8_2X8, - }, { - .fourcc = V4L2_PIX_FMT_NV61, - .uv_swap = 1, - .write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA, - .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422, - .mbus = MEDIA_BUS_FMT_YUYV8_2X8, - }, { - .fourcc = V4L2_PIX_FMT_YVU422M, - .uv_swap = 1, - .write_format = RKISP1_MI_CTRL_SP_WRITE_PLA, - .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422, - .mbus = MEDIA_BUS_FMT_YUYV8_2X8, - }, - /* yuv400 */ - { - .fourcc = V4L2_PIX_FMT_GREY, - .uv_swap = 0, - .write_format = RKISP1_MI_CTRL_SP_WRITE_PLA, - .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV400, - .mbus = MEDIA_BUS_FMT_YUYV8_2X8, - }, - /* rgb */ - { - .fourcc = V4L2_PIX_FMT_XBGR32, - .write_format = RKISP1_MI_CTRL_SP_WRITE_PLA, - .output_format = RKISP1_MI_CTRL_SP_OUTPUT_RGB888, - .mbus = MEDIA_BUS_FMT_YUYV8_2X8, - }, { - .fourcc = V4L2_PIX_FMT_RGB565, - .write_format = RKISP1_MI_CTRL_SP_WRITE_PLA, - .output_format = RKISP1_MI_CTRL_SP_OUTPUT_RGB565, - .mbus = MEDIA_BUS_FMT_YUYV8_2X8, - }, - /* yuv420 */ - { - .fourcc = V4L2_PIX_FMT_NV21, - .uv_swap = 1, - .write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA, - .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420, - .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, - }, { - .fourcc = V4L2_PIX_FMT_NV12, - .uv_swap = 0, - .write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA, - .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420, - .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, - }, { - .fourcc = V4L2_PIX_FMT_NV21M, - .uv_swap = 1, - .write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA, - .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420, - .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, - }, { - .fourcc = V4L2_PIX_FMT_NV12M, - .uv_swap = 0, - .write_format = RKISP1_MI_CTRL_SP_WRITE_SPLA, - .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420, - .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, - }, { - .fourcc = V4L2_PIX_FMT_YUV420, - .uv_swap = 0, - .write_format = RKISP1_MI_CTRL_SP_WRITE_PLA, - .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420, - .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, - }, { - .fourcc = V4L2_PIX_FMT_YVU420, - .uv_swap = 1, - .write_format = RKISP1_MI_CTRL_SP_WRITE_PLA, - .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV420, - .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, - }, -}; - -static const struct rkisp1_capture_config rkisp1_capture_config_mp = { - .fmts = rkisp1_mp_fmts, - .fmt_size = ARRAY_SIZE(rkisp1_mp_fmts), - .mi = { - .y_size_init = RKISP1_CIF_MI_MP_Y_SIZE_INIT, - .cb_size_init = RKISP1_CIF_MI_MP_CB_SIZE_INIT, - .cr_size_init = RKISP1_CIF_MI_MP_CR_SIZE_INIT, - .y_base_ad_init = RKISP1_CIF_MI_MP_Y_BASE_AD_INIT, - .cb_base_ad_init = RKISP1_CIF_MI_MP_CB_BASE_AD_INIT, - .cr_base_ad_init = RKISP1_CIF_MI_MP_CR_BASE_AD_INIT, - .y_offs_cnt_init = RKISP1_CIF_MI_MP_Y_OFFS_CNT_INIT, - .cb_offs_cnt_init = RKISP1_CIF_MI_MP_CB_OFFS_CNT_INIT, - .cr_offs_cnt_init = RKISP1_CIF_MI_MP_CR_OFFS_CNT_INIT, - }, -}; - -static const struct rkisp1_capture_config rkisp1_capture_config_sp = { - .fmts = rkisp1_sp_fmts, - .fmt_size = ARRAY_SIZE(rkisp1_sp_fmts), - .mi = { - .y_size_init = RKISP1_CIF_MI_SP_Y_SIZE_INIT, - .cb_size_init = RKISP1_CIF_MI_SP_CB_SIZE_INIT, - .cr_size_init = RKISP1_CIF_MI_SP_CR_SIZE_INIT, - .y_base_ad_init = RKISP1_CIF_MI_SP_Y_BASE_AD_INIT, - .cb_base_ad_init = RKISP1_CIF_MI_SP_CB_BASE_AD_INIT, - .cr_base_ad_init = RKISP1_CIF_MI_SP_CR_BASE_AD_INIT, - .y_offs_cnt_init = RKISP1_CIF_MI_SP_Y_OFFS_CNT_INIT, - .cb_offs_cnt_init = RKISP1_CIF_MI_SP_CB_OFFS_CNT_INIT, - .cr_offs_cnt_init = RKISP1_CIF_MI_SP_CR_OFFS_CNT_INIT, - }, -}; - -static inline struct rkisp1_vdev_node * -rkisp1_vdev_to_node(struct video_device *vdev) -{ - return container_of(vdev, struct rkisp1_vdev_node, vdev); -} - -int rkisp1_cap_enum_mbus_codes(struct rkisp1_capture *cap, - struct v4l2_subdev_mbus_code_enum *code) -{ - const struct rkisp1_capture_fmt_cfg *fmts = cap->config->fmts; - /* - * initialize curr_mbus to non existing mbus code 0 to ensure it is - * different from fmts[0].mbus - */ - u32 curr_mbus = 0; - int i, n = 0; - - for (i = 0; i < cap->config->fmt_size; i++) { - if (fmts[i].mbus == curr_mbus) - continue; - - curr_mbus = fmts[i].mbus; - if (n++ == code->index) { - code->code = curr_mbus; - return 0; - } - } - return -EINVAL; -} - -/* ---------------------------------------------------------------------------- - * Stream operations for self-picture path (sp) and main-picture path (mp) - */ - -static void rkisp1_mi_config_ctrl(struct rkisp1_capture *cap) -{ - u32 mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL); - - mi_ctrl &= ~GENMASK(17, 16); - mi_ctrl |= RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_64; - - mi_ctrl &= ~GENMASK(19, 18); - mi_ctrl |= RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_64; - - mi_ctrl |= RKISP1_CIF_MI_CTRL_INIT_BASE_EN | - RKISP1_CIF_MI_CTRL_INIT_OFFSET_EN; - - rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); -} - -static u32 rkisp1_pixfmt_comp_size(const struct v4l2_pix_format_mplane *pixm, - unsigned int component) -{ - /* - * If packed format, then plane_fmt[0].sizeimage is the sum of all - * components, so we need to calculate just the size of Y component. - * See rkisp1_fill_pixfmt(). - */ - if (!component && pixm->num_planes == 1) - return pixm->plane_fmt[0].bytesperline * pixm->height; - return pixm->plane_fmt[component].sizeimage; -} - -static void rkisp1_irq_frame_end_enable(struct rkisp1_capture *cap) -{ - u32 mi_imsc = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_IMSC); - - mi_imsc |= RKISP1_CIF_MI_FRAME(cap); - rkisp1_write(cap->rkisp1, mi_imsc, RKISP1_CIF_MI_IMSC); -} - -static void rkisp1_mp_config(struct rkisp1_capture *cap) -{ - const struct v4l2_pix_format_mplane *pixm = &cap->pix.fmt; - struct rkisp1_device *rkisp1 = cap->rkisp1; - u32 reg; - - rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y), - cap->config->mi.y_size_init); - rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB), - cap->config->mi.cb_size_init); - rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR), - cap->config->mi.cr_size_init); - - rkisp1_irq_frame_end_enable(cap); - - /* set uv swapping for semiplanar formats */ - if (cap->pix.info->comp_planes == 2) { - reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_XTD_FORMAT_CTRL); - if (cap->pix.cfg->uv_swap) - reg |= RKISP1_CIF_MI_XTD_FMT_CTRL_MP_CB_CR_SWAP; - else - reg &= ~RKISP1_CIF_MI_XTD_FMT_CTRL_MP_CB_CR_SWAP; - rkisp1_write(rkisp1, reg, RKISP1_CIF_MI_XTD_FORMAT_CTRL); - } - - rkisp1_mi_config_ctrl(cap); - - reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_CTRL); - reg &= ~RKISP1_MI_CTRL_MP_FMT_MASK; - reg |= cap->pix.cfg->write_format; - rkisp1_write(rkisp1, reg, RKISP1_CIF_MI_CTRL); - - reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_CTRL); - reg |= RKISP1_CIF_MI_MP_AUTOUPDATE_ENABLE; - rkisp1_write(rkisp1, reg, RKISP1_CIF_MI_CTRL); -} - -static void rkisp1_sp_config(struct rkisp1_capture *cap) -{ - const struct v4l2_pix_format_mplane *pixm = &cap->pix.fmt; - struct rkisp1_device *rkisp1 = cap->rkisp1; - u32 mi_ctrl, reg; - - rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y), - cap->config->mi.y_size_init); - rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB), - cap->config->mi.cb_size_init); - rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR), - cap->config->mi.cr_size_init); - - rkisp1_write(rkisp1, pixm->width, RKISP1_CIF_MI_SP_Y_PIC_WIDTH); - rkisp1_write(rkisp1, pixm->height, RKISP1_CIF_MI_SP_Y_PIC_HEIGHT); - rkisp1_write(rkisp1, cap->sp_y_stride, RKISP1_CIF_MI_SP_Y_LLENGTH); - - rkisp1_irq_frame_end_enable(cap); - - /* set uv swapping for semiplanar formats */ - if (cap->pix.info->comp_planes == 2) { - reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_XTD_FORMAT_CTRL); - if (cap->pix.cfg->uv_swap) - reg |= RKISP1_CIF_MI_XTD_FMT_CTRL_SP_CB_CR_SWAP; - else - reg &= ~RKISP1_CIF_MI_XTD_FMT_CTRL_SP_CB_CR_SWAP; - rkisp1_write(rkisp1, reg, RKISP1_CIF_MI_XTD_FORMAT_CTRL); - } - - rkisp1_mi_config_ctrl(cap); - - mi_ctrl = rkisp1_read(rkisp1, RKISP1_CIF_MI_CTRL); - mi_ctrl &= ~RKISP1_MI_CTRL_SP_FMT_MASK; - mi_ctrl |= cap->pix.cfg->write_format | - RKISP1_MI_CTRL_SP_INPUT_YUV422 | - cap->pix.cfg->output_format | - RKISP1_CIF_MI_SP_AUTOUPDATE_ENABLE; - rkisp1_write(rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); -} - -static void rkisp1_mp_disable(struct rkisp1_capture *cap) -{ - u32 mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL); - - mi_ctrl &= ~(RKISP1_CIF_MI_CTRL_MP_ENABLE | - RKISP1_CIF_MI_CTRL_RAW_ENABLE); - rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); -} - -static void rkisp1_sp_disable(struct rkisp1_capture *cap) -{ - u32 mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL); - - mi_ctrl &= ~RKISP1_CIF_MI_CTRL_SP_ENABLE; - rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); -} - -static void rkisp1_mp_enable(struct rkisp1_capture *cap) -{ - u32 mi_ctrl; - - rkisp1_mp_disable(cap); - - mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL); - if (v4l2_is_format_bayer(cap->pix.info)) - mi_ctrl |= RKISP1_CIF_MI_CTRL_RAW_ENABLE; - /* YUV */ - else - mi_ctrl |= RKISP1_CIF_MI_CTRL_MP_ENABLE; - - rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); -} - -static void rkisp1_sp_enable(struct rkisp1_capture *cap) -{ - u32 mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL); - - mi_ctrl |= RKISP1_CIF_MI_CTRL_SP_ENABLE; - rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); -} - -static void rkisp1_mp_sp_stop(struct rkisp1_capture *cap) -{ - if (!cap->is_streaming) - return; - rkisp1_write(cap->rkisp1, - RKISP1_CIF_MI_FRAME(cap), RKISP1_CIF_MI_ICR); - cap->ops->disable(cap); -} - -static bool rkisp1_mp_is_stopped(struct rkisp1_capture *cap) -{ - u32 en = RKISP1_CIF_MI_CTRL_SHD_MP_IN_ENABLED | - RKISP1_CIF_MI_CTRL_SHD_RAW_OUT_ENABLED; - - return !(rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL_SHD) & en); -} - -static bool rkisp1_sp_is_stopped(struct rkisp1_capture *cap) -{ - return !(rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL_SHD) & - RKISP1_CIF_MI_CTRL_SHD_SP_IN_ENABLED); -} - -static void rkisp1_mp_set_data_path(struct rkisp1_capture *cap) -{ - u32 dpcl = rkisp1_read(cap->rkisp1, RKISP1_CIF_VI_DPCL); - - dpcl = dpcl | RKISP1_CIF_VI_DPCL_CHAN_MODE_MP | - RKISP1_CIF_VI_DPCL_MP_MUX_MRSZ_MI; - rkisp1_write(cap->rkisp1, dpcl, RKISP1_CIF_VI_DPCL); -} - -static void rkisp1_sp_set_data_path(struct rkisp1_capture *cap) -{ - u32 dpcl = rkisp1_read(cap->rkisp1, RKISP1_CIF_VI_DPCL); - - dpcl |= RKISP1_CIF_VI_DPCL_CHAN_MODE_SP; - rkisp1_write(cap->rkisp1, dpcl, RKISP1_CIF_VI_DPCL); -} - -static struct rkisp1_capture_ops rkisp1_capture_ops_mp = { - .config = rkisp1_mp_config, - .enable = rkisp1_mp_enable, - .disable = rkisp1_mp_disable, - .stop = rkisp1_mp_sp_stop, - .set_data_path = rkisp1_mp_set_data_path, - .is_stopped = rkisp1_mp_is_stopped, -}; - -static struct rkisp1_capture_ops rkisp1_capture_ops_sp = { - .config = rkisp1_sp_config, - .enable = rkisp1_sp_enable, - .disable = rkisp1_sp_disable, - .stop = rkisp1_mp_sp_stop, - .set_data_path = rkisp1_sp_set_data_path, - .is_stopped = rkisp1_sp_is_stopped, -}; - -/* ---------------------------------------------------------------------------- - * Frame buffer operations - */ - -static int rkisp1_dummy_buf_create(struct rkisp1_capture *cap) -{ - const struct v4l2_pix_format_mplane *pixm = &cap->pix.fmt; - struct rkisp1_dummy_buffer *dummy_buf = &cap->buf.dummy; - - dummy_buf->size = max3(rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y), - rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB), - rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR)); - - /* The driver never access vaddr, no mapping is required */ - dummy_buf->vaddr = dma_alloc_attrs(cap->rkisp1->dev, - dummy_buf->size, - &dummy_buf->dma_addr, - GFP_KERNEL, - DMA_ATTR_NO_KERNEL_MAPPING); - if (!dummy_buf->vaddr) - return -ENOMEM; - - return 0; -} - -static void rkisp1_dummy_buf_destroy(struct rkisp1_capture *cap) -{ - dma_free_attrs(cap->rkisp1->dev, - cap->buf.dummy.size, cap->buf.dummy.vaddr, - cap->buf.dummy.dma_addr, DMA_ATTR_NO_KERNEL_MAPPING); -} - -static void rkisp1_set_next_buf(struct rkisp1_capture *cap) -{ - cap->buf.curr = cap->buf.next; - cap->buf.next = NULL; - - if (!list_empty(&cap->buf.queue)) { - u32 *buff_addr; - - cap->buf.next = list_first_entry(&cap->buf.queue, struct rkisp1_buffer, queue); - list_del(&cap->buf.next->queue); - - buff_addr = cap->buf.next->buff_addr; - - rkisp1_write(cap->rkisp1, - buff_addr[RKISP1_PLANE_Y], - cap->config->mi.y_base_ad_init); - rkisp1_write(cap->rkisp1, - buff_addr[RKISP1_PLANE_CB], - cap->config->mi.cb_base_ad_init); - rkisp1_write(cap->rkisp1, - buff_addr[RKISP1_PLANE_CR], - cap->config->mi.cr_base_ad_init); - } else { - /* - * Use the dummy space allocated by dma_alloc_coherent to - * throw data if there is no available buffer. - */ - rkisp1_write(cap->rkisp1, - cap->buf.dummy.dma_addr, - cap->config->mi.y_base_ad_init); - rkisp1_write(cap->rkisp1, - cap->buf.dummy.dma_addr, - cap->config->mi.cb_base_ad_init); - rkisp1_write(cap->rkisp1, - cap->buf.dummy.dma_addr, - cap->config->mi.cr_base_ad_init); - } - - /* Set plane offsets */ - rkisp1_write(cap->rkisp1, 0, cap->config->mi.y_offs_cnt_init); - rkisp1_write(cap->rkisp1, 0, cap->config->mi.cb_offs_cnt_init); - rkisp1_write(cap->rkisp1, 0, cap->config->mi.cr_offs_cnt_init); -} - -/* - * This function is called when a frame end comes. The next frame - * is processing and we should set up buffer for next-next frame, - * otherwise it will overflow. - */ -static void rkisp1_handle_buffer(struct rkisp1_capture *cap) -{ - struct rkisp1_isp *isp = &cap->rkisp1->isp; - struct rkisp1_buffer *curr_buf; - - spin_lock(&cap->buf.lock); - curr_buf = cap->buf.curr; - - if (curr_buf) { - curr_buf->vb.sequence = isp->frame_sequence; - curr_buf->vb.vb2_buf.timestamp = ktime_get_boottime_ns(); - curr_buf->vb.field = V4L2_FIELD_NONE; - vb2_buffer_done(&curr_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); - } else { - cap->rkisp1->debug.frame_drop[cap->id]++; - } - - rkisp1_set_next_buf(cap); - spin_unlock(&cap->buf.lock); -} - -void rkisp1_capture_isr(struct rkisp1_device *rkisp1) -{ - unsigned int i; - u32 status; - - status = rkisp1_read(rkisp1, RKISP1_CIF_MI_MIS); - rkisp1_write(rkisp1, status, RKISP1_CIF_MI_ICR); - - for (i = 0; i < ARRAY_SIZE(rkisp1->capture_devs); ++i) { - struct rkisp1_capture *cap = &rkisp1->capture_devs[i]; - - if (!(status & RKISP1_CIF_MI_FRAME(cap))) - continue; - if (!cap->is_stopping) { - rkisp1_handle_buffer(cap); - continue; - } - /* - * Make sure stream is actually stopped, whose state - * can be read from the shadow register, before - * wake_up() thread which would immediately free all - * frame buffers. stop() takes effect at the next - * frame end that sync the configurations to shadow - * regs. - */ - if (!cap->ops->is_stopped(cap)) { - cap->ops->stop(cap); - continue; - } - cap->is_stopping = false; - cap->is_streaming = false; - wake_up(&cap->done); - } -} - -/* ---------------------------------------------------------------------------- - * Vb2 operations - */ - -static int rkisp1_vb2_queue_setup(struct vb2_queue *queue, - unsigned int *num_buffers, - unsigned int *num_planes, - unsigned int sizes[], - struct device *alloc_devs[]) -{ - struct rkisp1_capture *cap = queue->drv_priv; - const struct v4l2_pix_format_mplane *pixm = &cap->pix.fmt; - unsigned int i; - - if (*num_planes) { - if (*num_planes != pixm->num_planes) - return -EINVAL; - - for (i = 0; i < pixm->num_planes; i++) - if (sizes[i] < pixm->plane_fmt[i].sizeimage) - return -EINVAL; - } else { - *num_planes = pixm->num_planes; - for (i = 0; i < pixm->num_planes; i++) - sizes[i] = pixm->plane_fmt[i].sizeimage; - } - - return 0; -} - -static void rkisp1_vb2_buf_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct rkisp1_buffer *ispbuf = - container_of(vbuf, struct rkisp1_buffer, vb); - struct rkisp1_capture *cap = vb->vb2_queue->drv_priv; - const struct v4l2_pix_format_mplane *pixm = &cap->pix.fmt; - unsigned int i; - - memset(ispbuf->buff_addr, 0, sizeof(ispbuf->buff_addr)); - for (i = 0; i < pixm->num_planes; i++) - ispbuf->buff_addr[i] = vb2_dma_contig_plane_dma_addr(vb, i); - - /* Convert to non-MPLANE */ - if (pixm->num_planes == 1) { - ispbuf->buff_addr[RKISP1_PLANE_CB] = - ispbuf->buff_addr[RKISP1_PLANE_Y] + - rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y); - ispbuf->buff_addr[RKISP1_PLANE_CR] = - ispbuf->buff_addr[RKISP1_PLANE_CB] + - rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB); - } - - /* - * uv swap can be supported for planar formats by switching - * the address of cb and cr - */ - if (cap->pix.info->comp_planes == 3 && cap->pix.cfg->uv_swap) - swap(ispbuf->buff_addr[RKISP1_PLANE_CR], - ispbuf->buff_addr[RKISP1_PLANE_CB]); - - spin_lock_irq(&cap->buf.lock); - list_add_tail(&ispbuf->queue, &cap->buf.queue); - spin_unlock_irq(&cap->buf.lock); -} - -static int rkisp1_vb2_buf_prepare(struct vb2_buffer *vb) -{ - struct rkisp1_capture *cap = vb->vb2_queue->drv_priv; - unsigned int i; - - for (i = 0; i < cap->pix.fmt.num_planes; i++) { - unsigned long size = cap->pix.fmt.plane_fmt[i].sizeimage; - - if (vb2_plane_size(vb, i) < size) { - dev_err(cap->rkisp1->dev, - "User buffer too small (%ld < %ld)\n", - vb2_plane_size(vb, i), size); - return -EINVAL; - } - vb2_set_plane_payload(vb, i, size); - } - - return 0; -} - -static void rkisp1_return_all_buffers(struct rkisp1_capture *cap, - enum vb2_buffer_state state) -{ - struct rkisp1_buffer *buf; - - spin_lock_irq(&cap->buf.lock); - if (cap->buf.curr) { - vb2_buffer_done(&cap->buf.curr->vb.vb2_buf, state); - cap->buf.curr = NULL; - } - if (cap->buf.next) { - vb2_buffer_done(&cap->buf.next->vb.vb2_buf, state); - cap->buf.next = NULL; - } - while (!list_empty(&cap->buf.queue)) { - buf = list_first_entry(&cap->buf.queue, - struct rkisp1_buffer, queue); - list_del(&buf->queue); - vb2_buffer_done(&buf->vb.vb2_buf, state); - } - spin_unlock_irq(&cap->buf.lock); -} - -/* - * Most of registers inside rockchip ISP1 have shadow register since - * they must be not be changed during processing a frame. - * Usually, each sub-module updates its shadow register after - * processing the last pixel of a frame. - */ -static void rkisp1_cap_stream_enable(struct rkisp1_capture *cap) -{ - struct rkisp1_device *rkisp1 = cap->rkisp1; - struct rkisp1_capture *other = &rkisp1->capture_devs[cap->id ^ 1]; - - cap->ops->set_data_path(cap); - cap->ops->config(cap); - - /* Setup a buffer for the next frame */ - spin_lock_irq(&cap->buf.lock); - rkisp1_set_next_buf(cap); - cap->ops->enable(cap); - /* It's safe to config ACTIVE and SHADOW regs for the - * first stream. While when the second is starting, do NOT - * force update because it also update the first one. - * - * The latter case would drop one more buf(that is 2) since - * there's not buf in shadow when the second FE received. This's - * also required because the second FE maybe corrupt especially - * when run at 120fps. - */ - if (!other->is_streaming) { - /* force cfg update */ - rkisp1_write(rkisp1, - RKISP1_CIF_MI_INIT_SOFT_UPD, RKISP1_CIF_MI_INIT); - rkisp1_set_next_buf(cap); - } - spin_unlock_irq(&cap->buf.lock); - cap->is_streaming = true; -} - -static void rkisp1_cap_stream_disable(struct rkisp1_capture *cap) -{ - int ret; - - /* Stream should stop in interrupt. If it dosn't, stop it by force. */ - cap->is_stopping = true; - ret = wait_event_timeout(cap->done, - !cap->is_streaming, - msecs_to_jiffies(1000)); - if (!ret) { - cap->rkisp1->debug.stop_timeout[cap->id]++; - cap->ops->stop(cap); - cap->is_stopping = false; - cap->is_streaming = false; - } -} - -/* - * rkisp1_pipeline_stream_disable - disable nodes in the pipeline - * - * Call s_stream(false) in the reverse order from - * rkisp1_pipeline_stream_enable() and disable the DMA engine. - * Should be called before media_pipeline_stop() - */ -static void rkisp1_pipeline_stream_disable(struct rkisp1_capture *cap) - __must_hold(&cap->rkisp1->stream_lock) -{ - struct rkisp1_device *rkisp1 = cap->rkisp1; - - rkisp1_cap_stream_disable(cap); - - /* - * If the other capture is streaming, isp and sensor nodes shouldn't - * be disabled, skip them. - */ - if (rkisp1->pipe.streaming_count < 2) { - v4l2_subdev_call(rkisp1->active_sensor->sd, video, s_stream, - false); - v4l2_subdev_call(&rkisp1->isp.sd, video, s_stream, false); - } - - v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video, s_stream, - false); -} - -/* - * rkisp1_pipeline_stream_enable - enable nodes in the pipeline - * - * Enable the DMA Engine and call s_stream(true) through the pipeline. - * Should be called after media_pipeline_start() - */ -static int rkisp1_pipeline_stream_enable(struct rkisp1_capture *cap) - __must_hold(&cap->rkisp1->stream_lock) -{ - struct rkisp1_device *rkisp1 = cap->rkisp1; - int ret; - - rkisp1_cap_stream_enable(cap); - - ret = v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video, - s_stream, true); - if (ret) - goto err_disable_cap; - - /* - * If the other capture is streaming, isp and sensor nodes are already - * enabled, skip them. - */ - if (rkisp1->pipe.streaming_count > 1) - return 0; - - ret = v4l2_subdev_call(&rkisp1->isp.sd, video, s_stream, true); - if (ret) - goto err_disable_rsz; - - ret = v4l2_subdev_call(rkisp1->active_sensor->sd, video, s_stream, - true); - if (ret) - goto err_disable_isp; - - return 0; - -err_disable_isp: - v4l2_subdev_call(&rkisp1->isp.sd, video, s_stream, false); -err_disable_rsz: - v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video, s_stream, - false); -err_disable_cap: - rkisp1_cap_stream_disable(cap); - - return ret; -} - -static void rkisp1_vb2_stop_streaming(struct vb2_queue *queue) -{ - struct rkisp1_capture *cap = queue->drv_priv; - struct rkisp1_vdev_node *node = &cap->vnode; - struct rkisp1_device *rkisp1 = cap->rkisp1; - int ret; - - mutex_lock(&cap->rkisp1->stream_lock); - - rkisp1_pipeline_stream_disable(cap); - - rkisp1_return_all_buffers(cap, VB2_BUF_STATE_ERROR); - - v4l2_pipeline_pm_put(&node->vdev.entity); - ret = pm_runtime_put(rkisp1->dev); - if (ret < 0) - dev_err(rkisp1->dev, "power down failed error:%d\n", ret); - - rkisp1_dummy_buf_destroy(cap); - - media_pipeline_stop(&node->vdev.entity); - - mutex_unlock(&cap->rkisp1->stream_lock); -} - -static int -rkisp1_vb2_start_streaming(struct vb2_queue *queue, unsigned int count) -{ - struct rkisp1_capture *cap = queue->drv_priv; - struct media_entity *entity = &cap->vnode.vdev.entity; - int ret; - - mutex_lock(&cap->rkisp1->stream_lock); - - ret = media_pipeline_start(entity, &cap->rkisp1->pipe); - if (ret) { - dev_err(cap->rkisp1->dev, "start pipeline failed %d\n", ret); - goto err_ret_buffers; - } - - ret = rkisp1_dummy_buf_create(cap); - if (ret) - goto err_pipeline_stop; - - ret = pm_runtime_get_sync(cap->rkisp1->dev); - if (ret < 0) { - pm_runtime_put_noidle(cap->rkisp1->dev); - dev_err(cap->rkisp1->dev, "power up failed %d\n", ret); - goto err_destroy_dummy; - } - ret = v4l2_pipeline_pm_get(entity); - if (ret) { - dev_err(cap->rkisp1->dev, "open cif pipeline failed %d\n", ret); - goto err_pipe_pm_put; - } - - ret = rkisp1_pipeline_stream_enable(cap); - if (ret) - goto err_v4l2_pm_put; - - mutex_unlock(&cap->rkisp1->stream_lock); - - return 0; - -err_v4l2_pm_put: - v4l2_pipeline_pm_put(entity); -err_pipe_pm_put: - pm_runtime_put(cap->rkisp1->dev); -err_destroy_dummy: - rkisp1_dummy_buf_destroy(cap); -err_pipeline_stop: - media_pipeline_stop(entity); -err_ret_buffers: - rkisp1_return_all_buffers(cap, VB2_BUF_STATE_QUEUED); - mutex_unlock(&cap->rkisp1->stream_lock); - - return ret; -} - -static struct vb2_ops rkisp1_vb2_ops = { - .queue_setup = rkisp1_vb2_queue_setup, - .buf_queue = rkisp1_vb2_buf_queue, - .buf_prepare = rkisp1_vb2_buf_prepare, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, - .stop_streaming = rkisp1_vb2_stop_streaming, - .start_streaming = rkisp1_vb2_start_streaming, -}; - -/* ---------------------------------------------------------------------------- - * IOCTLs operations - */ - -static const struct v4l2_format_info * -rkisp1_fill_pixfmt(struct v4l2_pix_format_mplane *pixm, - enum rkisp1_stream_id id) -{ - struct v4l2_plane_pix_format *plane_y = &pixm->plane_fmt[0]; - const struct v4l2_format_info *info; - unsigned int i; - u32 stride; - - memset(pixm->plane_fmt, 0, sizeof(pixm->plane_fmt)); - info = v4l2_format_info(pixm->pixelformat); - pixm->num_planes = info->mem_planes; - stride = info->bpp[0] * pixm->width; - /* Self path supports custom stride but Main path doesn't */ - if (id == RKISP1_MAINPATH || plane_y->bytesperline < stride) - plane_y->bytesperline = stride; - plane_y->sizeimage = plane_y->bytesperline * pixm->height; - - /* normalize stride to pixels per line */ - stride = DIV_ROUND_UP(plane_y->bytesperline, info->bpp[0]); - - for (i = 1; i < info->comp_planes; i++) { - struct v4l2_plane_pix_format *plane = &pixm->plane_fmt[i]; - - /* bytesperline for other components derive from Y component */ - plane->bytesperline = DIV_ROUND_UP(stride, info->hdiv) * - info->bpp[i]; - plane->sizeimage = plane->bytesperline * - DIV_ROUND_UP(pixm->height, info->vdiv); - } - - /* - * If pixfmt is packed, then plane_fmt[0] should contain the total size - * considering all components. plane_fmt[i] for i > 0 should be ignored - * by userspace as mem_planes == 1, but we are keeping information there - * for convenience. - */ - if (info->mem_planes == 1) - for (i = 1; i < info->comp_planes; i++) - plane_y->sizeimage += pixm->plane_fmt[i].sizeimage; - - return info; -} - -static const struct rkisp1_capture_fmt_cfg * -rkisp1_find_fmt_cfg(const struct rkisp1_capture *cap, const u32 pixelfmt) -{ - unsigned int i; - - for (i = 0; i < cap->config->fmt_size; i++) { - if (cap->config->fmts[i].fourcc == pixelfmt) - return &cap->config->fmts[i]; - } - return NULL; -} - -static void rkisp1_try_fmt(const struct rkisp1_capture *cap, - struct v4l2_pix_format_mplane *pixm, - const struct rkisp1_capture_fmt_cfg **fmt_cfg, - const struct v4l2_format_info **fmt_info) -{ - const struct rkisp1_capture_config *config = cap->config; - const struct rkisp1_capture_fmt_cfg *fmt; - const struct v4l2_format_info *info; - const unsigned int max_widths[] = { RKISP1_RSZ_MP_SRC_MAX_WIDTH, - RKISP1_RSZ_SP_SRC_MAX_WIDTH }; - const unsigned int max_heights[] = { RKISP1_RSZ_MP_SRC_MAX_HEIGHT, - RKISP1_RSZ_SP_SRC_MAX_HEIGHT}; - - fmt = rkisp1_find_fmt_cfg(cap, pixm->pixelformat); - if (!fmt) { - fmt = config->fmts; - pixm->pixelformat = fmt->fourcc; - } - - pixm->width = clamp_t(u32, pixm->width, - RKISP1_RSZ_SRC_MIN_WIDTH, max_widths[cap->id]); - pixm->height = clamp_t(u32, pixm->height, - RKISP1_RSZ_SRC_MIN_HEIGHT, max_heights[cap->id]); - - pixm->field = V4L2_FIELD_NONE; - pixm->colorspace = V4L2_COLORSPACE_DEFAULT; - pixm->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; - pixm->quantization = V4L2_QUANTIZATION_DEFAULT; - - info = rkisp1_fill_pixfmt(pixm, cap->id); - - if (fmt_cfg) - *fmt_cfg = fmt; - if (fmt_info) - *fmt_info = info; -} - -static void rkisp1_set_fmt(struct rkisp1_capture *cap, - struct v4l2_pix_format_mplane *pixm) -{ - rkisp1_try_fmt(cap, pixm, &cap->pix.cfg, &cap->pix.info); - cap->pix.fmt = *pixm; - - /* SP supports custom stride in number of pixels of the Y plane */ - if (cap->id == RKISP1_SELFPATH) - cap->sp_y_stride = pixm->plane_fmt[0].bytesperline / - cap->pix.info->bpp[0]; -} - -static int rkisp1_try_fmt_vid_cap_mplane(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct rkisp1_capture *cap = video_drvdata(file); - - rkisp1_try_fmt(cap, &f->fmt.pix_mp, NULL, NULL); - - return 0; -} - -static int rkisp1_enum_fmt_vid_cap_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct rkisp1_capture *cap = video_drvdata(file); - const struct rkisp1_capture_fmt_cfg *fmt = NULL; - unsigned int i, n = 0; - - if (!f->mbus_code) { - if (f->index >= cap->config->fmt_size) - return -EINVAL; - - fmt = &cap->config->fmts[f->index]; - f->pixelformat = fmt->fourcc; - return 0; - } - - for (i = 0; i < cap->config->fmt_size; i++) { - if (cap->config->fmts[i].mbus != f->mbus_code) - continue; - - if (n++ == f->index) { - f->pixelformat = cap->config->fmts[i].fourcc; - return 0; - } - } - return -EINVAL; -} - -static int rkisp1_s_fmt_vid_cap_mplane(struct file *file, - void *priv, struct v4l2_format *f) -{ - struct rkisp1_capture *cap = video_drvdata(file); - struct rkisp1_vdev_node *node = - rkisp1_vdev_to_node(&cap->vnode.vdev); - - if (vb2_is_busy(&node->buf_queue)) - return -EBUSY; - - rkisp1_set_fmt(cap, &f->fmt.pix_mp); - - return 0; -} - -static int rkisp1_g_fmt_vid_cap_mplane(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct rkisp1_capture *cap = video_drvdata(file); - - f->fmt.pix_mp = cap->pix.fmt; - - return 0; -} - -static int -rkisp1_querycap(struct file *file, void *priv, struct v4l2_capability *cap) -{ - struct rkisp1_capture *cap_dev = video_drvdata(file); - struct rkisp1_device *rkisp1 = cap_dev->rkisp1; - - strscpy(cap->driver, rkisp1->dev->driver->name, sizeof(cap->driver)); - strscpy(cap->card, rkisp1->dev->driver->name, sizeof(cap->card)); - strscpy(cap->bus_info, RKISP1_BUS_INFO, sizeof(cap->bus_info)); - - return 0; -} - -static const struct v4l2_ioctl_ops rkisp1_v4l2_ioctl_ops = { - .vidioc_reqbufs = vb2_ioctl_reqbufs, - .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_create_bufs = vb2_ioctl_create_bufs, - .vidioc_qbuf = vb2_ioctl_qbuf, - .vidioc_expbuf = vb2_ioctl_expbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_prepare_buf = vb2_ioctl_prepare_buf, - .vidioc_streamon = vb2_ioctl_streamon, - .vidioc_streamoff = vb2_ioctl_streamoff, - .vidioc_try_fmt_vid_cap_mplane = rkisp1_try_fmt_vid_cap_mplane, - .vidioc_s_fmt_vid_cap_mplane = rkisp1_s_fmt_vid_cap_mplane, - .vidioc_g_fmt_vid_cap_mplane = rkisp1_g_fmt_vid_cap_mplane, - .vidioc_enum_fmt_vid_cap = rkisp1_enum_fmt_vid_cap_mplane, - .vidioc_querycap = rkisp1_querycap, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -static int rkisp1_capture_link_validate(struct media_link *link) -{ - struct video_device *vdev = - media_entity_to_video_device(link->sink->entity); - struct v4l2_subdev *sd = - media_entity_to_v4l2_subdev(link->source->entity); - struct rkisp1_capture *cap = video_get_drvdata(vdev); - const struct rkisp1_capture_fmt_cfg *fmt = - rkisp1_find_fmt_cfg(cap, cap->pix.fmt.pixelformat); - struct v4l2_subdev_format sd_fmt; - int ret; - - sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; - sd_fmt.pad = link->source->index; - ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt); - if (ret) - return ret; - - if (sd_fmt.format.height != cap->pix.fmt.height || - sd_fmt.format.width != cap->pix.fmt.width || - sd_fmt.format.code != fmt->mbus) - return -EPIPE; - - return 0; -} - -/* ---------------------------------------------------------------------------- - * core functions - */ - -static const struct media_entity_operations rkisp1_media_ops = { - .link_validate = rkisp1_capture_link_validate, -}; - -static const struct v4l2_file_operations rkisp1_fops = { - .open = v4l2_fh_open, - .release = vb2_fop_release, - .unlocked_ioctl = video_ioctl2, - .poll = vb2_fop_poll, - .mmap = vb2_fop_mmap, -}; - -static void rkisp1_unregister_capture(struct rkisp1_capture *cap) -{ - media_entity_cleanup(&cap->vnode.vdev.entity); - vb2_video_unregister_device(&cap->vnode.vdev); -} - -void rkisp1_capture_devs_unregister(struct rkisp1_device *rkisp1) -{ - struct rkisp1_capture *mp = &rkisp1->capture_devs[RKISP1_MAINPATH]; - struct rkisp1_capture *sp = &rkisp1->capture_devs[RKISP1_SELFPATH]; - - rkisp1_unregister_capture(mp); - rkisp1_unregister_capture(sp); -} - -static int rkisp1_register_capture(struct rkisp1_capture *cap) -{ - const char * const dev_names[] = {RKISP1_MP_DEV_NAME, - RKISP1_SP_DEV_NAME}; - struct v4l2_device *v4l2_dev = &cap->rkisp1->v4l2_dev; - struct video_device *vdev = &cap->vnode.vdev; - struct rkisp1_vdev_node *node; - struct vb2_queue *q; - int ret; - - strscpy(vdev->name, dev_names[cap->id], sizeof(vdev->name)); - node = rkisp1_vdev_to_node(vdev); - mutex_init(&node->vlock); - - vdev->ioctl_ops = &rkisp1_v4l2_ioctl_ops; - vdev->release = video_device_release_empty; - vdev->fops = &rkisp1_fops; - vdev->minor = -1; - vdev->v4l2_dev = v4l2_dev; - vdev->lock = &node->vlock; - vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | - V4L2_CAP_STREAMING | V4L2_CAP_IO_MC; - vdev->entity.ops = &rkisp1_media_ops; - video_set_drvdata(vdev, cap); - vdev->vfl_dir = VFL_DIR_RX; - node->pad.flags = MEDIA_PAD_FL_SINK; - - q = &node->buf_queue; - q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - q->io_modes = VB2_MMAP | VB2_DMABUF; - q->drv_priv = cap; - q->ops = &rkisp1_vb2_ops; - q->mem_ops = &vb2_dma_contig_memops; - q->buf_struct_size = sizeof(struct rkisp1_buffer); - q->min_buffers_needed = RKISP1_MIN_BUFFERS_NEEDED; - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->lock = &node->vlock; - q->dev = cap->rkisp1->dev; - ret = vb2_queue_init(q); - if (ret) { - dev_err(cap->rkisp1->dev, - "vb2 queue init failed (err=%d)\n", ret); - return ret; - } - - vdev->queue = q; - - ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); - if (ret) { - dev_err(cap->rkisp1->dev, - "failed to register %s, ret=%d\n", vdev->name, ret); - return ret; - } - v4l2_info(v4l2_dev, "registered %s as /dev/video%d\n", vdev->name, - vdev->num); - - ret = media_entity_pads_init(&vdev->entity, 1, &node->pad); - if (ret) { - video_unregister_device(vdev); - return ret; - } - - return 0; -} - -static void -rkisp1_capture_init(struct rkisp1_device *rkisp1, enum rkisp1_stream_id id) -{ - struct rkisp1_capture *cap = &rkisp1->capture_devs[id]; - struct v4l2_pix_format_mplane pixm; - - memset(cap, 0, sizeof(*cap)); - cap->id = id; - cap->rkisp1 = rkisp1; - - INIT_LIST_HEAD(&cap->buf.queue); - init_waitqueue_head(&cap->done); - spin_lock_init(&cap->buf.lock); - if (cap->id == RKISP1_SELFPATH) { - cap->ops = &rkisp1_capture_ops_sp; - cap->config = &rkisp1_capture_config_sp; - } else { - cap->ops = &rkisp1_capture_ops_mp; - cap->config = &rkisp1_capture_config_mp; - } - - cap->is_streaming = false; - - memset(&pixm, 0, sizeof(pixm)); - pixm.pixelformat = V4L2_PIX_FMT_YUYV; - pixm.width = RKISP1_DEFAULT_WIDTH; - pixm.height = RKISP1_DEFAULT_HEIGHT; - rkisp1_set_fmt(cap, &pixm); -} - -int rkisp1_capture_devs_register(struct rkisp1_device *rkisp1) -{ - struct rkisp1_capture *cap; - unsigned int i, j; - int ret; - - for (i = 0; i < ARRAY_SIZE(rkisp1->capture_devs); i++) { - rkisp1_capture_init(rkisp1, i); - cap = &rkisp1->capture_devs[i]; - cap->rkisp1 = rkisp1; - ret = rkisp1_register_capture(cap); - if (ret) - goto err_unreg_capture_devs; - } - - return 0; - -err_unreg_capture_devs: - for (j = 0; j < i; j++) { - cap = &rkisp1->capture_devs[j]; - rkisp1_unregister_capture(cap); - } - - return ret; -} diff --git a/drivers/staging/media/rkisp1/rkisp1-common.c b/drivers/staging/media/rkisp1/rkisp1-common.c deleted file mode 100644 index cf889666e166..000000000000 --- a/drivers/staging/media/rkisp1/rkisp1-common.c +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -/* - * Rockchip ISP1 Driver - Common definitions - * - * Copyright (C) 2019 Collabora, Ltd. - */ - -#include - -#include "rkisp1-common.h" - -static const struct v4l2_rect rkisp1_sd_min_crop = { - .width = RKISP1_ISP_MIN_WIDTH, - .height = RKISP1_ISP_MIN_HEIGHT, - .top = 0, - .left = 0, -}; - -void rkisp1_sd_adjust_crop_rect(struct v4l2_rect *crop, - const struct v4l2_rect *bounds) -{ - v4l2_rect_set_min_size(crop, &rkisp1_sd_min_crop); - v4l2_rect_map_inside(crop, bounds); -} - -void rkisp1_sd_adjust_crop(struct v4l2_rect *crop, - const struct v4l2_mbus_framefmt *bounds) -{ - struct v4l2_rect crop_bounds = { - .left = 0, - .top = 0, - .width = bounds->width, - .height = bounds->height, - }; - - rkisp1_sd_adjust_crop_rect(crop, &crop_bounds); -} diff --git a/drivers/staging/media/rkisp1/rkisp1-common.h b/drivers/staging/media/rkisp1/rkisp1-common.h deleted file mode 100644 index 692333c66f9d..000000000000 --- a/drivers/staging/media/rkisp1/rkisp1-common.h +++ /dev/null @@ -1,485 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ -/* - * Rockchip ISP1 Driver - Common definitions - * - * Copyright (C) 2019 Collabora, Ltd. - * - * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd. - * Copyright (C) 2017 Rockchip Electronics Co., Ltd. - */ - -#ifndef _RKISP1_COMMON_H -#define _RKISP1_COMMON_H - -#include -#include -#include -#include -#include -#include -#include - -#include "rkisp1-regs.h" -#include "uapi/rkisp1-config.h" - -/* - * flags on the 'direction' field in struct 'rkisp1_isp_mbus_info' that indicate - * on which pad the media bus format is supported - */ -#define RKISP1_ISP_SD_SRC BIT(0) -#define RKISP1_ISP_SD_SINK BIT(1) - -/* min and max values for the widths and heights of the entities */ -#define RKISP1_ISP_MAX_WIDTH 4032 -#define RKISP1_ISP_MAX_HEIGHT 3024 -#define RKISP1_ISP_MIN_WIDTH 32 -#define RKISP1_ISP_MIN_HEIGHT 32 - -#define RKISP1_RSZ_MP_SRC_MAX_WIDTH 4416 -#define RKISP1_RSZ_MP_SRC_MAX_HEIGHT 3312 -#define RKISP1_RSZ_SP_SRC_MAX_WIDTH 1920 -#define RKISP1_RSZ_SP_SRC_MAX_HEIGHT 1920 -#define RKISP1_RSZ_SRC_MIN_WIDTH 32 -#define RKISP1_RSZ_SRC_MIN_HEIGHT 16 - -/* the default width and height of all the entities */ -#define RKISP1_DEFAULT_WIDTH 800 -#define RKISP1_DEFAULT_HEIGHT 600 - -#define RKISP1_DRIVER_NAME "rkisp1" -#define RKISP1_BUS_INFO "platform:" RKISP1_DRIVER_NAME - -/* maximum number of clocks */ -#define RKISP1_MAX_BUS_CLK 8 - -/* a bitmask of the ready stats */ -#define RKISP1_STATS_MEAS_MASK (RKISP1_CIF_ISP_AWB_DONE | \ - RKISP1_CIF_ISP_AFM_FIN | \ - RKISP1_CIF_ISP_EXP_END | \ - RKISP1_CIF_ISP_HIST_MEASURE_RDY) - -/* enum for the resizer pads */ -enum rkisp1_rsz_pad { - RKISP1_RSZ_PAD_SINK, - RKISP1_RSZ_PAD_SRC, - RKISP1_RSZ_PAD_MAX -}; - -/* enum for the capture id */ -enum rkisp1_stream_id { - RKISP1_MAINPATH, - RKISP1_SELFPATH, -}; - -/* bayer patterns */ -enum rkisp1_fmt_raw_pat_type { - RKISP1_RAW_RGGB = 0, - RKISP1_RAW_GRBG, - RKISP1_RAW_GBRG, - RKISP1_RAW_BGGR, -}; - -/* enum for the isp pads */ -enum rkisp1_isp_pad { - RKISP1_ISP_PAD_SINK_VIDEO, - RKISP1_ISP_PAD_SINK_PARAMS, - RKISP1_ISP_PAD_SOURCE_VIDEO, - RKISP1_ISP_PAD_SOURCE_STATS, - RKISP1_ISP_PAD_MAX -}; - -/* - * struct rkisp1_sensor_async - A container for the v4l2_async_subdev to add to the notifier - * of the v4l2-async API - * - * @asd: async_subdev variable for the sensor - * @lanes: number of lanes - * @mbus_type: type of bus (currently only CSI2 is supported) - * @mbus_flags: media bus (V4L2_MBUS_*) flags - * @sd: a pointer to v4l2_subdev struct of the sensor - * @pixel_rate_ctrl: pixel rate of the sensor, used to initialize the phy - * @dphy: a pointer to the phy - */ -struct rkisp1_sensor_async { - struct v4l2_async_subdev asd; - unsigned int lanes; - enum v4l2_mbus_type mbus_type; - unsigned int mbus_flags; - struct v4l2_subdev *sd; - struct v4l2_ctrl *pixel_rate_ctrl; - struct phy *dphy; -}; - -/* - * struct rkisp1_isp - ISP subdev entity - * - * @sd: v4l2_subdev variable - * @rkisp1: pointer to rkisp1_device - * @pads: media pads - * @pad_cfg: pads configurations - * @sink_fmt: input format - * @src_fmt: output format - * @ops_lock: ops serialization - * @is_dphy_errctrl_disabled: if dphy errctrl is disabled (avoid endless interrupt) - * @frame_sequence: used to synchronize frame_id between video devices. - */ -struct rkisp1_isp { - struct v4l2_subdev sd; - struct media_pad pads[RKISP1_ISP_PAD_MAX]; - struct v4l2_subdev_pad_config pad_cfg[RKISP1_ISP_PAD_MAX]; - const struct rkisp1_isp_mbus_info *sink_fmt; - const struct rkisp1_isp_mbus_info *src_fmt; - struct mutex ops_lock; /* serialize the subdevice ops */ - bool is_dphy_errctrl_disabled; - __u32 frame_sequence; -}; - -/* - * struct rkisp1_vdev_node - Container for the video nodes: params, stats, mainpath, selfpath - * - * @buf_queue: queue of buffers - * @vlock: lock of the video node - * @vdev: video node - * @pad: media pad - */ -struct rkisp1_vdev_node { - struct vb2_queue buf_queue; - struct mutex vlock; /* ioctl serialization mutex */ - struct video_device vdev; - struct media_pad pad; -}; - -/* - * struct rkisp1_buffer - A container for the vb2 buffers used by the video devices: - * params, stats, mainpath, selfpath - * - * @vb: vb2 buffer - * @queue: entry of the buffer in the queue - * @buff_addr: dma addresses of each plane, used only by the capture devices: selfpath, mainpath - * @vaddr: virtual address for buffers used by params and stats devices - */ -struct rkisp1_buffer { - struct vb2_v4l2_buffer vb; - struct list_head queue; - union { - u32 buff_addr[VIDEO_MAX_PLANES]; - void *vaddr; - }; -}; - -/* - * struct rkisp1_dummy_buffer - A buffer to write the next frame to in case - * there are no vb2 buffers available. - * - * @vaddr: return value of call to dma_alloc_attrs. - * @dma_addr: dma address of the buffer. - * @size: size of the buffer. - */ -struct rkisp1_dummy_buffer { - void *vaddr; - dma_addr_t dma_addr; - u32 size; -}; - -struct rkisp1_device; - -/* - * struct rkisp1_capture - ISP capture video device - * - * @vnode: video node - * @rkisp1: pointer to rkisp1_device - * @id: id of the capture, one of RKISP1_SELFPATH, RKISP1_MAINPATH - * @ops: list of callbacks to configure the capture device. - * @config: a pointer to the list of registers to configure the capture format. - * @is_streaming: device is streaming - * @is_stopping: stop_streaming callback was called and the device is in the process of - * stopping the streaming. - * @done: when stop_streaming callback is called, the device waits for the next irq - * handler to stop the streaming by waiting on the 'done' wait queue. - * If the irq handler is not called, the stream is stopped by the callback - * after timeout. - * @sp_y_stride: the selfpath allows to configure a y stride that is longer than the image width. - * @buf.lock: lock to protect buf.queue - * @buf.queue: queued buffer list - * @buf.dummy: dummy space to store dropped data - * - * rkisp1 uses shadow registers, so it needs two buffers at a time - * @buf.curr: the buffer used for current frame - * @buf.next: the buffer used for next frame - * @pix.cfg: pixel configuration - * @pix.info: a pointer to the v4l2_format_info of the pixel format - * @pix.fmt: buffer format - */ -struct rkisp1_capture { - struct rkisp1_vdev_node vnode; - struct rkisp1_device *rkisp1; - enum rkisp1_stream_id id; - struct rkisp1_capture_ops *ops; - const struct rkisp1_capture_config *config; - bool is_streaming; - bool is_stopping; - wait_queue_head_t done; - unsigned int sp_y_stride; - struct { - /* protects queue, curr and next */ - spinlock_t lock; - struct list_head queue; - struct rkisp1_dummy_buffer dummy; - struct rkisp1_buffer *curr; - struct rkisp1_buffer *next; - } buf; - struct { - const struct rkisp1_capture_fmt_cfg *cfg; - const struct v4l2_format_info *info; - struct v4l2_pix_format_mplane fmt; - } pix; -}; - -/* - * struct rkisp1_stats - ISP Statistics device - * - * @vnode: video node - * @rkisp1: pointer to the rkisp1 device - * @lock: locks the buffer list 'stat' - * @stat: queue of rkisp1_buffer - * @vdev_fmt: v4l2_format of the metadata format - */ -struct rkisp1_stats { - struct rkisp1_vdev_node vnode; - struct rkisp1_device *rkisp1; - - spinlock_t lock; /* locks the buffers list 'stats' */ - struct list_head stat; - struct v4l2_format vdev_fmt; -}; - -/* - * struct rkisp1_params - ISP input parameters device - * - * @vnode: video node - * @rkisp1: pointer to the rkisp1 device - * @config_lock: locks the buffer list 'params' - * @params: queue of rkisp1_buffer - * @vdev_fmt: v4l2_format of the metadata format - * @quantization: the quantization configured on the isp's src pad - * @raw_type: the bayer pattern on the isp video sink pad - */ -struct rkisp1_params { - struct rkisp1_vdev_node vnode; - struct rkisp1_device *rkisp1; - - spinlock_t config_lock; /* locks the buffers list 'params' */ - struct list_head params; - struct v4l2_format vdev_fmt; - - enum v4l2_quantization quantization; - enum rkisp1_fmt_raw_pat_type raw_type; -}; - -/* - * struct rkisp1_resizer - Resizer subdev - * - * @sd: v4l2_subdev variable - * @id: id of the resizer, one of RKISP1_SELFPATH, RKISP1_MAINPATH - * @rkisp1: pointer to the rkisp1 device - * @pads: media pads - * @pad_cfg: configurations for the pads - * @config: the set of registers to configure the resizer - * @pixel_enc: pixel encoding of the resizer - * @ops_lock: a lock for the subdev ops - */ -struct rkisp1_resizer { - struct v4l2_subdev sd; - enum rkisp1_stream_id id; - struct rkisp1_device *rkisp1; - struct media_pad pads[RKISP1_RSZ_PAD_MAX]; - struct v4l2_subdev_pad_config pad_cfg[RKISP1_RSZ_PAD_MAX]; - const struct rkisp1_rsz_config *config; - enum v4l2_pixel_encoding pixel_enc; - struct mutex ops_lock; /* serialize the subdevice ops */ -}; - -/* - * struct rkisp1_debug - Values to be exposed on debugfs. - * The parameters are counters of the number of times the - * event occurred since the driver was loaded. - * - * @data_loss: loss of data occurred within a line, processing failure - * @outform_size_error: size error is generated in outmux submodule - * @img_stabilization_size_error: size error is generated in image stabilization submodule - * @inform_size_err: size error is generated in inform submodule - * @mipi_error: mipi error occurred - * @stats_error: writing to the 'Interrupt clear register' did not clear - * it in the register 'Masked interrupt status' - * @stop_timeout: upon stream stop, the capture waits 1 second for the isr to stop - * the stream. This param is incremented in case of timeout. - * @frame_drop: a frame was ready but the buffer queue was empty so the frame - * was not sent to userspace - */ -struct rkisp1_debug { - struct dentry *debugfs_dir; - unsigned long data_loss; - unsigned long outform_size_error; - unsigned long img_stabilization_size_error; - unsigned long inform_size_error; - unsigned long irq_delay; - unsigned long mipi_error; - unsigned long stats_error; - unsigned long stop_timeout[2]; - unsigned long frame_drop[2]; -}; - -/* - * struct rkisp1_device - ISP platform device - * - * @base_addr: base register address - * @irq: the irq number - * @dev: a pointer to the struct device - * @clk_size: number of clocks - * @clks: array of clocks - * @v4l2_dev: v4l2_device variable - * @media_dev: media_device variable - * @notifier: a notifier to register on the v4l2-async API to be notified on the sensor - * @active_sensor: sensor in-use, set when streaming on - * @isp: ISP sub-device - * @resizer_devs: resizer sub-devices - * @capture_devs: capture devices - * @stats: ISP statistics metadata capture device - * @params: ISP parameters metadata output device - * @pipe: media pipeline - * @stream_lock: serializes {start/stop}_streaming callbacks between the capture devices. - * @debug: debug params to be exposed on debugfs - */ -struct rkisp1_device { - void __iomem *base_addr; - int irq; - struct device *dev; - unsigned int clk_size; - struct clk_bulk_data clks[RKISP1_MAX_BUS_CLK]; - struct v4l2_device v4l2_dev; - struct media_device media_dev; - struct v4l2_async_notifier notifier; - struct rkisp1_sensor_async *active_sensor; - struct rkisp1_isp isp; - struct rkisp1_resizer resizer_devs[2]; - struct rkisp1_capture capture_devs[2]; - struct rkisp1_stats stats; - struct rkisp1_params params; - struct media_pipeline pipe; - struct mutex stream_lock; /* serialize {start/stop}_streaming cb between capture devices */ - struct rkisp1_debug debug; -}; - -/* - * struct rkisp1_isp_mbus_info - ISP media bus info, Translates media bus code to hardware - * format values - * - * @mbus_code: media bus code - * @pixel_enc: pixel encoding - * @mipi_dt: mipi data type - * @yuv_seq: the order of the Y, Cb, Cr values - * @bus_width: bus width - * @bayer_pat: bayer pattern - * @direction: a bitmask of the flags indicating on which pad the format is supported on - */ -struct rkisp1_isp_mbus_info { - u32 mbus_code; - enum v4l2_pixel_encoding pixel_enc; - u32 mipi_dt; - u32 yuv_seq; - u8 bus_width; - enum rkisp1_fmt_raw_pat_type bayer_pat; - unsigned int direction; -}; - -static inline void -rkisp1_write(struct rkisp1_device *rkisp1, u32 val, unsigned int addr) -{ - writel(val, rkisp1->base_addr + addr); -} - -static inline u32 rkisp1_read(struct rkisp1_device *rkisp1, unsigned int addr) -{ - return readl(rkisp1->base_addr + addr); -} - -/* - * rkisp1_cap_enum_mbus_codes - A helper function that return the i'th supported mbus code - * of the capture entity. This is used to enumerate the supported - * mbus codes on the source pad of the resizer. - * - * @cap: the capture entity - * @code: the mbus code, the function reads the code->index and fills the code->code - */ -int rkisp1_cap_enum_mbus_codes(struct rkisp1_capture *cap, - struct v4l2_subdev_mbus_code_enum *code); - -/* - * rkisp1_sd_adjust_crop_rect - adjust a rectangle to fit into another rectangle. - * - * @crop: rectangle to adjust. - * @bounds: rectangle used as bounds. - */ -void rkisp1_sd_adjust_crop_rect(struct v4l2_rect *crop, - const struct v4l2_rect *bounds); - -/* - * rkisp1_sd_adjust_crop - adjust a rectangle to fit into media bus format - * - * @crop: rectangle to adjust. - * @bounds: media bus format used as bounds. - */ -void rkisp1_sd_adjust_crop(struct v4l2_rect *crop, - const struct v4l2_mbus_framefmt *bounds); - -/* - * rkisp1_isp_mbus_info - get the isp info of the media bus code - * - * @mbus_code: the media bus code - */ -const struct rkisp1_isp_mbus_info *rkisp1_isp_mbus_info_get(u32 mbus_code); - -/* rkisp1_params_configure - configure the params when stream starts. - * This function is called by the isp entity upon stream starts. - * The function applies the initial configuration of the parameters. - * - * @params: pointer to rkisp1_params. - * @bayer_pat: the bayer pattern on the isp video sink pad - * @quantization: the quantization configured on the isp's src pad - */ -void rkisp1_params_configure(struct rkisp1_params *params, - enum rkisp1_fmt_raw_pat_type bayer_pat, - enum v4l2_quantization quantization); - -/* rkisp1_params_disable - disable all parameters. - * This function is called by the isp entity upon stream start - * when capturing bayer format. - * - * @params: pointer to rkisp1_params. - */ -void rkisp1_params_disable(struct rkisp1_params *params); - -/* irq handlers */ -void rkisp1_isp_isr(struct rkisp1_device *rkisp1); -void rkisp1_mipi_isr(struct rkisp1_device *rkisp1); -void rkisp1_capture_isr(struct rkisp1_device *rkisp1); -void rkisp1_stats_isr(struct rkisp1_stats *stats, u32 isp_ris); -void rkisp1_params_isr(struct rkisp1_device *rkisp1); - -/* register/unregisters functions of the entities */ -int rkisp1_capture_devs_register(struct rkisp1_device *rkisp1); -void rkisp1_capture_devs_unregister(struct rkisp1_device *rkisp1); - -int rkisp1_isp_register(struct rkisp1_device *rkisp1); -void rkisp1_isp_unregister(struct rkisp1_device *rkisp1); - -int rkisp1_resizer_devs_register(struct rkisp1_device *rkisp1); -void rkisp1_resizer_devs_unregister(struct rkisp1_device *rkisp1); - -int rkisp1_stats_register(struct rkisp1_device *rkisp1); -void rkisp1_stats_unregister(struct rkisp1_device *rkisp1); - -int rkisp1_params_register(struct rkisp1_device *rkisp1); -void rkisp1_params_unregister(struct rkisp1_device *rkisp1); - -#endif /* _RKISP1_COMMON_H */ diff --git a/drivers/staging/media/rkisp1/rkisp1-dev.c b/drivers/staging/media/rkisp1/rkisp1-dev.c deleted file mode 100644 index 90d654346556..000000000000 --- a/drivers/staging/media/rkisp1/rkisp1-dev.c +++ /dev/null @@ -1,580 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -/* - * Rockchip ISP1 Driver - Base driver - * - * Copyright (C) 2019 Collabora, Ltd. - * - * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd. - * Copyright (C) 2017 Rockchip Electronics Co., Ltd. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rkisp1-common.h" - -/* - * ISP Details - * ----------- - * - * ISP Comprises with: - * MIPI serial camera interface - * Image Signal Processing - * Many Image Enhancement Blocks - * Crop - * Resizer - * RBG display ready image - * Image Rotation - * - * ISP Block Diagram - * ----------------- - * rkisp1-resizer.c rkisp1-capture.c - * |====================| |=======================| - * rkisp1-isp.c Main Picture Path - * |==========================| |===============================================| - * +-----------+ +--+--+--+--+ +--------+ +--------+ +-----------+ - * | | | | | | | | | | | | | - * +--------+ |\ | | | | | | | -->| Crop |->| RSZ |------------->| | - * | MIPI |--->| \ | | | | | | | | | | | | | | - * +--------+ | | | | |IE|IE|IE|IE| | +--------+ +--------+ | Memory | - * |MUX|--->| ISP |->|0 |1 |2 |3 |---+ | Interface | - * +--------+ | | | | | | | | | | +--------+ +--------+ +--------+ | | - * |Parallel|--->| / | | | | | | | | | | | | | | | | - * +--------+ |/ | | | | | | | -->| Crop |->| RSZ |->| RGB |->| | - * | | | | | | | | | | | | Rotate | | | - * +-----------+ +--+--+--+--+ +--------+ +--------+ +--------+ +-----------+ - * ^ - * +--------+ | |===============================================| - * | DMA |------------------------------------+ Self Picture Path - * +--------+ - * - * rkisp1-stats.c rkisp1-params.c - * |===============| |===============| - * +---------------+ +---------------+ - * | | | | - * | ISP | | ISP | - * | | | | - * +---------------+ +---------------+ - * - * - * Media Topology - * -------------- - * +----------+ +----------+ - * | Sensor 2 | | Sensor X | - * ------------ ... ------------ - * | 0 | | 0 | - * +----------+ +----------+ +-----------+ - * \ | | params | - * \ | | (output) | - * +----------+ \ | +-----------+ - * | Sensor 1 | v v | - * ------------ +------+------+ | - * | 0 |----->| 0 | 1 |<---------+ - * +----------+ |------+------| - * | ISP | - * |------+------| - * +-------------| 2 | 3 |----------+ - * | +------+------+ | - * | | | - * v v v - * +- ---------+ +-----------+ +-----------+ - * | 0 | | 0 | | stats | - * ------------- ------------- | (capture) | - * | Resizer | | Resizer | +-----------+ - * ------------| ------------| - * | 1 | | 1 | - * +-----------+ +-----------+ - * | | - * v v - * +-----------+ +-----------+ - * | selfpath | | mainpath | - * | (capture) | | (capture) | - * +-----------+ +-----------+ - */ - -struct rkisp1_match_data { - const char * const *clks; - unsigned int size; -}; - -/* ---------------------------------------------------------------------------- - * Sensor DT bindings - */ - -static int rkisp1_create_links(struct rkisp1_device *rkisp1) -{ - struct media_entity *source, *sink; - unsigned int flags, source_pad; - struct v4l2_subdev *sd; - unsigned int i; - int ret; - - /* sensor links */ - flags = MEDIA_LNK_FL_ENABLED; - list_for_each_entry(sd, &rkisp1->v4l2_dev.subdevs, list) { - if (sd == &rkisp1->isp.sd || - sd == &rkisp1->resizer_devs[RKISP1_MAINPATH].sd || - sd == &rkisp1->resizer_devs[RKISP1_SELFPATH].sd) - continue; - - ret = media_entity_get_fwnode_pad(&sd->entity, sd->fwnode, - MEDIA_PAD_FL_SOURCE); - if (ret < 0) { - dev_err(rkisp1->dev, "failed to find src pad for %s\n", - sd->name); - return ret; - } - source_pad = ret; - - ret = media_create_pad_link(&sd->entity, source_pad, - &rkisp1->isp.sd.entity, - RKISP1_ISP_PAD_SINK_VIDEO, - flags); - if (ret) - return ret; - - flags = 0; - } - - flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE; - - /* create ISP->RSZ->CAP links */ - for (i = 0; i < 2; i++) { - source = &rkisp1->isp.sd.entity; - sink = &rkisp1->resizer_devs[i].sd.entity; - ret = media_create_pad_link(source, RKISP1_ISP_PAD_SOURCE_VIDEO, - sink, RKISP1_RSZ_PAD_SINK, - MEDIA_LNK_FL_ENABLED); - if (ret) - return ret; - - source = sink; - sink = &rkisp1->capture_devs[i].vnode.vdev.entity; - ret = media_create_pad_link(source, RKISP1_RSZ_PAD_SRC, - sink, 0, flags); - if (ret) - return ret; - } - - /* params links */ - source = &rkisp1->params.vnode.vdev.entity; - sink = &rkisp1->isp.sd.entity; - ret = media_create_pad_link(source, 0, sink, - RKISP1_ISP_PAD_SINK_PARAMS, flags); - if (ret) - return ret; - - /* 3A stats links */ - source = &rkisp1->isp.sd.entity; - sink = &rkisp1->stats.vnode.vdev.entity; - return media_create_pad_link(source, RKISP1_ISP_PAD_SOURCE_STATS, - sink, 0, flags); -} - -static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *sd, - struct v4l2_async_subdev *asd) -{ - struct rkisp1_device *rkisp1 = - container_of(notifier, struct rkisp1_device, notifier); - struct rkisp1_sensor_async *s_asd = - container_of(asd, struct rkisp1_sensor_async, asd); - - s_asd->pixel_rate_ctrl = v4l2_ctrl_find(sd->ctrl_handler, - V4L2_CID_PIXEL_RATE); - s_asd->sd = sd; - s_asd->dphy = devm_phy_get(rkisp1->dev, "dphy"); - if (IS_ERR(s_asd->dphy)) { - if (PTR_ERR(s_asd->dphy) != -EPROBE_DEFER) - dev_err(rkisp1->dev, "Couldn't get the MIPI D-PHY\n"); - return PTR_ERR(s_asd->dphy); - } - - phy_init(s_asd->dphy); - - return 0; -} - -static void rkisp1_subdev_notifier_unbind(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *sd, - struct v4l2_async_subdev *asd) -{ - struct rkisp1_sensor_async *s_asd = - container_of(asd, struct rkisp1_sensor_async, asd); - - phy_exit(s_asd->dphy); -} - -static int rkisp1_subdev_notifier_complete(struct v4l2_async_notifier *notifier) -{ - struct rkisp1_device *rkisp1 = - container_of(notifier, struct rkisp1_device, notifier); - int ret; - - ret = rkisp1_create_links(rkisp1); - if (ret) - return ret; - - ret = v4l2_device_register_subdev_nodes(&rkisp1->v4l2_dev); - if (ret) - return ret; - - dev_dbg(rkisp1->dev, "Async subdev notifier completed\n"); - - return 0; -} - -static const struct v4l2_async_notifier_operations rkisp1_subdev_notifier_ops = { - .bound = rkisp1_subdev_notifier_bound, - .unbind = rkisp1_subdev_notifier_unbind, - .complete = rkisp1_subdev_notifier_complete, -}; - -static int rkisp1_subdev_notifier(struct rkisp1_device *rkisp1) -{ - struct v4l2_async_notifier *ntf = &rkisp1->notifier; - unsigned int next_id = 0; - int ret; - - v4l2_async_notifier_init(ntf); - - while (1) { - struct v4l2_fwnode_endpoint vep = { - .bus_type = V4L2_MBUS_CSI2_DPHY - }; - struct rkisp1_sensor_async *rk_asd = NULL; - struct fwnode_handle *ep; - - ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(rkisp1->dev), - 0, next_id, FWNODE_GRAPH_ENDPOINT_NEXT); - if (!ep) - break; - - ret = v4l2_fwnode_endpoint_parse(ep, &vep); - if (ret) - goto err_parse; - - rk_asd = kzalloc(sizeof(*rk_asd), GFP_KERNEL); - if (!rk_asd) { - ret = -ENOMEM; - goto err_parse; - } - - rk_asd->mbus_type = vep.bus_type; - rk_asd->mbus_flags = vep.bus.mipi_csi2.flags; - rk_asd->lanes = vep.bus.mipi_csi2.num_data_lanes; - - ret = v4l2_async_notifier_add_fwnode_remote_subdev(ntf, ep, - &rk_asd->asd); - if (ret) - goto err_parse; - - dev_dbg(rkisp1->dev, "registered ep id %d with %d lanes\n", - vep.base.id, rk_asd->lanes); - - next_id = vep.base.id + 1; - - fwnode_handle_put(ep); - - continue; -err_parse: - fwnode_handle_put(ep); - kfree(rk_asd); - v4l2_async_notifier_cleanup(ntf); - return ret; - } - - if (next_id == 0) - dev_dbg(rkisp1->dev, "no remote subdevice found\n"); - ntf->ops = &rkisp1_subdev_notifier_ops; - ret = v4l2_async_notifier_register(&rkisp1->v4l2_dev, ntf); - if (ret) { - v4l2_async_notifier_cleanup(ntf); - return ret; - } - return 0; -} - -/* ---------------------------------------------------------------------------- - * Power - */ - -static int __maybe_unused rkisp1_runtime_suspend(struct device *dev) -{ - struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); - - clk_bulk_disable_unprepare(rkisp1->clk_size, rkisp1->clks); - return pinctrl_pm_select_sleep_state(dev); -} - -static int __maybe_unused rkisp1_runtime_resume(struct device *dev) -{ - struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); - int ret; - - ret = pinctrl_pm_select_default_state(dev); - if (ret) - return ret; - ret = clk_bulk_prepare_enable(rkisp1->clk_size, rkisp1->clks); - if (ret) - return ret; - - return 0; -} - -static const struct dev_pm_ops rkisp1_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) - SET_RUNTIME_PM_OPS(rkisp1_runtime_suspend, rkisp1_runtime_resume, NULL) -}; - -/* ---------------------------------------------------------------------------- - * Core - */ - -static int rkisp1_entities_register(struct rkisp1_device *rkisp1) -{ - int ret; - - ret = rkisp1_isp_register(rkisp1); - if (ret) - return ret; - - ret = rkisp1_resizer_devs_register(rkisp1); - if (ret) - goto err_unreg_isp_subdev; - - ret = rkisp1_capture_devs_register(rkisp1); - if (ret) - goto err_unreg_resizer_devs; - - ret = rkisp1_stats_register(rkisp1); - if (ret) - goto err_unreg_capture_devs; - - ret = rkisp1_params_register(rkisp1); - if (ret) - goto err_unreg_stats; - - ret = rkisp1_subdev_notifier(rkisp1); - if (ret) { - dev_err(rkisp1->dev, - "Failed to register subdev notifier(%d)\n", ret); - goto err_unreg_params; - } - - return 0; -err_unreg_params: - rkisp1_params_unregister(rkisp1); -err_unreg_stats: - rkisp1_stats_unregister(rkisp1); -err_unreg_capture_devs: - rkisp1_capture_devs_unregister(rkisp1); -err_unreg_resizer_devs: - rkisp1_resizer_devs_unregister(rkisp1); -err_unreg_isp_subdev: - rkisp1_isp_unregister(rkisp1); - return ret; -} - -static irqreturn_t rkisp1_isr(int irq, void *ctx) -{ - struct device *dev = ctx; - struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); - - /* - * Call rkisp1_capture_isr() first to handle the frame that - * potentially completed using the current frame_sequence number before - * it is potentially incremented by rkisp1_isp_isr() in the vertical - * sync. - */ - rkisp1_capture_isr(rkisp1); - rkisp1_isp_isr(rkisp1); - rkisp1_mipi_isr(rkisp1); - - return IRQ_HANDLED; -} - -static const char * const rk3399_isp_clks[] = { - "isp", - "aclk", - "hclk", -}; - -static const struct rkisp1_match_data rk3399_isp_clk_data = { - .clks = rk3399_isp_clks, - .size = ARRAY_SIZE(rk3399_isp_clks), -}; - -static const struct of_device_id rkisp1_of_match[] = { - { - .compatible = "rockchip,rk3399-cif-isp", - .data = &rk3399_isp_clk_data, - }, - {}, -}; -MODULE_DEVICE_TABLE(of, rkisp1_of_match); - -static void rkisp1_debug_init(struct rkisp1_device *rkisp1) -{ - struct rkisp1_debug *debug = &rkisp1->debug; - - debug->debugfs_dir = debugfs_create_dir(RKISP1_DRIVER_NAME, NULL); - if (!debug->debugfs_dir) { - dev_dbg(rkisp1->dev, "failed to create debugfs directory\n"); - return; - } - debugfs_create_ulong("data_loss", 0444, debug->debugfs_dir, - &debug->data_loss); - debugfs_create_ulong("outform_size_err", 0444, debug->debugfs_dir, - &debug->outform_size_error); - debugfs_create_ulong("img_stabilization_size_error", 0444, - debug->debugfs_dir, - &debug->img_stabilization_size_error); - debugfs_create_ulong("inform_size_error", 0444, debug->debugfs_dir, - &debug->inform_size_error); - debugfs_create_ulong("irq_delay", 0444, debug->debugfs_dir, - &debug->irq_delay); - debugfs_create_ulong("mipi_error", 0444, debug->debugfs_dir, - &debug->mipi_error); - debugfs_create_ulong("stats_error", 0444, debug->debugfs_dir, - &debug->stats_error); - debugfs_create_ulong("mp_stop_timeout", 0444, debug->debugfs_dir, - &debug->stop_timeout[RKISP1_MAINPATH]); - debugfs_create_ulong("sp_stop_timeout", 0444, debug->debugfs_dir, - &debug->stop_timeout[RKISP1_SELFPATH]); - debugfs_create_ulong("mp_frame_drop", 0444, debug->debugfs_dir, - &debug->frame_drop[RKISP1_MAINPATH]); - debugfs_create_ulong("sp_frame_drop", 0444, debug->debugfs_dir, - &debug->frame_drop[RKISP1_SELFPATH]); -} - -static int rkisp1_probe(struct platform_device *pdev) -{ - const struct rkisp1_match_data *clk_data; - struct device *dev = &pdev->dev; - struct rkisp1_device *rkisp1; - struct v4l2_device *v4l2_dev; - unsigned int i; - int ret, irq; - - clk_data = of_device_get_match_data(&pdev->dev); - if (!clk_data) - return -ENODEV; - - rkisp1 = devm_kzalloc(dev, sizeof(*rkisp1), GFP_KERNEL); - if (!rkisp1) - return -ENOMEM; - - dev_set_drvdata(dev, rkisp1); - rkisp1->dev = dev; - - mutex_init(&rkisp1->stream_lock); - - rkisp1->base_addr = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(rkisp1->base_addr)) - return PTR_ERR(rkisp1->base_addr); - - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - - ret = devm_request_irq(dev, irq, rkisp1_isr, IRQF_SHARED, - dev_driver_string(dev), dev); - if (ret) { - dev_err(dev, "request irq failed: %d\n", ret); - return ret; - } - - rkisp1->irq = irq; - - for (i = 0; i < clk_data->size; i++) - rkisp1->clks[i].id = clk_data->clks[i]; - ret = devm_clk_bulk_get(dev, clk_data->size, rkisp1->clks); - if (ret) - return ret; - rkisp1->clk_size = clk_data->size; - - pm_runtime_enable(&pdev->dev); - - strscpy(rkisp1->media_dev.model, RKISP1_DRIVER_NAME, - sizeof(rkisp1->media_dev.model)); - rkisp1->media_dev.dev = &pdev->dev; - strscpy(rkisp1->media_dev.bus_info, RKISP1_BUS_INFO, - sizeof(rkisp1->media_dev.bus_info)); - media_device_init(&rkisp1->media_dev); - - v4l2_dev = &rkisp1->v4l2_dev; - v4l2_dev->mdev = &rkisp1->media_dev; - strscpy(v4l2_dev->name, RKISP1_DRIVER_NAME, sizeof(v4l2_dev->name)); - - ret = v4l2_device_register(rkisp1->dev, &rkisp1->v4l2_dev); - if (ret) - return ret; - - ret = media_device_register(&rkisp1->media_dev); - if (ret) { - dev_err(dev, "Failed to register media device: %d\n", ret); - goto err_unreg_v4l2_dev; - } - - ret = rkisp1_entities_register(rkisp1); - if (ret) - goto err_unreg_media_dev; - - rkisp1_debug_init(rkisp1); - - return 0; - -err_unreg_media_dev: - media_device_unregister(&rkisp1->media_dev); -err_unreg_v4l2_dev: - v4l2_device_unregister(&rkisp1->v4l2_dev); - pm_runtime_disable(&pdev->dev); - return ret; -} - -static int rkisp1_remove(struct platform_device *pdev) -{ - struct rkisp1_device *rkisp1 = platform_get_drvdata(pdev); - - v4l2_async_notifier_unregister(&rkisp1->notifier); - v4l2_async_notifier_cleanup(&rkisp1->notifier); - - rkisp1_params_unregister(rkisp1); - rkisp1_stats_unregister(rkisp1); - rkisp1_capture_devs_unregister(rkisp1); - rkisp1_resizer_devs_unregister(rkisp1); - rkisp1_isp_unregister(rkisp1); - - media_device_unregister(&rkisp1->media_dev); - v4l2_device_unregister(&rkisp1->v4l2_dev); - - pm_runtime_disable(&pdev->dev); - - debugfs_remove_recursive(rkisp1->debug.debugfs_dir); - return 0; -} - -static struct platform_driver rkisp1_drv = { - .driver = { - .name = RKISP1_DRIVER_NAME, - .of_match_table = of_match_ptr(rkisp1_of_match), - .pm = &rkisp1_pm_ops, - }, - .probe = rkisp1_probe, - .remove = rkisp1_remove, -}; - -module_platform_driver(rkisp1_drv); -MODULE_DESCRIPTION("Rockchip ISP1 platform driver"); -MODULE_LICENSE("Dual MIT/GPL"); diff --git a/drivers/staging/media/rkisp1/rkisp1-isp.c b/drivers/staging/media/rkisp1/rkisp1-isp.c deleted file mode 100644 index 48d08ff87da2..000000000000 --- a/drivers/staging/media/rkisp1/rkisp1-isp.c +++ /dev/null @@ -1,1161 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -/* - * Rockchip ISP1 Driver - ISP Subdevice - * - * Copyright (C) 2019 Collabora, Ltd. - * - * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd. - * Copyright (C) 2017 Rockchip Electronics Co., Ltd. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "rkisp1-common.h" - -#define RKISP1_DEF_SINK_PAD_FMT MEDIA_BUS_FMT_SRGGB10_1X10 -#define RKISP1_DEF_SRC_PAD_FMT MEDIA_BUS_FMT_YUYV8_2X8 - -#define RKISP1_ISP_DEV_NAME RKISP1_DRIVER_NAME "_isp" - -/* - * NOTE: MIPI controller and input MUX are also configured in this file. - * This is because ISP Subdev describes not only ISP submodule (input size, - * format, output size, format), but also a virtual route device. - */ - -/* - * There are many variables named with format/frame in below code, - * please see here for their meaning. - * Cropping in the sink pad defines the image region from the sensor. - * Cropping in the source pad defines the region for the Image Stabilizer (IS) - * - * Cropping regions of ISP - * - * +---------------------------------------------------------+ - * | Sensor image | - * | +---------------------------------------------------+ | - * | | CIF_ISP_ACQ (for black level) | | - * | | sink pad format | | - * | | +--------------------------------------------+ | | - * | | | CIF_ISP_OUT | | | - * | | | sink pad crop | | | - * | | | +---------------------------------+ | | | - * | | | | CIF_ISP_IS | | | | - * | | | | source pad crop and format | | | | - * | | | +---------------------------------+ | | | - * | | +--------------------------------------------+ | | - * | +---------------------------------------------------+ | - * +---------------------------------------------------------+ - */ - -static const struct rkisp1_isp_mbus_info rkisp1_isp_formats[] = { - { - .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, - .pixel_enc = V4L2_PIXEL_ENC_YUV, - .direction = RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW10, - .bayer_pat = RKISP1_RAW_RGGB, - .bus_width = 10, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW10, - .bayer_pat = RKISP1_RAW_BGGR, - .bus_width = 10, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW10, - .bayer_pat = RKISP1_RAW_GBRG, - .bus_width = 10, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW10, - .bayer_pat = RKISP1_RAW_GRBG, - .bus_width = 10, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW12, - .bayer_pat = RKISP1_RAW_RGGB, - .bus_width = 12, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW12, - .bayer_pat = RKISP1_RAW_BGGR, - .bus_width = 12, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW12, - .bayer_pat = RKISP1_RAW_GBRG, - .bus_width = 12, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW12, - .bayer_pat = RKISP1_RAW_GRBG, - .bus_width = 12, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW8, - .bayer_pat = RKISP1_RAW_RGGB, - .bus_width = 8, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW8, - .bayer_pat = RKISP1_RAW_BGGR, - .bus_width = 8, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW8, - .bayer_pat = RKISP1_RAW_GBRG, - .bus_width = 8, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW8, - .bayer_pat = RKISP1_RAW_GRBG, - .bus_width = 8, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16, - .pixel_enc = V4L2_PIXEL_ENC_YUV, - .mipi_dt = RKISP1_CIF_CSI2_DT_YUV422_8b, - .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_YCBYCR, - .bus_width = 16, - .direction = RKISP1_ISP_SD_SINK, - }, { - .mbus_code = MEDIA_BUS_FMT_YVYU8_1X16, - .pixel_enc = V4L2_PIXEL_ENC_YUV, - .mipi_dt = RKISP1_CIF_CSI2_DT_YUV422_8b, - .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_YCRYCB, - .bus_width = 16, - .direction = RKISP1_ISP_SD_SINK, - }, { - .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16, - .pixel_enc = V4L2_PIXEL_ENC_YUV, - .mipi_dt = RKISP1_CIF_CSI2_DT_YUV422_8b, - .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_CBYCRY, - .bus_width = 16, - .direction = RKISP1_ISP_SD_SINK, - }, { - .mbus_code = MEDIA_BUS_FMT_VYUY8_1X16, - .pixel_enc = V4L2_PIXEL_ENC_YUV, - .mipi_dt = RKISP1_CIF_CSI2_DT_YUV422_8b, - .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_CRYCBY, - .bus_width = 16, - .direction = RKISP1_ISP_SD_SINK, - }, -}; - -/* ---------------------------------------------------------------------------- - * Helpers - */ - -const struct rkisp1_isp_mbus_info *rkisp1_isp_mbus_info_get(u32 mbus_code) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(rkisp1_isp_formats); i++) { - const struct rkisp1_isp_mbus_info *fmt = &rkisp1_isp_formats[i]; - - if (fmt->mbus_code == mbus_code) - return fmt; - } - - return NULL; -} - -static struct v4l2_subdev *rkisp1_get_remote_sensor(struct v4l2_subdev *sd) -{ - struct media_pad *local, *remote; - struct media_entity *sensor_me; - - local = &sd->entity.pads[RKISP1_ISP_PAD_SINK_VIDEO]; - remote = media_entity_remote_pad(local); - if (!remote) - return NULL; - - sensor_me = remote->entity; - return media_entity_to_v4l2_subdev(sensor_me); -} - -static struct v4l2_mbus_framefmt * -rkisp1_isp_get_pad_fmt(struct rkisp1_isp *isp, - struct v4l2_subdev_pad_config *cfg, - unsigned int pad, u32 which) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&isp->sd, cfg, pad); - else - return v4l2_subdev_get_try_format(&isp->sd, isp->pad_cfg, pad); -} - -static struct v4l2_rect * -rkisp1_isp_get_pad_crop(struct rkisp1_isp *isp, - struct v4l2_subdev_pad_config *cfg, - unsigned int pad, u32 which) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_crop(&isp->sd, cfg, pad); - else - return v4l2_subdev_get_try_crop(&isp->sd, isp->pad_cfg, pad); -} - -/* ---------------------------------------------------------------------------- - * Camera Interface registers configurations - */ - -/* - * Image Stabilization. - * This should only be called when configuring CIF - * or at the frame end interrupt - */ -static void rkisp1_config_ism(struct rkisp1_device *rkisp1) -{ - struct v4l2_rect *src_crop = - rkisp1_isp_get_pad_crop(&rkisp1->isp, NULL, - RKISP1_ISP_PAD_SOURCE_VIDEO, - V4L2_SUBDEV_FORMAT_ACTIVE); - u32 val; - - rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_RECENTER); - rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_MAX_DX); - rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_MAX_DY); - rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_DISPLACE); - rkisp1_write(rkisp1, src_crop->left, RKISP1_CIF_ISP_IS_H_OFFS); - rkisp1_write(rkisp1, src_crop->top, RKISP1_CIF_ISP_IS_V_OFFS); - rkisp1_write(rkisp1, src_crop->width, RKISP1_CIF_ISP_IS_H_SIZE); - rkisp1_write(rkisp1, src_crop->height, RKISP1_CIF_ISP_IS_V_SIZE); - - /* IS(Image Stabilization) is always on, working as output crop */ - rkisp1_write(rkisp1, 1, RKISP1_CIF_ISP_IS_CTRL); - val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL); - val |= RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD; - rkisp1_write(rkisp1, val, RKISP1_CIF_ISP_CTRL); -} - -/* - * configure ISP blocks with input format, size...... - */ -static int rkisp1_config_isp(struct rkisp1_device *rkisp1) -{ - u32 isp_ctrl = 0, irq_mask = 0, acq_mult = 0, signal = 0; - const struct rkisp1_isp_mbus_info *src_fmt, *sink_fmt; - struct rkisp1_sensor_async *sensor; - struct v4l2_mbus_framefmt *sink_frm; - struct v4l2_rect *sink_crop; - - sensor = rkisp1->active_sensor; - sink_fmt = rkisp1->isp.sink_fmt; - src_fmt = rkisp1->isp.src_fmt; - sink_frm = rkisp1_isp_get_pad_fmt(&rkisp1->isp, NULL, - RKISP1_ISP_PAD_SINK_VIDEO, - V4L2_SUBDEV_FORMAT_ACTIVE); - sink_crop = rkisp1_isp_get_pad_crop(&rkisp1->isp, NULL, - RKISP1_ISP_PAD_SINK_VIDEO, - V4L2_SUBDEV_FORMAT_ACTIVE); - - if (sink_fmt->pixel_enc == V4L2_PIXEL_ENC_BAYER) { - acq_mult = 1; - if (src_fmt->pixel_enc == V4L2_PIXEL_ENC_BAYER) { - if (sensor->mbus_type == V4L2_MBUS_BT656) - isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT_ITU656; - else - isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT; - } else { - rkisp1_write(rkisp1, RKISP1_CIF_ISP_DEMOSAIC_TH(0xc), - RKISP1_CIF_ISP_DEMOSAIC); - - if (sensor->mbus_type == V4L2_MBUS_BT656) - isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU656; - else - isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU601; - } - } else if (sink_fmt->pixel_enc == V4L2_PIXEL_ENC_YUV) { - acq_mult = 2; - if (sensor->mbus_type == V4L2_MBUS_CSI2_DPHY) { - isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU601; - } else { - if (sensor->mbus_type == V4L2_MBUS_BT656) - isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU656; - else - isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU601; - } - - irq_mask |= RKISP1_CIF_ISP_DATA_LOSS; - } - - /* Set up input acquisition properties */ - if (sensor->mbus_type == V4L2_MBUS_BT656 || - sensor->mbus_type == V4L2_MBUS_PARALLEL) { - if (sensor->mbus_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) - signal = RKISP1_CIF_ISP_ACQ_PROP_POS_EDGE; - } - - if (sensor->mbus_type == V4L2_MBUS_PARALLEL) { - if (sensor->mbus_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) - signal |= RKISP1_CIF_ISP_ACQ_PROP_VSYNC_LOW; - - if (sensor->mbus_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) - signal |= RKISP1_CIF_ISP_ACQ_PROP_HSYNC_LOW; - } - - rkisp1_write(rkisp1, isp_ctrl, RKISP1_CIF_ISP_CTRL); - rkisp1_write(rkisp1, signal | sink_fmt->yuv_seq | - RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT(sink_fmt->bayer_pat) | - RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_ALL, - RKISP1_CIF_ISP_ACQ_PROP); - rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_ACQ_NR_FRAMES); - - /* Acquisition Size */ - rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_ACQ_H_OFFS); - rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_ACQ_V_OFFS); - rkisp1_write(rkisp1, - acq_mult * sink_frm->width, RKISP1_CIF_ISP_ACQ_H_SIZE); - rkisp1_write(rkisp1, sink_frm->height, RKISP1_CIF_ISP_ACQ_V_SIZE); - - /* ISP Out Area */ - rkisp1_write(rkisp1, sink_crop->left, RKISP1_CIF_ISP_OUT_H_OFFS); - rkisp1_write(rkisp1, sink_crop->top, RKISP1_CIF_ISP_OUT_V_OFFS); - rkisp1_write(rkisp1, sink_crop->width, RKISP1_CIF_ISP_OUT_H_SIZE); - rkisp1_write(rkisp1, sink_crop->height, RKISP1_CIF_ISP_OUT_V_SIZE); - - irq_mask |= RKISP1_CIF_ISP_FRAME | RKISP1_CIF_ISP_V_START | - RKISP1_CIF_ISP_PIC_SIZE_ERROR; - rkisp1_write(rkisp1, irq_mask, RKISP1_CIF_ISP_IMSC); - - if (src_fmt->pixel_enc == V4L2_PIXEL_ENC_BAYER) { - rkisp1_params_disable(&rkisp1->params); - } else { - struct v4l2_mbus_framefmt *src_frm; - - src_frm = rkisp1_isp_get_pad_fmt(&rkisp1->isp, NULL, - RKISP1_ISP_PAD_SINK_VIDEO, - V4L2_SUBDEV_FORMAT_ACTIVE); - rkisp1_params_configure(&rkisp1->params, sink_fmt->bayer_pat, - src_frm->quantization); - } - - return 0; -} - -static int rkisp1_config_dvp(struct rkisp1_device *rkisp1) -{ - const struct rkisp1_isp_mbus_info *sink_fmt = rkisp1->isp.sink_fmt; - u32 val, input_sel; - - switch (sink_fmt->bus_width) { - case 8: - input_sel = RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_8B_ZERO; - break; - case 10: - input_sel = RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_ZERO; - break; - case 12: - input_sel = RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_12B; - break; - default: - dev_err(rkisp1->dev, "Invalid bus width\n"); - return -EINVAL; - } - - val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_ACQ_PROP); - rkisp1_write(rkisp1, val | input_sel, RKISP1_CIF_ISP_ACQ_PROP); - - return 0; -} - -static int rkisp1_config_mipi(struct rkisp1_device *rkisp1) -{ - const struct rkisp1_isp_mbus_info *sink_fmt = rkisp1->isp.sink_fmt; - unsigned int lanes = rkisp1->active_sensor->lanes; - u32 mipi_ctrl; - - if (lanes < 1 || lanes > 4) - return -EINVAL; - - mipi_ctrl = RKISP1_CIF_MIPI_CTRL_NUM_LANES(lanes - 1) | - RKISP1_CIF_MIPI_CTRL_SHUTDOWNLANES(0xf) | - RKISP1_CIF_MIPI_CTRL_ERR_SOT_SYNC_HS_SKIP | - RKISP1_CIF_MIPI_CTRL_CLOCKLANE_ENA; - - rkisp1_write(rkisp1, mipi_ctrl, RKISP1_CIF_MIPI_CTRL); - - /* Configure Data Type and Virtual Channel */ - rkisp1_write(rkisp1, - RKISP1_CIF_MIPI_DATA_SEL_DT(sink_fmt->mipi_dt) | - RKISP1_CIF_MIPI_DATA_SEL_VC(0), - RKISP1_CIF_MIPI_IMG_DATA_SEL); - - /* Clear MIPI interrupts */ - rkisp1_write(rkisp1, ~0, RKISP1_CIF_MIPI_ICR); - /* - * Disable RKISP1_CIF_MIPI_ERR_DPHY interrupt here temporary for - * isp bus may be dead when switch isp. - */ - rkisp1_write(rkisp1, - RKISP1_CIF_MIPI_FRAME_END | RKISP1_CIF_MIPI_ERR_CSI | - RKISP1_CIF_MIPI_ERR_DPHY | - RKISP1_CIF_MIPI_SYNC_FIFO_OVFLW(0x03) | - RKISP1_CIF_MIPI_ADD_DATA_OVFLW, - RKISP1_CIF_MIPI_IMSC); - - dev_dbg(rkisp1->dev, "\n MIPI_CTRL 0x%08x\n" - " MIPI_IMG_DATA_SEL 0x%08x\n" - " MIPI_STATUS 0x%08x\n" - " MIPI_IMSC 0x%08x\n", - rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL), - rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMG_DATA_SEL), - rkisp1_read(rkisp1, RKISP1_CIF_MIPI_STATUS), - rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC)); - - return 0; -} - -/* Configure MUX */ -static int rkisp1_config_path(struct rkisp1_device *rkisp1) -{ - struct rkisp1_sensor_async *sensor = rkisp1->active_sensor; - u32 dpcl = rkisp1_read(rkisp1, RKISP1_CIF_VI_DPCL); - int ret = 0; - - if (sensor->mbus_type == V4L2_MBUS_BT656 || - sensor->mbus_type == V4L2_MBUS_PARALLEL) { - ret = rkisp1_config_dvp(rkisp1); - dpcl |= RKISP1_CIF_VI_DPCL_IF_SEL_PARALLEL; - } else if (sensor->mbus_type == V4L2_MBUS_CSI2_DPHY) { - ret = rkisp1_config_mipi(rkisp1); - dpcl |= RKISP1_CIF_VI_DPCL_IF_SEL_MIPI; - } - - rkisp1_write(rkisp1, dpcl, RKISP1_CIF_VI_DPCL); - - return ret; -} - -/* Hardware configure Entry */ -static int rkisp1_config_cif(struct rkisp1_device *rkisp1) -{ - u32 cif_id; - int ret; - - cif_id = rkisp1_read(rkisp1, RKISP1_CIF_VI_ID); - dev_dbg(rkisp1->dev, "CIF_ID 0x%08x\n", cif_id); - - ret = rkisp1_config_isp(rkisp1); - if (ret) - return ret; - ret = rkisp1_config_path(rkisp1); - if (ret) - return ret; - rkisp1_config_ism(rkisp1); - - return 0; -} - -static void rkisp1_isp_stop(struct rkisp1_device *rkisp1) -{ - u32 val; - - /* - * ISP(mi) stop in mi frame end -> Stop ISP(mipi) -> - * Stop ISP(isp) ->wait for ISP isp off - */ - /* stop and clear MI, MIPI, and ISP interrupts */ - rkisp1_write(rkisp1, 0, RKISP1_CIF_MIPI_IMSC); - rkisp1_write(rkisp1, ~0, RKISP1_CIF_MIPI_ICR); - - rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IMSC); - rkisp1_write(rkisp1, ~0, RKISP1_CIF_ISP_ICR); - - rkisp1_write(rkisp1, 0, RKISP1_CIF_MI_IMSC); - rkisp1_write(rkisp1, ~0, RKISP1_CIF_MI_ICR); - val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL); - rkisp1_write(rkisp1, val & (~RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA), - RKISP1_CIF_MIPI_CTRL); - /* stop ISP */ - val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL); - val &= ~(RKISP1_CIF_ISP_CTRL_ISP_INFORM_ENABLE | - RKISP1_CIF_ISP_CTRL_ISP_ENABLE); - rkisp1_write(rkisp1, val, RKISP1_CIF_ISP_CTRL); - - val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL); - rkisp1_write(rkisp1, val | RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD, - RKISP1_CIF_ISP_CTRL); - - readx_poll_timeout(readl, rkisp1->base_addr + RKISP1_CIF_ISP_RIS, - val, val & RKISP1_CIF_ISP_OFF, 20, 100); - rkisp1_write(rkisp1, - RKISP1_CIF_IRCL_MIPI_SW_RST | RKISP1_CIF_IRCL_ISP_SW_RST, - RKISP1_CIF_IRCL); - rkisp1_write(rkisp1, 0x0, RKISP1_CIF_IRCL); -} - -static void rkisp1_config_clk(struct rkisp1_device *rkisp1) -{ - u32 val = RKISP1_CIF_ICCL_ISP_CLK | RKISP1_CIF_ICCL_CP_CLK | - RKISP1_CIF_ICCL_MRSZ_CLK | RKISP1_CIF_ICCL_SRSZ_CLK | - RKISP1_CIF_ICCL_JPEG_CLK | RKISP1_CIF_ICCL_MI_CLK | - RKISP1_CIF_ICCL_IE_CLK | RKISP1_CIF_ICCL_MIPI_CLK | - RKISP1_CIF_ICCL_DCROP_CLK; - - rkisp1_write(rkisp1, val, RKISP1_CIF_ICCL); -} - -static void rkisp1_isp_start(struct rkisp1_device *rkisp1) -{ - struct rkisp1_sensor_async *sensor = rkisp1->active_sensor; - u32 val; - - rkisp1_config_clk(rkisp1); - - /* Activate MIPI */ - if (sensor->mbus_type == V4L2_MBUS_CSI2_DPHY) { - val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL); - rkisp1_write(rkisp1, val | RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA, - RKISP1_CIF_MIPI_CTRL); - } - /* Activate ISP */ - val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL); - val |= RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD | - RKISP1_CIF_ISP_CTRL_ISP_ENABLE | - RKISP1_CIF_ISP_CTRL_ISP_INFORM_ENABLE; - rkisp1_write(rkisp1, val, RKISP1_CIF_ISP_CTRL); - - /* - * CIF spec says to wait for sufficient time after enabling - * the MIPI interface and before starting the sensor output. - */ - usleep_range(1000, 1200); -} - -/* ---------------------------------------------------------------------------- - * Subdev pad operations - */ - -static int rkisp1_isp_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - unsigned int i, dir; - int pos = 0; - - if (code->pad == RKISP1_ISP_PAD_SINK_VIDEO) { - dir = RKISP1_ISP_SD_SINK; - } else if (code->pad == RKISP1_ISP_PAD_SOURCE_VIDEO) { - dir = RKISP1_ISP_SD_SRC; - } else { - if (code->index > 0) - return -EINVAL; - code->code = MEDIA_BUS_FMT_METADATA_FIXED; - return 0; - } - - if (code->index >= ARRAY_SIZE(rkisp1_isp_formats)) - return -EINVAL; - - for (i = 0; i < ARRAY_SIZE(rkisp1_isp_formats); i++) { - const struct rkisp1_isp_mbus_info *fmt = &rkisp1_isp_formats[i]; - - if (fmt->direction & dir) - pos++; - - if (code->index == pos - 1) { - code->code = fmt->mbus_code; - if (fmt->pixel_enc == V4L2_PIXEL_ENC_YUV && - dir == RKISP1_ISP_SD_SRC) - code->flags = - V4L2_SUBDEV_MBUS_CODE_CSC_QUANTIZATION; - return 0; - } - } - - return -EINVAL; -} - -static int rkisp1_isp_init_config(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg) -{ - struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; - struct v4l2_rect *sink_crop, *src_crop; - - sink_fmt = v4l2_subdev_get_try_format(sd, cfg, - RKISP1_ISP_PAD_SINK_VIDEO); - sink_fmt->width = RKISP1_DEFAULT_WIDTH; - sink_fmt->height = RKISP1_DEFAULT_HEIGHT; - sink_fmt->field = V4L2_FIELD_NONE; - sink_fmt->code = RKISP1_DEF_SINK_PAD_FMT; - - sink_crop = v4l2_subdev_get_try_crop(sd, cfg, - RKISP1_ISP_PAD_SINK_VIDEO); - sink_crop->width = RKISP1_DEFAULT_WIDTH; - sink_crop->height = RKISP1_DEFAULT_HEIGHT; - sink_crop->left = 0; - sink_crop->top = 0; - - src_fmt = v4l2_subdev_get_try_format(sd, cfg, - RKISP1_ISP_PAD_SOURCE_VIDEO); - *src_fmt = *sink_fmt; - src_fmt->code = RKISP1_DEF_SRC_PAD_FMT; - - src_crop = v4l2_subdev_get_try_crop(sd, cfg, - RKISP1_ISP_PAD_SOURCE_VIDEO); - *src_crop = *sink_crop; - - sink_fmt = v4l2_subdev_get_try_format(sd, cfg, - RKISP1_ISP_PAD_SINK_PARAMS); - src_fmt = v4l2_subdev_get_try_format(sd, cfg, - RKISP1_ISP_PAD_SOURCE_STATS); - sink_fmt->width = 0; - sink_fmt->height = 0; - sink_fmt->field = V4L2_FIELD_NONE; - sink_fmt->code = MEDIA_BUS_FMT_METADATA_FIXED; - *src_fmt = *sink_fmt; - - return 0; -} - -static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_mbus_framefmt *format, - unsigned int which) -{ - const struct rkisp1_isp_mbus_info *mbus_info; - struct v4l2_mbus_framefmt *src_fmt; - const struct v4l2_rect *src_crop; - - src_fmt = rkisp1_isp_get_pad_fmt(isp, cfg, - RKISP1_ISP_PAD_SOURCE_VIDEO, which); - src_crop = rkisp1_isp_get_pad_crop(isp, cfg, - RKISP1_ISP_PAD_SOURCE_VIDEO, which); - - src_fmt->code = format->code; - mbus_info = rkisp1_isp_mbus_info_get(src_fmt->code); - if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SRC)) { - src_fmt->code = RKISP1_DEF_SRC_PAD_FMT; - mbus_info = rkisp1_isp_mbus_info_get(src_fmt->code); - } - if (which == V4L2_SUBDEV_FORMAT_ACTIVE) - isp->src_fmt = mbus_info; - src_fmt->width = src_crop->width; - src_fmt->height = src_crop->height; - - /* - * The CSC API is used to allow userspace to force full - * quantization on YUV formats. - */ - if (format->flags & V4L2_MBUS_FRAMEFMT_SET_CSC && - format->quantization == V4L2_QUANTIZATION_FULL_RANGE && - mbus_info->pixel_enc == V4L2_PIXEL_ENC_YUV) - src_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; - else if (mbus_info->pixel_enc == V4L2_PIXEL_ENC_YUV) - src_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; - else - src_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; - - *format = *src_fmt; -} - -static void rkisp1_isp_set_src_crop(struct rkisp1_isp *isp, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_rect *r, unsigned int which) -{ - struct v4l2_mbus_framefmt *src_fmt; - const struct v4l2_rect *sink_crop; - struct v4l2_rect *src_crop; - - src_crop = rkisp1_isp_get_pad_crop(isp, cfg, - RKISP1_ISP_PAD_SOURCE_VIDEO, - which); - sink_crop = rkisp1_isp_get_pad_crop(isp, cfg, - RKISP1_ISP_PAD_SINK_VIDEO, - which); - - src_crop->left = ALIGN(r->left, 2); - src_crop->width = ALIGN(r->width, 2); - src_crop->top = r->top; - src_crop->height = r->height; - rkisp1_sd_adjust_crop_rect(src_crop, sink_crop); - - *r = *src_crop; - - /* Propagate to out format */ - src_fmt = rkisp1_isp_get_pad_fmt(isp, cfg, - RKISP1_ISP_PAD_SOURCE_VIDEO, which); - rkisp1_isp_set_src_fmt(isp, cfg, src_fmt, which); -} - -static void rkisp1_isp_set_sink_crop(struct rkisp1_isp *isp, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_rect *r, unsigned int which) -{ - struct v4l2_rect *sink_crop, *src_crop; - struct v4l2_mbus_framefmt *sink_fmt; - - sink_crop = rkisp1_isp_get_pad_crop(isp, cfg, RKISP1_ISP_PAD_SINK_VIDEO, - which); - sink_fmt = rkisp1_isp_get_pad_fmt(isp, cfg, RKISP1_ISP_PAD_SINK_VIDEO, - which); - - sink_crop->left = ALIGN(r->left, 2); - sink_crop->width = ALIGN(r->width, 2); - sink_crop->top = r->top; - sink_crop->height = r->height; - rkisp1_sd_adjust_crop(sink_crop, sink_fmt); - - *r = *sink_crop; - - /* Propagate to out crop */ - src_crop = rkisp1_isp_get_pad_crop(isp, cfg, - RKISP1_ISP_PAD_SOURCE_VIDEO, which); - rkisp1_isp_set_src_crop(isp, cfg, src_crop, which); -} - -static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_mbus_framefmt *format, - unsigned int which) -{ - const struct rkisp1_isp_mbus_info *mbus_info; - struct v4l2_mbus_framefmt *sink_fmt; - struct v4l2_rect *sink_crop; - - sink_fmt = rkisp1_isp_get_pad_fmt(isp, cfg, RKISP1_ISP_PAD_SINK_VIDEO, - which); - sink_fmt->code = format->code; - mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); - if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SINK)) { - sink_fmt->code = RKISP1_DEF_SINK_PAD_FMT; - mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); - } - if (which == V4L2_SUBDEV_FORMAT_ACTIVE) - isp->sink_fmt = mbus_info; - - sink_fmt->width = clamp_t(u32, format->width, - RKISP1_ISP_MIN_WIDTH, - RKISP1_ISP_MAX_WIDTH); - sink_fmt->height = clamp_t(u32, format->height, - RKISP1_ISP_MIN_HEIGHT, - RKISP1_ISP_MAX_HEIGHT); - - *format = *sink_fmt; - - /* Propagate to in crop */ - sink_crop = rkisp1_isp_get_pad_crop(isp, cfg, RKISP1_ISP_PAD_SINK_VIDEO, - which); - rkisp1_isp_set_sink_crop(isp, cfg, sink_crop, which); -} - -static int rkisp1_isp_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd); - - mutex_lock(&isp->ops_lock); - fmt->format = *rkisp1_isp_get_pad_fmt(isp, cfg, fmt->pad, fmt->which); - mutex_unlock(&isp->ops_lock); - return 0; -} - -static int rkisp1_isp_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd); - - mutex_lock(&isp->ops_lock); - if (fmt->pad == RKISP1_ISP_PAD_SINK_VIDEO) - rkisp1_isp_set_sink_fmt(isp, cfg, &fmt->format, fmt->which); - else if (fmt->pad == RKISP1_ISP_PAD_SOURCE_VIDEO) - rkisp1_isp_set_src_fmt(isp, cfg, &fmt->format, fmt->which); - else - fmt->format = *rkisp1_isp_get_pad_fmt(isp, cfg, fmt->pad, - fmt->which); - - mutex_unlock(&isp->ops_lock); - return 0; -} - -static int rkisp1_isp_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd); - int ret = 0; - - if (sel->pad != RKISP1_ISP_PAD_SOURCE_VIDEO && - sel->pad != RKISP1_ISP_PAD_SINK_VIDEO) - return -EINVAL; - - mutex_lock(&isp->ops_lock); - switch (sel->target) { - case V4L2_SEL_TGT_CROP_BOUNDS: - if (sel->pad == RKISP1_ISP_PAD_SINK_VIDEO) { - struct v4l2_mbus_framefmt *fmt; - - fmt = rkisp1_isp_get_pad_fmt(isp, cfg, sel->pad, - sel->which); - sel->r.height = fmt->height; - sel->r.width = fmt->width; - sel->r.left = 0; - sel->r.top = 0; - } else { - sel->r = *rkisp1_isp_get_pad_crop(isp, cfg, - RKISP1_ISP_PAD_SINK_VIDEO, - sel->which); - } - break; - case V4L2_SEL_TGT_CROP: - sel->r = *rkisp1_isp_get_pad_crop(isp, cfg, sel->pad, - sel->which); - break; - default: - ret = -EINVAL; - } - mutex_unlock(&isp->ops_lock); - return ret; -} - -static int rkisp1_isp_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct rkisp1_device *rkisp1 = - container_of(sd->v4l2_dev, struct rkisp1_device, v4l2_dev); - struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd); - int ret = 0; - - if (sel->target != V4L2_SEL_TGT_CROP) - return -EINVAL; - - dev_dbg(rkisp1->dev, "%s: pad: %d sel(%d,%d)/%dx%d\n", __func__, - sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height); - mutex_lock(&isp->ops_lock); - if (sel->pad == RKISP1_ISP_PAD_SINK_VIDEO) - rkisp1_isp_set_sink_crop(isp, cfg, &sel->r, sel->which); - else if (sel->pad == RKISP1_ISP_PAD_SOURCE_VIDEO) - rkisp1_isp_set_src_crop(isp, cfg, &sel->r, sel->which); - else - ret = -EINVAL; - - mutex_unlock(&isp->ops_lock); - return ret; -} - -static int rkisp1_subdev_link_validate(struct media_link *link) -{ - if (link->sink->index == RKISP1_ISP_PAD_SINK_PARAMS) - return 0; - - return v4l2_subdev_link_validate(link); -} - -static const struct v4l2_subdev_pad_ops rkisp1_isp_pad_ops = { - .enum_mbus_code = rkisp1_isp_enum_mbus_code, - .get_selection = rkisp1_isp_get_selection, - .set_selection = rkisp1_isp_set_selection, - .init_cfg = rkisp1_isp_init_config, - .get_fmt = rkisp1_isp_get_fmt, - .set_fmt = rkisp1_isp_set_fmt, - .link_validate = v4l2_subdev_link_validate_default, -}; - -/* ---------------------------------------------------------------------------- - * Stream operations - */ - -static int rkisp1_mipi_csi2_start(struct rkisp1_isp *isp, - struct rkisp1_sensor_async *sensor) -{ - struct rkisp1_device *rkisp1 = - container_of(isp->sd.v4l2_dev, struct rkisp1_device, v4l2_dev); - union phy_configure_opts opts; - struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy; - s64 pixel_clock; - - if (!sensor->pixel_rate_ctrl) { - dev_warn(rkisp1->dev, "No pixel rate control in sensor subdev\n"); - return -EPIPE; - } - - pixel_clock = v4l2_ctrl_g_ctrl_int64(sensor->pixel_rate_ctrl); - if (!pixel_clock) { - dev_err(rkisp1->dev, "Invalid pixel rate value\n"); - return -EINVAL; - } - - phy_mipi_dphy_get_default_config(pixel_clock, isp->sink_fmt->bus_width, - sensor->lanes, cfg); - phy_set_mode(sensor->dphy, PHY_MODE_MIPI_DPHY); - phy_configure(sensor->dphy, &opts); - phy_power_on(sensor->dphy); - - return 0; -} - -static void rkisp1_mipi_csi2_stop(struct rkisp1_sensor_async *sensor) -{ - phy_power_off(sensor->dphy); -} - -static int rkisp1_isp_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct rkisp1_device *rkisp1 = - container_of(sd->v4l2_dev, struct rkisp1_device, v4l2_dev); - struct rkisp1_isp *isp = &rkisp1->isp; - struct v4l2_subdev *sensor_sd; - int ret = 0; - - if (!enable) { - rkisp1_isp_stop(rkisp1); - rkisp1_mipi_csi2_stop(rkisp1->active_sensor); - return 0; - } - - sensor_sd = rkisp1_get_remote_sensor(sd); - if (!sensor_sd) { - dev_warn(rkisp1->dev, "No link between isp and sensor\n"); - return -ENODEV; - } - - rkisp1->active_sensor = container_of(sensor_sd->asd, - struct rkisp1_sensor_async, asd); - - if (rkisp1->active_sensor->mbus_type != V4L2_MBUS_CSI2_DPHY) - return -EINVAL; - - rkisp1->isp.frame_sequence = -1; - mutex_lock(&isp->ops_lock); - ret = rkisp1_config_cif(rkisp1); - if (ret) - goto mutex_unlock; - - ret = rkisp1_mipi_csi2_start(&rkisp1->isp, rkisp1->active_sensor); - if (ret) - goto mutex_unlock; - - rkisp1_isp_start(rkisp1); - -mutex_unlock: - mutex_unlock(&isp->ops_lock); - return ret; -} - -static int rkisp1_isp_subs_evt(struct v4l2_subdev *sd, struct v4l2_fh *fh, - struct v4l2_event_subscription *sub) -{ - if (sub->type != V4L2_EVENT_FRAME_SYNC) - return -EINVAL; - - /* V4L2_EVENT_FRAME_SYNC doesn't require an id, so zero should be set */ - if (sub->id != 0) - return -EINVAL; - - return v4l2_event_subscribe(fh, sub, 0, NULL); -} - -static const struct media_entity_operations rkisp1_isp_media_ops = { - .link_validate = rkisp1_subdev_link_validate, -}; - -static const struct v4l2_subdev_video_ops rkisp1_isp_video_ops = { - .s_stream = rkisp1_isp_s_stream, -}; - -static const struct v4l2_subdev_core_ops rkisp1_isp_core_ops = { - .subscribe_event = rkisp1_isp_subs_evt, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, -}; - -static const struct v4l2_subdev_ops rkisp1_isp_ops = { - .core = &rkisp1_isp_core_ops, - .video = &rkisp1_isp_video_ops, - .pad = &rkisp1_isp_pad_ops, -}; - -int rkisp1_isp_register(struct rkisp1_device *rkisp1) -{ - struct rkisp1_isp *isp = &rkisp1->isp; - struct media_pad *pads = isp->pads; - struct v4l2_subdev *sd = &isp->sd; - int ret; - - v4l2_subdev_init(sd, &rkisp1_isp_ops); - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; - sd->entity.ops = &rkisp1_isp_media_ops; - sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; - sd->owner = THIS_MODULE; - strscpy(sd->name, RKISP1_ISP_DEV_NAME, sizeof(sd->name)); - - pads[RKISP1_ISP_PAD_SINK_VIDEO].flags = MEDIA_PAD_FL_SINK | - MEDIA_PAD_FL_MUST_CONNECT; - pads[RKISP1_ISP_PAD_SINK_PARAMS].flags = MEDIA_PAD_FL_SINK; - pads[RKISP1_ISP_PAD_SOURCE_VIDEO].flags = MEDIA_PAD_FL_SOURCE; - pads[RKISP1_ISP_PAD_SOURCE_STATS].flags = MEDIA_PAD_FL_SOURCE; - - isp->sink_fmt = rkisp1_isp_mbus_info_get(RKISP1_DEF_SINK_PAD_FMT); - isp->src_fmt = rkisp1_isp_mbus_info_get(RKISP1_DEF_SRC_PAD_FMT); - - mutex_init(&isp->ops_lock); - ret = media_entity_pads_init(&sd->entity, RKISP1_ISP_PAD_MAX, pads); - if (ret) - return ret; - - ret = v4l2_device_register_subdev(&rkisp1->v4l2_dev, sd); - if (ret) { - dev_err(rkisp1->dev, "Failed to register isp subdev\n"); - goto err_cleanup_media_entity; - } - - rkisp1_isp_init_config(sd, rkisp1->isp.pad_cfg); - return 0; - -err_cleanup_media_entity: - media_entity_cleanup(&sd->entity); - - return ret; -} - -void rkisp1_isp_unregister(struct rkisp1_device *rkisp1) -{ - struct v4l2_subdev *sd = &rkisp1->isp.sd; - - v4l2_device_unregister_subdev(sd); - media_entity_cleanup(&sd->entity); -} - -/* ---------------------------------------------------------------------------- - * Interrupt handlers - */ - -void rkisp1_mipi_isr(struct rkisp1_device *rkisp1) -{ - u32 val, status; - - status = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_MIS); - if (!status) - return; - - rkisp1_write(rkisp1, status, RKISP1_CIF_MIPI_ICR); - - /* - * Disable DPHY errctrl interrupt, because this dphy - * erctrl signal is asserted until the next changes - * of line state. This time is may be too long and cpu - * is hold in this interrupt. - */ - if (status & RKISP1_CIF_MIPI_ERR_CTRL(0x0f)) { - val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC); - rkisp1_write(rkisp1, val & ~RKISP1_CIF_MIPI_ERR_CTRL(0x0f), - RKISP1_CIF_MIPI_IMSC); - rkisp1->isp.is_dphy_errctrl_disabled = true; - } - - /* - * Enable DPHY errctrl interrupt again, if mipi have receive - * the whole frame without any error. - */ - if (status == RKISP1_CIF_MIPI_FRAME_END) { - /* - * Enable DPHY errctrl interrupt again, if mipi have receive - * the whole frame without any error. - */ - if (rkisp1->isp.is_dphy_errctrl_disabled) { - val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC); - val |= RKISP1_CIF_MIPI_ERR_CTRL(0x0f); - rkisp1_write(rkisp1, val, RKISP1_CIF_MIPI_IMSC); - rkisp1->isp.is_dphy_errctrl_disabled = false; - } - } else { - rkisp1->debug.mipi_error++; - } -} - -static void rkisp1_isp_queue_event_sof(struct rkisp1_isp *isp) -{ - struct v4l2_event event = { - .type = V4L2_EVENT_FRAME_SYNC, - }; - event.u.frame_sync.frame_sequence = isp->frame_sequence; - - v4l2_event_queue(isp->sd.devnode, &event); -} - -void rkisp1_isp_isr(struct rkisp1_device *rkisp1) -{ - u32 status, isp_err; - - status = rkisp1_read(rkisp1, RKISP1_CIF_ISP_MIS); - if (!status) - return; - - rkisp1_write(rkisp1, status, RKISP1_CIF_ISP_ICR); - - /* Vertical sync signal, starting generating new frame */ - if (status & RKISP1_CIF_ISP_V_START) { - rkisp1->isp.frame_sequence++; - rkisp1_isp_queue_event_sof(&rkisp1->isp); - if (status & RKISP1_CIF_ISP_FRAME) { - WARN_ONCE(1, "irq delay is too long, buffers might not be in sync\n"); - rkisp1->debug.irq_delay++; - } - } - if (status & RKISP1_CIF_ISP_PIC_SIZE_ERROR) { - /* Clear pic_size_error */ - isp_err = rkisp1_read(rkisp1, RKISP1_CIF_ISP_ERR); - if (isp_err & RKISP1_CIF_ISP_ERR_INFORM_SIZE) - rkisp1->debug.inform_size_error++; - if (isp_err & RKISP1_CIF_ISP_ERR_IS_SIZE) - rkisp1->debug.img_stabilization_size_error++; - if (isp_err & RKISP1_CIF_ISP_ERR_OUTFORM_SIZE) - rkisp1->debug.outform_size_error++; - rkisp1_write(rkisp1, isp_err, RKISP1_CIF_ISP_ERR_CLR); - } else if (status & RKISP1_CIF_ISP_DATA_LOSS) { - /* keep track of data_loss in debugfs */ - rkisp1->debug.data_loss++; - } - - if (status & RKISP1_CIF_ISP_FRAME) { - u32 isp_ris; - - /* New frame from the sensor received */ - isp_ris = rkisp1_read(rkisp1, RKISP1_CIF_ISP_RIS); - if (isp_ris & RKISP1_STATS_MEAS_MASK) - rkisp1_stats_isr(&rkisp1->stats, isp_ris); - /* - * Then update changed configs. Some of them involve - * lot of register writes. Do those only one per frame. - * Do the updates in the order of the processing flow. - */ - rkisp1_params_isr(rkisp1); - } - -} diff --git a/drivers/staging/media/rkisp1/rkisp1-params.c b/drivers/staging/media/rkisp1/rkisp1-params.c deleted file mode 100644 index 298c16736b1c..000000000000 --- a/drivers/staging/media/rkisp1/rkisp1-params.c +++ /dev/null @@ -1,1572 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -/* - * Rockchip ISP1 Driver - Params subdevice - * - * Copyright (C) 2017 Rockchip Electronics Co., Ltd. - */ - -#include -#include -#include -#include -#include /* for ISP params */ - -#include "rkisp1-common.h" - -#define RKISP1_PARAMS_DEV_NAME RKISP1_DRIVER_NAME "_params" - -#define RKISP1_ISP_PARAMS_REQ_BUFS_MIN 2 -#define RKISP1_ISP_PARAMS_REQ_BUFS_MAX 8 - -#define RKISP1_ISP_DPCC_LINE_THRESH(n) \ - (RKISP1_CIF_ISP_DPCC_LINE_THRESH_1 + 0x14 * (n)) -#define RKISP1_ISP_DPCC_LINE_MAD_FAC(n) \ - (RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_1 + 0x14 * (n)) -#define RKISP1_ISP_DPCC_PG_FAC(n) \ - (RKISP1_CIF_ISP_DPCC_PG_FAC_1 + 0x14 * (n)) -#define RKISP1_ISP_DPCC_RND_THRESH(n) \ - (RKISP1_CIF_ISP_DPCC_RND_THRESH_1 + 0x14 * (n)) -#define RKISP1_ISP_DPCC_RG_FAC(n) \ - (RKISP1_CIF_ISP_DPCC_RG_FAC_1 + 0x14 * (n)) -#define RKISP1_ISP_CC_COEFF(n) \ - (RKISP1_CIF_ISP_CC_COEFF_0 + (n) * 4) - -static inline void -rkisp1_param_set_bits(struct rkisp1_params *params, u32 reg, u32 bit_mask) -{ - u32 val; - - val = rkisp1_read(params->rkisp1, reg); - rkisp1_write(params->rkisp1, val | bit_mask, reg); -} - -static inline void -rkisp1_param_clear_bits(struct rkisp1_params *params, u32 reg, u32 bit_mask) -{ - u32 val; - - val = rkisp1_read(params->rkisp1, reg); - rkisp1_write(params->rkisp1, val & ~bit_mask, reg); -} - -/* ISP BP interface function */ -static void rkisp1_dpcc_config(struct rkisp1_params *params, - const struct rkisp1_cif_isp_dpcc_config *arg) -{ - unsigned int i; - u32 mode; - - /* avoid to override the old enable value */ - mode = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_DPCC_MODE); - mode &= RKISP1_CIF_ISP_DPCC_ENA; - mode |= arg->mode & ~RKISP1_CIF_ISP_DPCC_ENA; - rkisp1_write(params->rkisp1, mode, RKISP1_CIF_ISP_DPCC_MODE); - rkisp1_write(params->rkisp1, arg->output_mode, - RKISP1_CIF_ISP_DPCC_OUTPUT_MODE); - rkisp1_write(params->rkisp1, arg->set_use, - RKISP1_CIF_ISP_DPCC_SET_USE); - - rkisp1_write(params->rkisp1, arg->methods[0].method, - RKISP1_CIF_ISP_DPCC_METHODS_SET_1); - rkisp1_write(params->rkisp1, arg->methods[1].method, - RKISP1_CIF_ISP_DPCC_METHODS_SET_2); - rkisp1_write(params->rkisp1, arg->methods[2].method, - RKISP1_CIF_ISP_DPCC_METHODS_SET_3); - for (i = 0; i < RKISP1_CIF_ISP_DPCC_METHODS_MAX; i++) { - rkisp1_write(params->rkisp1, arg->methods[i].line_thresh, - RKISP1_ISP_DPCC_LINE_THRESH(i)); - rkisp1_write(params->rkisp1, arg->methods[i].line_mad_fac, - RKISP1_ISP_DPCC_LINE_MAD_FAC(i)); - rkisp1_write(params->rkisp1, arg->methods[i].pg_fac, - RKISP1_ISP_DPCC_PG_FAC(i)); - rkisp1_write(params->rkisp1, arg->methods[i].rnd_thresh, - RKISP1_ISP_DPCC_RND_THRESH(i)); - rkisp1_write(params->rkisp1, arg->methods[i].rg_fac, - RKISP1_ISP_DPCC_RG_FAC(i)); - } - - rkisp1_write(params->rkisp1, arg->rnd_offs, - RKISP1_CIF_ISP_DPCC_RND_OFFS); - rkisp1_write(params->rkisp1, arg->ro_limits, - RKISP1_CIF_ISP_DPCC_RO_LIMITS); -} - -/* ISP black level subtraction interface function */ -static void rkisp1_bls_config(struct rkisp1_params *params, - const struct rkisp1_cif_isp_bls_config *arg) -{ - /* avoid to override the old enable value */ - u32 new_control; - - new_control = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_BLS_CTRL); - new_control &= RKISP1_CIF_ISP_BLS_ENA; - /* fixed subtraction values */ - if (!arg->enable_auto) { - const struct rkisp1_cif_isp_bls_fixed_val *pval = - &arg->fixed_val; - - switch (params->raw_type) { - case RKISP1_RAW_BGGR: - rkisp1_write(params->rkisp1, - pval->r, RKISP1_CIF_ISP_BLS_D_FIXED); - rkisp1_write(params->rkisp1, - pval->gr, RKISP1_CIF_ISP_BLS_C_FIXED); - rkisp1_write(params->rkisp1, - pval->gb, RKISP1_CIF_ISP_BLS_B_FIXED); - rkisp1_write(params->rkisp1, - pval->b, RKISP1_CIF_ISP_BLS_A_FIXED); - break; - case RKISP1_RAW_GBRG: - rkisp1_write(params->rkisp1, - pval->r, RKISP1_CIF_ISP_BLS_C_FIXED); - rkisp1_write(params->rkisp1, - pval->gr, RKISP1_CIF_ISP_BLS_D_FIXED); - rkisp1_write(params->rkisp1, - pval->gb, RKISP1_CIF_ISP_BLS_A_FIXED); - rkisp1_write(params->rkisp1, - pval->b, RKISP1_CIF_ISP_BLS_B_FIXED); - break; - case RKISP1_RAW_GRBG: - rkisp1_write(params->rkisp1, - pval->r, RKISP1_CIF_ISP_BLS_B_FIXED); - rkisp1_write(params->rkisp1, - pval->gr, RKISP1_CIF_ISP_BLS_A_FIXED); - rkisp1_write(params->rkisp1, - pval->gb, RKISP1_CIF_ISP_BLS_D_FIXED); - rkisp1_write(params->rkisp1, - pval->b, RKISP1_CIF_ISP_BLS_C_FIXED); - break; - case RKISP1_RAW_RGGB: - rkisp1_write(params->rkisp1, - pval->r, RKISP1_CIF_ISP_BLS_A_FIXED); - rkisp1_write(params->rkisp1, - pval->gr, RKISP1_CIF_ISP_BLS_B_FIXED); - rkisp1_write(params->rkisp1, - pval->gb, RKISP1_CIF_ISP_BLS_C_FIXED); - rkisp1_write(params->rkisp1, - pval->b, RKISP1_CIF_ISP_BLS_D_FIXED); - break; - default: - break; - } - - } else { - if (arg->en_windows & BIT(1)) { - rkisp1_write(params->rkisp1, arg->bls_window2.h_offs, - RKISP1_CIF_ISP_BLS_H2_START); - rkisp1_write(params->rkisp1, arg->bls_window2.h_size, - RKISP1_CIF_ISP_BLS_H2_STOP); - rkisp1_write(params->rkisp1, arg->bls_window2.v_offs, - RKISP1_CIF_ISP_BLS_V2_START); - rkisp1_write(params->rkisp1, arg->bls_window2.v_size, - RKISP1_CIF_ISP_BLS_V2_STOP); - new_control |= RKISP1_CIF_ISP_BLS_WINDOW_2; - } - - if (arg->en_windows & BIT(0)) { - rkisp1_write(params->rkisp1, arg->bls_window1.h_offs, - RKISP1_CIF_ISP_BLS_H1_START); - rkisp1_write(params->rkisp1, arg->bls_window1.h_size, - RKISP1_CIF_ISP_BLS_H1_STOP); - rkisp1_write(params->rkisp1, arg->bls_window1.v_offs, - RKISP1_CIF_ISP_BLS_V1_START); - rkisp1_write(params->rkisp1, arg->bls_window1.v_size, - RKISP1_CIF_ISP_BLS_V1_STOP); - new_control |= RKISP1_CIF_ISP_BLS_WINDOW_1; - } - - rkisp1_write(params->rkisp1, arg->bls_samples, - RKISP1_CIF_ISP_BLS_SAMPLES); - - new_control |= RKISP1_CIF_ISP_BLS_MODE_MEASURED; - } - rkisp1_write(params->rkisp1, new_control, RKISP1_CIF_ISP_BLS_CTRL); -} - -/* ISP LS correction interface function */ -static void -rkisp1_lsc_correct_matrix_config(struct rkisp1_params *params, - const struct rkisp1_cif_isp_lsc_config *pconfig) -{ - unsigned int isp_lsc_status, sram_addr, isp_lsc_table_sel, i, j, data; - - isp_lsc_status = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_LSC_STATUS); - - /* RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153 = ( 17 * 18 ) >> 1 */ - sram_addr = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ? - RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_0 : - RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153; - rkisp1_write(params->rkisp1, sram_addr, - RKISP1_CIF_ISP_LSC_R_TABLE_ADDR); - rkisp1_write(params->rkisp1, sram_addr, - RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR); - rkisp1_write(params->rkisp1, sram_addr, - RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR); - rkisp1_write(params->rkisp1, sram_addr, - RKISP1_CIF_ISP_LSC_B_TABLE_ADDR); - - /* program data tables (table size is 9 * 17 = 153) */ - for (i = 0; i < RKISP1_CIF_ISP_LSC_SAMPLES_MAX; i++) { - /* - * 17 sectors with 2 values in one DWORD = 9 - * DWORDs (2nd value of last DWORD unused) - */ - for (j = 0; j < RKISP1_CIF_ISP_LSC_SAMPLES_MAX - 1; j += 2) { - data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->r_data_tbl[i][j], - pconfig->r_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_R_TABLE_DATA); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->gr_data_tbl[i][j], - pconfig->gr_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_GR_TABLE_DATA); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->gb_data_tbl[i][j], - pconfig->gb_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_GB_TABLE_DATA); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->b_data_tbl[i][j], - pconfig->b_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_B_TABLE_DATA); - } - data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->r_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_R_TABLE_DATA); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->gr_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_GR_TABLE_DATA); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->gb_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_GB_TABLE_DATA); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA(pconfig->b_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_B_TABLE_DATA); - } - isp_lsc_table_sel = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ? - RKISP1_CIF_ISP_LSC_TABLE_0 : - RKISP1_CIF_ISP_LSC_TABLE_1; - rkisp1_write(params->rkisp1, isp_lsc_table_sel, - RKISP1_CIF_ISP_LSC_TABLE_SEL); -} - -static void rkisp1_lsc_config(struct rkisp1_params *params, - const struct rkisp1_cif_isp_lsc_config *arg) -{ - unsigned int i, data; - u32 lsc_ctrl; - - /* To config must be off , store the current status firstly */ - lsc_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_LSC_CTRL); - rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_LSC_CTRL, - RKISP1_CIF_ISP_LSC_CTRL_ENA); - rkisp1_lsc_correct_matrix_config(params, arg); - - for (i = 0; i < RKISP1_CIF_ISP_LSC_SECTORS_TBL_SIZE / 2; i++) { - /* program x size tables */ - data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->x_size_tbl[i * 2], - arg->x_size_tbl[i * 2 + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_XSIZE_01 + i * 4); - - /* program x grad tables */ - data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->x_grad_tbl[i * 2], - arg->x_grad_tbl[i * 2 + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_XGRAD_01 + i * 4); - - /* program y size tables */ - data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->y_size_tbl[i * 2], - arg->y_size_tbl[i * 2 + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_YSIZE_01 + i * 4); - - /* program y grad tables */ - data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->y_grad_tbl[i * 2], - arg->y_grad_tbl[i * 2 + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_YGRAD_01 + i * 4); - } - - /* restore the lsc ctrl status */ - if (lsc_ctrl & RKISP1_CIF_ISP_LSC_CTRL_ENA) { - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_LSC_CTRL, - RKISP1_CIF_ISP_LSC_CTRL_ENA); - } else { - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_LSC_CTRL, - RKISP1_CIF_ISP_LSC_CTRL_ENA); - } -} - -/* ISP Filtering function */ -static void rkisp1_flt_config(struct rkisp1_params *params, - const struct rkisp1_cif_isp_flt_config *arg) -{ - u32 filt_mode; - - rkisp1_write(params->rkisp1, - arg->thresh_bl0, RKISP1_CIF_ISP_FILT_THRESH_BL0); - rkisp1_write(params->rkisp1, - arg->thresh_bl1, RKISP1_CIF_ISP_FILT_THRESH_BL1); - rkisp1_write(params->rkisp1, - arg->thresh_sh0, RKISP1_CIF_ISP_FILT_THRESH_SH0); - rkisp1_write(params->rkisp1, - arg->thresh_sh1, RKISP1_CIF_ISP_FILT_THRESH_SH1); - rkisp1_write(params->rkisp1, arg->fac_bl0, RKISP1_CIF_ISP_FILT_FAC_BL0); - rkisp1_write(params->rkisp1, arg->fac_bl1, RKISP1_CIF_ISP_FILT_FAC_BL1); - rkisp1_write(params->rkisp1, arg->fac_mid, RKISP1_CIF_ISP_FILT_FAC_MID); - rkisp1_write(params->rkisp1, arg->fac_sh0, RKISP1_CIF_ISP_FILT_FAC_SH0); - rkisp1_write(params->rkisp1, arg->fac_sh1, RKISP1_CIF_ISP_FILT_FAC_SH1); - rkisp1_write(params->rkisp1, - arg->lum_weight, RKISP1_CIF_ISP_FILT_LUM_WEIGHT); - - rkisp1_write(params->rkisp1, - (arg->mode ? RKISP1_CIF_ISP_FLT_MODE_DNR : 0) | - RKISP1_CIF_ISP_FLT_CHROMA_V_MODE(arg->chr_v_mode) | - RKISP1_CIF_ISP_FLT_CHROMA_H_MODE(arg->chr_h_mode) | - RKISP1_CIF_ISP_FLT_GREEN_STAGE1(arg->grn_stage1), - RKISP1_CIF_ISP_FILT_MODE); - - /* avoid to override the old enable value */ - filt_mode = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_FILT_MODE); - filt_mode &= RKISP1_CIF_ISP_FLT_ENA; - if (arg->mode) - filt_mode |= RKISP1_CIF_ISP_FLT_MODE_DNR; - filt_mode |= RKISP1_CIF_ISP_FLT_CHROMA_V_MODE(arg->chr_v_mode) | - RKISP1_CIF_ISP_FLT_CHROMA_H_MODE(arg->chr_h_mode) | - RKISP1_CIF_ISP_FLT_GREEN_STAGE1(arg->grn_stage1); - rkisp1_write(params->rkisp1, filt_mode, RKISP1_CIF_ISP_FILT_MODE); -} - -/* ISP demosaic interface function */ -static int rkisp1_bdm_config(struct rkisp1_params *params, - const struct rkisp1_cif_isp_bdm_config *arg) -{ - u32 bdm_th; - - /* avoid to override the old enable value */ - bdm_th = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_DEMOSAIC); - bdm_th &= RKISP1_CIF_ISP_DEMOSAIC_BYPASS; - bdm_th |= arg->demosaic_th & ~RKISP1_CIF_ISP_DEMOSAIC_BYPASS; - /* set demosaic threshold */ - rkisp1_write(params->rkisp1, bdm_th, RKISP1_CIF_ISP_DEMOSAIC); - return 0; -} - -/* ISP GAMMA correction interface function */ -static void rkisp1_sdg_config(struct rkisp1_params *params, - const struct rkisp1_cif_isp_sdg_config *arg) -{ - unsigned int i; - - rkisp1_write(params->rkisp1, - arg->xa_pnts.gamma_dx0, RKISP1_CIF_ISP_GAMMA_DX_LO); - rkisp1_write(params->rkisp1, - arg->xa_pnts.gamma_dx1, RKISP1_CIF_ISP_GAMMA_DX_HI); - - for (i = 0; i < RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE; i++) { - rkisp1_write(params->rkisp1, arg->curve_r.gamma_y[i], - RKISP1_CIF_ISP_GAMMA_R_Y0 + i * 4); - rkisp1_write(params->rkisp1, arg->curve_g.gamma_y[i], - RKISP1_CIF_ISP_GAMMA_G_Y0 + i * 4); - rkisp1_write(params->rkisp1, arg->curve_b.gamma_y[i], - RKISP1_CIF_ISP_GAMMA_B_Y0 + i * 4); - } -} - -/* ISP GAMMA correction interface function */ -static void rkisp1_goc_config(struct rkisp1_params *params, - const struct rkisp1_cif_isp_goc_config *arg) -{ - unsigned int i; - - rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, - RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); - rkisp1_write(params->rkisp1, arg->mode, RKISP1_CIF_ISP_GAMMA_OUT_MODE); - - for (i = 0; i < RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES; i++) - rkisp1_write(params->rkisp1, arg->gamma_y[i], - RKISP1_CIF_ISP_GAMMA_OUT_Y_0 + i * 4); -} - -/* ISP Cross Talk */ -static void rkisp1_ctk_config(struct rkisp1_params *params, - const struct rkisp1_cif_isp_ctk_config *arg) -{ - unsigned int i, j, k = 0; - - for (i = 0; i < 3; i++) - for (j = 0; j < 3; j++) - rkisp1_write(params->rkisp1, arg->coeff[i][j], - RKISP1_CIF_ISP_CT_COEFF_0 + 4 * k++); - for (i = 0; i < 3; i++) - rkisp1_write(params->rkisp1, arg->ct_offset[i], - RKISP1_CIF_ISP_CT_OFFSET_R + i * 4); -} - -static void rkisp1_ctk_enable(struct rkisp1_params *params, bool en) -{ - if (en) - return; - - /* Write back the default values. */ - rkisp1_write(params->rkisp1, 0x80, RKISP1_CIF_ISP_CT_COEFF_0); - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_1); - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_2); - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_3); - rkisp1_write(params->rkisp1, 0x80, RKISP1_CIF_ISP_CT_COEFF_4); - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_5); - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_6); - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_7); - rkisp1_write(params->rkisp1, 0x80, RKISP1_CIF_ISP_CT_COEFF_8); - - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_OFFSET_R); - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_OFFSET_G); - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_OFFSET_B); -} - -/* ISP White Balance Mode */ -static void rkisp1_awb_meas_config(struct rkisp1_params *params, - const struct rkisp1_cif_isp_awb_meas_config *arg) -{ - u32 reg_val = 0; - /* based on the mode,configure the awb module */ - if (arg->awb_mode == RKISP1_CIF_ISP_AWB_MODE_YCBCR) { - /* Reference Cb and Cr */ - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_AWB_REF_CR_SET(arg->awb_ref_cr) | - arg->awb_ref_cb, RKISP1_CIF_ISP_AWB_REF); - /* Yc Threshold */ - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_AWB_MAX_Y_SET(arg->max_y) | - RKISP1_CIF_ISP_AWB_MIN_Y_SET(arg->min_y) | - RKISP1_CIF_ISP_AWB_MAX_CS_SET(arg->max_csum) | - arg->min_c, RKISP1_CIF_ISP_AWB_THRESH); - } - - reg_val = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP); - if (arg->enable_ymax_cmp) - reg_val |= RKISP1_CIF_ISP_AWB_YMAX_CMP_EN; - else - reg_val &= ~RKISP1_CIF_ISP_AWB_YMAX_CMP_EN; - rkisp1_write(params->rkisp1, reg_val, RKISP1_CIF_ISP_AWB_PROP); - - /* window offset */ - rkisp1_write(params->rkisp1, - arg->awb_wnd.v_offs, RKISP1_CIF_ISP_AWB_WND_V_OFFS); - rkisp1_write(params->rkisp1, - arg->awb_wnd.h_offs, RKISP1_CIF_ISP_AWB_WND_H_OFFS); - /* AWB window size */ - rkisp1_write(params->rkisp1, - arg->awb_wnd.v_size, RKISP1_CIF_ISP_AWB_WND_V_SIZE); - rkisp1_write(params->rkisp1, - arg->awb_wnd.h_size, RKISP1_CIF_ISP_AWB_WND_H_SIZE); - /* Number of frames */ - rkisp1_write(params->rkisp1, - arg->frames, RKISP1_CIF_ISP_AWB_FRAMES); -} - -static void -rkisp1_awb_meas_enable(struct rkisp1_params *params, - const struct rkisp1_cif_isp_awb_meas_config *arg, - bool en) -{ - u32 reg_val = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP); - - /* switch off */ - reg_val &= RKISP1_CIF_ISP_AWB_MODE_MASK_NONE; - - if (en) { - if (arg->awb_mode == RKISP1_CIF_ISP_AWB_MODE_RGB) - reg_val |= RKISP1_CIF_ISP_AWB_MODE_RGB_EN; - else - reg_val |= RKISP1_CIF_ISP_AWB_MODE_YCBCR_EN; - - rkisp1_write(params->rkisp1, reg_val, RKISP1_CIF_ISP_AWB_PROP); - - /* Measurements require AWB block be active. */ - rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, - RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); - } else { - rkisp1_write(params->rkisp1, - reg_val, RKISP1_CIF_ISP_AWB_PROP); - rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, - RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); - } -} - -static void -rkisp1_awb_gain_config(struct rkisp1_params *params, - const struct rkisp1_cif_isp_awb_gain_config *arg) -{ - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_green_r) | - arg->gain_green_b, RKISP1_CIF_ISP_AWB_GAIN_G); - - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_red) | - arg->gain_blue, RKISP1_CIF_ISP_AWB_GAIN_RB); -} - -static void rkisp1_aec_config(struct rkisp1_params *params, - const struct rkisp1_cif_isp_aec_config *arg) -{ - unsigned int block_hsize, block_vsize; - u32 exp_ctrl; - - /* avoid to override the old enable value */ - exp_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_EXP_CTRL); - exp_ctrl &= RKISP1_CIF_ISP_EXP_ENA; - if (arg->autostop) - exp_ctrl |= RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP; - if (arg->mode == RKISP1_CIF_ISP_EXP_MEASURING_MODE_1) - exp_ctrl |= RKISP1_CIF_ISP_EXP_CTRL_MEASMODE_1; - rkisp1_write(params->rkisp1, exp_ctrl, RKISP1_CIF_ISP_EXP_CTRL); - - rkisp1_write(params->rkisp1, - arg->meas_window.h_offs, RKISP1_CIF_ISP_EXP_H_OFFSET); - rkisp1_write(params->rkisp1, - arg->meas_window.v_offs, RKISP1_CIF_ISP_EXP_V_OFFSET); - - block_hsize = arg->meas_window.h_size / - RKISP1_CIF_ISP_EXP_COLUMN_NUM - 1; - block_vsize = arg->meas_window.v_size / - RKISP1_CIF_ISP_EXP_ROW_NUM - 1; - - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_EXP_H_SIZE_SET(block_hsize), - RKISP1_CIF_ISP_EXP_H_SIZE); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_EXP_V_SIZE_SET(block_vsize), - RKISP1_CIF_ISP_EXP_V_SIZE); -} - -static void rkisp1_cproc_config(struct rkisp1_params *params, - const struct rkisp1_cif_isp_cproc_config *arg) -{ - struct rkisp1_cif_isp_isp_other_cfg *cur_other_cfg = - container_of(arg, struct rkisp1_cif_isp_isp_other_cfg, cproc_config); - struct rkisp1_cif_isp_ie_config *cur_ie_config = - &cur_other_cfg->ie_config; - u32 effect = cur_ie_config->effect; - u32 quantization = params->quantization; - - rkisp1_write(params->rkisp1, arg->contrast, RKISP1_CIF_C_PROC_CONTRAST); - rkisp1_write(params->rkisp1, arg->hue, RKISP1_CIF_C_PROC_HUE); - rkisp1_write(params->rkisp1, arg->sat, RKISP1_CIF_C_PROC_SATURATION); - rkisp1_write(params->rkisp1, arg->brightness, - RKISP1_CIF_C_PROC_BRIGHTNESS); - - if (quantization != V4L2_QUANTIZATION_FULL_RANGE || - effect != V4L2_COLORFX_NONE) { - rkisp1_param_clear_bits(params, RKISP1_CIF_C_PROC_CTRL, - RKISP1_CIF_C_PROC_YOUT_FULL | - RKISP1_CIF_C_PROC_YIN_FULL | - RKISP1_CIF_C_PROC_COUT_FULL); - } else { - rkisp1_param_set_bits(params, RKISP1_CIF_C_PROC_CTRL, - RKISP1_CIF_C_PROC_YOUT_FULL | - RKISP1_CIF_C_PROC_YIN_FULL | - RKISP1_CIF_C_PROC_COUT_FULL); - } -} - -static void rkisp1_hst_config(struct rkisp1_params *params, - const struct rkisp1_cif_isp_hst_config *arg) -{ - unsigned int block_hsize, block_vsize; - static const u32 hist_weight_regs[] = { - RKISP1_CIF_ISP_HIST_WEIGHT_00TO30, - RKISP1_CIF_ISP_HIST_WEIGHT_40TO21, - RKISP1_CIF_ISP_HIST_WEIGHT_31TO12, - RKISP1_CIF_ISP_HIST_WEIGHT_22TO03, - RKISP1_CIF_ISP_HIST_WEIGHT_13TO43, - RKISP1_CIF_ISP_HIST_WEIGHT_04TO34, - RKISP1_CIF_ISP_HIST_WEIGHT_44, - }; - const u8 *weight; - unsigned int i; - u32 hist_prop; - - /* avoid to override the old enable value */ - hist_prop = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_HIST_PROP); - hist_prop &= RKISP1_CIF_ISP_HIST_PROP_MODE_MASK; - hist_prop |= RKISP1_CIF_ISP_HIST_PREDIV_SET(arg->histogram_predivider); - rkisp1_write(params->rkisp1, hist_prop, RKISP1_CIF_ISP_HIST_PROP); - rkisp1_write(params->rkisp1, - arg->meas_window.h_offs, - RKISP1_CIF_ISP_HIST_H_OFFS); - rkisp1_write(params->rkisp1, - arg->meas_window.v_offs, - RKISP1_CIF_ISP_HIST_V_OFFS); - - block_hsize = arg->meas_window.h_size / - RKISP1_CIF_ISP_HIST_COLUMN_NUM - 1; - block_vsize = arg->meas_window.v_size / RKISP1_CIF_ISP_HIST_ROW_NUM - 1; - - rkisp1_write(params->rkisp1, block_hsize, RKISP1_CIF_ISP_HIST_H_SIZE); - rkisp1_write(params->rkisp1, block_vsize, RKISP1_CIF_ISP_HIST_V_SIZE); - - weight = arg->hist_weight; - for (i = 0; i < ARRAY_SIZE(hist_weight_regs); ++i, weight += 4) - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_HIST_WEIGHT_SET(weight[0], - weight[1], - weight[2], - weight[3]), - hist_weight_regs[i]); -} - -static void -rkisp1_hst_enable(struct rkisp1_params *params, - const struct rkisp1_cif_isp_hst_config *arg, bool en) -{ - if (en) { - u32 hist_prop = rkisp1_read(params->rkisp1, - RKISP1_CIF_ISP_HIST_PROP); - - hist_prop &= ~RKISP1_CIF_ISP_HIST_PROP_MODE_MASK; - hist_prop |= arg->mode; - rkisp1_param_set_bits(params, RKISP1_CIF_ISP_HIST_PROP, - hist_prop); - } else { - rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_HIST_PROP, - RKISP1_CIF_ISP_HIST_PROP_MODE_MASK); - } -} - -static void rkisp1_afm_config(struct rkisp1_params *params, - const struct rkisp1_cif_isp_afc_config *arg) -{ - size_t num_of_win = min_t(size_t, ARRAY_SIZE(arg->afm_win), - arg->num_afm_win); - u32 afm_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AFM_CTRL); - unsigned int i; - - /* Switch off to configure. */ - rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_AFM_CTRL, - RKISP1_CIF_ISP_AFM_ENA); - - for (i = 0; i < num_of_win; i++) { - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_AFM_WINDOW_X(arg->afm_win[i].h_offs) | - RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_offs), - RKISP1_CIF_ISP_AFM_LT_A + i * 8); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_AFM_WINDOW_X(arg->afm_win[i].h_size + - arg->afm_win[i].h_offs) | - RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_size + - arg->afm_win[i].v_offs), - RKISP1_CIF_ISP_AFM_RB_A + i * 8); - } - rkisp1_write(params->rkisp1, arg->thres, RKISP1_CIF_ISP_AFM_THRES); - rkisp1_write(params->rkisp1, arg->var_shift, - RKISP1_CIF_ISP_AFM_VAR_SHIFT); - /* restore afm status */ - rkisp1_write(params->rkisp1, afm_ctrl, RKISP1_CIF_ISP_AFM_CTRL); -} - -static void rkisp1_ie_config(struct rkisp1_params *params, - const struct rkisp1_cif_isp_ie_config *arg) -{ - u32 eff_ctrl; - - eff_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_IMG_EFF_CTRL); - eff_ctrl &= ~RKISP1_CIF_IMG_EFF_CTRL_MODE_MASK; - - if (params->quantization == V4L2_QUANTIZATION_FULL_RANGE) - eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_YCBCR_FULL; - - switch (arg->effect) { - case V4L2_COLORFX_SEPIA: - eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_SEPIA; - break; - case V4L2_COLORFX_SET_CBCR: - rkisp1_write(params->rkisp1, arg->eff_tint, - RKISP1_CIF_IMG_EFF_TINT); - eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_SEPIA; - break; - /* - * Color selection is similar to water color(AQUA): - * grayscale + selected color w threshold - */ - case V4L2_COLORFX_AQUA: - eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_COLOR_SEL; - rkisp1_write(params->rkisp1, arg->color_sel, - RKISP1_CIF_IMG_EFF_COLOR_SEL); - break; - case V4L2_COLORFX_EMBOSS: - eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_EMBOSS; - rkisp1_write(params->rkisp1, arg->eff_mat_1, - RKISP1_CIF_IMG_EFF_MAT_1); - rkisp1_write(params->rkisp1, arg->eff_mat_2, - RKISP1_CIF_IMG_EFF_MAT_2); - rkisp1_write(params->rkisp1, arg->eff_mat_3, - RKISP1_CIF_IMG_EFF_MAT_3); - break; - case V4L2_COLORFX_SKETCH: - eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_SKETCH; - rkisp1_write(params->rkisp1, arg->eff_mat_3, - RKISP1_CIF_IMG_EFF_MAT_3); - rkisp1_write(params->rkisp1, arg->eff_mat_4, - RKISP1_CIF_IMG_EFF_MAT_4); - rkisp1_write(params->rkisp1, arg->eff_mat_5, - RKISP1_CIF_IMG_EFF_MAT_5); - break; - case V4L2_COLORFX_BW: - eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_BLACKWHITE; - break; - case V4L2_COLORFX_NEGATIVE: - eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_NEGATIVE; - break; - default: - break; - } - - rkisp1_write(params->rkisp1, eff_ctrl, RKISP1_CIF_IMG_EFF_CTRL); -} - -static void rkisp1_ie_enable(struct rkisp1_params *params, bool en) -{ - if (en) { - rkisp1_param_set_bits(params, RKISP1_CIF_ICCL, - RKISP1_CIF_ICCL_IE_CLK); - rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_CTRL_ENABLE, - RKISP1_CIF_IMG_EFF_CTRL); - rkisp1_param_set_bits(params, RKISP1_CIF_IMG_EFF_CTRL, - RKISP1_CIF_IMG_EFF_CTRL_CFG_UPD); - } else { - rkisp1_param_clear_bits(params, RKISP1_CIF_IMG_EFF_CTRL, - RKISP1_CIF_IMG_EFF_CTRL_ENABLE); - rkisp1_param_clear_bits(params, RKISP1_CIF_ICCL, - RKISP1_CIF_ICCL_IE_CLK); - } -} - -static void rkisp1_csm_config(struct rkisp1_params *params, bool full_range) -{ - static const u16 full_range_coeff[] = { - 0x0026, 0x004b, 0x000f, - 0x01ea, 0x01d6, 0x0040, - 0x0040, 0x01ca, 0x01f6 - }; - static const u16 limited_range_coeff[] = { - 0x0021, 0x0040, 0x000d, - 0x01ed, 0x01db, 0x0038, - 0x0038, 0x01d1, 0x01f7, - }; - unsigned int i; - - if (full_range) { - for (i = 0; i < ARRAY_SIZE(full_range_coeff); i++) - rkisp1_write(params->rkisp1, full_range_coeff[i], - RKISP1_CIF_ISP_CC_COEFF_0 + i * 4); - - rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, - RKISP1_CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA | - RKISP1_CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA); - } else { - for (i = 0; i < ARRAY_SIZE(limited_range_coeff); i++) - rkisp1_write(params->rkisp1, limited_range_coeff[i], - RKISP1_CIF_ISP_CC_COEFF_0 + i * 4); - - rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, - RKISP1_CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA | - RKISP1_CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA); - } -} - -/* ISP De-noise Pre-Filter(DPF) function */ -static void rkisp1_dpf_config(struct rkisp1_params *params, - const struct rkisp1_cif_isp_dpf_config *arg) -{ - unsigned int isp_dpf_mode, spatial_coeff, i; - - switch (arg->gain.mode) { - case RKISP1_CIF_ISP_DPF_GAIN_USAGE_NF_GAINS: - isp_dpf_mode = RKISP1_CIF_ISP_DPF_MODE_USE_NF_GAIN | - RKISP1_CIF_ISP_DPF_MODE_AWB_GAIN_COMP; - break; - case RKISP1_CIF_ISP_DPF_GAIN_USAGE_LSC_GAINS: - isp_dpf_mode = RKISP1_CIF_ISP_DPF_MODE_LSC_GAIN_COMP; - break; - case RKISP1_CIF_ISP_DPF_GAIN_USAGE_NF_LSC_GAINS: - isp_dpf_mode = RKISP1_CIF_ISP_DPF_MODE_USE_NF_GAIN | - RKISP1_CIF_ISP_DPF_MODE_AWB_GAIN_COMP | - RKISP1_CIF_ISP_DPF_MODE_LSC_GAIN_COMP; - break; - case RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_GAINS: - isp_dpf_mode = RKISP1_CIF_ISP_DPF_MODE_AWB_GAIN_COMP; - break; - case RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_LSC_GAINS: - isp_dpf_mode = RKISP1_CIF_ISP_DPF_MODE_LSC_GAIN_COMP | - RKISP1_CIF_ISP_DPF_MODE_AWB_GAIN_COMP; - break; - case RKISP1_CIF_ISP_DPF_GAIN_USAGE_DISABLED: - default: - isp_dpf_mode = 0; - break; - } - - if (arg->nll.scale_mode == RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC) - isp_dpf_mode |= RKISP1_CIF_ISP_DPF_MODE_NLL_SEGMENTATION; - if (arg->rb_flt.fltsize == RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_9x9) - isp_dpf_mode |= RKISP1_CIF_ISP_DPF_MODE_RB_FLTSIZE_9x9; - if (!arg->rb_flt.r_enable) - isp_dpf_mode |= RKISP1_CIF_ISP_DPF_MODE_R_FLT_DIS; - if (!arg->rb_flt.b_enable) - isp_dpf_mode |= RKISP1_CIF_ISP_DPF_MODE_B_FLT_DIS; - if (!arg->g_flt.gb_enable) - isp_dpf_mode |= RKISP1_CIF_ISP_DPF_MODE_GB_FLT_DIS; - if (!arg->g_flt.gr_enable) - isp_dpf_mode |= RKISP1_CIF_ISP_DPF_MODE_GR_FLT_DIS; - - rkisp1_param_set_bits(params, RKISP1_CIF_ISP_DPF_MODE, - isp_dpf_mode); - rkisp1_write(params->rkisp1, arg->gain.nf_b_gain, - RKISP1_CIF_ISP_DPF_NF_GAIN_B); - rkisp1_write(params->rkisp1, arg->gain.nf_r_gain, - RKISP1_CIF_ISP_DPF_NF_GAIN_R); - rkisp1_write(params->rkisp1, arg->gain.nf_gb_gain, - RKISP1_CIF_ISP_DPF_NF_GAIN_GB); - rkisp1_write(params->rkisp1, arg->gain.nf_gr_gain, - RKISP1_CIF_ISP_DPF_NF_GAIN_GR); - - for (i = 0; i < RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS; i++) { - rkisp1_write(params->rkisp1, arg->nll.coeff[i], - RKISP1_CIF_ISP_DPF_NULL_COEFF_0 + i * 4); - } - - spatial_coeff = arg->g_flt.spatial_coeff[0] | - (arg->g_flt.spatial_coeff[1] << 8) | - (arg->g_flt.spatial_coeff[2] << 16) | - (arg->g_flt.spatial_coeff[3] << 24); - rkisp1_write(params->rkisp1, spatial_coeff, - RKISP1_CIF_ISP_DPF_S_WEIGHT_G_1_4); - - spatial_coeff = arg->g_flt.spatial_coeff[4] | - (arg->g_flt.spatial_coeff[5] << 8); - rkisp1_write(params->rkisp1, spatial_coeff, - RKISP1_CIF_ISP_DPF_S_WEIGHT_G_5_6); - - spatial_coeff = arg->rb_flt.spatial_coeff[0] | - (arg->rb_flt.spatial_coeff[1] << 8) | - (arg->rb_flt.spatial_coeff[2] << 16) | - (arg->rb_flt.spatial_coeff[3] << 24); - rkisp1_write(params->rkisp1, spatial_coeff, - RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_1_4); - - spatial_coeff = arg->rb_flt.spatial_coeff[4] | - (arg->rb_flt.spatial_coeff[5] << 8); - rkisp1_write(params->rkisp1, spatial_coeff, - RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_5_6); -} - -static void -rkisp1_dpf_strength_config(struct rkisp1_params *params, - const struct rkisp1_cif_isp_dpf_strength_config *arg) -{ - rkisp1_write(params->rkisp1, arg->b, RKISP1_CIF_ISP_DPF_STRENGTH_B); - rkisp1_write(params->rkisp1, arg->g, RKISP1_CIF_ISP_DPF_STRENGTH_G); - rkisp1_write(params->rkisp1, arg->r, RKISP1_CIF_ISP_DPF_STRENGTH_R); -} - -static void -rkisp1_isp_isr_other_config(struct rkisp1_params *params, - const struct rkisp1_params_cfg *new_params) -{ - unsigned int module_en_update, module_cfg_update, module_ens; - - module_en_update = new_params->module_en_update; - module_cfg_update = new_params->module_cfg_update; - module_ens = new_params->module_ens; - - if ((module_en_update & RKISP1_CIF_ISP_MODULE_DPCC) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_DPCC)) { - /*update dpc config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_DPCC) - rkisp1_dpcc_config(params, - &new_params->others.dpcc_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_DPCC) { - if (module_ens & RKISP1_CIF_ISP_MODULE_DPCC) - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_DPCC_MODE, - RKISP1_CIF_ISP_DPCC_ENA); - else - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_DPCC_MODE, - RKISP1_CIF_ISP_DPCC_ENA); - } - } - - if ((module_en_update & RKISP1_CIF_ISP_MODULE_BLS) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_BLS)) { - /* update bls config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_BLS) - rkisp1_bls_config(params, - &new_params->others.bls_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_BLS) { - if (module_ens & RKISP1_CIF_ISP_MODULE_BLS) - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_BLS_CTRL, - RKISP1_CIF_ISP_BLS_ENA); - else - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_BLS_CTRL, - RKISP1_CIF_ISP_BLS_ENA); - } - } - - if ((module_en_update & RKISP1_CIF_ISP_MODULE_SDG) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_SDG)) { - /* update sdg config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_SDG) - rkisp1_sdg_config(params, - &new_params->others.sdg_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_SDG) { - if (module_ens & RKISP1_CIF_ISP_MODULE_SDG) - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_CTRL, - RKISP1_CIF_ISP_CTRL_ISP_GAMMA_IN_ENA); - else - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_CTRL, - RKISP1_CIF_ISP_CTRL_ISP_GAMMA_IN_ENA); - } - } - - if ((module_en_update & RKISP1_CIF_ISP_MODULE_LSC) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_LSC)) { - /* update lsc config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_LSC) - rkisp1_lsc_config(params, - &new_params->others.lsc_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_LSC) { - if (module_ens & RKISP1_CIF_ISP_MODULE_LSC) - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_LSC_CTRL, - RKISP1_CIF_ISP_LSC_CTRL_ENA); - else - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_LSC_CTRL, - RKISP1_CIF_ISP_LSC_CTRL_ENA); - } - } - - if ((module_en_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN)) { - /* update awb gains */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN) - rkisp1_awb_gain_config(params, - &new_params->others.awb_gain_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN) { - if (module_ens & RKISP1_CIF_ISP_MODULE_AWB_GAIN) - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_CTRL, - RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); - else - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_CTRL, - RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); - } - } - - if ((module_en_update & RKISP1_CIF_ISP_MODULE_BDM) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_BDM)) { - /* update bdm config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_BDM) - rkisp1_bdm_config(params, - &new_params->others.bdm_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_BDM) { - if (module_ens & RKISP1_CIF_ISP_MODULE_BDM) - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_DEMOSAIC, - RKISP1_CIF_ISP_DEMOSAIC_BYPASS); - else - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_DEMOSAIC, - RKISP1_CIF_ISP_DEMOSAIC_BYPASS); - } - } - - if ((module_en_update & RKISP1_CIF_ISP_MODULE_FLT) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_FLT)) { - /* update filter config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_FLT) - rkisp1_flt_config(params, - &new_params->others.flt_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_FLT) { - if (module_ens & RKISP1_CIF_ISP_MODULE_FLT) - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_FILT_MODE, - RKISP1_CIF_ISP_FLT_ENA); - else - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_FILT_MODE, - RKISP1_CIF_ISP_FLT_ENA); - } - } - - if ((module_en_update & RKISP1_CIF_ISP_MODULE_CTK) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_CTK)) { - /* update ctk config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_CTK) - rkisp1_ctk_config(params, - &new_params->others.ctk_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_CTK) - rkisp1_ctk_enable(params, - !!(module_ens & RKISP1_CIF_ISP_MODULE_CTK)); - } - - if ((module_en_update & RKISP1_CIF_ISP_MODULE_GOC) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_GOC)) { - /* update goc config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_GOC) - rkisp1_goc_config(params, - &new_params->others.goc_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_GOC) { - if (module_ens & RKISP1_CIF_ISP_MODULE_GOC) - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_CTRL, - RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); - else - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_CTRL, - RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); - } - } - - if ((module_en_update & RKISP1_CIF_ISP_MODULE_CPROC) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_CPROC)) { - /* update cproc config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_CPROC) { - rkisp1_cproc_config(params, - &new_params->others.cproc_config); - } - - if (module_en_update & RKISP1_CIF_ISP_MODULE_CPROC) { - if (module_ens & RKISP1_CIF_ISP_MODULE_CPROC) - rkisp1_param_set_bits(params, - RKISP1_CIF_C_PROC_CTRL, - RKISP1_CIF_C_PROC_CTR_ENABLE); - else - rkisp1_param_clear_bits(params, - RKISP1_CIF_C_PROC_CTRL, - RKISP1_CIF_C_PROC_CTR_ENABLE); - } - } - - if ((module_en_update & RKISP1_CIF_ISP_MODULE_IE) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_IE)) { - /* update ie config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_IE) - rkisp1_ie_config(params, - &new_params->others.ie_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_IE) - rkisp1_ie_enable(params, - !!(module_ens & RKISP1_CIF_ISP_MODULE_IE)); - } - - if ((module_en_update & RKISP1_CIF_ISP_MODULE_DPF) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_DPF)) { - /* update dpf config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_DPF) - rkisp1_dpf_config(params, - &new_params->others.dpf_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_DPF) { - if (module_ens & RKISP1_CIF_ISP_MODULE_DPF) - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_DPF_MODE, - RKISP1_CIF_ISP_DPF_MODE_EN); - else - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_DPF_MODE, - RKISP1_CIF_ISP_DPF_MODE_EN); - } - } - - if ((module_en_update & RKISP1_CIF_ISP_MODULE_DPF_STRENGTH) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_DPF_STRENGTH)) { - /* update dpf strength config */ - rkisp1_dpf_strength_config(params, - &new_params->others.dpf_strength_config); - } -} - -static void rkisp1_isp_isr_meas_config(struct rkisp1_params *params, - struct rkisp1_params_cfg *new_params) -{ - unsigned int module_en_update, module_cfg_update, module_ens; - - module_en_update = new_params->module_en_update; - module_cfg_update = new_params->module_cfg_update; - module_ens = new_params->module_ens; - - if ((module_en_update & RKISP1_CIF_ISP_MODULE_AWB) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB)) { - /* update awb config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB) - rkisp1_awb_meas_config(params, - &new_params->meas.awb_meas_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_AWB) - rkisp1_awb_meas_enable(params, - &new_params->meas.awb_meas_config, - !!(module_ens & RKISP1_CIF_ISP_MODULE_AWB)); - } - - if ((module_en_update & RKISP1_CIF_ISP_MODULE_AFC) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_AFC)) { - /* update afc config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AFC) - rkisp1_afm_config(params, - &new_params->meas.afc_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_AFC) { - if (module_ens & RKISP1_CIF_ISP_MODULE_AFC) - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_AFM_CTRL, - RKISP1_CIF_ISP_AFM_ENA); - else - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_AFM_CTRL, - RKISP1_CIF_ISP_AFM_ENA); - } - } - - if ((module_en_update & RKISP1_CIF_ISP_MODULE_HST) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_HST)) { - /* update hst config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_HST) - rkisp1_hst_config(params, - &new_params->meas.hst_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_HST) - rkisp1_hst_enable(params, - &new_params->meas.hst_config, - !!(module_ens & RKISP1_CIF_ISP_MODULE_HST)); - } - - if ((module_en_update & RKISP1_CIF_ISP_MODULE_AEC) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_AEC)) { - /* update aec config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AEC) - rkisp1_aec_config(params, - &new_params->meas.aec_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_AEC) { - if (module_ens & RKISP1_CIF_ISP_MODULE_AEC) - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_EXP_CTRL, - RKISP1_CIF_ISP_EXP_ENA); - else - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_EXP_CTRL, - RKISP1_CIF_ISP_EXP_ENA); - } - } -} - -static void rkisp1_params_apply_params_cfg(struct rkisp1_params *params, - unsigned int frame_sequence) -{ - struct rkisp1_params_cfg *new_params; - struct rkisp1_buffer *cur_buf = NULL; - - if (list_empty(¶ms->params)) - return; - - cur_buf = list_first_entry(¶ms->params, - struct rkisp1_buffer, queue); - - new_params = (struct rkisp1_params_cfg *)(cur_buf->vaddr); - - rkisp1_isp_isr_other_config(params, new_params); - rkisp1_isp_isr_meas_config(params, new_params); - - /* update shadow register immediately */ - rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD); - - list_del(&cur_buf->queue); - - cur_buf->vb.sequence = frame_sequence; - vb2_buffer_done(&cur_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); -} - -void rkisp1_params_isr(struct rkisp1_device *rkisp1) -{ - /* - * This isr is called when the ISR finishes processing a frame (RKISP1_CIF_ISP_FRAME). - * Configurations performed here will be applied on the next frame. - * Since frame_sequence is updated on the vertical sync signal, we should use - * frame_sequence + 1 here to indicate to userspace on which frame these parameters - * are being applied. - */ - unsigned int frame_sequence = rkisp1->isp.frame_sequence + 1; - struct rkisp1_params *params = &rkisp1->params; - - spin_lock(¶ms->config_lock); - rkisp1_params_apply_params_cfg(params, frame_sequence); - - spin_unlock(¶ms->config_lock); -} - -static const struct rkisp1_cif_isp_awb_meas_config rkisp1_awb_params_default_config = { - { - 0, 0, RKISP1_DEFAULT_WIDTH, RKISP1_DEFAULT_HEIGHT - }, - RKISP1_CIF_ISP_AWB_MODE_YCBCR, 200, 30, 20, 20, 0, 128, 128 -}; - -static const struct rkisp1_cif_isp_aec_config rkisp1_aec_params_default_config = { - RKISP1_CIF_ISP_EXP_MEASURING_MODE_0, - RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP_0, - { - RKISP1_DEFAULT_WIDTH >> 2, RKISP1_DEFAULT_HEIGHT >> 2, - RKISP1_DEFAULT_WIDTH >> 1, RKISP1_DEFAULT_HEIGHT >> 1 - } -}; - -static const struct rkisp1_cif_isp_hst_config rkisp1_hst_params_default_config = { - RKISP1_CIF_ISP_HISTOGRAM_MODE_RGB_COMBINED, - 3, - { - RKISP1_DEFAULT_WIDTH >> 2, RKISP1_DEFAULT_HEIGHT >> 2, - RKISP1_DEFAULT_WIDTH >> 1, RKISP1_DEFAULT_HEIGHT >> 1 - }, - { - 0, /* To be filled in with 0x01 at runtime. */ - } -}; - -static const struct rkisp1_cif_isp_afc_config rkisp1_afc_params_default_config = { - 1, - { - { - 300, 225, 200, 150 - } - }, - 4, - 14 -}; - -static void rkisp1_params_config_parameter(struct rkisp1_params *params) -{ - struct rkisp1_cif_isp_hst_config hst = rkisp1_hst_params_default_config; - - rkisp1_awb_meas_config(params, &rkisp1_awb_params_default_config); - rkisp1_awb_meas_enable(params, &rkisp1_awb_params_default_config, - true); - - rkisp1_aec_config(params, &rkisp1_aec_params_default_config); - rkisp1_param_set_bits(params, RKISP1_CIF_ISP_EXP_CTRL, - RKISP1_CIF_ISP_EXP_ENA); - - rkisp1_afm_config(params, &rkisp1_afc_params_default_config); - rkisp1_param_set_bits(params, RKISP1_CIF_ISP_AFM_CTRL, - RKISP1_CIF_ISP_AFM_ENA); - - memset(hst.hist_weight, 0x01, sizeof(hst.hist_weight)); - rkisp1_hst_config(params, &hst); - rkisp1_param_set_bits(params, RKISP1_CIF_ISP_HIST_PROP, - ~RKISP1_CIF_ISP_HIST_PROP_MODE_MASK | - rkisp1_hst_params_default_config.mode); - - /* set the range */ - if (params->quantization == V4L2_QUANTIZATION_FULL_RANGE) - rkisp1_csm_config(params, true); - else - rkisp1_csm_config(params, false); - - spin_lock_irq(¶ms->config_lock); - - /* apply the first buffer if there is one already */ - rkisp1_params_apply_params_cfg(params, 0); - - spin_unlock_irq(¶ms->config_lock); -} - -void rkisp1_params_configure(struct rkisp1_params *params, - enum rkisp1_fmt_raw_pat_type bayer_pat, - enum v4l2_quantization quantization) -{ - params->quantization = quantization; - params->raw_type = bayer_pat; - rkisp1_params_config_parameter(params); -} - -/* Not called when the camera active, thus not isr protection. */ -void rkisp1_params_disable(struct rkisp1_params *params) -{ - rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_DPCC_MODE, - RKISP1_CIF_ISP_DPCC_ENA); - rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_LSC_CTRL, - RKISP1_CIF_ISP_LSC_CTRL_ENA); - rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_BLS_CTRL, - RKISP1_CIF_ISP_BLS_ENA); - rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, - RKISP1_CIF_ISP_CTRL_ISP_GAMMA_IN_ENA); - rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, - RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); - rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_DEMOSAIC, - RKISP1_CIF_ISP_DEMOSAIC_BYPASS); - rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_FILT_MODE, - RKISP1_CIF_ISP_FLT_ENA); - rkisp1_awb_meas_enable(params, NULL, false); - rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, - RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); - rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_EXP_CTRL, - RKISP1_CIF_ISP_EXP_ENA); - rkisp1_ctk_enable(params, false); - rkisp1_param_clear_bits(params, RKISP1_CIF_C_PROC_CTRL, - RKISP1_CIF_C_PROC_CTR_ENABLE); - rkisp1_hst_enable(params, NULL, false); - rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_AFM_CTRL, - RKISP1_CIF_ISP_AFM_ENA); - rkisp1_ie_enable(params, false); - rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_DPF_MODE, - RKISP1_CIF_ISP_DPF_MODE_EN); -} - -static int rkisp1_params_enum_fmt_meta_out(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct video_device *video = video_devdata(file); - struct rkisp1_params *params = video_get_drvdata(video); - - if (f->index > 0 || f->type != video->queue->type) - return -EINVAL; - - f->pixelformat = params->vdev_fmt.fmt.meta.dataformat; - - return 0; -} - -static int rkisp1_params_g_fmt_meta_out(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct video_device *video = video_devdata(file); - struct rkisp1_params *params = video_get_drvdata(video); - struct v4l2_meta_format *meta = &f->fmt.meta; - - if (f->type != video->queue->type) - return -EINVAL; - - memset(meta, 0, sizeof(*meta)); - meta->dataformat = params->vdev_fmt.fmt.meta.dataformat; - meta->buffersize = params->vdev_fmt.fmt.meta.buffersize; - - return 0; -} - -static int rkisp1_params_querycap(struct file *file, - void *priv, struct v4l2_capability *cap) -{ - struct video_device *vdev = video_devdata(file); - - strscpy(cap->driver, RKISP1_DRIVER_NAME, sizeof(cap->driver)); - strscpy(cap->card, vdev->name, sizeof(cap->card)); - strscpy(cap->bus_info, RKISP1_BUS_INFO, sizeof(cap->bus_info)); - - return 0; -} - -/* ISP params video device IOCTLs */ -static const struct v4l2_ioctl_ops rkisp1_params_ioctl = { - .vidioc_reqbufs = vb2_ioctl_reqbufs, - .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_create_bufs = vb2_ioctl_create_bufs, - .vidioc_qbuf = vb2_ioctl_qbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_prepare_buf = vb2_ioctl_prepare_buf, - .vidioc_expbuf = vb2_ioctl_expbuf, - .vidioc_streamon = vb2_ioctl_streamon, - .vidioc_streamoff = vb2_ioctl_streamoff, - .vidioc_enum_fmt_meta_out = rkisp1_params_enum_fmt_meta_out, - .vidioc_g_fmt_meta_out = rkisp1_params_g_fmt_meta_out, - .vidioc_s_fmt_meta_out = rkisp1_params_g_fmt_meta_out, - .vidioc_try_fmt_meta_out = rkisp1_params_g_fmt_meta_out, - .vidioc_querycap = rkisp1_params_querycap, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -static int rkisp1_params_vb2_queue_setup(struct vb2_queue *vq, - unsigned int *num_buffers, - unsigned int *num_planes, - unsigned int sizes[], - struct device *alloc_devs[]) -{ - *num_buffers = clamp_t(u32, *num_buffers, - RKISP1_ISP_PARAMS_REQ_BUFS_MIN, - RKISP1_ISP_PARAMS_REQ_BUFS_MAX); - - *num_planes = 1; - - sizes[0] = sizeof(struct rkisp1_params_cfg); - - return 0; -} - -static void rkisp1_params_vb2_buf_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct rkisp1_buffer *params_buf = - container_of(vbuf, struct rkisp1_buffer, vb); - struct vb2_queue *vq = vb->vb2_queue; - struct rkisp1_params *params = vq->drv_priv; - - params_buf->vaddr = vb2_plane_vaddr(vb, 0); - spin_lock_irq(¶ms->config_lock); - list_add_tail(¶ms_buf->queue, ¶ms->params); - spin_unlock_irq(¶ms->config_lock); -} - -static int rkisp1_params_vb2_buf_prepare(struct vb2_buffer *vb) -{ - if (vb2_plane_size(vb, 0) < sizeof(struct rkisp1_params_cfg)) - return -EINVAL; - - vb2_set_plane_payload(vb, 0, sizeof(struct rkisp1_params_cfg)); - - return 0; -} - -static void rkisp1_params_vb2_stop_streaming(struct vb2_queue *vq) -{ - struct rkisp1_params *params = vq->drv_priv; - struct rkisp1_buffer *buf; - LIST_HEAD(tmp_list); - - /* - * we first move the buffers into a local list 'tmp_list' - * and then we can iterate it and call vb2_buffer_done - * without holding the lock - */ - spin_lock_irq(¶ms->config_lock); - list_splice_init(¶ms->params, &tmp_list); - spin_unlock_irq(¶ms->config_lock); - - list_for_each_entry(buf, &tmp_list, queue) - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); -} - -static struct vb2_ops rkisp1_params_vb2_ops = { - .queue_setup = rkisp1_params_vb2_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, - .buf_queue = rkisp1_params_vb2_buf_queue, - .buf_prepare = rkisp1_params_vb2_buf_prepare, - .stop_streaming = rkisp1_params_vb2_stop_streaming, - -}; - -static struct v4l2_file_operations rkisp1_params_fops = { - .mmap = vb2_fop_mmap, - .unlocked_ioctl = video_ioctl2, - .poll = vb2_fop_poll, - .open = v4l2_fh_open, - .release = vb2_fop_release -}; - -static int rkisp1_params_init_vb2_queue(struct vb2_queue *q, - struct rkisp1_params *params) -{ - struct rkisp1_vdev_node *node; - - node = container_of(q, struct rkisp1_vdev_node, buf_queue); - - q->type = V4L2_BUF_TYPE_META_OUTPUT; - q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; - q->drv_priv = params; - q->ops = &rkisp1_params_vb2_ops; - q->mem_ops = &vb2_vmalloc_memops; - q->buf_struct_size = sizeof(struct rkisp1_buffer); - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->lock = &node->vlock; - - return vb2_queue_init(q); -} - -static void rkisp1_init_params(struct rkisp1_params *params) -{ - params->vdev_fmt.fmt.meta.dataformat = - V4L2_META_FMT_RK_ISP1_PARAMS; - params->vdev_fmt.fmt.meta.buffersize = - sizeof(struct rkisp1_params_cfg); -} - -int rkisp1_params_register(struct rkisp1_device *rkisp1) -{ - struct rkisp1_params *params = &rkisp1->params; - struct rkisp1_vdev_node *node = ¶ms->vnode; - struct video_device *vdev = &node->vdev; - int ret; - - params->rkisp1 = rkisp1; - mutex_init(&node->vlock); - INIT_LIST_HEAD(¶ms->params); - spin_lock_init(¶ms->config_lock); - - strscpy(vdev->name, RKISP1_PARAMS_DEV_NAME, sizeof(vdev->name)); - - video_set_drvdata(vdev, params); - vdev->ioctl_ops = &rkisp1_params_ioctl; - vdev->fops = &rkisp1_params_fops; - vdev->release = video_device_release_empty; - /* - * Provide a mutex to v4l2 core. It will be used - * to protect all fops and v4l2 ioctls. - */ - vdev->lock = &node->vlock; - vdev->v4l2_dev = &rkisp1->v4l2_dev; - vdev->queue = &node->buf_queue; - vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_META_OUTPUT; - vdev->vfl_dir = VFL_DIR_TX; - rkisp1_params_init_vb2_queue(vdev->queue, params); - rkisp1_init_params(params); - video_set_drvdata(vdev, params); - - node->pad.flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_pads_init(&vdev->entity, 1, &node->pad); - if (ret) - return ret; - ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); - if (ret) { - dev_err(rkisp1->dev, - "failed to register %s, ret=%d\n", vdev->name, ret); - goto err_cleanup_media_entity; - } - return 0; -err_cleanup_media_entity: - media_entity_cleanup(&vdev->entity); - return ret; -} - -void rkisp1_params_unregister(struct rkisp1_device *rkisp1) -{ - struct rkisp1_params *params = &rkisp1->params; - struct rkisp1_vdev_node *node = ¶ms->vnode; - struct video_device *vdev = &node->vdev; - - vb2_video_unregister_device(vdev); - media_entity_cleanup(&vdev->entity); -} diff --git a/drivers/staging/media/rkisp1/rkisp1-regs.h b/drivers/staging/media/rkisp1/rkisp1-regs.h deleted file mode 100644 index 049f6c3a11df..000000000000 --- a/drivers/staging/media/rkisp1/rkisp1-regs.h +++ /dev/null @@ -1,1262 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ -/* - * Rockchip ISP1 Driver - Registers header - * - * Copyright (C) 2017 Rockchip Electronics Co., Ltd. - */ - -#ifndef _RKISP1_REGS_H -#define _RKISP1_REGS_H - -/* ISP_CTRL */ -#define RKISP1_CIF_ISP_CTRL_ISP_ENABLE BIT(0) -#define RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT (0 << 1) -#define RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU656 BIT(1) -#define RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU601 (2 << 1) -#define RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU601 (3 << 1) -#define RKISP1_CIF_ISP_CTRL_ISP_MODE_DATA_MODE (4 << 1) -#define RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU656 (5 << 1) -#define RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT_ITU656 (6 << 1) -#define RKISP1_CIF_ISP_CTRL_ISP_INFORM_ENABLE BIT(4) -#define RKISP1_CIF_ISP_CTRL_ISP_GAMMA_IN_ENA BIT(6) -#define RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA BIT(7) -#define RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD_PERMANENT BIT(8) -#define RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD BIT(9) -#define RKISP1_CIF_ISP_CTRL_ISP_GEN_CFG_UPD BIT(10) -#define RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA BIT(11) -#define RKISP1_CIF_ISP_CTRL_ISP_FLASH_MODE_ENA BIT(12) -#define RKISP1_CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA BIT(13) -#define RKISP1_CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA BIT(14) - -/* ISP_ACQ_PROP */ -#define RKISP1_CIF_ISP_ACQ_PROP_POS_EDGE BIT(0) -#define RKISP1_CIF_ISP_ACQ_PROP_HSYNC_LOW BIT(1) -#define RKISP1_CIF_ISP_ACQ_PROP_VSYNC_LOW BIT(2) -#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_RGGB (0 << 3) -#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_GRBG BIT(3) -#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_GBRG (2 << 3) -#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_BGGR (3 << 3) -#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT(pat) ((pat) << 3) -#define RKISP1_CIF_ISP_ACQ_PROP_YCBYCR (0 << 7) -#define RKISP1_CIF_ISP_ACQ_PROP_YCRYCB BIT(7) -#define RKISP1_CIF_ISP_ACQ_PROP_CBYCRY (2 << 7) -#define RKISP1_CIF_ISP_ACQ_PROP_CRYCBY (3 << 7) -#define RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_ALL (0 << 9) -#define RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_EVEN BIT(9) -#define RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_ODD (2 << 9) -#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_12B (0 << 12) -#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_ZERO BIT(12) -#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_MSB (2 << 12) -#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_8B_ZERO (3 << 12) -#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_8B_MSB (4 << 12) - -/* VI_DPCL */ -#define RKISP1_CIF_VI_DPCL_DMA_JPEG (0 << 0) -#define RKISP1_CIF_VI_DPCL_MP_MUX_MRSZ_MI BIT(0) -#define RKISP1_CIF_VI_DPCL_MP_MUX_MRSZ_JPEG (2 << 0) -#define RKISP1_CIF_VI_DPCL_CHAN_MODE_MP BIT(2) -#define RKISP1_CIF_VI_DPCL_CHAN_MODE_SP (2 << 2) -#define RKISP1_CIF_VI_DPCL_CHAN_MODE_MPSP (3 << 2) -#define RKISP1_CIF_VI_DPCL_DMA_SW_SPMUX (0 << 4) -#define RKISP1_CIF_VI_DPCL_DMA_SW_SI BIT(4) -#define RKISP1_CIF_VI_DPCL_DMA_SW_IE (2 << 4) -#define RKISP1_CIF_VI_DPCL_DMA_SW_JPEG (3 << 4) -#define RKISP1_CIF_VI_DPCL_DMA_SW_ISP (4 << 4) -#define RKISP1_CIF_VI_DPCL_IF_SEL_PARALLEL (0 << 8) -#define RKISP1_CIF_VI_DPCL_IF_SEL_SMIA BIT(8) -#define RKISP1_CIF_VI_DPCL_IF_SEL_MIPI (2 << 8) -#define RKISP1_CIF_VI_DPCL_DMA_IE_MUX_DMA BIT(10) -#define RKISP1_CIF_VI_DPCL_DMA_SP_MUX_DMA BIT(11) - -/* ISP_IMSC - ISP_MIS - ISP_RIS - ISP_ICR - ISP_ISR */ -#define RKISP1_CIF_ISP_OFF BIT(0) -#define RKISP1_CIF_ISP_FRAME BIT(1) -#define RKISP1_CIF_ISP_DATA_LOSS BIT(2) -#define RKISP1_CIF_ISP_PIC_SIZE_ERROR BIT(3) -#define RKISP1_CIF_ISP_AWB_DONE BIT(4) -#define RKISP1_CIF_ISP_FRAME_IN BIT(5) -#define RKISP1_CIF_ISP_V_START BIT(6) -#define RKISP1_CIF_ISP_H_START BIT(7) -#define RKISP1_CIF_ISP_FLASH_ON BIT(8) -#define RKISP1_CIF_ISP_FLASH_OFF BIT(9) -#define RKISP1_CIF_ISP_SHUTTER_ON BIT(10) -#define RKISP1_CIF_ISP_SHUTTER_OFF BIT(11) -#define RKISP1_CIF_ISP_AFM_SUM_OF BIT(12) -#define RKISP1_CIF_ISP_AFM_LUM_OF BIT(13) -#define RKISP1_CIF_ISP_AFM_FIN BIT(14) -#define RKISP1_CIF_ISP_HIST_MEASURE_RDY BIT(15) -#define RKISP1_CIF_ISP_FLASH_CAP BIT(17) -#define RKISP1_CIF_ISP_EXP_END BIT(18) -#define RKISP1_CIF_ISP_VSM_END BIT(19) - -/* ISP_ERR */ -#define RKISP1_CIF_ISP_ERR_INFORM_SIZE BIT(0) -#define RKISP1_CIF_ISP_ERR_IS_SIZE BIT(1) -#define RKISP1_CIF_ISP_ERR_OUTFORM_SIZE BIT(2) - -/* MI_CTRL */ -#define RKISP1_CIF_MI_CTRL_MP_ENABLE BIT(0) -#define RKISP1_CIF_MI_CTRL_SP_ENABLE (2 << 0) -#define RKISP1_CIF_MI_CTRL_JPEG_ENABLE (4 << 0) -#define RKISP1_CIF_MI_CTRL_RAW_ENABLE (8 << 0) -#define RKISP1_CIF_MI_CTRL_HFLIP BIT(4) -#define RKISP1_CIF_MI_CTRL_VFLIP BIT(5) -#define RKISP1_CIF_MI_CTRL_ROT BIT(6) -#define RKISP1_CIF_MI_BYTE_SWAP BIT(7) -#define RKISP1_CIF_MI_SP_Y_FULL_YUV2RGB BIT(8) -#define RKISP1_CIF_MI_SP_CBCR_FULL_YUV2RGB BIT(9) -#define RKISP1_CIF_MI_SP_422NONCOSITEED BIT(10) -#define RKISP1_CIF_MI_MP_PINGPONG_ENABEL BIT(11) -#define RKISP1_CIF_MI_SP_PINGPONG_ENABEL BIT(12) -#define RKISP1_CIF_MI_MP_AUTOUPDATE_ENABLE BIT(13) -#define RKISP1_CIF_MI_SP_AUTOUPDATE_ENABLE BIT(14) -#define RKISP1_CIF_MI_LAST_PIXEL_SIG_ENABLE BIT(15) -#define RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_16 (0 << 16) -#define RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_32 BIT(16) -#define RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_64 (2 << 16) -#define RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_16 (0 << 18) -#define RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_32 BIT(18) -#define RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_64 (2 << 18) -#define RKISP1_CIF_MI_CTRL_INIT_BASE_EN BIT(20) -#define RKISP1_CIF_MI_CTRL_INIT_OFFSET_EN BIT(21) -#define RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8 (0 << 22) -#define RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA BIT(22) -#define RKISP1_MI_CTRL_MP_WRITE_YUVINT (2 << 22) -#define RKISP1_MI_CTRL_MP_WRITE_RAW12 (2 << 22) -#define RKISP1_MI_CTRL_SP_WRITE_PLA (0 << 24) -#define RKISP1_MI_CTRL_SP_WRITE_SPLA BIT(24) -#define RKISP1_MI_CTRL_SP_WRITE_INT (2 << 24) -#define RKISP1_MI_CTRL_SP_INPUT_YUV400 (0 << 26) -#define RKISP1_MI_CTRL_SP_INPUT_YUV420 BIT(26) -#define RKISP1_MI_CTRL_SP_INPUT_YUV422 (2 << 26) -#define RKISP1_MI_CTRL_SP_INPUT_YUV444 (3 << 26) -#define RKISP1_MI_CTRL_SP_OUTPUT_YUV400 (0 << 28) -#define RKISP1_MI_CTRL_SP_OUTPUT_YUV420 BIT(28) -#define RKISP1_MI_CTRL_SP_OUTPUT_YUV422 (2 << 28) -#define RKISP1_MI_CTRL_SP_OUTPUT_YUV444 (3 << 28) -#define RKISP1_MI_CTRL_SP_OUTPUT_RGB565 (4 << 28) -#define RKISP1_MI_CTRL_SP_OUTPUT_RGB666 (5 << 28) -#define RKISP1_MI_CTRL_SP_OUTPUT_RGB888 (6 << 28) - -#define RKISP1_MI_CTRL_MP_FMT_MASK GENMASK(23, 22) -#define RKISP1_MI_CTRL_SP_FMT_MASK GENMASK(30, 24) - -/* MI_INIT */ -#define RKISP1_CIF_MI_INIT_SKIP BIT(2) -#define RKISP1_CIF_MI_INIT_SOFT_UPD BIT(4) - -/* MI_CTRL_SHD */ -#define RKISP1_CIF_MI_CTRL_SHD_MP_IN_ENABLED BIT(0) -#define RKISP1_CIF_MI_CTRL_SHD_SP_IN_ENABLED BIT(1) -#define RKISP1_CIF_MI_CTRL_SHD_JPEG_IN_ENABLED BIT(2) -#define RKISP1_CIF_MI_CTRL_SHD_RAW_IN_ENABLED BIT(3) -#define RKISP1_CIF_MI_CTRL_SHD_MP_OUT_ENABLED BIT(16) -#define RKISP1_CIF_MI_CTRL_SHD_SP_OUT_ENABLED BIT(17) -#define RKISP1_CIF_MI_CTRL_SHD_JPEG_OUT_ENABLED BIT(18) -#define RKISP1_CIF_MI_CTRL_SHD_RAW_OUT_ENABLED BIT(19) - -/* RSZ_CTRL */ -#define RKISP1_CIF_RSZ_CTRL_SCALE_HY_ENABLE BIT(0) -#define RKISP1_CIF_RSZ_CTRL_SCALE_HC_ENABLE BIT(1) -#define RKISP1_CIF_RSZ_CTRL_SCALE_VY_ENABLE BIT(2) -#define RKISP1_CIF_RSZ_CTRL_SCALE_VC_ENABLE BIT(3) -#define RKISP1_CIF_RSZ_CTRL_SCALE_HY_UP BIT(4) -#define RKISP1_CIF_RSZ_CTRL_SCALE_HC_UP BIT(5) -#define RKISP1_CIF_RSZ_CTRL_SCALE_VY_UP BIT(6) -#define RKISP1_CIF_RSZ_CTRL_SCALE_VC_UP BIT(7) -#define RKISP1_CIF_RSZ_CTRL_CFG_UPD BIT(8) -#define RKISP1_CIF_RSZ_CTRL_CFG_UPD_AUTO BIT(9) -#define RKISP1_CIF_RSZ_SCALER_FACTOR BIT(16) - -/* MI_IMSC - MI_MIS - MI_RIS - MI_ICR - MI_ISR */ -#define RKISP1_CIF_MI_FRAME(stream) BIT((stream)->id) -#define RKISP1_CIF_MI_MBLK_LINE BIT(2) -#define RKISP1_CIF_MI_FILL_MP_Y BIT(3) -#define RKISP1_CIF_MI_WRAP_MP_Y BIT(4) -#define RKISP1_CIF_MI_WRAP_MP_CB BIT(5) -#define RKISP1_CIF_MI_WRAP_MP_CR BIT(6) -#define RKISP1_CIF_MI_WRAP_SP_Y BIT(7) -#define RKISP1_CIF_MI_WRAP_SP_CB BIT(8) -#define RKISP1_CIF_MI_WRAP_SP_CR BIT(9) -#define RKISP1_CIF_MI_DMA_READY BIT(11) - -/* MI_STATUS */ -#define RKISP1_CIF_MI_STATUS_MP_Y_FIFO_FULL BIT(0) -#define RKISP1_CIF_MI_STATUS_SP_Y_FIFO_FULL BIT(4) - -/* MI_DMA_CTRL */ -#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_LUM_16 (0 << 0) -#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_LUM_32 BIT(0) -#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_LUM_64 (2 << 0) -#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_CHROM_16 (0 << 2) -#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_CHROM_32 BIT(2) -#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_CHROM_64 (2 << 2) -#define RKISP1_CIF_MI_DMA_CTRL_READ_FMT_PLANAR (0 << 4) -#define RKISP1_CIF_MI_DMA_CTRL_READ_FMT_SPLANAR BIT(4) -#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV400 (0 << 6) -#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV420 BIT(6) -#define RKISP1_CIF_MI_DMA_CTRL_READ_FMT_PACKED (2 << 4) -#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV422 (2 << 6) -#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV444 (3 << 6) -#define RKISP1_CIF_MI_DMA_CTRL_BYTE_SWAP BIT(8) -#define RKISP1_CIF_MI_DMA_CTRL_CONTINUOUS_ENA BIT(9) -#define RKISP1_CIF_MI_DMA_CTRL_RGB_BAYER_NO (0 << 12) -#define RKISP1_CIF_MI_DMA_CTRL_RGB_BAYER_8BIT BIT(12) -#define RKISP1_CIF_MI_DMA_CTRL_RGB_BAYER_16BIT (2 << 12) -/* MI_DMA_START */ -#define RKISP1_CIF_MI_DMA_START_ENABLE BIT(0) -/* MI_XTD_FORMAT_CTRL */ -#define RKISP1_CIF_MI_XTD_FMT_CTRL_MP_CB_CR_SWAP BIT(0) -#define RKISP1_CIF_MI_XTD_FMT_CTRL_SP_CB_CR_SWAP BIT(1) -#define RKISP1_CIF_MI_XTD_FMT_CTRL_DMA_CB_CR_SWAP BIT(2) - -/* CCL */ -#define RKISP1_CIF_CCL_CIF_CLK_DIS BIT(2) -/* ICCL */ -#define RKISP1_CIF_ICCL_ISP_CLK BIT(0) -#define RKISP1_CIF_ICCL_CP_CLK BIT(1) -#define RKISP1_CIF_ICCL_RES_2 BIT(2) -#define RKISP1_CIF_ICCL_MRSZ_CLK BIT(3) -#define RKISP1_CIF_ICCL_SRSZ_CLK BIT(4) -#define RKISP1_CIF_ICCL_JPEG_CLK BIT(5) -#define RKISP1_CIF_ICCL_MI_CLK BIT(6) -#define RKISP1_CIF_ICCL_RES_7 BIT(7) -#define RKISP1_CIF_ICCL_IE_CLK BIT(8) -#define RKISP1_CIF_ICCL_SIMP_CLK BIT(9) -#define RKISP1_CIF_ICCL_SMIA_CLK BIT(10) -#define RKISP1_CIF_ICCL_MIPI_CLK BIT(11) -#define RKISP1_CIF_ICCL_DCROP_CLK BIT(12) -/* IRCL */ -#define RKISP1_CIF_IRCL_ISP_SW_RST BIT(0) -#define RKISP1_CIF_IRCL_CP_SW_RST BIT(1) -#define RKISP1_CIF_IRCL_YCS_SW_RST BIT(2) -#define RKISP1_CIF_IRCL_MRSZ_SW_RST BIT(3) -#define RKISP1_CIF_IRCL_SRSZ_SW_RST BIT(4) -#define RKISP1_CIF_IRCL_JPEG_SW_RST BIT(5) -#define RKISP1_CIF_IRCL_MI_SW_RST BIT(6) -#define RKISP1_CIF_IRCL_CIF_SW_RST BIT(7) -#define RKISP1_CIF_IRCL_IE_SW_RST BIT(8) -#define RKISP1_CIF_IRCL_SI_SW_RST BIT(9) -#define RKISP1_CIF_IRCL_MIPI_SW_RST BIT(11) - -/* C_PROC_CTR */ -#define RKISP1_CIF_C_PROC_CTR_ENABLE BIT(0) -#define RKISP1_CIF_C_PROC_YOUT_FULL BIT(1) -#define RKISP1_CIF_C_PROC_YIN_FULL BIT(2) -#define RKISP1_CIF_C_PROC_COUT_FULL BIT(3) -#define RKISP1_CIF_C_PROC_CTRL_RESERVED 0xFFFFFFFE -#define RKISP1_CIF_C_PROC_CONTRAST_RESERVED 0xFFFFFF00 -#define RKISP1_CIF_C_PROC_BRIGHTNESS_RESERVED 0xFFFFFF00 -#define RKISP1_CIF_C_PROC_HUE_RESERVED 0xFFFFFF00 -#define RKISP1_CIF_C_PROC_SATURATION_RESERVED 0xFFFFFF00 -#define RKISP1_CIF_C_PROC_MACC_RESERVED 0xE000E000 -#define RKISP1_CIF_C_PROC_TONE_RESERVED 0xF000 -/* DUAL_CROP_CTRL */ -#define RKISP1_CIF_DUAL_CROP_MP_MODE_BYPASS (0 << 0) -#define RKISP1_CIF_DUAL_CROP_MP_MODE_YUV BIT(0) -#define RKISP1_CIF_DUAL_CROP_MP_MODE_RAW (2 << 0) -#define RKISP1_CIF_DUAL_CROP_SP_MODE_BYPASS (0 << 2) -#define RKISP1_CIF_DUAL_CROP_SP_MODE_YUV BIT(2) -#define RKISP1_CIF_DUAL_CROP_SP_MODE_RAW (2 << 2) -#define RKISP1_CIF_DUAL_CROP_CFG_UPD_PERMANENT BIT(4) -#define RKISP1_CIF_DUAL_CROP_CFG_UPD BIT(5) -#define RKISP1_CIF_DUAL_CROP_GEN_CFG_UPD BIT(6) - -/* IMG_EFF_CTRL */ -#define RKISP1_CIF_IMG_EFF_CTRL_ENABLE BIT(0) -#define RKISP1_CIF_IMG_EFF_CTRL_MODE_BLACKWHITE (0 << 1) -#define RKISP1_CIF_IMG_EFF_CTRL_MODE_NEGATIVE BIT(1) -#define RKISP1_CIF_IMG_EFF_CTRL_MODE_SEPIA (2 << 1) -#define RKISP1_CIF_IMG_EFF_CTRL_MODE_COLOR_SEL (3 << 1) -#define RKISP1_CIF_IMG_EFF_CTRL_MODE_EMBOSS (4 << 1) -#define RKISP1_CIF_IMG_EFF_CTRL_MODE_SKETCH (5 << 1) -#define RKISP1_CIF_IMG_EFF_CTRL_MODE_SHARPEN (6 << 1) -#define RKISP1_CIF_IMG_EFF_CTRL_CFG_UPD BIT(4) -#define RKISP1_CIF_IMG_EFF_CTRL_YCBCR_FULL BIT(5) - -#define RKISP1_CIF_IMG_EFF_CTRL_MODE_BLACKWHITE_SHIFT 0 -#define RKISP1_CIF_IMG_EFF_CTRL_MODE_NEGATIVE_SHIFT 1 -#define RKISP1_CIF_IMG_EFF_CTRL_MODE_SEPIA_SHIFT 2 -#define RKISP1_CIF_IMG_EFF_CTRL_MODE_COLOR_SEL_SHIFT 3 -#define RKISP1_CIF_IMG_EFF_CTRL_MODE_EMBOSS_SHIFT 4 -#define RKISP1_CIF_IMG_EFF_CTRL_MODE_SKETCH_SHIFT 5 -#define RKISP1_CIF_IMG_EFF_CTRL_MODE_SHARPEN_SHIFT 6 -#define RKISP1_CIF_IMG_EFF_CTRL_MODE_MASK 0xE - -/* IMG_EFF_COLOR_SEL */ -#define RKISP1_CIF_IMG_EFF_COLOR_RGB 0 -#define RKISP1_CIF_IMG_EFF_COLOR_B BIT(0) -#define RKISP1_CIF_IMG_EFF_COLOR_G (2 << 0) -#define RKISP1_CIF_IMG_EFF_COLOR_GB (3 << 0) -#define RKISP1_CIF_IMG_EFF_COLOR_R (4 << 0) -#define RKISP1_CIF_IMG_EFF_COLOR_RB (5 << 0) -#define RKISP1_CIF_IMG_EFF_COLOR_RG (6 << 0) -#define RKISP1_CIF_IMG_EFF_COLOR_RGB2 (7 << 0) - -/* MIPI_CTRL */ -#define RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA BIT(0) -#define RKISP1_CIF_MIPI_CTRL_SHUTDOWNLANES(a) (((a) & 0xF) << 8) -#define RKISP1_CIF_MIPI_CTRL_NUM_LANES(a) (((a) & 0x3) << 12) -#define RKISP1_CIF_MIPI_CTRL_ERR_SOT_HS_SKIP BIT(16) -#define RKISP1_CIF_MIPI_CTRL_ERR_SOT_SYNC_HS_SKIP BIT(17) -#define RKISP1_CIF_MIPI_CTRL_CLOCKLANE_ENA BIT(18) - -/* MIPI_DATA_SEL */ -#define RKISP1_CIF_MIPI_DATA_SEL_VC(a) (((a) & 0x3) << 6) -#define RKISP1_CIF_MIPI_DATA_SEL_DT(a) (((a) & 0x3F) << 0) -/* MIPI DATA_TYPE */ -#define RKISP1_CIF_CSI2_DT_YUV420_8b 0x18 -#define RKISP1_CIF_CSI2_DT_YUV420_10b 0x19 -#define RKISP1_CIF_CSI2_DT_YUV422_8b 0x1E -#define RKISP1_CIF_CSI2_DT_YUV422_10b 0x1F -#define RKISP1_CIF_CSI2_DT_RGB565 0x22 -#define RKISP1_CIF_CSI2_DT_RGB666 0x23 -#define RKISP1_CIF_CSI2_DT_RGB888 0x24 -#define RKISP1_CIF_CSI2_DT_RAW8 0x2A -#define RKISP1_CIF_CSI2_DT_RAW10 0x2B -#define RKISP1_CIF_CSI2_DT_RAW12 0x2C - -/* MIPI_IMSC, MIPI_RIS, MIPI_MIS, MIPI_ICR, MIPI_ISR */ -#define RKISP1_CIF_MIPI_SYNC_FIFO_OVFLW(a) (((a) & 0xF) << 0) -#define RKISP1_CIF_MIPI_ERR_SOT(a) (((a) & 0xF) << 4) -#define RKISP1_CIF_MIPI_ERR_SOT_SYNC(a) (((a) & 0xF) << 8) -#define RKISP1_CIF_MIPI_ERR_EOT_SYNC(a) (((a) & 0xF) << 12) -#define RKISP1_CIF_MIPI_ERR_CTRL(a) (((a) & 0xF) << 16) -#define RKISP1_CIF_MIPI_ERR_PROTOCOL BIT(20) -#define RKISP1_CIF_MIPI_ERR_ECC1 BIT(21) -#define RKISP1_CIF_MIPI_ERR_ECC2 BIT(22) -#define RKISP1_CIF_MIPI_ERR_CS BIT(23) -#define RKISP1_CIF_MIPI_FRAME_END BIT(24) -#define RKISP1_CIF_MIPI_ADD_DATA_OVFLW BIT(25) -#define RKISP1_CIF_MIPI_ADD_DATA_WATER_MARK BIT(26) - -#define RKISP1_CIF_MIPI_ERR_CSI (RKISP1_CIF_MIPI_ERR_PROTOCOL | \ - RKISP1_CIF_MIPI_ERR_ECC1 | \ - RKISP1_CIF_MIPI_ERR_ECC2 | \ - RKISP1_CIF_MIPI_ERR_CS) - -#define RKISP1_CIF_MIPI_ERR_DPHY (RKISP1_CIF_MIPI_ERR_SOT(3) | \ - RKISP1_CIF_MIPI_ERR_SOT_SYNC(3) | \ - RKISP1_CIF_MIPI_ERR_EOT_SYNC(3) | \ - RKISP1_CIF_MIPI_ERR_CTRL(3)) - -/* SUPER_IMPOSE */ -#define RKISP1_CIF_SUPER_IMP_CTRL_NORMAL_MODE BIT(0) -#define RKISP1_CIF_SUPER_IMP_CTRL_REF_IMG_MEM BIT(1) -#define RKISP1_CIF_SUPER_IMP_CTRL_TRANSP_DIS BIT(2) - -/* ISP HISTOGRAM CALCULATION : ISP_HIST_PROP */ -#define RKISP1_CIF_ISP_HIST_PROP_MODE_DIS (0 << 0) -#define RKISP1_CIF_ISP_HIST_PROP_MODE_RGB BIT(0) -#define RKISP1_CIF_ISP_HIST_PROP_MODE_RED (2 << 0) -#define RKISP1_CIF_ISP_HIST_PROP_MODE_GREEN (3 << 0) -#define RKISP1_CIF_ISP_HIST_PROP_MODE_BLUE (4 << 0) -#define RKISP1_CIF_ISP_HIST_PROP_MODE_LUM (5 << 0) -#define RKISP1_CIF_ISP_HIST_PROP_MODE_MASK 0x7 -#define RKISP1_CIF_ISP_HIST_PREDIV_SET(x) (((x) & 0x7F) << 3) -#define RKISP1_CIF_ISP_HIST_WEIGHT_SET(v0, v1, v2, v3) \ - (((v0) & 0x1F) | (((v1) & 0x1F) << 8) |\ - (((v2) & 0x1F) << 16) | \ - (((v3) & 0x1F) << 24)) - -#define RKISP1_CIF_ISP_HIST_WINDOW_OFFSET_RESERVED 0xFFFFF000 -#define RKISP1_CIF_ISP_HIST_WINDOW_SIZE_RESERVED 0xFFFFF800 -#define RKISP1_CIF_ISP_HIST_WEIGHT_RESERVED 0xE0E0E0E0 -#define RKISP1_CIF_ISP_MAX_HIST_PREDIVIDER 0x0000007F -#define RKISP1_CIF_ISP_HIST_ROW_NUM 5 -#define RKISP1_CIF_ISP_HIST_COLUMN_NUM 5 - -/* AUTO FOCUS MEASUREMENT: ISP_AFM_CTRL */ -#define RKISP1_ISP_AFM_CTRL_ENABLE BIT(0) - -/* SHUTTER CONTROL */ -#define RKISP1_CIF_ISP_SH_CTRL_SH_ENA BIT(0) -#define RKISP1_CIF_ISP_SH_CTRL_REP_EN BIT(1) -#define RKISP1_CIF_ISP_SH_CTRL_SRC_SH_TRIG BIT(2) -#define RKISP1_CIF_ISP_SH_CTRL_EDGE_POS BIT(3) -#define RKISP1_CIF_ISP_SH_CTRL_POL_LOW BIT(4) - -/* FLASH MODULE */ -/* ISP_FLASH_CMD */ -#define RKISP1_CIFFLASH_CMD_PRELIGHT_ON BIT(0) -#define RKISP1_CIFFLASH_CMD_FLASH_ON BIT(1) -#define RKISP1_CIFFLASH_CMD_PRE_FLASH_ON BIT(2) -/* ISP_FLASH_CONFIG */ -#define RKISP1_CIFFLASH_CONFIG_PRELIGHT_END BIT(0) -#define RKISP1_CIFFLASH_CONFIG_VSYNC_POS BIT(1) -#define RKISP1_CIFFLASH_CONFIG_PRELIGHT_LOW BIT(2) -#define RKISP1_CIFFLASH_CONFIG_SRC_FL_TRIG BIT(3) -#define RKISP1_CIFFLASH_CONFIG_DELAY(a) (((a) & 0xF) << 4) - -/* Demosaic: ISP_DEMOSAIC */ -#define RKISP1_CIF_ISP_DEMOSAIC_BYPASS BIT(10) -#define RKISP1_CIF_ISP_DEMOSAIC_TH(x) ((x) & 0xFF) - -/* AWB */ -/* ISP_AWB_PROP */ -#define RKISP1_CIF_ISP_AWB_YMAX_CMP_EN BIT(2) -#define RKISP1_CIF_ISP_AWB_YMAX_READ(x) (((x) >> 2) & 1) -#define RKISP1_CIF_ISP_AWB_MODE_RGB_EN ((1 << 31) | (0x2 << 0)) -#define RKISP1_CIF_ISP_AWB_MODE_YCBCR_EN ((0 << 31) | (0x2 << 0)) -#define RKISP1_CIF_ISP_AWB_MODE_MASK_NONE 0xFFFFFFFC -#define RKISP1_CIF_ISP_AWB_MODE_READ(x) ((x) & 3) -/* ISP_AWB_GAIN_RB, ISP_AWB_GAIN_G */ -#define RKISP1_CIF_ISP_AWB_GAIN_R_SET(x) (((x) & 0x3FF) << 16) -#define RKISP1_CIF_ISP_AWB_GAIN_R_READ(x) (((x) >> 16) & 0x3FF) -#define RKISP1_CIF_ISP_AWB_GAIN_B_SET(x) ((x) & 0x3FFF) -#define RKISP1_CIF_ISP_AWB_GAIN_B_READ(x) ((x) & 0x3FFF) -/* ISP_AWB_REF */ -#define RKISP1_CIF_ISP_AWB_REF_CR_SET(x) (((x) & 0xFF) << 8) -#define RKISP1_CIF_ISP_AWB_REF_CR_READ(x) (((x) >> 8) & 0xFF) -#define RKISP1_CIF_ISP_AWB_REF_CB_READ(x) ((x) & 0xFF) -/* ISP_AWB_THRESH */ -#define RKISP1_CIF_ISP_AWB_MAX_CS_SET(x) (((x) & 0xFF) << 8) -#define RKISP1_CIF_ISP_AWB_MAX_CS_READ(x) (((x) >> 8) & 0xFF) -#define RKISP1_CIF_ISP_AWB_MIN_C_READ(x) ((x) & 0xFF) -#define RKISP1_CIF_ISP_AWB_MIN_Y_SET(x) (((x) & 0xFF) << 16) -#define RKISP1_CIF_ISP_AWB_MIN_Y_READ(x) (((x) >> 16) & 0xFF) -#define RKISP1_CIF_ISP_AWB_MAX_Y_SET(x) (((x) & 0xFF) << 24) -#define RKISP1_CIF_ISP_AWB_MAX_Y_READ(x) (((x) >> 24) & 0xFF) -/* ISP_AWB_MEAN */ -#define RKISP1_CIF_ISP_AWB_GET_MEAN_CR_R(x) ((x) & 0xFF) -#define RKISP1_CIF_ISP_AWB_GET_MEAN_CB_B(x) (((x) >> 8) & 0xFF) -#define RKISP1_CIF_ISP_AWB_GET_MEAN_Y_G(x) (((x) >> 16) & 0xFF) -/* ISP_AWB_WHITE_CNT */ -#define RKISP1_CIF_ISP_AWB_GET_PIXEL_CNT(x) ((x) & 0x3FFFFFF) - -#define RKISP1_CIF_ISP_AWB_GAINS_MAX_VAL 0x000003FF -#define RKISP1_CIF_ISP_AWB_WINDOW_OFFSET_MAX 0x00000FFF -#define RKISP1_CIF_ISP_AWB_WINDOW_MAX_SIZE 0x00001FFF -#define RKISP1_CIF_ISP_AWB_CBCR_MAX_REF 0x000000FF -#define RKISP1_CIF_ISP_AWB_THRES_MAX_YC 0x000000FF - -/* AE */ -/* ISP_EXP_CTRL */ -#define RKISP1_CIF_ISP_EXP_ENA BIT(0) -#define RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP BIT(1) -/* - *'1' luminance calculation according to Y=(R+G+B) x 0.332 (85/256) - *'0' luminance calculation according to Y=16+0.25R+0.5G+0.1094B - */ -#define RKISP1_CIF_ISP_EXP_CTRL_MEASMODE_1 BIT(31) - -/* ISP_EXP_H_SIZE */ -#define RKISP1_CIF_ISP_EXP_H_SIZE_SET(x) ((x) & 0x7FF) -#define RKISP1_CIF_ISP_EXP_HEIGHT_MASK 0x000007FF -/* ISP_EXP_V_SIZE : vertical size must be a multiple of 2). */ -#define RKISP1_CIF_ISP_EXP_V_SIZE_SET(x) ((x) & 0x7FE) - -/* ISP_EXP_H_OFFSET */ -#define RKISP1_CIF_ISP_EXP_H_OFFSET_SET(x) ((x) & 0x1FFF) -#define RKISP1_CIF_ISP_EXP_MAX_HOFFS 2424 -/* ISP_EXP_V_OFFSET */ -#define RKISP1_CIF_ISP_EXP_V_OFFSET_SET(x) ((x) & 0x1FFF) -#define RKISP1_CIF_ISP_EXP_MAX_VOFFS 1806 - -#define RKISP1_CIF_ISP_EXP_ROW_NUM 5 -#define RKISP1_CIF_ISP_EXP_COLUMN_NUM 5 -#define RKISP1_CIF_ISP_EXP_NUM_LUMA_REGS \ - (RKISP1_CIF_ISP_EXP_ROW_NUM * RKISP1_CIF_ISP_EXP_COLUMN_NUM) -#define RKISP1_CIF_ISP_EXP_BLOCK_MAX_HSIZE 516 -#define RKISP1_CIF_ISP_EXP_BLOCK_MIN_HSIZE 35 -#define RKISP1_CIF_ISP_EXP_BLOCK_MAX_VSIZE 390 -#define RKISP1_CIF_ISP_EXP_BLOCK_MIN_VSIZE 28 -#define RKISP1_CIF_ISP_EXP_MAX_HSIZE \ - (RKISP1_CIF_ISP_EXP_BLOCK_MAX_HSIZE * RKISP1_CIF_ISP_EXP_COLUMN_NUM + 1) -#define RKISP1_CIF_ISP_EXP_MIN_HSIZE \ - (RKISP1_CIF_ISP_EXP_BLOCK_MIN_HSIZE * RKISP1_CIF_ISP_EXP_COLUMN_NUM + 1) -#define RKISP1_CIF_ISP_EXP_MAX_VSIZE \ - (RKISP1_CIF_ISP_EXP_BLOCK_MAX_VSIZE * RKISP1_CIF_ISP_EXP_ROW_NUM + 1) -#define RKISP1_CIF_ISP_EXP_MIN_VSIZE \ - (RKISP1_CIF_ISP_EXP_BLOCK_MIN_VSIZE * RKISP1_CIF_ISP_EXP_ROW_NUM + 1) - -/* LSC: ISP_LSC_CTRL */ -#define RKISP1_CIF_ISP_LSC_CTRL_ENA BIT(0) -#define RKISP1_CIF_ISP_LSC_SECT_SIZE_RESERVED 0xFC00FC00 -#define RKISP1_CIF_ISP_LSC_GRAD_RESERVED 0xF000F000 -#define RKISP1_CIF_ISP_LSC_SAMPLE_RESERVED 0xF000F000 -#define RKISP1_CIF_ISP_LSC_TABLE_DATA(v0, v1) \ - (((v0) & 0xFFF) | (((v1) & 0xFFF) << 12)) -#define RKISP1_CIF_ISP_LSC_SECT_SIZE(v0, v1) \ - (((v0) & 0xFFF) | (((v1) & 0xFFF) << 16)) -#define RKISP1_CIF_ISP_LSC_GRAD_SIZE(v0, v1) \ - (((v0) & 0xFFF) | (((v1) & 0xFFF) << 16)) - -/* LSC: ISP_LSC_TABLE_SEL */ -#define RKISP1_CIF_ISP_LSC_TABLE_0 0 -#define RKISP1_CIF_ISP_LSC_TABLE_1 1 - -/* LSC: ISP_LSC_STATUS */ -#define RKISP1_CIF_ISP_LSC_ACTIVE_TABLE BIT(1) -#define RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_0 0 -#define RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153 153 - -/* FLT */ -/* ISP_FILT_MODE */ -#define RKISP1_CIF_ISP_FLT_ENA BIT(0) - -/* - * 0: green filter static mode (active filter factor = FILT_FAC_MID) - * 1: dynamic noise reduction/sharpen Default - */ -#define RKISP1_CIF_ISP_FLT_MODE_DNR BIT(1) -#define RKISP1_CIF_ISP_FLT_MODE_MAX 1 -#define RKISP1_CIF_ISP_FLT_CHROMA_V_MODE(x) (((x) & 0x3) << 4) -#define RKISP1_CIF_ISP_FLT_CHROMA_H_MODE(x) (((x) & 0x3) << 6) -#define RKISP1_CIF_ISP_FLT_CHROMA_MODE_MAX 3 -#define RKISP1_CIF_ISP_FLT_GREEN_STAGE1(x) (((x) & 0xF) << 8) -#define RKISP1_CIF_ISP_FLT_GREEN_STAGE1_MAX 8 -#define RKISP1_CIF_ISP_FLT_THREAD_RESERVED 0xFFFFFC00 -#define RKISP1_CIF_ISP_FLT_FAC_RESERVED 0xFFFFFFC0 -#define RKISP1_CIF_ISP_FLT_LUM_WEIGHT_RESERVED 0xFFF80000 - -#define RKISP1_CIF_ISP_CTK_COEFF_RESERVED 0xFFFFF800 -#define RKISP1_CIF_ISP_XTALK_OFFSET_RESERVED 0xFFFFF000 - -/* GOC */ -#define RKISP1_CIF_ISP_GAMMA_OUT_MODE_EQU BIT(0) -#define RKISP1_CIF_ISP_GOC_MODE_MAX 1 -#define RKISP1_CIF_ISP_GOC_RESERVED 0xFFFFF800 -/* ISP_CTRL BIT 11*/ -#define RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA_READ(x) (((x) >> 11) & 1) - -/* DPCC */ -/* ISP_DPCC_MODE */ -#define RKISP1_CIF_ISP_DPCC_ENA BIT(0) -#define RKISP1_CIF_ISP_DPCC_MODE_MAX 0x07 -#define RKISP1_CIF_ISP_DPCC_OUTPUTMODE_MAX 0x0F -#define RKISP1_CIF_ISP_DPCC_SETUSE_MAX 0x0F -#define RKISP1_CIF_ISP_DPCC_METHODS_SET_RESERVED 0xFFFFE000 -#define RKISP1_CIF_ISP_DPCC_LINE_THRESH_RESERVED 0xFFFF0000 -#define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_RESERVED 0xFFFFC0C0 -#define RKISP1_CIF_ISP_DPCC_PG_FAC_RESERVED 0xFFFFC0C0 -#define RKISP1_CIF_ISP_DPCC_RND_THRESH_RESERVED 0xFFFF0000 -#define RKISP1_CIF_ISP_DPCC_RG_FAC_RESERVED 0xFFFFC0C0 -#define RKISP1_CIF_ISP_DPCC_RO_LIMIT_RESERVED 0xFFFFF000 -#define RKISP1_CIF_ISP_DPCC_RND_OFFS_RESERVED 0xFFFFF000 - -/* BLS */ -/* ISP_BLS_CTRL */ -#define RKISP1_CIF_ISP_BLS_ENA BIT(0) -#define RKISP1_CIF_ISP_BLS_MODE_MEASURED BIT(1) -#define RKISP1_CIF_ISP_BLS_MODE_FIXED 0 -#define RKISP1_CIF_ISP_BLS_WINDOW_1 BIT(2) -#define RKISP1_CIF_ISP_BLS_WINDOW_2 (2 << 2) - -/* GAMMA-IN */ -#define RKISP1_CIFISP_DEGAMMA_X_RESERVED \ - ((1 << 31) | (1 << 27) | (1 << 23) | (1 << 19) |\ - (1 << 15) | (1 << 11) | (1 << 7) | (1 << 3)) -#define RKISP1_CIFISP_DEGAMMA_Y_RESERVED 0xFFFFF000 - -/* AFM */ -#define RKISP1_CIF_ISP_AFM_ENA BIT(0) -#define RKISP1_CIF_ISP_AFM_THRES_RESERVED 0xFFFF0000 -#define RKISP1_CIF_ISP_AFM_VAR_SHIFT_RESERVED 0xFFF8FFF8 -#define RKISP1_CIF_ISP_AFM_WINDOW_X_RESERVED 0xE000 -#define RKISP1_CIF_ISP_AFM_WINDOW_Y_RESERVED 0xF000 -#define RKISP1_CIF_ISP_AFM_WINDOW_X_MIN 0x5 -#define RKISP1_CIF_ISP_AFM_WINDOW_Y_MIN 0x2 -#define RKISP1_CIF_ISP_AFM_WINDOW_X(x) (((x) & 0x1FFF) << 16) -#define RKISP1_CIF_ISP_AFM_WINDOW_Y(x) ((x) & 0x1FFF) - -/* DPF */ -#define RKISP1_CIF_ISP_DPF_MODE_EN BIT(0) -#define RKISP1_CIF_ISP_DPF_MODE_B_FLT_DIS BIT(1) -#define RKISP1_CIF_ISP_DPF_MODE_GB_FLT_DIS BIT(2) -#define RKISP1_CIF_ISP_DPF_MODE_GR_FLT_DIS BIT(3) -#define RKISP1_CIF_ISP_DPF_MODE_R_FLT_DIS BIT(4) -#define RKISP1_CIF_ISP_DPF_MODE_RB_FLTSIZE_9x9 BIT(5) -#define RKISP1_CIF_ISP_DPF_MODE_NLL_SEGMENTATION BIT(6) -#define RKISP1_CIF_ISP_DPF_MODE_AWB_GAIN_COMP BIT(7) -#define RKISP1_CIF_ISP_DPF_MODE_LSC_GAIN_COMP BIT(8) -#define RKISP1_CIF_ISP_DPF_MODE_USE_NF_GAIN BIT(9) -#define RKISP1_CIF_ISP_DPF_NF_GAIN_RESERVED 0xFFFFF000 -#define RKISP1_CIF_ISP_DPF_SPATIAL_COEFF_MAX 0x1F -#define RKISP1_CIF_ISP_DPF_NLL_COEFF_N_MAX 0x3FF - -/* =================================================================== */ -/* CIF Registers */ -/* =================================================================== */ -#define RKISP1_CIF_CTRL_BASE 0x00000000 -#define RKISP1_CIF_CCL (RKISP1_CIF_CTRL_BASE + 0x00000000) -#define RKISP1_CIF_VI_ID (RKISP1_CIF_CTRL_BASE + 0x00000008) -#define RKISP1_CIF_ICCL (RKISP1_CIF_CTRL_BASE + 0x00000010) -#define RKISP1_CIF_IRCL (RKISP1_CIF_CTRL_BASE + 0x00000014) -#define RKISP1_CIF_VI_DPCL (RKISP1_CIF_CTRL_BASE + 0x00000018) - -#define RKISP1_CIF_IMG_EFF_BASE 0x00000200 -#define RKISP1_CIF_IMG_EFF_CTRL (RKISP1_CIF_IMG_EFF_BASE + 0x00000000) -#define RKISP1_CIF_IMG_EFF_COLOR_SEL (RKISP1_CIF_IMG_EFF_BASE + 0x00000004) -#define RKISP1_CIF_IMG_EFF_MAT_1 (RKISP1_CIF_IMG_EFF_BASE + 0x00000008) -#define RKISP1_CIF_IMG_EFF_MAT_2 (RKISP1_CIF_IMG_EFF_BASE + 0x0000000C) -#define RKISP1_CIF_IMG_EFF_MAT_3 (RKISP1_CIF_IMG_EFF_BASE + 0x00000010) -#define RKISP1_CIF_IMG_EFF_MAT_4 (RKISP1_CIF_IMG_EFF_BASE + 0x00000014) -#define RKISP1_CIF_IMG_EFF_MAT_5 (RKISP1_CIF_IMG_EFF_BASE + 0x00000018) -#define RKISP1_CIF_IMG_EFF_TINT (RKISP1_CIF_IMG_EFF_BASE + 0x0000001C) -#define RKISP1_CIF_IMG_EFF_CTRL_SHD (RKISP1_CIF_IMG_EFF_BASE + 0x00000020) -#define RKISP1_CIF_IMG_EFF_SHARPEN (RKISP1_CIF_IMG_EFF_BASE + 0x00000024) - -#define RKISP1_CIF_SUPER_IMP_BASE 0x00000300 -#define RKISP1_CIF_SUPER_IMP_CTRL (RKISP1_CIF_SUPER_IMP_BASE + 0x00000000) -#define RKISP1_CIF_SUPER_IMP_OFFSET_X (RKISP1_CIF_SUPER_IMP_BASE + 0x00000004) -#define RKISP1_CIF_SUPER_IMP_OFFSET_Y (RKISP1_CIF_SUPER_IMP_BASE + 0x00000008) -#define RKISP1_CIF_SUPER_IMP_COLOR_Y (RKISP1_CIF_SUPER_IMP_BASE + 0x0000000C) -#define RKISP1_CIF_SUPER_IMP_COLOR_CB (RKISP1_CIF_SUPER_IMP_BASE + 0x00000010) -#define RKISP1_CIF_SUPER_IMP_COLOR_CR (RKISP1_CIF_SUPER_IMP_BASE + 0x00000014) - -#define RKISP1_CIF_ISP_BASE 0x00000400 -#define RKISP1_CIF_ISP_CTRL (RKISP1_CIF_ISP_BASE + 0x00000000) -#define RKISP1_CIF_ISP_ACQ_PROP (RKISP1_CIF_ISP_BASE + 0x00000004) -#define RKISP1_CIF_ISP_ACQ_H_OFFS (RKISP1_CIF_ISP_BASE + 0x00000008) -#define RKISP1_CIF_ISP_ACQ_V_OFFS (RKISP1_CIF_ISP_BASE + 0x0000000C) -#define RKISP1_CIF_ISP_ACQ_H_SIZE (RKISP1_CIF_ISP_BASE + 0x00000010) -#define RKISP1_CIF_ISP_ACQ_V_SIZE (RKISP1_CIF_ISP_BASE + 0x00000014) -#define RKISP1_CIF_ISP_ACQ_NR_FRAMES (RKISP1_CIF_ISP_BASE + 0x00000018) -#define RKISP1_CIF_ISP_GAMMA_DX_LO (RKISP1_CIF_ISP_BASE + 0x0000001C) -#define RKISP1_CIF_ISP_GAMMA_DX_HI (RKISP1_CIF_ISP_BASE + 0x00000020) -#define RKISP1_CIF_ISP_GAMMA_R_Y0 (RKISP1_CIF_ISP_BASE + 0x00000024) -#define RKISP1_CIF_ISP_GAMMA_R_Y1 (RKISP1_CIF_ISP_BASE + 0x00000028) -#define RKISP1_CIF_ISP_GAMMA_R_Y2 (RKISP1_CIF_ISP_BASE + 0x0000002C) -#define RKISP1_CIF_ISP_GAMMA_R_Y3 (RKISP1_CIF_ISP_BASE + 0x00000030) -#define RKISP1_CIF_ISP_GAMMA_R_Y4 (RKISP1_CIF_ISP_BASE + 0x00000034) -#define RKISP1_CIF_ISP_GAMMA_R_Y5 (RKISP1_CIF_ISP_BASE + 0x00000038) -#define RKISP1_CIF_ISP_GAMMA_R_Y6 (RKISP1_CIF_ISP_BASE + 0x0000003C) -#define RKISP1_CIF_ISP_GAMMA_R_Y7 (RKISP1_CIF_ISP_BASE + 0x00000040) -#define RKISP1_CIF_ISP_GAMMA_R_Y8 (RKISP1_CIF_ISP_BASE + 0x00000044) -#define RKISP1_CIF_ISP_GAMMA_R_Y9 (RKISP1_CIF_ISP_BASE + 0x00000048) -#define RKISP1_CIF_ISP_GAMMA_R_Y10 (RKISP1_CIF_ISP_BASE + 0x0000004C) -#define RKISP1_CIF_ISP_GAMMA_R_Y11 (RKISP1_CIF_ISP_BASE + 0x00000050) -#define RKISP1_CIF_ISP_GAMMA_R_Y12 (RKISP1_CIF_ISP_BASE + 0x00000054) -#define RKISP1_CIF_ISP_GAMMA_R_Y13 (RKISP1_CIF_ISP_BASE + 0x00000058) -#define RKISP1_CIF_ISP_GAMMA_R_Y14 (RKISP1_CIF_ISP_BASE + 0x0000005C) -#define RKISP1_CIF_ISP_GAMMA_R_Y15 (RKISP1_CIF_ISP_BASE + 0x00000060) -#define RKISP1_CIF_ISP_GAMMA_R_Y16 (RKISP1_CIF_ISP_BASE + 0x00000064) -#define RKISP1_CIF_ISP_GAMMA_G_Y0 (RKISP1_CIF_ISP_BASE + 0x00000068) -#define RKISP1_CIF_ISP_GAMMA_G_Y1 (RKISP1_CIF_ISP_BASE + 0x0000006C) -#define RKISP1_CIF_ISP_GAMMA_G_Y2 (RKISP1_CIF_ISP_BASE + 0x00000070) -#define RKISP1_CIF_ISP_GAMMA_G_Y3 (RKISP1_CIF_ISP_BASE + 0x00000074) -#define RKISP1_CIF_ISP_GAMMA_G_Y4 (RKISP1_CIF_ISP_BASE + 0x00000078) -#define RKISP1_CIF_ISP_GAMMA_G_Y5 (RKISP1_CIF_ISP_BASE + 0x0000007C) -#define RKISP1_CIF_ISP_GAMMA_G_Y6 (RKISP1_CIF_ISP_BASE + 0x00000080) -#define RKISP1_CIF_ISP_GAMMA_G_Y7 (RKISP1_CIF_ISP_BASE + 0x00000084) -#define RKISP1_CIF_ISP_GAMMA_G_Y8 (RKISP1_CIF_ISP_BASE + 0x00000088) -#define RKISP1_CIF_ISP_GAMMA_G_Y9 (RKISP1_CIF_ISP_BASE + 0x0000008C) -#define RKISP1_CIF_ISP_GAMMA_G_Y10 (RKISP1_CIF_ISP_BASE + 0x00000090) -#define RKISP1_CIF_ISP_GAMMA_G_Y11 (RKISP1_CIF_ISP_BASE + 0x00000094) -#define RKISP1_CIF_ISP_GAMMA_G_Y12 (RKISP1_CIF_ISP_BASE + 0x00000098) -#define RKISP1_CIF_ISP_GAMMA_G_Y13 (RKISP1_CIF_ISP_BASE + 0x0000009C) -#define RKISP1_CIF_ISP_GAMMA_G_Y14 (RKISP1_CIF_ISP_BASE + 0x000000A0) -#define RKISP1_CIF_ISP_GAMMA_G_Y15 (RKISP1_CIF_ISP_BASE + 0x000000A4) -#define RKISP1_CIF_ISP_GAMMA_G_Y16 (RKISP1_CIF_ISP_BASE + 0x000000A8) -#define RKISP1_CIF_ISP_GAMMA_B_Y0 (RKISP1_CIF_ISP_BASE + 0x000000AC) -#define RKISP1_CIF_ISP_GAMMA_B_Y1 (RKISP1_CIF_ISP_BASE + 0x000000B0) -#define RKISP1_CIF_ISP_GAMMA_B_Y2 (RKISP1_CIF_ISP_BASE + 0x000000B4) -#define RKISP1_CIF_ISP_GAMMA_B_Y3 (RKISP1_CIF_ISP_BASE + 0x000000B8) -#define RKISP1_CIF_ISP_GAMMA_B_Y4 (RKISP1_CIF_ISP_BASE + 0x000000BC) -#define RKISP1_CIF_ISP_GAMMA_B_Y5 (RKISP1_CIF_ISP_BASE + 0x000000C0) -#define RKISP1_CIF_ISP_GAMMA_B_Y6 (RKISP1_CIF_ISP_BASE + 0x000000C4) -#define RKISP1_CIF_ISP_GAMMA_B_Y7 (RKISP1_CIF_ISP_BASE + 0x000000C8) -#define RKISP1_CIF_ISP_GAMMA_B_Y8 (RKISP1_CIF_ISP_BASE + 0x000000CC) -#define RKISP1_CIF_ISP_GAMMA_B_Y9 (RKISP1_CIF_ISP_BASE + 0x000000D0) -#define RKISP1_CIF_ISP_GAMMA_B_Y10 (RKISP1_CIF_ISP_BASE + 0x000000D4) -#define RKISP1_CIF_ISP_GAMMA_B_Y11 (RKISP1_CIF_ISP_BASE + 0x000000D8) -#define RKISP1_CIF_ISP_GAMMA_B_Y12 (RKISP1_CIF_ISP_BASE + 0x000000DC) -#define RKISP1_CIF_ISP_GAMMA_B_Y13 (RKISP1_CIF_ISP_BASE + 0x000000E0) -#define RKISP1_CIF_ISP_GAMMA_B_Y14 (RKISP1_CIF_ISP_BASE + 0x000000E4) -#define RKISP1_CIF_ISP_GAMMA_B_Y15 (RKISP1_CIF_ISP_BASE + 0x000000E8) -#define RKISP1_CIF_ISP_GAMMA_B_Y16 (RKISP1_CIF_ISP_BASE + 0x000000EC) -#define RKISP1_CIF_ISP_AWB_PROP (RKISP1_CIF_ISP_BASE + 0x00000110) -#define RKISP1_CIF_ISP_AWB_WND_H_OFFS (RKISP1_CIF_ISP_BASE + 0x00000114) -#define RKISP1_CIF_ISP_AWB_WND_V_OFFS (RKISP1_CIF_ISP_BASE + 0x00000118) -#define RKISP1_CIF_ISP_AWB_WND_H_SIZE (RKISP1_CIF_ISP_BASE + 0x0000011C) -#define RKISP1_CIF_ISP_AWB_WND_V_SIZE (RKISP1_CIF_ISP_BASE + 0x00000120) -#define RKISP1_CIF_ISP_AWB_FRAMES (RKISP1_CIF_ISP_BASE + 0x00000124) -#define RKISP1_CIF_ISP_AWB_REF (RKISP1_CIF_ISP_BASE + 0x00000128) -#define RKISP1_CIF_ISP_AWB_THRESH (RKISP1_CIF_ISP_BASE + 0x0000012C) -#define RKISP1_CIF_ISP_AWB_GAIN_G (RKISP1_CIF_ISP_BASE + 0x00000138) -#define RKISP1_CIF_ISP_AWB_GAIN_RB (RKISP1_CIF_ISP_BASE + 0x0000013C) -#define RKISP1_CIF_ISP_AWB_WHITE_CNT (RKISP1_CIF_ISP_BASE + 0x00000140) -#define RKISP1_CIF_ISP_AWB_MEAN (RKISP1_CIF_ISP_BASE + 0x00000144) -#define RKISP1_CIF_ISP_CC_COEFF_0 (RKISP1_CIF_ISP_BASE + 0x00000170) -#define RKISP1_CIF_ISP_CC_COEFF_1 (RKISP1_CIF_ISP_BASE + 0x00000174) -#define RKISP1_CIF_ISP_CC_COEFF_2 (RKISP1_CIF_ISP_BASE + 0x00000178) -#define RKISP1_CIF_ISP_CC_COEFF_3 (RKISP1_CIF_ISP_BASE + 0x0000017C) -#define RKISP1_CIF_ISP_CC_COEFF_4 (RKISP1_CIF_ISP_BASE + 0x00000180) -#define RKISP1_CIF_ISP_CC_COEFF_5 (RKISP1_CIF_ISP_BASE + 0x00000184) -#define RKISP1_CIF_ISP_CC_COEFF_6 (RKISP1_CIF_ISP_BASE + 0x00000188) -#define RKISP1_CIF_ISP_CC_COEFF_7 (RKISP1_CIF_ISP_BASE + 0x0000018C) -#define RKISP1_CIF_ISP_CC_COEFF_8 (RKISP1_CIF_ISP_BASE + 0x00000190) -#define RKISP1_CIF_ISP_OUT_H_OFFS (RKISP1_CIF_ISP_BASE + 0x00000194) -#define RKISP1_CIF_ISP_OUT_V_OFFS (RKISP1_CIF_ISP_BASE + 0x00000198) -#define RKISP1_CIF_ISP_OUT_H_SIZE (RKISP1_CIF_ISP_BASE + 0x0000019C) -#define RKISP1_CIF_ISP_OUT_V_SIZE (RKISP1_CIF_ISP_BASE + 0x000001A0) -#define RKISP1_CIF_ISP_DEMOSAIC (RKISP1_CIF_ISP_BASE + 0x000001A4) -#define RKISP1_CIF_ISP_FLAGS_SHD (RKISP1_CIF_ISP_BASE + 0x000001A8) -#define RKISP1_CIF_ISP_OUT_H_OFFS_SHD (RKISP1_CIF_ISP_BASE + 0x000001AC) -#define RKISP1_CIF_ISP_OUT_V_OFFS_SHD (RKISP1_CIF_ISP_BASE + 0x000001B0) -#define RKISP1_CIF_ISP_OUT_H_SIZE_SHD (RKISP1_CIF_ISP_BASE + 0x000001B4) -#define RKISP1_CIF_ISP_OUT_V_SIZE_SHD (RKISP1_CIF_ISP_BASE + 0x000001B8) -#define RKISP1_CIF_ISP_IMSC (RKISP1_CIF_ISP_BASE + 0x000001BC) -#define RKISP1_CIF_ISP_RIS (RKISP1_CIF_ISP_BASE + 0x000001C0) -#define RKISP1_CIF_ISP_MIS (RKISP1_CIF_ISP_BASE + 0x000001C4) -#define RKISP1_CIF_ISP_ICR (RKISP1_CIF_ISP_BASE + 0x000001C8) -#define RKISP1_CIF_ISP_ISR (RKISP1_CIF_ISP_BASE + 0x000001CC) -#define RKISP1_CIF_ISP_CT_COEFF_0 (RKISP1_CIF_ISP_BASE + 0x000001D0) -#define RKISP1_CIF_ISP_CT_COEFF_1 (RKISP1_CIF_ISP_BASE + 0x000001D4) -#define RKISP1_CIF_ISP_CT_COEFF_2 (RKISP1_CIF_ISP_BASE + 0x000001D8) -#define RKISP1_CIF_ISP_CT_COEFF_3 (RKISP1_CIF_ISP_BASE + 0x000001DC) -#define RKISP1_CIF_ISP_CT_COEFF_4 (RKISP1_CIF_ISP_BASE + 0x000001E0) -#define RKISP1_CIF_ISP_CT_COEFF_5 (RKISP1_CIF_ISP_BASE + 0x000001E4) -#define RKISP1_CIF_ISP_CT_COEFF_6 (RKISP1_CIF_ISP_BASE + 0x000001E8) -#define RKISP1_CIF_ISP_CT_COEFF_7 (RKISP1_CIF_ISP_BASE + 0x000001EC) -#define RKISP1_CIF_ISP_CT_COEFF_8 (RKISP1_CIF_ISP_BASE + 0x000001F0) -#define RKISP1_CIF_ISP_GAMMA_OUT_MODE (RKISP1_CIF_ISP_BASE + 0x000001F4) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_0 (RKISP1_CIF_ISP_BASE + 0x000001F8) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_1 (RKISP1_CIF_ISP_BASE + 0x000001FC) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_2 (RKISP1_CIF_ISP_BASE + 0x00000200) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_3 (RKISP1_CIF_ISP_BASE + 0x00000204) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_4 (RKISP1_CIF_ISP_BASE + 0x00000208) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_5 (RKISP1_CIF_ISP_BASE + 0x0000020C) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_6 (RKISP1_CIF_ISP_BASE + 0x00000210) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_7 (RKISP1_CIF_ISP_BASE + 0x00000214) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_8 (RKISP1_CIF_ISP_BASE + 0x00000218) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_9 (RKISP1_CIF_ISP_BASE + 0x0000021C) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_10 (RKISP1_CIF_ISP_BASE + 0x00000220) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_11 (RKISP1_CIF_ISP_BASE + 0x00000224) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_12 (RKISP1_CIF_ISP_BASE + 0x00000228) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_13 (RKISP1_CIF_ISP_BASE + 0x0000022C) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_14 (RKISP1_CIF_ISP_BASE + 0x00000230) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_15 (RKISP1_CIF_ISP_BASE + 0x00000234) -#define RKISP1_CIF_ISP_GAMMA_OUT_Y_16 (RKISP1_CIF_ISP_BASE + 0x00000238) -#define RKISP1_CIF_ISP_ERR (RKISP1_CIF_ISP_BASE + 0x0000023C) -#define RKISP1_CIF_ISP_ERR_CLR (RKISP1_CIF_ISP_BASE + 0x00000240) -#define RKISP1_CIF_ISP_FRAME_COUNT (RKISP1_CIF_ISP_BASE + 0x00000244) -#define RKISP1_CIF_ISP_CT_OFFSET_R (RKISP1_CIF_ISP_BASE + 0x00000248) -#define RKISP1_CIF_ISP_CT_OFFSET_G (RKISP1_CIF_ISP_BASE + 0x0000024C) -#define RKISP1_CIF_ISP_CT_OFFSET_B (RKISP1_CIF_ISP_BASE + 0x00000250) - -#define RKISP1_CIF_ISP_FLASH_BASE 0x00000660 -#define RKISP1_CIF_ISP_FLASH_CMD (RKISP1_CIF_ISP_FLASH_BASE + 0x00000000) -#define RKISP1_CIF_ISP_FLASH_CONFIG (RKISP1_CIF_ISP_FLASH_BASE + 0x00000004) -#define RKISP1_CIF_ISP_FLASH_PREDIV (RKISP1_CIF_ISP_FLASH_BASE + 0x00000008) -#define RKISP1_CIF_ISP_FLASH_DELAY (RKISP1_CIF_ISP_FLASH_BASE + 0x0000000C) -#define RKISP1_CIF_ISP_FLASH_TIME (RKISP1_CIF_ISP_FLASH_BASE + 0x00000010) -#define RKISP1_CIF_ISP_FLASH_MAXP (RKISP1_CIF_ISP_FLASH_BASE + 0x00000014) - -#define RKISP1_CIF_ISP_SH_BASE 0x00000680 -#define RKISP1_CIF_ISP_SH_CTRL (RKISP1_CIF_ISP_SH_BASE + 0x00000000) -#define RKISP1_CIF_ISP_SH_PREDIV (RKISP1_CIF_ISP_SH_BASE + 0x00000004) -#define RKISP1_CIF_ISP_SH_DELAY (RKISP1_CIF_ISP_SH_BASE + 0x00000008) -#define RKISP1_CIF_ISP_SH_TIME (RKISP1_CIF_ISP_SH_BASE + 0x0000000C) - -#define RKISP1_CIF_C_PROC_BASE 0x00000800 -#define RKISP1_CIF_C_PROC_CTRL (RKISP1_CIF_C_PROC_BASE + 0x00000000) -#define RKISP1_CIF_C_PROC_CONTRAST (RKISP1_CIF_C_PROC_BASE + 0x00000004) -#define RKISP1_CIF_C_PROC_BRIGHTNESS (RKISP1_CIF_C_PROC_BASE + 0x00000008) -#define RKISP1_CIF_C_PROC_SATURATION (RKISP1_CIF_C_PROC_BASE + 0x0000000C) -#define RKISP1_CIF_C_PROC_HUE (RKISP1_CIF_C_PROC_BASE + 0x00000010) - -#define RKISP1_CIF_DUAL_CROP_BASE 0x00000880 -#define RKISP1_CIF_DUAL_CROP_CTRL (RKISP1_CIF_DUAL_CROP_BASE + 0x00000000) -#define RKISP1_CIF_DUAL_CROP_M_H_OFFS (RKISP1_CIF_DUAL_CROP_BASE + 0x00000004) -#define RKISP1_CIF_DUAL_CROP_M_V_OFFS (RKISP1_CIF_DUAL_CROP_BASE + 0x00000008) -#define RKISP1_CIF_DUAL_CROP_M_H_SIZE (RKISP1_CIF_DUAL_CROP_BASE + 0x0000000C) -#define RKISP1_CIF_DUAL_CROP_M_V_SIZE (RKISP1_CIF_DUAL_CROP_BASE + 0x00000010) -#define RKISP1_CIF_DUAL_CROP_S_H_OFFS (RKISP1_CIF_DUAL_CROP_BASE + 0x00000014) -#define RKISP1_CIF_DUAL_CROP_S_V_OFFS (RKISP1_CIF_DUAL_CROP_BASE + 0x00000018) -#define RKISP1_CIF_DUAL_CROP_S_H_SIZE (RKISP1_CIF_DUAL_CROP_BASE + 0x0000001C) -#define RKISP1_CIF_DUAL_CROP_S_V_SIZE (RKISP1_CIF_DUAL_CROP_BASE + 0x00000020) -#define RKISP1_CIF_DUAL_CROP_M_H_OFFS_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000024) -#define RKISP1_CIF_DUAL_CROP_M_V_OFFS_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000028) -#define RKISP1_CIF_DUAL_CROP_M_H_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x0000002C) -#define RKISP1_CIF_DUAL_CROP_M_V_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000030) -#define RKISP1_CIF_DUAL_CROP_S_H_OFFS_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000034) -#define RKISP1_CIF_DUAL_CROP_S_V_OFFS_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000038) -#define RKISP1_CIF_DUAL_CROP_S_H_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x0000003C) -#define RKISP1_CIF_DUAL_CROP_S_V_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000040) - -#define RKISP1_CIF_MRSZ_BASE 0x00000C00 -#define RKISP1_CIF_MRSZ_CTRL (RKISP1_CIF_MRSZ_BASE + 0x00000000) -#define RKISP1_CIF_MRSZ_SCALE_HY (RKISP1_CIF_MRSZ_BASE + 0x00000004) -#define RKISP1_CIF_MRSZ_SCALE_HCB (RKISP1_CIF_MRSZ_BASE + 0x00000008) -#define RKISP1_CIF_MRSZ_SCALE_HCR (RKISP1_CIF_MRSZ_BASE + 0x0000000C) -#define RKISP1_CIF_MRSZ_SCALE_VY (RKISP1_CIF_MRSZ_BASE + 0x00000010) -#define RKISP1_CIF_MRSZ_SCALE_VC (RKISP1_CIF_MRSZ_BASE + 0x00000014) -#define RKISP1_CIF_MRSZ_PHASE_HY (RKISP1_CIF_MRSZ_BASE + 0x00000018) -#define RKISP1_CIF_MRSZ_PHASE_HC (RKISP1_CIF_MRSZ_BASE + 0x0000001C) -#define RKISP1_CIF_MRSZ_PHASE_VY (RKISP1_CIF_MRSZ_BASE + 0x00000020) -#define RKISP1_CIF_MRSZ_PHASE_VC (RKISP1_CIF_MRSZ_BASE + 0x00000024) -#define RKISP1_CIF_MRSZ_SCALE_LUT_ADDR (RKISP1_CIF_MRSZ_BASE + 0x00000028) -#define RKISP1_CIF_MRSZ_SCALE_LUT (RKISP1_CIF_MRSZ_BASE + 0x0000002C) -#define RKISP1_CIF_MRSZ_CTRL_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000030) -#define RKISP1_CIF_MRSZ_SCALE_HY_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000034) -#define RKISP1_CIF_MRSZ_SCALE_HCB_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000038) -#define RKISP1_CIF_MRSZ_SCALE_HCR_SHD (RKISP1_CIF_MRSZ_BASE + 0x0000003C) -#define RKISP1_CIF_MRSZ_SCALE_VY_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000040) -#define RKISP1_CIF_MRSZ_SCALE_VC_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000044) -#define RKISP1_CIF_MRSZ_PHASE_HY_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000048) -#define RKISP1_CIF_MRSZ_PHASE_HC_SHD (RKISP1_CIF_MRSZ_BASE + 0x0000004C) -#define RKISP1_CIF_MRSZ_PHASE_VY_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000050) -#define RKISP1_CIF_MRSZ_PHASE_VC_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000054) - -#define RKISP1_CIF_SRSZ_BASE 0x00001000 -#define RKISP1_CIF_SRSZ_CTRL (RKISP1_CIF_SRSZ_BASE + 0x00000000) -#define RKISP1_CIF_SRSZ_SCALE_HY (RKISP1_CIF_SRSZ_BASE + 0x00000004) -#define RKISP1_CIF_SRSZ_SCALE_HCB (RKISP1_CIF_SRSZ_BASE + 0x00000008) -#define RKISP1_CIF_SRSZ_SCALE_HCR (RKISP1_CIF_SRSZ_BASE + 0x0000000C) -#define RKISP1_CIF_SRSZ_SCALE_VY (RKISP1_CIF_SRSZ_BASE + 0x00000010) -#define RKISP1_CIF_SRSZ_SCALE_VC (RKISP1_CIF_SRSZ_BASE + 0x00000014) -#define RKISP1_CIF_SRSZ_PHASE_HY (RKISP1_CIF_SRSZ_BASE + 0x00000018) -#define RKISP1_CIF_SRSZ_PHASE_HC (RKISP1_CIF_SRSZ_BASE + 0x0000001C) -#define RKISP1_CIF_SRSZ_PHASE_VY (RKISP1_CIF_SRSZ_BASE + 0x00000020) -#define RKISP1_CIF_SRSZ_PHASE_VC (RKISP1_CIF_SRSZ_BASE + 0x00000024) -#define RKISP1_CIF_SRSZ_SCALE_LUT_ADDR (RKISP1_CIF_SRSZ_BASE + 0x00000028) -#define RKISP1_CIF_SRSZ_SCALE_LUT (RKISP1_CIF_SRSZ_BASE + 0x0000002C) -#define RKISP1_CIF_SRSZ_CTRL_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000030) -#define RKISP1_CIF_SRSZ_SCALE_HY_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000034) -#define RKISP1_CIF_SRSZ_SCALE_HCB_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000038) -#define RKISP1_CIF_SRSZ_SCALE_HCR_SHD (RKISP1_CIF_SRSZ_BASE + 0x0000003C) -#define RKISP1_CIF_SRSZ_SCALE_VY_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000040) -#define RKISP1_CIF_SRSZ_SCALE_VC_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000044) -#define RKISP1_CIF_SRSZ_PHASE_HY_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000048) -#define RKISP1_CIF_SRSZ_PHASE_HC_SHD (RKISP1_CIF_SRSZ_BASE + 0x0000004C) -#define RKISP1_CIF_SRSZ_PHASE_VY_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000050) -#define RKISP1_CIF_SRSZ_PHASE_VC_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000054) - -#define RKISP1_CIF_MI_BASE 0x00001400 -#define RKISP1_CIF_MI_CTRL (RKISP1_CIF_MI_BASE + 0x00000000) -#define RKISP1_CIF_MI_INIT (RKISP1_CIF_MI_BASE + 0x00000004) -#define RKISP1_CIF_MI_MP_Y_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x00000008) -#define RKISP1_CIF_MI_MP_Y_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x0000000C) -#define RKISP1_CIF_MI_MP_Y_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000010) -#define RKISP1_CIF_MI_MP_Y_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x00000014) -#define RKISP1_CIF_MI_MP_Y_IRQ_OFFS_INIT (RKISP1_CIF_MI_BASE + 0x00000018) -#define RKISP1_CIF_MI_MP_CB_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x0000001C) -#define RKISP1_CIF_MI_MP_CB_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x00000020) -#define RKISP1_CIF_MI_MP_CB_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000024) -#define RKISP1_CIF_MI_MP_CB_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x00000028) -#define RKISP1_CIF_MI_MP_CR_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x0000002C) -#define RKISP1_CIF_MI_MP_CR_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x00000030) -#define RKISP1_CIF_MI_MP_CR_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000034) -#define RKISP1_CIF_MI_MP_CR_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x00000038) -#define RKISP1_CIF_MI_SP_Y_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x0000003C) -#define RKISP1_CIF_MI_SP_Y_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x00000040) -#define RKISP1_CIF_MI_SP_Y_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000044) -#define RKISP1_CIF_MI_SP_Y_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x00000048) -#define RKISP1_CIF_MI_SP_Y_LLENGTH (RKISP1_CIF_MI_BASE + 0x0000004C) -#define RKISP1_CIF_MI_SP_CB_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x00000050) -#define RKISP1_CIF_MI_SP_CB_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x00000054) -#define RKISP1_CIF_MI_SP_CB_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000058) -#define RKISP1_CIF_MI_SP_CB_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x0000005C) -#define RKISP1_CIF_MI_SP_CR_BASE_AD_INIT (RKISP1_CIF_MI_BASE + 0x00000060) -#define RKISP1_CIF_MI_SP_CR_SIZE_INIT (RKISP1_CIF_MI_BASE + 0x00000064) -#define RKISP1_CIF_MI_SP_CR_OFFS_CNT_INIT (RKISP1_CIF_MI_BASE + 0x00000068) -#define RKISP1_CIF_MI_SP_CR_OFFS_CNT_START (RKISP1_CIF_MI_BASE + 0x0000006C) -#define RKISP1_CIF_MI_BYTE_CNT (RKISP1_CIF_MI_BASE + 0x00000070) -#define RKISP1_CIF_MI_CTRL_SHD (RKISP1_CIF_MI_BASE + 0x00000074) -#define RKISP1_CIF_MI_MP_Y_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x00000078) -#define RKISP1_CIF_MI_MP_Y_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x0000007C) -#define RKISP1_CIF_MI_MP_Y_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x00000080) -#define RKISP1_CIF_MI_MP_Y_IRQ_OFFS_SHD (RKISP1_CIF_MI_BASE + 0x00000084) -#define RKISP1_CIF_MI_MP_CB_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x00000088) -#define RKISP1_CIF_MI_MP_CB_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x0000008C) -#define RKISP1_CIF_MI_MP_CB_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x00000090) -#define RKISP1_CIF_MI_MP_CR_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x00000094) -#define RKISP1_CIF_MI_MP_CR_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x00000098) -#define RKISP1_CIF_MI_MP_CR_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x0000009C) -#define RKISP1_CIF_MI_SP_Y_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x000000A0) -#define RKISP1_CIF_MI_SP_Y_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x000000A4) -#define RKISP1_CIF_MI_SP_Y_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x000000A8) -#define RKISP1_CIF_MI_SP_CB_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x000000B0) -#define RKISP1_CIF_MI_SP_CB_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x000000B4) -#define RKISP1_CIF_MI_SP_CB_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x000000B8) -#define RKISP1_CIF_MI_SP_CR_BASE_AD_SHD (RKISP1_CIF_MI_BASE + 0x000000BC) -#define RKISP1_CIF_MI_SP_CR_SIZE_SHD (RKISP1_CIF_MI_BASE + 0x000000C0) -#define RKISP1_CIF_MI_SP_CR_OFFS_CNT_SHD (RKISP1_CIF_MI_BASE + 0x000000C4) -#define RKISP1_CIF_MI_DMA_Y_PIC_START_AD (RKISP1_CIF_MI_BASE + 0x000000C8) -#define RKISP1_CIF_MI_DMA_Y_PIC_WIDTH (RKISP1_CIF_MI_BASE + 0x000000CC) -#define RKISP1_CIF_MI_DMA_Y_LLENGTH (RKISP1_CIF_MI_BASE + 0x000000D0) -#define RKISP1_CIF_MI_DMA_Y_PIC_SIZE (RKISP1_CIF_MI_BASE + 0x000000D4) -#define RKISP1_CIF_MI_DMA_CB_PIC_START_AD (RKISP1_CIF_MI_BASE + 0x000000D8) -#define RKISP1_CIF_MI_DMA_CR_PIC_START_AD (RKISP1_CIF_MI_BASE + 0x000000E8) -#define RKISP1_CIF_MI_IMSC (RKISP1_CIF_MI_BASE + 0x000000F8) -#define RKISP1_CIF_MI_RIS (RKISP1_CIF_MI_BASE + 0x000000FC) -#define RKISP1_CIF_MI_MIS (RKISP1_CIF_MI_BASE + 0x00000100) -#define RKISP1_CIF_MI_ICR (RKISP1_CIF_MI_BASE + 0x00000104) -#define RKISP1_CIF_MI_ISR (RKISP1_CIF_MI_BASE + 0x00000108) -#define RKISP1_CIF_MI_STATUS (RKISP1_CIF_MI_BASE + 0x0000010C) -#define RKISP1_CIF_MI_STATUS_CLR (RKISP1_CIF_MI_BASE + 0x00000110) -#define RKISP1_CIF_MI_SP_Y_PIC_WIDTH (RKISP1_CIF_MI_BASE + 0x00000114) -#define RKISP1_CIF_MI_SP_Y_PIC_HEIGHT (RKISP1_CIF_MI_BASE + 0x00000118) -#define RKISP1_CIF_MI_SP_Y_PIC_SIZE (RKISP1_CIF_MI_BASE + 0x0000011C) -#define RKISP1_CIF_MI_DMA_CTRL (RKISP1_CIF_MI_BASE + 0x00000120) -#define RKISP1_CIF_MI_DMA_START (RKISP1_CIF_MI_BASE + 0x00000124) -#define RKISP1_CIF_MI_DMA_STATUS (RKISP1_CIF_MI_BASE + 0x00000128) -#define RKISP1_CIF_MI_PIXEL_COUNT (RKISP1_CIF_MI_BASE + 0x0000012C) -#define RKISP1_CIF_MI_MP_Y_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000130) -#define RKISP1_CIF_MI_MP_CB_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000134) -#define RKISP1_CIF_MI_MP_CR_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000138) -#define RKISP1_CIF_MI_SP_Y_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x0000013C) -#define RKISP1_CIF_MI_SP_CB_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000140) -#define RKISP1_CIF_MI_SP_CR_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000144) -#define RKISP1_CIF_MI_XTD_FORMAT_CTRL (RKISP1_CIF_MI_BASE + 0x00000148) - -#define RKISP1_CIF_SMIA_BASE 0x00001A00 -#define RKISP1_CIF_SMIA_CTRL (RKISP1_CIF_SMIA_BASE + 0x00000000) -#define RKISP1_CIF_SMIA_STATUS (RKISP1_CIF_SMIA_BASE + 0x00000004) -#define RKISP1_CIF_SMIA_IMSC (RKISP1_CIF_SMIA_BASE + 0x00000008) -#define RKISP1_CIF_SMIA_RIS (RKISP1_CIF_SMIA_BASE + 0x0000000C) -#define RKISP1_CIF_SMIA_MIS (RKISP1_CIF_SMIA_BASE + 0x00000010) -#define RKISP1_CIF_SMIA_ICR (RKISP1_CIF_SMIA_BASE + 0x00000014) -#define RKISP1_CIF_SMIA_ISR (RKISP1_CIF_SMIA_BASE + 0x00000018) -#define RKISP1_CIF_SMIA_DATA_FORMAT_SEL (RKISP1_CIF_SMIA_BASE + 0x0000001C) -#define RKISP1_CIF_SMIA_SOF_EMB_DATA_LINES (RKISP1_CIF_SMIA_BASE + 0x00000020) -#define RKISP1_CIF_SMIA_EMB_HSTART (RKISP1_CIF_SMIA_BASE + 0x00000024) -#define RKISP1_CIF_SMIA_EMB_HSIZE (RKISP1_CIF_SMIA_BASE + 0x00000028) -#define RKISP1_CIF_SMIA_EMB_VSTART (RKISP1_CIF_SMIA_BASE + 0x0000002c) -#define RKISP1_CIF_SMIA_NUM_LINES (RKISP1_CIF_SMIA_BASE + 0x00000030) -#define RKISP1_CIF_SMIA_EMB_DATA_FIFO (RKISP1_CIF_SMIA_BASE + 0x00000034) -#define RKISP1_CIF_SMIA_EMB_DATA_WATERMARK (RKISP1_CIF_SMIA_BASE + 0x00000038) - -#define RKISP1_CIF_MIPI_BASE 0x00001C00 -#define RKISP1_CIF_MIPI_CTRL (RKISP1_CIF_MIPI_BASE + 0x00000000) -#define RKISP1_CIF_MIPI_STATUS (RKISP1_CIF_MIPI_BASE + 0x00000004) -#define RKISP1_CIF_MIPI_IMSC (RKISP1_CIF_MIPI_BASE + 0x00000008) -#define RKISP1_CIF_MIPI_RIS (RKISP1_CIF_MIPI_BASE + 0x0000000C) -#define RKISP1_CIF_MIPI_MIS (RKISP1_CIF_MIPI_BASE + 0x00000010) -#define RKISP1_CIF_MIPI_ICR (RKISP1_CIF_MIPI_BASE + 0x00000014) -#define RKISP1_CIF_MIPI_ISR (RKISP1_CIF_MIPI_BASE + 0x00000018) -#define RKISP1_CIF_MIPI_CUR_DATA_ID (RKISP1_CIF_MIPI_BASE + 0x0000001C) -#define RKISP1_CIF_MIPI_IMG_DATA_SEL (RKISP1_CIF_MIPI_BASE + 0x00000020) -#define RKISP1_CIF_MIPI_ADD_DATA_SEL_1 (RKISP1_CIF_MIPI_BASE + 0x00000024) -#define RKISP1_CIF_MIPI_ADD_DATA_SEL_2 (RKISP1_CIF_MIPI_BASE + 0x00000028) -#define RKISP1_CIF_MIPI_ADD_DATA_SEL_3 (RKISP1_CIF_MIPI_BASE + 0x0000002C) -#define RKISP1_CIF_MIPI_ADD_DATA_SEL_4 (RKISP1_CIF_MIPI_BASE + 0x00000030) -#define RKISP1_CIF_MIPI_ADD_DATA_FIFO (RKISP1_CIF_MIPI_BASE + 0x00000034) -#define RKISP1_CIF_MIPI_FIFO_FILL_LEVEL (RKISP1_CIF_MIPI_BASE + 0x00000038) -#define RKISP1_CIF_MIPI_COMPRESSED_MODE (RKISP1_CIF_MIPI_BASE + 0x0000003C) -#define RKISP1_CIF_MIPI_FRAME (RKISP1_CIF_MIPI_BASE + 0x00000040) -#define RKISP1_CIF_MIPI_GEN_SHORT_DT (RKISP1_CIF_MIPI_BASE + 0x00000044) -#define RKISP1_CIF_MIPI_GEN_SHORT_8_9 (RKISP1_CIF_MIPI_BASE + 0x00000048) -#define RKISP1_CIF_MIPI_GEN_SHORT_A_B (RKISP1_CIF_MIPI_BASE + 0x0000004C) -#define RKISP1_CIF_MIPI_GEN_SHORT_C_D (RKISP1_CIF_MIPI_BASE + 0x00000050) -#define RKISP1_CIF_MIPI_GEN_SHORT_E_F (RKISP1_CIF_MIPI_BASE + 0x00000054) - -#define RKISP1_CIF_ISP_AFM_BASE 0x00002000 -#define RKISP1_CIF_ISP_AFM_CTRL (RKISP1_CIF_ISP_AFM_BASE + 0x00000000) -#define RKISP1_CIF_ISP_AFM_LT_A (RKISP1_CIF_ISP_AFM_BASE + 0x00000004) -#define RKISP1_CIF_ISP_AFM_RB_A (RKISP1_CIF_ISP_AFM_BASE + 0x00000008) -#define RKISP1_CIF_ISP_AFM_LT_B (RKISP1_CIF_ISP_AFM_BASE + 0x0000000C) -#define RKISP1_CIF_ISP_AFM_RB_B (RKISP1_CIF_ISP_AFM_BASE + 0x00000010) -#define RKISP1_CIF_ISP_AFM_LT_C (RKISP1_CIF_ISP_AFM_BASE + 0x00000014) -#define RKISP1_CIF_ISP_AFM_RB_C (RKISP1_CIF_ISP_AFM_BASE + 0x00000018) -#define RKISP1_CIF_ISP_AFM_THRES (RKISP1_CIF_ISP_AFM_BASE + 0x0000001C) -#define RKISP1_CIF_ISP_AFM_VAR_SHIFT (RKISP1_CIF_ISP_AFM_BASE + 0x00000020) -#define RKISP1_CIF_ISP_AFM_SUM_A (RKISP1_CIF_ISP_AFM_BASE + 0x00000024) -#define RKISP1_CIF_ISP_AFM_SUM_B (RKISP1_CIF_ISP_AFM_BASE + 0x00000028) -#define RKISP1_CIF_ISP_AFM_SUM_C (RKISP1_CIF_ISP_AFM_BASE + 0x0000002C) -#define RKISP1_CIF_ISP_AFM_LUM_A (RKISP1_CIF_ISP_AFM_BASE + 0x00000030) -#define RKISP1_CIF_ISP_AFM_LUM_B (RKISP1_CIF_ISP_AFM_BASE + 0x00000034) -#define RKISP1_CIF_ISP_AFM_LUM_C (RKISP1_CIF_ISP_AFM_BASE + 0x00000038) - -#define RKISP1_CIF_ISP_LSC_BASE 0x00002200 -#define RKISP1_CIF_ISP_LSC_CTRL (RKISP1_CIF_ISP_LSC_BASE + 0x00000000) -#define RKISP1_CIF_ISP_LSC_R_TABLE_ADDR (RKISP1_CIF_ISP_LSC_BASE + 0x00000004) -#define RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR (RKISP1_CIF_ISP_LSC_BASE + 0x00000008) -#define RKISP1_CIF_ISP_LSC_B_TABLE_ADDR (RKISP1_CIF_ISP_LSC_BASE + 0x0000000C) -#define RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR (RKISP1_CIF_ISP_LSC_BASE + 0x00000010) -#define RKISP1_CIF_ISP_LSC_R_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x00000014) -#define RKISP1_CIF_ISP_LSC_GR_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x00000018) -#define RKISP1_CIF_ISP_LSC_B_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x0000001C) -#define RKISP1_CIF_ISP_LSC_GB_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x00000020) -#define RKISP1_CIF_ISP_LSC_XGRAD_01 (RKISP1_CIF_ISP_LSC_BASE + 0x00000024) -#define RKISP1_CIF_ISP_LSC_XGRAD_23 (RKISP1_CIF_ISP_LSC_BASE + 0x00000028) -#define RKISP1_CIF_ISP_LSC_XGRAD_45 (RKISP1_CIF_ISP_LSC_BASE + 0x0000002C) -#define RKISP1_CIF_ISP_LSC_XGRAD_67 (RKISP1_CIF_ISP_LSC_BASE + 0x00000030) -#define RKISP1_CIF_ISP_LSC_YGRAD_01 (RKISP1_CIF_ISP_LSC_BASE + 0x00000034) -#define RKISP1_CIF_ISP_LSC_YGRAD_23 (RKISP1_CIF_ISP_LSC_BASE + 0x00000038) -#define RKISP1_CIF_ISP_LSC_YGRAD_45 (RKISP1_CIF_ISP_LSC_BASE + 0x0000003C) -#define RKISP1_CIF_ISP_LSC_YGRAD_67 (RKISP1_CIF_ISP_LSC_BASE + 0x00000040) -#define RKISP1_CIF_ISP_LSC_XSIZE_01 (RKISP1_CIF_ISP_LSC_BASE + 0x00000044) -#define RKISP1_CIF_ISP_LSC_XSIZE_23 (RKISP1_CIF_ISP_LSC_BASE + 0x00000048) -#define RKISP1_CIF_ISP_LSC_XSIZE_45 (RKISP1_CIF_ISP_LSC_BASE + 0x0000004C) -#define RKISP1_CIF_ISP_LSC_XSIZE_67 (RKISP1_CIF_ISP_LSC_BASE + 0x00000050) -#define RKISP1_CIF_ISP_LSC_YSIZE_01 (RKISP1_CIF_ISP_LSC_BASE + 0x00000054) -#define RKISP1_CIF_ISP_LSC_YSIZE_23 (RKISP1_CIF_ISP_LSC_BASE + 0x00000058) -#define RKISP1_CIF_ISP_LSC_YSIZE_45 (RKISP1_CIF_ISP_LSC_BASE + 0x0000005C) -#define RKISP1_CIF_ISP_LSC_YSIZE_67 (RKISP1_CIF_ISP_LSC_BASE + 0x00000060) -#define RKISP1_CIF_ISP_LSC_TABLE_SEL (RKISP1_CIF_ISP_LSC_BASE + 0x00000064) -#define RKISP1_CIF_ISP_LSC_STATUS (RKISP1_CIF_ISP_LSC_BASE + 0x00000068) - -#define RKISP1_CIF_ISP_IS_BASE 0x00002300 -#define RKISP1_CIF_ISP_IS_CTRL (RKISP1_CIF_ISP_IS_BASE + 0x00000000) -#define RKISP1_CIF_ISP_IS_RECENTER (RKISP1_CIF_ISP_IS_BASE + 0x00000004) -#define RKISP1_CIF_ISP_IS_H_OFFS (RKISP1_CIF_ISP_IS_BASE + 0x00000008) -#define RKISP1_CIF_ISP_IS_V_OFFS (RKISP1_CIF_ISP_IS_BASE + 0x0000000C) -#define RKISP1_CIF_ISP_IS_H_SIZE (RKISP1_CIF_ISP_IS_BASE + 0x00000010) -#define RKISP1_CIF_ISP_IS_V_SIZE (RKISP1_CIF_ISP_IS_BASE + 0x00000014) -#define RKISP1_CIF_ISP_IS_MAX_DX (RKISP1_CIF_ISP_IS_BASE + 0x00000018) -#define RKISP1_CIF_ISP_IS_MAX_DY (RKISP1_CIF_ISP_IS_BASE + 0x0000001C) -#define RKISP1_CIF_ISP_IS_DISPLACE (RKISP1_CIF_ISP_IS_BASE + 0x00000020) -#define RKISP1_CIF_ISP_IS_H_OFFS_SHD (RKISP1_CIF_ISP_IS_BASE + 0x00000024) -#define RKISP1_CIF_ISP_IS_V_OFFS_SHD (RKISP1_CIF_ISP_IS_BASE + 0x00000028) -#define RKISP1_CIF_ISP_IS_H_SIZE_SHD (RKISP1_CIF_ISP_IS_BASE + 0x0000002C) -#define RKISP1_CIF_ISP_IS_V_SIZE_SHD (RKISP1_CIF_ISP_IS_BASE + 0x00000030) - -#define RKISP1_CIF_ISP_HIST_BASE 0x00002400 - -#define RKISP1_CIF_ISP_HIST_PROP (RKISP1_CIF_ISP_HIST_BASE + 0x00000000) -#define RKISP1_CIF_ISP_HIST_H_OFFS (RKISP1_CIF_ISP_HIST_BASE + 0x00000004) -#define RKISP1_CIF_ISP_HIST_V_OFFS (RKISP1_CIF_ISP_HIST_BASE + 0x00000008) -#define RKISP1_CIF_ISP_HIST_H_SIZE (RKISP1_CIF_ISP_HIST_BASE + 0x0000000C) -#define RKISP1_CIF_ISP_HIST_V_SIZE (RKISP1_CIF_ISP_HIST_BASE + 0x00000010) -#define RKISP1_CIF_ISP_HIST_BIN_0 (RKISP1_CIF_ISP_HIST_BASE + 0x00000014) -#define RKISP1_CIF_ISP_HIST_BIN_1 (RKISP1_CIF_ISP_HIST_BASE + 0x00000018) -#define RKISP1_CIF_ISP_HIST_BIN_2 (RKISP1_CIF_ISP_HIST_BASE + 0x0000001C) -#define RKISP1_CIF_ISP_HIST_BIN_3 (RKISP1_CIF_ISP_HIST_BASE + 0x00000020) -#define RKISP1_CIF_ISP_HIST_BIN_4 (RKISP1_CIF_ISP_HIST_BASE + 0x00000024) -#define RKISP1_CIF_ISP_HIST_BIN_5 (RKISP1_CIF_ISP_HIST_BASE + 0x00000028) -#define RKISP1_CIF_ISP_HIST_BIN_6 (RKISP1_CIF_ISP_HIST_BASE + 0x0000002C) -#define RKISP1_CIF_ISP_HIST_BIN_7 (RKISP1_CIF_ISP_HIST_BASE + 0x00000030) -#define RKISP1_CIF_ISP_HIST_BIN_8 (RKISP1_CIF_ISP_HIST_BASE + 0x00000034) -#define RKISP1_CIF_ISP_HIST_BIN_9 (RKISP1_CIF_ISP_HIST_BASE + 0x00000038) -#define RKISP1_CIF_ISP_HIST_BIN_10 (RKISP1_CIF_ISP_HIST_BASE + 0x0000003C) -#define RKISP1_CIF_ISP_HIST_BIN_11 (RKISP1_CIF_ISP_HIST_BASE + 0x00000040) -#define RKISP1_CIF_ISP_HIST_BIN_12 (RKISP1_CIF_ISP_HIST_BASE + 0x00000044) -#define RKISP1_CIF_ISP_HIST_BIN_13 (RKISP1_CIF_ISP_HIST_BASE + 0x00000048) -#define RKISP1_CIF_ISP_HIST_BIN_14 (RKISP1_CIF_ISP_HIST_BASE + 0x0000004C) -#define RKISP1_CIF_ISP_HIST_BIN_15 (RKISP1_CIF_ISP_HIST_BASE + 0x00000050) -#define RKISP1_CIF_ISP_HIST_WEIGHT_00TO30 (RKISP1_CIF_ISP_HIST_BASE + 0x00000054) -#define RKISP1_CIF_ISP_HIST_WEIGHT_40TO21 (RKISP1_CIF_ISP_HIST_BASE + 0x00000058) -#define RKISP1_CIF_ISP_HIST_WEIGHT_31TO12 (RKISP1_CIF_ISP_HIST_BASE + 0x0000005C) -#define RKISP1_CIF_ISP_HIST_WEIGHT_22TO03 (RKISP1_CIF_ISP_HIST_BASE + 0x00000060) -#define RKISP1_CIF_ISP_HIST_WEIGHT_13TO43 (RKISP1_CIF_ISP_HIST_BASE + 0x00000064) -#define RKISP1_CIF_ISP_HIST_WEIGHT_04TO34 (RKISP1_CIF_ISP_HIST_BASE + 0x00000068) -#define RKISP1_CIF_ISP_HIST_WEIGHT_44 (RKISP1_CIF_ISP_HIST_BASE + 0x0000006C) - -#define RKISP1_CIF_ISP_FILT_BASE 0x00002500 -#define RKISP1_CIF_ISP_FILT_MODE (RKISP1_CIF_ISP_FILT_BASE + 0x00000000) -#define RKISP1_CIF_ISP_FILT_THRESH_BL0 (RKISP1_CIF_ISP_FILT_BASE + 0x00000028) -#define RKISP1_CIF_ISP_FILT_THRESH_BL1 (RKISP1_CIF_ISP_FILT_BASE + 0x0000002c) -#define RKISP1_CIF_ISP_FILT_THRESH_SH0 (RKISP1_CIF_ISP_FILT_BASE + 0x00000030) -#define RKISP1_CIF_ISP_FILT_THRESH_SH1 (RKISP1_CIF_ISP_FILT_BASE + 0x00000034) -#define RKISP1_CIF_ISP_FILT_LUM_WEIGHT (RKISP1_CIF_ISP_FILT_BASE + 0x00000038) -#define RKISP1_CIF_ISP_FILT_FAC_SH1 (RKISP1_CIF_ISP_FILT_BASE + 0x0000003c) -#define RKISP1_CIF_ISP_FILT_FAC_SH0 (RKISP1_CIF_ISP_FILT_BASE + 0x00000040) -#define RKISP1_CIF_ISP_FILT_FAC_MID (RKISP1_CIF_ISP_FILT_BASE + 0x00000044) -#define RKISP1_CIF_ISP_FILT_FAC_BL0 (RKISP1_CIF_ISP_FILT_BASE + 0x00000048) -#define RKISP1_CIF_ISP_FILT_FAC_BL1 (RKISP1_CIF_ISP_FILT_BASE + 0x0000004C) - -#define RKISP1_CIF_ISP_CAC_BASE 0x00002580 -#define RKISP1_CIF_ISP_CAC_CTRL (RKISP1_CIF_ISP_CAC_BASE + 0x00000000) -#define RKISP1_CIF_ISP_CAC_COUNT_START (RKISP1_CIF_ISP_CAC_BASE + 0x00000004) -#define RKISP1_CIF_ISP_CAC_A (RKISP1_CIF_ISP_CAC_BASE + 0x00000008) -#define RKISP1_CIF_ISP_CAC_B (RKISP1_CIF_ISP_CAC_BASE + 0x0000000C) -#define RKISP1_CIF_ISP_CAC_C (RKISP1_CIF_ISP_CAC_BASE + 0x00000010) -#define RKISP1_CIF_ISP_X_NORM (RKISP1_CIF_ISP_CAC_BASE + 0x00000014) -#define RKISP1_CIF_ISP_Y_NORM (RKISP1_CIF_ISP_CAC_BASE + 0x00000018) - -#define RKISP1_CIF_ISP_EXP_BASE 0x00002600 -#define RKISP1_CIF_ISP_EXP_CTRL (RKISP1_CIF_ISP_EXP_BASE + 0x00000000) -#define RKISP1_CIF_ISP_EXP_H_OFFSET (RKISP1_CIF_ISP_EXP_BASE + 0x00000004) -#define RKISP1_CIF_ISP_EXP_V_OFFSET (RKISP1_CIF_ISP_EXP_BASE + 0x00000008) -#define RKISP1_CIF_ISP_EXP_H_SIZE (RKISP1_CIF_ISP_EXP_BASE + 0x0000000C) -#define RKISP1_CIF_ISP_EXP_V_SIZE (RKISP1_CIF_ISP_EXP_BASE + 0x00000010) -#define RKISP1_CIF_ISP_EXP_MEAN_00 (RKISP1_CIF_ISP_EXP_BASE + 0x00000014) -#define RKISP1_CIF_ISP_EXP_MEAN_10 (RKISP1_CIF_ISP_EXP_BASE + 0x00000018) -#define RKISP1_CIF_ISP_EXP_MEAN_20 (RKISP1_CIF_ISP_EXP_BASE + 0x0000001c) -#define RKISP1_CIF_ISP_EXP_MEAN_30 (RKISP1_CIF_ISP_EXP_BASE + 0x00000020) -#define RKISP1_CIF_ISP_EXP_MEAN_40 (RKISP1_CIF_ISP_EXP_BASE + 0x00000024) -#define RKISP1_CIF_ISP_EXP_MEAN_01 (RKISP1_CIF_ISP_EXP_BASE + 0x00000028) -#define RKISP1_CIF_ISP_EXP_MEAN_11 (RKISP1_CIF_ISP_EXP_BASE + 0x0000002c) -#define RKISP1_CIF_ISP_EXP_MEAN_21 (RKISP1_CIF_ISP_EXP_BASE + 0x00000030) -#define RKISP1_CIF_ISP_EXP_MEAN_31 (RKISP1_CIF_ISP_EXP_BASE + 0x00000034) -#define RKISP1_CIF_ISP_EXP_MEAN_41 (RKISP1_CIF_ISP_EXP_BASE + 0x00000038) -#define RKISP1_CIF_ISP_EXP_MEAN_02 (RKISP1_CIF_ISP_EXP_BASE + 0x0000003c) -#define RKISP1_CIF_ISP_EXP_MEAN_12 (RKISP1_CIF_ISP_EXP_BASE + 0x00000040) -#define RKISP1_CIF_ISP_EXP_MEAN_22 (RKISP1_CIF_ISP_EXP_BASE + 0x00000044) -#define RKISP1_CIF_ISP_EXP_MEAN_32 (RKISP1_CIF_ISP_EXP_BASE + 0x00000048) -#define RKISP1_CIF_ISP_EXP_MEAN_42 (RKISP1_CIF_ISP_EXP_BASE + 0x0000004c) -#define RKISP1_CIF_ISP_EXP_MEAN_03 (RKISP1_CIF_ISP_EXP_BASE + 0x00000050) -#define RKISP1_CIF_ISP_EXP_MEAN_13 (RKISP1_CIF_ISP_EXP_BASE + 0x00000054) -#define RKISP1_CIF_ISP_EXP_MEAN_23 (RKISP1_CIF_ISP_EXP_BASE + 0x00000058) -#define RKISP1_CIF_ISP_EXP_MEAN_33 (RKISP1_CIF_ISP_EXP_BASE + 0x0000005c) -#define RKISP1_CIF_ISP_EXP_MEAN_43 (RKISP1_CIF_ISP_EXP_BASE + 0x00000060) -#define RKISP1_CIF_ISP_EXP_MEAN_04 (RKISP1_CIF_ISP_EXP_BASE + 0x00000064) -#define RKISP1_CIF_ISP_EXP_MEAN_14 (RKISP1_CIF_ISP_EXP_BASE + 0x00000068) -#define RKISP1_CIF_ISP_EXP_MEAN_24 (RKISP1_CIF_ISP_EXP_BASE + 0x0000006c) -#define RKISP1_CIF_ISP_EXP_MEAN_34 (RKISP1_CIF_ISP_EXP_BASE + 0x00000070) -#define RKISP1_CIF_ISP_EXP_MEAN_44 (RKISP1_CIF_ISP_EXP_BASE + 0x00000074) - -#define RKISP1_CIF_ISP_BLS_BASE 0x00002700 -#define RKISP1_CIF_ISP_BLS_CTRL (RKISP1_CIF_ISP_BLS_BASE + 0x00000000) -#define RKISP1_CIF_ISP_BLS_SAMPLES (RKISP1_CIF_ISP_BLS_BASE + 0x00000004) -#define RKISP1_CIF_ISP_BLS_H1_START (RKISP1_CIF_ISP_BLS_BASE + 0x00000008) -#define RKISP1_CIF_ISP_BLS_H1_STOP (RKISP1_CIF_ISP_BLS_BASE + 0x0000000c) -#define RKISP1_CIF_ISP_BLS_V1_START (RKISP1_CIF_ISP_BLS_BASE + 0x00000010) -#define RKISP1_CIF_ISP_BLS_V1_STOP (RKISP1_CIF_ISP_BLS_BASE + 0x00000014) -#define RKISP1_CIF_ISP_BLS_H2_START (RKISP1_CIF_ISP_BLS_BASE + 0x00000018) -#define RKISP1_CIF_ISP_BLS_H2_STOP (RKISP1_CIF_ISP_BLS_BASE + 0x0000001c) -#define RKISP1_CIF_ISP_BLS_V2_START (RKISP1_CIF_ISP_BLS_BASE + 0x00000020) -#define RKISP1_CIF_ISP_BLS_V2_STOP (RKISP1_CIF_ISP_BLS_BASE + 0x00000024) -#define RKISP1_CIF_ISP_BLS_A_FIXED (RKISP1_CIF_ISP_BLS_BASE + 0x00000028) -#define RKISP1_CIF_ISP_BLS_B_FIXED (RKISP1_CIF_ISP_BLS_BASE + 0x0000002c) -#define RKISP1_CIF_ISP_BLS_C_FIXED (RKISP1_CIF_ISP_BLS_BASE + 0x00000030) -#define RKISP1_CIF_ISP_BLS_D_FIXED (RKISP1_CIF_ISP_BLS_BASE + 0x00000034) -#define RKISP1_CIF_ISP_BLS_A_MEASURED (RKISP1_CIF_ISP_BLS_BASE + 0x00000038) -#define RKISP1_CIF_ISP_BLS_B_MEASURED (RKISP1_CIF_ISP_BLS_BASE + 0x0000003c) -#define RKISP1_CIF_ISP_BLS_C_MEASURED (RKISP1_CIF_ISP_BLS_BASE + 0x00000040) -#define RKISP1_CIF_ISP_BLS_D_MEASURED (RKISP1_CIF_ISP_BLS_BASE + 0x00000044) - -#define RKISP1_CIF_ISP_DPF_BASE 0x00002800 -#define RKISP1_CIF_ISP_DPF_MODE (RKISP1_CIF_ISP_DPF_BASE + 0x00000000) -#define RKISP1_CIF_ISP_DPF_STRENGTH_R (RKISP1_CIF_ISP_DPF_BASE + 0x00000004) -#define RKISP1_CIF_ISP_DPF_STRENGTH_G (RKISP1_CIF_ISP_DPF_BASE + 0x00000008) -#define RKISP1_CIF_ISP_DPF_STRENGTH_B (RKISP1_CIF_ISP_DPF_BASE + 0x0000000C) -#define RKISP1_CIF_ISP_DPF_S_WEIGHT_G_1_4 (RKISP1_CIF_ISP_DPF_BASE + 0x00000010) -#define RKISP1_CIF_ISP_DPF_S_WEIGHT_G_5_6 (RKISP1_CIF_ISP_DPF_BASE + 0x00000014) -#define RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_1_4 (RKISP1_CIF_ISP_DPF_BASE + 0x00000018) -#define RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_5_6 (RKISP1_CIF_ISP_DPF_BASE + 0x0000001C) -#define RKISP1_CIF_ISP_DPF_NULL_COEFF_0 (RKISP1_CIF_ISP_DPF_BASE + 0x00000020) -#define RKISP1_CIF_ISP_DPF_NULL_COEFF_1 (RKISP1_CIF_ISP_DPF_BASE + 0x00000024) -#define RKISP1_CIF_ISP_DPF_NULL_COEFF_2 (RKISP1_CIF_ISP_DPF_BASE + 0x00000028) -#define RKISP1_CIF_ISP_DPF_NULL_COEFF_3 (RKISP1_CIF_ISP_DPF_BASE + 0x0000002C) -#define RKISP1_CIF_ISP_DPF_NULL_COEFF_4 (RKISP1_CIF_ISP_DPF_BASE + 0x00000030) -#define RKISP1_CIF_ISP_DPF_NULL_COEFF_5 (RKISP1_CIF_ISP_DPF_BASE + 0x00000034) -#define RKISP1_CIF_ISP_DPF_NULL_COEFF_6 (RKISP1_CIF_ISP_DPF_BASE + 0x00000038) -#define RKISP1_CIF_ISP_DPF_NULL_COEFF_7 (RKISP1_CIF_ISP_DPF_BASE + 0x0000003C) -#define RKISP1_CIF_ISP_DPF_NULL_COEFF_8 (RKISP1_CIF_ISP_DPF_BASE + 0x00000040) -#define RKISP1_CIF_ISP_DPF_NULL_COEFF_9 (RKISP1_CIF_ISP_DPF_BASE + 0x00000044) -#define RKISP1_CIF_ISP_DPF_NULL_COEFF_10 (RKISP1_CIF_ISP_DPF_BASE + 0x00000048) -#define RKISP1_CIF_ISP_DPF_NULL_COEFF_11 (RKISP1_CIF_ISP_DPF_BASE + 0x0000004C) -#define RKISP1_CIF_ISP_DPF_NULL_COEFF_12 (RKISP1_CIF_ISP_DPF_BASE + 0x00000050) -#define RKISP1_CIF_ISP_DPF_NULL_COEFF_13 (RKISP1_CIF_ISP_DPF_BASE + 0x00000054) -#define RKISP1_CIF_ISP_DPF_NULL_COEFF_14 (RKISP1_CIF_ISP_DPF_BASE + 0x00000058) -#define RKISP1_CIF_ISP_DPF_NULL_COEFF_15 (RKISP1_CIF_ISP_DPF_BASE + 0x0000005C) -#define RKISP1_CIF_ISP_DPF_NULL_COEFF_16 (RKISP1_CIF_ISP_DPF_BASE + 0x00000060) -#define RKISP1_CIF_ISP_DPF_NF_GAIN_R (RKISP1_CIF_ISP_DPF_BASE + 0x00000064) -#define RKISP1_CIF_ISP_DPF_NF_GAIN_GR (RKISP1_CIF_ISP_DPF_BASE + 0x00000068) -#define RKISP1_CIF_ISP_DPF_NF_GAIN_GB (RKISP1_CIF_ISP_DPF_BASE + 0x0000006C) -#define RKISP1_CIF_ISP_DPF_NF_GAIN_B (RKISP1_CIF_ISP_DPF_BASE + 0x00000070) - -#define RKISP1_CIF_ISP_DPCC_BASE 0x00002900 -#define RKISP1_CIF_ISP_DPCC_MODE (RKISP1_CIF_ISP_DPCC_BASE + 0x00000000) -#define RKISP1_CIF_ISP_DPCC_OUTPUT_MODE (RKISP1_CIF_ISP_DPCC_BASE + 0x00000004) -#define RKISP1_CIF_ISP_DPCC_SET_USE (RKISP1_CIF_ISP_DPCC_BASE + 0x00000008) -#define RKISP1_CIF_ISP_DPCC_METHODS_SET_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000000C) -#define RKISP1_CIF_ISP_DPCC_METHODS_SET_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000010) -#define RKISP1_CIF_ISP_DPCC_METHODS_SET_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000014) -#define RKISP1_CIF_ISP_DPCC_LINE_THRESH_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000018) -#define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000001C) -#define RKISP1_CIF_ISP_DPCC_PG_FAC_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000020) -#define RKISP1_CIF_ISP_DPCC_RND_THRESH_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000024) -#define RKISP1_CIF_ISP_DPCC_RG_FAC_1 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000028) -#define RKISP1_CIF_ISP_DPCC_LINE_THRESH_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000002C) -#define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000030) -#define RKISP1_CIF_ISP_DPCC_PG_FAC_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000034) -#define RKISP1_CIF_ISP_DPCC_RND_THRESH_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000038) -#define RKISP1_CIF_ISP_DPCC_RG_FAC_2 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000003C) -#define RKISP1_CIF_ISP_DPCC_LINE_THRESH_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000040) -#define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000044) -#define RKISP1_CIF_ISP_DPCC_PG_FAC_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000048) -#define RKISP1_CIF_ISP_DPCC_RND_THRESH_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x0000004C) -#define RKISP1_CIF_ISP_DPCC_RG_FAC_3 (RKISP1_CIF_ISP_DPCC_BASE + 0x00000050) -#define RKISP1_CIF_ISP_DPCC_RO_LIMITS (RKISP1_CIF_ISP_DPCC_BASE + 0x00000054) -#define RKISP1_CIF_ISP_DPCC_RND_OFFS (RKISP1_CIF_ISP_DPCC_BASE + 0x00000058) -#define RKISP1_CIF_ISP_DPCC_BPT_CTRL (RKISP1_CIF_ISP_DPCC_BASE + 0x0000005C) -#define RKISP1_CIF_ISP_DPCC_BPT_NUMBER (RKISP1_CIF_ISP_DPCC_BASE + 0x00000060) -#define RKISP1_CIF_ISP_DPCC_BPT_ADDR (RKISP1_CIF_ISP_DPCC_BASE + 0x00000064) -#define RKISP1_CIF_ISP_DPCC_BPT_DATA (RKISP1_CIF_ISP_DPCC_BASE + 0x00000068) - -#define RKISP1_CIF_ISP_WDR_BASE 0x00002A00 -#define RKISP1_CIF_ISP_WDR_CTRL (RKISP1_CIF_ISP_WDR_BASE + 0x00000000) -#define RKISP1_CIF_ISP_WDR_TONECURVE_1 (RKISP1_CIF_ISP_WDR_BASE + 0x00000004) -#define RKISP1_CIF_ISP_WDR_TONECURVE_2 (RKISP1_CIF_ISP_WDR_BASE + 0x00000008) -#define RKISP1_CIF_ISP_WDR_TONECURVE_3 (RKISP1_CIF_ISP_WDR_BASE + 0x0000000C) -#define RKISP1_CIF_ISP_WDR_TONECURVE_4 (RKISP1_CIF_ISP_WDR_BASE + 0x00000010) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_0 (RKISP1_CIF_ISP_WDR_BASE + 0x00000014) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_1 (RKISP1_CIF_ISP_WDR_BASE + 0x00000018) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_2 (RKISP1_CIF_ISP_WDR_BASE + 0x0000001C) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_3 (RKISP1_CIF_ISP_WDR_BASE + 0x00000020) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_4 (RKISP1_CIF_ISP_WDR_BASE + 0x00000024) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_5 (RKISP1_CIF_ISP_WDR_BASE + 0x00000028) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_6 (RKISP1_CIF_ISP_WDR_BASE + 0x0000002C) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_7 (RKISP1_CIF_ISP_WDR_BASE + 0x00000030) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_8 (RKISP1_CIF_ISP_WDR_BASE + 0x00000034) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_9 (RKISP1_CIF_ISP_WDR_BASE + 0x00000038) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_10 (RKISP1_CIF_ISP_WDR_BASE + 0x0000003C) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_11 (RKISP1_CIF_ISP_WDR_BASE + 0x00000040) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_12 (RKISP1_CIF_ISP_WDR_BASE + 0x00000044) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_13 (RKISP1_CIF_ISP_WDR_BASE + 0x00000048) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_14 (RKISP1_CIF_ISP_WDR_BASE + 0x0000004C) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_15 (RKISP1_CIF_ISP_WDR_BASE + 0x00000050) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_16 (RKISP1_CIF_ISP_WDR_BASE + 0x00000054) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_17 (RKISP1_CIF_ISP_WDR_BASE + 0x00000058) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_18 (RKISP1_CIF_ISP_WDR_BASE + 0x0000005C) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_19 (RKISP1_CIF_ISP_WDR_BASE + 0x00000060) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_20 (RKISP1_CIF_ISP_WDR_BASE + 0x00000064) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_21 (RKISP1_CIF_ISP_WDR_BASE + 0x00000068) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_22 (RKISP1_CIF_ISP_WDR_BASE + 0x0000006C) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_23 (RKISP1_CIF_ISP_WDR_BASE + 0x00000070) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_24 (RKISP1_CIF_ISP_WDR_BASE + 0x00000074) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_25 (RKISP1_CIF_ISP_WDR_BASE + 0x00000078) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_26 (RKISP1_CIF_ISP_WDR_BASE + 0x0000007C) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_27 (RKISP1_CIF_ISP_WDR_BASE + 0x00000080) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_28 (RKISP1_CIF_ISP_WDR_BASE + 0x00000084) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_29 (RKISP1_CIF_ISP_WDR_BASE + 0x00000088) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_30 (RKISP1_CIF_ISP_WDR_BASE + 0x0000008C) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_31 (RKISP1_CIF_ISP_WDR_BASE + 0x00000090) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_32 (RKISP1_CIF_ISP_WDR_BASE + 0x00000094) -#define RKISP1_CIF_ISP_WDR_OFFSET (RKISP1_CIF_ISP_WDR_BASE + 0x00000098) -#define RKISP1_CIF_ISP_WDR_DELTAMIN (RKISP1_CIF_ISP_WDR_BASE + 0x0000009C) -#define RKISP1_CIF_ISP_WDR_TONECURVE_1_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000A0) -#define RKISP1_CIF_ISP_WDR_TONECURVE_2_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000A4) -#define RKISP1_CIF_ISP_WDR_TONECURVE_3_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000A8) -#define RKISP1_CIF_ISP_WDR_TONECURVE_4_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000AC) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_0_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000B0) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_1_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000B4) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_2_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000B8) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_3_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000BC) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_4_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000C0) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_5_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000C4) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_6_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000C8) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_7_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000CC) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_8_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000D0) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_9_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000D4) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_10_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000D8) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_11_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000DC) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_12_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000E0) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_13_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000E4) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_14_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000E8) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_15_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000EC) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_16_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000F0) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_17_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000F4) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_18_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000F8) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_19_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000FC) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_20_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000100) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_21_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000104) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_22_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000108) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_23_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x0000010C) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_24_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000110) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_25_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000114) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_26_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000118) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_27_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x0000011C) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_28_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000120) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_29_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000124) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_30_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000128) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_31_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x0000012C) -#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_32_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000130) - -#define RKISP1_CIF_ISP_VSM_BASE 0x00002F00 -#define RKISP1_CIF_ISP_VSM_MODE (RKISP1_CIF_ISP_VSM_BASE + 0x00000000) -#define RKISP1_CIF_ISP_VSM_H_OFFS (RKISP1_CIF_ISP_VSM_BASE + 0x00000004) -#define RKISP1_CIF_ISP_VSM_V_OFFS (RKISP1_CIF_ISP_VSM_BASE + 0x00000008) -#define RKISP1_CIF_ISP_VSM_H_SIZE (RKISP1_CIF_ISP_VSM_BASE + 0x0000000C) -#define RKISP1_CIF_ISP_VSM_V_SIZE (RKISP1_CIF_ISP_VSM_BASE + 0x00000010) -#define RKISP1_CIF_ISP_VSM_H_SEGMENTS (RKISP1_CIF_ISP_VSM_BASE + 0x00000014) -#define RKISP1_CIF_ISP_VSM_V_SEGMENTS (RKISP1_CIF_ISP_VSM_BASE + 0x00000018) -#define RKISP1_CIF_ISP_VSM_DELTA_H (RKISP1_CIF_ISP_VSM_BASE + 0x0000001C) -#define RKISP1_CIF_ISP_VSM_DELTA_V (RKISP1_CIF_ISP_VSM_BASE + 0x00000020) - -#endif /* _RKISP1_REGS_H */ diff --git a/drivers/staging/media/rkisp1/rkisp1-resizer.c b/drivers/staging/media/rkisp1/rkisp1-resizer.c deleted file mode 100644 index 7ca5b47c5bf5..000000000000 --- a/drivers/staging/media/rkisp1/rkisp1-resizer.c +++ /dev/null @@ -1,846 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -/* - * Rockchip ISP1 Driver - V4l resizer device - * - * Copyright (C) 2019 Collabora, Ltd. - * - * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd. - * Copyright (C) 2017 Rockchip Electronics Co., Ltd. - */ - -#include "rkisp1-common.h" - -#define RKISP1_RSZ_SP_DEV_NAME RKISP1_DRIVER_NAME "_resizer_selfpath" -#define RKISP1_RSZ_MP_DEV_NAME RKISP1_DRIVER_NAME "_resizer_mainpath" - -#define RKISP1_DEF_FMT MEDIA_BUS_FMT_YUYV8_2X8 -#define RKISP1_DEF_PIXEL_ENC V4L2_PIXEL_ENC_YUV - -struct rkisp1_rsz_yuv_mbus_info { - u32 mbus_code; - u32 hdiv; - u32 vdiv; -}; - -static const struct rkisp1_rsz_yuv_mbus_info rkisp1_rsz_yuv_src_formats[] = { - { - .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, /* YUV422 */ - .hdiv = 2, - .vdiv = 1, - }, - { - .mbus_code = MEDIA_BUS_FMT_YUYV8_1_5X8, /* YUV420 */ - .hdiv = 2, - .vdiv = 2, - }, -}; - -static const struct rkisp1_rsz_yuv_mbus_info *rkisp1_rsz_get_yuv_mbus_info(u32 mbus_code) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(rkisp1_rsz_yuv_src_formats); i++) { - if (rkisp1_rsz_yuv_src_formats[i].mbus_code == mbus_code) - return &rkisp1_rsz_yuv_src_formats[i]; - } - - return NULL; -} - -enum rkisp1_shadow_regs_when { - RKISP1_SHADOW_REGS_SYNC, - RKISP1_SHADOW_REGS_ASYNC, -}; - -struct rkisp1_rsz_config { - /* constrains */ - const int max_rsz_width; - const int max_rsz_height; - const int min_rsz_width; - const int min_rsz_height; - /* registers */ - struct { - u32 ctrl; - u32 ctrl_shd; - u32 scale_hy; - u32 scale_hcr; - u32 scale_hcb; - u32 scale_vy; - u32 scale_vc; - u32 scale_lut; - u32 scale_lut_addr; - u32 scale_hy_shd; - u32 scale_hcr_shd; - u32 scale_hcb_shd; - u32 scale_vy_shd; - u32 scale_vc_shd; - u32 phase_hy; - u32 phase_hc; - u32 phase_vy; - u32 phase_vc; - u32 phase_hy_shd; - u32 phase_hc_shd; - u32 phase_vy_shd; - u32 phase_vc_shd; - } rsz; - struct { - u32 ctrl; - u32 yuvmode_mask; - u32 rawmode_mask; - u32 h_offset; - u32 v_offset; - u32 h_size; - u32 v_size; - } dual_crop; -}; - -static const struct rkisp1_rsz_config rkisp1_rsz_config_mp = { - /* constraints */ - .max_rsz_width = RKISP1_RSZ_MP_SRC_MAX_WIDTH, - .max_rsz_height = RKISP1_RSZ_MP_SRC_MAX_HEIGHT, - .min_rsz_width = RKISP1_RSZ_SRC_MIN_WIDTH, - .min_rsz_height = RKISP1_RSZ_SRC_MIN_HEIGHT, - /* registers */ - .rsz = { - .ctrl = RKISP1_CIF_MRSZ_CTRL, - .scale_hy = RKISP1_CIF_MRSZ_SCALE_HY, - .scale_hcr = RKISP1_CIF_MRSZ_SCALE_HCR, - .scale_hcb = RKISP1_CIF_MRSZ_SCALE_HCB, - .scale_vy = RKISP1_CIF_MRSZ_SCALE_VY, - .scale_vc = RKISP1_CIF_MRSZ_SCALE_VC, - .scale_lut = RKISP1_CIF_MRSZ_SCALE_LUT, - .scale_lut_addr = RKISP1_CIF_MRSZ_SCALE_LUT_ADDR, - .scale_hy_shd = RKISP1_CIF_MRSZ_SCALE_HY_SHD, - .scale_hcr_shd = RKISP1_CIF_MRSZ_SCALE_HCR_SHD, - .scale_hcb_shd = RKISP1_CIF_MRSZ_SCALE_HCB_SHD, - .scale_vy_shd = RKISP1_CIF_MRSZ_SCALE_VY_SHD, - .scale_vc_shd = RKISP1_CIF_MRSZ_SCALE_VC_SHD, - .phase_hy = RKISP1_CIF_MRSZ_PHASE_HY, - .phase_hc = RKISP1_CIF_MRSZ_PHASE_HC, - .phase_vy = RKISP1_CIF_MRSZ_PHASE_VY, - .phase_vc = RKISP1_CIF_MRSZ_PHASE_VC, - .ctrl_shd = RKISP1_CIF_MRSZ_CTRL_SHD, - .phase_hy_shd = RKISP1_CIF_MRSZ_PHASE_HY_SHD, - .phase_hc_shd = RKISP1_CIF_MRSZ_PHASE_HC_SHD, - .phase_vy_shd = RKISP1_CIF_MRSZ_PHASE_VY_SHD, - .phase_vc_shd = RKISP1_CIF_MRSZ_PHASE_VC_SHD, - }, - .dual_crop = { - .ctrl = RKISP1_CIF_DUAL_CROP_CTRL, - .yuvmode_mask = RKISP1_CIF_DUAL_CROP_MP_MODE_YUV, - .rawmode_mask = RKISP1_CIF_DUAL_CROP_MP_MODE_RAW, - .h_offset = RKISP1_CIF_DUAL_CROP_M_H_OFFS, - .v_offset = RKISP1_CIF_DUAL_CROP_M_V_OFFS, - .h_size = RKISP1_CIF_DUAL_CROP_M_H_SIZE, - .v_size = RKISP1_CIF_DUAL_CROP_M_V_SIZE, - }, -}; - -static const struct rkisp1_rsz_config rkisp1_rsz_config_sp = { - /* constraints */ - .max_rsz_width = RKISP1_RSZ_SP_SRC_MAX_WIDTH, - .max_rsz_height = RKISP1_RSZ_SP_SRC_MAX_HEIGHT, - .min_rsz_width = RKISP1_RSZ_SRC_MIN_WIDTH, - .min_rsz_height = RKISP1_RSZ_SRC_MIN_HEIGHT, - /* registers */ - .rsz = { - .ctrl = RKISP1_CIF_SRSZ_CTRL, - .scale_hy = RKISP1_CIF_SRSZ_SCALE_HY, - .scale_hcr = RKISP1_CIF_SRSZ_SCALE_HCR, - .scale_hcb = RKISP1_CIF_SRSZ_SCALE_HCB, - .scale_vy = RKISP1_CIF_SRSZ_SCALE_VY, - .scale_vc = RKISP1_CIF_SRSZ_SCALE_VC, - .scale_lut = RKISP1_CIF_SRSZ_SCALE_LUT, - .scale_lut_addr = RKISP1_CIF_SRSZ_SCALE_LUT_ADDR, - .scale_hy_shd = RKISP1_CIF_SRSZ_SCALE_HY_SHD, - .scale_hcr_shd = RKISP1_CIF_SRSZ_SCALE_HCR_SHD, - .scale_hcb_shd = RKISP1_CIF_SRSZ_SCALE_HCB_SHD, - .scale_vy_shd = RKISP1_CIF_SRSZ_SCALE_VY_SHD, - .scale_vc_shd = RKISP1_CIF_SRSZ_SCALE_VC_SHD, - .phase_hy = RKISP1_CIF_SRSZ_PHASE_HY, - .phase_hc = RKISP1_CIF_SRSZ_PHASE_HC, - .phase_vy = RKISP1_CIF_SRSZ_PHASE_VY, - .phase_vc = RKISP1_CIF_SRSZ_PHASE_VC, - .ctrl_shd = RKISP1_CIF_SRSZ_CTRL_SHD, - .phase_hy_shd = RKISP1_CIF_SRSZ_PHASE_HY_SHD, - .phase_hc_shd = RKISP1_CIF_SRSZ_PHASE_HC_SHD, - .phase_vy_shd = RKISP1_CIF_SRSZ_PHASE_VY_SHD, - .phase_vc_shd = RKISP1_CIF_SRSZ_PHASE_VC_SHD, - }, - .dual_crop = { - .ctrl = RKISP1_CIF_DUAL_CROP_CTRL, - .yuvmode_mask = RKISP1_CIF_DUAL_CROP_SP_MODE_YUV, - .rawmode_mask = RKISP1_CIF_DUAL_CROP_SP_MODE_RAW, - .h_offset = RKISP1_CIF_DUAL_CROP_S_H_OFFS, - .v_offset = RKISP1_CIF_DUAL_CROP_S_V_OFFS, - .h_size = RKISP1_CIF_DUAL_CROP_S_H_SIZE, - .v_size = RKISP1_CIF_DUAL_CROP_S_V_SIZE, - }, -}; - -static struct v4l2_mbus_framefmt * -rkisp1_rsz_get_pad_fmt(struct rkisp1_resizer *rsz, - struct v4l2_subdev_pad_config *cfg, - unsigned int pad, u32 which) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&rsz->sd, cfg, pad); - else - return v4l2_subdev_get_try_format(&rsz->sd, rsz->pad_cfg, pad); -} - -static struct v4l2_rect * -rkisp1_rsz_get_pad_crop(struct rkisp1_resizer *rsz, - struct v4l2_subdev_pad_config *cfg, - unsigned int pad, u32 which) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_crop(&rsz->sd, cfg, pad); - else - return v4l2_subdev_get_try_crop(&rsz->sd, rsz->pad_cfg, pad); -} - -/* ---------------------------------------------------------------------------- - * Dual crop hw configs - */ - -static void rkisp1_dcrop_disable(struct rkisp1_resizer *rsz, - enum rkisp1_shadow_regs_when when) -{ - u32 dc_ctrl = rkisp1_read(rsz->rkisp1, rsz->config->dual_crop.ctrl); - u32 mask = ~(rsz->config->dual_crop.yuvmode_mask | - rsz->config->dual_crop.rawmode_mask); - - dc_ctrl &= mask; - if (when == RKISP1_SHADOW_REGS_ASYNC) - dc_ctrl |= RKISP1_CIF_DUAL_CROP_GEN_CFG_UPD; - else - dc_ctrl |= RKISP1_CIF_DUAL_CROP_CFG_UPD; - rkisp1_write(rsz->rkisp1, dc_ctrl, rsz->config->dual_crop.ctrl); -} - -/* configure dual-crop unit */ -static void rkisp1_dcrop_config(struct rkisp1_resizer *rsz) -{ - struct rkisp1_device *rkisp1 = rsz->rkisp1; - struct v4l2_mbus_framefmt *sink_fmt; - struct v4l2_rect *sink_crop; - u32 dc_ctrl; - - sink_crop = rkisp1_rsz_get_pad_crop(rsz, NULL, RKISP1_RSZ_PAD_SINK, - V4L2_SUBDEV_FORMAT_ACTIVE); - sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, NULL, RKISP1_RSZ_PAD_SINK, - V4L2_SUBDEV_FORMAT_ACTIVE); - - if (sink_crop->width == sink_fmt->width && - sink_crop->height == sink_fmt->height && - sink_crop->left == 0 && sink_crop->top == 0) { - rkisp1_dcrop_disable(rsz, RKISP1_SHADOW_REGS_SYNC); - dev_dbg(rkisp1->dev, "capture %d crop disabled\n", rsz->id); - return; - } - - dc_ctrl = rkisp1_read(rkisp1, rsz->config->dual_crop.ctrl); - rkisp1_write(rkisp1, sink_crop->left, rsz->config->dual_crop.h_offset); - rkisp1_write(rkisp1, sink_crop->top, rsz->config->dual_crop.v_offset); - rkisp1_write(rkisp1, sink_crop->width, rsz->config->dual_crop.h_size); - rkisp1_write(rkisp1, sink_crop->height, rsz->config->dual_crop.v_size); - dc_ctrl |= rsz->config->dual_crop.yuvmode_mask; - dc_ctrl |= RKISP1_CIF_DUAL_CROP_CFG_UPD; - rkisp1_write(rkisp1, dc_ctrl, rsz->config->dual_crop.ctrl); - - dev_dbg(rkisp1->dev, "stream %d crop: %dx%d -> %dx%d\n", rsz->id, - sink_fmt->width, sink_fmt->height, - sink_crop->width, sink_crop->height); -} - -/* ---------------------------------------------------------------------------- - * Resizer hw configs - */ - -static void rkisp1_rsz_dump_regs(struct rkisp1_resizer *rsz) -{ - dev_dbg(rsz->rkisp1->dev, - "RSZ_CTRL 0x%08x/0x%08x\n" - "RSZ_SCALE_HY %d/%d\n" - "RSZ_SCALE_HCB %d/%d\n" - "RSZ_SCALE_HCR %d/%d\n" - "RSZ_SCALE_VY %d/%d\n" - "RSZ_SCALE_VC %d/%d\n" - "RSZ_PHASE_HY %d/%d\n" - "RSZ_PHASE_HC %d/%d\n" - "RSZ_PHASE_VY %d/%d\n" - "RSZ_PHASE_VC %d/%d\n", - rkisp1_read(rsz->rkisp1, rsz->config->rsz.ctrl), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.ctrl_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hy), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hy_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hcb), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hcb_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hcr), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hcr_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_vy), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_vy_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_vc), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_vc_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_hy), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_hy_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_hc), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_hc_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_vy), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_vy_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_vc), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_vc_shd)); -} - -static void rkisp1_rsz_update_shadow(struct rkisp1_resizer *rsz, - enum rkisp1_shadow_regs_when when) -{ - u32 ctrl_cfg = rkisp1_read(rsz->rkisp1, rsz->config->rsz.ctrl); - - if (when == RKISP1_SHADOW_REGS_ASYNC) - ctrl_cfg |= RKISP1_CIF_RSZ_CTRL_CFG_UPD_AUTO; - else - ctrl_cfg |= RKISP1_CIF_RSZ_CTRL_CFG_UPD; - - rkisp1_write(rsz->rkisp1, ctrl_cfg, rsz->config->rsz.ctrl); -} - -static u32 rkisp1_rsz_calc_ratio(u32 len_sink, u32 len_src) -{ - if (len_sink < len_src) - return ((len_sink - 1) * RKISP1_CIF_RSZ_SCALER_FACTOR) / - (len_src - 1); - - return ((len_src - 1) * RKISP1_CIF_RSZ_SCALER_FACTOR) / - (len_sink - 1) + 1; -} - -static void rkisp1_rsz_disable(struct rkisp1_resizer *rsz, - enum rkisp1_shadow_regs_when when) -{ - rkisp1_write(rsz->rkisp1, 0, rsz->config->rsz.ctrl); - - if (when == RKISP1_SHADOW_REGS_SYNC) - rkisp1_rsz_update_shadow(rsz, when); -} - -static void rkisp1_rsz_config_regs(struct rkisp1_resizer *rsz, - struct v4l2_rect *sink_y, - struct v4l2_rect *sink_c, - struct v4l2_rect *src_y, - struct v4l2_rect *src_c, - enum rkisp1_shadow_regs_when when) -{ - struct rkisp1_device *rkisp1 = rsz->rkisp1; - u32 ratio, rsz_ctrl = 0; - unsigned int i; - - /* No phase offset */ - rkisp1_write(rkisp1, 0, rsz->config->rsz.phase_hy); - rkisp1_write(rkisp1, 0, rsz->config->rsz.phase_hc); - rkisp1_write(rkisp1, 0, rsz->config->rsz.phase_vy); - rkisp1_write(rkisp1, 0, rsz->config->rsz.phase_vc); - - /* Linear interpolation */ - for (i = 0; i < 64; i++) { - rkisp1_write(rkisp1, i, rsz->config->rsz.scale_lut_addr); - rkisp1_write(rkisp1, i, rsz->config->rsz.scale_lut); - } - - if (sink_y->width != src_y->width) { - rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_HY_ENABLE; - if (sink_y->width < src_y->width) - rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_HY_UP; - ratio = rkisp1_rsz_calc_ratio(sink_y->width, src_y->width); - rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_hy); - } - - if (sink_c->width != src_c->width) { - rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_HC_ENABLE; - if (sink_c->width < src_c->width) - rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_HC_UP; - ratio = rkisp1_rsz_calc_ratio(sink_c->width, src_c->width); - rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_hcb); - rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_hcr); - } - - if (sink_y->height != src_y->height) { - rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_VY_ENABLE; - if (sink_y->height < src_y->height) - rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_VY_UP; - ratio = rkisp1_rsz_calc_ratio(sink_y->height, src_y->height); - rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_vy); - } - - if (sink_c->height != src_c->height) { - rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_VC_ENABLE; - if (sink_c->height < src_c->height) - rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_VC_UP; - ratio = rkisp1_rsz_calc_ratio(sink_c->height, src_c->height); - rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_vc); - } - - rkisp1_write(rkisp1, rsz_ctrl, rsz->config->rsz.ctrl); - - rkisp1_rsz_update_shadow(rsz, when); -} - -static void rkisp1_rsz_config(struct rkisp1_resizer *rsz, - enum rkisp1_shadow_regs_when when) -{ - const struct rkisp1_rsz_yuv_mbus_info *sink_yuv_info, *src_yuv_info; - struct v4l2_rect sink_y, sink_c, src_y, src_c; - struct v4l2_mbus_framefmt *src_fmt, *sink_fmt; - struct v4l2_rect *sink_crop; - - sink_crop = rkisp1_rsz_get_pad_crop(rsz, NULL, RKISP1_RSZ_PAD_SINK, - V4L2_SUBDEV_FORMAT_ACTIVE); - src_fmt = rkisp1_rsz_get_pad_fmt(rsz, NULL, RKISP1_RSZ_PAD_SRC, - V4L2_SUBDEV_FORMAT_ACTIVE); - src_yuv_info = rkisp1_rsz_get_yuv_mbus_info(src_fmt->code); - sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, NULL, RKISP1_RSZ_PAD_SINK, - V4L2_SUBDEV_FORMAT_ACTIVE); - sink_yuv_info = rkisp1_rsz_get_yuv_mbus_info(sink_fmt->code); - - /* - * The resizer only works on yuv formats, - * so return if it is bayer format. - */ - if (rsz->pixel_enc == V4L2_PIXEL_ENC_BAYER) { - rkisp1_rsz_disable(rsz, when); - return; - } - - sink_y.width = sink_crop->width; - sink_y.height = sink_crop->height; - src_y.width = src_fmt->width; - src_y.height = src_fmt->height; - - sink_c.width = sink_y.width / sink_yuv_info->hdiv; - sink_c.height = sink_y.height / sink_yuv_info->vdiv; - - /* - * The resizer is used not only to change the dimensions of the frame - * but also to change the scale for YUV formats, - * (4:2:2 -> 4:2:0 for example). So the width/height of the CbCr - * streams should be set according to the media bus format in the src pad. - */ - src_c.width = src_y.width / src_yuv_info->hdiv; - src_c.height = src_y.height / src_yuv_info->vdiv; - - if (sink_c.width == src_c.width && sink_c.height == src_c.height) { - rkisp1_rsz_disable(rsz, when); - return; - } - - dev_dbg(rsz->rkisp1->dev, "stream %d rsz/scale: %dx%d -> %dx%d\n", - rsz->id, sink_crop->width, sink_crop->height, - src_fmt->width, src_fmt->height); - dev_dbg(rsz->rkisp1->dev, "chroma scaling %dx%d -> %dx%d\n", - sink_c.width, sink_c.height, src_c.width, src_c.height); - - /* set values in the hw */ - rkisp1_rsz_config_regs(rsz, &sink_y, &sink_c, &src_y, &src_c, when); - - rkisp1_rsz_dump_regs(rsz); -} - -/* ---------------------------------------------------------------------------- - * Subdev pad operations - */ - -static int rkisp1_rsz_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - struct rkisp1_resizer *rsz = - container_of(sd, struct rkisp1_resizer, sd); - struct v4l2_subdev_pad_config dummy_cfg; - u32 pad = code->pad; - int ret; - - if (code->pad == RKISP1_RSZ_PAD_SRC) { - /* supported mbus codes on the src are the same as in the capture */ - struct rkisp1_capture *cap = &rsz->rkisp1->capture_devs[rsz->id]; - - return rkisp1_cap_enum_mbus_codes(cap, code); - } - - /* - * The selfpath capture doesn't support bayer formats. Therefore the selfpath resizer - * should support only YUV422 on the sink pad - */ - if (rsz->id == RKISP1_SELFPATH) { - if (code->index > 0) - return -EINVAL; - code->code = MEDIA_BUS_FMT_YUYV8_2X8; - return 0; - } - - /* supported mbus codes on the sink pad are the same as isp src pad */ - code->pad = RKISP1_ISP_PAD_SOURCE_VIDEO; - ret = v4l2_subdev_call(&rsz->rkisp1->isp.sd, pad, enum_mbus_code, - &dummy_cfg, code); - - /* restore pad */ - code->pad = pad; - code->flags = 0; - return ret; -} - -static int rkisp1_rsz_init_config(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg) -{ - struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; - struct v4l2_rect *sink_crop; - - sink_fmt = v4l2_subdev_get_try_format(sd, cfg, RKISP1_RSZ_PAD_SRC); - sink_fmt->width = RKISP1_DEFAULT_WIDTH; - sink_fmt->height = RKISP1_DEFAULT_HEIGHT; - sink_fmt->field = V4L2_FIELD_NONE; - sink_fmt->code = RKISP1_DEF_FMT; - - sink_crop = v4l2_subdev_get_try_crop(sd, cfg, RKISP1_RSZ_PAD_SINK); - sink_crop->width = RKISP1_DEFAULT_WIDTH; - sink_crop->height = RKISP1_DEFAULT_HEIGHT; - sink_crop->left = 0; - sink_crop->top = 0; - - src_fmt = v4l2_subdev_get_try_format(sd, cfg, RKISP1_RSZ_PAD_SINK); - *src_fmt = *sink_fmt; - - /* NOTE: there is no crop in the source pad, only in the sink */ - - return 0; -} - -static void rkisp1_rsz_set_src_fmt(struct rkisp1_resizer *rsz, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_mbus_framefmt *format, - unsigned int which) -{ - const struct rkisp1_isp_mbus_info *mbus_info; - struct v4l2_mbus_framefmt *src_fmt; - - src_fmt = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SRC, which); - mbus_info = rkisp1_isp_mbus_info_get(src_fmt->code); - - /* for YUV formats, userspace can change the mbus code on the src pad if it is supported */ - if (mbus_info->pixel_enc == V4L2_PIXEL_ENC_YUV && - rkisp1_rsz_get_yuv_mbus_info(format->code)) - src_fmt->code = format->code; - - src_fmt->width = clamp_t(u32, format->width, - rsz->config->min_rsz_width, - rsz->config->max_rsz_width); - src_fmt->height = clamp_t(u32, format->height, - rsz->config->min_rsz_height, - rsz->config->max_rsz_height); - - *format = *src_fmt; -} - -static void rkisp1_rsz_set_sink_crop(struct rkisp1_resizer *rsz, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_rect *r, - unsigned int which) -{ - const struct rkisp1_isp_mbus_info *mbus_info; - struct v4l2_mbus_framefmt *sink_fmt; - struct v4l2_rect *sink_crop; - - sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SINK, which); - sink_crop = rkisp1_rsz_get_pad_crop(rsz, cfg, RKISP1_RSZ_PAD_SINK, - which); - - /* Not crop for MP bayer raw data */ - mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); - - if (rsz->id == RKISP1_MAINPATH && - mbus_info->pixel_enc == V4L2_PIXEL_ENC_BAYER) { - sink_crop->left = 0; - sink_crop->top = 0; - sink_crop->width = sink_fmt->width; - sink_crop->height = sink_fmt->height; - - *r = *sink_crop; - return; - } - - sink_crop->left = ALIGN(r->left, 2); - sink_crop->width = ALIGN(r->width, 2); - sink_crop->top = r->top; - sink_crop->height = r->height; - rkisp1_sd_adjust_crop(sink_crop, sink_fmt); - - *r = *sink_crop; -} - -static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_mbus_framefmt *format, - unsigned int which) -{ - const struct rkisp1_isp_mbus_info *mbus_info; - struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; - struct v4l2_rect *sink_crop; - - sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SINK, which); - src_fmt = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SRC, which); - sink_crop = rkisp1_rsz_get_pad_crop(rsz, cfg, RKISP1_RSZ_PAD_SINK, - which); - if (rsz->id == RKISP1_SELFPATH) - sink_fmt->code = MEDIA_BUS_FMT_YUYV8_2X8; - else - sink_fmt->code = format->code; - - mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); - if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SRC)) { - sink_fmt->code = RKISP1_DEF_FMT; - mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); - } - if (which == V4L2_SUBDEV_FORMAT_ACTIVE) - rsz->pixel_enc = mbus_info->pixel_enc; - - /* Propagete to source pad */ - src_fmt->code = sink_fmt->code; - - sink_fmt->width = clamp_t(u32, format->width, - RKISP1_ISP_MIN_WIDTH, - RKISP1_ISP_MAX_WIDTH); - sink_fmt->height = clamp_t(u32, format->height, - RKISP1_ISP_MIN_HEIGHT, - RKISP1_ISP_MAX_HEIGHT); - - *format = *sink_fmt; - - /* Update sink crop */ - rkisp1_rsz_set_sink_crop(rsz, cfg, sink_crop, which); -} - -static int rkisp1_rsz_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct rkisp1_resizer *rsz = - container_of(sd, struct rkisp1_resizer, sd); - - mutex_lock(&rsz->ops_lock); - fmt->format = *rkisp1_rsz_get_pad_fmt(rsz, cfg, fmt->pad, fmt->which); - mutex_unlock(&rsz->ops_lock); - return 0; -} - -static int rkisp1_rsz_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct rkisp1_resizer *rsz = - container_of(sd, struct rkisp1_resizer, sd); - - mutex_lock(&rsz->ops_lock); - if (fmt->pad == RKISP1_RSZ_PAD_SINK) - rkisp1_rsz_set_sink_fmt(rsz, cfg, &fmt->format, fmt->which); - else - rkisp1_rsz_set_src_fmt(rsz, cfg, &fmt->format, fmt->which); - - mutex_unlock(&rsz->ops_lock); - return 0; -} - -static int rkisp1_rsz_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct rkisp1_resizer *rsz = - container_of(sd, struct rkisp1_resizer, sd); - struct v4l2_mbus_framefmt *mf_sink; - int ret = 0; - - if (sel->pad == RKISP1_RSZ_PAD_SRC) - return -EINVAL; - - mutex_lock(&rsz->ops_lock); - switch (sel->target) { - case V4L2_SEL_TGT_CROP_BOUNDS: - mf_sink = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SINK, - sel->which); - sel->r.height = mf_sink->height; - sel->r.width = mf_sink->width; - sel->r.left = 0; - sel->r.top = 0; - break; - case V4L2_SEL_TGT_CROP: - sel->r = *rkisp1_rsz_get_pad_crop(rsz, cfg, RKISP1_RSZ_PAD_SINK, - sel->which); - break; - default: - ret = -EINVAL; - } - - mutex_unlock(&rsz->ops_lock); - return ret; -} - -static int rkisp1_rsz_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct rkisp1_resizer *rsz = - container_of(sd, struct rkisp1_resizer, sd); - - if (sel->target != V4L2_SEL_TGT_CROP || sel->pad == RKISP1_RSZ_PAD_SRC) - return -EINVAL; - - dev_dbg(rsz->rkisp1->dev, "%s: pad: %d sel(%d,%d)/%dx%d\n", __func__, - sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height); - - mutex_lock(&rsz->ops_lock); - rkisp1_rsz_set_sink_crop(rsz, cfg, &sel->r, sel->which); - mutex_unlock(&rsz->ops_lock); - - return 0; -} - -static const struct media_entity_operations rkisp1_rsz_media_ops = { - .link_validate = v4l2_subdev_link_validate, -}; - -static const struct v4l2_subdev_pad_ops rkisp1_rsz_pad_ops = { - .enum_mbus_code = rkisp1_rsz_enum_mbus_code, - .get_selection = rkisp1_rsz_get_selection, - .set_selection = rkisp1_rsz_set_selection, - .init_cfg = rkisp1_rsz_init_config, - .get_fmt = rkisp1_rsz_get_fmt, - .set_fmt = rkisp1_rsz_set_fmt, - .link_validate = v4l2_subdev_link_validate_default, -}; - -/* ---------------------------------------------------------------------------- - * Stream operations - */ - -static int rkisp1_rsz_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct rkisp1_resizer *rsz = - container_of(sd, struct rkisp1_resizer, sd); - struct rkisp1_device *rkisp1 = rsz->rkisp1; - struct rkisp1_capture *other = &rkisp1->capture_devs[rsz->id ^ 1]; - enum rkisp1_shadow_regs_when when = RKISP1_SHADOW_REGS_SYNC; - - if (!enable) { - rkisp1_dcrop_disable(rsz, RKISP1_SHADOW_REGS_ASYNC); - rkisp1_rsz_disable(rsz, RKISP1_SHADOW_REGS_ASYNC); - return 0; - } - - if (other->is_streaming) - when = RKISP1_SHADOW_REGS_ASYNC; - - mutex_lock(&rsz->ops_lock); - rkisp1_rsz_config(rsz, when); - rkisp1_dcrop_config(rsz); - - mutex_unlock(&rsz->ops_lock); - return 0; -} - -static const struct v4l2_subdev_video_ops rkisp1_rsz_video_ops = { - .s_stream = rkisp1_rsz_s_stream, -}; - -static const struct v4l2_subdev_ops rkisp1_rsz_ops = { - .video = &rkisp1_rsz_video_ops, - .pad = &rkisp1_rsz_pad_ops, -}; - -static void rkisp1_rsz_unregister(struct rkisp1_resizer *rsz) -{ - v4l2_device_unregister_subdev(&rsz->sd); - media_entity_cleanup(&rsz->sd.entity); -} - -static int rkisp1_rsz_register(struct rkisp1_resizer *rsz) -{ - static const char * const dev_names[] = { - RKISP1_RSZ_MP_DEV_NAME, - RKISP1_RSZ_SP_DEV_NAME - }; - struct media_pad *pads = rsz->pads; - struct v4l2_subdev *sd = &rsz->sd; - int ret; - - if (rsz->id == RKISP1_SELFPATH) - rsz->config = &rkisp1_rsz_config_sp; - else - rsz->config = &rkisp1_rsz_config_mp; - - v4l2_subdev_init(sd, &rkisp1_rsz_ops); - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - sd->entity.ops = &rkisp1_rsz_media_ops; - sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER; - sd->owner = THIS_MODULE; - strscpy(sd->name, dev_names[rsz->id], sizeof(sd->name)); - - pads[RKISP1_RSZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK | - MEDIA_PAD_FL_MUST_CONNECT; - pads[RKISP1_RSZ_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE | - MEDIA_PAD_FL_MUST_CONNECT; - - rsz->pixel_enc = RKISP1_DEF_PIXEL_ENC; - - mutex_init(&rsz->ops_lock); - ret = media_entity_pads_init(&sd->entity, RKISP1_RSZ_PAD_MAX, pads); - if (ret) - return ret; - - ret = v4l2_device_register_subdev(&rsz->rkisp1->v4l2_dev, sd); - if (ret) { - dev_err(sd->dev, "Failed to register resizer subdev\n"); - goto err_cleanup_media_entity; - } - - rkisp1_rsz_init_config(sd, rsz->pad_cfg); - return 0; - -err_cleanup_media_entity: - media_entity_cleanup(&sd->entity); - - return ret; -} - -int rkisp1_resizer_devs_register(struct rkisp1_device *rkisp1) -{ - struct rkisp1_resizer *rsz; - unsigned int i, j; - int ret; - - for (i = 0; i < ARRAY_SIZE(rkisp1->resizer_devs); i++) { - rsz = &rkisp1->resizer_devs[i]; - rsz->rkisp1 = rkisp1; - rsz->id = i; - ret = rkisp1_rsz_register(rsz); - if (ret) - goto err_unreg_resizer_devs; - } - - return 0; - -err_unreg_resizer_devs: - for (j = 0; j < i; j++) { - rsz = &rkisp1->resizer_devs[j]; - rkisp1_rsz_unregister(rsz); - } - - return ret; -} - -void rkisp1_resizer_devs_unregister(struct rkisp1_device *rkisp1) -{ - struct rkisp1_resizer *mp = &rkisp1->resizer_devs[RKISP1_MAINPATH]; - struct rkisp1_resizer *sp = &rkisp1->resizer_devs[RKISP1_SELFPATH]; - - rkisp1_rsz_unregister(mp); - rkisp1_rsz_unregister(sp); -} diff --git a/drivers/staging/media/rkisp1/rkisp1-stats.c b/drivers/staging/media/rkisp1/rkisp1-stats.c deleted file mode 100644 index 3ddab8fa8f2d..000000000000 --- a/drivers/staging/media/rkisp1/rkisp1-stats.c +++ /dev/null @@ -1,415 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -/* - * Rockchip ISP1 Driver - Stats subdevice - * - * Copyright (C) 2017 Rockchip Electronics Co., Ltd. - */ - -#include -#include -#include -#include -#include /* for ISP statistics */ - -#include "rkisp1-common.h" - -#define RKISP1_STATS_DEV_NAME RKISP1_DRIVER_NAME "_stats" - -#define RKISP1_ISP_STATS_REQ_BUFS_MIN 2 -#define RKISP1_ISP_STATS_REQ_BUFS_MAX 8 - -static int rkisp1_stats_enum_fmt_meta_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct video_device *video = video_devdata(file); - struct rkisp1_stats *stats = video_get_drvdata(video); - - if (f->index > 0 || f->type != video->queue->type) - return -EINVAL; - - f->pixelformat = stats->vdev_fmt.fmt.meta.dataformat; - return 0; -} - -static int rkisp1_stats_g_fmt_meta_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct video_device *video = video_devdata(file); - struct rkisp1_stats *stats = video_get_drvdata(video); - struct v4l2_meta_format *meta = &f->fmt.meta; - - if (f->type != video->queue->type) - return -EINVAL; - - memset(meta, 0, sizeof(*meta)); - meta->dataformat = stats->vdev_fmt.fmt.meta.dataformat; - meta->buffersize = stats->vdev_fmt.fmt.meta.buffersize; - - return 0; -} - -static int rkisp1_stats_querycap(struct file *file, - void *priv, struct v4l2_capability *cap) -{ - struct video_device *vdev = video_devdata(file); - - strscpy(cap->driver, RKISP1_DRIVER_NAME, sizeof(cap->driver)); - strscpy(cap->card, vdev->name, sizeof(cap->card)); - strscpy(cap->bus_info, RKISP1_BUS_INFO, sizeof(cap->bus_info)); - - return 0; -} - -/* ISP video device IOCTLs */ -static const struct v4l2_ioctl_ops rkisp1_stats_ioctl = { - .vidioc_reqbufs = vb2_ioctl_reqbufs, - .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_create_bufs = vb2_ioctl_create_bufs, - .vidioc_qbuf = vb2_ioctl_qbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_prepare_buf = vb2_ioctl_prepare_buf, - .vidioc_expbuf = vb2_ioctl_expbuf, - .vidioc_streamon = vb2_ioctl_streamon, - .vidioc_streamoff = vb2_ioctl_streamoff, - .vidioc_enum_fmt_meta_cap = rkisp1_stats_enum_fmt_meta_cap, - .vidioc_g_fmt_meta_cap = rkisp1_stats_g_fmt_meta_cap, - .vidioc_s_fmt_meta_cap = rkisp1_stats_g_fmt_meta_cap, - .vidioc_try_fmt_meta_cap = rkisp1_stats_g_fmt_meta_cap, - .vidioc_querycap = rkisp1_stats_querycap, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -static const struct v4l2_file_operations rkisp1_stats_fops = { - .mmap = vb2_fop_mmap, - .unlocked_ioctl = video_ioctl2, - .poll = vb2_fop_poll, - .open = v4l2_fh_open, - .release = vb2_fop_release -}; - -static int rkisp1_stats_vb2_queue_setup(struct vb2_queue *vq, - unsigned int *num_buffers, - unsigned int *num_planes, - unsigned int sizes[], - struct device *alloc_devs[]) -{ - *num_planes = 1; - - *num_buffers = clamp_t(u32, *num_buffers, RKISP1_ISP_STATS_REQ_BUFS_MIN, - RKISP1_ISP_STATS_REQ_BUFS_MAX); - - sizes[0] = sizeof(struct rkisp1_stat_buffer); - - return 0; -} - -static void rkisp1_stats_vb2_buf_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct rkisp1_buffer *stats_buf = - container_of(vbuf, struct rkisp1_buffer, vb); - struct vb2_queue *vq = vb->vb2_queue; - struct rkisp1_stats *stats_dev = vq->drv_priv; - - stats_buf->vaddr = vb2_plane_vaddr(vb, 0); - - spin_lock_irq(&stats_dev->lock); - list_add_tail(&stats_buf->queue, &stats_dev->stat); - spin_unlock_irq(&stats_dev->lock); -} - -static int rkisp1_stats_vb2_buf_prepare(struct vb2_buffer *vb) -{ - if (vb2_plane_size(vb, 0) < sizeof(struct rkisp1_stat_buffer)) - return -EINVAL; - - vb2_set_plane_payload(vb, 0, sizeof(struct rkisp1_stat_buffer)); - - return 0; -} - -static void rkisp1_stats_vb2_stop_streaming(struct vb2_queue *vq) -{ - struct rkisp1_stats *stats = vq->drv_priv; - struct rkisp1_buffer *buf; - unsigned int i; - - spin_lock_irq(&stats->lock); - for (i = 0; i < RKISP1_ISP_STATS_REQ_BUFS_MAX; i++) { - if (list_empty(&stats->stat)) - break; - buf = list_first_entry(&stats->stat, - struct rkisp1_buffer, queue); - list_del(&buf->queue); - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); - } - spin_unlock_irq(&stats->lock); -} - -static const struct vb2_ops rkisp1_stats_vb2_ops = { - .queue_setup = rkisp1_stats_vb2_queue_setup, - .buf_queue = rkisp1_stats_vb2_buf_queue, - .buf_prepare = rkisp1_stats_vb2_buf_prepare, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, - .stop_streaming = rkisp1_stats_vb2_stop_streaming, -}; - -static int -rkisp1_stats_init_vb2_queue(struct vb2_queue *q, struct rkisp1_stats *stats) -{ - struct rkisp1_vdev_node *node; - - node = container_of(q, struct rkisp1_vdev_node, buf_queue); - - q->type = V4L2_BUF_TYPE_META_CAPTURE; - q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; - q->drv_priv = stats; - q->ops = &rkisp1_stats_vb2_ops; - q->mem_ops = &vb2_vmalloc_memops; - q->buf_struct_size = sizeof(struct rkisp1_buffer); - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->lock = &node->vlock; - - return vb2_queue_init(q); -} - -static void rkisp1_stats_get_awb_meas(struct rkisp1_stats *stats, - struct rkisp1_stat_buffer *pbuf) -{ - /* Protect against concurrent access from ISR? */ - struct rkisp1_device *rkisp1 = stats->rkisp1; - u32 reg_val; - - pbuf->meas_type |= RKISP1_CIF_ISP_STAT_AWB; - reg_val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AWB_WHITE_CNT); - pbuf->params.awb.awb_mean[0].cnt = - RKISP1_CIF_ISP_AWB_GET_PIXEL_CNT(reg_val); - reg_val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AWB_MEAN); - - pbuf->params.awb.awb_mean[0].mean_cr_or_r = - RKISP1_CIF_ISP_AWB_GET_MEAN_CR_R(reg_val); - pbuf->params.awb.awb_mean[0].mean_cb_or_b = - RKISP1_CIF_ISP_AWB_GET_MEAN_CB_B(reg_val); - pbuf->params.awb.awb_mean[0].mean_y_or_g = - RKISP1_CIF_ISP_AWB_GET_MEAN_Y_G(reg_val); -} - -static void rkisp1_stats_get_aec_meas(struct rkisp1_stats *stats, - struct rkisp1_stat_buffer *pbuf) -{ - struct rkisp1_device *rkisp1 = stats->rkisp1; - unsigned int i; - - pbuf->meas_type |= RKISP1_CIF_ISP_STAT_AUTOEXP; - for (i = 0; i < RKISP1_CIF_ISP_AE_MEAN_MAX; i++) - pbuf->params.ae.exp_mean[i] = - (u8)rkisp1_read(rkisp1, - RKISP1_CIF_ISP_EXP_MEAN_00 + i * 4); -} - -static void rkisp1_stats_get_afc_meas(struct rkisp1_stats *stats, - struct rkisp1_stat_buffer *pbuf) -{ - struct rkisp1_device *rkisp1 = stats->rkisp1; - struct rkisp1_cif_isp_af_stat *af; - - pbuf->meas_type |= RKISP1_CIF_ISP_STAT_AFM; - - af = &pbuf->params.af; - af->window[0].sum = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AFM_SUM_A); - af->window[0].lum = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AFM_LUM_A); - af->window[1].sum = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AFM_SUM_B); - af->window[1].lum = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AFM_LUM_B); - af->window[2].sum = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AFM_SUM_C); - af->window[2].lum = rkisp1_read(rkisp1, RKISP1_CIF_ISP_AFM_LUM_C); -} - -static void rkisp1_stats_get_hst_meas(struct rkisp1_stats *stats, - struct rkisp1_stat_buffer *pbuf) -{ - struct rkisp1_device *rkisp1 = stats->rkisp1; - unsigned int i; - - pbuf->meas_type |= RKISP1_CIF_ISP_STAT_HIST; - for (i = 0; i < RKISP1_CIF_ISP_HIST_BIN_N_MAX; i++) - pbuf->params.hist.hist_bins[i] = - (u8)rkisp1_read(rkisp1, - RKISP1_CIF_ISP_HIST_BIN_0 + i * 4); -} - -static void rkisp1_stats_get_bls_meas(struct rkisp1_stats *stats, - struct rkisp1_stat_buffer *pbuf) -{ - struct rkisp1_device *rkisp1 = stats->rkisp1; - const struct rkisp1_isp_mbus_info *in_fmt = rkisp1->isp.sink_fmt; - struct rkisp1_cif_isp_bls_meas_val *bls_val; - - bls_val = &pbuf->params.ae.bls_val; - if (in_fmt->bayer_pat == RKISP1_RAW_BGGR) { - bls_val->meas_b = - rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_A_MEASURED); - bls_val->meas_gb = - rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_B_MEASURED); - bls_val->meas_gr = - rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_C_MEASURED); - bls_val->meas_r = - rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_D_MEASURED); - } else if (in_fmt->bayer_pat == RKISP1_RAW_GBRG) { - bls_val->meas_gb = - rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_A_MEASURED); - bls_val->meas_b = - rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_B_MEASURED); - bls_val->meas_r = - rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_C_MEASURED); - bls_val->meas_gr = - rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_D_MEASURED); - } else if (in_fmt->bayer_pat == RKISP1_RAW_GRBG) { - bls_val->meas_gr = - rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_A_MEASURED); - bls_val->meas_r = - rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_B_MEASURED); - bls_val->meas_b = - rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_C_MEASURED); - bls_val->meas_gb = - rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_D_MEASURED); - } else if (in_fmt->bayer_pat == RKISP1_RAW_RGGB) { - bls_val->meas_r = - rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_A_MEASURED); - bls_val->meas_gr = - rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_B_MEASURED); - bls_val->meas_gb = - rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_C_MEASURED); - bls_val->meas_b = - rkisp1_read(rkisp1, RKISP1_CIF_ISP_BLS_D_MEASURED); - } -} - -static void -rkisp1_stats_send_measurement(struct rkisp1_stats *stats, u32 isp_ris) -{ - struct rkisp1_stat_buffer *cur_stat_buf; - struct rkisp1_buffer *cur_buf = NULL; - unsigned int frame_sequence = stats->rkisp1->isp.frame_sequence; - u64 timestamp = ktime_get_ns(); - - /* get one empty buffer */ - if (!list_empty(&stats->stat)) { - cur_buf = list_first_entry(&stats->stat, - struct rkisp1_buffer, queue); - list_del(&cur_buf->queue); - } - - if (!cur_buf) - return; - - cur_stat_buf = - (struct rkisp1_stat_buffer *)(cur_buf->vaddr); - - if (isp_ris & RKISP1_CIF_ISP_AWB_DONE) - rkisp1_stats_get_awb_meas(stats, cur_stat_buf); - - if (isp_ris & RKISP1_CIF_ISP_AFM_FIN) - rkisp1_stats_get_afc_meas(stats, cur_stat_buf); - - if (isp_ris & RKISP1_CIF_ISP_EXP_END) { - rkisp1_stats_get_aec_meas(stats, cur_stat_buf); - rkisp1_stats_get_bls_meas(stats, cur_stat_buf); - } - - if (isp_ris & RKISP1_CIF_ISP_HIST_MEASURE_RDY) - rkisp1_stats_get_hst_meas(stats, cur_stat_buf); - - vb2_set_plane_payload(&cur_buf->vb.vb2_buf, 0, - sizeof(struct rkisp1_stat_buffer)); - cur_buf->vb.sequence = frame_sequence; - cur_buf->vb.vb2_buf.timestamp = timestamp; - vb2_buffer_done(&cur_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); -} - -void rkisp1_stats_isr(struct rkisp1_stats *stats, u32 isp_ris) -{ - struct rkisp1_device *rkisp1 = stats->rkisp1; - unsigned int isp_mis_tmp = 0; - - spin_lock(&stats->lock); - - rkisp1_write(rkisp1, RKISP1_STATS_MEAS_MASK, RKISP1_CIF_ISP_ICR); - - isp_mis_tmp = rkisp1_read(rkisp1, RKISP1_CIF_ISP_MIS); - if (isp_mis_tmp & RKISP1_STATS_MEAS_MASK) - rkisp1->debug.stats_error++; - - if (isp_ris & RKISP1_STATS_MEAS_MASK) - rkisp1_stats_send_measurement(stats, isp_ris); - - spin_unlock(&stats->lock); -} - -static void rkisp1_init_stats(struct rkisp1_stats *stats) -{ - stats->vdev_fmt.fmt.meta.dataformat = - V4L2_META_FMT_RK_ISP1_STAT_3A; - stats->vdev_fmt.fmt.meta.buffersize = - sizeof(struct rkisp1_stat_buffer); -} - -int rkisp1_stats_register(struct rkisp1_device *rkisp1) -{ - struct rkisp1_stats *stats = &rkisp1->stats; - struct rkisp1_vdev_node *node = &stats->vnode; - struct video_device *vdev = &node->vdev; - int ret; - - stats->rkisp1 = rkisp1; - mutex_init(&node->vlock); - INIT_LIST_HEAD(&stats->stat); - spin_lock_init(&stats->lock); - - strscpy(vdev->name, RKISP1_STATS_DEV_NAME, sizeof(vdev->name)); - - video_set_drvdata(vdev, stats); - vdev->ioctl_ops = &rkisp1_stats_ioctl; - vdev->fops = &rkisp1_stats_fops; - vdev->release = video_device_release_empty; - vdev->lock = &node->vlock; - vdev->v4l2_dev = &rkisp1->v4l2_dev; - vdev->queue = &node->buf_queue; - vdev->device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING; - vdev->vfl_dir = VFL_DIR_RX; - rkisp1_stats_init_vb2_queue(vdev->queue, stats); - rkisp1_init_stats(stats); - video_set_drvdata(vdev, stats); - - node->pad.flags = MEDIA_PAD_FL_SINK; - ret = media_entity_pads_init(&vdev->entity, 1, &node->pad); - if (ret) - goto err_mutex_destroy; - - ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); - if (ret) { - dev_err(&vdev->dev, - "failed to register %s, ret=%d\n", vdev->name, ret); - goto err_cleanup_media_entity; - } - - return 0; - -err_cleanup_media_entity: - media_entity_cleanup(&vdev->entity); -err_mutex_destroy: - mutex_destroy(&node->vlock); - return ret; -} - -void rkisp1_stats_unregister(struct rkisp1_device *rkisp1) -{ - struct rkisp1_stats *stats = &rkisp1->stats; - struct rkisp1_vdev_node *node = &stats->vnode; - struct video_device *vdev = &node->vdev; - - vb2_video_unregister_device(vdev); - media_entity_cleanup(&vdev->entity); - mutex_destroy(&node->vlock); -} diff --git a/drivers/staging/media/rkisp1/uapi/rkisp1-config.h b/drivers/staging/media/rkisp1/uapi/rkisp1-config.h deleted file mode 100644 index 6e449e784260..000000000000 --- a/drivers/staging/media/rkisp1/uapi/rkisp1-config.h +++ /dev/null @@ -1,884 +0,0 @@ -/* SPDX-License-Identifier: ((GPL-2.0+ WITH Linux-syscall-note) OR MIT) */ -/* - * Rockchip ISP1 userspace API - * Copyright (C) 2017 Rockchip Electronics Co., Ltd. - */ - -#ifndef _UAPI_RKISP1_CONFIG_H -#define _UAPI_RKISP1_CONFIG_H - -#include - -/* Defect Pixel Cluster Detection */ -#define RKISP1_CIF_ISP_MODULE_DPCC (1U << 0) -/* Black Level Subtraction */ -#define RKISP1_CIF_ISP_MODULE_BLS (1U << 1) -/* Sensor De-gamma */ -#define RKISP1_CIF_ISP_MODULE_SDG (1U << 2) -/* Histogram */ -#define RKISP1_CIF_ISP_MODULE_HST (1U << 3) -/* Lens Shade Control */ -#define RKISP1_CIF_ISP_MODULE_LSC (1U << 4) -/* Auto White Balance Gain */ -#define RKISP1_CIF_ISP_MODULE_AWB_GAIN (1U << 5) -/* Filter */ -#define RKISP1_CIF_ISP_MODULE_FLT (1U << 6) -/* Bayer Demosaic */ -#define RKISP1_CIF_ISP_MODULE_BDM (1U << 7) -/* Cross Talk */ -#define RKISP1_CIF_ISP_MODULE_CTK (1U << 8) -/* Gamma Out Curve */ -#define RKISP1_CIF_ISP_MODULE_GOC (1U << 9) -/* Color Processing */ -#define RKISP1_CIF_ISP_MODULE_CPROC (1U << 10) -/* Auto Focus Control */ -#define RKISP1_CIF_ISP_MODULE_AFC (1U << 11) -/* Auto White Balancing */ -#define RKISP1_CIF_ISP_MODULE_AWB (1U << 12) -/* Image Effect */ -#define RKISP1_CIF_ISP_MODULE_IE (1U << 13) -/* Auto Exposure Control */ -#define RKISP1_CIF_ISP_MODULE_AEC (1U << 14) -/* Wide Dynamic Range */ -#define RKISP1_CIF_ISP_MODULE_WDR (1U << 15) -/* Denoise Pre-Filter */ -#define RKISP1_CIF_ISP_MODULE_DPF (1U << 16) -/* Denoise Pre-Filter Strength */ -#define RKISP1_CIF_ISP_MODULE_DPF_STRENGTH (1U << 17) - -#define RKISP1_CIF_ISP_CTK_COEFF_MAX 0x100 -#define RKISP1_CIF_ISP_CTK_OFFSET_MAX 0x800 - -#define RKISP1_CIF_ISP_AE_MEAN_MAX 25 -#define RKISP1_CIF_ISP_HIST_BIN_N_MAX 16 -#define RKISP1_CIF_ISP_AFM_MAX_WINDOWS 3 -#define RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE 17 - -#define RKISP1_CIF_ISP_BDM_MAX_TH 0xff - -/* - * Black level compensation - */ -/* maximum value for horizontal start address */ -#define RKISP1_CIF_ISP_BLS_START_H_MAX 0x00000fff -/* maximum value for horizontal stop address */ -#define RKISP1_CIF_ISP_BLS_STOP_H_MAX 0x00000fff -/* maximum value for vertical start address */ -#define RKISP1_CIF_ISP_BLS_START_V_MAX 0x00000fff -/* maximum value for vertical stop address */ -#define RKISP1_CIF_ISP_BLS_STOP_V_MAX 0x00000fff -/* maximum is 2^18 = 262144*/ -#define RKISP1_CIF_ISP_BLS_SAMPLES_MAX 0x00000012 -/* maximum value for fixed black level */ -#define RKISP1_CIF_ISP_BLS_FIX_SUB_MAX 0x00000fff -/* minimum value for fixed black level */ -#define RKISP1_CIF_ISP_BLS_FIX_SUB_MIN 0xfffff000 -/* 13 bit range (signed)*/ -#define RKISP1_CIF_ISP_BLS_FIX_MASK 0x00001fff - -/* - * Automatic white balance measurements - */ -#define RKISP1_CIF_ISP_AWB_MAX_GRID 1 -#define RKISP1_CIF_ISP_AWB_MAX_FRAMES 7 - -/* - * Gamma out - */ -/* Maximum number of color samples supported */ -#define RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES 17 - -/* - * Lens shade correction - */ -#define RKISP1_CIF_ISP_LSC_SECTORS_TBL_SIZE 8 - -/* - * The following matches the tuning process, - * not the max capabilities of the chip. - */ -#define RKISP1_CIF_ISP_LSC_SAMPLES_MAX 17 - -/* - * Histogram calculation - */ -/* Last 3 values unused. */ -#define RKISP1_CIF_ISP_HISTOGRAM_WEIGHT_GRIDS_SIZE 28 - -/* - * Defect Pixel Cluster Correction - */ -#define RKISP1_CIF_ISP_DPCC_METHODS_MAX 3 - -/* - * Denoising pre filter - */ -#define RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS 17 -#define RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS 6 - -/* - * Measurement types - */ -#define RKISP1_CIF_ISP_STAT_AWB (1U << 0) -#define RKISP1_CIF_ISP_STAT_AUTOEXP (1U << 1) -#define RKISP1_CIF_ISP_STAT_AFM (1U << 2) -#define RKISP1_CIF_ISP_STAT_HIST (1U << 3) - -enum rkisp1_cif_isp_histogram_mode { - RKISP1_CIF_ISP_HISTOGRAM_MODE_DISABLE, - RKISP1_CIF_ISP_HISTOGRAM_MODE_RGB_COMBINED, - RKISP1_CIF_ISP_HISTOGRAM_MODE_R_HISTOGRAM, - RKISP1_CIF_ISP_HISTOGRAM_MODE_G_HISTOGRAM, - RKISP1_CIF_ISP_HISTOGRAM_MODE_B_HISTOGRAM, - RKISP1_CIF_ISP_HISTOGRAM_MODE_Y_HISTOGRAM -}; - -enum rkisp1_cif_isp_awb_mode_type { - RKISP1_CIF_ISP_AWB_MODE_MANUAL, - RKISP1_CIF_ISP_AWB_MODE_RGB, - RKISP1_CIF_ISP_AWB_MODE_YCBCR -}; - -enum rkisp1_cif_isp_flt_mode { - RKISP1_CIF_ISP_FLT_STATIC_MODE, - RKISP1_CIF_ISP_FLT_DYNAMIC_MODE -}; - -/** - * enum rkisp1_cif_isp_exp_ctrl_autostop - stop modes - * @RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP_0: continuous measurement - * @RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP_1: stop measuring after a complete frame - */ -enum rkisp1_cif_isp_exp_ctrl_autostop { - RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP_0 = 0, - RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP_1 = 1, -}; - -/** - * enum rkisp1_cif_isp_exp_meas_mode - Exposure measure mode - * @RKISP1_CIF_ISP_EXP_MEASURING_MODE_0: Y = 16 + 0.25R + 0.5G + 0.1094B - * @RKISP1_CIF_ISP_EXP_MEASURING_MODE_1: Y = (R + G + B) x (85/256) - */ -enum rkisp1_cif_isp_exp_meas_mode { - RKISP1_CIF_ISP_EXP_MEASURING_MODE_0, - RKISP1_CIF_ISP_EXP_MEASURING_MODE_1, -}; - -/*---------- PART1: Input Parameters ------------*/ - -/** - * struct rkisp1_cif_isp_window - measurement window. - * - * Measurements are calculated per window inside the frame. - * This struct represents a window for a measurement. - * - * @h_offs: the horizontal offset of the window from the left of the frame in pixels. - * @v_offs: the vertical offset of the window from the top of the frame in pixels. - * @h_size: the horizontal size of the window in pixels - * @v_size: the vertical size of the window in pixels. - */ -struct rkisp1_cif_isp_window { - __u16 h_offs; - __u16 v_offs; - __u16 h_size; - __u16 v_size; -}; - -/** - * struct rkisp1_cif_isp_bls_fixed_val - BLS fixed subtraction values - * - * The values will be subtracted from the sensor - * values. Therefore a negative value means addition instead of subtraction! - * - * @r: Fixed (signed!) subtraction value for Bayer pattern R - * @gr: Fixed (signed!) subtraction value for Bayer pattern Gr - * @gb: Fixed (signed!) subtraction value for Bayer pattern Gb - * @b: Fixed (signed!) subtraction value for Bayer pattern B - */ -struct rkisp1_cif_isp_bls_fixed_val { - __s16 r; - __s16 gr; - __s16 gb; - __s16 b; -}; - -/** - * struct rkisp1_cif_isp_bls_config - Configuration used by black level subtraction - * - * @enable_auto: Automatic mode activated means that the measured values - * are subtracted. Otherwise the fixed subtraction - * values will be subtracted. - * @en_windows: enabled window - * @bls_window1: Measurement window 1 size - * @bls_window2: Measurement window 2 size - * @bls_samples: Set amount of measured pixels for each Bayer position - * (A, B,C and D) to 2^bls_samples. - * @fixed_val: Fixed subtraction values - */ -struct rkisp1_cif_isp_bls_config { - __u8 enable_auto; - __u8 en_windows; - struct rkisp1_cif_isp_window bls_window1; - struct rkisp1_cif_isp_window bls_window2; - __u8 bls_samples; - struct rkisp1_cif_isp_bls_fixed_val fixed_val; -}; - -/** - * struct rkisp1_cif_isp_dpcc_methods_config - Methods Configuration used by DPCC - * - * Methods Configuration used by Defect Pixel Cluster Correction - * - * @method: Method enable bits - * @line_thresh: Line threshold - * @line_mad_fac: Line MAD factor - * @pg_fac: Peak gradient factor - * @rnd_thresh: Rank Neighbor Difference threshold - * @rg_fac: Rank gradient factor - */ -struct rkisp1_cif_isp_dpcc_methods_config { - __u32 method; - __u32 line_thresh; - __u32 line_mad_fac; - __u32 pg_fac; - __u32 rnd_thresh; - __u32 rg_fac; -}; - -/** - * struct rkisp1_cif_isp_dpcc_config - Configuration used by DPCC - * - * Configuration used by Defect Pixel Cluster Correction - * - * @mode: dpcc output mode - * @output_mode: whether use hard coded methods - * @set_use: stage1 methods set - * @methods: methods config - * @ro_limits: rank order limits - * @rnd_offs: differential rank offsets for rank neighbor difference - */ -struct rkisp1_cif_isp_dpcc_config { - __u32 mode; - __u32 output_mode; - __u32 set_use; - struct rkisp1_cif_isp_dpcc_methods_config methods[RKISP1_CIF_ISP_DPCC_METHODS_MAX]; - __u32 ro_limits; - __u32 rnd_offs; -}; - -/** - * struct rkisp1_cif_isp_gamma_corr_curve - gamma curve point definition y-axis (output). - * - * The reset values define a linear curve which has the same effect as bypass. Reset values are: - * gamma_y[0] = 0x0000, gamma_y[1] = 0x0100, ... gamma_y[15] = 0x0f00, gamma_y[16] = 0xfff - * - * @gamma_y: the values for the y-axis of gamma curve points. Each value is 12 bit. - */ -struct rkisp1_cif_isp_gamma_corr_curve { - __u16 gamma_y[RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE]; -}; - -/** - * struct rkisp1_cif_isp_gamma_curve_x_axis_pnts - De-Gamma Curve definition x increments - * (sampling points). gamma_dx0 is for the lower samples (1-8), gamma_dx1 is for the - * higher samples (9-16). The reset values for both fields is 0x44444444. This means - * that each sample is 4 units away from the previous one on the x-axis. - * - * @gamma_dx0: gamma curve sample points definitions. Bits 0:2 for sample 1. Bit 3 unused. - * Bits 4:6 for sample 2. bit 7 unused ... Bits 28:30 for sample 8. Bit 31 unused - * @gamma_dx1: gamma curve sample points definitions. Bits 0:2 for sample 9. Bit 3 unused. - * Bits 4:6 for sample 10. bit 7 unused ... Bits 28:30 for sample 16. Bit 31 unused - */ -struct rkisp1_cif_isp_gamma_curve_x_axis_pnts { - __u32 gamma_dx0; - __u32 gamma_dx1; -}; - -/** - * struct rkisp1_cif_isp_sdg_config - Configuration used by sensor degamma - * - * @curve_r: gamma curve point definition axis for red - * @curve_g: gamma curve point definition axis for green - * @curve_b: gamma curve point definition axis for blue - * @xa_pnts: x axis increments - */ -struct rkisp1_cif_isp_sdg_config { - struct rkisp1_cif_isp_gamma_corr_curve curve_r; - struct rkisp1_cif_isp_gamma_corr_curve curve_g; - struct rkisp1_cif_isp_gamma_corr_curve curve_b; - struct rkisp1_cif_isp_gamma_curve_x_axis_pnts xa_pnts; -}; - -/** - * struct rkisp1_cif_isp_lsc_config - Configuration used by Lens shading correction - * - * @r_data_tbl: sample table red - * @gr_data_tbl: sample table green (red) - * @gb_data_tbl: sample table green (blue) - * @b_data_tbl: sample table blue - * @x_grad_tbl: gradient table x - * @y_grad_tbl: gradient table y - * @x_size_tbl: size table x - * @y_size_tbl: size table y - * @config_width: not used at the moment - * @config_height: not used at the moment - */ -struct rkisp1_cif_isp_lsc_config { - __u16 r_data_tbl[RKISP1_CIF_ISP_LSC_SAMPLES_MAX][RKISP1_CIF_ISP_LSC_SAMPLES_MAX]; - __u16 gr_data_tbl[RKISP1_CIF_ISP_LSC_SAMPLES_MAX][RKISP1_CIF_ISP_LSC_SAMPLES_MAX]; - __u16 gb_data_tbl[RKISP1_CIF_ISP_LSC_SAMPLES_MAX][RKISP1_CIF_ISP_LSC_SAMPLES_MAX]; - __u16 b_data_tbl[RKISP1_CIF_ISP_LSC_SAMPLES_MAX][RKISP1_CIF_ISP_LSC_SAMPLES_MAX]; - - __u16 x_grad_tbl[RKISP1_CIF_ISP_LSC_SECTORS_TBL_SIZE]; - __u16 y_grad_tbl[RKISP1_CIF_ISP_LSC_SECTORS_TBL_SIZE]; - - __u16 x_size_tbl[RKISP1_CIF_ISP_LSC_SECTORS_TBL_SIZE]; - __u16 y_size_tbl[RKISP1_CIF_ISP_LSC_SECTORS_TBL_SIZE]; - __u16 config_width; - __u16 config_height; -}; - -/** - * struct rkisp1_cif_isp_ie_config - Configuration used by image effects - * - * @effect: values from 'enum v4l2_colorfx'. Possible values are: V4L2_COLORFX_SEPIA, - * V4L2_COLORFX_SET_CBCR, V4L2_COLORFX_AQUA, V4L2_COLORFX_EMBOSS, - * V4L2_COLORFX_SKETCH, V4L2_COLORFX_BW, V4L2_COLORFX_NEGATIVE - * @color_sel: bits 0:2 - colors bitmask (001 - blue, 010 - green, 100 - red). - * bits 8:15 - Threshold value of the RGB colors for the color selection effect. - * @eff_mat_1: 3x3 Matrix Coefficients for Emboss Effect 1 - * @eff_mat_2: 3x3 Matrix Coefficients for Emboss Effect 2 - * @eff_mat_3: 3x3 Matrix Coefficients for Emboss 3/Sketch 1 - * @eff_mat_4: 3x3 Matrix Coefficients for Sketch Effect 2 - * @eff_mat_5: 3x3 Matrix Coefficients for Sketch Effect 3 - * @eff_tint: Chrominance increment values of tint (used for sepia effect) - */ -struct rkisp1_cif_isp_ie_config { - __u16 effect; - __u16 color_sel; - __u16 eff_mat_1; - __u16 eff_mat_2; - __u16 eff_mat_3; - __u16 eff_mat_4; - __u16 eff_mat_5; - __u16 eff_tint; -}; - -/** - * struct rkisp1_cif_isp_cproc_config - Configuration used by Color Processing - * - * @c_out_range: Chrominance pixel clipping range at output. - * (0 for limit, 1 for full) - * @y_in_range: Luminance pixel clipping range at output. - * @y_out_range: Luminance pixel clipping range at output. - * @contrast: 00~ff, 0.0~1.992 - * @brightness: 80~7F, -128~+127 - * @sat: saturation, 00~FF, 0.0~1.992 - * @hue: 80~7F, -90~+87.188 - */ -struct rkisp1_cif_isp_cproc_config { - __u8 c_out_range; - __u8 y_in_range; - __u8 y_out_range; - __u8 contrast; - __u8 brightness; - __u8 sat; - __u8 hue; -}; - -/** - * struct rkisp1_cif_isp_awb_meas_config - Configuration used by auto white balance - * - * @awb_mode: the awb meas mode. From enum rkisp1_cif_isp_awb_mode_type. - * @awb_wnd: white balance measurement window (in pixels) - * @max_y: only pixels values < max_y contribute to awb measurement, set to 0 - * to disable this feature - * @min_y: only pixels values > min_y contribute to awb measurement - * @max_csum: Chrominance sum maximum value, only consider pixels with Cb+Cr, - * smaller than threshold for awb measurements - * @min_c: Chrominance minimum value, only consider pixels with Cb/Cr - * each greater than threshold value for awb measurements - * @frames: number of frames - 1 used for mean value calculation - * (ucFrames=0 means 1 Frame) - * @awb_ref_cr: reference Cr value for AWB regulation, target for AWB - * @awb_ref_cb: reference Cb value for AWB regulation, target for AWB - * @enable_ymax_cmp: enable Y_MAX compare (Not valid in RGB measurement mode.) - */ -struct rkisp1_cif_isp_awb_meas_config { - /* - * Note: currently the h and v offsets are mapped to grid offsets - */ - struct rkisp1_cif_isp_window awb_wnd; - __u32 awb_mode; - __u8 max_y; - __u8 min_y; - __u8 max_csum; - __u8 min_c; - __u8 frames; - __u8 awb_ref_cr; - __u8 awb_ref_cb; - __u8 enable_ymax_cmp; -}; - -/** - * struct rkisp1_cif_isp_awb_gain_config - Configuration used by auto white balance gain - * - * All fields in this struct are 10 bit, where: - * 0x100h = 1, unsigned integer value, range 0 to 4 with 8 bit fractional part. - * - * out_data_x = ( AWB_GAIN_X * in_data + 128) >> 8 - * - * @gain_red: gain value for red component. - * @gain_green_r: gain value for green component in red line. - * @gain_blue: gain value for blue component. - * @gain_green_b: gain value for green component in blue line. - */ -struct rkisp1_cif_isp_awb_gain_config { - __u16 gain_red; - __u16 gain_green_r; - __u16 gain_blue; - __u16 gain_green_b; -}; - -/** - * struct rkisp1_cif_isp_flt_config - Configuration used by ISP filtering - * - * All 4 threshold fields (thresh_*) are 10 bits. - * All 6 factor fields (fac_*) are 6 bits. - * - * @mode: ISP_FILT_MODE register fields (from enum rkisp1_cif_isp_flt_mode) - * @grn_stage1: Green filter stage 1 select (range 0x0...0x8) - * @chr_h_mode: Chroma filter horizontal mode - * @chr_v_mode: Chroma filter vertical mode - * @thresh_bl0: If thresh_bl1 < sum_grad < thresh_bl0 then fac_bl0 is selected (blurring th) - * @thresh_bl1: If sum_grad < thresh_bl1 then fac_bl1 is selected (blurring th) - * @thresh_sh0: If thresh_sh0 < sum_grad < thresh_sh1 then thresh_sh0 is selected (sharpening th) - * @thresh_sh1: If thresh_sh1 < sum_grad then thresh_sh1 is selected (sharpening th) - * @lum_weight: Parameters for luminance weight function. - * @fac_sh1: filter factor for sharp1 level - * @fac_sh0: filter factor for sharp0 level - * @fac_mid: filter factor for mid level and for static filter mode - * @fac_bl0: filter factor for blur 0 level - * @fac_bl1: filter factor for blur 1 level (max blur) - */ -struct rkisp1_cif_isp_flt_config { - __u32 mode; - __u8 grn_stage1; - __u8 chr_h_mode; - __u8 chr_v_mode; - __u32 thresh_bl0; - __u32 thresh_bl1; - __u32 thresh_sh0; - __u32 thresh_sh1; - __u32 lum_weight; - __u32 fac_sh1; - __u32 fac_sh0; - __u32 fac_mid; - __u32 fac_bl0; - __u32 fac_bl1; -}; - -/** - * struct rkisp1_cif_isp_bdm_config - Configuration used by Bayer DeMosaic - * - * @demosaic_th: threshold for bayer demosaicing texture detection - */ -struct rkisp1_cif_isp_bdm_config { - __u8 demosaic_th; -}; - -/** - * struct rkisp1_cif_isp_ctk_config - Configuration used by Cross Talk correction - * - * @coeff: color correction matrix. Values are 11-bit signed fixed-point numbers with 4 bit integer - * and 7 bit fractional part, ranging from -8 (0x400) to +7.992 (0x3FF). 0 is - * represented by 0x000 and a coefficient value of 1 as 0x080. - * @ct_offset: Red, Green, Blue offsets for the crosstalk correction matrix - */ -struct rkisp1_cif_isp_ctk_config { - __u16 coeff[3][3]; - __u16 ct_offset[3]; -}; - -enum rkisp1_cif_isp_goc_mode { - RKISP1_CIF_ISP_GOC_MODE_LOGARITHMIC, - RKISP1_CIF_ISP_GOC_MODE_EQUIDISTANT -}; - -/** - * struct rkisp1_cif_isp_goc_config - Configuration used by Gamma Out correction - * - * @mode: goc mode (from enum rkisp1_cif_isp_goc_mode) - * @gamma_y: gamma out curve y-axis for all color components - */ -struct rkisp1_cif_isp_goc_config { - __u32 mode; - __u16 gamma_y[RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES]; -}; - -/** - * struct rkisp1_cif_isp_hst_config - Configuration used by Histogram - * - * @mode: histogram mode (from enum rkisp1_cif_isp_histogram_mode) - * @histogram_predivider: process every stepsize pixel, all other pixels are - * skipped - * @meas_window: coordinates of the measure window - * @hist_weight: weighting factor for sub-windows - */ -struct rkisp1_cif_isp_hst_config { - __u32 mode; - __u8 histogram_predivider; - struct rkisp1_cif_isp_window meas_window; - __u8 hist_weight[RKISP1_CIF_ISP_HISTOGRAM_WEIGHT_GRIDS_SIZE]; -}; - -/** - * struct rkisp1_cif_isp_aec_config - Configuration used by Auto Exposure Control - * - * @mode: Exposure measure mode (from enum rkisp1_cif_isp_exp_meas_mode) - * @autostop: stop mode (from enum rkisp1_cif_isp_exp_ctrl_autostop) - * @meas_window: coordinates of the measure window - */ -struct rkisp1_cif_isp_aec_config { - __u32 mode; - __u32 autostop; - struct rkisp1_cif_isp_window meas_window; -}; - -/** - * struct rkisp1_cif_isp_afc_config - Configuration used by Auto Focus Control - * - * @num_afm_win: max RKISP1_CIF_ISP_AFM_MAX_WINDOWS - * @afm_win: coordinates of the meas window - * @thres: threshold used for minimizing the influence of noise - * @var_shift: the number of bits for the shift operation at the end of the - * calculation chain. - */ -struct rkisp1_cif_isp_afc_config { - __u8 num_afm_win; - struct rkisp1_cif_isp_window afm_win[RKISP1_CIF_ISP_AFM_MAX_WINDOWS]; - __u32 thres; - __u32 var_shift; -}; - -/** - * enum rkisp1_cif_isp_dpf_gain_usage - dpf gain usage - * @RKISP1_CIF_ISP_DPF_GAIN_USAGE_DISABLED: don't use any gains in preprocessing stage - * @RKISP1_CIF_ISP_DPF_GAIN_USAGE_NF_GAINS: use only the noise function gains from - * registers DPF_NF_GAIN_R, ... - * @RKISP1_CIF_ISP_DPF_GAIN_USAGE_LSC_GAINS: use only the gains from LSC module - * @RKISP1_CIF_ISP_DPF_GAIN_USAGE_NF_LSC_GAINS: use the noise function gains and the - * gains from LSC module - * @RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_GAINS: use only the gains from AWB module - * @RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_LSC_GAINS: use the gains from AWB and LSC module - * @RKISP1_CIF_ISP_DPF_GAIN_USAGE_MAX: upper border (only for an internal evaluation) - */ -enum rkisp1_cif_isp_dpf_gain_usage { - RKISP1_CIF_ISP_DPF_GAIN_USAGE_DISABLED, - RKISP1_CIF_ISP_DPF_GAIN_USAGE_NF_GAINS, - RKISP1_CIF_ISP_DPF_GAIN_USAGE_LSC_GAINS, - RKISP1_CIF_ISP_DPF_GAIN_USAGE_NF_LSC_GAINS, - RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_GAINS, - RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_LSC_GAINS, - RKISP1_CIF_ISP_DPF_GAIN_USAGE_MAX -}; - -/** - * enum rkisp1_cif_isp_dpf_rb_filtersize - Red and blue filter sizes - * @RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_13x9: red and blue filter kernel size 13x9 - * (means 7x5 active pixel) - * @RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_9x9: red and blue filter kernel size 9x9 - * (means 5x5 active pixel) - */ -enum rkisp1_cif_isp_dpf_rb_filtersize { - RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_13x9, - RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_9x9, -}; - -/** - * enum rkisp1_cif_isp_dpf_nll_scale_mode - dpf noise level scale mode - * @RKISP1_CIF_ISP_NLL_SCALE_LINEAR: use a linear scaling - * @RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC: use a logarithmic scaling - */ -enum rkisp1_cif_isp_dpf_nll_scale_mode { - RKISP1_CIF_ISP_NLL_SCALE_LINEAR, - RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC, -}; - -/** - * struct rkisp1_cif_isp_dpf_nll - Noise level lookup - * - * @coeff: Noise level Lookup coefficient - * @scale_mode: dpf noise level scale mode (from enum rkisp1_cif_isp_dpf_nll_scale_mode) - */ -struct rkisp1_cif_isp_dpf_nll { - __u16 coeff[RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS]; - __u32 scale_mode; -}; - -/** - * struct rkisp1_cif_isp_dpf_rb_flt - Red blue filter config - * - * @fltsize: The filter size for the red and blue pixels - * (from enum rkisp1_cif_isp_dpf_rb_filtersize) - * @spatial_coeff: Spatial weights - * @r_enable: enable filter processing for red pixels - * @b_enable: enable filter processing for blue pixels - */ -struct rkisp1_cif_isp_dpf_rb_flt { - __u32 fltsize; - __u8 spatial_coeff[RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS]; - __u8 r_enable; - __u8 b_enable; -}; - -/** - * struct rkisp1_cif_isp_dpf_g_flt - Green filter Configuration - * - * @spatial_coeff: Spatial weights - * @gr_enable: enable filter processing for green pixels in green/red lines - * @gb_enable: enable filter processing for green pixels in green/blue lines - */ -struct rkisp1_cif_isp_dpf_g_flt { - __u8 spatial_coeff[RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS]; - __u8 gr_enable; - __u8 gb_enable; -}; - -/** - * struct rkisp1_cif_isp_dpf_gain - Noise function Configuration - * - * @mode: dpf gain usage (from enum rkisp1_cif_isp_dpf_gain_usage) - * @nf_r_gain: Noise function Gain that replaces the AWB gain for red pixels - * @nf_b_gain: Noise function Gain that replaces the AWB gain for blue pixels - * @nf_gr_gain: Noise function Gain that replaces the AWB gain - * for green pixels in a red line - * @nf_gb_gain: Noise function Gain that replaces the AWB gain - * for green pixels in a blue line - */ -struct rkisp1_cif_isp_dpf_gain { - __u32 mode; - __u16 nf_r_gain; - __u16 nf_b_gain; - __u16 nf_gr_gain; - __u16 nf_gb_gain; -}; - -/** - * struct rkisp1_cif_isp_dpf_config - Configuration used by De-noising pre-filter - * - * @gain: noise function gain - * @g_flt: green filter config - * @rb_flt: red blue filter config - * @nll: noise level lookup - */ -struct rkisp1_cif_isp_dpf_config { - struct rkisp1_cif_isp_dpf_gain gain; - struct rkisp1_cif_isp_dpf_g_flt g_flt; - struct rkisp1_cif_isp_dpf_rb_flt rb_flt; - struct rkisp1_cif_isp_dpf_nll nll; -}; - -/** - * struct rkisp1_cif_isp_dpf_strength_config - strength of the filter - * - * @r: filter strength of the RED filter - * @g: filter strength of the GREEN filter - * @b: filter strength of the BLUE filter - */ -struct rkisp1_cif_isp_dpf_strength_config { - __u8 r; - __u8 g; - __u8 b; -}; - -/** - * struct rkisp1_cif_isp_isp_other_cfg - Parameters for some blocks in rockchip isp1 - * - * @dpcc_config: Defect Pixel Cluster Correction config - * @bls_config: Black Level Subtraction config - * @sdg_config: sensor degamma config - * @lsc_config: Lens Shade config - * @awb_gain_config: Auto White balance gain config - * @flt_config: filter config - * @bdm_config: demosaic config - * @ctk_config: cross talk config - * @goc_config: gamma out config - * @bls_config: black level subtraction config - * @dpf_config: De-noising pre-filter config - * @dpf_strength_config: dpf strength config - * @cproc_config: color process config - * @ie_config: image effects config - */ -struct rkisp1_cif_isp_isp_other_cfg { - struct rkisp1_cif_isp_dpcc_config dpcc_config; - struct rkisp1_cif_isp_bls_config bls_config; - struct rkisp1_cif_isp_sdg_config sdg_config; - struct rkisp1_cif_isp_lsc_config lsc_config; - struct rkisp1_cif_isp_awb_gain_config awb_gain_config; - struct rkisp1_cif_isp_flt_config flt_config; - struct rkisp1_cif_isp_bdm_config bdm_config; - struct rkisp1_cif_isp_ctk_config ctk_config; - struct rkisp1_cif_isp_goc_config goc_config; - struct rkisp1_cif_isp_dpf_config dpf_config; - struct rkisp1_cif_isp_dpf_strength_config dpf_strength_config; - struct rkisp1_cif_isp_cproc_config cproc_config; - struct rkisp1_cif_isp_ie_config ie_config; -}; - -/** - * struct rkisp1_cif_isp_isp_meas_cfg - Rockchip ISP1 Measure Parameters - * - * @awb_meas_config: auto white balance config - * @hst_config: histogram config - * @aec_config: auto exposure config - * @afc_config: auto focus config - */ -struct rkisp1_cif_isp_isp_meas_cfg { - struct rkisp1_cif_isp_awb_meas_config awb_meas_config; - struct rkisp1_cif_isp_hst_config hst_config; - struct rkisp1_cif_isp_aec_config aec_config; - struct rkisp1_cif_isp_afc_config afc_config; -}; - -/** - * struct rkisp1_params_cfg - Rockchip ISP1 Input Parameters Meta Data - * - * @module_en_update: mask the enable bits of which module should be updated - * @module_ens: mask the enable value of each module, only update the module - * which correspond bit was set in module_en_update - * @module_cfg_update: mask the config bits of which module should be updated - * @meas: measurement config - * @others: other config - */ -struct rkisp1_params_cfg { - __u32 module_en_update; - __u32 module_ens; - __u32 module_cfg_update; - - struct rkisp1_cif_isp_isp_meas_cfg meas; - struct rkisp1_cif_isp_isp_other_cfg others; -}; - -/*---------- PART2: Measurement Statistics ------------*/ - -/** - * struct rkisp1_cif_isp_awb_meas - AWB measured values - * - * @cnt: White pixel count, number of "white pixels" found during last - * measurement - * @mean_y_or_g: Mean value of Y within window and frames, - * Green if RGB is selected. - * @mean_cb_or_b: Mean value of Cb within window and frames, - * Blue if RGB is selected. - * @mean_cr_or_r: Mean value of Cr within window and frames, - * Red if RGB is selected. - */ -struct rkisp1_cif_isp_awb_meas { - __u32 cnt; - __u8 mean_y_or_g; - __u8 mean_cb_or_b; - __u8 mean_cr_or_r; -}; - -/** - * struct rkisp1_cif_isp_awb_stat - statistics automatic white balance data - * - * @awb_mean: Mean measured data - */ -struct rkisp1_cif_isp_awb_stat { - struct rkisp1_cif_isp_awb_meas awb_mean[RKISP1_CIF_ISP_AWB_MAX_GRID]; -}; - -/** - * struct rkisp1_cif_isp_bls_meas_val - BLS measured values - * - * @meas_r: Mean measured value for Bayer pattern R - * @meas_gr: Mean measured value for Bayer pattern Gr - * @meas_gb: Mean measured value for Bayer pattern Gb - * @meas_b: Mean measured value for Bayer pattern B - */ -struct rkisp1_cif_isp_bls_meas_val { - __u16 meas_r; - __u16 meas_gr; - __u16 meas_gb; - __u16 meas_b; -}; - -/** - * struct rkisp1_cif_isp_ae_stat - statistics auto exposure data - * - * @exp_mean: Mean luminance value of block xx - * @bls_val: BLS measured values - * - * Image is divided into 5x5 blocks. - */ -struct rkisp1_cif_isp_ae_stat { - __u8 exp_mean[RKISP1_CIF_ISP_AE_MEAN_MAX]; - struct rkisp1_cif_isp_bls_meas_val bls_val; -}; - -/** - * struct rkisp1_cif_isp_af_meas_val - AF measured values - * - * @sum: sharpness value - * @lum: luminance value - */ -struct rkisp1_cif_isp_af_meas_val { - __u32 sum; - __u32 lum; -}; - -/** - * struct rkisp1_cif_isp_af_stat - statistics auto focus data - * - * @window: AF measured value of window x - * - * The module measures the sharpness in 3 windows of selectable size via - * register settings(ISP_AFM_*_A/B/C) - */ -struct rkisp1_cif_isp_af_stat { - struct rkisp1_cif_isp_af_meas_val window[RKISP1_CIF_ISP_AFM_MAX_WINDOWS]; -}; - -/** - * struct rkisp1_cif_isp_hist_stat - statistics histogram data - * - * @hist_bins: measured bin counters - * - * Measurement window divided into 25 sub-windows, set - * with ISP_HIST_XXX - */ -struct rkisp1_cif_isp_hist_stat { - __u16 hist_bins[RKISP1_CIF_ISP_HIST_BIN_N_MAX]; -}; - -/** - * struct rkisp1_cif_isp_stat - Rockchip ISP1 Statistics Data - * - * @awb: statistics data for automatic white balance - * @ae: statistics data for auto exposure - * @af: statistics data for auto focus - * @hist: statistics histogram data - */ -struct rkisp1_cif_isp_stat { - struct rkisp1_cif_isp_awb_stat awb; - struct rkisp1_cif_isp_ae_stat ae; - struct rkisp1_cif_isp_af_stat af; - struct rkisp1_cif_isp_hist_stat hist; -}; - -/** - * struct rkisp1_stat_buffer - Rockchip ISP1 Statistics Meta Data - * - * @meas_type: measurement types (RKISP1_CIF_ISP_STAT_* definitions) - * @frame_id: frame ID for sync - * @params: statistics data - */ -struct rkisp1_stat_buffer { - __u32 meas_type; - __u32 frame_id; - struct rkisp1_cif_isp_stat params; -}; - -#endif /* _UAPI_RKISP1_CONFIG_H */ diff --git a/include/uapi/linux/rkisp1-config.h b/include/uapi/linux/rkisp1-config.h new file mode 100644 index 000000000000..6e449e784260 --- /dev/null +++ b/include/uapi/linux/rkisp1-config.h @@ -0,0 +1,884 @@ +/* SPDX-License-Identifier: ((GPL-2.0+ WITH Linux-syscall-note) OR MIT) */ +/* + * Rockchip ISP1 userspace API + * Copyright (C) 2017 Rockchip Electronics Co., Ltd. + */ + +#ifndef _UAPI_RKISP1_CONFIG_H +#define _UAPI_RKISP1_CONFIG_H + +#include + +/* Defect Pixel Cluster Detection */ +#define RKISP1_CIF_ISP_MODULE_DPCC (1U << 0) +/* Black Level Subtraction */ +#define RKISP1_CIF_ISP_MODULE_BLS (1U << 1) +/* Sensor De-gamma */ +#define RKISP1_CIF_ISP_MODULE_SDG (1U << 2) +/* Histogram */ +#define RKISP1_CIF_ISP_MODULE_HST (1U << 3) +/* Lens Shade Control */ +#define RKISP1_CIF_ISP_MODULE_LSC (1U << 4) +/* Auto White Balance Gain */ +#define RKISP1_CIF_ISP_MODULE_AWB_GAIN (1U << 5) +/* Filter */ +#define RKISP1_CIF_ISP_MODULE_FLT (1U << 6) +/* Bayer Demosaic */ +#define RKISP1_CIF_ISP_MODULE_BDM (1U << 7) +/* Cross Talk */ +#define RKISP1_CIF_ISP_MODULE_CTK (1U << 8) +/* Gamma Out Curve */ +#define RKISP1_CIF_ISP_MODULE_GOC (1U << 9) +/* Color Processing */ +#define RKISP1_CIF_ISP_MODULE_CPROC (1U << 10) +/* Auto Focus Control */ +#define RKISP1_CIF_ISP_MODULE_AFC (1U << 11) +/* Auto White Balancing */ +#define RKISP1_CIF_ISP_MODULE_AWB (1U << 12) +/* Image Effect */ +#define RKISP1_CIF_ISP_MODULE_IE (1U << 13) +/* Auto Exposure Control */ +#define RKISP1_CIF_ISP_MODULE_AEC (1U << 14) +/* Wide Dynamic Range */ +#define RKISP1_CIF_ISP_MODULE_WDR (1U << 15) +/* Denoise Pre-Filter */ +#define RKISP1_CIF_ISP_MODULE_DPF (1U << 16) +/* Denoise Pre-Filter Strength */ +#define RKISP1_CIF_ISP_MODULE_DPF_STRENGTH (1U << 17) + +#define RKISP1_CIF_ISP_CTK_COEFF_MAX 0x100 +#define RKISP1_CIF_ISP_CTK_OFFSET_MAX 0x800 + +#define RKISP1_CIF_ISP_AE_MEAN_MAX 25 +#define RKISP1_CIF_ISP_HIST_BIN_N_MAX 16 +#define RKISP1_CIF_ISP_AFM_MAX_WINDOWS 3 +#define RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE 17 + +#define RKISP1_CIF_ISP_BDM_MAX_TH 0xff + +/* + * Black level compensation + */ +/* maximum value for horizontal start address */ +#define RKISP1_CIF_ISP_BLS_START_H_MAX 0x00000fff +/* maximum value for horizontal stop address */ +#define RKISP1_CIF_ISP_BLS_STOP_H_MAX 0x00000fff +/* maximum value for vertical start address */ +#define RKISP1_CIF_ISP_BLS_START_V_MAX 0x00000fff +/* maximum value for vertical stop address */ +#define RKISP1_CIF_ISP_BLS_STOP_V_MAX 0x00000fff +/* maximum is 2^18 = 262144*/ +#define RKISP1_CIF_ISP_BLS_SAMPLES_MAX 0x00000012 +/* maximum value for fixed black level */ +#define RKISP1_CIF_ISP_BLS_FIX_SUB_MAX 0x00000fff +/* minimum value for fixed black level */ +#define RKISP1_CIF_ISP_BLS_FIX_SUB_MIN 0xfffff000 +/* 13 bit range (signed)*/ +#define RKISP1_CIF_ISP_BLS_FIX_MASK 0x00001fff + +/* + * Automatic white balance measurements + */ +#define RKISP1_CIF_ISP_AWB_MAX_GRID 1 +#define RKISP1_CIF_ISP_AWB_MAX_FRAMES 7 + +/* + * Gamma out + */ +/* Maximum number of color samples supported */ +#define RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES 17 + +/* + * Lens shade correction + */ +#define RKISP1_CIF_ISP_LSC_SECTORS_TBL_SIZE 8 + +/* + * The following matches the tuning process, + * not the max capabilities of the chip. + */ +#define RKISP1_CIF_ISP_LSC_SAMPLES_MAX 17 + +/* + * Histogram calculation + */ +/* Last 3 values unused. */ +#define RKISP1_CIF_ISP_HISTOGRAM_WEIGHT_GRIDS_SIZE 28 + +/* + * Defect Pixel Cluster Correction + */ +#define RKISP1_CIF_ISP_DPCC_METHODS_MAX 3 + +/* + * Denoising pre filter + */ +#define RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS 17 +#define RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS 6 + +/* + * Measurement types + */ +#define RKISP1_CIF_ISP_STAT_AWB (1U << 0) +#define RKISP1_CIF_ISP_STAT_AUTOEXP (1U << 1) +#define RKISP1_CIF_ISP_STAT_AFM (1U << 2) +#define RKISP1_CIF_ISP_STAT_HIST (1U << 3) + +enum rkisp1_cif_isp_histogram_mode { + RKISP1_CIF_ISP_HISTOGRAM_MODE_DISABLE, + RKISP1_CIF_ISP_HISTOGRAM_MODE_RGB_COMBINED, + RKISP1_CIF_ISP_HISTOGRAM_MODE_R_HISTOGRAM, + RKISP1_CIF_ISP_HISTOGRAM_MODE_G_HISTOGRAM, + RKISP1_CIF_ISP_HISTOGRAM_MODE_B_HISTOGRAM, + RKISP1_CIF_ISP_HISTOGRAM_MODE_Y_HISTOGRAM +}; + +enum rkisp1_cif_isp_awb_mode_type { + RKISP1_CIF_ISP_AWB_MODE_MANUAL, + RKISP1_CIF_ISP_AWB_MODE_RGB, + RKISP1_CIF_ISP_AWB_MODE_YCBCR +}; + +enum rkisp1_cif_isp_flt_mode { + RKISP1_CIF_ISP_FLT_STATIC_MODE, + RKISP1_CIF_ISP_FLT_DYNAMIC_MODE +}; + +/** + * enum rkisp1_cif_isp_exp_ctrl_autostop - stop modes + * @RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP_0: continuous measurement + * @RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP_1: stop measuring after a complete frame + */ +enum rkisp1_cif_isp_exp_ctrl_autostop { + RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP_0 = 0, + RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP_1 = 1, +}; + +/** + * enum rkisp1_cif_isp_exp_meas_mode - Exposure measure mode + * @RKISP1_CIF_ISP_EXP_MEASURING_MODE_0: Y = 16 + 0.25R + 0.5G + 0.1094B + * @RKISP1_CIF_ISP_EXP_MEASURING_MODE_1: Y = (R + G + B) x (85/256) + */ +enum rkisp1_cif_isp_exp_meas_mode { + RKISP1_CIF_ISP_EXP_MEASURING_MODE_0, + RKISP1_CIF_ISP_EXP_MEASURING_MODE_1, +}; + +/*---------- PART1: Input Parameters ------------*/ + +/** + * struct rkisp1_cif_isp_window - measurement window. + * + * Measurements are calculated per window inside the frame. + * This struct represents a window for a measurement. + * + * @h_offs: the horizontal offset of the window from the left of the frame in pixels. + * @v_offs: the vertical offset of the window from the top of the frame in pixels. + * @h_size: the horizontal size of the window in pixels + * @v_size: the vertical size of the window in pixels. + */ +struct rkisp1_cif_isp_window { + __u16 h_offs; + __u16 v_offs; + __u16 h_size; + __u16 v_size; +}; + +/** + * struct rkisp1_cif_isp_bls_fixed_val - BLS fixed subtraction values + * + * The values will be subtracted from the sensor + * values. Therefore a negative value means addition instead of subtraction! + * + * @r: Fixed (signed!) subtraction value for Bayer pattern R + * @gr: Fixed (signed!) subtraction value for Bayer pattern Gr + * @gb: Fixed (signed!) subtraction value for Bayer pattern Gb + * @b: Fixed (signed!) subtraction value for Bayer pattern B + */ +struct rkisp1_cif_isp_bls_fixed_val { + __s16 r; + __s16 gr; + __s16 gb; + __s16 b; +}; + +/** + * struct rkisp1_cif_isp_bls_config - Configuration used by black level subtraction + * + * @enable_auto: Automatic mode activated means that the measured values + * are subtracted. Otherwise the fixed subtraction + * values will be subtracted. + * @en_windows: enabled window + * @bls_window1: Measurement window 1 size + * @bls_window2: Measurement window 2 size + * @bls_samples: Set amount of measured pixels for each Bayer position + * (A, B,C and D) to 2^bls_samples. + * @fixed_val: Fixed subtraction values + */ +struct rkisp1_cif_isp_bls_config { + __u8 enable_auto; + __u8 en_windows; + struct rkisp1_cif_isp_window bls_window1; + struct rkisp1_cif_isp_window bls_window2; + __u8 bls_samples; + struct rkisp1_cif_isp_bls_fixed_val fixed_val; +}; + +/** + * struct rkisp1_cif_isp_dpcc_methods_config - Methods Configuration used by DPCC + * + * Methods Configuration used by Defect Pixel Cluster Correction + * + * @method: Method enable bits + * @line_thresh: Line threshold + * @line_mad_fac: Line MAD factor + * @pg_fac: Peak gradient factor + * @rnd_thresh: Rank Neighbor Difference threshold + * @rg_fac: Rank gradient factor + */ +struct rkisp1_cif_isp_dpcc_methods_config { + __u32 method; + __u32 line_thresh; + __u32 line_mad_fac; + __u32 pg_fac; + __u32 rnd_thresh; + __u32 rg_fac; +}; + +/** + * struct rkisp1_cif_isp_dpcc_config - Configuration used by DPCC + * + * Configuration used by Defect Pixel Cluster Correction + * + * @mode: dpcc output mode + * @output_mode: whether use hard coded methods + * @set_use: stage1 methods set + * @methods: methods config + * @ro_limits: rank order limits + * @rnd_offs: differential rank offsets for rank neighbor difference + */ +struct rkisp1_cif_isp_dpcc_config { + __u32 mode; + __u32 output_mode; + __u32 set_use; + struct rkisp1_cif_isp_dpcc_methods_config methods[RKISP1_CIF_ISP_DPCC_METHODS_MAX]; + __u32 ro_limits; + __u32 rnd_offs; +}; + +/** + * struct rkisp1_cif_isp_gamma_corr_curve - gamma curve point definition y-axis (output). + * + * The reset values define a linear curve which has the same effect as bypass. Reset values are: + * gamma_y[0] = 0x0000, gamma_y[1] = 0x0100, ... gamma_y[15] = 0x0f00, gamma_y[16] = 0xfff + * + * @gamma_y: the values for the y-axis of gamma curve points. Each value is 12 bit. + */ +struct rkisp1_cif_isp_gamma_corr_curve { + __u16 gamma_y[RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE]; +}; + +/** + * struct rkisp1_cif_isp_gamma_curve_x_axis_pnts - De-Gamma Curve definition x increments + * (sampling points). gamma_dx0 is for the lower samples (1-8), gamma_dx1 is for the + * higher samples (9-16). The reset values for both fields is 0x44444444. This means + * that each sample is 4 units away from the previous one on the x-axis. + * + * @gamma_dx0: gamma curve sample points definitions. Bits 0:2 for sample 1. Bit 3 unused. + * Bits 4:6 for sample 2. bit 7 unused ... Bits 28:30 for sample 8. Bit 31 unused + * @gamma_dx1: gamma curve sample points definitions. Bits 0:2 for sample 9. Bit 3 unused. + * Bits 4:6 for sample 10. bit 7 unused ... Bits 28:30 for sample 16. Bit 31 unused + */ +struct rkisp1_cif_isp_gamma_curve_x_axis_pnts { + __u32 gamma_dx0; + __u32 gamma_dx1; +}; + +/** + * struct rkisp1_cif_isp_sdg_config - Configuration used by sensor degamma + * + * @curve_r: gamma curve point definition axis for red + * @curve_g: gamma curve point definition axis for green + * @curve_b: gamma curve point definition axis for blue + * @xa_pnts: x axis increments + */ +struct rkisp1_cif_isp_sdg_config { + struct rkisp1_cif_isp_gamma_corr_curve curve_r; + struct rkisp1_cif_isp_gamma_corr_curve curve_g; + struct rkisp1_cif_isp_gamma_corr_curve curve_b; + struct rkisp1_cif_isp_gamma_curve_x_axis_pnts xa_pnts; +}; + +/** + * struct rkisp1_cif_isp_lsc_config - Configuration used by Lens shading correction + * + * @r_data_tbl: sample table red + * @gr_data_tbl: sample table green (red) + * @gb_data_tbl: sample table green (blue) + * @b_data_tbl: sample table blue + * @x_grad_tbl: gradient table x + * @y_grad_tbl: gradient table y + * @x_size_tbl: size table x + * @y_size_tbl: size table y + * @config_width: not used at the moment + * @config_height: not used at the moment + */ +struct rkisp1_cif_isp_lsc_config { + __u16 r_data_tbl[RKISP1_CIF_ISP_LSC_SAMPLES_MAX][RKISP1_CIF_ISP_LSC_SAMPLES_MAX]; + __u16 gr_data_tbl[RKISP1_CIF_ISP_LSC_SAMPLES_MAX][RKISP1_CIF_ISP_LSC_SAMPLES_MAX]; + __u16 gb_data_tbl[RKISP1_CIF_ISP_LSC_SAMPLES_MAX][RKISP1_CIF_ISP_LSC_SAMPLES_MAX]; + __u16 b_data_tbl[RKISP1_CIF_ISP_LSC_SAMPLES_MAX][RKISP1_CIF_ISP_LSC_SAMPLES_MAX]; + + __u16 x_grad_tbl[RKISP1_CIF_ISP_LSC_SECTORS_TBL_SIZE]; + __u16 y_grad_tbl[RKISP1_CIF_ISP_LSC_SECTORS_TBL_SIZE]; + + __u16 x_size_tbl[RKISP1_CIF_ISP_LSC_SECTORS_TBL_SIZE]; + __u16 y_size_tbl[RKISP1_CIF_ISP_LSC_SECTORS_TBL_SIZE]; + __u16 config_width; + __u16 config_height; +}; + +/** + * struct rkisp1_cif_isp_ie_config - Configuration used by image effects + * + * @effect: values from 'enum v4l2_colorfx'. Possible values are: V4L2_COLORFX_SEPIA, + * V4L2_COLORFX_SET_CBCR, V4L2_COLORFX_AQUA, V4L2_COLORFX_EMBOSS, + * V4L2_COLORFX_SKETCH, V4L2_COLORFX_BW, V4L2_COLORFX_NEGATIVE + * @color_sel: bits 0:2 - colors bitmask (001 - blue, 010 - green, 100 - red). + * bits 8:15 - Threshold value of the RGB colors for the color selection effect. + * @eff_mat_1: 3x3 Matrix Coefficients for Emboss Effect 1 + * @eff_mat_2: 3x3 Matrix Coefficients for Emboss Effect 2 + * @eff_mat_3: 3x3 Matrix Coefficients for Emboss 3/Sketch 1 + * @eff_mat_4: 3x3 Matrix Coefficients for Sketch Effect 2 + * @eff_mat_5: 3x3 Matrix Coefficients for Sketch Effect 3 + * @eff_tint: Chrominance increment values of tint (used for sepia effect) + */ +struct rkisp1_cif_isp_ie_config { + __u16 effect; + __u16 color_sel; + __u16 eff_mat_1; + __u16 eff_mat_2; + __u16 eff_mat_3; + __u16 eff_mat_4; + __u16 eff_mat_5; + __u16 eff_tint; +}; + +/** + * struct rkisp1_cif_isp_cproc_config - Configuration used by Color Processing + * + * @c_out_range: Chrominance pixel clipping range at output. + * (0 for limit, 1 for full) + * @y_in_range: Luminance pixel clipping range at output. + * @y_out_range: Luminance pixel clipping range at output. + * @contrast: 00~ff, 0.0~1.992 + * @brightness: 80~7F, -128~+127 + * @sat: saturation, 00~FF, 0.0~1.992 + * @hue: 80~7F, -90~+87.188 + */ +struct rkisp1_cif_isp_cproc_config { + __u8 c_out_range; + __u8 y_in_range; + __u8 y_out_range; + __u8 contrast; + __u8 brightness; + __u8 sat; + __u8 hue; +}; + +/** + * struct rkisp1_cif_isp_awb_meas_config - Configuration used by auto white balance + * + * @awb_mode: the awb meas mode. From enum rkisp1_cif_isp_awb_mode_type. + * @awb_wnd: white balance measurement window (in pixels) + * @max_y: only pixels values < max_y contribute to awb measurement, set to 0 + * to disable this feature + * @min_y: only pixels values > min_y contribute to awb measurement + * @max_csum: Chrominance sum maximum value, only consider pixels with Cb+Cr, + * smaller than threshold for awb measurements + * @min_c: Chrominance minimum value, only consider pixels with Cb/Cr + * each greater than threshold value for awb measurements + * @frames: number of frames - 1 used for mean value calculation + * (ucFrames=0 means 1 Frame) + * @awb_ref_cr: reference Cr value for AWB regulation, target for AWB + * @awb_ref_cb: reference Cb value for AWB regulation, target for AWB + * @enable_ymax_cmp: enable Y_MAX compare (Not valid in RGB measurement mode.) + */ +struct rkisp1_cif_isp_awb_meas_config { + /* + * Note: currently the h and v offsets are mapped to grid offsets + */ + struct rkisp1_cif_isp_window awb_wnd; + __u32 awb_mode; + __u8 max_y; + __u8 min_y; + __u8 max_csum; + __u8 min_c; + __u8 frames; + __u8 awb_ref_cr; + __u8 awb_ref_cb; + __u8 enable_ymax_cmp; +}; + +/** + * struct rkisp1_cif_isp_awb_gain_config - Configuration used by auto white balance gain + * + * All fields in this struct are 10 bit, where: + * 0x100h = 1, unsigned integer value, range 0 to 4 with 8 bit fractional part. + * + * out_data_x = ( AWB_GAIN_X * in_data + 128) >> 8 + * + * @gain_red: gain value for red component. + * @gain_green_r: gain value for green component in red line. + * @gain_blue: gain value for blue component. + * @gain_green_b: gain value for green component in blue line. + */ +struct rkisp1_cif_isp_awb_gain_config { + __u16 gain_red; + __u16 gain_green_r; + __u16 gain_blue; + __u16 gain_green_b; +}; + +/** + * struct rkisp1_cif_isp_flt_config - Configuration used by ISP filtering + * + * All 4 threshold fields (thresh_*) are 10 bits. + * All 6 factor fields (fac_*) are 6 bits. + * + * @mode: ISP_FILT_MODE register fields (from enum rkisp1_cif_isp_flt_mode) + * @grn_stage1: Green filter stage 1 select (range 0x0...0x8) + * @chr_h_mode: Chroma filter horizontal mode + * @chr_v_mode: Chroma filter vertical mode + * @thresh_bl0: If thresh_bl1 < sum_grad < thresh_bl0 then fac_bl0 is selected (blurring th) + * @thresh_bl1: If sum_grad < thresh_bl1 then fac_bl1 is selected (blurring th) + * @thresh_sh0: If thresh_sh0 < sum_grad < thresh_sh1 then thresh_sh0 is selected (sharpening th) + * @thresh_sh1: If thresh_sh1 < sum_grad then thresh_sh1 is selected (sharpening th) + * @lum_weight: Parameters for luminance weight function. + * @fac_sh1: filter factor for sharp1 level + * @fac_sh0: filter factor for sharp0 level + * @fac_mid: filter factor for mid level and for static filter mode + * @fac_bl0: filter factor for blur 0 level + * @fac_bl1: filter factor for blur 1 level (max blur) + */ +struct rkisp1_cif_isp_flt_config { + __u32 mode; + __u8 grn_stage1; + __u8 chr_h_mode; + __u8 chr_v_mode; + __u32 thresh_bl0; + __u32 thresh_bl1; + __u32 thresh_sh0; + __u32 thresh_sh1; + __u32 lum_weight; + __u32 fac_sh1; + __u32 fac_sh0; + __u32 fac_mid; + __u32 fac_bl0; + __u32 fac_bl1; +}; + +/** + * struct rkisp1_cif_isp_bdm_config - Configuration used by Bayer DeMosaic + * + * @demosaic_th: threshold for bayer demosaicing texture detection + */ +struct rkisp1_cif_isp_bdm_config { + __u8 demosaic_th; +}; + +/** + * struct rkisp1_cif_isp_ctk_config - Configuration used by Cross Talk correction + * + * @coeff: color correction matrix. Values are 11-bit signed fixed-point numbers with 4 bit integer + * and 7 bit fractional part, ranging from -8 (0x400) to +7.992 (0x3FF). 0 is + * represented by 0x000 and a coefficient value of 1 as 0x080. + * @ct_offset: Red, Green, Blue offsets for the crosstalk correction matrix + */ +struct rkisp1_cif_isp_ctk_config { + __u16 coeff[3][3]; + __u16 ct_offset[3]; +}; + +enum rkisp1_cif_isp_goc_mode { + RKISP1_CIF_ISP_GOC_MODE_LOGARITHMIC, + RKISP1_CIF_ISP_GOC_MODE_EQUIDISTANT +}; + +/** + * struct rkisp1_cif_isp_goc_config - Configuration used by Gamma Out correction + * + * @mode: goc mode (from enum rkisp1_cif_isp_goc_mode) + * @gamma_y: gamma out curve y-axis for all color components + */ +struct rkisp1_cif_isp_goc_config { + __u32 mode; + __u16 gamma_y[RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES]; +}; + +/** + * struct rkisp1_cif_isp_hst_config - Configuration used by Histogram + * + * @mode: histogram mode (from enum rkisp1_cif_isp_histogram_mode) + * @histogram_predivider: process every stepsize pixel, all other pixels are + * skipped + * @meas_window: coordinates of the measure window + * @hist_weight: weighting factor for sub-windows + */ +struct rkisp1_cif_isp_hst_config { + __u32 mode; + __u8 histogram_predivider; + struct rkisp1_cif_isp_window meas_window; + __u8 hist_weight[RKISP1_CIF_ISP_HISTOGRAM_WEIGHT_GRIDS_SIZE]; +}; + +/** + * struct rkisp1_cif_isp_aec_config - Configuration used by Auto Exposure Control + * + * @mode: Exposure measure mode (from enum rkisp1_cif_isp_exp_meas_mode) + * @autostop: stop mode (from enum rkisp1_cif_isp_exp_ctrl_autostop) + * @meas_window: coordinates of the measure window + */ +struct rkisp1_cif_isp_aec_config { + __u32 mode; + __u32 autostop; + struct rkisp1_cif_isp_window meas_window; +}; + +/** + * struct rkisp1_cif_isp_afc_config - Configuration used by Auto Focus Control + * + * @num_afm_win: max RKISP1_CIF_ISP_AFM_MAX_WINDOWS + * @afm_win: coordinates of the meas window + * @thres: threshold used for minimizing the influence of noise + * @var_shift: the number of bits for the shift operation at the end of the + * calculation chain. + */ +struct rkisp1_cif_isp_afc_config { + __u8 num_afm_win; + struct rkisp1_cif_isp_window afm_win[RKISP1_CIF_ISP_AFM_MAX_WINDOWS]; + __u32 thres; + __u32 var_shift; +}; + +/** + * enum rkisp1_cif_isp_dpf_gain_usage - dpf gain usage + * @RKISP1_CIF_ISP_DPF_GAIN_USAGE_DISABLED: don't use any gains in preprocessing stage + * @RKISP1_CIF_ISP_DPF_GAIN_USAGE_NF_GAINS: use only the noise function gains from + * registers DPF_NF_GAIN_R, ... + * @RKISP1_CIF_ISP_DPF_GAIN_USAGE_LSC_GAINS: use only the gains from LSC module + * @RKISP1_CIF_ISP_DPF_GAIN_USAGE_NF_LSC_GAINS: use the noise function gains and the + * gains from LSC module + * @RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_GAINS: use only the gains from AWB module + * @RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_LSC_GAINS: use the gains from AWB and LSC module + * @RKISP1_CIF_ISP_DPF_GAIN_USAGE_MAX: upper border (only for an internal evaluation) + */ +enum rkisp1_cif_isp_dpf_gain_usage { + RKISP1_CIF_ISP_DPF_GAIN_USAGE_DISABLED, + RKISP1_CIF_ISP_DPF_GAIN_USAGE_NF_GAINS, + RKISP1_CIF_ISP_DPF_GAIN_USAGE_LSC_GAINS, + RKISP1_CIF_ISP_DPF_GAIN_USAGE_NF_LSC_GAINS, + RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_GAINS, + RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_LSC_GAINS, + RKISP1_CIF_ISP_DPF_GAIN_USAGE_MAX +}; + +/** + * enum rkisp1_cif_isp_dpf_rb_filtersize - Red and blue filter sizes + * @RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_13x9: red and blue filter kernel size 13x9 + * (means 7x5 active pixel) + * @RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_9x9: red and blue filter kernel size 9x9 + * (means 5x5 active pixel) + */ +enum rkisp1_cif_isp_dpf_rb_filtersize { + RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_13x9, + RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_9x9, +}; + +/** + * enum rkisp1_cif_isp_dpf_nll_scale_mode - dpf noise level scale mode + * @RKISP1_CIF_ISP_NLL_SCALE_LINEAR: use a linear scaling + * @RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC: use a logarithmic scaling + */ +enum rkisp1_cif_isp_dpf_nll_scale_mode { + RKISP1_CIF_ISP_NLL_SCALE_LINEAR, + RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC, +}; + +/** + * struct rkisp1_cif_isp_dpf_nll - Noise level lookup + * + * @coeff: Noise level Lookup coefficient + * @scale_mode: dpf noise level scale mode (from enum rkisp1_cif_isp_dpf_nll_scale_mode) + */ +struct rkisp1_cif_isp_dpf_nll { + __u16 coeff[RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS]; + __u32 scale_mode; +}; + +/** + * struct rkisp1_cif_isp_dpf_rb_flt - Red blue filter config + * + * @fltsize: The filter size for the red and blue pixels + * (from enum rkisp1_cif_isp_dpf_rb_filtersize) + * @spatial_coeff: Spatial weights + * @r_enable: enable filter processing for red pixels + * @b_enable: enable filter processing for blue pixels + */ +struct rkisp1_cif_isp_dpf_rb_flt { + __u32 fltsize; + __u8 spatial_coeff[RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS]; + __u8 r_enable; + __u8 b_enable; +}; + +/** + * struct rkisp1_cif_isp_dpf_g_flt - Green filter Configuration + * + * @spatial_coeff: Spatial weights + * @gr_enable: enable filter processing for green pixels in green/red lines + * @gb_enable: enable filter processing for green pixels in green/blue lines + */ +struct rkisp1_cif_isp_dpf_g_flt { + __u8 spatial_coeff[RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS]; + __u8 gr_enable; + __u8 gb_enable; +}; + +/** + * struct rkisp1_cif_isp_dpf_gain - Noise function Configuration + * + * @mode: dpf gain usage (from enum rkisp1_cif_isp_dpf_gain_usage) + * @nf_r_gain: Noise function Gain that replaces the AWB gain for red pixels + * @nf_b_gain: Noise function Gain that replaces the AWB gain for blue pixels + * @nf_gr_gain: Noise function Gain that replaces the AWB gain + * for green pixels in a red line + * @nf_gb_gain: Noise function Gain that replaces the AWB gain + * for green pixels in a blue line + */ +struct rkisp1_cif_isp_dpf_gain { + __u32 mode; + __u16 nf_r_gain; + __u16 nf_b_gain; + __u16 nf_gr_gain; + __u16 nf_gb_gain; +}; + +/** + * struct rkisp1_cif_isp_dpf_config - Configuration used by De-noising pre-filter + * + * @gain: noise function gain + * @g_flt: green filter config + * @rb_flt: red blue filter config + * @nll: noise level lookup + */ +struct rkisp1_cif_isp_dpf_config { + struct rkisp1_cif_isp_dpf_gain gain; + struct rkisp1_cif_isp_dpf_g_flt g_flt; + struct rkisp1_cif_isp_dpf_rb_flt rb_flt; + struct rkisp1_cif_isp_dpf_nll nll; +}; + +/** + * struct rkisp1_cif_isp_dpf_strength_config - strength of the filter + * + * @r: filter strength of the RED filter + * @g: filter strength of the GREEN filter + * @b: filter strength of the BLUE filter + */ +struct rkisp1_cif_isp_dpf_strength_config { + __u8 r; + __u8 g; + __u8 b; +}; + +/** + * struct rkisp1_cif_isp_isp_other_cfg - Parameters for some blocks in rockchip isp1 + * + * @dpcc_config: Defect Pixel Cluster Correction config + * @bls_config: Black Level Subtraction config + * @sdg_config: sensor degamma config + * @lsc_config: Lens Shade config + * @awb_gain_config: Auto White balance gain config + * @flt_config: filter config + * @bdm_config: demosaic config + * @ctk_config: cross talk config + * @goc_config: gamma out config + * @bls_config: black level subtraction config + * @dpf_config: De-noising pre-filter config + * @dpf_strength_config: dpf strength config + * @cproc_config: color process config + * @ie_config: image effects config + */ +struct rkisp1_cif_isp_isp_other_cfg { + struct rkisp1_cif_isp_dpcc_config dpcc_config; + struct rkisp1_cif_isp_bls_config bls_config; + struct rkisp1_cif_isp_sdg_config sdg_config; + struct rkisp1_cif_isp_lsc_config lsc_config; + struct rkisp1_cif_isp_awb_gain_config awb_gain_config; + struct rkisp1_cif_isp_flt_config flt_config; + struct rkisp1_cif_isp_bdm_config bdm_config; + struct rkisp1_cif_isp_ctk_config ctk_config; + struct rkisp1_cif_isp_goc_config goc_config; + struct rkisp1_cif_isp_dpf_config dpf_config; + struct rkisp1_cif_isp_dpf_strength_config dpf_strength_config; + struct rkisp1_cif_isp_cproc_config cproc_config; + struct rkisp1_cif_isp_ie_config ie_config; +}; + +/** + * struct rkisp1_cif_isp_isp_meas_cfg - Rockchip ISP1 Measure Parameters + * + * @awb_meas_config: auto white balance config + * @hst_config: histogram config + * @aec_config: auto exposure config + * @afc_config: auto focus config + */ +struct rkisp1_cif_isp_isp_meas_cfg { + struct rkisp1_cif_isp_awb_meas_config awb_meas_config; + struct rkisp1_cif_isp_hst_config hst_config; + struct rkisp1_cif_isp_aec_config aec_config; + struct rkisp1_cif_isp_afc_config afc_config; +}; + +/** + * struct rkisp1_params_cfg - Rockchip ISP1 Input Parameters Meta Data + * + * @module_en_update: mask the enable bits of which module should be updated + * @module_ens: mask the enable value of each module, only update the module + * which correspond bit was set in module_en_update + * @module_cfg_update: mask the config bits of which module should be updated + * @meas: measurement config + * @others: other config + */ +struct rkisp1_params_cfg { + __u32 module_en_update; + __u32 module_ens; + __u32 module_cfg_update; + + struct rkisp1_cif_isp_isp_meas_cfg meas; + struct rkisp1_cif_isp_isp_other_cfg others; +}; + +/*---------- PART2: Measurement Statistics ------------*/ + +/** + * struct rkisp1_cif_isp_awb_meas - AWB measured values + * + * @cnt: White pixel count, number of "white pixels" found during last + * measurement + * @mean_y_or_g: Mean value of Y within window and frames, + * Green if RGB is selected. + * @mean_cb_or_b: Mean value of Cb within window and frames, + * Blue if RGB is selected. + * @mean_cr_or_r: Mean value of Cr within window and frames, + * Red if RGB is selected. + */ +struct rkisp1_cif_isp_awb_meas { + __u32 cnt; + __u8 mean_y_or_g; + __u8 mean_cb_or_b; + __u8 mean_cr_or_r; +}; + +/** + * struct rkisp1_cif_isp_awb_stat - statistics automatic white balance data + * + * @awb_mean: Mean measured data + */ +struct rkisp1_cif_isp_awb_stat { + struct rkisp1_cif_isp_awb_meas awb_mean[RKISP1_CIF_ISP_AWB_MAX_GRID]; +}; + +/** + * struct rkisp1_cif_isp_bls_meas_val - BLS measured values + * + * @meas_r: Mean measured value for Bayer pattern R + * @meas_gr: Mean measured value for Bayer pattern Gr + * @meas_gb: Mean measured value for Bayer pattern Gb + * @meas_b: Mean measured value for Bayer pattern B + */ +struct rkisp1_cif_isp_bls_meas_val { + __u16 meas_r; + __u16 meas_gr; + __u16 meas_gb; + __u16 meas_b; +}; + +/** + * struct rkisp1_cif_isp_ae_stat - statistics auto exposure data + * + * @exp_mean: Mean luminance value of block xx + * @bls_val: BLS measured values + * + * Image is divided into 5x5 blocks. + */ +struct rkisp1_cif_isp_ae_stat { + __u8 exp_mean[RKISP1_CIF_ISP_AE_MEAN_MAX]; + struct rkisp1_cif_isp_bls_meas_val bls_val; +}; + +/** + * struct rkisp1_cif_isp_af_meas_val - AF measured values + * + * @sum: sharpness value + * @lum: luminance value + */ +struct rkisp1_cif_isp_af_meas_val { + __u32 sum; + __u32 lum; +}; + +/** + * struct rkisp1_cif_isp_af_stat - statistics auto focus data + * + * @window: AF measured value of window x + * + * The module measures the sharpness in 3 windows of selectable size via + * register settings(ISP_AFM_*_A/B/C) + */ +struct rkisp1_cif_isp_af_stat { + struct rkisp1_cif_isp_af_meas_val window[RKISP1_CIF_ISP_AFM_MAX_WINDOWS]; +}; + +/** + * struct rkisp1_cif_isp_hist_stat - statistics histogram data + * + * @hist_bins: measured bin counters + * + * Measurement window divided into 25 sub-windows, set + * with ISP_HIST_XXX + */ +struct rkisp1_cif_isp_hist_stat { + __u16 hist_bins[RKISP1_CIF_ISP_HIST_BIN_N_MAX]; +}; + +/** + * struct rkisp1_cif_isp_stat - Rockchip ISP1 Statistics Data + * + * @awb: statistics data for automatic white balance + * @ae: statistics data for auto exposure + * @af: statistics data for auto focus + * @hist: statistics histogram data + */ +struct rkisp1_cif_isp_stat { + struct rkisp1_cif_isp_awb_stat awb; + struct rkisp1_cif_isp_ae_stat ae; + struct rkisp1_cif_isp_af_stat af; + struct rkisp1_cif_isp_hist_stat hist; +}; + +/** + * struct rkisp1_stat_buffer - Rockchip ISP1 Statistics Meta Data + * + * @meas_type: measurement types (RKISP1_CIF_ISP_STAT_* definitions) + * @frame_id: frame ID for sync + * @params: statistics data + */ +struct rkisp1_stat_buffer { + __u32 meas_type; + __u32 frame_id; + struct rkisp1_cif_isp_stat params; +}; + +#endif /* _UAPI_RKISP1_CONFIG_H */ -- cgit v1.2.3 From 273775eea8ad94bfdde3a82b96836e8ec34dbe08 Mon Sep 17 00:00:00 2001 From: Dikshita Agarwal Date: Tue, 3 Nov 2020 07:57:37 +0100 Subject: media: v4l2-ctrls: allow V4L2_CTRL_TYPE_BUTTON with request api remove check for V4L2_CTRL_TYPE_BUTTON from v4l2_ctrl_request_clone and v4l2_ctrl_request_setup(). Signed-off-by: Dikshita Agarwal Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index bd7f330c941c..ad47d00e28d6 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -3363,9 +3363,6 @@ static int v4l2_ctrl_request_clone(struct v4l2_ctrl_handler *hdl, /* Skip refs inherited from other devices */ if (ref->from_other_dev) continue; - /* And buttons */ - if (ctrl->type == V4L2_CTRL_TYPE_BUTTON) - continue; err = handler_new_ref(hdl, ctrl, &new_ref, false, true); if (err) break; @@ -4447,8 +4444,7 @@ int v4l2_ctrl_request_setup(struct media_request *req, * Skip if this control was already handled by a cluster. * Skip button controls and read-only controls. */ - if (ref->req_done || ctrl->type == V4L2_CTRL_TYPE_BUTTON || - (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)) + if (ref->req_done || (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)) continue; v4l2_ctrl_lock(master); -- cgit v1.2.3 From cf7f34777a5b4100a3a44ff95f3d949c62892bdd Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 10 Nov 2020 00:07:22 +0100 Subject: media: vim2m: Register video device after setting up internals Prevent NULL (or close to NULL) pointer dereference in various places by registering the video device only when the V4L2 m2m framework has been set up. Fixes: commit 96d8eab5d0a1 ("V4L/DVB: [v5,2/2] v4l: Add a mem-to-mem videobuf framework test device") Signed-off-by: Sakari Ailus Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/test-drivers/vim2m.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/media/test-drivers/vim2m.c b/drivers/media/test-drivers/vim2m.c index a776bb8e0e09..331a9053a0ed 100644 --- a/drivers/media/test-drivers/vim2m.c +++ b/drivers/media/test-drivers/vim2m.c @@ -1325,12 +1325,6 @@ static int vim2m_probe(struct platform_device *pdev) vfd->lock = &dev->dev_mutex; vfd->v4l2_dev = &dev->v4l2_dev; - ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); - if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); - goto error_v4l2; - } - video_set_drvdata(vfd, dev); v4l2_info(&dev->v4l2_dev, "Device registered as /dev/video%d\n", vfd->num); @@ -1345,6 +1339,12 @@ static int vim2m_probe(struct platform_device *pdev) goto error_dev; } + ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); + if (ret) { + v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); + goto error_m2m; + } + #ifdef CONFIG_MEDIA_CONTROLLER dev->mdev.dev = &pdev->dev; strscpy(dev->mdev.model, "vim2m", sizeof(dev->mdev.model)); @@ -1358,7 +1358,7 @@ static int vim2m_probe(struct platform_device *pdev) MEDIA_ENT_F_PROC_VIDEO_SCALER); if (ret) { v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n"); - goto error_dev; + goto error_v4l2; } ret = media_device_register(&dev->mdev); @@ -1373,11 +1373,13 @@ static int vim2m_probe(struct platform_device *pdev) error_m2m_mc: v4l2_m2m_unregister_media_controller(dev->m2m_dev); #endif -error_dev: +error_v4l2: video_unregister_device(&dev->vfd); /* vim2m_device_release called by video_unregister_device to release various objects */ return ret; -error_v4l2: +error_m2m: + v4l2_m2m_release(dev->m2m_dev); +error_dev: v4l2_device_unregister(&dev->v4l2_dev); error_free: kfree(dev); -- cgit v1.2.3 From 88c660840c7c78e7a041a88cb33492258b8dae73 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Tue, 10 Nov 2020 04:04:03 +0100 Subject: media: cx231xx: Use snd_card_free_when_closed() instead of snd_card_free(). cx231xx_close_extension and hence cx231xx_audio_fini() are called with the cx231xx device lock held, but snd_cx231xx_pcm_close() also grabs that mutex when closing the file on behalf of arecord. There seems to be no reason to wait for sound card resources to be released, so let the release be asynchronous. Tested with a Hauppauge 955Q (2040:b123) and Linux 5.9.6; the hang described in the bug no longer occurs and disconnecting the device correctly terminates arecord with ENODEV. Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=204087 Signed-off-by: Zebediah Figura Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-audio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c index de42db6f6ad1..9c71b32552df 100644 --- a/drivers/media/usb/cx231xx/cx231xx-audio.c +++ b/drivers/media/usb/cx231xx/cx231xx-audio.c @@ -670,7 +670,7 @@ static int cx231xx_audio_fini(struct cx231xx *dev) } if (dev->adev.sndcard) { - snd_card_free(dev->adev.sndcard); + snd_card_free_when_closed(dev->adev.sndcard); kfree(dev->adev.alt_max_pkt_size); dev->adev.sndcard = NULL; } -- cgit v1.2.3 From 23ffa0399c693246a7442b98d71265e92e827912 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 10 Nov 2020 09:10:51 +0100 Subject: media: saa7134: improve f->fmt.win.clips NULL check Fix this smatch error: saa7134-video.c:1286 saa7134_g_fmt_vid_overlay() error: we previously assumed 'f->fmt.win.clips' could be null (see line 1279) This is actually a false error since if f->fmt.win.clips is NULL, clipcount will be set to 0, so the clips array won't be touched, but it doesn't hurt to make this explicit in the code. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/saa7134-video.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index c24716f4ce23..0f9d6b9edb90 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -1276,8 +1276,10 @@ static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv, return -EINVAL; } f->fmt.win = dev->win; - if (!f->fmt.win.clips) - clipcount = 0; + if (!f->fmt.win.clips) { + f->fmt.win.clipcount = 0; + return 0; + } if (dev->nclips < clipcount) clipcount = dev->nclips; f->fmt.win.clipcount = clipcount; -- cgit v1.2.3 From dcdff74fa6bc00c32079d0bebd620764c26f2d89 Mon Sep 17 00:00:00 2001 From: Qinglang Miao Date: Wed, 11 Nov 2020 04:22:01 +0100 Subject: media: solo6x10: fix missing snd_card_free in error handling case Fix to goto snd_error in error handling case when fails to do snd_ctl_add, as done elsewhere in this function. Fixes: 28cae868cd24 ("[media] solo6x10: move out of staging into drivers/media/pci.") Reported-by: Hulk Robot Signed-off-by: Qinglang Miao Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/solo6x10/solo6x10-g723.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/solo6x10/solo6x10-g723.c b/drivers/media/pci/solo6x10/solo6x10-g723.c index 906ce86437ae..d137b94869d8 100644 --- a/drivers/media/pci/solo6x10/solo6x10-g723.c +++ b/drivers/media/pci/solo6x10/solo6x10-g723.c @@ -385,7 +385,7 @@ int solo_g723_init(struct solo_dev *solo_dev) ret = snd_ctl_add(card, snd_ctl_new1(&kctl, solo_dev)); if (ret < 0) - return ret; + goto snd_error; ret = solo_snd_pcm_init(solo_dev); if (ret < 0) -- cgit v1.2.3 From 9463e07df8e0f93931e32c6f415d3f82bda63f35 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Nov 2020 09:47:44 +0100 Subject: media: v4l2-compat-ioctl32.c: add missing #ifdef CONFIG_COMPAT_32BIT_TIMEs In two places time32 structures were defined, but they are not used if CONFIG_COMPAT_32BIT_TIME is not set. Put these two structs under #ifdef CONFIG_COMPAT_32BIT_TIME as well to clearly indicate that they are only used if that config option is set. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 58d29284db13..0ca75f6784c5 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -304,6 +304,7 @@ struct v4l2_buffer32 { __s32 request_fd; }; +#ifdef CONFIG_COMPAT_32BIT_TIME struct v4l2_buffer32_time32 { __u32 index; __u32 type; /* enum v4l2_buf_type */ @@ -326,6 +327,7 @@ struct v4l2_buffer32_time32 { __u32 reserved2; __s32 request_fd; }; +#endif static int get_v4l2_plane32(struct v4l2_plane *p64, struct v4l2_plane32 __user *p32, @@ -763,6 +765,7 @@ struct v4l2_event32 { __u32 reserved[8]; }; +#ifdef CONFIG_COMPAT_32BIT_TIME struct v4l2_event32_time32 { __u32 type; union { @@ -775,6 +778,7 @@ struct v4l2_event32_time32 { __u32 id; __u32 reserved[8]; }; +#endif static int put_v4l2_event32(struct v4l2_event *p64, struct v4l2_event32 __user *p32) @@ -849,13 +853,10 @@ static int put_v4l2_edid32(struct v4l2_edid *p64, #define VIDIOC_G_FMT32 _IOWR('V', 4, struct v4l2_format32) #define VIDIOC_S_FMT32 _IOWR('V', 5, struct v4l2_format32) #define VIDIOC_QUERYBUF32 _IOWR('V', 9, struct v4l2_buffer32) -#define VIDIOC_QUERYBUF32_TIME32 _IOWR('V', 9, struct v4l2_buffer32_time32) #define VIDIOC_G_FBUF32 _IOR ('V', 10, struct v4l2_framebuffer32) #define VIDIOC_S_FBUF32 _IOW ('V', 11, struct v4l2_framebuffer32) #define VIDIOC_QBUF32 _IOWR('V', 15, struct v4l2_buffer32) -#define VIDIOC_QBUF32_TIME32 _IOWR('V', 15, struct v4l2_buffer32_time32) #define VIDIOC_DQBUF32 _IOWR('V', 17, struct v4l2_buffer32) -#define VIDIOC_DQBUF32_TIME32 _IOWR('V', 17, struct v4l2_buffer32_time32) #define VIDIOC_ENUMSTD32 _IOWR('V', 25, struct v4l2_standard32) #define VIDIOC_ENUMINPUT32 _IOWR('V', 26, struct v4l2_input32) #define VIDIOC_G_EDID32 _IOWR('V', 40, struct v4l2_edid32) @@ -865,10 +866,18 @@ static int put_v4l2_edid32(struct v4l2_edid *p64, #define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32) #define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32) #define VIDIOC_DQEVENT32 _IOR ('V', 89, struct v4l2_event32) -#define VIDIOC_DQEVENT32_TIME32 _IOR ('V', 89, struct v4l2_event32_time32) #define VIDIOC_CREATE_BUFS32 _IOWR('V', 92, struct v4l2_create_buffers32) #define VIDIOC_PREPARE_BUF32 _IOWR('V', 93, struct v4l2_buffer32) -#define VIDIOC_PREPARE_BUF32_TIME32 _IOWR('V', 93, struct v4l2_buffer32_time32) + +#ifdef CONFIG_COMPAT_32BIT_TIME +#define VIDIOC_QUERYBUF32_TIME32 _IOWR('V', 9, struct v4l2_buffer32_time32) +#define VIDIOC_QBUF32_TIME32 _IOWR('V', 15, struct v4l2_buffer32_time32) +#define VIDIOC_DQBUF32_TIME32 _IOWR('V', 17, struct v4l2_buffer32_time32) +#ifdef CONFIG_X86_64 +#define VIDIOC_DQEVENT32_TIME32 _IOR ('V', 89, struct v4l2_event32_time32) +#endif +#define VIDIOC_PREPARE_BUF32_TIME32 _IOWR('V', 93, struct v4l2_buffer32_time32) +#endif unsigned int v4l2_compat_translate_cmd(unsigned int cmd) { @@ -1055,10 +1064,12 @@ int v4l2_compat_get_array_args(struct file *file, void *mbuf, } break; } +#ifdef CONFIG_COMPAT_32BIT_TIME case VIDIOC_QUERYBUF32_TIME32: case VIDIOC_QBUF32_TIME32: case VIDIOC_DQBUF32_TIME32: case VIDIOC_PREPARE_BUF32_TIME32: +#endif case VIDIOC_QUERYBUF32: case VIDIOC_QBUF32: case VIDIOC_DQBUF32: @@ -1145,10 +1156,12 @@ int v4l2_compat_put_array_args(struct file *file, void __user *user_ptr, } break; } +#ifdef CONFIG_COMPAT_32BIT_TIME case VIDIOC_QUERYBUF32_TIME32: case VIDIOC_QBUF32_TIME32: case VIDIOC_DQBUF32_TIME32: case VIDIOC_PREPARE_BUF32_TIME32: +#endif case VIDIOC_QUERYBUF32: case VIDIOC_QBUF32: case VIDIOC_DQBUF32: -- cgit v1.2.3 From a25ba1021a6275941c44c639ad76a83248182022 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 28 Oct 2020 16:55:20 +0100 Subject: media: ipu3-cio2: Use macros from mm.h There are few nice macros in mm.h, some of which we may use here. Signed-off-by: Andy Shevchenko Reviewed-by: Bingbu Cao Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/intel/ipu3/ipu3-cio2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index d060cfe473d8..4fc36b5a8090 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -194,9 +195,8 @@ static void cio2_fbpt_entry_init_buf(struct cio2_device *cio2, * 4095 (PAGE_SIZE - 1) means every single byte in the last page * is available for DMA transfer. */ - entry[1].second_entry.last_page_available_bytes = - (remaining & ~PAGE_MASK) ? - (remaining & ~PAGE_MASK) - 1 : PAGE_SIZE - 1; + remaining = offset_in_page(remaining) ?: PAGE_SIZE; + entry[1].second_entry.last_page_available_bytes = remaining - 1; /* Fill FBPT */ remaining = length; i = 0; -- cgit v1.2.3 From d3f863a63fe4332cfda6174dfd4d2532eca7faf0 Mon Sep 17 00:00:00 2001 From: Tianshu Qiu Date: Thu, 29 Oct 2020 03:59:01 +0100 Subject: media: i2c: Add ov9734 image sensor driver Add a v4l2 sub-device driver for the OminiVision ov9734 image sensor which can deliver maximum 720p image frames at 30 fps. This driver also add vertical blanking, exposure, test pattern, digital and analog gain control for the image sensor. Signed-off-by: Bingbu Cao Signed-off-by: Tianshu Qiu Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 8 + drivers/media/i2c/Kconfig | 14 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/ov9734.c | 1018 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1041 insertions(+) create mode 100644 drivers/media/i2c/ov9734.c diff --git a/MAINTAINERS b/MAINTAINERS index 352b8eaa21f7..20e4afc53bdb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12995,6 +12995,14 @@ T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/ov9650.txt F: drivers/media/i2c/ov9650.c +OMNIVISION OV9734 SENSOR DRIVER +M: Tianshu Qiu +R: Bingbu Cao +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: drivers/media/i2c/ov9734.c + ONENAND FLASH DRIVER M: Kyungmin Park L: linux-mtd@lists.infradead.org diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index c64326ca331c..369b6d859da5 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -1051,6 +1051,20 @@ config VIDEO_OV9650 This is a V4L2 sensor driver for the Omnivision OV9650 and OV9652 camera sensors. +config VIDEO_OV9734 + tristate "OmniVision OV9734 sensor support" + depends on VIDEO_V4L2 && I2C + depends on ACPI || COMPILE_TEST + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + select V4L2_FWNODE + help + This is a Video4Linux2 sensor driver for the OmniVision + OV9734 camera. + + To compile this driver as a module, choose M here: the + module's name is ov9734. + config VIDEO_OV13858 tristate "OmniVision OV13858 sensor support" depends on I2C && VIDEO_V4L2 diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index f0a77473979d..b448506ce503 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -83,6 +83,7 @@ obj-$(CONFIG_VIDEO_OV7740) += ov7740.o obj-$(CONFIG_VIDEO_OV8856) += ov8856.o obj-$(CONFIG_VIDEO_OV9640) += ov9640.o obj-$(CONFIG_VIDEO_OV9650) += ov9650.o +obj-$(CONFIG_VIDEO_OV9734) += ov9734.o obj-$(CONFIG_VIDEO_OV13858) += ov13858.o obj-$(CONFIG_VIDEO_MT9M001) += mt9m001.o obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o diff --git a/drivers/media/i2c/ov9734.c b/drivers/media/i2c/ov9734.c new file mode 100644 index 000000000000..4b9a2e9288e7 --- /dev/null +++ b/drivers/media/i2c/ov9734.c @@ -0,0 +1,1018 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2020 Intel Corporation. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OV9734_LINK_FREQ_180MHZ 180000000ULL +#define OV9734_SCLK 36000000LL +#define OV9734_MCLK 19200000 +/* ov9734 only support 1-lane mipi output */ +#define OV9734_DATA_LANES 1 +#define OV9734_RGB_DEPTH 10 + +#define OV9734_REG_CHIP_ID 0x300a +#define OV9734_CHIP_ID 0x9734 + +#define OV9734_REG_MODE_SELECT 0x0100 +#define OV9734_MODE_STANDBY 0x00 +#define OV9734_MODE_STREAMING 0x01 + +/* vertical-timings from sensor */ +#define OV9734_REG_VTS 0x380e +#define OV9734_VTS_30FPS 0x0322 +#define OV9734_VTS_30FPS_MIN 0x0322 +#define OV9734_VTS_MAX 0x7fff + +/* horizontal-timings from sensor */ +#define OV9734_REG_HTS 0x380c + +/* Exposure controls from sensor */ +#define OV9734_REG_EXPOSURE 0x3500 +#define OV9734_EXPOSURE_MIN 4 +#define OV9734_EXPOSURE_MAX_MARGIN 4 +#define OV9734_EXPOSURE_STEP 1 + +/* Analog gain controls from sensor */ +#define OV9734_REG_ANALOG_GAIN 0x350a +#define OV9734_ANAL_GAIN_MIN 16 +#define OV9734_ANAL_GAIN_MAX 248 +#define OV9734_ANAL_GAIN_STEP 1 + +/* Digital gain controls from sensor */ +#define OV9734_REG_MWB_R_GAIN 0x5180 +#define OV9734_REG_MWB_G_GAIN 0x5182 +#define OV9734_REG_MWB_B_GAIN 0x5184 +#define OV9734_DGTL_GAIN_MIN 256 +#define OV9734_DGTL_GAIN_MAX 1023 +#define OV9734_DGTL_GAIN_STEP 1 +#define OV9734_DGTL_GAIN_DEFAULT 256 + +/* Test Pattern Control */ +#define OV9734_REG_TEST_PATTERN 0x5080 +#define OV9734_TEST_PATTERN_ENABLE BIT(7) +#define OV9734_TEST_PATTERN_BAR_SHIFT 2 + +enum { + OV9734_LINK_FREQ_180MHZ_INDEX, +}; + +struct ov9734_reg { + u16 address; + u8 val; +}; + +struct ov9734_reg_list { + u32 num_of_regs; + const struct ov9734_reg *regs; +}; + +struct ov9734_link_freq_config { + const struct ov9734_reg_list reg_list; +}; + +struct ov9734_mode { + /* Frame width in pixels */ + u32 width; + + /* Frame height in pixels */ + u32 height; + + /* Horizontal timining size */ + u32 hts; + + /* Default vertical timining size */ + u32 vts_def; + + /* Min vertical timining size */ + u32 vts_min; + + /* Link frequency needed for this resolution */ + u32 link_freq_index; + + /* Sensor register settings for this resolution */ + const struct ov9734_reg_list reg_list; +}; + +static const struct ov9734_reg mipi_data_rate_360mbps[] = { + {0x3030, 0x19}, + {0x3080, 0x02}, + {0x3081, 0x4b}, + {0x3082, 0x04}, + {0x3083, 0x00}, + {0x3084, 0x02}, + {0x3085, 0x01}, + {0x3086, 0x01}, + {0x3089, 0x01}, + {0x308a, 0x00}, + {0x301e, 0x15}, + {0x3103, 0x01}, +}; + +static const struct ov9734_reg mode_1296x734_regs[] = { + {0x3001, 0x00}, + {0x3002, 0x00}, + {0x3007, 0x00}, + {0x3010, 0x00}, + {0x3011, 0x08}, + {0x3014, 0x22}, + {0x3600, 0x55}, + {0x3601, 0x02}, + {0x3605, 0x22}, + {0x3611, 0xe7}, + {0x3654, 0x10}, + {0x3655, 0x77}, + {0x3656, 0x77}, + {0x3657, 0x07}, + {0x3658, 0x22}, + {0x3659, 0x22}, + {0x365a, 0x02}, + {0x3784, 0x05}, + {0x3785, 0x55}, + {0x37c0, 0x07}, + {0x3800, 0x00}, + {0x3801, 0x04}, + {0x3802, 0x00}, + {0x3803, 0x04}, + {0x3804, 0x05}, + {0x3805, 0x0b}, + {0x3806, 0x02}, + {0x3807, 0xdb}, + {0x3808, 0x05}, + {0x3809, 0x00}, + {0x380a, 0x02}, + {0x380b, 0xd0}, + {0x380c, 0x05}, + {0x380d, 0xc6}, + {0x380e, 0x03}, + {0x380f, 0x22}, + {0x3810, 0x00}, + {0x3811, 0x04}, + {0x3812, 0x00}, + {0x3813, 0x04}, + {0x3816, 0x00}, + {0x3817, 0x00}, + {0x3818, 0x00}, + {0x3819, 0x04}, + {0x3820, 0x18}, + {0x3821, 0x00}, + {0x382c, 0x06}, + {0x3500, 0x00}, + {0x3501, 0x31}, + {0x3502, 0x00}, + {0x3503, 0x03}, + {0x3504, 0x00}, + {0x3505, 0x00}, + {0x3509, 0x10}, + {0x350a, 0x00}, + {0x350b, 0x40}, + {0x3d00, 0x00}, + {0x3d01, 0x00}, + {0x3d02, 0x00}, + {0x3d03, 0x00}, + {0x3d04, 0x00}, + {0x3d05, 0x00}, + {0x3d06, 0x00}, + {0x3d07, 0x00}, + {0x3d08, 0x00}, + {0x3d09, 0x00}, + {0x3d0a, 0x00}, + {0x3d0b, 0x00}, + {0x3d0c, 0x00}, + {0x3d0d, 0x00}, + {0x3d0e, 0x00}, + {0x3d0f, 0x00}, + {0x3d80, 0x00}, + {0x3d81, 0x00}, + {0x3d82, 0x38}, + {0x3d83, 0xa4}, + {0x3d84, 0x00}, + {0x3d85, 0x00}, + {0x3d86, 0x1f}, + {0x3d87, 0x03}, + {0x3d8b, 0x00}, + {0x3d8f, 0x00}, + {0x4001, 0xe0}, + {0x4009, 0x0b}, + {0x4300, 0x03}, + {0x4301, 0xff}, + {0x4304, 0x00}, + {0x4305, 0x00}, + {0x4309, 0x00}, + {0x4600, 0x00}, + {0x4601, 0x80}, + {0x4800, 0x00}, + {0x4805, 0x00}, + {0x4821, 0x50}, + {0x4823, 0x50}, + {0x4837, 0x2d}, + {0x4a00, 0x00}, + {0x4f00, 0x80}, + {0x4f01, 0x10}, + {0x4f02, 0x00}, + {0x4f03, 0x00}, + {0x4f04, 0x00}, + {0x4f05, 0x00}, + {0x4f06, 0x00}, + {0x4f07, 0x00}, + {0x4f08, 0x00}, + {0x4f09, 0x00}, + {0x5000, 0x2f}, + {0x500c, 0x00}, + {0x500d, 0x00}, + {0x500e, 0x00}, + {0x500f, 0x00}, + {0x5010, 0x00}, + {0x5011, 0x00}, + {0x5012, 0x00}, + {0x5013, 0x00}, + {0x5014, 0x00}, + {0x5015, 0x00}, + {0x5016, 0x00}, + {0x5017, 0x00}, + {0x5080, 0x00}, + {0x5180, 0x01}, + {0x5181, 0x00}, + {0x5182, 0x01}, + {0x5183, 0x00}, + {0x5184, 0x01}, + {0x5185, 0x00}, + {0x5708, 0x06}, + {0x380f, 0x2a}, + {0x5780, 0x3e}, + {0x5781, 0x0f}, + {0x5782, 0x44}, + {0x5783, 0x02}, + {0x5784, 0x01}, + {0x5785, 0x01}, + {0x5786, 0x00}, + {0x5787, 0x04}, + {0x5788, 0x02}, + {0x5789, 0x0f}, + {0x578a, 0xfd}, + {0x578b, 0xf5}, + {0x578c, 0xf5}, + {0x578d, 0x03}, + {0x578e, 0x08}, + {0x578f, 0x0c}, + {0x5790, 0x08}, + {0x5791, 0x04}, + {0x5792, 0x00}, + {0x5793, 0x52}, + {0x5794, 0xa3}, + {0x5000, 0x3f}, + {0x3801, 0x00}, + {0x3803, 0x00}, + {0x3805, 0x0f}, + {0x3807, 0xdf}, + {0x3809, 0x10}, + {0x380b, 0xde}, + {0x3811, 0x00}, + {0x3813, 0x01}, +}; + +static const char * const ov9734_test_pattern_menu[] = { + "Disabled", + "Standard Color Bar", + "Top-Bottom Darker Color Bar", + "Right-Left Darker Color Bar", + "Bottom-Top Darker Color Bar", +}; + +static const s64 link_freq_menu_items[] = { + OV9734_LINK_FREQ_180MHZ, +}; + +static const struct ov9734_link_freq_config link_freq_configs[] = { + [OV9734_LINK_FREQ_180MHZ_INDEX] = { + .reg_list = { + .num_of_regs = ARRAY_SIZE(mipi_data_rate_360mbps), + .regs = mipi_data_rate_360mbps, + } + }, +}; + +static const struct ov9734_mode supported_modes[] = { + { + .width = 1296, + .height = 734, + .hts = 0x5c6, + .vts_def = OV9734_VTS_30FPS, + .vts_min = OV9734_VTS_30FPS_MIN, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1296x734_regs), + .regs = mode_1296x734_regs, + }, + .link_freq_index = OV9734_LINK_FREQ_180MHZ_INDEX, + }, +}; + +struct ov9734 { + struct v4l2_subdev sd; + struct media_pad pad; + struct v4l2_ctrl_handler ctrl_handler; + + /* V4L2 Controls */ + struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *pixel_rate; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *exposure; + + /* Current mode */ + const struct ov9734_mode *cur_mode; + + /* To serialize asynchronus callbacks */ + struct mutex mutex; + + /* Streaming on/off */ + bool streaming; +}; + +static inline struct ov9734 *to_ov9734(struct v4l2_subdev *subdev) +{ + return container_of(subdev, struct ov9734, sd); +} + +static u64 to_pixel_rate(u32 f_index) +{ + u64 pixel_rate = link_freq_menu_items[f_index] * 2 * OV9734_DATA_LANES; + + do_div(pixel_rate, OV9734_RGB_DEPTH); + + return pixel_rate; +} + +static u64 to_pixels_per_line(u32 hts, u32 f_index) +{ + u64 ppl = hts * to_pixel_rate(f_index); + + do_div(ppl, OV9734_SCLK); + + return ppl; +} + +static int ov9734_read_reg(struct ov9734 *ov9734, u16 reg, u16 len, u32 *val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov9734->sd); + struct i2c_msg msgs[2]; + u8 addr_buf[2]; + u8 data_buf[4] = {0}; + int ret; + + if (len > sizeof(data_buf)) + return -EINVAL; + + put_unaligned_be16(reg, addr_buf); + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = sizeof(addr_buf); + msgs[0].buf = addr_buf; + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = &data_buf[sizeof(data_buf) - len]; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) + return ret < 0 ? ret : -EIO; + + *val = get_unaligned_be32(data_buf); + + return 0; +} + +static int ov9734_write_reg(struct ov9734 *ov9734, u16 reg, u16 len, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov9734->sd); + u8 buf[6]; + int ret = 0; + + if (len > 4) + return -EINVAL; + + put_unaligned_be16(reg, buf); + put_unaligned_be32(val << 8 * (4 - len), buf + 2); + + ret = i2c_master_send(client, buf, len + 2); + if (ret != len + 2) + return ret < 0 ? ret : -EIO; + + return 0; +} + +static int ov9734_write_reg_list(struct ov9734 *ov9734, + const struct ov9734_reg_list *r_list) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov9734->sd); + unsigned int i; + int ret; + + for (i = 0; i < r_list->num_of_regs; i++) { + ret = ov9734_write_reg(ov9734, r_list->regs[i].address, 1, + r_list->regs[i].val); + if (ret) { + dev_err_ratelimited(&client->dev, + "write reg 0x%4.4x return err = %d", + r_list->regs[i].address, ret); + return ret; + } + } + + return 0; +} + +static int ov9734_update_digital_gain(struct ov9734 *ov9734, u32 d_gain) +{ + int ret; + + ret = ov9734_write_reg(ov9734, OV9734_REG_MWB_R_GAIN, 2, d_gain); + if (ret) + return ret; + + ret = ov9734_write_reg(ov9734, OV9734_REG_MWB_G_GAIN, 2, d_gain); + if (ret) + return ret; + + return ov9734_write_reg(ov9734, OV9734_REG_MWB_B_GAIN, 2, d_gain); +} + +static int ov9734_test_pattern(struct ov9734 *ov9734, u32 pattern) +{ + if (pattern) + pattern = (pattern - 1) << OV9734_TEST_PATTERN_BAR_SHIFT | + OV9734_TEST_PATTERN_ENABLE; + + return ov9734_write_reg(ov9734, OV9734_REG_TEST_PATTERN, 1, pattern); +} + +static int ov9734_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov9734 *ov9734 = container_of(ctrl->handler, + struct ov9734, ctrl_handler); + struct i2c_client *client = v4l2_get_subdevdata(&ov9734->sd); + s64 exposure_max; + int ret = 0; + + /* Propagate change of current control to all related controls */ + if (ctrl->id == V4L2_CID_VBLANK) { + /* Update max exposure while meeting expected vblanking */ + exposure_max = ov9734->cur_mode->height + ctrl->val - + OV9734_EXPOSURE_MAX_MARGIN; + __v4l2_ctrl_modify_range(ov9734->exposure, + ov9734->exposure->minimum, + exposure_max, ov9734->exposure->step, + exposure_max); + } + + /* V4L2 controls values will be applied only when power is already up */ + if (!pm_runtime_get_if_in_use(&client->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_ANALOGUE_GAIN: + ret = ov9734_write_reg(ov9734, OV9734_REG_ANALOG_GAIN, + 2, ctrl->val); + break; + + case V4L2_CID_DIGITAL_GAIN: + ret = ov9734_update_digital_gain(ov9734, ctrl->val); + break; + + case V4L2_CID_EXPOSURE: + /* 4 least significant bits of expsoure are fractional part */ + ret = ov9734_write_reg(ov9734, OV9734_REG_EXPOSURE, + 3, ctrl->val << 4); + break; + + case V4L2_CID_VBLANK: + ret = ov9734_write_reg(ov9734, OV9734_REG_VTS, 2, + ov9734->cur_mode->height + ctrl->val); + break; + + case V4L2_CID_TEST_PATTERN: + ret = ov9734_test_pattern(ov9734, ctrl->val); + break; + + default: + ret = -EINVAL; + break; + } + + pm_runtime_put(&client->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops ov9734_ctrl_ops = { + .s_ctrl = ov9734_set_ctrl, +}; + +static int ov9734_init_controls(struct ov9734 *ov9734) +{ + struct v4l2_ctrl_handler *ctrl_hdlr; + const struct ov9734_mode *cur_mode; + s64 exposure_max, h_blank, pixel_rate; + u32 vblank_min, vblank_max, vblank_default; + int ret, size; + + ctrl_hdlr = &ov9734->ctrl_handler; + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8); + if (ret) + return ret; + + ctrl_hdlr->lock = &ov9734->mutex; + cur_mode = ov9734->cur_mode; + size = ARRAY_SIZE(link_freq_menu_items); + ov9734->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &ov9734_ctrl_ops, + V4L2_CID_LINK_FREQ, + size - 1, 0, + link_freq_menu_items); + if (ov9734->link_freq) + ov9734->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + pixel_rate = to_pixel_rate(OV9734_LINK_FREQ_180MHZ_INDEX); + ov9734->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov9734_ctrl_ops, + V4L2_CID_PIXEL_RATE, 0, + pixel_rate, 1, pixel_rate); + vblank_min = cur_mode->vts_min - cur_mode->height; + vblank_max = OV9734_VTS_MAX - cur_mode->height; + vblank_default = cur_mode->vts_def - cur_mode->height; + ov9734->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov9734_ctrl_ops, + V4L2_CID_VBLANK, vblank_min, + vblank_max, 1, vblank_default); + h_blank = to_pixels_per_line(cur_mode->hts, cur_mode->link_freq_index); + h_blank -= cur_mode->width; + ov9734->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov9734_ctrl_ops, + V4L2_CID_HBLANK, h_blank, h_blank, 1, + h_blank); + if (ov9734->hblank) + ov9734->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + v4l2_ctrl_new_std(ctrl_hdlr, &ov9734_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, + OV9734_ANAL_GAIN_MIN, OV9734_ANAL_GAIN_MAX, + OV9734_ANAL_GAIN_STEP, OV9734_ANAL_GAIN_MIN); + v4l2_ctrl_new_std(ctrl_hdlr, &ov9734_ctrl_ops, V4L2_CID_DIGITAL_GAIN, + OV9734_DGTL_GAIN_MIN, OV9734_DGTL_GAIN_MAX, + OV9734_DGTL_GAIN_STEP, OV9734_DGTL_GAIN_DEFAULT); + exposure_max = ov9734->cur_mode->vts_def - OV9734_EXPOSURE_MAX_MARGIN; + ov9734->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov9734_ctrl_ops, + V4L2_CID_EXPOSURE, + OV9734_EXPOSURE_MIN, exposure_max, + OV9734_EXPOSURE_STEP, + exposure_max); + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &ov9734_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov9734_test_pattern_menu) - 1, + 0, 0, ov9734_test_pattern_menu); + if (ctrl_hdlr->error) + return ctrl_hdlr->error; + + ov9734->sd.ctrl_handler = ctrl_hdlr; + + return 0; +} + +static void ov9734_update_pad_format(const struct ov9734_mode *mode, + struct v4l2_mbus_framefmt *fmt) +{ + fmt->width = mode->width; + fmt->height = mode->height; + fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; + fmt->field = V4L2_FIELD_NONE; +} + +static int ov9734_start_streaming(struct ov9734 *ov9734) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov9734->sd); + const struct ov9734_reg_list *reg_list; + int link_freq_index, ret; + + link_freq_index = ov9734->cur_mode->link_freq_index; + reg_list = &link_freq_configs[link_freq_index].reg_list; + ret = ov9734_write_reg_list(ov9734, reg_list); + if (ret) { + dev_err(&client->dev, "failed to set plls"); + return ret; + } + + reg_list = &ov9734->cur_mode->reg_list; + ret = ov9734_write_reg_list(ov9734, reg_list); + if (ret) { + dev_err(&client->dev, "failed to set mode"); + return ret; + } + + ret = __v4l2_ctrl_handler_setup(ov9734->sd.ctrl_handler); + if (ret) + return ret; + + ret = ov9734_write_reg(ov9734, OV9734_REG_MODE_SELECT, + 1, OV9734_MODE_STREAMING); + if (ret) + dev_err(&client->dev, "failed to start stream"); + + return ret; +} + +static void ov9734_stop_streaming(struct ov9734 *ov9734) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov9734->sd); + + if (ov9734_write_reg(ov9734, OV9734_REG_MODE_SELECT, + 1, OV9734_MODE_STANDBY)) + dev_err(&client->dev, "failed to stop stream"); +} + +static int ov9734_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct ov9734 *ov9734 = to_ov9734(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + if (ov9734->streaming == enable) + return 0; + + mutex_lock(&ov9734->mutex); + if (enable) { + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) { + pm_runtime_put_noidle(&client->dev); + mutex_unlock(&ov9734->mutex); + return ret; + } + + ret = ov9734_start_streaming(ov9734); + if (ret) { + enable = 0; + ov9734_stop_streaming(ov9734); + pm_runtime_put(&client->dev); + } + } else { + ov9734_stop_streaming(ov9734); + pm_runtime_put(&client->dev); + } + + ov9734->streaming = enable; + mutex_unlock(&ov9734->mutex); + + return ret; +} + +static int __maybe_unused ov9734_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov9734 *ov9734 = to_ov9734(sd); + + mutex_lock(&ov9734->mutex); + if (ov9734->streaming) + ov9734_stop_streaming(ov9734); + + mutex_unlock(&ov9734->mutex); + + return 0; +} + +static int __maybe_unused ov9734_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov9734 *ov9734 = to_ov9734(sd); + int ret = 0; + + mutex_lock(&ov9734->mutex); + if (!ov9734->streaming) + goto exit; + + ret = ov9734_start_streaming(ov9734); + if (ret) { + ov9734->streaming = false; + ov9734_stop_streaming(ov9734); + } + +exit: + mutex_unlock(&ov9734->mutex); + return ret; +} + +static int ov9734_set_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ov9734 *ov9734 = to_ov9734(sd); + const struct ov9734_mode *mode; + s32 vblank_def, h_blank; + + mode = v4l2_find_nearest_size(supported_modes, + ARRAY_SIZE(supported_modes), width, + height, fmt->format.width, + fmt->format.height); + + mutex_lock(&ov9734->mutex); + ov9734_update_pad_format(mode, &fmt->format); + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format; + } else { + ov9734->cur_mode = mode; + __v4l2_ctrl_s_ctrl(ov9734->link_freq, mode->link_freq_index); + __v4l2_ctrl_s_ctrl_int64(ov9734->pixel_rate, + to_pixel_rate(mode->link_freq_index)); + + /* Update limits and set FPS to default */ + vblank_def = mode->vts_def - mode->height; + __v4l2_ctrl_modify_range(ov9734->vblank, + mode->vts_min - mode->height, + OV9734_VTS_MAX - mode->height, 1, + vblank_def); + __v4l2_ctrl_s_ctrl(ov9734->vblank, vblank_def); + h_blank = to_pixels_per_line(mode->hts, mode->link_freq_index) - + mode->width; + __v4l2_ctrl_modify_range(ov9734->hblank, h_blank, h_blank, 1, + h_blank); + } + + mutex_unlock(&ov9734->mutex); + + return 0; +} + +static int ov9734_get_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ov9734 *ov9734 = to_ov9734(sd); + + mutex_lock(&ov9734->mutex); + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) + fmt->format = *v4l2_subdev_get_try_format(&ov9734->sd, cfg, + fmt->pad); + else + ov9734_update_pad_format(ov9734->cur_mode, &fmt->format); + + mutex_unlock(&ov9734->mutex); + + return 0; +} + +static int ov9734_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index > 0) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SGRBG10_1X10; + + return 0; +} + +static int ov9734_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + + if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) + return -EINVAL; + + fse->min_width = supported_modes[fse->index].width; + fse->max_width = fse->min_width; + fse->min_height = supported_modes[fse->index].height; + fse->max_height = fse->min_height; + + return 0; +} + +static int ov9734_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct ov9734 *ov9734 = to_ov9734(sd); + + mutex_lock(&ov9734->mutex); + ov9734_update_pad_format(&supported_modes[0], + v4l2_subdev_get_try_format(sd, fh->pad, 0)); + mutex_unlock(&ov9734->mutex); + + return 0; +} + +static const struct v4l2_subdev_video_ops ov9734_video_ops = { + .s_stream = ov9734_set_stream, +}; + +static const struct v4l2_subdev_pad_ops ov9734_pad_ops = { + .set_fmt = ov9734_set_format, + .get_fmt = ov9734_get_format, + .enum_mbus_code = ov9734_enum_mbus_code, + .enum_frame_size = ov9734_enum_frame_size, +}; + +static const struct v4l2_subdev_ops ov9734_subdev_ops = { + .video = &ov9734_video_ops, + .pad = &ov9734_pad_ops, +}; + +static const struct media_entity_operations ov9734_subdev_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static const struct v4l2_subdev_internal_ops ov9734_internal_ops = { + .open = ov9734_open, +}; + +static int ov9734_identify_module(struct ov9734 *ov9734) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov9734->sd); + int ret; + u32 val; + + ret = ov9734_read_reg(ov9734, OV9734_REG_CHIP_ID, 2, &val); + if (ret) + return ret; + + if (val != OV9734_CHIP_ID) { + dev_err(&client->dev, "chip id mismatch: %x!=%x", + OV9734_CHIP_ID, val); + return -ENXIO; + } + + return 0; +} + +static int ov9734_check_hwcfg(struct device *dev) +{ + struct fwnode_handle *ep; + struct fwnode_handle *fwnode = dev_fwnode(dev); + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; + u32 mclk; + int ret; + unsigned int i, j; + + if (!fwnode) + return -ENXIO; + + ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); + if (ret) + return ret; + + if (mclk != OV9734_MCLK) { + dev_err(dev, "external clock %d is not supported", mclk); + return -EINVAL; + } + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) + return -ENXIO; + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + fwnode_handle_put(ep); + if (ret) + return ret; + + if (!bus_cfg.nr_of_link_frequencies) { + dev_err(dev, "no link frequencies defined"); + ret = -EINVAL; + goto check_hwcfg_error; + } + + for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) { + for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) { + if (link_freq_menu_items[i] == + bus_cfg.link_frequencies[j]) + break; + } + + if (j == bus_cfg.nr_of_link_frequencies) { + dev_err(dev, "no link frequency %lld supported", + link_freq_menu_items[i]); + ret = -EINVAL; + goto check_hwcfg_error; + } + } + +check_hwcfg_error: + v4l2_fwnode_endpoint_free(&bus_cfg); + + return ret; +} + +static int ov9734_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov9734 *ov9734 = to_ov9734(sd); + + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + pm_runtime_disable(&client->dev); + mutex_destroy(&ov9734->mutex); + + return 0; +} + +static int ov9734_probe(struct i2c_client *client) +{ + struct ov9734 *ov9734; + int ret; + + ret = ov9734_check_hwcfg(&client->dev); + if (ret) { + dev_err(&client->dev, "failed to check HW configuration: %d", + ret); + return ret; + } + + ov9734 = devm_kzalloc(&client->dev, sizeof(*ov9734), GFP_KERNEL); + if (!ov9734) + return -ENOMEM; + + v4l2_i2c_subdev_init(&ov9734->sd, client, &ov9734_subdev_ops); + ret = ov9734_identify_module(ov9734); + if (ret) { + dev_err(&client->dev, "failed to find sensor: %d", ret); + return ret; + } + + mutex_init(&ov9734->mutex); + ov9734->cur_mode = &supported_modes[0]; + ret = ov9734_init_controls(ov9734); + if (ret) { + dev_err(&client->dev, "failed to init controls: %d", ret); + goto probe_error_v4l2_ctrl_handler_free; + } + + ov9734->sd.internal_ops = &ov9734_internal_ops; + ov9734->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + ov9734->sd.entity.ops = &ov9734_subdev_entity_ops; + ov9734->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ov9734->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&ov9734->sd.entity, 1, &ov9734->pad); + if (ret) { + dev_err(&client->dev, "failed to init entity pads: %d", ret); + goto probe_error_v4l2_ctrl_handler_free; + } + + ret = v4l2_async_register_subdev_sensor_common(&ov9734->sd); + if (ret < 0) { + dev_err(&client->dev, "failed to register V4L2 subdev: %d", + ret); + goto probe_error_media_entity_cleanup; + } + + /* + * Device is already turned on by i2c-core with ACPI domain PM. + * Enable runtime PM and turn off the device. + */ + pm_runtime_set_active(&client->dev); + pm_runtime_enable(&client->dev); + pm_runtime_idle(&client->dev); + + return 0; + +probe_error_media_entity_cleanup: + media_entity_cleanup(&ov9734->sd.entity); + +probe_error_v4l2_ctrl_handler_free: + v4l2_ctrl_handler_free(ov9734->sd.ctrl_handler); + mutex_destroy(&ov9734->mutex); + + return ret; +} + +static const struct dev_pm_ops ov9734_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ov9734_suspend, ov9734_resume) +}; + +static const struct acpi_device_id ov9734_acpi_ids[] = { + { "OVTI9734", }, + {} +}; + +MODULE_DEVICE_TABLE(acpi, ov9734_acpi_ids); + +static struct i2c_driver ov9734_i2c_driver = { + .driver = { + .name = "ov9734", + .pm = &ov9734_pm_ops, + .acpi_match_table = ov9734_acpi_ids, + }, + .probe_new = ov9734_probe, + .remove = ov9734_remove, +}; + +module_i2c_driver(ov9734_i2c_driver); + +MODULE_AUTHOR("Qiu, Tianshu "); +MODULE_AUTHOR("Bingbu Cao "); +MODULE_DESCRIPTION("OmniVision OV9734 sensor driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From e2881c64519d235a90e93aefd61bb51a4a22d08b Mon Sep 17 00:00:00 2001 From: Hugues Fruchet Date: Wed, 4 Nov 2020 18:32:10 +0100 Subject: media: dt-bindings: media: st,stm32-dcmi: add support of BT656 bus Add support of BT656 embedded synchronization bus mode in DCMI driver. Add "bus-type" property and make it required so that there is no ambiguity between parallel mode (bus-type=5) and BT656 mode (bus-type=6). BT656 mode allows to save hardware synchro lines hsync & vsync by replacing them with synchro codes embedded in data stream, hence hsync-active & vsync-active properties are useless in this mode. With DCMI, BT656 bus mode is only compatible with 8 bits width data bus. Signed-off-by: Hugues Fruchet Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/st,stm32-dcmi.yaml | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml b/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml index 3fe778cb5cc3..c18574bb3e81 100644 --- a/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml +++ b/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml @@ -44,6 +44,43 @@ properties: bindings defined in Documentation/devicetree/bindings/media/video-interfaces.txt. + properties: + endpoint: + type: object + + properties: + bus-type: + enum: [5, 6] + default: 5 + + bus-width: + enum: [8, 10, 12, 14] + default: 8 + + remote-endpoint: true + + allOf: + - if: + properties: + bus-type: + const: 6 + + then: + properties: + hsync-active: false + vsync-active: false + bus-width: + enum: [8] + + required: + - remote-endpoint + - bus-type + - pclk-sample + + unevaluatedProperties: false + + additionalProperties: false + required: - compatible - reg @@ -75,6 +112,7 @@ examples: port { dcmi_0: endpoint { remote-endpoint = <&ov5640_0>; + bus-type = <5>; bus-width = <8>; hsync-active = <0>; vsync-active = <0>; -- cgit v1.2.3 From 3c80f6f81e64de5721867721d4a3e90bb602c787 Mon Sep 17 00:00:00 2001 From: Hugues Fruchet Date: Wed, 4 Nov 2020 18:32:09 +0100 Subject: media: stm32-dcmi: add support of BT656 bus Add support of BT656 embedded synchronization bus. This mode allows to save hardware synchro lines hsync & vsync by replacing them with synchro codes embedded in data stream. This bus type is only compatible with 8 bits width data bus. Due to reserved values 0x00 & 0xff used for synchro codes, valid data vary from 0x1 to 0xfe, this is up to sensor to clip accordingly pixel data. As a consequence of this clipping, JPEG is not supported with this bus type. DCMI crop feature is also not available with this bus type. Signed-off-by: Hugues Fruchet Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/stm32/stm32-dcmi.c | 37 +++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index 5b988f676bad..b745f1342c2e 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -157,6 +157,7 @@ struct stm32_dcmi { struct vb2_queue queue; struct v4l2_fwnode_bus_parallel bus; + enum v4l2_mbus_type bus_type; struct completion complete; struct clk *mclk; enum state state; @@ -777,6 +778,23 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) if (dcmi->bus.flags & V4L2_MBUS_PCLK_SAMPLE_RISING) val |= CR_PCKPOL; + /* + * BT656 embedded synchronisation bus mode. + * + * Default SAV/EAV mode is supported here with default codes + * SAV=0xff000080 & EAV=0xff00009d. + * With DCMI this means LSC=SAV=0x80 & LEC=EAV=0x9d. + */ + if (dcmi->bus_type == V4L2_MBUS_BT656) { + val |= CR_ESS; + + /* Unmask all codes */ + reg_write(dcmi->regs, DCMI_ESUR, 0xffffffff);/* FEC:LEC:LSC:FSC */ + + /* Trig on LSC=0x80 & LEC=0x9d codes, ignore FSC and FEC */ + reg_write(dcmi->regs, DCMI_ESCR, 0xff9d80ff);/* FEC:LEC:LSC:FSC */ + } + reg_write(dcmi->regs, DCMI_CR, val); /* Set crop */ @@ -1067,8 +1085,9 @@ static int dcmi_set_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f) if (ret) return ret; - /* Disable crop if JPEG is requested */ - if (pix->pixelformat == V4L2_PIX_FMT_JPEG) + /* Disable crop if JPEG is requested or BT656 bus is selected */ + if (pix->pixelformat == V4L2_PIX_FMT_JPEG && + dcmi->bus_type != V4L2_MBUS_BT656) dcmi->do_crop = false; /* pix to mbus format */ @@ -1608,6 +1627,11 @@ static int dcmi_formats_init(struct stm32_dcmi *dcmi) if (dcmi_formats[i].mbus_code != mbus_code.code) continue; + /* Exclude JPEG if BT656 bus is selected */ + if (dcmi_formats[i].fourcc == V4L2_PIX_FMT_JPEG && + dcmi->bus_type == V4L2_MBUS_BT656) + continue; + /* Code supported, have we got this fourcc yet? */ for (j = 0; j < num_fmts; j++) if (sd_fmts[j]->fourcc == @@ -1891,9 +1915,18 @@ static int dcmi_probe(struct platform_device *pdev) dev_err(&pdev->dev, "CSI bus not supported\n"); return -ENODEV; } + + if (ep.bus_type == V4L2_MBUS_BT656 && + ep.bus.parallel.bus_width != 8) { + dev_err(&pdev->dev, "BT656 bus conflicts with %u bits bus width (8 bits required)\n", + ep.bus.parallel.bus_width); + return -ENODEV; + } + dcmi->bus.flags = ep.bus.parallel.flags; dcmi->bus.bus_width = ep.bus.parallel.bus_width; dcmi->bus.data_shift = ep.bus.parallel.data_shift; + dcmi->bus_type = ep.bus_type; irq = platform_get_irq(pdev, 0); if (irq <= 0) -- cgit v1.2.3 From 798f1a6b0efcb33e5f3abe048aa9d546ca849cd8 Mon Sep 17 00:00:00 2001 From: Bingbu Cao Date: Fri, 13 Nov 2020 04:06:57 +0100 Subject: media: ov2740: only do OTP data read on demand from user OTP data access of ov2740 in probe need power up, it may cause the camera flash LED blink during probe if the LED use same power rail with camera, this patch move the OTP data access out of probe, it will only occur on demand from user by nvmem sysfs. Signed-off-by: Bingbu Cao Signed-off-by: Qingwu Zhang Reviewed-by: Tomasz Figa Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov2740.c | 116 ++++++++++++++++++++++++++++++++------------- 1 file changed, 84 insertions(+), 32 deletions(-) diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c index 64ecb6917dd3..16a1e4e16dd8 100644 --- a/drivers/media/i2c/ov2740.c +++ b/drivers/media/i2c/ov2740.c @@ -71,9 +71,10 @@ #define OV2740_REG_OTP_CUSTOMER 0x7010 struct nvm_data { - char *nvm_buffer; + struct i2c_client *client; struct nvmem_device *nvmem; struct regmap *regmap; + char *nvm_buffer; }; enum { @@ -335,6 +336,9 @@ struct ov2740 { /* Streaming on/off */ bool streaming; + + /* NVM data inforamtion */ + struct nvm_data *nvm; }; static inline struct ov2740 *to_ov2740(struct v4l2_subdev *subdev) @@ -930,45 +934,57 @@ static int ov2740_remove(struct i2c_client *client) return 0; } -static int ov2740_load_otp_data(struct i2c_client *client, struct nvm_data *nvm) +static int ov2740_load_otp_data(struct nvm_data *nvm) { + struct i2c_client *client = nvm->client; struct ov2740 *ov2740 = to_ov2740(i2c_get_clientdata(client)); u32 isp_ctrl00 = 0; u32 isp_ctrl01 = 0; int ret; + if (!nvm) + return -EINVAL; + + if (nvm->nvm_buffer) + return 0; + + nvm->nvm_buffer = kzalloc(CUSTOMER_USE_OTP_SIZE, GFP_KERNEL); + if (!nvm->nvm_buffer) + return -ENOMEM; + ret = ov2740_read_reg(ov2740, OV2740_REG_ISP_CTRL00, 1, &isp_ctrl00); if (ret) { dev_err(&client->dev, "failed to read ISP CTRL00\n"); - goto exit; + goto err; } + ret = ov2740_read_reg(ov2740, OV2740_REG_ISP_CTRL01, 1, &isp_ctrl01); if (ret) { dev_err(&client->dev, "failed to read ISP CTRL01\n"); - goto exit; + goto err; } /* Clear bit 5 of ISP CTRL00 */ ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL00, 1, isp_ctrl00 & ~BIT(5)); if (ret) { - dev_err(&client->dev, "failed to write ISP CTRL00\n"); - goto exit; + dev_err(&client->dev, "failed to set ISP CTRL00\n"); + goto err; } /* Clear bit 7 of ISP CTRL01 */ ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL01, 1, isp_ctrl01 & ~BIT(7)); if (ret) { - dev_err(&client->dev, "failed to write ISP CTRL01\n"); - goto exit; + dev_err(&client->dev, "failed to set ISP CTRL01\n"); + goto err; } ret = ov2740_write_reg(ov2740, OV2740_REG_MODE_SELECT, 1, OV2740_MODE_STREAMING); if (ret) { - dev_err(&client->dev, "failed to start streaming\n"); - goto exit; + dev_err(&client->dev, "failed to set streaming mode\n"); + goto err; } /* @@ -981,15 +997,33 @@ static int ov2740_load_otp_data(struct i2c_client *client, struct nvm_data *nvm) nvm->nvm_buffer, CUSTOMER_USE_OTP_SIZE); if (ret) { dev_err(&client->dev, "failed to read OTP data, ret %d\n", ret); - goto exit; + goto err; + } + + ret = ov2740_write_reg(ov2740, OV2740_REG_MODE_SELECT, 1, + OV2740_MODE_STANDBY); + if (ret) { + dev_err(&client->dev, "failed to set streaming mode\n"); + goto err; } - ov2740_write_reg(ov2740, OV2740_REG_MODE_SELECT, 1, - OV2740_MODE_STANDBY); - ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL01, 1, isp_ctrl01); - ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL00, 1, isp_ctrl00); + ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL01, 1, isp_ctrl01); + if (ret) { + dev_err(&client->dev, "failed to set ISP CTRL01\n"); + goto err; + } + + ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL00, 1, isp_ctrl00); + if (ret) { + dev_err(&client->dev, "failed to set ISP CTRL00\n"); + goto err; + } + + return 0; +err: + kfree(nvm->nvm_buffer); + nvm->nvm_buffer = NULL; -exit: return ret; } @@ -997,29 +1031,48 @@ static int ov2740_nvmem_read(void *priv, unsigned int off, void *val, size_t count) { struct nvm_data *nvm = priv; + struct v4l2_subdev *sd = i2c_get_clientdata(nvm->client); + struct device *dev = &nvm->client->dev; + struct ov2740 *ov2740 = to_ov2740(sd); + int ret = 0; - memcpy(val, nvm->nvm_buffer + off, count); + mutex_lock(&ov2740->mutex); - return 0; + if (nvm->nvm_buffer) { + memcpy(val, nvm->nvm_buffer + off, count); + goto exit; + } + + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + pm_runtime_put_noidle(dev); + goto exit; + } + + ret = ov2740_load_otp_data(nvm); + if (!ret) + memcpy(val, nvm->nvm_buffer + off, count); + + pm_runtime_put(dev); +exit: + mutex_unlock(&ov2740->mutex); + return ret; } -static int ov2740_register_nvmem(struct i2c_client *client) +static int ov2740_register_nvmem(struct i2c_client *client, + struct ov2740 *ov2740) { struct nvm_data *nvm; struct regmap_config regmap_config = { }; struct nvmem_config nvmem_config = { }; struct regmap *regmap; struct device *dev = &client->dev; - int ret = 0; + int ret; nvm = devm_kzalloc(dev, sizeof(*nvm), GFP_KERNEL); if (!nvm) return -ENOMEM; - nvm->nvm_buffer = devm_kzalloc(dev, CUSTOMER_USE_OTP_SIZE, GFP_KERNEL); - if (!nvm->nvm_buffer) - return -ENOMEM; - regmap_config.val_bits = 8; regmap_config.reg_bits = 16; regmap_config.disable_locking = true; @@ -1028,12 +1081,7 @@ static int ov2740_register_nvmem(struct i2c_client *client) return PTR_ERR(regmap); nvm->regmap = regmap; - - ret = ov2740_load_otp_data(client, nvm); - if (ret) { - dev_err(dev, "failed to load OTP data, ret %d\n", ret); - return ret; - } + nvm->client = client; nvmem_config.name = dev_name(dev); nvmem_config.dev = dev; @@ -1051,7 +1099,11 @@ static int ov2740_register_nvmem(struct i2c_client *client) nvm->nvmem = devm_nvmem_register(dev, &nvmem_config); - return PTR_ERR_OR_ZERO(nvm->nvmem); + ret = PTR_ERR_OR_ZERO(nvm->nvmem); + if (!ret) + ov2740->nvm = nvm; + + return ret; } static int ov2740_probe(struct i2c_client *client) @@ -1103,7 +1155,7 @@ static int ov2740_probe(struct i2c_client *client) goto probe_error_media_entity_cleanup; } - ret = ov2740_register_nvmem(client); + ret = ov2740_register_nvmem(client, ov2740); if (ret) dev_warn(&client->dev, "register nvmem failed, ret %d\n", ret); -- cgit v1.2.3 From 5e6fd339b68df81f35a70b4aa0501e3eec1dd2de Mon Sep 17 00:00:00 2001 From: Bingbu Cao Date: Fri, 13 Nov 2020 04:06:58 +0100 Subject: media: ov2740: allow OTP data access during streaming OTP data access of ov2740 need enable the streaming mode to load and it could be done in any time, so driver need allow the OTP data access during streaming instead of return EBUSY, this patch try to read the OTP data out in STREAMON if OTP data is not ready before first time streaming start. Signed-off-by: Bingbu Cao Signed-off-by: Qingwu Zhang Reviewed-by: Tomasz Figa Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov2740.c | 189 +++++++++++++++++++++++---------------------- 1 file changed, 96 insertions(+), 93 deletions(-) diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c index 16a1e4e16dd8..99016546cbec 100644 --- a/drivers/media/i2c/ov2740.c +++ b/drivers/media/i2c/ov2740.c @@ -598,13 +598,109 @@ static void ov2740_update_pad_format(const struct ov2740_mode *mode, fmt->field = V4L2_FIELD_NONE; } +static int ov2740_load_otp_data(struct nvm_data *nvm) +{ + struct i2c_client *client = nvm->client; + struct ov2740 *ov2740 = to_ov2740(i2c_get_clientdata(client)); + u32 isp_ctrl00 = 0; + u32 isp_ctrl01 = 0; + int ret; + + if (!nvm) + return -EINVAL; + + if (nvm->nvm_buffer) + return 0; + + nvm->nvm_buffer = kzalloc(CUSTOMER_USE_OTP_SIZE, GFP_KERNEL); + if (!nvm->nvm_buffer) + return -ENOMEM; + + ret = ov2740_read_reg(ov2740, OV2740_REG_ISP_CTRL00, 1, &isp_ctrl00); + if (ret) { + dev_err(&client->dev, "failed to read ISP CTRL00\n"); + goto err; + } + + ret = ov2740_read_reg(ov2740, OV2740_REG_ISP_CTRL01, 1, &isp_ctrl01); + if (ret) { + dev_err(&client->dev, "failed to read ISP CTRL01\n"); + goto err; + } + + /* Clear bit 5 of ISP CTRL00 */ + ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL00, 1, + isp_ctrl00 & ~BIT(5)); + if (ret) { + dev_err(&client->dev, "failed to set ISP CTRL00\n"); + goto err; + } + + /* Clear bit 7 of ISP CTRL01 */ + ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL01, 1, + isp_ctrl01 & ~BIT(7)); + if (ret) { + dev_err(&client->dev, "failed to set ISP CTRL01\n"); + goto err; + } + + ret = ov2740_write_reg(ov2740, OV2740_REG_MODE_SELECT, 1, + OV2740_MODE_STREAMING); + if (ret) { + dev_err(&client->dev, "failed to set streaming mode\n"); + goto err; + } + + /* + * Users are not allowed to access OTP-related registers and memory + * during the 20 ms period after streaming starts (0x100 = 0x01). + */ + msleep(20); + + ret = regmap_bulk_read(nvm->regmap, OV2740_REG_OTP_CUSTOMER, + nvm->nvm_buffer, CUSTOMER_USE_OTP_SIZE); + if (ret) { + dev_err(&client->dev, "failed to read OTP data, ret %d\n", ret); + goto err; + } + + ret = ov2740_write_reg(ov2740, OV2740_REG_MODE_SELECT, 1, + OV2740_MODE_STANDBY); + if (ret) { + dev_err(&client->dev, "failed to set streaming mode\n"); + goto err; + } + + ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL01, 1, isp_ctrl01); + if (ret) { + dev_err(&client->dev, "failed to set ISP CTRL01\n"); + goto err; + } + + ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL00, 1, isp_ctrl00); + if (ret) { + dev_err(&client->dev, "failed to set ISP CTRL00\n"); + goto err; + } + + return 0; +err: + kfree(nvm->nvm_buffer); + nvm->nvm_buffer = NULL; + + return ret; +} + static int ov2740_start_streaming(struct ov2740 *ov2740) { struct i2c_client *client = v4l2_get_subdevdata(&ov2740->sd); + struct nvm_data *nvm = ov2740->nvm; const struct ov2740_reg_list *reg_list; int link_freq_index; int ret = 0; + ov2740_load_otp_data(nvm); + link_freq_index = ov2740->cur_mode->link_freq_index; reg_list = &link_freq_configs[link_freq_index].reg_list; ret = ov2740_write_reg_list(ov2740, reg_list); @@ -934,99 +1030,6 @@ static int ov2740_remove(struct i2c_client *client) return 0; } -static int ov2740_load_otp_data(struct nvm_data *nvm) -{ - struct i2c_client *client = nvm->client; - struct ov2740 *ov2740 = to_ov2740(i2c_get_clientdata(client)); - u32 isp_ctrl00 = 0; - u32 isp_ctrl01 = 0; - int ret; - - if (!nvm) - return -EINVAL; - - if (nvm->nvm_buffer) - return 0; - - nvm->nvm_buffer = kzalloc(CUSTOMER_USE_OTP_SIZE, GFP_KERNEL); - if (!nvm->nvm_buffer) - return -ENOMEM; - - ret = ov2740_read_reg(ov2740, OV2740_REG_ISP_CTRL00, 1, &isp_ctrl00); - if (ret) { - dev_err(&client->dev, "failed to read ISP CTRL00\n"); - goto err; - } - - ret = ov2740_read_reg(ov2740, OV2740_REG_ISP_CTRL01, 1, &isp_ctrl01); - if (ret) { - dev_err(&client->dev, "failed to read ISP CTRL01\n"); - goto err; - } - - /* Clear bit 5 of ISP CTRL00 */ - ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL00, 1, - isp_ctrl00 & ~BIT(5)); - if (ret) { - dev_err(&client->dev, "failed to set ISP CTRL00\n"); - goto err; - } - - /* Clear bit 7 of ISP CTRL01 */ - ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL01, 1, - isp_ctrl01 & ~BIT(7)); - if (ret) { - dev_err(&client->dev, "failed to set ISP CTRL01\n"); - goto err; - } - - ret = ov2740_write_reg(ov2740, OV2740_REG_MODE_SELECT, 1, - OV2740_MODE_STREAMING); - if (ret) { - dev_err(&client->dev, "failed to set streaming mode\n"); - goto err; - } - - /* - * Users are not allowed to access OTP-related registers and memory - * during the 20 ms period after streaming starts (0x100 = 0x01). - */ - msleep(20); - - ret = regmap_bulk_read(nvm->regmap, OV2740_REG_OTP_CUSTOMER, - nvm->nvm_buffer, CUSTOMER_USE_OTP_SIZE); - if (ret) { - dev_err(&client->dev, "failed to read OTP data, ret %d\n", ret); - goto err; - } - - ret = ov2740_write_reg(ov2740, OV2740_REG_MODE_SELECT, 1, - OV2740_MODE_STANDBY); - if (ret) { - dev_err(&client->dev, "failed to set streaming mode\n"); - goto err; - } - - ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL01, 1, isp_ctrl01); - if (ret) { - dev_err(&client->dev, "failed to set ISP CTRL01\n"); - goto err; - } - - ret = ov2740_write_reg(ov2740, OV2740_REG_ISP_CTRL00, 1, isp_ctrl00); - if (ret) { - dev_err(&client->dev, "failed to set ISP CTRL00\n"); - goto err; - } - - return 0; -err: - kfree(nvm->nvm_buffer); - nvm->nvm_buffer = NULL; - - return ret; -} - static int ov2740_nvmem_read(void *priv, unsigned int off, void *val, size_t count) { -- cgit v1.2.3 From b5c17905fb97e4e3c2fccdd168f6d2e7d54076e5 Mon Sep 17 00:00:00 2001 From: Xu Wang Date: Wed, 4 Nov 2020 10:29:48 +0100 Subject: media: i2c: mt9p031: Remove redundant null check before clk_disable_unprepare Because clk_disable_unprepare() already checked NULL clock parameter, so the additional check is unnecessary, just remove it. Signed-off-by: Xu Wang Reviewed-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/mt9p031.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index dc23b9ed510a..a633b934d93e 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -346,8 +346,7 @@ static void mt9p031_power_off(struct mt9p031 *mt9p031) regulator_bulk_disable(ARRAY_SIZE(mt9p031->regulators), mt9p031->regulators); - if (mt9p031->clk) - clk_disable_unprepare(mt9p031->clk); + clk_disable_unprepare(mt9p031->clk); } static int __mt9p031_set_power(struct mt9p031 *mt9p031, bool on) -- cgit v1.2.3 From 7966ceb4dde4d694387c40c5bac5bb01d40d48dc Mon Sep 17 00:00:00 2001 From: Nigel Christian Date: Sat, 31 Oct 2020 03:21:55 +0100 Subject: media: ipu3-cio2: fix trivial style warning Comment has 'the' repeated twice. Let's clean it up. This patch reduces checkpatch warnings for this file to nil. Signed-off-by: Nigel Christian Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/intel/ipu3/ipu3-cio2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index 4fc36b5a8090..36e354ecf71e 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -291,7 +291,7 @@ static s32 cio2_rx_timing(s32 a, s32 b, s64 freq, int def) return r; }; -/* Calculate the the delay value for termination enable of clock lane HS Rx */ +/* Calculate the delay value for termination enable of clock lane HS Rx */ static int cio2_csi2_calc_timing(struct cio2_device *cio2, struct cio2_queue *q, struct cio2_csi2_timing *timing, unsigned int bpp, unsigned int lanes) -- cgit v1.2.3 From 57226cd8c8bf14e2dfcb3deb4e44bb74ccdafda2 Mon Sep 17 00:00:00 2001 From: Rui Miguel Silva Date: Wed, 21 Oct 2020 23:25:41 +0200 Subject: media: dt-bindings: ov2680: convert bindings to yaml Convert ov2680 sensor bindings documentation to yaml schema, remove the textual bindings document and update MAINTAINERS entry. Signed-off-by: Rui Miguel Silva Reviewed-by: Jacopo Mondi Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/i2c/ov2680.txt | 46 ---------- .../devicetree/bindings/media/i2c/ovti,ov2680.yaml | 99 ++++++++++++++++++++++ MAINTAINERS | 2 +- 3 files changed, 100 insertions(+), 47 deletions(-) delete mode 100644 Documentation/devicetree/bindings/media/i2c/ov2680.txt create mode 100644 Documentation/devicetree/bindings/media/i2c/ovti,ov2680.yaml diff --git a/Documentation/devicetree/bindings/media/i2c/ov2680.txt b/Documentation/devicetree/bindings/media/i2c/ov2680.txt deleted file mode 100644 index 11e925ed9dad..000000000000 --- a/Documentation/devicetree/bindings/media/i2c/ov2680.txt +++ /dev/null @@ -1,46 +0,0 @@ -* Omnivision OV2680 MIPI CSI-2 sensor - -Required Properties: -- compatible: should be "ovti,ov2680". -- clocks: reference to the xvclk input clock. -- clock-names: should be "xvclk". -- DOVDD-supply: Digital I/O voltage supply. -- DVDD-supply: Digital core voltage supply. -- AVDD-supply: Analog voltage supply. - -Optional Properties: -- reset-gpios: reference to the GPIO connected to the powerdown/reset pin, - if any. This is an active low signal to the OV2680. - -The device node must contain one 'port' child node for its digital output -video port, and this port must have a single endpoint in accordance with - the video interface bindings defined in -Documentation/devicetree/bindings/media/video-interfaces.txt. - -Endpoint node required properties for CSI-2 connection are: -- remote-endpoint: a phandle to the bus receiver's endpoint node. -- clock-lanes: should be set to <0> (clock lane on hardware lane 0). -- data-lanes: should be set to <1> (one CSI-2 lane supported). - -Example: - -&i2c2 { - ov2680: camera-sensor@36 { - compatible = "ovti,ov2680"; - reg = <0x36>; - clocks = <&osc>; - clock-names = "xvclk"; - reset-gpios = <&gpio1 3 GPIO_ACTIVE_LOW>; - DOVDD-supply = <&sw2_reg>; - DVDD-supply = <&sw2_reg>; - AVDD-supply = <®_peri_3p15v>; - - port { - ov2680_to_mipi: endpoint { - remote-endpoint = <&mipi_from_sensor>; - clock-lanes = <0>; - data-lanes = <1>; - }; - }; - }; -}; diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov2680.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov2680.yaml new file mode 100644 index 000000000000..43bf749807e1 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov2680.yaml @@ -0,0 +1,99 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/ovti,ov2680.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Omnivision OV2680 CMOS Sensor + +maintainers: + - Rui Miguel Silva + +description: |- + The OV2680 color sensor is a low voltage, high performance 1/5 inch UXGA (2 + megapixel) CMOS image sensor that provides a single-chip UXGA (1600 x 1200) + camera. It provides full-frame, sub-sampled, or windowed 10-bit images in + various formats via the control of the Serial Camera Control Bus (SCCB) + interface. The OV2680 has an image array capable of operating at up to 30 + frames per second (fps) in UXGA resolution. + +properties: + compatible: + const: ovti,ov2680 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + const: xvclk + + reset-gpios: + description: + The phandle and specifier for the GPIO that controls sensor reset. + This corresponds to the hardware pin XSHUTDOWN which is physically + active low. + maxItems: 1 + + dovdd-supply: + description: + Definition of the regulator used as interface power supply. + + avdd-supply: + description: + Definition of the regulator used as analog power supply. + + dvdd-supply: + description: + Definition of the regulator used as digital power supply. + + port: + type: object + description: + A node containing an output port node with an endpoint definition + as documented in + Documentation/devicetree/bindings/media/video-interfaces.txt + +required: + - compatible + - reg + - clocks + - clock-names + - dovdd-supply + - avdd-supply + - dvdd-supply + - reset-gpios + - port + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + ov2680: camera-sensor@36 { + compatible = "ovti,ov2680"; + reg = <0x36>; + clocks = <&osc>; + clock-names = "xvclk"; + reset-gpios = <&gpio1 3 GPIO_ACTIVE_LOW>; + + dovdd-supply = <&sw2_reg>; + dvdd-supply = <&sw2_reg>; + avdd-supply = <®_peri_3p15v>; + + port { + ov2680_to_mipi: endpoint { + remote-endpoint = <&mipi_from_sensor>; + }; + }; + }; + }; + +... diff --git a/MAINTAINERS b/MAINTAINERS index 20e4afc53bdb..551def33e98f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12889,7 +12889,7 @@ M: Rui Miguel Silva L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git -F: Documentation/devicetree/bindings/media/i2c/ov2680.txt +F: Documentation/devicetree/bindings/media/i2c/ov2680.yaml F: drivers/media/i2c/ov2680.c OMNIVISION OV2685 SENSOR DRIVER -- cgit v1.2.3 From 338de94d220d5c413b029460a59e7a5ebeeb903f Mon Sep 17 00:00:00 2001 From: Rui Miguel Silva Date: Wed, 21 Oct 2020 23:25:42 +0200 Subject: media: dt-bindings: imx7-csi: convert bindings to yaml Convert imx7-csi bindings documentation to yaml schema, remove the textual bindings document and update MAINTAINERS entry. Signed-off-by: Rui Miguel Silva Reviewed-by: Jacopo Mondi Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/imx7-csi.txt | 42 ------------- .../devicetree/bindings/media/nxp,imx7-csi.yaml | 71 ++++++++++++++++++++++ MAINTAINERS | 2 +- 3 files changed, 72 insertions(+), 43 deletions(-) delete mode 100644 Documentation/devicetree/bindings/media/imx7-csi.txt create mode 100644 Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml diff --git a/Documentation/devicetree/bindings/media/imx7-csi.txt b/Documentation/devicetree/bindings/media/imx7-csi.txt deleted file mode 100644 index d80ceefa0c00..000000000000 --- a/Documentation/devicetree/bindings/media/imx7-csi.txt +++ /dev/null @@ -1,42 +0,0 @@ -Freescale i.MX7 CMOS Sensor Interface -===================================== - -csi node --------- - -This is device node for the CMOS Sensor Interface (CSI) which enables the chip -to connect directly to external CMOS image sensors. - -Required properties: - -- compatible : "fsl,imx7-csi" or "fsl,imx6ul-csi"; -- reg : base address and length of the register set for the device; -- interrupts : should contain CSI interrupt; -- clocks : list of clock specifiers, see - Documentation/devicetree/bindings/clock/clock-bindings.txt for details; -- clock-names : must contain "mclk"; - -The device node shall contain one 'port' child node with one child 'endpoint' -node, according to the bindings defined in: -Documentation/devicetree/bindings/media/video-interfaces.txt. - -In the following example a remote endpoint is a video multiplexer. - -example: - - csi: csi@30710000 { - #address-cells = <1>; - #size-cells = <0>; - - compatible = "fsl,imx7-csi"; - reg = <0x30710000 0x10000>; - interrupts = ; - clocks = <&clks IMX7D_CSI_MCLK_ROOT_CLK>; - clock-names = "mclk"; - - port { - csi_from_csi_mux: endpoint { - remote-endpoint = <&csi_mux_to_csi>; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml b/Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml new file mode 100644 index 000000000000..4e81a47e60ac --- /dev/null +++ b/Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml @@ -0,0 +1,71 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/nxp,imx7-csi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: i.MX7 CMOS Sensor Interface + +maintainers: + - Rui Miguel Silva + +description: | + This is device node for the CMOS Sensor Interface (CSI) which enables the + chip to connect directly to external CMOS image sensors. + +properties: + compatible: + enum: + - fsl,imx7-csi + - fsl,imx6ul-csi + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: mclk + + port: + type: object + description: + A node containing input port nodes with endpoint definitions as documented + in Documentation/devicetree/bindings/media/video-interfaces.txt + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - port + +additionalProperties: false + +examples: + - | + #include + #include + #include + + csi: csi@30710000 { + compatible = "fsl,imx7-csi"; + reg = <0x30710000 0x10000>; + interrupts = ; + clocks = <&clks IMX7D_CSI_MCLK_ROOT_CLK>; + clock-names = "mclk"; + + port { + csi_from_csi_mux: endpoint { + remote-endpoint = <&csi_mux_to_csi>; + }; + }; + }; + +... diff --git a/MAINTAINERS b/MAINTAINERS index 551def33e98f..221385eedc9d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10849,8 +10849,8 @@ L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git F: Documentation/admin-guide/media/imx7.rst -F: Documentation/devicetree/bindings/media/imx7-csi.txt F: Documentation/devicetree/bindings/media/imx7-mipi-csi2.txt +F: Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml F: drivers/staging/media/imx/imx7-media-csi.c F: drivers/staging/media/imx/imx7-mipi-csis.c -- cgit v1.2.3 From 8b7c7828a311a18932ca63228ff3745a86cb880a Mon Sep 17 00:00:00 2001 From: Rui Miguel Silva Date: Wed, 21 Oct 2020 23:25:43 +0200 Subject: media: dt-bindings: imx7-mipi-csi2: convert bindings to yaml Convert imx7 mipi csi2 bindings documentation to yaml schema, remove the textual document and update MAINTAINERS entry. Signed-off-by: Rui Miguel Silva Reviewed-by: Jacopo Mondi Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/imx7-mipi-csi2.txt | 90 ----------- .../bindings/media/nxp,imx7-mipi-csi2.yaml | 173 +++++++++++++++++++++ MAINTAINERS | 2 +- 3 files changed, 174 insertions(+), 91 deletions(-) delete mode 100644 Documentation/devicetree/bindings/media/imx7-mipi-csi2.txt create mode 100644 Documentation/devicetree/bindings/media/nxp,imx7-mipi-csi2.yaml diff --git a/Documentation/devicetree/bindings/media/imx7-mipi-csi2.txt b/Documentation/devicetree/bindings/media/imx7-mipi-csi2.txt deleted file mode 100644 index 71fd74ed3ec8..000000000000 --- a/Documentation/devicetree/bindings/media/imx7-mipi-csi2.txt +++ /dev/null @@ -1,90 +0,0 @@ -Freescale i.MX7 Mipi CSI2 -========================= - -mipi_csi2 node --------------- - -This is the device node for the MIPI CSI-2 receiver core in i.MX7 SoC. It is -compatible with previous version of Samsung D-phy. - -Required properties: - -- compatible : "fsl,imx7-mipi-csi2"; -- reg : base address and length of the register set for the device; -- interrupts : should contain MIPI CSIS interrupt; -- clocks : list of clock specifiers, see - Documentation/devicetree/bindings/clock/clock-bindings.txt for details; -- clock-names : must contain "pclk", "wrap" and "phy" entries, matching - entries in the clock property; -- power-domains : a phandle to the power domain, see - Documentation/devicetree/bindings/power/power_domain.txt for details. -- reset-names : should include following entry "mrst"; -- resets : a list of phandle, should contain reset entry of - reset-names; -- phy-supply : from the generic phy bindings, a phandle to a regulator that - provides power to MIPI CSIS core; - -Optional properties: - -- clock-frequency : The IP's main (system bus) clock frequency in Hz, default - value when this property is not specified is 166 MHz; -- fsl,csis-hs-settle : differential receiver (HS-RX) settle time; - -The device node should contain two 'port' child nodes with one child 'endpoint' -node, according to the bindings defined in: - Documentation/devicetree/bindings/ media/video-interfaces.txt. - The following are properties specific to those nodes. - -port node ---------- - -- reg : (required) can take the values 0 or 1, where 0 shall be - related to the sink port and port 1 shall be the source - one; - -endpoint node -------------- - -- data-lanes : (required) an array specifying active physical MIPI-CSI2 - data input lanes and their mapping to logical lanes; this - shall only be applied to port 0 (sink port), the array's - content is unused only its length is meaningful, - in this case the maximum length supported is 2; - -example: - - mipi_csi: mipi-csi@30750000 { - #address-cells = <1>; - #size-cells = <0>; - - compatible = "fsl,imx7-mipi-csi2"; - reg = <0x30750000 0x10000>; - interrupts = ; - clocks = <&clks IMX7D_IPG_ROOT_CLK>, - <&clks IMX7D_MIPI_CSI_ROOT_CLK>, - <&clks IMX7D_MIPI_DPHY_ROOT_CLK>; - clock-names = "pclk", "wrap", "phy"; - clock-frequency = <166000000>; - power-domains = <&pgc_mipi_phy>; - phy-supply = <®_1p0d>; - resets = <&src IMX7_RESET_MIPI_PHY_MRST>; - reset-names = "mrst"; - fsl,csis-hs-settle = <3>; - - port@0 { - reg = <0>; - - mipi_from_sensor: endpoint { - remote-endpoint = <&ov2680_to_mipi>; - data-lanes = <1>; - }; - }; - - port@1 { - reg = <1>; - - mipi_vc0_to_csi_mux: endpoint { - remote-endpoint = <&csi_mux_from_mipi_vc0>; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/media/nxp,imx7-mipi-csi2.yaml b/Documentation/devicetree/bindings/media/nxp,imx7-mipi-csi2.yaml new file mode 100644 index 000000000000..0668332959e7 --- /dev/null +++ b/Documentation/devicetree/bindings/media/nxp,imx7-mipi-csi2.yaml @@ -0,0 +1,173 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/nxp,imx7-mipi-csi2.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP i.MX7 Mipi CSI2 + +maintainers: + - Rui Miguel Silva + +description: | + This is the device node for the MIPI CSI-2 receiver core in i.MX7 soc. It is + compatible with previous version of samsung d-phy. + +properties: + compatible: + const: fsl,imx7-mipi-csi2 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + minItems: 3 + maxItems: 3 + + clock-names: + items: + - const: pclk + - const: wrap + - const: phy + + power-domains: + maxItems: 1 + + phy-supply: + description: + Phandle to a regulator that provides power to the PHY. This + regulator will be managed during the PHY power on/off sequence. + + resets: + maxItems: 1 + + reset-names: + const: mrst + + clock-frequency: + description: + The IP main (system bus) clock frequency in Hertz + default: 166000000 + + fsl,csis-hs-settle: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Differential receiver (HS-RX) settle time + + ports: + type: object + description: + A node containing input and output port nodes with endpoint definitions + as documented in + Documentation/devicetree/bindings/media/video-interfaces.txt + + properties: + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + + port@0: + type: object + description: + Input port node, single endpoint describing the CSI-2 transmitter. + + properties: + reg: + const: 0 + + endpoint: + type: object + + properties: + data-lanes: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: See ../video-interfaces.txt + oneOf: + - items: + - const: 1 + - items: + - const: 1 + - const: 2 + + remote-endpoint: true + + required: + - data-lanes + - remote-endpoint + + additionalProperties: false + + additionalProperties: false + + port@1: + type: object + description: + Output port node + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - power-domains + - phy-supply + - resets + - reset-names + - ports + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + + mipi_csi: mipi-csi@30750000 { + compatible = "fsl,imx7-mipi-csi2"; + reg = <0x30750000 0x10000>; + interrupts = ; + + clocks = <&clks IMX7D_IPG_ROOT_CLK>, + <&clks IMX7D_MIPI_CSI_ROOT_CLK>, + <&clks IMX7D_MIPI_DPHY_ROOT_CLK>; + clock-names = "pclk", "wrap", "phy"; + clock-frequency = <166000000>; + + power-domains = <&pgc_mipi_phy>; + phy-supply = <®_1p0d>; + resets = <&src IMX7_RESET_MIPI_PHY_MRST>; + reset-names = "mrst"; + fsl,csis-hs-settle = <3>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + mipi_from_sensor: endpoint { + remote-endpoint = <&ov2680_to_mipi>; + data-lanes = <1>; + }; + }; + + port@1 { + reg = <1>; + + mipi_vc0_to_csi_mux: endpoint { + remote-endpoint = <&csi_mux_from_mipi_vc0>; + }; + }; + }; + }; + +... diff --git a/MAINTAINERS b/MAINTAINERS index 221385eedc9d..e3a828249c8c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10849,8 +10849,8 @@ L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git F: Documentation/admin-guide/media/imx7.rst -F: Documentation/devicetree/bindings/media/imx7-mipi-csi2.txt F: Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml +F: Documentation/devicetree/bindings/media/nxp,imx7-mipi-csi2.yaml F: drivers/staging/media/imx/imx7-media-csi.c F: drivers/staging/media/imx/imx7-mipi-csis.c -- cgit v1.2.3 From defbac5d79b02e5c006e08f02a8f6fdcdca1a5db Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 16 Nov 2020 16:42:38 +0100 Subject: media: i2c: imx219: Declare that the driver can create events The flag V4L2_SUBDEV_FL_HAS_EVENTS is required if the subdev can generate events. It can create events from the ctrl handler, therefore this is required. Signed-off-by: Dave Stevenson Signed-off-by: Dafna Hirschfeld Reviewed-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx219.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index d5349d1ca485..2b17ec0ddbbe 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -1494,7 +1494,8 @@ static int imx219_probe(struct i2c_client *client) /* Initialize subdev */ imx219->sd.internal_ops = &imx219_internal_ops; - imx219->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + imx219->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | + V4L2_SUBDEV_FL_HAS_EVENTS; imx219->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; /* Initialize source pad */ -- cgit v1.2.3 From 3f56df4c8ffeb120ed41906d3aae71799b7e726a Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 9 Nov 2020 23:16:52 +0100 Subject: media: sunxi-cir: ensure IR is handled when it is continuous If a user holds a button down on a remote, then no ir idle interrupt will be generated until the user releases the button, depending on how quickly the remote repeats. No IR is processed until that point, which means that holding down a button may not do anything. This also resolves an issue on a Cubieboard 1 where the IR receiver is picking up ambient infrared as IR and spews out endless "rc rc0: IR event FIFO is full!" messages unless you choose to live in the dark. Cc: stable@vger.kernel.org Tested-by: Hans Verkuil Acked-by: Maxime Ripard Reported-by: Hans Verkuil Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/sunxi-cir.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c index ddee6ee37bab..4afc5895bee7 100644 --- a/drivers/media/rc/sunxi-cir.c +++ b/drivers/media/rc/sunxi-cir.c @@ -137,6 +137,8 @@ static irqreturn_t sunxi_ir_irq(int irqno, void *dev_id) } else if (status & REG_RXSTA_RPE) { ir_raw_event_set_idle(ir->rc, true); ir_raw_event_handle(ir->rc); + } else { + ir_raw_event_handle(ir->rc); } spin_unlock(&ir->ir_lock); -- cgit v1.2.3 From 371443de3c991f7b025d5203754a3497b7ea7c32 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Tue, 10 Nov 2020 09:30:38 +0100 Subject: media: sunxi-cir: allow timeout to be set at runtime This allows the timeout to be set with the LIRC_SET_REC_TIMEOUT ioctl. The timeout was hardcoded at just over 20ms, but returned 120ms when queried with the LIRC_GET_REC_TIMEOUT ioctl. This also ensures the idle threshold is set correctly with a base clock other than 8Mhz. Acked-by: Maxime Ripard Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/sunxi-cir.c | 48 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c index 4afc5895bee7..8555c7798706 100644 --- a/drivers/media/rc/sunxi-cir.c +++ b/drivers/media/rc/sunxi-cir.c @@ -73,10 +73,6 @@ #define SUNXI_IR_BASE_CLK 8000000 /* Noise threshold in samples */ #define SUNXI_IR_RXNOISE 1 -/* Idle Threshold in samples */ -#define SUNXI_IR_RXIDLE 20 -/* Time after which device stops sending data in ms */ -#define SUNXI_IR_TIMEOUT 120 /** * struct sunxi_ir_quirks - Differences between SoC variants. @@ -146,6 +142,41 @@ static irqreturn_t sunxi_ir_irq(int irqno, void *dev_id) return IRQ_HANDLED; } +/* Convert idle threshold to usec */ +static unsigned int sunxi_ithr_to_usec(unsigned int base_clk, unsigned int ithr) +{ + return DIV_ROUND_CLOSEST(USEC_PER_SEC * (ithr + 1), + base_clk / (128 * 64)); +} + +/* Convert usec to idle threshold */ +static unsigned int sunxi_usec_to_ithr(unsigned int base_clk, unsigned int usec) +{ + /* make sure we don't end up with a timeout less than requested */ + return DIV_ROUND_UP((base_clk / (128 * 64)) * usec, USEC_PER_SEC) - 1; +} + +static int sunxi_ir_set_timeout(struct rc_dev *rc_dev, unsigned int timeout) +{ + struct sunxi_ir *ir = rc_dev->priv; + unsigned int base_clk = clk_get_rate(ir->clk); + unsigned long flags; + + unsigned int ithr = sunxi_usec_to_ithr(base_clk, timeout); + + dev_dbg(rc_dev->dev.parent, "setting idle threshold to %u\n", ithr); + + spin_lock_irqsave(&ir->ir_lock, flags); + /* Set noise threshold and idle threshold */ + writel(REG_CIR_NTHR(SUNXI_IR_RXNOISE) | REG_CIR_ITHR(ithr), + ir->base + SUNXI_IR_CIR_REG); + spin_unlock_irqrestore(&ir->ir_lock, flags); + + rc_dev->timeout = sunxi_ithr_to_usec(base_clk, ithr); + + return 0; +} + static int sunxi_ir_probe(struct platform_device *pdev) { int ret = 0; @@ -242,9 +273,11 @@ static int sunxi_ir_probe(struct platform_device *pdev) ir->rc->map_name = ir->map_name ?: RC_MAP_EMPTY; ir->rc->dev.parent = dev; ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; - /* Frequency after IR internal divider with sample period in ns */ + /* Frequency after IR internal divider with sample period in us */ ir->rc->rx_resolution = (USEC_PER_SEC / (b_clk_freq / 64)); - ir->rc->timeout = MS_TO_US(SUNXI_IR_TIMEOUT); + ir->rc->min_timeout = sunxi_ithr_to_usec(b_clk_freq, 0); + ir->rc->max_timeout = sunxi_ithr_to_usec(b_clk_freq, 255); + ir->rc->s_timeout = sunxi_ir_set_timeout; ir->rc->driver_name = SUNXI_IR_DEV; ret = rc_register_device(ir->rc); @@ -272,8 +305,7 @@ static int sunxi_ir_probe(struct platform_device *pdev) writel(REG_CTL_MD, ir->base+SUNXI_IR_CTL_REG); /* Set noise threshold and idle threshold */ - writel(REG_CIR_NTHR(SUNXI_IR_RXNOISE)|REG_CIR_ITHR(SUNXI_IR_RXIDLE), - ir->base + SUNXI_IR_CIR_REG); + sunxi_ir_set_timeout(ir->rc, IR_DEFAULT_TIMEOUT); /* Invert Input Signal */ writel(REG_RXCTL_RPPI, ir->base + SUNXI_IR_RXCTL_REG); -- cgit v1.2.3 From cea357bc25713f909bd9d6f0d71eae5e3a5b4e85 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 18 Nov 2020 11:43:40 +0100 Subject: media: lirc: ensure RC_PROTO_MAX has documentation The enum rc_proto value RC_PROTO_MAX has no documentation, this is causing a warning while building the documentation. Fixes: 72e637fec558 ("media: rc: validate that "rc_proto" is reasonable") Reported-by: Stephen Rothwell Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/lirc.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/linux/lirc.h b/include/uapi/linux/lirc.h index c1eb960adde3..bf0672a6d341 100644 --- a/include/uapi/linux/lirc.h +++ b/include/uapi/linux/lirc.h @@ -196,6 +196,7 @@ struct lirc_scancode { * @RC_PROTO_RCMM24: RC-MM protocol 24 bits * @RC_PROTO_RCMM32: RC-MM protocol 32 bits * @RC_PROTO_XBOX_DVD: Xbox DVD Movie Playback Kit protocol + * @RC_PROTO_MAX: Maximum value of enum rc_proto */ enum rc_proto { RC_PROTO_UNKNOWN = 0, -- cgit v1.2.3 From 864ed874d74a36e9b708e41c98cf791bb7786507 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 22 Oct 2020 19:47:00 +0200 Subject: media: camss: ispif: Correctly reset based on the VFE ID Resetting the ISPIF VFE0 context is wrong if we are using the VFE1 for dual-camera or simply because a secondary camera is connected to it: in this case the reset will always happen on the VFE0 ctx of the ISPIF, which is .. useless. Fix this usecase by adding the ISPIF_RST_CMD_1 address and choose where to do the (or what to) reset based on the VFE line id. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Robert Foss Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/camss/camss-ispif.c | 85 ++++++++++++++++--------- drivers/media/platform/qcom/camss/camss-ispif.h | 2 +- 2 files changed, 56 insertions(+), 31 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c index db94cfd6c508..754f0d044c38 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.c +++ b/drivers/media/platform/qcom/camss/camss-ispif.c @@ -26,6 +26,7 @@ #define MSM_ISPIF_NAME "msm_ispif" #define ISPIF_RST_CMD_0 0x008 +#define ISPIF_RST_CMD_1 0x00c #define ISPIF_RST_CMD_0_STROBED_RST_EN (1 << 0) #define ISPIF_RST_CMD_0_MISC_LOGIC_RST (1 << 1) #define ISPIF_RST_CMD_0_SW_REG_RST (1 << 2) @@ -179,7 +180,10 @@ static irqreturn_t ispif_isr_8x96(int irq, void *dev) writel(0x1, ispif->base + ISPIF_IRQ_GLOBAL_CLEAR_CMD); if ((value0 >> 27) & 0x1) - complete(&ispif->reset_complete); + complete(&ispif->reset_complete[0]); + + if ((value3 >> 27) & 0x1) + complete(&ispif->reset_complete[1]); if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW)) dev_err_ratelimited(to_device(ispif), "VFE0 pix0 overflow\n"); @@ -237,7 +241,7 @@ static irqreturn_t ispif_isr_8x16(int irq, void *dev) writel(0x1, ispif->base + ISPIF_IRQ_GLOBAL_CLEAR_CMD); if ((value0 >> 27) & 0x1) - complete(&ispif->reset_complete); + complete(&ispif->reset_complete[0]); if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW)) dev_err_ratelimited(to_device(ispif), "VFE0 pix0 overflow\n"); @@ -257,33 +261,18 @@ static irqreturn_t ispif_isr_8x16(int irq, void *dev) return IRQ_HANDLED; } -/* - * ispif_reset - Trigger reset on ISPIF module and wait to complete - * @ispif: ISPIF device - * - * Return 0 on success or a negative error code otherwise - */ -static int ispif_reset(struct ispif_device *ispif) +static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id) { unsigned long time; u32 val; - int ret; - - ret = camss_pm_domain_on(to_camss(ispif), PM_DOMAIN_VFE0); - if (ret < 0) - return ret; - ret = camss_pm_domain_on(to_camss(ispif), PM_DOMAIN_VFE1); - if (ret < 0) - return ret; - - ret = camss_enable_clocks(ispif->nclocks_for_reset, - ispif->clock_for_reset, - to_device(ispif)); - if (ret < 0) - return ret; + if (vfe_id > (to_camss(ispif)->vfe_num - 1)) { + dev_err(to_device(ispif), + "Error: asked reset for invalid VFE%d\n", vfe_id); + return -ENOENT; + } - reinit_completion(&ispif->reset_complete); + reinit_completion(&ispif->reset_complete[vfe_id]); val = ISPIF_RST_CMD_0_STROBED_RST_EN | ISPIF_RST_CMD_0_MISC_LOGIC_RST | @@ -303,15 +292,50 @@ static int ispif_reset(struct ispif_device *ispif) ISPIF_RST_CMD_0_RDI_OUTPUT_1_MISR_RST | ISPIF_RST_CMD_0_RDI_OUTPUT_2_MISR_RST; - writel_relaxed(val, ispif->base + ISPIF_RST_CMD_0); + if (vfe_id == 1) + writel_relaxed(val, ispif->base + ISPIF_RST_CMD_1); + else + writel_relaxed(val, ispif->base + ISPIF_RST_CMD_0); - time = wait_for_completion_timeout(&ispif->reset_complete, + time = wait_for_completion_timeout(&ispif->reset_complete[vfe_id], msecs_to_jiffies(ISPIF_RESET_TIMEOUT_MS)); if (!time) { - dev_err(to_device(ispif), "ISPIF reset timeout\n"); - ret = -EIO; + dev_err(to_device(ispif), + "ISPIF for VFE%d reset timeout\n", vfe_id); + return -EIO; } + return 0; +} + +/* + * ispif_reset - Trigger reset on ISPIF module and wait to complete + * @ispif: ISPIF device + * + * Return 0 on success or a negative error code otherwise + */ +static int ispif_reset(struct ispif_device *ispif, u8 vfe_id) +{ + int ret; + + ret = camss_pm_domain_on(to_camss(ispif), PM_DOMAIN_VFE0); + if (ret < 0) + return ret; + + ret = camss_pm_domain_on(to_camss(ispif), PM_DOMAIN_VFE1); + if (ret < 0) + return ret; + + ret = camss_enable_clocks(ispif->nclocks_for_reset, + ispif->clock_for_reset, + to_device(ispif)); + if (ret < 0) + return ret; + + ret = ispif_vfe_reset(ispif, vfe_id); + if (ret) + dev_dbg(to_device(ispif), "ISPIF Reset failed\n"); + camss_disable_clocks(ispif->nclocks_for_reset, ispif->clock_for_reset); camss_pm_domain_off(to_camss(ispif), PM_DOMAIN_VFE0); @@ -355,7 +379,7 @@ static int ispif_set_power(struct v4l2_subdev *sd, int on) goto exit; } - ret = ispif_reset(ispif); + ret = ispif_reset(ispif, line->vfe_id); if (ret < 0) { pm_runtime_put_sync(dev); camss_disable_clocks(ispif->nclocks, ispif->clock); @@ -1192,7 +1216,8 @@ int msm_ispif_subdev_init(struct ispif_device *ispif, mutex_init(&ispif->config_lock); - init_completion(&ispif->reset_complete); + for (i = 0; i < MSM_ISPIF_VFE_NUM; i++) + init_completion(&ispif->reset_complete[i]); return 0; } diff --git a/drivers/media/platform/qcom/camss/camss-ispif.h b/drivers/media/platform/qcom/camss/camss-ispif.h index 1a5ba2425a42..4132174f7ea1 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.h +++ b/drivers/media/platform/qcom/camss/camss-ispif.h @@ -56,7 +56,7 @@ struct ispif_device { int nclocks; struct camss_clock *clock_for_reset; int nclocks_for_reset; - struct completion reset_complete; + struct completion reset_complete[MSM_ISPIF_VFE_NUM]; int power_count; struct mutex power_lock; struct ispif_intf_cmd_reg intf_cmd[MSM_ISPIF_VFE_NUM]; -- cgit v1.2.3 From 1786653aa2e3b1533cb576b13dabdf4032ce76e5 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 22 Oct 2020 19:47:01 +0200 Subject: media: camss: vfe-4-7: Rename get_ub_size, set_qos, set_ds, wm_enable In preparation to add support for VFE 4.8, rename these functions by adding the vfe version that they are referred to (for example, vfe_get_ub_size -> vfe47_get_ub_size), as these are the only ones that will be different for the VFE version 4.8. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Robert Foss Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/camss/camss-vfe-4-7.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c index 0dca8bf9281e..6f380a450ca1 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c @@ -246,7 +246,7 @@ static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev) dev_err(dev, "VFE HW Version = 0x%08x\n", hw_version); } -static u16 vfe_get_ub_size(u8 vfe_id) +static u16 vfe47_get_ub_size(u8 vfe_id) { if (vfe_id == 0) return MSM_VFE_VFE0_UB_SIZE_RDI; @@ -299,7 +299,7 @@ static void vfe_halt_clear(struct vfe_device *vfe) writel_relaxed(0x0, vfe->base + VFE_0_BUS_BDG_CMD); } -static void vfe_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable) +static void vfe47_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable) { if (enable) vfe_reg_set(vfe, VFE_0_BUS_IMAGE_MASTER_n_WR_CFG(wm), @@ -883,7 +883,7 @@ static void vfe_set_clamp_cfg(struct vfe_device *vfe) writel_relaxed(val, vfe->base + VFE_0_CLAMP_ENC_MIN_CFG); } -static void vfe_set_qos(struct vfe_device *vfe) +static void vfe47_set_qos(struct vfe_device *vfe) { u32 val = VFE_0_BUS_BDG_QOS_CFG_0_CFG; u32 val7 = VFE_0_BUS_BDG_QOS_CFG_7_CFG; @@ -898,7 +898,7 @@ static void vfe_set_qos(struct vfe_device *vfe) writel_relaxed(val7, vfe->base + VFE_0_BUS_BDG_QOS_CFG_7); } -static void vfe_set_ds(struct vfe_device *vfe) +static void vfe47_set_ds(struct vfe_device *vfe) { u32 val = VFE_0_BUS_BDG_DS_CFG_0_CFG; u32 val16 = VFE_0_BUS_BDG_DS_CFG_16_CFG; @@ -1098,11 +1098,11 @@ static irqreturn_t vfe_isr(int irq, void *dev) const struct vfe_hw_ops vfe_ops_4_7 = { .hw_version_read = vfe_hw_version_read, - .get_ub_size = vfe_get_ub_size, + .get_ub_size = vfe47_get_ub_size, .global_reset = vfe_global_reset, .halt_request = vfe_halt_request, .halt_clear = vfe_halt_clear, - .wm_enable = vfe_wm_enable, + .wm_enable = vfe47_wm_enable, .wm_frame_based = vfe_wm_frame_based, .wm_line_based = vfe_wm_line_based, .wm_set_framedrop_period = vfe_wm_set_framedrop_period, @@ -1128,8 +1128,8 @@ const struct vfe_hw_ops vfe_ops_4_7 = { .set_scale_cfg = vfe_set_scale_cfg, .set_crop_cfg = vfe_set_crop_cfg, .set_clamp_cfg = vfe_set_clamp_cfg, - .set_qos = vfe_set_qos, - .set_ds = vfe_set_ds, + .set_qos = vfe47_set_qos, + .set_ds = vfe47_set_ds, .set_cgc_override = vfe_set_cgc_override, .set_camif_cfg = vfe_set_camif_cfg, .set_camif_cmd = vfe_set_camif_cmd, -- cgit v1.2.3 From 40296e712cad0008f627a56151c1a0e6297e1309 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 22 Oct 2020 19:47:02 +0200 Subject: media: camss: vfe: Add support for VFE 4.8 Add the support for VFE 4.8 in the camss-vfe-4-7 driver, as this one really is a minor revision, requiring the very same management and basically having the same register layout as VFE 4.7, but needing a different QoS and DS configuration, using a different register to enable the wm and habing the same UB size for both instances (instead of a different size between instance 0 and 1). Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Robert Foss Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/camss/camss-vfe-4-7.c | 115 ++++++++++++++++++++++ drivers/media/platform/qcom/camss/camss-vfe.h | 1 + 2 files changed, 116 insertions(+) diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c index 6f380a450ca1..b5704a2f119b 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c @@ -133,6 +133,11 @@ #define VFE_0_BUS_BDG_QOS_CFG_7 0x420 #define VFE_0_BUS_BDG_QOS_CFG_7_CFG 0x0001aaa9 +#define VFE48_0_BUS_BDG_QOS_CFG_0_CFG 0xaaa5aaa5 +#define VFE48_0_BUS_BDG_QOS_CFG_3_CFG 0xaa55aaa5 +#define VFE48_0_BUS_BDG_QOS_CFG_4_CFG 0xaa55aa55 +#define VFE48_0_BUS_BDG_QOS_CFG_7_CFG 0x0005aa55 + #define VFE_0_BUS_BDG_DS_CFG_0 0x424 #define VFE_0_BUS_BDG_DS_CFG_0_CFG 0xcccc0011 #define VFE_0_BUS_BDG_DS_CFG_1 0x428 @@ -153,6 +158,9 @@ #define VFE_0_BUS_BDG_DS_CFG_16 0x464 #define VFE_0_BUS_BDG_DS_CFG_16_CFG 0x40000103 +#define VFE48_0_BUS_BDG_DS_CFG_0_CFG 0xcccc1111 +#define VFE48_0_BUS_BDG_DS_CFG_16_CFG 0x00000110 + #define VFE_0_RDI_CFG_x(x) (0x46c + (0x4 * (x))) #define VFE_0_RDI_CFG_x_RDI_STREAM_SEL_SHIFT 28 #define VFE_0_RDI_CFG_x_RDI_STREAM_SEL_MASK (0xf << 28) @@ -231,6 +239,9 @@ #define VFE_0_REALIGN_BUF_CFG_CR_ODD_PIXEL BIT(3) #define VFE_0_REALIGN_BUF_CFG_HSUB_ENABLE BIT(4) +#define VFE48_0_BUS_IMAGE_MASTER_CMD 0xcec +#define VFE48_0_BUS_IMAGE_MASTER_n_SHIFT(x) (2 * (x)) + #define CAMIF_TIMEOUT_SLEEP_US 1000 #define CAMIF_TIMEOUT_ALL_US 1000000 @@ -1139,3 +1150,107 @@ const struct vfe_hw_ops vfe_ops_4_7 = { .violation_read = vfe_violation_read, .isr = vfe_isr, }; + +static u16 vfe48_get_ub_size(u8 vfe_id) +{ + /* On VFE4.8 the ub-size is the same on both instances */ + return MSM_VFE_VFE0_UB_SIZE_RDI; +} + +static void vfe48_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable) +{ + if (enable) + writel_relaxed(2 << VFE48_0_BUS_IMAGE_MASTER_n_SHIFT(wm), + vfe->base + VFE48_0_BUS_IMAGE_MASTER_CMD); + else + writel_relaxed(1 << VFE48_0_BUS_IMAGE_MASTER_n_SHIFT(wm), + vfe->base + VFE48_0_BUS_IMAGE_MASTER_CMD); + + /* The WM must be enabled before sending other commands */ + wmb(); +} + +static void vfe48_set_qos(struct vfe_device *vfe) +{ + u32 val = VFE48_0_BUS_BDG_QOS_CFG_0_CFG; + u32 val3 = VFE48_0_BUS_BDG_QOS_CFG_3_CFG; + u32 val4 = VFE48_0_BUS_BDG_QOS_CFG_4_CFG; + u32 val7 = VFE48_0_BUS_BDG_QOS_CFG_7_CFG; + + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_0); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_1); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_2); + writel_relaxed(val3, vfe->base + VFE_0_BUS_BDG_QOS_CFG_3); + writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_4); + writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_5); + writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_6); + writel_relaxed(val7, vfe->base + VFE_0_BUS_BDG_QOS_CFG_7); +} + +static void vfe48_set_ds(struct vfe_device *vfe) +{ + u32 val = VFE48_0_BUS_BDG_DS_CFG_0_CFG; + u32 val16 = VFE48_0_BUS_BDG_DS_CFG_16_CFG; + + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_0); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_1); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_2); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_3); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_4); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_5); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_6); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_7); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_8); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_9); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_10); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_11); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_12); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_13); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_14); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_15); + writel_relaxed(val16, vfe->base + VFE_0_BUS_BDG_DS_CFG_16); +} + +const struct vfe_hw_ops vfe_ops_4_8 = { + .hw_version_read = vfe_hw_version_read, + .get_ub_size = vfe48_get_ub_size, + .global_reset = vfe_global_reset, + .halt_request = vfe_halt_request, + .halt_clear = vfe_halt_clear, + .wm_enable = vfe48_wm_enable, + .wm_frame_based = vfe_wm_frame_based, + .wm_line_based = vfe_wm_line_based, + .wm_set_framedrop_period = vfe_wm_set_framedrop_period, + .wm_set_framedrop_pattern = vfe_wm_set_framedrop_pattern, + .wm_set_ub_cfg = vfe_wm_set_ub_cfg, + .bus_reload_wm = vfe_bus_reload_wm, + .wm_set_ping_addr = vfe_wm_set_ping_addr, + .wm_set_pong_addr = vfe_wm_set_pong_addr, + .wm_get_ping_pong_status = vfe_wm_get_ping_pong_status, + .bus_enable_wr_if = vfe_bus_enable_wr_if, + .bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi, + .wm_set_subsample = vfe_wm_set_subsample, + .bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi, + .set_xbar_cfg = vfe_set_xbar_cfg, + .set_realign_cfg = vfe_set_realign_cfg, + .set_rdi_cid = vfe_set_rdi_cid, + .reg_update = vfe_reg_update, + .reg_update_clear = vfe_reg_update_clear, + .enable_irq_wm_line = vfe_enable_irq_wm_line, + .enable_irq_pix_line = vfe_enable_irq_pix_line, + .enable_irq_common = vfe_enable_irq_common, + .set_demux_cfg = vfe_set_demux_cfg, + .set_scale_cfg = vfe_set_scale_cfg, + .set_crop_cfg = vfe_set_crop_cfg, + .set_clamp_cfg = vfe_set_clamp_cfg, + .set_qos = vfe48_set_qos, + .set_ds = vfe48_set_ds, + .set_cgc_override = vfe_set_cgc_override, + .set_camif_cfg = vfe_set_camif_cfg, + .set_camif_cmd = vfe_set_camif_cmd, + .set_module_cfg = vfe_set_module_cfg, + .camif_wait_for_stop = vfe_camif_wait_for_stop, + .isr_read = vfe_isr_read, + .violation_read = vfe_violation_read, + .isr = vfe_isr, +}; diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h index a90b0d2cc6de..5bce6736e4bb 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.h +++ b/drivers/media/platform/qcom/camss/camss-vfe.h @@ -180,5 +180,6 @@ void msm_vfe_get_vfe_line_id(struct media_entity *entity, enum vfe_line_id *id); extern const struct vfe_hw_ops vfe_ops_4_1; extern const struct vfe_hw_ops vfe_ops_4_7; +extern const struct vfe_hw_ops vfe_ops_4_8; #endif /* QC_MSM_CAMSS_VFE_H */ -- cgit v1.2.3 From 3cba9d22c358a3a095cbfcc7bec26e67c29ee361 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 22 Oct 2020 19:47:05 +0200 Subject: media: dt-bindings: media: qcom,camss: Add bindings for SDM660 camss Add bindings for qcom,sdm660-camss in order to support the camera subsystem on SDM630/660 and SDA variants. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Robert Foss Acked-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/qcom,camss.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/media/qcom,camss.txt b/Documentation/devicetree/bindings/media/qcom,camss.txt index 09eb6ed99114..498234629e21 100644 --- a/Documentation/devicetree/bindings/media/qcom,camss.txt +++ b/Documentation/devicetree/bindings/media/qcom,camss.txt @@ -8,6 +8,7 @@ Qualcomm Camera Subsystem Definition: Should contain one of: - "qcom,msm8916-camss" - "qcom,msm8996-camss" + - "qcom,sdm660-camss" - reg: Usage: required Value type: @@ -64,30 +65,36 @@ Qualcomm Camera Subsystem Value type: Definition: Should contain the following entries: - "top_ahb" + - "throttle_axi" (660 only) - "ispif_ahb" - "csiphy0_timer" - "csiphy1_timer" - "csiphy2_timer" (8996 only) + - "csiphy_ahb2crif" (660 only) - "csi0_ahb" - "csi0" - "csi0_phy" - "csi0_pix" - "csi0_rdi" + - "cphy_csid0" (660 only) - "csi1_ahb" - "csi1" - "csi1_phy" - "csi1_pix" - "csi1_rdi" + - "cphy_csid1" (660 only) - "csi2_ahb" (8996 only) - "csi2" (8996 only) - "csi2_phy" (8996 only) - "csi2_pix" (8996 only) - "csi2_rdi" (8996 only) + - "cphy_csid2" (660 only) - "csi3_ahb" (8996 only) - "csi3" (8996 only) - "csi3_phy" (8996 only) - "csi3_pix" (8996 only) - "csi3_rdi" (8996 only) + - "cphy_csid3" (660 only) - "ahb" - "vfe0" - "csi_vfe0" -- cgit v1.2.3 From 9e5d158189c6a6259c1c78bc95d8ae950b4ec66a Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 22 Oct 2020 19:47:03 +0200 Subject: media: camss: Add support for SDM630/636/660 camera subsystem Add support for the Qualcomm SDM630/636/660 and SDA variants' camera subsystem. These SoCs are equipped with: - 3x CSI PHY 3-Phase v1.0 (downstream csiphy-v3.5) - 4x CSID v5.0 - 2x ISPIF v3.0 - 2x VFE 4.8 As a note, this camera subsystem is very similar to the one that is found in the MSM8998/APQ8098 SoCs. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Robert Foss Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/camss/camss-csid.c | 9 +- drivers/media/platform/qcom/camss/camss-csiphy.c | 3 +- drivers/media/platform/qcom/camss/camss-ispif.c | 15 +- drivers/media/platform/qcom/camss/camss-vfe.c | 19 ++- drivers/media/platform/qcom/camss/camss-video.c | 3 +- drivers/media/platform/qcom/camss/camss.c | 206 ++++++++++++++++++++++- drivers/media/platform/qcom/camss/camss.h | 1 + 7 files changed, 237 insertions(+), 19 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c index 2ffcda06706b..be3fe76f3dc3 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.c +++ b/drivers/media/platform/qcom/camss/camss-csid.c @@ -383,7 +383,8 @@ static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code, return 0; return sink_code; - } else if (csid->camss->version == CAMSS_8x96) { + } else if (csid->camss->version == CAMSS_8x96 || + csid->camss->version == CAMSS_660) { switch (sink_code) { case MEDIA_BUS_FMT_SBGGR10_1X10: { @@ -718,7 +719,8 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable) val |= df << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT; val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP; - if (csid->camss->version == CAMSS_8x96) { + if (csid->camss->version == CAMSS_8x96 || + csid->camss->version == CAMSS_660) { u32 sink_code = csid->fmt[MSM_CSID_PAD_SINK].code; u32 src_code = csid->fmt[MSM_CSID_PAD_SRC].code; @@ -1098,7 +1100,8 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid, csid->formats = csid_formats_8x16; csid->nformats = ARRAY_SIZE(csid_formats_8x16); - } else if (camss->version == CAMSS_8x96) { + } else if (camss->version == CAMSS_8x96 || + camss->version == CAMSS_660) { csid->formats = csid_formats_8x96; csid->nformats = ARRAY_SIZE(csid_formats_8x96); diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index 85b24054f35e..defd394b670d 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -554,7 +554,8 @@ int msm_csiphy_subdev_init(struct camss *camss, csiphy->ops = &csiphy_ops_2ph_1_0; csiphy->formats = csiphy_formats_8x16; csiphy->nformats = ARRAY_SIZE(csiphy_formats_8x16); - } else if (camss->version == CAMSS_8x96) { + } else if (camss->version == CAMSS_8x96 || + camss->version == CAMSS_660) { csiphy->ops = &csiphy_ops_3ph_1_0; csiphy->formats = csiphy_formats_8x96; csiphy->nformats = ARRAY_SIZE(csiphy_formats_8x96); diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c index 754f0d044c38..adeb92808998 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.c +++ b/drivers/media/platform/qcom/camss/camss-ispif.c @@ -825,7 +825,8 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable) ispif_select_csid(ispif, intf, csid, vfe, 1); ispif_select_cid(ispif, intf, cid, vfe, 1); ispif_config_irq(ispif, intf, vfe, 1); - if (to_camss(ispif)->version == CAMSS_8x96) + if (to_camss(ispif)->version == CAMSS_8x96 || + to_camss(ispif)->version == CAMSS_660) ispif_config_pack(ispif, line->fmt[MSM_ISPIF_PAD_SINK].code, intf, cid, vfe, 1); @@ -842,7 +843,8 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable) return ret; mutex_lock(&ispif->config_lock); - if (to_camss(ispif)->version == CAMSS_8x96) + if (to_camss(ispif)->version == CAMSS_8x96 || + to_camss(ispif)->version == CAMSS_660) ispif_config_pack(ispif, line->fmt[MSM_ISPIF_PAD_SINK].code, intf, cid, vfe, 0); @@ -1098,7 +1100,8 @@ int msm_ispif_subdev_init(struct ispif_device *ispif, /* Number of ISPIF lines - same as number of CSID hardware modules */ if (to_camss(ispif)->version == CAMSS_8x16) ispif->line_num = 2; - else if (to_camss(ispif)->version == CAMSS_8x96) + else if (to_camss(ispif)->version == CAMSS_8x96 || + to_camss(ispif)->version == CAMSS_660) ispif->line_num = 4; else return -EINVAL; @@ -1116,7 +1119,8 @@ int msm_ispif_subdev_init(struct ispif_device *ispif, ispif->line[i].formats = ispif_formats_8x16; ispif->line[i].nformats = ARRAY_SIZE(ispif_formats_8x16); - } else if (to_camss(ispif)->version == CAMSS_8x96) { + } else if (to_camss(ispif)->version == CAMSS_8x96 || + to_camss(ispif)->version == CAMSS_660) { ispif->line[i].formats = ispif_formats_8x96; ispif->line[i].nformats = ARRAY_SIZE(ispif_formats_8x96); @@ -1156,7 +1160,8 @@ int msm_ispif_subdev_init(struct ispif_device *ispif, if (to_camss(ispif)->version == CAMSS_8x16) ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x16, IRQF_TRIGGER_RISING, ispif->irq_name, ispif); - else if (to_camss(ispif)->version == CAMSS_8x96) + else if (to_camss(ispif)->version == CAMSS_8x96 || + to_camss(ispif)->version == CAMSS_660) ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x96, IRQF_TRIGGER_RISING, ispif->irq_name, ispif); else diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index b7d2293a5004..fae2b513b2f9 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -205,7 +205,8 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code, return sink_code; } - else if (vfe->camss->version == CAMSS_8x96) + else if (vfe->camss->version == CAMSS_8x96 || + vfe->camss->version == CAMSS_660) switch (sink_code) { case MEDIA_BUS_FMT_YUYV8_2X8: { @@ -1991,12 +1992,19 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, vfe->isr_ops.comp_done = vfe_isr_comp_done; vfe->isr_ops.wm_done = vfe_isr_wm_done; - if (camss->version == CAMSS_8x16) + switch (camss->version) { + case CAMSS_8x16: vfe->ops = &vfe_ops_4_1; - else if (camss->version == CAMSS_8x96) + break; + case CAMSS_8x96: vfe->ops = &vfe_ops_4_7; - else + break; + case CAMSS_660: + vfe->ops = &vfe_ops_4_8; + break; + default: return -EINVAL; + } /* Memory */ @@ -2095,7 +2103,8 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, l->formats = formats_rdi_8x16; l->nformats = ARRAY_SIZE(formats_rdi_8x16); } - } else if (camss->version == CAMSS_8x96) { + } else if (camss->version == CAMSS_8x96 || + camss->version == CAMSS_660) { if (i == VFE_LINE_PIX) { l->formats = formats_pix_8x96; l->nformats = ARRAY_SIZE(formats_pix_8x96); diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index 114c3ae4a4ab..fbba9e45d732 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -970,7 +970,8 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev, video->formats = formats_rdi_8x16; video->nformats = ARRAY_SIZE(formats_rdi_8x16); } - } else if (video->camss->version == CAMSS_8x96) { + } else if (video->camss->version == CAMSS_8x96 || + video->camss->version == CAMSS_660) { if (is_pix) { video->formats = formats_pix_8x96; video->nformats = ARRAY_SIZE(formats_pix_8x96); diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index 9186881afc98..8fefce57bc49 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -283,6 +283,188 @@ static const struct resources vfe_res_8x96[] = { } }; +static const struct resources csiphy_res_660[] = { + /* CSIPHY0 */ + { + .regulator = { NULL }, + .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy0_timer", + "csi0_phy", "csiphy_ahb2crif" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 100000000, 200000000, 269333333 }, + { 0 } }, + .reg = { "csiphy0", "csiphy0_clk_mux" }, + .interrupt = { "csiphy0" } + }, + + /* CSIPHY1 */ + { + .regulator = { NULL }, + .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy1_timer", + "csi1_phy", "csiphy_ahb2crif" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 100000000, 200000000, 269333333 }, + { 0 } }, + .reg = { "csiphy1", "csiphy1_clk_mux" }, + .interrupt = { "csiphy1" } + }, + + /* CSIPHY2 */ + { + .regulator = { NULL }, + .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy2_timer", + "csi2_phy", "csiphy_ahb2crif" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 100000000, 200000000, 269333333 }, + { 0 } }, + .reg = { "csiphy2", "csiphy2_clk_mux" }, + .interrupt = { "csiphy2" } + } +}; + +static const struct resources csid_res_660[] = { + /* CSID0 */ + { + .regulator = { "vdda", "vdd_sec" }, + .clock = { "top_ahb", "ispif_ahb", "csi0_ahb", "ahb", + "csi0", "csi0_phy", "csi0_pix", "csi0_rdi", + "cphy_csid0" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 100000000, 200000000, 310000000, + 404000000, 465000000 }, + { 0 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "csid0" }, + .interrupt = { "csid0" } + }, + + /* CSID1 */ + { + .regulator = { "vdda", "vdd_sec" }, + .clock = { "top_ahb", "ispif_ahb", "csi1_ahb", "ahb", + "csi1", "csi1_phy", "csi1_pix", "csi1_rdi", + "cphy_csid1" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 100000000, 200000000, 310000000, + 404000000, 465000000 }, + { 0 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "csid1" }, + .interrupt = { "csid1" } + }, + + /* CSID2 */ + { + .regulator = { "vdda", "vdd_sec" }, + .clock = { "top_ahb", "ispif_ahb", "csi2_ahb", "ahb", + "csi2", "csi2_phy", "csi2_pix", "csi2_rdi", + "cphy_csid2" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 100000000, 200000000, 310000000, + 404000000, 465000000 }, + { 0 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "csid2" }, + .interrupt = { "csid2" } + }, + + /* CSID3 */ + { + .regulator = { "vdda", "vdd_sec" }, + .clock = { "top_ahb", "ispif_ahb", "csi3_ahb", "ahb", + "csi3", "csi3_phy", "csi3_pix", "csi3_rdi", + "cphy_csid3" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 100000000, 200000000, 310000000, + 404000000, 465000000 }, + { 0 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "csid3" }, + .interrupt = { "csid3" } + } +}; + +static const struct resources_ispif ispif_res_660 = { + /* ISPIF */ + .clock = { "top_ahb", "ahb", "ispif_ahb", + "csi0", "csi0_pix", "csi0_rdi", + "csi1", "csi1_pix", "csi1_rdi", + "csi2", "csi2_pix", "csi2_rdi", + "csi3", "csi3_pix", "csi3_rdi" }, + .clock_for_reset = { "vfe0", "csi_vfe0", "vfe1", "csi_vfe1" }, + .reg = { "ispif", "csi_clk_mux" }, + .interrupt = "ispif" +}; + +static const struct resources vfe_res_660[] = { + /* VFE0 */ + { + .regulator = { NULL }, + .clock = { "throttle_axi", "top_ahb", "ahb", "vfe0", + "csi_vfe0", "vfe_ahb", "vfe0_ahb", "vfe_axi", + "vfe0_stream"}, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 120000000, 200000000, 256000000, + 300000000, 404000000, 480000000, + 540000000, 576000000 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "vfe0" }, + .interrupt = { "vfe0" } + }, + + /* VFE1 */ + { + .regulator = { NULL }, + .clock = { "throttle_axi", "top_ahb", "ahb", "vfe1", + "csi_vfe1", "vfe_ahb", "vfe1_ahb", "vfe_axi", + "vfe1_stream"}, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 120000000, 200000000, 256000000, + 300000000, 404000000, 480000000, + 540000000, 576000000 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "vfe1" }, + .interrupt = { "vfe1" } + } +}; + /* * camss_add_clock_margin - Add margin to clock frequency rate * @rate: Clock frequency rate @@ -397,7 +579,8 @@ int camss_get_pixel_clock(struct media_entity *entity, u32 *pixel_clock) int camss_pm_domain_on(struct camss *camss, int id) { - if (camss->version == CAMSS_8x96) { + if (camss->version == CAMSS_8x96 || + camss->version == CAMSS_660) { camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id], DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE); @@ -411,7 +594,8 @@ int camss_pm_domain_on(struct camss *camss, int id) void camss_pm_domain_off(struct camss *camss, int id) { - if (camss->version == CAMSS_8x96) + if (camss->version == CAMSS_8x96 || + camss->version == CAMSS_660) device_link_del(camss->genpd_link[id]); } @@ -533,6 +717,11 @@ static int camss_init_subdevices(struct camss *camss) csid_res = csid_res_8x96; ispif_res = &ispif_res_8x96; vfe_res = vfe_res_8x96; + } else if (camss->version == CAMSS_660) { + csiphy_res = csiphy_res_660; + csid_res = csid_res_660; + ispif_res = &ispif_res_660; + vfe_res = vfe_res_660; } else { return -EINVAL; } @@ -833,6 +1022,12 @@ static int camss_probe(struct platform_device *pdev) camss->csiphy_num = 3; camss->csid_num = 4; camss->vfe_num = 2; + } else if (of_device_is_compatible(dev->of_node, + "qcom,sdm660-camss")) { + camss->version = CAMSS_660; + camss->csiphy_num = 3; + camss->csid_num = 4; + camss->vfe_num = 2; } else { ret = -EINVAL; goto err_free; @@ -919,7 +1114,8 @@ static int camss_probe(struct platform_device *pdev) } } - if (camss->version == CAMSS_8x96) { + if (camss->version == CAMSS_8x96 || + camss->version == CAMSS_660) { camss->genpd[PM_DOMAIN_VFE0] = dev_pm_domain_attach_by_id( camss->dev, PM_DOMAIN_VFE0); if (IS_ERR(camss->genpd[PM_DOMAIN_VFE0])) @@ -958,7 +1154,8 @@ void camss_delete(struct camss *camss) pm_runtime_disable(camss->dev); - if (camss->version == CAMSS_8x96) { + if (camss->version == CAMSS_8x96 || + camss->version == CAMSS_660) { dev_pm_domain_detach(camss->genpd[PM_DOMAIN_VFE0], true); dev_pm_domain_detach(camss->genpd[PM_DOMAIN_VFE1], true); } @@ -989,6 +1186,7 @@ static int camss_remove(struct platform_device *pdev) static const struct of_device_id camss_dt_match[] = { { .compatible = "qcom,msm8916-camss" }, { .compatible = "qcom,msm8996-camss" }, + { .compatible = "qcom,sdm660-camss" }, { } }; diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index 1376b07889bf..3a0484683cd6 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -65,6 +65,7 @@ enum pm_domain { enum camss_version { CAMSS_8x16, CAMSS_8x96, + CAMSS_660, }; struct camss { -- cgit v1.2.3 From e486781b74cc611d85e66ff0fc6324f65b25196c Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 22 Oct 2020 19:47:04 +0200 Subject: media: camss: csiphy-3ph: Add support for SDM630/660 The CSIPHY on SDM630/660 needs a slightly longer T_HS_CLK_MISS configuration on lanes CFG4. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Robert Foss Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c index 2e65caf1ecae..97cb9de85031 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c @@ -8,6 +8,7 @@ * Copyright (C) 2016-2018 Linaro Ltd. */ +#include "camss.h" #include "camss-csiphy.h" #include @@ -21,6 +22,7 @@ #define CSIPHY_3PH_LNn_CFG3(n) (0x008 + 0x100 * (n)) #define CSIPHY_3PH_LNn_CFG4(n) (0x00c + 0x100 * (n)) #define CSIPHY_3PH_LNn_CFG4_T_HS_CLK_MISS 0xa4 +#define CSIPHY_3PH_LNn_CFG4_T_HS_CLK_MISS_660 0xa5 #define CSIPHY_3PH_LNn_CFG5(n) (0x010 + 0x100 * (n)) #define CSIPHY_3PH_LNn_CFG5_T_HS_DTERM 0x02 #define CSIPHY_3PH_LNn_CFG5_HS_REC_EQ_FQ_INT 0x50 @@ -198,7 +200,10 @@ static void csiphy_lanes_enable(struct csiphy_device *csiphy, val = CSIPHY_3PH_LNn_CFG1_SWI_REC_DLY_PRG; writel_relaxed(val, csiphy->base + CSIPHY_3PH_LNn_CFG1(l)); - val = CSIPHY_3PH_LNn_CFG4_T_HS_CLK_MISS; + if (csiphy->camss->version == CAMSS_660) + val = CSIPHY_3PH_LNn_CFG4_T_HS_CLK_MISS_660; + else + val = CSIPHY_3PH_LNn_CFG4_T_HS_CLK_MISS; writel_relaxed(val, csiphy->base + CSIPHY_3PH_LNn_CFG4(l)); val = CSIPHY_3PH_LNn_MISC1_IS_CLKLANE; -- cgit v1.2.3 From 4863b93cfd2dfe88557f820b3399c3fa2163ec43 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Thu, 22 Oct 2020 19:47:06 +0200 Subject: media: camss: csiphy: Set rate on csiX_phy clock on SDM630/660 The SDM630/660 SoCs (and variants) have another clock source for the PHY, which must be set to a rate that's equal or greater than the CSI PHY timer clock: failing to do this will produce PHY overflows when trying to get a stream from a very high bandwidth camera sensor and outputting no frame or a partial one. Since I haven't found any usecase in which the csiX_phy clock needs to be higher than the csiXphy_timer, let's just set the same rate on both, which seems to work just perfect. Signed-off-by: AngeloGioacchino Del Regno Reviewed-by: Robert Foss Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/camss/camss-csiphy.c | 22 +++++++++++++++++++--- drivers/media/platform/qcom/camss/camss-csiphy.h | 1 + 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index defd394b670d..509c9a59c09c 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -113,9 +113,7 @@ static int csiphy_set_clock_rates(struct csiphy_device *csiphy) for (i = 0; i < csiphy->nclocks; i++) { struct camss_clock *clock = &csiphy->clock[i]; - if (!strcmp(clock->name, "csiphy0_timer") || - !strcmp(clock->name, "csiphy1_timer") || - !strcmp(clock->name, "csiphy2_timer")) { + if (csiphy->rate_set[i]) { u8 bpp = csiphy_get_bpp(csiphy->formats, csiphy->nformats, csiphy->fmt[MSM_CSIPHY_PAD_SINK].code); @@ -613,6 +611,13 @@ int msm_csiphy_subdev_init(struct camss *camss, if (!csiphy->clock) return -ENOMEM; + csiphy->rate_set = devm_kcalloc(dev, + csiphy->nclocks, + sizeof(*csiphy->rate_set), + GFP_KERNEL); + if (!csiphy->rate_set) + return -ENOMEM; + for (i = 0; i < csiphy->nclocks; i++) { struct camss_clock *clock = &csiphy->clock[i]; @@ -640,6 +645,17 @@ int msm_csiphy_subdev_init(struct camss *camss, for (j = 0; j < clock->nfreqs; j++) clock->freq[j] = res->clock_rate[i][j]; + + if (!strcmp(clock->name, "csiphy0_timer") || + !strcmp(clock->name, "csiphy1_timer") || + !strcmp(clock->name, "csiphy2_timer")) + csiphy->rate_set[i] = true; + + if (camss->version == CAMSS_660 && + (!strcmp(clock->name, "csi0_phy") || + !strcmp(clock->name, "csi1_phy") || + !strcmp(clock->name, "csi2_phy"))) + csiphy->rate_set[i] = true; } return 0; diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.h b/drivers/media/platform/qcom/camss/camss-csiphy.h index 376f865ad383..f7967ef836dc 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.h +++ b/drivers/media/platform/qcom/camss/camss-csiphy.h @@ -66,6 +66,7 @@ struct csiphy_device { u32 irq; char irq_name[30]; struct camss_clock *clock; + bool *rate_set; int nclocks; u32 timer_clk_rate; struct csiphy_config cfg; -- cgit v1.2.3 From ac7f9d0283d0d38d8853f67dfd86f02f722f6079 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 26 Nov 2020 12:13:36 +0100 Subject: media: docs: uAPI: rc: dual-license the docs with GPL v2 Make the license for those documents also compatible with GPLv2. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sean Young --- Documentation/userspace-api/media/rc/keytable.c.rst | 2 +- Documentation/userspace-api/media/rc/lirc-dev-intro.rst | 2 +- Documentation/userspace-api/media/rc/lirc-dev.rst | 2 +- Documentation/userspace-api/media/rc/lirc-func.rst | 2 +- Documentation/userspace-api/media/rc/lirc-get-features.rst | 2 +- Documentation/userspace-api/media/rc/lirc-get-rec-mode.rst | 2 +- Documentation/userspace-api/media/rc/lirc-get-rec-resolution.rst | 2 +- Documentation/userspace-api/media/rc/lirc-get-send-mode.rst | 2 +- Documentation/userspace-api/media/rc/lirc-get-timeout.rst | 2 +- Documentation/userspace-api/media/rc/lirc-header.rst | 2 +- Documentation/userspace-api/media/rc/lirc-read.rst | 2 +- Documentation/userspace-api/media/rc/lirc-set-measure-carrier-mode.rst | 2 +- Documentation/userspace-api/media/rc/lirc-set-rec-carrier-range.rst | 2 +- Documentation/userspace-api/media/rc/lirc-set-rec-carrier.rst | 2 +- Documentation/userspace-api/media/rc/lirc-set-rec-timeout-reports.rst | 2 +- Documentation/userspace-api/media/rc/lirc-set-rec-timeout.rst | 2 +- Documentation/userspace-api/media/rc/lirc-set-send-carrier.rst | 2 +- Documentation/userspace-api/media/rc/lirc-set-send-duty-cycle.rst | 2 +- Documentation/userspace-api/media/rc/lirc-set-transmitter-mask.rst | 2 +- Documentation/userspace-api/media/rc/lirc-set-wideband-receiver.rst | 2 +- Documentation/userspace-api/media/rc/lirc-write.rst | 2 +- Documentation/userspace-api/media/rc/rc-intro.rst | 2 +- Documentation/userspace-api/media/rc/rc-protos.rst | 2 +- Documentation/userspace-api/media/rc/rc-sysfs-nodes.rst | 2 +- Documentation/userspace-api/media/rc/rc-table-change.rst | 2 +- Documentation/userspace-api/media/rc/rc-tables.rst | 2 +- Documentation/userspace-api/media/rc/remote_controllers.rst | 2 +- 27 files changed, 27 insertions(+), 27 deletions(-) diff --git a/Documentation/userspace-api/media/rc/keytable.c.rst b/Documentation/userspace-api/media/rc/keytable.c.rst index 0b50cfaf2d86..243e02d2611f 100644 --- a/Documentation/userspace-api/media/rc/keytable.c.rst +++ b/Documentation/userspace-api/media/rc/keytable.c.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later file: uapi/v4l/keytable.c ========================= diff --git a/Documentation/userspace-api/media/rc/lirc-dev-intro.rst b/Documentation/userspace-api/media/rc/lirc-dev-intro.rst index 167b354bf051..266b646d584e 100644 --- a/Documentation/userspace-api/media/rc/lirc-dev-intro.rst +++ b/Documentation/userspace-api/media/rc/lirc-dev-intro.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later .. _lirc_dev_intro: diff --git a/Documentation/userspace-api/media/rc/lirc-dev.rst b/Documentation/userspace-api/media/rc/lirc-dev.rst index 5510dc02a822..978f86d30fae 100644 --- a/Documentation/userspace-api/media/rc/lirc-dev.rst +++ b/Documentation/userspace-api/media/rc/lirc-dev.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later .. _lirc_dev: diff --git a/Documentation/userspace-api/media/rc/lirc-func.rst b/Documentation/userspace-api/media/rc/lirc-func.rst index 420a3dbf0d6b..793f295d3ac9 100644 --- a/Documentation/userspace-api/media/rc/lirc-func.rst +++ b/Documentation/userspace-api/media/rc/lirc-func.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later .. _lirc_func: diff --git a/Documentation/userspace-api/media/rc/lirc-get-features.rst b/Documentation/userspace-api/media/rc/lirc-get-features.rst index 66a243dbd437..4bf25860f932 100644 --- a/Documentation/userspace-api/media/rc/lirc-get-features.rst +++ b/Documentation/userspace-api/media/rc/lirc-get-features.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later .. c:namespace:: RC .. _lirc_get_features: diff --git a/Documentation/userspace-api/media/rc/lirc-get-rec-mode.rst b/Documentation/userspace-api/media/rc/lirc-get-rec-mode.rst index 188478ed1233..628fe31792b2 100644 --- a/Documentation/userspace-api/media/rc/lirc-get-rec-mode.rst +++ b/Documentation/userspace-api/media/rc/lirc-get-rec-mode.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later .. c:namespace:: RC .. _lirc_get_rec_mode: diff --git a/Documentation/userspace-api/media/rc/lirc-get-rec-resolution.rst b/Documentation/userspace-api/media/rc/lirc-get-rec-resolution.rst index e29445c5ce16..4dfa9c23634b 100644 --- a/Documentation/userspace-api/media/rc/lirc-get-rec-resolution.rst +++ b/Documentation/userspace-api/media/rc/lirc-get-rec-resolution.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later .. c:namespace:: RC .. _lirc_get_rec_resolution: diff --git a/Documentation/userspace-api/media/rc/lirc-get-send-mode.rst b/Documentation/userspace-api/media/rc/lirc-get-send-mode.rst index 77472fb5608a..637871805be6 100644 --- a/Documentation/userspace-api/media/rc/lirc-get-send-mode.rst +++ b/Documentation/userspace-api/media/rc/lirc-get-send-mode.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later .. c:namespace:: RC .. _lirc_get_send_mode: diff --git a/Documentation/userspace-api/media/rc/lirc-get-timeout.rst b/Documentation/userspace-api/media/rc/lirc-get-timeout.rst index f5f3e06d6206..597c3282ae12 100644 --- a/Documentation/userspace-api/media/rc/lirc-get-timeout.rst +++ b/Documentation/userspace-api/media/rc/lirc-get-timeout.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later .. c:namespace:: RC .. _lirc_get_min_timeout: diff --git a/Documentation/userspace-api/media/rc/lirc-header.rst b/Documentation/userspace-api/media/rc/lirc-header.rst index 8bd0acc9913a..54cb40b8a065 100644 --- a/Documentation/userspace-api/media/rc/lirc-header.rst +++ b/Documentation/userspace-api/media/rc/lirc-header.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later .. _lirc_header: diff --git a/Documentation/userspace-api/media/rc/lirc-read.rst b/Documentation/userspace-api/media/rc/lirc-read.rst index d589560214f4..ce34318698b7 100644 --- a/Documentation/userspace-api/media/rc/lirc-read.rst +++ b/Documentation/userspace-api/media/rc/lirc-read.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later .. c:namespace:: RC .. _lirc-read: diff --git a/Documentation/userspace-api/media/rc/lirc-set-measure-carrier-mode.rst b/Documentation/userspace-api/media/rc/lirc-set-measure-carrier-mode.rst index 9bf9811a905a..04ced1aa664b 100644 --- a/Documentation/userspace-api/media/rc/lirc-set-measure-carrier-mode.rst +++ b/Documentation/userspace-api/media/rc/lirc-set-measure-carrier-mode.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later .. c:namespace:: RC .. _lirc_set_measure_carrier_mode: diff --git a/Documentation/userspace-api/media/rc/lirc-set-rec-carrier-range.rst b/Documentation/userspace-api/media/rc/lirc-set-rec-carrier-range.rst index 530bc223930a..7512dc86b03a 100644 --- a/Documentation/userspace-api/media/rc/lirc-set-rec-carrier-range.rst +++ b/Documentation/userspace-api/media/rc/lirc-set-rec-carrier-range.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later .. c:namespace:: RC .. _lirc_set_rec_carrier_range: diff --git a/Documentation/userspace-api/media/rc/lirc-set-rec-carrier.rst b/Documentation/userspace-api/media/rc/lirc-set-rec-carrier.rst index 28c928f1cc14..60e321446ea7 100644 --- a/Documentation/userspace-api/media/rc/lirc-set-rec-carrier.rst +++ b/Documentation/userspace-api/media/rc/lirc-set-rec-carrier.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later .. c:namespace:: RC .. _lirc_set_rec_carrier: diff --git a/Documentation/userspace-api/media/rc/lirc-set-rec-timeout-reports.rst b/Documentation/userspace-api/media/rc/lirc-set-rec-timeout-reports.rst index 83e7155c5796..aebe81012939 100644 --- a/Documentation/userspace-api/media/rc/lirc-set-rec-timeout-reports.rst +++ b/Documentation/userspace-api/media/rc/lirc-set-rec-timeout-reports.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later .. c:namespace:: RC .. _lirc_set_rec_timeout_reports: diff --git a/Documentation/userspace-api/media/rc/lirc-set-rec-timeout.rst b/Documentation/userspace-api/media/rc/lirc-set-rec-timeout.rst index 8f3f9adf54ab..bf9fb2cc61c3 100644 --- a/Documentation/userspace-api/media/rc/lirc-set-rec-timeout.rst +++ b/Documentation/userspace-api/media/rc/lirc-set-rec-timeout.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later .. c:namespace:: RC .. _lirc_set_rec_timeout: diff --git a/Documentation/userspace-api/media/rc/lirc-set-send-carrier.rst b/Documentation/userspace-api/media/rc/lirc-set-send-carrier.rst index e3810ba58746..a003f9447553 100644 --- a/Documentation/userspace-api/media/rc/lirc-set-send-carrier.rst +++ b/Documentation/userspace-api/media/rc/lirc-set-send-carrier.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later .. c:namespace:: RC .. _lirc_set_send_carrier: diff --git a/Documentation/userspace-api/media/rc/lirc-set-send-duty-cycle.rst b/Documentation/userspace-api/media/rc/lirc-set-send-duty-cycle.rst index 52a072529af9..2979752acbcd 100644 --- a/Documentation/userspace-api/media/rc/lirc-set-send-duty-cycle.rst +++ b/Documentation/userspace-api/media/rc/lirc-set-send-duty-cycle.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later .. c:namespace:: RC .. _lirc_set_send_duty_cycle: diff --git a/Documentation/userspace-api/media/rc/lirc-set-transmitter-mask.rst b/Documentation/userspace-api/media/rc/lirc-set-transmitter-mask.rst index 68f4cc2e3ae3..38acbcd6e91c 100644 --- a/Documentation/userspace-api/media/rc/lirc-set-transmitter-mask.rst +++ b/Documentation/userspace-api/media/rc/lirc-set-transmitter-mask.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later .. c:namespace:: RC .. _lirc_set_transmitter_mask: diff --git a/Documentation/userspace-api/media/rc/lirc-set-wideband-receiver.rst b/Documentation/userspace-api/media/rc/lirc-set-wideband-receiver.rst index be5321c4a91f..c9d578e291b8 100644 --- a/Documentation/userspace-api/media/rc/lirc-set-wideband-receiver.rst +++ b/Documentation/userspace-api/media/rc/lirc-set-wideband-receiver.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later .. c:namespace:: RC .. _lirc_set_wideband_receiver: diff --git a/Documentation/userspace-api/media/rc/lirc-write.rst b/Documentation/userspace-api/media/rc/lirc-write.rst index c1c3230d4fd6..970a8b3fa1ca 100644 --- a/Documentation/userspace-api/media/rc/lirc-write.rst +++ b/Documentation/userspace-api/media/rc/lirc-write.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later .. c:namespace:: RC .. _lirc-write: diff --git a/Documentation/userspace-api/media/rc/rc-intro.rst b/Documentation/userspace-api/media/rc/rc-intro.rst index 1338478e2bd4..2ba62cde2369 100644 --- a/Documentation/userspace-api/media/rc/rc-intro.rst +++ b/Documentation/userspace-api/media/rc/rc-intro.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later .. _Remote_controllers_Intro: diff --git a/Documentation/userspace-api/media/rc/rc-protos.rst b/Documentation/userspace-api/media/rc/rc-protos.rst index 2e290584a210..a2eab3b45647 100644 --- a/Documentation/userspace-api/media/rc/rc-protos.rst +++ b/Documentation/userspace-api/media/rc/rc-protos.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later .. _Remote_controllers_Protocols: diff --git a/Documentation/userspace-api/media/rc/rc-sysfs-nodes.rst b/Documentation/userspace-api/media/rc/rc-sysfs-nodes.rst index 43c442696438..34d6a0a1f4d3 100644 --- a/Documentation/userspace-api/media/rc/rc-sysfs-nodes.rst +++ b/Documentation/userspace-api/media/rc/rc-sysfs-nodes.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later .. _remote_controllers_sysfs_nodes: diff --git a/Documentation/userspace-api/media/rc/rc-table-change.rst b/Documentation/userspace-api/media/rc/rc-table-change.rst index 61c77b080ae8..d7de8a56ddfe 100644 --- a/Documentation/userspace-api/media/rc/rc-table-change.rst +++ b/Documentation/userspace-api/media/rc/rc-table-change.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later .. _Remote_controllers_table_change: diff --git a/Documentation/userspace-api/media/rc/rc-tables.rst b/Documentation/userspace-api/media/rc/rc-tables.rst index 8dc11657fc23..aafbfda1f401 100644 --- a/Documentation/userspace-api/media/rc/rc-tables.rst +++ b/Documentation/userspace-api/media/rc/rc-tables.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later .. _Remote_controllers_tables: diff --git a/Documentation/userspace-api/media/rc/remote_controllers.rst b/Documentation/userspace-api/media/rc/remote_controllers.rst index 2d9078accb35..f89291838637 100644 --- a/Documentation/userspace-api/media/rc/remote_controllers.rst +++ b/Documentation/userspace-api/media/rc/remote_controllers.rst @@ -1,4 +1,4 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later .. include:: .. _remote_controllers: -- cgit v1.2.3 From 4fe21dec6c2830dfcad107ff1ba050c7328f122b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 26 Nov 2020 13:55:39 +0100 Subject: media: rc: improve LIRC documentation Add documentation for enum rc_proto and struct lirc_scancode at the generated docs. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sean Young --- Documentation/userspace-api/media/rc/lirc-dev-intro.rst | 11 +++++++++-- include/uapi/linux/lirc.h | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Documentation/userspace-api/media/rc/lirc-dev-intro.rst b/Documentation/userspace-api/media/rc/lirc-dev-intro.rst index 266b646d584e..c88973732282 100644 --- a/Documentation/userspace-api/media/rc/lirc-dev-intro.rst +++ b/Documentation/userspace-api/media/rc/lirc-dev-intro.rst @@ -57,12 +57,12 @@ on the following table. This mode is for both sending and receiving IR. - For transmitting (aka sending), create a ``struct lirc_scancode`` with + For transmitting (aka sending), create a struct lirc_scancode with the desired scancode set in the ``scancode`` member, :c:type:`rc_proto` set to the :ref:`IR protocol `, and all other members set to 0. Write this struct to the lirc device. - For receiving, you read ``struct lirc_scancode`` from the LIRC device. + For receiving, you read struct lirc_scancode from the LIRC device. The ``scancode`` field is set to the received scancode and the :ref:`IR protocol ` is set in :c:type:`rc_proto`. If the scancode maps to a valid key code, this is set @@ -136,6 +136,13 @@ on the following table. This mode is used only for IR send. +************************************* +Data types used by LIRC_MODE_SCANCODE +************************************* + +.. kernel-doc:: include/uapi/linux/lirc.h + :identifiers: lirc_scancode rc_proto + ******************** BPF based IR decoder ******************** diff --git a/include/uapi/linux/lirc.h b/include/uapi/linux/lirc.h index bf0672a6d341..c45a4eaea667 100644 --- a/include/uapi/linux/lirc.h +++ b/include/uapi/linux/lirc.h @@ -139,7 +139,7 @@ */ #define LIRC_GET_REC_TIMEOUT _IOR('i', 0x00000024, __u32) -/* +/** * struct lirc_scancode - decoded scancode with protocol for use with * LIRC_MODE_SCANCODE * -- cgit v1.2.3 From abf287eeff4c6da6aa804bbd429dfd9d0dfb6ea7 Mon Sep 17 00:00:00 2001 From: Keita Suzuki Date: Wed, 9 Sep 2020 14:56:57 +0200 Subject: media: siano: fix memory leak of debugfs members in smsdvb_hotplug When dvb_create_media_graph fails, the debugfs kept inside client should be released. However, the current implementation does not release them. Fix this by adding a new goto label to call smsdvb_debugfs_release. Fixes: 0d3ab8410dcb ("[media] dvb core: must check dvb_create_media_graph()") Signed-off-by: Keita Suzuki Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smsdvb-main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c index 88f90dfd368b..ae17407e477a 100644 --- a/drivers/media/common/siano/smsdvb-main.c +++ b/drivers/media/common/siano/smsdvb-main.c @@ -1169,12 +1169,15 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev, rc = dvb_create_media_graph(&client->adapter, true); if (rc < 0) { pr_err("dvb_create_media_graph failed %d\n", rc); - goto client_error; + goto media_graph_error; } pr_info("DVB interface registered.\n"); return 0; +media_graph_error: + smsdvb_debugfs_release(client); + client_error: dvb_unregister_frontend(&client->frontend); -- cgit v1.2.3 From 9cd4bcfb1683fbf7ca603b0f1909f086c0057d1d Mon Sep 17 00:00:00 2001 From: Kai Muenz Date: Tue, 6 Oct 2020 20:13:09 +0200 Subject: media: dvb-usb: Add Hauppauge MAX S2's USB-IDs Hauppauge MAX S2 or WinTV NOVA HD USB2.0. Signed-off-by: Kai Muenz Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/dw2102.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c index a27a68440325..f0e686b05dc6 100644 --- a/drivers/media/usb/dvb-usb/dw2102.c +++ b/drivers/media/usb/dvb-usb/dw2102.c @@ -1770,6 +1770,7 @@ enum dw2102_table_entry { TEVII_S660, PROF_7500, GENIATECH_SU3000, + HAUPPAUGE_MAX_S2, TERRATEC_CINERGY_S2, TEVII_S480_1, TEVII_S480_2, @@ -1802,6 +1803,7 @@ static struct usb_device_id dw2102_table[] = { [TEVII_S660] = {USB_DEVICE(0x9022, USB_PID_TEVII_S660)}, [PROF_7500] = {USB_DEVICE(0x3034, 0x7500)}, [GENIATECH_SU3000] = {USB_DEVICE(0x1f4d, 0x3000)}, + [HAUPPAUGE_MAX_S2] = {USB_DEVICE(0x2040, 0xd900)}, [TERRATEC_CINERGY_S2] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_S2_R1)}, [TEVII_S480_1] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)}, [TEVII_S480_2] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)}, @@ -2230,12 +2232,16 @@ static struct dvb_usb_device_properties su3000_properties = { }}, } }, - .num_device_descs = 8, + .num_device_descs = 9, .devices = { { "SU3000HD DVB-S USB2.0", { &dw2102_table[GENIATECH_SU3000], NULL }, { NULL }, }, + { "Hauppauge MAX S2 or WinTV NOVA HD USB2.0", + { &dw2102_table[HAUPPAUGE_MAX_S2], NULL }, + { NULL }, + }, { "Terratec Cinergy S2 USB HD", { &dw2102_table[TERRATEC_CINERGY_S2], NULL }, { NULL }, -- cgit v1.2.3 From 2a14dfaffe2cabf0614e6507d0d749a5b36c2987 Mon Sep 17 00:00:00 2001 From: Christian Hewitt Date: Wed, 25 Nov 2020 12:07:21 +0100 Subject: media: rc: add keymap for KHAMSIN remote This remote ships with the Amlogic SML-5442TW IPTV/VOD Set-Top Box used by O2.cz. This keymap adds support for the default IR controls. Signed-off-by: Christian Hewitt Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/rc.yaml | 1 + drivers/media/rc/keymaps/Makefile | 1 + drivers/media/rc/keymaps/rc-khamsin.c | 75 +++++++++++++++++++++++++ include/media/rc-map.h | 1 + 4 files changed, 78 insertions(+) create mode 100644 drivers/media/rc/keymaps/rc-khamsin.c diff --git a/Documentation/devicetree/bindings/media/rc.yaml b/Documentation/devicetree/bindings/media/rc.yaml index 8ad2cba5f61f..03cf40f91d6c 100644 --- a/Documentation/devicetree/bindings/media/rc.yaml +++ b/Documentation/devicetree/bindings/media/rc.yaml @@ -83,6 +83,7 @@ properties: - rc-it913x-v2 - rc-kaiomy - rc-khadas + - rc-khamsin - rc-kworld-315u - rc-kworld-pc150u - rc-kworld-plus-tv-analog diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index aaa1bf81d00d..1c4d6bec0ae4 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -60,6 +60,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-it913x-v2.o \ rc-kaiomy.o \ rc-khadas.o \ + rc-khamsin.o \ rc-kworld-315u.o \ rc-kworld-pc150u.o \ rc-kworld-plus-tv-analog.o \ diff --git a/drivers/media/rc/keymaps/rc-khamsin.c b/drivers/media/rc/keymaps/rc-khamsin.c new file mode 100644 index 000000000000..0c98c2faacff --- /dev/null +++ b/drivers/media/rc/keymaps/rc-khamsin.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2020 Christian Hewitt + +#include +#include + +/* + * KHAMSIN is an IR/Bluetooth RCU supplied with the SmartLabs + * SML-5442TW DVB-S/VOD box. The RCU has separate IR (TV) and + * BT (STB) modes. This keymap suppors the IR controls. + */ + +static struct rc_map_table khamsin[] = { + { 0x70702, KEY_POWER}, + + { 0x70701, KEY_VIDEO}, // source + + { 0x7076c, KEY_RED}, + { 0x70714, KEY_GREEN}, + { 0x70715, KEY_YELLOW}, + { 0x70716, KEY_BLUE}, + + { 0x7071a, KEY_MENU}, + { 0x7074f, KEY_EPG}, + + { 0x70760, KEY_UP }, + { 0x70761, KEY_DOWN }, + { 0x70765, KEY_LEFT }, + { 0x70762, KEY_RIGHT }, + { 0x70768, KEY_ENTER }, + + { 0x7072d, KEY_ESC }, // back + + { 0x70707, KEY_VOLUMEUP }, + { 0x7070b, KEY_VOLUMEDOWN }, + { 0x7070f, KEY_MUTE }, + { 0x70712, KEY_CHANNELUP }, + { 0x70710, KEY_CHANNELDOWN }, + + { 0x70704, KEY_1 }, + { 0x70705, KEY_2 }, + { 0x70706, KEY_3 }, + { 0x70708, KEY_4 }, + { 0x70709, KEY_5 }, + { 0x7070a, KEY_6 }, + { 0x7070c, KEY_7 }, + { 0x7070d, KEY_8 }, + { 0x7070e, KEY_9 }, + { 0x70711, KEY_0 }, +}; + +static struct rc_map_list khamsin_map = { + .map = { + .scan = khamsin, + .size = ARRAY_SIZE(khamsin), + .rc_proto = RC_PROTO_NECX, + .name = RC_MAP_KHAMSIN, + } +}; + +static int __init init_rc_map_khamsin(void) +{ + return rc_map_register(&khamsin_map); +} + +static void __exit exit_rc_map_khamsin(void) +{ + rc_map_unregister(&khamsin_map); +} + +module_init(init_rc_map_khamsin) +module_exit(exit_rc_map_khamsin) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Hewitt "); diff --git a/include/media/rc-map.h b/include/media/rc-map.h index 7dbb91c601a7..fa270f16a97b 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -263,6 +263,7 @@ struct rc_map *rc_map_get(const char *name); #define RC_MAP_IT913X_V2 "rc-it913x-v2" #define RC_MAP_KAIOMY "rc-kaiomy" #define RC_MAP_KHADAS "rc-khadas" +#define RC_MAP_KHAMSIN "rc-khamsin" #define RC_MAP_KWORLD_315U "rc-kworld-315u" #define RC_MAP_KWORLD_PC150U "rc-kworld-pc150u" #define RC_MAP_KWORLD_PLUS_TV_ANALOG "rc-kworld-plus-tv-analog" -- cgit v1.2.3 From 711561a41d1f70ad939c3ff3cf00e75fa8238337 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 26 Nov 2020 10:05:16 +0100 Subject: media: lirc: fix lirc.h documentation generation The rc_proto enum values should be ignored for now, otherwise we get warnings like: Documentation/output/lirc.h.rst:6: WARNING: undefined label: rc-proto-max (if the link has no caption the label must precede a section header) Reported-by: Stephen Rothwell Fixes: 72e637fec558 ("media: rc: validate that "rc_proto" is reasonable") Fixes: cea357bc2571 ("media: lirc: ensure RC_PROTO_MAX has documentation") Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/lirc.h.rst.exceptions | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/userspace-api/media/lirc.h.rst.exceptions b/Documentation/userspace-api/media/lirc.h.rst.exceptions index ac768d769113..e74b73cd0e9e 100644 --- a/Documentation/userspace-api/media/lirc.h.rst.exceptions +++ b/Documentation/userspace-api/media/lirc.h.rst.exceptions @@ -64,6 +64,7 @@ ignore symbol RC_PROTO_RCMM12 ignore symbol RC_PROTO_RCMM24 ignore symbol RC_PROTO_RCMM32 ignore symbol RC_PROTO_XBOX_DVD +ignore symbol RC_PROTO_MAX # Undocumented macros -- cgit v1.2.3 From d0ac1a26ed5943127cb0156148735f5f52a07075 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 27 Nov 2020 07:40:21 +0100 Subject: media: gp8psk: initialize stats at power control logic As reported on: https://lore.kernel.org/linux-media/20190627222020.45909-1-willemdebruijn.kernel@gmail.com/ if gp8psk_usb_in_op() returns an error, the status var is not initialized. Yet, this var is used later on, in order to identify: - if the device was already started; - if firmware has loaded; - if the LNBf was powered on. Using status = 0 seems to ensure that everything will be properly powered up. So, instead of the proposed solution, let's just set status = 0. Reported-by: syzbot Reported-by: Willem de Bruijn Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/gp8psk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/dvb-usb/gp8psk.c b/drivers/media/usb/dvb-usb/gp8psk.c index c07f46f5176e..b4f661bb5648 100644 --- a/drivers/media/usb/dvb-usb/gp8psk.c +++ b/drivers/media/usb/dvb-usb/gp8psk.c @@ -182,7 +182,7 @@ out_rel_fw: static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff) { - u8 status, buf; + u8 status = 0, buf; int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); if (onoff) { -- cgit v1.2.3 From bf9d46f751e75bf3d9a48bd69675f95d86ff7eb9 Mon Sep 17 00:00:00 2001 From: Nishka Dasgupta Date: Tue, 16 Jul 2019 07:38:31 +0200 Subject: media: platform: sti: c8sectpfe: core: Add of_node_put() at goto Each iteration of for_each_child_of_node puts the previous node, but in the case of a goto from the middle of the loop, there is no put, thus causing a memory leak. Hence add a new label that puts the last used node, and edit the goto statements in the middle of the loop to first go to the new label. Issue found with Coccinelle. Signed-off-by: Nishka Dasgupta Acked-by: Patrice Chotard Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c index dbe7788083a4..f0cbcb8a9677 100644 --- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c +++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c @@ -765,7 +765,7 @@ static int c8sectpfe_probe(struct platform_device *pdev) if (!fei->channel_data[index]) { ret = -ENOMEM; - goto err_clk_disable; + goto err_node_put; } tsin = fei->channel_data[index]; @@ -775,7 +775,7 @@ static int c8sectpfe_probe(struct platform_device *pdev) ret = of_property_read_u32(child, "tsin-num", &tsin->tsin_id); if (ret) { dev_err(&pdev->dev, "No tsin_num found\n"); - goto err_clk_disable; + goto err_node_put; } /* sanity check value */ @@ -784,7 +784,7 @@ static int c8sectpfe_probe(struct platform_device *pdev) "tsin-num %d specified greater than number\n\tof input block hw in SoC! (%d)", tsin->tsin_id, fei->hw_stats.num_ib); ret = -EINVAL; - goto err_clk_disable; + goto err_node_put; } tsin->invert_ts_clk = of_property_read_bool(child, @@ -800,14 +800,14 @@ static int c8sectpfe_probe(struct platform_device *pdev) &tsin->dvb_card); if (ret) { dev_err(&pdev->dev, "No dvb-card found\n"); - goto err_clk_disable; + goto err_node_put; } i2c_bus = of_parse_phandle(child, "i2c-bus", 0); if (!i2c_bus) { dev_err(&pdev->dev, "No i2c-bus found\n"); ret = -ENODEV; - goto err_clk_disable; + goto err_node_put; } tsin->i2c_adapter = of_find_i2c_adapter_by_node(i2c_bus); @@ -815,7 +815,7 @@ static int c8sectpfe_probe(struct platform_device *pdev) dev_err(&pdev->dev, "No i2c adapter found\n"); of_node_put(i2c_bus); ret = -ENODEV; - goto err_clk_disable; + goto err_node_put; } of_node_put(i2c_bus); @@ -826,7 +826,7 @@ static int c8sectpfe_probe(struct platform_device *pdev) dev_err(dev, "reset gpio for tsin%d not valid (gpio=%d)\n", tsin->tsin_id, tsin->rst_gpio); - goto err_clk_disable; + goto err_node_put; } ret = devm_gpio_request_one(dev, tsin->rst_gpio, @@ -834,7 +834,7 @@ static int c8sectpfe_probe(struct platform_device *pdev) if (ret && ret != -EBUSY) { dev_err(dev, "Can't request tsin%d reset gpio\n" , fei->channel_data[index]->tsin_id); - goto err_clk_disable; + goto err_node_put; } if (!ret) { @@ -877,6 +877,8 @@ static int c8sectpfe_probe(struct platform_device *pdev) return 0; +err_node_put: + of_node_put(child); err_clk_disable: clk_disable_unprepare(fei->c8sectpfeclk); return ret; -- cgit v1.2.3 From 3ec7fdc58363bb204c75d6158e3560fd7cabbf5c Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Mon, 29 Jul 2019 12:14:44 +0200 Subject: media: usb: msi2500: Fix a possible null-pointer dereference in msi2500_stop_streaming() In msi2500_stop_streaming(), there is an if statement on line 870 to check whether dev->udev is NULL: if (dev->udev) When dev->udev is NULL, it is used on line 877: msi2500_ctrl_msg(dev, CMD_STOP_STREAMING, 0) usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), ...) Thus, a possible null-pointer dereference may occur. To fix this bug, dev->udev is checked before calling msi2500_ctrl_msg(). This bug is found by a static analysis tool STCheck written by us. Signed-off-by: Jia-Ju Bai Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/msi2500/msi2500.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c index 65be6f140fe8..269f3ef34bc9 100644 --- a/drivers/media/usb/msi2500/msi2500.c +++ b/drivers/media/usb/msi2500/msi2500.c @@ -867,7 +867,7 @@ static void msi2500_stop_streaming(struct vb2_queue *vq) /* according to tests, at least 700us delay is required */ msleep(20); - if (!msi2500_ctrl_msg(dev, CMD_STOP_STREAMING, 0)) { + if (dev->udev && !msi2500_ctrl_msg(dev, CMD_STOP_STREAMING, 0)) { /* sleep USB IF / ADC */ msi2500_ctrl_msg(dev, CMD_WREG, 0x01000003); } -- cgit v1.2.3 From 9c60cc797cf72e95bb39f32316e9f0e5f85435f9 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 17 Aug 2019 03:12:10 +0200 Subject: media: msi2500: assign SPI bus number dynamically SPI bus number must be assigned dynamically for each device, otherwise it will crash when multiple devices are plugged to system. Reported-and-tested-by: syzbot+c60ddb60b685777d9d59@syzkaller.appspotmail.com Cc: stable@vger.kernel.org Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/msi2500/msi2500.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c index 269f3ef34bc9..63882a5248ae 100644 --- a/drivers/media/usb/msi2500/msi2500.c +++ b/drivers/media/usb/msi2500/msi2500.c @@ -1230,7 +1230,7 @@ static int msi2500_probe(struct usb_interface *intf, } dev->master = master; - master->bus_num = 0; + master->bus_num = -1; master->num_chipselect = 1; master->transfer_one_message = msi2500_transfer_one_message; spi_master_set_devdata(master, dev); -- cgit v1.2.3 From eeb76afbe8d91e112396c6281cd020725160f006 Mon Sep 17 00:00:00 2001 From: Daniel Gomez Date: Thu, 3 Oct 2019 16:46:24 +0200 Subject: media: imx214: Fix stop streaming Stop video streaming when requested. When s_stream is called to stop the video streaming, if/else condition calls start_streaming function instead of the one for stopping it. Fixes: 436190596241 ("media: imx214: Add imx214 camera sensor driver") Signed-off-by: Daniel Gomez Signed-off-by: Ricardo Ribalda Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx214.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c index 1ef5af9a8c8b..cee1a4817af9 100644 --- a/drivers/media/i2c/imx214.c +++ b/drivers/media/i2c/imx214.c @@ -786,7 +786,7 @@ static int imx214_s_stream(struct v4l2_subdev *subdev, int enable) if (ret < 0) goto err_rpm_put; } else { - ret = imx214_start_streaming(imx214); + ret = imx214_stop_streaming(imx214); if (ret < 0) goto err_rpm_put; pm_runtime_put(imx214->dev); -- cgit v1.2.3 From 7ae53081901b52cebfdd5b39b373abaac5d1d4ef Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Wed, 9 Oct 2019 16:55:24 +0200 Subject: media: uvcvideo: Use DIV_ROUND_CLOSEST directly to make it readable The kernel.h macro DIV_ROUND_CLOSEST performs the computation (x + d/2)/d but is perhaps more readable. Signed-off-by: zhong jiang Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_ctrl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index f479d8971dfb..011e69427b7c 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -1608,8 +1608,8 @@ int uvc_ctrl_set(struct uvc_fh *handle, if (step == 0) step = 1; - xctrl->value = min + ((u32)(xctrl->value - min) + step / 2) - / step * step; + xctrl->value = min + DIV_ROUND_CLOSEST((u32)(xctrl->value - min), + step) * step; if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED) xctrl->value = clamp(xctrl->value, min, max); else -- cgit v1.2.3 From dc10472baf6d55eda47d54c2ca8b7aaefbe1e799 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 14 Jan 2020 06:10:05 +0100 Subject: media: c8sectpfe: clean up some indenting The "seg_num," line wasn't indented. All the arguments can fit nicely on two lines. Signed-off-by: Dan Carpenter Reviewed-by: Patrice Chotard Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c index f0cbcb8a9677..5ceb366648b3 100644 --- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c +++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c @@ -1034,9 +1034,8 @@ static void load_imem_segment(struct c8sectpfei *fei, Elf32_Phdr *phdr, dev_dbg(fei->dev, "Loading IMEM segment %d 0x%08x\n\t (0x%x bytes) -> 0x%p (0x%x bytes)\n", -seg_num, - phdr->p_paddr, phdr->p_filesz, - dest, phdr->p_memsz + phdr->p_memsz / 3); + seg_num, phdr->p_paddr, phdr->p_filesz, dest, + phdr->p_memsz + phdr->p_memsz / 3); for (i = 0; i < phdr->p_filesz; i++) { -- cgit v1.2.3 From 9b1b0cb0636166187478ef68d5b95f5caea062ec Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 4 Mar 2020 15:23:12 +0100 Subject: media: max2175: fix max2175_set_csm_mode() error code This is supposed to return negative error codes but the type is bool so it returns true instead. Fixes: b47b79d8a231 ("[media] media: i2c: max2175: Add MAX2175 support") Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/max2175.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/max2175.c b/drivers/media/i2c/max2175.c index 03b4ed3a61b8..661208c9bfc5 100644 --- a/drivers/media/i2c/max2175.c +++ b/drivers/media/i2c/max2175.c @@ -503,7 +503,7 @@ static void max2175_set_bbfilter(struct max2175 *ctx) } } -static bool max2175_set_csm_mode(struct max2175 *ctx, +static int max2175_set_csm_mode(struct max2175 *ctx, enum max2175_csm_mode new_mode) { int ret = max2175_poll_csm_ready(ctx); -- cgit v1.2.3 From 6814e218b9c0fc3a1a6aaf8ee186f7e91968173c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 10 Apr 2020 13:39:13 +0200 Subject: media: mantis: remove redundant assignment to variable err The variable err is being initialized with a value that is never read and it is being updated later with a new value. The initialization is redundant and can be removed. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/mantis/hopper_vp3028.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/mantis/hopper_vp3028.c b/drivers/media/pci/mantis/hopper_vp3028.c index 37bd386f3ed8..ce1e8737b14b 100644 --- a/drivers/media/pci/mantis/hopper_vp3028.c +++ b/drivers/media/pci/mantis/hopper_vp3028.c @@ -33,7 +33,7 @@ static int vp3028_frontend_init(struct mantis_pci *mantis, struct dvb_frontend * { struct i2c_adapter *adapter = &mantis->adapter; struct mantis_hwconfig *config = mantis->hwconfig; - int err = 0; + int err; mantis_gpio_set_bits(mantis, config->reset, 0); msleep(100); -- cgit v1.2.3 From fbef89886da6d7735d20fdde16a1ee6ed6c6ab56 Mon Sep 17 00:00:00 2001 From: Sameer Puri Date: Mon, 13 Apr 2020 17:51:47 +0200 Subject: media: i2c: imx219: remove redundant writes These writes to 0x162, 0x163 already appear earlier in the struct for the 1920x1080 mode and do not need to be repeated. Signed-off-by: Sameer Puri Reviewed-by: Dave Stevenson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx219.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 2b17ec0ddbbe..982828d19d64 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -262,8 +262,6 @@ static const struct imx219_reg mode_1920_1080_regs[] = { {0x4793, 0x10}, {0x4797, 0x0e}, {0x479b, 0x0e}, - {0x0162, 0x0d}, - {0x0163, 0x78}, }; static const struct imx219_reg mode_1640_1232_regs[] = { -- cgit v1.2.3 From 8b0ff6650325ed7a166c2b971e9319e5b5facef0 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 4 Jun 2020 11:40:30 +0200 Subject: media: Remove superfluous dependency for MEDIA_SUPPORT_FILTER The MEDIA_SUPPORT_FILTER configuration option is located inside a block protected by "#if MEDIA_SUPPORT", so there is no need to have an explicit dependency on MEDIA_SUPPORT. Drop it. Fixes: c6774ee035dcb878 ("media: Kconfig: make filtering devices optional") Signed-off-by: Geert Uytterhoeven Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index a6d073f2e036..6222b3ae220b 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -24,7 +24,6 @@ if MEDIA_SUPPORT config MEDIA_SUPPORT_FILTER bool "Filter media drivers" - depends on MEDIA_SUPPORT default y if !EMBEDDED && !EXPERT help Configuring the media subsystem can be complex, as there are -- cgit v1.2.3 From 4aab0a2d471837de024b1227103872816b20b82e Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 4 Jul 2020 01:55:27 +0200 Subject: media: Documentation: userspace-api/media: dvb/ca: drop doubled word Drop the doubled word "and". Signed-off-by: Randy Dunlap Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/dvb/ca.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/userspace-api/media/dvb/ca.rst b/Documentation/userspace-api/media/dvb/ca.rst index 6f6821e322a9..0dc00e5e4a8c 100644 --- a/Documentation/userspace-api/media/dvb/ca.rst +++ b/Documentation/userspace-api/media/dvb/ca.rst @@ -7,7 +7,7 @@ Digital TV CA Device #################### The Digital TV CA device controls the conditional access hardware. It -can be accessed through ``/dev/dvb/adapter?/ca?``. Data types and and ioctl +can be accessed through ``/dev/dvb/adapter?/ca?``. Data types and ioctl definitions can be accessed by including ``linux/dvb/ca.h`` in your application. -- cgit v1.2.3 From eabed8f256426a2008bace782fdf6c9a5cb8020f Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 4 Jul 2020 01:55:28 +0200 Subject: media: Documentation: userspace-api/media: dvb/demux: drop doubled word Drop the doubled word "and". Signed-off-by: Randy Dunlap Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/dvb/demux.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/userspace-api/media/dvb/demux.rst b/Documentation/userspace-api/media/dvb/demux.rst index 364ef48472ee..ef05abcf14d1 100644 --- a/Documentation/userspace-api/media/dvb/demux.rst +++ b/Documentation/userspace-api/media/dvb/demux.rst @@ -11,7 +11,7 @@ digital TV. If the driver and hardware supports, those filters are implemented at the hardware. Otherwise, the Kernel provides a software emulation. -It can be accessed through ``/dev/adapter?/demux?``. Data types and and +It can be accessed through ``/dev/adapter?/demux?``. Data types and ioctl definitions can be accessed by including ``linux/dvb/dmx.h`` in your application. -- cgit v1.2.3 From 08bbe2d882b3b97b9c453b7d4a9fca4b8c27d921 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 4 Jul 2020 01:55:29 +0200 Subject: media: Documentation: userspace-api/media: dvb/dmx-qbuf: drop doubled word Drop the doubled word "the". Signed-off-by: Randy Dunlap Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/dvb/dmx-qbuf.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/userspace-api/media/dvb/dmx-qbuf.rst b/Documentation/userspace-api/media/dvb/dmx-qbuf.rst index 17e70143c1b0..1a13a33834db 100644 --- a/Documentation/userspace-api/media/dvb/dmx-qbuf.rst +++ b/Documentation/userspace-api/media/dvb/dmx-qbuf.rst @@ -50,7 +50,7 @@ by a :ref:`DMX_QUERYBUF` ioctl will do as well. When ``DMX_QBUF`` is called with a pointer to this structure, it locks the memory pages of the buffer in physical memory, so they cannot be swapped out to disk. Buffers remain locked until dequeued, until the -the device is closed. +device is closed. Applications call the ``DMX_DQBUF`` ioctl to dequeue a filled (capturing) buffer from the driver's outgoing queue. -- cgit v1.2.3 From c302763139246d613d1c2693ae0b5b3830367d57 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 4 Jul 2020 01:55:31 +0200 Subject: media: Documentation: userspace-api/media: dvb/video: drop doubled word Drop the doubled word "and". Signed-off-by: Randy Dunlap Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/dvb/video.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/userspace-api/media/dvb/video.rst b/Documentation/userspace-api/media/dvb/video.rst index 3ed1bbfb93c3..38a8d39a1d25 100644 --- a/Documentation/userspace-api/media/dvb/video.rst +++ b/Documentation/userspace-api/media/dvb/video.rst @@ -8,7 +8,7 @@ Digital TV Video Device The Digital TV video device controls the MPEG2 video decoder of the Digital TV hardware. It can be accessed through **/dev/dvb/adapter0/video0**. Data -types and and ioctl definitions can be accessed by including +types and ioctl definitions can be accessed by including **linux/dvb/video.h** in your application. Note that the Digital TV video device only controls decoding of the MPEG video -- cgit v1.2.3 From 33bbc0b35bbb77559246134cfc0ecc2e1a9126ea Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 4 Jul 2020 01:55:36 +0200 Subject: media: Documentation: userspace-api/media: v4l/vidioc-qbuf: drop doubled word Drop the doubled word "the". Signed-off-by: Randy Dunlap Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/v4l/vidioc-qbuf.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/userspace-api/media/v4l/vidioc-qbuf.rst b/Documentation/userspace-api/media/v4l/vidioc-qbuf.rst index fbf8c5962d8a..77e0747a6d28 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-qbuf.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-qbuf.rst @@ -163,7 +163,7 @@ EINVAL The buffer ``type`` is not supported, or the ``index`` is out of bounds, or no buffers have been allocated yet, or the ``userptr`` or ``length`` are invalid, or the ``V4L2_BUF_FLAG_REQUEST_FD`` flag was - set but the the given ``request_fd`` was invalid, or ``m.fd`` was + set but the given ``request_fd`` was invalid, or ``m.fd`` was an invalid DMABUF file descriptor. EIO -- cgit v1.2.3 From 650ddad381caac23de0f4e538d4a45c902911cc4 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 4 Jul 2020 01:55:35 +0200 Subject: media: Documentation: userspace-api/media: v4l/vidioc-g-output: drop doubled word Drop the doubled word "standard.". Signed-off-by: Randy Dunlap Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/v4l/vidioc-g-output.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/userspace-api/media/v4l/vidioc-g-output.rst b/Documentation/userspace-api/media/v4l/vidioc-g-output.rst index 3138c4cc8fe3..dbcdd51dd2a8 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-g-output.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-g-output.rst @@ -46,7 +46,7 @@ To select a video output applications store the number of the desired output in an integer and call the :ref:`VIDIOC_S_OUTPUT ` ioctl with a pointer to this integer. Side effects are possible. For example outputs may support different video standards, so the driver may implicitly -switch the current standard. standard. Because of these possible side +switch the current standard. Because of these possible side effects applications must select an output before querying or negotiating any other parameters. -- cgit v1.2.3 From c5c91a1d0b17cba2d532157332ca2e65983a7dd5 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 4 Jul 2020 01:55:34 +0200 Subject: media: Documentation: userspace-api/media: v4l/vidioc-g-ext-ctrls: drop doubled word Drop the doubled word "controls". Signed-off-by: Randy Dunlap Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst index f2173e310d67..a8d12bd50d22 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst @@ -53,7 +53,7 @@ by the ``controls`` fields. To get the current value of a set of controls applications initialize the ``id``, ``size`` and ``reserved2`` fields of each struct :c:type:`v4l2_ext_control` and call the -:ref:`VIDIOC_G_EXT_CTRLS ` ioctl. String controls controls must also set the +:ref:`VIDIOC_G_EXT_CTRLS ` ioctl. String controls must also set the ``string`` field. Controls of compound types (``V4L2_CTRL_FLAG_HAS_PAYLOAD`` is set) must set the ``ptr`` field. -- cgit v1.2.3 From 4d06867e7d420ee58c5008397f1dbafb099a84b7 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 4 Jul 2020 01:55:33 +0200 Subject: media: Documentation: userspace-api/media: v4l/selection-api-config: drop doubled word Drop the doubled word "in". Signed-off-by: Randy Dunlap Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/v4l/selection-api-configuration.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/userspace-api/media/v4l/selection-api-configuration.rst b/Documentation/userspace-api/media/v4l/selection-api-configuration.rst index 37617eda2fa6..fee49bf1a1c0 100644 --- a/Documentation/userspace-api/media/v4l/selection-api-configuration.rst +++ b/Documentation/userspace-api/media/v4l/selection-api-configuration.rst @@ -94,7 +94,7 @@ specified using :ref:`VIDIOC_S_FMT ` ioctl. The top left corner, width and height of the source rectangle, that is the area from which image date are processed by the hardware, is given -by the ``V4L2_SEL_TGT_CROP``. Its coordinates are expressed in in the +by the ``V4L2_SEL_TGT_CROP``. Its coordinates are expressed in the same coordinate system as the bounds rectangle. The active cropping area must lie completely inside the crop boundaries and the driver may further adjust the requested size and/or position according to hardware -- cgit v1.2.3 From f9b7dd05b7a5fb848eef6276db32bbb17b5000c7 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 4 Jul 2020 01:55:32 +0200 Subject: media: Documentation: userspace-api/media: dvb/audio: drop doubled word Drop the doubled word "Any". Signed-off-by: Randy Dunlap Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/v4l/buffer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/userspace-api/media/v4l/buffer.rst b/Documentation/userspace-api/media/v4l/buffer.rst index 7dbdfbb4a0a9..1b0fdc160533 100644 --- a/Documentation/userspace-api/media/v4l/buffer.rst +++ b/Documentation/userspace-api/media/v4l/buffer.rst @@ -604,7 +604,7 @@ Buffer Flags :ref:`VIDIOC_DQBUF ` ioctl is called. Due to hardware limitations, the last buffer may be empty. In this case the driver will set the ``bytesused`` field to 0, regardless of - the format. Any Any subsequent call to the + the format. Any subsequent call to the :ref:`VIDIOC_DQBUF ` ioctl will not block anymore, but return an ``EPIPE`` error code. * .. _`V4L2-BUF-FLAG-REQUEST-FD`: -- cgit v1.2.3 From fbb89ee65da81d51d4d8e4718710d2a3ff53bc5b Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 4 Jul 2020 01:55:30 +0200 Subject: media: Documentation: userspace-api/media: dvb/net: drop doubled word Drop the doubled word "and". Signed-off-by: Randy Dunlap Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/dvb/net.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/userspace-api/media/dvb/net.rst b/Documentation/userspace-api/media/dvb/net.rst index 33368f5150c5..020a023d3b61 100644 --- a/Documentation/userspace-api/media/dvb/net.rst +++ b/Documentation/userspace-api/media/dvb/net.rst @@ -23,7 +23,7 @@ types that are present on the transport stream. This is done through virtual ``dvb?_?`` network interfaces, and will be controlled/routed via the standard ip tools (like ip, route, netstat, ifconfig, etc). -Data types and and ioctl definitions are defined via ``linux/dvb/net.h`` +Data types and ioctl definitions are defined via ``linux/dvb/net.h`` header. -- cgit v1.2.3 From e2c8f9ad20ea354cd713bf274f92769ab3c845cd Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 4 Jul 2020 01:55:26 +0200 Subject: media: Documentation: userspace-api/media: dvb/audio: drop doubled word Drop the doubled word "and". Signed-off-by: Randy Dunlap Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/dvb/audio.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/userspace-api/media/dvb/audio.rst b/Documentation/userspace-api/media/dvb/audio.rst index 071abac9d52d..eaae5675a47d 100644 --- a/Documentation/userspace-api/media/dvb/audio.rst +++ b/Documentation/userspace-api/media/dvb/audio.rst @@ -8,7 +8,7 @@ Digital TV Audio Device The Digital TV audio device controls the MPEG2 audio decoder of the Digital TV hardware. It can be accessed through ``/dev/dvb/adapter?/audio?``. Data -types and and ioctl definitions can be accessed by including +types and ioctl definitions can be accessed by including ``linux/dvb/audio.h`` in your application. Please note that some Digital TV cards don’t have their own MPEG decoder, which -- cgit v1.2.3 From fe209bf531d65012a157e7033119b0ebdeaa0935 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 4 Jul 2020 05:44:53 +0200 Subject: media: Documentation/driver-api: media/cec-core: drop doubled word Drop the doubled word "the". Signed-off-by: Randy Dunlap Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab --- Documentation/driver-api/media/cec-core.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/driver-api/media/cec-core.rst b/Documentation/driver-api/media/cec-core.rst index 9c6aff3b0ddf..a26dc87eee8f 100644 --- a/Documentation/driver-api/media/cec-core.rst +++ b/Documentation/driver-api/media/cec-core.rst @@ -335,7 +335,7 @@ So this must work: $ cat einj.txt >error-inj The first callback is called when this file is read and it should show the -the current error injection state:: +current error injection state:: int (*error_inj_show)(struct cec_adapter *adap, struct seq_file *sf); -- cgit v1.2.3 From eeee0dfda6d51a6c1ee5959680bcf299fcd5cfa9 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 4 Jul 2020 05:45:01 +0200 Subject: media: Documentation/driver-api: media/v4l2-controls: drop doubled words Drop the doubled words "type" and "the". Signed-off-by: Randy Dunlap Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab --- Documentation/driver-api/media/v4l2-controls.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/driver-api/media/v4l2-controls.rst b/Documentation/driver-api/media/v4l2-controls.rst index 77f42ea3bac7..b2e91804829b 100644 --- a/Documentation/driver-api/media/v4l2-controls.rst +++ b/Documentation/driver-api/media/v4l2-controls.rst @@ -335,7 +335,7 @@ current and new values: union v4l2_ctrl_ptr p_new; union v4l2_ctrl_ptr p_cur; -If the control has a simple s32 type type, then: +If the control has a simple s32 type, then: .. code-block:: c @@ -349,7 +349,7 @@ Within the control ops you can freely use these. The val and cur.val speak for themselves. The p_char pointers point to character buffers of length ctrl->maximum + 1, and are always 0-terminated. -Unless the control is marked volatile the p_cur field points to the the +Unless the control is marked volatile the p_cur field points to the current cached control value. When you create a new control this value is made identical to the default value. After calling v4l2_ctrl_handler_setup() this value is passed to the hardware. It is generally a good idea to call this -- cgit v1.2.3 From 3cf80a75e16a1146645b869a579748e945da6c42 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 4 Jul 2020 05:44:55 +0200 Subject: media: Documentation/driver-api: media/v4l2-dev: drop doubled word Drop the doubled word "device". Signed-off-by: Randy Dunlap Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab --- Documentation/driver-api/media/v4l2-dev.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/driver-api/media/v4l2-dev.rst b/Documentation/driver-api/media/v4l2-dev.rst index 666330af31ed..99e3b5fa7444 100644 --- a/Documentation/driver-api/media/v4l2-dev.rst +++ b/Documentation/driver-api/media/v4l2-dev.rst @@ -212,7 +212,7 @@ types exist: ========================== ==================== ============================== The last argument gives you a certain amount of control over the device -device node number used (i.e. the X in ``videoX``). Normally you will pass -1 +node number used (i.e. the X in ``videoX``). Normally you will pass -1 to let the v4l2 framework pick the first free number. But sometimes users want to select a specific node number. It is common that drivers allow the user to select a specific device node number through a driver module -- cgit v1.2.3 From 1785c8290489bb4b9f2897b7f545fd06e1f6d226 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 4 Jul 2020 05:44:54 +0200 Subject: media: Documentation/driver-api: media/dtv-frontend: drop doubled word Drop the doubled word "errors". Signed-off-by: Randy Dunlap Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab --- Documentation/driver-api/media/dtv-frontend.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/driver-api/media/dtv-frontend.rst b/Documentation/driver-api/media/dtv-frontend.rst index 91f77fe58e83..ea43cdb5b0e4 100644 --- a/Documentation/driver-api/media/dtv-frontend.rst +++ b/Documentation/driver-api/media/dtv-frontend.rst @@ -244,7 +244,7 @@ Carrier Signal to Noise ratio (:ref:`DTV-STAT-CNR`) Having it available after inner FEC is more common. Bit counts post-FEC (:ref:`DTV-STAT-POST-ERROR-BIT-COUNT` and :ref:`DTV-STAT-POST-TOTAL-BIT-COUNT`) - - Those counters measure the number of bits and bit errors errors after + - Those counters measure the number of bits and bit errors after the forward error correction (FEC) on the inner coding block (after Viterbi, LDPC or other inner code). @@ -253,7 +253,7 @@ Bit counts post-FEC (:ref:`DTV-STAT-POST-ERROR-BIT-COUNT` and :ref:`DTV-STAT-POS see :c:type:`fe_status`). Bit counts pre-FEC (:ref:`DTV-STAT-PRE-ERROR-BIT-COUNT` and :ref:`DTV-STAT-PRE-TOTAL-BIT-COUNT`) - - Those counters measure the number of bits and bit errors errors before + - Those counters measure the number of bits and bit errors before the forward error correction (FEC) on the inner coding block (before Viterbi, LDPC or other inner code). @@ -263,7 +263,7 @@ Bit counts pre-FEC (:ref:`DTV-STAT-PRE-ERROR-BIT-COUNT` and :ref:`DTV-STAT-PRE-T after ``FE_HAS_VITERBI``, see :c:type:`fe_status`). Block counts (:ref:`DTV-STAT-ERROR-BLOCK-COUNT` and :ref:`DTV-STAT-TOTAL-BLOCK-COUNT`) - - Those counters measure the number of blocks and block errors errors after + - Those counters measure the number of blocks and block errors after the forward error correction (FEC) on the inner coding block (before Viterbi, LDPC or other inner code). -- cgit v1.2.3 From 965045caa11c43adfdf720c8009fea0b33bfc0a6 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Wed, 8 Jul 2020 17:18:13 +0200 Subject: media: Replace HTTP links with HTTPS ones: SI2165 MEDIA DRIVER Rationale: Reduces attack surface on kernel devs opening the links for MITM as HTTPS traffic is much harder to manipulate. Deterministic algorithm: For each file: If not .svg: For each line: If doesn't contain `\bxmlns\b`: If neither `\bgnu\.org/license`, nor `\bmozilla\.org/MPL\b`: If both the HTTP and HTTPS versions return 200 OK and serve the same content: Replace HTTP with HTTPS. Signed-off-by: Alexander A. Klimov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/si2165.c | 2 +- drivers/media/dvb-frontends/si2165.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c index 3fdaef1935ef..ebee230afb7b 100644 --- a/drivers/media/dvb-frontends/si2165.c +++ b/drivers/media/dvb-frontends/si2165.c @@ -5,7 +5,7 @@ * Copyright (C) 2013-2017 Matthias Schwarzott * * References: - * http://www.silabs.com/Support%20Documents/TechnicalDocs/Si2165-short.pdf + * https://www.silabs.com/Support%20Documents/TechnicalDocs/Si2165-short.pdf */ #include diff --git a/drivers/media/dvb-frontends/si2165.h b/drivers/media/dvb-frontends/si2165.h index 0b19317f3a31..adc5e18754ad 100644 --- a/drivers/media/dvb-frontends/si2165.h +++ b/drivers/media/dvb-frontends/si2165.h @@ -5,7 +5,7 @@ * Copyright (C) 2013-2017 Matthias Schwarzott * * References: - * http://www.silabs.com/Support%20Documents/TechnicalDocs/Si2165-short.pdf + * https://www.silabs.com/Support%20Documents/TechnicalDocs/Si2165-short.pdf */ #ifndef _DVB_SI2165_H -- cgit v1.2.3 From f0cf9985507c649b033affe206f94adea288a5ee Mon Sep 17 00:00:00 2001 From: Bixuan Cui Date: Thu, 16 Jul 2020 19:17:42 +0200 Subject: media: tuners: reduce stack usage in mxl5005s_reconfigure Fix the warning: [-Werror=-Wframe-larger-than=] drivers/media/tuners/mxl5005s.c: In function 'mxl5005s_reconfigure': drivers/media/tuners/mxl5005s.c:3953:1: warning: the frame size of 1152 bytes is larger than 1024 bytes Signed-off-by: Bixuan Cui Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/mxl5005s.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/media/tuners/mxl5005s.c b/drivers/media/tuners/mxl5005s.c index 1c07e2225fb3..f6e82a8e7d37 100644 --- a/drivers/media/tuners/mxl5005s.c +++ b/drivers/media/tuners/mxl5005s.c @@ -3926,15 +3926,26 @@ static int mxl5005s_reconfigure(struct dvb_frontend *fe, u32 mod_type, u32 bandwidth) { struct mxl5005s_state *state = fe->tuner_priv; - - u8 AddrTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX]; - u8 ByteTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX]; + u8 *AddrTable; + u8 *ByteTable; int TableLen; dprintk(1, "%s(type=%d, bw=%d)\n", __func__, mod_type, bandwidth); mxl5005s_reset(fe); + AddrTable = kcalloc(MXL5005S_REG_WRITING_TABLE_LEN_MAX, sizeof(u8), + GFP_KERNEL); + if (!AddrTable) + return -ENOMEM; + + ByteTable = kcalloc(MXL5005S_REG_WRITING_TABLE_LEN_MAX, sizeof(u8), + GFP_KERNEL); + if (!ByteTable) { + kfree(AddrTable); + return -ENOMEM; + } + /* Tuner initialization stage 0 */ MXL_GetMasterControl(ByteTable, MC_SYNTH_RESET); AddrTable[0] = MASTER_CONTROL_ADDR; @@ -3949,6 +3960,9 @@ static int mxl5005s_reconfigure(struct dvb_frontend *fe, u32 mod_type, mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen); + kfree(AddrTable); + kfree(ByteTable); + return 0; } -- cgit v1.2.3 From f79469016e579346ebb581f4645056ff0597e1fa Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 27 Jul 2020 14:45:27 +0200 Subject: media: b2c2: switch from 'pci_' to 'dma_' API The wrappers in include/linux/pci-dma-compat.h should go away. The patch has been generated with the coccinelle script below and has been hand modified to replace GFP_ with a correct flag. It has been compile tested. When memory is allocated in 'flexcop_dma_allocate()', GFP_KERNEL can be used because it is only called from the probe function (i.e. 'flexcop_pci_probe()') and no lock is taken. The call chain is: flexcop_pci_probe --> flexcop_pci_dma_init --> flexcop_dma_allocate @@ @@ - PCI_DMA_BIDIRECTIONAL + DMA_BIDIRECTIONAL @@ @@ - PCI_DMA_TODEVICE + DMA_TO_DEVICE @@ @@ - PCI_DMA_FROMDEVICE + DMA_FROM_DEVICE @@ @@ - PCI_DMA_NONE + DMA_NONE @@ expression e1, e2, e3; @@ - pci_alloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3; @@ - pci_zalloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3, e4; @@ - pci_free_consistent(e1, e2, e3, e4) + dma_free_coherent(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_single(e1, e2, e3, e4) + dma_map_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_single(e1, e2, e3, e4) + dma_unmap_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4, e5; @@ - pci_map_page(e1, e2, e3, e4, e5) + dma_map_page(&e1->dev, e2, e3, e4, e5) @@ expression e1, e2, e3, e4; @@ - pci_unmap_page(e1, e2, e3, e4) + dma_unmap_page(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_sg(e1, e2, e3, e4) + dma_map_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_sg(e1, e2, e3, e4) + dma_unmap_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_cpu(e1, e2, e3, e4) + dma_sync_single_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_device(e1, e2, e3, e4) + dma_sync_single_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_cpu(e1, e2, e3, e4) + dma_sync_sg_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_device(e1, e2, e3, e4) + dma_sync_sg_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2; @@ - pci_dma_mapping_error(e1, e2) + dma_mapping_error(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_dma_mask(e1, e2) + dma_set_mask(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_consistent_dma_mask(e1, e2) + dma_set_coherent_mask(&e1->dev, e2) Signed-off-by: Christophe JAILLET Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/b2c2/flexcop-dma.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/pci/b2c2/flexcop-dma.c b/drivers/media/pci/b2c2/flexcop-dma.c index ba45b378d739..ff8058568240 100644 --- a/drivers/media/pci/b2c2/flexcop-dma.c +++ b/drivers/media/pci/b2c2/flexcop-dma.c @@ -17,7 +17,7 @@ int flexcop_dma_allocate(struct pci_dev *pdev, return -EINVAL; } - tcpu = pci_alloc_consistent(pdev, size, &tdma); + tcpu = dma_alloc_coherent(&pdev->dev, size, &tdma, GFP_KERNEL); if (tcpu != NULL) { dma->pdev = pdev; dma->cpu_addr0 = tcpu; @@ -33,8 +33,8 @@ EXPORT_SYMBOL(flexcop_dma_allocate); void flexcop_dma_free(struct flexcop_dma *dma) { - pci_free_consistent(dma->pdev, dma->size*2, - dma->cpu_addr0, dma->dma_addr0); + dma_free_coherent(&dma->pdev->dev, dma->size * 2, dma->cpu_addr0, + dma->dma_addr0); memset(dma, 0, sizeof(struct flexcop_dma)); } EXPORT_SYMBOL(flexcop_dma_free); -- cgit v1.2.3 From b2a004d3d8407a1544acd01e3ae2db5bc60afe4b Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 27 Jul 2020 15:51:37 +0200 Subject: media: bt8xx: switch from 'pci_' to 'dma_' API The wrappers in include/linux/pci-dma-compat.h should go away. The patch has been generated with the coccinelle script below and has been hand modified to replace GFP_ with a correct flag. It has been compile tested. When memory is allocated in 'bt878_mem_alloc()' (bt878.c), GFP_KERNEL can be used because it is only called from the probe function (i.e. 'bt878_probe()') and no lock is taken. When memory is allocated in 'btcx_riscmem_alloc()' (btcx-risc.c), GFP_KERNEL can be used because all the callers either already use GFP_KERNEL or are called from a probe function or are called from a .buf_prepare function. The 4 callers are all in 'bttv-risc.c'. - bttv_risc_packed() and bttv_risc_planar(): only called from 'videobuf_queue_ops''s '.buf_prepare' functions. The call chains are: .buf_prepare (in 'bttv-driver.c') --> buffer_prepare (in 'bttv-driver.c') --> bttv_prepare_buffer --> bttv_buffer_risc --> bttv_risc_packed (x8 times) --> bttv_risc_planar (x6 times) .buf_prepare (in 'bttv-vbi.c') --> vbi_buffer_prepare (in 'bttv-vbi.c') --> bttv_risc_packed (x2 times) - bttv_risc_overlay(): already uses GFP_KERNEL - bttv_risc_init_main(): only called from the 'bttv_probe()' probe function and no spin_lock is taken in the between @@ @@ - PCI_DMA_BIDIRECTIONAL + DMA_BIDIRECTIONAL @@ @@ - PCI_DMA_TODEVICE + DMA_TO_DEVICE @@ @@ - PCI_DMA_FROMDEVICE + DMA_FROM_DEVICE @@ @@ - PCI_DMA_NONE + DMA_NONE @@ expression e1, e2, e3; @@ - pci_alloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3; @@ - pci_zalloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3, e4; @@ - pci_free_consistent(e1, e2, e3, e4) + dma_free_coherent(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_single(e1, e2, e3, e4) + dma_map_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_single(e1, e2, e3, e4) + dma_unmap_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4, e5; @@ - pci_map_page(e1, e2, e3, e4, e5) + dma_map_page(&e1->dev, e2, e3, e4, e5) @@ expression e1, e2, e3, e4; @@ - pci_unmap_page(e1, e2, e3, e4) + dma_unmap_page(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_sg(e1, e2, e3, e4) + dma_map_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_sg(e1, e2, e3, e4) + dma_unmap_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_cpu(e1, e2, e3, e4) + dma_sync_single_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_device(e1, e2, e3, e4) + dma_sync_single_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_cpu(e1, e2, e3, e4) + dma_sync_sg_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_device(e1, e2, e3, e4) + dma_sync_sg_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2; @@ - pci_dma_mapping_error(e1, e2) + dma_mapping_error(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_dma_mask(e1, e2) + dma_set_mask(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_consistent_dma_mask(e1, e2) + dma_set_coherent_mask(&e1->dev, e2) Signed-off-by: Christophe JAILLET Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bt878.c | 16 ++++++++-------- drivers/media/pci/bt8xx/btcx-risc.c | 4 ++-- drivers/media/pci/bt8xx/bttv-driver.c | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/media/pci/bt8xx/bt878.c b/drivers/media/pci/bt8xx/bt878.c index 79ba15a9385a..78dd35c9b65d 100644 --- a/drivers/media/pci/bt8xx/bt878.c +++ b/drivers/media/pci/bt8xx/bt878.c @@ -67,14 +67,14 @@ EXPORT_SYMBOL(bt878); static void bt878_mem_free(struct bt878 *bt) { if (bt->buf_cpu) { - pci_free_consistent(bt->dev, bt->buf_size, bt->buf_cpu, - bt->buf_dma); + dma_free_coherent(&bt->dev->dev, bt->buf_size, bt->buf_cpu, + bt->buf_dma); bt->buf_cpu = NULL; } if (bt->risc_cpu) { - pci_free_consistent(bt->dev, bt->risc_size, bt->risc_cpu, - bt->risc_dma); + dma_free_coherent(&bt->dev->dev, bt->risc_size, bt->risc_cpu, + bt->risc_dma); bt->risc_cpu = NULL; } } @@ -84,16 +84,16 @@ static int bt878_mem_alloc(struct bt878 *bt) if (!bt->buf_cpu) { bt->buf_size = 128 * 1024; - bt->buf_cpu = pci_zalloc_consistent(bt->dev, bt->buf_size, - &bt->buf_dma); + bt->buf_cpu = dma_alloc_coherent(&bt->dev->dev, bt->buf_size, + &bt->buf_dma, GFP_KERNEL); if (!bt->buf_cpu) return -ENOMEM; } if (!bt->risc_cpu) { bt->risc_size = PAGE_SIZE; - bt->risc_cpu = pci_zalloc_consistent(bt->dev, bt->risc_size, - &bt->risc_dma); + bt->risc_cpu = dma_alloc_coherent(&bt->dev->dev, bt->risc_size, + &bt->risc_dma, GFP_KERNEL); if (!bt->risc_cpu) { bt878_mem_free(bt); return -ENOMEM; diff --git a/drivers/media/pci/bt8xx/btcx-risc.c b/drivers/media/pci/bt8xx/btcx-risc.c index 51257980f539..13bb1490a568 100644 --- a/drivers/media/pci/bt8xx/btcx-risc.c +++ b/drivers/media/pci/bt8xx/btcx-risc.c @@ -48,7 +48,7 @@ void btcx_riscmem_free(struct pci_dev *pci, dprintk("btcx: riscmem free [%d] dma=%lx\n", memcnt, (unsigned long)risc->dma); - pci_free_consistent(pci, risc->size, risc->cpu, risc->dma); + dma_free_coherent(&pci->dev, risc->size, risc->cpu, risc->dma); memset(risc,0,sizeof(*risc)); } @@ -62,7 +62,7 @@ int btcx_riscmem_alloc(struct pci_dev *pci, if (NULL != risc->cpu && risc->size < size) btcx_riscmem_free(pci,risc); if (NULL == risc->cpu) { - cpu = pci_alloc_consistent(pci, size, &dma); + cpu = dma_alloc_coherent(&pci->dev, size, &dma, GFP_KERNEL); if (NULL == cpu) return -ENOMEM; risc->cpu = cpu; diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 956a12e311c0..2aba3e281321 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -4008,7 +4008,7 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) result = -EIO; goto free_mem; } - if (pci_set_dma_mask(dev, DMA_BIT_MASK(32))) { + if (dma_set_mask(&dev->dev, DMA_BIT_MASK(32))) { pr_warn("%d: No suitable DMA available\n", btv->c.nr); result = -EIO; goto free_mem; -- cgit v1.2.3 From c79464f30e18dd02a66333d60c437c1fa98ee28f Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 27 Jul 2020 15:51:51 +0200 Subject: media: bt8xx: avoid a useless memset Avoid a memset after a call to 'dma_alloc_coherent()'. This is useless since commit 518a2f1925c3 ("dma-mapping: zero memory returned from dma_alloc_*") Signed-off-by: Christophe JAILLET Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/btcx-risc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/pci/bt8xx/btcx-risc.c b/drivers/media/pci/bt8xx/btcx-risc.c index 13bb1490a568..b3179038b900 100644 --- a/drivers/media/pci/bt8xx/btcx-risc.c +++ b/drivers/media/pci/bt8xx/btcx-risc.c @@ -73,7 +73,6 @@ int btcx_riscmem_alloc(struct pci_dev *pci, dprintk("btcx: riscmem alloc [%d] dma=%lx cpu=%p size=%d\n", memcnt, (unsigned long)dma, cpu, size); } - memset(risc->cpu,0,risc->size); return 0; } -- cgit v1.2.3 From acc4c91ebbfb29bad4a55b923175170b297ff431 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Tue, 28 Jul 2020 12:18:54 +0200 Subject: media: dm1105: switch from 'pci_' to 'dma_' API The wrappers in include/linux/pci-dma-compat.h should go away. The patch has been generated with the coccinelle script below and has been hand modified to replace GFP_ with a correct flag. It has been compile tested. When memory is allocated, GFP_KERNEL can be used because it is called from the probe function and no lock is taken. The call chain is: dm1105_probe --> dm1105_hw_init --> dm1105_dma_map @@ @@ - PCI_DMA_BIDIRECTIONAL + DMA_BIDIRECTIONAL @@ @@ - PCI_DMA_TODEVICE + DMA_TO_DEVICE @@ @@ - PCI_DMA_FROMDEVICE + DMA_FROM_DEVICE @@ @@ - PCI_DMA_NONE + DMA_NONE @@ expression e1, e2, e3; @@ - pci_alloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3; @@ - pci_zalloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3, e4; @@ - pci_free_consistent(e1, e2, e3, e4) + dma_free_coherent(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_single(e1, e2, e3, e4) + dma_map_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_single(e1, e2, e3, e4) + dma_unmap_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4, e5; @@ - pci_map_page(e1, e2, e3, e4, e5) + dma_map_page(&e1->dev, e2, e3, e4, e5) @@ expression e1, e2, e3, e4; @@ - pci_unmap_page(e1, e2, e3, e4) + dma_unmap_page(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_sg(e1, e2, e3, e4) + dma_map_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_sg(e1, e2, e3, e4) + dma_unmap_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_cpu(e1, e2, e3, e4) + dma_sync_single_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_device(e1, e2, e3, e4) + dma_sync_single_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_cpu(e1, e2, e3, e4) + dma_sync_sg_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_device(e1, e2, e3, e4) + dma_sync_sg_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2; @@ - pci_dma_mapping_error(e1, e2) + dma_mapping_error(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_dma_mask(e1, e2) + dma_set_mask(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_consistent_dma_mask(e1, e2) + dma_set_coherent_mask(&e1->dev, e2) Signed-off-by: Christophe JAILLET Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/dm1105/dm1105.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c index 9dce31d2b525..4ac645a56c14 100644 --- a/drivers/media/pci/dm1105/dm1105.c +++ b/drivers/media/pci/dm1105/dm1105.c @@ -604,19 +604,17 @@ static void dm1105_set_dma_addr(struct dm1105_dev *dev) static int dm1105_dma_map(struct dm1105_dev *dev) { - dev->ts_buf = pci_alloc_consistent(dev->pdev, - 6 * DM1105_DMA_BYTES, - &dev->dma_addr); + dev->ts_buf = dma_alloc_coherent(&dev->pdev->dev, + 6 * DM1105_DMA_BYTES, &dev->dma_addr, + GFP_KERNEL); return !dev->ts_buf; } static void dm1105_dma_unmap(struct dm1105_dev *dev) { - pci_free_consistent(dev->pdev, - 6 * DM1105_DMA_BYTES, - dev->ts_buf, - dev->dma_addr); + dma_free_coherent(&dev->pdev->dev, 6 * DM1105_DMA_BYTES, dev->ts_buf, + dev->dma_addr); } static void dm1105_enable_irqs(struct dm1105_dev *dev) @@ -1010,7 +1008,7 @@ static int dm1105_probe(struct pci_dev *pdev, if (ret < 0) goto err_kfree; - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); if (ret < 0) goto err_pci_disable_device; -- cgit v1.2.3 From a3f132df0e5f25399c9592c2d14997975ddbf290 Mon Sep 17 00:00:00 2001 From: Vaibhav Gupta Date: Tue, 28 Jul 2020 12:24:18 +0200 Subject: media: bttv: use generic power management Drivers using legacy power management .suspen()/.resume() callbacks have to manage PCI states and device's PM states themselves. They also need to take care of standard configuration registers. Switch to generic power management framework using a single "struct dev_pm_ops" variable to take the unnecessary load from the driver. This also avoids the need for the driver to directly call most of the PCI helper functions and device power state control functions, as through the generic framework PCI Core takes care of the necessary operations, and drivers are required to do only device-specific jobs. Signed-off-by: Vaibhav Gupta Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 56 ++++++++++------------------------- 1 file changed, 16 insertions(+), 40 deletions(-) diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 2aba3e281321..1f62a9d8ea1d 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -4262,15 +4262,14 @@ static void bttv_remove(struct pci_dev *pci_dev) return; } -#ifdef CONFIG_PM -static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state) +static int __maybe_unused bttv_suspend(struct device *dev) { - struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); struct bttv *btv = to_bttv(v4l2_dev); struct bttv_buffer_set idle; unsigned long flags; - dprintk("%d: suspend %d\n", btv->c.nr, state.event); + dprintk("%d: suspend\n", btv->c.nr); /* stop dma + irqs */ spin_lock_irqsave(&btv->s_lock,flags); @@ -4290,42 +4289,19 @@ static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state) btv->state.gpio_enable = btread(BT848_GPIO_OUT_EN); btv->state.gpio_data = gpio_read(); - /* save pci state */ - pci_save_state(pci_dev); - if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) { - pci_disable_device(pci_dev); - btv->state.disabled = 1; - } + btv->state.disabled = 1; return 0; } -static int bttv_resume(struct pci_dev *pci_dev) +static int __maybe_unused bttv_resume(struct device *dev) { - struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); struct bttv *btv = to_bttv(v4l2_dev); unsigned long flags; - int err; dprintk("%d: resume\n", btv->c.nr); - /* restore pci state */ - if (btv->state.disabled) { - err=pci_enable_device(pci_dev); - if (err) { - pr_warn("%d: Can't enable device\n", btv->c.nr); - return err; - } - btv->state.disabled = 0; - } - err=pci_set_power_state(pci_dev, PCI_D0); - if (err) { - pci_disable_device(pci_dev); - pr_warn("%d: Can't enable device\n", btv->c.nr); - btv->state.disabled = 1; - return err; - } - - pci_restore_state(pci_dev); + btv->state.disabled = 0; /* restore bt878 state */ bttv_reinit_bt848(btv); @@ -4343,7 +4319,6 @@ static int bttv_resume(struct pci_dev *pci_dev) spin_unlock_irqrestore(&btv->s_lock,flags); return 0; } -#endif static const struct pci_device_id bttv_pci_tbl[] = { {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT848), 0}, @@ -4356,15 +4331,16 @@ static const struct pci_device_id bttv_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, bttv_pci_tbl); +static SIMPLE_DEV_PM_OPS(bttv_pm_ops, + bttv_suspend, + bttv_resume); + static struct pci_driver bttv_pci_driver = { - .name = "bttv", - .id_table = bttv_pci_tbl, - .probe = bttv_probe, - .remove = bttv_remove, -#ifdef CONFIG_PM - .suspend = bttv_suspend, - .resume = bttv_resume, -#endif + .name = "bttv", + .id_table = bttv_pci_tbl, + .probe = bttv_probe, + .remove = bttv_remove, + .driver.pm = &bttv_pm_ops, }; static int __init bttv_init_module(void) -- cgit v1.2.3 From 1ec0b899c2b776c0c2dd03044b171a52b5211570 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 3 Feb 2020 10:39:24 +0100 Subject: media: ccs: Add the generator for CCS register definitions and limits Add register definitions of the MIPI CCS 1.1 standard. The CCS driver makes extended use of device's capability registers that are dependent on CCS version. This involves having an in-memory data structure for limit and capability information, creating that data structure and accessing it. The register definitions as well as the definitions of this data structure are generated from a text file using a Perl script. Add the generator script to make it easy to update the generated files. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../driver-api/media/drivers/ccs/ccs-regs.txt | 1041 ++++++++++++++++++++ .../driver-api/media/drivers/ccs/mk-ccs-regs | 433 ++++++++ MAINTAINERS | 1 + 3 files changed, 1475 insertions(+) create mode 100644 Documentation/driver-api/media/drivers/ccs/ccs-regs.txt create mode 100755 Documentation/driver-api/media/drivers/ccs/mk-ccs-regs diff --git a/Documentation/driver-api/media/drivers/ccs/ccs-regs.txt b/Documentation/driver-api/media/drivers/ccs/ccs-regs.txt new file mode 100644 index 000000000000..93f0131aa304 --- /dev/null +++ b/Documentation/driver-api/media/drivers/ccs/ccs-regs.txt @@ -0,0 +1,1041 @@ +# Copyright (C) 2019--2020 Intel Corporation +# SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause + +# register rflags +# - f field LSB MSB rflags +# - e enum value # after a field +# - e enum value [LSB MSB] +# - b bool bit +# - l arg name min max elsize [discontig...] +# +# rflags +# 8, 16, 32 register bits (default is 8) +# v1.1 defined in version 1.1 +# f formula +# float_ireal iReal or IEEE 754; 32 bits +# ireal unsigned iReal + +# general status registers +module_model_id 0x0000 16 +module_revision_number_major 0x0002 8 +frame_count 0x0005 8 +pixel_order 0x0006 8 +- e GRBG 0 +- e RGGB 1 +- e BGGR 2 +- e GBRG 3 +MIPI_CCS_version 0x0007 8 +- e v1_0 0x10 +- e v1_1 0x11 +- f major 4 7 +- f minor 0 3 +data_pedestal 0x0008 16 +module_manufacturer_id 0x000e 16 +module_revision_number_minor 0x0010 8 +module_date_year 0x0012 8 +module_date_month 0x0013 8 +module_date_day 0x0014 8 +module_date_phase 0x0015 8 +- f 0 2 +- e ts 0 +- e es 1 +- e cs 2 +- e mp 3 +sensor_model_id 0x0016 16 +sensor_revision_number 0x0018 8 +sensor_firmware_version 0x001a 8 +serial_number 0x001c 32 +sensor_manufacturer_id 0x0020 16 +sensor_revision_number_16 0x0022 16 + +# frame format description registers +frame_format_model_type 0x0040 8 +- e 2-byte 1 +- e 4-byte 2 +frame_format_model_subtype 0x0041 8 +- f rows 0 3 +- f columns 4 7 +frame_format_descriptor(n) 0x0042 16 f +- l n 0 14 2 +- f pixels 0 11 +- f pcode 12 15 +- e embedded 1 +- e dummy_pixel 2 +- e black_pixel 3 +- e dark_pixel 4 +- e visible_pixel 5 +- e manuf_specific_0 8 +- e manuf_specific_1 9 +- e manuf_specific_2 10 +- e manuf_specific_3 11 +- e manuf_specific_4 12 +- e manuf_specific_5 13 +- e manuf_specific_6 14 +frame_format_descriptor_4(n) 0x0060 32 f +- l n 0 7 4 +- f pixels 0 15 +- f pcode 28 31 +- e embedded 1 +- e dummy_pixel 2 +- e black_pixel 3 +- e dark_pixel 4 +- e visible_pixel 5 +- e manuf_specific_0 8 +- e manuf_specific_1 9 +- e manuf_specific_2 10 +- e manuf_specific_3 11 +- e manuf_specific_4 12 +- e manuf_specific_5 13 +- e manuf_specific_6 14 + +# analog gain description registers +analog_gain_capability 0x0080 16 +- e global 0 +- e alternate_global 2 +analog_gain_code_min 0x0084 16 +analog_gain_code_max 0x0086 16 +analog_gain_code_step 0x0088 16 +analog_gain_type 0x008a 16 +analog_gain_m0 0x008c 16 +analog_gain_c0 0x008e 16 +analog_gain_m1 0x0090 16 +analog_gain_c1 0x0092 16 +analog_linear_gain_min 0x0094 16 v1.1 +analog_linear_gain_max 0x0096 16 v1.1 +analog_linear_gain_step_size 0x0098 16 v1.1 +analog_exponential_gain_min 0x009a 16 v1.1 +analog_exponential_gain_max 0x009c 16 v1.1 +analog_exponential_gain_step_size 0x009e 16 v1.1 + +# data format description registers +data_format_model_type 0x00c0 8 +- e normal 1 +- e extended 2 +data_format_model_subtype 0x00c1 8 +- f rows 0 3 +- f columns 4 7 +data_format_descriptor(n) 0x00c2 16 f +- l n 0 15 2 +- f compressed 0 7 +- f uncompressed 8 15 + +# general set-up registers +mode_select 0x0100 8 +- e software_standby 0 +- e streaming 1 +image_orientation 0x0101 8 +- b horizontal_mirror 0 +- b vertical_flip 1 +software_reset 0x0103 8 +- e off 0 +- e on 1 +grouped_parameter_hold 0x0104 8 +mask_corrupted_frames 0x0105 8 +- e allow 0 +- e mask 1 +fast_standby_ctrl 0x0106 8 +- e complete_frames 0 +- e frame_truncation 1 +CCI_address_ctrl 0x0107 8 +2nd_CCI_if_ctrl 0x0108 8 +- b enable 0 +- b ack 1 +2nd_CCI_address_ctrl 0x0109 8 +CSI_channel_identifier 0x0110 8 +CSI_signaling_mode 0x0111 8 +- e csi_2_dphy 2 +- e csi_2_cphy 3 +CSI_data_format 0x0112 16 +CSI_lane_mode 0x0114 8 +DPCM_Frame_DT 0x011d 8 +Bottom_embedded_data_DT 0x011e 8 +Bottom_embedded_data_VC 0x011f 8 + +gain_mode 0x0120 8 +- e global 0 +- e alternate 1 +ADC_bit_depth 0x0121 8 +emb_data_ctrl 0x0122 v1.1 +- b raw8_packing_for_raw16 0 +- b raw10_packing_for_raw20 1 +- b raw12_packing_for_raw24 2 + +GPIO_TRIG_mode 0x0130 8 +extclk_frequency_mhz 0x0136 16 ireal +temp_sensor_ctrl 0x0138 8 +- b enable 0 +temp_sensor_mode 0x0139 8 +temp_sensor_output 0x013a 8 + +# integration time registers +fine_integration_time 0x0200 16 +coarse_integration_time 0x0202 16 + +# analog gain registers +analog_gain_code_global 0x0204 16 +analog_linear_gain_global 0x0206 16 v1.1 +analog_exponential_gain_global 0x0208 16 v1.1 + +# digital gain registers +digital_gain_global 0x020e 16 + +# hdr control registers +Short_analog_gain_global 0x0216 16 +Short_digital_gain_global 0x0218 16 + +HDR_mode 0x0220 8 +- b enabled 0 +- b separate_analog_gain 1 +- b upscaling 2 +- b reset_sync 3 +- b timing_mode 4 +- b exposure_ctrl_direct 5 +- b separate_digital_gain 6 +HDR_resolution_reduction 0x0221 8 +- f row 0 3 +- f column 4 7 +Exposure_ratio 0x0222 8 +HDR_internal_bit_depth 0x0223 8 +Direct_short_integration_time 0x0224 16 +Short_analog_linear_gain_global 0x0226 16 v1.1 +Short_analog_exponential_gain_global 0x0228 16 v1.1 + +# clock set-up registers +vt_pix_clk_div 0x0300 16 +vt_sys_clk_div 0x0302 16 +pre_pll_clk_div 0x0304 16 +#vt_pre_pll_clk_div 0x0304 16 +pll_multiplier 0x0306 16 +#vt_pll_multiplier 0x0306 16 +op_pix_clk_div 0x0308 16 +op_sys_clk_div 0x030a 16 +op_pre_pll_clk_div 0x030c 16 +op_pll_multiplier 0x031e 16 +pll_mode 0x0310 8 +- f 0 0 +- e single 0 +- e dual 1 +op_pix_clk_div_rev 0x0312 16 v1.1 +op_sys_clk_div_rev 0x0314 16 v1.1 + +# frame timing registers +frame_length_lines 0x0340 16 +line_length_pck 0x0342 16 + +# image size registers +x_addr_start 0x0344 16 +y_addr_start 0x0346 16 +x_addr_end 0x0348 16 +y_addr_end 0x034a 16 +x_output_size 0x034c 16 +y_output_size 0x034e 16 + +# timing mode registers +Frame_length_ctrl 0x0350 8 +- b automatic 0 +Timing_mode_ctrl 0x0352 8 +- b manual_readout 0 +- b delayed_exposure 1 +Start_readout_rs 0x0353 8 +- b manual_readout_start 0 +Frame_margin 0x0354 16 + +# sub-sampling registers +x_even_inc 0x0380 16 +x_odd_inc 0x0382 16 +y_even_inc 0x0384 16 +y_odd_inc 0x0386 16 + +# monochrome readout registers +monochrome_en 0x0390 v1.1 +- e enabled 0 + +# image scaling registers +Scaling_mode 0x0400 16 +- e no_scaling 0 +- e horizontal 1 +scale_m 0x0404 16 +scale_n 0x0406 16 +digital_crop_x_offset 0x0408 16 +digital_crop_y_offset 0x040a 16 +digital_crop_image_width 0x040c 16 +digital_crop_image_height 0x040e 16 + +# image compression registers +compression_mode 0x0500 16 +- e none 0 +- e dpcm_pcm_simple 1 + +# test pattern registers +test_pattern_mode 0x0600 16 +- e none 0 +- e solid_color 1 +- e color_bars 2 +- e fade_to_grey 3 +- e pn9 4 +- e color_tile 5 +test_data_red 0x0602 16 +test_data_greenR 0x0604 16 +test_data_blue 0x0606 16 +test_data_greenB 0x0608 16 +value_step_size_smooth 0x060a 8 +value_step_size_quantised 0x060b 8 + +# phy configuration registers +tclk_post 0x0800 8 +ths_prepare 0x0801 8 +ths_zero_min 0x0802 8 +ths_trail 0x0803 8 +tclk_trail_min 0x0804 8 +tclk_prepare 0x0805 8 +tclk_zero 0x0806 8 +tlpx 0x0807 8 +phy_ctrl 0x0808 8 +- e auto 0 +- e UI 1 +- e manual 2 +tclk_post_ex 0x080a 16 +ths_prepare_ex 0x080c 16 +ths_zero_min_ex 0x080e 16 +ths_trail_ex 0x0810 16 +tclk_trail_min_ex 0x0812 16 +tclk_prepare_ex 0x0814 16 +tclk_zero_ex 0x0816 16 +tlpx_ex 0x0818 16 + +# link rate register +requested_link_rate 0x0820 32 u16.16 + +# equalization control registers +DPHY_equalization_mode 0x0824 8 v1.1 +- b eq2 0 +PHY_equalization_ctrl 0x0825 8 v1.1 +- b enable 0 + +# d-phy preamble control registers +DPHY_preamble_ctrl 0x0826 8 v1.1 +- b enable 0 +DPHY_preamble_length 0x0826 8 v1.1 + +# d-phy spread spectrum control registers +PHY_SSC_ctrl 0x0828 8 v1.1 +- b enable 0 + +# manual lp control register +manual_LP_ctrl 0x0829 8 v1.1 +- b enable 0 + +# additional phy configuration registers +twakeup 0x082a v1.1 +tinit 0x082b v1.1 +ths_exit 0x082c v1.1 +ths_exit_ex 0x082e 16 v1.1 + +# phy calibration configuration registers +PHY_periodic_calibration_ctrl 0x0830 8 +- b frame_blanking 0 +PHY_periodic_calibration_interval 0x0831 8 +PHY_init_calibration_ctrl 0x0832 8 +- b stream_start 0 +DPHY_calibration_mode 0x0833 8 v1.1 +- b also_alternate 0 +CPHY_calibration_mode 0x0834 8 v1.1 +- e format_1 0 +- e format_2 1 +- e format_3 2 +t3_calpreamble_length 0x0835 8 v1.1 +t3_calpreamble_length_per 0x0836 8 v1.1 +t3_calaltseq_length 0x0837 8 v1.1 +t3_calaltseq_length_per 0x0838 8 v1.1 +FM2_init_seed 0x083a 16 v1.1 +t3_caludefseq_length 0x083c 16 v1.1 +t3_caludefseq_length_per 0x083e 16 v1.1 + +# c-phy manual control registers +TGR_Preamble_Length 0x0841 8 +- b preamable_prog_seq 7 +- f begin_preamble_length 0 5 +TGR_Post_Length 0x0842 8 +- f post_length 0 4 +TGR_Preamble_Prog_Sequence(n2) 0x0843 +- l n2 0 6 1 +- f symbol_n_1 3 5 +- f symbol_n 0 2 +t3_prepare 0x084e 16 +t3_lpx 0x0850 16 + +# alps control register +ALPS_ctrl 0x085a 8 +- b lvlp_dphy 0 +- b lvlp_cphy 1 +- b alp_cphy 2 + +# lrte control registers +TX_REG_CSI_EPD_EN_SSP_cphy 0x0860 16 +TX_REG_CSI_EPD_OP_SLP_cphy 0x0862 16 +TX_REG_CSI_EPD_EN_SSP_dphy 0x0864 16 +TX_REG_CSI_EPD_OP_SLP_dphy 0x0866 16 +TX_REG_CSI_EPD_MISC_OPTION_cphy 0x0868 v1.1 +TX_REG_CSI_EPD_MISC_OPTION_dphy 0x0869 v1.1 + +# scrambling control registers +Scrambling_ctrl 0x0870 +- b enabled 0 +- f 2 3 +- e 1_seed_cphy 0 +- e 4_seed_cphy 3 +lane_seed_value(seed, lane) 0x0872 16 +- l seed 0 3 0x10 +- l lane 0 7 0x2 + +# usl control registers +TX_USL_REV_ENTRY 0x08c0 16 v1.1 +TX_USL_REV_Clock_Counter 0x08c2 16 v1.1 +TX_USL_REV_LP_Counter 0x08c4 16 v1.1 +TX_USL_REV_Frame_Counter 0x08c6 16 v1.1 +TX_USL_REV_Chronological_Timer 0x08c8 16 v1.1 +TX_USL_FWD_ENTRY 0x08ca 16 v1.1 +TX_USL_GPIO 0x08cc 16 v1.1 +TX_USL_Operation 0x08ce 16 v1.1 +- b reset 0 +TX_USL_ALP_ctrl 0x08d0 16 v1.1 +- b clock_pause 0 +TX_USL_APP_BTA_ACK_TIMEOUT 0x08d2 16 v1.1 +TX_USL_SNS_BTA_ACK_TIMEOUT 0x08d2 16 v1.1 +USL_Clock_Mode_d_ctrl 0x08d2 v1.1 +- b cont_clock_standby 0 +- b cont_clock_vblank 1 +- b cont_clock_hblank 2 + +# binning configuration registers +binning_mode 0x0900 8 +binning_type 0x0901 8 +binning_weighting 0x0902 8 + +# data transfer interface registers +data_transfer_if_1_ctrl 0x0a00 8 +- b enable 0 +- b write 1 +- b clear_error 2 +data_transfer_if_1_status 0x0a01 8 +- b read_if_ready 0 +- b write_if_ready 1 +- b data_corrupted 2 +- b improper_if_usage 3 +data_transfer_if_1_page_select 0x0a02 8 +data_transfer_if_1_data(p) 0x0a04 8 f +- l p 0 63 1 + +# image processing and sensor correction configuration registers +shading_correction_en 0x0b00 8 +- b enable 0 +luminance_correction_level 0x0b01 8 +green_imbalance_filter_en 0x0b02 8 +- b enable 0 +mapped_defect_correct_en 0x0b05 8 +- b enable 0 +single_defect_correct_en 0x0b06 8 +- b enable 0 +dynamic_couplet_correct_en 0x0b08 8 +- b enable 0 +combined_defect_correct_en 0x0b0a 8 +- b enable 0 +module_specific_correction_en 0x0b0c 8 +- b enable 0 +dynamic_triplet_defect_correct_en 0x0b13 8 +- b enable 0 +NF_ctrl 0x0b15 8 +- b luma 0 +- b chroma 1 +- b combined 2 + +# optical black pixel readout registers +OB_readout_control 0x0b30 8 +- b enable 0 +- b interleaving 1 +OB_virtual_channel 0x0b31 8 +OB_DT 0x0b32 8 +OB_data_format 0x0b33 8 + +# color temperature feedback registers +color_temperature 0x0b8c 16 +absolute_gain_greenr 0x0b8e 16 +absolute_gain_red 0x0b90 16 +absolute_gain_blue 0x0b92 16 +absolute_gain_greenb 0x0b94 16 + +# cfa conversion registers +CFA_conversion_ctrl 0x0ba0 v1.1 +- b bayer_conversion_enable 0 + +# flash strobe and sa strobe control registers +flash_strobe_adjustment 0x0c12 8 +flash_strobe_start_point 0x0c14 16 +tflash_strobe_delay_rs_ctrl 0x0c16 16 +tflash_strobe_width_high_rs_ctrl 0x0c18 16 +flash_mode_rs 0x0c1a 8 +- b continuous 0 +- b truncate 1 +- b async 3 +flash_trigger_rs 0x0c1b 8 +flash_status 0x0c1c 8 +- b retimed 0 +sa_strobe_mode 0x0c1d 8 +- b continuous 0 +- b truncate 1 +- b async 3 +- b adjust_edge 4 +sa_strobe_start_point 0x0c1e 16 +tsa_strobe_delay_ctrl 0x0c20 16 +tsa_strobe_width_ctrl 0x0c22 16 +sa_strobe_trigger 0x0c24 8 +sa_strobe_status 0x0c25 8 +- b retimed 0 +tSA_strobe_re_delay_ctrl 0x0c30 16 +tSA_strobe_fe_delay_ctrl 0x0c32 16 + +# pdaf control registers +PDAF_ctrl 0x0d00 16 +- b enable 0 +- b processed 1 +- b interleaved 2 +- b visible_pdaf_correction 3 +PDAF_VC 0x0d02 8 +PDAF_DT 0x0d03 8 +pd_x_addr_start 0x0d04 16 +pd_y_addr_start 0x0d06 16 +pd_x_addr_end 0x0d08 16 +pd_y_addr_end 0x0d0a 16 + +# bracketing interface configuration registers +bracketing_LUT_ctrl 0x0e00 8 +bracketing_LUT_mode 0x0e01 8 +- b continue_streaming 0 +- b loop_mode 1 +bracketing_LUT_entry_ctrl 0x0e02 8 +bracketing_LUT_frame(n) 0x0e10 v1.1 f +- l n 0 0xef 1 + +# integration time and gain parameter limit registers +integration_time_capability 0x1000 16 +- b fine 0 +coarse_integration_time_min 0x1004 16 +coarse_integration_time_max_margin 0x1006 16 +fine_integration_time_min 0x1008 16 +fine_integration_time_max_margin 0x100a 16 + +# digital gain parameter limit registers +digital_gain_capability 0x1081 +- e none 0 +- e global 2 +digital_gain_min 0x1084 16 +digital_gain_max 0x1086 16 +digital_gain_step_size 0x1088 16 + +# data pedestal capability registers +Pedestal_capability 0x10e0 8 v1.1 + +# adc capability registers +ADC_capability 0x10f0 8 +- b bit_depth_ctrl 0 +ADC_bit_depth_capability 0x10f4 32 v1.1 + +# video timing parameter limit registers +min_ext_clk_freq_mhz 0x1100 32 float_ireal +max_ext_clk_freq_mhz 0x1104 32 float_ireal +min_pre_pll_clk_div 0x1108 16 +# min_vt_pre_pll_clk_div 0x1108 16 +max_pre_pll_clk_div 0x110a 16 +# max_vt_pre_pll_clk_div 0x110a 16 +min_pll_ip_clk_freq_mhz 0x110c 32 float_ireal +# min_vt_pll_ip_clk_freq_mhz 0x110c 32 float_ireal +max_pll_ip_clk_freq_mhz 0x1110 32 float_ireal +# max_vt_pll_ip_clk_freq_mhz 0x1110 32 float_ireal +min_pll_multiplier 0x1114 16 +# min_vt_pll_multiplier 0x1114 16 +max_pll_multiplier 0x1116 16 +# max_vt_pll_multiplier 0x1116 16 +min_pll_op_clk_freq_mhz 0x1118 32 float_ireal +max_pll_op_clk_freq_mhz 0x111c 32 float_ireal + +# video timing set-up capability registers +min_vt_sys_clk_div 0x1120 16 +max_vt_sys_clk_div 0x1122 16 +min_vt_sys_clk_freq_mhz 0x1124 32 float_ireal +max_vt_sys_clk_freq_mhz 0x1128 32 float_ireal +min_vt_pix_clk_freq_mhz 0x112c 32 float_ireal +max_vt_pix_clk_freq_mhz 0x1130 32 float_ireal +min_vt_pix_clk_div 0x1134 16 +max_vt_pix_clk_div 0x1136 16 +clock_calculation 0x1138 +- b lane_speed 0 +- b link_decoupled 1 +- b dual_pll_op_sys_ddr 2 +- b dual_pll_op_pix_ddr 3 +num_of_vt_lanes 0x1139 +num_of_op_lanes 0x113a +op_bits_per_lane 0x113b 8 v1.1 + +# frame timing parameter limits +min_frame_length_lines 0x1140 16 +max_frame_length_lines 0x1142 16 +min_line_length_pck 0x1144 16 +max_line_length_pck 0x1146 16 +min_line_blanking_pck 0x1148 16 +min_frame_blanking_lines 0x114a 16 +min_line_length_pck_step_size 0x114c +timing_mode_capability 0x114d +- b auto_frame_length 0 +- b rolling_shutter_manual_readout 2 +- b delayed_exposure_start 3 +- b manual_exposure_embedded_data 4 +frame_margin_max_value 0x114e 16 +frame_margin_min_value 0x1150 +gain_delay_type 0x1151 +- e fixed 0 +- e variable 1 + +# output clock set-up capability registers +min_op_sys_clk_div 0x1160 16 +max_op_sys_clk_div 0x1162 16 +min_op_sys_clk_freq_mhz 0x1164 32 float_ireal +max_op_sys_clk_freq_mhz 0x1168 32 float_ireal +min_op_pix_clk_div 0x116c 16 +max_op_pix_clk_div 0x116e 16 +min_op_pix_clk_freq_mhz 0x1170 32 float_ireal +max_op_pix_clk_freq_mhz 0x1174 32 float_ireal + +# image size parameter limit registers +x_addr_min 0x1180 16 +y_addr_min 0x1182 16 +x_addr_max 0x1184 16 +y_addr_max 0x1186 16 +min_x_output_size 0x1188 16 +min_y_output_size 0x118a 16 +max_x_output_size 0x118c 16 +max_y_output_size 0x118e 16 + +x_addr_start_div_constant 0x1190 v1.1 +y_addr_start_div_constant 0x1191 v1.1 +x_addr_end_div_constant 0x1192 v1.1 +y_addr_end_div_constant 0x1193 v1.1 +x_size_div 0x1194 v1.1 +y_size_div 0x1195 v1.1 +x_output_div 0x1196 v1.1 +y_output_div 0x1197 v1.1 +non_flexible_resolution_support 0x1198 v1.1 +- b new_pix_addr 0 +- b new_output_res 1 +- b output_crop_no_pad 2 +- b output_size_lane_dep 3 + +min_op_pre_pll_clk_div 0x11a0 16 +max_op_pre_pll_clk_div 0x11a2 16 +min_op_pll_ip_clk_freq_mhz 0x11a4 32 float_ireal +max_op_pll_ip_clk_freq_mhz 0x11a8 32 float_ireal +min_op_pll_multiplier 0x11ac 16 +max_op_pll_multiplier 0x11ae 16 +min_op_pll_op_clk_freq_mhz 0x11b0 32 float_ireal +max_op_pll_op_clk_freq_mhz 0x11b4 32 float_ireal +clock_tree_pll_capability 0x11b8 8 +- b dual_pll 0 +- b single_pll 1 +- b ext_divider 2 +- b flexible_op_pix_clk_div 3 +clock_capa_type_capability 0x11b9 v1.1 +- b ireal 0 + +# sub-sampling parameters limit registers +min_even_inc 0x11c0 16 +min_odd_inc 0x11c2 16 +max_even_inc 0x11c4 16 +max_odd_inc 0x11c6 16 +aux_subsamp_capability 0x11c8 v1.1 +- b factor_power_of_2 1 +aux_subsamp_mono_capability 0x11c9 v1.1 +- b factor_power_of_2 1 +monochrome_capability 0x11ca v1.1 +- e inc_odd 0 +- e inc_even 1 +pixel_readout_capability 0x11cb v1.1 +- e bayer 0 +- e monochrome 1 +- e bayer_and_mono 2 +min_even_inc_mono 0x11cc 16 v1.1 +max_even_inc_mono 0x11ce 16 v1.1 +min_odd_inc_mono 0x11d0 16 v1.1 +max_odd_inc_mono 0x11d2 16 v1.1 +min_even_inc_bc2 0x11d4 16 v1.1 +max_even_inc_bc2 0x11d6 16 v1.1 +min_odd_inc_bc2 0x11d8 16 v1.1 +max_odd_inc_bc2 0x11da 16 v1.1 +min_even_inc_mono_bc2 0x11dc 16 v1.1 +max_even_inc_mono_bc2 0x11de 16 v1.1 +min_odd_inc_mono_bc2 0x11f0 16 v1.1 +max_odd_inc_mono_bc2 0x11f2 16 v1.1 + +# image scaling limit parameters +scaling_capability 0x1200 16 +- e none 0 +- e horizontal 1 +- e reserved 2 +scaler_m_min 0x1204 16 +scaler_m_max 0x1206 16 +scaler_n_min 0x1208 16 +scaler_n_max 0x120a 16 +digital_crop_capability 0x120e +- e none 0 +- e input_crop 1 + +# hdr limit registers +hdr_capability_1 0x1210 +- b 2x2_binning 0 +- b combined_analog_gain 1 +- b separate_analog_gain 2 +- b upscaling 3 +- b reset_sync 4 +- b direct_short_exp_timing 5 +- b direct_short_exp_synthesis 6 +min_hdr_bit_depth 0x1211 +hdr_resolution_sub_types 0x1212 +hdr_resolution_sub_type(n) 0x1213 +- l n 0 1 1 +- f row 0 3 +- f column 4 7 +hdr_capability_2 0x121b +- b combined_digital_gain 0 +- b separate_digital_gain 1 +- b timing_mode 3 +- b synthesis_mode 4 +max_hdr_bit_depth 0x121c + +# usl capability register +usl_support_capability 0x1230 v1.1 +- b clock_tree 0 +- b rev_clock_tree 1 +- b rev_clock_calc 2 +usl_clock_mode_d_capability 0x1231 v1.1 +- b cont_clock_standby 0 +- b cont_clock_vblank 1 +- b cont_clock_hblank 2 +- b noncont_clock_standby 3 +- b noncont_clock_vblank 4 +- b noncont_clock_hblank 5 +min_op_sys_clk_div_rev 0x1234 v1.1 +max_op_sys_clk_div_rev 0x1236 v1.1 +min_op_pix_clk_div_rev 0x1238 v1.1 +max_op_pix_clk_div_rev 0x123a v1.1 +min_op_sys_clk_freq_rev_mhz 0x123c 32 v1.1 float_ireal +max_op_sys_clk_freq_rev_mhz 0x1240 32 v1.1 float_ireal +min_op_pix_clk_freq_rev_mhz 0x1244 32 v1.1 float_ireal +max_op_pix_clk_freq_rev_mhz 0x1248 32 v1.1 float_ireal +max_bitrate_rev_d_mode_mbps 0x124c 32 v1.1 ireal +max_symrate_rev_c_mode_msps 0x1250 32 v1.1 ireal + +# image compression capability registers +compression_capability 0x1300 +- b dpcm_pcm_simple 0 + +# test mode capability registers +test_mode_capability 0x1310 16 +- b solid_color 0 +- b color_bars 1 +- b fade_to_grey 2 +- b pn9 3 +- b color_tile 5 +pn9_data_format1 0x1312 +pn9_data_format2 0x1313 +pn9_data_format3 0x1314 +pn9_data_format4 0x1315 +pn9_misc_capability 0x1316 +- f num_pixels 0 2 +- b compression 3 +test_pattern_capability 0x1317 v1.1 +- b no_repeat 1 +pattern_size_div_m1 0x1318 v1.1 + +# fifo capability registers +fifo_support_capability 0x1502 +- e none 0 +- e derating 1 +- e derating_overrating 2 + +# csi-2 capability registers +phy_ctrl_capability 0x1600 +- b auto_phy_ctl 0 +- b ui_phy_ctl 1 +- b dphy_time_ui_reg_1_ctl 2 +- b dphy_time_ui_reg_2_ctl 3 +- b dphy_time_ctl 4 +- b dphy_ext_time_ui_reg_1_ctl 5 +- b dphy_ext_time_ui_reg_2_ctl 6 +- b dphy_ext_time_ctl 7 +csi_dphy_lane_mode_capability 0x1601 +- b 1_lane 0 +- b 2_lane 1 +- b 3_lane 2 +- b 4_lane 3 +- b 5_lane 4 +- b 6_lane 5 +- b 7_lane 6 +- b 8_lane 7 +csi_signaling_mode_capability 0x1602 +- b csi_dphy 2 +- b csi_cphy 3 +fast_standby_capability 0x1603 +- e no_frame_truncation 0 +- e frame_truncation 1 +csi_address_control_capability 0x1604 +- b cci_addr_change 0 +- b 2nd_cci_addr 1 +- b sw_changeable_2nd_cci_addr 2 +data_type_capability 0x1605 +- b dpcm_programmable 0 +- b bottom_embedded_dt_programmable 1 +- b bottom_embedded_vc_programmable 2 +- b ext_vc_range 3 +csi_cphy_lane_mode_capability 0x1606 +- b 1_lane 0 +- b 2_lane 1 +- b 3_lane 2 +- b 4_lane 3 +- b 5_lane 4 +- b 6_lane 5 +- b 7_lane 6 +- b 8_lane 7 +emb_data_capability 0x1607 v1.1 +- b two_bytes_per_raw16 0 +- b two_bytes_per_raw20 1 +- b two_bytes_per_raw24 2 +- b no_one_byte_per_raw16 3 +- b no_one_byte_per_raw20 4 +- b no_one_byte_per_raw24 5 +max_per_lane_bitrate_lane_d_mode_mbps(n) 0x1608 32 ireal +- l n 0 7 4 4,0x32 +temp_sensor_capability 0x1618 +- b supported 0 +- b CCS_format 1 +- b reset_0x80 2 +max_per_lane_bitrate_lane_c_mode_mbps(n) 0x161a 32 ireal +- l n 0 7 4 4,0x30 +dphy_equalization_capability 0x162b +- b equalization_ctrl 0 +- b eq1 1 +- b eq2 2 +cphy_equalization_capability 0x162c +- b equalization_ctrl 0 +dphy_preamble_capability 0x162d +- b preamble_seq_ctrl 0 +dphy_ssc_capability 0x162e +- b supported 0 +cphy_calibration_capability 0x162f +- b manual 0 +- b manual_streaming 1 +- b format_1_ctrl 2 +- b format_2_ctrl 3 +- b format_3_ctrl 4 +dphy_calibration_capability 0x1630 +- b manual 0 +- b manual_streaming 1 +- b alternate_seq 2 +phy_ctrl_capability_2 0x1631 +- b tgr_length 0 +- b tgr_preamble_prog_seq 1 +- b extra_cphy_manual_timing 2 +- b clock_based_manual_cdphy 3 +- b clock_based_manual_dphy 4 +- b clock_based_manual_cphy 5 +- b manual_lp_dphy 6 +- b manual_lp_cphy 7 +lrte_cphy_capability 0x1632 +- b pdq_short 0 +- b spacer_short 1 +- b pdq_long 2 +- b spacer_long 3 +- b spacer_no_pdq 4 +lrte_dphy_capability 0x1633 +- b pdq_short_opt1 0 +- b spacer_short_opt1 1 +- b pdq_long_opt1 2 +- b spacer_long_opt1 3 +- b spacer_short_opt2 4 +- b spacer_long_opt2 5 +- b spacer_no_pdq_opt1 6 +- b spacer_variable_opt2 7 +alps_capability_dphy 0x1634 +- e lvlp_not_supported 0 0x3 +- e lvlp_supported 1 0x3 +- e controllable_lvlp 2 0x3 +alps_capability_cphy 0x1635 +- e lvlp_not_supported 0 0x3 +- e lvlp_supported 1 0x3 +- e controllable_lvlp 2 0x3 +- e alp_not_supported 0xc 0xc +- e alp_supported 0xd 0xc +- e controllable_alp 0xe 0xc +scrambling_capability 0x1636 +- b scrambling_supported 0 +- f max_seeds_per_lane_c 1 2 +- e 1 0 +- e 4 3 +- f num_seed_regs 3 5 +- e 0 0 +- e 1 1 +- e 4 4 +- b num_seed_per_lane 6 +dphy_manual_constant 0x1637 +cphy_manual_constant 0x1638 +CSI2_interface_capability_misc 0x1639 v1.1 +- b eotp_short_pkt_opt2 0 +PHY_ctrl_capability_3 0x165c v1.1 +- b dphy_timing_not_multiple 0 +- b dphy_min_timing_value_1 1 +- b twakeup_supported 2 +- b tinit_supported 3 +- b ths_exit_supported 4 +- b cphy_timing_not_multiple 5 +- b cphy_min_timing_value_1 6 +dphy_sf 0x165d v1.1 +cphy_sf 0x165e v1.1 +- f twakeup 0 3 +- f tinit 4 7 +dphy_limits_1 0x165f v1.1 +- f ths_prepare 0 3 +- f ths_zero 4 7 +dphy_limits_2 0x1660 v1.1 +- f ths_trail 0 3 +- f tclk_trail_min 4 7 +dphy_limits_3 0x1661 v1.1 +- f tclk_prepare 0 3 +- f tclk_zero 4 7 +dphy_limits_4 0x1662 v1.1 +- f tclk_post 0 3 +- f tlpx 4 7 +dphy_limits_5 0x1663 v1.1 +- f ths_exit 0 3 +- f twakeup 4 7 +dphy_limits_6 0x1664 v1.1 +- f tinit 0 3 +cphy_limits_1 0x1665 v1.1 +- f t3_prepare_max 0 3 +- f t3_lpx_max 4 7 +cphy_limits_2 0x1666 v1.1 +- f ths_exit_max 0 3 +- f twakeup_max 4 7 +cphy_limits_3 0x1667 v1.1 +- f tinit_max 0 3 + +# binning capability registers +min_frame_length_lines_bin 0x1700 16 +max_frame_length_lines_bin 0x1702 16 +min_line_length_pck_bin 0x1704 16 +max_line_length_pck_bin 0x1706 16 +min_line_blanking_pck_bin 0x1708 16 +fine_integration_time_min_bin 0x170a 16 +fine_integration_time_max_margin_bin 0x170c 16 +binning_capability 0x1710 +- e unsupported 0 +- e binning_then_subsampling 1 +- e subsampling_then_binning 2 +binning_weighting_capability 0x1711 +- b averaged 0 +- b summed 1 +- b bayer_corrected 2 +- b module_specific_weight 3 +binning_sub_types 0x1712 +binning_sub_type(n) 0x1713 +- l n 0 63 1 +- f row 0 3 +- f column 4 7 +binning_weighting_mono_capability 0x1771 v1.1 +- b averaged 0 +- b summed 1 +- b bayer_corrected 2 +- b module_specific_weight 3 +binning_sub_types_mono 0x1772 v1.1 +binning_sub_type_mono(n) 0x1773 v1.1 f +- l n 0 63 1 + +# data transfer interface capability registers +data_transfer_if_capability 0x1800 +- b supported 0 +- b polling 2 + +# sensor correction capability registers +shading_correction_capability 0x1900 +- b color_shading 0 +- b luminance_correction 1 +green_imbalance_capability 0x1901 +- b supported 0 +module_specific_correction_capability 0x1903 +defect_correction_capability 0x1904 16 +- b mapped_defect 0 +- b dynamic_couplet 2 +- b dynamic_single 5 +- b combined_dynamic 8 +defect_correction_capability_2 0x1906 16 +- b dynamic_triplet 3 +nf_capability 0x1908 +- b luma 0 +- b chroma 1 +- b combined 2 + +# optical black readout capability registers +ob_readout_capability 0x1980 +- b controllable_readout 0 +- b visible_pixel_readout 1 +- b different_vc_readout 2 +- b different_dt_readout 3 +- b prog_data_format 4 + +# color feedback capability registers +color_feedback_capability 0x1987 +- b kelvin 0 +- b awb_gain 1 + +# cfa pattern capability registers +CFA_pattern_capability 0x1990 v1.1 +- e bayer 0 +- e monochrome 1 +- e 4x4_quad_bayer 2 +- e vendor_specific 3 +CFA_pattern_conversion_capability 0x1991 v1.1 +- b bayer 0 + +# timer capability registers +flash_mode_capability 0x1a02 +- b single_strobe 0 +sa_strobe_mode_capability 0x1a03 +- b fixed_width 0 +- b edge_ctrl 1 + +# soft reset capability registers +reset_max_delay 0x1a10 v1.1 +reset_min_time 0x1a11 v1.1 + +# pdaf capability registers +pdaf_capability_1 0x1b80 +- b supported 0 +- b processed_bottom_embedded 1 +- b processed_interleaved 2 +- b raw_bottom_embedded 3 +- b raw_interleaved 4 +- b visible_pdaf_correction 5 +- b vc_interleaving 6 +- b dt_interleaving 7 +pdaf_capability_2 0x1b81 +- b ROI 0 +- b after_digital_crop 1 +- b ctrl_retimed 2 + +# bracketing interface capability registers +bracketing_lut_capability_1 0x1c00 +- b coarse_integration 0 +- b global_analog_gain 1 +- b flash 4 +- b global_digital_gain 5 +- b alternate_global_analog_gain 6 +bracketing_lut_capability_2 0x1c01 +- b single_bracketing_mode 0 +- b looped_bracketing_mode 1 +bracketing_lut_size 0x1c02 diff --git a/Documentation/driver-api/media/drivers/ccs/mk-ccs-regs b/Documentation/driver-api/media/drivers/ccs/mk-ccs-regs new file mode 100755 index 000000000000..3d6a2a7aac3a --- /dev/null +++ b/Documentation/driver-api/media/drivers/ccs/mk-ccs-regs @@ -0,0 +1,433 @@ +#!/usr/bin/perl -w +# SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause +# Copyright (C) 2019--2020 Intel Corporation + +use Getopt::Long qw(:config no_ignore_case); +use File::Basename; + +my $ccsregs = "ccs-regs.txt"; +my $header; +my $regarray; +my $limitc; +my $limith; +my $kernel; +my $help; + +GetOptions("ccsregs|c=s" => \$ccsregs, + "header|e=s" => \$header, + "regarray|r=s" => \$regarray, + "limitc|l=s" => \$limitc, + "limith|L=s" => \$limith, + "kernel|k" => \$kernel, + "help|h" => \$help) or die "can't parse options"; + +$help = 1 if ! defined $header || ! defined $limitc || ! defined $limith; + +if (defined $help) { + print <\n#include \n"; +my $uint32_t = ! defined $kernel ? 'uint32_t' : 'u32'; +my $uint16_t = ! defined $kernel ? 'uint16_t' : 'u16'; + +open(my $R, "< $ccsregs") or die "can't open $ccsregs"; + +open(my $H, "> $header") or die "can't open $header"; +my $A; +if (defined $regarray) { + open($A, "> $regarray") or die "can't open $regarray"; +} +open(my $LC, "> $limitc") or die "can't open $limitc"; +open(my $LH, "> $limith") or die "can't open $limith"; + +my %this; + +sub is_limit_reg($) { + my $addr = hex $_[0]; + + return 0 if $addr < 0x40; # weed out status registers + return 0 if $addr >= 0x100 && $addr < 0xfff; # weed out configuration registers + + return 1; +} + +my $uc_header = basename uc $header; +$uc_header =~ s/[^A-Z0-9]/_/g; + +my $copyright = "/* Copyright (C) 2019--2020 Intel Corporation */\n"; +my $license = "SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause"; + +for my $fh ($A, $LC) { + print $fh "// $license\n$copyright\n" if defined $fh; +} + +for my $fh ($H, $LH) { + print $fh "/* $license */\n$copyright\n"; +} + +sub bit_def($) { + my $bit = shift @_; + + return "BIT($bit)" if defined $kernel; + return "(1U << $bit)" if $bit =~ /^[a-zA-Z0-9_]+$/; + return "(1U << ($bit))"; +} + +print $H <\n\n" if defined $kernel; + +print $H < +#include +#include "ccs-extra.h" +#include "ccs-regs.h" + +EOF + if defined $A; + +my $uc_limith = basename uc $limith; +$uc_limith =~ s/[^A-Z0-9]/_/g; + +print $LH <{elsize}; + my $h = $this->{argparams}; + + foreach my $arg (@{$this->{args}}) { + my $apref = $h->{$arg}; + + $size *= $apref->{max} - $apref->{min} + 1; + } + + return $size; +} + +sub print_args($$$) { + my ($this, $postfix, $is_same_reg) = @_; + my ($args, $argparams, $name) = + ($this->{args}, $this->{argparams}, $this->{name}); + my $varname = "ccs_reg_arg_" . (lc $name) . $postfix; + my @mins; + my @sorted_args = @{$this->{sorted_args}}; + my $lim_arg; + my $size = arr_size($this); + + $argdescs .= "static const struct ccs_reg_arg " . $varname . "[] = {\n"; + + foreach my $sorted_arg (@sorted_args) { + push @mins, $argparams->{$sorted_arg}->{min}; + } + + foreach my $sorted_arg (@sorted_args) { + my $h = $argparams->{$sorted_arg}; + + $argdescs .= "\t{ \"$sorted_arg\", $h->{min}, $h->{max}, $h->{elsize} },\n"; + + $lim_arg .= defined $lim_arg ? ", $h->{min}" : "$h->{min}"; + } + + $argdescs .= "};\n\n"; + + $reglist .= "\t{ CCS_R_" . (uc $name) . "(" . (join ",", (@mins)) . + "), $size, sizeof($varname) / sizeof(*$varname)," . + " \"" . (lc $name) . "\", $varname },\n"; + + print $LC tabconv sprintf "\t{ CCS_R_" . (uc $name) . "($lim_arg), " . + $size . ", " . ($is_same_reg ? "CCS_L_FL_SAME_REG" : "0") . + ", \"$name" . (defined $this->{discontig} ? " $lim_arg" : "") . "\" },\n" + if is_limit_reg $this->{base_addr}; +} + +my $hdr_data; + +while (<$R>) { + chop; + s/^\s*//; + next if /^[#;]/ || /^$/; + if (s/^-\s*//) { + if (s/^b\s*//) { + my ($bit, $addr) = split /\t+/; + $bit = uc $bit; + $hdr_data .= sprintf "#define %-62s %s", "CCS_" . (uc ${this{name}}) ."_$bit", bit_def($addr) . "\n"; + } elsif (s/^f\s*//) { + s/[,\.-]/_/g; + my @a = split /\s+/; + my ($msb, $lsb, $this_field) = reverse @a; + @a = ( { "name" => "SHIFT", "addr" => $lsb, "fmt" => "%uU", }, + { "name" => "MASK", "addr" => (1 << ($msb + 1)) - 1 - ((1 << $lsb) - 1), "fmt" => "0x%" . join(".", ($this{"elsize"} >> 2) x 2) . "x" } ); + $this{"field"} = $this_field; + foreach my $ar (@a) { + #print $ar->{fmt}."\n"; + $hdr_data .= sprintf "#define %-62s " . $ar->{"fmt"} . "\n", "CCS_" . (uc $this{"name"}) . (defined $this_field ? "_" . uc $this_field : "") . "_" . $ar->{"name"}, $ar->{"addr"} . "\n"; + } + } elsif (s/^e\s*//) { + s/[,\.-]/_/g; + my ($enum, $addr) = split /\s+/; + $enum = uc $enum; + $hdr_data .= sprintf "#define %-62s %s", "CCS_" . (uc ${this{name}}) . (defined $this{"field"} ? "_" . uc $this{"field"} : "") ."_$enum", $addr . ($addr =~ /0x/i ? "" : "U") . "\n"; + } elsif (s/^l\s*//) { + my ($arg, $min, $max, $elsize, @discontig) = split /\s+/; + my $size; + + foreach my $num ($min, $max) { + $num = hex $num if $num =~ /0x/i; + } + + $hdr_data .= sprintf "#define %-62s %s", "CCS_LIM_" . (uc ${this{name}} . "_MIN_$arg"), $min . ($min =~ /0x/i ? "" : "U") . "\n"; + $hdr_data .= sprintf "#define %-62s %s", "CCS_LIM_" . (uc ${this{name}} . "_MAX_$arg"), $max . ($max =~ /0x/i ? "" : "U") . "\n"; + + my $h = $this{argparams}; + + $h->{$arg} = { "min" => $min, + "max" => $max, + "elsize" => $elsize =~ /^0x/ ? hex $elsize : $elsize, + "discontig" => \@discontig }; + + $this{discontig} = $arg if @discontig; + + next if $#{$this{args}} + 1 != scalar keys %{$this{argparams}}; + + my $reg_formula = "($this{addr}"; + my $lim_formula; + + foreach my $arg (@{$this{args}}) { + my $d = $h->{$arg}->{discontig}; + my $times = $h->{$arg}->{elsize} != 1 ? + " * " . $h->{$arg}->{elsize} : ""; + + if (@$d) { + my ($lim, $offset) = split /,/, $d->[0]; + + $reg_formula .= " + (($arg) < $lim ? ($arg)$times : $offset + (($arg) - $lim)$times)"; + } else { + $reg_formula .= " + ($arg)$times"; + } + + $lim_formula .= (defined $lim_formula ? " + " : "") . "($arg)$times"; + } + + $reg_formula .= ")\n"; + $lim_formula =~ s/^\(([a-z0-9]+)\)$/$1/i; + + print $H tabconv sprintf("#define %-62s %s", "CCS_R_" . (uc $this{name}) . + $this{arglist}, $reg_formula); + + print $H tabconv $hdr_data; + undef $hdr_data; + + # Sort arguments in descending order by size + @{$this{sorted_args}} = sort { + $h->{$a}->{elsize} <= $h->{$b}->{elsize} + } @{$this{args}}; + + if (defined $this{discontig}) { + my $da = $this{argparams}->{$this{discontig}}; + my ($first_discontig) = split /,/, $da->{discontig}->[0]; + my $max = $da->{max}; + + $da->{max} = $first_discontig - 1; + print_args(\%this, "", 0); + + $da->{min} = $da->{max} + 1; + $da->{max} = $max; + print_args(\%this, $first_discontig, 1); + } else { + print_args(\%this, "", 0); + } + + next unless is_limit_reg $this{base_addr}; + + print $LH tabconv sprintf "#define %-63s%s\n", + "CCS_L_" . (uc $this{name}) . "_OFFSET(" . + (join ", ", @{$this{args}}) . ")", "($lim_formula)"; + } + + if (! @{$this{args}}) { + print $H tabconv($hdr_data); + undef $hdr_data; + } + + next; + } + + my ($name, $addr, @flags) = split /\t+/, $_; + my $args = []; + + my $sp; + + ($name, $addr, $args) = name_split($name, $addr) if /\(.*\)/; + + $name =~ s/[,\.-]/_/g; + + my $flagstring = ""; + my $size = elem_size(@flags); + $flagstring .= "| CCS_FL_16BIT " if $size eq "2"; + $flagstring .= "| CCS_FL_32BIT " if $size eq "4"; + $flagstring .= "| CCS_FL_FLOAT_IREAL " if grep /^float_ireal$/, @flags; + $flagstring .= "| CCS_FL_IREAL " if grep /^ireal$/, @flags; + $flagstring =~ s/^\| //; + $flagstring =~ s/ $//; + $flagstring = "($flagstring)" if $flagstring =~ /\|/; + my $base_addr = $addr; + $addr = "($addr | $flagstring)" if $flagstring ne ""; + + my $arglist = @$args ? "(" . (join ", ", @$args) . ")" : ""; + $hdr_data .= sprintf "#define %-62s %s\n", "CCS_R_" . (uc $name), $addr + if !@$args; + + $name =~ s/\(.*//; + + %this = ( name => $name, + addr => $addr, + base_addr => $base_addr, + argparams => {}, + args => $args, + arglist => $arglist, + elsize => $size, + ); + + if (!@$args) { + $reglist .= "\t{ CCS_R_" . (uc $name) . ", 1, 0, \"" . (lc $name) . "\", NULL },\n"; + print $H tabconv $hdr_data; + undef $hdr_data; + + print $LC tabconv sprintf "\t{ CCS_R_" . (uc $name) . ", " . + $this{elsize} . ", 0, \"$name\" },\n" + if is_limit_reg $this{base_addr}; + } + + print $LH tabconv sprintf "#define %-63s%s\n", + "CCS_L_" . (uc $this{name}), $limitcount++ + if is_limit_reg $this{base_addr}; +} + +if (defined $A) { + print $A $argdescs, $reglist; + + print $A "\t{ 0 }\n"; + + print $A "};\n"; +} + +print $H "\n#endif /* __${uc_header}__ */\n"; + +print $LH tabconv sprintf "#define %-63s%s\n", "CCS_L_LAST", $limitcount; + +print $LH "\n#endif /* __${uc_limith}__ */\n"; + +print $LC "\t{ 0 } /* Guardian */\n"; +print $LC "};\n"; + +close($R); +close($H); +close($A) if defined $A; +close($LC); +close($LH); diff --git a/MAINTAINERS b/MAINTAINERS index a22392994667..0864fe0f945a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16108,6 +16108,7 @@ M: Sakari Ailus L: linux-media@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/media/i2c/nokia,smia.txt +F: Documentation/driver-api/media/drivers/ccs/ F: drivers/media/i2c/smiapp-pll.c F: drivers/media/i2c/smiapp-pll.h F: drivers/media/i2c/smiapp/ -- cgit v1.2.3 From 4ad97bfb1a7ee826b7f253750ba47f2e991c12ec Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 5 Nov 2020 17:08:23 +0100 Subject: media: Documentation: ccs: Add CCS driver documentation Document the MIPI CCS driver and the C register definition generator. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- Documentation/driver-api/media/drivers/ccs/ccs.rst | 82 ++++++++++++++++++++++ Documentation/driver-api/media/drivers/index.rst | 1 + 2 files changed, 83 insertions(+) create mode 100644 Documentation/driver-api/media/drivers/ccs/ccs.rst diff --git a/Documentation/driver-api/media/drivers/ccs/ccs.rst b/Documentation/driver-api/media/drivers/ccs/ccs.rst new file mode 100644 index 000000000000..9164c9fa8b42 --- /dev/null +++ b/Documentation/driver-api/media/drivers/ccs/ccs.rst @@ -0,0 +1,82 @@ +.. SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause + +.. include:: + +MIPI CCS camera sensor driver +============================= + +The MIPI CCS camera sensor driver is a generic driver for `MIPI CCS +`_ compliant +camera sensors. It exposes three sub-devices representing the pixel array, +the binner and the scaler. + +As the capabilities of individual devices vary, the driver exposes +interfaces based on the capabilities that exist in hardware. + +Pixel Array sub-device +---------------------- + +The pixel array sub-device represents the camera sensor's pixel matrix, as well +as analogue crop functionality present in many compliant devices. The analogue +crop is configured using the ``V4L2_SEL_TGT_CROP`` on the source pad (0) of the +entity. The size of the pixel matrix can be obtained by getting the +``V4L2_SEL_TGT_NATIVE_SIZE`` target. + +Binner +------ + +The binner sub-device represents the binning functionality on the sensor. For +that purpose, selection target ``V4L2_SEL_TGT_COMPOSE`` is supported on the +sink pad (0). + +Additionally, if a device has no scaler or digital crop functionality, the +source pad (1) expses another digital crop selection rectangle that can only +crop at the end of the lines and frames. + +Scaler +------ + +The scaler sub-device represents the digital crop and scaling functionality of +the sensor. The V4L2 selection target ``V4L2_SEL_TGT_CROP`` is used to +configure the digital crop on the sink pad (0) when digital crop is supported. +Scaling is configured using selection target ``V4L2_SEL_TGT_COMPOSE`` on the +sink pad (0) as well. + +Additionally, if the scaler sub-device exists, its source pad (1) exposes +another digital crop selection rectangle that can only crop at the end of the +lines and frames. + +Digital and analogue crop +------------------------- + +Digital crop functionality is referred to as cropping that effectively works by +dropping some data on the floor. Analogue crop, on the other hand, means that +the cropped information is never retrieved. In case of camera sensors, the +analogue data is never read from the pixel matrix that are outside the +configured selection rectangle that designates crop. The difference has an +effect in device timing and likely also in power consumption. + +Register definition generator +----------------------------- + +The ccs-regs.txt file contains MIPI CCS register definitions that are used +to produce C source code files for definitions that can be better used by +programs written in C language. As there are many dependencies between the +produced files, please do not modify them manually as it's error-prone and +in vain, but instead change the script producing them. + +Usage +~~~~~ + +Conventionally the script is called this way to update the CCS driver +definitions: + +.. code-block:: none + + $ Documentation/driver-api/media/drivers/ccs/mk-ccs-regs -k \ + -e drivers/media/i2c/ccs/ccs-regs.h \ + -L drivers/media/i2c/ccs/ccs-limits.h \ + -l drivers/media/i2c/ccs/ccs-limits.c \ + -c Documentation/driver-api/media/drivers/ccs/ccs-regs.txt + +**Copyright** |copy| 2020 Intel Corporation diff --git a/Documentation/driver-api/media/drivers/index.rst b/Documentation/driver-api/media/drivers/index.rst index eb7011782863..426cda633bf0 100644 --- a/Documentation/driver-api/media/drivers/index.rst +++ b/Documentation/driver-api/media/drivers/index.rst @@ -26,6 +26,7 @@ Video4Linux (V4L) drivers tuners vimc-devel zoran + ccs/ccs Digital TV drivers -- cgit v1.2.3 From 6493c4b777c2bca7fcfaabca2388d82f186f9be3 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 22 Oct 2020 08:57:04 +0200 Subject: media: smiapp: Import CCS definitions Import CCS register and limit definitions. These files are generated by a Perl script based on a text-based register definition file. The generator was added on commit 1ec0b899c2b7 ("media: ccs: Add the generator for CCS register definitions and limits") Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/ccs-limits.c | 239 +++++++++ drivers/media/i2c/smiapp/ccs-limits.h | 259 +++++++++ drivers/media/i2c/smiapp/ccs-regs.h | 954 ++++++++++++++++++++++++++++++++++ 3 files changed, 1452 insertions(+) create mode 100644 drivers/media/i2c/smiapp/ccs-limits.c create mode 100644 drivers/media/i2c/smiapp/ccs-limits.h create mode 100644 drivers/media/i2c/smiapp/ccs-regs.h diff --git a/drivers/media/i2c/smiapp/ccs-limits.c b/drivers/media/i2c/smiapp/ccs-limits.c new file mode 100644 index 000000000000..f5511789ac83 --- /dev/null +++ b/drivers/media/i2c/smiapp/ccs-limits.c @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause +/* Copyright (C) 2019--2020 Intel Corporation */ + +#include "ccs-limits.h" +#include "ccs-regs.h" + +const struct ccs_limit ccs_limits[] = { + { CCS_R_FRAME_FORMAT_MODEL_TYPE, 1, 0, "frame_format_model_type" }, + { CCS_R_FRAME_FORMAT_MODEL_SUBTYPE, 1, 0, "frame_format_model_subtype" }, + { CCS_R_FRAME_FORMAT_DESCRIPTOR(0), 30, 0, "frame_format_descriptor" }, + { CCS_R_FRAME_FORMAT_DESCRIPTOR_4(0), 32, 0, "frame_format_descriptor_4" }, + { CCS_R_ANALOG_GAIN_CAPABILITY, 2, 0, "analog_gain_capability" }, + { CCS_R_ANALOG_GAIN_CODE_MIN, 2, 0, "analog_gain_code_min" }, + { CCS_R_ANALOG_GAIN_CODE_MAX, 2, 0, "analog_gain_code_max" }, + { CCS_R_ANALOG_GAIN_CODE_STEP, 2, 0, "analog_gain_code_step" }, + { CCS_R_ANALOG_GAIN_TYPE, 2, 0, "analog_gain_type" }, + { CCS_R_ANALOG_GAIN_M0, 2, 0, "analog_gain_m0" }, + { CCS_R_ANALOG_GAIN_C0, 2, 0, "analog_gain_c0" }, + { CCS_R_ANALOG_GAIN_M1, 2, 0, "analog_gain_m1" }, + { CCS_R_ANALOG_GAIN_C1, 2, 0, "analog_gain_c1" }, + { CCS_R_ANALOG_LINEAR_GAIN_MIN, 2, 0, "analog_linear_gain_min" }, + { CCS_R_ANALOG_LINEAR_GAIN_MAX, 2, 0, "analog_linear_gain_max" }, + { CCS_R_ANALOG_LINEAR_GAIN_STEP_SIZE, 2, 0, "analog_linear_gain_step_size" }, + { CCS_R_ANALOG_EXPONENTIAL_GAIN_MIN, 2, 0, "analog_exponential_gain_min" }, + { CCS_R_ANALOG_EXPONENTIAL_GAIN_MAX, 2, 0, "analog_exponential_gain_max" }, + { CCS_R_ANALOG_EXPONENTIAL_GAIN_STEP_SIZE, 2, 0, "analog_exponential_gain_step_size" }, + { CCS_R_DATA_FORMAT_MODEL_TYPE, 1, 0, "data_format_model_type" }, + { CCS_R_DATA_FORMAT_MODEL_SUBTYPE, 1, 0, "data_format_model_subtype" }, + { CCS_R_DATA_FORMAT_DESCRIPTOR(0), 32, 0, "data_format_descriptor" }, + { CCS_R_INTEGRATION_TIME_CAPABILITY, 2, 0, "integration_time_capability" }, + { CCS_R_COARSE_INTEGRATION_TIME_MIN, 2, 0, "coarse_integration_time_min" }, + { CCS_R_COARSE_INTEGRATION_TIME_MAX_MARGIN, 2, 0, "coarse_integration_time_max_margin" }, + { CCS_R_FINE_INTEGRATION_TIME_MIN, 2, 0, "fine_integration_time_min" }, + { CCS_R_FINE_INTEGRATION_TIME_MAX_MARGIN, 2, 0, "fine_integration_time_max_margin" }, + { CCS_R_DIGITAL_GAIN_CAPABILITY, 1, 0, "digital_gain_capability" }, + { CCS_R_DIGITAL_GAIN_MIN, 2, 0, "digital_gain_min" }, + { CCS_R_DIGITAL_GAIN_MAX, 2, 0, "digital_gain_max" }, + { CCS_R_DIGITAL_GAIN_STEP_SIZE, 2, 0, "digital_gain_step_size" }, + { CCS_R_PEDESTAL_CAPABILITY, 1, 0, "Pedestal_capability" }, + { CCS_R_ADC_CAPABILITY, 1, 0, "ADC_capability" }, + { CCS_R_ADC_BIT_DEPTH_CAPABILITY, 4, 0, "ADC_bit_depth_capability" }, + { CCS_R_MIN_EXT_CLK_FREQ_MHZ, 4, 0, "min_ext_clk_freq_mhz" }, + { CCS_R_MAX_EXT_CLK_FREQ_MHZ, 4, 0, "max_ext_clk_freq_mhz" }, + { CCS_R_MIN_PRE_PLL_CLK_DIV, 2, 0, "min_pre_pll_clk_div" }, + { CCS_R_MAX_PRE_PLL_CLK_DIV, 2, 0, "max_pre_pll_clk_div" }, + { CCS_R_MIN_PLL_IP_CLK_FREQ_MHZ, 4, 0, "min_pll_ip_clk_freq_mhz" }, + { CCS_R_MAX_PLL_IP_CLK_FREQ_MHZ, 4, 0, "max_pll_ip_clk_freq_mhz" }, + { CCS_R_MIN_PLL_MULTIPLIER, 2, 0, "min_pll_multiplier" }, + { CCS_R_MAX_PLL_MULTIPLIER, 2, 0, "max_pll_multiplier" }, + { CCS_R_MIN_PLL_OP_CLK_FREQ_MHZ, 4, 0, "min_pll_op_clk_freq_mhz" }, + { CCS_R_MAX_PLL_OP_CLK_FREQ_MHZ, 4, 0, "max_pll_op_clk_freq_mhz" }, + { CCS_R_MIN_VT_SYS_CLK_DIV, 2, 0, "min_vt_sys_clk_div" }, + { CCS_R_MAX_VT_SYS_CLK_DIV, 2, 0, "max_vt_sys_clk_div" }, + { CCS_R_MIN_VT_SYS_CLK_FREQ_MHZ, 4, 0, "min_vt_sys_clk_freq_mhz" }, + { CCS_R_MAX_VT_SYS_CLK_FREQ_MHZ, 4, 0, "max_vt_sys_clk_freq_mhz" }, + { CCS_R_MIN_VT_PIX_CLK_FREQ_MHZ, 4, 0, "min_vt_pix_clk_freq_mhz" }, + { CCS_R_MAX_VT_PIX_CLK_FREQ_MHZ, 4, 0, "max_vt_pix_clk_freq_mhz" }, + { CCS_R_MIN_VT_PIX_CLK_DIV, 2, 0, "min_vt_pix_clk_div" }, + { CCS_R_MAX_VT_PIX_CLK_DIV, 2, 0, "max_vt_pix_clk_div" }, + { CCS_R_CLOCK_CALCULATION, 1, 0, "clock_calculation" }, + { CCS_R_NUM_OF_VT_LANES, 1, 0, "num_of_vt_lanes" }, + { CCS_R_NUM_OF_OP_LANES, 1, 0, "num_of_op_lanes" }, + { CCS_R_OP_BITS_PER_LANE, 1, 0, "op_bits_per_lane" }, + { CCS_R_MIN_FRAME_LENGTH_LINES, 2, 0, "min_frame_length_lines" }, + { CCS_R_MAX_FRAME_LENGTH_LINES, 2, 0, "max_frame_length_lines" }, + { CCS_R_MIN_LINE_LENGTH_PCK, 2, 0, "min_line_length_pck" }, + { CCS_R_MAX_LINE_LENGTH_PCK, 2, 0, "max_line_length_pck" }, + { CCS_R_MIN_LINE_BLANKING_PCK, 2, 0, "min_line_blanking_pck" }, + { CCS_R_MIN_FRAME_BLANKING_LINES, 2, 0, "min_frame_blanking_lines" }, + { CCS_R_MIN_LINE_LENGTH_PCK_STEP_SIZE, 1, 0, "min_line_length_pck_step_size" }, + { CCS_R_TIMING_MODE_CAPABILITY, 1, 0, "timing_mode_capability" }, + { CCS_R_FRAME_MARGIN_MAX_VALUE, 2, 0, "frame_margin_max_value" }, + { CCS_R_FRAME_MARGIN_MIN_VALUE, 1, 0, "frame_margin_min_value" }, + { CCS_R_GAIN_DELAY_TYPE, 1, 0, "gain_delay_type" }, + { CCS_R_MIN_OP_SYS_CLK_DIV, 2, 0, "min_op_sys_clk_div" }, + { CCS_R_MAX_OP_SYS_CLK_DIV, 2, 0, "max_op_sys_clk_div" }, + { CCS_R_MIN_OP_SYS_CLK_FREQ_MHZ, 4, 0, "min_op_sys_clk_freq_mhz" }, + { CCS_R_MAX_OP_SYS_CLK_FREQ_MHZ, 4, 0, "max_op_sys_clk_freq_mhz" }, + { CCS_R_MIN_OP_PIX_CLK_DIV, 2, 0, "min_op_pix_clk_div" }, + { CCS_R_MAX_OP_PIX_CLK_DIV, 2, 0, "max_op_pix_clk_div" }, + { CCS_R_MIN_OP_PIX_CLK_FREQ_MHZ, 4, 0, "min_op_pix_clk_freq_mhz" }, + { CCS_R_MAX_OP_PIX_CLK_FREQ_MHZ, 4, 0, "max_op_pix_clk_freq_mhz" }, + { CCS_R_X_ADDR_MIN, 2, 0, "x_addr_min" }, + { CCS_R_Y_ADDR_MIN, 2, 0, "y_addr_min" }, + { CCS_R_X_ADDR_MAX, 2, 0, "x_addr_max" }, + { CCS_R_Y_ADDR_MAX, 2, 0, "y_addr_max" }, + { CCS_R_MIN_X_OUTPUT_SIZE, 2, 0, "min_x_output_size" }, + { CCS_R_MIN_Y_OUTPUT_SIZE, 2, 0, "min_y_output_size" }, + { CCS_R_MAX_X_OUTPUT_SIZE, 2, 0, "max_x_output_size" }, + { CCS_R_MAX_Y_OUTPUT_SIZE, 2, 0, "max_y_output_size" }, + { CCS_R_X_ADDR_START_DIV_CONSTANT, 1, 0, "x_addr_start_div_constant" }, + { CCS_R_Y_ADDR_START_DIV_CONSTANT, 1, 0, "y_addr_start_div_constant" }, + { CCS_R_X_ADDR_END_DIV_CONSTANT, 1, 0, "x_addr_end_div_constant" }, + { CCS_R_Y_ADDR_END_DIV_CONSTANT, 1, 0, "y_addr_end_div_constant" }, + { CCS_R_X_SIZE_DIV, 1, 0, "x_size_div" }, + { CCS_R_Y_SIZE_DIV, 1, 0, "y_size_div" }, + { CCS_R_X_OUTPUT_DIV, 1, 0, "x_output_div" }, + { CCS_R_Y_OUTPUT_DIV, 1, 0, "y_output_div" }, + { CCS_R_NON_FLEXIBLE_RESOLUTION_SUPPORT, 1, 0, "non_flexible_resolution_support" }, + { CCS_R_MIN_OP_PRE_PLL_CLK_DIV, 2, 0, "min_op_pre_pll_clk_div" }, + { CCS_R_MAX_OP_PRE_PLL_CLK_DIV, 2, 0, "max_op_pre_pll_clk_div" }, + { CCS_R_MIN_OP_PLL_IP_CLK_FREQ_MHZ, 4, 0, "min_op_pll_ip_clk_freq_mhz" }, + { CCS_R_MAX_OP_PLL_IP_CLK_FREQ_MHZ, 4, 0, "max_op_pll_ip_clk_freq_mhz" }, + { CCS_R_MIN_OP_PLL_MULTIPLIER, 2, 0, "min_op_pll_multiplier" }, + { CCS_R_MAX_OP_PLL_MULTIPLIER, 2, 0, "max_op_pll_multiplier" }, + { CCS_R_MIN_OP_PLL_OP_CLK_FREQ_MHZ, 4, 0, "min_op_pll_op_clk_freq_mhz" }, + { CCS_R_MAX_OP_PLL_OP_CLK_FREQ_MHZ, 4, 0, "max_op_pll_op_clk_freq_mhz" }, + { CCS_R_CLOCK_TREE_PLL_CAPABILITY, 1, 0, "clock_tree_pll_capability" }, + { CCS_R_CLOCK_CAPA_TYPE_CAPABILITY, 1, 0, "clock_capa_type_capability" }, + { CCS_R_MIN_EVEN_INC, 2, 0, "min_even_inc" }, + { CCS_R_MIN_ODD_INC, 2, 0, "min_odd_inc" }, + { CCS_R_MAX_EVEN_INC, 2, 0, "max_even_inc" }, + { CCS_R_MAX_ODD_INC, 2, 0, "max_odd_inc" }, + { CCS_R_AUX_SUBSAMP_CAPABILITY, 1, 0, "aux_subsamp_capability" }, + { CCS_R_AUX_SUBSAMP_MONO_CAPABILITY, 1, 0, "aux_subsamp_mono_capability" }, + { CCS_R_MONOCHROME_CAPABILITY, 1, 0, "monochrome_capability" }, + { CCS_R_PIXEL_READOUT_CAPABILITY, 1, 0, "pixel_readout_capability" }, + { CCS_R_MIN_EVEN_INC_MONO, 2, 0, "min_even_inc_mono" }, + { CCS_R_MAX_EVEN_INC_MONO, 2, 0, "max_even_inc_mono" }, + { CCS_R_MIN_ODD_INC_MONO, 2, 0, "min_odd_inc_mono" }, + { CCS_R_MAX_ODD_INC_MONO, 2, 0, "max_odd_inc_mono" }, + { CCS_R_MIN_EVEN_INC_BC2, 2, 0, "min_even_inc_bc2" }, + { CCS_R_MAX_EVEN_INC_BC2, 2, 0, "max_even_inc_bc2" }, + { CCS_R_MIN_ODD_INC_BC2, 2, 0, "min_odd_inc_bc2" }, + { CCS_R_MAX_ODD_INC_BC2, 2, 0, "max_odd_inc_bc2" }, + { CCS_R_MIN_EVEN_INC_MONO_BC2, 2, 0, "min_even_inc_mono_bc2" }, + { CCS_R_MAX_EVEN_INC_MONO_BC2, 2, 0, "max_even_inc_mono_bc2" }, + { CCS_R_MIN_ODD_INC_MONO_BC2, 2, 0, "min_odd_inc_mono_bc2" }, + { CCS_R_MAX_ODD_INC_MONO_BC2, 2, 0, "max_odd_inc_mono_bc2" }, + { CCS_R_SCALING_CAPABILITY, 2, 0, "scaling_capability" }, + { CCS_R_SCALER_M_MIN, 2, 0, "scaler_m_min" }, + { CCS_R_SCALER_M_MAX, 2, 0, "scaler_m_max" }, + { CCS_R_SCALER_N_MIN, 2, 0, "scaler_n_min" }, + { CCS_R_SCALER_N_MAX, 2, 0, "scaler_n_max" }, + { CCS_R_DIGITAL_CROP_CAPABILITY, 1, 0, "digital_crop_capability" }, + { CCS_R_HDR_CAPABILITY_1, 1, 0, "hdr_capability_1" }, + { CCS_R_MIN_HDR_BIT_DEPTH, 1, 0, "min_hdr_bit_depth" }, + { CCS_R_HDR_RESOLUTION_SUB_TYPES, 1, 0, "hdr_resolution_sub_types" }, + { CCS_R_HDR_RESOLUTION_SUB_TYPE(0), 2, 0, "hdr_resolution_sub_type" }, + { CCS_R_HDR_CAPABILITY_2, 1, 0, "hdr_capability_2" }, + { CCS_R_MAX_HDR_BIT_DEPTH, 1, 0, "max_hdr_bit_depth" }, + { CCS_R_USL_SUPPORT_CAPABILITY, 1, 0, "usl_support_capability" }, + { CCS_R_USL_CLOCK_MODE_D_CAPABILITY, 1, 0, "usl_clock_mode_d_capability" }, + { CCS_R_MIN_OP_SYS_CLK_DIV_REV, 1, 0, "min_op_sys_clk_div_rev" }, + { CCS_R_MAX_OP_SYS_CLK_DIV_REV, 1, 0, "max_op_sys_clk_div_rev" }, + { CCS_R_MIN_OP_PIX_CLK_DIV_REV, 1, 0, "min_op_pix_clk_div_rev" }, + { CCS_R_MAX_OP_PIX_CLK_DIV_REV, 1, 0, "max_op_pix_clk_div_rev" }, + { CCS_R_MIN_OP_SYS_CLK_FREQ_REV_MHZ, 4, 0, "min_op_sys_clk_freq_rev_mhz" }, + { CCS_R_MAX_OP_SYS_CLK_FREQ_REV_MHZ, 4, 0, "max_op_sys_clk_freq_rev_mhz" }, + { CCS_R_MIN_OP_PIX_CLK_FREQ_REV_MHZ, 4, 0, "min_op_pix_clk_freq_rev_mhz" }, + { CCS_R_MAX_OP_PIX_CLK_FREQ_REV_MHZ, 4, 0, "max_op_pix_clk_freq_rev_mhz" }, + { CCS_R_MAX_BITRATE_REV_D_MODE_MBPS, 4, 0, "max_bitrate_rev_d_mode_mbps" }, + { CCS_R_MAX_SYMRATE_REV_C_MODE_MSPS, 4, 0, "max_symrate_rev_c_mode_msps" }, + { CCS_R_COMPRESSION_CAPABILITY, 1, 0, "compression_capability" }, + { CCS_R_TEST_MODE_CAPABILITY, 2, 0, "test_mode_capability" }, + { CCS_R_PN9_DATA_FORMAT1, 1, 0, "pn9_data_format1" }, + { CCS_R_PN9_DATA_FORMAT2, 1, 0, "pn9_data_format2" }, + { CCS_R_PN9_DATA_FORMAT3, 1, 0, "pn9_data_format3" }, + { CCS_R_PN9_DATA_FORMAT4, 1, 0, "pn9_data_format4" }, + { CCS_R_PN9_MISC_CAPABILITY, 1, 0, "pn9_misc_capability" }, + { CCS_R_TEST_PATTERN_CAPABILITY, 1, 0, "test_pattern_capability" }, + { CCS_R_PATTERN_SIZE_DIV_M1, 1, 0, "pattern_size_div_m1" }, + { CCS_R_FIFO_SUPPORT_CAPABILITY, 1, 0, "fifo_support_capability" }, + { CCS_R_PHY_CTRL_CAPABILITY, 1, 0, "phy_ctrl_capability" }, + { CCS_R_CSI_DPHY_LANE_MODE_CAPABILITY, 1, 0, "csi_dphy_lane_mode_capability" }, + { CCS_R_CSI_SIGNALING_MODE_CAPABILITY, 1, 0, "csi_signaling_mode_capability" }, + { CCS_R_FAST_STANDBY_CAPABILITY, 1, 0, "fast_standby_capability" }, + { CCS_R_CSI_ADDRESS_CONTROL_CAPABILITY, 1, 0, "csi_address_control_capability" }, + { CCS_R_DATA_TYPE_CAPABILITY, 1, 0, "data_type_capability" }, + { CCS_R_CSI_CPHY_LANE_MODE_CAPABILITY, 1, 0, "csi_cphy_lane_mode_capability" }, + { CCS_R_EMB_DATA_CAPABILITY, 1, 0, "emb_data_capability" }, + { CCS_R_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS(0), 16, 0, "max_per_lane_bitrate_lane_d_mode_mbps 0" }, + { CCS_R_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS(4), 16, CCS_L_FL_SAME_REG, "max_per_lane_bitrate_lane_d_mode_mbps 4" }, + { CCS_R_TEMP_SENSOR_CAPABILITY, 1, 0, "temp_sensor_capability" }, + { CCS_R_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS(0), 16, 0, "max_per_lane_bitrate_lane_c_mode_mbps 0" }, + { CCS_R_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS(4), 16, CCS_L_FL_SAME_REG, "max_per_lane_bitrate_lane_c_mode_mbps 4" }, + { CCS_R_DPHY_EQUALIZATION_CAPABILITY, 1, 0, "dphy_equalization_capability" }, + { CCS_R_CPHY_EQUALIZATION_CAPABILITY, 1, 0, "cphy_equalization_capability" }, + { CCS_R_DPHY_PREAMBLE_CAPABILITY, 1, 0, "dphy_preamble_capability" }, + { CCS_R_DPHY_SSC_CAPABILITY, 1, 0, "dphy_ssc_capability" }, + { CCS_R_CPHY_CALIBRATION_CAPABILITY, 1, 0, "cphy_calibration_capability" }, + { CCS_R_DPHY_CALIBRATION_CAPABILITY, 1, 0, "dphy_calibration_capability" }, + { CCS_R_PHY_CTRL_CAPABILITY_2, 1, 0, "phy_ctrl_capability_2" }, + { CCS_R_LRTE_CPHY_CAPABILITY, 1, 0, "lrte_cphy_capability" }, + { CCS_R_LRTE_DPHY_CAPABILITY, 1, 0, "lrte_dphy_capability" }, + { CCS_R_ALPS_CAPABILITY_DPHY, 1, 0, "alps_capability_dphy" }, + { CCS_R_ALPS_CAPABILITY_CPHY, 1, 0, "alps_capability_cphy" }, + { CCS_R_SCRAMBLING_CAPABILITY, 1, 0, "scrambling_capability" }, + { CCS_R_DPHY_MANUAL_CONSTANT, 1, 0, "dphy_manual_constant" }, + { CCS_R_CPHY_MANUAL_CONSTANT, 1, 0, "cphy_manual_constant" }, + { CCS_R_CSI2_INTERFACE_CAPABILITY_MISC, 1, 0, "CSI2_interface_capability_misc" }, + { CCS_R_PHY_CTRL_CAPABILITY_3, 1, 0, "PHY_ctrl_capability_3" }, + { CCS_R_DPHY_SF, 1, 0, "dphy_sf" }, + { CCS_R_CPHY_SF, 1, 0, "cphy_sf" }, + { CCS_R_DPHY_LIMITS_1, 1, 0, "dphy_limits_1" }, + { CCS_R_DPHY_LIMITS_2, 1, 0, "dphy_limits_2" }, + { CCS_R_DPHY_LIMITS_3, 1, 0, "dphy_limits_3" }, + { CCS_R_DPHY_LIMITS_4, 1, 0, "dphy_limits_4" }, + { CCS_R_DPHY_LIMITS_5, 1, 0, "dphy_limits_5" }, + { CCS_R_DPHY_LIMITS_6, 1, 0, "dphy_limits_6" }, + { CCS_R_CPHY_LIMITS_1, 1, 0, "cphy_limits_1" }, + { CCS_R_CPHY_LIMITS_2, 1, 0, "cphy_limits_2" }, + { CCS_R_CPHY_LIMITS_3, 1, 0, "cphy_limits_3" }, + { CCS_R_MIN_FRAME_LENGTH_LINES_BIN, 2, 0, "min_frame_length_lines_bin" }, + { CCS_R_MAX_FRAME_LENGTH_LINES_BIN, 2, 0, "max_frame_length_lines_bin" }, + { CCS_R_MIN_LINE_LENGTH_PCK_BIN, 2, 0, "min_line_length_pck_bin" }, + { CCS_R_MAX_LINE_LENGTH_PCK_BIN, 2, 0, "max_line_length_pck_bin" }, + { CCS_R_MIN_LINE_BLANKING_PCK_BIN, 2, 0, "min_line_blanking_pck_bin" }, + { CCS_R_FINE_INTEGRATION_TIME_MIN_BIN, 2, 0, "fine_integration_time_min_bin" }, + { CCS_R_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN, 2, 0, "fine_integration_time_max_margin_bin" }, + { CCS_R_BINNING_CAPABILITY, 1, 0, "binning_capability" }, + { CCS_R_BINNING_WEIGHTING_CAPABILITY, 1, 0, "binning_weighting_capability" }, + { CCS_R_BINNING_SUB_TYPES, 1, 0, "binning_sub_types" }, + { CCS_R_BINNING_SUB_TYPE(0), 64, 0, "binning_sub_type" }, + { CCS_R_BINNING_WEIGHTING_MONO_CAPABILITY, 1, 0, "binning_weighting_mono_capability" }, + { CCS_R_BINNING_SUB_TYPES_MONO, 1, 0, "binning_sub_types_mono" }, + { CCS_R_BINNING_SUB_TYPE_MONO(0), 64, 0, "binning_sub_type_mono" }, + { CCS_R_DATA_TRANSFER_IF_CAPABILITY, 1, 0, "data_transfer_if_capability" }, + { CCS_R_SHADING_CORRECTION_CAPABILITY, 1, 0, "shading_correction_capability" }, + { CCS_R_GREEN_IMBALANCE_CAPABILITY, 1, 0, "green_imbalance_capability" }, + { CCS_R_MODULE_SPECIFIC_CORRECTION_CAPABILITY, 1, 0, "module_specific_correction_capability" }, + { CCS_R_DEFECT_CORRECTION_CAPABILITY, 2, 0, "defect_correction_capability" }, + { CCS_R_DEFECT_CORRECTION_CAPABILITY_2, 2, 0, "defect_correction_capability_2" }, + { CCS_R_NF_CAPABILITY, 1, 0, "nf_capability" }, + { CCS_R_OB_READOUT_CAPABILITY, 1, 0, "ob_readout_capability" }, + { CCS_R_COLOR_FEEDBACK_CAPABILITY, 1, 0, "color_feedback_capability" }, + { CCS_R_CFA_PATTERN_CAPABILITY, 1, 0, "CFA_pattern_capability" }, + { CCS_R_CFA_PATTERN_CONVERSION_CAPABILITY, 1, 0, "CFA_pattern_conversion_capability" }, + { CCS_R_FLASH_MODE_CAPABILITY, 1, 0, "flash_mode_capability" }, + { CCS_R_SA_STROBE_MODE_CAPABILITY, 1, 0, "sa_strobe_mode_capability" }, + { CCS_R_RESET_MAX_DELAY, 1, 0, "reset_max_delay" }, + { CCS_R_RESET_MIN_TIME, 1, 0, "reset_min_time" }, + { CCS_R_PDAF_CAPABILITY_1, 1, 0, "pdaf_capability_1" }, + { CCS_R_PDAF_CAPABILITY_2, 1, 0, "pdaf_capability_2" }, + { CCS_R_BRACKETING_LUT_CAPABILITY_1, 1, 0, "bracketing_lut_capability_1" }, + { CCS_R_BRACKETING_LUT_CAPABILITY_2, 1, 0, "bracketing_lut_capability_2" }, + { CCS_R_BRACKETING_LUT_SIZE, 1, 0, "bracketing_lut_size" }, + { 0 } /* Guardian */ +}; diff --git a/drivers/media/i2c/smiapp/ccs-limits.h b/drivers/media/i2c/smiapp/ccs-limits.h new file mode 100644 index 000000000000..1efa43c23a2e --- /dev/null +++ b/drivers/media/i2c/smiapp/ccs-limits.h @@ -0,0 +1,259 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */ +/* Copyright (C) 2019--2020 Intel Corporation */ + +#ifndef __CCS_LIMITS_H__ +#define __CCS_LIMITS_H__ + +#include +#include + +struct ccs_limit { + u32 reg; + u16 size; + u16 flags; + const char *name; +}; + +#define CCS_L_FL_SAME_REG BIT(0) + +extern const struct ccs_limit ccs_limits[]; + +#define CCS_L_FRAME_FORMAT_MODEL_TYPE 0 +#define CCS_L_FRAME_FORMAT_MODEL_SUBTYPE 1 +#define CCS_L_FRAME_FORMAT_DESCRIPTOR 2 +#define CCS_L_FRAME_FORMAT_DESCRIPTOR_OFFSET(n) ((n) * 2) +#define CCS_L_FRAME_FORMAT_DESCRIPTOR_4 3 +#define CCS_L_FRAME_FORMAT_DESCRIPTOR_4_OFFSET(n) ((n) * 4) +#define CCS_L_ANALOG_GAIN_CAPABILITY 4 +#define CCS_L_ANALOG_GAIN_CODE_MIN 5 +#define CCS_L_ANALOG_GAIN_CODE_MAX 6 +#define CCS_L_ANALOG_GAIN_CODE_STEP 7 +#define CCS_L_ANALOG_GAIN_TYPE 8 +#define CCS_L_ANALOG_GAIN_M0 9 +#define CCS_L_ANALOG_GAIN_C0 10 +#define CCS_L_ANALOG_GAIN_M1 11 +#define CCS_L_ANALOG_GAIN_C1 12 +#define CCS_L_ANALOG_LINEAR_GAIN_MIN 13 +#define CCS_L_ANALOG_LINEAR_GAIN_MAX 14 +#define CCS_L_ANALOG_LINEAR_GAIN_STEP_SIZE 15 +#define CCS_L_ANALOG_EXPONENTIAL_GAIN_MIN 16 +#define CCS_L_ANALOG_EXPONENTIAL_GAIN_MAX 17 +#define CCS_L_ANALOG_EXPONENTIAL_GAIN_STEP_SIZE 18 +#define CCS_L_DATA_FORMAT_MODEL_TYPE 19 +#define CCS_L_DATA_FORMAT_MODEL_SUBTYPE 20 +#define CCS_L_DATA_FORMAT_DESCRIPTOR 21 +#define CCS_L_DATA_FORMAT_DESCRIPTOR_OFFSET(n) ((n) * 2) +#define CCS_L_INTEGRATION_TIME_CAPABILITY 22 +#define CCS_L_COARSE_INTEGRATION_TIME_MIN 23 +#define CCS_L_COARSE_INTEGRATION_TIME_MAX_MARGIN 24 +#define CCS_L_FINE_INTEGRATION_TIME_MIN 25 +#define CCS_L_FINE_INTEGRATION_TIME_MAX_MARGIN 26 +#define CCS_L_DIGITAL_GAIN_CAPABILITY 27 +#define CCS_L_DIGITAL_GAIN_MIN 28 +#define CCS_L_DIGITAL_GAIN_MAX 29 +#define CCS_L_DIGITAL_GAIN_STEP_SIZE 30 +#define CCS_L_PEDESTAL_CAPABILITY 31 +#define CCS_L_ADC_CAPABILITY 32 +#define CCS_L_ADC_BIT_DEPTH_CAPABILITY 33 +#define CCS_L_MIN_EXT_CLK_FREQ_MHZ 34 +#define CCS_L_MAX_EXT_CLK_FREQ_MHZ 35 +#define CCS_L_MIN_PRE_PLL_CLK_DIV 36 +#define CCS_L_MAX_PRE_PLL_CLK_DIV 37 +#define CCS_L_MIN_PLL_IP_CLK_FREQ_MHZ 38 +#define CCS_L_MAX_PLL_IP_CLK_FREQ_MHZ 39 +#define CCS_L_MIN_PLL_MULTIPLIER 40 +#define CCS_L_MAX_PLL_MULTIPLIER 41 +#define CCS_L_MIN_PLL_OP_CLK_FREQ_MHZ 42 +#define CCS_L_MAX_PLL_OP_CLK_FREQ_MHZ 43 +#define CCS_L_MIN_VT_SYS_CLK_DIV 44 +#define CCS_L_MAX_VT_SYS_CLK_DIV 45 +#define CCS_L_MIN_VT_SYS_CLK_FREQ_MHZ 46 +#define CCS_L_MAX_VT_SYS_CLK_FREQ_MHZ 47 +#define CCS_L_MIN_VT_PIX_CLK_FREQ_MHZ 48 +#define CCS_L_MAX_VT_PIX_CLK_FREQ_MHZ 49 +#define CCS_L_MIN_VT_PIX_CLK_DIV 50 +#define CCS_L_MAX_VT_PIX_CLK_DIV 51 +#define CCS_L_CLOCK_CALCULATION 52 +#define CCS_L_NUM_OF_VT_LANES 53 +#define CCS_L_NUM_OF_OP_LANES 54 +#define CCS_L_OP_BITS_PER_LANE 55 +#define CCS_L_MIN_FRAME_LENGTH_LINES 56 +#define CCS_L_MAX_FRAME_LENGTH_LINES 57 +#define CCS_L_MIN_LINE_LENGTH_PCK 58 +#define CCS_L_MAX_LINE_LENGTH_PCK 59 +#define CCS_L_MIN_LINE_BLANKING_PCK 60 +#define CCS_L_MIN_FRAME_BLANKING_LINES 61 +#define CCS_L_MIN_LINE_LENGTH_PCK_STEP_SIZE 62 +#define CCS_L_TIMING_MODE_CAPABILITY 63 +#define CCS_L_FRAME_MARGIN_MAX_VALUE 64 +#define CCS_L_FRAME_MARGIN_MIN_VALUE 65 +#define CCS_L_GAIN_DELAY_TYPE 66 +#define CCS_L_MIN_OP_SYS_CLK_DIV 67 +#define CCS_L_MAX_OP_SYS_CLK_DIV 68 +#define CCS_L_MIN_OP_SYS_CLK_FREQ_MHZ 69 +#define CCS_L_MAX_OP_SYS_CLK_FREQ_MHZ 70 +#define CCS_L_MIN_OP_PIX_CLK_DIV 71 +#define CCS_L_MAX_OP_PIX_CLK_DIV 72 +#define CCS_L_MIN_OP_PIX_CLK_FREQ_MHZ 73 +#define CCS_L_MAX_OP_PIX_CLK_FREQ_MHZ 74 +#define CCS_L_X_ADDR_MIN 75 +#define CCS_L_Y_ADDR_MIN 76 +#define CCS_L_X_ADDR_MAX 77 +#define CCS_L_Y_ADDR_MAX 78 +#define CCS_L_MIN_X_OUTPUT_SIZE 79 +#define CCS_L_MIN_Y_OUTPUT_SIZE 80 +#define CCS_L_MAX_X_OUTPUT_SIZE 81 +#define CCS_L_MAX_Y_OUTPUT_SIZE 82 +#define CCS_L_X_ADDR_START_DIV_CONSTANT 83 +#define CCS_L_Y_ADDR_START_DIV_CONSTANT 84 +#define CCS_L_X_ADDR_END_DIV_CONSTANT 85 +#define CCS_L_Y_ADDR_END_DIV_CONSTANT 86 +#define CCS_L_X_SIZE_DIV 87 +#define CCS_L_Y_SIZE_DIV 88 +#define CCS_L_X_OUTPUT_DIV 89 +#define CCS_L_Y_OUTPUT_DIV 90 +#define CCS_L_NON_FLEXIBLE_RESOLUTION_SUPPORT 91 +#define CCS_L_MIN_OP_PRE_PLL_CLK_DIV 92 +#define CCS_L_MAX_OP_PRE_PLL_CLK_DIV 93 +#define CCS_L_MIN_OP_PLL_IP_CLK_FREQ_MHZ 94 +#define CCS_L_MAX_OP_PLL_IP_CLK_FREQ_MHZ 95 +#define CCS_L_MIN_OP_PLL_MULTIPLIER 96 +#define CCS_L_MAX_OP_PLL_MULTIPLIER 97 +#define CCS_L_MIN_OP_PLL_OP_CLK_FREQ_MHZ 98 +#define CCS_L_MAX_OP_PLL_OP_CLK_FREQ_MHZ 99 +#define CCS_L_CLOCK_TREE_PLL_CAPABILITY 100 +#define CCS_L_CLOCK_CAPA_TYPE_CAPABILITY 101 +#define CCS_L_MIN_EVEN_INC 102 +#define CCS_L_MIN_ODD_INC 103 +#define CCS_L_MAX_EVEN_INC 104 +#define CCS_L_MAX_ODD_INC 105 +#define CCS_L_AUX_SUBSAMP_CAPABILITY 106 +#define CCS_L_AUX_SUBSAMP_MONO_CAPABILITY 107 +#define CCS_L_MONOCHROME_CAPABILITY 108 +#define CCS_L_PIXEL_READOUT_CAPABILITY 109 +#define CCS_L_MIN_EVEN_INC_MONO 110 +#define CCS_L_MAX_EVEN_INC_MONO 111 +#define CCS_L_MIN_ODD_INC_MONO 112 +#define CCS_L_MAX_ODD_INC_MONO 113 +#define CCS_L_MIN_EVEN_INC_BC2 114 +#define CCS_L_MAX_EVEN_INC_BC2 115 +#define CCS_L_MIN_ODD_INC_BC2 116 +#define CCS_L_MAX_ODD_INC_BC2 117 +#define CCS_L_MIN_EVEN_INC_MONO_BC2 118 +#define CCS_L_MAX_EVEN_INC_MONO_BC2 119 +#define CCS_L_MIN_ODD_INC_MONO_BC2 120 +#define CCS_L_MAX_ODD_INC_MONO_BC2 121 +#define CCS_L_SCALING_CAPABILITY 122 +#define CCS_L_SCALER_M_MIN 123 +#define CCS_L_SCALER_M_MAX 124 +#define CCS_L_SCALER_N_MIN 125 +#define CCS_L_SCALER_N_MAX 126 +#define CCS_L_DIGITAL_CROP_CAPABILITY 127 +#define CCS_L_HDR_CAPABILITY_1 128 +#define CCS_L_MIN_HDR_BIT_DEPTH 129 +#define CCS_L_HDR_RESOLUTION_SUB_TYPES 130 +#define CCS_L_HDR_RESOLUTION_SUB_TYPE 131 +#define CCS_L_HDR_RESOLUTION_SUB_TYPE_OFFSET(n) (n) +#define CCS_L_HDR_CAPABILITY_2 132 +#define CCS_L_MAX_HDR_BIT_DEPTH 133 +#define CCS_L_USL_SUPPORT_CAPABILITY 134 +#define CCS_L_USL_CLOCK_MODE_D_CAPABILITY 135 +#define CCS_L_MIN_OP_SYS_CLK_DIV_REV 136 +#define CCS_L_MAX_OP_SYS_CLK_DIV_REV 137 +#define CCS_L_MIN_OP_PIX_CLK_DIV_REV 138 +#define CCS_L_MAX_OP_PIX_CLK_DIV_REV 139 +#define CCS_L_MIN_OP_SYS_CLK_FREQ_REV_MHZ 140 +#define CCS_L_MAX_OP_SYS_CLK_FREQ_REV_MHZ 141 +#define CCS_L_MIN_OP_PIX_CLK_FREQ_REV_MHZ 142 +#define CCS_L_MAX_OP_PIX_CLK_FREQ_REV_MHZ 143 +#define CCS_L_MAX_BITRATE_REV_D_MODE_MBPS 144 +#define CCS_L_MAX_SYMRATE_REV_C_MODE_MSPS 145 +#define CCS_L_COMPRESSION_CAPABILITY 146 +#define CCS_L_TEST_MODE_CAPABILITY 147 +#define CCS_L_PN9_DATA_FORMAT1 148 +#define CCS_L_PN9_DATA_FORMAT2 149 +#define CCS_L_PN9_DATA_FORMAT3 150 +#define CCS_L_PN9_DATA_FORMAT4 151 +#define CCS_L_PN9_MISC_CAPABILITY 152 +#define CCS_L_TEST_PATTERN_CAPABILITY 153 +#define CCS_L_PATTERN_SIZE_DIV_M1 154 +#define CCS_L_FIFO_SUPPORT_CAPABILITY 155 +#define CCS_L_PHY_CTRL_CAPABILITY 156 +#define CCS_L_CSI_DPHY_LANE_MODE_CAPABILITY 157 +#define CCS_L_CSI_SIGNALING_MODE_CAPABILITY 158 +#define CCS_L_FAST_STANDBY_CAPABILITY 159 +#define CCS_L_CSI_ADDRESS_CONTROL_CAPABILITY 160 +#define CCS_L_DATA_TYPE_CAPABILITY 161 +#define CCS_L_CSI_CPHY_LANE_MODE_CAPABILITY 162 +#define CCS_L_EMB_DATA_CAPABILITY 163 +#define CCS_L_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS 164 +#define CCS_L_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS_OFFSET(n) ((n) * 4) +#define CCS_L_TEMP_SENSOR_CAPABILITY 165 +#define CCS_L_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS 166 +#define CCS_L_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS_OFFSET(n) ((n) * 4) +#define CCS_L_DPHY_EQUALIZATION_CAPABILITY 167 +#define CCS_L_CPHY_EQUALIZATION_CAPABILITY 168 +#define CCS_L_DPHY_PREAMBLE_CAPABILITY 169 +#define CCS_L_DPHY_SSC_CAPABILITY 170 +#define CCS_L_CPHY_CALIBRATION_CAPABILITY 171 +#define CCS_L_DPHY_CALIBRATION_CAPABILITY 172 +#define CCS_L_PHY_CTRL_CAPABILITY_2 173 +#define CCS_L_LRTE_CPHY_CAPABILITY 174 +#define CCS_L_LRTE_DPHY_CAPABILITY 175 +#define CCS_L_ALPS_CAPABILITY_DPHY 176 +#define CCS_L_ALPS_CAPABILITY_CPHY 177 +#define CCS_L_SCRAMBLING_CAPABILITY 178 +#define CCS_L_DPHY_MANUAL_CONSTANT 179 +#define CCS_L_CPHY_MANUAL_CONSTANT 180 +#define CCS_L_CSI2_INTERFACE_CAPABILITY_MISC 181 +#define CCS_L_PHY_CTRL_CAPABILITY_3 182 +#define CCS_L_DPHY_SF 183 +#define CCS_L_CPHY_SF 184 +#define CCS_L_DPHY_LIMITS_1 185 +#define CCS_L_DPHY_LIMITS_2 186 +#define CCS_L_DPHY_LIMITS_3 187 +#define CCS_L_DPHY_LIMITS_4 188 +#define CCS_L_DPHY_LIMITS_5 189 +#define CCS_L_DPHY_LIMITS_6 190 +#define CCS_L_CPHY_LIMITS_1 191 +#define CCS_L_CPHY_LIMITS_2 192 +#define CCS_L_CPHY_LIMITS_3 193 +#define CCS_L_MIN_FRAME_LENGTH_LINES_BIN 194 +#define CCS_L_MAX_FRAME_LENGTH_LINES_BIN 195 +#define CCS_L_MIN_LINE_LENGTH_PCK_BIN 196 +#define CCS_L_MAX_LINE_LENGTH_PCK_BIN 197 +#define CCS_L_MIN_LINE_BLANKING_PCK_BIN 198 +#define CCS_L_FINE_INTEGRATION_TIME_MIN_BIN 199 +#define CCS_L_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN 200 +#define CCS_L_BINNING_CAPABILITY 201 +#define CCS_L_BINNING_WEIGHTING_CAPABILITY 202 +#define CCS_L_BINNING_SUB_TYPES 203 +#define CCS_L_BINNING_SUB_TYPE 204 +#define CCS_L_BINNING_SUB_TYPE_OFFSET(n) (n) +#define CCS_L_BINNING_WEIGHTING_MONO_CAPABILITY 205 +#define CCS_L_BINNING_SUB_TYPES_MONO 206 +#define CCS_L_BINNING_SUB_TYPE_MONO 207 +#define CCS_L_BINNING_SUB_TYPE_MONO_OFFSET(n) (n) +#define CCS_L_DATA_TRANSFER_IF_CAPABILITY 208 +#define CCS_L_SHADING_CORRECTION_CAPABILITY 209 +#define CCS_L_GREEN_IMBALANCE_CAPABILITY 210 +#define CCS_L_MODULE_SPECIFIC_CORRECTION_CAPABILITY 211 +#define CCS_L_DEFECT_CORRECTION_CAPABILITY 212 +#define CCS_L_DEFECT_CORRECTION_CAPABILITY_2 213 +#define CCS_L_NF_CAPABILITY 214 +#define CCS_L_OB_READOUT_CAPABILITY 215 +#define CCS_L_COLOR_FEEDBACK_CAPABILITY 216 +#define CCS_L_CFA_PATTERN_CAPABILITY 217 +#define CCS_L_CFA_PATTERN_CONVERSION_CAPABILITY 218 +#define CCS_L_FLASH_MODE_CAPABILITY 219 +#define CCS_L_SA_STROBE_MODE_CAPABILITY 220 +#define CCS_L_RESET_MAX_DELAY 221 +#define CCS_L_RESET_MIN_TIME 222 +#define CCS_L_PDAF_CAPABILITY_1 223 +#define CCS_L_PDAF_CAPABILITY_2 224 +#define CCS_L_BRACKETING_LUT_CAPABILITY_1 225 +#define CCS_L_BRACKETING_LUT_CAPABILITY_2 226 +#define CCS_L_BRACKETING_LUT_SIZE 227 +#define CCS_L_LAST 228 + +#endif /* __CCS_LIMITS_H__ */ diff --git a/drivers/media/i2c/smiapp/ccs-regs.h b/drivers/media/i2c/smiapp/ccs-regs.h new file mode 100644 index 000000000000..4b3e5df2121f --- /dev/null +++ b/drivers/media/i2c/smiapp/ccs-regs.h @@ -0,0 +1,954 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */ +/* Copyright (C) 2019--2020 Intel Corporation */ + +#ifndef __CCS_REGS_H__ +#define __CCS_REGS_H__ + +#include + +#define CCS_FL_BASE 16 +#define CCS_FL_16BIT BIT(CCS_FL_BASE) +#define CCS_FL_32BIT BIT(CCS_FL_BASE + 1) +#define CCS_FL_FLOAT_IREAL BIT(CCS_FL_BASE + 2) +#define CCS_FL_IREAL BIT(CCS_FL_BASE + 3) +#define CCS_R_ADDR(r) ((r) & 0xffff) + +#define CCS_R_MODULE_MODEL_ID (0x0000 | CCS_FL_16BIT) +#define CCS_R_MODULE_REVISION_NUMBER_MAJOR 0x0002 +#define CCS_R_FRAME_COUNT 0x0005 +#define CCS_R_PIXEL_ORDER 0x0006 +#define CCS_PIXEL_ORDER_GRBG 0U +#define CCS_PIXEL_ORDER_RGGB 1U +#define CCS_PIXEL_ORDER_BGGR 2U +#define CCS_PIXEL_ORDER_GBRG 3U +#define CCS_R_MIPI_CCS_VERSION 0x0007 +#define CCS_MIPI_CCS_VERSION_V1_0 0x10 +#define CCS_MIPI_CCS_VERSION_V1_1 0x11 +#define CCS_MIPI_CCS_VERSION_MAJOR_SHIFT 4U +#define CCS_MIPI_CCS_VERSION_MAJOR_MASK 0xf0 +#define CCS_MIPI_CCS_VERSION_MINOR_SHIFT 0U +#define CCS_MIPI_CCS_VERSION_MINOR_MASK 0xf +#define CCS_R_DATA_PEDESTAL (0x0008 | CCS_FL_16BIT) +#define CCS_R_MODULE_MANUFACTURER_ID (0x000e | CCS_FL_16BIT) +#define CCS_R_MODULE_REVISION_NUMBER_MINOR 0x0010 +#define CCS_R_MODULE_DATE_YEAR 0x0012 +#define CCS_R_MODULE_DATE_MONTH 0x0013 +#define CCS_R_MODULE_DATE_DAY 0x0014 +#define CCS_R_MODULE_DATE_PHASE 0x0015 +#define CCS_MODULE_DATE_PHASE_SHIFT 0U +#define CCS_MODULE_DATE_PHASE_MASK 0x7 +#define CCS_MODULE_DATE_PHASE_TS 0U +#define CCS_MODULE_DATE_PHASE_ES 1U +#define CCS_MODULE_DATE_PHASE_CS 2U +#define CCS_MODULE_DATE_PHASE_MP 3U +#define CCS_R_SENSOR_MODEL_ID (0x0016 | CCS_FL_16BIT) +#define CCS_R_SENSOR_REVISION_NUMBER 0x0018 +#define CCS_R_SENSOR_FIRMWARE_VERSION 0x001a +#define CCS_R_SERIAL_NUMBER (0x001c | CCS_FL_32BIT) +#define CCS_R_SENSOR_MANUFACTURER_ID (0x0020 | CCS_FL_16BIT) +#define CCS_R_SENSOR_REVISION_NUMBER_16 (0x0022 | CCS_FL_16BIT) +#define CCS_R_FRAME_FORMAT_MODEL_TYPE 0x0040 +#define CCS_FRAME_FORMAT_MODEL_TYPE_2_BYTE 1U +#define CCS_FRAME_FORMAT_MODEL_TYPE_4_BYTE 2U +#define CCS_R_FRAME_FORMAT_MODEL_SUBTYPE 0x0041 +#define CCS_FRAME_FORMAT_MODEL_SUBTYPE_ROWS_SHIFT 0U +#define CCS_FRAME_FORMAT_MODEL_SUBTYPE_ROWS_MASK 0xf +#define CCS_FRAME_FORMAT_MODEL_SUBTYPE_COLUMNS_SHIFT 4U +#define CCS_FRAME_FORMAT_MODEL_SUBTYPE_COLUMNS_MASK 0xf0 +#define CCS_R_FRAME_FORMAT_DESCRIPTOR(n) ((0x0042 | CCS_FL_16BIT) + (n) * 2) +#define CCS_LIM_FRAME_FORMAT_DESCRIPTOR_MIN_N 0U +#define CCS_LIM_FRAME_FORMAT_DESCRIPTOR_MAX_N 14U +#define CCS_R_FRAME_FORMAT_DESCRIPTOR_4(n) ((0x0060 | CCS_FL_32BIT) + (n) * 4) +#define CCS_FRAME_FORMAT_DESCRIPTOR_PIXELS_SHIFT 0U +#define CCS_FRAME_FORMAT_DESCRIPTOR_PIXELS_MASK 0xfff +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_SHIFT 12U +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MASK 0xf000 +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_EMBEDDED 1U +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_DUMMY_PIXEL 2U +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_BLACK_PIXEL 3U +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_DARK_PIXEL 4U +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_VISIBLE_PIXEL 5U +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MANUF_SPECIFIC_0 8U +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MANUF_SPECIFIC_1 9U +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MANUF_SPECIFIC_2 10U +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MANUF_SPECIFIC_3 11U +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MANUF_SPECIFIC_4 12U +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MANUF_SPECIFIC_5 13U +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MANUF_SPECIFIC_6 14U +#define CCS_LIM_FRAME_FORMAT_DESCRIPTOR_4_MIN_N 0U +#define CCS_LIM_FRAME_FORMAT_DESCRIPTOR_4_MAX_N 7U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PIXELS_SHIFT 0U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PIXELS_MASK 0xffff +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_SHIFT 28U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MASK 0xf0000000 +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_EMBEDDED 1U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_DUMMY_PIXEL 2U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_BLACK_PIXEL 3U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_DARK_PIXEL 4U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_VISIBLE_PIXEL 5U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_0 8U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_1 9U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_2 10U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_3 11U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_4 12U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_5 13U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_6 14U +#define CCS_R_ANALOG_GAIN_CAPABILITY (0x0080 | CCS_FL_16BIT) +#define CCS_ANALOG_GAIN_CAPABILITY_GLOBAL 0U +#define CCS_ANALOG_GAIN_CAPABILITY_ALTERNATE_GLOBAL 2U +#define CCS_R_ANALOG_GAIN_CODE_MIN (0x0084 | CCS_FL_16BIT) +#define CCS_R_ANALOG_GAIN_CODE_MAX (0x0086 | CCS_FL_16BIT) +#define CCS_R_ANALOG_GAIN_CODE_STEP (0x0088 | CCS_FL_16BIT) +#define CCS_R_ANALOG_GAIN_TYPE (0x008a | CCS_FL_16BIT) +#define CCS_R_ANALOG_GAIN_M0 (0x008c | CCS_FL_16BIT) +#define CCS_R_ANALOG_GAIN_C0 (0x008e | CCS_FL_16BIT) +#define CCS_R_ANALOG_GAIN_M1 (0x0090 | CCS_FL_16BIT) +#define CCS_R_ANALOG_GAIN_C1 (0x0092 | CCS_FL_16BIT) +#define CCS_R_ANALOG_LINEAR_GAIN_MIN (0x0094 | CCS_FL_16BIT) +#define CCS_R_ANALOG_LINEAR_GAIN_MAX (0x0096 | CCS_FL_16BIT) +#define CCS_R_ANALOG_LINEAR_GAIN_STEP_SIZE (0x0098 | CCS_FL_16BIT) +#define CCS_R_ANALOG_EXPONENTIAL_GAIN_MIN (0x009a | CCS_FL_16BIT) +#define CCS_R_ANALOG_EXPONENTIAL_GAIN_MAX (0x009c | CCS_FL_16BIT) +#define CCS_R_ANALOG_EXPONENTIAL_GAIN_STEP_SIZE (0x009e | CCS_FL_16BIT) +#define CCS_R_DATA_FORMAT_MODEL_TYPE 0x00c0 +#define CCS_DATA_FORMAT_MODEL_TYPE_NORMAL 1U +#define CCS_DATA_FORMAT_MODEL_TYPE_EXTENDED 2U +#define CCS_R_DATA_FORMAT_MODEL_SUBTYPE 0x00c1 +#define CCS_DATA_FORMAT_MODEL_SUBTYPE_ROWS_SHIFT 0U +#define CCS_DATA_FORMAT_MODEL_SUBTYPE_ROWS_MASK 0xf +#define CCS_DATA_FORMAT_MODEL_SUBTYPE_COLUMNS_SHIFT 4U +#define CCS_DATA_FORMAT_MODEL_SUBTYPE_COLUMNS_MASK 0xf0 +#define CCS_R_DATA_FORMAT_DESCRIPTOR(n) ((0x00c2 | CCS_FL_16BIT) + (n) * 2) +#define CCS_LIM_DATA_FORMAT_DESCRIPTOR_MIN_N 0U +#define CCS_LIM_DATA_FORMAT_DESCRIPTOR_MAX_N 15U +#define CCS_DATA_FORMAT_DESCRIPTOR_COMPRESSED_SHIFT 0U +#define CCS_DATA_FORMAT_DESCRIPTOR_COMPRESSED_MASK 0xff +#define CCS_DATA_FORMAT_DESCRIPTOR_UNCOMPRESSED_SHIFT 8U +#define CCS_DATA_FORMAT_DESCRIPTOR_UNCOMPRESSED_MASK 0xff00 +#define CCS_R_MODE_SELECT 0x0100 +#define CCS_MODE_SELECT_SOFTWARE_STANDBY 0U +#define CCS_MODE_SELECT_STREAMING 1U +#define CCS_R_IMAGE_ORIENTATION 0x0101 +#define CCS_IMAGE_ORIENTATION_HORIZONTAL_MIRROR BIT(0) +#define CCS_IMAGE_ORIENTATION_VERTICAL_FLIP BIT(1) +#define CCS_R_SOFTWARE_RESET 0x0103 +#define CCS_SOFTWARE_RESET_OFF 0U +#define CCS_SOFTWARE_RESET_ON 1U +#define CCS_R_GROUPED_PARAMETER_HOLD 0x0104 +#define CCS_R_MASK_CORRUPTED_FRAMES 0x0105 +#define CCS_MASK_CORRUPTED_FRAMES_ALLOW 0U +#define CCS_MASK_CORRUPTED_FRAMES_MASK 1U +#define CCS_R_FAST_STANDBY_CTRL 0x0106 +#define CCS_FAST_STANDBY_CTRL_COMPLETE_FRAMES 0U +#define CCS_FAST_STANDBY_CTRL_FRAME_TRUNCATION 1U +#define CCS_R_CCI_ADDRESS_CTRL 0x0107 +#define CCS_R_2ND_CCI_IF_CTRL 0x0108 +#define CCS_2ND_CCI_IF_CTRL_ENABLE BIT(0) +#define CCS_2ND_CCI_IF_CTRL_ACK BIT(1) +#define CCS_R_2ND_CCI_ADDRESS_CTRL 0x0109 +#define CCS_R_CSI_CHANNEL_IDENTIFIER 0x0110 +#define CCS_R_CSI_SIGNALING_MODE 0x0111 +#define CCS_CSI_SIGNALING_MODE_CSI_2_DPHY 2U +#define CCS_CSI_SIGNALING_MODE_CSI_2_CPHY 3U +#define CCS_R_CSI_DATA_FORMAT (0x0112 | CCS_FL_16BIT) +#define CCS_R_CSI_LANE_MODE 0x0114 +#define CCS_R_DPCM_FRAME_DT 0x011d +#define CCS_R_BOTTOM_EMBEDDED_DATA_DT 0x011e +#define CCS_R_BOTTOM_EMBEDDED_DATA_VC 0x011f +#define CCS_R_GAIN_MODE 0x0120 +#define CCS_GAIN_MODE_GLOBAL 0U +#define CCS_GAIN_MODE_ALTERNATE 1U +#define CCS_R_ADC_BIT_DEPTH 0x0121 +#define CCS_R_EMB_DATA_CTRL 0x0122 +#define CCS_EMB_DATA_CTRL_RAW8_PACKING_FOR_RAW16 BIT(0) +#define CCS_EMB_DATA_CTRL_RAW10_PACKING_FOR_RAW20 BIT(1) +#define CCS_EMB_DATA_CTRL_RAW12_PACKING_FOR_RAW24 BIT(2) +#define CCS_R_GPIO_TRIG_MODE 0x0130 +#define CCS_R_EXTCLK_FREQUENCY_MHZ (0x0136 | (CCS_FL_16BIT | CCS_FL_IREAL)) +#define CCS_R_TEMP_SENSOR_CTRL 0x0138 +#define CCS_TEMP_SENSOR_CTRL_ENABLE BIT(0) +#define CCS_R_TEMP_SENSOR_MODE 0x0139 +#define CCS_R_TEMP_SENSOR_OUTPUT 0x013a +#define CCS_R_FINE_INTEGRATION_TIME (0x0200 | CCS_FL_16BIT) +#define CCS_R_COARSE_INTEGRATION_TIME (0x0202 | CCS_FL_16BIT) +#define CCS_R_ANALOG_GAIN_CODE_GLOBAL (0x0204 | CCS_FL_16BIT) +#define CCS_R_ANALOG_LINEAR_GAIN_GLOBAL (0x0206 | CCS_FL_16BIT) +#define CCS_R_ANALOG_EXPONENTIAL_GAIN_GLOBAL (0x0208 | CCS_FL_16BIT) +#define CCS_R_DIGITAL_GAIN_GLOBAL (0x020e | CCS_FL_16BIT) +#define CCS_R_SHORT_ANALOG_GAIN_GLOBAL (0x0216 | CCS_FL_16BIT) +#define CCS_R_SHORT_DIGITAL_GAIN_GLOBAL (0x0218 | CCS_FL_16BIT) +#define CCS_R_HDR_MODE 0x0220 +#define CCS_HDR_MODE_ENABLED BIT(0) +#define CCS_HDR_MODE_SEPARATE_ANALOG_GAIN BIT(1) +#define CCS_HDR_MODE_UPSCALING BIT(2) +#define CCS_HDR_MODE_RESET_SYNC BIT(3) +#define CCS_HDR_MODE_TIMING_MODE BIT(4) +#define CCS_HDR_MODE_EXPOSURE_CTRL_DIRECT BIT(5) +#define CCS_HDR_MODE_SEPARATE_DIGITAL_GAIN BIT(6) +#define CCS_R_HDR_RESOLUTION_REDUCTION 0x0221 +#define CCS_HDR_RESOLUTION_REDUCTION_ROW_SHIFT 0U +#define CCS_HDR_RESOLUTION_REDUCTION_ROW_MASK 0xf +#define CCS_HDR_RESOLUTION_REDUCTION_COLUMN_SHIFT 4U +#define CCS_HDR_RESOLUTION_REDUCTION_COLUMN_MASK 0xf0 +#define CCS_R_EXPOSURE_RATIO 0x0222 +#define CCS_R_HDR_INTERNAL_BIT_DEPTH 0x0223 +#define CCS_R_DIRECT_SHORT_INTEGRATION_TIME (0x0224 | CCS_FL_16BIT) +#define CCS_R_SHORT_ANALOG_LINEAR_GAIN_GLOBAL (0x0226 | CCS_FL_16BIT) +#define CCS_R_SHORT_ANALOG_EXPONENTIAL_GAIN_GLOBAL (0x0228 | CCS_FL_16BIT) +#define CCS_R_VT_PIX_CLK_DIV (0x0300 | CCS_FL_16BIT) +#define CCS_R_VT_SYS_CLK_DIV (0x0302 | CCS_FL_16BIT) +#define CCS_R_PRE_PLL_CLK_DIV (0x0304 | CCS_FL_16BIT) +#define CCS_R_PLL_MULTIPLIER (0x0306 | CCS_FL_16BIT) +#define CCS_R_OP_PIX_CLK_DIV (0x0308 | CCS_FL_16BIT) +#define CCS_R_OP_SYS_CLK_DIV (0x030a | CCS_FL_16BIT) +#define CCS_R_OP_PRE_PLL_CLK_DIV (0x030c | CCS_FL_16BIT) +#define CCS_R_OP_PLL_MULTIPLIER (0x031e | CCS_FL_16BIT) +#define CCS_R_PLL_MODE 0x0310 +#define CCS_PLL_MODE_SHIFT 0U +#define CCS_PLL_MODE_MASK 0x1 +#define CCS_PLL_MODE_SINGLE 0U +#define CCS_PLL_MODE_DUAL 1U +#define CCS_R_OP_PIX_CLK_DIV_REV (0x0312 | CCS_FL_16BIT) +#define CCS_R_OP_SYS_CLK_DIV_REV (0x0314 | CCS_FL_16BIT) +#define CCS_R_FRAME_LENGTH_LINES (0x0340 | CCS_FL_16BIT) +#define CCS_R_LINE_LENGTH_PCK (0x0342 | CCS_FL_16BIT) +#define CCS_R_X_ADDR_START (0x0344 | CCS_FL_16BIT) +#define CCS_R_Y_ADDR_START (0x0346 | CCS_FL_16BIT) +#define CCS_R_X_ADDR_END (0x0348 | CCS_FL_16BIT) +#define CCS_R_Y_ADDR_END (0x034a | CCS_FL_16BIT) +#define CCS_R_X_OUTPUT_SIZE (0x034c | CCS_FL_16BIT) +#define CCS_R_Y_OUTPUT_SIZE (0x034e | CCS_FL_16BIT) +#define CCS_R_FRAME_LENGTH_CTRL 0x0350 +#define CCS_FRAME_LENGTH_CTRL_AUTOMATIC BIT(0) +#define CCS_R_TIMING_MODE_CTRL 0x0352 +#define CCS_TIMING_MODE_CTRL_MANUAL_READOUT BIT(0) +#define CCS_TIMING_MODE_CTRL_DELAYED_EXPOSURE BIT(1) +#define CCS_R_START_READOUT_RS 0x0353 +#define CCS_START_READOUT_RS_MANUAL_READOUT_START BIT(0) +#define CCS_R_FRAME_MARGIN (0x0354 | CCS_FL_16BIT) +#define CCS_R_X_EVEN_INC (0x0380 | CCS_FL_16BIT) +#define CCS_R_X_ODD_INC (0x0382 | CCS_FL_16BIT) +#define CCS_R_Y_EVEN_INC (0x0384 | CCS_FL_16BIT) +#define CCS_R_Y_ODD_INC (0x0386 | CCS_FL_16BIT) +#define CCS_R_MONOCHROME_EN 0x0390 +#define CCS_MONOCHROME_EN_ENABLED 0U +#define CCS_R_SCALING_MODE (0x0400 | CCS_FL_16BIT) +#define CCS_SCALING_MODE_NO_SCALING 0U +#define CCS_SCALING_MODE_HORIZONTAL 1U +#define CCS_R_SCALE_M (0x0404 | CCS_FL_16BIT) +#define CCS_R_SCALE_N (0x0406 | CCS_FL_16BIT) +#define CCS_R_DIGITAL_CROP_X_OFFSET (0x0408 | CCS_FL_16BIT) +#define CCS_R_DIGITAL_CROP_Y_OFFSET (0x040a | CCS_FL_16BIT) +#define CCS_R_DIGITAL_CROP_IMAGE_WIDTH (0x040c | CCS_FL_16BIT) +#define CCS_R_DIGITAL_CROP_IMAGE_HEIGHT (0x040e | CCS_FL_16BIT) +#define CCS_R_COMPRESSION_MODE (0x0500 | CCS_FL_16BIT) +#define CCS_COMPRESSION_MODE_NONE 0U +#define CCS_COMPRESSION_MODE_DPCM_PCM_SIMPLE 1U +#define CCS_R_TEST_PATTERN_MODE (0x0600 | CCS_FL_16BIT) +#define CCS_TEST_PATTERN_MODE_NONE 0U +#define CCS_TEST_PATTERN_MODE_SOLID_COLOR 1U +#define CCS_TEST_PATTERN_MODE_COLOR_BARS 2U +#define CCS_TEST_PATTERN_MODE_FADE_TO_GREY 3U +#define CCS_TEST_PATTERN_MODE_PN9 4U +#define CCS_TEST_PATTERN_MODE_COLOR_TILE 5U +#define CCS_R_TEST_DATA_RED (0x0602 | CCS_FL_16BIT) +#define CCS_R_TEST_DATA_GREENR (0x0604 | CCS_FL_16BIT) +#define CCS_R_TEST_DATA_BLUE (0x0606 | CCS_FL_16BIT) +#define CCS_R_TEST_DATA_GREENB (0x0608 | CCS_FL_16BIT) +#define CCS_R_VALUE_STEP_SIZE_SMOOTH 0x060a +#define CCS_R_VALUE_STEP_SIZE_QUANTISED 0x060b +#define CCS_R_TCLK_POST 0x0800 +#define CCS_R_THS_PREPARE 0x0801 +#define CCS_R_THS_ZERO_MIN 0x0802 +#define CCS_R_THS_TRAIL 0x0803 +#define CCS_R_TCLK_TRAIL_MIN 0x0804 +#define CCS_R_TCLK_PREPARE 0x0805 +#define CCS_R_TCLK_ZERO 0x0806 +#define CCS_R_TLPX 0x0807 +#define CCS_R_PHY_CTRL 0x0808 +#define CCS_PHY_CTRL_AUTO 0U +#define CCS_PHY_CTRL_UI 1U +#define CCS_PHY_CTRL_MANUAL 2U +#define CCS_R_TCLK_POST_EX (0x080a | CCS_FL_16BIT) +#define CCS_R_THS_PREPARE_EX (0x080c | CCS_FL_16BIT) +#define CCS_R_THS_ZERO_MIN_EX (0x080e | CCS_FL_16BIT) +#define CCS_R_THS_TRAIL_EX (0x0810 | CCS_FL_16BIT) +#define CCS_R_TCLK_TRAIL_MIN_EX (0x0812 | CCS_FL_16BIT) +#define CCS_R_TCLK_PREPARE_EX (0x0814 | CCS_FL_16BIT) +#define CCS_R_TCLK_ZERO_EX (0x0816 | CCS_FL_16BIT) +#define CCS_R_TLPX_EX (0x0818 | CCS_FL_16BIT) +#define CCS_R_REQUESTED_LINK_RATE (0x0820 | CCS_FL_32BIT) +#define CCS_R_DPHY_EQUALIZATION_MODE 0x0824 +#define CCS_DPHY_EQUALIZATION_MODE_EQ2 BIT(0) +#define CCS_R_PHY_EQUALIZATION_CTRL 0x0825 +#define CCS_PHY_EQUALIZATION_CTRL_ENABLE BIT(0) +#define CCS_R_DPHY_PREAMBLE_CTRL 0x0826 +#define CCS_DPHY_PREAMBLE_CTRL_ENABLE BIT(0) +#define CCS_R_DPHY_PREAMBLE_LENGTH 0x0826 +#define CCS_R_PHY_SSC_CTRL 0x0828 +#define CCS_PHY_SSC_CTRL_ENABLE BIT(0) +#define CCS_R_MANUAL_LP_CTRL 0x0829 +#define CCS_MANUAL_LP_CTRL_ENABLE BIT(0) +#define CCS_R_TWAKEUP 0x082a +#define CCS_R_TINIT 0x082b +#define CCS_R_THS_EXIT 0x082c +#define CCS_R_THS_EXIT_EX (0x082e | CCS_FL_16BIT) +#define CCS_R_PHY_PERIODIC_CALIBRATION_CTRL 0x0830 +#define CCS_PHY_PERIODIC_CALIBRATION_CTRL_FRAME_BLANKING BIT(0) +#define CCS_R_PHY_PERIODIC_CALIBRATION_INTERVAL 0x0831 +#define CCS_R_PHY_INIT_CALIBRATION_CTRL 0x0832 +#define CCS_PHY_INIT_CALIBRATION_CTRL_STREAM_START BIT(0) +#define CCS_R_DPHY_CALIBRATION_MODE 0x0833 +#define CCS_DPHY_CALIBRATION_MODE_ALSO_ALTERNATE BIT(0) +#define CCS_R_CPHY_CALIBRATION_MODE 0x0834 +#define CCS_CPHY_CALIBRATION_MODE_FORMAT_1 0U +#define CCS_CPHY_CALIBRATION_MODE_FORMAT_2 1U +#define CCS_CPHY_CALIBRATION_MODE_FORMAT_3 2U +#define CCS_R_T3_CALPREAMBLE_LENGTH 0x0835 +#define CCS_R_T3_CALPREAMBLE_LENGTH_PER 0x0836 +#define CCS_R_T3_CALALTSEQ_LENGTH 0x0837 +#define CCS_R_T3_CALALTSEQ_LENGTH_PER 0x0838 +#define CCS_R_FM2_INIT_SEED (0x083a | CCS_FL_16BIT) +#define CCS_R_T3_CALUDEFSEQ_LENGTH (0x083c | CCS_FL_16BIT) +#define CCS_R_T3_CALUDEFSEQ_LENGTH_PER (0x083e | CCS_FL_16BIT) +#define CCS_R_TGR_PREAMBLE_LENGTH 0x0841 +#define CCS_TGR_PREAMBLE_LENGTH_PREAMABLE_PROG_SEQ BIT(7) +#define CCS_TGR_PREAMBLE_LENGTH_BEGIN_PREAMBLE_LENGTH_SHIFT 0U +#define CCS_TGR_PREAMBLE_LENGTH_BEGIN_PREAMBLE_LENGTH_MASK 0x3f +#define CCS_R_TGR_POST_LENGTH 0x0842 +#define CCS_TGR_POST_LENGTH_POST_LENGTH_SHIFT 0U +#define CCS_TGR_POST_LENGTH_POST_LENGTH_MASK 0x1f +#define CCS_R_TGR_PREAMBLE_PROG_SEQUENCE(n2) (0x0843 + (n2)) +#define CCS_LIM_TGR_PREAMBLE_PROG_SEQUENCE_MIN_N2 0U +#define CCS_LIM_TGR_PREAMBLE_PROG_SEQUENCE_MAX_N2 6U +#define CCS_TGR_PREAMBLE_PROG_SEQUENCE_SYMBOL_N_1_SHIFT 3U +#define CCS_TGR_PREAMBLE_PROG_SEQUENCE_SYMBOL_N_1_MASK 0x38 +#define CCS_TGR_PREAMBLE_PROG_SEQUENCE_SYMBOL_N_SHIFT 0U +#define CCS_TGR_PREAMBLE_PROG_SEQUENCE_SYMBOL_N_MASK 0x7 +#define CCS_R_T3_PREPARE (0x084e | CCS_FL_16BIT) +#define CCS_R_T3_LPX (0x0850 | CCS_FL_16BIT) +#define CCS_R_ALPS_CTRL 0x085a +#define CCS_ALPS_CTRL_LVLP_DPHY BIT(0) +#define CCS_ALPS_CTRL_LVLP_CPHY BIT(1) +#define CCS_ALPS_CTRL_ALP_CPHY BIT(2) +#define CCS_R_TX_REG_CSI_EPD_EN_SSP_CPHY (0x0860 | CCS_FL_16BIT) +#define CCS_R_TX_REG_CSI_EPD_OP_SLP_CPHY (0x0862 | CCS_FL_16BIT) +#define CCS_R_TX_REG_CSI_EPD_EN_SSP_DPHY (0x0864 | CCS_FL_16BIT) +#define CCS_R_TX_REG_CSI_EPD_OP_SLP_DPHY (0x0866 | CCS_FL_16BIT) +#define CCS_R_TX_REG_CSI_EPD_MISC_OPTION_CPHY 0x0868 +#define CCS_R_TX_REG_CSI_EPD_MISC_OPTION_DPHY 0x0869 +#define CCS_R_SCRAMBLING_CTRL 0x0870 +#define CCS_SCRAMBLING_CTRL_ENABLED BIT(0) +#define CCS_SCRAMBLING_CTRL_SHIFT 2U +#define CCS_SCRAMBLING_CTRL_MASK 0xc +#define CCS_SCRAMBLING_CTRL_1_SEED_CPHY 0U +#define CCS_SCRAMBLING_CTRL_4_SEED_CPHY 3U +#define CCS_R_LANE_SEED_VALUE(seed, lane) ((0x0872 | CCS_FL_16BIT) + (seed) * 16 + (lane) * 2) +#define CCS_LIM_LANE_SEED_VALUE_MIN_SEED 0U +#define CCS_LIM_LANE_SEED_VALUE_MAX_SEED 3U +#define CCS_LIM_LANE_SEED_VALUE_MIN_LANE 0U +#define CCS_LIM_LANE_SEED_VALUE_MAX_LANE 7U +#define CCS_R_TX_USL_REV_ENTRY (0x08c0 | CCS_FL_16BIT) +#define CCS_R_TX_USL_REV_CLOCK_COUNTER (0x08c2 | CCS_FL_16BIT) +#define CCS_R_TX_USL_REV_LP_COUNTER (0x08c4 | CCS_FL_16BIT) +#define CCS_R_TX_USL_REV_FRAME_COUNTER (0x08c6 | CCS_FL_16BIT) +#define CCS_R_TX_USL_REV_CHRONOLOGICAL_TIMER (0x08c8 | CCS_FL_16BIT) +#define CCS_R_TX_USL_FWD_ENTRY (0x08ca | CCS_FL_16BIT) +#define CCS_R_TX_USL_GPIO (0x08cc | CCS_FL_16BIT) +#define CCS_R_TX_USL_OPERATION (0x08ce | CCS_FL_16BIT) +#define CCS_TX_USL_OPERATION_RESET BIT(0) +#define CCS_R_TX_USL_ALP_CTRL (0x08d0 | CCS_FL_16BIT) +#define CCS_TX_USL_ALP_CTRL_CLOCK_PAUSE BIT(0) +#define CCS_R_TX_USL_APP_BTA_ACK_TIMEOUT (0x08d2 | CCS_FL_16BIT) +#define CCS_R_TX_USL_SNS_BTA_ACK_TIMEOUT (0x08d2 | CCS_FL_16BIT) +#define CCS_R_USL_CLOCK_MODE_D_CTRL 0x08d2 +#define CCS_USL_CLOCK_MODE_D_CTRL_CONT_CLOCK_STANDBY BIT(0) +#define CCS_USL_CLOCK_MODE_D_CTRL_CONT_CLOCK_VBLANK BIT(1) +#define CCS_USL_CLOCK_MODE_D_CTRL_CONT_CLOCK_HBLANK BIT(2) +#define CCS_R_BINNING_MODE 0x0900 +#define CCS_R_BINNING_TYPE 0x0901 +#define CCS_R_BINNING_WEIGHTING 0x0902 +#define CCS_R_DATA_TRANSFER_IF_1_CTRL 0x0a00 +#define CCS_DATA_TRANSFER_IF_1_CTRL_ENABLE BIT(0) +#define CCS_DATA_TRANSFER_IF_1_CTRL_WRITE BIT(1) +#define CCS_DATA_TRANSFER_IF_1_CTRL_CLEAR_ERROR BIT(2) +#define CCS_R_DATA_TRANSFER_IF_1_STATUS 0x0a01 +#define CCS_DATA_TRANSFER_IF_1_STATUS_READ_IF_READY BIT(0) +#define CCS_DATA_TRANSFER_IF_1_STATUS_WRITE_IF_READY BIT(1) +#define CCS_DATA_TRANSFER_IF_1_STATUS_DATA_CORRUPTED BIT(2) +#define CCS_DATA_TRANSFER_IF_1_STATUS_IMPROPER_IF_USAGE BIT(3) +#define CCS_R_DATA_TRANSFER_IF_1_PAGE_SELECT 0x0a02 +#define CCS_R_DATA_TRANSFER_IF_1_DATA(p) (0x0a04 + (p)) +#define CCS_LIM_DATA_TRANSFER_IF_1_DATA_MIN_P 0U +#define CCS_LIM_DATA_TRANSFER_IF_1_DATA_MAX_P 63U +#define CCS_R_SHADING_CORRECTION_EN 0x0b00 +#define CCS_SHADING_CORRECTION_EN_ENABLE BIT(0) +#define CCS_R_LUMINANCE_CORRECTION_LEVEL 0x0b01 +#define CCS_R_GREEN_IMBALANCE_FILTER_EN 0x0b02 +#define CCS_GREEN_IMBALANCE_FILTER_EN_ENABLE BIT(0) +#define CCS_R_MAPPED_DEFECT_CORRECT_EN 0x0b05 +#define CCS_MAPPED_DEFECT_CORRECT_EN_ENABLE BIT(0) +#define CCS_R_SINGLE_DEFECT_CORRECT_EN 0x0b06 +#define CCS_SINGLE_DEFECT_CORRECT_EN_ENABLE BIT(0) +#define CCS_R_DYNAMIC_COUPLET_CORRECT_EN 0x0b08 +#define CCS_DYNAMIC_COUPLET_CORRECT_EN_ENABLE BIT(0) +#define CCS_R_COMBINED_DEFECT_CORRECT_EN 0x0b0a +#define CCS_COMBINED_DEFECT_CORRECT_EN_ENABLE BIT(0) +#define CCS_R_MODULE_SPECIFIC_CORRECTION_EN 0x0b0c +#define CCS_MODULE_SPECIFIC_CORRECTION_EN_ENABLE BIT(0) +#define CCS_R_DYNAMIC_TRIPLET_DEFECT_CORRECT_EN 0x0b13 +#define CCS_DYNAMIC_TRIPLET_DEFECT_CORRECT_EN_ENABLE BIT(0) +#define CCS_R_NF_CTRL 0x0b15 +#define CCS_NF_CTRL_LUMA BIT(0) +#define CCS_NF_CTRL_CHROMA BIT(1) +#define CCS_NF_CTRL_COMBINED BIT(2) +#define CCS_R_OB_READOUT_CONTROL 0x0b30 +#define CCS_OB_READOUT_CONTROL_ENABLE BIT(0) +#define CCS_OB_READOUT_CONTROL_INTERLEAVING BIT(1) +#define CCS_R_OB_VIRTUAL_CHANNEL 0x0b31 +#define CCS_R_OB_DT 0x0b32 +#define CCS_R_OB_DATA_FORMAT 0x0b33 +#define CCS_R_COLOR_TEMPERATURE (0x0b8c | CCS_FL_16BIT) +#define CCS_R_ABSOLUTE_GAIN_GREENR (0x0b8e | CCS_FL_16BIT) +#define CCS_R_ABSOLUTE_GAIN_RED (0x0b90 | CCS_FL_16BIT) +#define CCS_R_ABSOLUTE_GAIN_BLUE (0x0b92 | CCS_FL_16BIT) +#define CCS_R_ABSOLUTE_GAIN_GREENB (0x0b94 | CCS_FL_16BIT) +#define CCS_R_CFA_CONVERSION_CTRL 0x0ba0 +#define CCS_CFA_CONVERSION_CTRL_BAYER_CONVERSION_ENABLE BIT(0) +#define CCS_R_FLASH_STROBE_ADJUSTMENT 0x0c12 +#define CCS_R_FLASH_STROBE_START_POINT (0x0c14 | CCS_FL_16BIT) +#define CCS_R_TFLASH_STROBE_DELAY_RS_CTRL (0x0c16 | CCS_FL_16BIT) +#define CCS_R_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL (0x0c18 | CCS_FL_16BIT) +#define CCS_R_FLASH_MODE_RS 0x0c1a +#define CCS_FLASH_MODE_RS_CONTINUOUS BIT(0) +#define CCS_FLASH_MODE_RS_TRUNCATE BIT(1) +#define CCS_FLASH_MODE_RS_ASYNC BIT(3) +#define CCS_R_FLASH_TRIGGER_RS 0x0c1b +#define CCS_R_FLASH_STATUS 0x0c1c +#define CCS_FLASH_STATUS_RETIMED BIT(0) +#define CCS_R_SA_STROBE_MODE 0x0c1d +#define CCS_SA_STROBE_MODE_CONTINUOUS BIT(0) +#define CCS_SA_STROBE_MODE_TRUNCATE BIT(1) +#define CCS_SA_STROBE_MODE_ASYNC BIT(3) +#define CCS_SA_STROBE_MODE_ADJUST_EDGE BIT(4) +#define CCS_R_SA_STROBE_START_POINT (0x0c1e | CCS_FL_16BIT) +#define CCS_R_TSA_STROBE_DELAY_CTRL (0x0c20 | CCS_FL_16BIT) +#define CCS_R_TSA_STROBE_WIDTH_CTRL (0x0c22 | CCS_FL_16BIT) +#define CCS_R_SA_STROBE_TRIGGER 0x0c24 +#define CCS_R_SA_STROBE_STATUS 0x0c25 +#define CCS_SA_STROBE_STATUS_RETIMED BIT(0) +#define CCS_R_TSA_STROBE_RE_DELAY_CTRL (0x0c30 | CCS_FL_16BIT) +#define CCS_R_TSA_STROBE_FE_DELAY_CTRL (0x0c32 | CCS_FL_16BIT) +#define CCS_R_PDAF_CTRL (0x0d00 | CCS_FL_16BIT) +#define CCS_PDAF_CTRL_ENABLE BIT(0) +#define CCS_PDAF_CTRL_PROCESSED BIT(1) +#define CCS_PDAF_CTRL_INTERLEAVED BIT(2) +#define CCS_PDAF_CTRL_VISIBLE_PDAF_CORRECTION BIT(3) +#define CCS_R_PDAF_VC 0x0d02 +#define CCS_R_PDAF_DT 0x0d03 +#define CCS_R_PD_X_ADDR_START (0x0d04 | CCS_FL_16BIT) +#define CCS_R_PD_Y_ADDR_START (0x0d06 | CCS_FL_16BIT) +#define CCS_R_PD_X_ADDR_END (0x0d08 | CCS_FL_16BIT) +#define CCS_R_PD_Y_ADDR_END (0x0d0a | CCS_FL_16BIT) +#define CCS_R_BRACKETING_LUT_CTRL 0x0e00 +#define CCS_R_BRACKETING_LUT_MODE 0x0e01 +#define CCS_BRACKETING_LUT_MODE_CONTINUE_STREAMING BIT(0) +#define CCS_BRACKETING_LUT_MODE_LOOP_MODE BIT(1) +#define CCS_R_BRACKETING_LUT_ENTRY_CTRL 0x0e02 +#define CCS_R_BRACKETING_LUT_FRAME(n) (0x0e10 + (n)) +#define CCS_LIM_BRACKETING_LUT_FRAME_MIN_N 0U +#define CCS_LIM_BRACKETING_LUT_FRAME_MAX_N 239U +#define CCS_R_INTEGRATION_TIME_CAPABILITY (0x1000 | CCS_FL_16BIT) +#define CCS_INTEGRATION_TIME_CAPABILITY_FINE BIT(0) +#define CCS_R_COARSE_INTEGRATION_TIME_MIN (0x1004 | CCS_FL_16BIT) +#define CCS_R_COARSE_INTEGRATION_TIME_MAX_MARGIN (0x1006 | CCS_FL_16BIT) +#define CCS_R_FINE_INTEGRATION_TIME_MIN (0x1008 | CCS_FL_16BIT) +#define CCS_R_FINE_INTEGRATION_TIME_MAX_MARGIN (0x100a | CCS_FL_16BIT) +#define CCS_R_DIGITAL_GAIN_CAPABILITY 0x1081 +#define CCS_DIGITAL_GAIN_CAPABILITY_NONE 0U +#define CCS_DIGITAL_GAIN_CAPABILITY_GLOBAL 2U +#define CCS_R_DIGITAL_GAIN_MIN (0x1084 | CCS_FL_16BIT) +#define CCS_R_DIGITAL_GAIN_MAX (0x1086 | CCS_FL_16BIT) +#define CCS_R_DIGITAL_GAIN_STEP_SIZE (0x1088 | CCS_FL_16BIT) +#define CCS_R_PEDESTAL_CAPABILITY 0x10e0 +#define CCS_R_ADC_CAPABILITY 0x10f0 +#define CCS_ADC_CAPABILITY_BIT_DEPTH_CTRL BIT(0) +#define CCS_R_ADC_BIT_DEPTH_CAPABILITY (0x10f4 | CCS_FL_32BIT) +#define CCS_R_MIN_EXT_CLK_FREQ_MHZ (0x1100 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MAX_EXT_CLK_FREQ_MHZ (0x1104 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MIN_PRE_PLL_CLK_DIV (0x1108 | CCS_FL_16BIT) +#define CCS_R_MAX_PRE_PLL_CLK_DIV (0x110a | CCS_FL_16BIT) +#define CCS_R_MIN_PLL_IP_CLK_FREQ_MHZ (0x110c | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MAX_PLL_IP_CLK_FREQ_MHZ (0x1110 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MIN_PLL_MULTIPLIER (0x1114 | CCS_FL_16BIT) +#define CCS_R_MAX_PLL_MULTIPLIER (0x1116 | CCS_FL_16BIT) +#define CCS_R_MIN_PLL_OP_CLK_FREQ_MHZ (0x1118 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MAX_PLL_OP_CLK_FREQ_MHZ (0x111c | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MIN_VT_SYS_CLK_DIV (0x1120 | CCS_FL_16BIT) +#define CCS_R_MAX_VT_SYS_CLK_DIV (0x1122 | CCS_FL_16BIT) +#define CCS_R_MIN_VT_SYS_CLK_FREQ_MHZ (0x1124 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MAX_VT_SYS_CLK_FREQ_MHZ (0x1128 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MIN_VT_PIX_CLK_FREQ_MHZ (0x112c | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MAX_VT_PIX_CLK_FREQ_MHZ (0x1130 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MIN_VT_PIX_CLK_DIV (0x1134 | CCS_FL_16BIT) +#define CCS_R_MAX_VT_PIX_CLK_DIV (0x1136 | CCS_FL_16BIT) +#define CCS_R_CLOCK_CALCULATION 0x1138 +#define CCS_CLOCK_CALCULATION_LANE_SPEED BIT(0) +#define CCS_CLOCK_CALCULATION_LINK_DECOUPLED BIT(1) +#define CCS_CLOCK_CALCULATION_DUAL_PLL_OP_SYS_DDR BIT(2) +#define CCS_CLOCK_CALCULATION_DUAL_PLL_OP_PIX_DDR BIT(3) +#define CCS_R_NUM_OF_VT_LANES 0x1139 +#define CCS_R_NUM_OF_OP_LANES 0x113a +#define CCS_R_OP_BITS_PER_LANE 0x113b +#define CCS_R_MIN_FRAME_LENGTH_LINES (0x1140 | CCS_FL_16BIT) +#define CCS_R_MAX_FRAME_LENGTH_LINES (0x1142 | CCS_FL_16BIT) +#define CCS_R_MIN_LINE_LENGTH_PCK (0x1144 | CCS_FL_16BIT) +#define CCS_R_MAX_LINE_LENGTH_PCK (0x1146 | CCS_FL_16BIT) +#define CCS_R_MIN_LINE_BLANKING_PCK (0x1148 | CCS_FL_16BIT) +#define CCS_R_MIN_FRAME_BLANKING_LINES (0x114a | CCS_FL_16BIT) +#define CCS_R_MIN_LINE_LENGTH_PCK_STEP_SIZE 0x114c +#define CCS_R_TIMING_MODE_CAPABILITY 0x114d +#define CCS_TIMING_MODE_CAPABILITY_AUTO_FRAME_LENGTH BIT(0) +#define CCS_TIMING_MODE_CAPABILITY_ROLLING_SHUTTER_MANUAL_READOUT BIT(2) +#define CCS_TIMING_MODE_CAPABILITY_DELAYED_EXPOSURE_START BIT(3) +#define CCS_TIMING_MODE_CAPABILITY_MANUAL_EXPOSURE_EMBEDDED_DATA BIT(4) +#define CCS_R_FRAME_MARGIN_MAX_VALUE (0x114e | CCS_FL_16BIT) +#define CCS_R_FRAME_MARGIN_MIN_VALUE 0x1150 +#define CCS_R_GAIN_DELAY_TYPE 0x1151 +#define CCS_GAIN_DELAY_TYPE_FIXED 0U +#define CCS_GAIN_DELAY_TYPE_VARIABLE 1U +#define CCS_R_MIN_OP_SYS_CLK_DIV (0x1160 | CCS_FL_16BIT) +#define CCS_R_MAX_OP_SYS_CLK_DIV (0x1162 | CCS_FL_16BIT) +#define CCS_R_MIN_OP_SYS_CLK_FREQ_MHZ (0x1164 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MAX_OP_SYS_CLK_FREQ_MHZ (0x1168 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MIN_OP_PIX_CLK_DIV (0x116c | CCS_FL_16BIT) +#define CCS_R_MAX_OP_PIX_CLK_DIV (0x116e | CCS_FL_16BIT) +#define CCS_R_MIN_OP_PIX_CLK_FREQ_MHZ (0x1170 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MAX_OP_PIX_CLK_FREQ_MHZ (0x1174 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_X_ADDR_MIN (0x1180 | CCS_FL_16BIT) +#define CCS_R_Y_ADDR_MIN (0x1182 | CCS_FL_16BIT) +#define CCS_R_X_ADDR_MAX (0x1184 | CCS_FL_16BIT) +#define CCS_R_Y_ADDR_MAX (0x1186 | CCS_FL_16BIT) +#define CCS_R_MIN_X_OUTPUT_SIZE (0x1188 | CCS_FL_16BIT) +#define CCS_R_MIN_Y_OUTPUT_SIZE (0x118a | CCS_FL_16BIT) +#define CCS_R_MAX_X_OUTPUT_SIZE (0x118c | CCS_FL_16BIT) +#define CCS_R_MAX_Y_OUTPUT_SIZE (0x118e | CCS_FL_16BIT) +#define CCS_R_X_ADDR_START_DIV_CONSTANT 0x1190 +#define CCS_R_Y_ADDR_START_DIV_CONSTANT 0x1191 +#define CCS_R_X_ADDR_END_DIV_CONSTANT 0x1192 +#define CCS_R_Y_ADDR_END_DIV_CONSTANT 0x1193 +#define CCS_R_X_SIZE_DIV 0x1194 +#define CCS_R_Y_SIZE_DIV 0x1195 +#define CCS_R_X_OUTPUT_DIV 0x1196 +#define CCS_R_Y_OUTPUT_DIV 0x1197 +#define CCS_R_NON_FLEXIBLE_RESOLUTION_SUPPORT 0x1198 +#define CCS_NON_FLEXIBLE_RESOLUTION_SUPPORT_NEW_PIX_ADDR BIT(0) +#define CCS_NON_FLEXIBLE_RESOLUTION_SUPPORT_NEW_OUTPUT_RES BIT(1) +#define CCS_NON_FLEXIBLE_RESOLUTION_SUPPORT_OUTPUT_CROP_NO_PAD BIT(2) +#define CCS_NON_FLEXIBLE_RESOLUTION_SUPPORT_OUTPUT_SIZE_LANE_DEP BIT(3) +#define CCS_R_MIN_OP_PRE_PLL_CLK_DIV (0x11a0 | CCS_FL_16BIT) +#define CCS_R_MAX_OP_PRE_PLL_CLK_DIV (0x11a2 | CCS_FL_16BIT) +#define CCS_R_MIN_OP_PLL_IP_CLK_FREQ_MHZ (0x11a4 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MAX_OP_PLL_IP_CLK_FREQ_MHZ (0x11a8 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MIN_OP_PLL_MULTIPLIER (0x11ac | CCS_FL_16BIT) +#define CCS_R_MAX_OP_PLL_MULTIPLIER (0x11ae | CCS_FL_16BIT) +#define CCS_R_MIN_OP_PLL_OP_CLK_FREQ_MHZ (0x11b0 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MAX_OP_PLL_OP_CLK_FREQ_MHZ (0x11b4 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_CLOCK_TREE_PLL_CAPABILITY 0x11b8 +#define CCS_CLOCK_TREE_PLL_CAPABILITY_DUAL_PLL BIT(0) +#define CCS_CLOCK_TREE_PLL_CAPABILITY_SINGLE_PLL BIT(1) +#define CCS_CLOCK_TREE_PLL_CAPABILITY_EXT_DIVIDER BIT(2) +#define CCS_CLOCK_TREE_PLL_CAPABILITY_FLEXIBLE_OP_PIX_CLK_DIV BIT(3) +#define CCS_R_CLOCK_CAPA_TYPE_CAPABILITY 0x11b9 +#define CCS_CLOCK_CAPA_TYPE_CAPABILITY_IREAL BIT(0) +#define CCS_R_MIN_EVEN_INC (0x11c0 | CCS_FL_16BIT) +#define CCS_R_MIN_ODD_INC (0x11c2 | CCS_FL_16BIT) +#define CCS_R_MAX_EVEN_INC (0x11c4 | CCS_FL_16BIT) +#define CCS_R_MAX_ODD_INC (0x11c6 | CCS_FL_16BIT) +#define CCS_R_AUX_SUBSAMP_CAPABILITY 0x11c8 +#define CCS_AUX_SUBSAMP_CAPABILITY_FACTOR_POWER_OF_2 BIT(1) +#define CCS_R_AUX_SUBSAMP_MONO_CAPABILITY 0x11c9 +#define CCS_AUX_SUBSAMP_MONO_CAPABILITY_FACTOR_POWER_OF_2 BIT(1) +#define CCS_R_MONOCHROME_CAPABILITY 0x11ca +#define CCS_MONOCHROME_CAPABILITY_INC_ODD 0U +#define CCS_MONOCHROME_CAPABILITY_INC_EVEN 1U +#define CCS_R_PIXEL_READOUT_CAPABILITY 0x11cb +#define CCS_PIXEL_READOUT_CAPABILITY_BAYER 0U +#define CCS_PIXEL_READOUT_CAPABILITY_MONOCHROME 1U +#define CCS_PIXEL_READOUT_CAPABILITY_BAYER_AND_MONO 2U +#define CCS_R_MIN_EVEN_INC_MONO (0x11cc | CCS_FL_16BIT) +#define CCS_R_MAX_EVEN_INC_MONO (0x11ce | CCS_FL_16BIT) +#define CCS_R_MIN_ODD_INC_MONO (0x11d0 | CCS_FL_16BIT) +#define CCS_R_MAX_ODD_INC_MONO (0x11d2 | CCS_FL_16BIT) +#define CCS_R_MIN_EVEN_INC_BC2 (0x11d4 | CCS_FL_16BIT) +#define CCS_R_MAX_EVEN_INC_BC2 (0x11d6 | CCS_FL_16BIT) +#define CCS_R_MIN_ODD_INC_BC2 (0x11d8 | CCS_FL_16BIT) +#define CCS_R_MAX_ODD_INC_BC2 (0x11da | CCS_FL_16BIT) +#define CCS_R_MIN_EVEN_INC_MONO_BC2 (0x11dc | CCS_FL_16BIT) +#define CCS_R_MAX_EVEN_INC_MONO_BC2 (0x11de | CCS_FL_16BIT) +#define CCS_R_MIN_ODD_INC_MONO_BC2 (0x11f0 | CCS_FL_16BIT) +#define CCS_R_MAX_ODD_INC_MONO_BC2 (0x11f2 | CCS_FL_16BIT) +#define CCS_R_SCALING_CAPABILITY (0x1200 | CCS_FL_16BIT) +#define CCS_SCALING_CAPABILITY_NONE 0U +#define CCS_SCALING_CAPABILITY_HORIZONTAL 1U +#define CCS_SCALING_CAPABILITY_RESERVED 2U +#define CCS_R_SCALER_M_MIN (0x1204 | CCS_FL_16BIT) +#define CCS_R_SCALER_M_MAX (0x1206 | CCS_FL_16BIT) +#define CCS_R_SCALER_N_MIN (0x1208 | CCS_FL_16BIT) +#define CCS_R_SCALER_N_MAX (0x120a | CCS_FL_16BIT) +#define CCS_R_DIGITAL_CROP_CAPABILITY 0x120e +#define CCS_DIGITAL_CROP_CAPABILITY_NONE 0U +#define CCS_DIGITAL_CROP_CAPABILITY_INPUT_CROP 1U +#define CCS_R_HDR_CAPABILITY_1 0x1210 +#define CCS_HDR_CAPABILITY_1_2X2_BINNING BIT(0) +#define CCS_HDR_CAPABILITY_1_COMBINED_ANALOG_GAIN BIT(1) +#define CCS_HDR_CAPABILITY_1_SEPARATE_ANALOG_GAIN BIT(2) +#define CCS_HDR_CAPABILITY_1_UPSCALING BIT(3) +#define CCS_HDR_CAPABILITY_1_RESET_SYNC BIT(4) +#define CCS_HDR_CAPABILITY_1_DIRECT_SHORT_EXP_TIMING BIT(5) +#define CCS_HDR_CAPABILITY_1_DIRECT_SHORT_EXP_SYNTHESIS BIT(6) +#define CCS_R_MIN_HDR_BIT_DEPTH 0x1211 +#define CCS_R_HDR_RESOLUTION_SUB_TYPES 0x1212 +#define CCS_R_HDR_RESOLUTION_SUB_TYPE(n) (0x1213 + (n)) +#define CCS_LIM_HDR_RESOLUTION_SUB_TYPE_MIN_N 0U +#define CCS_LIM_HDR_RESOLUTION_SUB_TYPE_MAX_N 1U +#define CCS_HDR_RESOLUTION_SUB_TYPE_ROW_SHIFT 0U +#define CCS_HDR_RESOLUTION_SUB_TYPE_ROW_MASK 0xf +#define CCS_HDR_RESOLUTION_SUB_TYPE_COLUMN_SHIFT 4U +#define CCS_HDR_RESOLUTION_SUB_TYPE_COLUMN_MASK 0xf0 +#define CCS_R_HDR_CAPABILITY_2 0x121b +#define CCS_HDR_CAPABILITY_2_COMBINED_DIGITAL_GAIN BIT(0) +#define CCS_HDR_CAPABILITY_2_SEPARATE_DIGITAL_GAIN BIT(1) +#define CCS_HDR_CAPABILITY_2_TIMING_MODE BIT(3) +#define CCS_HDR_CAPABILITY_2_SYNTHESIS_MODE BIT(4) +#define CCS_R_MAX_HDR_BIT_DEPTH 0x121c +#define CCS_R_USL_SUPPORT_CAPABILITY 0x1230 +#define CCS_USL_SUPPORT_CAPABILITY_CLOCK_TREE BIT(0) +#define CCS_USL_SUPPORT_CAPABILITY_REV_CLOCK_TREE BIT(1) +#define CCS_USL_SUPPORT_CAPABILITY_REV_CLOCK_CALC BIT(2) +#define CCS_R_USL_CLOCK_MODE_D_CAPABILITY 0x1231 +#define CCS_USL_CLOCK_MODE_D_CAPABILITY_CONT_CLOCK_STANDBY BIT(0) +#define CCS_USL_CLOCK_MODE_D_CAPABILITY_CONT_CLOCK_VBLANK BIT(1) +#define CCS_USL_CLOCK_MODE_D_CAPABILITY_CONT_CLOCK_HBLANK BIT(2) +#define CCS_USL_CLOCK_MODE_D_CAPABILITY_NONCONT_CLOCK_STANDBY BIT(3) +#define CCS_USL_CLOCK_MODE_D_CAPABILITY_NONCONT_CLOCK_VBLANK BIT(4) +#define CCS_USL_CLOCK_MODE_D_CAPABILITY_NONCONT_CLOCK_HBLANK BIT(5) +#define CCS_R_MIN_OP_SYS_CLK_DIV_REV 0x1234 +#define CCS_R_MAX_OP_SYS_CLK_DIV_REV 0x1236 +#define CCS_R_MIN_OP_PIX_CLK_DIV_REV 0x1238 +#define CCS_R_MAX_OP_PIX_CLK_DIV_REV 0x123a +#define CCS_R_MIN_OP_SYS_CLK_FREQ_REV_MHZ (0x123c | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MAX_OP_SYS_CLK_FREQ_REV_MHZ (0x1240 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MIN_OP_PIX_CLK_FREQ_REV_MHZ (0x1244 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MAX_OP_PIX_CLK_FREQ_REV_MHZ (0x1248 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MAX_BITRATE_REV_D_MODE_MBPS (0x124c | (CCS_FL_32BIT | CCS_FL_IREAL)) +#define CCS_R_MAX_SYMRATE_REV_C_MODE_MSPS (0x1250 | (CCS_FL_32BIT | CCS_FL_IREAL)) +#define CCS_R_COMPRESSION_CAPABILITY 0x1300 +#define CCS_COMPRESSION_CAPABILITY_DPCM_PCM_SIMPLE BIT(0) +#define CCS_R_TEST_MODE_CAPABILITY (0x1310 | CCS_FL_16BIT) +#define CCS_TEST_MODE_CAPABILITY_SOLID_COLOR BIT(0) +#define CCS_TEST_MODE_CAPABILITY_COLOR_BARS BIT(1) +#define CCS_TEST_MODE_CAPABILITY_FADE_TO_GREY BIT(2) +#define CCS_TEST_MODE_CAPABILITY_PN9 BIT(3) +#define CCS_TEST_MODE_CAPABILITY_COLOR_TILE BIT(5) +#define CCS_R_PN9_DATA_FORMAT1 0x1312 +#define CCS_R_PN9_DATA_FORMAT2 0x1313 +#define CCS_R_PN9_DATA_FORMAT3 0x1314 +#define CCS_R_PN9_DATA_FORMAT4 0x1315 +#define CCS_R_PN9_MISC_CAPABILITY 0x1316 +#define CCS_PN9_MISC_CAPABILITY_NUM_PIXELS_SHIFT 0U +#define CCS_PN9_MISC_CAPABILITY_NUM_PIXELS_MASK 0x7 +#define CCS_PN9_MISC_CAPABILITY_COMPRESSION BIT(3) +#define CCS_R_TEST_PATTERN_CAPABILITY 0x1317 +#define CCS_TEST_PATTERN_CAPABILITY_NO_REPEAT BIT(1) +#define CCS_R_PATTERN_SIZE_DIV_M1 0x1318 +#define CCS_R_FIFO_SUPPORT_CAPABILITY 0x1502 +#define CCS_FIFO_SUPPORT_CAPABILITY_NONE 0U +#define CCS_FIFO_SUPPORT_CAPABILITY_DERATING 1U +#define CCS_FIFO_SUPPORT_CAPABILITY_DERATING_OVERRATING 2U +#define CCS_R_PHY_CTRL_CAPABILITY 0x1600 +#define CCS_PHY_CTRL_CAPABILITY_AUTO_PHY_CTL BIT(0) +#define CCS_PHY_CTRL_CAPABILITY_UI_PHY_CTL BIT(1) +#define CCS_PHY_CTRL_CAPABILITY_DPHY_TIME_UI_REG_1_CTL BIT(2) +#define CCS_PHY_CTRL_CAPABILITY_DPHY_TIME_UI_REG_2_CTL BIT(3) +#define CCS_PHY_CTRL_CAPABILITY_DPHY_TIME_CTL BIT(4) +#define CCS_PHY_CTRL_CAPABILITY_DPHY_EXT_TIME_UI_REG_1_CTL BIT(5) +#define CCS_PHY_CTRL_CAPABILITY_DPHY_EXT_TIME_UI_REG_2_CTL BIT(6) +#define CCS_PHY_CTRL_CAPABILITY_DPHY_EXT_TIME_CTL BIT(7) +#define CCS_R_CSI_DPHY_LANE_MODE_CAPABILITY 0x1601 +#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_1_LANE BIT(0) +#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_2_LANE BIT(1) +#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_3_LANE BIT(2) +#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_4_LANE BIT(3) +#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_5_LANE BIT(4) +#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_6_LANE BIT(5) +#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_7_LANE BIT(6) +#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_8_LANE BIT(7) +#define CCS_R_CSI_SIGNALING_MODE_CAPABILITY 0x1602 +#define CCS_CSI_SIGNALING_MODE_CAPABILITY_CSI_DPHY BIT(2) +#define CCS_CSI_SIGNALING_MODE_CAPABILITY_CSI_CPHY BIT(3) +#define CCS_R_FAST_STANDBY_CAPABILITY 0x1603 +#define CCS_FAST_STANDBY_CAPABILITY_NO_FRAME_TRUNCATION 0U +#define CCS_FAST_STANDBY_CAPABILITY_FRAME_TRUNCATION 1U +#define CCS_R_CSI_ADDRESS_CONTROL_CAPABILITY 0x1604 +#define CCS_CSI_ADDRESS_CONTROL_CAPABILITY_CCI_ADDR_CHANGE BIT(0) +#define CCS_CSI_ADDRESS_CONTROL_CAPABILITY_2ND_CCI_ADDR BIT(1) +#define CCS_CSI_ADDRESS_CONTROL_CAPABILITY_SW_CHANGEABLE_2ND_CCI_ADDR BIT(2) +#define CCS_R_DATA_TYPE_CAPABILITY 0x1605 +#define CCS_DATA_TYPE_CAPABILITY_DPCM_PROGRAMMABLE BIT(0) +#define CCS_DATA_TYPE_CAPABILITY_BOTTOM_EMBEDDED_DT_PROGRAMMABLE BIT(1) +#define CCS_DATA_TYPE_CAPABILITY_BOTTOM_EMBEDDED_VC_PROGRAMMABLE BIT(2) +#define CCS_DATA_TYPE_CAPABILITY_EXT_VC_RANGE BIT(3) +#define CCS_R_CSI_CPHY_LANE_MODE_CAPABILITY 0x1606 +#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_1_LANE BIT(0) +#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_2_LANE BIT(1) +#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_3_LANE BIT(2) +#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_4_LANE BIT(3) +#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_5_LANE BIT(4) +#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_6_LANE BIT(5) +#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_7_LANE BIT(6) +#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_8_LANE BIT(7) +#define CCS_R_EMB_DATA_CAPABILITY 0x1607 +#define CCS_EMB_DATA_CAPABILITY_TWO_BYTES_PER_RAW16 BIT(0) +#define CCS_EMB_DATA_CAPABILITY_TWO_BYTES_PER_RAW20 BIT(1) +#define CCS_EMB_DATA_CAPABILITY_TWO_BYTES_PER_RAW24 BIT(2) +#define CCS_EMB_DATA_CAPABILITY_NO_ONE_BYTE_PER_RAW16 BIT(3) +#define CCS_EMB_DATA_CAPABILITY_NO_ONE_BYTE_PER_RAW20 BIT(4) +#define CCS_EMB_DATA_CAPABILITY_NO_ONE_BYTE_PER_RAW24 BIT(5) +#define CCS_R_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS(n) ((0x1608 | (CCS_FL_32BIT | CCS_FL_IREAL)) + ((n) < 4 ? (n) * 4 : 0x32 + ((n) - 4) * 4)) +#define CCS_LIM_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS_MIN_N 0U +#define CCS_LIM_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS_MAX_N 7U +#define CCS_R_TEMP_SENSOR_CAPABILITY 0x1618 +#define CCS_TEMP_SENSOR_CAPABILITY_SUPPORTED BIT(0) +#define CCS_TEMP_SENSOR_CAPABILITY_CCS_FORMAT BIT(1) +#define CCS_TEMP_SENSOR_CAPABILITY_RESET_0X80 BIT(2) +#define CCS_R_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS(n) ((0x161a | (CCS_FL_32BIT | CCS_FL_IREAL)) + ((n) < 4 ? (n) * 4 : 0x30 + ((n) - 4) * 4)) +#define CCS_LIM_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS_MIN_N 0U +#define CCS_LIM_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS_MAX_N 7U +#define CCS_R_DPHY_EQUALIZATION_CAPABILITY 0x162b +#define CCS_DPHY_EQUALIZATION_CAPABILITY_EQUALIZATION_CTRL BIT(0) +#define CCS_DPHY_EQUALIZATION_CAPABILITY_EQ1 BIT(1) +#define CCS_DPHY_EQUALIZATION_CAPABILITY_EQ2 BIT(2) +#define CCS_R_CPHY_EQUALIZATION_CAPABILITY 0x162c +#define CCS_CPHY_EQUALIZATION_CAPABILITY_EQUALIZATION_CTRL BIT(0) +#define CCS_R_DPHY_PREAMBLE_CAPABILITY 0x162d +#define CCS_DPHY_PREAMBLE_CAPABILITY_PREAMBLE_SEQ_CTRL BIT(0) +#define CCS_R_DPHY_SSC_CAPABILITY 0x162e +#define CCS_DPHY_SSC_CAPABILITY_SUPPORTED BIT(0) +#define CCS_R_CPHY_CALIBRATION_CAPABILITY 0x162f +#define CCS_CPHY_CALIBRATION_CAPABILITY_MANUAL BIT(0) +#define CCS_CPHY_CALIBRATION_CAPABILITY_MANUAL_STREAMING BIT(1) +#define CCS_CPHY_CALIBRATION_CAPABILITY_FORMAT_1_CTRL BIT(2) +#define CCS_CPHY_CALIBRATION_CAPABILITY_FORMAT_2_CTRL BIT(3) +#define CCS_CPHY_CALIBRATION_CAPABILITY_FORMAT_3_CTRL BIT(4) +#define CCS_R_DPHY_CALIBRATION_CAPABILITY 0x1630 +#define CCS_DPHY_CALIBRATION_CAPABILITY_MANUAL BIT(0) +#define CCS_DPHY_CALIBRATION_CAPABILITY_MANUAL_STREAMING BIT(1) +#define CCS_DPHY_CALIBRATION_CAPABILITY_ALTERNATE_SEQ BIT(2) +#define CCS_R_PHY_CTRL_CAPABILITY_2 0x1631 +#define CCS_PHY_CTRL_CAPABILITY_2_TGR_LENGTH BIT(0) +#define CCS_PHY_CTRL_CAPABILITY_2_TGR_PREAMBLE_PROG_SEQ BIT(1) +#define CCS_PHY_CTRL_CAPABILITY_2_EXTRA_CPHY_MANUAL_TIMING BIT(2) +#define CCS_PHY_CTRL_CAPABILITY_2_CLOCK_BASED_MANUAL_CDPHY BIT(3) +#define CCS_PHY_CTRL_CAPABILITY_2_CLOCK_BASED_MANUAL_DPHY BIT(4) +#define CCS_PHY_CTRL_CAPABILITY_2_CLOCK_BASED_MANUAL_CPHY BIT(5) +#define CCS_PHY_CTRL_CAPABILITY_2_MANUAL_LP_DPHY BIT(6) +#define CCS_PHY_CTRL_CAPABILITY_2_MANUAL_LP_CPHY BIT(7) +#define CCS_R_LRTE_CPHY_CAPABILITY 0x1632 +#define CCS_LRTE_CPHY_CAPABILITY_PDQ_SHORT BIT(0) +#define CCS_LRTE_CPHY_CAPABILITY_SPACER_SHORT BIT(1) +#define CCS_LRTE_CPHY_CAPABILITY_PDQ_LONG BIT(2) +#define CCS_LRTE_CPHY_CAPABILITY_SPACER_LONG BIT(3) +#define CCS_LRTE_CPHY_CAPABILITY_SPACER_NO_PDQ BIT(4) +#define CCS_R_LRTE_DPHY_CAPABILITY 0x1633 +#define CCS_LRTE_DPHY_CAPABILITY_PDQ_SHORT_OPT1 BIT(0) +#define CCS_LRTE_DPHY_CAPABILITY_SPACER_SHORT_OPT1 BIT(1) +#define CCS_LRTE_DPHY_CAPABILITY_PDQ_LONG_OPT1 BIT(2) +#define CCS_LRTE_DPHY_CAPABILITY_SPACER_LONG_OPT1 BIT(3) +#define CCS_LRTE_DPHY_CAPABILITY_SPACER_SHORT_OPT2 BIT(4) +#define CCS_LRTE_DPHY_CAPABILITY_SPACER_LONG_OPT2 BIT(5) +#define CCS_LRTE_DPHY_CAPABILITY_SPACER_NO_PDQ_OPT1 BIT(6) +#define CCS_LRTE_DPHY_CAPABILITY_SPACER_VARIABLE_OPT2 BIT(7) +#define CCS_R_ALPS_CAPABILITY_DPHY 0x1634 +#define CCS_ALPS_CAPABILITY_DPHY_LVLP_NOT_SUPPORTED 0U +#define CCS_ALPS_CAPABILITY_DPHY_LVLP_SUPPORTED 1U +#define CCS_ALPS_CAPABILITY_DPHY_CONTROLLABLE_LVLP 2U +#define CCS_R_ALPS_CAPABILITY_CPHY 0x1635 +#define CCS_ALPS_CAPABILITY_CPHY_LVLP_NOT_SUPPORTED 0U +#define CCS_ALPS_CAPABILITY_CPHY_LVLP_SUPPORTED 1U +#define CCS_ALPS_CAPABILITY_CPHY_CONTROLLABLE_LVLP 2U +#define CCS_ALPS_CAPABILITY_CPHY_ALP_NOT_SUPPORTED 0xc +#define CCS_ALPS_CAPABILITY_CPHY_ALP_SUPPORTED 0xd +#define CCS_ALPS_CAPABILITY_CPHY_CONTROLLABLE_ALP 0xe +#define CCS_R_SCRAMBLING_CAPABILITY 0x1636 +#define CCS_SCRAMBLING_CAPABILITY_SCRAMBLING_SUPPORTED BIT(0) +#define CCS_SCRAMBLING_CAPABILITY_MAX_SEEDS_PER_LANE_C_SHIFT 1U +#define CCS_SCRAMBLING_CAPABILITY_MAX_SEEDS_PER_LANE_C_MASK 0x6 +#define CCS_SCRAMBLING_CAPABILITY_MAX_SEEDS_PER_LANE_C_1 0U +#define CCS_SCRAMBLING_CAPABILITY_MAX_SEEDS_PER_LANE_C_4 3U +#define CCS_SCRAMBLING_CAPABILITY_NUM_SEED_REGS_SHIFT 3U +#define CCS_SCRAMBLING_CAPABILITY_NUM_SEED_REGS_MASK 0x38 +#define CCS_SCRAMBLING_CAPABILITY_NUM_SEED_REGS_0 0U +#define CCS_SCRAMBLING_CAPABILITY_NUM_SEED_REGS_1 1U +#define CCS_SCRAMBLING_CAPABILITY_NUM_SEED_REGS_4 4U +#define CCS_SCRAMBLING_CAPABILITY_NUM_SEED_PER_LANE BIT(6) +#define CCS_R_DPHY_MANUAL_CONSTANT 0x1637 +#define CCS_R_CPHY_MANUAL_CONSTANT 0x1638 +#define CCS_R_CSI2_INTERFACE_CAPABILITY_MISC 0x1639 +#define CCS_CSI2_INTERFACE_CAPABILITY_MISC_EOTP_SHORT_PKT_OPT2 BIT(0) +#define CCS_R_PHY_CTRL_CAPABILITY_3 0x165c +#define CCS_PHY_CTRL_CAPABILITY_3_DPHY_TIMING_NOT_MULTIPLE BIT(0) +#define CCS_PHY_CTRL_CAPABILITY_3_DPHY_MIN_TIMING_VALUE_1 BIT(1) +#define CCS_PHY_CTRL_CAPABILITY_3_TWAKEUP_SUPPORTED BIT(2) +#define CCS_PHY_CTRL_CAPABILITY_3_TINIT_SUPPORTED BIT(3) +#define CCS_PHY_CTRL_CAPABILITY_3_THS_EXIT_SUPPORTED BIT(4) +#define CCS_PHY_CTRL_CAPABILITY_3_CPHY_TIMING_NOT_MULTIPLE BIT(5) +#define CCS_PHY_CTRL_CAPABILITY_3_CPHY_MIN_TIMING_VALUE_1 BIT(6) +#define CCS_R_DPHY_SF 0x165d +#define CCS_R_CPHY_SF 0x165e +#define CCS_CPHY_SF_TWAKEUP_SHIFT 0U +#define CCS_CPHY_SF_TWAKEUP_MASK 0xf +#define CCS_CPHY_SF_TINIT_SHIFT 4U +#define CCS_CPHY_SF_TINIT_MASK 0xf0 +#define CCS_R_DPHY_LIMITS_1 0x165f +#define CCS_DPHY_LIMITS_1_THS_PREPARE_SHIFT 0U +#define CCS_DPHY_LIMITS_1_THS_PREPARE_MASK 0xf +#define CCS_DPHY_LIMITS_1_THS_ZERO_SHIFT 4U +#define CCS_DPHY_LIMITS_1_THS_ZERO_MASK 0xf0 +#define CCS_R_DPHY_LIMITS_2 0x1660 +#define CCS_DPHY_LIMITS_2_THS_TRAIL_SHIFT 0U +#define CCS_DPHY_LIMITS_2_THS_TRAIL_MASK 0xf +#define CCS_DPHY_LIMITS_2_TCLK_TRAIL_MIN_SHIFT 4U +#define CCS_DPHY_LIMITS_2_TCLK_TRAIL_MIN_MASK 0xf0 +#define CCS_R_DPHY_LIMITS_3 0x1661 +#define CCS_DPHY_LIMITS_3_TCLK_PREPARE_SHIFT 0U +#define CCS_DPHY_LIMITS_3_TCLK_PREPARE_MASK 0xf +#define CCS_DPHY_LIMITS_3_TCLK_ZERO_SHIFT 4U +#define CCS_DPHY_LIMITS_3_TCLK_ZERO_MASK 0xf0 +#define CCS_R_DPHY_LIMITS_4 0x1662 +#define CCS_DPHY_LIMITS_4_TCLK_POST_SHIFT 0U +#define CCS_DPHY_LIMITS_4_TCLK_POST_MASK 0xf +#define CCS_DPHY_LIMITS_4_TLPX_SHIFT 4U +#define CCS_DPHY_LIMITS_4_TLPX_MASK 0xf0 +#define CCS_R_DPHY_LIMITS_5 0x1663 +#define CCS_DPHY_LIMITS_5_THS_EXIT_SHIFT 0U +#define CCS_DPHY_LIMITS_5_THS_EXIT_MASK 0xf +#define CCS_DPHY_LIMITS_5_TWAKEUP_SHIFT 4U +#define CCS_DPHY_LIMITS_5_TWAKEUP_MASK 0xf0 +#define CCS_R_DPHY_LIMITS_6 0x1664 +#define CCS_DPHY_LIMITS_6_TINIT_SHIFT 0U +#define CCS_DPHY_LIMITS_6_TINIT_MASK 0xf +#define CCS_R_CPHY_LIMITS_1 0x1665 +#define CCS_CPHY_LIMITS_1_T3_PREPARE_MAX_SHIFT 0U +#define CCS_CPHY_LIMITS_1_T3_PREPARE_MAX_MASK 0xf +#define CCS_CPHY_LIMITS_1_T3_LPX_MAX_SHIFT 4U +#define CCS_CPHY_LIMITS_1_T3_LPX_MAX_MASK 0xf0 +#define CCS_R_CPHY_LIMITS_2 0x1666 +#define CCS_CPHY_LIMITS_2_THS_EXIT_MAX_SHIFT 0U +#define CCS_CPHY_LIMITS_2_THS_EXIT_MAX_MASK 0xf +#define CCS_CPHY_LIMITS_2_TWAKEUP_MAX_SHIFT 4U +#define CCS_CPHY_LIMITS_2_TWAKEUP_MAX_MASK 0xf0 +#define CCS_R_CPHY_LIMITS_3 0x1667 +#define CCS_CPHY_LIMITS_3_TINIT_MAX_SHIFT 0U +#define CCS_CPHY_LIMITS_3_TINIT_MAX_MASK 0xf +#define CCS_R_MIN_FRAME_LENGTH_LINES_BIN (0x1700 | CCS_FL_16BIT) +#define CCS_R_MAX_FRAME_LENGTH_LINES_BIN (0x1702 | CCS_FL_16BIT) +#define CCS_R_MIN_LINE_LENGTH_PCK_BIN (0x1704 | CCS_FL_16BIT) +#define CCS_R_MAX_LINE_LENGTH_PCK_BIN (0x1706 | CCS_FL_16BIT) +#define CCS_R_MIN_LINE_BLANKING_PCK_BIN (0x1708 | CCS_FL_16BIT) +#define CCS_R_FINE_INTEGRATION_TIME_MIN_BIN (0x170a | CCS_FL_16BIT) +#define CCS_R_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN (0x170c | CCS_FL_16BIT) +#define CCS_R_BINNING_CAPABILITY 0x1710 +#define CCS_BINNING_CAPABILITY_UNSUPPORTED 0U +#define CCS_BINNING_CAPABILITY_BINNING_THEN_SUBSAMPLING 1U +#define CCS_BINNING_CAPABILITY_SUBSAMPLING_THEN_BINNING 2U +#define CCS_R_BINNING_WEIGHTING_CAPABILITY 0x1711 +#define CCS_BINNING_WEIGHTING_CAPABILITY_AVERAGED BIT(0) +#define CCS_BINNING_WEIGHTING_CAPABILITY_SUMMED BIT(1) +#define CCS_BINNING_WEIGHTING_CAPABILITY_BAYER_CORRECTED BIT(2) +#define CCS_BINNING_WEIGHTING_CAPABILITY_MODULE_SPECIFIC_WEIGHT BIT(3) +#define CCS_R_BINNING_SUB_TYPES 0x1712 +#define CCS_R_BINNING_SUB_TYPE(n) (0x1713 + (n)) +#define CCS_LIM_BINNING_SUB_TYPE_MIN_N 0U +#define CCS_LIM_BINNING_SUB_TYPE_MAX_N 63U +#define CCS_BINNING_SUB_TYPE_ROW_SHIFT 0U +#define CCS_BINNING_SUB_TYPE_ROW_MASK 0xf +#define CCS_BINNING_SUB_TYPE_COLUMN_SHIFT 4U +#define CCS_BINNING_SUB_TYPE_COLUMN_MASK 0xf0 +#define CCS_R_BINNING_WEIGHTING_MONO_CAPABILITY 0x1771 +#define CCS_BINNING_WEIGHTING_MONO_CAPABILITY_AVERAGED BIT(0) +#define CCS_BINNING_WEIGHTING_MONO_CAPABILITY_SUMMED BIT(1) +#define CCS_BINNING_WEIGHTING_MONO_CAPABILITY_BAYER_CORRECTED BIT(2) +#define CCS_BINNING_WEIGHTING_MONO_CAPABILITY_MODULE_SPECIFIC_WEIGHT BIT(3) +#define CCS_R_BINNING_SUB_TYPES_MONO 0x1772 +#define CCS_R_BINNING_SUB_TYPE_MONO(n) (0x1773 + (n)) +#define CCS_LIM_BINNING_SUB_TYPE_MONO_MIN_N 0U +#define CCS_LIM_BINNING_SUB_TYPE_MONO_MAX_N 63U +#define CCS_R_DATA_TRANSFER_IF_CAPABILITY 0x1800 +#define CCS_DATA_TRANSFER_IF_CAPABILITY_SUPPORTED BIT(0) +#define CCS_DATA_TRANSFER_IF_CAPABILITY_POLLING BIT(2) +#define CCS_R_SHADING_CORRECTION_CAPABILITY 0x1900 +#define CCS_SHADING_CORRECTION_CAPABILITY_COLOR_SHADING BIT(0) +#define CCS_SHADING_CORRECTION_CAPABILITY_LUMINANCE_CORRECTION BIT(1) +#define CCS_R_GREEN_IMBALANCE_CAPABILITY 0x1901 +#define CCS_GREEN_IMBALANCE_CAPABILITY_SUPPORTED BIT(0) +#define CCS_R_MODULE_SPECIFIC_CORRECTION_CAPABILITY 0x1903 +#define CCS_R_DEFECT_CORRECTION_CAPABILITY (0x1904 | CCS_FL_16BIT) +#define CCS_DEFECT_CORRECTION_CAPABILITY_MAPPED_DEFECT BIT(0) +#define CCS_DEFECT_CORRECTION_CAPABILITY_DYNAMIC_COUPLET BIT(2) +#define CCS_DEFECT_CORRECTION_CAPABILITY_DYNAMIC_SINGLE BIT(5) +#define CCS_DEFECT_CORRECTION_CAPABILITY_COMBINED_DYNAMIC BIT(8) +#define CCS_R_DEFECT_CORRECTION_CAPABILITY_2 (0x1906 | CCS_FL_16BIT) +#define CCS_DEFECT_CORRECTION_CAPABILITY_2_DYNAMIC_TRIPLET BIT(3) +#define CCS_R_NF_CAPABILITY 0x1908 +#define CCS_NF_CAPABILITY_LUMA BIT(0) +#define CCS_NF_CAPABILITY_CHROMA BIT(1) +#define CCS_NF_CAPABILITY_COMBINED BIT(2) +#define CCS_R_OB_READOUT_CAPABILITY 0x1980 +#define CCS_OB_READOUT_CAPABILITY_CONTROLLABLE_READOUT BIT(0) +#define CCS_OB_READOUT_CAPABILITY_VISIBLE_PIXEL_READOUT BIT(1) +#define CCS_OB_READOUT_CAPABILITY_DIFFERENT_VC_READOUT BIT(2) +#define CCS_OB_READOUT_CAPABILITY_DIFFERENT_DT_READOUT BIT(3) +#define CCS_OB_READOUT_CAPABILITY_PROG_DATA_FORMAT BIT(4) +#define CCS_R_COLOR_FEEDBACK_CAPABILITY 0x1987 +#define CCS_COLOR_FEEDBACK_CAPABILITY_KELVIN BIT(0) +#define CCS_COLOR_FEEDBACK_CAPABILITY_AWB_GAIN BIT(1) +#define CCS_R_CFA_PATTERN_CAPABILITY 0x1990 +#define CCS_CFA_PATTERN_CAPABILITY_BAYER 0U +#define CCS_CFA_PATTERN_CAPABILITY_MONOCHROME 1U +#define CCS_CFA_PATTERN_CAPABILITY_4X4_QUAD_BAYER 2U +#define CCS_CFA_PATTERN_CAPABILITY_VENDOR_SPECIFIC 3U +#define CCS_R_CFA_PATTERN_CONVERSION_CAPABILITY 0x1991 +#define CCS_CFA_PATTERN_CONVERSION_CAPABILITY_BAYER BIT(0) +#define CCS_R_FLASH_MODE_CAPABILITY 0x1a02 +#define CCS_FLASH_MODE_CAPABILITY_SINGLE_STROBE BIT(0) +#define CCS_R_SA_STROBE_MODE_CAPABILITY 0x1a03 +#define CCS_SA_STROBE_MODE_CAPABILITY_FIXED_WIDTH BIT(0) +#define CCS_SA_STROBE_MODE_CAPABILITY_EDGE_CTRL BIT(1) +#define CCS_R_RESET_MAX_DELAY 0x1a10 +#define CCS_R_RESET_MIN_TIME 0x1a11 +#define CCS_R_PDAF_CAPABILITY_1 0x1b80 +#define CCS_PDAF_CAPABILITY_1_SUPPORTED BIT(0) +#define CCS_PDAF_CAPABILITY_1_PROCESSED_BOTTOM_EMBEDDED BIT(1) +#define CCS_PDAF_CAPABILITY_1_PROCESSED_INTERLEAVED BIT(2) +#define CCS_PDAF_CAPABILITY_1_RAW_BOTTOM_EMBEDDED BIT(3) +#define CCS_PDAF_CAPABILITY_1_RAW_INTERLEAVED BIT(4) +#define CCS_PDAF_CAPABILITY_1_VISIBLE_PDAF_CORRECTION BIT(5) +#define CCS_PDAF_CAPABILITY_1_VC_INTERLEAVING BIT(6) +#define CCS_PDAF_CAPABILITY_1_DT_INTERLEAVING BIT(7) +#define CCS_R_PDAF_CAPABILITY_2 0x1b81 +#define CCS_PDAF_CAPABILITY_2_ROI BIT(0) +#define CCS_PDAF_CAPABILITY_2_AFTER_DIGITAL_CROP BIT(1) +#define CCS_PDAF_CAPABILITY_2_CTRL_RETIMED BIT(2) +#define CCS_R_BRACKETING_LUT_CAPABILITY_1 0x1c00 +#define CCS_BRACKETING_LUT_CAPABILITY_1_COARSE_INTEGRATION BIT(0) +#define CCS_BRACKETING_LUT_CAPABILITY_1_GLOBAL_ANALOG_GAIN BIT(1) +#define CCS_BRACKETING_LUT_CAPABILITY_1_FLASH BIT(4) +#define CCS_BRACKETING_LUT_CAPABILITY_1_GLOBAL_DIGITAL_GAIN BIT(5) +#define CCS_BRACKETING_LUT_CAPABILITY_1_ALTERNATE_GLOBAL_ANALOG_GAIN BIT(6) +#define CCS_R_BRACKETING_LUT_CAPABILITY_2 0x1c01 +#define CCS_BRACKETING_LUT_CAPABILITY_2_SINGLE_BRACKETING_MODE BIT(0) +#define CCS_BRACKETING_LUT_CAPABILITY_2_LOOPED_BRACKETING_MODE BIT(1) +#define CCS_R_BRACKETING_LUT_SIZE 0x1c02 + +#endif /* __CCS_REGS_H__ */ -- cgit v1.2.3 From 82731a194fc155eb734941bb1f777caea4077ffa Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 3 Feb 2020 12:38:42 +0100 Subject: media: smiapp: Use CCS register flags Use the CCS register flags instead of the old smia flags. The new flags include the register width information that was separate from the register flags previously. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-reg-defs.h | 8 ++++---- drivers/media/i2c/smiapp/smiapp-regs.c | 20 +++++++++++++------- drivers/media/i2c/smiapp/smiapp-regs.h | 13 ++++--------- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/drivers/media/i2c/smiapp/smiapp-reg-defs.h b/drivers/media/i2c/smiapp/smiapp-reg-defs.h index 865488befc09..ec574007908b 100644 --- a/drivers/media/i2c/smiapp/smiapp-reg-defs.h +++ b/drivers/media/i2c/smiapp/smiapp-reg-defs.h @@ -7,11 +7,11 @@ * Copyright (C) 2011--2012 Nokia Corporation * Contact: Sakari Ailus */ -#define SMIAPP_REG_MK_U8(r) ((SMIAPP_REG_8BIT << 16) | (r)) -#define SMIAPP_REG_MK_U16(r) ((SMIAPP_REG_16BIT << 16) | (r)) -#define SMIAPP_REG_MK_U32(r) ((SMIAPP_REG_32BIT << 16) | (r)) +#define SMIAPP_REG_MK_U8(r) (r) +#define SMIAPP_REG_MK_U16(r) (CCS_FL_16BIT | (r)) +#define SMIAPP_REG_MK_U32(r) (CCS_FL_32BIT | (r)) -#define SMIAPP_REG_MK_F32(r) (SMIAPP_REG_FLAG_FLOAT | (SMIAPP_REG_32BIT << 16) | (r)) +#define SMIAPP_REG_MK_F32(r) (CCS_FL_FLOAT_IREAL | CCS_FL_32BIT | (r)) #define SMIAPP_REG_U16_MODEL_ID SMIAPP_REG_MK_U16(0x0000) #define SMIAPP_REG_U8_REVISION_NUMBER_MAJOR SMIAPP_REG_MK_U8(0x0002) diff --git a/drivers/media/i2c/smiapp/smiapp-regs.c b/drivers/media/i2c/smiapp/smiapp-regs.c index 1b58b7c6c839..904054d303ba 100644 --- a/drivers/media/i2c/smiapp/smiapp-regs.c +++ b/drivers/media/i2c/smiapp/smiapp-regs.c @@ -133,6 +133,16 @@ static int ____smiapp_read_8only(struct smiapp_sensor *sensor, u16 reg, return 0; } +unsigned int ccs_reg_width(u32 reg) +{ + if (reg & CCS_FL_16BIT) + return sizeof(uint16_t); + if (reg & CCS_FL_32BIT) + return sizeof(uint32_t); + + return sizeof(uint8_t); +} + /* * Read a 8/16/32-bit i2c register. The value is returned in 'val'. * Returns zero if successful, or non-zero otherwise. @@ -141,13 +151,9 @@ static int __smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val, bool only8) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - u8 len = SMIAPP_REG_WIDTH(reg); + unsigned int len = ccs_reg_width(reg); int rval; - if (len != SMIAPP_REG_8BIT && len != SMIAPP_REG_16BIT - && len != SMIAPP_REG_32BIT) - return -EINVAL; - if (!only8) rval = ____smiapp_read(sensor, SMIAPP_REG_ADDR(reg), len, val); else @@ -156,7 +162,7 @@ static int __smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val, if (rval < 0) return rval; - if (reg & SMIAPP_REG_FLAG_FLOAT) + if (reg & CCS_FL_FLOAT_IREAL) *val = float_to_u32_mul_1000000(client, *val); return 0; @@ -204,7 +210,7 @@ int smiapp_write_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 val) struct i2c_msg msg; unsigned char data[6]; unsigned int retries; - u8 len = SMIAPP_REG_WIDTH(reg); + unsigned int len = ccs_reg_width(reg); int r; if (len > sizeof(data) - 2) diff --git a/drivers/media/i2c/smiapp/smiapp-regs.h b/drivers/media/i2c/smiapp/smiapp-regs.h index 8fda6ed5668c..7223f5f89109 100644 --- a/drivers/media/i2c/smiapp/smiapp-regs.h +++ b/drivers/media/i2c/smiapp/smiapp-regs.h @@ -14,16 +14,9 @@ #include #include -#define SMIAPP_REG_ADDR(reg) ((u16)reg) -#define SMIAPP_REG_WIDTH(reg) ((u8)(reg >> 16)) -#define SMIAPP_REG_FLAGS(reg) ((u8)(reg >> 24)) - -/* Use upper 8 bits of the type field for flags */ -#define SMIAPP_REG_FLAG_FLOAT (1 << 24) +#include "ccs-regs.h" -#define SMIAPP_REG_8BIT 1 -#define SMIAPP_REG_16BIT 2 -#define SMIAPP_REG_32BIT 4 +#define SMIAPP_REG_ADDR(reg) ((u16)reg) struct smiapp_sensor; @@ -33,4 +26,6 @@ int smiapp_read_8only(struct smiapp_sensor *sensor, u32 reg, u32 *val); int smiapp_write_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 val); int smiapp_write(struct smiapp_sensor *sensor, u32 reg, u32 val); +unsigned int ccs_reg_width(u32 reg); + #endif -- cgit v1.2.3 From ab47d5cd825310478900b33d712a0e39bf3bb716 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 5 Feb 2020 15:21:06 +0100 Subject: media: smiapp: Calculate CCS limit offsets and limit buffer size Calculate the limit offsets and the size of the limit buffer. CCS limits are read into this buffer, and the offsets are helpful in accessing the information in it. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/Makefile | 2 +- drivers/media/i2c/smiapp/smiapp-core.c | 40 +++++++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/smiapp/Makefile b/drivers/media/i2c/smiapp/Makefile index 86f57a43f8e8..efb643d2acac 100644 --- a/drivers/media/i2c/smiapp/Makefile +++ b/drivers/media/i2c/smiapp/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only smiapp-objs += smiapp-core.o smiapp-regs.o \ - smiapp-quirk.o smiapp-limits.o + smiapp-quirk.o smiapp-limits.o ccs-limits.o obj-$(CONFIG_VIDEO_SMIAPP) += smiapp.o ccflags-y += -I $(srctree)/drivers/media/i2c diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 105ef29152e8..75862e7647f8 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -27,6 +27,7 @@ #include #include +#include "ccs-limits.h" #include "smiapp.h" #define SMIAPP_ALIGN_DIM(dim, flags) \ @@ -34,6 +35,11 @@ ? ALIGN((dim), 2) \ : (dim) & ~1) +static struct ccs_limit_offset { + u16 lim; + u16 info; +} ccs_limit_offsets[CCS_L_LAST + 1]; + /* * smiapp_module_idents - supported camera modules */ @@ -3166,7 +3172,39 @@ static struct i2c_driver smiapp_i2c_driver = { .id_table = smiapp_id_table, }; -module_i2c_driver(smiapp_i2c_driver); +static int smiapp_module_init(void) +{ + unsigned int i, l; + + for (i = 0, l = 0; ccs_limits[i].size && l < CCS_L_LAST; i++) { + if (!(ccs_limits[i].flags & CCS_L_FL_SAME_REG)) { + ccs_limit_offsets[l + 1].lim = + ALIGN(ccs_limit_offsets[l].lim + + ccs_limits[i].size, + ccs_reg_width(ccs_limits[i + 1].reg)); + ccs_limit_offsets[l].info = i; + l++; + } else { + ccs_limit_offsets[l].lim += ccs_limits[i].size; + } + } + + if (WARN_ON(ccs_limits[i].size)) + return -EINVAL; + + if (WARN_ON(l != CCS_L_LAST)) + return -EINVAL; + + return i2c_register_driver(THIS_MODULE, &smiapp_i2c_driver); +} + +static void smiapp_module_cleanup(void) +{ + i2c_del_driver(&smiapp_i2c_driver); +} + +module_init(smiapp_module_init); +module_exit(smiapp_module_cleanup); MODULE_AUTHOR("Sakari Ailus "); MODULE_DESCRIPTION("Generic SMIA/SMIA++ camera module driver"); -- cgit v1.2.3 From cb50351be662729834e8159cc29af8be35a7c277 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 28 May 2020 11:39:00 +0200 Subject: media: smiapp: Remove macros for defining registers, merge definitions Remove macros for defining new SMIA registers, instead put the register flags to the register definition itself. Also move the register flags to the same file. This is not expected to be updated but rather left there as a reference. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-quirk.c | 2 +- drivers/media/i2c/smiapp/smiapp-reg-defs.h | 1046 +++++++++++++++------------- drivers/media/i2c/smiapp/smiapp-reg.h | 116 --- drivers/media/i2c/smiapp/smiapp.h | 2 +- 4 files changed, 570 insertions(+), 596 deletions(-) delete mode 100644 drivers/media/i2c/smiapp/smiapp-reg.h diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.c b/drivers/media/i2c/smiapp/smiapp-quirk.c index ab96d6067fc3..308ca0b03f5a 100644 --- a/drivers/media/i2c/smiapp/smiapp-quirk.c +++ b/drivers/media/i2c/smiapp/smiapp-quirk.c @@ -14,7 +14,7 @@ static int smiapp_write_8(struct smiapp_sensor *sensor, u16 reg, u8 val) { - return smiapp_write(sensor, SMIAPP_REG_MK_U8(reg), val); + return smiapp_write(sensor, reg, val); } static int smiapp_write_8s(struct smiapp_sensor *sensor, diff --git a/drivers/media/i2c/smiapp/smiapp-reg-defs.h b/drivers/media/i2c/smiapp/smiapp-reg-defs.h index ec574007908b..06b69b1ab55f 100644 --- a/drivers/media/i2c/smiapp/smiapp-reg-defs.h +++ b/drivers/media/i2c/smiapp/smiapp-reg-defs.h @@ -7,483 +7,573 @@ * Copyright (C) 2011--2012 Nokia Corporation * Contact: Sakari Ailus */ -#define SMIAPP_REG_MK_U8(r) (r) -#define SMIAPP_REG_MK_U16(r) (CCS_FL_16BIT | (r)) -#define SMIAPP_REG_MK_U32(r) (CCS_FL_32BIT | (r)) -#define SMIAPP_REG_MK_F32(r) (CCS_FL_FLOAT_IREAL | CCS_FL_32BIT | (r)) +#ifndef __SMIAPP_REG_DEFS_H__ +#define __SMIAPP_REG_DEFS_H__ -#define SMIAPP_REG_U16_MODEL_ID SMIAPP_REG_MK_U16(0x0000) -#define SMIAPP_REG_U8_REVISION_NUMBER_MAJOR SMIAPP_REG_MK_U8(0x0002) -#define SMIAPP_REG_U8_MANUFACTURER_ID SMIAPP_REG_MK_U8(0x0003) -#define SMIAPP_REG_U8_SMIA_VERSION SMIAPP_REG_MK_U8(0x0004) -#define SMIAPP_REG_U8_FRAME_COUNT SMIAPP_REG_MK_U8(0x0005) -#define SMIAPP_REG_U8_PIXEL_ORDER SMIAPP_REG_MK_U8(0x0006) -#define SMIAPP_REG_U16_DATA_PEDESTAL SMIAPP_REG_MK_U16(0x0008) -#define SMIAPP_REG_U8_PIXEL_DEPTH SMIAPP_REG_MK_U8(0x000c) -#define SMIAPP_REG_U8_REVISION_NUMBER_MINOR SMIAPP_REG_MK_U8(0x0010) -#define SMIAPP_REG_U8_SMIAPP_VERSION SMIAPP_REG_MK_U8(0x0011) -#define SMIAPP_REG_U8_MODULE_DATE_YEAR SMIAPP_REG_MK_U8(0x0012) -#define SMIAPP_REG_U8_MODULE_DATE_MONTH SMIAPP_REG_MK_U8(0x0013) -#define SMIAPP_REG_U8_MODULE_DATE_DAY SMIAPP_REG_MK_U8(0x0014) -#define SMIAPP_REG_U8_MODULE_DATE_PHASE SMIAPP_REG_MK_U8(0x0015) -#define SMIAPP_REG_U16_SENSOR_MODEL_ID SMIAPP_REG_MK_U16(0x0016) -#define SMIAPP_REG_U8_SENSOR_REVISION_NUMBER SMIAPP_REG_MK_U8(0x0018) -#define SMIAPP_REG_U8_SENSOR_MANUFACTURER_ID SMIAPP_REG_MK_U8(0x0019) -#define SMIAPP_REG_U8_SENSOR_FIRMWARE_VERSION SMIAPP_REG_MK_U8(0x001a) -#define SMIAPP_REG_U32_SERIAL_NUMBER SMIAPP_REG_MK_U32(0x001c) -#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_TYPE SMIAPP_REG_MK_U8(0x0040) -#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_SUBTYPE SMIAPP_REG_MK_U8(0x0041) -#define SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(n) SMIAPP_REG_MK_U16(0x0042 + ((n) << 1)) /* 0 <= n <= 14 */ -#define SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(n) SMIAPP_REG_MK_U32(0x0060 + ((n) << 2)) /* 0 <= n <= 7 */ -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CAPABILITY SMIAPP_REG_MK_U16(0x0080) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MIN SMIAPP_REG_MK_U16(0x0084) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MAX SMIAPP_REG_MK_U16(0x0086) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_STEP SMIAPP_REG_MK_U16(0x0088) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_TYPE SMIAPP_REG_MK_U16(0x008a) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_M0 SMIAPP_REG_MK_U16(0x008c) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_C0 SMIAPP_REG_MK_U16(0x008e) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_M1 SMIAPP_REG_MK_U16(0x0090) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_C1 SMIAPP_REG_MK_U16(0x0092) -#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_TYPE SMIAPP_REG_MK_U8(0x00c0) -#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_SUBTYPE SMIAPP_REG_MK_U8(0x00c1) -#define SMIAPP_REG_U16_DATA_FORMAT_DESCRIPTOR(n) SMIAPP_REG_MK_U16(0x00c2 + ((n) << 1)) -#define SMIAPP_REG_U8_MODE_SELECT SMIAPP_REG_MK_U8(0x0100) -#define SMIAPP_REG_U8_IMAGE_ORIENTATION SMIAPP_REG_MK_U8(0x0101) -#define SMIAPP_REG_U8_SOFTWARE_RESET SMIAPP_REG_MK_U8(0x0103) -#define SMIAPP_REG_U8_GROUPED_PARAMETER_HOLD SMIAPP_REG_MK_U8(0x0104) -#define SMIAPP_REG_U8_MASK_CORRUPTED_FRAMES SMIAPP_REG_MK_U8(0x0105) -#define SMIAPP_REG_U8_FAST_STANDBY_CTRL SMIAPP_REG_MK_U8(0x0106) -#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL SMIAPP_REG_MK_U8(0x0107) -#define SMIAPP_REG_U8_2ND_CCI_IF_CONTROL SMIAPP_REG_MK_U8(0x0108) -#define SMIAPP_REG_U8_2ND_CCI_ADDRESS_CONTROL SMIAPP_REG_MK_U8(0x0109) -#define SMIAPP_REG_U8_CSI_CHANNEL_IDENTIFIER SMIAPP_REG_MK_U8(0x0110) -#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE SMIAPP_REG_MK_U8(0x0111) -#define SMIAPP_REG_U16_CSI_DATA_FORMAT SMIAPP_REG_MK_U16(0x0112) -#define SMIAPP_REG_U8_CSI_LANE_MODE SMIAPP_REG_MK_U8(0x0114) -#define SMIAPP_REG_U8_CSI2_10_TO_8_DT SMIAPP_REG_MK_U8(0x0115) -#define SMIAPP_REG_U8_CSI2_10_TO_7_DT SMIAPP_REG_MK_U8(0x0116) -#define SMIAPP_REG_U8_CSI2_10_TO_6_DT SMIAPP_REG_MK_U8(0x0117) -#define SMIAPP_REG_U8_CSI2_12_TO_8_DT SMIAPP_REG_MK_U8(0x0118) -#define SMIAPP_REG_U8_CSI2_12_TO_7_DT SMIAPP_REG_MK_U8(0x0119) -#define SMIAPP_REG_U8_CSI2_12_TO_6_DT SMIAPP_REG_MK_U8(0x011a) -#define SMIAPP_REG_U8_CSI2_14_TO_10_DT SMIAPP_REG_MK_U8(0x011b) -#define SMIAPP_REG_U8_CSI2_14_TO_8_DT SMIAPP_REG_MK_U8(0x011c) -#define SMIAPP_REG_U8_CSI2_16_TO_10_DT SMIAPP_REG_MK_U8(0x011d) -#define SMIAPP_REG_U8_CSI2_16_TO_8_DT SMIAPP_REG_MK_U8(0x011e) -#define SMIAPP_REG_U8_GAIN_MODE SMIAPP_REG_MK_U8(0x0120) -#define SMIAPP_REG_U16_VANA_VOLTAGE SMIAPP_REG_MK_U16(0x0130) -#define SMIAPP_REG_U16_VDIG_VOLTAGE SMIAPP_REG_MK_U16(0x0132) -#define SMIAPP_REG_U16_VIO_VOLTAGE SMIAPP_REG_MK_U16(0x0134) -#define SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ SMIAPP_REG_MK_U16(0x0136) -#define SMIAPP_REG_U8_TEMP_SENSOR_CONTROL SMIAPP_REG_MK_U8(0x0138) -#define SMIAPP_REG_U8_TEMP_SENSOR_MODE SMIAPP_REG_MK_U8(0x0139) -#define SMIAPP_REG_U8_TEMP_SENSOR_OUTPUT SMIAPP_REG_MK_U8(0x013a) -#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME SMIAPP_REG_MK_U16(0x0200) -#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME SMIAPP_REG_MK_U16(0x0202) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GLOBAL SMIAPP_REG_MK_U16(0x0204) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENR SMIAPP_REG_MK_U16(0x0206) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_RED SMIAPP_REG_MK_U16(0x0208) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_BLUE SMIAPP_REG_MK_U16(0x020a) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENB SMIAPP_REG_MK_U16(0x020c) -#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENR SMIAPP_REG_MK_U16(0x020e) -#define SMIAPP_REG_U16_DIGITAL_GAIN_RED SMIAPP_REG_MK_U16(0x0210) -#define SMIAPP_REG_U16_DIGITAL_GAIN_BLUE SMIAPP_REG_MK_U16(0x0212) -#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENB SMIAPP_REG_MK_U16(0x0214) -#define SMIAPP_REG_U16_VT_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x0300) -#define SMIAPP_REG_U16_VT_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x0302) -#define SMIAPP_REG_U16_PRE_PLL_CLK_DIV SMIAPP_REG_MK_U16(0x0304) -#define SMIAPP_REG_U16_PLL_MULTIPLIER SMIAPP_REG_MK_U16(0x0306) -#define SMIAPP_REG_U16_OP_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x0308) -#define SMIAPP_REG_U16_OP_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x030a) -#define SMIAPP_REG_U16_FRAME_LENGTH_LINES SMIAPP_REG_MK_U16(0x0340) -#define SMIAPP_REG_U16_LINE_LENGTH_PCK SMIAPP_REG_MK_U16(0x0342) -#define SMIAPP_REG_U16_X_ADDR_START SMIAPP_REG_MK_U16(0x0344) -#define SMIAPP_REG_U16_Y_ADDR_START SMIAPP_REG_MK_U16(0x0346) -#define SMIAPP_REG_U16_X_ADDR_END SMIAPP_REG_MK_U16(0x0348) -#define SMIAPP_REG_U16_Y_ADDR_END SMIAPP_REG_MK_U16(0x034a) -#define SMIAPP_REG_U16_X_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x034c) -#define SMIAPP_REG_U16_Y_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x034e) -#define SMIAPP_REG_U16_X_EVEN_INC SMIAPP_REG_MK_U16(0x0380) -#define SMIAPP_REG_U16_X_ODD_INC SMIAPP_REG_MK_U16(0x0382) -#define SMIAPP_REG_U16_Y_EVEN_INC SMIAPP_REG_MK_U16(0x0384) -#define SMIAPP_REG_U16_Y_ODD_INC SMIAPP_REG_MK_U16(0x0386) -#define SMIAPP_REG_U16_SCALING_MODE SMIAPP_REG_MK_U16(0x0400) -#define SMIAPP_REG_U16_SPATIAL_SAMPLING SMIAPP_REG_MK_U16(0x0402) -#define SMIAPP_REG_U16_SCALE_M SMIAPP_REG_MK_U16(0x0404) -#define SMIAPP_REG_U16_SCALE_N SMIAPP_REG_MK_U16(0x0406) -#define SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET SMIAPP_REG_MK_U16(0x0408) -#define SMIAPP_REG_U16_DIGITAL_CROP_Y_OFFSET SMIAPP_REG_MK_U16(0x040a) -#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_WIDTH SMIAPP_REG_MK_U16(0x040c) -#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_HEIGHT SMIAPP_REG_MK_U16(0x040e) -#define SMIAPP_REG_U16_COMPRESSION_MODE SMIAPP_REG_MK_U16(0x0500) -#define SMIAPP_REG_U16_TEST_PATTERN_MODE SMIAPP_REG_MK_U16(0x0600) -#define SMIAPP_REG_U16_TEST_DATA_RED SMIAPP_REG_MK_U16(0x0602) -#define SMIAPP_REG_U16_TEST_DATA_GREENR SMIAPP_REG_MK_U16(0x0604) -#define SMIAPP_REG_U16_TEST_DATA_BLUE SMIAPP_REG_MK_U16(0x0606) -#define SMIAPP_REG_U16_TEST_DATA_GREENB SMIAPP_REG_MK_U16(0x0608) -#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_WIDTH SMIAPP_REG_MK_U16(0x060a) -#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_POSITION SMIAPP_REG_MK_U16(0x060c) -#define SMIAPP_REG_U16_VERTICAL_CURSOR_WIDTH SMIAPP_REG_MK_U16(0x060e) -#define SMIAPP_REG_U16_VERTICAL_CURSOR_POSITION SMIAPP_REG_MK_U16(0x0610) -#define SMIAPP_REG_U16_FIFO_WATER_MARK_PIXELS SMIAPP_REG_MK_U16(0x0700) -#define SMIAPP_REG_U8_TCLK_POST SMIAPP_REG_MK_U8(0x0800) -#define SMIAPP_REG_U8_THS_PREPARE SMIAPP_REG_MK_U8(0x0801) -#define SMIAPP_REG_U8_THS_ZERO_MIN SMIAPP_REG_MK_U8(0x0802) -#define SMIAPP_REG_U8_THS_TRAIL SMIAPP_REG_MK_U8(0x0803) -#define SMIAPP_REG_U8_TCLK_TRAIL_MIN SMIAPP_REG_MK_U8(0x0804) -#define SMIAPP_REG_U8_TCLK_PREPARE SMIAPP_REG_MK_U8(0x0805) -#define SMIAPP_REG_U8_TCLK_ZERO SMIAPP_REG_MK_U8(0x0806) -#define SMIAPP_REG_U8_TLPX SMIAPP_REG_MK_U8(0x0807) -#define SMIAPP_REG_U8_DPHY_CTRL SMIAPP_REG_MK_U8(0x0808) -#define SMIAPP_REG_U32_REQUESTED_LINK_BIT_RATE_MBPS SMIAPP_REG_MK_U32(0x0820) -#define SMIAPP_REG_U8_BINNING_MODE SMIAPP_REG_MK_U8(0x0900) -#define SMIAPP_REG_U8_BINNING_TYPE SMIAPP_REG_MK_U8(0x0901) -#define SMIAPP_REG_U8_BINNING_WEIGHTING SMIAPP_REG_MK_U8(0x0902) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL SMIAPP_REG_MK_U8(0x0a00) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS SMIAPP_REG_MK_U8(0x0a01) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_PAGE_SELECT SMIAPP_REG_MK_U8(0x0a02) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_0 SMIAPP_REG_MK_U8(0x0a04) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_1 SMIAPP_REG_MK_U8(0x0a05) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_2 SMIAPP_REG_MK_U8(0x0a06) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_3 SMIAPP_REG_MK_U8(0x0a07) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_4 SMIAPP_REG_MK_U8(0x0a08) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_5 SMIAPP_REG_MK_U8(0x0a09) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_12 SMIAPP_REG_MK_U8(0x0a10) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_13 SMIAPP_REG_MK_U8(0x0a11) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_14 SMIAPP_REG_MK_U8(0x0a12) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_15 SMIAPP_REG_MK_U8(0x0a13) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_16 SMIAPP_REG_MK_U8(0x0a14) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_17 SMIAPP_REG_MK_U8(0x0a15) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_18 SMIAPP_REG_MK_U8(0x0a16) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_19 SMIAPP_REG_MK_U8(0x0a17) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_20 SMIAPP_REG_MK_U8(0x0a18) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_21 SMIAPP_REG_MK_U8(0x0a19) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_22 SMIAPP_REG_MK_U8(0x0a1a) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_23 SMIAPP_REG_MK_U8(0x0a1b) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_24 SMIAPP_REG_MK_U8(0x0a1c) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_25 SMIAPP_REG_MK_U8(0x0a1d) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_26 SMIAPP_REG_MK_U8(0x0a1e) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_27 SMIAPP_REG_MK_U8(0x0a1f) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_28 SMIAPP_REG_MK_U8(0x0a20) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_29 SMIAPP_REG_MK_U8(0x0a21) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_30 SMIAPP_REG_MK_U8(0x0a22) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_31 SMIAPP_REG_MK_U8(0x0a23) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_32 SMIAPP_REG_MK_U8(0x0a24) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_33 SMIAPP_REG_MK_U8(0x0a25) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_34 SMIAPP_REG_MK_U8(0x0a26) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_35 SMIAPP_REG_MK_U8(0x0a27) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_36 SMIAPP_REG_MK_U8(0x0a28) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_37 SMIAPP_REG_MK_U8(0x0a29) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_38 SMIAPP_REG_MK_U8(0x0a2a) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_39 SMIAPP_REG_MK_U8(0x0a2b) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_40 SMIAPP_REG_MK_U8(0x0a2c) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_41 SMIAPP_REG_MK_U8(0x0a2d) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_42 SMIAPP_REG_MK_U8(0x0a2e) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_43 SMIAPP_REG_MK_U8(0x0a2f) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_44 SMIAPP_REG_MK_U8(0x0a30) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_45 SMIAPP_REG_MK_U8(0x0a31) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_46 SMIAPP_REG_MK_U8(0x0a32) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_47 SMIAPP_REG_MK_U8(0x0a33) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_48 SMIAPP_REG_MK_U8(0x0a34) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_49 SMIAPP_REG_MK_U8(0x0a35) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_50 SMIAPP_REG_MK_U8(0x0a36) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_51 SMIAPP_REG_MK_U8(0x0a37) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_52 SMIAPP_REG_MK_U8(0x0a38) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_53 SMIAPP_REG_MK_U8(0x0a39) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_54 SMIAPP_REG_MK_U8(0x0a3a) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_55 SMIAPP_REG_MK_U8(0x0a3b) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_56 SMIAPP_REG_MK_U8(0x0a3c) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_57 SMIAPP_REG_MK_U8(0x0a3d) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_58 SMIAPP_REG_MK_U8(0x0a3e) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_59 SMIAPP_REG_MK_U8(0x0a3f) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_60 SMIAPP_REG_MK_U8(0x0a40) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_61 SMIAPP_REG_MK_U8(0x0a41) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_62 SMIAPP_REG_MK_U8(0x0a42) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_63 SMIAPP_REG_MK_U8(0x0a43) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_CTRL SMIAPP_REG_MK_U8(0x0a44) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_STATUS SMIAPP_REG_MK_U8(0x0a45) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_PAGE_SELECT SMIAPP_REG_MK_U8(0x0a46) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_0 SMIAPP_REG_MK_U8(0x0a48) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_1 SMIAPP_REG_MK_U8(0x0a49) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_2 SMIAPP_REG_MK_U8(0x0a4a) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_3 SMIAPP_REG_MK_U8(0x0a4b) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_4 SMIAPP_REG_MK_U8(0x0a4c) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_5 SMIAPP_REG_MK_U8(0x0a4d) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_6 SMIAPP_REG_MK_U8(0x0a4e) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_7 SMIAPP_REG_MK_U8(0x0a4f) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_8 SMIAPP_REG_MK_U8(0x0a50) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_9 SMIAPP_REG_MK_U8(0x0a51) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_10 SMIAPP_REG_MK_U8(0x0a52) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_11 SMIAPP_REG_MK_U8(0x0a53) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_12 SMIAPP_REG_MK_U8(0x0a54) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_13 SMIAPP_REG_MK_U8(0x0a55) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_14 SMIAPP_REG_MK_U8(0x0a56) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_15 SMIAPP_REG_MK_U8(0x0a57) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_16 SMIAPP_REG_MK_U8(0x0a58) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_17 SMIAPP_REG_MK_U8(0x0a59) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_18 SMIAPP_REG_MK_U8(0x0a5a) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_19 SMIAPP_REG_MK_U8(0x0a5b) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_20 SMIAPP_REG_MK_U8(0x0a5c) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_21 SMIAPP_REG_MK_U8(0x0a5d) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_22 SMIAPP_REG_MK_U8(0x0a5e) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_23 SMIAPP_REG_MK_U8(0x0a5f) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_24 SMIAPP_REG_MK_U8(0x0a60) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_25 SMIAPP_REG_MK_U8(0x0a61) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_26 SMIAPP_REG_MK_U8(0x0a62) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_27 SMIAPP_REG_MK_U8(0x0a63) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_28 SMIAPP_REG_MK_U8(0x0a64) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_29 SMIAPP_REG_MK_U8(0x0a65) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_30 SMIAPP_REG_MK_U8(0x0a66) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_31 SMIAPP_REG_MK_U8(0x0a67) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_32 SMIAPP_REG_MK_U8(0x0a68) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_33 SMIAPP_REG_MK_U8(0x0a69) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_34 SMIAPP_REG_MK_U8(0x0a6a) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_35 SMIAPP_REG_MK_U8(0x0a6b) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_36 SMIAPP_REG_MK_U8(0x0a6c) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_37 SMIAPP_REG_MK_U8(0x0a6d) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_38 SMIAPP_REG_MK_U8(0x0a6e) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_39 SMIAPP_REG_MK_U8(0x0a6f) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_40 SMIAPP_REG_MK_U8(0x0a70) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_41 SMIAPP_REG_MK_U8(0x0a71) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_42 SMIAPP_REG_MK_U8(0x0a72) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_43 SMIAPP_REG_MK_U8(0x0a73) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_44 SMIAPP_REG_MK_U8(0x0a74) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_45 SMIAPP_REG_MK_U8(0x0a75) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_46 SMIAPP_REG_MK_U8(0x0a76) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_47 SMIAPP_REG_MK_U8(0x0a77) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_48 SMIAPP_REG_MK_U8(0x0a78) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_49 SMIAPP_REG_MK_U8(0x0a79) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_50 SMIAPP_REG_MK_U8(0x0a7a) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_51 SMIAPP_REG_MK_U8(0x0a7b) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_52 SMIAPP_REG_MK_U8(0x0a7c) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_53 SMIAPP_REG_MK_U8(0x0a7d) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_54 SMIAPP_REG_MK_U8(0x0a7e) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_55 SMIAPP_REG_MK_U8(0x0a7f) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_56 SMIAPP_REG_MK_U8(0x0a80) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_57 SMIAPP_REG_MK_U8(0x0a81) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_58 SMIAPP_REG_MK_U8(0x0a82) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_59 SMIAPP_REG_MK_U8(0x0a83) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_60 SMIAPP_REG_MK_U8(0x0a84) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_61 SMIAPP_REG_MK_U8(0x0a85) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_62 SMIAPP_REG_MK_U8(0x0a86) -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_63 SMIAPP_REG_MK_U8(0x0a87) -#define SMIAPP_REG_U8_SHADING_CORRECTION_ENABLE SMIAPP_REG_MK_U8(0x0b00) -#define SMIAPP_REG_U8_LUMINANCE_CORRECTION_LEVEL SMIAPP_REG_MK_U8(0x0b01) -#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_ENABLE SMIAPP_REG_MK_U8(0x0b02) -#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_WEIGHT SMIAPP_REG_MK_U8(0x0b03) -#define SMIAPP_REG_U8_BLACK_LEVEL_CORRECTION_ENABLE SMIAPP_REG_MK_U8(0x0b04) -#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b05) -#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b06) -#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_WEIGHT SMIAPP_REG_MK_U8(0x0b07) -#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b08) -#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_WEIGHT SMIAPP_REG_MK_U8(0x0b09) -#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b0a) -#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_WEIGHT SMIAPP_REG_MK_U8(0x0b0b) -#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_ENABLE SMIAPP_REG_MK_U8(0x0b0c) -#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_WEIGHT SMIAPP_REG_MK_U8(0x0b0d) -#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b0e) -#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ADJUST SMIAPP_REG_MK_U8(0x0b0f) -#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ADJUST SMIAPP_REG_MK_U8(0x0b10) -#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b11) -#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ADJUST SMIAPP_REG_MK_U8(0x0b12) -#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b13) -#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ADJUST SMIAPP_REG_MK_U8(0x0b14) -#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b15) -#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ADJUST SMIAPP_REG_MK_U8(0x0b16) -#define SMIAPP_REG_U8_EDOF_MODE SMIAPP_REG_MK_U8(0x0b80) -#define SMIAPP_REG_U8_SHARPNESS SMIAPP_REG_MK_U8(0x0b83) -#define SMIAPP_REG_U8_DENOISING SMIAPP_REG_MK_U8(0x0b84) -#define SMIAPP_REG_U8_MODULE_SPECIFIC SMIAPP_REG_MK_U8(0x0b85) -#define SMIAPP_REG_U16_DEPTH_OF_FIELD SMIAPP_REG_MK_U16(0x0b86) -#define SMIAPP_REG_U16_FOCUS_DISTANCE SMIAPP_REG_MK_U16(0x0b88) -#define SMIAPP_REG_U8_ESTIMATION_MODE_CTRL SMIAPP_REG_MK_U8(0x0b8a) -#define SMIAPP_REG_U16_COLOUR_TEMPERATURE SMIAPP_REG_MK_U16(0x0b8c) -#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENR SMIAPP_REG_MK_U16(0x0b8e) -#define SMIAPP_REG_U16_ABSOLUTE_GAIN_RED SMIAPP_REG_MK_U16(0x0b90) -#define SMIAPP_REG_U16_ABSOLUTE_GAIN_BLUE SMIAPP_REG_MK_U16(0x0b92) -#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENB SMIAPP_REG_MK_U16(0x0b94) -#define SMIAPP_REG_U8_ESTIMATION_ZONE_MODE SMIAPP_REG_MK_U8(0x0bc0) -#define SMIAPP_REG_U16_FIXED_ZONE_WEIGHTING SMIAPP_REG_MK_U16(0x0bc2) -#define SMIAPP_REG_U16_CUSTOM_ZONE_X_START SMIAPP_REG_MK_U16(0x0bc4) -#define SMIAPP_REG_U16_CUSTOM_ZONE_Y_START SMIAPP_REG_MK_U16(0x0bc6) -#define SMIAPP_REG_U16_CUSTOM_ZONE_WIDTH SMIAPP_REG_MK_U16(0x0bc8) -#define SMIAPP_REG_U16_CUSTOM_ZONE_HEIGHT SMIAPP_REG_MK_U16(0x0bca) -#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL1 SMIAPP_REG_MK_U8(0x0c00) -#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL2 SMIAPP_REG_MK_U8(0x0c01) -#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_1 SMIAPP_REG_MK_U8(0x0c02) -#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_2 SMIAPP_REG_MK_U8(0x0c03) -#define SMIAPP_REG_U16_TRDY_CTRL SMIAPP_REG_MK_U16(0x0c04) -#define SMIAPP_REG_U16_TRDOUT_CTRL SMIAPP_REG_MK_U16(0x0c06) -#define SMIAPP_REG_U16_TSHUTTER_STROBE_DELAY_CTRL SMIAPP_REG_MK_U16(0x0c08) -#define SMIAPP_REG_U16_TSHUTTER_STROBE_WIDTH_CTRL SMIAPP_REG_MK_U16(0x0c0a) -#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_CTRL SMIAPP_REG_MK_U16(0x0c0c) -#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_CTRL SMIAPP_REG_MK_U16(0x0c0e) -#define SMIAPP_REG_U16_TGRST_INTERVAL_CTRL SMIAPP_REG_MK_U16(0x0c10) -#define SMIAPP_REG_U8_FLASH_STROBE_ADJUSTMENT SMIAPP_REG_MK_U8(0x0c12) -#define SMIAPP_REG_U16_FLASH_STROBE_START_POINT SMIAPP_REG_MK_U16(0x0c14) -#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_RS_CTRL SMIAPP_REG_MK_U16(0x0c16) -#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL SMIAPP_REG_MK_U16(0x0c18) -#define SMIAPP_REG_U8_FLASH_MODE_RS SMIAPP_REG_MK_U8(0x0c1a) -#define SMIAPP_REG_U8_FLASH_TRIGGER_RS SMIAPP_REG_MK_U8(0x0c1b) -#define SMIAPP_REG_U8_FLASH_STATUS SMIAPP_REG_MK_U8(0x0c1c) -#define SMIAPP_REG_U8_SA_STROBE_MODE SMIAPP_REG_MK_U8(0x0c1d) -#define SMIAPP_REG_U16_SA_STROBE_START_POINT SMIAPP_REG_MK_U16(0x0c1e) -#define SMIAPP_REG_U16_TSA_STROBE_DELAY_CTRL SMIAPP_REG_MK_U16(0x0c20) -#define SMIAPP_REG_U16_TSA_STROBE_WIDTH_CTRL SMIAPP_REG_MK_U16(0x0c22) -#define SMIAPP_REG_U8_SA_STROBE_TRIGGER SMIAPP_REG_MK_U8(0x0c24) -#define SMIAPP_REG_U8_SPECIAL_ACTUATOR_STATUS SMIAPP_REG_MK_U8(0x0c25) -#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_RS_CTRL SMIAPP_REG_MK_U16(0x0c26) -#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_RS_CTRL SMIAPP_REG_MK_U16(0x0c28) -#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_RS_CTRL SMIAPP_REG_MK_U8(0x0c2a) -#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_CTRL SMIAPP_REG_MK_U8(0x0c2b) -#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_CTRL SMIAPP_REG_MK_U16(0x0c2c) -#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_CTRL SMIAPP_REG_MK_U16(0x0c2e) -#define SMIAPP_REG_U8_LOW_LEVEL_CTRL SMIAPP_REG_MK_U8(0x0c80) -#define SMIAPP_REG_U16_MAIN_TRIGGER_REF_POINT SMIAPP_REG_MK_U16(0x0c82) -#define SMIAPP_REG_U16_MAIN_TRIGGER_T3 SMIAPP_REG_MK_U16(0x0c84) -#define SMIAPP_REG_U8_MAIN_TRIGGER_COUNT SMIAPP_REG_MK_U8(0x0c86) -#define SMIAPP_REG_U16_PHASE1_TRIGGER_T3 SMIAPP_REG_MK_U16(0x0c88) -#define SMIAPP_REG_U8_PHASE1_TRIGGER_COUNT SMIAPP_REG_MK_U8(0x0c8a) -#define SMIAPP_REG_U16_PHASE2_TRIGGER_T3 SMIAPP_REG_MK_U16(0x0c8c) -#define SMIAPP_REG_U8_PHASE2_TRIGGER_COUNT SMIAPP_REG_MK_U8(0x0c8e) -#define SMIAPP_REG_U8_MECH_SHUTTER_CTRL SMIAPP_REG_MK_U8(0x0d00) -#define SMIAPP_REG_U8_OPERATION_MODE SMIAPP_REG_MK_U8(0x0d01) -#define SMIAPP_REG_U8_ACT_STATE1 SMIAPP_REG_MK_U8(0x0d02) -#define SMIAPP_REG_U8_ACT_STATE2 SMIAPP_REG_MK_U8(0x0d03) -#define SMIAPP_REG_U16_FOCUS_CHANGE SMIAPP_REG_MK_U16(0x0d80) -#define SMIAPP_REG_U16_FOCUS_CHANGE_CONTROL SMIAPP_REG_MK_U16(0x0d82) -#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE1 SMIAPP_REG_MK_U16(0x0d84) -#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE2 SMIAPP_REG_MK_U16(0x0d86) -#define SMIAPP_REG_U8_STROBE_COUNT_PHASE1 SMIAPP_REG_MK_U8(0x0d88) -#define SMIAPP_REG_U8_STROBE_COUNT_PHASE2 SMIAPP_REG_MK_U8(0x0d89) -#define SMIAPP_REG_U8_POSITION SMIAPP_REG_MK_U8(0x0d8a) -#define SMIAPP_REG_U8_BRACKETING_LUT_CONTROL SMIAPP_REG_MK_U8(0x0e00) -#define SMIAPP_REG_U8_BRACKETING_LUT_MODE SMIAPP_REG_MK_U8(0x0e01) -#define SMIAPP_REG_U8_BRACKETING_LUT_ENTRY_CONTROL SMIAPP_REG_MK_U8(0x0e02) -#define SMIAPP_REG_U8_LUT_PARAMETERS_START SMIAPP_REG_MK_U8(0x0e10) -#define SMIAPP_REG_U8_LUT_PARAMETERS_END SMIAPP_REG_MK_U8(0x0eff) -#define SMIAPP_REG_U16_INTEGRATION_TIME_CAPABILITY SMIAPP_REG_MK_U16(0x1000) -#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MIN SMIAPP_REG_MK_U16(0x1004) -#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MAX_MARGIN SMIAPP_REG_MK_U16(0x1006) -#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN SMIAPP_REG_MK_U16(0x1008) -#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN SMIAPP_REG_MK_U16(0x100a) -#define SMIAPP_REG_U16_DIGITAL_GAIN_CAPABILITY SMIAPP_REG_MK_U16(0x1080) -#define SMIAPP_REG_U16_DIGITAL_GAIN_MIN SMIAPP_REG_MK_U16(0x1084) -#define SMIAPP_REG_U16_DIGITAL_GAIN_MAX SMIAPP_REG_MK_U16(0x1086) -#define SMIAPP_REG_U16_DIGITAL_GAIN_STEP_SIZE SMIAPP_REG_MK_U16(0x1088) -#define SMIAPP_REG_F32_MIN_EXT_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1100) -#define SMIAPP_REG_F32_MAX_EXT_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1104) -#define SMIAPP_REG_U16_MIN_PRE_PLL_CLK_DIV SMIAPP_REG_MK_U16(0x1108) -#define SMIAPP_REG_U16_MAX_PRE_PLL_CLK_DIV SMIAPP_REG_MK_U16(0x110a) -#define SMIAPP_REG_F32_MIN_PLL_IP_FREQ_HZ SMIAPP_REG_MK_F32(0x110c) -#define SMIAPP_REG_F32_MAX_PLL_IP_FREQ_HZ SMIAPP_REG_MK_F32(0x1110) -#define SMIAPP_REG_U16_MIN_PLL_MULTIPLIER SMIAPP_REG_MK_U16(0x1114) -#define SMIAPP_REG_U16_MAX_PLL_MULTIPLIER SMIAPP_REG_MK_U16(0x1116) -#define SMIAPP_REG_F32_MIN_PLL_OP_FREQ_HZ SMIAPP_REG_MK_F32(0x1118) -#define SMIAPP_REG_F32_MAX_PLL_OP_FREQ_HZ SMIAPP_REG_MK_F32(0x111c) -#define SMIAPP_REG_U16_MIN_VT_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x1120) -#define SMIAPP_REG_U16_MAX_VT_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x1122) -#define SMIAPP_REG_F32_MIN_VT_SYS_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1124) -#define SMIAPP_REG_F32_MAX_VT_SYS_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1128) -#define SMIAPP_REG_F32_MIN_VT_PIX_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x112c) -#define SMIAPP_REG_F32_MAX_VT_PIX_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1130) -#define SMIAPP_REG_U16_MIN_VT_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x1134) -#define SMIAPP_REG_U16_MAX_VT_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x1136) -#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES SMIAPP_REG_MK_U16(0x1140) -#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES SMIAPP_REG_MK_U16(0x1142) -#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK SMIAPP_REG_MK_U16(0x1144) -#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK SMIAPP_REG_MK_U16(0x1146) -#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK SMIAPP_REG_MK_U16(0x1148) -#define SMIAPP_REG_U16_MIN_FRAME_BLANKING_LINES SMIAPP_REG_MK_U16(0x114a) -#define SMIAPP_REG_U8_MIN_LINE_LENGTH_PCK_STEP_SIZE SMIAPP_REG_MK_U8(0x114c) -#define SMIAPP_REG_U16_MIN_OP_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x1160) -#define SMIAPP_REG_U16_MAX_OP_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x1162) -#define SMIAPP_REG_F32_MIN_OP_SYS_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1164) -#define SMIAPP_REG_F32_MAX_OP_SYS_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1168) -#define SMIAPP_REG_U16_MIN_OP_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x116c) -#define SMIAPP_REG_U16_MAX_OP_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x116e) -#define SMIAPP_REG_F32_MIN_OP_PIX_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1170) -#define SMIAPP_REG_F32_MAX_OP_PIX_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1174) -#define SMIAPP_REG_U16_X_ADDR_MIN SMIAPP_REG_MK_U16(0x1180) -#define SMIAPP_REG_U16_Y_ADDR_MIN SMIAPP_REG_MK_U16(0x1182) -#define SMIAPP_REG_U16_X_ADDR_MAX SMIAPP_REG_MK_U16(0x1184) -#define SMIAPP_REG_U16_Y_ADDR_MAX SMIAPP_REG_MK_U16(0x1186) -#define SMIAPP_REG_U16_MIN_X_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x1188) -#define SMIAPP_REG_U16_MIN_Y_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x118a) -#define SMIAPP_REG_U16_MAX_X_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x118c) -#define SMIAPP_REG_U16_MAX_Y_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x118e) -#define SMIAPP_REG_U16_MIN_EVEN_INC SMIAPP_REG_MK_U16(0x11c0) -#define SMIAPP_REG_U16_MAX_EVEN_INC SMIAPP_REG_MK_U16(0x11c2) -#define SMIAPP_REG_U16_MIN_ODD_INC SMIAPP_REG_MK_U16(0x11c4) -#define SMIAPP_REG_U16_MAX_ODD_INC SMIAPP_REG_MK_U16(0x11c6) -#define SMIAPP_REG_U16_SCALING_CAPABILITY SMIAPP_REG_MK_U16(0x1200) -#define SMIAPP_REG_U16_SCALER_M_MIN SMIAPP_REG_MK_U16(0x1204) -#define SMIAPP_REG_U16_SCALER_M_MAX SMIAPP_REG_MK_U16(0x1206) -#define SMIAPP_REG_U16_SCALER_N_MIN SMIAPP_REG_MK_U16(0x1208) -#define SMIAPP_REG_U16_SCALER_N_MAX SMIAPP_REG_MK_U16(0x120a) -#define SMIAPP_REG_U16_SPATIAL_SAMPLING_CAPABILITY SMIAPP_REG_MK_U16(0x120c) -#define SMIAPP_REG_U8_DIGITAL_CROP_CAPABILITY SMIAPP_REG_MK_U8(0x120e) -#define SMIAPP_REG_U16_COMPRESSION_CAPABILITY SMIAPP_REG_MK_U16(0x1300) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINRED SMIAPP_REG_MK_U16(0x1400) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINRED SMIAPP_REG_MK_U16(0x1402) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINRED SMIAPP_REG_MK_U16(0x1404) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINGREEN SMIAPP_REG_MK_U16(0x1406) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINGREEN SMIAPP_REG_MK_U16(0x1408) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINGREEN SMIAPP_REG_MK_U16(0x140a) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINBLUE SMIAPP_REG_MK_U16(0x140c) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINBLUE SMIAPP_REG_MK_U16(0x140e) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINBLUE SMIAPP_REG_MK_U16(0x1410) -#define SMIAPP_REG_U16_FIFO_SIZE_PIXELS SMIAPP_REG_MK_U16(0x1500) -#define SMIAPP_REG_U8_FIFO_SUPPORT_CAPABILITY SMIAPP_REG_MK_U8(0x1502) -#define SMIAPP_REG_U8_DPHY_CTRL_CAPABILITY SMIAPP_REG_MK_U8(0x1600) -#define SMIAPP_REG_U8_CSI_LANE_MODE_CAPABILITY SMIAPP_REG_MK_U8(0x1601) -#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE_CAPABILITY SMIAPP_REG_MK_U8(0x1602) -#define SMIAPP_REG_U8_FAST_STANDBY_CAPABILITY SMIAPP_REG_MK_U8(0x1603) -#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL_CAPABILITY SMIAPP_REG_MK_U8(0x1604) -#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS SMIAPP_REG_MK_U32(0x1608) -#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS SMIAPP_REG_MK_U32(0x160c) -#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS SMIAPP_REG_MK_U32(0x1610) -#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS SMIAPP_REG_MK_U32(0x1614) -#define SMIAPP_REG_U8_TEMP_SENSOR_CAPABILITY SMIAPP_REG_MK_U8(0x1618) -#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES_BIN SMIAPP_REG_MK_U16(0x1700) -#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES_BIN SMIAPP_REG_MK_U16(0x1702) -#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK_BIN SMIAPP_REG_MK_U16(0x1704) -#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK_BIN SMIAPP_REG_MK_U16(0x1706) -#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK_BIN SMIAPP_REG_MK_U16(0x1708) -#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN_BIN SMIAPP_REG_MK_U16(0x170a) -#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN SMIAPP_REG_MK_U16(0x170c) -#define SMIAPP_REG_U8_BINNING_CAPABILITY SMIAPP_REG_MK_U8(0x1710) -#define SMIAPP_REG_U8_BINNING_WEIGHTING_CAPABILITY SMIAPP_REG_MK_U8(0x1711) -#define SMIAPP_REG_U8_BINNING_SUBTYPES SMIAPP_REG_MK_U8(0x1712) -#define SMIAPP_REG_U8_BINNING_TYPE_n(n) SMIAPP_REG_MK_U8(0x1713 + (n)) /* 1 <= n <= 237 */ -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_CAPABILITY SMIAPP_REG_MK_U8(0x1800) -#define SMIAPP_REG_U8_SHADING_CORRECTION_CAPABILITY SMIAPP_REG_MK_U8(0x1900) -#define SMIAPP_REG_U8_GREEN_IMBALANCE_CAPABILITY SMIAPP_REG_MK_U8(0x1901) -#define SMIAPP_REG_U8_BLACK_LEVEL_CAPABILITY SMIAPP_REG_MK_U8(0x1902) -#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_CAPABILITY SMIAPP_REG_MK_U8(0x1903) -#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY SMIAPP_REG_MK_U16(0x1904) -#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY_2 SMIAPP_REG_MK_U16(0x1906) -#define SMIAPP_REG_U8_EDOF_CAPABILITY SMIAPP_REG_MK_U8(0x1980) -#define SMIAPP_REG_U8_ESTIMATION_FRAMES SMIAPP_REG_MK_U8(0x1981) -#define SMIAPP_REG_U8_SUPPORTS_SHARPNESS_ADJ SMIAPP_REG_MK_U8(0x1982) -#define SMIAPP_REG_U8_SUPPORTS_DENOISING_ADJ SMIAPP_REG_MK_U8(0x1983) -#define SMIAPP_REG_U8_SUPPORTS_MODULE_SPECIFIC_ADJ SMIAPP_REG_MK_U8(0x1984) -#define SMIAPP_REG_U8_SUPPORTS_DEPTH_OF_FIELD_ADJ SMIAPP_REG_MK_U8(0x1985) -#define SMIAPP_REG_U8_SUPPORTS_FOCUS_DISTANCE_ADJ SMIAPP_REG_MK_U8(0x1986) -#define SMIAPP_REG_U8_COLOUR_FEEDBACK_CAPABILITY SMIAPP_REG_MK_U8(0x1987) -#define SMIAPP_REG_U8_EDOF_SUPPORT_AB_NXM SMIAPP_REG_MK_U8(0x1988) -#define SMIAPP_REG_U8_ESTIMATION_MODE_CAPABILITY SMIAPP_REG_MK_U8(0x19c0) -#define SMIAPP_REG_U8_ESTIMATION_ZONE_CAPABILITY SMIAPP_REG_MK_U8(0x19c1) -#define SMIAPP_REG_U16_EST_DEPTH_OF_FIELD SMIAPP_REG_MK_U16(0x19c2) -#define SMIAPP_REG_U16_EST_FOCUS_DISTANCE SMIAPP_REG_MK_U16(0x19c4) -#define SMIAPP_REG_U16_CAPABILITY_TRDY_MIN SMIAPP_REG_MK_U16(0x1a00) -#define SMIAPP_REG_U8_FLASH_MODE_CAPABILITY SMIAPP_REG_MK_U8(0x1a02) -#define SMIAPP_REG_U16_MECH_SHUT_AND_ACT_START_ADDR SMIAPP_REG_MK_U16(0x1b02) -#define SMIAPP_REG_U8_ACTUATOR_CAPABILITY SMIAPP_REG_MK_U8(0x1b04) -#define SMIAPP_REG_U16_ACTUATOR_TYPE SMIAPP_REG_MK_U16(0x1b40) -#define SMIAPP_REG_U8_AF_DEVICE_ADDRESS SMIAPP_REG_MK_U8(0x1b42) -#define SMIAPP_REG_U16_FOCUS_CHANGE_ADDRESS SMIAPP_REG_MK_U16(0x1b44) -#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_1 SMIAPP_REG_MK_U8(0x1c00) -#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_2 SMIAPP_REG_MK_U8(0x1c01) -#define SMIAPP_REG_U8_BRACKETING_LUT_SIZE SMIAPP_REG_MK_U8(0x1c02) +/* Register addresses */ +#define SMIAPP_REG_U16_MODEL_ID (0x0000 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_REVISION_NUMBER_MAJOR 0x0002 +#define SMIAPP_REG_U8_MANUFACTURER_ID 0x0003 +#define SMIAPP_REG_U8_SMIA_VERSION 0x0004 +#define SMIAPP_REG_U8_FRAME_COUNT 0x0005 +#define SMIAPP_REG_U8_PIXEL_ORDER 0x0006 +#define SMIAPP_REG_U16_DATA_PEDESTAL (0x0008 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_PIXEL_DEPTH 0x000c +#define SMIAPP_REG_U8_REVISION_NUMBER_MINOR 0x0010 +#define SMIAPP_REG_U8_SMIAPP_VERSION 0x0011 +#define SMIAPP_REG_U8_MODULE_DATE_YEAR 0x0012 +#define SMIAPP_REG_U8_MODULE_DATE_MONTH 0x0013 +#define SMIAPP_REG_U8_MODULE_DATE_DAY 0x0014 +#define SMIAPP_REG_U8_MODULE_DATE_PHASE 0x0015 +#define SMIAPP_REG_U16_SENSOR_MODEL_ID (0x0016 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_SENSOR_REVISION_NUMBER 0x0018 +#define SMIAPP_REG_U8_SENSOR_MANUFACTURER_ID 0x0019 +#define SMIAPP_REG_U8_SENSOR_FIRMWARE_VERSION 0x001a +#define SMIAPP_REG_U32_SERIAL_NUMBER (0x001c | CCS_FL_32BIT) +#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_TYPE 0x0040 +#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_SUBTYPE 0x0041 +#define SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(n) ((0x0042 + ((n) << 1)) | CCS_FL_16BIT) /* 0 <= n <= 14 */ +#define SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(n) ((0x0060 + ((n) << 2)) | CCS_FL_32BIT) /* 0 <= n <= 7 */ +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CAPABILITY (0x0080 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MIN (0x0084 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MAX (0x0086 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_STEP (0x0088 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_TYPE (0x008a | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_M0 (0x008c | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_C0 (0x008e | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_M1 (0x0090 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_C1 (0x0092 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_TYPE 0x00c0 +#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_SUBTYPE 0x00c1 +#define SMIAPP_REG_U16_DATA_FORMAT_DESCRIPTOR(n) ((0x00c2 + ((n) << 1)) | CCS_FL_16BIT) +#define SMIAPP_REG_U8_MODE_SELECT 0x0100 +#define SMIAPP_REG_U8_IMAGE_ORIENTATION 0x0101 +#define SMIAPP_REG_U8_SOFTWARE_RESET 0x0103 +#define SMIAPP_REG_U8_GROUPED_PARAMETER_HOLD 0x0104 +#define SMIAPP_REG_U8_MASK_CORRUPTED_FRAMES 0x0105 +#define SMIAPP_REG_U8_FAST_STANDBY_CTRL 0x0106 +#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL 0x0107 +#define SMIAPP_REG_U8_2ND_CCI_IF_CONTROL 0x0108 +#define SMIAPP_REG_U8_2ND_CCI_ADDRESS_CONTROL 0x0109 +#define SMIAPP_REG_U8_CSI_CHANNEL_IDENTIFIER 0x0110 +#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE 0x0111 +#define SMIAPP_REG_U16_CSI_DATA_FORMAT (0x0112 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_CSI_LANE_MODE 0x0114 +#define SMIAPP_REG_U8_CSI2_10_TO_8_DT 0x0115 +#define SMIAPP_REG_U8_CSI2_10_TO_7_DT 0x0116 +#define SMIAPP_REG_U8_CSI2_10_TO_6_DT 0x0117 +#define SMIAPP_REG_U8_CSI2_12_TO_8_DT 0x0118 +#define SMIAPP_REG_U8_CSI2_12_TO_7_DT 0x0119 +#define SMIAPP_REG_U8_CSI2_12_TO_6_DT 0x011a +#define SMIAPP_REG_U8_CSI2_14_TO_10_DT 0x011b +#define SMIAPP_REG_U8_CSI2_14_TO_8_DT 0x011c +#define SMIAPP_REG_U8_CSI2_16_TO_10_DT 0x011d +#define SMIAPP_REG_U8_CSI2_16_TO_8_DT 0x011e +#define SMIAPP_REG_U8_GAIN_MODE 0x0120 +#define SMIAPP_REG_U16_VANA_VOLTAGE (0x0130 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_VDIG_VOLTAGE (0x0132 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_VIO_VOLTAGE (0x0134 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ (0x0136 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_TEMP_SENSOR_CONTROL 0x0138 +#define SMIAPP_REG_U8_TEMP_SENSOR_MODE 0x0139 +#define SMIAPP_REG_U8_TEMP_SENSOR_OUTPUT 0x013a +#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME (0x0200 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME (0x0202 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GLOBAL (0x0204 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENR (0x0206 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_RED (0x0208 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_BLUE (0x020a | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENB (0x020c | CCS_FL_16BIT) +#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENR (0x020e | CCS_FL_16BIT) +#define SMIAPP_REG_U16_DIGITAL_GAIN_RED (0x0210 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_DIGITAL_GAIN_BLUE (0x0212 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENB (0x0214 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_VT_PIX_CLK_DIV (0x0300 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_VT_SYS_CLK_DIV (0x0302 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_PRE_PLL_CLK_DIV (0x0304 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_PLL_MULTIPLIER (0x0306 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_OP_PIX_CLK_DIV (0x0308 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_OP_SYS_CLK_DIV (0x030a | CCS_FL_16BIT) +#define SMIAPP_REG_U16_FRAME_LENGTH_LINES (0x0340 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_LINE_LENGTH_PCK (0x0342 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_X_ADDR_START (0x0344 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_Y_ADDR_START (0x0346 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_X_ADDR_END (0x0348 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_Y_ADDR_END (0x034a | CCS_FL_16BIT) +#define SMIAPP_REG_U16_X_OUTPUT_SIZE (0x034c | CCS_FL_16BIT) +#define SMIAPP_REG_U16_Y_OUTPUT_SIZE (0x034e | CCS_FL_16BIT) +#define SMIAPP_REG_U16_X_EVEN_INC (0x0380 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_X_ODD_INC (0x0382 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_Y_EVEN_INC (0x0384 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_Y_ODD_INC (0x0386 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_SCALING_MODE (0x0400 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_SPATIAL_SAMPLING (0x0402 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_SCALE_M (0x0404 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_SCALE_N (0x0406 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET (0x0408 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_DIGITAL_CROP_Y_OFFSET (0x040a | CCS_FL_16BIT) +#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_WIDTH (0x040c | CCS_FL_16BIT) +#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_HEIGHT (0x040e | CCS_FL_16BIT) +#define SMIAPP_REG_U16_COMPRESSION_MODE (0x0500 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TEST_PATTERN_MODE (0x0600 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TEST_DATA_RED (0x0602 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TEST_DATA_GREENR (0x0604 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TEST_DATA_BLUE (0x0606 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TEST_DATA_GREENB (0x0608 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_WIDTH (0x060a | CCS_FL_16BIT) +#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_POSITION (0x060c | CCS_FL_16BIT) +#define SMIAPP_REG_U16_VERTICAL_CURSOR_WIDTH (0x060e | CCS_FL_16BIT) +#define SMIAPP_REG_U16_VERTICAL_CURSOR_POSITION (0x0610 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_FIFO_WATER_MARK_PIXELS (0x0700 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_TCLK_POST 0x0800 +#define SMIAPP_REG_U8_THS_PREPARE 0x0801 +#define SMIAPP_REG_U8_THS_ZERO_MIN 0x0802 +#define SMIAPP_REG_U8_THS_TRAIL 0x0803 +#define SMIAPP_REG_U8_TCLK_TRAIL_MIN 0x0804 +#define SMIAPP_REG_U8_TCLK_PREPARE 0x0805 +#define SMIAPP_REG_U8_TCLK_ZERO 0x0806 +#define SMIAPP_REG_U8_TLPX 0x0807 +#define SMIAPP_REG_U8_DPHY_CTRL 0x0808 +#define SMIAPP_REG_U32_REQUESTED_LINK_BIT_RATE_MBPS (0x0820 | CCS_FL_32BIT) +#define SMIAPP_REG_U8_BINNING_MODE 0x0900 +#define SMIAPP_REG_U8_BINNING_TYPE 0x0901 +#define SMIAPP_REG_U8_BINNING_WEIGHTING 0x0902 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL 0x0a00 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS 0x0a01 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_PAGE_SELECT 0x0a02 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_0 0x0a04 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_1 0x0a05 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_2 0x0a06 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_3 0x0a07 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_4 0x0a08 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_5 0x0a09 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_12 0x0a10 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_13 0x0a11 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_14 0x0a12 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_15 0x0a13 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_16 0x0a14 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_17 0x0a15 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_18 0x0a16 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_19 0x0a17 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_20 0x0a18 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_21 0x0a19 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_22 0x0a1a +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_23 0x0a1b +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_24 0x0a1c +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_25 0x0a1d +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_26 0x0a1e +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_27 0x0a1f +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_28 0x0a20 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_29 0x0a21 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_30 0x0a22 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_31 0x0a23 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_32 0x0a24 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_33 0x0a25 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_34 0x0a26 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_35 0x0a27 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_36 0x0a28 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_37 0x0a29 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_38 0x0a2a +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_39 0x0a2b +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_40 0x0a2c +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_41 0x0a2d +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_42 0x0a2e +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_43 0x0a2f +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_44 0x0a30 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_45 0x0a31 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_46 0x0a32 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_47 0x0a33 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_48 0x0a34 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_49 0x0a35 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_50 0x0a36 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_51 0x0a37 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_52 0x0a38 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_53 0x0a39 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_54 0x0a3a +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_55 0x0a3b +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_56 0x0a3c +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_57 0x0a3d +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_58 0x0a3e +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_59 0x0a3f +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_60 0x0a40 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_61 0x0a41 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_62 0x0a42 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_63 0x0a43 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_CTRL 0x0a44 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_STATUS 0x0a45 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_PAGE_SELECT 0x0a46 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_0 0x0a48 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_1 0x0a49 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_2 0x0a4a +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_3 0x0a4b +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_4 0x0a4c +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_5 0x0a4d +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_6 0x0a4e +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_7 0x0a4f +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_8 0x0a50 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_9 0x0a51 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_10 0x0a52 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_11 0x0a53 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_12 0x0a54 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_13 0x0a55 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_14 0x0a56 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_15 0x0a57 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_16 0x0a58 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_17 0x0a59 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_18 0x0a5a +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_19 0x0a5b +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_20 0x0a5c +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_21 0x0a5d +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_22 0x0a5e +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_23 0x0a5f +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_24 0x0a60 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_25 0x0a61 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_26 0x0a62 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_27 0x0a63 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_28 0x0a64 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_29 0x0a65 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_30 0x0a66 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_31 0x0a67 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_32 0x0a68 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_33 0x0a69 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_34 0x0a6a +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_35 0x0a6b +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_36 0x0a6c +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_37 0x0a6d +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_38 0x0a6e +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_39 0x0a6f +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_40 0x0a70 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_41 0x0a71 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_42 0x0a72 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_43 0x0a73 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_44 0x0a74 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_45 0x0a75 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_46 0x0a76 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_47 0x0a77 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_48 0x0a78 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_49 0x0a79 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_50 0x0a7a +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_51 0x0a7b +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_52 0x0a7c +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_53 0x0a7d +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_54 0x0a7e +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_55 0x0a7f +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_56 0x0a80 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_57 0x0a81 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_58 0x0a82 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_59 0x0a83 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_60 0x0a84 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_61 0x0a85 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_62 0x0a86 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_63 0x0a87 +#define SMIAPP_REG_U8_SHADING_CORRECTION_ENABLE 0x0b00 +#define SMIAPP_REG_U8_LUMINANCE_CORRECTION_LEVEL 0x0b01 +#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_ENABLE 0x0b02 +#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_WEIGHT 0x0b03 +#define SMIAPP_REG_U8_BLACK_LEVEL_CORRECTION_ENABLE 0x0b04 +#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ENABLE 0x0b05 +#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_ENABLE 0x0b06 +#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_WEIGHT 0x0b07 +#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_ENABLE 0x0b08 +#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_WEIGHT 0x0b09 +#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_ENABLE 0x0b0a +#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_WEIGHT 0x0b0b +#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_ENABLE 0x0b0c +#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_WEIGHT 0x0b0d +#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ENABLE 0x0b0e +#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ADJUST 0x0b0f +#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ADJUST 0x0b10 +#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ENABLE 0x0b11 +#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ADJUST 0x0b12 +#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ENABLE 0x0b13 +#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ADJUST 0x0b14 +#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ENABLE 0x0b15 +#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ADJUST 0x0b16 +#define SMIAPP_REG_U8_EDOF_MODE 0x0b80 +#define SMIAPP_REG_U8_SHARPNESS 0x0b83 +#define SMIAPP_REG_U8_DENOISING 0x0b84 +#define SMIAPP_REG_U8_MODULE_SPECIFIC 0x0b85 +#define SMIAPP_REG_U16_DEPTH_OF_FIELD (0x0b86 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_FOCUS_DISTANCE (0x0b88 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_ESTIMATION_MODE_CTRL 0x0b8a +#define SMIAPP_REG_U16_COLOUR_TEMPERATURE (0x0b8c | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENR (0x0b8e | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ABSOLUTE_GAIN_RED (0x0b90 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ABSOLUTE_GAIN_BLUE (0x0b92 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENB (0x0b94 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_ESTIMATION_ZONE_MODE 0x0bc0 +#define SMIAPP_REG_U16_FIXED_ZONE_WEIGHTING (0x0bc2 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_CUSTOM_ZONE_X_START (0x0bc4 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_CUSTOM_ZONE_Y_START (0x0bc6 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_CUSTOM_ZONE_WIDTH (0x0bc8 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_CUSTOM_ZONE_HEIGHT (0x0bca | CCS_FL_16BIT) +#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL1 0x0c00 +#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL2 0x0c01 +#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_1 0x0c02 +#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_2 0x0c03 +#define SMIAPP_REG_U16_TRDY_CTRL (0x0c04 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TRDOUT_CTRL (0x0c06 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TSHUTTER_STROBE_DELAY_CTRL (0x0c08 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TSHUTTER_STROBE_WIDTH_CTRL (0x0c0a | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_CTRL (0x0c0c | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_CTRL (0x0c0e | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TGRST_INTERVAL_CTRL (0x0c10 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_FLASH_STROBE_ADJUSTMENT 0x0c12 +#define SMIAPP_REG_U16_FLASH_STROBE_START_POINT (0x0c14 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_RS_CTRL (0x0c16 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL (0x0c18 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_FLASH_MODE_RS 0x0c1a +#define SMIAPP_REG_U8_FLASH_TRIGGER_RS 0x0c1b +#define SMIAPP_REG_U8_FLASH_STATUS 0x0c1c +#define SMIAPP_REG_U8_SA_STROBE_MODE 0x0c1d +#define SMIAPP_REG_U16_SA_STROBE_START_POINT (0x0c1e | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TSA_STROBE_DELAY_CTRL (0x0c20 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TSA_STROBE_WIDTH_CTRL (0x0c22 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_SA_STROBE_TRIGGER 0x0c24 +#define SMIAPP_REG_U8_SPECIAL_ACTUATOR_STATUS 0x0c25 +#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_RS_CTRL (0x0c26 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_RS_CTRL (0x0c28 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_RS_CTRL 0x0c2a +#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_CTRL 0x0c2b +#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_CTRL (0x0c2c | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_CTRL (0x0c2e | CCS_FL_16BIT) +#define SMIAPP_REG_U8_LOW_LEVEL_CTRL 0x0c80 +#define SMIAPP_REG_U16_MAIN_TRIGGER_REF_POINT (0x0c82 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAIN_TRIGGER_T3 (0x0c84 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_MAIN_TRIGGER_COUNT 0x0c86 +#define SMIAPP_REG_U16_PHASE1_TRIGGER_T3 (0x0c88 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_PHASE1_TRIGGER_COUNT 0x0c8a +#define SMIAPP_REG_U16_PHASE2_TRIGGER_T3 (0x0c8c | CCS_FL_16BIT) +#define SMIAPP_REG_U8_PHASE2_TRIGGER_COUNT 0x0c8e +#define SMIAPP_REG_U8_MECH_SHUTTER_CTRL 0x0d00 +#define SMIAPP_REG_U8_OPERATION_MODE 0x0d01 +#define SMIAPP_REG_U8_ACT_STATE1 0x0d02 +#define SMIAPP_REG_U8_ACT_STATE2 0x0d03 +#define SMIAPP_REG_U16_FOCUS_CHANGE (0x0d80 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_FOCUS_CHANGE_CONTROL (0x0d82 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE1 (0x0d84 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE2 (0x0d86 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_STROBE_COUNT_PHASE1 0x0d88 +#define SMIAPP_REG_U8_STROBE_COUNT_PHASE2 0x0d89 +#define SMIAPP_REG_U8_POSITION 0x0d8a +#define SMIAPP_REG_U8_BRACKETING_LUT_CONTROL 0x0e00 +#define SMIAPP_REG_U8_BRACKETING_LUT_MODE 0x0e01 +#define SMIAPP_REG_U8_BRACKETING_LUT_ENTRY_CONTROL 0x0e02 +#define SMIAPP_REG_U8_LUT_PARAMETERS_START 0x0e10 +#define SMIAPP_REG_U8_LUT_PARAMETERS_END 0x0eff +#define SMIAPP_REG_U16_INTEGRATION_TIME_CAPABILITY (0x1000 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MIN (0x1004 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MAX_MARGIN (0x1006 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN (0x1008 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN (0x100a | CCS_FL_16BIT) +#define SMIAPP_REG_U16_DIGITAL_GAIN_CAPABILITY (0x1080 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_DIGITAL_GAIN_MIN (0x1084 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_DIGITAL_GAIN_MAX (0x1086 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_DIGITAL_GAIN_STEP_SIZE (0x1088 | CCS_FL_16BIT) +#define SMIAPP_REG_F32_MIN_EXT_CLK_FREQ_HZ (0x1100 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_F32_MAX_EXT_CLK_FREQ_HZ (0x1104 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_U16_MIN_PRE_PLL_CLK_DIV (0x1108 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_PRE_PLL_CLK_DIV (0x110a | CCS_FL_16BIT) +#define SMIAPP_REG_F32_MIN_PLL_IP_FREQ_HZ (0x110c | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_F32_MAX_PLL_IP_FREQ_HZ (0x1110 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_U16_MIN_PLL_MULTIPLIER (0x1114 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_PLL_MULTIPLIER (0x1116 | CCS_FL_16BIT) +#define SMIAPP_REG_F32_MIN_PLL_OP_FREQ_HZ (0x1118 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_F32_MAX_PLL_OP_FREQ_HZ (0x111c | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_U16_MIN_VT_SYS_CLK_DIV (0x1120 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_VT_SYS_CLK_DIV (0x1122 | CCS_FL_16BIT) +#define SMIAPP_REG_F32_MIN_VT_SYS_CLK_FREQ_HZ (0x1124 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_F32_MAX_VT_SYS_CLK_FREQ_HZ (0x1128 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_F32_MIN_VT_PIX_CLK_FREQ_HZ (0x112c | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_F32_MAX_VT_PIX_CLK_FREQ_HZ (0x1130 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_U16_MIN_VT_PIX_CLK_DIV (0x1134 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_VT_PIX_CLK_DIV (0x1136 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES (0x1140 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES (0x1142 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK (0x1144 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK (0x1146 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK (0x1148 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MIN_FRAME_BLANKING_LINES (0x114a | CCS_FL_16BIT) +#define SMIAPP_REG_U8_MIN_LINE_LENGTH_PCK_STEP_SIZE 0x114c +#define SMIAPP_REG_U16_MIN_OP_SYS_CLK_DIV (0x1160 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_OP_SYS_CLK_DIV (0x1162 | CCS_FL_16BIT) +#define SMIAPP_REG_F32_MIN_OP_SYS_CLK_FREQ_HZ (0x1164 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_F32_MAX_OP_SYS_CLK_FREQ_HZ (0x1168 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_U16_MIN_OP_PIX_CLK_DIV (0x116c | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_OP_PIX_CLK_DIV (0x116e | CCS_FL_16BIT) +#define SMIAPP_REG_F32_MIN_OP_PIX_CLK_FREQ_HZ (0x1170 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_F32_MAX_OP_PIX_CLK_FREQ_HZ (0x1174 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_U16_X_ADDR_MIN (0x1180 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_Y_ADDR_MIN (0x1182 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_X_ADDR_MAX (0x1184 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_Y_ADDR_MAX (0x1186 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MIN_X_OUTPUT_SIZE (0x1188 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MIN_Y_OUTPUT_SIZE (0x118a | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_X_OUTPUT_SIZE (0x118c | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_Y_OUTPUT_SIZE (0x118e | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MIN_EVEN_INC (0x11c0 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_EVEN_INC (0x11c2 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MIN_ODD_INC (0x11c4 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_ODD_INC (0x11c6 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_SCALING_CAPABILITY (0x1200 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_SCALER_M_MIN (0x1204 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_SCALER_M_MAX (0x1206 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_SCALER_N_MIN (0x1208 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_SCALER_N_MAX (0x120a | CCS_FL_16BIT) +#define SMIAPP_REG_U16_SPATIAL_SAMPLING_CAPABILITY (0x120c | CCS_FL_16BIT) +#define SMIAPP_REG_U8_DIGITAL_CROP_CAPABILITY 0x120e +#define SMIAPP_REG_U16_COMPRESSION_CAPABILITY (0x1300 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINRED (0x1400 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINRED (0x1402 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINRED (0x1404 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINGREEN (0x1406 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINGREEN (0x1408 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINGREEN (0x140a | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINBLUE (0x140c | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINBLUE (0x140e | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINBLUE (0x1410 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_FIFO_SIZE_PIXELS (0x1500 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_FIFO_SUPPORT_CAPABILITY 0x1502 +#define SMIAPP_REG_U8_DPHY_CTRL_CAPABILITY 0x1600 +#define SMIAPP_REG_U8_CSI_LANE_MODE_CAPABILITY 0x1601 +#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE_CAPABILITY 0x1602 +#define SMIAPP_REG_U8_FAST_STANDBY_CAPABILITY 0x1603 +#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL_CAPABILITY 0x1604 +#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS (0x1608 | CCS_FL_32BIT) +#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS (0x160c | CCS_FL_32BIT) +#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS (0x1610 | CCS_FL_32BIT) +#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS (0x1614 | CCS_FL_32BIT) +#define SMIAPP_REG_U8_TEMP_SENSOR_CAPABILITY 0x1618 +#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES_BIN (0x1700 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES_BIN (0x1702 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK_BIN (0x1704 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK_BIN (0x1706 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK_BIN (0x1708 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN_BIN (0x170a | CCS_FL_16BIT) +#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN (0x170c | CCS_FL_16BIT) +#define SMIAPP_REG_U8_BINNING_CAPABILITY 0x1710 +#define SMIAPP_REG_U8_BINNING_WEIGHTING_CAPABILITY 0x1711 +#define SMIAPP_REG_U8_BINNING_SUBTYPES 0x1712 +#define SMIAPP_REG_U8_BINNING_TYPE_n(n) (0x1713 + (n)) /* 1 <= n <= 237 */ +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_CAPABILITY 0x1800 +#define SMIAPP_REG_U8_SHADING_CORRECTION_CAPABILITY 0x1900 +#define SMIAPP_REG_U8_GREEN_IMBALANCE_CAPABILITY 0x1901 +#define SMIAPP_REG_U8_BLACK_LEVEL_CAPABILITY 0x1902 +#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_CAPABILITY 0x1903 +#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY (0x1904 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY_2 (0x1906 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_EDOF_CAPABILITY 0x1980 +#define SMIAPP_REG_U8_ESTIMATION_FRAMES 0x1981 +#define SMIAPP_REG_U8_SUPPORTS_SHARPNESS_ADJ 0x1982 +#define SMIAPP_REG_U8_SUPPORTS_DENOISING_ADJ 0x1983 +#define SMIAPP_REG_U8_SUPPORTS_MODULE_SPECIFIC_ADJ 0x1984 +#define SMIAPP_REG_U8_SUPPORTS_DEPTH_OF_FIELD_ADJ 0x1985 +#define SMIAPP_REG_U8_SUPPORTS_FOCUS_DISTANCE_ADJ 0x1986 +#define SMIAPP_REG_U8_COLOUR_FEEDBACK_CAPABILITY 0x1987 +#define SMIAPP_REG_U8_EDOF_SUPPORT_AB_NXM 0x1988 +#define SMIAPP_REG_U8_ESTIMATION_MODE_CAPABILITY 0x19c0 +#define SMIAPP_REG_U8_ESTIMATION_ZONE_CAPABILITY 0x19c1 +#define SMIAPP_REG_U16_EST_DEPTH_OF_FIELD (0x19c2 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_EST_FOCUS_DISTANCE (0x19c4 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_CAPABILITY_TRDY_MIN (0x1a00 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_FLASH_MODE_CAPABILITY 0x1a02 +#define SMIAPP_REG_U16_MECH_SHUT_AND_ACT_START_ADDR (0x1b02 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_ACTUATOR_CAPABILITY 0x1b04 +#define SMIAPP_REG_U16_ACTUATOR_TYPE (0x1b40 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_AF_DEVICE_ADDRESS 0x1b42 +#define SMIAPP_REG_U16_FOCUS_CHANGE_ADDRESS (0x1b44 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_1 0x1c00 +#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_2 0x1c01 +#define SMIAPP_REG_U8_BRACKETING_LUT_SIZE 0x1c02 + +/* Register bit definitions */ +#define SMIAPP_IMAGE_ORIENTATION_HFLIP BIT(0) +#define SMIAPP_IMAGE_ORIENTATION_VFLIP BIT(1) + +#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_EN BIT(0) +#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_WR_EN BIT(1) +#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_ERR_CLEAR BIT(2) +#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY BIT(0) +#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_WR_READY BIT(1) +#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_EDATA BIT(2) +#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_EUSAGE BIT(3) + +#define SMIAPP_DATA_TRANSFER_IF_CAPABILITY_SUPPORTED BIT(0) +#define SMIAPP_DATA_TRANSFER_IF_CAPABILITY_POLL BIT(2) + +#define SMIAPP_SOFTWARE_RESET BIT(0) + +#define SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE BIT(0) +#define SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE BIT(1) + +#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK 0 +#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE 1 +#define SMIAPP_CSI_SIGNALLING_MODE_CSI2 2 + +#define SMIAPP_DPHY_CTRL_AUTOMATIC 0 +/* DPHY control based on REQUESTED_LINK_BIT_RATE_MBPS */ +#define SMIAPP_DPHY_CTRL_UI 1 +#define SMIAPP_DPHY_CTRL_REGISTER 2 + +#define SMIAPP_COMPRESSION_MODE_SIMPLE_PREDICTOR 1 +#define SMIAPP_COMPRESSION_MODE_ADVANCED_PREDICTOR 2 + +#define SMIAPP_MODE_SELECT_SOFTWARE_STANDBY 0 +#define SMIAPP_MODE_SELECT_STREAMING 1 + +#define SMIAPP_SCALING_MODE_NONE 0 +#define SMIAPP_SCALING_MODE_HORIZONTAL 1 +#define SMIAPP_SCALING_MODE_BOTH 2 + +#define SMIAPP_SCALING_CAPABILITY_NONE 0 +#define SMIAPP_SCALING_CAPABILITY_HORIZONTAL 1 +#define SMIAPP_SCALING_CAPABILITY_BOTH 2 /* horizontal/both */ + +/* digital crop right before scaler */ +#define SMIAPP_DIGITAL_CROP_CAPABILITY_NONE 0 +#define SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP 1 + +#define SMIAPP_BINNING_CAPABILITY_NO 0 +#define SMIAPP_BINNING_CAPABILITY_YES 1 + +/* Maximum number of binning subtypes */ +#define SMIAPP_BINNING_SUBTYPES 253 + +#define SMIAPP_PIXEL_ORDER_GRBG 0 +#define SMIAPP_PIXEL_ORDER_RGGB 1 +#define SMIAPP_PIXEL_ORDER_BGGR 2 +#define SMIAPP_PIXEL_ORDER_GBRG 3 + +#define SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL 1 +#define SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED 2 +#define SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL_N 8 +#define SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED_N 16 + +#define SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE 0x01 +#define SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE 0x02 +#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NROWS_MASK 0x0f +#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_MASK 0xf0 +#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_SHIFT 4 + +#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_MASK 0xf000 +#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_SHIFT 12 +#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELS_MASK 0x0fff + +#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_MASK 0xf0000000 +#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_SHIFT 28 +#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELS_MASK 0x0000ffff + +#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED 1 +#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DUMMY 2 +#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_BLACK 3 +#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DARK 4 +#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE 5 + +#define SMIAPP_FAST_STANDBY_CTRL_COMPLETE_FRAMES 0 +#define SMIAPP_FAST_STANDBY_CTRL_IMMEDIATE 1 + +/* Scaling N factor */ +#define SMIAPP_SCALE_N 16 + +#endif /* __SMIAPP_REG_DEFS_H__ */ diff --git a/drivers/media/i2c/smiapp/smiapp-reg.h b/drivers/media/i2c/smiapp/smiapp-reg.h deleted file mode 100644 index e6f96309786f..000000000000 --- a/drivers/media/i2c/smiapp/smiapp-reg.h +++ /dev/null @@ -1,116 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * drivers/media/i2c/smiapp/smiapp-reg.h - * - * Generic driver for SMIA/SMIA++ compliant camera modules - * - * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus - */ - -#ifndef __SMIAPP_REG_H_ -#define __SMIAPP_REG_H_ - -#include - -#include "smiapp-reg-defs.h" - -/* Bits for above register */ -#define SMIAPP_IMAGE_ORIENTATION_HFLIP BIT(0) -#define SMIAPP_IMAGE_ORIENTATION_VFLIP BIT(1) - -#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_EN BIT(0) -#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_WR_EN BIT(1) -#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_ERR_CLEAR BIT(2) -#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY BIT(0) -#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_WR_READY BIT(1) -#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_EDATA BIT(2) -#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_EUSAGE BIT(3) - -#define SMIAPP_DATA_TRANSFER_IF_CAPABILITY_SUPPORTED BIT(0) -#define SMIAPP_DATA_TRANSFER_IF_CAPABILITY_POLL BIT(2) - -#define SMIAPP_SOFTWARE_RESET BIT(0) - -#define SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE BIT(0) -#define SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE BIT(1) - -#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK 0 -#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE 1 -#define SMIAPP_CSI_SIGNALLING_MODE_CSI2 2 - -#define SMIAPP_DPHY_CTRL_AUTOMATIC 0 -/* DPHY control based on REQUESTED_LINK_BIT_RATE_MBPS */ -#define SMIAPP_DPHY_CTRL_UI 1 -#define SMIAPP_DPHY_CTRL_REGISTER 2 - -#define SMIAPP_COMPRESSION_MODE_SIMPLE_PREDICTOR 1 -#define SMIAPP_COMPRESSION_MODE_ADVANCED_PREDICTOR 2 - -#define SMIAPP_MODE_SELECT_SOFTWARE_STANDBY 0 -#define SMIAPP_MODE_SELECT_STREAMING 1 - -#define SMIAPP_SCALING_MODE_NONE 0 -#define SMIAPP_SCALING_MODE_HORIZONTAL 1 -#define SMIAPP_SCALING_MODE_BOTH 2 - -#define SMIAPP_SCALING_CAPABILITY_NONE 0 -#define SMIAPP_SCALING_CAPABILITY_HORIZONTAL 1 -#define SMIAPP_SCALING_CAPABILITY_BOTH 2 /* horizontal/both */ - -/* digital crop right before scaler */ -#define SMIAPP_DIGITAL_CROP_CAPABILITY_NONE 0 -#define SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP 1 - -#define SMIAPP_BINNING_CAPABILITY_NO 0 -#define SMIAPP_BINNING_CAPABILITY_YES 1 - -/* Maximum number of binning subtypes */ -#define SMIAPP_BINNING_SUBTYPES 253 - -#define SMIAPP_PIXEL_ORDER_GRBG 0 -#define SMIAPP_PIXEL_ORDER_RGGB 1 -#define SMIAPP_PIXEL_ORDER_BGGR 2 -#define SMIAPP_PIXEL_ORDER_GBRG 3 - -#define SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL 1 -#define SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED 2 -#define SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL_N 8 -#define SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED_N 16 - -#define SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE 0x01 -#define SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE 0x02 -#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NROWS_MASK 0x0f -#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_MASK 0xf0 -#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_SHIFT 4 - -#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_MASK 0xf000 -#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_SHIFT 12 -#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELS_MASK 0x0fff - -#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_MASK 0xf0000000 -#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_SHIFT 28 -#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELS_MASK 0x0000ffff - -#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED 1 -#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DUMMY 2 -#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_BLACK 3 -#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DARK 4 -#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE 5 - -#define SMIAPP_FAST_STANDBY_CTRL_COMPLETE_FRAMES 0 -#define SMIAPP_FAST_STANDBY_CTRL_IMMEDIATE 1 - -/* Scaling N factor */ -#define SMIAPP_SCALE_N 16 - -/* Image statistics registers */ -/* Registers 0x2000 to 0x2fff are reserved for future - * use for statistics features. - */ - -/* Manufacturer Specific Registers: 0x3000 to 0x3fff - * The manufacturer specifies these as a black box. - */ - -#endif /* __SMIAPP_REG_H_ */ diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h index 6f469934f9e3..7cef97db7f47 100644 --- a/drivers/media/i2c/smiapp/smiapp.h +++ b/drivers/media/i2c/smiapp/smiapp.h @@ -16,7 +16,7 @@ #include #include "smiapp-pll.h" -#include "smiapp-reg.h" +#include "smiapp-reg-defs.h" #include "smiapp-regs.h" #include "smiapp-quirk.h" -- cgit v1.2.3 From e66a7c84908688e99bd7da4a48bfcba1b292fe54 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 3 Feb 2020 14:48:48 +0100 Subject: media: smiapp: Add macros for accessing CCS registers Add two helper macros for reading and writing the CCS registers as defined in ccs-regs.h. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-regs.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/i2c/smiapp/smiapp-regs.h b/drivers/media/i2c/smiapp/smiapp-regs.h index 7223f5f89109..dc946096f368 100644 --- a/drivers/media/i2c/smiapp/smiapp-regs.h +++ b/drivers/media/i2c/smiapp/smiapp-regs.h @@ -28,4 +28,10 @@ int smiapp_write(struct smiapp_sensor *sensor, u32 reg, u32 val); unsigned int ccs_reg_width(u32 reg); +#define ccs_read(sensor, reg_name, val) \ + smiapp_read(sensor, CCS_R_##reg_name, val) + +#define ccs_write(sensor, reg_name, val) \ + smiapp_write(sensor, CCS_R_##reg_name, val) + #endif -- cgit v1.2.3 From 503a88422fb0fc021b22b276f5d906eb9e7fce6e Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 3 Feb 2020 15:54:53 +0100 Subject: media: smiapp: Use MIPI CCS version and manufacturer ID information Read MIPI CCS manufacturer and version information, and use the CCS IDs over SMIA whenever they are set. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 76 +++++++++++++++++++++++++--------- drivers/media/i2c/smiapp/smiapp.h | 20 +++++---- 2 files changed, 68 insertions(+), 28 deletions(-) diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 75862e7647f8..bc9c80221d2f 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2356,9 +2356,14 @@ smiapp_sysfs_ident_read(struct device *dev, struct device_attribute *attr, struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); struct smiapp_module_info *minfo = &sensor->minfo; - return snprintf(buf, PAGE_SIZE, "%2.2x%4.4x%2.2x\n", - minfo->manufacturer_id, minfo->model_id, - minfo->revision_number_major) + 1; + if (minfo->mipi_manufacturer_id) + return snprintf(buf, PAGE_SIZE, "%4.4x%4.4x%2.2x\n", + minfo->mipi_manufacturer_id, minfo->model_id, + minfo->revision_number_major) + 1; + else + return snprintf(buf, PAGE_SIZE, "%2.2x%4.4x%2.2x\n", + minfo->smia_manufacturer_id, minfo->model_id, + minfo->revision_number_major) + 1; } static DEVICE_ATTR(ident, S_IRUGO, smiapp_sysfs_ident_read, NULL); @@ -2377,8 +2382,11 @@ static int smiapp_identify_module(struct smiapp_sensor *sensor) minfo->name = SMIAPP_NAME; /* Module info */ - rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_MANUFACTURER_ID, - &minfo->manufacturer_id); + rval = ccs_read(sensor, MODULE_MANUFACTURER_ID, + &minfo->mipi_manufacturer_id); + if (!rval && !minfo->mipi_manufacturer_id) + rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_MANUFACTURER_ID, + &minfo->smia_manufacturer_id); if (!rval) rval = smiapp_read_8only(sensor, SMIAPP_REG_U16_MODEL_ID, &minfo->model_id); @@ -2404,9 +2412,12 @@ static int smiapp_identify_module(struct smiapp_sensor *sensor) /* Sensor info */ if (!rval) + rval = ccs_read(sensor, SENSOR_MANUFACTURER_ID, + &minfo->sensor_mipi_manufacturer_id); + if (!rval && !minfo->sensor_mipi_manufacturer_id) rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_SENSOR_MANUFACTURER_ID, - &minfo->sensor_manufacturer_id); + &minfo->sensor_smia_manufacturer_id); if (!rval) rval = smiapp_read_8only(sensor, SMIAPP_REG_U16_SENSOR_MODEL_ID, @@ -2422,9 +2433,11 @@ static int smiapp_identify_module(struct smiapp_sensor *sensor) /* SMIA */ if (!rval) + rval = ccs_read(sensor, MIPI_CCS_VERSION, &minfo->ccs_version); + if (!rval && !minfo->ccs_version) rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_SMIA_VERSION, &minfo->smia_version); - if (!rval) + if (!rval && !minfo->ccs_version) rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_SMIAPP_VERSION, &minfo->smiapp_version); @@ -2433,38 +2446,62 @@ static int smiapp_identify_module(struct smiapp_sensor *sensor) return -ENODEV; } - dev_dbg(&client->dev, "module 0x%2.2x-0x%4.4x\n", - minfo->manufacturer_id, minfo->model_id); + if (minfo->mipi_manufacturer_id) + dev_dbg(&client->dev, "MIPI CCS module 0x%4.4x-0x%4.4x\n", + minfo->mipi_manufacturer_id, minfo->model_id); + else + dev_dbg(&client->dev, "SMIA module 0x%2.2x-0x%4.4x\n", + minfo->smia_manufacturer_id, minfo->model_id); dev_dbg(&client->dev, "module revision 0x%2.2x-0x%2.2x date %2.2d-%2.2d-%2.2d\n", minfo->revision_number_major, minfo->revision_number_minor, minfo->module_year, minfo->module_month, minfo->module_day); - dev_dbg(&client->dev, "sensor 0x%2.2x-0x%4.4x\n", - minfo->sensor_manufacturer_id, minfo->sensor_model_id); + if (minfo->sensor_mipi_manufacturer_id) + dev_dbg(&client->dev, "MIPI CCS sensor 0x%4.4x-0x%4.4x\n", + minfo->sensor_mipi_manufacturer_id, + minfo->sensor_model_id); + else + dev_dbg(&client->dev, "SMIA sensor 0x%2.2x-0x%4.4x\n", + minfo->sensor_smia_manufacturer_id, + minfo->sensor_model_id); dev_dbg(&client->dev, "sensor revision 0x%2.2x firmware version 0x%2.2x\n", minfo->sensor_revision_number, minfo->sensor_firmware_version); - dev_dbg(&client->dev, "smia version %2.2d smiapp version %2.2d\n", - minfo->smia_version, minfo->smiapp_version); + if (minfo->ccs_version) + dev_dbg(&client->dev, "MIPI CCS version %u.%u", + (minfo->ccs_version & CCS_MIPI_CCS_VERSION_MAJOR_MASK) + >> CCS_MIPI_CCS_VERSION_MAJOR_SHIFT, + (minfo->ccs_version & CCS_MIPI_CCS_VERSION_MINOR_MASK)); + else + dev_dbg(&client->dev, + "smia version %2.2d smiapp version %2.2d\n", + minfo->smia_version, minfo->smiapp_version); /* * Some modules have bad data in the lvalues below. Hope the * rvalues have better stuff. The lvalues are module * parameters whereas the rvalues are sensor parameters. */ - if (!minfo->manufacturer_id && !minfo->model_id) { - minfo->manufacturer_id = minfo->sensor_manufacturer_id; + if (minfo->sensor_smia_manufacturer_id && + !minfo->smia_manufacturer_id && !minfo->model_id) { + minfo->smia_manufacturer_id = + minfo->sensor_smia_manufacturer_id; minfo->model_id = minfo->sensor_model_id; minfo->revision_number_major = minfo->sensor_revision_number; } for (i = 0; i < ARRAY_SIZE(smiapp_module_idents); i++) { - if (smiapp_module_idents[i].manufacturer_id - != minfo->manufacturer_id) + if (smiapp_module_idents[i].mipi_manufacturer_id && + smiapp_module_idents[i].mipi_manufacturer_id + != minfo->mipi_manufacturer_id) + continue; + if (smiapp_module_idents[i].smia_manufacturer_id && + smiapp_module_idents[i].smia_manufacturer_id + != minfo->smia_manufacturer_id) continue; if (smiapp_module_idents[i].model_id != minfo->model_id) continue; @@ -2488,9 +2525,8 @@ static int smiapp_identify_module(struct smiapp_sensor *sensor) dev_warn(&client->dev, "no quirks for this module; let's hope it's fully compliant\n"); - dev_dbg(&client->dev, "the sensor is called %s, ident %2.2x%4.4x%2.2x\n", - minfo->name, minfo->manufacturer_id, minfo->model_id, - minfo->revision_number_major); + dev_dbg(&client->dev, "the sensor is called %s\n", + minfo->name); return 0; } diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h index 7cef97db7f47..b1d0e3d71630 100644 --- a/drivers/media/i2c/smiapp/smiapp.h +++ b/drivers/media/i2c/smiapp/smiapp.h @@ -91,8 +91,9 @@ struct smiapp_quirk; #define SMIAPP_MODULE_IDENT_FLAG_REV_LE (1 << 0) struct smiapp_module_ident { - u8 manufacturer_id; + u16 mipi_manufacturer_id; u16 model_id; + u8 smia_manufacturer_id; u8 revision_number_major; u8 flags; @@ -102,7 +103,8 @@ struct smiapp_module_ident { }; struct smiapp_module_info { - u32 manufacturer_id; + u32 smia_manufacturer_id; + u32 mipi_manufacturer_id; u32 model_id; u32 revision_number_major; u32 revision_number_minor; @@ -111,13 +113,15 @@ struct smiapp_module_info { u32 module_month; u32 module_day; - u32 sensor_manufacturer_id; + u32 sensor_smia_manufacturer_id; + u32 sensor_mipi_manufacturer_id; u32 sensor_model_id; u32 sensor_revision_number; u32 sensor_firmware_version; u32 smia_version; u32 smiapp_version; + u32 ccs_version; u32 smiapp_profile; @@ -126,7 +130,7 @@ struct smiapp_module_info { }; #define SMIAPP_IDENT_FQ(manufacturer, model, rev, fl, _name, _quirk) \ - { .manufacturer_id = manufacturer, \ + { .smia_manufacturer_id = manufacturer, \ .model_id = model, \ .revision_number_major = rev, \ .flags = fl, \ @@ -134,7 +138,7 @@ struct smiapp_module_info { .quirk = _quirk, } #define SMIAPP_IDENT_LQ(manufacturer, model, rev, _name, _quirk) \ - { .manufacturer_id = manufacturer, \ + { .smia_manufacturer_id = manufacturer, \ .model_id = model, \ .revision_number_major = rev, \ .flags = SMIAPP_MODULE_IDENT_FLAG_REV_LE, \ @@ -142,14 +146,14 @@ struct smiapp_module_info { .quirk = _quirk, } #define SMIAPP_IDENT_L(manufacturer, model, rev, _name) \ - { .manufacturer_id = manufacturer, \ + { .smia_manufacturer_id = manufacturer, \ .model_id = model, \ .revision_number_major = rev, \ .flags = SMIAPP_MODULE_IDENT_FLAG_REV_LE, \ .name = _name, } #define SMIAPP_IDENT_Q(manufacturer, model, rev, _name, _quirk) \ - { .manufacturer_id = manufacturer, \ + { .smia_manufacturer_id = manufacturer, \ .model_id = model, \ .revision_number_major = rev, \ .flags = 0, \ @@ -157,7 +161,7 @@ struct smiapp_module_info { .quirk = _quirk, } #define SMIAPP_IDENT(manufacturer, model, rev, _name) \ - { .manufacturer_id = manufacturer, \ + { .smia_manufacturer_id = manufacturer, \ .model_id = model, \ .revision_number_major = rev, \ .flags = 0, \ -- cgit v1.2.3 From ca296a11156a00cc2336ba5fbcbcf2c6c41755c5 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 6 Feb 2020 15:06:12 +0100 Subject: media: smiapp: Read CCS limit values Read limit and capability values into a driver allocated buffer. This will later replace (most of) the existing SMIA limits. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 177 ++++++++++++++++++++++++++++++++- drivers/media/i2c/smiapp/smiapp.h | 4 + 2 files changed, 176 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index bc9c80221d2f..4b33b9a1d52c 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -28,6 +28,7 @@ #include #include "ccs-limits.h" +#include "ccs-regs.h" #include "smiapp.h" #define SMIAPP_ALIGN_DIM(dim, flags) \ @@ -102,6 +103,164 @@ static int smiapp_read_all_smia_limits(struct smiapp_sensor *sensor) return 0; } +static void ccs_assign_limit(void *ptr, unsigned int width, u32 val) +{ + switch (width) { + case sizeof(u8): + *(u8 *)ptr = val; + break; + case sizeof(u16): + *(u16 *)ptr = val; + break; + case sizeof(u32): + *(u32 *)ptr = val; + break; + } +} + +static int ccs_limit_ptr(struct smiapp_sensor *sensor, unsigned int limit, + unsigned int offset, void **__ptr) +{ + const struct ccs_limit *linfo; + + if (WARN_ON(limit >= CCS_L_LAST)) + return -EINVAL; + + linfo = &ccs_limits[ccs_limit_offsets[limit].info]; + + if (WARN_ON(!sensor->ccs_limits) || + WARN_ON(offset + ccs_reg_width(linfo->reg) > + ccs_limit_offsets[limit + 1].lim)) + return -EINVAL; + + *__ptr = sensor->ccs_limits + ccs_limit_offsets[limit].lim + offset; + + return 0; +} + +void ccs_replace_limit(struct smiapp_sensor *sensor, + unsigned int limit, unsigned int offset, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + const struct ccs_limit *linfo; + void *ptr; + int ret; + + ret = ccs_limit_ptr(sensor, limit, offset, &ptr); + if (ret) + return; + + linfo = &ccs_limits[ccs_limit_offsets[limit].info]; + + dev_dbg(&client->dev, "quirk: 0x%8.8x \"%s\" %u = %d, 0x%x\n", + linfo->reg, linfo->name, offset, val, val); + + ccs_assign_limit(ptr, ccs_reg_width(linfo->reg), val); +} + +static u32 ccs_get_limit(struct smiapp_sensor *sensor, + unsigned int limit, unsigned int offset) +{ + void *ptr; + int ret; + + ret = ccs_limit_ptr(sensor, limit, offset, &ptr); + if (ret) + return 0; + + switch (ccs_reg_width(ccs_limits[ccs_limit_offsets[limit].info].reg)) { + case sizeof(u8): + return *(u8 *)ptr; + case sizeof(u16): + return *(u16 *)ptr; + case sizeof(u32): + return *(u32 *)ptr; + } + + WARN_ON(1); + + return 0; +} + +#define CCS_LIM(sensor, limit) \ + ccs_get_limit(sensor, CCS_L_##limit, 0) + +#define CCS_LIM_AT(sensor, limit, offset) \ + ccs_get_limit(sensor, CCS_L_##limit, CCS_L_##limit##_OFFSET(offset)) + +static int ccs_read_all_limits(struct smiapp_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + void *ptr, *alloc, *end; + unsigned int i, l; + int ret; + + kfree(sensor->ccs_limits); + sensor->ccs_limits = NULL; + + alloc = kzalloc(ccs_limit_offsets[CCS_L_LAST].lim, GFP_KERNEL); + if (!alloc) + return -ENOMEM; + + end = alloc + ccs_limit_offsets[CCS_L_LAST].lim; + + for (i = 0, l = 0, ptr = alloc; ccs_limits[i].size; i++) { + u32 reg = ccs_limits[i].reg; + unsigned int width = ccs_reg_width(reg); + unsigned int j; + + if (l == CCS_L_LAST) { + dev_err(&client->dev, + "internal error --- end of limit array\n"); + ret = -EINVAL; + goto out_err; + } + + for (j = 0; j < ccs_limits[i].size / width; + j++, reg += width, ptr += width) { + u32 val; + + ret = smiapp_read(sensor, reg, &val); + if (ret) + goto out_err; + + if (ptr + width > end) { + dev_err(&client->dev, + "internal error --- no room for regs\n"); + ret = -EINVAL; + goto out_err; + } + + ccs_assign_limit(ptr, width, val); + + dev_dbg(&client->dev, "0x%8.8x \"%s\" = %u, 0x%x\n", + reg, ccs_limits[i].name, val, val); + } + + if (ccs_limits[i].flags & CCS_L_FL_SAME_REG) + continue; + + l++; + ptr = alloc + ccs_limit_offsets[l].lim; + } + + if (l != CCS_L_LAST) { + dev_err(&client->dev, + "internal error --- insufficient limits\n"); + ret = -EINVAL; + goto out_err; + } + + sensor->ccs_limits = alloc; + + return 0; + +out_err: + kfree(alloc); + + return ret; +} + static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); @@ -2970,10 +3129,14 @@ static int smiapp_probe(struct i2c_client *client) goto out_power_off; } + rval = ccs_read_all_limits(sensor); + if (rval) + goto out_power_off; + rval = smiapp_read_frame_fmt(sensor); if (rval) { rval = -ENODEV; - goto out_power_off; + goto out_free_ccs_limits; } /* @@ -2997,7 +3160,7 @@ static int smiapp_probe(struct i2c_client *client) rval = smiapp_call_quirk(sensor, limits); if (rval) { dev_err(&client->dev, "limits quirks failed\n"); - goto out_power_off; + goto out_free_ccs_limits; } if (SMIA_LIM(sensor, BINNING_CAPABILITY)) { @@ -3007,7 +3170,7 @@ static int smiapp_probe(struct i2c_client *client) SMIAPP_REG_U8_BINNING_SUBTYPES, &val); if (rval < 0) { rval = -ENODEV; - goto out_power_off; + goto out_free_ccs_limits; } sensor->nbinning_subtypes = min_t(u8, val, SMIAPP_BINNING_SUBTYPES); @@ -3017,7 +3180,7 @@ static int smiapp_probe(struct i2c_client *client) sensor, SMIAPP_REG_U8_BINNING_TYPE_n(i), &val); if (rval < 0) { rval = -ENODEV; - goto out_power_off; + goto out_free_ccs_limits; } sensor->binning_subtypes[i] = *(struct smiapp_binning_subtype *)&val; @@ -3033,7 +3196,7 @@ static int smiapp_probe(struct i2c_client *client) if (device_create_file(&client->dev, &dev_attr_ident) != 0) { dev_err(&client->dev, "sysfs ident entry creation failed\n"); rval = -ENOENT; - goto out_power_off; + goto out_free_ccs_limits; } if (sensor->minfo.smiapp_version && @@ -3150,6 +3313,9 @@ out_media_entity_cleanup: out_cleanup: smiapp_cleanup(sensor); +out_free_ccs_limits: + kfree(sensor->ccs_limits); + out_power_off: smiapp_power_off(&client->dev); mutex_destroy(&sensor->mutex); @@ -3176,6 +3342,7 @@ static int smiapp_remove(struct i2c_client *client) } smiapp_cleanup(sensor); mutex_destroy(&sensor->mutex); + kfree(sensor->ccs_limits); return 0; } diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h index b1d0e3d71630..08ca1b3d1b2f 100644 --- a/drivers/media/i2c/smiapp/smiapp.h +++ b/drivers/media/i2c/smiapp/smiapp.h @@ -228,6 +228,7 @@ struct smiapp_sensor { struct clk *ext_clk; struct gpio_desc *xshutdown; u32 limits[SMIAPP_LIMIT_LAST]; + void *ccs_limits; u8 nbinning_subtypes; struct smiapp_binning_subtype binning_subtypes[SMIAPP_BINNING_SUBTYPES]; u32 mbus_frame_fmts; @@ -281,4 +282,7 @@ struct smiapp_sensor { #define to_smiapp_sensor(_sd) \ (to_smiapp_subdev(_sd)->sensor) +void ccs_replace_limit(struct smiapp_sensor *sensor, + unsigned int limit, unsigned int offset, u32 val); + #endif /* __SMIAPP_PRIV_H_ */ -- cgit v1.2.3 From 3e158e1f1ec2aca4287bc12323c7e88d4e3b4f38 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 10 Feb 2020 10:09:03 +0100 Subject: media: smiapp: Switch to CCS limits Use the CCS limit definitions instead of the SMIA ones. This allows accessing CCS capabilities where needed as well as dropping the old SMIA limits. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/Makefile | 2 +- drivers/media/i2c/smiapp/smiapp-core.c | 255 +++++++++++++------------------ drivers/media/i2c/smiapp/smiapp-limits.c | 118 -------------- drivers/media/i2c/smiapp/smiapp-limits.h | 114 -------------- drivers/media/i2c/smiapp/smiapp-quirk.c | 25 +-- drivers/media/i2c/smiapp/smiapp-quirk.h | 3 - drivers/media/i2c/smiapp/smiapp.h | 10 -- 7 files changed, 113 insertions(+), 414 deletions(-) delete mode 100644 drivers/media/i2c/smiapp/smiapp-limits.c delete mode 100644 drivers/media/i2c/smiapp/smiapp-limits.h diff --git a/drivers/media/i2c/smiapp/Makefile b/drivers/media/i2c/smiapp/Makefile index efb643d2acac..a7bf53dd4a63 100644 --- a/drivers/media/i2c/smiapp/Makefile +++ b/drivers/media/i2c/smiapp/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only smiapp-objs += smiapp-core.o smiapp-regs.o \ - smiapp-quirk.o smiapp-limits.o ccs-limits.o + smiapp-quirk.o ccs-limits.o obj-$(CONFIG_VIDEO_SMIAPP) += smiapp.o ccflags-y += -I $(srctree)/drivers/media/i2c diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 4b33b9a1d52c..2c1a13507965 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -64,45 +64,6 @@ static const struct smiapp_module_ident smiapp_module_idents[] = { * */ -static u32 smiapp_get_limit(struct smiapp_sensor *sensor, - unsigned int limit) -{ - if (WARN_ON(limit >= SMIAPP_LIMIT_LAST)) - return 1; - - return sensor->limits[limit]; -} - -#define SMIA_LIM(sensor, limit) \ - smiapp_get_limit(sensor, SMIAPP_LIMIT_##limit) - -static int smiapp_read_all_smia_limits(struct smiapp_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - unsigned int i; - int rval; - - for (i = 0; i < SMIAPP_LIMIT_LAST; i++) { - u32 val; - - rval = smiapp_read( - sensor, smiapp_reg_limits[i].addr, &val); - if (rval) - return rval; - - sensor->limits[i] = val; - - dev_dbg(&client->dev, "0x%8.8x \"%s\" = %u, 0x%x\n", - smiapp_reg_limits[i].addr, - smiapp_reg_limits[i].what, val, val); - } - - if (SMIA_LIM(sensor, SCALER_N_MIN) == 0) - smiapp_replace_limit(sensor, SMIAPP_LIMIT_SCALER_N_MIN, 16); - - return 0; -} - static void ccs_assign_limit(void *ptr, unsigned int width, u32 val) { switch (width) { @@ -253,6 +214,9 @@ static int ccs_read_all_limits(struct smiapp_sensor *sensor) sensor->ccs_limits = alloc; + if (CCS_LIM(sensor, SCALER_N_MIN) < 16) + ccs_replace_limit(sensor, CCS_L_SCALER_N_MIN, 0, 16); + return 0; out_err: @@ -444,35 +408,35 @@ static int smiapp_pll_try(struct smiapp_sensor *sensor, { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); struct smiapp_pll_limits lim = { - .min_pre_pll_clk_div = SMIA_LIM(sensor, MIN_PRE_PLL_CLK_DIV), - .max_pre_pll_clk_div = SMIA_LIM(sensor, MAX_PRE_PLL_CLK_DIV), - .min_pll_ip_freq_hz = SMIA_LIM(sensor, MIN_PLL_IP_FREQ_HZ), - .max_pll_ip_freq_hz = SMIA_LIM(sensor, MAX_PLL_IP_FREQ_HZ), - .min_pll_multiplier = SMIA_LIM(sensor, MIN_PLL_MULTIPLIER), - .max_pll_multiplier = SMIA_LIM(sensor, MAX_PLL_MULTIPLIER), - .min_pll_op_freq_hz = SMIA_LIM(sensor, MIN_PLL_OP_FREQ_HZ), - .max_pll_op_freq_hz = SMIA_LIM(sensor, MAX_PLL_OP_FREQ_HZ), - - .op.min_sys_clk_div = SMIA_LIM(sensor, MIN_OP_SYS_CLK_DIV), - .op.max_sys_clk_div = SMIA_LIM(sensor, MAX_OP_SYS_CLK_DIV), - .op.min_pix_clk_div = SMIA_LIM(sensor, MIN_OP_PIX_CLK_DIV), - .op.max_pix_clk_div = SMIA_LIM(sensor, MAX_OP_PIX_CLK_DIV), - .op.min_sys_clk_freq_hz = SMIA_LIM(sensor, MIN_OP_SYS_CLK_FREQ_HZ), - .op.max_sys_clk_freq_hz = SMIA_LIM(sensor, MAX_OP_SYS_CLK_FREQ_HZ), - .op.min_pix_clk_freq_hz = SMIA_LIM(sensor, MIN_OP_PIX_CLK_FREQ_HZ), - .op.max_pix_clk_freq_hz = SMIA_LIM(sensor, MAX_OP_PIX_CLK_FREQ_HZ), - - .vt.min_sys_clk_div = SMIA_LIM(sensor, MIN_VT_SYS_CLK_DIV), - .vt.max_sys_clk_div = SMIA_LIM(sensor, MAX_VT_SYS_CLK_DIV), - .vt.min_pix_clk_div = SMIA_LIM(sensor, MIN_VT_PIX_CLK_DIV), - .vt.max_pix_clk_div = SMIA_LIM(sensor, MAX_VT_PIX_CLK_DIV), - .vt.min_sys_clk_freq_hz = SMIA_LIM(sensor, MIN_VT_SYS_CLK_FREQ_HZ), - .vt.max_sys_clk_freq_hz = SMIA_LIM(sensor, MAX_VT_SYS_CLK_FREQ_HZ), - .vt.min_pix_clk_freq_hz = SMIA_LIM(sensor, MIN_VT_PIX_CLK_FREQ_HZ), - .vt.max_pix_clk_freq_hz = SMIA_LIM(sensor, MAX_VT_PIX_CLK_FREQ_HZ), - - .min_line_length_pck_bin = SMIA_LIM(sensor, MIN_LINE_LENGTH_PCK_BIN), - .min_line_length_pck = SMIA_LIM(sensor, MIN_LINE_LENGTH_PCK), + .min_pre_pll_clk_div = CCS_LIM(sensor, MIN_PRE_PLL_CLK_DIV), + .max_pre_pll_clk_div = CCS_LIM(sensor, MAX_PRE_PLL_CLK_DIV), + .min_pll_ip_freq_hz = CCS_LIM(sensor, MIN_PLL_IP_CLK_FREQ_MHZ), + .max_pll_ip_freq_hz = CCS_LIM(sensor, MAX_PLL_IP_CLK_FREQ_MHZ), + .min_pll_multiplier = CCS_LIM(sensor, MIN_PLL_MULTIPLIER), + .max_pll_multiplier = CCS_LIM(sensor, MAX_PLL_MULTIPLIER), + .min_pll_op_freq_hz = CCS_LIM(sensor, MIN_PLL_OP_CLK_FREQ_MHZ), + .max_pll_op_freq_hz = CCS_LIM(sensor, MAX_PLL_OP_CLK_FREQ_MHZ), + + .op.min_sys_clk_div = CCS_LIM(sensor, MIN_OP_SYS_CLK_DIV), + .op.max_sys_clk_div = CCS_LIM(sensor, MAX_OP_SYS_CLK_DIV), + .op.min_pix_clk_div = CCS_LIM(sensor, MIN_OP_PIX_CLK_DIV), + .op.max_pix_clk_div = CCS_LIM(sensor, MAX_OP_PIX_CLK_DIV), + .op.min_sys_clk_freq_hz = CCS_LIM(sensor, MIN_OP_SYS_CLK_FREQ_MHZ), + .op.max_sys_clk_freq_hz = CCS_LIM(sensor, MAX_OP_SYS_CLK_FREQ_MHZ), + .op.min_pix_clk_freq_hz = CCS_LIM(sensor, MIN_OP_PIX_CLK_FREQ_MHZ), + .op.max_pix_clk_freq_hz = CCS_LIM(sensor, MAX_OP_PIX_CLK_FREQ_MHZ), + + .vt.min_sys_clk_div = CCS_LIM(sensor, MIN_VT_SYS_CLK_DIV), + .vt.max_sys_clk_div = CCS_LIM(sensor, MAX_VT_SYS_CLK_DIV), + .vt.min_pix_clk_div = CCS_LIM(sensor, MIN_VT_PIX_CLK_DIV), + .vt.max_pix_clk_div = CCS_LIM(sensor, MAX_VT_PIX_CLK_DIV), + .vt.min_sys_clk_freq_hz = CCS_LIM(sensor, MIN_VT_SYS_CLK_FREQ_MHZ), + .vt.max_sys_clk_freq_hz = CCS_LIM(sensor, MAX_VT_SYS_CLK_FREQ_MHZ), + .vt.min_pix_clk_freq_hz = CCS_LIM(sensor, MIN_VT_PIX_CLK_FREQ_MHZ), + .vt.max_pix_clk_freq_hz = CCS_LIM(sensor, MAX_VT_PIX_CLK_FREQ_MHZ), + + .min_line_length_pck_bin = CCS_LIM(sensor, MIN_LINE_LENGTH_PCK_BIN), + .min_line_length_pck = CCS_LIM(sensor, MIN_LINE_LENGTH_PCK), }; return smiapp_pll_calculate(&client->dev, &lim, pll); @@ -515,7 +479,7 @@ static void __smiapp_update_exposure_limits(struct smiapp_sensor *sensor) max = sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height + sensor->vblank->val - - SMIA_LIM(sensor, COARSE_INTEGRATION_TIME_MAX_MARGIN); + - CCS_LIM(sensor, COARSE_INTEGRATION_TIME_MAX_MARGIN); __v4l2_ctrl_modify_range(ctrl, ctrl->minimum, max, ctrl->step, max); } @@ -770,10 +734,10 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor) sensor->analog_gain = v4l2_ctrl_new_std( &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, - SMIA_LIM(sensor, ANALOGUE_GAIN_CODE_MIN), - SMIA_LIM(sensor, ANALOGUE_GAIN_CODE_MAX), - max(SMIA_LIM(sensor, ANALOGUE_GAIN_CODE_STEP), 1U), - SMIA_LIM(sensor, ANALOGUE_GAIN_CODE_MIN)); + CCS_LIM(sensor, ANALOG_GAIN_CODE_MIN), + CCS_LIM(sensor, ANALOG_GAIN_CODE_MAX), + max(CCS_LIM(sensor, ANALOG_GAIN_CODE_STEP), 1U), + CCS_LIM(sensor, ANALOG_GAIN_CODE_MIN)); /* Exposure limits will be updated soon, use just something here. */ sensor->exposure = v4l2_ctrl_new_std( @@ -1032,21 +996,21 @@ static void smiapp_update_blanking(struct smiapp_sensor *sensor) int min, max; if (sensor->binning_vertical > 1 || sensor->binning_horizontal > 1) { - min_fll = SMIA_LIM(sensor, MIN_FRAME_LENGTH_LINES_BIN); - max_fll = SMIA_LIM(sensor, MAX_FRAME_LENGTH_LINES_BIN); - min_llp = SMIA_LIM(sensor, MIN_LINE_LENGTH_PCK_BIN); - max_llp = SMIA_LIM(sensor, MAX_LINE_LENGTH_PCK_BIN); - min_lbp = SMIA_LIM(sensor, MIN_LINE_BLANKING_PCK_BIN); + min_fll = CCS_LIM(sensor, MIN_FRAME_LENGTH_LINES_BIN); + max_fll = CCS_LIM(sensor, MAX_FRAME_LENGTH_LINES_BIN); + min_llp = CCS_LIM(sensor, MIN_LINE_LENGTH_PCK_BIN); + max_llp = CCS_LIM(sensor, MAX_LINE_LENGTH_PCK_BIN); + min_lbp = CCS_LIM(sensor, MIN_LINE_BLANKING_PCK_BIN); } else { - min_fll = SMIA_LIM(sensor, MIN_FRAME_LENGTH_LINES); - max_fll = SMIA_LIM(sensor, MAX_FRAME_LENGTH_LINES); - min_llp = SMIA_LIM(sensor, MIN_LINE_LENGTH_PCK); - max_llp = SMIA_LIM(sensor, MAX_LINE_LENGTH_PCK); - min_lbp = SMIA_LIM(sensor, MIN_LINE_BLANKING_PCK); + min_fll = CCS_LIM(sensor, MIN_FRAME_LENGTH_LINES); + max_fll = CCS_LIM(sensor, MAX_FRAME_LENGTH_LINES); + min_llp = CCS_LIM(sensor, MIN_LINE_LENGTH_PCK); + max_llp = CCS_LIM(sensor, MAX_LINE_LENGTH_PCK); + min_lbp = CCS_LIM(sensor, MIN_LINE_BLANKING_PCK); } min = max_t(int, - SMIA_LIM(sensor, MIN_FRAME_BLANKING_LINES), + CCS_LIM(sensor, MIN_FRAME_BLANKING_LINES), min_fll - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height); max = max_fll - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height; @@ -1124,8 +1088,8 @@ static int smiapp_read_nvm_page(struct smiapp_sensor *sensor, u32 p, u8 *nvm, return -ENODATA; } - if (SMIA_LIM(sensor, DATA_TRANSFER_IF_CAPABILITY) & - SMIAPP_DATA_TRANSFER_IF_CAPABILITY_POLL) { + if (CCS_LIM(sensor, DATA_TRANSFER_IF_CAPABILITY) & + CCS_DATA_TRANSFER_IF_CAPABILITY_POLLING) { for (i = 1000; i > 0; i--) { if (s & SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY) break; @@ -1577,8 +1541,8 @@ static int smiapp_start_streaming(struct smiapp_sensor *sensor) */ /* Digital crop */ - if (SMIA_LIM(sensor, DIGITAL_CROP_CAPABILITY) - == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) { + if (CCS_LIM(sensor, DIGITAL_CROP_CAPABILITY) + == CCS_DIGITAL_CROP_CAPABILITY_INPUT_CROP) { rval = smiapp_write( sensor, SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET, sensor->scaler->crop[SMIAPP_PAD_SINK].left); @@ -1605,8 +1569,8 @@ static int smiapp_start_streaming(struct smiapp_sensor *sensor) } /* Scaling */ - if (SMIA_LIM(sensor, SCALING_CAPABILITY) - != SMIAPP_SCALING_CAPABILITY_NONE) { + if (CCS_LIM(sensor, SCALING_CAPABILITY) + != CCS_SCALING_CAPABILITY_NONE) { rval = smiapp_write(sensor, SMIAPP_REG_U16_SCALING_MODE, sensor->scaling_mode); if (rval < 0) @@ -1628,9 +1592,9 @@ static int smiapp_start_streaming(struct smiapp_sensor *sensor) if (rval < 0) goto out; - if ((SMIA_LIM(sensor, FLASH_MODE_CAPABILITY) & - (SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE | - SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE)) && + if (CCS_LIM(sensor, FLASH_MODE_CAPABILITY) & + (CCS_FLASH_MODE_CAPABILITY_SINGLE_STROBE | + SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE) && sensor->hwcfg->strobe_setup != NULL && sensor->hwcfg->strobe_setup->trigger != 0) { rval = smiapp_setup_flash_strobe(sensor); @@ -1876,7 +1840,7 @@ static void smiapp_propagate(struct v4l2_subdev *subdev, if (which == V4L2_SUBDEV_FORMAT_ACTIVE) { if (ssd == sensor->scaler) { sensor->scale_m = - SMIA_LIM(sensor, SCALER_N_MIN); + CCS_LIM(sensor, SCALER_N_MIN); sensor->scaling_mode = SMIAPP_SCALING_MODE_NONE; } else if (ssd == sensor->binner) { @@ -1988,12 +1952,12 @@ static int smiapp_set_format(struct v4l2_subdev *subdev, fmt->format.width = clamp(fmt->format.width, - SMIA_LIM(sensor, MIN_X_OUTPUT_SIZE), - SMIA_LIM(sensor, MAX_X_OUTPUT_SIZE)); + CCS_LIM(sensor, MIN_X_OUTPUT_SIZE), + CCS_LIM(sensor, MAX_X_OUTPUT_SIZE)); fmt->format.height = clamp(fmt->format.height, - SMIA_LIM(sensor, MIN_Y_OUTPUT_SIZE), - SMIA_LIM(sensor, MAX_Y_OUTPUT_SIZE)); + CCS_LIM(sensor, MIN_Y_OUTPUT_SIZE), + CCS_LIM(sensor, MAX_Y_OUTPUT_SIZE)); smiapp_get_crop_compose(subdev, cfg, crops, NULL, fmt->which); @@ -2046,7 +2010,7 @@ static int scaling_goodness(struct v4l2_subdev *subdev, int w, int ask_w, val -= abs(w - ask_w); val -= abs(h - ask_h); - if (w < SMIA_LIM(sensor, MIN_X_OUTPUT_SIZE)) + if (w < CCS_LIM(sensor, MIN_X_OUTPUT_SIZE)) val -= SCALING_GOODNESS_EXTREME; dev_dbg(&client->dev, "w %d ask_w %d h %d ask_h %d goodness %d\n", @@ -2112,7 +2076,7 @@ static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev, struct i2c_client *client = v4l2_get_subdevdata(subdev); struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); u32 min, max, a, b, max_m; - u32 scale_m = SMIA_LIM(sensor, SCALER_N_MIN); + u32 scale_m = CCS_LIM(sensor, SCALER_N_MIN); int mode = SMIAPP_SCALING_MODE_HORIZONTAL; u32 try[4]; u32 ntry = 0; @@ -2125,19 +2089,19 @@ static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev, crops[SMIAPP_PAD_SINK]->height); a = crops[SMIAPP_PAD_SINK]->width - * SMIA_LIM(sensor, SCALER_N_MIN) / sel->r.width; + * CCS_LIM(sensor, SCALER_N_MIN) / sel->r.width; b = crops[SMIAPP_PAD_SINK]->height - * SMIA_LIM(sensor, SCALER_N_MIN) / sel->r.height; + * CCS_LIM(sensor, SCALER_N_MIN) / sel->r.height; max_m = crops[SMIAPP_PAD_SINK]->width - * SMIA_LIM(sensor, SCALER_N_MIN) - / SMIA_LIM(sensor, MIN_X_OUTPUT_SIZE); + * CCS_LIM(sensor, SCALER_N_MIN) + / CCS_LIM(sensor, MIN_X_OUTPUT_SIZE); - a = clamp(a, SMIA_LIM(sensor, SCALER_M_MIN), - SMIA_LIM(sensor, SCALER_M_MAX)); - b = clamp(b, SMIA_LIM(sensor, SCALER_M_MIN), - SMIA_LIM(sensor, SCALER_M_MAX)); - max_m = clamp(max_m, SMIA_LIM(sensor, SCALER_M_MIN), - SMIA_LIM(sensor, SCALER_M_MAX)); + a = clamp(a, CCS_LIM(sensor, SCALER_M_MIN), + CCS_LIM(sensor, SCALER_M_MAX)); + b = clamp(b, CCS_LIM(sensor, SCALER_M_MIN), + CCS_LIM(sensor, SCALER_M_MAX)); + max_m = clamp(max_m, CCS_LIM(sensor, SCALER_M_MIN), + CCS_LIM(sensor, SCALER_M_MAX)); dev_dbg(&client->dev, "scaling: a %d b %d max_m %d\n", a, b, max_m); @@ -2163,8 +2127,7 @@ static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev, int this = scaling_goodness( subdev, crops[SMIAPP_PAD_SINK]->width - / try[i] - * SMIA_LIM(sensor, SCALER_N_MIN), + / try[i] * CCS_LIM(sensor, SCALER_N_MIN), sel->r.width, crops[SMIAPP_PAD_SINK]->height, sel->r.height, @@ -2178,18 +2141,18 @@ static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev, best = this; } - if (SMIA_LIM(sensor, SCALING_CAPABILITY) - == SMIAPP_SCALING_CAPABILITY_HORIZONTAL) + if (CCS_LIM(sensor, SCALING_CAPABILITY) + == CCS_SCALING_CAPABILITY_HORIZONTAL) continue; this = scaling_goodness( subdev, crops[SMIAPP_PAD_SINK]->width / try[i] - * SMIA_LIM(sensor, SCALER_N_MIN), + * CCS_LIM(sensor, SCALER_N_MIN), sel->r.width, crops[SMIAPP_PAD_SINK]->height / try[i] - * SMIA_LIM(sensor, SCALER_N_MIN), + * CCS_LIM(sensor, SCALER_N_MIN), sel->r.height, sel->flags); @@ -2203,12 +2166,12 @@ static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev, sel->r.width = (crops[SMIAPP_PAD_SINK]->width / scale_m - * SMIA_LIM(sensor, SCALER_N_MIN)) & ~1; + * CCS_LIM(sensor, SCALER_N_MIN)) & ~1; if (mode == SMIAPP_SCALING_MODE_BOTH) sel->r.height = (crops[SMIAPP_PAD_SINK]->height / scale_m - * SMIA_LIM(sensor, SCALER_N_MIN)) + * CCS_LIM(sensor, SCALER_N_MIN)) & ~1; else sel->r.height = crops[SMIAPP_PAD_SINK]->height; @@ -2262,10 +2225,9 @@ static int __smiapp_sel_supported(struct v4l2_subdev *subdev, if (ssd == sensor->src && sel->pad == SMIAPP_PAD_SRC) return 0; - if (ssd == sensor->scaler - && sel->pad == SMIAPP_PAD_SINK - && SMIA_LIM(sensor, DIGITAL_CROP_CAPABILITY) - == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) + if (ssd == sensor->scaler && sel->pad == SMIAPP_PAD_SINK && + CCS_LIM(sensor, DIGITAL_CROP_CAPABILITY) + == CCS_DIGITAL_CROP_CAPABILITY_INPUT_CROP) return 0; return -EINVAL; case V4L2_SEL_TGT_NATIVE_SIZE: @@ -2279,9 +2241,8 @@ static int __smiapp_sel_supported(struct v4l2_subdev *subdev, return -EINVAL; if (ssd == sensor->binner) return 0; - if (ssd == sensor->scaler - && SMIA_LIM(sensor, SCALING_CAPABILITY) - != SMIAPP_SCALING_CAPABILITY_NONE) + if (ssd == sensor->scaler && CCS_LIM(sensor, SCALING_CAPABILITY) + != CCS_SCALING_CAPABILITY_NONE) return 0; fallthrough; default: @@ -2345,8 +2306,8 @@ static void smiapp_get_native_size(struct smiapp_subdev *ssd, { r->top = 0; r->left = 0; - r->width = SMIA_LIM(ssd->sensor, X_ADDR_MAX) + 1; - r->height = SMIA_LIM(ssd->sensor, Y_ADDR_MAX) + 1; + r->width = CCS_LIM(ssd->sensor, X_ADDR_MAX) + 1; + r->height = CCS_LIM(ssd->sensor, Y_ADDR_MAX) + 1; } static int __smiapp_get_selection(struct v4l2_subdev *subdev, @@ -2431,10 +2392,10 @@ static int smiapp_set_selection(struct v4l2_subdev *subdev, sel->r.height = SMIAPP_ALIGN_DIM(sel->r.height, sel->flags); sel->r.width = max_t(unsigned int, - SMIA_LIM(sensor, MIN_X_OUTPUT_SIZE), + CCS_LIM(sensor, MIN_X_OUTPUT_SIZE), sel->r.width); sel->r.height = max_t(unsigned int, - SMIA_LIM(sensor, MIN_Y_OUTPUT_SIZE), + CCS_LIM(sensor, MIN_Y_OUTPUT_SIZE), sel->r.height); switch (sel->target) { @@ -3123,12 +3084,6 @@ static int smiapp_probe(struct i2c_client *client) goto out_power_off; } - rval = smiapp_read_all_smia_limits(sensor); - if (rval) { - rval = -ENODEV; - goto out_power_off; - } - rval = ccs_read_all_limits(sensor); if (rval) goto out_power_off; @@ -3163,7 +3118,7 @@ static int smiapp_probe(struct i2c_client *client) goto out_free_ccs_limits; } - if (SMIA_LIM(sensor, BINNING_CAPABILITY)) { + if (CCS_LIM(sensor, BINNING_CAPABILITY)) { u32 val; rval = smiapp_read(sensor, @@ -3200,8 +3155,8 @@ static int smiapp_probe(struct i2c_client *client) } if (sensor->minfo.smiapp_version && - SMIA_LIM(sensor, DATA_TRANSFER_IF_CAPABILITY) & - SMIAPP_DATA_TRANSFER_IF_CAPABILITY_SUPPORTED) { + CCS_LIM(sensor, DATA_TRANSFER_IF_CAPABILITY) & + CCS_DATA_TRANSFER_IF_CAPABILITY_SUPPORTED) { if (device_create_file(&client->dev, &dev_attr_nvm) != 0) { dev_err(&client->dev, "sysfs nvm entry failed\n"); rval = -EBUSY; @@ -3210,22 +3165,22 @@ static int smiapp_probe(struct i2c_client *client) } /* We consider this as profile 0 sensor if any of these are zero. */ - if (!SMIA_LIM(sensor, MIN_OP_SYS_CLK_DIV) || - !SMIA_LIM(sensor, MAX_OP_SYS_CLK_DIV) || - !SMIA_LIM(sensor, MIN_OP_PIX_CLK_DIV) || - !SMIA_LIM(sensor, MAX_OP_PIX_CLK_DIV)) { + if (!CCS_LIM(sensor, MIN_OP_SYS_CLK_DIV) || + !CCS_LIM(sensor, MAX_OP_SYS_CLK_DIV) || + !CCS_LIM(sensor, MIN_OP_PIX_CLK_DIV) || + !CCS_LIM(sensor, MAX_OP_PIX_CLK_DIV)) { sensor->minfo.smiapp_profile = SMIAPP_PROFILE_0; - } else if (SMIA_LIM(sensor, SCALING_CAPABILITY) - != SMIAPP_SCALING_CAPABILITY_NONE) { - if (SMIA_LIM(sensor, SCALING_CAPABILITY) - == SMIAPP_SCALING_CAPABILITY_HORIZONTAL) + } else if (CCS_LIM(sensor, SCALING_CAPABILITY) + != CCS_SCALING_CAPABILITY_NONE) { + if (CCS_LIM(sensor, SCALING_CAPABILITY) + == CCS_SCALING_CAPABILITY_HORIZONTAL) sensor->minfo.smiapp_profile = SMIAPP_PROFILE_1; else sensor->minfo.smiapp_profile = SMIAPP_PROFILE_2; sensor->scaler = &sensor->ssds[sensor->ssds_used]; sensor->ssds_used++; - } else if (SMIA_LIM(sensor, DIGITAL_CROP_CAPABILITY) - == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) { + } else if (CCS_LIM(sensor, DIGITAL_CROP_CAPABILITY) + == CCS_DIGITAL_CROP_CAPABILITY_INPUT_CROP) { sensor->scaler = &sensor->ssds[sensor->ssds_used]; sensor->ssds_used++; } @@ -3234,13 +3189,13 @@ static int smiapp_probe(struct i2c_client *client) sensor->pixel_array = &sensor->ssds[sensor->ssds_used]; sensor->ssds_used++; - sensor->scale_m = SMIA_LIM(sensor, SCALER_N_MIN); + sensor->scale_m = CCS_LIM(sensor, SCALER_N_MIN); /* prepare PLL configuration input values */ sensor->pll.bus_type = SMIAPP_PLL_BUS_TYPE_CSI2; sensor->pll.csi2.lanes = sensor->hwcfg->lanes; sensor->pll.ext_clk_freq_hz = sensor->hwcfg->ext_clk; - sensor->pll.scale_n = SMIA_LIM(sensor, SCALER_N_MIN); + sensor->pll.scale_n = CCS_LIM(sensor, SCALER_N_MIN); /* Profile 0 sensors have no separate OP clock branch. */ if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) sensor->pll.flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS; diff --git a/drivers/media/i2c/smiapp/smiapp-limits.c b/drivers/media/i2c/smiapp/smiapp-limits.c deleted file mode 100644 index de5ee5296713..000000000000 --- a/drivers/media/i2c/smiapp/smiapp-limits.c +++ /dev/null @@ -1,118 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * drivers/media/i2c/smiapp/smiapp-limits.c - * - * Generic driver for SMIA/SMIA++ compliant camera modules - * - * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus - */ - -#include "smiapp.h" - -struct smiapp_reg_limits smiapp_reg_limits[] = { - { SMIAPP_REG_U16_ANALOGUE_GAIN_CAPABILITY, "analogue_gain_capability" }, /* 0 */ - { SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MIN, "analogue_gain_code_min" }, - { SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MAX, "analogue_gain_code_max" }, - { SMIAPP_REG_U8_THS_ZERO_MIN, "ths_zero_min" }, - { SMIAPP_REG_U8_TCLK_TRAIL_MIN, "tclk_trail_min" }, - { SMIAPP_REG_U16_INTEGRATION_TIME_CAPABILITY, "integration_time_capability" }, /* 5 */ - { SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MIN, "coarse_integration_time_min" }, - { SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MAX_MARGIN, "coarse_integration_time_max_margin" }, - { SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN, "fine_integration_time_min" }, - { SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN, "fine_integration_time_max_margin" }, - { SMIAPP_REG_U16_DIGITAL_GAIN_CAPABILITY, "digital_gain_capability" }, /* 10 */ - { SMIAPP_REG_U16_DIGITAL_GAIN_MIN, "digital_gain_min" }, - { SMIAPP_REG_U16_DIGITAL_GAIN_MAX, "digital_gain_max" }, - { SMIAPP_REG_F32_MIN_EXT_CLK_FREQ_HZ, "min_ext_clk_freq_hz" }, - { SMIAPP_REG_F32_MAX_EXT_CLK_FREQ_HZ, "max_ext_clk_freq_hz" }, - { SMIAPP_REG_U16_MIN_PRE_PLL_CLK_DIV, "min_pre_pll_clk_div" }, /* 15 */ - { SMIAPP_REG_U16_MAX_PRE_PLL_CLK_DIV, "max_pre_pll_clk_div" }, - { SMIAPP_REG_F32_MIN_PLL_IP_FREQ_HZ, "min_pll_ip_freq_hz" }, - { SMIAPP_REG_F32_MAX_PLL_IP_FREQ_HZ, "max_pll_ip_freq_hz" }, - { SMIAPP_REG_U16_MIN_PLL_MULTIPLIER, "min_pll_multiplier" }, - { SMIAPP_REG_U16_MAX_PLL_MULTIPLIER, "max_pll_multiplier" }, /* 20 */ - { SMIAPP_REG_F32_MIN_PLL_OP_FREQ_HZ, "min_pll_op_freq_hz" }, - { SMIAPP_REG_F32_MAX_PLL_OP_FREQ_HZ, "max_pll_op_freq_hz" }, - { SMIAPP_REG_U16_MIN_VT_SYS_CLK_DIV, "min_vt_sys_clk_div" }, - { SMIAPP_REG_U16_MAX_VT_SYS_CLK_DIV, "max_vt_sys_clk_div" }, - { SMIAPP_REG_F32_MIN_VT_SYS_CLK_FREQ_HZ, "min_vt_sys_clk_freq_hz" }, /* 25 */ - { SMIAPP_REG_F32_MAX_VT_SYS_CLK_FREQ_HZ, "max_vt_sys_clk_freq_hz" }, - { SMIAPP_REG_F32_MIN_VT_PIX_CLK_FREQ_HZ, "min_vt_pix_clk_freq_hz" }, - { SMIAPP_REG_F32_MAX_VT_PIX_CLK_FREQ_HZ, "max_vt_pix_clk_freq_hz" }, - { SMIAPP_REG_U16_MIN_VT_PIX_CLK_DIV, "min_vt_pix_clk_div" }, - { SMIAPP_REG_U16_MAX_VT_PIX_CLK_DIV, "max_vt_pix_clk_div" }, /* 30 */ - { SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES, "min_frame_length_lines" }, - { SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES, "max_frame_length_lines" }, - { SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK, "min_line_length_pck" }, - { SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK, "max_line_length_pck" }, - { SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK, "min_line_blanking_pck" }, /* 35 */ - { SMIAPP_REG_U16_MIN_FRAME_BLANKING_LINES, "min_frame_blanking_lines" }, - { SMIAPP_REG_U8_MIN_LINE_LENGTH_PCK_STEP_SIZE, "min_line_length_pck_step_size" }, - { SMIAPP_REG_U16_MIN_OP_SYS_CLK_DIV, "min_op_sys_clk_div" }, - { SMIAPP_REG_U16_MAX_OP_SYS_CLK_DIV, "max_op_sys_clk_div" }, - { SMIAPP_REG_F32_MIN_OP_SYS_CLK_FREQ_HZ, "min_op_sys_clk_freq_hz" }, /* 40 */ - { SMIAPP_REG_F32_MAX_OP_SYS_CLK_FREQ_HZ, "max_op_sys_clk_freq_hz" }, - { SMIAPP_REG_U16_MIN_OP_PIX_CLK_DIV, "min_op_pix_clk_div" }, - { SMIAPP_REG_U16_MAX_OP_PIX_CLK_DIV, "max_op_pix_clk_div" }, - { SMIAPP_REG_F32_MIN_OP_PIX_CLK_FREQ_HZ, "min_op_pix_clk_freq_hz" }, - { SMIAPP_REG_F32_MAX_OP_PIX_CLK_FREQ_HZ, "max_op_pix_clk_freq_hz" }, /* 45 */ - { SMIAPP_REG_U16_X_ADDR_MIN, "x_addr_min" }, - { SMIAPP_REG_U16_Y_ADDR_MIN, "y_addr_min" }, - { SMIAPP_REG_U16_X_ADDR_MAX, "x_addr_max" }, - { SMIAPP_REG_U16_Y_ADDR_MAX, "y_addr_max" }, - { SMIAPP_REG_U16_MIN_X_OUTPUT_SIZE, "min_x_output_size" }, /* 50 */ - { SMIAPP_REG_U16_MIN_Y_OUTPUT_SIZE, "min_y_output_size" }, - { SMIAPP_REG_U16_MAX_X_OUTPUT_SIZE, "max_x_output_size" }, - { SMIAPP_REG_U16_MAX_Y_OUTPUT_SIZE, "max_y_output_size" }, - { SMIAPP_REG_U16_MIN_EVEN_INC, "min_even_inc" }, - { SMIAPP_REG_U16_MAX_EVEN_INC, "max_even_inc" }, /* 55 */ - { SMIAPP_REG_U16_MIN_ODD_INC, "min_odd_inc" }, - { SMIAPP_REG_U16_MAX_ODD_INC, "max_odd_inc" }, - { SMIAPP_REG_U16_SCALING_CAPABILITY, "scaling_capability" }, - { SMIAPP_REG_U16_SCALER_M_MIN, "scaler_m_min" }, - { SMIAPP_REG_U16_SCALER_M_MAX, "scaler_m_max" }, /* 60 */ - { SMIAPP_REG_U16_SCALER_N_MIN, "scaler_n_min" }, - { SMIAPP_REG_U16_SCALER_N_MAX, "scaler_n_max" }, - { SMIAPP_REG_U16_SPATIAL_SAMPLING_CAPABILITY, "spatial_sampling_capability" }, - { SMIAPP_REG_U8_DIGITAL_CROP_CAPABILITY, "digital_crop_capability" }, - { SMIAPP_REG_U16_COMPRESSION_CAPABILITY, "compression_capability" }, /* 65 */ - { SMIAPP_REG_U8_FIFO_SUPPORT_CAPABILITY, "fifo_support_capability" }, - { SMIAPP_REG_U8_DPHY_CTRL_CAPABILITY, "dphy_ctrl_capability" }, - { SMIAPP_REG_U8_CSI_LANE_MODE_CAPABILITY, "csi_lane_mode_capability" }, - { SMIAPP_REG_U8_CSI_SIGNALLING_MODE_CAPABILITY, "csi_signalling_mode_capability" }, - { SMIAPP_REG_U8_FAST_STANDBY_CAPABILITY, "fast_standby_capability" }, /* 70 */ - { SMIAPP_REG_U8_CCI_ADDRESS_CONTROL_CAPABILITY, "cci_address_control_capability" }, - { SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS, "max_per_lane_bitrate_1_lane_mode_mbps" }, - { SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS, "max_per_lane_bitrate_2_lane_mode_mbps" }, - { SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS, "max_per_lane_bitrate_3_lane_mode_mbps" }, - { SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS, "max_per_lane_bitrate_4_lane_mode_mbps" }, /* 75 */ - { SMIAPP_REG_U8_TEMP_SENSOR_CAPABILITY, "temp_sensor_capability" }, - { SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES_BIN, "min_frame_length_lines_bin" }, - { SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES_BIN, "max_frame_length_lines_bin" }, - { SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK_BIN, "min_line_length_pck_bin" }, - { SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK_BIN, "max_line_length_pck_bin" }, /* 80 */ - { SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK_BIN, "min_line_blanking_pck_bin" }, - { SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN_BIN, "fine_integration_time_min_bin" }, - { SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN, "fine_integration_time_max_margin_bin" }, - { SMIAPP_REG_U8_BINNING_CAPABILITY, "binning_capability" }, - { SMIAPP_REG_U8_BINNING_WEIGHTING_CAPABILITY, "binning_weighting_capability" }, /* 85 */ - { SMIAPP_REG_U8_DATA_TRANSFER_IF_CAPABILITY, "data_transfer_if_capability" }, - { SMIAPP_REG_U8_SHADING_CORRECTION_CAPABILITY, "shading_correction_capability" }, - { SMIAPP_REG_U8_GREEN_IMBALANCE_CAPABILITY, "green_imbalance_capability" }, - { SMIAPP_REG_U8_BLACK_LEVEL_CAPABILITY, "black_level_capability" }, - { SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_CAPABILITY, "module_specific_correction_capability" }, /* 90 */ - { SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY, "defect_correction_capability" }, - { SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY_2, "defect_correction_capability_2" }, - { SMIAPP_REG_U8_EDOF_CAPABILITY, "edof_capability" }, - { SMIAPP_REG_U8_COLOUR_FEEDBACK_CAPABILITY, "colour_feedback_capability" }, - { SMIAPP_REG_U8_ESTIMATION_MODE_CAPABILITY, "estimation_mode_capability" }, /* 95 */ - { SMIAPP_REG_U8_ESTIMATION_ZONE_CAPABILITY, "estimation_zone_capability" }, - { SMIAPP_REG_U16_CAPABILITY_TRDY_MIN, "capability_trdy_min" }, - { SMIAPP_REG_U8_FLASH_MODE_CAPABILITY, "flash_mode_capability" }, - { SMIAPP_REG_U8_ACTUATOR_CAPABILITY, "actuator_capability" }, - { SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_1, "bracketing_lut_capability_1" }, /* 100 */ - { SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_2, "bracketing_lut_capability_2" }, - { SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_STEP, "analogue_gain_code_step" }, - { 0, NULL }, -}; diff --git a/drivers/media/i2c/smiapp/smiapp-limits.h b/drivers/media/i2c/smiapp/smiapp-limits.h deleted file mode 100644 index dbac0b4975f9..000000000000 --- a/drivers/media/i2c/smiapp/smiapp-limits.h +++ /dev/null @@ -1,114 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * drivers/media/i2c/smiapp/smiapp-limits.h - * - * Generic driver for SMIA/SMIA++ compliant camera modules - * - * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus - */ - -#define SMIAPP_LIMIT_ANALOGUE_GAIN_CAPABILITY 0 -#define SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN 1 -#define SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX 2 -#define SMIAPP_LIMIT_THS_ZERO_MIN 3 -#define SMIAPP_LIMIT_TCLK_TRAIL_MIN 4 -#define SMIAPP_LIMIT_INTEGRATION_TIME_CAPABILITY 5 -#define SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MIN 6 -#define SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN 7 -#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN 8 -#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN 9 -#define SMIAPP_LIMIT_DIGITAL_GAIN_CAPABILITY 10 -#define SMIAPP_LIMIT_DIGITAL_GAIN_MIN 11 -#define SMIAPP_LIMIT_DIGITAL_GAIN_MAX 12 -#define SMIAPP_LIMIT_MIN_EXT_CLK_FREQ_HZ 13 -#define SMIAPP_LIMIT_MAX_EXT_CLK_FREQ_HZ 14 -#define SMIAPP_LIMIT_MIN_PRE_PLL_CLK_DIV 15 -#define SMIAPP_LIMIT_MAX_PRE_PLL_CLK_DIV 16 -#define SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ 17 -#define SMIAPP_LIMIT_MAX_PLL_IP_FREQ_HZ 18 -#define SMIAPP_LIMIT_MIN_PLL_MULTIPLIER 19 -#define SMIAPP_LIMIT_MAX_PLL_MULTIPLIER 20 -#define SMIAPP_LIMIT_MIN_PLL_OP_FREQ_HZ 21 -#define SMIAPP_LIMIT_MAX_PLL_OP_FREQ_HZ 22 -#define SMIAPP_LIMIT_MIN_VT_SYS_CLK_DIV 23 -#define SMIAPP_LIMIT_MAX_VT_SYS_CLK_DIV 24 -#define SMIAPP_LIMIT_MIN_VT_SYS_CLK_FREQ_HZ 25 -#define SMIAPP_LIMIT_MAX_VT_SYS_CLK_FREQ_HZ 26 -#define SMIAPP_LIMIT_MIN_VT_PIX_CLK_FREQ_HZ 27 -#define SMIAPP_LIMIT_MAX_VT_PIX_CLK_FREQ_HZ 28 -#define SMIAPP_LIMIT_MIN_VT_PIX_CLK_DIV 29 -#define SMIAPP_LIMIT_MAX_VT_PIX_CLK_DIV 30 -#define SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES 31 -#define SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES 32 -#define SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK 33 -#define SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK 34 -#define SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK 35 -#define SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES 36 -#define SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_STEP_SIZE 37 -#define SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV 38 -#define SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV 39 -#define SMIAPP_LIMIT_MIN_OP_SYS_CLK_FREQ_HZ 40 -#define SMIAPP_LIMIT_MAX_OP_SYS_CLK_FREQ_HZ 41 -#define SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV 42 -#define SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV 43 -#define SMIAPP_LIMIT_MIN_OP_PIX_CLK_FREQ_HZ 44 -#define SMIAPP_LIMIT_MAX_OP_PIX_CLK_FREQ_HZ 45 -#define SMIAPP_LIMIT_X_ADDR_MIN 46 -#define SMIAPP_LIMIT_Y_ADDR_MIN 47 -#define SMIAPP_LIMIT_X_ADDR_MAX 48 -#define SMIAPP_LIMIT_Y_ADDR_MAX 49 -#define SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE 50 -#define SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE 51 -#define SMIAPP_LIMIT_MAX_X_OUTPUT_SIZE 52 -#define SMIAPP_LIMIT_MAX_Y_OUTPUT_SIZE 53 -#define SMIAPP_LIMIT_MIN_EVEN_INC 54 -#define SMIAPP_LIMIT_MAX_EVEN_INC 55 -#define SMIAPP_LIMIT_MIN_ODD_INC 56 -#define SMIAPP_LIMIT_MAX_ODD_INC 57 -#define SMIAPP_LIMIT_SCALING_CAPABILITY 58 -#define SMIAPP_LIMIT_SCALER_M_MIN 59 -#define SMIAPP_LIMIT_SCALER_M_MAX 60 -#define SMIAPP_LIMIT_SCALER_N_MIN 61 -#define SMIAPP_LIMIT_SCALER_N_MAX 62 -#define SMIAPP_LIMIT_SPATIAL_SAMPLING_CAPABILITY 63 -#define SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY 64 -#define SMIAPP_LIMIT_COMPRESSION_CAPABILITY 65 -#define SMIAPP_LIMIT_FIFO_SUPPORT_CAPABILITY 66 -#define SMIAPP_LIMIT_DPHY_CTRL_CAPABILITY 67 -#define SMIAPP_LIMIT_CSI_LANE_MODE_CAPABILITY 68 -#define SMIAPP_LIMIT_CSI_SIGNALLING_MODE_CAPABILITY 69 -#define SMIAPP_LIMIT_FAST_STANDBY_CAPABILITY 70 -#define SMIAPP_LIMIT_CCI_ADDRESS_CONTROL_CAPABILITY 71 -#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS 72 -#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS 73 -#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS 74 -#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS 75 -#define SMIAPP_LIMIT_TEMP_SENSOR_CAPABILITY 76 -#define SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN 77 -#define SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN 78 -#define SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN 79 -#define SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN 80 -#define SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN 81 -#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN_BIN 82 -#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN 83 -#define SMIAPP_LIMIT_BINNING_CAPABILITY 84 -#define SMIAPP_LIMIT_BINNING_WEIGHTING_CAPABILITY 85 -#define SMIAPP_LIMIT_DATA_TRANSFER_IF_CAPABILITY 86 -#define SMIAPP_LIMIT_SHADING_CORRECTION_CAPABILITY 87 -#define SMIAPP_LIMIT_GREEN_IMBALANCE_CAPABILITY 88 -#define SMIAPP_LIMIT_BLACK_LEVEL_CAPABILITY 89 -#define SMIAPP_LIMIT_MODULE_SPECIFIC_CORRECTION_CAPABILITY 90 -#define SMIAPP_LIMIT_DEFECT_CORRECTION_CAPABILITY 91 -#define SMIAPP_LIMIT_DEFECT_CORRECTION_CAPABILITY_2 92 -#define SMIAPP_LIMIT_EDOF_CAPABILITY 93 -#define SMIAPP_LIMIT_COLOUR_FEEDBACK_CAPABILITY 94 -#define SMIAPP_LIMIT_ESTIMATION_MODE_CAPABILITY 95 -#define SMIAPP_LIMIT_ESTIMATION_ZONE_CAPABILITY 96 -#define SMIAPP_LIMIT_CAPABILITY_TRDY_MIN 97 -#define SMIAPP_LIMIT_FLASH_MODE_CAPABILITY 98 -#define SMIAPP_LIMIT_ACTUATOR_CAPABILITY 99 -#define SMIAPP_LIMIT_BRACKETING_LUT_CAPABILITY_1 100 -#define SMIAPP_LIMIT_BRACKETING_LUT_CAPABILITY_2 101 -#define SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_STEP 102 -#define SMIAPP_LIMIT_LAST 103 diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.c b/drivers/media/i2c/smiapp/smiapp-quirk.c index 308ca0b03f5a..24630c7650d2 100644 --- a/drivers/media/i2c/smiapp/smiapp-quirk.c +++ b/drivers/media/i2c/smiapp/smiapp-quirk.c @@ -10,6 +10,8 @@ #include +#include "ccs-limits.h" + #include "smiapp.h" static int smiapp_write_8(struct smiapp_sensor *sensor, u16 reg, u8 val) @@ -36,17 +38,6 @@ static int smiapp_write_8s(struct smiapp_sensor *sensor, return 0; } -void smiapp_replace_limit(struct smiapp_sensor *sensor, - u32 limit, u32 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - - dev_dbg(&client->dev, "quirk: 0x%8.8x \"%s\" = %d, 0x%x\n", - smiapp_reg_limits[limit].addr, - smiapp_reg_limits[limit].what, val, val); - sensor->limits[limit] = val; -} - static int jt8ew9_limits(struct smiapp_sensor *sensor) { if (sensor->minfo.revision_number_major < 0x03) @@ -54,9 +45,8 @@ static int jt8ew9_limits(struct smiapp_sensor *sensor) /* Below 24 gain doesn't have effect at all, */ /* but ~59 is needed for full dynamic range */ - smiapp_replace_limit(sensor, SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN, 59); - smiapp_replace_limit( - sensor, SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX, 6000); + ccs_replace_limit(sensor, CCS_L_ANALOG_GAIN_CODE_MIN, 0, 59); + ccs_replace_limit(sensor, CCS_L_ANALOG_GAIN_CODE_MAX, 0, 6000); return 0; } @@ -126,9 +116,8 @@ const struct smiapp_quirk smiapp_imx125es_quirk = { static int jt8ev1_limits(struct smiapp_sensor *sensor) { - smiapp_replace_limit(sensor, SMIAPP_LIMIT_X_ADDR_MAX, 4271); - smiapp_replace_limit(sensor, - SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN, 184); + ccs_replace_limit(sensor, CCS_L_X_ADDR_MAX, 0, 4271); + ccs_replace_limit(sensor, CCS_L_MIN_LINE_BLANKING_PCK_BIN, 0, 184); return 0; } @@ -221,7 +210,7 @@ const struct smiapp_quirk smiapp_jt8ev1_quirk = { static int tcm8500md_limits(struct smiapp_sensor *sensor) { - smiapp_replace_limit(sensor, SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ, 2700000); + ccs_replace_limit(sensor, CCS_L_MIN_PLL_IP_CLK_FREQ_MHZ, 0, 2700000); return 0; } diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.h b/drivers/media/i2c/smiapp/smiapp-quirk.h index 17505be60c1d..8a479f17cd19 100644 --- a/drivers/media/i2c/smiapp/smiapp-quirk.h +++ b/drivers/media/i2c/smiapp/smiapp-quirk.h @@ -55,9 +55,6 @@ struct smiapp_reg_8 { u8 val; }; -void smiapp_replace_limit(struct smiapp_sensor *sensor, - u32 limit, u32 val); - #define SMIAPP_MK_QUIRK_REG_8(_reg, _val) \ { \ .reg = (u16)_reg, \ diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h index 08ca1b3d1b2f..1a67cf485dcc 100644 --- a/drivers/media/i2c/smiapp/smiapp.h +++ b/drivers/media/i2c/smiapp/smiapp.h @@ -84,8 +84,6 @@ struct smiapp_hwconfig { struct smiapp_flash_strobe_parms *strobe_setup; }; -#include "smiapp-limits.h" - struct smiapp_quirk; #define SMIAPP_MODULE_IDENT_FLAG_REV_LE (1 << 0) @@ -167,13 +165,6 @@ struct smiapp_module_info { .flags = 0, \ .name = _name, } -struct smiapp_reg_limits { - u32 addr; - char *what; -}; - -extern struct smiapp_reg_limits smiapp_reg_limits[]; - struct smiapp_csi_data_format { u32 code; u8 width; @@ -227,7 +218,6 @@ struct smiapp_sensor { struct regulator *vana; struct clk *ext_clk; struct gpio_desc *xshutdown; - u32 limits[SMIAPP_LIMIT_LAST]; void *ccs_limits; u8 nbinning_subtypes; struct smiapp_binning_subtype binning_subtypes[SMIAPP_BINNING_SUBTYPES]; -- cgit v1.2.3 From fd9065812c7b4537f73c0f83cb5e955bddc070ad Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 10 Feb 2020 12:53:14 +0100 Subject: media: smiapp: Obtain frame descriptor from CCS limits Obtain the frame descriptor from the CCS limits, instead of reading them directly from the frame descriptor registers. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 70 +++++++++++++++------------------- 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 2c1a13507965..daeff6186727 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -228,34 +228,29 @@ out_err: static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - u32 fmt_model_type, fmt_model_subtype, ncol_desc, nrow_desc; + u8 fmt_model_type, fmt_model_subtype, ncol_desc, nrow_desc; unsigned int i; int pixel_count = 0; int line_count = 0; - int rval; - - rval = smiapp_read(sensor, SMIAPP_REG_U8_FRAME_FORMAT_MODEL_TYPE, - &fmt_model_type); - if (rval) - return rval; - rval = smiapp_read(sensor, SMIAPP_REG_U8_FRAME_FORMAT_MODEL_SUBTYPE, - &fmt_model_subtype); - if (rval) - return rval; + fmt_model_type = CCS_LIM(sensor, FRAME_FORMAT_MODEL_TYPE); + fmt_model_subtype = CCS_LIM(sensor, FRAME_FORMAT_MODEL_SUBTYPE); ncol_desc = (fmt_model_subtype - & SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_MASK) - >> SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_SHIFT; + & CCS_FRAME_FORMAT_MODEL_SUBTYPE_COLUMNS_MASK) + >> CCS_FRAME_FORMAT_MODEL_SUBTYPE_COLUMNS_SHIFT; nrow_desc = fmt_model_subtype - & SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NROWS_MASK; + & CCS_FRAME_FORMAT_MODEL_SUBTYPE_ROWS_MASK; dev_dbg(&client->dev, "format_model_type %s\n", - fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE + fmt_model_type == CCS_FRAME_FORMAT_MODEL_TYPE_2_BYTE ? "2 byte" : - fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE + fmt_model_type == CCS_FRAME_FORMAT_MODEL_TYPE_4_BYTE ? "4 byte" : "is simply bad"); + dev_dbg(&client->dev, "%u column and %u row descriptors\n", + ncol_desc, nrow_desc); + for (i = 0; i < ncol_desc + nrow_desc; i++) { u32 desc; u32 pixelcode; @@ -264,29 +259,24 @@ static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor) char *what; u32 reg; - if (fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE) { - reg = SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(i); - rval = smiapp_read(sensor, reg, &desc); - if (rval) - return rval; + if (fmt_model_type == CCS_FRAME_FORMAT_MODEL_TYPE_2_BYTE) { + desc = CCS_LIM_AT(sensor, FRAME_FORMAT_DESCRIPTOR, i); pixelcode = (desc - & SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_MASK) - >> SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_SHIFT; - pixels = desc & SMIAPP_FRAME_FORMAT_DESC_2_PIXELS_MASK; + & CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MASK) + >> CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_SHIFT; + pixels = desc & CCS_FRAME_FORMAT_DESCRIPTOR_PIXELS_MASK; } else if (fmt_model_type - == SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE) { - reg = SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(i); - rval = smiapp_read(sensor, reg, &desc); - if (rval) - return rval; + == CCS_FRAME_FORMAT_MODEL_TYPE_4_BYTE) { + desc = CCS_LIM_AT(sensor, FRAME_FORMAT_DESCRIPTOR_4, i); pixelcode = (desc - & SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_MASK) - >> SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_SHIFT; - pixels = desc & SMIAPP_FRAME_FORMAT_DESC_4_PIXELS_MASK; + & CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MASK) + >> CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_SHIFT; + pixels = desc & + CCS_FRAME_FORMAT_DESCRIPTOR_4_PIXELS_MASK; } else { dev_dbg(&client->dev, "invalid frame format model type %d\n", @@ -300,19 +290,19 @@ static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor) which = "rows"; switch (pixelcode) { - case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED: + case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_EMBEDDED: what = "embedded"; break; - case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DUMMY: + case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_DUMMY_PIXEL: what = "dummy"; break; - case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_BLACK: + case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_BLACK_PIXEL: what = "black"; break; - case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DARK: + case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_DARK_PIXEL: what = "dark"; break; - case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE: + case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_VISIBLE_PIXEL: what = "visible"; break; default: @@ -326,7 +316,7 @@ static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor) if (i < ncol_desc) { if (pixelcode == - SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE) + CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_VISIBLE_PIXEL) sensor->visible_pixel_start = pixel_count; pixel_count += pixels; continue; @@ -334,13 +324,13 @@ static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor) /* Handle row descriptors */ switch (pixelcode) { - case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED: + case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_EMBEDDED: if (sensor->embedded_end) break; sensor->embedded_start = line_count; sensor->embedded_end = line_count + pixels; break; - case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE: + case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_VISIBLE_PIXEL: sensor->image_start = line_count; break; } -- cgit v1.2.3 From 642d7c3eafaac33b6c09f220c7d72a58929b913a Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 10 Feb 2020 15:02:32 +0100 Subject: media: smiapp: Use CCS limits in reading data format descriptors The CCS limits have the information so use it instead. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index daeff6186727..c332b6ecf0bd 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -842,10 +842,7 @@ static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor) unsigned int i, pixel_order; int rval; - rval = smiapp_read( - sensor, SMIAPP_REG_U8_DATA_FORMAT_MODEL_TYPE, &type); - if (rval) - return rval; + type = CCS_LIM(sensor, DATA_FORMAT_MODEL_TYPE); dev_dbg(&client->dev, "data_format_model_type %d\n", type); @@ -863,11 +860,11 @@ static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor) pixel_order_str[pixel_order]); switch (type) { - case SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL: + case CCS_DATA_FORMAT_MODEL_TYPE_NORMAL: n = SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL_N; break; - case SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED: - n = SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED_N; + case CCS_DATA_FORMAT_MODEL_TYPE_EXTENDED: + n = CCS_LIM_DATA_FORMAT_DESCRIPTOR_MAX_N + 1; break; default: return -EINVAL; @@ -879,11 +876,7 @@ static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor) for (i = 0; i < n; i++) { unsigned int fmt, j; - rval = smiapp_read( - sensor, - SMIAPP_REG_U16_DATA_FORMAT_DESCRIPTOR(i), &fmt); - if (rval) - return rval; + fmt = CCS_LIM_AT(sensor, DATA_FORMAT_DESCRIPTOR, i); dev_dbg(&client->dev, "%u: bpp %u, compressed %u\n", i, fmt >> 8, (u8)fmt); @@ -895,7 +888,10 @@ static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor) if (f->pixel_order != SMIAPP_PIXEL_ORDER_GRBG) continue; - if (f->width != fmt >> 8 || f->compressed != (u8)fmt) + if (f->width != fmt >> + CCS_DATA_FORMAT_DESCRIPTOR_UNCOMPRESSED_SHIFT || + f->compressed != + (fmt & CCS_DATA_FORMAT_DESCRIPTOR_COMPRESSED_MASK)) continue; dev_dbg(&client->dev, "jolly good! %d\n", j); -- cgit v1.2.3 From 19a435f9ea48f296527f713e0afb25d89527c63b Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 11 Feb 2020 10:37:47 +0100 Subject: media: smiapp: Use CCS limits in reading binning capabilities Use CCS limits for obtaining binning capabilities and subtypes. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index c332b6ecf0bd..d786f91c1eae 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -3105,26 +3105,17 @@ static int smiapp_probe(struct i2c_client *client) } if (CCS_LIM(sensor, BINNING_CAPABILITY)) { - u32 val; - - rval = smiapp_read(sensor, - SMIAPP_REG_U8_BINNING_SUBTYPES, &val); - if (rval < 0) { - rval = -ENODEV; - goto out_free_ccs_limits; - } - sensor->nbinning_subtypes = min_t(u8, val, - SMIAPP_BINNING_SUBTYPES); + sensor->nbinning_subtypes = + min_t(u8, CCS_LIM(sensor, BINNING_SUB_TYPES), + CCS_LIM_BINNING_SUB_TYPE_MAX_N); for (i = 0; i < sensor->nbinning_subtypes; i++) { - rval = smiapp_read( - sensor, SMIAPP_REG_U8_BINNING_TYPE_n(i), &val); - if (rval < 0) { - rval = -ENODEV; - goto out_free_ccs_limits; - } - sensor->binning_subtypes[i] = - *(struct smiapp_binning_subtype *)&val; + sensor->binning_subtypes[i].horizontal = + CCS_LIM_AT(sensor, BINNING_SUB_TYPE, i) >> + CCS_BINNING_SUB_TYPE_COLUMN_SHIFT; + sensor->binning_subtypes[i].vertical = + CCS_LIM_AT(sensor, BINNING_SUB_TYPE, i) & + CCS_BINNING_SUB_TYPE_ROW_MASK; dev_dbg(&client->dev, "binning %xx%x\n", sensor->binning_subtypes[i].horizontal, -- cgit v1.2.3 From 42aab58f456a28a5d4b175e7cf7d43276ed3d06b Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 11 Feb 2020 10:18:31 +0100 Subject: media: smiapp: Use CCS registers Switch to CCS standard registers where they exist. The still relevant SMIA registers are left as-is and the redundant ones are removed. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 272 ++++++++++++++------------------- drivers/media/i2c/smiapp/smiapp.h | 4 +- 2 files changed, 118 insertions(+), 158 deletions(-) diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index d786f91c1eae..382a2d14f0f4 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -28,7 +28,6 @@ #include #include "ccs-limits.h" -#include "ccs-regs.h" #include "smiapp.h" #define SMIAPP_ALIGN_DIM(dim, flags) \ @@ -357,40 +356,34 @@ static int smiapp_pll_configure(struct smiapp_sensor *sensor) struct smiapp_pll *pll = &sensor->pll; int rval; - rval = smiapp_write( - sensor, SMIAPP_REG_U16_VT_PIX_CLK_DIV, pll->vt.pix_clk_div); + rval = ccs_write(sensor, VT_PIX_CLK_DIV, pll->vt.pix_clk_div); if (rval < 0) return rval; - rval = smiapp_write( - sensor, SMIAPP_REG_U16_VT_SYS_CLK_DIV, pll->vt.sys_clk_div); + rval = ccs_write(sensor, VT_SYS_CLK_DIV, pll->vt.sys_clk_div); if (rval < 0) return rval; - rval = smiapp_write( - sensor, SMIAPP_REG_U16_PRE_PLL_CLK_DIV, pll->pre_pll_clk_div); + rval = ccs_write(sensor, PRE_PLL_CLK_DIV, pll->pre_pll_clk_div); if (rval < 0) return rval; - rval = smiapp_write( - sensor, SMIAPP_REG_U16_PLL_MULTIPLIER, pll->pll_multiplier); + rval = ccs_write(sensor, PLL_MULTIPLIER, pll->pll_multiplier); if (rval < 0) return rval; /* Lane op clock ratio does not apply here. */ - rval = smiapp_write( - sensor, SMIAPP_REG_U32_REQUESTED_LINK_BIT_RATE_MBPS, - DIV_ROUND_UP(pll->op.sys_clk_freq_hz, 1000000 / 256 / 256)); + rval = ccs_write(sensor, REQUESTED_LINK_RATE, + DIV_ROUND_UP(pll->op.sys_clk_freq_hz, + 1000000 / 256 / 256)); if (rval < 0 || sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) return rval; - rval = smiapp_write( - sensor, SMIAPP_REG_U16_OP_PIX_CLK_DIV, pll->op.pix_clk_div); + rval = ccs_write(sensor, OP_PIX_CLK_DIV, pll->op.pix_clk_div); if (rval < 0) return rval; - return smiapp_write( - sensor, SMIAPP_REG_U16_OP_SYS_CLK_DIV, pll->op.sys_clk_div); + return ccs_write(sensor, OP_SYS_CLK_DIV, pll->op.sys_clk_div); } static int smiapp_pll_try(struct smiapp_sensor *sensor, @@ -522,10 +515,10 @@ static u32 smiapp_pixel_order(struct smiapp_sensor *sensor) if (sensor->hflip) { if (sensor->hflip->val) - flip |= SMIAPP_IMAGE_ORIENTATION_HFLIP; + flip |= CCS_IMAGE_ORIENTATION_HORIZONTAL_MIRROR; if (sensor->vflip->val) - flip |= SMIAPP_IMAGE_ORIENTATION_VFLIP; + flip |= CCS_IMAGE_ORIENTATION_VERTICAL_FLIP; } flip ^= sensor->hvflip_inv_mask; @@ -585,10 +578,10 @@ static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl) return -EBUSY; if (sensor->hflip->val) - orient |= SMIAPP_IMAGE_ORIENTATION_HFLIP; + orient |= CCS_IMAGE_ORIENTATION_HORIZONTAL_MIRROR; if (sensor->vflip->val) - orient |= SMIAPP_IMAGE_ORIENTATION_VFLIP; + orient |= CCS_IMAGE_ORIENTATION_VERTICAL_FLIP; orient ^= sensor->hvflip_inv_mask; @@ -633,60 +626,50 @@ static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl) switch (ctrl->id) { case V4L2_CID_ANALOGUE_GAIN: - rval = smiapp_write( - sensor, - SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GLOBAL, ctrl->val); + rval = ccs_write(sensor, ANALOG_GAIN_CODE_GLOBAL, ctrl->val); break; case V4L2_CID_EXPOSURE: - rval = smiapp_write( - sensor, - SMIAPP_REG_U16_COARSE_INTEGRATION_TIME, ctrl->val); + rval = ccs_write(sensor, COARSE_INTEGRATION_TIME, ctrl->val); break; case V4L2_CID_HFLIP: case V4L2_CID_VFLIP: - rval = smiapp_write(sensor, SMIAPP_REG_U8_IMAGE_ORIENTATION, - orient); + rval = ccs_write(sensor, IMAGE_ORIENTATION, orient); break; case V4L2_CID_VBLANK: - rval = smiapp_write( - sensor, SMIAPP_REG_U16_FRAME_LENGTH_LINES, - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height - + ctrl->val); + rval = ccs_write(sensor, FRAME_LENGTH_LINES, + sensor->pixel_array->crop[ + SMIAPP_PA_PAD_SRC].height + + ctrl->val); break; case V4L2_CID_HBLANK: - rval = smiapp_write( - sensor, SMIAPP_REG_U16_LINE_LENGTH_PCK, - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width - + ctrl->val); + rval = ccs_write(sensor, LINE_LENGTH_PCK, + sensor->pixel_array->crop[ + SMIAPP_PA_PAD_SRC].width + + ctrl->val); break; case V4L2_CID_TEST_PATTERN: - rval = smiapp_write( - sensor, SMIAPP_REG_U16_TEST_PATTERN_MODE, ctrl->val); + rval = ccs_write(sensor, TEST_PATTERN_MODE, ctrl->val); break; case V4L2_CID_TEST_PATTERN_RED: - rval = smiapp_write( - sensor, SMIAPP_REG_U16_TEST_DATA_RED, ctrl->val); + rval = ccs_write(sensor, TEST_DATA_RED, ctrl->val); break; case V4L2_CID_TEST_PATTERN_GREENR: - rval = smiapp_write( - sensor, SMIAPP_REG_U16_TEST_DATA_GREENR, ctrl->val); + rval = ccs_write(sensor, TEST_DATA_GREENR, ctrl->val); break; case V4L2_CID_TEST_PATTERN_BLUE: - rval = smiapp_write( - sensor, SMIAPP_REG_U16_TEST_DATA_BLUE, ctrl->val); + rval = ccs_write(sensor, TEST_DATA_BLUE, ctrl->val); break; case V4L2_CID_TEST_PATTERN_GREENB: - rval = smiapp_write( - sensor, SMIAPP_REG_U16_TEST_DATA_GREENB, ctrl->val); + rval = ccs_write(sensor, TEST_DATA_GREENB, ctrl->val); break; case V4L2_CID_PIXEL_RATE: @@ -846,8 +829,7 @@ static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor) dev_dbg(&client->dev, "data_format_model_type %d\n", type); - rval = smiapp_read(sensor, SMIAPP_REG_U8_PIXEL_ORDER, - &pixel_order); + rval = ccs_read(sensor, PIXEL_ORDER, &pixel_order); if (rval) return rval; @@ -1054,22 +1036,20 @@ static int smiapp_read_nvm_page(struct smiapp_sensor *sensor, u32 p, u8 *nvm, *status = 0; - rval = smiapp_write(sensor, - SMIAPP_REG_U8_DATA_TRANSFER_IF_1_PAGE_SELECT, p); + rval = ccs_write(sensor, DATA_TRANSFER_IF_1_PAGE_SELECT, p); if (rval) return rval; - rval = smiapp_write(sensor, SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL, - SMIAPP_DATA_TRANSFER_IF_1_CTRL_EN); + rval = ccs_write(sensor, DATA_TRANSFER_IF_1_CTRL, + CCS_DATA_TRANSFER_IF_1_CTRL_ENABLE); if (rval) return rval; - rval = smiapp_read(sensor, SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS, - &s); + rval = ccs_read(sensor, DATA_TRANSFER_IF_1_STATUS, &s); if (rval) return rval; - if (s & SMIAPP_DATA_TRANSFER_IF_1_STATUS_EUSAGE) { + if (s & CCS_DATA_TRANSFER_IF_1_STATUS_IMPROPER_IF_USAGE) { *status = s; return -ENODATA; } @@ -1077,14 +1057,10 @@ static int smiapp_read_nvm_page(struct smiapp_sensor *sensor, u32 p, u8 *nvm, if (CCS_LIM(sensor, DATA_TRANSFER_IF_CAPABILITY) & CCS_DATA_TRANSFER_IF_CAPABILITY_POLLING) { for (i = 1000; i > 0; i--) { - if (s & SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY) + if (s & CCS_DATA_TRANSFER_IF_1_STATUS_READ_IF_READY) break; - rval = smiapp_read( - sensor, - SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS, - &s); - + rval = ccs_read(sensor, DATA_TRANSFER_IF_1_STATUS, &s); if (rval) return rval; } @@ -1093,12 +1069,10 @@ static int smiapp_read_nvm_page(struct smiapp_sensor *sensor, u32 p, u8 *nvm, return -ETIMEDOUT; } - for (i = 0; i < SMIAPP_NVM_PAGE_SIZE; i++) { + for (i = 0; i <= CCS_LIM_DATA_TRANSFER_IF_1_DATA_MAX_P; i++) { u32 v; - rval = smiapp_read(sensor, - SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_0 + i, - &v); + rval = ccs_read(sensor, DATA_TRANSFER_IF_1_DATA(i), &v); if (rval) return rval; @@ -1115,20 +1089,21 @@ static int smiapp_read_nvm(struct smiapp_sensor *sensor, unsigned char *nvm, u32 p; int rval = 0, rval2; - for (p = 0; p < nvm_size / SMIAPP_NVM_PAGE_SIZE && !rval; p++) { + for (p = 0; p < nvm_size / (CCS_LIM_DATA_TRANSFER_IF_1_DATA_MAX_P + 1) + && !rval; p++) { rval = smiapp_read_nvm_page(sensor, p, nvm, &status); - nvm += SMIAPP_NVM_PAGE_SIZE; + nvm += CCS_LIM_DATA_TRANSFER_IF_1_DATA_MAX_P + 1; } if (rval == -ENODATA && - status & SMIAPP_DATA_TRANSFER_IF_1_STATUS_EUSAGE) + status & CCS_DATA_TRANSFER_IF_1_STATUS_IMPROPER_IF_USAGE) rval = 0; - rval2 = smiapp_write(sensor, SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL, 0); + rval2 = ccs_write(sensor, DATA_TRANSFER_IF_1_CTRL, 0); if (rval < 0) return rval; else - return rval2 ?: p * SMIAPP_NVM_PAGE_SIZE; + return rval2 ?: p * (CCS_LIM_DATA_TRANSFER_IF_1_DATA_MAX_P + 1); } /* @@ -1144,16 +1119,15 @@ static int smiapp_change_cci_addr(struct smiapp_sensor *sensor) client->addr = sensor->hwcfg->i2c_addr_dfl; - rval = smiapp_write(sensor, - SMIAPP_REG_U8_CCI_ADDRESS_CONTROL, - sensor->hwcfg->i2c_addr_alt << 1); + rval = ccs_write(sensor, CCI_ADDRESS_CTRL, + sensor->hwcfg->i2c_addr_alt << 1); if (rval) return rval; client->addr = sensor->hwcfg->i2c_addr_alt; /* verify addr change went ok */ - rval = smiapp_read(sensor, SMIAPP_REG_U8_CCI_ADDRESS_CONTROL, &val); + rval = ccs_read(sensor, CCI_ADDRESS_CTRL, &val); if (rval) return rval; @@ -1259,34 +1233,30 @@ static int smiapp_setup_flash_strobe(struct smiapp_sensor *sensor) strobe_width_high_rs = (tmp + strobe_adjustment - 1) / strobe_adjustment; - rval = smiapp_write(sensor, SMIAPP_REG_U8_FLASH_MODE_RS, - strobe_setup->mode); + rval = ccs_write(sensor, FLASH_MODE_RS, strobe_setup->mode); if (rval < 0) goto out; - rval = smiapp_write(sensor, SMIAPP_REG_U8_FLASH_STROBE_ADJUSTMENT, - strobe_adjustment); + rval = ccs_write(sensor, FLASH_STROBE_ADJUSTMENT, strobe_adjustment); if (rval < 0) goto out; - rval = smiapp_write( - sensor, SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL, - strobe_width_high_rs); + rval = ccs_write(sensor, TFLASH_STROBE_WIDTH_HIGH_RS_CTRL, + strobe_width_high_rs); if (rval < 0) goto out; - rval = smiapp_write(sensor, SMIAPP_REG_U16_TFLASH_STROBE_DELAY_RS_CTRL, - strobe_setup->strobe_delay); + rval = ccs_write(sensor, TFLASH_STROBE_DELAY_RS_CTRL, + strobe_setup->strobe_delay); if (rval < 0) goto out; - rval = smiapp_write(sensor, SMIAPP_REG_U16_FLASH_STROBE_START_POINT, - strobe_setup->stobe_start_point); + rval = ccs_write(sensor, FLASH_STROBE_START_POINT, + strobe_setup->stobe_start_point); if (rval < 0) goto out; - rval = smiapp_write(sensor, SMIAPP_REG_U8_FLASH_TRIGGER_RS, - strobe_setup->trigger); + rval = ccs_write(sensor, FLASH_TRIGGER_RS, strobe_setup->trigger); out: sensor->hwcfg->strobe_setup->trigger = 0; @@ -1349,8 +1319,7 @@ static int smiapp_power_on(struct device *dev) } } - rval = smiapp_write(sensor, SMIAPP_REG_U8_SOFTWARE_RESET, - SMIAPP_SOFTWARE_RESET); + rval = ccs_write(sensor, SOFTWARE_RESET, CCS_SOFTWARE_RESET_ON); if (rval < 0) { dev_err(dev, "software reset failed\n"); goto out_cci_addr_fail; @@ -1364,45 +1333,42 @@ static int smiapp_power_on(struct device *dev) } } - rval = smiapp_write(sensor, SMIAPP_REG_U16_COMPRESSION_MODE, - SMIAPP_COMPRESSION_MODE_SIMPLE_PREDICTOR); + rval = ccs_write(sensor, COMPRESSION_MODE, + CCS_COMPRESSION_MODE_DPCM_PCM_SIMPLE); if (rval) { dev_err(dev, "compression mode set failed\n"); goto out_cci_addr_fail; } - rval = smiapp_write( - sensor, SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ, - sensor->hwcfg->ext_clk / (1000000 / (1 << 8))); + rval = ccs_write(sensor, EXTCLK_FREQUENCY_MHZ, + sensor->hwcfg->ext_clk / (1000000 / (1 << 8))); if (rval) { dev_err(dev, "extclk frequency set failed\n"); goto out_cci_addr_fail; } - rval = smiapp_write(sensor, SMIAPP_REG_U8_CSI_LANE_MODE, - sensor->hwcfg->lanes - 1); + rval = ccs_write(sensor, CSI_LANE_MODE, sensor->hwcfg->lanes - 1); if (rval) { dev_err(dev, "csi lane mode set failed\n"); goto out_cci_addr_fail; } - rval = smiapp_write(sensor, SMIAPP_REG_U8_FAST_STANDBY_CTRL, - SMIAPP_FAST_STANDBY_CTRL_IMMEDIATE); + rval = ccs_write(sensor, FAST_STANDBY_CTRL, + CCS_FAST_STANDBY_CTRL_FRAME_TRUNCATION); if (rval) { dev_err(dev, "fast standby set failed\n"); goto out_cci_addr_fail; } - rval = smiapp_write(sensor, SMIAPP_REG_U8_CSI_SIGNALLING_MODE, - sensor->hwcfg->csi_signalling_mode); + rval = ccs_write(sensor, CSI_SIGNALING_MODE, + sensor->hwcfg->csi_signalling_mode); if (rval) { dev_err(dev, "csi signalling mode set failed\n"); goto out_cci_addr_fail; } /* DPHY control done by sensor based on requested link rate */ - rval = smiapp_write(sensor, SMIAPP_REG_U8_DPHY_CTRL, - SMIAPP_DPHY_CTRL_UI); + rval = ccs_write(sensor, PHY_CTRL, CCS_PHY_CTRL_UI); if (rval < 0) goto out_cci_addr_fail; @@ -1439,9 +1405,7 @@ static int smiapp_power_off(struct device *dev) * will fail. So do a soft reset explicitly here. */ if (sensor->hwcfg->i2c_addr_alt) - smiapp_write(sensor, - SMIAPP_REG_U8_SOFTWARE_RESET, - SMIAPP_SOFTWARE_RESET); + ccs_write(sensor, SOFTWARE_RESET, CCS_SOFTWARE_RESET_ON); gpiod_set_value(sensor->xshutdown, 0); clk_disable_unprepare(sensor->ext_clk); @@ -1464,9 +1428,9 @@ static int smiapp_start_streaming(struct smiapp_sensor *sensor) mutex_lock(&sensor->mutex); - rval = smiapp_write(sensor, SMIAPP_REG_U16_CSI_DATA_FORMAT, - (sensor->csi_format->width << 8) | - sensor->csi_format->compressed); + rval = ccs_write(sensor, CSI_DATA_FORMAT, + (sensor->csi_format->width << 8) | + sensor->csi_format->compressed); if (rval) goto out; @@ -1479,14 +1443,13 @@ static int smiapp_start_streaming(struct smiapp_sensor *sensor) (sensor->binning_horizontal << 4) | sensor->binning_vertical; - rval = smiapp_write( - sensor, SMIAPP_REG_U8_BINNING_TYPE, binning_type); + rval = ccs_write(sensor, BINNING_TYPE, binning_type); if (rval < 0) goto out; binning_mode = 1; } - rval = smiapp_write(sensor, SMIAPP_REG_U8_BINNING_MODE, binning_mode); + rval = ccs_write(sensor, BINNING_MODE, binning_mode); if (rval < 0) goto out; @@ -1496,26 +1459,26 @@ static int smiapp_start_streaming(struct smiapp_sensor *sensor) goto out; /* Analog crop start coordinates */ - rval = smiapp_write(sensor, SMIAPP_REG_U16_X_ADDR_START, - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].left); + rval = ccs_write(sensor, X_ADDR_START, + sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].left); if (rval < 0) goto out; - rval = smiapp_write(sensor, SMIAPP_REG_U16_Y_ADDR_START, - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].top); + rval = ccs_write(sensor, Y_ADDR_START, + sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].top); if (rval < 0) goto out; /* Analog crop end coordinates */ - rval = smiapp_write( - sensor, SMIAPP_REG_U16_X_ADDR_END, + rval = ccs_write( + sensor, X_ADDR_END, sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].left + sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width - 1); if (rval < 0) goto out; - rval = smiapp_write( - sensor, SMIAPP_REG_U16_Y_ADDR_END, + rval = ccs_write( + sensor, Y_ADDR_END, sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].top + sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height - 1); if (rval < 0) @@ -1529,26 +1492,26 @@ static int smiapp_start_streaming(struct smiapp_sensor *sensor) /* Digital crop */ if (CCS_LIM(sensor, DIGITAL_CROP_CAPABILITY) == CCS_DIGITAL_CROP_CAPABILITY_INPUT_CROP) { - rval = smiapp_write( - sensor, SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET, + rval = ccs_write( + sensor, DIGITAL_CROP_X_OFFSET, sensor->scaler->crop[SMIAPP_PAD_SINK].left); if (rval < 0) goto out; - rval = smiapp_write( - sensor, SMIAPP_REG_U16_DIGITAL_CROP_Y_OFFSET, + rval = ccs_write( + sensor, DIGITAL_CROP_Y_OFFSET, sensor->scaler->crop[SMIAPP_PAD_SINK].top); if (rval < 0) goto out; - rval = smiapp_write( - sensor, SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_WIDTH, + rval = ccs_write( + sensor, DIGITAL_CROP_IMAGE_WIDTH, sensor->scaler->crop[SMIAPP_PAD_SINK].width); if (rval < 0) goto out; - rval = smiapp_write( - sensor, SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_HEIGHT, + rval = ccs_write( + sensor, DIGITAL_CROP_IMAGE_HEIGHT, sensor->scaler->crop[SMIAPP_PAD_SINK].height); if (rval < 0) goto out; @@ -1557,24 +1520,22 @@ static int smiapp_start_streaming(struct smiapp_sensor *sensor) /* Scaling */ if (CCS_LIM(sensor, SCALING_CAPABILITY) != CCS_SCALING_CAPABILITY_NONE) { - rval = smiapp_write(sensor, SMIAPP_REG_U16_SCALING_MODE, - sensor->scaling_mode); + rval = ccs_write(sensor, SCALING_MODE, sensor->scaling_mode); if (rval < 0) goto out; - rval = smiapp_write(sensor, SMIAPP_REG_U16_SCALE_M, - sensor->scale_m); + rval = ccs_write(sensor, SCALE_M, sensor->scale_m); if (rval < 0) goto out; } /* Output size from sensor */ - rval = smiapp_write(sensor, SMIAPP_REG_U16_X_OUTPUT_SIZE, - sensor->src->crop[SMIAPP_PAD_SRC].width); + rval = ccs_write(sensor, X_OUTPUT_SIZE, + sensor->src->crop[SMIAPP_PAD_SRC].width); if (rval < 0) goto out; - rval = smiapp_write(sensor, SMIAPP_REG_U16_Y_OUTPUT_SIZE, - sensor->src->crop[SMIAPP_PAD_SRC].height); + rval = ccs_write(sensor, Y_OUTPUT_SIZE, + sensor->src->crop[SMIAPP_PAD_SRC].height); if (rval < 0) goto out; @@ -1594,8 +1555,7 @@ static int smiapp_start_streaming(struct smiapp_sensor *sensor) goto out; } - rval = smiapp_write(sensor, SMIAPP_REG_U8_MODE_SELECT, - SMIAPP_MODE_SELECT_STREAMING); + rval = ccs_write(sensor, MODE_SELECT, CCS_MODE_SELECT_STREAMING); out: mutex_unlock(&sensor->mutex); @@ -1609,8 +1569,7 @@ static int smiapp_stop_streaming(struct smiapp_sensor *sensor) int rval; mutex_lock(&sensor->mutex); - rval = smiapp_write(sensor, SMIAPP_REG_U8_MODE_SELECT, - SMIAPP_MODE_SELECT_SOFTWARE_STANDBY); + rval = ccs_write(sensor, MODE_SELECT, CCS_MODE_SELECT_SOFTWARE_STANDBY); if (rval) goto out; @@ -1828,7 +1787,7 @@ static void smiapp_propagate(struct v4l2_subdev *subdev, sensor->scale_m = CCS_LIM(sensor, SCALER_N_MIN); sensor->scaling_mode = - SMIAPP_SCALING_MODE_NONE; + CCS_SCALING_MODE_NO_SCALING; } else if (ssd == sensor->binner) { sensor->binning_horizontal = 1; sensor->binning_vertical = 1; @@ -2063,7 +2022,7 @@ static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev, struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); u32 min, max, a, b, max_m; u32 scale_m = CCS_LIM(sensor, SCALER_N_MIN); - int mode = SMIAPP_SCALING_MODE_HORIZONTAL; + int mode = CCS_SCALING_MODE_HORIZONTAL; u32 try[4]; u32 ntry = 0; unsigned int i; @@ -2123,7 +2082,7 @@ static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev, if (this > best) { scale_m = try[i]; - mode = SMIAPP_SCALING_MODE_HORIZONTAL; + mode = CCS_SCALING_MODE_HORIZONTAL; best = this; } @@ -2494,26 +2453,24 @@ static int smiapp_identify_module(struct smiapp_sensor *sensor) rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_MANUFACTURER_ID, &minfo->smia_manufacturer_id); if (!rval) - rval = smiapp_read_8only(sensor, SMIAPP_REG_U16_MODEL_ID, + rval = smiapp_read_8only(sensor, CCS_R_MODULE_MODEL_ID, &minfo->model_id); if (!rval) rval = smiapp_read_8only(sensor, - SMIAPP_REG_U8_REVISION_NUMBER_MAJOR, + CCS_R_MODULE_REVISION_NUMBER_MAJOR, &minfo->revision_number_major); if (!rval) rval = smiapp_read_8only(sensor, - SMIAPP_REG_U8_REVISION_NUMBER_MINOR, + CCS_R_MODULE_REVISION_NUMBER_MINOR, &minfo->revision_number_minor); if (!rval) - rval = smiapp_read_8only(sensor, - SMIAPP_REG_U8_MODULE_DATE_YEAR, + rval = smiapp_read_8only(sensor, CCS_R_MODULE_DATE_YEAR, &minfo->module_year); if (!rval) - rval = smiapp_read_8only(sensor, - SMIAPP_REG_U8_MODULE_DATE_MONTH, + rval = smiapp_read_8only(sensor, CCS_R_MODULE_DATE_MONTH, &minfo->module_month); if (!rval) - rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_MODULE_DATE_DAY, + rval = smiapp_read_8only(sensor, CCS_R_MODULE_DATE_DAY, &minfo->module_day); /* Sensor info */ @@ -2522,19 +2479,19 @@ static int smiapp_identify_module(struct smiapp_sensor *sensor) &minfo->sensor_mipi_manufacturer_id); if (!rval && !minfo->sensor_mipi_manufacturer_id) rval = smiapp_read_8only(sensor, - SMIAPP_REG_U8_SENSOR_MANUFACTURER_ID, + CCS_R_SENSOR_MANUFACTURER_ID, &minfo->sensor_smia_manufacturer_id); if (!rval) rval = smiapp_read_8only(sensor, - SMIAPP_REG_U16_SENSOR_MODEL_ID, + CCS_R_SENSOR_MODEL_ID, &minfo->sensor_model_id); if (!rval) rval = smiapp_read_8only(sensor, - SMIAPP_REG_U8_SENSOR_REVISION_NUMBER, + CCS_R_SENSOR_REVISION_NUMBER, &minfo->sensor_revision_number); if (!rval) rval = smiapp_read_8only(sensor, - SMIAPP_REG_U8_SENSOR_FIRMWARE_VERSION, + CCS_R_SENSOR_FIRMWARE_VERSION, &minfo->sensor_firmware_version); /* SMIA */ @@ -2919,7 +2876,7 @@ static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev) switch (bus_cfg.bus_type) { case V4L2_MBUS_CSI2_DPHY: - hwcfg->csi_signalling_mode = SMIAPP_CSI_SIGNALLING_MODE_CSI2; + hwcfg->csi_signalling_mode = CCS_CSI_SIGNALING_MODE_CSI_2_DPHY; hwcfg->lanes = bus_cfg.bus.mipi_csi2.num_data_lanes; break; case V4L2_MBUS_CCP2: @@ -3095,8 +3052,9 @@ static int smiapp_probe(struct i2c_client *client) */ if (sensor->hwcfg->module_board_orient == SMIAPP_MODULE_BOARD_ORIENT_180) - sensor->hvflip_inv_mask = SMIAPP_IMAGE_ORIENTATION_HFLIP | - SMIAPP_IMAGE_ORIENTATION_VFLIP; + sensor->hvflip_inv_mask = + CCS_IMAGE_ORIENTATION_HORIZONTAL_MIRROR | + CCS_IMAGE_ORIENTATION_VERTICAL_FLIP; rval = smiapp_call_quirk(sensor, limits); if (rval) { diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h index 1a67cf485dcc..c6e4e05a7522 100644 --- a/drivers/media/i2c/smiapp/smiapp.h +++ b/drivers/media/i2c/smiapp/smiapp.h @@ -15,6 +15,8 @@ #include #include +#include "ccs-regs.h" + #include "smiapp-pll.h" #include "smiapp-reg-defs.h" #include "smiapp-regs.h" @@ -220,7 +222,7 @@ struct smiapp_sensor { struct gpio_desc *xshutdown; void *ccs_limits; u8 nbinning_subtypes; - struct smiapp_binning_subtype binning_subtypes[SMIAPP_BINNING_SUBTYPES]; + struct smiapp_binning_subtype binning_subtypes[CCS_LIM_BINNING_SUB_TYPE_MAX_N + 1]; u32 mbus_frame_fmts; const struct smiapp_csi_data_format *csi_format; const struct smiapp_csi_data_format *internal_csi_format; -- cgit v1.2.3 From 235ac9a4b36c4173d2f318098544bb010bfc3295 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 11 Feb 2020 11:14:10 +0100 Subject: media: smiapp: Remove quirk function for writing a single 8-bit register This function is no longer needed as the smiapp_write() function can be used to write 8-bit registers with plain register addresses. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-quirk.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.c b/drivers/media/i2c/smiapp/smiapp-quirk.c index 24630c7650d2..9422eb61b424 100644 --- a/drivers/media/i2c/smiapp/smiapp-quirk.c +++ b/drivers/media/i2c/smiapp/smiapp-quirk.c @@ -14,11 +14,6 @@ #include "smiapp.h" -static int smiapp_write_8(struct smiapp_sensor *sensor, u16 reg, u8 val) -{ - return smiapp_write(sensor, reg, val); -} - static int smiapp_write_8s(struct smiapp_sensor *sensor, const struct smiapp_reg_8 *regs, int len) { @@ -26,7 +21,7 @@ static int smiapp_write_8s(struct smiapp_sensor *sensor, int rval; for (; len > 0; len--, regs++) { - rval = smiapp_write_8(sensor, regs->reg, regs->val); + rval = smiapp_write(sensor, regs->reg, regs->val); if (rval < 0) { dev_err(&client->dev, "error %d writing reg 0x%4.4x, val 0x%2.2x", @@ -170,7 +165,7 @@ static int jt8ev1_post_poweron(struct smiapp_sensor *sensor) static int jt8ev1_pre_streamon(struct smiapp_sensor *sensor) { - return smiapp_write_8(sensor, 0x3328, 0x00); + return smiapp_write(sensor, 0x3328, 0x00); } static int jt8ev1_post_streamoff(struct smiapp_sensor *sensor) @@ -178,7 +173,7 @@ static int jt8ev1_post_streamoff(struct smiapp_sensor *sensor) int rval; /* Workaround: allows fast standby to work properly */ - rval = smiapp_write_8(sensor, 0x3205, 0x04); + rval = smiapp_write(sensor, 0x3205, 0x04); if (rval < 0) return rval; @@ -186,11 +181,11 @@ static int jt8ev1_post_streamoff(struct smiapp_sensor *sensor) usleep_range(2000, 2050); /* Restore it */ - rval = smiapp_write_8(sensor, 0x3205, 0x00); + rval = smiapp_write(sensor, 0x3205, 0x00); if (rval < 0) return rval; - return smiapp_write_8(sensor, 0x3328, 0x80); + return smiapp_write(sensor, 0x3328, 0x80); } static int jt8ev1_init(struct smiapp_sensor *sensor) -- cgit v1.2.3 From 47ff2ff267ee4f259154ddd578b25224393d306b Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 11 Feb 2020 12:16:14 +0100 Subject: media: smiapp: Rename register access functions Rename register access functions by changing smiapp to ccs. The functions operating on register addresses have "addr" appended to the name. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 67 +++++++++++++++++---------------- drivers/media/i2c/smiapp/smiapp-quirk.c | 22 +++++------ drivers/media/i2c/smiapp/smiapp-regs.c | 47 ++++++++++++----------- drivers/media/i2c/smiapp/smiapp-regs.h | 14 +++---- 4 files changed, 76 insertions(+), 74 deletions(-) diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 382a2d14f0f4..b12e41a6a410 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -180,7 +180,7 @@ static int ccs_read_all_limits(struct smiapp_sensor *sensor) j++, reg += width, ptr += width) { u32 val; - ret = smiapp_read(sensor, reg, &val); + ret = ccs_read_addr(sensor, reg, &val); if (ret) goto out_err; @@ -2450,59 +2450,60 @@ static int smiapp_identify_module(struct smiapp_sensor *sensor) rval = ccs_read(sensor, MODULE_MANUFACTURER_ID, &minfo->mipi_manufacturer_id); if (!rval && !minfo->mipi_manufacturer_id) - rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_MANUFACTURER_ID, - &minfo->smia_manufacturer_id); + rval = ccs_read_addr_8only(sensor, + SMIAPP_REG_U8_MANUFACTURER_ID, + &minfo->smia_manufacturer_id); if (!rval) - rval = smiapp_read_8only(sensor, CCS_R_MODULE_MODEL_ID, - &minfo->model_id); + rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_MODEL_ID, + &minfo->model_id); if (!rval) - rval = smiapp_read_8only(sensor, - CCS_R_MODULE_REVISION_NUMBER_MAJOR, - &minfo->revision_number_major); + rval = ccs_read_addr_8only(sensor, + CCS_R_MODULE_REVISION_NUMBER_MAJOR, + &minfo->revision_number_major); if (!rval) - rval = smiapp_read_8only(sensor, - CCS_R_MODULE_REVISION_NUMBER_MINOR, - &minfo->revision_number_minor); + rval = ccs_read_addr_8only(sensor, + CCS_R_MODULE_REVISION_NUMBER_MINOR, + &minfo->revision_number_minor); if (!rval) - rval = smiapp_read_8only(sensor, CCS_R_MODULE_DATE_YEAR, - &minfo->module_year); + rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_YEAR, + &minfo->module_year); if (!rval) - rval = smiapp_read_8only(sensor, CCS_R_MODULE_DATE_MONTH, - &minfo->module_month); + rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_MONTH, + &minfo->module_month); if (!rval) - rval = smiapp_read_8only(sensor, CCS_R_MODULE_DATE_DAY, - &minfo->module_day); + rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_DAY, + &minfo->module_day); /* Sensor info */ if (!rval) rval = ccs_read(sensor, SENSOR_MANUFACTURER_ID, &minfo->sensor_mipi_manufacturer_id); if (!rval && !minfo->sensor_mipi_manufacturer_id) - rval = smiapp_read_8only(sensor, - CCS_R_SENSOR_MANUFACTURER_ID, - &minfo->sensor_smia_manufacturer_id); + rval = ccs_read_addr_8only(sensor, + CCS_R_SENSOR_MANUFACTURER_ID, + &minfo->sensor_smia_manufacturer_id); if (!rval) - rval = smiapp_read_8only(sensor, - CCS_R_SENSOR_MODEL_ID, - &minfo->sensor_model_id); + rval = ccs_read_addr_8only(sensor, + CCS_R_SENSOR_MODEL_ID, + &minfo->sensor_model_id); if (!rval) - rval = smiapp_read_8only(sensor, - CCS_R_SENSOR_REVISION_NUMBER, - &minfo->sensor_revision_number); + rval = ccs_read_addr_8only(sensor, + CCS_R_SENSOR_REVISION_NUMBER, + &minfo->sensor_revision_number); if (!rval) - rval = smiapp_read_8only(sensor, - CCS_R_SENSOR_FIRMWARE_VERSION, - &minfo->sensor_firmware_version); + rval = ccs_read_addr_8only(sensor, + CCS_R_SENSOR_FIRMWARE_VERSION, + &minfo->sensor_firmware_version); /* SMIA */ if (!rval) rval = ccs_read(sensor, MIPI_CCS_VERSION, &minfo->ccs_version); if (!rval && !minfo->ccs_version) - rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_SMIA_VERSION, - &minfo->smia_version); + rval = ccs_read_addr_8only(sensor, SMIAPP_REG_U8_SMIA_VERSION, + &minfo->smia_version); if (!rval && !minfo->ccs_version) - rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_SMIAPP_VERSION, - &minfo->smiapp_version); + rval = ccs_read_addr_8only(sensor, SMIAPP_REG_U8_SMIAPP_VERSION, + &minfo->smiapp_version); if (rval) { dev_err(&client->dev, "sensor detection failed\n"); diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.c b/drivers/media/i2c/smiapp/smiapp-quirk.c index 9422eb61b424..5db97a16eccf 100644 --- a/drivers/media/i2c/smiapp/smiapp-quirk.c +++ b/drivers/media/i2c/smiapp/smiapp-quirk.c @@ -14,14 +14,14 @@ #include "smiapp.h" -static int smiapp_write_8s(struct smiapp_sensor *sensor, - const struct smiapp_reg_8 *regs, int len) +static int ccs_write_addr_8s(struct smiapp_sensor *sensor, + const struct smiapp_reg_8 *regs, int len) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); int rval; for (; len > 0; len--, regs++) { - rval = smiapp_write(sensor, regs->reg, regs->val); + rval = ccs_write_addr(sensor, regs->reg, regs->val); if (rval < 0) { dev_err(&client->dev, "error %d writing reg 0x%4.4x, val 0x%2.2x", @@ -81,7 +81,7 @@ static int jt8ew9_post_poweron(struct smiapp_sensor *sensor) }; - return smiapp_write_8s(sensor, regs, ARRAY_SIZE(regs)); + return ccs_write_addr_8s(sensor, regs, ARRAY_SIZE(regs)); } const struct smiapp_quirk smiapp_jt8ew9_quirk = { @@ -102,7 +102,7 @@ static int imx125es_post_poweron(struct smiapp_sensor *sensor) { 0x3b08, 0x8c }, }; - return smiapp_write_8s(sensor, regs, ARRAY_SIZE(regs)); + return ccs_write_addr_8s(sensor, regs, ARRAY_SIZE(regs)); } const struct smiapp_quirk smiapp_imx125es_quirk = { @@ -148,13 +148,13 @@ static int jt8ev1_post_poweron(struct smiapp_sensor *sensor) { 0x30b0, 0x01 }, }; - rval = smiapp_write_8s(sensor, regs, ARRAY_SIZE(regs)); + rval = ccs_write_addr_8s(sensor, regs, ARRAY_SIZE(regs)); if (rval < 0) return rval; switch (sensor->hwcfg->ext_clk) { case 9600000: - return smiapp_write_8s(sensor, regs_96, + return ccs_write_addr_8s(sensor, regs_96, ARRAY_SIZE(regs_96)); default: dev_warn(&client->dev, "no MSRs for %d Hz ext_clk\n", @@ -165,7 +165,7 @@ static int jt8ev1_post_poweron(struct smiapp_sensor *sensor) static int jt8ev1_pre_streamon(struct smiapp_sensor *sensor) { - return smiapp_write(sensor, 0x3328, 0x00); + return ccs_write_addr(sensor, 0x3328, 0x00); } static int jt8ev1_post_streamoff(struct smiapp_sensor *sensor) @@ -173,7 +173,7 @@ static int jt8ev1_post_streamoff(struct smiapp_sensor *sensor) int rval; /* Workaround: allows fast standby to work properly */ - rval = smiapp_write(sensor, 0x3205, 0x04); + rval = ccs_write_addr(sensor, 0x3205, 0x04); if (rval < 0) return rval; @@ -181,11 +181,11 @@ static int jt8ev1_post_streamoff(struct smiapp_sensor *sensor) usleep_range(2000, 2050); /* Restore it */ - rval = smiapp_write(sensor, 0x3205, 0x00); + rval = ccs_write_addr(sensor, 0x3205, 0x00); if (rval < 0) return rval; - return smiapp_write(sensor, 0x3328, 0x80); + return ccs_write_addr(sensor, 0x3328, 0x80); } static int jt8ev1_init(struct smiapp_sensor *sensor) diff --git a/drivers/media/i2c/smiapp/smiapp-regs.c b/drivers/media/i2c/smiapp/smiapp-regs.c index 904054d303ba..173d9f8fe56c 100644 --- a/drivers/media/i2c/smiapp/smiapp-regs.c +++ b/drivers/media/i2c/smiapp/smiapp-regs.c @@ -66,8 +66,8 @@ static uint32_t float_to_u32_mul_1000000(struct i2c_client *client, * Read a 8/16/32-bit i2c register. The value is returned in 'val'. * Returns zero if successful, or non-zero otherwise. */ -static int ____smiapp_read(struct smiapp_sensor *sensor, u16 reg, - u16 len, u32 *val) +static int ____ccs_read_addr(struct smiapp_sensor *sensor, u16 reg, u16 len, + u32 *val) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); struct i2c_msg msg; @@ -113,8 +113,8 @@ err: } /* Read a register using 8-bit access only. */ -static int ____smiapp_read_8only(struct smiapp_sensor *sensor, u16 reg, - u16 len, u32 *val) +static int ____ccs_read_addr_8only(struct smiapp_sensor *sensor, u16 reg, + u16 len, u32 *val) { unsigned int i; int rval; @@ -124,7 +124,7 @@ static int ____smiapp_read_8only(struct smiapp_sensor *sensor, u16 reg, for (i = 0; i < len; i++) { u32 val8; - rval = ____smiapp_read(sensor, reg + i, 1, &val8); + rval = ____ccs_read_addr(sensor, reg + i, 1, &val8); if (rval < 0) return rval; *val |= val8 << ((len - i - 1) << 3); @@ -147,18 +147,19 @@ unsigned int ccs_reg_width(u32 reg) * Read a 8/16/32-bit i2c register. The value is returned in 'val'. * Returns zero if successful, or non-zero otherwise. */ -static int __smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val, - bool only8) +static int __ccs_read_addr(struct smiapp_sensor *sensor, u32 reg, u32 *val, + bool only8) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); unsigned int len = ccs_reg_width(reg); int rval; if (!only8) - rval = ____smiapp_read(sensor, SMIAPP_REG_ADDR(reg), len, val); + rval = ____ccs_read_addr(sensor, SMIAPP_REG_ADDR(reg), len, + val); else - rval = ____smiapp_read_8only(sensor, SMIAPP_REG_ADDR(reg), len, - val); + rval = ____ccs_read_addr_8only(sensor, SMIAPP_REG_ADDR(reg), + len, val); if (rval < 0) return rval; @@ -168,16 +169,16 @@ static int __smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val, return 0; } -int smiapp_read_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 *val) +int ccs_read_addr_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 *val) { - return __smiapp_read( + return __ccs_read_addr( sensor, reg, val, smiapp_needs_quirk(sensor, SMIAPP_QUIRK_FLAG_8BIT_READ_ONLY)); } -static int smiapp_read_quirk(struct smiapp_sensor *sensor, u32 reg, u32 *val, - bool force8) +static int ccs_read_addr_quirk(struct smiapp_sensor *sensor, u32 reg, u32 *val, + bool force8) { int rval; @@ -189,22 +190,22 @@ static int smiapp_read_quirk(struct smiapp_sensor *sensor, u32 reg, u32 *val, return rval; if (force8) - return __smiapp_read(sensor, reg, val, true); + return __ccs_read_addr(sensor, reg, val, true); - return smiapp_read_no_quirk(sensor, reg, val); + return ccs_read_addr_no_quirk(sensor, reg, val); } -int smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val) +int ccs_read_addr(struct smiapp_sensor *sensor, u32 reg, u32 *val) { - return smiapp_read_quirk(sensor, reg, val, false); + return ccs_read_addr_quirk(sensor, reg, val, false); } -int smiapp_read_8only(struct smiapp_sensor *sensor, u32 reg, u32 *val) +int ccs_read_addr_8only(struct smiapp_sensor *sensor, u32 reg, u32 *val) { - return smiapp_read_quirk(sensor, reg, val, true); + return ccs_read_addr_quirk(sensor, reg, val, true); } -int smiapp_write_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 val) +int ccs_write_addr_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 val) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); struct i2c_msg msg; @@ -253,7 +254,7 @@ int smiapp_write_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 val) * Write to a 8/16-bit register. * Returns zero if successful, or non-zero otherwise. */ -int smiapp_write(struct smiapp_sensor *sensor, u32 reg, u32 val) +int ccs_write_addr(struct smiapp_sensor *sensor, u32 reg, u32 val) { int rval; @@ -263,5 +264,5 @@ int smiapp_write(struct smiapp_sensor *sensor, u32 reg, u32 val) if (rval < 0) return rval; - return smiapp_write_no_quirk(sensor, reg, val); + return ccs_write_addr_no_quirk(sensor, reg, val); } diff --git a/drivers/media/i2c/smiapp/smiapp-regs.h b/drivers/media/i2c/smiapp/smiapp-regs.h index dc946096f368..5df794f65dfc 100644 --- a/drivers/media/i2c/smiapp/smiapp-regs.h +++ b/drivers/media/i2c/smiapp/smiapp-regs.h @@ -20,18 +20,18 @@ struct smiapp_sensor; -int smiapp_read_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 *val); -int smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val); -int smiapp_read_8only(struct smiapp_sensor *sensor, u32 reg, u32 *val); -int smiapp_write_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 val); -int smiapp_write(struct smiapp_sensor *sensor, u32 reg, u32 val); +int ccs_read_addr_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 *val); +int ccs_read_addr(struct smiapp_sensor *sensor, u32 reg, u32 *val); +int ccs_read_addr_8only(struct smiapp_sensor *sensor, u32 reg, u32 *val); +int ccs_write_addr_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 val); +int ccs_write_addr(struct smiapp_sensor *sensor, u32 reg, u32 val); unsigned int ccs_reg_width(u32 reg); #define ccs_read(sensor, reg_name, val) \ - smiapp_read(sensor, CCS_R_##reg_name, val) + ccs_read_addr(sensor, CCS_R_##reg_name, val) #define ccs_write(sensor, reg_name, val) \ - smiapp_write(sensor, CCS_R_##reg_name, val) + ccs_write_addr(sensor, CCS_R_##reg_name, val) #endif -- cgit v1.2.3 From 161cc847370a92f2d39f79edc640b599a497c862 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 11 Feb 2020 14:19:13 +0100 Subject: media: smiapp: Internal rename to CCS Rename internal names to reflect the driver's new reference. The module name remains the same. Also fix trivial coding style issues on the way related to e.g. alignment changes due to the rename. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/Makefile | 4 +- drivers/media/i2c/smiapp/ccs-core.c | 3299 ++++++++++++++++++++++++++++ drivers/media/i2c/smiapp/ccs-quirk.c | 214 ++ drivers/media/i2c/smiapp/ccs-quirk.h | 78 + drivers/media/i2c/smiapp/ccs-reg-access.c | 265 +++ drivers/media/i2c/smiapp/ccs-reg-access.h | 37 + drivers/media/i2c/smiapp/ccs.h | 280 +++ drivers/media/i2c/smiapp/smiapp-core.c | 3305 ----------------------------- drivers/media/i2c/smiapp/smiapp-quirk.c | 215 -- drivers/media/i2c/smiapp/smiapp-quirk.h | 78 - drivers/media/i2c/smiapp/smiapp-regs.c | 268 --- drivers/media/i2c/smiapp/smiapp-regs.h | 37 - drivers/media/i2c/smiapp/smiapp.h | 280 --- 13 files changed, 4175 insertions(+), 4185 deletions(-) create mode 100644 drivers/media/i2c/smiapp/ccs-core.c create mode 100644 drivers/media/i2c/smiapp/ccs-quirk.c create mode 100644 drivers/media/i2c/smiapp/ccs-quirk.h create mode 100644 drivers/media/i2c/smiapp/ccs-reg-access.c create mode 100644 drivers/media/i2c/smiapp/ccs-reg-access.h create mode 100644 drivers/media/i2c/smiapp/ccs.h delete mode 100644 drivers/media/i2c/smiapp/smiapp-core.c delete mode 100644 drivers/media/i2c/smiapp/smiapp-quirk.c delete mode 100644 drivers/media/i2c/smiapp/smiapp-quirk.h delete mode 100644 drivers/media/i2c/smiapp/smiapp-regs.c delete mode 100644 drivers/media/i2c/smiapp/smiapp-regs.h delete mode 100644 drivers/media/i2c/smiapp/smiapp.h diff --git a/drivers/media/i2c/smiapp/Makefile b/drivers/media/i2c/smiapp/Makefile index a7bf53dd4a63..c9d300b5d2bc 100644 --- a/drivers/media/i2c/smiapp/Makefile +++ b/drivers/media/i2c/smiapp/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -smiapp-objs += smiapp-core.o smiapp-regs.o \ - smiapp-quirk.o ccs-limits.o +smiapp-objs += ccs-core.o ccs-reg-access.o \ + ccs-quirk.o ccs-limits.o obj-$(CONFIG_VIDEO_SMIAPP) += smiapp.o ccflags-y += -I $(srctree)/drivers/media/i2c diff --git a/drivers/media/i2c/smiapp/ccs-core.c b/drivers/media/i2c/smiapp/ccs-core.c new file mode 100644 index 000000000000..f9dbf1407a33 --- /dev/null +++ b/drivers/media/i2c/smiapp/ccs-core.c @@ -0,0 +1,3299 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * drivers/media/i2c/smiapp/ccs-core.c + * + * Generic driver for SMIA/SMIA++ compliant camera modules + * + * Copyright (C) 2010--2012 Nokia Corporation + * Contact: Sakari Ailus + * + * Based on smiapp driver by Vimarsh Zutshi + * Based on jt8ev1.c by Vimarsh Zutshi + * Based on smia-sensor.c by Tuukka Toivonen + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ccs.h" +#include "ccs-limits.h" + +#define CCS_ALIGN_DIM(dim, flags) \ + ((flags) & V4L2_SEL_FLAG_GE \ + ? ALIGN((dim), 2) \ + : (dim) & ~1) + +static struct ccs_limit_offset { + u16 lim; + u16 info; +} ccs_limit_offsets[CCS_L_LAST + 1]; + +/* + * ccs_module_idents - supported camera modules + */ +static const struct ccs_module_ident ccs_module_idents[] = { + CCS_IDENT_L(0x01, 0x022b, -1, "vs6555"), + CCS_IDENT_L(0x01, 0x022e, -1, "vw6558"), + CCS_IDENT_L(0x07, 0x7698, -1, "ovm7698"), + CCS_IDENT_L(0x0b, 0x4242, -1, "smiapp-003"), + CCS_IDENT_L(0x0c, 0x208a, -1, "tcm8330md"), + CCS_IDENT_LQ(0x0c, 0x2134, -1, "tcm8500md", &smiapp_tcm8500md_quirk), + CCS_IDENT_L(0x0c, 0x213e, -1, "et8en2"), + CCS_IDENT_L(0x0c, 0x2184, -1, "tcm8580md"), + CCS_IDENT_LQ(0x0c, 0x560f, -1, "jt8ew9", &smiapp_jt8ew9_quirk), + CCS_IDENT_LQ(0x10, 0x4141, -1, "jt8ev1", &smiapp_jt8ev1_quirk), + CCS_IDENT_LQ(0x10, 0x4241, -1, "imx125es", &smiapp_imx125es_quirk), +}; + +/* + * + * Dynamic Capability Identification + * + */ + +static void ccs_assign_limit(void *ptr, unsigned int width, u32 val) +{ + switch (width) { + case sizeof(u8): + *(u8 *)ptr = val; + break; + case sizeof(u16): + *(u16 *)ptr = val; + break; + case sizeof(u32): + *(u32 *)ptr = val; + break; + } +} + +static int ccs_limit_ptr(struct ccs_sensor *sensor, unsigned int limit, + unsigned int offset, void **__ptr) +{ + const struct ccs_limit *linfo; + + if (WARN_ON(limit >= CCS_L_LAST)) + return -EINVAL; + + linfo = &ccs_limits[ccs_limit_offsets[limit].info]; + + if (WARN_ON(!sensor->ccs_limits) || + WARN_ON(offset + ccs_reg_width(linfo->reg) > + ccs_limit_offsets[limit + 1].lim)) + return -EINVAL; + + *__ptr = sensor->ccs_limits + ccs_limit_offsets[limit].lim + offset; + + return 0; +} + +void ccs_replace_limit(struct ccs_sensor *sensor, + unsigned int limit, unsigned int offset, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + const struct ccs_limit *linfo; + void *ptr; + int ret; + + ret = ccs_limit_ptr(sensor, limit, offset, &ptr); + if (ret) + return; + + linfo = &ccs_limits[ccs_limit_offsets[limit].info]; + + dev_dbg(&client->dev, "quirk: 0x%8.8x \"%s\" %u = %d, 0x%x\n", + linfo->reg, linfo->name, offset, val, val); + + ccs_assign_limit(ptr, ccs_reg_width(linfo->reg), val); +} + +static u32 ccs_get_limit(struct ccs_sensor *sensor, + unsigned int limit, unsigned int offset) +{ + void *ptr; + int ret; + + ret = ccs_limit_ptr(sensor, limit, offset, &ptr); + if (ret) + return 0; + + switch (ccs_reg_width(ccs_limits[ccs_limit_offsets[limit].info].reg)) { + case sizeof(u8): + return *(u8 *)ptr; + case sizeof(u16): + return *(u16 *)ptr; + case sizeof(u32): + return *(u32 *)ptr; + } + + WARN_ON(1); + + return 0; +} + +#define CCS_LIM(sensor, limit) \ + ccs_get_limit(sensor, CCS_L_##limit, 0) + +#define CCS_LIM_AT(sensor, limit, offset) \ + ccs_get_limit(sensor, CCS_L_##limit, CCS_L_##limit##_OFFSET(offset)) + +static int ccs_read_all_limits(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + void *ptr, *alloc, *end; + unsigned int i, l; + int ret; + + kfree(sensor->ccs_limits); + sensor->ccs_limits = NULL; + + alloc = kzalloc(ccs_limit_offsets[CCS_L_LAST].lim, GFP_KERNEL); + if (!alloc) + return -ENOMEM; + + end = alloc + ccs_limit_offsets[CCS_L_LAST].lim; + + for (i = 0, l = 0, ptr = alloc; ccs_limits[i].size; i++) { + u32 reg = ccs_limits[i].reg; + unsigned int width = ccs_reg_width(reg); + unsigned int j; + + if (l == CCS_L_LAST) { + dev_err(&client->dev, + "internal error --- end of limit array\n"); + ret = -EINVAL; + goto out_err; + } + + for (j = 0; j < ccs_limits[i].size / width; + j++, reg += width, ptr += width) { + u32 val; + + ret = ccs_read_addr(sensor, reg, &val); + if (ret) + goto out_err; + + if (ptr + width > end) { + dev_err(&client->dev, + "internal error --- no room for regs\n"); + ret = -EINVAL; + goto out_err; + } + + ccs_assign_limit(ptr, width, val); + + dev_dbg(&client->dev, "0x%8.8x \"%s\" = %u, 0x%x\n", + reg, ccs_limits[i].name, val, val); + } + + if (ccs_limits[i].flags & CCS_L_FL_SAME_REG) + continue; + + l++; + ptr = alloc + ccs_limit_offsets[l].lim; + } + + if (l != CCS_L_LAST) { + dev_err(&client->dev, + "internal error --- insufficient limits\n"); + ret = -EINVAL; + goto out_err; + } + + sensor->ccs_limits = alloc; + + if (CCS_LIM(sensor, SCALER_N_MIN) < 16) + ccs_replace_limit(sensor, CCS_L_SCALER_N_MIN, 0, 16); + + return 0; + +out_err: + kfree(alloc); + + return ret; +} + +static int ccs_read_frame_fmt(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + u8 fmt_model_type, fmt_model_subtype, ncol_desc, nrow_desc; + unsigned int i; + int pixel_count = 0; + int line_count = 0; + + fmt_model_type = CCS_LIM(sensor, FRAME_FORMAT_MODEL_TYPE); + fmt_model_subtype = CCS_LIM(sensor, FRAME_FORMAT_MODEL_SUBTYPE); + + ncol_desc = (fmt_model_subtype + & CCS_FRAME_FORMAT_MODEL_SUBTYPE_COLUMNS_MASK) + >> CCS_FRAME_FORMAT_MODEL_SUBTYPE_COLUMNS_SHIFT; + nrow_desc = fmt_model_subtype + & CCS_FRAME_FORMAT_MODEL_SUBTYPE_ROWS_MASK; + + dev_dbg(&client->dev, "format_model_type %s\n", + fmt_model_type == CCS_FRAME_FORMAT_MODEL_TYPE_2_BYTE + ? "2 byte" : + fmt_model_type == CCS_FRAME_FORMAT_MODEL_TYPE_4_BYTE + ? "4 byte" : "is simply bad"); + + dev_dbg(&client->dev, "%u column and %u row descriptors\n", + ncol_desc, nrow_desc); + + for (i = 0; i < ncol_desc + nrow_desc; i++) { + u32 desc; + u32 pixelcode; + u32 pixels; + char *which; + char *what; + u32 reg; + + if (fmt_model_type == CCS_FRAME_FORMAT_MODEL_TYPE_2_BYTE) { + desc = CCS_LIM_AT(sensor, FRAME_FORMAT_DESCRIPTOR, i); + + pixelcode = + (desc + & CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MASK) + >> CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_SHIFT; + pixels = desc & CCS_FRAME_FORMAT_DESCRIPTOR_PIXELS_MASK; + } else if (fmt_model_type + == CCS_FRAME_FORMAT_MODEL_TYPE_4_BYTE) { + desc = CCS_LIM_AT(sensor, FRAME_FORMAT_DESCRIPTOR_4, i); + + pixelcode = + (desc + & CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MASK) + >> CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_SHIFT; + pixels = desc & + CCS_FRAME_FORMAT_DESCRIPTOR_4_PIXELS_MASK; + } else { + dev_dbg(&client->dev, + "invalid frame format model type %d\n", + fmt_model_type); + return -EINVAL; + } + + if (i < ncol_desc) + which = "columns"; + else + which = "rows"; + + switch (pixelcode) { + case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_EMBEDDED: + what = "embedded"; + break; + case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_DUMMY_PIXEL: + what = "dummy"; + break; + case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_BLACK_PIXEL: + what = "black"; + break; + case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_DARK_PIXEL: + what = "dark"; + break; + case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_VISIBLE_PIXEL: + what = "visible"; + break; + default: + what = "invalid"; + break; + } + + dev_dbg(&client->dev, + "0x%8.8x %s pixels: %d %s (pixelcode %u)\n", reg, + what, pixels, which, pixelcode); + + if (i < ncol_desc) { + if (pixelcode == + CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_VISIBLE_PIXEL) + sensor->visible_pixel_start = pixel_count; + pixel_count += pixels; + continue; + } + + /* Handle row descriptors */ + switch (pixelcode) { + case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_EMBEDDED: + if (sensor->embedded_end) + break; + sensor->embedded_start = line_count; + sensor->embedded_end = line_count + pixels; + break; + case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_VISIBLE_PIXEL: + sensor->image_start = line_count; + break; + } + line_count += pixels; + } + + if (sensor->embedded_end > sensor->image_start) { + dev_dbg(&client->dev, + "adjusting image start line to %u (was %u)\n", + sensor->embedded_end, sensor->image_start); + sensor->image_start = sensor->embedded_end; + } + + dev_dbg(&client->dev, "embedded data from lines %d to %d\n", + sensor->embedded_start, sensor->embedded_end); + dev_dbg(&client->dev, "image data starts at line %d\n", + sensor->image_start); + + return 0; +} + +static int ccs_pll_configure(struct ccs_sensor *sensor) +{ + struct smiapp_pll *pll = &sensor->pll; + int rval; + + rval = ccs_write(sensor, VT_PIX_CLK_DIV, pll->vt.pix_clk_div); + if (rval < 0) + return rval; + + rval = ccs_write(sensor, VT_SYS_CLK_DIV, pll->vt.sys_clk_div); + if (rval < 0) + return rval; + + rval = ccs_write(sensor, PRE_PLL_CLK_DIV, pll->pre_pll_clk_div); + if (rval < 0) + return rval; + + rval = ccs_write(sensor, PLL_MULTIPLIER, pll->pll_multiplier); + if (rval < 0) + return rval; + + /* Lane op clock ratio does not apply here. */ + rval = ccs_write(sensor, REQUESTED_LINK_RATE, + DIV_ROUND_UP(pll->op.sys_clk_freq_hz, + 1000000 / 256 / 256)); + if (rval < 0 || sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) + return rval; + + rval = ccs_write(sensor, OP_PIX_CLK_DIV, pll->op.pix_clk_div); + if (rval < 0) + return rval; + + return ccs_write(sensor, OP_SYS_CLK_DIV, pll->op.sys_clk_div); +} + +static int ccs_pll_try(struct ccs_sensor *sensor, struct smiapp_pll *pll) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + struct smiapp_pll_limits lim = { + .min_pre_pll_clk_div = CCS_LIM(sensor, MIN_PRE_PLL_CLK_DIV), + .max_pre_pll_clk_div = CCS_LIM(sensor, MAX_PRE_PLL_CLK_DIV), + .min_pll_ip_freq_hz = CCS_LIM(sensor, MIN_PLL_IP_CLK_FREQ_MHZ), + .max_pll_ip_freq_hz = CCS_LIM(sensor, MAX_PLL_IP_CLK_FREQ_MHZ), + .min_pll_multiplier = CCS_LIM(sensor, MIN_PLL_MULTIPLIER), + .max_pll_multiplier = CCS_LIM(sensor, MAX_PLL_MULTIPLIER), + .min_pll_op_freq_hz = CCS_LIM(sensor, MIN_PLL_OP_CLK_FREQ_MHZ), + .max_pll_op_freq_hz = CCS_LIM(sensor, MAX_PLL_OP_CLK_FREQ_MHZ), + + .op.min_sys_clk_div = CCS_LIM(sensor, MIN_OP_SYS_CLK_DIV), + .op.max_sys_clk_div = CCS_LIM(sensor, MAX_OP_SYS_CLK_DIV), + .op.min_pix_clk_div = CCS_LIM(sensor, MIN_OP_PIX_CLK_DIV), + .op.max_pix_clk_div = CCS_LIM(sensor, MAX_OP_PIX_CLK_DIV), + .op.min_sys_clk_freq_hz = CCS_LIM(sensor, MIN_OP_SYS_CLK_FREQ_MHZ), + .op.max_sys_clk_freq_hz = CCS_LIM(sensor, MAX_OP_SYS_CLK_FREQ_MHZ), + .op.min_pix_clk_freq_hz = CCS_LIM(sensor, MIN_OP_PIX_CLK_FREQ_MHZ), + .op.max_pix_clk_freq_hz = CCS_LIM(sensor, MAX_OP_PIX_CLK_FREQ_MHZ), + + .vt.min_sys_clk_div = CCS_LIM(sensor, MIN_VT_SYS_CLK_DIV), + .vt.max_sys_clk_div = CCS_LIM(sensor, MAX_VT_SYS_CLK_DIV), + .vt.min_pix_clk_div = CCS_LIM(sensor, MIN_VT_PIX_CLK_DIV), + .vt.max_pix_clk_div = CCS_LIM(sensor, MAX_VT_PIX_CLK_DIV), + .vt.min_sys_clk_freq_hz = CCS_LIM(sensor, MIN_VT_SYS_CLK_FREQ_MHZ), + .vt.max_sys_clk_freq_hz = CCS_LIM(sensor, MAX_VT_SYS_CLK_FREQ_MHZ), + .vt.min_pix_clk_freq_hz = CCS_LIM(sensor, MIN_VT_PIX_CLK_FREQ_MHZ), + .vt.max_pix_clk_freq_hz = CCS_LIM(sensor, MAX_VT_PIX_CLK_FREQ_MHZ), + + .min_line_length_pck_bin = CCS_LIM(sensor, MIN_LINE_LENGTH_PCK_BIN), + .min_line_length_pck = CCS_LIM(sensor, MIN_LINE_LENGTH_PCK), + }; + + return smiapp_pll_calculate(&client->dev, &lim, pll); +} + +static int ccs_pll_update(struct ccs_sensor *sensor) +{ + struct smiapp_pll *pll = &sensor->pll; + int rval; + + pll->binning_horizontal = sensor->binning_horizontal; + pll->binning_vertical = sensor->binning_vertical; + pll->link_freq = + sensor->link_freq->qmenu_int[sensor->link_freq->val]; + pll->scale_m = sensor->scale_m; + pll->bits_per_pixel = sensor->csi_format->compressed; + + rval = ccs_pll_try(sensor, pll); + if (rval < 0) + return rval; + + __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_parray, + pll->pixel_rate_pixel_array); + __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_csi, pll->pixel_rate_csi); + + return 0; +} + + +/* + * + * V4L2 Controls handling + * + */ + +static void __ccs_update_exposure_limits(struct ccs_sensor *sensor) +{ + struct v4l2_ctrl *ctrl = sensor->exposure; + int max; + + max = sensor->pixel_array->crop[CCS_PA_PAD_SRC].height + + sensor->vblank->val + - CCS_LIM(sensor, COARSE_INTEGRATION_TIME_MAX_MARGIN); + + __v4l2_ctrl_modify_range(ctrl, ctrl->minimum, max, ctrl->step, max); +} + +/* + * Order matters. + * + * 1. Bits-per-pixel, descending. + * 2. Bits-per-pixel compressed, descending. + * 3. Pixel order, same as in pixel_order_str. Formats for all four pixel + * orders must be defined. + */ +static const struct ccs_csi_data_format ccs_csi_data_formats[] = { + { MEDIA_BUS_FMT_SGRBG16_1X16, 16, 16, CCS_PIXEL_ORDER_GRBG, }, + { MEDIA_BUS_FMT_SRGGB16_1X16, 16, 16, CCS_PIXEL_ORDER_RGGB, }, + { MEDIA_BUS_FMT_SBGGR16_1X16, 16, 16, CCS_PIXEL_ORDER_BGGR, }, + { MEDIA_BUS_FMT_SGBRG16_1X16, 16, 16, CCS_PIXEL_ORDER_GBRG, }, + { MEDIA_BUS_FMT_SGRBG14_1X14, 14, 14, CCS_PIXEL_ORDER_GRBG, }, + { MEDIA_BUS_FMT_SRGGB14_1X14, 14, 14, CCS_PIXEL_ORDER_RGGB, }, + { MEDIA_BUS_FMT_SBGGR14_1X14, 14, 14, CCS_PIXEL_ORDER_BGGR, }, + { MEDIA_BUS_FMT_SGBRG14_1X14, 14, 14, CCS_PIXEL_ORDER_GBRG, }, + { MEDIA_BUS_FMT_SGRBG12_1X12, 12, 12, CCS_PIXEL_ORDER_GRBG, }, + { MEDIA_BUS_FMT_SRGGB12_1X12, 12, 12, CCS_PIXEL_ORDER_RGGB, }, + { MEDIA_BUS_FMT_SBGGR12_1X12, 12, 12, CCS_PIXEL_ORDER_BGGR, }, + { MEDIA_BUS_FMT_SGBRG12_1X12, 12, 12, CCS_PIXEL_ORDER_GBRG, }, + { MEDIA_BUS_FMT_SGRBG10_1X10, 10, 10, CCS_PIXEL_ORDER_GRBG, }, + { MEDIA_BUS_FMT_SRGGB10_1X10, 10, 10, CCS_PIXEL_ORDER_RGGB, }, + { MEDIA_BUS_FMT_SBGGR10_1X10, 10, 10, CCS_PIXEL_ORDER_BGGR, }, + { MEDIA_BUS_FMT_SGBRG10_1X10, 10, 10, CCS_PIXEL_ORDER_GBRG, }, + { MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, 10, 8, CCS_PIXEL_ORDER_GRBG, }, + { MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, 10, 8, CCS_PIXEL_ORDER_RGGB, }, + { MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, 10, 8, CCS_PIXEL_ORDER_BGGR, }, + { MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, 10, 8, CCS_PIXEL_ORDER_GBRG, }, + { MEDIA_BUS_FMT_SGRBG8_1X8, 8, 8, CCS_PIXEL_ORDER_GRBG, }, + { MEDIA_BUS_FMT_SRGGB8_1X8, 8, 8, CCS_PIXEL_ORDER_RGGB, }, + { MEDIA_BUS_FMT_SBGGR8_1X8, 8, 8, CCS_PIXEL_ORDER_BGGR, }, + { MEDIA_BUS_FMT_SGBRG8_1X8, 8, 8, CCS_PIXEL_ORDER_GBRG, }, +}; + +static const char *pixel_order_str[] = { "GRBG", "RGGB", "BGGR", "GBRG" }; + +#define to_csi_format_idx(fmt) (((unsigned long)(fmt) \ + - (unsigned long)ccs_csi_data_formats) \ + / sizeof(*ccs_csi_data_formats)) + +static u32 ccs_pixel_order(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int flip = 0; + + if (sensor->hflip) { + if (sensor->hflip->val) + flip |= CCS_IMAGE_ORIENTATION_HORIZONTAL_MIRROR; + + if (sensor->vflip->val) + flip |= CCS_IMAGE_ORIENTATION_VERTICAL_FLIP; + } + + flip ^= sensor->hvflip_inv_mask; + + dev_dbg(&client->dev, "flip %d\n", flip); + return sensor->default_pixel_order ^ flip; +} + +static void ccs_update_mbus_formats(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + unsigned int csi_format_idx = + to_csi_format_idx(sensor->csi_format) & ~3; + unsigned int internal_csi_format_idx = + to_csi_format_idx(sensor->internal_csi_format) & ~3; + unsigned int pixel_order = ccs_pixel_order(sensor); + + sensor->mbus_frame_fmts = + sensor->default_mbus_frame_fmts << pixel_order; + sensor->csi_format = + &ccs_csi_data_formats[csi_format_idx + pixel_order]; + sensor->internal_csi_format = + &ccs_csi_data_formats[internal_csi_format_idx + + pixel_order]; + + BUG_ON(max(internal_csi_format_idx, csi_format_idx) + pixel_order + >= ARRAY_SIZE(ccs_csi_data_formats)); + + dev_dbg(&client->dev, "new pixel order %s\n", + pixel_order_str[pixel_order]); +} + +static const char * const ccs_test_patterns[] = { + "Disabled", + "Solid Colour", + "Eight Vertical Colour Bars", + "Colour Bars With Fade to Grey", + "Pseudorandom Sequence (PN9)", +}; + +static int ccs_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ccs_sensor *sensor = + container_of(ctrl->handler, struct ccs_subdev, ctrl_handler) + ->sensor; + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int pm_status; + u32 orient = 0; + unsigned int i; + int exposure; + int rval; + + switch (ctrl->id) { + case V4L2_CID_HFLIP: + case V4L2_CID_VFLIP: + if (sensor->streaming) + return -EBUSY; + + if (sensor->hflip->val) + orient |= CCS_IMAGE_ORIENTATION_HORIZONTAL_MIRROR; + + if (sensor->vflip->val) + orient |= CCS_IMAGE_ORIENTATION_VERTICAL_FLIP; + + orient ^= sensor->hvflip_inv_mask; + + ccs_update_mbus_formats(sensor); + + break; + case V4L2_CID_VBLANK: + exposure = sensor->exposure->val; + + __ccs_update_exposure_limits(sensor); + + if (exposure > sensor->exposure->maximum) { + sensor->exposure->val = sensor->exposure->maximum; + rval = ccs_set_ctrl(sensor->exposure); + if (rval < 0) + return rval; + } + + break; + case V4L2_CID_LINK_FREQ: + if (sensor->streaming) + return -EBUSY; + + rval = ccs_pll_update(sensor); + if (rval) + return rval; + + return 0; + case V4L2_CID_TEST_PATTERN: + for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) + v4l2_ctrl_activate( + sensor->test_data[i], + ctrl->val == + V4L2_SMIAPP_TEST_PATTERN_MODE_SOLID_COLOUR); + + break; + } + + pm_status = pm_runtime_get_if_active(&client->dev, true); + if (!pm_status) + return 0; + + switch (ctrl->id) { + case V4L2_CID_ANALOGUE_GAIN: + rval = ccs_write(sensor, ANALOG_GAIN_CODE_GLOBAL, ctrl->val); + + break; + case V4L2_CID_EXPOSURE: + rval = ccs_write(sensor, COARSE_INTEGRATION_TIME, ctrl->val); + + break; + case V4L2_CID_HFLIP: + case V4L2_CID_VFLIP: + rval = ccs_write(sensor, IMAGE_ORIENTATION, orient); + + break; + case V4L2_CID_VBLANK: + rval = ccs_write(sensor, FRAME_LENGTH_LINES, + sensor->pixel_array->crop[ + CCS_PA_PAD_SRC].height + + ctrl->val); + + break; + case V4L2_CID_HBLANK: + rval = ccs_write(sensor, LINE_LENGTH_PCK, + sensor->pixel_array->crop[ + CCS_PA_PAD_SRC].width + + ctrl->val); + + break; + case V4L2_CID_TEST_PATTERN: + rval = ccs_write(sensor, TEST_PATTERN_MODE, ctrl->val); + + break; + case V4L2_CID_TEST_PATTERN_RED: + rval = ccs_write(sensor, TEST_DATA_RED, ctrl->val); + + break; + case V4L2_CID_TEST_PATTERN_GREENR: + rval = ccs_write(sensor, TEST_DATA_GREENR, ctrl->val); + + break; + case V4L2_CID_TEST_PATTERN_BLUE: + rval = ccs_write(sensor, TEST_DATA_BLUE, ctrl->val); + + break; + case V4L2_CID_TEST_PATTERN_GREENB: + rval = ccs_write(sensor, TEST_DATA_GREENB, ctrl->val); + + break; + case V4L2_CID_PIXEL_RATE: + /* For v4l2_ctrl_s_ctrl_int64() used internally. */ + rval = 0; + + break; + default: + rval = -EINVAL; + } + + if (pm_status > 0) { + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); + } + + return rval; +} + +static const struct v4l2_ctrl_ops ccs_ctrl_ops = { + .s_ctrl = ccs_set_ctrl, +}; + +static int ccs_init_controls(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int rval; + + rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 12); + if (rval) + return rval; + + sensor->pixel_array->ctrl_handler.lock = &sensor->mutex; + + sensor->analog_gain = v4l2_ctrl_new_std( + &sensor->pixel_array->ctrl_handler, &ccs_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, + CCS_LIM(sensor, ANALOG_GAIN_CODE_MIN), + CCS_LIM(sensor, ANALOG_GAIN_CODE_MAX), + max(CCS_LIM(sensor, ANALOG_GAIN_CODE_STEP), 1U), + CCS_LIM(sensor, ANALOG_GAIN_CODE_MIN)); + + /* Exposure limits will be updated soon, use just something here. */ + sensor->exposure = v4l2_ctrl_new_std( + &sensor->pixel_array->ctrl_handler, &ccs_ctrl_ops, + V4L2_CID_EXPOSURE, 0, 0, 1, 0); + + sensor->hflip = v4l2_ctrl_new_std( + &sensor->pixel_array->ctrl_handler, &ccs_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + sensor->vflip = v4l2_ctrl_new_std( + &sensor->pixel_array->ctrl_handler, &ccs_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + + sensor->vblank = v4l2_ctrl_new_std( + &sensor->pixel_array->ctrl_handler, &ccs_ctrl_ops, + V4L2_CID_VBLANK, 0, 1, 1, 0); + + if (sensor->vblank) + sensor->vblank->flags |= V4L2_CTRL_FLAG_UPDATE; + + sensor->hblank = v4l2_ctrl_new_std( + &sensor->pixel_array->ctrl_handler, &ccs_ctrl_ops, + V4L2_CID_HBLANK, 0, 1, 1, 0); + + if (sensor->hblank) + sensor->hblank->flags |= V4L2_CTRL_FLAG_UPDATE; + + sensor->pixel_rate_parray = v4l2_ctrl_new_std( + &sensor->pixel_array->ctrl_handler, &ccs_ctrl_ops, + V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1); + + v4l2_ctrl_new_std_menu_items(&sensor->pixel_array->ctrl_handler, + &ccs_ctrl_ops, V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ccs_test_patterns) - 1, + 0, 0, ccs_test_patterns); + + if (sensor->pixel_array->ctrl_handler.error) { + dev_err(&client->dev, + "pixel array controls initialization failed (%d)\n", + sensor->pixel_array->ctrl_handler.error); + return sensor->pixel_array->ctrl_handler.error; + } + + sensor->pixel_array->sd.ctrl_handler = + &sensor->pixel_array->ctrl_handler; + + v4l2_ctrl_cluster(2, &sensor->hflip); + + rval = v4l2_ctrl_handler_init(&sensor->src->ctrl_handler, 0); + if (rval) + return rval; + + sensor->src->ctrl_handler.lock = &sensor->mutex; + + sensor->pixel_rate_csi = v4l2_ctrl_new_std( + &sensor->src->ctrl_handler, &ccs_ctrl_ops, + V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1); + + if (sensor->src->ctrl_handler.error) { + dev_err(&client->dev, + "src controls initialization failed (%d)\n", + sensor->src->ctrl_handler.error); + return sensor->src->ctrl_handler.error; + } + + sensor->src->sd.ctrl_handler = &sensor->src->ctrl_handler; + + return 0; +} + +/* + * For controls that require information on available media bus codes + * and linke frequencies. + */ +static int ccs_init_late_controls(struct ccs_sensor *sensor) +{ + unsigned long *valid_link_freqs = &sensor->valid_link_freqs[ + sensor->csi_format->compressed - sensor->compressed_min_bpp]; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) { + int max_value = (1 << sensor->csi_format->width) - 1; + + sensor->test_data[i] = v4l2_ctrl_new_std( + &sensor->pixel_array->ctrl_handler, + &ccs_ctrl_ops, V4L2_CID_TEST_PATTERN_RED + i, + 0, max_value, 1, max_value); + } + + sensor->link_freq = v4l2_ctrl_new_int_menu( + &sensor->src->ctrl_handler, &ccs_ctrl_ops, + V4L2_CID_LINK_FREQ, __fls(*valid_link_freqs), + __ffs(*valid_link_freqs), sensor->hwcfg->op_sys_clock); + + return sensor->src->ctrl_handler.error; +} + +static void ccs_free_controls(struct ccs_sensor *sensor) +{ + unsigned int i; + + for (i = 0; i < sensor->ssds_used; i++) + v4l2_ctrl_handler_free(&sensor->ssds[i].ctrl_handler); +} + +static int ccs_get_mbus_formats(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + struct smiapp_pll *pll = &sensor->pll; + u8 compressed_max_bpp = 0; + unsigned int type, n; + unsigned int i, pixel_order; + int rval; + + type = CCS_LIM(sensor, DATA_FORMAT_MODEL_TYPE); + + dev_dbg(&client->dev, "data_format_model_type %d\n", type); + + rval = ccs_read(sensor, PIXEL_ORDER, &pixel_order); + if (rval) + return rval; + + if (pixel_order >= ARRAY_SIZE(pixel_order_str)) { + dev_dbg(&client->dev, "bad pixel order %d\n", pixel_order); + return -EINVAL; + } + + dev_dbg(&client->dev, "pixel order %d (%s)\n", pixel_order, + pixel_order_str[pixel_order]); + + switch (type) { + case CCS_DATA_FORMAT_MODEL_TYPE_NORMAL: + n = SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL_N; + break; + case CCS_DATA_FORMAT_MODEL_TYPE_EXTENDED: + n = CCS_LIM_DATA_FORMAT_DESCRIPTOR_MAX_N + 1; + break; + default: + return -EINVAL; + } + + sensor->default_pixel_order = pixel_order; + sensor->mbus_frame_fmts = 0; + + for (i = 0; i < n; i++) { + unsigned int fmt, j; + + fmt = CCS_LIM_AT(sensor, DATA_FORMAT_DESCRIPTOR, i); + + dev_dbg(&client->dev, "%u: bpp %u, compressed %u\n", + i, fmt >> 8, (u8)fmt); + + for (j = 0; j < ARRAY_SIZE(ccs_csi_data_formats); j++) { + const struct ccs_csi_data_format *f = + &ccs_csi_data_formats[j]; + + if (f->pixel_order != CCS_PIXEL_ORDER_GRBG) + continue; + + if (f->width != fmt >> + CCS_DATA_FORMAT_DESCRIPTOR_UNCOMPRESSED_SHIFT || + f->compressed != + (fmt & CCS_DATA_FORMAT_DESCRIPTOR_COMPRESSED_MASK)) + continue; + + dev_dbg(&client->dev, "jolly good! %d\n", j); + + sensor->default_mbus_frame_fmts |= 1 << j; + } + } + + /* Figure out which BPP values can be used with which formats. */ + pll->binning_horizontal = 1; + pll->binning_vertical = 1; + pll->scale_m = sensor->scale_m; + + for (i = 0; i < ARRAY_SIZE(ccs_csi_data_formats); i++) { + sensor->compressed_min_bpp = + min(ccs_csi_data_formats[i].compressed, + sensor->compressed_min_bpp); + compressed_max_bpp = + max(ccs_csi_data_formats[i].compressed, + compressed_max_bpp); + } + + sensor->valid_link_freqs = devm_kcalloc( + &client->dev, + compressed_max_bpp - sensor->compressed_min_bpp + 1, + sizeof(*sensor->valid_link_freqs), GFP_KERNEL); + if (!sensor->valid_link_freqs) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(ccs_csi_data_formats); i++) { + const struct ccs_csi_data_format *f = + &ccs_csi_data_formats[i]; + unsigned long *valid_link_freqs = + &sensor->valid_link_freqs[ + f->compressed - sensor->compressed_min_bpp]; + unsigned int j; + + if (!(sensor->default_mbus_frame_fmts & 1 << i)) + continue; + + pll->bits_per_pixel = f->compressed; + + for (j = 0; sensor->hwcfg->op_sys_clock[j]; j++) { + pll->link_freq = sensor->hwcfg->op_sys_clock[j]; + + rval = ccs_pll_try(sensor, pll); + dev_dbg(&client->dev, "link freq %u Hz, bpp %u %s\n", + pll->link_freq, pll->bits_per_pixel, + rval ? "not ok" : "ok"); + if (rval) + continue; + + set_bit(j, valid_link_freqs); + } + + if (!*valid_link_freqs) { + dev_info(&client->dev, + "no valid link frequencies for %u bpp\n", + f->compressed); + sensor->default_mbus_frame_fmts &= ~BIT(i); + continue; + } + + if (!sensor->csi_format + || f->width > sensor->csi_format->width + || (f->width == sensor->csi_format->width + && f->compressed > sensor->csi_format->compressed)) { + sensor->csi_format = f; + sensor->internal_csi_format = f; + } + } + + if (!sensor->csi_format) { + dev_err(&client->dev, "no supported mbus code found\n"); + return -EINVAL; + } + + ccs_update_mbus_formats(sensor); + + return 0; +} + +static void ccs_update_blanking(struct ccs_sensor *sensor) +{ + struct v4l2_ctrl *vblank = sensor->vblank; + struct v4l2_ctrl *hblank = sensor->hblank; + uint16_t min_fll, max_fll, min_llp, max_llp, min_lbp; + int min, max; + + if (sensor->binning_vertical > 1 || sensor->binning_horizontal > 1) { + min_fll = CCS_LIM(sensor, MIN_FRAME_LENGTH_LINES_BIN); + max_fll = CCS_LIM(sensor, MAX_FRAME_LENGTH_LINES_BIN); + min_llp = CCS_LIM(sensor, MIN_LINE_LENGTH_PCK_BIN); + max_llp = CCS_LIM(sensor, MAX_LINE_LENGTH_PCK_BIN); + min_lbp = CCS_LIM(sensor, MIN_LINE_BLANKING_PCK_BIN); + } else { + min_fll = CCS_LIM(sensor, MIN_FRAME_LENGTH_LINES); + max_fll = CCS_LIM(sensor, MAX_FRAME_LENGTH_LINES); + min_llp = CCS_LIM(sensor, MIN_LINE_LENGTH_PCK); + max_llp = CCS_LIM(sensor, MAX_LINE_LENGTH_PCK); + min_lbp = CCS_LIM(sensor, MIN_LINE_BLANKING_PCK); + } + + min = max_t(int, + CCS_LIM(sensor, MIN_FRAME_BLANKING_LINES), + min_fll - + sensor->pixel_array->crop[CCS_PA_PAD_SRC].height); + max = max_fll - sensor->pixel_array->crop[CCS_PA_PAD_SRC].height; + + __v4l2_ctrl_modify_range(vblank, min, max, vblank->step, min); + + min = max_t(int, + min_llp - + sensor->pixel_array->crop[CCS_PA_PAD_SRC].width, + min_lbp); + max = max_llp - sensor->pixel_array->crop[CCS_PA_PAD_SRC].width; + + __v4l2_ctrl_modify_range(hblank, min, max, hblank->step, min); + + __ccs_update_exposure_limits(sensor); +} + +static int ccs_pll_blanking_update(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int rval; + + rval = ccs_pll_update(sensor); + if (rval < 0) + return rval; + + /* Output from pixel array, including blanking */ + ccs_update_blanking(sensor); + + dev_dbg(&client->dev, "vblank\t\t%d\n", sensor->vblank->val); + dev_dbg(&client->dev, "hblank\t\t%d\n", sensor->hblank->val); + + dev_dbg(&client->dev, "real timeperframe\t100/%d\n", + sensor->pll.pixel_rate_pixel_array / + ((sensor->pixel_array->crop[CCS_PA_PAD_SRC].width + + sensor->hblank->val) * + (sensor->pixel_array->crop[CCS_PA_PAD_SRC].height + + sensor->vblank->val) / 100)); + + return 0; +} + +/* + * + * SMIA++ NVM handling + * + */ + +static int ccs_read_nvm_page(struct ccs_sensor *sensor, u32 p, u8 *nvm, + u8 *status) +{ + unsigned int i; + int rval; + u32 s; + + *status = 0; + + rval = ccs_write(sensor, DATA_TRANSFER_IF_1_PAGE_SELECT, p); + if (rval) + return rval; + + rval = ccs_write(sensor, DATA_TRANSFER_IF_1_CTRL, + CCS_DATA_TRANSFER_IF_1_CTRL_ENABLE); + if (rval) + return rval; + + rval = ccs_read(sensor, DATA_TRANSFER_IF_1_STATUS, &s); + if (rval) + return rval; + + if (s & CCS_DATA_TRANSFER_IF_1_STATUS_IMPROPER_IF_USAGE) { + *status = s; + return -ENODATA; + } + + if (CCS_LIM(sensor, DATA_TRANSFER_IF_CAPABILITY) & + CCS_DATA_TRANSFER_IF_CAPABILITY_POLLING) { + for (i = 1000; i > 0; i--) { + if (s & CCS_DATA_TRANSFER_IF_1_STATUS_READ_IF_READY) + break; + + rval = ccs_read(sensor, DATA_TRANSFER_IF_1_STATUS, &s); + if (rval) + return rval; + } + + if (!i) + return -ETIMEDOUT; + } + + for (i = 0; i <= CCS_LIM_DATA_TRANSFER_IF_1_DATA_MAX_P; i++) { + u32 v; + + rval = ccs_read(sensor, DATA_TRANSFER_IF_1_DATA(i), &v); + if (rval) + return rval; + + *nvm++ = v; + } + + return 0; +} + +static int ccs_read_nvm(struct ccs_sensor *sensor, unsigned char *nvm, + size_t nvm_size) +{ + u8 status = 0; + u32 p; + int rval = 0, rval2; + + for (p = 0; p < nvm_size / (CCS_LIM_DATA_TRANSFER_IF_1_DATA_MAX_P + 1) + && !rval; p++) { + rval = ccs_read_nvm_page(sensor, p, nvm, &status); + nvm += CCS_LIM_DATA_TRANSFER_IF_1_DATA_MAX_P + 1; + } + + if (rval == -ENODATA && + status & CCS_DATA_TRANSFER_IF_1_STATUS_IMPROPER_IF_USAGE) + rval = 0; + + rval2 = ccs_write(sensor, DATA_TRANSFER_IF_1_CTRL, 0); + if (rval < 0) + return rval; + else + return rval2 ?: p * (CCS_LIM_DATA_TRANSFER_IF_1_DATA_MAX_P + 1); +} + +/* + * + * SMIA++ CCI address control + * + */ +static int ccs_change_cci_addr(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int rval; + u32 val; + + client->addr = sensor->hwcfg->i2c_addr_dfl; + + rval = ccs_write(sensor, CCI_ADDRESS_CTRL, + sensor->hwcfg->i2c_addr_alt << 1); + if (rval) + return rval; + + client->addr = sensor->hwcfg->i2c_addr_alt; + + /* verify addr change went ok */ + rval = ccs_read(sensor, CCI_ADDRESS_CTRL, &val); + if (rval) + return rval; + + if (val != sensor->hwcfg->i2c_addr_alt << 1) + return -ENODEV; + + return 0; +} + +/* + * + * SMIA++ Mode Control + * + */ +static int ccs_setup_flash_strobe(struct ccs_sensor *sensor) +{ + struct ccs_flash_strobe_parms *strobe_setup; + unsigned int ext_freq = sensor->hwcfg->ext_clk; + u32 tmp; + u32 strobe_adjustment; + u32 strobe_width_high_rs; + int rval; + + strobe_setup = sensor->hwcfg->strobe_setup; + + /* + * How to calculate registers related to strobe length. Please + * do not change, or if you do at least know what you're + * doing. :-) + * + * Sakari Ailus 2010-10-25 + * + * flash_strobe_length [us] / 10^6 = (tFlash_strobe_width_ctrl + * / EXTCLK freq [Hz]) * flash_strobe_adjustment + * + * tFlash_strobe_width_ctrl E N, [1 - 0xffff] + * flash_strobe_adjustment E N, [1 - 0xff] + * + * The formula above is written as below to keep it on one + * line: + * + * l / 10^6 = w / e * a + * + * Let's mark w * a by x: + * + * x = w * a + * + * Thus, we get: + * + * x = l * e / 10^6 + * + * The strobe width must be at least as long as requested, + * thus rounding upwards is needed. + * + * x = (l * e + 10^6 - 1) / 10^6 + * ----------------------------- + * + * Maximum possible accuracy is wanted at all times. Thus keep + * a as small as possible. + * + * Calculate a, assuming maximum w, with rounding upwards: + * + * a = (x + (2^16 - 1) - 1) / (2^16 - 1) + * ------------------------------------- + * + * Thus, we also get w, with that a, with rounding upwards: + * + * w = (x + a - 1) / a + * ------------------- + * + * To get limits: + * + * x E [1, (2^16 - 1) * (2^8 - 1)] + * + * Substituting maximum x to the original formula (with rounding), + * the maximum l is thus + * + * (2^16 - 1) * (2^8 - 1) * 10^6 = l * e + 10^6 - 1 + * + * l = (10^6 * (2^16 - 1) * (2^8 - 1) - 10^6 + 1) / e + * -------------------------------------------------- + * + * flash_strobe_length must be clamped between 1 and + * (10^6 * (2^16 - 1) * (2^8 - 1) - 10^6 + 1) / EXTCLK freq. + * + * Then, + * + * flash_strobe_adjustment = ((flash_strobe_length * + * EXTCLK freq + 10^6 - 1) / 10^6 + (2^16 - 1) - 1) / (2^16 - 1) + * + * tFlash_strobe_width_ctrl = ((flash_strobe_length * + * EXTCLK freq + 10^6 - 1) / 10^6 + + * flash_strobe_adjustment - 1) / flash_strobe_adjustment + */ + tmp = div_u64(1000000ULL * ((1 << 16) - 1) * ((1 << 8) - 1) - + 1000000 + 1, ext_freq); + strobe_setup->strobe_width_high_us = + clamp_t(u32, strobe_setup->strobe_width_high_us, 1, tmp); + + tmp = div_u64(((u64)strobe_setup->strobe_width_high_us * (u64)ext_freq + + 1000000 - 1), 1000000ULL); + strobe_adjustment = (tmp + (1 << 16) - 1 - 1) / ((1 << 16) - 1); + strobe_width_high_rs = (tmp + strobe_adjustment - 1) / + strobe_adjustment; + + rval = ccs_write(sensor, FLASH_MODE_RS, strobe_setup->mode); + if (rval < 0) + goto out; + + rval = ccs_write(sensor, FLASH_STROBE_ADJUSTMENT, strobe_adjustment); + if (rval < 0) + goto out; + + rval = ccs_write(sensor, TFLASH_STROBE_WIDTH_HIGH_RS_CTRL, + strobe_width_high_rs); + if (rval < 0) + goto out; + + rval = ccs_write(sensor, TFLASH_STROBE_DELAY_RS_CTRL, + strobe_setup->strobe_delay); + if (rval < 0) + goto out; + + rval = ccs_write(sensor, FLASH_STROBE_START_POINT, + strobe_setup->stobe_start_point); + if (rval < 0) + goto out; + + rval = ccs_write(sensor, FLASH_TRIGGER_RS, strobe_setup->trigger); + +out: + sensor->hwcfg->strobe_setup->trigger = 0; + + return rval; +} + +/* ----------------------------------------------------------------------------- + * Power management + */ + +static int ccs_power_on(struct device *dev) +{ + struct v4l2_subdev *subdev = dev_get_drvdata(dev); + struct ccs_subdev *ssd = to_ccs_subdev(subdev); + /* + * The sub-device related to the I2C device is always the + * source one, i.e. ssds[0]. + */ + struct ccs_sensor *sensor = + container_of(ssd, struct ccs_sensor, ssds[0]); + unsigned int sleep; + int rval; + + rval = regulator_enable(sensor->vana); + if (rval) { + dev_err(dev, "failed to enable vana regulator\n"); + return rval; + } + usleep_range(1000, 1000); + + rval = clk_prepare_enable(sensor->ext_clk); + if (rval < 0) { + dev_dbg(dev, "failed to enable xclk\n"); + goto out_xclk_fail; + } + usleep_range(1000, 1000); + + gpiod_set_value(sensor->xshutdown, 1); + + sleep = SMIAPP_RESET_DELAY(sensor->hwcfg->ext_clk); + usleep_range(sleep, sleep); + + /* + * Failures to respond to the address change command have been noticed. + * Those failures seem to be caused by the sensor requiring a longer + * boot time than advertised. An additional 10ms delay seems to work + * around the issue, but the SMIA++ I2C write retry hack makes the delay + * unnecessary. The failures need to be investigated to find a proper + * fix, and a delay will likely need to be added here if the I2C write + * retry hack is reverted before the root cause of the boot time issue + * is found. + */ + + if (sensor->hwcfg->i2c_addr_alt) { + rval = ccs_change_cci_addr(sensor); + if (rval) { + dev_err(dev, "cci address change error\n"); + goto out_cci_addr_fail; + } + } + + rval = ccs_write(sensor, SOFTWARE_RESET, CCS_SOFTWARE_RESET_ON); + if (rval < 0) { + dev_err(dev, "software reset failed\n"); + goto out_cci_addr_fail; + } + + if (sensor->hwcfg->i2c_addr_alt) { + rval = ccs_change_cci_addr(sensor); + if (rval) { + dev_err(dev, "cci address change error\n"); + goto out_cci_addr_fail; + } + } + + rval = ccs_write(sensor, COMPRESSION_MODE, + CCS_COMPRESSION_MODE_DPCM_PCM_SIMPLE); + if (rval) { + dev_err(dev, "compression mode set failed\n"); + goto out_cci_addr_fail; + } + + rval = ccs_write(sensor, EXTCLK_FREQUENCY_MHZ, + sensor->hwcfg->ext_clk / (1000000 / (1 << 8))); + if (rval) { + dev_err(dev, "extclk frequency set failed\n"); + goto out_cci_addr_fail; + } + + rval = ccs_write(sensor, CSI_LANE_MODE, sensor->hwcfg->lanes - 1); + if (rval) { + dev_err(dev, "csi lane mode set failed\n"); + goto out_cci_addr_fail; + } + + rval = ccs_write(sensor, FAST_STANDBY_CTRL, + CCS_FAST_STANDBY_CTRL_FRAME_TRUNCATION); + if (rval) { + dev_err(dev, "fast standby set failed\n"); + goto out_cci_addr_fail; + } + + rval = ccs_write(sensor, CSI_SIGNALING_MODE, + sensor->hwcfg->csi_signalling_mode); + if (rval) { + dev_err(dev, "csi signalling mode set failed\n"); + goto out_cci_addr_fail; + } + + /* DPHY control done by sensor based on requested link rate */ + rval = ccs_write(sensor, PHY_CTRL, CCS_PHY_CTRL_UI); + if (rval < 0) + goto out_cci_addr_fail; + + rval = ccs_call_quirk(sensor, post_poweron); + if (rval) { + dev_err(dev, "post_poweron quirks failed\n"); + goto out_cci_addr_fail; + } + + return 0; + +out_cci_addr_fail: + gpiod_set_value(sensor->xshutdown, 0); + clk_disable_unprepare(sensor->ext_clk); + +out_xclk_fail: + regulator_disable(sensor->vana); + + return rval; +} + +static int ccs_power_off(struct device *dev) +{ + struct v4l2_subdev *subdev = dev_get_drvdata(dev); + struct ccs_subdev *ssd = to_ccs_subdev(subdev); + struct ccs_sensor *sensor = + container_of(ssd, struct ccs_sensor, ssds[0]); + + /* + * Currently power/clock to lens are enable/disabled separately + * but they are essentially the same signals. So if the sensor is + * powered off while the lens is powered on the sensor does not + * really see a power off and next time the cci address change + * will fail. So do a soft reset explicitly here. + */ + if (sensor->hwcfg->i2c_addr_alt) + ccs_write(sensor, SOFTWARE_RESET, CCS_SOFTWARE_RESET_ON); + + gpiod_set_value(sensor->xshutdown, 0); + clk_disable_unprepare(sensor->ext_clk); + usleep_range(5000, 5000); + regulator_disable(sensor->vana); + sensor->streaming = false; + + return 0; +} + +/* ----------------------------------------------------------------------------- + * Video stream management + */ + +static int ccs_start_streaming(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + unsigned int binning_mode; + int rval; + + mutex_lock(&sensor->mutex); + + rval = ccs_write(sensor, CSI_DATA_FORMAT, + (sensor->csi_format->width << 8) | + sensor->csi_format->compressed); + if (rval) + goto out; + + /* Binning configuration */ + if (sensor->binning_horizontal == 1 && + sensor->binning_vertical == 1) { + binning_mode = 0; + } else { + u8 binning_type = + (sensor->binning_horizontal << 4) + | sensor->binning_vertical; + + rval = ccs_write(sensor, BINNING_TYPE, binning_type); + if (rval < 0) + goto out; + + binning_mode = 1; + } + rval = ccs_write(sensor, BINNING_MODE, binning_mode); + if (rval < 0) + goto out; + + /* Set up PLL */ + rval = ccs_pll_configure(sensor); + if (rval) + goto out; + + /* Analog crop start coordinates */ + rval = ccs_write(sensor, X_ADDR_START, + sensor->pixel_array->crop[CCS_PA_PAD_SRC].left); + if (rval < 0) + goto out; + + rval = ccs_write(sensor, Y_ADDR_START, + sensor->pixel_array->crop[CCS_PA_PAD_SRC].top); + if (rval < 0) + goto out; + + /* Analog crop end coordinates */ + rval = ccs_write( + sensor, X_ADDR_END, + sensor->pixel_array->crop[CCS_PA_PAD_SRC].left + + sensor->pixel_array->crop[CCS_PA_PAD_SRC].width - 1); + if (rval < 0) + goto out; + + rval = ccs_write( + sensor, Y_ADDR_END, + sensor->pixel_array->crop[CCS_PA_PAD_SRC].top + + sensor->pixel_array->crop[CCS_PA_PAD_SRC].height - 1); + if (rval < 0) + goto out; + + /* + * Output from pixel array, including blanking, is set using + * controls below. No need to set here. + */ + + /* Digital crop */ + if (CCS_LIM(sensor, DIGITAL_CROP_CAPABILITY) + == CCS_DIGITAL_CROP_CAPABILITY_INPUT_CROP) { + rval = ccs_write( + sensor, DIGITAL_CROP_X_OFFSET, + sensor->scaler->crop[CCS_PAD_SINK].left); + if (rval < 0) + goto out; + + rval = ccs_write( + sensor, DIGITAL_CROP_Y_OFFSET, + sensor->scaler->crop[CCS_PAD_SINK].top); + if (rval < 0) + goto out; + + rval = ccs_write( + sensor, DIGITAL_CROP_IMAGE_WIDTH, + sensor->scaler->crop[CCS_PAD_SINK].width); + if (rval < 0) + goto out; + + rval = ccs_write( + sensor, DIGITAL_CROP_IMAGE_HEIGHT, + sensor->scaler->crop[CCS_PAD_SINK].height); + if (rval < 0) + goto out; + } + + /* Scaling */ + if (CCS_LIM(sensor, SCALING_CAPABILITY) + != CCS_SCALING_CAPABILITY_NONE) { + rval = ccs_write(sensor, SCALING_MODE, sensor->scaling_mode); + if (rval < 0) + goto out; + + rval = ccs_write(sensor, SCALE_M, sensor->scale_m); + if (rval < 0) + goto out; + } + + /* Output size from sensor */ + rval = ccs_write(sensor, X_OUTPUT_SIZE, + sensor->src->crop[CCS_PAD_SRC].width); + if (rval < 0) + goto out; + rval = ccs_write(sensor, Y_OUTPUT_SIZE, + sensor->src->crop[CCS_PAD_SRC].height); + if (rval < 0) + goto out; + + if (CCS_LIM(sensor, FLASH_MODE_CAPABILITY) & + (CCS_FLASH_MODE_CAPABILITY_SINGLE_STROBE | + SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE) && + sensor->hwcfg->strobe_setup != NULL && + sensor->hwcfg->strobe_setup->trigger != 0) { + rval = ccs_setup_flash_strobe(sensor); + if (rval) + goto out; + } + + rval = ccs_call_quirk(sensor, pre_streamon); + if (rval) { + dev_err(&client->dev, "pre_streamon quirks failed\n"); + goto out; + } + + rval = ccs_write(sensor, MODE_SELECT, CCS_MODE_SELECT_STREAMING); + +out: + mutex_unlock(&sensor->mutex); + + return rval; +} + +static int ccs_stop_streaming(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int rval; + + mutex_lock(&sensor->mutex); + rval = ccs_write(sensor, MODE_SELECT, CCS_MODE_SELECT_SOFTWARE_STANDBY); + if (rval) + goto out; + + rval = ccs_call_quirk(sensor, post_streamoff); + if (rval) + dev_err(&client->dev, "post_streamoff quirks failed\n"); + +out: + mutex_unlock(&sensor->mutex); + return rval; +} + +/* ----------------------------------------------------------------------------- + * V4L2 subdev video operations + */ + +static int ccs_pm_get_init(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int rval; + + rval = pm_runtime_get_sync(&client->dev); + if (rval < 0) { + if (rval != -EBUSY && rval != -EAGAIN) + pm_runtime_set_active(&client->dev); + pm_runtime_put_noidle(&client->dev); + + return rval; + } else if (!rval) { + rval = v4l2_ctrl_handler_setup(&sensor->pixel_array-> + ctrl_handler); + if (rval) + return rval; + + return v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler); + } + + return 0; +} + +static int ccs_set_stream(struct v4l2_subdev *subdev, int enable) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int rval; + + if (sensor->streaming == enable) + return 0; + + if (!enable) { + ccs_stop_streaming(sensor); + sensor->streaming = false; + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); + + return 0; + } + + rval = ccs_pm_get_init(sensor); + if (rval) + return rval; + + sensor->streaming = true; + + rval = ccs_start_streaming(sensor); + if (rval < 0) { + sensor->streaming = false; + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); + } + + return rval; +} + +static int ccs_enum_mbus_code(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct i2c_client *client = v4l2_get_subdevdata(subdev); + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + unsigned int i; + int idx = -1; + int rval = -EINVAL; + + mutex_lock(&sensor->mutex); + + dev_err(&client->dev, "subdev %s, pad %d, index %d\n", + subdev->name, code->pad, code->index); + + if (subdev != &sensor->src->sd || code->pad != CCS_PAD_SRC) { + if (code->index) + goto out; + + code->code = sensor->internal_csi_format->code; + rval = 0; + goto out; + } + + for (i = 0; i < ARRAY_SIZE(ccs_csi_data_formats); i++) { + if (sensor->mbus_frame_fmts & (1 << i)) + idx++; + + if (idx == code->index) { + code->code = ccs_csi_data_formats[i].code; + dev_err(&client->dev, "found index %d, i %d, code %x\n", + code->index, i, code->code); + rval = 0; + break; + } + } + +out: + mutex_unlock(&sensor->mutex); + + return rval; +} + +static u32 __ccs_get_mbus_code(struct v4l2_subdev *subdev, unsigned int pad) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + + if (subdev == &sensor->src->sd && pad == CCS_PAD_SRC) + return sensor->csi_format->code; + else + return sensor->internal_csi_format->code; +} + +static int __ccs_get_format(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ccs_subdev *ssd = to_ccs_subdev(subdev); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + fmt->format = *v4l2_subdev_get_try_format(subdev, cfg, + fmt->pad); + } else { + struct v4l2_rect *r; + + if (fmt->pad == ssd->source_pad) + r = &ssd->crop[ssd->source_pad]; + else + r = &ssd->sink_fmt; + + fmt->format.code = __ccs_get_mbus_code(subdev, fmt->pad); + fmt->format.width = r->width; + fmt->format.height = r->height; + fmt->format.field = V4L2_FIELD_NONE; + } + + return 0; +} + +static int ccs_get_format(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + int rval; + + mutex_lock(&sensor->mutex); + rval = __ccs_get_format(subdev, cfg, fmt); + mutex_unlock(&sensor->mutex); + + return rval; +} + +static void ccs_get_crop_compose(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_rect **crops, + struct v4l2_rect **comps, int which) +{ + struct ccs_subdev *ssd = to_ccs_subdev(subdev); + unsigned int i; + + if (which == V4L2_SUBDEV_FORMAT_ACTIVE) { + if (crops) + for (i = 0; i < subdev->entity.num_pads; i++) + crops[i] = &ssd->crop[i]; + if (comps) + *comps = &ssd->compose; + } else { + if (crops) { + for (i = 0; i < subdev->entity.num_pads; i++) { + crops[i] = v4l2_subdev_get_try_crop(subdev, cfg, i); + BUG_ON(!crops[i]); + } + } + if (comps) { + *comps = v4l2_subdev_get_try_compose(subdev, cfg, + CCS_PAD_SINK); + BUG_ON(!*comps); + } + } +} + +/* Changes require propagation only on sink pad. */ +static void ccs_propagate(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, int which, + int target) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + struct ccs_subdev *ssd = to_ccs_subdev(subdev); + struct v4l2_rect *comp, *crops[CCS_PADS]; + + ccs_get_crop_compose(subdev, cfg, crops, &comp, which); + + switch (target) { + case V4L2_SEL_TGT_CROP: + comp->width = crops[CCS_PAD_SINK]->width; + comp->height = crops[CCS_PAD_SINK]->height; + if (which == V4L2_SUBDEV_FORMAT_ACTIVE) { + if (ssd == sensor->scaler) { + sensor->scale_m = + CCS_LIM(sensor, SCALER_N_MIN); + sensor->scaling_mode = + CCS_SCALING_MODE_NO_SCALING; + } else if (ssd == sensor->binner) { + sensor->binning_horizontal = 1; + sensor->binning_vertical = 1; + } + } + fallthrough; + case V4L2_SEL_TGT_COMPOSE: + *crops[CCS_PAD_SRC] = *comp; + break; + default: + BUG(); + } +} + +static const struct ccs_csi_data_format +*ccs_validate_csi_data_format(struct ccs_sensor *sensor, u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ccs_csi_data_formats); i++) { + if (sensor->mbus_frame_fmts & (1 << i) && + ccs_csi_data_formats[i].code == code) + return &ccs_csi_data_formats[i]; + } + + return sensor->csi_format; +} + +static int ccs_set_format_source(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + const struct ccs_csi_data_format *csi_format, + *old_csi_format = sensor->csi_format; + unsigned long *valid_link_freqs; + u32 code = fmt->format.code; + unsigned int i; + int rval; + + rval = __ccs_get_format(subdev, cfg, fmt); + if (rval) + return rval; + + /* + * Media bus code is changeable on src subdev's source pad. On + * other source pads we just get format here. + */ + if (subdev != &sensor->src->sd) + return 0; + + csi_format = ccs_validate_csi_data_format(sensor, code); + + fmt->format.code = csi_format->code; + + if (fmt->which != V4L2_SUBDEV_FORMAT_ACTIVE) + return 0; + + sensor->csi_format = csi_format; + + if (csi_format->width != old_csi_format->width) + for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) + __v4l2_ctrl_modify_range( + sensor->test_data[i], 0, + (1 << csi_format->width) - 1, 1, 0); + + if (csi_format->compressed == old_csi_format->compressed) + return 0; + + valid_link_freqs = + &sensor->valid_link_freqs[sensor->csi_format->compressed + - sensor->compressed_min_bpp]; + + __v4l2_ctrl_modify_range( + sensor->link_freq, 0, + __fls(*valid_link_freqs), ~*valid_link_freqs, + __ffs(*valid_link_freqs)); + + return ccs_pll_update(sensor); +} + +static int ccs_set_format(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + struct ccs_subdev *ssd = to_ccs_subdev(subdev); + struct v4l2_rect *crops[CCS_PADS]; + + mutex_lock(&sensor->mutex); + + if (fmt->pad == ssd->source_pad) { + int rval; + + rval = ccs_set_format_source(subdev, cfg, fmt); + + mutex_unlock(&sensor->mutex); + + return rval; + } + + /* Sink pad. Width and height are changeable here. */ + fmt->format.code = __ccs_get_mbus_code(subdev, fmt->pad); + fmt->format.width &= ~1; + fmt->format.height &= ~1; + fmt->format.field = V4L2_FIELD_NONE; + + fmt->format.width = + clamp(fmt->format.width, + CCS_LIM(sensor, MIN_X_OUTPUT_SIZE), + CCS_LIM(sensor, MAX_X_OUTPUT_SIZE)); + fmt->format.height = + clamp(fmt->format.height, + CCS_LIM(sensor, MIN_Y_OUTPUT_SIZE), + CCS_LIM(sensor, MAX_Y_OUTPUT_SIZE)); + + ccs_get_crop_compose(subdev, cfg, crops, NULL, fmt->which); + + crops[ssd->sink_pad]->left = 0; + crops[ssd->sink_pad]->top = 0; + crops[ssd->sink_pad]->width = fmt->format.width; + crops[ssd->sink_pad]->height = fmt->format.height; + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) + ssd->sink_fmt = *crops[ssd->sink_pad]; + ccs_propagate(subdev, cfg, fmt->which, V4L2_SEL_TGT_CROP); + + mutex_unlock(&sensor->mutex); + + return 0; +} + +/* + * Calculate goodness of scaled image size compared to expected image + * size and flags provided. + */ +#define SCALING_GOODNESS 100000 +#define SCALING_GOODNESS_EXTREME 100000000 +static int scaling_goodness(struct v4l2_subdev *subdev, int w, int ask_w, + int h, int ask_h, u32 flags) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + struct i2c_client *client = v4l2_get_subdevdata(subdev); + int val = 0; + + w &= ~1; + ask_w &= ~1; + h &= ~1; + ask_h &= ~1; + + if (flags & V4L2_SEL_FLAG_GE) { + if (w < ask_w) + val -= SCALING_GOODNESS; + if (h < ask_h) + val -= SCALING_GOODNESS; + } + + if (flags & V4L2_SEL_FLAG_LE) { + if (w > ask_w) + val -= SCALING_GOODNESS; + if (h > ask_h) + val -= SCALING_GOODNESS; + } + + val -= abs(w - ask_w); + val -= abs(h - ask_h); + + if (w < CCS_LIM(sensor, MIN_X_OUTPUT_SIZE)) + val -= SCALING_GOODNESS_EXTREME; + + dev_dbg(&client->dev, "w %d ask_w %d h %d ask_h %d goodness %d\n", + w, ask_w, h, ask_h, val); + + return val; +} + +static void ccs_set_compose_binner(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel, + struct v4l2_rect **crops, + struct v4l2_rect *comp) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + unsigned int i; + unsigned int binh = 1, binv = 1; + int best = scaling_goodness( + subdev, + crops[CCS_PAD_SINK]->width, sel->r.width, + crops[CCS_PAD_SINK]->height, sel->r.height, sel->flags); + + for (i = 0; i < sensor->nbinning_subtypes; i++) { + int this = scaling_goodness( + subdev, + crops[CCS_PAD_SINK]->width + / sensor->binning_subtypes[i].horizontal, + sel->r.width, + crops[CCS_PAD_SINK]->height + / sensor->binning_subtypes[i].vertical, + sel->r.height, sel->flags); + + if (this > best) { + binh = sensor->binning_subtypes[i].horizontal; + binv = sensor->binning_subtypes[i].vertical; + best = this; + } + } + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + sensor->binning_vertical = binv; + sensor->binning_horizontal = binh; + } + + sel->r.width = (crops[CCS_PAD_SINK]->width / binh) & ~1; + sel->r.height = (crops[CCS_PAD_SINK]->height / binv) & ~1; +} + +/* + * Calculate best scaling ratio and mode for given output resolution. + * + * Try all of these: horizontal ratio, vertical ratio and smallest + * size possible (horizontally). + * + * Also try whether horizontal scaler or full scaler gives a better + * result. + */ +static void ccs_set_compose_scaler(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel, + struct v4l2_rect **crops, + struct v4l2_rect *comp) +{ + struct i2c_client *client = v4l2_get_subdevdata(subdev); + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + u32 min, max, a, b, max_m; + u32 scale_m = CCS_LIM(sensor, SCALER_N_MIN); + int mode = CCS_SCALING_MODE_HORIZONTAL; + u32 try[4]; + u32 ntry = 0; + unsigned int i; + int best = INT_MIN; + + sel->r.width = min_t(unsigned int, sel->r.width, + crops[CCS_PAD_SINK]->width); + sel->r.height = min_t(unsigned int, sel->r.height, + crops[CCS_PAD_SINK]->height); + + a = crops[CCS_PAD_SINK]->width + * CCS_LIM(sensor, SCALER_N_MIN) / sel->r.width; + b = crops[CCS_PAD_SINK]->height + * CCS_LIM(sensor, SCALER_N_MIN) / sel->r.height; + max_m = crops[CCS_PAD_SINK]->width + * CCS_LIM(sensor, SCALER_N_MIN) + / CCS_LIM(sensor, MIN_X_OUTPUT_SIZE); + + a = clamp(a, CCS_LIM(sensor, SCALER_M_MIN), + CCS_LIM(sensor, SCALER_M_MAX)); + b = clamp(b, CCS_LIM(sensor, SCALER_M_MIN), + CCS_LIM(sensor, SCALER_M_MAX)); + max_m = clamp(max_m, CCS_LIM(sensor, SCALER_M_MIN), + CCS_LIM(sensor, SCALER_M_MAX)); + + dev_dbg(&client->dev, "scaling: a %d b %d max_m %d\n", a, b, max_m); + + min = min(max_m, min(a, b)); + max = min(max_m, max(a, b)); + + try[ntry] = min; + ntry++; + if (min != max) { + try[ntry] = max; + ntry++; + } + if (max != max_m) { + try[ntry] = min + 1; + ntry++; + if (min != max) { + try[ntry] = max + 1; + ntry++; + } + } + + for (i = 0; i < ntry; i++) { + int this = scaling_goodness( + subdev, + crops[CCS_PAD_SINK]->width + / try[i] * CCS_LIM(sensor, SCALER_N_MIN), + sel->r.width, + crops[CCS_PAD_SINK]->height, + sel->r.height, + sel->flags); + + dev_dbg(&client->dev, "trying factor %d (%d)\n", try[i], i); + + if (this > best) { + scale_m = try[i]; + mode = CCS_SCALING_MODE_HORIZONTAL; + best = this; + } + + if (CCS_LIM(sensor, SCALING_CAPABILITY) + == CCS_SCALING_CAPABILITY_HORIZONTAL) + continue; + + this = scaling_goodness( + subdev, crops[CCS_PAD_SINK]->width + / try[i] + * CCS_LIM(sensor, SCALER_N_MIN), + sel->r.width, + crops[CCS_PAD_SINK]->height + / try[i] + * CCS_LIM(sensor, SCALER_N_MIN), + sel->r.height, + sel->flags); + + if (this > best) { + scale_m = try[i]; + mode = SMIAPP_SCALING_MODE_BOTH; + best = this; + } + } + + sel->r.width = + (crops[CCS_PAD_SINK]->width + / scale_m + * CCS_LIM(sensor, SCALER_N_MIN)) & ~1; + if (mode == SMIAPP_SCALING_MODE_BOTH) + sel->r.height = + (crops[CCS_PAD_SINK]->height + / scale_m + * CCS_LIM(sensor, SCALER_N_MIN)) + & ~1; + else + sel->r.height = crops[CCS_PAD_SINK]->height; + + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + sensor->scale_m = scale_m; + sensor->scaling_mode = mode; + } +} +/* We're only called on source pads. This function sets scaling. */ +static int ccs_set_compose(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + struct ccs_subdev *ssd = to_ccs_subdev(subdev); + struct v4l2_rect *comp, *crops[CCS_PADS]; + + ccs_get_crop_compose(subdev, cfg, crops, &comp, sel->which); + + sel->r.top = 0; + sel->r.left = 0; + + if (ssd == sensor->binner) + ccs_set_compose_binner(subdev, cfg, sel, crops, comp); + else + ccs_set_compose_scaler(subdev, cfg, sel, crops, comp); + + *comp = sel->r; + ccs_propagate(subdev, cfg, sel->which, V4L2_SEL_TGT_COMPOSE); + + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return ccs_pll_blanking_update(sensor); + + return 0; +} + +static int __ccs_sel_supported(struct v4l2_subdev *subdev, + struct v4l2_subdev_selection *sel) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + struct ccs_subdev *ssd = to_ccs_subdev(subdev); + + /* We only implement crop in three places. */ + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + case V4L2_SEL_TGT_CROP_BOUNDS: + if (ssd == sensor->pixel_array && sel->pad == CCS_PA_PAD_SRC) + return 0; + if (ssd == sensor->src && sel->pad == CCS_PAD_SRC) + return 0; + if (ssd == sensor->scaler && sel->pad == CCS_PAD_SINK && + CCS_LIM(sensor, DIGITAL_CROP_CAPABILITY) + == CCS_DIGITAL_CROP_CAPABILITY_INPUT_CROP) + return 0; + return -EINVAL; + case V4L2_SEL_TGT_NATIVE_SIZE: + if (ssd == sensor->pixel_array && sel->pad == CCS_PA_PAD_SRC) + return 0; + return -EINVAL; + case V4L2_SEL_TGT_COMPOSE: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + if (sel->pad == ssd->source_pad) + return -EINVAL; + if (ssd == sensor->binner) + return 0; + if (ssd == sensor->scaler && CCS_LIM(sensor, SCALING_CAPABILITY) + != CCS_SCALING_CAPABILITY_NONE) + return 0; + fallthrough; + default: + return -EINVAL; + } +} + +static int ccs_set_crop(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + struct ccs_subdev *ssd = to_ccs_subdev(subdev); + struct v4l2_rect *src_size, *crops[CCS_PADS]; + struct v4l2_rect _r; + + ccs_get_crop_compose(subdev, cfg, crops, NULL, sel->which); + + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + if (sel->pad == ssd->sink_pad) + src_size = &ssd->sink_fmt; + else + src_size = &ssd->compose; + } else { + if (sel->pad == ssd->sink_pad) { + _r.left = 0; + _r.top = 0; + _r.width = v4l2_subdev_get_try_format(subdev, cfg, sel->pad) + ->width; + _r.height = v4l2_subdev_get_try_format(subdev, cfg, sel->pad) + ->height; + src_size = &_r; + } else { + src_size = v4l2_subdev_get_try_compose( + subdev, cfg, ssd->sink_pad); + } + } + + if (ssd == sensor->src && sel->pad == CCS_PAD_SRC) { + sel->r.left = 0; + sel->r.top = 0; + } + + sel->r.width = min(sel->r.width, src_size->width); + sel->r.height = min(sel->r.height, src_size->height); + + sel->r.left = min_t(int, sel->r.left, src_size->width - sel->r.width); + sel->r.top = min_t(int, sel->r.top, src_size->height - sel->r.height); + + *crops[sel->pad] = sel->r; + + if (ssd != sensor->pixel_array && sel->pad == CCS_PAD_SINK) + ccs_propagate(subdev, cfg, sel->which, V4L2_SEL_TGT_CROP); + + return 0; +} + +static void ccs_get_native_size(struct ccs_subdev *ssd, struct v4l2_rect *r) +{ + r->top = 0; + r->left = 0; + r->width = CCS_LIM(ssd->sensor, X_ADDR_MAX) + 1; + r->height = CCS_LIM(ssd->sensor, Y_ADDR_MAX) + 1; +} + +static int __ccs_get_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + struct ccs_subdev *ssd = to_ccs_subdev(subdev); + struct v4l2_rect *comp, *crops[CCS_PADS]; + struct v4l2_rect sink_fmt; + int ret; + + ret = __ccs_sel_supported(subdev, sel); + if (ret) + return ret; + + ccs_get_crop_compose(subdev, cfg, crops, &comp, sel->which); + + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + sink_fmt = ssd->sink_fmt; + } else { + struct v4l2_mbus_framefmt *fmt = + v4l2_subdev_get_try_format(subdev, cfg, ssd->sink_pad); + + sink_fmt.left = 0; + sink_fmt.top = 0; + sink_fmt.width = fmt->width; + sink_fmt.height = fmt->height; + } + + switch (sel->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_NATIVE_SIZE: + if (ssd == sensor->pixel_array) + ccs_get_native_size(ssd, &sel->r); + else if (sel->pad == ssd->sink_pad) + sel->r = sink_fmt; + else + sel->r = *comp; + break; + case V4L2_SEL_TGT_CROP: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + sel->r = *crops[sel->pad]; + break; + case V4L2_SEL_TGT_COMPOSE: + sel->r = *comp; + break; + } + + return 0; +} + +static int ccs_get_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + int rval; + + mutex_lock(&sensor->mutex); + rval = __ccs_get_selection(subdev, cfg, sel); + mutex_unlock(&sensor->mutex); + + return rval; +} + +static int ccs_set_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + int ret; + + ret = __ccs_sel_supported(subdev, sel); + if (ret) + return ret; + + mutex_lock(&sensor->mutex); + + sel->r.left = max(0, sel->r.left & ~1); + sel->r.top = max(0, sel->r.top & ~1); + sel->r.width = CCS_ALIGN_DIM(sel->r.width, sel->flags); + sel->r.height = CCS_ALIGN_DIM(sel->r.height, sel->flags); + + sel->r.width = max_t(unsigned int, + CCS_LIM(sensor, MIN_X_OUTPUT_SIZE), + sel->r.width); + sel->r.height = max_t(unsigned int, + CCS_LIM(sensor, MIN_Y_OUTPUT_SIZE), + sel->r.height); + + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + ret = ccs_set_crop(subdev, cfg, sel); + break; + case V4L2_SEL_TGT_COMPOSE: + ret = ccs_set_compose(subdev, cfg, sel); + break; + default: + ret = -EINVAL; + } + + mutex_unlock(&sensor->mutex); + return ret; +} + +static int ccs_get_skip_frames(struct v4l2_subdev *subdev, u32 *frames) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + + *frames = sensor->frame_skip; + return 0; +} + +static int ccs_get_skip_top_lines(struct v4l2_subdev *subdev, u32 *lines) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + + *lines = sensor->image_start; + + return 0; +} + +/* ----------------------------------------------------------------------------- + * sysfs attributes + */ + +static ssize_t +ccs_sysfs_nvm_read(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct v4l2_subdev *subdev = i2c_get_clientdata(to_i2c_client(dev)); + struct i2c_client *client = v4l2_get_subdevdata(subdev); + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + int rval; + + if (!sensor->dev_init_done) + return -EBUSY; + + rval = ccs_pm_get_init(sensor); + if (rval < 0) + return -ENODEV; + + rval = ccs_read_nvm(sensor, buf, PAGE_SIZE); + if (rval < 0) { + pm_runtime_put(&client->dev); + dev_err(&client->dev, "nvm read failed\n"); + return -ENODEV; + } + + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); + + /* + * NVM is still way below a PAGE_SIZE, so we can safely + * assume this for now. + */ + return rval; +} +static DEVICE_ATTR(nvm, S_IRUGO, ccs_sysfs_nvm_read, NULL); + +static ssize_t +ccs_sysfs_ident_read(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct v4l2_subdev *subdev = i2c_get_clientdata(to_i2c_client(dev)); + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + struct ccs_module_info *minfo = &sensor->minfo; + + if (minfo->mipi_manufacturer_id) + return snprintf(buf, PAGE_SIZE, "%4.4x%4.4x%2.2x\n", + minfo->mipi_manufacturer_id, minfo->model_id, + minfo->revision_number_major) + 1; + else + return snprintf(buf, PAGE_SIZE, "%2.2x%4.4x%2.2x\n", + minfo->smia_manufacturer_id, minfo->model_id, + minfo->revision_number_major) + 1; +} + +static DEVICE_ATTR(ident, S_IRUGO, ccs_sysfs_ident_read, NULL); + +/* ----------------------------------------------------------------------------- + * V4L2 subdev core operations + */ + +static int ccs_identify_module(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + struct ccs_module_info *minfo = &sensor->minfo; + unsigned int i; + int rval = 0; + + minfo->name = SMIAPP_NAME; + + /* Module info */ + rval = ccs_read(sensor, MODULE_MANUFACTURER_ID, + &minfo->mipi_manufacturer_id); + if (!rval && !minfo->mipi_manufacturer_id) + rval = ccs_read_addr_8only(sensor, + SMIAPP_REG_U8_MANUFACTURER_ID, + &minfo->smia_manufacturer_id); + if (!rval) + rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_MODEL_ID, + &minfo->model_id); + if (!rval) + rval = ccs_read_addr_8only(sensor, + CCS_R_MODULE_REVISION_NUMBER_MAJOR, + &minfo->revision_number_major); + if (!rval) + rval = ccs_read_addr_8only(sensor, + CCS_R_MODULE_REVISION_NUMBER_MINOR, + &minfo->revision_number_minor); + if (!rval) + rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_YEAR, + &minfo->module_year); + if (!rval) + rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_MONTH, + &minfo->module_month); + if (!rval) + rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_DAY, + &minfo->module_day); + + /* Sensor info */ + if (!rval) + rval = ccs_read(sensor, SENSOR_MANUFACTURER_ID, + &minfo->sensor_mipi_manufacturer_id); + if (!rval && !minfo->sensor_mipi_manufacturer_id) + rval = ccs_read_addr_8only(sensor, + CCS_R_SENSOR_MANUFACTURER_ID, + &minfo->sensor_smia_manufacturer_id); + if (!rval) + rval = ccs_read_addr_8only(sensor, + CCS_R_SENSOR_MODEL_ID, + &minfo->sensor_model_id); + if (!rval) + rval = ccs_read_addr_8only(sensor, + CCS_R_SENSOR_REVISION_NUMBER, + &minfo->sensor_revision_number); + if (!rval) + rval = ccs_read_addr_8only(sensor, + CCS_R_SENSOR_FIRMWARE_VERSION, + &minfo->sensor_firmware_version); + + /* SMIA */ + if (!rval) + rval = ccs_read(sensor, MIPI_CCS_VERSION, &minfo->ccs_version); + if (!rval && !minfo->ccs_version) + rval = ccs_read_addr_8only(sensor, SMIAPP_REG_U8_SMIA_VERSION, + &minfo->smia_version); + if (!rval && !minfo->ccs_version) + rval = ccs_read_addr_8only(sensor, SMIAPP_REG_U8_SMIAPP_VERSION, + &minfo->smiapp_version); + + if (rval) { + dev_err(&client->dev, "sensor detection failed\n"); + return -ENODEV; + } + + if (minfo->mipi_manufacturer_id) + dev_dbg(&client->dev, "MIPI CCS module 0x%4.4x-0x%4.4x\n", + minfo->mipi_manufacturer_id, minfo->model_id); + else + dev_dbg(&client->dev, "SMIA module 0x%2.2x-0x%4.4x\n", + minfo->smia_manufacturer_id, minfo->model_id); + + dev_dbg(&client->dev, + "module revision 0x%2.2x-0x%2.2x date %2.2d-%2.2d-%2.2d\n", + minfo->revision_number_major, minfo->revision_number_minor, + minfo->module_year, minfo->module_month, minfo->module_day); + + if (minfo->sensor_mipi_manufacturer_id) + dev_dbg(&client->dev, "MIPI CCS sensor 0x%4.4x-0x%4.4x\n", + minfo->sensor_mipi_manufacturer_id, + minfo->sensor_model_id); + else + dev_dbg(&client->dev, "SMIA sensor 0x%2.2x-0x%4.4x\n", + minfo->sensor_smia_manufacturer_id, + minfo->sensor_model_id); + + dev_dbg(&client->dev, + "sensor revision 0x%2.2x firmware version 0x%2.2x\n", + minfo->sensor_revision_number, minfo->sensor_firmware_version); + + if (minfo->ccs_version) + dev_dbg(&client->dev, "MIPI CCS version %u.%u", + (minfo->ccs_version & CCS_MIPI_CCS_VERSION_MAJOR_MASK) + >> CCS_MIPI_CCS_VERSION_MAJOR_SHIFT, + (minfo->ccs_version & CCS_MIPI_CCS_VERSION_MINOR_MASK)); + else + dev_dbg(&client->dev, + "smia version %2.2d smiapp version %2.2d\n", + minfo->smia_version, minfo->smiapp_version); + + /* + * Some modules have bad data in the lvalues below. Hope the + * rvalues have better stuff. The lvalues are module + * parameters whereas the rvalues are sensor parameters. + */ + if (minfo->sensor_smia_manufacturer_id && + !minfo->smia_manufacturer_id && !minfo->model_id) { + minfo->smia_manufacturer_id = + minfo->sensor_smia_manufacturer_id; + minfo->model_id = minfo->sensor_model_id; + minfo->revision_number_major = minfo->sensor_revision_number; + } + + for (i = 0; i < ARRAY_SIZE(ccs_module_idents); i++) { + if (ccs_module_idents[i].mipi_manufacturer_id && + ccs_module_idents[i].mipi_manufacturer_id + != minfo->mipi_manufacturer_id) + continue; + if (ccs_module_idents[i].smia_manufacturer_id && + ccs_module_idents[i].smia_manufacturer_id + != minfo->smia_manufacturer_id) + continue; + if (ccs_module_idents[i].model_id != minfo->model_id) + continue; + if (ccs_module_idents[i].flags + & CCS_MODULE_IDENT_FLAG_REV_LE) { + if (ccs_module_idents[i].revision_number_major + < minfo->revision_number_major) + continue; + } else { + if (ccs_module_idents[i].revision_number_major + != minfo->revision_number_major) + continue; + } + + minfo->name = ccs_module_idents[i].name; + minfo->quirk = ccs_module_idents[i].quirk; + break; + } + + if (i >= ARRAY_SIZE(ccs_module_idents)) + dev_warn(&client->dev, + "no quirks for this module; let's hope it's fully compliant\n"); + + dev_dbg(&client->dev, "the sensor is called %s\n", + minfo->name); + + return 0; +} + +static const struct v4l2_subdev_ops ccs_ops; +static const struct v4l2_subdev_internal_ops ccs_internal_ops; +static const struct media_entity_operations ccs_entity_ops; + +static int ccs_register_subdev(struct ccs_sensor *sensor, + struct ccs_subdev *ssd, + struct ccs_subdev *sink_ssd, + u16 source_pad, u16 sink_pad, u32 link_flags) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int rval; + + if (!sink_ssd) + return 0; + + rval = media_entity_pads_init(&ssd->sd.entity, + ssd->npads, ssd->pads); + if (rval) { + dev_err(&client->dev, + "media_entity_pads_init failed\n"); + return rval; + } + + rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev, + &ssd->sd); + if (rval) { + dev_err(&client->dev, + "v4l2_device_register_subdev failed\n"); + return rval; + } + + rval = media_create_pad_link(&ssd->sd.entity, source_pad, + &sink_ssd->sd.entity, sink_pad, + link_flags); + if (rval) { + dev_err(&client->dev, + "media_create_pad_link failed\n"); + v4l2_device_unregister_subdev(&ssd->sd); + return rval; + } + + return 0; +} + +static void ccs_unregistered(struct v4l2_subdev *subdev) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + unsigned int i; + + for (i = 1; i < sensor->ssds_used; i++) + v4l2_device_unregister_subdev(&sensor->ssds[i].sd); +} + +static int ccs_registered(struct v4l2_subdev *subdev) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + int rval; + + if (sensor->scaler) { + rval = ccs_register_subdev(sensor, sensor->binner, + sensor->scaler, + CCS_PAD_SRC, CCS_PAD_SINK, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (rval < 0) + return rval; + } + + rval = ccs_register_subdev(sensor, sensor->pixel_array, sensor->binner, + CCS_PA_PAD_SRC, CCS_PAD_SINK, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (rval) + goto out_err; + + return 0; + +out_err: + ccs_unregistered(subdev); + + return rval; +} + +static void ccs_cleanup(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + + device_remove_file(&client->dev, &dev_attr_nvm); + device_remove_file(&client->dev, &dev_attr_ident); + + ccs_free_controls(sensor); +} + +static void ccs_create_subdev(struct ccs_sensor *sensor, + struct ccs_subdev *ssd, const char *name, + unsigned short num_pads) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + + if (!ssd) + return; + + if (ssd != sensor->src) + v4l2_subdev_init(&ssd->sd, &ccs_ops); + + ssd->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + ssd->sensor = sensor; + + ssd->npads = num_pads; + ssd->source_pad = num_pads - 1; + + v4l2_i2c_subdev_set_name(&ssd->sd, client, sensor->minfo.name, name); + + ccs_get_native_size(ssd, &ssd->sink_fmt); + + ssd->compose.width = ssd->sink_fmt.width; + ssd->compose.height = ssd->sink_fmt.height; + ssd->crop[ssd->source_pad] = ssd->compose; + ssd->pads[ssd->source_pad].flags = MEDIA_PAD_FL_SOURCE; + if (ssd != sensor->pixel_array) { + ssd->crop[ssd->sink_pad] = ssd->compose; + ssd->pads[ssd->sink_pad].flags = MEDIA_PAD_FL_SINK; + } + + ssd->sd.entity.ops = &ccs_entity_ops; + + if (ssd == sensor->src) + return; + + ssd->sd.internal_ops = &ccs_internal_ops; + ssd->sd.owner = THIS_MODULE; + ssd->sd.dev = &client->dev; + v4l2_set_subdevdata(&ssd->sd, client); +} + +static int ccs_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct ccs_subdev *ssd = to_ccs_subdev(sd); + struct ccs_sensor *sensor = ssd->sensor; + unsigned int i; + + mutex_lock(&sensor->mutex); + + for (i = 0; i < ssd->npads; i++) { + struct v4l2_mbus_framefmt *try_fmt = + v4l2_subdev_get_try_format(sd, fh->pad, i); + struct v4l2_rect *try_crop = + v4l2_subdev_get_try_crop(sd, fh->pad, i); + struct v4l2_rect *try_comp; + + ccs_get_native_size(ssd, try_crop); + + try_fmt->width = try_crop->width; + try_fmt->height = try_crop->height; + try_fmt->code = sensor->internal_csi_format->code; + try_fmt->field = V4L2_FIELD_NONE; + + if (ssd != sensor->pixel_array) + continue; + + try_comp = v4l2_subdev_get_try_compose(sd, fh->pad, i); + *try_comp = *try_crop; + } + + mutex_unlock(&sensor->mutex); + + return 0; +} + +static const struct v4l2_subdev_video_ops ccs_video_ops = { + .s_stream = ccs_set_stream, +}; + +static const struct v4l2_subdev_pad_ops ccs_pad_ops = { + .enum_mbus_code = ccs_enum_mbus_code, + .get_fmt = ccs_get_format, + .set_fmt = ccs_set_format, + .get_selection = ccs_get_selection, + .set_selection = ccs_set_selection, +}; + +static const struct v4l2_subdev_sensor_ops ccs_sensor_ops = { + .g_skip_frames = ccs_get_skip_frames, + .g_skip_top_lines = ccs_get_skip_top_lines, +}; + +static const struct v4l2_subdev_ops ccs_ops = { + .video = &ccs_video_ops, + .pad = &ccs_pad_ops, + .sensor = &ccs_sensor_ops, +}; + +static const struct media_entity_operations ccs_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static const struct v4l2_subdev_internal_ops ccs_internal_src_ops = { + .registered = ccs_registered, + .unregistered = ccs_unregistered, + .open = ccs_open, +}; + +static const struct v4l2_subdev_internal_ops ccs_internal_ops = { + .open = ccs_open, +}; + +/* ----------------------------------------------------------------------------- + * I2C Driver + */ + +static int __maybe_unused ccs_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + bool streaming = sensor->streaming; + int rval; + + rval = pm_runtime_get_sync(dev); + if (rval < 0) { + if (rval != -EBUSY && rval != -EAGAIN) + pm_runtime_set_active(&client->dev); + pm_runtime_put(dev); + return -EAGAIN; + } + + if (sensor->streaming) + ccs_stop_streaming(sensor); + + /* save state for resume */ + sensor->streaming = streaming; + + return 0; +} + +static int __maybe_unused ccs_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + int rval = 0; + + pm_runtime_put(dev); + + if (sensor->streaming) + rval = ccs_start_streaming(sensor); + + return rval; +} + +static struct ccs_hwconfig *ccs_get_hwconfig(struct device *dev) +{ + struct ccs_hwconfig *hwcfg; + struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 }; + struct fwnode_handle *ep; + struct fwnode_handle *fwnode = dev_fwnode(dev); + u32 rotation; + int i; + int rval; + + if (!fwnode) + return dev->platform_data; + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) + return NULL; + + bus_cfg.bus_type = V4L2_MBUS_CSI2_DPHY; + rval = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + if (rval == -ENXIO) { + bus_cfg = (struct v4l2_fwnode_endpoint) + { .bus_type = V4L2_MBUS_CCP2 }; + rval = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + } + if (rval) + goto out_err; + + hwcfg = devm_kzalloc(dev, sizeof(*hwcfg), GFP_KERNEL); + if (!hwcfg) + goto out_err; + + switch (bus_cfg.bus_type) { + case V4L2_MBUS_CSI2_DPHY: + hwcfg->csi_signalling_mode = CCS_CSI_SIGNALING_MODE_CSI_2_DPHY; + hwcfg->lanes = bus_cfg.bus.mipi_csi2.num_data_lanes; + break; + case V4L2_MBUS_CCP2: + hwcfg->csi_signalling_mode = (bus_cfg.bus.mipi_csi1.strobe) ? + SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE : + SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK; + hwcfg->lanes = 1; + break; + default: + dev_err(dev, "unsupported bus %u\n", bus_cfg.bus_type); + goto out_err; + } + + dev_dbg(dev, "lanes %u\n", hwcfg->lanes); + + rval = fwnode_property_read_u32(fwnode, "rotation", &rotation); + if (!rval) { + switch (rotation) { + case 180: + hwcfg->module_board_orient = + CCS_MODULE_BOARD_ORIENT_180; + fallthrough; + case 0: + break; + default: + dev_err(dev, "invalid rotation %u\n", rotation); + goto out_err; + } + } + + rval = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", + &hwcfg->ext_clk); + if (rval) + dev_info(dev, "can't get clock-frequency\n"); + + dev_dbg(dev, "clk %d, mode %d\n", hwcfg->ext_clk, + hwcfg->csi_signalling_mode); + + if (!bus_cfg.nr_of_link_frequencies) { + dev_warn(dev, "no link frequencies defined\n"); + goto out_err; + } + + hwcfg->op_sys_clock = devm_kcalloc( + dev, bus_cfg.nr_of_link_frequencies + 1 /* guardian */, + sizeof(*hwcfg->op_sys_clock), GFP_KERNEL); + if (!hwcfg->op_sys_clock) + goto out_err; + + for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) { + hwcfg->op_sys_clock[i] = bus_cfg.link_frequencies[i]; + dev_dbg(dev, "freq %d: %lld\n", i, hwcfg->op_sys_clock[i]); + } + + v4l2_fwnode_endpoint_free(&bus_cfg); + fwnode_handle_put(ep); + return hwcfg; + +out_err: + v4l2_fwnode_endpoint_free(&bus_cfg); + fwnode_handle_put(ep); + return NULL; +} + +static int ccs_probe(struct i2c_client *client) +{ + struct ccs_sensor *sensor; + struct ccs_hwconfig *hwcfg = ccs_get_hwconfig(&client->dev); + unsigned int i; + int rval; + + if (hwcfg == NULL) + return -ENODEV; + + sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL); + if (sensor == NULL) + return -ENOMEM; + + sensor->hwcfg = hwcfg; + sensor->src = &sensor->ssds[sensor->ssds_used]; + + v4l2_i2c_subdev_init(&sensor->src->sd, client, &ccs_ops); + sensor->src->sd.internal_ops = &ccs_internal_src_ops; + + sensor->vana = devm_regulator_get(&client->dev, "vana"); + if (IS_ERR(sensor->vana)) { + dev_err(&client->dev, "could not get regulator for vana\n"); + return PTR_ERR(sensor->vana); + } + + sensor->ext_clk = devm_clk_get(&client->dev, NULL); + if (PTR_ERR(sensor->ext_clk) == -ENOENT) { + dev_info(&client->dev, "no clock defined, continuing...\n"); + sensor->ext_clk = NULL; + } else if (IS_ERR(sensor->ext_clk)) { + dev_err(&client->dev, "could not get clock (%ld)\n", + PTR_ERR(sensor->ext_clk)); + return -EPROBE_DEFER; + } + + if (sensor->ext_clk) { + if (sensor->hwcfg->ext_clk) { + unsigned long rate; + + rval = clk_set_rate(sensor->ext_clk, + sensor->hwcfg->ext_clk); + if (rval < 0) { + dev_err(&client->dev, + "unable to set clock freq to %u\n", + sensor->hwcfg->ext_clk); + return rval; + } + + rate = clk_get_rate(sensor->ext_clk); + if (rate != sensor->hwcfg->ext_clk) { + dev_err(&client->dev, + "can't set clock freq, asked for %u but got %lu\n", + sensor->hwcfg->ext_clk, rate); + return rval; + } + } else { + sensor->hwcfg->ext_clk = clk_get_rate(sensor->ext_clk); + dev_dbg(&client->dev, "obtained clock freq %u\n", + sensor->hwcfg->ext_clk); + } + } else if (sensor->hwcfg->ext_clk) { + dev_dbg(&client->dev, "assuming clock freq %u\n", + sensor->hwcfg->ext_clk); + } else { + dev_err(&client->dev, "unable to obtain clock freq\n"); + return -EINVAL; + } + + sensor->xshutdown = devm_gpiod_get_optional(&client->dev, "xshutdown", + GPIOD_OUT_LOW); + if (IS_ERR(sensor->xshutdown)) + return PTR_ERR(sensor->xshutdown); + + rval = ccs_power_on(&client->dev); + if (rval < 0) + return rval; + + mutex_init(&sensor->mutex); + + rval = ccs_identify_module(sensor); + if (rval) { + rval = -ENODEV; + goto out_power_off; + } + + rval = ccs_read_all_limits(sensor); + if (rval) + goto out_power_off; + + rval = ccs_read_frame_fmt(sensor); + if (rval) { + rval = -ENODEV; + goto out_free_ccs_limits; + } + + /* + * Handle Sensor Module orientation on the board. + * + * The application of H-FLIP and V-FLIP on the sensor is modified by + * the sensor orientation on the board. + * + * For CCS_BOARD_SENSOR_ORIENT_180 the default behaviour is to set + * both H-FLIP and V-FLIP for normal operation which also implies + * that a set/unset operation for user space HFLIP and VFLIP v4l2 + * controls will need to be internally inverted. + * + * Rotation also changes the bayer pattern. + */ + if (sensor->hwcfg->module_board_orient == + CCS_MODULE_BOARD_ORIENT_180) + sensor->hvflip_inv_mask = + CCS_IMAGE_ORIENTATION_HORIZONTAL_MIRROR | + CCS_IMAGE_ORIENTATION_VERTICAL_FLIP; + + rval = ccs_call_quirk(sensor, limits); + if (rval) { + dev_err(&client->dev, "limits quirks failed\n"); + goto out_free_ccs_limits; + } + + if (CCS_LIM(sensor, BINNING_CAPABILITY)) { + sensor->nbinning_subtypes = + min_t(u8, CCS_LIM(sensor, BINNING_SUB_TYPES), + CCS_LIM_BINNING_SUB_TYPE_MAX_N); + + for (i = 0; i < sensor->nbinning_subtypes; i++) { + sensor->binning_subtypes[i].horizontal = + CCS_LIM_AT(sensor, BINNING_SUB_TYPE, i) >> + CCS_BINNING_SUB_TYPE_COLUMN_SHIFT; + sensor->binning_subtypes[i].vertical = + CCS_LIM_AT(sensor, BINNING_SUB_TYPE, i) & + CCS_BINNING_SUB_TYPE_ROW_MASK; + + dev_dbg(&client->dev, "binning %xx%x\n", + sensor->binning_subtypes[i].horizontal, + sensor->binning_subtypes[i].vertical); + } + } + sensor->binning_horizontal = 1; + sensor->binning_vertical = 1; + + if (device_create_file(&client->dev, &dev_attr_ident) != 0) { + dev_err(&client->dev, "sysfs ident entry creation failed\n"); + rval = -ENOENT; + goto out_free_ccs_limits; + } + + if (sensor->minfo.smiapp_version && + CCS_LIM(sensor, DATA_TRANSFER_IF_CAPABILITY) & + CCS_DATA_TRANSFER_IF_CAPABILITY_SUPPORTED) { + if (device_create_file(&client->dev, &dev_attr_nvm) != 0) { + dev_err(&client->dev, "sysfs nvm entry failed\n"); + rval = -EBUSY; + goto out_cleanup; + } + } + + /* We consider this as profile 0 sensor if any of these are zero. */ + if (!CCS_LIM(sensor, MIN_OP_SYS_CLK_DIV) || + !CCS_LIM(sensor, MAX_OP_SYS_CLK_DIV) || + !CCS_LIM(sensor, MIN_OP_PIX_CLK_DIV) || + !CCS_LIM(sensor, MAX_OP_PIX_CLK_DIV)) { + sensor->minfo.smiapp_profile = SMIAPP_PROFILE_0; + } else if (CCS_LIM(sensor, SCALING_CAPABILITY) + != CCS_SCALING_CAPABILITY_NONE) { + if (CCS_LIM(sensor, SCALING_CAPABILITY) + == CCS_SCALING_CAPABILITY_HORIZONTAL) + sensor->minfo.smiapp_profile = SMIAPP_PROFILE_1; + else + sensor->minfo.smiapp_profile = SMIAPP_PROFILE_2; + sensor->scaler = &sensor->ssds[sensor->ssds_used]; + sensor->ssds_used++; + } else if (CCS_LIM(sensor, DIGITAL_CROP_CAPABILITY) + == CCS_DIGITAL_CROP_CAPABILITY_INPUT_CROP) { + sensor->scaler = &sensor->ssds[sensor->ssds_used]; + sensor->ssds_used++; + } + sensor->binner = &sensor->ssds[sensor->ssds_used]; + sensor->ssds_used++; + sensor->pixel_array = &sensor->ssds[sensor->ssds_used]; + sensor->ssds_used++; + + sensor->scale_m = CCS_LIM(sensor, SCALER_N_MIN); + + /* prepare PLL configuration input values */ + sensor->pll.bus_type = SMIAPP_PLL_BUS_TYPE_CSI2; + sensor->pll.csi2.lanes = sensor->hwcfg->lanes; + sensor->pll.ext_clk_freq_hz = sensor->hwcfg->ext_clk; + sensor->pll.scale_n = CCS_LIM(sensor, SCALER_N_MIN); + /* Profile 0 sensors have no separate OP clock branch. */ + if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) + sensor->pll.flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS; + + ccs_create_subdev(sensor, sensor->scaler, " scaler", 2); + ccs_create_subdev(sensor, sensor->binner, " binner", 2); + ccs_create_subdev(sensor, sensor->pixel_array, " pixel_array", 1); + + dev_dbg(&client->dev, "profile %d\n", sensor->minfo.smiapp_profile); + + sensor->pixel_array->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + rval = ccs_init_controls(sensor); + if (rval < 0) + goto out_cleanup; + + rval = ccs_call_quirk(sensor, init); + if (rval) + goto out_cleanup; + + rval = ccs_get_mbus_formats(sensor); + if (rval) { + rval = -ENODEV; + goto out_cleanup; + } + + rval = ccs_init_late_controls(sensor); + if (rval) { + rval = -ENODEV; + goto out_cleanup; + } + + mutex_lock(&sensor->mutex); + rval = ccs_pll_blanking_update(sensor); + mutex_unlock(&sensor->mutex); + if (rval) { + dev_err(&client->dev, "update mode failed\n"); + goto out_cleanup; + } + + sensor->streaming = false; + sensor->dev_init_done = true; + + rval = media_entity_pads_init(&sensor->src->sd.entity, 2, + sensor->src->pads); + if (rval < 0) + goto out_media_entity_cleanup; + + pm_runtime_set_active(&client->dev); + pm_runtime_get_noresume(&client->dev); + pm_runtime_enable(&client->dev); + + rval = v4l2_async_register_subdev_sensor_common(&sensor->src->sd); + if (rval < 0) + goto out_disable_runtime_pm; + + pm_runtime_set_autosuspend_delay(&client->dev, 1000); + pm_runtime_use_autosuspend(&client->dev); + pm_runtime_put_autosuspend(&client->dev); + + return 0; + +out_disable_runtime_pm: + pm_runtime_put_noidle(&client->dev); + pm_runtime_disable(&client->dev); + +out_media_entity_cleanup: + media_entity_cleanup(&sensor->src->sd.entity); + +out_cleanup: + ccs_cleanup(sensor); + +out_free_ccs_limits: + kfree(sensor->ccs_limits); + +out_power_off: + ccs_power_off(&client->dev); + mutex_destroy(&sensor->mutex); + + return rval; +} + +static int ccs_remove(struct i2c_client *client) +{ + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + unsigned int i; + + v4l2_async_unregister_subdev(subdev); + + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + ccs_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); + + for (i = 0; i < sensor->ssds_used; i++) { + v4l2_device_unregister_subdev(&sensor->ssds[i].sd); + media_entity_cleanup(&sensor->ssds[i].sd.entity); + } + ccs_cleanup(sensor); + mutex_destroy(&sensor->mutex); + kfree(sensor->ccs_limits); + + return 0; +} + +static const struct of_device_id ccs_of_table[] = { + { .compatible = "nokia,smia" }, + { }, +}; +MODULE_DEVICE_TABLE(of, ccs_of_table); + +static const struct i2c_device_id ccs_id_table[] = { + { SMIAPP_NAME, 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, ccs_id_table); + +static const struct dev_pm_ops ccs_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ccs_suspend, ccs_resume) + SET_RUNTIME_PM_OPS(ccs_power_off, ccs_power_on, NULL) +}; + +static struct i2c_driver ccs_i2c_driver = { + .driver = { + .of_match_table = ccs_of_table, + .name = CCS_NAME, + .pm = &ccs_pm_ops, + }, + .probe_new = ccs_probe, + .remove = ccs_remove, + .id_table = ccs_id_table, +}; + +static int ccs_module_init(void) +{ + unsigned int i, l; + + for (i = 0, l = 0; ccs_limits[i].size && l < CCS_L_LAST; i++) { + if (!(ccs_limits[i].flags & CCS_L_FL_SAME_REG)) { + ccs_limit_offsets[l + 1].lim = + ALIGN(ccs_limit_offsets[l].lim + + ccs_limits[i].size, + ccs_reg_width(ccs_limits[i + 1].reg)); + ccs_limit_offsets[l].info = i; + l++; + } else { + ccs_limit_offsets[l].lim += ccs_limits[i].size; + } + } + + if (WARN_ON(ccs_limits[i].size)) + return -EINVAL; + + if (WARN_ON(l != CCS_L_LAST)) + return -EINVAL; + + return i2c_register_driver(THIS_MODULE, &ccs_i2c_driver); +} + +static void ccs_module_cleanup(void) +{ + i2c_del_driver(&ccs_i2c_driver); +} + +module_init(ccs_module_init); +module_exit(ccs_module_cleanup); + +MODULE_AUTHOR("Sakari Ailus "); +MODULE_DESCRIPTION("Generic MIPI CCS/SMIA/SMIA++ camera sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/smiapp/ccs-quirk.c b/drivers/media/i2c/smiapp/ccs-quirk.c new file mode 100644 index 000000000000..6c48d0901952 --- /dev/null +++ b/drivers/media/i2c/smiapp/ccs-quirk.c @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * drivers/media/i2c/smiapp/ccs-quirk.c + * + * Generic driver for SMIA/SMIA++ compliant camera modules + * + * Copyright (C) 2011--2012 Nokia Corporation + * Contact: Sakari Ailus + */ + +#include + +#include "ccs.h" +#include "ccs-limits.h" + +static int ccs_write_addr_8s(struct ccs_sensor *sensor, + const struct ccs_reg_8 *regs, int len) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int rval; + + for (; len > 0; len--, regs++) { + rval = ccs_write_addr(sensor, regs->reg, regs->val); + if (rval < 0) { + dev_err(&client->dev, + "error %d writing reg 0x%4.4x, val 0x%2.2x", + rval, regs->reg, regs->val); + return rval; + } + } + + return 0; +} + +static int jt8ew9_limits(struct ccs_sensor *sensor) +{ + if (sensor->minfo.revision_number_major < 0x03) + sensor->frame_skip = 1; + + /* Below 24 gain doesn't have effect at all, */ + /* but ~59 is needed for full dynamic range */ + ccs_replace_limit(sensor, CCS_L_ANALOG_GAIN_CODE_MIN, 0, 59); + ccs_replace_limit(sensor, CCS_L_ANALOG_GAIN_CODE_MAX, 0, 6000); + + return 0; +} + +static int jt8ew9_post_poweron(struct ccs_sensor *sensor) +{ + static const struct ccs_reg_8 regs[] = { + { 0x30a3, 0xd8 }, /* Output port control : LVDS ports only */ + { 0x30ae, 0x00 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */ + { 0x30af, 0xd0 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */ + { 0x322d, 0x04 }, /* Adjusting Processing Image Size to Scaler Toshiba Recommendation Setting */ + { 0x3255, 0x0f }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */ + { 0x3256, 0x15 }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */ + { 0x3258, 0x70 }, /* Analog Gain Control Toshiba Recommendation Setting */ + { 0x3259, 0x70 }, /* Analog Gain Control Toshiba Recommendation Setting */ + { 0x325f, 0x7c }, /* Analog Gain Control Toshiba Recommendation Setting */ + { 0x3302, 0x06 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */ + { 0x3304, 0x00 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */ + { 0x3307, 0x22 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */ + { 0x3308, 0x8d }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */ + { 0x331e, 0x0f }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ + { 0x3320, 0x30 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ + { 0x3321, 0x11 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ + { 0x3322, 0x98 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ + { 0x3323, 0x64 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ + { 0x3325, 0x83 }, /* Read Out Timing Control Toshiba Recommendation Setting */ + { 0x3330, 0x18 }, /* Read Out Timing Control Toshiba Recommendation Setting */ + { 0x333c, 0x01 }, /* Read Out Timing Control Toshiba Recommendation Setting */ + { 0x3345, 0x2f }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ + { 0x33de, 0x38 }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */ + /* Taken from v03. No idea what the rest are. */ + { 0x32e0, 0x05 }, + { 0x32e1, 0x05 }, + { 0x32e2, 0x04 }, + { 0x32e5, 0x04 }, + { 0x32e6, 0x04 }, + + }; + + return ccs_write_addr_8s(sensor, regs, ARRAY_SIZE(regs)); +} + +const struct ccs_quirk smiapp_jt8ew9_quirk = { + .limits = jt8ew9_limits, + .post_poweron = jt8ew9_post_poweron, +}; + +static int imx125es_post_poweron(struct ccs_sensor *sensor) +{ + /* Taken from v02. No idea what the other two are. */ + static const struct ccs_reg_8 regs[] = { + /* + * 0x3302: clk during frame blanking: + * 0x00 - HS mode, 0x01 - LP11 + */ + { 0x3302, 0x01 }, + { 0x302d, 0x00 }, + { 0x3b08, 0x8c }, + }; + + return ccs_write_addr_8s(sensor, regs, ARRAY_SIZE(regs)); +} + +const struct ccs_quirk smiapp_imx125es_quirk = { + .post_poweron = imx125es_post_poweron, +}; + +static int jt8ev1_limits(struct ccs_sensor *sensor) +{ + ccs_replace_limit(sensor, CCS_L_X_ADDR_MAX, 0, 4271); + ccs_replace_limit(sensor, CCS_L_MIN_LINE_BLANKING_PCK_BIN, 0, 184); + + return 0; +} + +static int jt8ev1_post_poweron(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int rval; + static const struct ccs_reg_8 regs[] = { + { 0x3031, 0xcd }, /* For digital binning (EQ_MONI) */ + { 0x30a3, 0xd0 }, /* FLASH STROBE enable */ + { 0x3237, 0x00 }, /* For control of pulse timing for ADC */ + { 0x3238, 0x43 }, + { 0x3301, 0x06 }, /* For analog bias for sensor */ + { 0x3302, 0x06 }, + { 0x3304, 0x00 }, + { 0x3305, 0x88 }, + { 0x332a, 0x14 }, + { 0x332c, 0x6b }, + { 0x3336, 0x01 }, + { 0x333f, 0x1f }, + { 0x3355, 0x00 }, + { 0x3356, 0x20 }, + { 0x33bf, 0x20 }, /* Adjust the FBC speed */ + { 0x33c9, 0x20 }, + { 0x33ce, 0x30 }, /* Adjust the parameter for logic function */ + { 0x33cf, 0xec }, /* For Black sun */ + { 0x3328, 0x80 }, /* Ugh. No idea what's this. */ + }; + static const struct ccs_reg_8 regs_96[] = { + { 0x30ae, 0x00 }, /* For control of ADC clock */ + { 0x30af, 0xd0 }, + { 0x30b0, 0x01 }, + }; + + rval = ccs_write_addr_8s(sensor, regs, ARRAY_SIZE(regs)); + if (rval < 0) + return rval; + + switch (sensor->hwcfg->ext_clk) { + case 9600000: + return ccs_write_addr_8s(sensor, regs_96, + ARRAY_SIZE(regs_96)); + default: + dev_warn(&client->dev, "no MSRs for %d Hz ext_clk\n", + sensor->hwcfg->ext_clk); + return 0; + } +} + +static int jt8ev1_pre_streamon(struct ccs_sensor *sensor) +{ + return ccs_write_addr(sensor, 0x3328, 0x00); +} + +static int jt8ev1_post_streamoff(struct ccs_sensor *sensor) +{ + int rval; + + /* Workaround: allows fast standby to work properly */ + rval = ccs_write_addr(sensor, 0x3205, 0x04); + if (rval < 0) + return rval; + + /* Wait for 1 ms + one line => 2 ms is likely enough */ + usleep_range(2000, 2050); + + /* Restore it */ + rval = ccs_write_addr(sensor, 0x3205, 0x00); + if (rval < 0) + return rval; + + return ccs_write_addr(sensor, 0x3328, 0x80); +} + +static int jt8ev1_init(struct ccs_sensor *sensor) +{ + sensor->pll.flags |= SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE; + + return 0; +} + +const struct ccs_quirk smiapp_jt8ev1_quirk = { + .limits = jt8ev1_limits, + .post_poweron = jt8ev1_post_poweron, + .pre_streamon = jt8ev1_pre_streamon, + .post_streamoff = jt8ev1_post_streamoff, + .init = jt8ev1_init, +}; + +static int tcm8500md_limits(struct ccs_sensor *sensor) +{ + ccs_replace_limit(sensor, CCS_L_MIN_PLL_IP_CLK_FREQ_MHZ, 0, 2700000); + + return 0; +} + +const struct ccs_quirk smiapp_tcm8500md_quirk = { + .limits = tcm8500md_limits, +}; diff --git a/drivers/media/i2c/smiapp/ccs-quirk.h b/drivers/media/i2c/smiapp/ccs-quirk.h new file mode 100644 index 000000000000..d208379158f2 --- /dev/null +++ b/drivers/media/i2c/smiapp/ccs-quirk.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * drivers/media/i2c/smiapp/ccs-quirk.h + * + * Generic driver for SMIA/SMIA++ compliant camera modules + * + * Copyright (C) 2011--2012 Nokia Corporation + * Contact: Sakari Ailus + */ + +#ifndef __CCS_QUIRK__ +#define __CCS_QUIRK__ + +struct ccs_sensor; + +/** + * struct ccs_quirk - quirks for sensors that deviate from SMIA++ standard + * + * @limits: Replace sensor->limits with values which can't be read from + * sensor registers. Called the first time the sensor is powered up. + * @post_poweron: Called always after the sensor has been fully powered on. + * @pre_streamon: Called just before streaming is enabled. + * @post_streamon: Called right after stopping streaming. + * @pll_flags: Return flags for the PLL calculator. + * @init: Quirk initialisation, called the last in probe(). This is + * also appropriate for adding sensor specific controls, for instance. + * @reg_access: Register access quirk. The quirk may divert the access + * to another register, or no register at all. + * + * @write: Is this read (false) or write (true) access? + * @reg: Pointer to the register to access + * @value: Register value, set by the caller on write, or + * by the quirk on read + * + * @return: 0 on success, -ENOIOCTLCMD if no register + * access may be done by the caller (default read + * value is zero), else negative error code on error + */ +struct ccs_quirk { + int (*limits)(struct ccs_sensor *sensor); + int (*post_poweron)(struct ccs_sensor *sensor); + int (*pre_streamon)(struct ccs_sensor *sensor); + int (*post_streamoff)(struct ccs_sensor *sensor); + unsigned long (*pll_flags)(struct ccs_sensor *sensor); + int (*init)(struct ccs_sensor *sensor); + int (*reg_access)(struct ccs_sensor *sensor, bool write, u32 *reg, + u32 *val); + unsigned long flags; +}; + +#define CCS_QUIRK_FLAG_8BIT_READ_ONLY (1 << 0) + +struct ccs_reg_8 { + u16 reg; + u8 val; +}; + +#define CCS_MK_QUIRK_REG_8(_reg, _val) \ + { \ + .reg = (u16)_reg, \ + .val = _val, \ + } + +#define ccs_call_quirk(sensor, _quirk, ...) \ + ((sensor)->minfo.quirk && \ + (sensor)->minfo.quirk->_quirk ? \ + (sensor)->minfo.quirk->_quirk(sensor, ##__VA_ARGS__) : 0) + +#define ccs_needs_quirk(sensor, _quirk) \ + ((sensor)->minfo.quirk ? \ + (sensor)->minfo.quirk->flags & _quirk : 0) + +extern const struct ccs_quirk smiapp_jt8ev1_quirk; +extern const struct ccs_quirk smiapp_imx125es_quirk; +extern const struct ccs_quirk smiapp_jt8ew9_quirk; +extern const struct ccs_quirk smiapp_tcm8500md_quirk; + +#endif /* __CCS_QUIRK__ */ diff --git a/drivers/media/i2c/smiapp/ccs-reg-access.c b/drivers/media/i2c/smiapp/ccs-reg-access.c new file mode 100644 index 000000000000..4e6d212473fc --- /dev/null +++ b/drivers/media/i2c/smiapp/ccs-reg-access.c @@ -0,0 +1,265 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * drivers/media/i2c/smiapp/ccs-regs.c + * + * Generic driver for SMIA/SMIA++ compliant camera modules + * + * Copyright (C) 2011--2012 Nokia Corporation + * Contact: Sakari Ailus + */ + +#include + +#include +#include + +#include "ccs.h" + +static uint32_t float_to_u32_mul_1000000(struct i2c_client *client, + uint32_t phloat) +{ + int32_t exp; + uint64_t man; + + if (phloat >= 0x80000000) { + dev_err(&client->dev, "this is a negative number\n"); + return 0; + } + + if (phloat == 0x7f800000) + return ~0; /* Inf. */ + + if ((phloat & 0x7f800000) == 0x7f800000) { + dev_err(&client->dev, "NaN or other special number\n"); + return 0; + } + + /* Valid cases begin here */ + if (phloat == 0) + return 0; /* Valid zero */ + + if (phloat > 0x4f800000) + return ~0; /* larger than 4294967295 */ + + /* + * Unbias exponent (note how phloat is now guaranteed to + * have 0 in the high bit) + */ + exp = ((int32_t)phloat >> 23) - 127; + + /* Extract mantissa, add missing '1' bit and it's in MHz */ + man = ((phloat & 0x7fffff) | 0x800000) * 1000000ULL; + + if (exp < 0) + man >>= -exp; + else + man <<= exp; + + man >>= 23; /* Remove mantissa bias */ + + return man & 0xffffffff; +} + + +/* + * Read a 8/16/32-bit i2c register. The value is returned in 'val'. + * Returns zero if successful, or non-zero otherwise. + */ +static int ____ccs_read_addr(struct ccs_sensor *sensor, u16 reg, u16 len, + u32 *val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + struct i2c_msg msg; + unsigned char data_buf[sizeof(u32)] = { 0 }; + unsigned char offset_buf[sizeof(u16)]; + int r; + + if (len > sizeof(data_buf)) + return -EINVAL; + + msg.addr = client->addr; + msg.flags = 0; + msg.len = sizeof(offset_buf); + msg.buf = offset_buf; + put_unaligned_be16(reg, offset_buf); + + r = i2c_transfer(client->adapter, &msg, 1); + if (r != 1) { + if (r >= 0) + r = -EBUSY; + goto err; + } + + msg.len = len; + msg.flags = I2C_M_RD; + msg.buf = &data_buf[sizeof(data_buf) - len]; + + r = i2c_transfer(client->adapter, &msg, 1); + if (r != 1) { + if (r >= 0) + r = -EBUSY; + goto err; + } + + *val = get_unaligned_be32(data_buf); + + return 0; + +err: + dev_err(&client->dev, "read from offset 0x%x error %d\n", reg, r); + + return r; +} + +/* Read a register using 8-bit access only. */ +static int ____ccs_read_addr_8only(struct ccs_sensor *sensor, u16 reg, + u16 len, u32 *val) +{ + unsigned int i; + int rval; + + *val = 0; + + for (i = 0; i < len; i++) { + u32 val8; + + rval = ____ccs_read_addr(sensor, reg + i, 1, &val8); + if (rval < 0) + return rval; + *val |= val8 << ((len - i - 1) << 3); + } + + return 0; +} + +unsigned int ccs_reg_width(u32 reg) +{ + if (reg & CCS_FL_16BIT) + return sizeof(uint16_t); + if (reg & CCS_FL_32BIT) + return sizeof(uint32_t); + + return sizeof(uint8_t); +} + +/* + * Read a 8/16/32-bit i2c register. The value is returned in 'val'. + * Returns zero if successful, or non-zero otherwise. + */ +static int __ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val, + bool only8) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + unsigned int len = ccs_reg_width(reg); + int rval; + + if (!only8) + rval = ____ccs_read_addr(sensor, CCS_REG_ADDR(reg), len, val); + else + rval = ____ccs_read_addr_8only(sensor, CCS_REG_ADDR(reg), len, + val); + if (rval < 0) + return rval; + + if (reg & CCS_FL_FLOAT_IREAL) + *val = float_to_u32_mul_1000000(client, *val); + + return 0; +} + +int ccs_read_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 *val) +{ + return __ccs_read_addr( + sensor, reg, val, + ccs_needs_quirk(sensor, CCS_QUIRK_FLAG_8BIT_READ_ONLY)); +} + +static int ccs_read_addr_quirk(struct ccs_sensor *sensor, u32 reg, u32 *val, + bool force8) +{ + int rval; + + *val = 0; + rval = ccs_call_quirk(sensor, reg_access, false, ®, val); + if (rval == -ENOIOCTLCMD) + return 0; + if (rval < 0) + return rval; + + if (force8) + return __ccs_read_addr(sensor, reg, val, true); + + return ccs_read_addr_no_quirk(sensor, reg, val); +} + +int ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val) +{ + return ccs_read_addr_quirk(sensor, reg, val, false); +} + +int ccs_read_addr_8only(struct ccs_sensor *sensor, u32 reg, u32 *val) +{ + return ccs_read_addr_quirk(sensor, reg, val, true); +} + +int ccs_write_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + struct i2c_msg msg; + unsigned char data[6]; + unsigned int retries; + unsigned int len = ccs_reg_width(reg); + int r; + + if (len > sizeof(data) - 2) + return -EINVAL; + + msg.addr = client->addr; + msg.flags = 0; /* Write */ + msg.len = 2 + len; + msg.buf = data; + + put_unaligned_be16(CCS_REG_ADDR(reg), data); + put_unaligned_be32(val << (8 * (sizeof(val) - len)), data + 2); + + for (retries = 0; retries < 5; retries++) { + /* + * Due to unknown reason sensor stops responding. This + * loop is a temporaty solution until the root cause + * is found. + */ + r = i2c_transfer(client->adapter, &msg, 1); + if (r == 1) { + if (retries) + dev_err(&client->dev, + "sensor i2c stall encountered. retries: %d\n", + retries); + return 0; + } + + usleep_range(2000, 2000); + } + + dev_err(&client->dev, + "wrote 0x%x to offset 0x%x error %d\n", val, + CCS_REG_ADDR(reg), r); + + return r; +} + +/* + * Write to a 8/16-bit register. + * Returns zero if successful, or non-zero otherwise. + */ +int ccs_write_addr(struct ccs_sensor *sensor, u32 reg, u32 val) +{ + int rval; + + rval = ccs_call_quirk(sensor, reg_access, true, ®, &val); + if (rval == -ENOIOCTLCMD) + return 0; + if (rval < 0) + return rval; + + return ccs_write_addr_no_quirk(sensor, reg, val); +} diff --git a/drivers/media/i2c/smiapp/ccs-reg-access.h b/drivers/media/i2c/smiapp/ccs-reg-access.h new file mode 100644 index 000000000000..76ac036a9538 --- /dev/null +++ b/drivers/media/i2c/smiapp/ccs-reg-access.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * include/media/smiapp/ccs-regs.h + * + * Generic driver for SMIA/SMIA++ compliant camera modules + * + * Copyright (C) 2011--2012 Nokia Corporation + * Contact: Sakari Ailus + */ + +#ifndef SMIAPP_REGS_H +#define SMIAPP_REGS_H + +#include +#include + +#include "ccs-regs.h" + +#define CCS_REG_ADDR(reg) ((u16)reg) + +struct ccs_sensor; + +int ccs_read_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 *val); +int ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val); +int ccs_read_addr_8only(struct ccs_sensor *sensor, u32 reg, u32 *val); +int ccs_write_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 val); +int ccs_write_addr(struct ccs_sensor *sensor, u32 reg, u32 val); + +unsigned int ccs_reg_width(u32 reg); + +#define ccs_read(sensor, reg_name, val) \ + ccs_read_addr(sensor, CCS_R_##reg_name, val) + +#define ccs_write(sensor, reg_name, val) \ + ccs_write_addr(sensor, CCS_R_##reg_name, val) + +#endif diff --git a/drivers/media/i2c/smiapp/ccs.h b/drivers/media/i2c/smiapp/ccs.h new file mode 100644 index 000000000000..20b1125d87dc --- /dev/null +++ b/drivers/media/i2c/smiapp/ccs.h @@ -0,0 +1,280 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * drivers/media/i2c/smiapp/ccs.h + * + * Generic driver for SMIA/SMIA++ compliant camera modules + * + * Copyright (C) 2010--2012 Nokia Corporation + * Contact: Sakari Ailus + */ + +#ifndef __CCS_H__ +#define __CCS_H__ + +#include +#include +#include + +#include "ccs-quirk.h" +#include "ccs-regs.h" +#include "ccs-reg-access.h" +#include "../smiapp-pll.h" +#include "smiapp-reg-defs.h" + +/* + * Standard SMIA++ constants + */ +#define SMIA_VERSION_1 10 +#define SMIAPP_VERSION_0_8 8 /* Draft 0.8 */ +#define SMIAPP_VERSION_0_9 9 /* Draft 0.9 */ +#define SMIAPP_VERSION_1 10 + +#define SMIAPP_PROFILE_0 0 +#define SMIAPP_PROFILE_1 1 +#define SMIAPP_PROFILE_2 2 + +#define SMIAPP_NVM_PAGE_SIZE 64 /* bytes */ + +#define SMIAPP_RESET_DELAY_CLOCKS 2400 +#define SMIAPP_RESET_DELAY(clk) \ + (1000 + (SMIAPP_RESET_DELAY_CLOCKS * 1000 \ + + (clk) / 1000 - 1) / ((clk) / 1000)) + +#define CCS_COLOUR_COMPONENTS 4 + +#define SMIAPP_NAME "smiapp" +#define CCS_NAME "ccs" + +#define CCS_DFL_I2C_ADDR (0x20 >> 1) /* Default I2C Address */ +#define CCS_ALT_I2C_ADDR (0x6e >> 1) /* Alternate I2C Address */ + +/* + * Sometimes due to board layout considerations the camera module can be + * mounted rotated. The typical rotation used is 180 degrees which can be + * corrected by giving a default H-FLIP and V-FLIP in the sensor readout. + * FIXME: rotation also changes the bayer pattern. + */ +enum ccs_module_board_orient { + CCS_MODULE_BOARD_ORIENT_0 = 0, + CCS_MODULE_BOARD_ORIENT_180, +}; + +struct ccs_flash_strobe_parms { + u8 mode; + u32 strobe_width_high_us; + u16 strobe_delay; + u16 stobe_start_point; + u8 trigger; +}; + +struct ccs_hwconfig { + /* + * Change the cci address if i2c_addr_alt is set. + * Both default and alternate cci addr need to be present + */ + unsigned short i2c_addr_dfl; /* Default i2c addr */ + unsigned short i2c_addr_alt; /* Alternate i2c addr */ + + uint32_t ext_clk; /* sensor external clk */ + + unsigned int lanes; /* Number of CSI-2 lanes */ + uint32_t csi_signalling_mode; /* CCS_CSI_SIGNALLING_MODE_* */ + uint64_t *op_sys_clock; + + enum ccs_module_board_orient module_board_orient; + + struct ccs_flash_strobe_parms *strobe_setup; +}; + +struct ccs_quirk; + +#define CCS_MODULE_IDENT_FLAG_REV_LE (1 << 0) + +struct ccs_module_ident { + u16 mipi_manufacturer_id; + u16 model_id; + u8 smia_manufacturer_id; + u8 revision_number_major; + + u8 flags; + + char *name; + const struct ccs_quirk *quirk; +}; + +struct ccs_module_info { + u32 smia_manufacturer_id; + u32 mipi_manufacturer_id; + u32 model_id; + u32 revision_number_major; + u32 revision_number_minor; + + u32 module_year; + u32 module_month; + u32 module_day; + + u32 sensor_smia_manufacturer_id; + u32 sensor_mipi_manufacturer_id; + u32 sensor_model_id; + u32 sensor_revision_number; + u32 sensor_firmware_version; + + u32 smia_version; + u32 smiapp_version; + u32 ccs_version; + + u32 smiapp_profile; + + char *name; + const struct ccs_quirk *quirk; +}; + +#define CCS_IDENT_FQ(manufacturer, model, rev, fl, _name, _quirk) \ + { .smia_manufacturer_id = manufacturer, \ + .model_id = model, \ + .revision_number_major = rev, \ + .flags = fl, \ + .name = _name, \ + .quirk = _quirk, } + +#define CCS_IDENT_LQ(manufacturer, model, rev, _name, _quirk) \ + { .smia_manufacturer_id = manufacturer, \ + .model_id = model, \ + .revision_number_major = rev, \ + .flags = CCS_MODULE_IDENT_FLAG_REV_LE, \ + .name = _name, \ + .quirk = _quirk, } + +#define CCS_IDENT_L(manufacturer, model, rev, _name) \ + { .smia_manufacturer_id = manufacturer, \ + .model_id = model, \ + .revision_number_major = rev, \ + .flags = CCS_MODULE_IDENT_FLAG_REV_LE, \ + .name = _name, } + +#define CCS_IDENT_Q(manufacturer, model, rev, _name, _quirk) \ + { .smia_manufacturer_id = manufacturer, \ + .model_id = model, \ + .revision_number_major = rev, \ + .flags = 0, \ + .name = _name, \ + .quirk = _quirk, } + +#define CCS_IDENT(manufacturer, model, rev, _name) \ + { .smia_manufacturer_id = manufacturer, \ + .model_id = model, \ + .revision_number_major = rev, \ + .flags = 0, \ + .name = _name, } + +struct ccs_csi_data_format { + u32 code; + u8 width; + u8 compressed; + u8 pixel_order; +}; + +#define CCS_SUBDEVS 3 + +#define CCS_PA_PAD_SRC 0 +#define CCS_PAD_SINK 0 +#define CCS_PAD_SRC 1 +#define CCS_PADS 2 + +struct ccs_binning_subtype { + u8 horizontal:4; + u8 vertical:4; +} __packed; + +struct ccs_subdev { + struct v4l2_subdev sd; + struct media_pad pads[CCS_PADS]; + struct v4l2_rect sink_fmt; + struct v4l2_rect crop[CCS_PADS]; + struct v4l2_rect compose; /* compose on sink */ + unsigned short sink_pad; + unsigned short source_pad; + int npads; + struct ccs_sensor *sensor; + struct v4l2_ctrl_handler ctrl_handler; +}; + +/* + * struct ccs_sensor - Main device structure + */ +struct ccs_sensor { + /* + * "mutex" is used to serialise access to all fields here + * except v4l2_ctrls at the end of the struct. "mutex" is also + * used to serialise access to file handle specific + * information. + */ + struct mutex mutex; + struct ccs_subdev ssds[CCS_SUBDEVS]; + u32 ssds_used; + struct ccs_subdev *src; + struct ccs_subdev *binner; + struct ccs_subdev *scaler; + struct ccs_subdev *pixel_array; + struct ccs_hwconfig *hwcfg; + struct regulator *vana; + struct clk *ext_clk; + struct gpio_desc *xshutdown; + void *ccs_limits; + u8 nbinning_subtypes; + struct ccs_binning_subtype binning_subtypes[CCS_LIM_BINNING_SUB_TYPE_MAX_N + 1]; + u32 mbus_frame_fmts; + const struct ccs_csi_data_format *csi_format; + const struct ccs_csi_data_format *internal_csi_format; + u32 default_mbus_frame_fmts; + int default_pixel_order; + + u8 binning_horizontal; + u8 binning_vertical; + + u8 scale_m; + u8 scaling_mode; + + u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */ + u8 frame_skip; + u16 embedded_start; /* embedded data start line */ + u16 embedded_end; + u16 image_start; /* image data start line */ + u16 visible_pixel_start; /* start pixel of the visible image */ + + bool streaming; + bool dev_init_done; + u8 compressed_min_bpp; + + struct ccs_module_info minfo; + + struct smiapp_pll pll; + + /* Is a default format supported for a given BPP? */ + unsigned long *valid_link_freqs; + + /* Pixel array controls */ + struct v4l2_ctrl *analog_gain; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *pixel_rate_parray; + /* src controls */ + struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *pixel_rate_csi; + /* test pattern colour components */ + struct v4l2_ctrl *test_data[CCS_COLOUR_COMPONENTS]; +}; + +#define to_ccs_subdev(_sd) \ + container_of(_sd, struct ccs_subdev, sd) + +#define to_ccs_sensor(_sd) \ + (to_ccs_subdev(_sd)->sensor) + +void ccs_replace_limit(struct ccs_sensor *sensor, + unsigned int limit, unsigned int offset, u32 val); + +#endif /* __CCS_H__ */ diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c deleted file mode 100644 index b12e41a6a410..000000000000 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ /dev/null @@ -1,3305 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * drivers/media/i2c/smiapp/smiapp-core.c - * - * Generic driver for SMIA/SMIA++ compliant camera modules - * - * Copyright (C) 2010--2012 Nokia Corporation - * Contact: Sakari Ailus - * - * Based on smiapp driver by Vimarsh Zutshi - * Based on jt8ev1.c by Vimarsh Zutshi - * Based on smia-sensor.c by Tuukka Toivonen - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ccs-limits.h" -#include "smiapp.h" - -#define SMIAPP_ALIGN_DIM(dim, flags) \ - ((flags) & V4L2_SEL_FLAG_GE \ - ? ALIGN((dim), 2) \ - : (dim) & ~1) - -static struct ccs_limit_offset { - u16 lim; - u16 info; -} ccs_limit_offsets[CCS_L_LAST + 1]; - -/* - * smiapp_module_idents - supported camera modules - */ -static const struct smiapp_module_ident smiapp_module_idents[] = { - SMIAPP_IDENT_L(0x01, 0x022b, -1, "vs6555"), - SMIAPP_IDENT_L(0x01, 0x022e, -1, "vw6558"), - SMIAPP_IDENT_L(0x07, 0x7698, -1, "ovm7698"), - SMIAPP_IDENT_L(0x0b, 0x4242, -1, "smiapp-003"), - SMIAPP_IDENT_L(0x0c, 0x208a, -1, "tcm8330md"), - SMIAPP_IDENT_LQ(0x0c, 0x2134, -1, "tcm8500md", &smiapp_tcm8500md_quirk), - SMIAPP_IDENT_L(0x0c, 0x213e, -1, "et8en2"), - SMIAPP_IDENT_L(0x0c, 0x2184, -1, "tcm8580md"), - SMIAPP_IDENT_LQ(0x0c, 0x560f, -1, "jt8ew9", &smiapp_jt8ew9_quirk), - SMIAPP_IDENT_LQ(0x10, 0x4141, -1, "jt8ev1", &smiapp_jt8ev1_quirk), - SMIAPP_IDENT_LQ(0x10, 0x4241, -1, "imx125es", &smiapp_imx125es_quirk), -}; - -/* - * - * Dynamic Capability Identification - * - */ - -static void ccs_assign_limit(void *ptr, unsigned int width, u32 val) -{ - switch (width) { - case sizeof(u8): - *(u8 *)ptr = val; - break; - case sizeof(u16): - *(u16 *)ptr = val; - break; - case sizeof(u32): - *(u32 *)ptr = val; - break; - } -} - -static int ccs_limit_ptr(struct smiapp_sensor *sensor, unsigned int limit, - unsigned int offset, void **__ptr) -{ - const struct ccs_limit *linfo; - - if (WARN_ON(limit >= CCS_L_LAST)) - return -EINVAL; - - linfo = &ccs_limits[ccs_limit_offsets[limit].info]; - - if (WARN_ON(!sensor->ccs_limits) || - WARN_ON(offset + ccs_reg_width(linfo->reg) > - ccs_limit_offsets[limit + 1].lim)) - return -EINVAL; - - *__ptr = sensor->ccs_limits + ccs_limit_offsets[limit].lim + offset; - - return 0; -} - -void ccs_replace_limit(struct smiapp_sensor *sensor, - unsigned int limit, unsigned int offset, u32 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - const struct ccs_limit *linfo; - void *ptr; - int ret; - - ret = ccs_limit_ptr(sensor, limit, offset, &ptr); - if (ret) - return; - - linfo = &ccs_limits[ccs_limit_offsets[limit].info]; - - dev_dbg(&client->dev, "quirk: 0x%8.8x \"%s\" %u = %d, 0x%x\n", - linfo->reg, linfo->name, offset, val, val); - - ccs_assign_limit(ptr, ccs_reg_width(linfo->reg), val); -} - -static u32 ccs_get_limit(struct smiapp_sensor *sensor, - unsigned int limit, unsigned int offset) -{ - void *ptr; - int ret; - - ret = ccs_limit_ptr(sensor, limit, offset, &ptr); - if (ret) - return 0; - - switch (ccs_reg_width(ccs_limits[ccs_limit_offsets[limit].info].reg)) { - case sizeof(u8): - return *(u8 *)ptr; - case sizeof(u16): - return *(u16 *)ptr; - case sizeof(u32): - return *(u32 *)ptr; - } - - WARN_ON(1); - - return 0; -} - -#define CCS_LIM(sensor, limit) \ - ccs_get_limit(sensor, CCS_L_##limit, 0) - -#define CCS_LIM_AT(sensor, limit, offset) \ - ccs_get_limit(sensor, CCS_L_##limit, CCS_L_##limit##_OFFSET(offset)) - -static int ccs_read_all_limits(struct smiapp_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - void *ptr, *alloc, *end; - unsigned int i, l; - int ret; - - kfree(sensor->ccs_limits); - sensor->ccs_limits = NULL; - - alloc = kzalloc(ccs_limit_offsets[CCS_L_LAST].lim, GFP_KERNEL); - if (!alloc) - return -ENOMEM; - - end = alloc + ccs_limit_offsets[CCS_L_LAST].lim; - - for (i = 0, l = 0, ptr = alloc; ccs_limits[i].size; i++) { - u32 reg = ccs_limits[i].reg; - unsigned int width = ccs_reg_width(reg); - unsigned int j; - - if (l == CCS_L_LAST) { - dev_err(&client->dev, - "internal error --- end of limit array\n"); - ret = -EINVAL; - goto out_err; - } - - for (j = 0; j < ccs_limits[i].size / width; - j++, reg += width, ptr += width) { - u32 val; - - ret = ccs_read_addr(sensor, reg, &val); - if (ret) - goto out_err; - - if (ptr + width > end) { - dev_err(&client->dev, - "internal error --- no room for regs\n"); - ret = -EINVAL; - goto out_err; - } - - ccs_assign_limit(ptr, width, val); - - dev_dbg(&client->dev, "0x%8.8x \"%s\" = %u, 0x%x\n", - reg, ccs_limits[i].name, val, val); - } - - if (ccs_limits[i].flags & CCS_L_FL_SAME_REG) - continue; - - l++; - ptr = alloc + ccs_limit_offsets[l].lim; - } - - if (l != CCS_L_LAST) { - dev_err(&client->dev, - "internal error --- insufficient limits\n"); - ret = -EINVAL; - goto out_err; - } - - sensor->ccs_limits = alloc; - - if (CCS_LIM(sensor, SCALER_N_MIN) < 16) - ccs_replace_limit(sensor, CCS_L_SCALER_N_MIN, 0, 16); - - return 0; - -out_err: - kfree(alloc); - - return ret; -} - -static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - u8 fmt_model_type, fmt_model_subtype, ncol_desc, nrow_desc; - unsigned int i; - int pixel_count = 0; - int line_count = 0; - - fmt_model_type = CCS_LIM(sensor, FRAME_FORMAT_MODEL_TYPE); - fmt_model_subtype = CCS_LIM(sensor, FRAME_FORMAT_MODEL_SUBTYPE); - - ncol_desc = (fmt_model_subtype - & CCS_FRAME_FORMAT_MODEL_SUBTYPE_COLUMNS_MASK) - >> CCS_FRAME_FORMAT_MODEL_SUBTYPE_COLUMNS_SHIFT; - nrow_desc = fmt_model_subtype - & CCS_FRAME_FORMAT_MODEL_SUBTYPE_ROWS_MASK; - - dev_dbg(&client->dev, "format_model_type %s\n", - fmt_model_type == CCS_FRAME_FORMAT_MODEL_TYPE_2_BYTE - ? "2 byte" : - fmt_model_type == CCS_FRAME_FORMAT_MODEL_TYPE_4_BYTE - ? "4 byte" : "is simply bad"); - - dev_dbg(&client->dev, "%u column and %u row descriptors\n", - ncol_desc, nrow_desc); - - for (i = 0; i < ncol_desc + nrow_desc; i++) { - u32 desc; - u32 pixelcode; - u32 pixels; - char *which; - char *what; - u32 reg; - - if (fmt_model_type == CCS_FRAME_FORMAT_MODEL_TYPE_2_BYTE) { - desc = CCS_LIM_AT(sensor, FRAME_FORMAT_DESCRIPTOR, i); - - pixelcode = - (desc - & CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MASK) - >> CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_SHIFT; - pixels = desc & CCS_FRAME_FORMAT_DESCRIPTOR_PIXELS_MASK; - } else if (fmt_model_type - == CCS_FRAME_FORMAT_MODEL_TYPE_4_BYTE) { - desc = CCS_LIM_AT(sensor, FRAME_FORMAT_DESCRIPTOR_4, i); - - pixelcode = - (desc - & CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MASK) - >> CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_SHIFT; - pixels = desc & - CCS_FRAME_FORMAT_DESCRIPTOR_4_PIXELS_MASK; - } else { - dev_dbg(&client->dev, - "invalid frame format model type %d\n", - fmt_model_type); - return -EINVAL; - } - - if (i < ncol_desc) - which = "columns"; - else - which = "rows"; - - switch (pixelcode) { - case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_EMBEDDED: - what = "embedded"; - break; - case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_DUMMY_PIXEL: - what = "dummy"; - break; - case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_BLACK_PIXEL: - what = "black"; - break; - case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_DARK_PIXEL: - what = "dark"; - break; - case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_VISIBLE_PIXEL: - what = "visible"; - break; - default: - what = "invalid"; - break; - } - - dev_dbg(&client->dev, - "0x%8.8x %s pixels: %d %s (pixelcode %u)\n", reg, - what, pixels, which, pixelcode); - - if (i < ncol_desc) { - if (pixelcode == - CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_VISIBLE_PIXEL) - sensor->visible_pixel_start = pixel_count; - pixel_count += pixels; - continue; - } - - /* Handle row descriptors */ - switch (pixelcode) { - case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_EMBEDDED: - if (sensor->embedded_end) - break; - sensor->embedded_start = line_count; - sensor->embedded_end = line_count + pixels; - break; - case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_VISIBLE_PIXEL: - sensor->image_start = line_count; - break; - } - line_count += pixels; - } - - if (sensor->embedded_end > sensor->image_start) { - dev_dbg(&client->dev, - "adjusting image start line to %u (was %u)\n", - sensor->embedded_end, sensor->image_start); - sensor->image_start = sensor->embedded_end; - } - - dev_dbg(&client->dev, "embedded data from lines %d to %d\n", - sensor->embedded_start, sensor->embedded_end); - dev_dbg(&client->dev, "image data starts at line %d\n", - sensor->image_start); - - return 0; -} - -static int smiapp_pll_configure(struct smiapp_sensor *sensor) -{ - struct smiapp_pll *pll = &sensor->pll; - int rval; - - rval = ccs_write(sensor, VT_PIX_CLK_DIV, pll->vt.pix_clk_div); - if (rval < 0) - return rval; - - rval = ccs_write(sensor, VT_SYS_CLK_DIV, pll->vt.sys_clk_div); - if (rval < 0) - return rval; - - rval = ccs_write(sensor, PRE_PLL_CLK_DIV, pll->pre_pll_clk_div); - if (rval < 0) - return rval; - - rval = ccs_write(sensor, PLL_MULTIPLIER, pll->pll_multiplier); - if (rval < 0) - return rval; - - /* Lane op clock ratio does not apply here. */ - rval = ccs_write(sensor, REQUESTED_LINK_RATE, - DIV_ROUND_UP(pll->op.sys_clk_freq_hz, - 1000000 / 256 / 256)); - if (rval < 0 || sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) - return rval; - - rval = ccs_write(sensor, OP_PIX_CLK_DIV, pll->op.pix_clk_div); - if (rval < 0) - return rval; - - return ccs_write(sensor, OP_SYS_CLK_DIV, pll->op.sys_clk_div); -} - -static int smiapp_pll_try(struct smiapp_sensor *sensor, - struct smiapp_pll *pll) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - struct smiapp_pll_limits lim = { - .min_pre_pll_clk_div = CCS_LIM(sensor, MIN_PRE_PLL_CLK_DIV), - .max_pre_pll_clk_div = CCS_LIM(sensor, MAX_PRE_PLL_CLK_DIV), - .min_pll_ip_freq_hz = CCS_LIM(sensor, MIN_PLL_IP_CLK_FREQ_MHZ), - .max_pll_ip_freq_hz = CCS_LIM(sensor, MAX_PLL_IP_CLK_FREQ_MHZ), - .min_pll_multiplier = CCS_LIM(sensor, MIN_PLL_MULTIPLIER), - .max_pll_multiplier = CCS_LIM(sensor, MAX_PLL_MULTIPLIER), - .min_pll_op_freq_hz = CCS_LIM(sensor, MIN_PLL_OP_CLK_FREQ_MHZ), - .max_pll_op_freq_hz = CCS_LIM(sensor, MAX_PLL_OP_CLK_FREQ_MHZ), - - .op.min_sys_clk_div = CCS_LIM(sensor, MIN_OP_SYS_CLK_DIV), - .op.max_sys_clk_div = CCS_LIM(sensor, MAX_OP_SYS_CLK_DIV), - .op.min_pix_clk_div = CCS_LIM(sensor, MIN_OP_PIX_CLK_DIV), - .op.max_pix_clk_div = CCS_LIM(sensor, MAX_OP_PIX_CLK_DIV), - .op.min_sys_clk_freq_hz = CCS_LIM(sensor, MIN_OP_SYS_CLK_FREQ_MHZ), - .op.max_sys_clk_freq_hz = CCS_LIM(sensor, MAX_OP_SYS_CLK_FREQ_MHZ), - .op.min_pix_clk_freq_hz = CCS_LIM(sensor, MIN_OP_PIX_CLK_FREQ_MHZ), - .op.max_pix_clk_freq_hz = CCS_LIM(sensor, MAX_OP_PIX_CLK_FREQ_MHZ), - - .vt.min_sys_clk_div = CCS_LIM(sensor, MIN_VT_SYS_CLK_DIV), - .vt.max_sys_clk_div = CCS_LIM(sensor, MAX_VT_SYS_CLK_DIV), - .vt.min_pix_clk_div = CCS_LIM(sensor, MIN_VT_PIX_CLK_DIV), - .vt.max_pix_clk_div = CCS_LIM(sensor, MAX_VT_PIX_CLK_DIV), - .vt.min_sys_clk_freq_hz = CCS_LIM(sensor, MIN_VT_SYS_CLK_FREQ_MHZ), - .vt.max_sys_clk_freq_hz = CCS_LIM(sensor, MAX_VT_SYS_CLK_FREQ_MHZ), - .vt.min_pix_clk_freq_hz = CCS_LIM(sensor, MIN_VT_PIX_CLK_FREQ_MHZ), - .vt.max_pix_clk_freq_hz = CCS_LIM(sensor, MAX_VT_PIX_CLK_FREQ_MHZ), - - .min_line_length_pck_bin = CCS_LIM(sensor, MIN_LINE_LENGTH_PCK_BIN), - .min_line_length_pck = CCS_LIM(sensor, MIN_LINE_LENGTH_PCK), - }; - - return smiapp_pll_calculate(&client->dev, &lim, pll); -} - -static int smiapp_pll_update(struct smiapp_sensor *sensor) -{ - struct smiapp_pll *pll = &sensor->pll; - int rval; - - pll->binning_horizontal = sensor->binning_horizontal; - pll->binning_vertical = sensor->binning_vertical; - pll->link_freq = - sensor->link_freq->qmenu_int[sensor->link_freq->val]; - pll->scale_m = sensor->scale_m; - pll->bits_per_pixel = sensor->csi_format->compressed; - - rval = smiapp_pll_try(sensor, pll); - if (rval < 0) - return rval; - - __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_parray, - pll->pixel_rate_pixel_array); - __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_csi, pll->pixel_rate_csi); - - return 0; -} - - -/* - * - * V4L2 Controls handling - * - */ - -static void __smiapp_update_exposure_limits(struct smiapp_sensor *sensor) -{ - struct v4l2_ctrl *ctrl = sensor->exposure; - int max; - - max = sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height - + sensor->vblank->val - - CCS_LIM(sensor, COARSE_INTEGRATION_TIME_MAX_MARGIN); - - __v4l2_ctrl_modify_range(ctrl, ctrl->minimum, max, ctrl->step, max); -} - -/* - * Order matters. - * - * 1. Bits-per-pixel, descending. - * 2. Bits-per-pixel compressed, descending. - * 3. Pixel order, same as in pixel_order_str. Formats for all four pixel - * orders must be defined. - */ -static const struct smiapp_csi_data_format smiapp_csi_data_formats[] = { - { MEDIA_BUS_FMT_SGRBG16_1X16, 16, 16, SMIAPP_PIXEL_ORDER_GRBG, }, - { MEDIA_BUS_FMT_SRGGB16_1X16, 16, 16, SMIAPP_PIXEL_ORDER_RGGB, }, - { MEDIA_BUS_FMT_SBGGR16_1X16, 16, 16, SMIAPP_PIXEL_ORDER_BGGR, }, - { MEDIA_BUS_FMT_SGBRG16_1X16, 16, 16, SMIAPP_PIXEL_ORDER_GBRG, }, - { MEDIA_BUS_FMT_SGRBG14_1X14, 14, 14, SMIAPP_PIXEL_ORDER_GRBG, }, - { MEDIA_BUS_FMT_SRGGB14_1X14, 14, 14, SMIAPP_PIXEL_ORDER_RGGB, }, - { MEDIA_BUS_FMT_SBGGR14_1X14, 14, 14, SMIAPP_PIXEL_ORDER_BGGR, }, - { MEDIA_BUS_FMT_SGBRG14_1X14, 14, 14, SMIAPP_PIXEL_ORDER_GBRG, }, - { MEDIA_BUS_FMT_SGRBG12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_GRBG, }, - { MEDIA_BUS_FMT_SRGGB12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_RGGB, }, - { MEDIA_BUS_FMT_SBGGR12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_BGGR, }, - { MEDIA_BUS_FMT_SGBRG12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_GBRG, }, - { MEDIA_BUS_FMT_SGRBG10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_GRBG, }, - { MEDIA_BUS_FMT_SRGGB10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_RGGB, }, - { MEDIA_BUS_FMT_SBGGR10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_BGGR, }, - { MEDIA_BUS_FMT_SGBRG10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_GBRG, }, - { MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_GRBG, }, - { MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_RGGB, }, - { MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_BGGR, }, - { MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_GBRG, }, - { MEDIA_BUS_FMT_SGRBG8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_GRBG, }, - { MEDIA_BUS_FMT_SRGGB8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_RGGB, }, - { MEDIA_BUS_FMT_SBGGR8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_BGGR, }, - { MEDIA_BUS_FMT_SGBRG8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_GBRG, }, -}; - -static const char *pixel_order_str[] = { "GRBG", "RGGB", "BGGR", "GBRG" }; - -#define to_csi_format_idx(fmt) (((unsigned long)(fmt) \ - - (unsigned long)smiapp_csi_data_formats) \ - / sizeof(*smiapp_csi_data_formats)) - -static u32 smiapp_pixel_order(struct smiapp_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - int flip = 0; - - if (sensor->hflip) { - if (sensor->hflip->val) - flip |= CCS_IMAGE_ORIENTATION_HORIZONTAL_MIRROR; - - if (sensor->vflip->val) - flip |= CCS_IMAGE_ORIENTATION_VERTICAL_FLIP; - } - - flip ^= sensor->hvflip_inv_mask; - - dev_dbg(&client->dev, "flip %d\n", flip); - return sensor->default_pixel_order ^ flip; -} - -static void smiapp_update_mbus_formats(struct smiapp_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - unsigned int csi_format_idx = - to_csi_format_idx(sensor->csi_format) & ~3; - unsigned int internal_csi_format_idx = - to_csi_format_idx(sensor->internal_csi_format) & ~3; - unsigned int pixel_order = smiapp_pixel_order(sensor); - - sensor->mbus_frame_fmts = - sensor->default_mbus_frame_fmts << pixel_order; - sensor->csi_format = - &smiapp_csi_data_formats[csi_format_idx + pixel_order]; - sensor->internal_csi_format = - &smiapp_csi_data_formats[internal_csi_format_idx - + pixel_order]; - - BUG_ON(max(internal_csi_format_idx, csi_format_idx) + pixel_order - >= ARRAY_SIZE(smiapp_csi_data_formats)); - - dev_dbg(&client->dev, "new pixel order %s\n", - pixel_order_str[pixel_order]); -} - -static const char * const smiapp_test_patterns[] = { - "Disabled", - "Solid Colour", - "Eight Vertical Colour Bars", - "Colour Bars With Fade to Grey", - "Pseudorandom Sequence (PN9)", -}; - -static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl) -{ - struct smiapp_sensor *sensor = - container_of(ctrl->handler, struct smiapp_subdev, ctrl_handler) - ->sensor; - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - int pm_status; - u32 orient = 0; - unsigned int i; - int exposure; - int rval; - - switch (ctrl->id) { - case V4L2_CID_HFLIP: - case V4L2_CID_VFLIP: - if (sensor->streaming) - return -EBUSY; - - if (sensor->hflip->val) - orient |= CCS_IMAGE_ORIENTATION_HORIZONTAL_MIRROR; - - if (sensor->vflip->val) - orient |= CCS_IMAGE_ORIENTATION_VERTICAL_FLIP; - - orient ^= sensor->hvflip_inv_mask; - - smiapp_update_mbus_formats(sensor); - - break; - case V4L2_CID_VBLANK: - exposure = sensor->exposure->val; - - __smiapp_update_exposure_limits(sensor); - - if (exposure > sensor->exposure->maximum) { - sensor->exposure->val = sensor->exposure->maximum; - rval = smiapp_set_ctrl(sensor->exposure); - if (rval < 0) - return rval; - } - - break; - case V4L2_CID_LINK_FREQ: - if (sensor->streaming) - return -EBUSY; - - rval = smiapp_pll_update(sensor); - if (rval) - return rval; - - return 0; - case V4L2_CID_TEST_PATTERN: - for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) - v4l2_ctrl_activate( - sensor->test_data[i], - ctrl->val == - V4L2_SMIAPP_TEST_PATTERN_MODE_SOLID_COLOUR); - - break; - } - - pm_status = pm_runtime_get_if_active(&client->dev, true); - if (!pm_status) - return 0; - - switch (ctrl->id) { - case V4L2_CID_ANALOGUE_GAIN: - rval = ccs_write(sensor, ANALOG_GAIN_CODE_GLOBAL, ctrl->val); - - break; - case V4L2_CID_EXPOSURE: - rval = ccs_write(sensor, COARSE_INTEGRATION_TIME, ctrl->val); - - break; - case V4L2_CID_HFLIP: - case V4L2_CID_VFLIP: - rval = ccs_write(sensor, IMAGE_ORIENTATION, orient); - - break; - case V4L2_CID_VBLANK: - rval = ccs_write(sensor, FRAME_LENGTH_LINES, - sensor->pixel_array->crop[ - SMIAPP_PA_PAD_SRC].height - + ctrl->val); - - break; - case V4L2_CID_HBLANK: - rval = ccs_write(sensor, LINE_LENGTH_PCK, - sensor->pixel_array->crop[ - SMIAPP_PA_PAD_SRC].width - + ctrl->val); - - break; - case V4L2_CID_TEST_PATTERN: - rval = ccs_write(sensor, TEST_PATTERN_MODE, ctrl->val); - - break; - case V4L2_CID_TEST_PATTERN_RED: - rval = ccs_write(sensor, TEST_DATA_RED, ctrl->val); - - break; - case V4L2_CID_TEST_PATTERN_GREENR: - rval = ccs_write(sensor, TEST_DATA_GREENR, ctrl->val); - - break; - case V4L2_CID_TEST_PATTERN_BLUE: - rval = ccs_write(sensor, TEST_DATA_BLUE, ctrl->val); - - break; - case V4L2_CID_TEST_PATTERN_GREENB: - rval = ccs_write(sensor, TEST_DATA_GREENB, ctrl->val); - - break; - case V4L2_CID_PIXEL_RATE: - /* For v4l2_ctrl_s_ctrl_int64() used internally. */ - rval = 0; - - break; - default: - rval = -EINVAL; - } - - if (pm_status > 0) { - pm_runtime_mark_last_busy(&client->dev); - pm_runtime_put_autosuspend(&client->dev); - } - - return rval; -} - -static const struct v4l2_ctrl_ops smiapp_ctrl_ops = { - .s_ctrl = smiapp_set_ctrl, -}; - -static int smiapp_init_controls(struct smiapp_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - int rval; - - rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 12); - if (rval) - return rval; - - sensor->pixel_array->ctrl_handler.lock = &sensor->mutex; - - sensor->analog_gain = v4l2_ctrl_new_std( - &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops, - V4L2_CID_ANALOGUE_GAIN, - CCS_LIM(sensor, ANALOG_GAIN_CODE_MIN), - CCS_LIM(sensor, ANALOG_GAIN_CODE_MAX), - max(CCS_LIM(sensor, ANALOG_GAIN_CODE_STEP), 1U), - CCS_LIM(sensor, ANALOG_GAIN_CODE_MIN)); - - /* Exposure limits will be updated soon, use just something here. */ - sensor->exposure = v4l2_ctrl_new_std( - &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops, - V4L2_CID_EXPOSURE, 0, 0, 1, 0); - - sensor->hflip = v4l2_ctrl_new_std( - &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops, - V4L2_CID_HFLIP, 0, 1, 1, 0); - sensor->vflip = v4l2_ctrl_new_std( - &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); - - sensor->vblank = v4l2_ctrl_new_std( - &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops, - V4L2_CID_VBLANK, 0, 1, 1, 0); - - if (sensor->vblank) - sensor->vblank->flags |= V4L2_CTRL_FLAG_UPDATE; - - sensor->hblank = v4l2_ctrl_new_std( - &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops, - V4L2_CID_HBLANK, 0, 1, 1, 0); - - if (sensor->hblank) - sensor->hblank->flags |= V4L2_CTRL_FLAG_UPDATE; - - sensor->pixel_rate_parray = v4l2_ctrl_new_std( - &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops, - V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1); - - v4l2_ctrl_new_std_menu_items(&sensor->pixel_array->ctrl_handler, - &smiapp_ctrl_ops, V4L2_CID_TEST_PATTERN, - ARRAY_SIZE(smiapp_test_patterns) - 1, - 0, 0, smiapp_test_patterns); - - if (sensor->pixel_array->ctrl_handler.error) { - dev_err(&client->dev, - "pixel array controls initialization failed (%d)\n", - sensor->pixel_array->ctrl_handler.error); - return sensor->pixel_array->ctrl_handler.error; - } - - sensor->pixel_array->sd.ctrl_handler = - &sensor->pixel_array->ctrl_handler; - - v4l2_ctrl_cluster(2, &sensor->hflip); - - rval = v4l2_ctrl_handler_init(&sensor->src->ctrl_handler, 0); - if (rval) - return rval; - - sensor->src->ctrl_handler.lock = &sensor->mutex; - - sensor->pixel_rate_csi = v4l2_ctrl_new_std( - &sensor->src->ctrl_handler, &smiapp_ctrl_ops, - V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1); - - if (sensor->src->ctrl_handler.error) { - dev_err(&client->dev, - "src controls initialization failed (%d)\n", - sensor->src->ctrl_handler.error); - return sensor->src->ctrl_handler.error; - } - - sensor->src->sd.ctrl_handler = &sensor->src->ctrl_handler; - - return 0; -} - -/* - * For controls that require information on available media bus codes - * and linke frequencies. - */ -static int smiapp_init_late_controls(struct smiapp_sensor *sensor) -{ - unsigned long *valid_link_freqs = &sensor->valid_link_freqs[ - sensor->csi_format->compressed - sensor->compressed_min_bpp]; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) { - int max_value = (1 << sensor->csi_format->width) - 1; - - sensor->test_data[i] = v4l2_ctrl_new_std( - &sensor->pixel_array->ctrl_handler, - &smiapp_ctrl_ops, V4L2_CID_TEST_PATTERN_RED + i, - 0, max_value, 1, max_value); - } - - sensor->link_freq = v4l2_ctrl_new_int_menu( - &sensor->src->ctrl_handler, &smiapp_ctrl_ops, - V4L2_CID_LINK_FREQ, __fls(*valid_link_freqs), - __ffs(*valid_link_freqs), sensor->hwcfg->op_sys_clock); - - return sensor->src->ctrl_handler.error; -} - -static void smiapp_free_controls(struct smiapp_sensor *sensor) -{ - unsigned int i; - - for (i = 0; i < sensor->ssds_used; i++) - v4l2_ctrl_handler_free(&sensor->ssds[i].ctrl_handler); -} - -static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - struct smiapp_pll *pll = &sensor->pll; - u8 compressed_max_bpp = 0; - unsigned int type, n; - unsigned int i, pixel_order; - int rval; - - type = CCS_LIM(sensor, DATA_FORMAT_MODEL_TYPE); - - dev_dbg(&client->dev, "data_format_model_type %d\n", type); - - rval = ccs_read(sensor, PIXEL_ORDER, &pixel_order); - if (rval) - return rval; - - if (pixel_order >= ARRAY_SIZE(pixel_order_str)) { - dev_dbg(&client->dev, "bad pixel order %d\n", pixel_order); - return -EINVAL; - } - - dev_dbg(&client->dev, "pixel order %d (%s)\n", pixel_order, - pixel_order_str[pixel_order]); - - switch (type) { - case CCS_DATA_FORMAT_MODEL_TYPE_NORMAL: - n = SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL_N; - break; - case CCS_DATA_FORMAT_MODEL_TYPE_EXTENDED: - n = CCS_LIM_DATA_FORMAT_DESCRIPTOR_MAX_N + 1; - break; - default: - return -EINVAL; - } - - sensor->default_pixel_order = pixel_order; - sensor->mbus_frame_fmts = 0; - - for (i = 0; i < n; i++) { - unsigned int fmt, j; - - fmt = CCS_LIM_AT(sensor, DATA_FORMAT_DESCRIPTOR, i); - - dev_dbg(&client->dev, "%u: bpp %u, compressed %u\n", - i, fmt >> 8, (u8)fmt); - - for (j = 0; j < ARRAY_SIZE(smiapp_csi_data_formats); j++) { - const struct smiapp_csi_data_format *f = - &smiapp_csi_data_formats[j]; - - if (f->pixel_order != SMIAPP_PIXEL_ORDER_GRBG) - continue; - - if (f->width != fmt >> - CCS_DATA_FORMAT_DESCRIPTOR_UNCOMPRESSED_SHIFT || - f->compressed != - (fmt & CCS_DATA_FORMAT_DESCRIPTOR_COMPRESSED_MASK)) - continue; - - dev_dbg(&client->dev, "jolly good! %d\n", j); - - sensor->default_mbus_frame_fmts |= 1 << j; - } - } - - /* Figure out which BPP values can be used with which formats. */ - pll->binning_horizontal = 1; - pll->binning_vertical = 1; - pll->scale_m = sensor->scale_m; - - for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) { - sensor->compressed_min_bpp = - min(smiapp_csi_data_formats[i].compressed, - sensor->compressed_min_bpp); - compressed_max_bpp = - max(smiapp_csi_data_formats[i].compressed, - compressed_max_bpp); - } - - sensor->valid_link_freqs = devm_kcalloc( - &client->dev, - compressed_max_bpp - sensor->compressed_min_bpp + 1, - sizeof(*sensor->valid_link_freqs), GFP_KERNEL); - if (!sensor->valid_link_freqs) - return -ENOMEM; - - for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) { - const struct smiapp_csi_data_format *f = - &smiapp_csi_data_formats[i]; - unsigned long *valid_link_freqs = - &sensor->valid_link_freqs[ - f->compressed - sensor->compressed_min_bpp]; - unsigned int j; - - if (!(sensor->default_mbus_frame_fmts & 1 << i)) - continue; - - pll->bits_per_pixel = f->compressed; - - for (j = 0; sensor->hwcfg->op_sys_clock[j]; j++) { - pll->link_freq = sensor->hwcfg->op_sys_clock[j]; - - rval = smiapp_pll_try(sensor, pll); - dev_dbg(&client->dev, "link freq %u Hz, bpp %u %s\n", - pll->link_freq, pll->bits_per_pixel, - rval ? "not ok" : "ok"); - if (rval) - continue; - - set_bit(j, valid_link_freqs); - } - - if (!*valid_link_freqs) { - dev_info(&client->dev, - "no valid link frequencies for %u bpp\n", - f->compressed); - sensor->default_mbus_frame_fmts &= ~BIT(i); - continue; - } - - if (!sensor->csi_format - || f->width > sensor->csi_format->width - || (f->width == sensor->csi_format->width - && f->compressed > sensor->csi_format->compressed)) { - sensor->csi_format = f; - sensor->internal_csi_format = f; - } - } - - if (!sensor->csi_format) { - dev_err(&client->dev, "no supported mbus code found\n"); - return -EINVAL; - } - - smiapp_update_mbus_formats(sensor); - - return 0; -} - -static void smiapp_update_blanking(struct smiapp_sensor *sensor) -{ - struct v4l2_ctrl *vblank = sensor->vblank; - struct v4l2_ctrl *hblank = sensor->hblank; - uint16_t min_fll, max_fll, min_llp, max_llp, min_lbp; - int min, max; - - if (sensor->binning_vertical > 1 || sensor->binning_horizontal > 1) { - min_fll = CCS_LIM(sensor, MIN_FRAME_LENGTH_LINES_BIN); - max_fll = CCS_LIM(sensor, MAX_FRAME_LENGTH_LINES_BIN); - min_llp = CCS_LIM(sensor, MIN_LINE_LENGTH_PCK_BIN); - max_llp = CCS_LIM(sensor, MAX_LINE_LENGTH_PCK_BIN); - min_lbp = CCS_LIM(sensor, MIN_LINE_BLANKING_PCK_BIN); - } else { - min_fll = CCS_LIM(sensor, MIN_FRAME_LENGTH_LINES); - max_fll = CCS_LIM(sensor, MAX_FRAME_LENGTH_LINES); - min_llp = CCS_LIM(sensor, MIN_LINE_LENGTH_PCK); - max_llp = CCS_LIM(sensor, MAX_LINE_LENGTH_PCK); - min_lbp = CCS_LIM(sensor, MIN_LINE_BLANKING_PCK); - } - - min = max_t(int, - CCS_LIM(sensor, MIN_FRAME_BLANKING_LINES), - min_fll - - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height); - max = max_fll - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height; - - __v4l2_ctrl_modify_range(vblank, min, max, vblank->step, min); - - min = max_t(int, - min_llp - - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width, - min_lbp); - max = max_llp - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width; - - __v4l2_ctrl_modify_range(hblank, min, max, hblank->step, min); - - __smiapp_update_exposure_limits(sensor); -} - -static int smiapp_pll_blanking_update(struct smiapp_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - int rval; - - rval = smiapp_pll_update(sensor); - if (rval < 0) - return rval; - - /* Output from pixel array, including blanking */ - smiapp_update_blanking(sensor); - - dev_dbg(&client->dev, "vblank\t\t%d\n", sensor->vblank->val); - dev_dbg(&client->dev, "hblank\t\t%d\n", sensor->hblank->val); - - dev_dbg(&client->dev, "real timeperframe\t100/%d\n", - sensor->pll.pixel_rate_pixel_array / - ((sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width - + sensor->hblank->val) * - (sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height - + sensor->vblank->val) / 100)); - - return 0; -} - -/* - * - * SMIA++ NVM handling - * - */ - -static int smiapp_read_nvm_page(struct smiapp_sensor *sensor, u32 p, u8 *nvm, - u8 *status) -{ - unsigned int i; - int rval; - u32 s; - - *status = 0; - - rval = ccs_write(sensor, DATA_TRANSFER_IF_1_PAGE_SELECT, p); - if (rval) - return rval; - - rval = ccs_write(sensor, DATA_TRANSFER_IF_1_CTRL, - CCS_DATA_TRANSFER_IF_1_CTRL_ENABLE); - if (rval) - return rval; - - rval = ccs_read(sensor, DATA_TRANSFER_IF_1_STATUS, &s); - if (rval) - return rval; - - if (s & CCS_DATA_TRANSFER_IF_1_STATUS_IMPROPER_IF_USAGE) { - *status = s; - return -ENODATA; - } - - if (CCS_LIM(sensor, DATA_TRANSFER_IF_CAPABILITY) & - CCS_DATA_TRANSFER_IF_CAPABILITY_POLLING) { - for (i = 1000; i > 0; i--) { - if (s & CCS_DATA_TRANSFER_IF_1_STATUS_READ_IF_READY) - break; - - rval = ccs_read(sensor, DATA_TRANSFER_IF_1_STATUS, &s); - if (rval) - return rval; - } - - if (!i) - return -ETIMEDOUT; - } - - for (i = 0; i <= CCS_LIM_DATA_TRANSFER_IF_1_DATA_MAX_P; i++) { - u32 v; - - rval = ccs_read(sensor, DATA_TRANSFER_IF_1_DATA(i), &v); - if (rval) - return rval; - - *nvm++ = v; - } - - return 0; -} - -static int smiapp_read_nvm(struct smiapp_sensor *sensor, unsigned char *nvm, - size_t nvm_size) -{ - u8 status = 0; - u32 p; - int rval = 0, rval2; - - for (p = 0; p < nvm_size / (CCS_LIM_DATA_TRANSFER_IF_1_DATA_MAX_P + 1) - && !rval; p++) { - rval = smiapp_read_nvm_page(sensor, p, nvm, &status); - nvm += CCS_LIM_DATA_TRANSFER_IF_1_DATA_MAX_P + 1; - } - - if (rval == -ENODATA && - status & CCS_DATA_TRANSFER_IF_1_STATUS_IMPROPER_IF_USAGE) - rval = 0; - - rval2 = ccs_write(sensor, DATA_TRANSFER_IF_1_CTRL, 0); - if (rval < 0) - return rval; - else - return rval2 ?: p * (CCS_LIM_DATA_TRANSFER_IF_1_DATA_MAX_P + 1); -} - -/* - * - * SMIA++ CCI address control - * - */ -static int smiapp_change_cci_addr(struct smiapp_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - int rval; - u32 val; - - client->addr = sensor->hwcfg->i2c_addr_dfl; - - rval = ccs_write(sensor, CCI_ADDRESS_CTRL, - sensor->hwcfg->i2c_addr_alt << 1); - if (rval) - return rval; - - client->addr = sensor->hwcfg->i2c_addr_alt; - - /* verify addr change went ok */ - rval = ccs_read(sensor, CCI_ADDRESS_CTRL, &val); - if (rval) - return rval; - - if (val != sensor->hwcfg->i2c_addr_alt << 1) - return -ENODEV; - - return 0; -} - -/* - * - * SMIA++ Mode Control - * - */ -static int smiapp_setup_flash_strobe(struct smiapp_sensor *sensor) -{ - struct smiapp_flash_strobe_parms *strobe_setup; - unsigned int ext_freq = sensor->hwcfg->ext_clk; - u32 tmp; - u32 strobe_adjustment; - u32 strobe_width_high_rs; - int rval; - - strobe_setup = sensor->hwcfg->strobe_setup; - - /* - * How to calculate registers related to strobe length. Please - * do not change, or if you do at least know what you're - * doing. :-) - * - * Sakari Ailus 2010-10-25 - * - * flash_strobe_length [us] / 10^6 = (tFlash_strobe_width_ctrl - * / EXTCLK freq [Hz]) * flash_strobe_adjustment - * - * tFlash_strobe_width_ctrl E N, [1 - 0xffff] - * flash_strobe_adjustment E N, [1 - 0xff] - * - * The formula above is written as below to keep it on one - * line: - * - * l / 10^6 = w / e * a - * - * Let's mark w * a by x: - * - * x = w * a - * - * Thus, we get: - * - * x = l * e / 10^6 - * - * The strobe width must be at least as long as requested, - * thus rounding upwards is needed. - * - * x = (l * e + 10^6 - 1) / 10^6 - * ----------------------------- - * - * Maximum possible accuracy is wanted at all times. Thus keep - * a as small as possible. - * - * Calculate a, assuming maximum w, with rounding upwards: - * - * a = (x + (2^16 - 1) - 1) / (2^16 - 1) - * ------------------------------------- - * - * Thus, we also get w, with that a, with rounding upwards: - * - * w = (x + a - 1) / a - * ------------------- - * - * To get limits: - * - * x E [1, (2^16 - 1) * (2^8 - 1)] - * - * Substituting maximum x to the original formula (with rounding), - * the maximum l is thus - * - * (2^16 - 1) * (2^8 - 1) * 10^6 = l * e + 10^6 - 1 - * - * l = (10^6 * (2^16 - 1) * (2^8 - 1) - 10^6 + 1) / e - * -------------------------------------------------- - * - * flash_strobe_length must be clamped between 1 and - * (10^6 * (2^16 - 1) * (2^8 - 1) - 10^6 + 1) / EXTCLK freq. - * - * Then, - * - * flash_strobe_adjustment = ((flash_strobe_length * - * EXTCLK freq + 10^6 - 1) / 10^6 + (2^16 - 1) - 1) / (2^16 - 1) - * - * tFlash_strobe_width_ctrl = ((flash_strobe_length * - * EXTCLK freq + 10^6 - 1) / 10^6 + - * flash_strobe_adjustment - 1) / flash_strobe_adjustment - */ - tmp = div_u64(1000000ULL * ((1 << 16) - 1) * ((1 << 8) - 1) - - 1000000 + 1, ext_freq); - strobe_setup->strobe_width_high_us = - clamp_t(u32, strobe_setup->strobe_width_high_us, 1, tmp); - - tmp = div_u64(((u64)strobe_setup->strobe_width_high_us * (u64)ext_freq + - 1000000 - 1), 1000000ULL); - strobe_adjustment = (tmp + (1 << 16) - 1 - 1) / ((1 << 16) - 1); - strobe_width_high_rs = (tmp + strobe_adjustment - 1) / - strobe_adjustment; - - rval = ccs_write(sensor, FLASH_MODE_RS, strobe_setup->mode); - if (rval < 0) - goto out; - - rval = ccs_write(sensor, FLASH_STROBE_ADJUSTMENT, strobe_adjustment); - if (rval < 0) - goto out; - - rval = ccs_write(sensor, TFLASH_STROBE_WIDTH_HIGH_RS_CTRL, - strobe_width_high_rs); - if (rval < 0) - goto out; - - rval = ccs_write(sensor, TFLASH_STROBE_DELAY_RS_CTRL, - strobe_setup->strobe_delay); - if (rval < 0) - goto out; - - rval = ccs_write(sensor, FLASH_STROBE_START_POINT, - strobe_setup->stobe_start_point); - if (rval < 0) - goto out; - - rval = ccs_write(sensor, FLASH_TRIGGER_RS, strobe_setup->trigger); - -out: - sensor->hwcfg->strobe_setup->trigger = 0; - - return rval; -} - -/* ----------------------------------------------------------------------------- - * Power management - */ - -static int smiapp_power_on(struct device *dev) -{ - struct v4l2_subdev *subdev = dev_get_drvdata(dev); - struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); - /* - * The sub-device related to the I2C device is always the - * source one, i.e. ssds[0]. - */ - struct smiapp_sensor *sensor = - container_of(ssd, struct smiapp_sensor, ssds[0]); - unsigned int sleep; - int rval; - - rval = regulator_enable(sensor->vana); - if (rval) { - dev_err(dev, "failed to enable vana regulator\n"); - return rval; - } - usleep_range(1000, 1000); - - rval = clk_prepare_enable(sensor->ext_clk); - if (rval < 0) { - dev_dbg(dev, "failed to enable xclk\n"); - goto out_xclk_fail; - } - usleep_range(1000, 1000); - - gpiod_set_value(sensor->xshutdown, 1); - - sleep = SMIAPP_RESET_DELAY(sensor->hwcfg->ext_clk); - usleep_range(sleep, sleep); - - /* - * Failures to respond to the address change command have been noticed. - * Those failures seem to be caused by the sensor requiring a longer - * boot time than advertised. An additional 10ms delay seems to work - * around the issue, but the SMIA++ I2C write retry hack makes the delay - * unnecessary. The failures need to be investigated to find a proper - * fix, and a delay will likely need to be added here if the I2C write - * retry hack is reverted before the root cause of the boot time issue - * is found. - */ - - if (sensor->hwcfg->i2c_addr_alt) { - rval = smiapp_change_cci_addr(sensor); - if (rval) { - dev_err(dev, "cci address change error\n"); - goto out_cci_addr_fail; - } - } - - rval = ccs_write(sensor, SOFTWARE_RESET, CCS_SOFTWARE_RESET_ON); - if (rval < 0) { - dev_err(dev, "software reset failed\n"); - goto out_cci_addr_fail; - } - - if (sensor->hwcfg->i2c_addr_alt) { - rval = smiapp_change_cci_addr(sensor); - if (rval) { - dev_err(dev, "cci address change error\n"); - goto out_cci_addr_fail; - } - } - - rval = ccs_write(sensor, COMPRESSION_MODE, - CCS_COMPRESSION_MODE_DPCM_PCM_SIMPLE); - if (rval) { - dev_err(dev, "compression mode set failed\n"); - goto out_cci_addr_fail; - } - - rval = ccs_write(sensor, EXTCLK_FREQUENCY_MHZ, - sensor->hwcfg->ext_clk / (1000000 / (1 << 8))); - if (rval) { - dev_err(dev, "extclk frequency set failed\n"); - goto out_cci_addr_fail; - } - - rval = ccs_write(sensor, CSI_LANE_MODE, sensor->hwcfg->lanes - 1); - if (rval) { - dev_err(dev, "csi lane mode set failed\n"); - goto out_cci_addr_fail; - } - - rval = ccs_write(sensor, FAST_STANDBY_CTRL, - CCS_FAST_STANDBY_CTRL_FRAME_TRUNCATION); - if (rval) { - dev_err(dev, "fast standby set failed\n"); - goto out_cci_addr_fail; - } - - rval = ccs_write(sensor, CSI_SIGNALING_MODE, - sensor->hwcfg->csi_signalling_mode); - if (rval) { - dev_err(dev, "csi signalling mode set failed\n"); - goto out_cci_addr_fail; - } - - /* DPHY control done by sensor based on requested link rate */ - rval = ccs_write(sensor, PHY_CTRL, CCS_PHY_CTRL_UI); - if (rval < 0) - goto out_cci_addr_fail; - - rval = smiapp_call_quirk(sensor, post_poweron); - if (rval) { - dev_err(dev, "post_poweron quirks failed\n"); - goto out_cci_addr_fail; - } - - return 0; - -out_cci_addr_fail: - gpiod_set_value(sensor->xshutdown, 0); - clk_disable_unprepare(sensor->ext_clk); - -out_xclk_fail: - regulator_disable(sensor->vana); - - return rval; -} - -static int smiapp_power_off(struct device *dev) -{ - struct v4l2_subdev *subdev = dev_get_drvdata(dev); - struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); - struct smiapp_sensor *sensor = - container_of(ssd, struct smiapp_sensor, ssds[0]); - - /* - * Currently power/clock to lens are enable/disabled separately - * but they are essentially the same signals. So if the sensor is - * powered off while the lens is powered on the sensor does not - * really see a power off and next time the cci address change - * will fail. So do a soft reset explicitly here. - */ - if (sensor->hwcfg->i2c_addr_alt) - ccs_write(sensor, SOFTWARE_RESET, CCS_SOFTWARE_RESET_ON); - - gpiod_set_value(sensor->xshutdown, 0); - clk_disable_unprepare(sensor->ext_clk); - usleep_range(5000, 5000); - regulator_disable(sensor->vana); - sensor->streaming = false; - - return 0; -} - -/* ----------------------------------------------------------------------------- - * Video stream management - */ - -static int smiapp_start_streaming(struct smiapp_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - unsigned int binning_mode; - int rval; - - mutex_lock(&sensor->mutex); - - rval = ccs_write(sensor, CSI_DATA_FORMAT, - (sensor->csi_format->width << 8) | - sensor->csi_format->compressed); - if (rval) - goto out; - - /* Binning configuration */ - if (sensor->binning_horizontal == 1 && - sensor->binning_vertical == 1) { - binning_mode = 0; - } else { - u8 binning_type = - (sensor->binning_horizontal << 4) - | sensor->binning_vertical; - - rval = ccs_write(sensor, BINNING_TYPE, binning_type); - if (rval < 0) - goto out; - - binning_mode = 1; - } - rval = ccs_write(sensor, BINNING_MODE, binning_mode); - if (rval < 0) - goto out; - - /* Set up PLL */ - rval = smiapp_pll_configure(sensor); - if (rval) - goto out; - - /* Analog crop start coordinates */ - rval = ccs_write(sensor, X_ADDR_START, - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].left); - if (rval < 0) - goto out; - - rval = ccs_write(sensor, Y_ADDR_START, - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].top); - if (rval < 0) - goto out; - - /* Analog crop end coordinates */ - rval = ccs_write( - sensor, X_ADDR_END, - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].left - + sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width - 1); - if (rval < 0) - goto out; - - rval = ccs_write( - sensor, Y_ADDR_END, - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].top - + sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height - 1); - if (rval < 0) - goto out; - - /* - * Output from pixel array, including blanking, is set using - * controls below. No need to set here. - */ - - /* Digital crop */ - if (CCS_LIM(sensor, DIGITAL_CROP_CAPABILITY) - == CCS_DIGITAL_CROP_CAPABILITY_INPUT_CROP) { - rval = ccs_write( - sensor, DIGITAL_CROP_X_OFFSET, - sensor->scaler->crop[SMIAPP_PAD_SINK].left); - if (rval < 0) - goto out; - - rval = ccs_write( - sensor, DIGITAL_CROP_Y_OFFSET, - sensor->scaler->crop[SMIAPP_PAD_SINK].top); - if (rval < 0) - goto out; - - rval = ccs_write( - sensor, DIGITAL_CROP_IMAGE_WIDTH, - sensor->scaler->crop[SMIAPP_PAD_SINK].width); - if (rval < 0) - goto out; - - rval = ccs_write( - sensor, DIGITAL_CROP_IMAGE_HEIGHT, - sensor->scaler->crop[SMIAPP_PAD_SINK].height); - if (rval < 0) - goto out; - } - - /* Scaling */ - if (CCS_LIM(sensor, SCALING_CAPABILITY) - != CCS_SCALING_CAPABILITY_NONE) { - rval = ccs_write(sensor, SCALING_MODE, sensor->scaling_mode); - if (rval < 0) - goto out; - - rval = ccs_write(sensor, SCALE_M, sensor->scale_m); - if (rval < 0) - goto out; - } - - /* Output size from sensor */ - rval = ccs_write(sensor, X_OUTPUT_SIZE, - sensor->src->crop[SMIAPP_PAD_SRC].width); - if (rval < 0) - goto out; - rval = ccs_write(sensor, Y_OUTPUT_SIZE, - sensor->src->crop[SMIAPP_PAD_SRC].height); - if (rval < 0) - goto out; - - if (CCS_LIM(sensor, FLASH_MODE_CAPABILITY) & - (CCS_FLASH_MODE_CAPABILITY_SINGLE_STROBE | - SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE) && - sensor->hwcfg->strobe_setup != NULL && - sensor->hwcfg->strobe_setup->trigger != 0) { - rval = smiapp_setup_flash_strobe(sensor); - if (rval) - goto out; - } - - rval = smiapp_call_quirk(sensor, pre_streamon); - if (rval) { - dev_err(&client->dev, "pre_streamon quirks failed\n"); - goto out; - } - - rval = ccs_write(sensor, MODE_SELECT, CCS_MODE_SELECT_STREAMING); - -out: - mutex_unlock(&sensor->mutex); - - return rval; -} - -static int smiapp_stop_streaming(struct smiapp_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - int rval; - - mutex_lock(&sensor->mutex); - rval = ccs_write(sensor, MODE_SELECT, CCS_MODE_SELECT_SOFTWARE_STANDBY); - if (rval) - goto out; - - rval = smiapp_call_quirk(sensor, post_streamoff); - if (rval) - dev_err(&client->dev, "post_streamoff quirks failed\n"); - -out: - mutex_unlock(&sensor->mutex); - return rval; -} - -/* ----------------------------------------------------------------------------- - * V4L2 subdev video operations - */ - -static int smiapp_pm_get_init(struct smiapp_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - int rval; - - rval = pm_runtime_get_sync(&client->dev); - if (rval < 0) { - if (rval != -EBUSY && rval != -EAGAIN) - pm_runtime_set_active(&client->dev); - pm_runtime_put_noidle(&client->dev); - - return rval; - } else if (!rval) { - rval = v4l2_ctrl_handler_setup(&sensor->pixel_array-> - ctrl_handler); - if (rval) - return rval; - - return v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler); - } - - return 0; -} - -static int smiapp_set_stream(struct v4l2_subdev *subdev, int enable) -{ - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - int rval; - - if (sensor->streaming == enable) - return 0; - - if (!enable) { - smiapp_stop_streaming(sensor); - sensor->streaming = false; - pm_runtime_mark_last_busy(&client->dev); - pm_runtime_put_autosuspend(&client->dev); - - return 0; - } - - rval = smiapp_pm_get_init(sensor); - if (rval) - return rval; - - sensor->streaming = true; - - rval = smiapp_start_streaming(sensor); - if (rval < 0) { - sensor->streaming = false; - pm_runtime_mark_last_busy(&client->dev); - pm_runtime_put_autosuspend(&client->dev); - } - - return rval; -} - -static int smiapp_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - struct i2c_client *client = v4l2_get_subdevdata(subdev); - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - unsigned int i; - int idx = -1; - int rval = -EINVAL; - - mutex_lock(&sensor->mutex); - - dev_err(&client->dev, "subdev %s, pad %d, index %d\n", - subdev->name, code->pad, code->index); - - if (subdev != &sensor->src->sd || code->pad != SMIAPP_PAD_SRC) { - if (code->index) - goto out; - - code->code = sensor->internal_csi_format->code; - rval = 0; - goto out; - } - - for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) { - if (sensor->mbus_frame_fmts & (1 << i)) - idx++; - - if (idx == code->index) { - code->code = smiapp_csi_data_formats[i].code; - dev_err(&client->dev, "found index %d, i %d, code %x\n", - code->index, i, code->code); - rval = 0; - break; - } - } - -out: - mutex_unlock(&sensor->mutex); - - return rval; -} - -static u32 __smiapp_get_mbus_code(struct v4l2_subdev *subdev, - unsigned int pad) -{ - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - - if (subdev == &sensor->src->sd && pad == SMIAPP_PAD_SRC) - return sensor->csi_format->code; - else - return sensor->internal_csi_format->code; -} - -static int __smiapp_get_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); - - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - fmt->format = *v4l2_subdev_get_try_format(subdev, cfg, - fmt->pad); - } else { - struct v4l2_rect *r; - - if (fmt->pad == ssd->source_pad) - r = &ssd->crop[ssd->source_pad]; - else - r = &ssd->sink_fmt; - - fmt->format.code = __smiapp_get_mbus_code(subdev, fmt->pad); - fmt->format.width = r->width; - fmt->format.height = r->height; - fmt->format.field = V4L2_FIELD_NONE; - } - - return 0; -} - -static int smiapp_get_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - int rval; - - mutex_lock(&sensor->mutex); - rval = __smiapp_get_format(subdev, cfg, fmt); - mutex_unlock(&sensor->mutex); - - return rval; -} - -static void smiapp_get_crop_compose(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_rect **crops, - struct v4l2_rect **comps, int which) -{ - struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); - unsigned int i; - - if (which == V4L2_SUBDEV_FORMAT_ACTIVE) { - if (crops) - for (i = 0; i < subdev->entity.num_pads; i++) - crops[i] = &ssd->crop[i]; - if (comps) - *comps = &ssd->compose; - } else { - if (crops) { - for (i = 0; i < subdev->entity.num_pads; i++) { - crops[i] = v4l2_subdev_get_try_crop(subdev, cfg, i); - BUG_ON(!crops[i]); - } - } - if (comps) { - *comps = v4l2_subdev_get_try_compose(subdev, cfg, - SMIAPP_PAD_SINK); - BUG_ON(!*comps); - } - } -} - -/* Changes require propagation only on sink pad. */ -static void smiapp_propagate(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, int which, - int target) -{ - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); - struct v4l2_rect *comp, *crops[SMIAPP_PADS]; - - smiapp_get_crop_compose(subdev, cfg, crops, &comp, which); - - switch (target) { - case V4L2_SEL_TGT_CROP: - comp->width = crops[SMIAPP_PAD_SINK]->width; - comp->height = crops[SMIAPP_PAD_SINK]->height; - if (which == V4L2_SUBDEV_FORMAT_ACTIVE) { - if (ssd == sensor->scaler) { - sensor->scale_m = - CCS_LIM(sensor, SCALER_N_MIN); - sensor->scaling_mode = - CCS_SCALING_MODE_NO_SCALING; - } else if (ssd == sensor->binner) { - sensor->binning_horizontal = 1; - sensor->binning_vertical = 1; - } - } - fallthrough; - case V4L2_SEL_TGT_COMPOSE: - *crops[SMIAPP_PAD_SRC] = *comp; - break; - default: - BUG(); - } -} - -static const struct smiapp_csi_data_format -*smiapp_validate_csi_data_format(struct smiapp_sensor *sensor, u32 code) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) { - if (sensor->mbus_frame_fmts & (1 << i) - && smiapp_csi_data_formats[i].code == code) - return &smiapp_csi_data_formats[i]; - } - - return sensor->csi_format; -} - -static int smiapp_set_format_source(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - const struct smiapp_csi_data_format *csi_format, - *old_csi_format = sensor->csi_format; - unsigned long *valid_link_freqs; - u32 code = fmt->format.code; - unsigned int i; - int rval; - - rval = __smiapp_get_format(subdev, cfg, fmt); - if (rval) - return rval; - - /* - * Media bus code is changeable on src subdev's source pad. On - * other source pads we just get format here. - */ - if (subdev != &sensor->src->sd) - return 0; - - csi_format = smiapp_validate_csi_data_format(sensor, code); - - fmt->format.code = csi_format->code; - - if (fmt->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return 0; - - sensor->csi_format = csi_format; - - if (csi_format->width != old_csi_format->width) - for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) - __v4l2_ctrl_modify_range( - sensor->test_data[i], 0, - (1 << csi_format->width) - 1, 1, 0); - - if (csi_format->compressed == old_csi_format->compressed) - return 0; - - valid_link_freqs = - &sensor->valid_link_freqs[sensor->csi_format->compressed - - sensor->compressed_min_bpp]; - - __v4l2_ctrl_modify_range( - sensor->link_freq, 0, - __fls(*valid_link_freqs), ~*valid_link_freqs, - __ffs(*valid_link_freqs)); - - return smiapp_pll_update(sensor); -} - -static int smiapp_set_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); - struct v4l2_rect *crops[SMIAPP_PADS]; - - mutex_lock(&sensor->mutex); - - if (fmt->pad == ssd->source_pad) { - int rval; - - rval = smiapp_set_format_source(subdev, cfg, fmt); - - mutex_unlock(&sensor->mutex); - - return rval; - } - - /* Sink pad. Width and height are changeable here. */ - fmt->format.code = __smiapp_get_mbus_code(subdev, fmt->pad); - fmt->format.width &= ~1; - fmt->format.height &= ~1; - fmt->format.field = V4L2_FIELD_NONE; - - fmt->format.width = - clamp(fmt->format.width, - CCS_LIM(sensor, MIN_X_OUTPUT_SIZE), - CCS_LIM(sensor, MAX_X_OUTPUT_SIZE)); - fmt->format.height = - clamp(fmt->format.height, - CCS_LIM(sensor, MIN_Y_OUTPUT_SIZE), - CCS_LIM(sensor, MAX_Y_OUTPUT_SIZE)); - - smiapp_get_crop_compose(subdev, cfg, crops, NULL, fmt->which); - - crops[ssd->sink_pad]->left = 0; - crops[ssd->sink_pad]->top = 0; - crops[ssd->sink_pad]->width = fmt->format.width; - crops[ssd->sink_pad]->height = fmt->format.height; - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) - ssd->sink_fmt = *crops[ssd->sink_pad]; - smiapp_propagate(subdev, cfg, fmt->which, - V4L2_SEL_TGT_CROP); - - mutex_unlock(&sensor->mutex); - - return 0; -} - -/* - * Calculate goodness of scaled image size compared to expected image - * size and flags provided. - */ -#define SCALING_GOODNESS 100000 -#define SCALING_GOODNESS_EXTREME 100000000 -static int scaling_goodness(struct v4l2_subdev *subdev, int w, int ask_w, - int h, int ask_h, u32 flags) -{ - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - struct i2c_client *client = v4l2_get_subdevdata(subdev); - int val = 0; - - w &= ~1; - ask_w &= ~1; - h &= ~1; - ask_h &= ~1; - - if (flags & V4L2_SEL_FLAG_GE) { - if (w < ask_w) - val -= SCALING_GOODNESS; - if (h < ask_h) - val -= SCALING_GOODNESS; - } - - if (flags & V4L2_SEL_FLAG_LE) { - if (w > ask_w) - val -= SCALING_GOODNESS; - if (h > ask_h) - val -= SCALING_GOODNESS; - } - - val -= abs(w - ask_w); - val -= abs(h - ask_h); - - if (w < CCS_LIM(sensor, MIN_X_OUTPUT_SIZE)) - val -= SCALING_GOODNESS_EXTREME; - - dev_dbg(&client->dev, "w %d ask_w %d h %d ask_h %d goodness %d\n", - w, ask_w, h, ask_h, val); - - return val; -} - -static void smiapp_set_compose_binner(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel, - struct v4l2_rect **crops, - struct v4l2_rect *comp) -{ - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - unsigned int i; - unsigned int binh = 1, binv = 1; - int best = scaling_goodness( - subdev, - crops[SMIAPP_PAD_SINK]->width, sel->r.width, - crops[SMIAPP_PAD_SINK]->height, sel->r.height, sel->flags); - - for (i = 0; i < sensor->nbinning_subtypes; i++) { - int this = scaling_goodness( - subdev, - crops[SMIAPP_PAD_SINK]->width - / sensor->binning_subtypes[i].horizontal, - sel->r.width, - crops[SMIAPP_PAD_SINK]->height - / sensor->binning_subtypes[i].vertical, - sel->r.height, sel->flags); - - if (this > best) { - binh = sensor->binning_subtypes[i].horizontal; - binv = sensor->binning_subtypes[i].vertical; - best = this; - } - } - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - sensor->binning_vertical = binv; - sensor->binning_horizontal = binh; - } - - sel->r.width = (crops[SMIAPP_PAD_SINK]->width / binh) & ~1; - sel->r.height = (crops[SMIAPP_PAD_SINK]->height / binv) & ~1; -} - -/* - * Calculate best scaling ratio and mode for given output resolution. - * - * Try all of these: horizontal ratio, vertical ratio and smallest - * size possible (horizontally). - * - * Also try whether horizontal scaler or full scaler gives a better - * result. - */ -static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel, - struct v4l2_rect **crops, - struct v4l2_rect *comp) -{ - struct i2c_client *client = v4l2_get_subdevdata(subdev); - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - u32 min, max, a, b, max_m; - u32 scale_m = CCS_LIM(sensor, SCALER_N_MIN); - int mode = CCS_SCALING_MODE_HORIZONTAL; - u32 try[4]; - u32 ntry = 0; - unsigned int i; - int best = INT_MIN; - - sel->r.width = min_t(unsigned int, sel->r.width, - crops[SMIAPP_PAD_SINK]->width); - sel->r.height = min_t(unsigned int, sel->r.height, - crops[SMIAPP_PAD_SINK]->height); - - a = crops[SMIAPP_PAD_SINK]->width - * CCS_LIM(sensor, SCALER_N_MIN) / sel->r.width; - b = crops[SMIAPP_PAD_SINK]->height - * CCS_LIM(sensor, SCALER_N_MIN) / sel->r.height; - max_m = crops[SMIAPP_PAD_SINK]->width - * CCS_LIM(sensor, SCALER_N_MIN) - / CCS_LIM(sensor, MIN_X_OUTPUT_SIZE); - - a = clamp(a, CCS_LIM(sensor, SCALER_M_MIN), - CCS_LIM(sensor, SCALER_M_MAX)); - b = clamp(b, CCS_LIM(sensor, SCALER_M_MIN), - CCS_LIM(sensor, SCALER_M_MAX)); - max_m = clamp(max_m, CCS_LIM(sensor, SCALER_M_MIN), - CCS_LIM(sensor, SCALER_M_MAX)); - - dev_dbg(&client->dev, "scaling: a %d b %d max_m %d\n", a, b, max_m); - - min = min(max_m, min(a, b)); - max = min(max_m, max(a, b)); - - try[ntry] = min; - ntry++; - if (min != max) { - try[ntry] = max; - ntry++; - } - if (max != max_m) { - try[ntry] = min + 1; - ntry++; - if (min != max) { - try[ntry] = max + 1; - ntry++; - } - } - - for (i = 0; i < ntry; i++) { - int this = scaling_goodness( - subdev, - crops[SMIAPP_PAD_SINK]->width - / try[i] * CCS_LIM(sensor, SCALER_N_MIN), - sel->r.width, - crops[SMIAPP_PAD_SINK]->height, - sel->r.height, - sel->flags); - - dev_dbg(&client->dev, "trying factor %d (%d)\n", try[i], i); - - if (this > best) { - scale_m = try[i]; - mode = CCS_SCALING_MODE_HORIZONTAL; - best = this; - } - - if (CCS_LIM(sensor, SCALING_CAPABILITY) - == CCS_SCALING_CAPABILITY_HORIZONTAL) - continue; - - this = scaling_goodness( - subdev, crops[SMIAPP_PAD_SINK]->width - / try[i] - * CCS_LIM(sensor, SCALER_N_MIN), - sel->r.width, - crops[SMIAPP_PAD_SINK]->height - / try[i] - * CCS_LIM(sensor, SCALER_N_MIN), - sel->r.height, - sel->flags); - - if (this > best) { - scale_m = try[i]; - mode = SMIAPP_SCALING_MODE_BOTH; - best = this; - } - } - - sel->r.width = - (crops[SMIAPP_PAD_SINK]->width - / scale_m - * CCS_LIM(sensor, SCALER_N_MIN)) & ~1; - if (mode == SMIAPP_SCALING_MODE_BOTH) - sel->r.height = - (crops[SMIAPP_PAD_SINK]->height - / scale_m - * CCS_LIM(sensor, SCALER_N_MIN)) - & ~1; - else - sel->r.height = crops[SMIAPP_PAD_SINK]->height; - - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - sensor->scale_m = scale_m; - sensor->scaling_mode = mode; - } -} -/* We're only called on source pads. This function sets scaling. */ -static int smiapp_set_compose(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); - struct v4l2_rect *comp, *crops[SMIAPP_PADS]; - - smiapp_get_crop_compose(subdev, cfg, crops, &comp, sel->which); - - sel->r.top = 0; - sel->r.left = 0; - - if (ssd == sensor->binner) - smiapp_set_compose_binner(subdev, cfg, sel, crops, comp); - else - smiapp_set_compose_scaler(subdev, cfg, sel, crops, comp); - - *comp = sel->r; - smiapp_propagate(subdev, cfg, sel->which, V4L2_SEL_TGT_COMPOSE); - - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) - return smiapp_pll_blanking_update(sensor); - - return 0; -} - -static int __smiapp_sel_supported(struct v4l2_subdev *subdev, - struct v4l2_subdev_selection *sel) -{ - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); - - /* We only implement crop in three places. */ - switch (sel->target) { - case V4L2_SEL_TGT_CROP: - case V4L2_SEL_TGT_CROP_BOUNDS: - if (ssd == sensor->pixel_array - && sel->pad == SMIAPP_PA_PAD_SRC) - return 0; - if (ssd == sensor->src - && sel->pad == SMIAPP_PAD_SRC) - return 0; - if (ssd == sensor->scaler && sel->pad == SMIAPP_PAD_SINK && - CCS_LIM(sensor, DIGITAL_CROP_CAPABILITY) - == CCS_DIGITAL_CROP_CAPABILITY_INPUT_CROP) - return 0; - return -EINVAL; - case V4L2_SEL_TGT_NATIVE_SIZE: - if (ssd == sensor->pixel_array - && sel->pad == SMIAPP_PA_PAD_SRC) - return 0; - return -EINVAL; - case V4L2_SEL_TGT_COMPOSE: - case V4L2_SEL_TGT_COMPOSE_BOUNDS: - if (sel->pad == ssd->source_pad) - return -EINVAL; - if (ssd == sensor->binner) - return 0; - if (ssd == sensor->scaler && CCS_LIM(sensor, SCALING_CAPABILITY) - != CCS_SCALING_CAPABILITY_NONE) - return 0; - fallthrough; - default: - return -EINVAL; - } -} - -static int smiapp_set_crop(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); - struct v4l2_rect *src_size, *crops[SMIAPP_PADS]; - struct v4l2_rect _r; - - smiapp_get_crop_compose(subdev, cfg, crops, NULL, sel->which); - - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - if (sel->pad == ssd->sink_pad) - src_size = &ssd->sink_fmt; - else - src_size = &ssd->compose; - } else { - if (sel->pad == ssd->sink_pad) { - _r.left = 0; - _r.top = 0; - _r.width = v4l2_subdev_get_try_format(subdev, cfg, sel->pad) - ->width; - _r.height = v4l2_subdev_get_try_format(subdev, cfg, sel->pad) - ->height; - src_size = &_r; - } else { - src_size = v4l2_subdev_get_try_compose( - subdev, cfg, ssd->sink_pad); - } - } - - if (ssd == sensor->src && sel->pad == SMIAPP_PAD_SRC) { - sel->r.left = 0; - sel->r.top = 0; - } - - sel->r.width = min(sel->r.width, src_size->width); - sel->r.height = min(sel->r.height, src_size->height); - - sel->r.left = min_t(int, sel->r.left, src_size->width - sel->r.width); - sel->r.top = min_t(int, sel->r.top, src_size->height - sel->r.height); - - *crops[sel->pad] = sel->r; - - if (ssd != sensor->pixel_array && sel->pad == SMIAPP_PAD_SINK) - smiapp_propagate(subdev, cfg, sel->which, - V4L2_SEL_TGT_CROP); - - return 0; -} - -static void smiapp_get_native_size(struct smiapp_subdev *ssd, - struct v4l2_rect *r) -{ - r->top = 0; - r->left = 0; - r->width = CCS_LIM(ssd->sensor, X_ADDR_MAX) + 1; - r->height = CCS_LIM(ssd->sensor, Y_ADDR_MAX) + 1; -} - -static int __smiapp_get_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); - struct v4l2_rect *comp, *crops[SMIAPP_PADS]; - struct v4l2_rect sink_fmt; - int ret; - - ret = __smiapp_sel_supported(subdev, sel); - if (ret) - return ret; - - smiapp_get_crop_compose(subdev, cfg, crops, &comp, sel->which); - - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - sink_fmt = ssd->sink_fmt; - } else { - struct v4l2_mbus_framefmt *fmt = - v4l2_subdev_get_try_format(subdev, cfg, ssd->sink_pad); - - sink_fmt.left = 0; - sink_fmt.top = 0; - sink_fmt.width = fmt->width; - sink_fmt.height = fmt->height; - } - - switch (sel->target) { - case V4L2_SEL_TGT_CROP_BOUNDS: - case V4L2_SEL_TGT_NATIVE_SIZE: - if (ssd == sensor->pixel_array) - smiapp_get_native_size(ssd, &sel->r); - else if (sel->pad == ssd->sink_pad) - sel->r = sink_fmt; - else - sel->r = *comp; - break; - case V4L2_SEL_TGT_CROP: - case V4L2_SEL_TGT_COMPOSE_BOUNDS: - sel->r = *crops[sel->pad]; - break; - case V4L2_SEL_TGT_COMPOSE: - sel->r = *comp; - break; - } - - return 0; -} - -static int smiapp_get_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - int rval; - - mutex_lock(&sensor->mutex); - rval = __smiapp_get_selection(subdev, cfg, sel); - mutex_unlock(&sensor->mutex); - - return rval; -} -static int smiapp_set_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - int ret; - - ret = __smiapp_sel_supported(subdev, sel); - if (ret) - return ret; - - mutex_lock(&sensor->mutex); - - sel->r.left = max(0, sel->r.left & ~1); - sel->r.top = max(0, sel->r.top & ~1); - sel->r.width = SMIAPP_ALIGN_DIM(sel->r.width, sel->flags); - sel->r.height = SMIAPP_ALIGN_DIM(sel->r.height, sel->flags); - - sel->r.width = max_t(unsigned int, - CCS_LIM(sensor, MIN_X_OUTPUT_SIZE), - sel->r.width); - sel->r.height = max_t(unsigned int, - CCS_LIM(sensor, MIN_Y_OUTPUT_SIZE), - sel->r.height); - - switch (sel->target) { - case V4L2_SEL_TGT_CROP: - ret = smiapp_set_crop(subdev, cfg, sel); - break; - case V4L2_SEL_TGT_COMPOSE: - ret = smiapp_set_compose(subdev, cfg, sel); - break; - default: - ret = -EINVAL; - } - - mutex_unlock(&sensor->mutex); - return ret; -} - -static int smiapp_get_skip_frames(struct v4l2_subdev *subdev, u32 *frames) -{ - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - - *frames = sensor->frame_skip; - return 0; -} - -static int smiapp_get_skip_top_lines(struct v4l2_subdev *subdev, u32 *lines) -{ - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - - *lines = sensor->image_start; - - return 0; -} - -/* ----------------------------------------------------------------------------- - * sysfs attributes - */ - -static ssize_t -smiapp_sysfs_nvm_read(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct v4l2_subdev *subdev = i2c_get_clientdata(to_i2c_client(dev)); - struct i2c_client *client = v4l2_get_subdevdata(subdev); - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - int rval; - - if (!sensor->dev_init_done) - return -EBUSY; - - rval = smiapp_pm_get_init(sensor); - if (rval < 0) - return -ENODEV; - - rval = smiapp_read_nvm(sensor, buf, PAGE_SIZE); - if (rval < 0) { - pm_runtime_put(&client->dev); - dev_err(&client->dev, "nvm read failed\n"); - return -ENODEV; - } - - pm_runtime_mark_last_busy(&client->dev); - pm_runtime_put_autosuspend(&client->dev); - - /* - * NVM is still way below a PAGE_SIZE, so we can safely - * assume this for now. - */ - return rval; -} -static DEVICE_ATTR(nvm, S_IRUGO, smiapp_sysfs_nvm_read, NULL); - -static ssize_t -smiapp_sysfs_ident_read(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct v4l2_subdev *subdev = i2c_get_clientdata(to_i2c_client(dev)); - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - struct smiapp_module_info *minfo = &sensor->minfo; - - if (minfo->mipi_manufacturer_id) - return snprintf(buf, PAGE_SIZE, "%4.4x%4.4x%2.2x\n", - minfo->mipi_manufacturer_id, minfo->model_id, - minfo->revision_number_major) + 1; - else - return snprintf(buf, PAGE_SIZE, "%2.2x%4.4x%2.2x\n", - minfo->smia_manufacturer_id, minfo->model_id, - minfo->revision_number_major) + 1; -} - -static DEVICE_ATTR(ident, S_IRUGO, smiapp_sysfs_ident_read, NULL); - -/* ----------------------------------------------------------------------------- - * V4L2 subdev core operations - */ - -static int smiapp_identify_module(struct smiapp_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - struct smiapp_module_info *minfo = &sensor->minfo; - unsigned int i; - int rval = 0; - - minfo->name = SMIAPP_NAME; - - /* Module info */ - rval = ccs_read(sensor, MODULE_MANUFACTURER_ID, - &minfo->mipi_manufacturer_id); - if (!rval && !minfo->mipi_manufacturer_id) - rval = ccs_read_addr_8only(sensor, - SMIAPP_REG_U8_MANUFACTURER_ID, - &minfo->smia_manufacturer_id); - if (!rval) - rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_MODEL_ID, - &minfo->model_id); - if (!rval) - rval = ccs_read_addr_8only(sensor, - CCS_R_MODULE_REVISION_NUMBER_MAJOR, - &minfo->revision_number_major); - if (!rval) - rval = ccs_read_addr_8only(sensor, - CCS_R_MODULE_REVISION_NUMBER_MINOR, - &minfo->revision_number_minor); - if (!rval) - rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_YEAR, - &minfo->module_year); - if (!rval) - rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_MONTH, - &minfo->module_month); - if (!rval) - rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_DAY, - &minfo->module_day); - - /* Sensor info */ - if (!rval) - rval = ccs_read(sensor, SENSOR_MANUFACTURER_ID, - &minfo->sensor_mipi_manufacturer_id); - if (!rval && !minfo->sensor_mipi_manufacturer_id) - rval = ccs_read_addr_8only(sensor, - CCS_R_SENSOR_MANUFACTURER_ID, - &minfo->sensor_smia_manufacturer_id); - if (!rval) - rval = ccs_read_addr_8only(sensor, - CCS_R_SENSOR_MODEL_ID, - &minfo->sensor_model_id); - if (!rval) - rval = ccs_read_addr_8only(sensor, - CCS_R_SENSOR_REVISION_NUMBER, - &minfo->sensor_revision_number); - if (!rval) - rval = ccs_read_addr_8only(sensor, - CCS_R_SENSOR_FIRMWARE_VERSION, - &minfo->sensor_firmware_version); - - /* SMIA */ - if (!rval) - rval = ccs_read(sensor, MIPI_CCS_VERSION, &minfo->ccs_version); - if (!rval && !minfo->ccs_version) - rval = ccs_read_addr_8only(sensor, SMIAPP_REG_U8_SMIA_VERSION, - &minfo->smia_version); - if (!rval && !minfo->ccs_version) - rval = ccs_read_addr_8only(sensor, SMIAPP_REG_U8_SMIAPP_VERSION, - &minfo->smiapp_version); - - if (rval) { - dev_err(&client->dev, "sensor detection failed\n"); - return -ENODEV; - } - - if (minfo->mipi_manufacturer_id) - dev_dbg(&client->dev, "MIPI CCS module 0x%4.4x-0x%4.4x\n", - minfo->mipi_manufacturer_id, minfo->model_id); - else - dev_dbg(&client->dev, "SMIA module 0x%2.2x-0x%4.4x\n", - minfo->smia_manufacturer_id, minfo->model_id); - - dev_dbg(&client->dev, - "module revision 0x%2.2x-0x%2.2x date %2.2d-%2.2d-%2.2d\n", - minfo->revision_number_major, minfo->revision_number_minor, - minfo->module_year, minfo->module_month, minfo->module_day); - - if (minfo->sensor_mipi_manufacturer_id) - dev_dbg(&client->dev, "MIPI CCS sensor 0x%4.4x-0x%4.4x\n", - minfo->sensor_mipi_manufacturer_id, - minfo->sensor_model_id); - else - dev_dbg(&client->dev, "SMIA sensor 0x%2.2x-0x%4.4x\n", - minfo->sensor_smia_manufacturer_id, - minfo->sensor_model_id); - - dev_dbg(&client->dev, - "sensor revision 0x%2.2x firmware version 0x%2.2x\n", - minfo->sensor_revision_number, minfo->sensor_firmware_version); - - if (minfo->ccs_version) - dev_dbg(&client->dev, "MIPI CCS version %u.%u", - (minfo->ccs_version & CCS_MIPI_CCS_VERSION_MAJOR_MASK) - >> CCS_MIPI_CCS_VERSION_MAJOR_SHIFT, - (minfo->ccs_version & CCS_MIPI_CCS_VERSION_MINOR_MASK)); - else - dev_dbg(&client->dev, - "smia version %2.2d smiapp version %2.2d\n", - minfo->smia_version, minfo->smiapp_version); - - /* - * Some modules have bad data in the lvalues below. Hope the - * rvalues have better stuff. The lvalues are module - * parameters whereas the rvalues are sensor parameters. - */ - if (minfo->sensor_smia_manufacturer_id && - !minfo->smia_manufacturer_id && !minfo->model_id) { - minfo->smia_manufacturer_id = - minfo->sensor_smia_manufacturer_id; - minfo->model_id = minfo->sensor_model_id; - minfo->revision_number_major = minfo->sensor_revision_number; - } - - for (i = 0; i < ARRAY_SIZE(smiapp_module_idents); i++) { - if (smiapp_module_idents[i].mipi_manufacturer_id && - smiapp_module_idents[i].mipi_manufacturer_id - != minfo->mipi_manufacturer_id) - continue; - if (smiapp_module_idents[i].smia_manufacturer_id && - smiapp_module_idents[i].smia_manufacturer_id - != minfo->smia_manufacturer_id) - continue; - if (smiapp_module_idents[i].model_id != minfo->model_id) - continue; - if (smiapp_module_idents[i].flags - & SMIAPP_MODULE_IDENT_FLAG_REV_LE) { - if (smiapp_module_idents[i].revision_number_major - < minfo->revision_number_major) - continue; - } else { - if (smiapp_module_idents[i].revision_number_major - != minfo->revision_number_major) - continue; - } - - minfo->name = smiapp_module_idents[i].name; - minfo->quirk = smiapp_module_idents[i].quirk; - break; - } - - if (i >= ARRAY_SIZE(smiapp_module_idents)) - dev_warn(&client->dev, - "no quirks for this module; let's hope it's fully compliant\n"); - - dev_dbg(&client->dev, "the sensor is called %s\n", - minfo->name); - - return 0; -} - -static const struct v4l2_subdev_ops smiapp_ops; -static const struct v4l2_subdev_internal_ops smiapp_internal_ops; -static const struct media_entity_operations smiapp_entity_ops; - -static int smiapp_register_subdev(struct smiapp_sensor *sensor, - struct smiapp_subdev *ssd, - struct smiapp_subdev *sink_ssd, - u16 source_pad, u16 sink_pad, u32 link_flags) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - int rval; - - if (!sink_ssd) - return 0; - - rval = media_entity_pads_init(&ssd->sd.entity, - ssd->npads, ssd->pads); - if (rval) { - dev_err(&client->dev, - "media_entity_pads_init failed\n"); - return rval; - } - - rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev, - &ssd->sd); - if (rval) { - dev_err(&client->dev, - "v4l2_device_register_subdev failed\n"); - return rval; - } - - rval = media_create_pad_link(&ssd->sd.entity, source_pad, - &sink_ssd->sd.entity, sink_pad, - link_flags); - if (rval) { - dev_err(&client->dev, - "media_create_pad_link failed\n"); - v4l2_device_unregister_subdev(&ssd->sd); - return rval; - } - - return 0; -} - -static void smiapp_unregistered(struct v4l2_subdev *subdev) -{ - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - unsigned int i; - - for (i = 1; i < sensor->ssds_used; i++) - v4l2_device_unregister_subdev(&sensor->ssds[i].sd); -} - -static int smiapp_registered(struct v4l2_subdev *subdev) -{ - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - int rval; - - if (sensor->scaler) { - rval = smiapp_register_subdev( - sensor, sensor->binner, sensor->scaler, - SMIAPP_PAD_SRC, SMIAPP_PAD_SINK, - MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); - if (rval < 0) - return rval; - } - - rval = smiapp_register_subdev( - sensor, sensor->pixel_array, sensor->binner, - SMIAPP_PA_PAD_SRC, SMIAPP_PAD_SINK, - MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); - if (rval) - goto out_err; - - return 0; - -out_err: - smiapp_unregistered(subdev); - - return rval; -} - -static void smiapp_cleanup(struct smiapp_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - - device_remove_file(&client->dev, &dev_attr_nvm); - device_remove_file(&client->dev, &dev_attr_ident); - - smiapp_free_controls(sensor); -} - -static void smiapp_create_subdev(struct smiapp_sensor *sensor, - struct smiapp_subdev *ssd, const char *name, - unsigned short num_pads) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - - if (!ssd) - return; - - if (ssd != sensor->src) - v4l2_subdev_init(&ssd->sd, &smiapp_ops); - - ssd->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - ssd->sensor = sensor; - - ssd->npads = num_pads; - ssd->source_pad = num_pads - 1; - - v4l2_i2c_subdev_set_name(&ssd->sd, client, sensor->minfo.name, name); - - smiapp_get_native_size(ssd, &ssd->sink_fmt); - - ssd->compose.width = ssd->sink_fmt.width; - ssd->compose.height = ssd->sink_fmt.height; - ssd->crop[ssd->source_pad] = ssd->compose; - ssd->pads[ssd->source_pad].flags = MEDIA_PAD_FL_SOURCE; - if (ssd != sensor->pixel_array) { - ssd->crop[ssd->sink_pad] = ssd->compose; - ssd->pads[ssd->sink_pad].flags = MEDIA_PAD_FL_SINK; - } - - ssd->sd.entity.ops = &smiapp_entity_ops; - - if (ssd == sensor->src) - return; - - ssd->sd.internal_ops = &smiapp_internal_ops; - ssd->sd.owner = THIS_MODULE; - ssd->sd.dev = &client->dev; - v4l2_set_subdevdata(&ssd->sd, client); -} - -static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - struct smiapp_subdev *ssd = to_smiapp_subdev(sd); - struct smiapp_sensor *sensor = ssd->sensor; - unsigned int i; - - mutex_lock(&sensor->mutex); - - for (i = 0; i < ssd->npads; i++) { - struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_get_try_format(sd, fh->pad, i); - struct v4l2_rect *try_crop = - v4l2_subdev_get_try_crop(sd, fh->pad, i); - struct v4l2_rect *try_comp; - - smiapp_get_native_size(ssd, try_crop); - - try_fmt->width = try_crop->width; - try_fmt->height = try_crop->height; - try_fmt->code = sensor->internal_csi_format->code; - try_fmt->field = V4L2_FIELD_NONE; - - if (ssd != sensor->pixel_array) - continue; - - try_comp = v4l2_subdev_get_try_compose(sd, fh->pad, i); - *try_comp = *try_crop; - } - - mutex_unlock(&sensor->mutex); - - return 0; -} - -static const struct v4l2_subdev_video_ops smiapp_video_ops = { - .s_stream = smiapp_set_stream, -}; - -static const struct v4l2_subdev_pad_ops smiapp_pad_ops = { - .enum_mbus_code = smiapp_enum_mbus_code, - .get_fmt = smiapp_get_format, - .set_fmt = smiapp_set_format, - .get_selection = smiapp_get_selection, - .set_selection = smiapp_set_selection, -}; - -static const struct v4l2_subdev_sensor_ops smiapp_sensor_ops = { - .g_skip_frames = smiapp_get_skip_frames, - .g_skip_top_lines = smiapp_get_skip_top_lines, -}; - -static const struct v4l2_subdev_ops smiapp_ops = { - .video = &smiapp_video_ops, - .pad = &smiapp_pad_ops, - .sensor = &smiapp_sensor_ops, -}; - -static const struct media_entity_operations smiapp_entity_ops = { - .link_validate = v4l2_subdev_link_validate, -}; - -static const struct v4l2_subdev_internal_ops smiapp_internal_src_ops = { - .registered = smiapp_registered, - .unregistered = smiapp_unregistered, - .open = smiapp_open, -}; - -static const struct v4l2_subdev_internal_ops smiapp_internal_ops = { - .open = smiapp_open, -}; - -/* ----------------------------------------------------------------------------- - * I2C Driver - */ - -static int __maybe_unused smiapp_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *subdev = i2c_get_clientdata(client); - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - bool streaming = sensor->streaming; - int rval; - - rval = pm_runtime_get_sync(dev); - if (rval < 0) { - if (rval != -EBUSY && rval != -EAGAIN) - pm_runtime_set_active(&client->dev); - pm_runtime_put(dev); - return -EAGAIN; - } - - if (sensor->streaming) - smiapp_stop_streaming(sensor); - - /* save state for resume */ - sensor->streaming = streaming; - - return 0; -} - -static int __maybe_unused smiapp_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *subdev = i2c_get_clientdata(client); - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - int rval = 0; - - pm_runtime_put(dev); - - if (sensor->streaming) - rval = smiapp_start_streaming(sensor); - - return rval; -} - -static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev) -{ - struct smiapp_hwconfig *hwcfg; - struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 }; - struct fwnode_handle *ep; - struct fwnode_handle *fwnode = dev_fwnode(dev); - u32 rotation; - int i; - int rval; - - if (!fwnode) - return dev->platform_data; - - ep = fwnode_graph_get_next_endpoint(fwnode, NULL); - if (!ep) - return NULL; - - bus_cfg.bus_type = V4L2_MBUS_CSI2_DPHY; - rval = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); - if (rval == -ENXIO) { - bus_cfg = (struct v4l2_fwnode_endpoint) - { .bus_type = V4L2_MBUS_CCP2 }; - rval = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); - } - if (rval) - goto out_err; - - hwcfg = devm_kzalloc(dev, sizeof(*hwcfg), GFP_KERNEL); - if (!hwcfg) - goto out_err; - - switch (bus_cfg.bus_type) { - case V4L2_MBUS_CSI2_DPHY: - hwcfg->csi_signalling_mode = CCS_CSI_SIGNALING_MODE_CSI_2_DPHY; - hwcfg->lanes = bus_cfg.bus.mipi_csi2.num_data_lanes; - break; - case V4L2_MBUS_CCP2: - hwcfg->csi_signalling_mode = (bus_cfg.bus.mipi_csi1.strobe) ? - SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE : - SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK; - hwcfg->lanes = 1; - break; - default: - dev_err(dev, "unsupported bus %u\n", bus_cfg.bus_type); - goto out_err; - } - - dev_dbg(dev, "lanes %u\n", hwcfg->lanes); - - rval = fwnode_property_read_u32(fwnode, "rotation", &rotation); - if (!rval) { - switch (rotation) { - case 180: - hwcfg->module_board_orient = - SMIAPP_MODULE_BOARD_ORIENT_180; - fallthrough; - case 0: - break; - default: - dev_err(dev, "invalid rotation %u\n", rotation); - goto out_err; - } - } - - rval = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &hwcfg->ext_clk); - if (rval) - dev_info(dev, "can't get clock-frequency\n"); - - dev_dbg(dev, "clk %d, mode %d\n", hwcfg->ext_clk, - hwcfg->csi_signalling_mode); - - if (!bus_cfg.nr_of_link_frequencies) { - dev_warn(dev, "no link frequencies defined\n"); - goto out_err; - } - - hwcfg->op_sys_clock = devm_kcalloc( - dev, bus_cfg.nr_of_link_frequencies + 1 /* guardian */, - sizeof(*hwcfg->op_sys_clock), GFP_KERNEL); - if (!hwcfg->op_sys_clock) - goto out_err; - - for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) { - hwcfg->op_sys_clock[i] = bus_cfg.link_frequencies[i]; - dev_dbg(dev, "freq %d: %lld\n", i, hwcfg->op_sys_clock[i]); - } - - v4l2_fwnode_endpoint_free(&bus_cfg); - fwnode_handle_put(ep); - return hwcfg; - -out_err: - v4l2_fwnode_endpoint_free(&bus_cfg); - fwnode_handle_put(ep); - return NULL; -} - -static int smiapp_probe(struct i2c_client *client) -{ - struct smiapp_sensor *sensor; - struct smiapp_hwconfig *hwcfg = smiapp_get_hwconfig(&client->dev); - unsigned int i; - int rval; - - if (hwcfg == NULL) - return -ENODEV; - - sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL); - if (sensor == NULL) - return -ENOMEM; - - sensor->hwcfg = hwcfg; - sensor->src = &sensor->ssds[sensor->ssds_used]; - - v4l2_i2c_subdev_init(&sensor->src->sd, client, &smiapp_ops); - sensor->src->sd.internal_ops = &smiapp_internal_src_ops; - - sensor->vana = devm_regulator_get(&client->dev, "vana"); - if (IS_ERR(sensor->vana)) { - dev_err(&client->dev, "could not get regulator for vana\n"); - return PTR_ERR(sensor->vana); - } - - sensor->ext_clk = devm_clk_get(&client->dev, NULL); - if (PTR_ERR(sensor->ext_clk) == -ENOENT) { - dev_info(&client->dev, "no clock defined, continuing...\n"); - sensor->ext_clk = NULL; - } else if (IS_ERR(sensor->ext_clk)) { - dev_err(&client->dev, "could not get clock (%ld)\n", - PTR_ERR(sensor->ext_clk)); - return -EPROBE_DEFER; - } - - if (sensor->ext_clk) { - if (sensor->hwcfg->ext_clk) { - unsigned long rate; - - rval = clk_set_rate(sensor->ext_clk, - sensor->hwcfg->ext_clk); - if (rval < 0) { - dev_err(&client->dev, - "unable to set clock freq to %u\n", - sensor->hwcfg->ext_clk); - return rval; - } - - rate = clk_get_rate(sensor->ext_clk); - if (rate != sensor->hwcfg->ext_clk) { - dev_err(&client->dev, - "can't set clock freq, asked for %u but got %lu\n", - sensor->hwcfg->ext_clk, rate); - return rval; - } - } else { - sensor->hwcfg->ext_clk = clk_get_rate(sensor->ext_clk); - dev_dbg(&client->dev, "obtained clock freq %u\n", - sensor->hwcfg->ext_clk); - } - } else if (sensor->hwcfg->ext_clk) { - dev_dbg(&client->dev, "assuming clock freq %u\n", - sensor->hwcfg->ext_clk); - } else { - dev_err(&client->dev, "unable to obtain clock freq\n"); - return -EINVAL; - } - - sensor->xshutdown = devm_gpiod_get_optional(&client->dev, "xshutdown", - GPIOD_OUT_LOW); - if (IS_ERR(sensor->xshutdown)) - return PTR_ERR(sensor->xshutdown); - - rval = smiapp_power_on(&client->dev); - if (rval < 0) - return rval; - - mutex_init(&sensor->mutex); - - rval = smiapp_identify_module(sensor); - if (rval) { - rval = -ENODEV; - goto out_power_off; - } - - rval = ccs_read_all_limits(sensor); - if (rval) - goto out_power_off; - - rval = smiapp_read_frame_fmt(sensor); - if (rval) { - rval = -ENODEV; - goto out_free_ccs_limits; - } - - /* - * Handle Sensor Module orientation on the board. - * - * The application of H-FLIP and V-FLIP on the sensor is modified by - * the sensor orientation on the board. - * - * For SMIAPP_BOARD_SENSOR_ORIENT_180 the default behaviour is to set - * both H-FLIP and V-FLIP for normal operation which also implies - * that a set/unset operation for user space HFLIP and VFLIP v4l2 - * controls will need to be internally inverted. - * - * Rotation also changes the bayer pattern. - */ - if (sensor->hwcfg->module_board_orient == - SMIAPP_MODULE_BOARD_ORIENT_180) - sensor->hvflip_inv_mask = - CCS_IMAGE_ORIENTATION_HORIZONTAL_MIRROR | - CCS_IMAGE_ORIENTATION_VERTICAL_FLIP; - - rval = smiapp_call_quirk(sensor, limits); - if (rval) { - dev_err(&client->dev, "limits quirks failed\n"); - goto out_free_ccs_limits; - } - - if (CCS_LIM(sensor, BINNING_CAPABILITY)) { - sensor->nbinning_subtypes = - min_t(u8, CCS_LIM(sensor, BINNING_SUB_TYPES), - CCS_LIM_BINNING_SUB_TYPE_MAX_N); - - for (i = 0; i < sensor->nbinning_subtypes; i++) { - sensor->binning_subtypes[i].horizontal = - CCS_LIM_AT(sensor, BINNING_SUB_TYPE, i) >> - CCS_BINNING_SUB_TYPE_COLUMN_SHIFT; - sensor->binning_subtypes[i].vertical = - CCS_LIM_AT(sensor, BINNING_SUB_TYPE, i) & - CCS_BINNING_SUB_TYPE_ROW_MASK; - - dev_dbg(&client->dev, "binning %xx%x\n", - sensor->binning_subtypes[i].horizontal, - sensor->binning_subtypes[i].vertical); - } - } - sensor->binning_horizontal = 1; - sensor->binning_vertical = 1; - - if (device_create_file(&client->dev, &dev_attr_ident) != 0) { - dev_err(&client->dev, "sysfs ident entry creation failed\n"); - rval = -ENOENT; - goto out_free_ccs_limits; - } - - if (sensor->minfo.smiapp_version && - CCS_LIM(sensor, DATA_TRANSFER_IF_CAPABILITY) & - CCS_DATA_TRANSFER_IF_CAPABILITY_SUPPORTED) { - if (device_create_file(&client->dev, &dev_attr_nvm) != 0) { - dev_err(&client->dev, "sysfs nvm entry failed\n"); - rval = -EBUSY; - goto out_cleanup; - } - } - - /* We consider this as profile 0 sensor if any of these are zero. */ - if (!CCS_LIM(sensor, MIN_OP_SYS_CLK_DIV) || - !CCS_LIM(sensor, MAX_OP_SYS_CLK_DIV) || - !CCS_LIM(sensor, MIN_OP_PIX_CLK_DIV) || - !CCS_LIM(sensor, MAX_OP_PIX_CLK_DIV)) { - sensor->minfo.smiapp_profile = SMIAPP_PROFILE_0; - } else if (CCS_LIM(sensor, SCALING_CAPABILITY) - != CCS_SCALING_CAPABILITY_NONE) { - if (CCS_LIM(sensor, SCALING_CAPABILITY) - == CCS_SCALING_CAPABILITY_HORIZONTAL) - sensor->minfo.smiapp_profile = SMIAPP_PROFILE_1; - else - sensor->minfo.smiapp_profile = SMIAPP_PROFILE_2; - sensor->scaler = &sensor->ssds[sensor->ssds_used]; - sensor->ssds_used++; - } else if (CCS_LIM(sensor, DIGITAL_CROP_CAPABILITY) - == CCS_DIGITAL_CROP_CAPABILITY_INPUT_CROP) { - sensor->scaler = &sensor->ssds[sensor->ssds_used]; - sensor->ssds_used++; - } - sensor->binner = &sensor->ssds[sensor->ssds_used]; - sensor->ssds_used++; - sensor->pixel_array = &sensor->ssds[sensor->ssds_used]; - sensor->ssds_used++; - - sensor->scale_m = CCS_LIM(sensor, SCALER_N_MIN); - - /* prepare PLL configuration input values */ - sensor->pll.bus_type = SMIAPP_PLL_BUS_TYPE_CSI2; - sensor->pll.csi2.lanes = sensor->hwcfg->lanes; - sensor->pll.ext_clk_freq_hz = sensor->hwcfg->ext_clk; - sensor->pll.scale_n = CCS_LIM(sensor, SCALER_N_MIN); - /* Profile 0 sensors have no separate OP clock branch. */ - if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) - sensor->pll.flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS; - - smiapp_create_subdev(sensor, sensor->scaler, " scaler", 2); - smiapp_create_subdev(sensor, sensor->binner, " binner", 2); - smiapp_create_subdev(sensor, sensor->pixel_array, " pixel_array", 1); - - dev_dbg(&client->dev, "profile %d\n", sensor->minfo.smiapp_profile); - - sensor->pixel_array->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - - rval = smiapp_init_controls(sensor); - if (rval < 0) - goto out_cleanup; - - rval = smiapp_call_quirk(sensor, init); - if (rval) - goto out_cleanup; - - rval = smiapp_get_mbus_formats(sensor); - if (rval) { - rval = -ENODEV; - goto out_cleanup; - } - - rval = smiapp_init_late_controls(sensor); - if (rval) { - rval = -ENODEV; - goto out_cleanup; - } - - mutex_lock(&sensor->mutex); - rval = smiapp_pll_blanking_update(sensor); - mutex_unlock(&sensor->mutex); - if (rval) { - dev_err(&client->dev, "update mode failed\n"); - goto out_cleanup; - } - - sensor->streaming = false; - sensor->dev_init_done = true; - - rval = media_entity_pads_init(&sensor->src->sd.entity, 2, - sensor->src->pads); - if (rval < 0) - goto out_media_entity_cleanup; - - pm_runtime_set_active(&client->dev); - pm_runtime_get_noresume(&client->dev); - pm_runtime_enable(&client->dev); - - rval = v4l2_async_register_subdev_sensor_common(&sensor->src->sd); - if (rval < 0) - goto out_disable_runtime_pm; - - pm_runtime_set_autosuspend_delay(&client->dev, 1000); - pm_runtime_use_autosuspend(&client->dev); - pm_runtime_put_autosuspend(&client->dev); - - return 0; - -out_disable_runtime_pm: - pm_runtime_put_noidle(&client->dev); - pm_runtime_disable(&client->dev); - -out_media_entity_cleanup: - media_entity_cleanup(&sensor->src->sd.entity); - -out_cleanup: - smiapp_cleanup(sensor); - -out_free_ccs_limits: - kfree(sensor->ccs_limits); - -out_power_off: - smiapp_power_off(&client->dev); - mutex_destroy(&sensor->mutex); - - return rval; -} - -static int smiapp_remove(struct i2c_client *client) -{ - struct v4l2_subdev *subdev = i2c_get_clientdata(client); - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - unsigned int i; - - v4l2_async_unregister_subdev(subdev); - - pm_runtime_disable(&client->dev); - if (!pm_runtime_status_suspended(&client->dev)) - smiapp_power_off(&client->dev); - pm_runtime_set_suspended(&client->dev); - - for (i = 0; i < sensor->ssds_used; i++) { - v4l2_device_unregister_subdev(&sensor->ssds[i].sd); - media_entity_cleanup(&sensor->ssds[i].sd.entity); - } - smiapp_cleanup(sensor); - mutex_destroy(&sensor->mutex); - kfree(sensor->ccs_limits); - - return 0; -} - -static const struct of_device_id smiapp_of_table[] = { - { .compatible = "nokia,smia" }, - { }, -}; -MODULE_DEVICE_TABLE(of, smiapp_of_table); - -static const struct i2c_device_id smiapp_id_table[] = { - { SMIAPP_NAME, 0 }, - { }, -}; -MODULE_DEVICE_TABLE(i2c, smiapp_id_table); - -static const struct dev_pm_ops smiapp_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(smiapp_suspend, smiapp_resume) - SET_RUNTIME_PM_OPS(smiapp_power_off, smiapp_power_on, NULL) -}; - -static struct i2c_driver smiapp_i2c_driver = { - .driver = { - .of_match_table = smiapp_of_table, - .name = SMIAPP_NAME, - .pm = &smiapp_pm_ops, - }, - .probe_new = smiapp_probe, - .remove = smiapp_remove, - .id_table = smiapp_id_table, -}; - -static int smiapp_module_init(void) -{ - unsigned int i, l; - - for (i = 0, l = 0; ccs_limits[i].size && l < CCS_L_LAST; i++) { - if (!(ccs_limits[i].flags & CCS_L_FL_SAME_REG)) { - ccs_limit_offsets[l + 1].lim = - ALIGN(ccs_limit_offsets[l].lim + - ccs_limits[i].size, - ccs_reg_width(ccs_limits[i + 1].reg)); - ccs_limit_offsets[l].info = i; - l++; - } else { - ccs_limit_offsets[l].lim += ccs_limits[i].size; - } - } - - if (WARN_ON(ccs_limits[i].size)) - return -EINVAL; - - if (WARN_ON(l != CCS_L_LAST)) - return -EINVAL; - - return i2c_register_driver(THIS_MODULE, &smiapp_i2c_driver); -} - -static void smiapp_module_cleanup(void) -{ - i2c_del_driver(&smiapp_i2c_driver); -} - -module_init(smiapp_module_init); -module_exit(smiapp_module_cleanup); - -MODULE_AUTHOR("Sakari Ailus "); -MODULE_DESCRIPTION("Generic SMIA/SMIA++ camera module driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.c b/drivers/media/i2c/smiapp/smiapp-quirk.c deleted file mode 100644 index 5db97a16eccf..000000000000 --- a/drivers/media/i2c/smiapp/smiapp-quirk.c +++ /dev/null @@ -1,215 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * drivers/media/i2c/smiapp/smiapp-quirk.c - * - * Generic driver for SMIA/SMIA++ compliant camera modules - * - * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus - */ - -#include - -#include "ccs-limits.h" - -#include "smiapp.h" - -static int ccs_write_addr_8s(struct smiapp_sensor *sensor, - const struct smiapp_reg_8 *regs, int len) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - int rval; - - for (; len > 0; len--, regs++) { - rval = ccs_write_addr(sensor, regs->reg, regs->val); - if (rval < 0) { - dev_err(&client->dev, - "error %d writing reg 0x%4.4x, val 0x%2.2x", - rval, regs->reg, regs->val); - return rval; - } - } - - return 0; -} - -static int jt8ew9_limits(struct smiapp_sensor *sensor) -{ - if (sensor->minfo.revision_number_major < 0x03) - sensor->frame_skip = 1; - - /* Below 24 gain doesn't have effect at all, */ - /* but ~59 is needed for full dynamic range */ - ccs_replace_limit(sensor, CCS_L_ANALOG_GAIN_CODE_MIN, 0, 59); - ccs_replace_limit(sensor, CCS_L_ANALOG_GAIN_CODE_MAX, 0, 6000); - - return 0; -} - -static int jt8ew9_post_poweron(struct smiapp_sensor *sensor) -{ - static const struct smiapp_reg_8 regs[] = { - { 0x30a3, 0xd8 }, /* Output port control : LVDS ports only */ - { 0x30ae, 0x00 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */ - { 0x30af, 0xd0 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */ - { 0x322d, 0x04 }, /* Adjusting Processing Image Size to Scaler Toshiba Recommendation Setting */ - { 0x3255, 0x0f }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */ - { 0x3256, 0x15 }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */ - { 0x3258, 0x70 }, /* Analog Gain Control Toshiba Recommendation Setting */ - { 0x3259, 0x70 }, /* Analog Gain Control Toshiba Recommendation Setting */ - { 0x325f, 0x7c }, /* Analog Gain Control Toshiba Recommendation Setting */ - { 0x3302, 0x06 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */ - { 0x3304, 0x00 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */ - { 0x3307, 0x22 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */ - { 0x3308, 0x8d }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */ - { 0x331e, 0x0f }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ - { 0x3320, 0x30 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ - { 0x3321, 0x11 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ - { 0x3322, 0x98 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ - { 0x3323, 0x64 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ - { 0x3325, 0x83 }, /* Read Out Timing Control Toshiba Recommendation Setting */ - { 0x3330, 0x18 }, /* Read Out Timing Control Toshiba Recommendation Setting */ - { 0x333c, 0x01 }, /* Read Out Timing Control Toshiba Recommendation Setting */ - { 0x3345, 0x2f }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ - { 0x33de, 0x38 }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */ - /* Taken from v03. No idea what the rest are. */ - { 0x32e0, 0x05 }, - { 0x32e1, 0x05 }, - { 0x32e2, 0x04 }, - { 0x32e5, 0x04 }, - { 0x32e6, 0x04 }, - - }; - - return ccs_write_addr_8s(sensor, regs, ARRAY_SIZE(regs)); -} - -const struct smiapp_quirk smiapp_jt8ew9_quirk = { - .limits = jt8ew9_limits, - .post_poweron = jt8ew9_post_poweron, -}; - -static int imx125es_post_poweron(struct smiapp_sensor *sensor) -{ - /* Taken from v02. No idea what the other two are. */ - static const struct smiapp_reg_8 regs[] = { - /* - * 0x3302: clk during frame blanking: - * 0x00 - HS mode, 0x01 - LP11 - */ - { 0x3302, 0x01 }, - { 0x302d, 0x00 }, - { 0x3b08, 0x8c }, - }; - - return ccs_write_addr_8s(sensor, regs, ARRAY_SIZE(regs)); -} - -const struct smiapp_quirk smiapp_imx125es_quirk = { - .post_poweron = imx125es_post_poweron, -}; - -static int jt8ev1_limits(struct smiapp_sensor *sensor) -{ - ccs_replace_limit(sensor, CCS_L_X_ADDR_MAX, 0, 4271); - ccs_replace_limit(sensor, CCS_L_MIN_LINE_BLANKING_PCK_BIN, 0, 184); - - return 0; -} - -static int jt8ev1_post_poweron(struct smiapp_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - int rval; - static const struct smiapp_reg_8 regs[] = { - { 0x3031, 0xcd }, /* For digital binning (EQ_MONI) */ - { 0x30a3, 0xd0 }, /* FLASH STROBE enable */ - { 0x3237, 0x00 }, /* For control of pulse timing for ADC */ - { 0x3238, 0x43 }, - { 0x3301, 0x06 }, /* For analog bias for sensor */ - { 0x3302, 0x06 }, - { 0x3304, 0x00 }, - { 0x3305, 0x88 }, - { 0x332a, 0x14 }, - { 0x332c, 0x6b }, - { 0x3336, 0x01 }, - { 0x333f, 0x1f }, - { 0x3355, 0x00 }, - { 0x3356, 0x20 }, - { 0x33bf, 0x20 }, /* Adjust the FBC speed */ - { 0x33c9, 0x20 }, - { 0x33ce, 0x30 }, /* Adjust the parameter for logic function */ - { 0x33cf, 0xec }, /* For Black sun */ - { 0x3328, 0x80 }, /* Ugh. No idea what's this. */ - }; - static const struct smiapp_reg_8 regs_96[] = { - { 0x30ae, 0x00 }, /* For control of ADC clock */ - { 0x30af, 0xd0 }, - { 0x30b0, 0x01 }, - }; - - rval = ccs_write_addr_8s(sensor, regs, ARRAY_SIZE(regs)); - if (rval < 0) - return rval; - - switch (sensor->hwcfg->ext_clk) { - case 9600000: - return ccs_write_addr_8s(sensor, regs_96, - ARRAY_SIZE(regs_96)); - default: - dev_warn(&client->dev, "no MSRs for %d Hz ext_clk\n", - sensor->hwcfg->ext_clk); - return 0; - } -} - -static int jt8ev1_pre_streamon(struct smiapp_sensor *sensor) -{ - return ccs_write_addr(sensor, 0x3328, 0x00); -} - -static int jt8ev1_post_streamoff(struct smiapp_sensor *sensor) -{ - int rval; - - /* Workaround: allows fast standby to work properly */ - rval = ccs_write_addr(sensor, 0x3205, 0x04); - if (rval < 0) - return rval; - - /* Wait for 1 ms + one line => 2 ms is likely enough */ - usleep_range(2000, 2050); - - /* Restore it */ - rval = ccs_write_addr(sensor, 0x3205, 0x00); - if (rval < 0) - return rval; - - return ccs_write_addr(sensor, 0x3328, 0x80); -} - -static int jt8ev1_init(struct smiapp_sensor *sensor) -{ - sensor->pll.flags |= SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE; - - return 0; -} - -const struct smiapp_quirk smiapp_jt8ev1_quirk = { - .limits = jt8ev1_limits, - .post_poweron = jt8ev1_post_poweron, - .pre_streamon = jt8ev1_pre_streamon, - .post_streamoff = jt8ev1_post_streamoff, - .init = jt8ev1_init, -}; - -static int tcm8500md_limits(struct smiapp_sensor *sensor) -{ - ccs_replace_limit(sensor, CCS_L_MIN_PLL_IP_CLK_FREQ_MHZ, 0, 2700000); - - return 0; -} - -const struct smiapp_quirk smiapp_tcm8500md_quirk = { - .limits = tcm8500md_limits, -}; diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.h b/drivers/media/i2c/smiapp/smiapp-quirk.h deleted file mode 100644 index 8a479f17cd19..000000000000 --- a/drivers/media/i2c/smiapp/smiapp-quirk.h +++ /dev/null @@ -1,78 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * drivers/media/i2c/smiapp/smiapp-quirk.h - * - * Generic driver for SMIA/SMIA++ compliant camera modules - * - * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus - */ - -#ifndef __SMIAPP_QUIRK__ -#define __SMIAPP_QUIRK__ - -struct smiapp_sensor; - -/** - * struct smiapp_quirk - quirks for sensors that deviate from SMIA++ standard - * - * @limits: Replace sensor->limits with values which can't be read from - * sensor registers. Called the first time the sensor is powered up. - * @post_poweron: Called always after the sensor has been fully powered on. - * @pre_streamon: Called just before streaming is enabled. - * @post_streamon: Called right after stopping streaming. - * @pll_flags: Return flags for the PLL calculator. - * @init: Quirk initialisation, called the last in probe(). This is - * also appropriate for adding sensor specific controls, for instance. - * @reg_access: Register access quirk. The quirk may divert the access - * to another register, or no register at all. - * - * @write: Is this read (false) or write (true) access? - * @reg: Pointer to the register to access - * @value: Register value, set by the caller on write, or - * by the quirk on read - * - * @return: 0 on success, -ENOIOCTLCMD if no register - * access may be done by the caller (default read - * value is zero), else negative error code on error - */ -struct smiapp_quirk { - int (*limits)(struct smiapp_sensor *sensor); - int (*post_poweron)(struct smiapp_sensor *sensor); - int (*pre_streamon)(struct smiapp_sensor *sensor); - int (*post_streamoff)(struct smiapp_sensor *sensor); - unsigned long (*pll_flags)(struct smiapp_sensor *sensor); - int (*init)(struct smiapp_sensor *sensor); - int (*reg_access)(struct smiapp_sensor *sensor, bool write, u32 *reg, - u32 *val); - unsigned long flags; -}; - -#define SMIAPP_QUIRK_FLAG_8BIT_READ_ONLY (1 << 0) - -struct smiapp_reg_8 { - u16 reg; - u8 val; -}; - -#define SMIAPP_MK_QUIRK_REG_8(_reg, _val) \ - { \ - .reg = (u16)_reg, \ - .val = _val, \ - } - -#define smiapp_call_quirk(sensor, _quirk, ...) \ - ((sensor)->minfo.quirk && \ - (sensor)->minfo.quirk->_quirk ? \ - (sensor)->minfo.quirk->_quirk(sensor, ##__VA_ARGS__) : 0) - -#define smiapp_needs_quirk(sensor, _quirk) \ - ((sensor)->minfo.quirk ? \ - (sensor)->minfo.quirk->flags & _quirk : 0) - -extern const struct smiapp_quirk smiapp_jt8ev1_quirk; -extern const struct smiapp_quirk smiapp_imx125es_quirk; -extern const struct smiapp_quirk smiapp_jt8ew9_quirk; -extern const struct smiapp_quirk smiapp_tcm8500md_quirk; - -#endif /* __SMIAPP_QUIRK__ */ diff --git a/drivers/media/i2c/smiapp/smiapp-regs.c b/drivers/media/i2c/smiapp/smiapp-regs.c deleted file mode 100644 index 173d9f8fe56c..000000000000 --- a/drivers/media/i2c/smiapp/smiapp-regs.c +++ /dev/null @@ -1,268 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * drivers/media/i2c/smiapp/smiapp-regs.c - * - * Generic driver for SMIA/SMIA++ compliant camera modules - * - * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus - */ - -#include - -#include -#include - -#include "smiapp.h" -#include "smiapp-regs.h" - -static uint32_t float_to_u32_mul_1000000(struct i2c_client *client, - uint32_t phloat) -{ - int32_t exp; - uint64_t man; - - if (phloat >= 0x80000000) { - dev_err(&client->dev, "this is a negative number\n"); - return 0; - } - - if (phloat == 0x7f800000) - return ~0; /* Inf. */ - - if ((phloat & 0x7f800000) == 0x7f800000) { - dev_err(&client->dev, "NaN or other special number\n"); - return 0; - } - - /* Valid cases begin here */ - if (phloat == 0) - return 0; /* Valid zero */ - - if (phloat > 0x4f800000) - return ~0; /* larger than 4294967295 */ - - /* - * Unbias exponent (note how phloat is now guaranteed to - * have 0 in the high bit) - */ - exp = ((int32_t)phloat >> 23) - 127; - - /* Extract mantissa, add missing '1' bit and it's in MHz */ - man = ((phloat & 0x7fffff) | 0x800000) * 1000000ULL; - - if (exp < 0) - man >>= -exp; - else - man <<= exp; - - man >>= 23; /* Remove mantissa bias */ - - return man & 0xffffffff; -} - - -/* - * Read a 8/16/32-bit i2c register. The value is returned in 'val'. - * Returns zero if successful, or non-zero otherwise. - */ -static int ____ccs_read_addr(struct smiapp_sensor *sensor, u16 reg, u16 len, - u32 *val) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - struct i2c_msg msg; - unsigned char data_buf[sizeof(u32)] = { 0 }; - unsigned char offset_buf[sizeof(u16)]; - int r; - - if (len > sizeof(data_buf)) - return -EINVAL; - - msg.addr = client->addr; - msg.flags = 0; - msg.len = sizeof(offset_buf); - msg.buf = offset_buf; - put_unaligned_be16(reg, offset_buf); - - r = i2c_transfer(client->adapter, &msg, 1); - if (r != 1) { - if (r >= 0) - r = -EBUSY; - goto err; - } - - msg.len = len; - msg.flags = I2C_M_RD; - msg.buf = &data_buf[sizeof(data_buf) - len]; - - r = i2c_transfer(client->adapter, &msg, 1); - if (r != 1) { - if (r >= 0) - r = -EBUSY; - goto err; - } - - *val = get_unaligned_be32(data_buf); - - return 0; - -err: - dev_err(&client->dev, "read from offset 0x%x error %d\n", reg, r); - - return r; -} - -/* Read a register using 8-bit access only. */ -static int ____ccs_read_addr_8only(struct smiapp_sensor *sensor, u16 reg, - u16 len, u32 *val) -{ - unsigned int i; - int rval; - - *val = 0; - - for (i = 0; i < len; i++) { - u32 val8; - - rval = ____ccs_read_addr(sensor, reg + i, 1, &val8); - if (rval < 0) - return rval; - *val |= val8 << ((len - i - 1) << 3); - } - - return 0; -} - -unsigned int ccs_reg_width(u32 reg) -{ - if (reg & CCS_FL_16BIT) - return sizeof(uint16_t); - if (reg & CCS_FL_32BIT) - return sizeof(uint32_t); - - return sizeof(uint8_t); -} - -/* - * Read a 8/16/32-bit i2c register. The value is returned in 'val'. - * Returns zero if successful, or non-zero otherwise. - */ -static int __ccs_read_addr(struct smiapp_sensor *sensor, u32 reg, u32 *val, - bool only8) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - unsigned int len = ccs_reg_width(reg); - int rval; - - if (!only8) - rval = ____ccs_read_addr(sensor, SMIAPP_REG_ADDR(reg), len, - val); - else - rval = ____ccs_read_addr_8only(sensor, SMIAPP_REG_ADDR(reg), - len, val); - if (rval < 0) - return rval; - - if (reg & CCS_FL_FLOAT_IREAL) - *val = float_to_u32_mul_1000000(client, *val); - - return 0; -} - -int ccs_read_addr_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 *val) -{ - return __ccs_read_addr( - sensor, reg, val, - smiapp_needs_quirk(sensor, - SMIAPP_QUIRK_FLAG_8BIT_READ_ONLY)); -} - -static int ccs_read_addr_quirk(struct smiapp_sensor *sensor, u32 reg, u32 *val, - bool force8) -{ - int rval; - - *val = 0; - rval = smiapp_call_quirk(sensor, reg_access, false, ®, val); - if (rval == -ENOIOCTLCMD) - return 0; - if (rval < 0) - return rval; - - if (force8) - return __ccs_read_addr(sensor, reg, val, true); - - return ccs_read_addr_no_quirk(sensor, reg, val); -} - -int ccs_read_addr(struct smiapp_sensor *sensor, u32 reg, u32 *val) -{ - return ccs_read_addr_quirk(sensor, reg, val, false); -} - -int ccs_read_addr_8only(struct smiapp_sensor *sensor, u32 reg, u32 *val) -{ - return ccs_read_addr_quirk(sensor, reg, val, true); -} - -int ccs_write_addr_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - struct i2c_msg msg; - unsigned char data[6]; - unsigned int retries; - unsigned int len = ccs_reg_width(reg); - int r; - - if (len > sizeof(data) - 2) - return -EINVAL; - - msg.addr = client->addr; - msg.flags = 0; /* Write */ - msg.len = 2 + len; - msg.buf = data; - - put_unaligned_be16(SMIAPP_REG_ADDR(reg), data); - put_unaligned_be32(val << (8 * (sizeof(val) - len)), data + 2); - - for (retries = 0; retries < 5; retries++) { - /* - * Due to unknown reason sensor stops responding. This - * loop is a temporaty solution until the root cause - * is found. - */ - r = i2c_transfer(client->adapter, &msg, 1); - if (r == 1) { - if (retries) - dev_err(&client->dev, - "sensor i2c stall encountered. retries: %d\n", - retries); - return 0; - } - - usleep_range(2000, 2000); - } - - dev_err(&client->dev, - "wrote 0x%x to offset 0x%x error %d\n", val, - SMIAPP_REG_ADDR(reg), r); - - return r; -} - -/* - * Write to a 8/16-bit register. - * Returns zero if successful, or non-zero otherwise. - */ -int ccs_write_addr(struct smiapp_sensor *sensor, u32 reg, u32 val) -{ - int rval; - - rval = smiapp_call_quirk(sensor, reg_access, true, ®, &val); - if (rval == -ENOIOCTLCMD) - return 0; - if (rval < 0) - return rval; - - return ccs_write_addr_no_quirk(sensor, reg, val); -} diff --git a/drivers/media/i2c/smiapp/smiapp-regs.h b/drivers/media/i2c/smiapp/smiapp-regs.h deleted file mode 100644 index 5df794f65dfc..000000000000 --- a/drivers/media/i2c/smiapp/smiapp-regs.h +++ /dev/null @@ -1,37 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * include/media/smiapp/smiapp-regs.h - * - * Generic driver for SMIA/SMIA++ compliant camera modules - * - * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus - */ - -#ifndef SMIAPP_REGS_H -#define SMIAPP_REGS_H - -#include -#include - -#include "ccs-regs.h" - -#define SMIAPP_REG_ADDR(reg) ((u16)reg) - -struct smiapp_sensor; - -int ccs_read_addr_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 *val); -int ccs_read_addr(struct smiapp_sensor *sensor, u32 reg, u32 *val); -int ccs_read_addr_8only(struct smiapp_sensor *sensor, u32 reg, u32 *val); -int ccs_write_addr_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 val); -int ccs_write_addr(struct smiapp_sensor *sensor, u32 reg, u32 val); - -unsigned int ccs_reg_width(u32 reg); - -#define ccs_read(sensor, reg_name, val) \ - ccs_read_addr(sensor, CCS_R_##reg_name, val) - -#define ccs_write(sensor, reg_name, val) \ - ccs_write_addr(sensor, CCS_R_##reg_name, val) - -#endif diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h deleted file mode 100644 index c6e4e05a7522..000000000000 --- a/drivers/media/i2c/smiapp/smiapp.h +++ /dev/null @@ -1,280 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * drivers/media/i2c/smiapp/smiapp.h - * - * Generic driver for SMIA/SMIA++ compliant camera modules - * - * Copyright (C) 2010--2012 Nokia Corporation - * Contact: Sakari Ailus - */ - -#ifndef __SMIAPP_PRIV_H_ -#define __SMIAPP_PRIV_H_ - -#include -#include -#include - -#include "ccs-regs.h" - -#include "smiapp-pll.h" -#include "smiapp-reg-defs.h" -#include "smiapp-regs.h" -#include "smiapp-quirk.h" - -/* - * Standard SMIA++ constants - */ -#define SMIA_VERSION_1 10 -#define SMIAPP_VERSION_0_8 8 /* Draft 0.8 */ -#define SMIAPP_VERSION_0_9 9 /* Draft 0.9 */ -#define SMIAPP_VERSION_1 10 - -#define SMIAPP_PROFILE_0 0 -#define SMIAPP_PROFILE_1 1 -#define SMIAPP_PROFILE_2 2 - -#define SMIAPP_NVM_PAGE_SIZE 64 /* bytes */ - -#define SMIAPP_RESET_DELAY_CLOCKS 2400 -#define SMIAPP_RESET_DELAY(clk) \ - (1000 + (SMIAPP_RESET_DELAY_CLOCKS * 1000 \ - + (clk) / 1000 - 1) / ((clk) / 1000)) - -#define SMIAPP_COLOUR_COMPONENTS 4 - -#define SMIAPP_NAME "smiapp" - -#define SMIAPP_DFL_I2C_ADDR (0x20 >> 1) /* Default I2C Address */ -#define SMIAPP_ALT_I2C_ADDR (0x6e >> 1) /* Alternate I2C Address */ - -/* - * Sometimes due to board layout considerations the camera module can be - * mounted rotated. The typical rotation used is 180 degrees which can be - * corrected by giving a default H-FLIP and V-FLIP in the sensor readout. - * FIXME: rotation also changes the bayer pattern. - */ -enum smiapp_module_board_orient { - SMIAPP_MODULE_BOARD_ORIENT_0 = 0, - SMIAPP_MODULE_BOARD_ORIENT_180, -}; - -struct smiapp_flash_strobe_parms { - u8 mode; - u32 strobe_width_high_us; - u16 strobe_delay; - u16 stobe_start_point; - u8 trigger; -}; - -struct smiapp_hwconfig { - /* - * Change the cci address if i2c_addr_alt is set. - * Both default and alternate cci addr need to be present - */ - unsigned short i2c_addr_dfl; /* Default i2c addr */ - unsigned short i2c_addr_alt; /* Alternate i2c addr */ - - uint32_t ext_clk; /* sensor external clk */ - - unsigned int lanes; /* Number of CSI-2 lanes */ - uint32_t csi_signalling_mode; /* SMIAPP_CSI_SIGNALLING_MODE_* */ - uint64_t *op_sys_clock; - - enum smiapp_module_board_orient module_board_orient; - - struct smiapp_flash_strobe_parms *strobe_setup; -}; - -struct smiapp_quirk; - -#define SMIAPP_MODULE_IDENT_FLAG_REV_LE (1 << 0) - -struct smiapp_module_ident { - u16 mipi_manufacturer_id; - u16 model_id; - u8 smia_manufacturer_id; - u8 revision_number_major; - - u8 flags; - - char *name; - const struct smiapp_quirk *quirk; -}; - -struct smiapp_module_info { - u32 smia_manufacturer_id; - u32 mipi_manufacturer_id; - u32 model_id; - u32 revision_number_major; - u32 revision_number_minor; - - u32 module_year; - u32 module_month; - u32 module_day; - - u32 sensor_smia_manufacturer_id; - u32 sensor_mipi_manufacturer_id; - u32 sensor_model_id; - u32 sensor_revision_number; - u32 sensor_firmware_version; - - u32 smia_version; - u32 smiapp_version; - u32 ccs_version; - - u32 smiapp_profile; - - char *name; - const struct smiapp_quirk *quirk; -}; - -#define SMIAPP_IDENT_FQ(manufacturer, model, rev, fl, _name, _quirk) \ - { .smia_manufacturer_id = manufacturer, \ - .model_id = model, \ - .revision_number_major = rev, \ - .flags = fl, \ - .name = _name, \ - .quirk = _quirk, } - -#define SMIAPP_IDENT_LQ(manufacturer, model, rev, _name, _quirk) \ - { .smia_manufacturer_id = manufacturer, \ - .model_id = model, \ - .revision_number_major = rev, \ - .flags = SMIAPP_MODULE_IDENT_FLAG_REV_LE, \ - .name = _name, \ - .quirk = _quirk, } - -#define SMIAPP_IDENT_L(manufacturer, model, rev, _name) \ - { .smia_manufacturer_id = manufacturer, \ - .model_id = model, \ - .revision_number_major = rev, \ - .flags = SMIAPP_MODULE_IDENT_FLAG_REV_LE, \ - .name = _name, } - -#define SMIAPP_IDENT_Q(manufacturer, model, rev, _name, _quirk) \ - { .smia_manufacturer_id = manufacturer, \ - .model_id = model, \ - .revision_number_major = rev, \ - .flags = 0, \ - .name = _name, \ - .quirk = _quirk, } - -#define SMIAPP_IDENT(manufacturer, model, rev, _name) \ - { .smia_manufacturer_id = manufacturer, \ - .model_id = model, \ - .revision_number_major = rev, \ - .flags = 0, \ - .name = _name, } - -struct smiapp_csi_data_format { - u32 code; - u8 width; - u8 compressed; - u8 pixel_order; -}; - -#define SMIAPP_SUBDEVS 3 - -#define SMIAPP_PA_PAD_SRC 0 -#define SMIAPP_PAD_SINK 0 -#define SMIAPP_PAD_SRC 1 -#define SMIAPP_PADS 2 - -struct smiapp_binning_subtype { - u8 horizontal:4; - u8 vertical:4; -} __packed; - -struct smiapp_subdev { - struct v4l2_subdev sd; - struct media_pad pads[SMIAPP_PADS]; - struct v4l2_rect sink_fmt; - struct v4l2_rect crop[SMIAPP_PADS]; - struct v4l2_rect compose; /* compose on sink */ - unsigned short sink_pad; - unsigned short source_pad; - int npads; - struct smiapp_sensor *sensor; - struct v4l2_ctrl_handler ctrl_handler; -}; - -/* - * struct smiapp_sensor - Main device structure - */ -struct smiapp_sensor { - /* - * "mutex" is used to serialise access to all fields here - * except v4l2_ctrls at the end of the struct. "mutex" is also - * used to serialise access to file handle specific - * information. - */ - struct mutex mutex; - struct smiapp_subdev ssds[SMIAPP_SUBDEVS]; - u32 ssds_used; - struct smiapp_subdev *src; - struct smiapp_subdev *binner; - struct smiapp_subdev *scaler; - struct smiapp_subdev *pixel_array; - struct smiapp_hwconfig *hwcfg; - struct regulator *vana; - struct clk *ext_clk; - struct gpio_desc *xshutdown; - void *ccs_limits; - u8 nbinning_subtypes; - struct smiapp_binning_subtype binning_subtypes[CCS_LIM_BINNING_SUB_TYPE_MAX_N + 1]; - u32 mbus_frame_fmts; - const struct smiapp_csi_data_format *csi_format; - const struct smiapp_csi_data_format *internal_csi_format; - u32 default_mbus_frame_fmts; - int default_pixel_order; - - u8 binning_horizontal; - u8 binning_vertical; - - u8 scale_m; - u8 scaling_mode; - - u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */ - u8 frame_skip; - u16 embedded_start; /* embedded data start line */ - u16 embedded_end; - u16 image_start; /* image data start line */ - u16 visible_pixel_start; /* start pixel of the visible image */ - - bool streaming; - bool dev_init_done; - u8 compressed_min_bpp; - - struct smiapp_module_info minfo; - - struct smiapp_pll pll; - - /* Is a default format supported for a given BPP? */ - unsigned long *valid_link_freqs; - - /* Pixel array controls */ - struct v4l2_ctrl *analog_gain; - struct v4l2_ctrl *exposure; - struct v4l2_ctrl *hflip; - struct v4l2_ctrl *vflip; - struct v4l2_ctrl *vblank; - struct v4l2_ctrl *hblank; - struct v4l2_ctrl *pixel_rate_parray; - /* src controls */ - struct v4l2_ctrl *link_freq; - struct v4l2_ctrl *pixel_rate_csi; - /* test pattern colour components */ - struct v4l2_ctrl *test_data[SMIAPP_COLOUR_COMPONENTS]; -}; - -#define to_smiapp_subdev(_sd) \ - container_of(_sd, struct smiapp_subdev, sd) - -#define to_smiapp_sensor(_sd) \ - (to_smiapp_subdev(_sd)->sensor) - -void ccs_replace_limit(struct smiapp_sensor *sensor, - unsigned int limit, unsigned int offset, u32 val); - -#endif /* __SMIAPP_PRIV_H_ */ -- cgit v1.2.3 From 571b6caff4e890035deeb1451f2c1e5dca0e0dd2 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 2 Sep 2020 15:51:29 +0200 Subject: media: smiapp: Differentiate CCS sensors from SMIA in subdev naming Call CCS compliant sensors as "ccs" instead of "smiapp" in absence of a device specific name. This is done based on the value of the manufacturer ID register that is only present in CCS. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/ccs-core.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/smiapp/ccs-core.c b/drivers/media/i2c/smiapp/ccs-core.c index f9dbf1407a33..30c4d8edce9d 100644 --- a/drivers/media/i2c/smiapp/ccs-core.c +++ b/drivers/media/i2c/smiapp/ccs-core.c @@ -2437,8 +2437,6 @@ static int ccs_identify_module(struct ccs_sensor *sensor) unsigned int i; int rval = 0; - minfo->name = SMIAPP_NAME; - /* Module info */ rval = ccs_read(sensor, MODULE_MANUFACTURER_ID, &minfo->mipi_manufacturer_id); @@ -2528,15 +2526,18 @@ static int ccs_identify_module(struct ccs_sensor *sensor) "sensor revision 0x%2.2x firmware version 0x%2.2x\n", minfo->sensor_revision_number, minfo->sensor_firmware_version); - if (minfo->ccs_version) + if (minfo->ccs_version) { dev_dbg(&client->dev, "MIPI CCS version %u.%u", (minfo->ccs_version & CCS_MIPI_CCS_VERSION_MAJOR_MASK) >> CCS_MIPI_CCS_VERSION_MAJOR_SHIFT, (minfo->ccs_version & CCS_MIPI_CCS_VERSION_MINOR_MASK)); - else + minfo->name = CCS_NAME; + } else { dev_dbg(&client->dev, "smia version %2.2d smiapp version %2.2d\n", minfo->smia_version, minfo->smiapp_version); + minfo->name = SMIAPP_NAME; + } /* * Some modules have bad data in the lvalues below. Hope the -- cgit v1.2.3 From b24cc2a18c50e4e315abc76a86b26b4c49652f79 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 11 Feb 2020 19:05:57 +0100 Subject: media: smiapp: Rename as "ccs" Rename the "smiapp" driver as "ccs". MIPI CCS is the contemporary standard for raw Bayer camera sensors. The driver retains support for the SMIA++ and SMIA compliant camera sensors. A module alias is added for old user space using "smiapp" module name. Add Intel copyright while at it. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 22 +- drivers/media/i2c/Kconfig | 2 +- drivers/media/i2c/Makefile | 2 +- drivers/media/i2c/ccs/Kconfig | 11 + drivers/media/i2c/ccs/Makefile | 6 + drivers/media/i2c/ccs/ccs-core.c | 3302 ++++++++++++++++++++++++++++ drivers/media/i2c/ccs/ccs-limits.c | 239 ++ drivers/media/i2c/ccs/ccs-limits.h | 259 +++ drivers/media/i2c/ccs/ccs-quirk.c | 215 ++ drivers/media/i2c/ccs/ccs-quirk.h | 79 + drivers/media/i2c/ccs/ccs-reg-access.c | 266 +++ drivers/media/i2c/ccs/ccs-reg-access.h | 38 + drivers/media/i2c/ccs/ccs-regs.h | 954 ++++++++ drivers/media/i2c/ccs/ccs.h | 281 +++ drivers/media/i2c/ccs/smiapp-reg-defs.h | 580 +++++ drivers/media/i2c/smiapp/Kconfig | 10 - drivers/media/i2c/smiapp/Makefile | 6 - drivers/media/i2c/smiapp/ccs-core.c | 3300 --------------------------- drivers/media/i2c/smiapp/ccs-limits.c | 239 -- drivers/media/i2c/smiapp/ccs-limits.h | 259 --- drivers/media/i2c/smiapp/ccs-quirk.c | 214 -- drivers/media/i2c/smiapp/ccs-quirk.h | 78 - drivers/media/i2c/smiapp/ccs-reg-access.c | 265 --- drivers/media/i2c/smiapp/ccs-reg-access.h | 37 - drivers/media/i2c/smiapp/ccs-regs.h | 954 -------- drivers/media/i2c/smiapp/ccs.h | 280 --- drivers/media/i2c/smiapp/smiapp-reg-defs.h | 579 ----- 27 files changed, 6243 insertions(+), 6234 deletions(-) create mode 100644 drivers/media/i2c/ccs/Kconfig create mode 100644 drivers/media/i2c/ccs/Makefile create mode 100644 drivers/media/i2c/ccs/ccs-core.c create mode 100644 drivers/media/i2c/ccs/ccs-limits.c create mode 100644 drivers/media/i2c/ccs/ccs-limits.h create mode 100644 drivers/media/i2c/ccs/ccs-quirk.c create mode 100644 drivers/media/i2c/ccs/ccs-quirk.h create mode 100644 drivers/media/i2c/ccs/ccs-reg-access.c create mode 100644 drivers/media/i2c/ccs/ccs-reg-access.h create mode 100644 drivers/media/i2c/ccs/ccs-regs.h create mode 100644 drivers/media/i2c/ccs/ccs.h create mode 100644 drivers/media/i2c/ccs/smiapp-reg-defs.h delete mode 100644 drivers/media/i2c/smiapp/Kconfig delete mode 100644 drivers/media/i2c/smiapp/Makefile delete mode 100644 drivers/media/i2c/smiapp/ccs-core.c delete mode 100644 drivers/media/i2c/smiapp/ccs-limits.c delete mode 100644 drivers/media/i2c/smiapp/ccs-limits.h delete mode 100644 drivers/media/i2c/smiapp/ccs-quirk.c delete mode 100644 drivers/media/i2c/smiapp/ccs-quirk.h delete mode 100644 drivers/media/i2c/smiapp/ccs-reg-access.c delete mode 100644 drivers/media/i2c/smiapp/ccs-reg-access.h delete mode 100644 drivers/media/i2c/smiapp/ccs-regs.h delete mode 100644 drivers/media/i2c/smiapp/ccs.h delete mode 100644 drivers/media/i2c/smiapp/smiapp-reg-defs.h diff --git a/MAINTAINERS b/MAINTAINERS index 0864fe0f945a..e23b3e4d9a9d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11630,6 +11630,17 @@ M: Oliver Neukum S: Maintained F: drivers/usb/image/microtek.* +MIPI CCS, SMIA AND SMIA++ IMAGE SENSOR DRIVER +M: Sakari Ailus +L: linux-media@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/media/i2c/nokia,smia.txt +F: Documentation/driver-api/media/drivers/ccs/ +F: drivers/media/i2c/ccs/ +F: drivers/media/i2c/smiapp-pll.c +F: drivers/media/i2c/smiapp-pll.h +F: include/uapi/linux/smiapp.h + MIPS M: Thomas Bogendoerfer L: linux-mips@vger.kernel.org @@ -16103,17 +16114,6 @@ S: Maintained F: drivers/firmware/smccc/ F: include/linux/arm-smccc.h -SMIA AND SMIA++ IMAGE SENSOR DRIVER -M: Sakari Ailus -L: linux-media@vger.kernel.org -S: Maintained -F: Documentation/devicetree/bindings/media/i2c/nokia,smia.txt -F: Documentation/driver-api/media/drivers/ccs/ -F: drivers/media/i2c/smiapp-pll.c -F: drivers/media/i2c/smiapp-pll.h -F: drivers/media/i2c/smiapp/ -F: include/uapi/linux/smiapp.h - SMM665 HARDWARE MONITOR DRIVER M: Guenter Roeck L: linux-hwmon@vger.kernel.org diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 369b6d859da5..3787c22767d9 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -1247,7 +1247,7 @@ config VIDEO_S5K5BAF This is a V4L2 sensor driver for Samsung S5K5BAF 2M camera sensor with an embedded SoC image signal processor. -source "drivers/media/i2c/smiapp/Kconfig" +source "drivers/media/i2c/ccs/Kconfig" source "drivers/media/i2c/et8ek8/Kconfig" config VIDEO_S5C73M3 diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index b448506ce503..5c733394171d 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -2,7 +2,7 @@ msp3400-objs := msp3400-driver.o msp3400-kthreads.o obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o -obj-$(CONFIG_VIDEO_SMIAPP) += smiapp/ +obj-$(CONFIG_VIDEO_CCS) += ccs/ obj-$(CONFIG_VIDEO_ET8EK8) += et8ek8/ obj-$(CONFIG_VIDEO_CX25840) += cx25840/ obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/ diff --git a/drivers/media/i2c/ccs/Kconfig b/drivers/media/i2c/ccs/Kconfig new file mode 100644 index 000000000000..b4f8b10da420 --- /dev/null +++ b/drivers/media/i2c/ccs/Kconfig @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-only +config VIDEO_CCS + tristate "MIPI CCS/SMIA++/SMIA sensor support" + depends on I2C && VIDEO_V4L2 && HAVE_CLK + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + select VIDEO_SMIAPP_PLL + select V4L2_FWNODE + help + This is a generic driver for MIPI CCS, SMIA++ and SMIA compliant + camera sensors. diff --git a/drivers/media/i2c/ccs/Makefile b/drivers/media/i2c/ccs/Makefile new file mode 100644 index 000000000000..08dd4e948fb0 --- /dev/null +++ b/drivers/media/i2c/ccs/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +ccs-objs += ccs-core.o ccs-reg-access.o \ + ccs-quirk.o ccs-limits.o +obj-$(CONFIG_VIDEO_CCS) += ccs.o + +ccflags-y += -I $(srctree)/drivers/media/i2c diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c new file mode 100644 index 000000000000..2dfb26cb3a40 --- /dev/null +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -0,0 +1,3302 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * drivers/media/i2c/ccs/ccs-core.c + * + * Generic driver for MIPI CCS/SMIA/SMIA++ compliant camera sensors + * + * Copyright (C) 2020 Intel Corporation + * Copyright (C) 2010--2012 Nokia Corporation + * Contact: Sakari Ailus + * + * Based on smiapp driver by Vimarsh Zutshi + * Based on jt8ev1.c by Vimarsh Zutshi + * Based on smia-sensor.c by Tuukka Toivonen + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ccs.h" +#include "ccs-limits.h" + +#define CCS_ALIGN_DIM(dim, flags) \ + ((flags) & V4L2_SEL_FLAG_GE \ + ? ALIGN((dim), 2) \ + : (dim) & ~1) + +static struct ccs_limit_offset { + u16 lim; + u16 info; +} ccs_limit_offsets[CCS_L_LAST + 1]; + +/* + * ccs_module_idents - supported camera modules + */ +static const struct ccs_module_ident ccs_module_idents[] = { + CCS_IDENT_L(0x01, 0x022b, -1, "vs6555"), + CCS_IDENT_L(0x01, 0x022e, -1, "vw6558"), + CCS_IDENT_L(0x07, 0x7698, -1, "ovm7698"), + CCS_IDENT_L(0x0b, 0x4242, -1, "smiapp-003"), + CCS_IDENT_L(0x0c, 0x208a, -1, "tcm8330md"), + CCS_IDENT_LQ(0x0c, 0x2134, -1, "tcm8500md", &smiapp_tcm8500md_quirk), + CCS_IDENT_L(0x0c, 0x213e, -1, "et8en2"), + CCS_IDENT_L(0x0c, 0x2184, -1, "tcm8580md"), + CCS_IDENT_LQ(0x0c, 0x560f, -1, "jt8ew9", &smiapp_jt8ew9_quirk), + CCS_IDENT_LQ(0x10, 0x4141, -1, "jt8ev1", &smiapp_jt8ev1_quirk), + CCS_IDENT_LQ(0x10, 0x4241, -1, "imx125es", &smiapp_imx125es_quirk), +}; + +/* + * + * Dynamic Capability Identification + * + */ + +static void ccs_assign_limit(void *ptr, unsigned int width, u32 val) +{ + switch (width) { + case sizeof(u8): + *(u8 *)ptr = val; + break; + case sizeof(u16): + *(u16 *)ptr = val; + break; + case sizeof(u32): + *(u32 *)ptr = val; + break; + } +} + +static int ccs_limit_ptr(struct ccs_sensor *sensor, unsigned int limit, + unsigned int offset, void **__ptr) +{ + const struct ccs_limit *linfo; + + if (WARN_ON(limit >= CCS_L_LAST)) + return -EINVAL; + + linfo = &ccs_limits[ccs_limit_offsets[limit].info]; + + if (WARN_ON(!sensor->ccs_limits) || + WARN_ON(offset + ccs_reg_width(linfo->reg) > + ccs_limit_offsets[limit + 1].lim)) + return -EINVAL; + + *__ptr = sensor->ccs_limits + ccs_limit_offsets[limit].lim + offset; + + return 0; +} + +void ccs_replace_limit(struct ccs_sensor *sensor, + unsigned int limit, unsigned int offset, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + const struct ccs_limit *linfo; + void *ptr; + int ret; + + ret = ccs_limit_ptr(sensor, limit, offset, &ptr); + if (ret) + return; + + linfo = &ccs_limits[ccs_limit_offsets[limit].info]; + + dev_dbg(&client->dev, "quirk: 0x%8.8x \"%s\" %u = %d, 0x%x\n", + linfo->reg, linfo->name, offset, val, val); + + ccs_assign_limit(ptr, ccs_reg_width(linfo->reg), val); +} + +static u32 ccs_get_limit(struct ccs_sensor *sensor, + unsigned int limit, unsigned int offset) +{ + void *ptr; + int ret; + + ret = ccs_limit_ptr(sensor, limit, offset, &ptr); + if (ret) + return 0; + + switch (ccs_reg_width(ccs_limits[ccs_limit_offsets[limit].info].reg)) { + case sizeof(u8): + return *(u8 *)ptr; + case sizeof(u16): + return *(u16 *)ptr; + case sizeof(u32): + return *(u32 *)ptr; + } + + WARN_ON(1); + + return 0; +} + +#define CCS_LIM(sensor, limit) \ + ccs_get_limit(sensor, CCS_L_##limit, 0) + +#define CCS_LIM_AT(sensor, limit, offset) \ + ccs_get_limit(sensor, CCS_L_##limit, CCS_L_##limit##_OFFSET(offset)) + +static int ccs_read_all_limits(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + void *ptr, *alloc, *end; + unsigned int i, l; + int ret; + + kfree(sensor->ccs_limits); + sensor->ccs_limits = NULL; + + alloc = kzalloc(ccs_limit_offsets[CCS_L_LAST].lim, GFP_KERNEL); + if (!alloc) + return -ENOMEM; + + end = alloc + ccs_limit_offsets[CCS_L_LAST].lim; + + for (i = 0, l = 0, ptr = alloc; ccs_limits[i].size; i++) { + u32 reg = ccs_limits[i].reg; + unsigned int width = ccs_reg_width(reg); + unsigned int j; + + if (l == CCS_L_LAST) { + dev_err(&client->dev, + "internal error --- end of limit array\n"); + ret = -EINVAL; + goto out_err; + } + + for (j = 0; j < ccs_limits[i].size / width; + j++, reg += width, ptr += width) { + u32 val; + + ret = ccs_read_addr(sensor, reg, &val); + if (ret) + goto out_err; + + if (ptr + width > end) { + dev_err(&client->dev, + "internal error --- no room for regs\n"); + ret = -EINVAL; + goto out_err; + } + + ccs_assign_limit(ptr, width, val); + + dev_dbg(&client->dev, "0x%8.8x \"%s\" = %u, 0x%x\n", + reg, ccs_limits[i].name, val, val); + } + + if (ccs_limits[i].flags & CCS_L_FL_SAME_REG) + continue; + + l++; + ptr = alloc + ccs_limit_offsets[l].lim; + } + + if (l != CCS_L_LAST) { + dev_err(&client->dev, + "internal error --- insufficient limits\n"); + ret = -EINVAL; + goto out_err; + } + + sensor->ccs_limits = alloc; + + if (CCS_LIM(sensor, SCALER_N_MIN) < 16) + ccs_replace_limit(sensor, CCS_L_SCALER_N_MIN, 0, 16); + + return 0; + +out_err: + kfree(alloc); + + return ret; +} + +static int ccs_read_frame_fmt(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + u8 fmt_model_type, fmt_model_subtype, ncol_desc, nrow_desc; + unsigned int i; + int pixel_count = 0; + int line_count = 0; + + fmt_model_type = CCS_LIM(sensor, FRAME_FORMAT_MODEL_TYPE); + fmt_model_subtype = CCS_LIM(sensor, FRAME_FORMAT_MODEL_SUBTYPE); + + ncol_desc = (fmt_model_subtype + & CCS_FRAME_FORMAT_MODEL_SUBTYPE_COLUMNS_MASK) + >> CCS_FRAME_FORMAT_MODEL_SUBTYPE_COLUMNS_SHIFT; + nrow_desc = fmt_model_subtype + & CCS_FRAME_FORMAT_MODEL_SUBTYPE_ROWS_MASK; + + dev_dbg(&client->dev, "format_model_type %s\n", + fmt_model_type == CCS_FRAME_FORMAT_MODEL_TYPE_2_BYTE + ? "2 byte" : + fmt_model_type == CCS_FRAME_FORMAT_MODEL_TYPE_4_BYTE + ? "4 byte" : "is simply bad"); + + dev_dbg(&client->dev, "%u column and %u row descriptors\n", + ncol_desc, nrow_desc); + + for (i = 0; i < ncol_desc + nrow_desc; i++) { + u32 desc; + u32 pixelcode; + u32 pixels; + char *which; + char *what; + u32 reg; + + if (fmt_model_type == CCS_FRAME_FORMAT_MODEL_TYPE_2_BYTE) { + desc = CCS_LIM_AT(sensor, FRAME_FORMAT_DESCRIPTOR, i); + + pixelcode = + (desc + & CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MASK) + >> CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_SHIFT; + pixels = desc & CCS_FRAME_FORMAT_DESCRIPTOR_PIXELS_MASK; + } else if (fmt_model_type + == CCS_FRAME_FORMAT_MODEL_TYPE_4_BYTE) { + desc = CCS_LIM_AT(sensor, FRAME_FORMAT_DESCRIPTOR_4, i); + + pixelcode = + (desc + & CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MASK) + >> CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_SHIFT; + pixels = desc & + CCS_FRAME_FORMAT_DESCRIPTOR_4_PIXELS_MASK; + } else { + dev_dbg(&client->dev, + "invalid frame format model type %d\n", + fmt_model_type); + return -EINVAL; + } + + if (i < ncol_desc) + which = "columns"; + else + which = "rows"; + + switch (pixelcode) { + case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_EMBEDDED: + what = "embedded"; + break; + case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_DUMMY_PIXEL: + what = "dummy"; + break; + case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_BLACK_PIXEL: + what = "black"; + break; + case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_DARK_PIXEL: + what = "dark"; + break; + case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_VISIBLE_PIXEL: + what = "visible"; + break; + default: + what = "invalid"; + break; + } + + dev_dbg(&client->dev, + "0x%8.8x %s pixels: %d %s (pixelcode %u)\n", reg, + what, pixels, which, pixelcode); + + if (i < ncol_desc) { + if (pixelcode == + CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_VISIBLE_PIXEL) + sensor->visible_pixel_start = pixel_count; + pixel_count += pixels; + continue; + } + + /* Handle row descriptors */ + switch (pixelcode) { + case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_EMBEDDED: + if (sensor->embedded_end) + break; + sensor->embedded_start = line_count; + sensor->embedded_end = line_count + pixels; + break; + case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_VISIBLE_PIXEL: + sensor->image_start = line_count; + break; + } + line_count += pixels; + } + + if (sensor->embedded_end > sensor->image_start) { + dev_dbg(&client->dev, + "adjusting image start line to %u (was %u)\n", + sensor->embedded_end, sensor->image_start); + sensor->image_start = sensor->embedded_end; + } + + dev_dbg(&client->dev, "embedded data from lines %d to %d\n", + sensor->embedded_start, sensor->embedded_end); + dev_dbg(&client->dev, "image data starts at line %d\n", + sensor->image_start); + + return 0; +} + +static int ccs_pll_configure(struct ccs_sensor *sensor) +{ + struct smiapp_pll *pll = &sensor->pll; + int rval; + + rval = ccs_write(sensor, VT_PIX_CLK_DIV, pll->vt.pix_clk_div); + if (rval < 0) + return rval; + + rval = ccs_write(sensor, VT_SYS_CLK_DIV, pll->vt.sys_clk_div); + if (rval < 0) + return rval; + + rval = ccs_write(sensor, PRE_PLL_CLK_DIV, pll->pre_pll_clk_div); + if (rval < 0) + return rval; + + rval = ccs_write(sensor, PLL_MULTIPLIER, pll->pll_multiplier); + if (rval < 0) + return rval; + + /* Lane op clock ratio does not apply here. */ + rval = ccs_write(sensor, REQUESTED_LINK_RATE, + DIV_ROUND_UP(pll->op.sys_clk_freq_hz, + 1000000 / 256 / 256)); + if (rval < 0 || sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) + return rval; + + rval = ccs_write(sensor, OP_PIX_CLK_DIV, pll->op.pix_clk_div); + if (rval < 0) + return rval; + + return ccs_write(sensor, OP_SYS_CLK_DIV, pll->op.sys_clk_div); +} + +static int ccs_pll_try(struct ccs_sensor *sensor, struct smiapp_pll *pll) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + struct smiapp_pll_limits lim = { + .min_pre_pll_clk_div = CCS_LIM(sensor, MIN_PRE_PLL_CLK_DIV), + .max_pre_pll_clk_div = CCS_LIM(sensor, MAX_PRE_PLL_CLK_DIV), + .min_pll_ip_freq_hz = CCS_LIM(sensor, MIN_PLL_IP_CLK_FREQ_MHZ), + .max_pll_ip_freq_hz = CCS_LIM(sensor, MAX_PLL_IP_CLK_FREQ_MHZ), + .min_pll_multiplier = CCS_LIM(sensor, MIN_PLL_MULTIPLIER), + .max_pll_multiplier = CCS_LIM(sensor, MAX_PLL_MULTIPLIER), + .min_pll_op_freq_hz = CCS_LIM(sensor, MIN_PLL_OP_CLK_FREQ_MHZ), + .max_pll_op_freq_hz = CCS_LIM(sensor, MAX_PLL_OP_CLK_FREQ_MHZ), + + .op.min_sys_clk_div = CCS_LIM(sensor, MIN_OP_SYS_CLK_DIV), + .op.max_sys_clk_div = CCS_LIM(sensor, MAX_OP_SYS_CLK_DIV), + .op.min_pix_clk_div = CCS_LIM(sensor, MIN_OP_PIX_CLK_DIV), + .op.max_pix_clk_div = CCS_LIM(sensor, MAX_OP_PIX_CLK_DIV), + .op.min_sys_clk_freq_hz = CCS_LIM(sensor, MIN_OP_SYS_CLK_FREQ_MHZ), + .op.max_sys_clk_freq_hz = CCS_LIM(sensor, MAX_OP_SYS_CLK_FREQ_MHZ), + .op.min_pix_clk_freq_hz = CCS_LIM(sensor, MIN_OP_PIX_CLK_FREQ_MHZ), + .op.max_pix_clk_freq_hz = CCS_LIM(sensor, MAX_OP_PIX_CLK_FREQ_MHZ), + + .vt.min_sys_clk_div = CCS_LIM(sensor, MIN_VT_SYS_CLK_DIV), + .vt.max_sys_clk_div = CCS_LIM(sensor, MAX_VT_SYS_CLK_DIV), + .vt.min_pix_clk_div = CCS_LIM(sensor, MIN_VT_PIX_CLK_DIV), + .vt.max_pix_clk_div = CCS_LIM(sensor, MAX_VT_PIX_CLK_DIV), + .vt.min_sys_clk_freq_hz = CCS_LIM(sensor, MIN_VT_SYS_CLK_FREQ_MHZ), + .vt.max_sys_clk_freq_hz = CCS_LIM(sensor, MAX_VT_SYS_CLK_FREQ_MHZ), + .vt.min_pix_clk_freq_hz = CCS_LIM(sensor, MIN_VT_PIX_CLK_FREQ_MHZ), + .vt.max_pix_clk_freq_hz = CCS_LIM(sensor, MAX_VT_PIX_CLK_FREQ_MHZ), + + .min_line_length_pck_bin = CCS_LIM(sensor, MIN_LINE_LENGTH_PCK_BIN), + .min_line_length_pck = CCS_LIM(sensor, MIN_LINE_LENGTH_PCK), + }; + + return smiapp_pll_calculate(&client->dev, &lim, pll); +} + +static int ccs_pll_update(struct ccs_sensor *sensor) +{ + struct smiapp_pll *pll = &sensor->pll; + int rval; + + pll->binning_horizontal = sensor->binning_horizontal; + pll->binning_vertical = sensor->binning_vertical; + pll->link_freq = + sensor->link_freq->qmenu_int[sensor->link_freq->val]; + pll->scale_m = sensor->scale_m; + pll->bits_per_pixel = sensor->csi_format->compressed; + + rval = ccs_pll_try(sensor, pll); + if (rval < 0) + return rval; + + __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_parray, + pll->pixel_rate_pixel_array); + __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_csi, pll->pixel_rate_csi); + + return 0; +} + + +/* + * + * V4L2 Controls handling + * + */ + +static void __ccs_update_exposure_limits(struct ccs_sensor *sensor) +{ + struct v4l2_ctrl *ctrl = sensor->exposure; + int max; + + max = sensor->pixel_array->crop[CCS_PA_PAD_SRC].height + + sensor->vblank->val + - CCS_LIM(sensor, COARSE_INTEGRATION_TIME_MAX_MARGIN); + + __v4l2_ctrl_modify_range(ctrl, ctrl->minimum, max, ctrl->step, max); +} + +/* + * Order matters. + * + * 1. Bits-per-pixel, descending. + * 2. Bits-per-pixel compressed, descending. + * 3. Pixel order, same as in pixel_order_str. Formats for all four pixel + * orders must be defined. + */ +static const struct ccs_csi_data_format ccs_csi_data_formats[] = { + { MEDIA_BUS_FMT_SGRBG16_1X16, 16, 16, CCS_PIXEL_ORDER_GRBG, }, + { MEDIA_BUS_FMT_SRGGB16_1X16, 16, 16, CCS_PIXEL_ORDER_RGGB, }, + { MEDIA_BUS_FMT_SBGGR16_1X16, 16, 16, CCS_PIXEL_ORDER_BGGR, }, + { MEDIA_BUS_FMT_SGBRG16_1X16, 16, 16, CCS_PIXEL_ORDER_GBRG, }, + { MEDIA_BUS_FMT_SGRBG14_1X14, 14, 14, CCS_PIXEL_ORDER_GRBG, }, + { MEDIA_BUS_FMT_SRGGB14_1X14, 14, 14, CCS_PIXEL_ORDER_RGGB, }, + { MEDIA_BUS_FMT_SBGGR14_1X14, 14, 14, CCS_PIXEL_ORDER_BGGR, }, + { MEDIA_BUS_FMT_SGBRG14_1X14, 14, 14, CCS_PIXEL_ORDER_GBRG, }, + { MEDIA_BUS_FMT_SGRBG12_1X12, 12, 12, CCS_PIXEL_ORDER_GRBG, }, + { MEDIA_BUS_FMT_SRGGB12_1X12, 12, 12, CCS_PIXEL_ORDER_RGGB, }, + { MEDIA_BUS_FMT_SBGGR12_1X12, 12, 12, CCS_PIXEL_ORDER_BGGR, }, + { MEDIA_BUS_FMT_SGBRG12_1X12, 12, 12, CCS_PIXEL_ORDER_GBRG, }, + { MEDIA_BUS_FMT_SGRBG10_1X10, 10, 10, CCS_PIXEL_ORDER_GRBG, }, + { MEDIA_BUS_FMT_SRGGB10_1X10, 10, 10, CCS_PIXEL_ORDER_RGGB, }, + { MEDIA_BUS_FMT_SBGGR10_1X10, 10, 10, CCS_PIXEL_ORDER_BGGR, }, + { MEDIA_BUS_FMT_SGBRG10_1X10, 10, 10, CCS_PIXEL_ORDER_GBRG, }, + { MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, 10, 8, CCS_PIXEL_ORDER_GRBG, }, + { MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, 10, 8, CCS_PIXEL_ORDER_RGGB, }, + { MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, 10, 8, CCS_PIXEL_ORDER_BGGR, }, + { MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, 10, 8, CCS_PIXEL_ORDER_GBRG, }, + { MEDIA_BUS_FMT_SGRBG8_1X8, 8, 8, CCS_PIXEL_ORDER_GRBG, }, + { MEDIA_BUS_FMT_SRGGB8_1X8, 8, 8, CCS_PIXEL_ORDER_RGGB, }, + { MEDIA_BUS_FMT_SBGGR8_1X8, 8, 8, CCS_PIXEL_ORDER_BGGR, }, + { MEDIA_BUS_FMT_SGBRG8_1X8, 8, 8, CCS_PIXEL_ORDER_GBRG, }, +}; + +static const char *pixel_order_str[] = { "GRBG", "RGGB", "BGGR", "GBRG" }; + +#define to_csi_format_idx(fmt) (((unsigned long)(fmt) \ + - (unsigned long)ccs_csi_data_formats) \ + / sizeof(*ccs_csi_data_formats)) + +static u32 ccs_pixel_order(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int flip = 0; + + if (sensor->hflip) { + if (sensor->hflip->val) + flip |= CCS_IMAGE_ORIENTATION_HORIZONTAL_MIRROR; + + if (sensor->vflip->val) + flip |= CCS_IMAGE_ORIENTATION_VERTICAL_FLIP; + } + + flip ^= sensor->hvflip_inv_mask; + + dev_dbg(&client->dev, "flip %d\n", flip); + return sensor->default_pixel_order ^ flip; +} + +static void ccs_update_mbus_formats(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + unsigned int csi_format_idx = + to_csi_format_idx(sensor->csi_format) & ~3; + unsigned int internal_csi_format_idx = + to_csi_format_idx(sensor->internal_csi_format) & ~3; + unsigned int pixel_order = ccs_pixel_order(sensor); + + sensor->mbus_frame_fmts = + sensor->default_mbus_frame_fmts << pixel_order; + sensor->csi_format = + &ccs_csi_data_formats[csi_format_idx + pixel_order]; + sensor->internal_csi_format = + &ccs_csi_data_formats[internal_csi_format_idx + + pixel_order]; + + BUG_ON(max(internal_csi_format_idx, csi_format_idx) + pixel_order + >= ARRAY_SIZE(ccs_csi_data_formats)); + + dev_dbg(&client->dev, "new pixel order %s\n", + pixel_order_str[pixel_order]); +} + +static const char * const ccs_test_patterns[] = { + "Disabled", + "Solid Colour", + "Eight Vertical Colour Bars", + "Colour Bars With Fade to Grey", + "Pseudorandom Sequence (PN9)", +}; + +static int ccs_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ccs_sensor *sensor = + container_of(ctrl->handler, struct ccs_subdev, ctrl_handler) + ->sensor; + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int pm_status; + u32 orient = 0; + unsigned int i; + int exposure; + int rval; + + switch (ctrl->id) { + case V4L2_CID_HFLIP: + case V4L2_CID_VFLIP: + if (sensor->streaming) + return -EBUSY; + + if (sensor->hflip->val) + orient |= CCS_IMAGE_ORIENTATION_HORIZONTAL_MIRROR; + + if (sensor->vflip->val) + orient |= CCS_IMAGE_ORIENTATION_VERTICAL_FLIP; + + orient ^= sensor->hvflip_inv_mask; + + ccs_update_mbus_formats(sensor); + + break; + case V4L2_CID_VBLANK: + exposure = sensor->exposure->val; + + __ccs_update_exposure_limits(sensor); + + if (exposure > sensor->exposure->maximum) { + sensor->exposure->val = sensor->exposure->maximum; + rval = ccs_set_ctrl(sensor->exposure); + if (rval < 0) + return rval; + } + + break; + case V4L2_CID_LINK_FREQ: + if (sensor->streaming) + return -EBUSY; + + rval = ccs_pll_update(sensor); + if (rval) + return rval; + + return 0; + case V4L2_CID_TEST_PATTERN: + for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) + v4l2_ctrl_activate( + sensor->test_data[i], + ctrl->val == + V4L2_SMIAPP_TEST_PATTERN_MODE_SOLID_COLOUR); + + break; + } + + pm_status = pm_runtime_get_if_active(&client->dev, true); + if (!pm_status) + return 0; + + switch (ctrl->id) { + case V4L2_CID_ANALOGUE_GAIN: + rval = ccs_write(sensor, ANALOG_GAIN_CODE_GLOBAL, ctrl->val); + + break; + case V4L2_CID_EXPOSURE: + rval = ccs_write(sensor, COARSE_INTEGRATION_TIME, ctrl->val); + + break; + case V4L2_CID_HFLIP: + case V4L2_CID_VFLIP: + rval = ccs_write(sensor, IMAGE_ORIENTATION, orient); + + break; + case V4L2_CID_VBLANK: + rval = ccs_write(sensor, FRAME_LENGTH_LINES, + sensor->pixel_array->crop[ + CCS_PA_PAD_SRC].height + + ctrl->val); + + break; + case V4L2_CID_HBLANK: + rval = ccs_write(sensor, LINE_LENGTH_PCK, + sensor->pixel_array->crop[ + CCS_PA_PAD_SRC].width + + ctrl->val); + + break; + case V4L2_CID_TEST_PATTERN: + rval = ccs_write(sensor, TEST_PATTERN_MODE, ctrl->val); + + break; + case V4L2_CID_TEST_PATTERN_RED: + rval = ccs_write(sensor, TEST_DATA_RED, ctrl->val); + + break; + case V4L2_CID_TEST_PATTERN_GREENR: + rval = ccs_write(sensor, TEST_DATA_GREENR, ctrl->val); + + break; + case V4L2_CID_TEST_PATTERN_BLUE: + rval = ccs_write(sensor, TEST_DATA_BLUE, ctrl->val); + + break; + case V4L2_CID_TEST_PATTERN_GREENB: + rval = ccs_write(sensor, TEST_DATA_GREENB, ctrl->val); + + break; + case V4L2_CID_PIXEL_RATE: + /* For v4l2_ctrl_s_ctrl_int64() used internally. */ + rval = 0; + + break; + default: + rval = -EINVAL; + } + + if (pm_status > 0) { + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); + } + + return rval; +} + +static const struct v4l2_ctrl_ops ccs_ctrl_ops = { + .s_ctrl = ccs_set_ctrl, +}; + +static int ccs_init_controls(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int rval; + + rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 12); + if (rval) + return rval; + + sensor->pixel_array->ctrl_handler.lock = &sensor->mutex; + + sensor->analog_gain = v4l2_ctrl_new_std( + &sensor->pixel_array->ctrl_handler, &ccs_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, + CCS_LIM(sensor, ANALOG_GAIN_CODE_MIN), + CCS_LIM(sensor, ANALOG_GAIN_CODE_MAX), + max(CCS_LIM(sensor, ANALOG_GAIN_CODE_STEP), 1U), + CCS_LIM(sensor, ANALOG_GAIN_CODE_MIN)); + + /* Exposure limits will be updated soon, use just something here. */ + sensor->exposure = v4l2_ctrl_new_std( + &sensor->pixel_array->ctrl_handler, &ccs_ctrl_ops, + V4L2_CID_EXPOSURE, 0, 0, 1, 0); + + sensor->hflip = v4l2_ctrl_new_std( + &sensor->pixel_array->ctrl_handler, &ccs_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + sensor->vflip = v4l2_ctrl_new_std( + &sensor->pixel_array->ctrl_handler, &ccs_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + + sensor->vblank = v4l2_ctrl_new_std( + &sensor->pixel_array->ctrl_handler, &ccs_ctrl_ops, + V4L2_CID_VBLANK, 0, 1, 1, 0); + + if (sensor->vblank) + sensor->vblank->flags |= V4L2_CTRL_FLAG_UPDATE; + + sensor->hblank = v4l2_ctrl_new_std( + &sensor->pixel_array->ctrl_handler, &ccs_ctrl_ops, + V4L2_CID_HBLANK, 0, 1, 1, 0); + + if (sensor->hblank) + sensor->hblank->flags |= V4L2_CTRL_FLAG_UPDATE; + + sensor->pixel_rate_parray = v4l2_ctrl_new_std( + &sensor->pixel_array->ctrl_handler, &ccs_ctrl_ops, + V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1); + + v4l2_ctrl_new_std_menu_items(&sensor->pixel_array->ctrl_handler, + &ccs_ctrl_ops, V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ccs_test_patterns) - 1, + 0, 0, ccs_test_patterns); + + if (sensor->pixel_array->ctrl_handler.error) { + dev_err(&client->dev, + "pixel array controls initialization failed (%d)\n", + sensor->pixel_array->ctrl_handler.error); + return sensor->pixel_array->ctrl_handler.error; + } + + sensor->pixel_array->sd.ctrl_handler = + &sensor->pixel_array->ctrl_handler; + + v4l2_ctrl_cluster(2, &sensor->hflip); + + rval = v4l2_ctrl_handler_init(&sensor->src->ctrl_handler, 0); + if (rval) + return rval; + + sensor->src->ctrl_handler.lock = &sensor->mutex; + + sensor->pixel_rate_csi = v4l2_ctrl_new_std( + &sensor->src->ctrl_handler, &ccs_ctrl_ops, + V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1); + + if (sensor->src->ctrl_handler.error) { + dev_err(&client->dev, + "src controls initialization failed (%d)\n", + sensor->src->ctrl_handler.error); + return sensor->src->ctrl_handler.error; + } + + sensor->src->sd.ctrl_handler = &sensor->src->ctrl_handler; + + return 0; +} + +/* + * For controls that require information on available media bus codes + * and linke frequencies. + */ +static int ccs_init_late_controls(struct ccs_sensor *sensor) +{ + unsigned long *valid_link_freqs = &sensor->valid_link_freqs[ + sensor->csi_format->compressed - sensor->compressed_min_bpp]; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) { + int max_value = (1 << sensor->csi_format->width) - 1; + + sensor->test_data[i] = v4l2_ctrl_new_std( + &sensor->pixel_array->ctrl_handler, + &ccs_ctrl_ops, V4L2_CID_TEST_PATTERN_RED + i, + 0, max_value, 1, max_value); + } + + sensor->link_freq = v4l2_ctrl_new_int_menu( + &sensor->src->ctrl_handler, &ccs_ctrl_ops, + V4L2_CID_LINK_FREQ, __fls(*valid_link_freqs), + __ffs(*valid_link_freqs), sensor->hwcfg->op_sys_clock); + + return sensor->src->ctrl_handler.error; +} + +static void ccs_free_controls(struct ccs_sensor *sensor) +{ + unsigned int i; + + for (i = 0; i < sensor->ssds_used; i++) + v4l2_ctrl_handler_free(&sensor->ssds[i].ctrl_handler); +} + +static int ccs_get_mbus_formats(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + struct smiapp_pll *pll = &sensor->pll; + u8 compressed_max_bpp = 0; + unsigned int type, n; + unsigned int i, pixel_order; + int rval; + + type = CCS_LIM(sensor, DATA_FORMAT_MODEL_TYPE); + + dev_dbg(&client->dev, "data_format_model_type %d\n", type); + + rval = ccs_read(sensor, PIXEL_ORDER, &pixel_order); + if (rval) + return rval; + + if (pixel_order >= ARRAY_SIZE(pixel_order_str)) { + dev_dbg(&client->dev, "bad pixel order %d\n", pixel_order); + return -EINVAL; + } + + dev_dbg(&client->dev, "pixel order %d (%s)\n", pixel_order, + pixel_order_str[pixel_order]); + + switch (type) { + case CCS_DATA_FORMAT_MODEL_TYPE_NORMAL: + n = SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL_N; + break; + case CCS_DATA_FORMAT_MODEL_TYPE_EXTENDED: + n = CCS_LIM_DATA_FORMAT_DESCRIPTOR_MAX_N + 1; + break; + default: + return -EINVAL; + } + + sensor->default_pixel_order = pixel_order; + sensor->mbus_frame_fmts = 0; + + for (i = 0; i < n; i++) { + unsigned int fmt, j; + + fmt = CCS_LIM_AT(sensor, DATA_FORMAT_DESCRIPTOR, i); + + dev_dbg(&client->dev, "%u: bpp %u, compressed %u\n", + i, fmt >> 8, (u8)fmt); + + for (j = 0; j < ARRAY_SIZE(ccs_csi_data_formats); j++) { + const struct ccs_csi_data_format *f = + &ccs_csi_data_formats[j]; + + if (f->pixel_order != CCS_PIXEL_ORDER_GRBG) + continue; + + if (f->width != fmt >> + CCS_DATA_FORMAT_DESCRIPTOR_UNCOMPRESSED_SHIFT || + f->compressed != + (fmt & CCS_DATA_FORMAT_DESCRIPTOR_COMPRESSED_MASK)) + continue; + + dev_dbg(&client->dev, "jolly good! %d\n", j); + + sensor->default_mbus_frame_fmts |= 1 << j; + } + } + + /* Figure out which BPP values can be used with which formats. */ + pll->binning_horizontal = 1; + pll->binning_vertical = 1; + pll->scale_m = sensor->scale_m; + + for (i = 0; i < ARRAY_SIZE(ccs_csi_data_formats); i++) { + sensor->compressed_min_bpp = + min(ccs_csi_data_formats[i].compressed, + sensor->compressed_min_bpp); + compressed_max_bpp = + max(ccs_csi_data_formats[i].compressed, + compressed_max_bpp); + } + + sensor->valid_link_freqs = devm_kcalloc( + &client->dev, + compressed_max_bpp - sensor->compressed_min_bpp + 1, + sizeof(*sensor->valid_link_freqs), GFP_KERNEL); + if (!sensor->valid_link_freqs) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(ccs_csi_data_formats); i++) { + const struct ccs_csi_data_format *f = + &ccs_csi_data_formats[i]; + unsigned long *valid_link_freqs = + &sensor->valid_link_freqs[ + f->compressed - sensor->compressed_min_bpp]; + unsigned int j; + + if (!(sensor->default_mbus_frame_fmts & 1 << i)) + continue; + + pll->bits_per_pixel = f->compressed; + + for (j = 0; sensor->hwcfg->op_sys_clock[j]; j++) { + pll->link_freq = sensor->hwcfg->op_sys_clock[j]; + + rval = ccs_pll_try(sensor, pll); + dev_dbg(&client->dev, "link freq %u Hz, bpp %u %s\n", + pll->link_freq, pll->bits_per_pixel, + rval ? "not ok" : "ok"); + if (rval) + continue; + + set_bit(j, valid_link_freqs); + } + + if (!*valid_link_freqs) { + dev_info(&client->dev, + "no valid link frequencies for %u bpp\n", + f->compressed); + sensor->default_mbus_frame_fmts &= ~BIT(i); + continue; + } + + if (!sensor->csi_format + || f->width > sensor->csi_format->width + || (f->width == sensor->csi_format->width + && f->compressed > sensor->csi_format->compressed)) { + sensor->csi_format = f; + sensor->internal_csi_format = f; + } + } + + if (!sensor->csi_format) { + dev_err(&client->dev, "no supported mbus code found\n"); + return -EINVAL; + } + + ccs_update_mbus_formats(sensor); + + return 0; +} + +static void ccs_update_blanking(struct ccs_sensor *sensor) +{ + struct v4l2_ctrl *vblank = sensor->vblank; + struct v4l2_ctrl *hblank = sensor->hblank; + uint16_t min_fll, max_fll, min_llp, max_llp, min_lbp; + int min, max; + + if (sensor->binning_vertical > 1 || sensor->binning_horizontal > 1) { + min_fll = CCS_LIM(sensor, MIN_FRAME_LENGTH_LINES_BIN); + max_fll = CCS_LIM(sensor, MAX_FRAME_LENGTH_LINES_BIN); + min_llp = CCS_LIM(sensor, MIN_LINE_LENGTH_PCK_BIN); + max_llp = CCS_LIM(sensor, MAX_LINE_LENGTH_PCK_BIN); + min_lbp = CCS_LIM(sensor, MIN_LINE_BLANKING_PCK_BIN); + } else { + min_fll = CCS_LIM(sensor, MIN_FRAME_LENGTH_LINES); + max_fll = CCS_LIM(sensor, MAX_FRAME_LENGTH_LINES); + min_llp = CCS_LIM(sensor, MIN_LINE_LENGTH_PCK); + max_llp = CCS_LIM(sensor, MAX_LINE_LENGTH_PCK); + min_lbp = CCS_LIM(sensor, MIN_LINE_BLANKING_PCK); + } + + min = max_t(int, + CCS_LIM(sensor, MIN_FRAME_BLANKING_LINES), + min_fll - + sensor->pixel_array->crop[CCS_PA_PAD_SRC].height); + max = max_fll - sensor->pixel_array->crop[CCS_PA_PAD_SRC].height; + + __v4l2_ctrl_modify_range(vblank, min, max, vblank->step, min); + + min = max_t(int, + min_llp - + sensor->pixel_array->crop[CCS_PA_PAD_SRC].width, + min_lbp); + max = max_llp - sensor->pixel_array->crop[CCS_PA_PAD_SRC].width; + + __v4l2_ctrl_modify_range(hblank, min, max, hblank->step, min); + + __ccs_update_exposure_limits(sensor); +} + +static int ccs_pll_blanking_update(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int rval; + + rval = ccs_pll_update(sensor); + if (rval < 0) + return rval; + + /* Output from pixel array, including blanking */ + ccs_update_blanking(sensor); + + dev_dbg(&client->dev, "vblank\t\t%d\n", sensor->vblank->val); + dev_dbg(&client->dev, "hblank\t\t%d\n", sensor->hblank->val); + + dev_dbg(&client->dev, "real timeperframe\t100/%d\n", + sensor->pll.pixel_rate_pixel_array / + ((sensor->pixel_array->crop[CCS_PA_PAD_SRC].width + + sensor->hblank->val) * + (sensor->pixel_array->crop[CCS_PA_PAD_SRC].height + + sensor->vblank->val) / 100)); + + return 0; +} + +/* + * + * SMIA++ NVM handling + * + */ + +static int ccs_read_nvm_page(struct ccs_sensor *sensor, u32 p, u8 *nvm, + u8 *status) +{ + unsigned int i; + int rval; + u32 s; + + *status = 0; + + rval = ccs_write(sensor, DATA_TRANSFER_IF_1_PAGE_SELECT, p); + if (rval) + return rval; + + rval = ccs_write(sensor, DATA_TRANSFER_IF_1_CTRL, + CCS_DATA_TRANSFER_IF_1_CTRL_ENABLE); + if (rval) + return rval; + + rval = ccs_read(sensor, DATA_TRANSFER_IF_1_STATUS, &s); + if (rval) + return rval; + + if (s & CCS_DATA_TRANSFER_IF_1_STATUS_IMPROPER_IF_USAGE) { + *status = s; + return -ENODATA; + } + + if (CCS_LIM(sensor, DATA_TRANSFER_IF_CAPABILITY) & + CCS_DATA_TRANSFER_IF_CAPABILITY_POLLING) { + for (i = 1000; i > 0; i--) { + if (s & CCS_DATA_TRANSFER_IF_1_STATUS_READ_IF_READY) + break; + + rval = ccs_read(sensor, DATA_TRANSFER_IF_1_STATUS, &s); + if (rval) + return rval; + } + + if (!i) + return -ETIMEDOUT; + } + + for (i = 0; i <= CCS_LIM_DATA_TRANSFER_IF_1_DATA_MAX_P; i++) { + u32 v; + + rval = ccs_read(sensor, DATA_TRANSFER_IF_1_DATA(i), &v); + if (rval) + return rval; + + *nvm++ = v; + } + + return 0; +} + +static int ccs_read_nvm(struct ccs_sensor *sensor, unsigned char *nvm, + size_t nvm_size) +{ + u8 status = 0; + u32 p; + int rval = 0, rval2; + + for (p = 0; p < nvm_size / (CCS_LIM_DATA_TRANSFER_IF_1_DATA_MAX_P + 1) + && !rval; p++) { + rval = ccs_read_nvm_page(sensor, p, nvm, &status); + nvm += CCS_LIM_DATA_TRANSFER_IF_1_DATA_MAX_P + 1; + } + + if (rval == -ENODATA && + status & CCS_DATA_TRANSFER_IF_1_STATUS_IMPROPER_IF_USAGE) + rval = 0; + + rval2 = ccs_write(sensor, DATA_TRANSFER_IF_1_CTRL, 0); + if (rval < 0) + return rval; + else + return rval2 ?: p * (CCS_LIM_DATA_TRANSFER_IF_1_DATA_MAX_P + 1); +} + +/* + * + * SMIA++ CCI address control + * + */ +static int ccs_change_cci_addr(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int rval; + u32 val; + + client->addr = sensor->hwcfg->i2c_addr_dfl; + + rval = ccs_write(sensor, CCI_ADDRESS_CTRL, + sensor->hwcfg->i2c_addr_alt << 1); + if (rval) + return rval; + + client->addr = sensor->hwcfg->i2c_addr_alt; + + /* verify addr change went ok */ + rval = ccs_read(sensor, CCI_ADDRESS_CTRL, &val); + if (rval) + return rval; + + if (val != sensor->hwcfg->i2c_addr_alt << 1) + return -ENODEV; + + return 0; +} + +/* + * + * SMIA++ Mode Control + * + */ +static int ccs_setup_flash_strobe(struct ccs_sensor *sensor) +{ + struct ccs_flash_strobe_parms *strobe_setup; + unsigned int ext_freq = sensor->hwcfg->ext_clk; + u32 tmp; + u32 strobe_adjustment; + u32 strobe_width_high_rs; + int rval; + + strobe_setup = sensor->hwcfg->strobe_setup; + + /* + * How to calculate registers related to strobe length. Please + * do not change, or if you do at least know what you're + * doing. :-) + * + * Sakari Ailus 2010-10-25 + * + * flash_strobe_length [us] / 10^6 = (tFlash_strobe_width_ctrl + * / EXTCLK freq [Hz]) * flash_strobe_adjustment + * + * tFlash_strobe_width_ctrl E N, [1 - 0xffff] + * flash_strobe_adjustment E N, [1 - 0xff] + * + * The formula above is written as below to keep it on one + * line: + * + * l / 10^6 = w / e * a + * + * Let's mark w * a by x: + * + * x = w * a + * + * Thus, we get: + * + * x = l * e / 10^6 + * + * The strobe width must be at least as long as requested, + * thus rounding upwards is needed. + * + * x = (l * e + 10^6 - 1) / 10^6 + * ----------------------------- + * + * Maximum possible accuracy is wanted at all times. Thus keep + * a as small as possible. + * + * Calculate a, assuming maximum w, with rounding upwards: + * + * a = (x + (2^16 - 1) - 1) / (2^16 - 1) + * ------------------------------------- + * + * Thus, we also get w, with that a, with rounding upwards: + * + * w = (x + a - 1) / a + * ------------------- + * + * To get limits: + * + * x E [1, (2^16 - 1) * (2^8 - 1)] + * + * Substituting maximum x to the original formula (with rounding), + * the maximum l is thus + * + * (2^16 - 1) * (2^8 - 1) * 10^6 = l * e + 10^6 - 1 + * + * l = (10^6 * (2^16 - 1) * (2^8 - 1) - 10^6 + 1) / e + * -------------------------------------------------- + * + * flash_strobe_length must be clamped between 1 and + * (10^6 * (2^16 - 1) * (2^8 - 1) - 10^6 + 1) / EXTCLK freq. + * + * Then, + * + * flash_strobe_adjustment = ((flash_strobe_length * + * EXTCLK freq + 10^6 - 1) / 10^6 + (2^16 - 1) - 1) / (2^16 - 1) + * + * tFlash_strobe_width_ctrl = ((flash_strobe_length * + * EXTCLK freq + 10^6 - 1) / 10^6 + + * flash_strobe_adjustment - 1) / flash_strobe_adjustment + */ + tmp = div_u64(1000000ULL * ((1 << 16) - 1) * ((1 << 8) - 1) - + 1000000 + 1, ext_freq); + strobe_setup->strobe_width_high_us = + clamp_t(u32, strobe_setup->strobe_width_high_us, 1, tmp); + + tmp = div_u64(((u64)strobe_setup->strobe_width_high_us * (u64)ext_freq + + 1000000 - 1), 1000000ULL); + strobe_adjustment = (tmp + (1 << 16) - 1 - 1) / ((1 << 16) - 1); + strobe_width_high_rs = (tmp + strobe_adjustment - 1) / + strobe_adjustment; + + rval = ccs_write(sensor, FLASH_MODE_RS, strobe_setup->mode); + if (rval < 0) + goto out; + + rval = ccs_write(sensor, FLASH_STROBE_ADJUSTMENT, strobe_adjustment); + if (rval < 0) + goto out; + + rval = ccs_write(sensor, TFLASH_STROBE_WIDTH_HIGH_RS_CTRL, + strobe_width_high_rs); + if (rval < 0) + goto out; + + rval = ccs_write(sensor, TFLASH_STROBE_DELAY_RS_CTRL, + strobe_setup->strobe_delay); + if (rval < 0) + goto out; + + rval = ccs_write(sensor, FLASH_STROBE_START_POINT, + strobe_setup->stobe_start_point); + if (rval < 0) + goto out; + + rval = ccs_write(sensor, FLASH_TRIGGER_RS, strobe_setup->trigger); + +out: + sensor->hwcfg->strobe_setup->trigger = 0; + + return rval; +} + +/* ----------------------------------------------------------------------------- + * Power management + */ + +static int ccs_power_on(struct device *dev) +{ + struct v4l2_subdev *subdev = dev_get_drvdata(dev); + struct ccs_subdev *ssd = to_ccs_subdev(subdev); + /* + * The sub-device related to the I2C device is always the + * source one, i.e. ssds[0]. + */ + struct ccs_sensor *sensor = + container_of(ssd, struct ccs_sensor, ssds[0]); + unsigned int sleep; + int rval; + + rval = regulator_enable(sensor->vana); + if (rval) { + dev_err(dev, "failed to enable vana regulator\n"); + return rval; + } + usleep_range(1000, 1000); + + rval = clk_prepare_enable(sensor->ext_clk); + if (rval < 0) { + dev_dbg(dev, "failed to enable xclk\n"); + goto out_xclk_fail; + } + usleep_range(1000, 1000); + + gpiod_set_value(sensor->xshutdown, 1); + + sleep = SMIAPP_RESET_DELAY(sensor->hwcfg->ext_clk); + usleep_range(sleep, sleep); + + /* + * Failures to respond to the address change command have been noticed. + * Those failures seem to be caused by the sensor requiring a longer + * boot time than advertised. An additional 10ms delay seems to work + * around the issue, but the SMIA++ I2C write retry hack makes the delay + * unnecessary. The failures need to be investigated to find a proper + * fix, and a delay will likely need to be added here if the I2C write + * retry hack is reverted before the root cause of the boot time issue + * is found. + */ + + if (sensor->hwcfg->i2c_addr_alt) { + rval = ccs_change_cci_addr(sensor); + if (rval) { + dev_err(dev, "cci address change error\n"); + goto out_cci_addr_fail; + } + } + + rval = ccs_write(sensor, SOFTWARE_RESET, CCS_SOFTWARE_RESET_ON); + if (rval < 0) { + dev_err(dev, "software reset failed\n"); + goto out_cci_addr_fail; + } + + if (sensor->hwcfg->i2c_addr_alt) { + rval = ccs_change_cci_addr(sensor); + if (rval) { + dev_err(dev, "cci address change error\n"); + goto out_cci_addr_fail; + } + } + + rval = ccs_write(sensor, COMPRESSION_MODE, + CCS_COMPRESSION_MODE_DPCM_PCM_SIMPLE); + if (rval) { + dev_err(dev, "compression mode set failed\n"); + goto out_cci_addr_fail; + } + + rval = ccs_write(sensor, EXTCLK_FREQUENCY_MHZ, + sensor->hwcfg->ext_clk / (1000000 / (1 << 8))); + if (rval) { + dev_err(dev, "extclk frequency set failed\n"); + goto out_cci_addr_fail; + } + + rval = ccs_write(sensor, CSI_LANE_MODE, sensor->hwcfg->lanes - 1); + if (rval) { + dev_err(dev, "csi lane mode set failed\n"); + goto out_cci_addr_fail; + } + + rval = ccs_write(sensor, FAST_STANDBY_CTRL, + CCS_FAST_STANDBY_CTRL_FRAME_TRUNCATION); + if (rval) { + dev_err(dev, "fast standby set failed\n"); + goto out_cci_addr_fail; + } + + rval = ccs_write(sensor, CSI_SIGNALING_MODE, + sensor->hwcfg->csi_signalling_mode); + if (rval) { + dev_err(dev, "csi signalling mode set failed\n"); + goto out_cci_addr_fail; + } + + /* DPHY control done by sensor based on requested link rate */ + rval = ccs_write(sensor, PHY_CTRL, CCS_PHY_CTRL_UI); + if (rval < 0) + goto out_cci_addr_fail; + + rval = ccs_call_quirk(sensor, post_poweron); + if (rval) { + dev_err(dev, "post_poweron quirks failed\n"); + goto out_cci_addr_fail; + } + + return 0; + +out_cci_addr_fail: + gpiod_set_value(sensor->xshutdown, 0); + clk_disable_unprepare(sensor->ext_clk); + +out_xclk_fail: + regulator_disable(sensor->vana); + + return rval; +} + +static int ccs_power_off(struct device *dev) +{ + struct v4l2_subdev *subdev = dev_get_drvdata(dev); + struct ccs_subdev *ssd = to_ccs_subdev(subdev); + struct ccs_sensor *sensor = + container_of(ssd, struct ccs_sensor, ssds[0]); + + /* + * Currently power/clock to lens are enable/disabled separately + * but they are essentially the same signals. So if the sensor is + * powered off while the lens is powered on the sensor does not + * really see a power off and next time the cci address change + * will fail. So do a soft reset explicitly here. + */ + if (sensor->hwcfg->i2c_addr_alt) + ccs_write(sensor, SOFTWARE_RESET, CCS_SOFTWARE_RESET_ON); + + gpiod_set_value(sensor->xshutdown, 0); + clk_disable_unprepare(sensor->ext_clk); + usleep_range(5000, 5000); + regulator_disable(sensor->vana); + sensor->streaming = false; + + return 0; +} + +/* ----------------------------------------------------------------------------- + * Video stream management + */ + +static int ccs_start_streaming(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + unsigned int binning_mode; + int rval; + + mutex_lock(&sensor->mutex); + + rval = ccs_write(sensor, CSI_DATA_FORMAT, + (sensor->csi_format->width << 8) | + sensor->csi_format->compressed); + if (rval) + goto out; + + /* Binning configuration */ + if (sensor->binning_horizontal == 1 && + sensor->binning_vertical == 1) { + binning_mode = 0; + } else { + u8 binning_type = + (sensor->binning_horizontal << 4) + | sensor->binning_vertical; + + rval = ccs_write(sensor, BINNING_TYPE, binning_type); + if (rval < 0) + goto out; + + binning_mode = 1; + } + rval = ccs_write(sensor, BINNING_MODE, binning_mode); + if (rval < 0) + goto out; + + /* Set up PLL */ + rval = ccs_pll_configure(sensor); + if (rval) + goto out; + + /* Analog crop start coordinates */ + rval = ccs_write(sensor, X_ADDR_START, + sensor->pixel_array->crop[CCS_PA_PAD_SRC].left); + if (rval < 0) + goto out; + + rval = ccs_write(sensor, Y_ADDR_START, + sensor->pixel_array->crop[CCS_PA_PAD_SRC].top); + if (rval < 0) + goto out; + + /* Analog crop end coordinates */ + rval = ccs_write( + sensor, X_ADDR_END, + sensor->pixel_array->crop[CCS_PA_PAD_SRC].left + + sensor->pixel_array->crop[CCS_PA_PAD_SRC].width - 1); + if (rval < 0) + goto out; + + rval = ccs_write( + sensor, Y_ADDR_END, + sensor->pixel_array->crop[CCS_PA_PAD_SRC].top + + sensor->pixel_array->crop[CCS_PA_PAD_SRC].height - 1); + if (rval < 0) + goto out; + + /* + * Output from pixel array, including blanking, is set using + * controls below. No need to set here. + */ + + /* Digital crop */ + if (CCS_LIM(sensor, DIGITAL_CROP_CAPABILITY) + == CCS_DIGITAL_CROP_CAPABILITY_INPUT_CROP) { + rval = ccs_write( + sensor, DIGITAL_CROP_X_OFFSET, + sensor->scaler->crop[CCS_PAD_SINK].left); + if (rval < 0) + goto out; + + rval = ccs_write( + sensor, DIGITAL_CROP_Y_OFFSET, + sensor->scaler->crop[CCS_PAD_SINK].top); + if (rval < 0) + goto out; + + rval = ccs_write( + sensor, DIGITAL_CROP_IMAGE_WIDTH, + sensor->scaler->crop[CCS_PAD_SINK].width); + if (rval < 0) + goto out; + + rval = ccs_write( + sensor, DIGITAL_CROP_IMAGE_HEIGHT, + sensor->scaler->crop[CCS_PAD_SINK].height); + if (rval < 0) + goto out; + } + + /* Scaling */ + if (CCS_LIM(sensor, SCALING_CAPABILITY) + != CCS_SCALING_CAPABILITY_NONE) { + rval = ccs_write(sensor, SCALING_MODE, sensor->scaling_mode); + if (rval < 0) + goto out; + + rval = ccs_write(sensor, SCALE_M, sensor->scale_m); + if (rval < 0) + goto out; + } + + /* Output size from sensor */ + rval = ccs_write(sensor, X_OUTPUT_SIZE, + sensor->src->crop[CCS_PAD_SRC].width); + if (rval < 0) + goto out; + rval = ccs_write(sensor, Y_OUTPUT_SIZE, + sensor->src->crop[CCS_PAD_SRC].height); + if (rval < 0) + goto out; + + if (CCS_LIM(sensor, FLASH_MODE_CAPABILITY) & + (CCS_FLASH_MODE_CAPABILITY_SINGLE_STROBE | + SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE) && + sensor->hwcfg->strobe_setup != NULL && + sensor->hwcfg->strobe_setup->trigger != 0) { + rval = ccs_setup_flash_strobe(sensor); + if (rval) + goto out; + } + + rval = ccs_call_quirk(sensor, pre_streamon); + if (rval) { + dev_err(&client->dev, "pre_streamon quirks failed\n"); + goto out; + } + + rval = ccs_write(sensor, MODE_SELECT, CCS_MODE_SELECT_STREAMING); + +out: + mutex_unlock(&sensor->mutex); + + return rval; +} + +static int ccs_stop_streaming(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int rval; + + mutex_lock(&sensor->mutex); + rval = ccs_write(sensor, MODE_SELECT, CCS_MODE_SELECT_SOFTWARE_STANDBY); + if (rval) + goto out; + + rval = ccs_call_quirk(sensor, post_streamoff); + if (rval) + dev_err(&client->dev, "post_streamoff quirks failed\n"); + +out: + mutex_unlock(&sensor->mutex); + return rval; +} + +/* ----------------------------------------------------------------------------- + * V4L2 subdev video operations + */ + +static int ccs_pm_get_init(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int rval; + + rval = pm_runtime_get_sync(&client->dev); + if (rval < 0) { + if (rval != -EBUSY && rval != -EAGAIN) + pm_runtime_set_active(&client->dev); + pm_runtime_put_noidle(&client->dev); + + return rval; + } else if (!rval) { + rval = v4l2_ctrl_handler_setup(&sensor->pixel_array-> + ctrl_handler); + if (rval) + return rval; + + return v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler); + } + + return 0; +} + +static int ccs_set_stream(struct v4l2_subdev *subdev, int enable) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int rval; + + if (sensor->streaming == enable) + return 0; + + if (!enable) { + ccs_stop_streaming(sensor); + sensor->streaming = false; + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); + + return 0; + } + + rval = ccs_pm_get_init(sensor); + if (rval) + return rval; + + sensor->streaming = true; + + rval = ccs_start_streaming(sensor); + if (rval < 0) { + sensor->streaming = false; + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); + } + + return rval; +} + +static int ccs_enum_mbus_code(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct i2c_client *client = v4l2_get_subdevdata(subdev); + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + unsigned int i; + int idx = -1; + int rval = -EINVAL; + + mutex_lock(&sensor->mutex); + + dev_err(&client->dev, "subdev %s, pad %d, index %d\n", + subdev->name, code->pad, code->index); + + if (subdev != &sensor->src->sd || code->pad != CCS_PAD_SRC) { + if (code->index) + goto out; + + code->code = sensor->internal_csi_format->code; + rval = 0; + goto out; + } + + for (i = 0; i < ARRAY_SIZE(ccs_csi_data_formats); i++) { + if (sensor->mbus_frame_fmts & (1 << i)) + idx++; + + if (idx == code->index) { + code->code = ccs_csi_data_formats[i].code; + dev_err(&client->dev, "found index %d, i %d, code %x\n", + code->index, i, code->code); + rval = 0; + break; + } + } + +out: + mutex_unlock(&sensor->mutex); + + return rval; +} + +static u32 __ccs_get_mbus_code(struct v4l2_subdev *subdev, unsigned int pad) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + + if (subdev == &sensor->src->sd && pad == CCS_PAD_SRC) + return sensor->csi_format->code; + else + return sensor->internal_csi_format->code; +} + +static int __ccs_get_format(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ccs_subdev *ssd = to_ccs_subdev(subdev); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + fmt->format = *v4l2_subdev_get_try_format(subdev, cfg, + fmt->pad); + } else { + struct v4l2_rect *r; + + if (fmt->pad == ssd->source_pad) + r = &ssd->crop[ssd->source_pad]; + else + r = &ssd->sink_fmt; + + fmt->format.code = __ccs_get_mbus_code(subdev, fmt->pad); + fmt->format.width = r->width; + fmt->format.height = r->height; + fmt->format.field = V4L2_FIELD_NONE; + } + + return 0; +} + +static int ccs_get_format(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + int rval; + + mutex_lock(&sensor->mutex); + rval = __ccs_get_format(subdev, cfg, fmt); + mutex_unlock(&sensor->mutex); + + return rval; +} + +static void ccs_get_crop_compose(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_rect **crops, + struct v4l2_rect **comps, int which) +{ + struct ccs_subdev *ssd = to_ccs_subdev(subdev); + unsigned int i; + + if (which == V4L2_SUBDEV_FORMAT_ACTIVE) { + if (crops) + for (i = 0; i < subdev->entity.num_pads; i++) + crops[i] = &ssd->crop[i]; + if (comps) + *comps = &ssd->compose; + } else { + if (crops) { + for (i = 0; i < subdev->entity.num_pads; i++) { + crops[i] = v4l2_subdev_get_try_crop(subdev, cfg, i); + BUG_ON(!crops[i]); + } + } + if (comps) { + *comps = v4l2_subdev_get_try_compose(subdev, cfg, + CCS_PAD_SINK); + BUG_ON(!*comps); + } + } +} + +/* Changes require propagation only on sink pad. */ +static void ccs_propagate(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, int which, + int target) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + struct ccs_subdev *ssd = to_ccs_subdev(subdev); + struct v4l2_rect *comp, *crops[CCS_PADS]; + + ccs_get_crop_compose(subdev, cfg, crops, &comp, which); + + switch (target) { + case V4L2_SEL_TGT_CROP: + comp->width = crops[CCS_PAD_SINK]->width; + comp->height = crops[CCS_PAD_SINK]->height; + if (which == V4L2_SUBDEV_FORMAT_ACTIVE) { + if (ssd == sensor->scaler) { + sensor->scale_m = + CCS_LIM(sensor, SCALER_N_MIN); + sensor->scaling_mode = + CCS_SCALING_MODE_NO_SCALING; + } else if (ssd == sensor->binner) { + sensor->binning_horizontal = 1; + sensor->binning_vertical = 1; + } + } + fallthrough; + case V4L2_SEL_TGT_COMPOSE: + *crops[CCS_PAD_SRC] = *comp; + break; + default: + BUG(); + } +} + +static const struct ccs_csi_data_format +*ccs_validate_csi_data_format(struct ccs_sensor *sensor, u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ccs_csi_data_formats); i++) { + if (sensor->mbus_frame_fmts & (1 << i) && + ccs_csi_data_formats[i].code == code) + return &ccs_csi_data_formats[i]; + } + + return sensor->csi_format; +} + +static int ccs_set_format_source(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + const struct ccs_csi_data_format *csi_format, + *old_csi_format = sensor->csi_format; + unsigned long *valid_link_freqs; + u32 code = fmt->format.code; + unsigned int i; + int rval; + + rval = __ccs_get_format(subdev, cfg, fmt); + if (rval) + return rval; + + /* + * Media bus code is changeable on src subdev's source pad. On + * other source pads we just get format here. + */ + if (subdev != &sensor->src->sd) + return 0; + + csi_format = ccs_validate_csi_data_format(sensor, code); + + fmt->format.code = csi_format->code; + + if (fmt->which != V4L2_SUBDEV_FORMAT_ACTIVE) + return 0; + + sensor->csi_format = csi_format; + + if (csi_format->width != old_csi_format->width) + for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) + __v4l2_ctrl_modify_range( + sensor->test_data[i], 0, + (1 << csi_format->width) - 1, 1, 0); + + if (csi_format->compressed == old_csi_format->compressed) + return 0; + + valid_link_freqs = + &sensor->valid_link_freqs[sensor->csi_format->compressed + - sensor->compressed_min_bpp]; + + __v4l2_ctrl_modify_range( + sensor->link_freq, 0, + __fls(*valid_link_freqs), ~*valid_link_freqs, + __ffs(*valid_link_freqs)); + + return ccs_pll_update(sensor); +} + +static int ccs_set_format(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + struct ccs_subdev *ssd = to_ccs_subdev(subdev); + struct v4l2_rect *crops[CCS_PADS]; + + mutex_lock(&sensor->mutex); + + if (fmt->pad == ssd->source_pad) { + int rval; + + rval = ccs_set_format_source(subdev, cfg, fmt); + + mutex_unlock(&sensor->mutex); + + return rval; + } + + /* Sink pad. Width and height are changeable here. */ + fmt->format.code = __ccs_get_mbus_code(subdev, fmt->pad); + fmt->format.width &= ~1; + fmt->format.height &= ~1; + fmt->format.field = V4L2_FIELD_NONE; + + fmt->format.width = + clamp(fmt->format.width, + CCS_LIM(sensor, MIN_X_OUTPUT_SIZE), + CCS_LIM(sensor, MAX_X_OUTPUT_SIZE)); + fmt->format.height = + clamp(fmt->format.height, + CCS_LIM(sensor, MIN_Y_OUTPUT_SIZE), + CCS_LIM(sensor, MAX_Y_OUTPUT_SIZE)); + + ccs_get_crop_compose(subdev, cfg, crops, NULL, fmt->which); + + crops[ssd->sink_pad]->left = 0; + crops[ssd->sink_pad]->top = 0; + crops[ssd->sink_pad]->width = fmt->format.width; + crops[ssd->sink_pad]->height = fmt->format.height; + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) + ssd->sink_fmt = *crops[ssd->sink_pad]; + ccs_propagate(subdev, cfg, fmt->which, V4L2_SEL_TGT_CROP); + + mutex_unlock(&sensor->mutex); + + return 0; +} + +/* + * Calculate goodness of scaled image size compared to expected image + * size and flags provided. + */ +#define SCALING_GOODNESS 100000 +#define SCALING_GOODNESS_EXTREME 100000000 +static int scaling_goodness(struct v4l2_subdev *subdev, int w, int ask_w, + int h, int ask_h, u32 flags) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + struct i2c_client *client = v4l2_get_subdevdata(subdev); + int val = 0; + + w &= ~1; + ask_w &= ~1; + h &= ~1; + ask_h &= ~1; + + if (flags & V4L2_SEL_FLAG_GE) { + if (w < ask_w) + val -= SCALING_GOODNESS; + if (h < ask_h) + val -= SCALING_GOODNESS; + } + + if (flags & V4L2_SEL_FLAG_LE) { + if (w > ask_w) + val -= SCALING_GOODNESS; + if (h > ask_h) + val -= SCALING_GOODNESS; + } + + val -= abs(w - ask_w); + val -= abs(h - ask_h); + + if (w < CCS_LIM(sensor, MIN_X_OUTPUT_SIZE)) + val -= SCALING_GOODNESS_EXTREME; + + dev_dbg(&client->dev, "w %d ask_w %d h %d ask_h %d goodness %d\n", + w, ask_w, h, ask_h, val); + + return val; +} + +static void ccs_set_compose_binner(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel, + struct v4l2_rect **crops, + struct v4l2_rect *comp) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + unsigned int i; + unsigned int binh = 1, binv = 1; + int best = scaling_goodness( + subdev, + crops[CCS_PAD_SINK]->width, sel->r.width, + crops[CCS_PAD_SINK]->height, sel->r.height, sel->flags); + + for (i = 0; i < sensor->nbinning_subtypes; i++) { + int this = scaling_goodness( + subdev, + crops[CCS_PAD_SINK]->width + / sensor->binning_subtypes[i].horizontal, + sel->r.width, + crops[CCS_PAD_SINK]->height + / sensor->binning_subtypes[i].vertical, + sel->r.height, sel->flags); + + if (this > best) { + binh = sensor->binning_subtypes[i].horizontal; + binv = sensor->binning_subtypes[i].vertical; + best = this; + } + } + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + sensor->binning_vertical = binv; + sensor->binning_horizontal = binh; + } + + sel->r.width = (crops[CCS_PAD_SINK]->width / binh) & ~1; + sel->r.height = (crops[CCS_PAD_SINK]->height / binv) & ~1; +} + +/* + * Calculate best scaling ratio and mode for given output resolution. + * + * Try all of these: horizontal ratio, vertical ratio and smallest + * size possible (horizontally). + * + * Also try whether horizontal scaler or full scaler gives a better + * result. + */ +static void ccs_set_compose_scaler(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel, + struct v4l2_rect **crops, + struct v4l2_rect *comp) +{ + struct i2c_client *client = v4l2_get_subdevdata(subdev); + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + u32 min, max, a, b, max_m; + u32 scale_m = CCS_LIM(sensor, SCALER_N_MIN); + int mode = CCS_SCALING_MODE_HORIZONTAL; + u32 try[4]; + u32 ntry = 0; + unsigned int i; + int best = INT_MIN; + + sel->r.width = min_t(unsigned int, sel->r.width, + crops[CCS_PAD_SINK]->width); + sel->r.height = min_t(unsigned int, sel->r.height, + crops[CCS_PAD_SINK]->height); + + a = crops[CCS_PAD_SINK]->width + * CCS_LIM(sensor, SCALER_N_MIN) / sel->r.width; + b = crops[CCS_PAD_SINK]->height + * CCS_LIM(sensor, SCALER_N_MIN) / sel->r.height; + max_m = crops[CCS_PAD_SINK]->width + * CCS_LIM(sensor, SCALER_N_MIN) + / CCS_LIM(sensor, MIN_X_OUTPUT_SIZE); + + a = clamp(a, CCS_LIM(sensor, SCALER_M_MIN), + CCS_LIM(sensor, SCALER_M_MAX)); + b = clamp(b, CCS_LIM(sensor, SCALER_M_MIN), + CCS_LIM(sensor, SCALER_M_MAX)); + max_m = clamp(max_m, CCS_LIM(sensor, SCALER_M_MIN), + CCS_LIM(sensor, SCALER_M_MAX)); + + dev_dbg(&client->dev, "scaling: a %d b %d max_m %d\n", a, b, max_m); + + min = min(max_m, min(a, b)); + max = min(max_m, max(a, b)); + + try[ntry] = min; + ntry++; + if (min != max) { + try[ntry] = max; + ntry++; + } + if (max != max_m) { + try[ntry] = min + 1; + ntry++; + if (min != max) { + try[ntry] = max + 1; + ntry++; + } + } + + for (i = 0; i < ntry; i++) { + int this = scaling_goodness( + subdev, + crops[CCS_PAD_SINK]->width + / try[i] * CCS_LIM(sensor, SCALER_N_MIN), + sel->r.width, + crops[CCS_PAD_SINK]->height, + sel->r.height, + sel->flags); + + dev_dbg(&client->dev, "trying factor %d (%d)\n", try[i], i); + + if (this > best) { + scale_m = try[i]; + mode = CCS_SCALING_MODE_HORIZONTAL; + best = this; + } + + if (CCS_LIM(sensor, SCALING_CAPABILITY) + == CCS_SCALING_CAPABILITY_HORIZONTAL) + continue; + + this = scaling_goodness( + subdev, crops[CCS_PAD_SINK]->width + / try[i] + * CCS_LIM(sensor, SCALER_N_MIN), + sel->r.width, + crops[CCS_PAD_SINK]->height + / try[i] + * CCS_LIM(sensor, SCALER_N_MIN), + sel->r.height, + sel->flags); + + if (this > best) { + scale_m = try[i]; + mode = SMIAPP_SCALING_MODE_BOTH; + best = this; + } + } + + sel->r.width = + (crops[CCS_PAD_SINK]->width + / scale_m + * CCS_LIM(sensor, SCALER_N_MIN)) & ~1; + if (mode == SMIAPP_SCALING_MODE_BOTH) + sel->r.height = + (crops[CCS_PAD_SINK]->height + / scale_m + * CCS_LIM(sensor, SCALER_N_MIN)) + & ~1; + else + sel->r.height = crops[CCS_PAD_SINK]->height; + + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + sensor->scale_m = scale_m; + sensor->scaling_mode = mode; + } +} +/* We're only called on source pads. This function sets scaling. */ +static int ccs_set_compose(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + struct ccs_subdev *ssd = to_ccs_subdev(subdev); + struct v4l2_rect *comp, *crops[CCS_PADS]; + + ccs_get_crop_compose(subdev, cfg, crops, &comp, sel->which); + + sel->r.top = 0; + sel->r.left = 0; + + if (ssd == sensor->binner) + ccs_set_compose_binner(subdev, cfg, sel, crops, comp); + else + ccs_set_compose_scaler(subdev, cfg, sel, crops, comp); + + *comp = sel->r; + ccs_propagate(subdev, cfg, sel->which, V4L2_SEL_TGT_COMPOSE); + + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return ccs_pll_blanking_update(sensor); + + return 0; +} + +static int __ccs_sel_supported(struct v4l2_subdev *subdev, + struct v4l2_subdev_selection *sel) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + struct ccs_subdev *ssd = to_ccs_subdev(subdev); + + /* We only implement crop in three places. */ + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + case V4L2_SEL_TGT_CROP_BOUNDS: + if (ssd == sensor->pixel_array && sel->pad == CCS_PA_PAD_SRC) + return 0; + if (ssd == sensor->src && sel->pad == CCS_PAD_SRC) + return 0; + if (ssd == sensor->scaler && sel->pad == CCS_PAD_SINK && + CCS_LIM(sensor, DIGITAL_CROP_CAPABILITY) + == CCS_DIGITAL_CROP_CAPABILITY_INPUT_CROP) + return 0; + return -EINVAL; + case V4L2_SEL_TGT_NATIVE_SIZE: + if (ssd == sensor->pixel_array && sel->pad == CCS_PA_PAD_SRC) + return 0; + return -EINVAL; + case V4L2_SEL_TGT_COMPOSE: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + if (sel->pad == ssd->source_pad) + return -EINVAL; + if (ssd == sensor->binner) + return 0; + if (ssd == sensor->scaler && CCS_LIM(sensor, SCALING_CAPABILITY) + != CCS_SCALING_CAPABILITY_NONE) + return 0; + fallthrough; + default: + return -EINVAL; + } +} + +static int ccs_set_crop(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + struct ccs_subdev *ssd = to_ccs_subdev(subdev); + struct v4l2_rect *src_size, *crops[CCS_PADS]; + struct v4l2_rect _r; + + ccs_get_crop_compose(subdev, cfg, crops, NULL, sel->which); + + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + if (sel->pad == ssd->sink_pad) + src_size = &ssd->sink_fmt; + else + src_size = &ssd->compose; + } else { + if (sel->pad == ssd->sink_pad) { + _r.left = 0; + _r.top = 0; + _r.width = v4l2_subdev_get_try_format(subdev, cfg, sel->pad) + ->width; + _r.height = v4l2_subdev_get_try_format(subdev, cfg, sel->pad) + ->height; + src_size = &_r; + } else { + src_size = v4l2_subdev_get_try_compose( + subdev, cfg, ssd->sink_pad); + } + } + + if (ssd == sensor->src && sel->pad == CCS_PAD_SRC) { + sel->r.left = 0; + sel->r.top = 0; + } + + sel->r.width = min(sel->r.width, src_size->width); + sel->r.height = min(sel->r.height, src_size->height); + + sel->r.left = min_t(int, sel->r.left, src_size->width - sel->r.width); + sel->r.top = min_t(int, sel->r.top, src_size->height - sel->r.height); + + *crops[sel->pad] = sel->r; + + if (ssd != sensor->pixel_array && sel->pad == CCS_PAD_SINK) + ccs_propagate(subdev, cfg, sel->which, V4L2_SEL_TGT_CROP); + + return 0; +} + +static void ccs_get_native_size(struct ccs_subdev *ssd, struct v4l2_rect *r) +{ + r->top = 0; + r->left = 0; + r->width = CCS_LIM(ssd->sensor, X_ADDR_MAX) + 1; + r->height = CCS_LIM(ssd->sensor, Y_ADDR_MAX) + 1; +} + +static int __ccs_get_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + struct ccs_subdev *ssd = to_ccs_subdev(subdev); + struct v4l2_rect *comp, *crops[CCS_PADS]; + struct v4l2_rect sink_fmt; + int ret; + + ret = __ccs_sel_supported(subdev, sel); + if (ret) + return ret; + + ccs_get_crop_compose(subdev, cfg, crops, &comp, sel->which); + + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + sink_fmt = ssd->sink_fmt; + } else { + struct v4l2_mbus_framefmt *fmt = + v4l2_subdev_get_try_format(subdev, cfg, ssd->sink_pad); + + sink_fmt.left = 0; + sink_fmt.top = 0; + sink_fmt.width = fmt->width; + sink_fmt.height = fmt->height; + } + + switch (sel->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_NATIVE_SIZE: + if (ssd == sensor->pixel_array) + ccs_get_native_size(ssd, &sel->r); + else if (sel->pad == ssd->sink_pad) + sel->r = sink_fmt; + else + sel->r = *comp; + break; + case V4L2_SEL_TGT_CROP: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + sel->r = *crops[sel->pad]; + break; + case V4L2_SEL_TGT_COMPOSE: + sel->r = *comp; + break; + } + + return 0; +} + +static int ccs_get_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + int rval; + + mutex_lock(&sensor->mutex); + rval = __ccs_get_selection(subdev, cfg, sel); + mutex_unlock(&sensor->mutex); + + return rval; +} + +static int ccs_set_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + int ret; + + ret = __ccs_sel_supported(subdev, sel); + if (ret) + return ret; + + mutex_lock(&sensor->mutex); + + sel->r.left = max(0, sel->r.left & ~1); + sel->r.top = max(0, sel->r.top & ~1); + sel->r.width = CCS_ALIGN_DIM(sel->r.width, sel->flags); + sel->r.height = CCS_ALIGN_DIM(sel->r.height, sel->flags); + + sel->r.width = max_t(unsigned int, + CCS_LIM(sensor, MIN_X_OUTPUT_SIZE), + sel->r.width); + sel->r.height = max_t(unsigned int, + CCS_LIM(sensor, MIN_Y_OUTPUT_SIZE), + sel->r.height); + + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + ret = ccs_set_crop(subdev, cfg, sel); + break; + case V4L2_SEL_TGT_COMPOSE: + ret = ccs_set_compose(subdev, cfg, sel); + break; + default: + ret = -EINVAL; + } + + mutex_unlock(&sensor->mutex); + return ret; +} + +static int ccs_get_skip_frames(struct v4l2_subdev *subdev, u32 *frames) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + + *frames = sensor->frame_skip; + return 0; +} + +static int ccs_get_skip_top_lines(struct v4l2_subdev *subdev, u32 *lines) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + + *lines = sensor->image_start; + + return 0; +} + +/* ----------------------------------------------------------------------------- + * sysfs attributes + */ + +static ssize_t +ccs_sysfs_nvm_read(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct v4l2_subdev *subdev = i2c_get_clientdata(to_i2c_client(dev)); + struct i2c_client *client = v4l2_get_subdevdata(subdev); + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + int rval; + + if (!sensor->dev_init_done) + return -EBUSY; + + rval = ccs_pm_get_init(sensor); + if (rval < 0) + return -ENODEV; + + rval = ccs_read_nvm(sensor, buf, PAGE_SIZE); + if (rval < 0) { + pm_runtime_put(&client->dev); + dev_err(&client->dev, "nvm read failed\n"); + return -ENODEV; + } + + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); + + /* + * NVM is still way below a PAGE_SIZE, so we can safely + * assume this for now. + */ + return rval; +} +static DEVICE_ATTR(nvm, S_IRUGO, ccs_sysfs_nvm_read, NULL); + +static ssize_t +ccs_sysfs_ident_read(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct v4l2_subdev *subdev = i2c_get_clientdata(to_i2c_client(dev)); + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + struct ccs_module_info *minfo = &sensor->minfo; + + if (minfo->mipi_manufacturer_id) + return snprintf(buf, PAGE_SIZE, "%4.4x%4.4x%2.2x\n", + minfo->mipi_manufacturer_id, minfo->model_id, + minfo->revision_number_major) + 1; + else + return snprintf(buf, PAGE_SIZE, "%2.2x%4.4x%2.2x\n", + minfo->smia_manufacturer_id, minfo->model_id, + minfo->revision_number_major) + 1; +} + +static DEVICE_ATTR(ident, S_IRUGO, ccs_sysfs_ident_read, NULL); + +/* ----------------------------------------------------------------------------- + * V4L2 subdev core operations + */ + +static int ccs_identify_module(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + struct ccs_module_info *minfo = &sensor->minfo; + unsigned int i; + int rval = 0; + + /* Module info */ + rval = ccs_read(sensor, MODULE_MANUFACTURER_ID, + &minfo->mipi_manufacturer_id); + if (!rval && !minfo->mipi_manufacturer_id) + rval = ccs_read_addr_8only(sensor, + SMIAPP_REG_U8_MANUFACTURER_ID, + &minfo->smia_manufacturer_id); + if (!rval) + rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_MODEL_ID, + &minfo->model_id); + if (!rval) + rval = ccs_read_addr_8only(sensor, + CCS_R_MODULE_REVISION_NUMBER_MAJOR, + &minfo->revision_number_major); + if (!rval) + rval = ccs_read_addr_8only(sensor, + CCS_R_MODULE_REVISION_NUMBER_MINOR, + &minfo->revision_number_minor); + if (!rval) + rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_YEAR, + &minfo->module_year); + if (!rval) + rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_MONTH, + &minfo->module_month); + if (!rval) + rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_DAY, + &minfo->module_day); + + /* Sensor info */ + if (!rval) + rval = ccs_read(sensor, SENSOR_MANUFACTURER_ID, + &minfo->sensor_mipi_manufacturer_id); + if (!rval && !minfo->sensor_mipi_manufacturer_id) + rval = ccs_read_addr_8only(sensor, + CCS_R_SENSOR_MANUFACTURER_ID, + &minfo->sensor_smia_manufacturer_id); + if (!rval) + rval = ccs_read_addr_8only(sensor, + CCS_R_SENSOR_MODEL_ID, + &minfo->sensor_model_id); + if (!rval) + rval = ccs_read_addr_8only(sensor, + CCS_R_SENSOR_REVISION_NUMBER, + &minfo->sensor_revision_number); + if (!rval) + rval = ccs_read_addr_8only(sensor, + CCS_R_SENSOR_FIRMWARE_VERSION, + &minfo->sensor_firmware_version); + + /* SMIA */ + if (!rval) + rval = ccs_read(sensor, MIPI_CCS_VERSION, &minfo->ccs_version); + if (!rval && !minfo->ccs_version) + rval = ccs_read_addr_8only(sensor, SMIAPP_REG_U8_SMIA_VERSION, + &minfo->smia_version); + if (!rval && !minfo->ccs_version) + rval = ccs_read_addr_8only(sensor, SMIAPP_REG_U8_SMIAPP_VERSION, + &minfo->smiapp_version); + + if (rval) { + dev_err(&client->dev, "sensor detection failed\n"); + return -ENODEV; + } + + if (minfo->mipi_manufacturer_id) + dev_dbg(&client->dev, "MIPI CCS module 0x%4.4x-0x%4.4x\n", + minfo->mipi_manufacturer_id, minfo->model_id); + else + dev_dbg(&client->dev, "SMIA module 0x%2.2x-0x%4.4x\n", + minfo->smia_manufacturer_id, minfo->model_id); + + dev_dbg(&client->dev, + "module revision 0x%2.2x-0x%2.2x date %2.2d-%2.2d-%2.2d\n", + minfo->revision_number_major, minfo->revision_number_minor, + minfo->module_year, minfo->module_month, minfo->module_day); + + if (minfo->sensor_mipi_manufacturer_id) + dev_dbg(&client->dev, "MIPI CCS sensor 0x%4.4x-0x%4.4x\n", + minfo->sensor_mipi_manufacturer_id, + minfo->sensor_model_id); + else + dev_dbg(&client->dev, "SMIA sensor 0x%2.2x-0x%4.4x\n", + minfo->sensor_smia_manufacturer_id, + minfo->sensor_model_id); + + dev_dbg(&client->dev, + "sensor revision 0x%2.2x firmware version 0x%2.2x\n", + minfo->sensor_revision_number, minfo->sensor_firmware_version); + + if (minfo->ccs_version) { + dev_dbg(&client->dev, "MIPI CCS version %u.%u", + (minfo->ccs_version & CCS_MIPI_CCS_VERSION_MAJOR_MASK) + >> CCS_MIPI_CCS_VERSION_MAJOR_SHIFT, + (minfo->ccs_version & CCS_MIPI_CCS_VERSION_MINOR_MASK)); + minfo->name = CCS_NAME; + } else { + dev_dbg(&client->dev, + "smia version %2.2d smiapp version %2.2d\n", + minfo->smia_version, minfo->smiapp_version); + minfo->name = SMIAPP_NAME; + } + + /* + * Some modules have bad data in the lvalues below. Hope the + * rvalues have better stuff. The lvalues are module + * parameters whereas the rvalues are sensor parameters. + */ + if (minfo->sensor_smia_manufacturer_id && + !minfo->smia_manufacturer_id && !minfo->model_id) { + minfo->smia_manufacturer_id = + minfo->sensor_smia_manufacturer_id; + minfo->model_id = minfo->sensor_model_id; + minfo->revision_number_major = minfo->sensor_revision_number; + } + + for (i = 0; i < ARRAY_SIZE(ccs_module_idents); i++) { + if (ccs_module_idents[i].mipi_manufacturer_id && + ccs_module_idents[i].mipi_manufacturer_id + != minfo->mipi_manufacturer_id) + continue; + if (ccs_module_idents[i].smia_manufacturer_id && + ccs_module_idents[i].smia_manufacturer_id + != minfo->smia_manufacturer_id) + continue; + if (ccs_module_idents[i].model_id != minfo->model_id) + continue; + if (ccs_module_idents[i].flags + & CCS_MODULE_IDENT_FLAG_REV_LE) { + if (ccs_module_idents[i].revision_number_major + < minfo->revision_number_major) + continue; + } else { + if (ccs_module_idents[i].revision_number_major + != minfo->revision_number_major) + continue; + } + + minfo->name = ccs_module_idents[i].name; + minfo->quirk = ccs_module_idents[i].quirk; + break; + } + + if (i >= ARRAY_SIZE(ccs_module_idents)) + dev_warn(&client->dev, + "no quirks for this module; let's hope it's fully compliant\n"); + + dev_dbg(&client->dev, "the sensor is called %s\n", + minfo->name); + + return 0; +} + +static const struct v4l2_subdev_ops ccs_ops; +static const struct v4l2_subdev_internal_ops ccs_internal_ops; +static const struct media_entity_operations ccs_entity_ops; + +static int ccs_register_subdev(struct ccs_sensor *sensor, + struct ccs_subdev *ssd, + struct ccs_subdev *sink_ssd, + u16 source_pad, u16 sink_pad, u32 link_flags) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int rval; + + if (!sink_ssd) + return 0; + + rval = media_entity_pads_init(&ssd->sd.entity, + ssd->npads, ssd->pads); + if (rval) { + dev_err(&client->dev, + "media_entity_pads_init failed\n"); + return rval; + } + + rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev, + &ssd->sd); + if (rval) { + dev_err(&client->dev, + "v4l2_device_register_subdev failed\n"); + return rval; + } + + rval = media_create_pad_link(&ssd->sd.entity, source_pad, + &sink_ssd->sd.entity, sink_pad, + link_flags); + if (rval) { + dev_err(&client->dev, + "media_create_pad_link failed\n"); + v4l2_device_unregister_subdev(&ssd->sd); + return rval; + } + + return 0; +} + +static void ccs_unregistered(struct v4l2_subdev *subdev) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + unsigned int i; + + for (i = 1; i < sensor->ssds_used; i++) + v4l2_device_unregister_subdev(&sensor->ssds[i].sd); +} + +static int ccs_registered(struct v4l2_subdev *subdev) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + int rval; + + if (sensor->scaler) { + rval = ccs_register_subdev(sensor, sensor->binner, + sensor->scaler, + CCS_PAD_SRC, CCS_PAD_SINK, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (rval < 0) + return rval; + } + + rval = ccs_register_subdev(sensor, sensor->pixel_array, sensor->binner, + CCS_PA_PAD_SRC, CCS_PAD_SINK, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (rval) + goto out_err; + + return 0; + +out_err: + ccs_unregistered(subdev); + + return rval; +} + +static void ccs_cleanup(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + + device_remove_file(&client->dev, &dev_attr_nvm); + device_remove_file(&client->dev, &dev_attr_ident); + + ccs_free_controls(sensor); +} + +static void ccs_create_subdev(struct ccs_sensor *sensor, + struct ccs_subdev *ssd, const char *name, + unsigned short num_pads) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + + if (!ssd) + return; + + if (ssd != sensor->src) + v4l2_subdev_init(&ssd->sd, &ccs_ops); + + ssd->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + ssd->sensor = sensor; + + ssd->npads = num_pads; + ssd->source_pad = num_pads - 1; + + v4l2_i2c_subdev_set_name(&ssd->sd, client, sensor->minfo.name, name); + + ccs_get_native_size(ssd, &ssd->sink_fmt); + + ssd->compose.width = ssd->sink_fmt.width; + ssd->compose.height = ssd->sink_fmt.height; + ssd->crop[ssd->source_pad] = ssd->compose; + ssd->pads[ssd->source_pad].flags = MEDIA_PAD_FL_SOURCE; + if (ssd != sensor->pixel_array) { + ssd->crop[ssd->sink_pad] = ssd->compose; + ssd->pads[ssd->sink_pad].flags = MEDIA_PAD_FL_SINK; + } + + ssd->sd.entity.ops = &ccs_entity_ops; + + if (ssd == sensor->src) + return; + + ssd->sd.internal_ops = &ccs_internal_ops; + ssd->sd.owner = THIS_MODULE; + ssd->sd.dev = &client->dev; + v4l2_set_subdevdata(&ssd->sd, client); +} + +static int ccs_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct ccs_subdev *ssd = to_ccs_subdev(sd); + struct ccs_sensor *sensor = ssd->sensor; + unsigned int i; + + mutex_lock(&sensor->mutex); + + for (i = 0; i < ssd->npads; i++) { + struct v4l2_mbus_framefmt *try_fmt = + v4l2_subdev_get_try_format(sd, fh->pad, i); + struct v4l2_rect *try_crop = + v4l2_subdev_get_try_crop(sd, fh->pad, i); + struct v4l2_rect *try_comp; + + ccs_get_native_size(ssd, try_crop); + + try_fmt->width = try_crop->width; + try_fmt->height = try_crop->height; + try_fmt->code = sensor->internal_csi_format->code; + try_fmt->field = V4L2_FIELD_NONE; + + if (ssd != sensor->pixel_array) + continue; + + try_comp = v4l2_subdev_get_try_compose(sd, fh->pad, i); + *try_comp = *try_crop; + } + + mutex_unlock(&sensor->mutex); + + return 0; +} + +static const struct v4l2_subdev_video_ops ccs_video_ops = { + .s_stream = ccs_set_stream, +}; + +static const struct v4l2_subdev_pad_ops ccs_pad_ops = { + .enum_mbus_code = ccs_enum_mbus_code, + .get_fmt = ccs_get_format, + .set_fmt = ccs_set_format, + .get_selection = ccs_get_selection, + .set_selection = ccs_set_selection, +}; + +static const struct v4l2_subdev_sensor_ops ccs_sensor_ops = { + .g_skip_frames = ccs_get_skip_frames, + .g_skip_top_lines = ccs_get_skip_top_lines, +}; + +static const struct v4l2_subdev_ops ccs_ops = { + .video = &ccs_video_ops, + .pad = &ccs_pad_ops, + .sensor = &ccs_sensor_ops, +}; + +static const struct media_entity_operations ccs_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static const struct v4l2_subdev_internal_ops ccs_internal_src_ops = { + .registered = ccs_registered, + .unregistered = ccs_unregistered, + .open = ccs_open, +}; + +static const struct v4l2_subdev_internal_ops ccs_internal_ops = { + .open = ccs_open, +}; + +/* ----------------------------------------------------------------------------- + * I2C Driver + */ + +static int __maybe_unused ccs_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + bool streaming = sensor->streaming; + int rval; + + rval = pm_runtime_get_sync(dev); + if (rval < 0) { + if (rval != -EBUSY && rval != -EAGAIN) + pm_runtime_set_active(&client->dev); + pm_runtime_put(dev); + return -EAGAIN; + } + + if (sensor->streaming) + ccs_stop_streaming(sensor); + + /* save state for resume */ + sensor->streaming = streaming; + + return 0; +} + +static int __maybe_unused ccs_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + int rval = 0; + + pm_runtime_put(dev); + + if (sensor->streaming) + rval = ccs_start_streaming(sensor); + + return rval; +} + +static struct ccs_hwconfig *ccs_get_hwconfig(struct device *dev) +{ + struct ccs_hwconfig *hwcfg; + struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 }; + struct fwnode_handle *ep; + struct fwnode_handle *fwnode = dev_fwnode(dev); + u32 rotation; + int i; + int rval; + + if (!fwnode) + return dev->platform_data; + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) + return NULL; + + bus_cfg.bus_type = V4L2_MBUS_CSI2_DPHY; + rval = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + if (rval == -ENXIO) { + bus_cfg = (struct v4l2_fwnode_endpoint) + { .bus_type = V4L2_MBUS_CCP2 }; + rval = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + } + if (rval) + goto out_err; + + hwcfg = devm_kzalloc(dev, sizeof(*hwcfg), GFP_KERNEL); + if (!hwcfg) + goto out_err; + + switch (bus_cfg.bus_type) { + case V4L2_MBUS_CSI2_DPHY: + hwcfg->csi_signalling_mode = CCS_CSI_SIGNALING_MODE_CSI_2_DPHY; + hwcfg->lanes = bus_cfg.bus.mipi_csi2.num_data_lanes; + break; + case V4L2_MBUS_CCP2: + hwcfg->csi_signalling_mode = (bus_cfg.bus.mipi_csi1.strobe) ? + SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE : + SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK; + hwcfg->lanes = 1; + break; + default: + dev_err(dev, "unsupported bus %u\n", bus_cfg.bus_type); + goto out_err; + } + + dev_dbg(dev, "lanes %u\n", hwcfg->lanes); + + rval = fwnode_property_read_u32(fwnode, "rotation", &rotation); + if (!rval) { + switch (rotation) { + case 180: + hwcfg->module_board_orient = + CCS_MODULE_BOARD_ORIENT_180; + fallthrough; + case 0: + break; + default: + dev_err(dev, "invalid rotation %u\n", rotation); + goto out_err; + } + } + + rval = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", + &hwcfg->ext_clk); + if (rval) + dev_info(dev, "can't get clock-frequency\n"); + + dev_dbg(dev, "clk %d, mode %d\n", hwcfg->ext_clk, + hwcfg->csi_signalling_mode); + + if (!bus_cfg.nr_of_link_frequencies) { + dev_warn(dev, "no link frequencies defined\n"); + goto out_err; + } + + hwcfg->op_sys_clock = devm_kcalloc( + dev, bus_cfg.nr_of_link_frequencies + 1 /* guardian */, + sizeof(*hwcfg->op_sys_clock), GFP_KERNEL); + if (!hwcfg->op_sys_clock) + goto out_err; + + for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) { + hwcfg->op_sys_clock[i] = bus_cfg.link_frequencies[i]; + dev_dbg(dev, "freq %d: %lld\n", i, hwcfg->op_sys_clock[i]); + } + + v4l2_fwnode_endpoint_free(&bus_cfg); + fwnode_handle_put(ep); + return hwcfg; + +out_err: + v4l2_fwnode_endpoint_free(&bus_cfg); + fwnode_handle_put(ep); + return NULL; +} + +static int ccs_probe(struct i2c_client *client) +{ + struct ccs_sensor *sensor; + struct ccs_hwconfig *hwcfg = ccs_get_hwconfig(&client->dev); + unsigned int i; + int rval; + + if (hwcfg == NULL) + return -ENODEV; + + sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL); + if (sensor == NULL) + return -ENOMEM; + + sensor->hwcfg = hwcfg; + sensor->src = &sensor->ssds[sensor->ssds_used]; + + v4l2_i2c_subdev_init(&sensor->src->sd, client, &ccs_ops); + sensor->src->sd.internal_ops = &ccs_internal_src_ops; + + sensor->vana = devm_regulator_get(&client->dev, "vana"); + if (IS_ERR(sensor->vana)) { + dev_err(&client->dev, "could not get regulator for vana\n"); + return PTR_ERR(sensor->vana); + } + + sensor->ext_clk = devm_clk_get(&client->dev, NULL); + if (PTR_ERR(sensor->ext_clk) == -ENOENT) { + dev_info(&client->dev, "no clock defined, continuing...\n"); + sensor->ext_clk = NULL; + } else if (IS_ERR(sensor->ext_clk)) { + dev_err(&client->dev, "could not get clock (%ld)\n", + PTR_ERR(sensor->ext_clk)); + return -EPROBE_DEFER; + } + + if (sensor->ext_clk) { + if (sensor->hwcfg->ext_clk) { + unsigned long rate; + + rval = clk_set_rate(sensor->ext_clk, + sensor->hwcfg->ext_clk); + if (rval < 0) { + dev_err(&client->dev, + "unable to set clock freq to %u\n", + sensor->hwcfg->ext_clk); + return rval; + } + + rate = clk_get_rate(sensor->ext_clk); + if (rate != sensor->hwcfg->ext_clk) { + dev_err(&client->dev, + "can't set clock freq, asked for %u but got %lu\n", + sensor->hwcfg->ext_clk, rate); + return rval; + } + } else { + sensor->hwcfg->ext_clk = clk_get_rate(sensor->ext_clk); + dev_dbg(&client->dev, "obtained clock freq %u\n", + sensor->hwcfg->ext_clk); + } + } else if (sensor->hwcfg->ext_clk) { + dev_dbg(&client->dev, "assuming clock freq %u\n", + sensor->hwcfg->ext_clk); + } else { + dev_err(&client->dev, "unable to obtain clock freq\n"); + return -EINVAL; + } + + sensor->xshutdown = devm_gpiod_get_optional(&client->dev, "xshutdown", + GPIOD_OUT_LOW); + if (IS_ERR(sensor->xshutdown)) + return PTR_ERR(sensor->xshutdown); + + rval = ccs_power_on(&client->dev); + if (rval < 0) + return rval; + + mutex_init(&sensor->mutex); + + rval = ccs_identify_module(sensor); + if (rval) { + rval = -ENODEV; + goto out_power_off; + } + + rval = ccs_read_all_limits(sensor); + if (rval) + goto out_power_off; + + rval = ccs_read_frame_fmt(sensor); + if (rval) { + rval = -ENODEV; + goto out_free_ccs_limits; + } + + /* + * Handle Sensor Module orientation on the board. + * + * The application of H-FLIP and V-FLIP on the sensor is modified by + * the sensor orientation on the board. + * + * For CCS_BOARD_SENSOR_ORIENT_180 the default behaviour is to set + * both H-FLIP and V-FLIP for normal operation which also implies + * that a set/unset operation for user space HFLIP and VFLIP v4l2 + * controls will need to be internally inverted. + * + * Rotation also changes the bayer pattern. + */ + if (sensor->hwcfg->module_board_orient == + CCS_MODULE_BOARD_ORIENT_180) + sensor->hvflip_inv_mask = + CCS_IMAGE_ORIENTATION_HORIZONTAL_MIRROR | + CCS_IMAGE_ORIENTATION_VERTICAL_FLIP; + + rval = ccs_call_quirk(sensor, limits); + if (rval) { + dev_err(&client->dev, "limits quirks failed\n"); + goto out_free_ccs_limits; + } + + if (CCS_LIM(sensor, BINNING_CAPABILITY)) { + sensor->nbinning_subtypes = + min_t(u8, CCS_LIM(sensor, BINNING_SUB_TYPES), + CCS_LIM_BINNING_SUB_TYPE_MAX_N); + + for (i = 0; i < sensor->nbinning_subtypes; i++) { + sensor->binning_subtypes[i].horizontal = + CCS_LIM_AT(sensor, BINNING_SUB_TYPE, i) >> + CCS_BINNING_SUB_TYPE_COLUMN_SHIFT; + sensor->binning_subtypes[i].vertical = + CCS_LIM_AT(sensor, BINNING_SUB_TYPE, i) & + CCS_BINNING_SUB_TYPE_ROW_MASK; + + dev_dbg(&client->dev, "binning %xx%x\n", + sensor->binning_subtypes[i].horizontal, + sensor->binning_subtypes[i].vertical); + } + } + sensor->binning_horizontal = 1; + sensor->binning_vertical = 1; + + if (device_create_file(&client->dev, &dev_attr_ident) != 0) { + dev_err(&client->dev, "sysfs ident entry creation failed\n"); + rval = -ENOENT; + goto out_free_ccs_limits; + } + + if (sensor->minfo.smiapp_version && + CCS_LIM(sensor, DATA_TRANSFER_IF_CAPABILITY) & + CCS_DATA_TRANSFER_IF_CAPABILITY_SUPPORTED) { + if (device_create_file(&client->dev, &dev_attr_nvm) != 0) { + dev_err(&client->dev, "sysfs nvm entry failed\n"); + rval = -EBUSY; + goto out_cleanup; + } + } + + /* We consider this as profile 0 sensor if any of these are zero. */ + if (!CCS_LIM(sensor, MIN_OP_SYS_CLK_DIV) || + !CCS_LIM(sensor, MAX_OP_SYS_CLK_DIV) || + !CCS_LIM(sensor, MIN_OP_PIX_CLK_DIV) || + !CCS_LIM(sensor, MAX_OP_PIX_CLK_DIV)) { + sensor->minfo.smiapp_profile = SMIAPP_PROFILE_0; + } else if (CCS_LIM(sensor, SCALING_CAPABILITY) + != CCS_SCALING_CAPABILITY_NONE) { + if (CCS_LIM(sensor, SCALING_CAPABILITY) + == CCS_SCALING_CAPABILITY_HORIZONTAL) + sensor->minfo.smiapp_profile = SMIAPP_PROFILE_1; + else + sensor->minfo.smiapp_profile = SMIAPP_PROFILE_2; + sensor->scaler = &sensor->ssds[sensor->ssds_used]; + sensor->ssds_used++; + } else if (CCS_LIM(sensor, DIGITAL_CROP_CAPABILITY) + == CCS_DIGITAL_CROP_CAPABILITY_INPUT_CROP) { + sensor->scaler = &sensor->ssds[sensor->ssds_used]; + sensor->ssds_used++; + } + sensor->binner = &sensor->ssds[sensor->ssds_used]; + sensor->ssds_used++; + sensor->pixel_array = &sensor->ssds[sensor->ssds_used]; + sensor->ssds_used++; + + sensor->scale_m = CCS_LIM(sensor, SCALER_N_MIN); + + /* prepare PLL configuration input values */ + sensor->pll.bus_type = SMIAPP_PLL_BUS_TYPE_CSI2; + sensor->pll.csi2.lanes = sensor->hwcfg->lanes; + sensor->pll.ext_clk_freq_hz = sensor->hwcfg->ext_clk; + sensor->pll.scale_n = CCS_LIM(sensor, SCALER_N_MIN); + /* Profile 0 sensors have no separate OP clock branch. */ + if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) + sensor->pll.flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS; + + ccs_create_subdev(sensor, sensor->scaler, " scaler", 2); + ccs_create_subdev(sensor, sensor->binner, " binner", 2); + ccs_create_subdev(sensor, sensor->pixel_array, " pixel_array", 1); + + dev_dbg(&client->dev, "profile %d\n", sensor->minfo.smiapp_profile); + + sensor->pixel_array->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + rval = ccs_init_controls(sensor); + if (rval < 0) + goto out_cleanup; + + rval = ccs_call_quirk(sensor, init); + if (rval) + goto out_cleanup; + + rval = ccs_get_mbus_formats(sensor); + if (rval) { + rval = -ENODEV; + goto out_cleanup; + } + + rval = ccs_init_late_controls(sensor); + if (rval) { + rval = -ENODEV; + goto out_cleanup; + } + + mutex_lock(&sensor->mutex); + rval = ccs_pll_blanking_update(sensor); + mutex_unlock(&sensor->mutex); + if (rval) { + dev_err(&client->dev, "update mode failed\n"); + goto out_cleanup; + } + + sensor->streaming = false; + sensor->dev_init_done = true; + + rval = media_entity_pads_init(&sensor->src->sd.entity, 2, + sensor->src->pads); + if (rval < 0) + goto out_media_entity_cleanup; + + pm_runtime_set_active(&client->dev); + pm_runtime_get_noresume(&client->dev); + pm_runtime_enable(&client->dev); + + rval = v4l2_async_register_subdev_sensor_common(&sensor->src->sd); + if (rval < 0) + goto out_disable_runtime_pm; + + pm_runtime_set_autosuspend_delay(&client->dev, 1000); + pm_runtime_use_autosuspend(&client->dev); + pm_runtime_put_autosuspend(&client->dev); + + return 0; + +out_disable_runtime_pm: + pm_runtime_put_noidle(&client->dev); + pm_runtime_disable(&client->dev); + +out_media_entity_cleanup: + media_entity_cleanup(&sensor->src->sd.entity); + +out_cleanup: + ccs_cleanup(sensor); + +out_free_ccs_limits: + kfree(sensor->ccs_limits); + +out_power_off: + ccs_power_off(&client->dev); + mutex_destroy(&sensor->mutex); + + return rval; +} + +static int ccs_remove(struct i2c_client *client) +{ + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + unsigned int i; + + v4l2_async_unregister_subdev(subdev); + + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + ccs_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); + + for (i = 0; i < sensor->ssds_used; i++) { + v4l2_device_unregister_subdev(&sensor->ssds[i].sd); + media_entity_cleanup(&sensor->ssds[i].sd.entity); + } + ccs_cleanup(sensor); + mutex_destroy(&sensor->mutex); + kfree(sensor->ccs_limits); + + return 0; +} + +static const struct of_device_id ccs_of_table[] = { + { .compatible = "nokia,smia" }, + { }, +}; +MODULE_DEVICE_TABLE(of, ccs_of_table); + +static const struct i2c_device_id ccs_id_table[] = { + { SMIAPP_NAME, 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, ccs_id_table); + +static const struct dev_pm_ops ccs_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ccs_suspend, ccs_resume) + SET_RUNTIME_PM_OPS(ccs_power_off, ccs_power_on, NULL) +}; + +static struct i2c_driver ccs_i2c_driver = { + .driver = { + .of_match_table = ccs_of_table, + .name = CCS_NAME, + .pm = &ccs_pm_ops, + }, + .probe_new = ccs_probe, + .remove = ccs_remove, + .id_table = ccs_id_table, +}; + +static int ccs_module_init(void) +{ + unsigned int i, l; + + for (i = 0, l = 0; ccs_limits[i].size && l < CCS_L_LAST; i++) { + if (!(ccs_limits[i].flags & CCS_L_FL_SAME_REG)) { + ccs_limit_offsets[l + 1].lim = + ALIGN(ccs_limit_offsets[l].lim + + ccs_limits[i].size, + ccs_reg_width(ccs_limits[i + 1].reg)); + ccs_limit_offsets[l].info = i; + l++; + } else { + ccs_limit_offsets[l].lim += ccs_limits[i].size; + } + } + + if (WARN_ON(ccs_limits[i].size)) + return -EINVAL; + + if (WARN_ON(l != CCS_L_LAST)) + return -EINVAL; + + return i2c_register_driver(THIS_MODULE, &ccs_i2c_driver); +} + +static void ccs_module_cleanup(void) +{ + i2c_del_driver(&ccs_i2c_driver); +} + +module_init(ccs_module_init); +module_exit(ccs_module_cleanup); + +MODULE_AUTHOR("Sakari Ailus "); +MODULE_DESCRIPTION("Generic MIPI CCS/SMIA/SMIA++ camera sensor driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("smiapp"); diff --git a/drivers/media/i2c/ccs/ccs-limits.c b/drivers/media/i2c/ccs/ccs-limits.c new file mode 100644 index 000000000000..f5511789ac83 --- /dev/null +++ b/drivers/media/i2c/ccs/ccs-limits.c @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause +/* Copyright (C) 2019--2020 Intel Corporation */ + +#include "ccs-limits.h" +#include "ccs-regs.h" + +const struct ccs_limit ccs_limits[] = { + { CCS_R_FRAME_FORMAT_MODEL_TYPE, 1, 0, "frame_format_model_type" }, + { CCS_R_FRAME_FORMAT_MODEL_SUBTYPE, 1, 0, "frame_format_model_subtype" }, + { CCS_R_FRAME_FORMAT_DESCRIPTOR(0), 30, 0, "frame_format_descriptor" }, + { CCS_R_FRAME_FORMAT_DESCRIPTOR_4(0), 32, 0, "frame_format_descriptor_4" }, + { CCS_R_ANALOG_GAIN_CAPABILITY, 2, 0, "analog_gain_capability" }, + { CCS_R_ANALOG_GAIN_CODE_MIN, 2, 0, "analog_gain_code_min" }, + { CCS_R_ANALOG_GAIN_CODE_MAX, 2, 0, "analog_gain_code_max" }, + { CCS_R_ANALOG_GAIN_CODE_STEP, 2, 0, "analog_gain_code_step" }, + { CCS_R_ANALOG_GAIN_TYPE, 2, 0, "analog_gain_type" }, + { CCS_R_ANALOG_GAIN_M0, 2, 0, "analog_gain_m0" }, + { CCS_R_ANALOG_GAIN_C0, 2, 0, "analog_gain_c0" }, + { CCS_R_ANALOG_GAIN_M1, 2, 0, "analog_gain_m1" }, + { CCS_R_ANALOG_GAIN_C1, 2, 0, "analog_gain_c1" }, + { CCS_R_ANALOG_LINEAR_GAIN_MIN, 2, 0, "analog_linear_gain_min" }, + { CCS_R_ANALOG_LINEAR_GAIN_MAX, 2, 0, "analog_linear_gain_max" }, + { CCS_R_ANALOG_LINEAR_GAIN_STEP_SIZE, 2, 0, "analog_linear_gain_step_size" }, + { CCS_R_ANALOG_EXPONENTIAL_GAIN_MIN, 2, 0, "analog_exponential_gain_min" }, + { CCS_R_ANALOG_EXPONENTIAL_GAIN_MAX, 2, 0, "analog_exponential_gain_max" }, + { CCS_R_ANALOG_EXPONENTIAL_GAIN_STEP_SIZE, 2, 0, "analog_exponential_gain_step_size" }, + { CCS_R_DATA_FORMAT_MODEL_TYPE, 1, 0, "data_format_model_type" }, + { CCS_R_DATA_FORMAT_MODEL_SUBTYPE, 1, 0, "data_format_model_subtype" }, + { CCS_R_DATA_FORMAT_DESCRIPTOR(0), 32, 0, "data_format_descriptor" }, + { CCS_R_INTEGRATION_TIME_CAPABILITY, 2, 0, "integration_time_capability" }, + { CCS_R_COARSE_INTEGRATION_TIME_MIN, 2, 0, "coarse_integration_time_min" }, + { CCS_R_COARSE_INTEGRATION_TIME_MAX_MARGIN, 2, 0, "coarse_integration_time_max_margin" }, + { CCS_R_FINE_INTEGRATION_TIME_MIN, 2, 0, "fine_integration_time_min" }, + { CCS_R_FINE_INTEGRATION_TIME_MAX_MARGIN, 2, 0, "fine_integration_time_max_margin" }, + { CCS_R_DIGITAL_GAIN_CAPABILITY, 1, 0, "digital_gain_capability" }, + { CCS_R_DIGITAL_GAIN_MIN, 2, 0, "digital_gain_min" }, + { CCS_R_DIGITAL_GAIN_MAX, 2, 0, "digital_gain_max" }, + { CCS_R_DIGITAL_GAIN_STEP_SIZE, 2, 0, "digital_gain_step_size" }, + { CCS_R_PEDESTAL_CAPABILITY, 1, 0, "Pedestal_capability" }, + { CCS_R_ADC_CAPABILITY, 1, 0, "ADC_capability" }, + { CCS_R_ADC_BIT_DEPTH_CAPABILITY, 4, 0, "ADC_bit_depth_capability" }, + { CCS_R_MIN_EXT_CLK_FREQ_MHZ, 4, 0, "min_ext_clk_freq_mhz" }, + { CCS_R_MAX_EXT_CLK_FREQ_MHZ, 4, 0, "max_ext_clk_freq_mhz" }, + { CCS_R_MIN_PRE_PLL_CLK_DIV, 2, 0, "min_pre_pll_clk_div" }, + { CCS_R_MAX_PRE_PLL_CLK_DIV, 2, 0, "max_pre_pll_clk_div" }, + { CCS_R_MIN_PLL_IP_CLK_FREQ_MHZ, 4, 0, "min_pll_ip_clk_freq_mhz" }, + { CCS_R_MAX_PLL_IP_CLK_FREQ_MHZ, 4, 0, "max_pll_ip_clk_freq_mhz" }, + { CCS_R_MIN_PLL_MULTIPLIER, 2, 0, "min_pll_multiplier" }, + { CCS_R_MAX_PLL_MULTIPLIER, 2, 0, "max_pll_multiplier" }, + { CCS_R_MIN_PLL_OP_CLK_FREQ_MHZ, 4, 0, "min_pll_op_clk_freq_mhz" }, + { CCS_R_MAX_PLL_OP_CLK_FREQ_MHZ, 4, 0, "max_pll_op_clk_freq_mhz" }, + { CCS_R_MIN_VT_SYS_CLK_DIV, 2, 0, "min_vt_sys_clk_div" }, + { CCS_R_MAX_VT_SYS_CLK_DIV, 2, 0, "max_vt_sys_clk_div" }, + { CCS_R_MIN_VT_SYS_CLK_FREQ_MHZ, 4, 0, "min_vt_sys_clk_freq_mhz" }, + { CCS_R_MAX_VT_SYS_CLK_FREQ_MHZ, 4, 0, "max_vt_sys_clk_freq_mhz" }, + { CCS_R_MIN_VT_PIX_CLK_FREQ_MHZ, 4, 0, "min_vt_pix_clk_freq_mhz" }, + { CCS_R_MAX_VT_PIX_CLK_FREQ_MHZ, 4, 0, "max_vt_pix_clk_freq_mhz" }, + { CCS_R_MIN_VT_PIX_CLK_DIV, 2, 0, "min_vt_pix_clk_div" }, + { CCS_R_MAX_VT_PIX_CLK_DIV, 2, 0, "max_vt_pix_clk_div" }, + { CCS_R_CLOCK_CALCULATION, 1, 0, "clock_calculation" }, + { CCS_R_NUM_OF_VT_LANES, 1, 0, "num_of_vt_lanes" }, + { CCS_R_NUM_OF_OP_LANES, 1, 0, "num_of_op_lanes" }, + { CCS_R_OP_BITS_PER_LANE, 1, 0, "op_bits_per_lane" }, + { CCS_R_MIN_FRAME_LENGTH_LINES, 2, 0, "min_frame_length_lines" }, + { CCS_R_MAX_FRAME_LENGTH_LINES, 2, 0, "max_frame_length_lines" }, + { CCS_R_MIN_LINE_LENGTH_PCK, 2, 0, "min_line_length_pck" }, + { CCS_R_MAX_LINE_LENGTH_PCK, 2, 0, "max_line_length_pck" }, + { CCS_R_MIN_LINE_BLANKING_PCK, 2, 0, "min_line_blanking_pck" }, + { CCS_R_MIN_FRAME_BLANKING_LINES, 2, 0, "min_frame_blanking_lines" }, + { CCS_R_MIN_LINE_LENGTH_PCK_STEP_SIZE, 1, 0, "min_line_length_pck_step_size" }, + { CCS_R_TIMING_MODE_CAPABILITY, 1, 0, "timing_mode_capability" }, + { CCS_R_FRAME_MARGIN_MAX_VALUE, 2, 0, "frame_margin_max_value" }, + { CCS_R_FRAME_MARGIN_MIN_VALUE, 1, 0, "frame_margin_min_value" }, + { CCS_R_GAIN_DELAY_TYPE, 1, 0, "gain_delay_type" }, + { CCS_R_MIN_OP_SYS_CLK_DIV, 2, 0, "min_op_sys_clk_div" }, + { CCS_R_MAX_OP_SYS_CLK_DIV, 2, 0, "max_op_sys_clk_div" }, + { CCS_R_MIN_OP_SYS_CLK_FREQ_MHZ, 4, 0, "min_op_sys_clk_freq_mhz" }, + { CCS_R_MAX_OP_SYS_CLK_FREQ_MHZ, 4, 0, "max_op_sys_clk_freq_mhz" }, + { CCS_R_MIN_OP_PIX_CLK_DIV, 2, 0, "min_op_pix_clk_div" }, + { CCS_R_MAX_OP_PIX_CLK_DIV, 2, 0, "max_op_pix_clk_div" }, + { CCS_R_MIN_OP_PIX_CLK_FREQ_MHZ, 4, 0, "min_op_pix_clk_freq_mhz" }, + { CCS_R_MAX_OP_PIX_CLK_FREQ_MHZ, 4, 0, "max_op_pix_clk_freq_mhz" }, + { CCS_R_X_ADDR_MIN, 2, 0, "x_addr_min" }, + { CCS_R_Y_ADDR_MIN, 2, 0, "y_addr_min" }, + { CCS_R_X_ADDR_MAX, 2, 0, "x_addr_max" }, + { CCS_R_Y_ADDR_MAX, 2, 0, "y_addr_max" }, + { CCS_R_MIN_X_OUTPUT_SIZE, 2, 0, "min_x_output_size" }, + { CCS_R_MIN_Y_OUTPUT_SIZE, 2, 0, "min_y_output_size" }, + { CCS_R_MAX_X_OUTPUT_SIZE, 2, 0, "max_x_output_size" }, + { CCS_R_MAX_Y_OUTPUT_SIZE, 2, 0, "max_y_output_size" }, + { CCS_R_X_ADDR_START_DIV_CONSTANT, 1, 0, "x_addr_start_div_constant" }, + { CCS_R_Y_ADDR_START_DIV_CONSTANT, 1, 0, "y_addr_start_div_constant" }, + { CCS_R_X_ADDR_END_DIV_CONSTANT, 1, 0, "x_addr_end_div_constant" }, + { CCS_R_Y_ADDR_END_DIV_CONSTANT, 1, 0, "y_addr_end_div_constant" }, + { CCS_R_X_SIZE_DIV, 1, 0, "x_size_div" }, + { CCS_R_Y_SIZE_DIV, 1, 0, "y_size_div" }, + { CCS_R_X_OUTPUT_DIV, 1, 0, "x_output_div" }, + { CCS_R_Y_OUTPUT_DIV, 1, 0, "y_output_div" }, + { CCS_R_NON_FLEXIBLE_RESOLUTION_SUPPORT, 1, 0, "non_flexible_resolution_support" }, + { CCS_R_MIN_OP_PRE_PLL_CLK_DIV, 2, 0, "min_op_pre_pll_clk_div" }, + { CCS_R_MAX_OP_PRE_PLL_CLK_DIV, 2, 0, "max_op_pre_pll_clk_div" }, + { CCS_R_MIN_OP_PLL_IP_CLK_FREQ_MHZ, 4, 0, "min_op_pll_ip_clk_freq_mhz" }, + { CCS_R_MAX_OP_PLL_IP_CLK_FREQ_MHZ, 4, 0, "max_op_pll_ip_clk_freq_mhz" }, + { CCS_R_MIN_OP_PLL_MULTIPLIER, 2, 0, "min_op_pll_multiplier" }, + { CCS_R_MAX_OP_PLL_MULTIPLIER, 2, 0, "max_op_pll_multiplier" }, + { CCS_R_MIN_OP_PLL_OP_CLK_FREQ_MHZ, 4, 0, "min_op_pll_op_clk_freq_mhz" }, + { CCS_R_MAX_OP_PLL_OP_CLK_FREQ_MHZ, 4, 0, "max_op_pll_op_clk_freq_mhz" }, + { CCS_R_CLOCK_TREE_PLL_CAPABILITY, 1, 0, "clock_tree_pll_capability" }, + { CCS_R_CLOCK_CAPA_TYPE_CAPABILITY, 1, 0, "clock_capa_type_capability" }, + { CCS_R_MIN_EVEN_INC, 2, 0, "min_even_inc" }, + { CCS_R_MIN_ODD_INC, 2, 0, "min_odd_inc" }, + { CCS_R_MAX_EVEN_INC, 2, 0, "max_even_inc" }, + { CCS_R_MAX_ODD_INC, 2, 0, "max_odd_inc" }, + { CCS_R_AUX_SUBSAMP_CAPABILITY, 1, 0, "aux_subsamp_capability" }, + { CCS_R_AUX_SUBSAMP_MONO_CAPABILITY, 1, 0, "aux_subsamp_mono_capability" }, + { CCS_R_MONOCHROME_CAPABILITY, 1, 0, "monochrome_capability" }, + { CCS_R_PIXEL_READOUT_CAPABILITY, 1, 0, "pixel_readout_capability" }, + { CCS_R_MIN_EVEN_INC_MONO, 2, 0, "min_even_inc_mono" }, + { CCS_R_MAX_EVEN_INC_MONO, 2, 0, "max_even_inc_mono" }, + { CCS_R_MIN_ODD_INC_MONO, 2, 0, "min_odd_inc_mono" }, + { CCS_R_MAX_ODD_INC_MONO, 2, 0, "max_odd_inc_mono" }, + { CCS_R_MIN_EVEN_INC_BC2, 2, 0, "min_even_inc_bc2" }, + { CCS_R_MAX_EVEN_INC_BC2, 2, 0, "max_even_inc_bc2" }, + { CCS_R_MIN_ODD_INC_BC2, 2, 0, "min_odd_inc_bc2" }, + { CCS_R_MAX_ODD_INC_BC2, 2, 0, "max_odd_inc_bc2" }, + { CCS_R_MIN_EVEN_INC_MONO_BC2, 2, 0, "min_even_inc_mono_bc2" }, + { CCS_R_MAX_EVEN_INC_MONO_BC2, 2, 0, "max_even_inc_mono_bc2" }, + { CCS_R_MIN_ODD_INC_MONO_BC2, 2, 0, "min_odd_inc_mono_bc2" }, + { CCS_R_MAX_ODD_INC_MONO_BC2, 2, 0, "max_odd_inc_mono_bc2" }, + { CCS_R_SCALING_CAPABILITY, 2, 0, "scaling_capability" }, + { CCS_R_SCALER_M_MIN, 2, 0, "scaler_m_min" }, + { CCS_R_SCALER_M_MAX, 2, 0, "scaler_m_max" }, + { CCS_R_SCALER_N_MIN, 2, 0, "scaler_n_min" }, + { CCS_R_SCALER_N_MAX, 2, 0, "scaler_n_max" }, + { CCS_R_DIGITAL_CROP_CAPABILITY, 1, 0, "digital_crop_capability" }, + { CCS_R_HDR_CAPABILITY_1, 1, 0, "hdr_capability_1" }, + { CCS_R_MIN_HDR_BIT_DEPTH, 1, 0, "min_hdr_bit_depth" }, + { CCS_R_HDR_RESOLUTION_SUB_TYPES, 1, 0, "hdr_resolution_sub_types" }, + { CCS_R_HDR_RESOLUTION_SUB_TYPE(0), 2, 0, "hdr_resolution_sub_type" }, + { CCS_R_HDR_CAPABILITY_2, 1, 0, "hdr_capability_2" }, + { CCS_R_MAX_HDR_BIT_DEPTH, 1, 0, "max_hdr_bit_depth" }, + { CCS_R_USL_SUPPORT_CAPABILITY, 1, 0, "usl_support_capability" }, + { CCS_R_USL_CLOCK_MODE_D_CAPABILITY, 1, 0, "usl_clock_mode_d_capability" }, + { CCS_R_MIN_OP_SYS_CLK_DIV_REV, 1, 0, "min_op_sys_clk_div_rev" }, + { CCS_R_MAX_OP_SYS_CLK_DIV_REV, 1, 0, "max_op_sys_clk_div_rev" }, + { CCS_R_MIN_OP_PIX_CLK_DIV_REV, 1, 0, "min_op_pix_clk_div_rev" }, + { CCS_R_MAX_OP_PIX_CLK_DIV_REV, 1, 0, "max_op_pix_clk_div_rev" }, + { CCS_R_MIN_OP_SYS_CLK_FREQ_REV_MHZ, 4, 0, "min_op_sys_clk_freq_rev_mhz" }, + { CCS_R_MAX_OP_SYS_CLK_FREQ_REV_MHZ, 4, 0, "max_op_sys_clk_freq_rev_mhz" }, + { CCS_R_MIN_OP_PIX_CLK_FREQ_REV_MHZ, 4, 0, "min_op_pix_clk_freq_rev_mhz" }, + { CCS_R_MAX_OP_PIX_CLK_FREQ_REV_MHZ, 4, 0, "max_op_pix_clk_freq_rev_mhz" }, + { CCS_R_MAX_BITRATE_REV_D_MODE_MBPS, 4, 0, "max_bitrate_rev_d_mode_mbps" }, + { CCS_R_MAX_SYMRATE_REV_C_MODE_MSPS, 4, 0, "max_symrate_rev_c_mode_msps" }, + { CCS_R_COMPRESSION_CAPABILITY, 1, 0, "compression_capability" }, + { CCS_R_TEST_MODE_CAPABILITY, 2, 0, "test_mode_capability" }, + { CCS_R_PN9_DATA_FORMAT1, 1, 0, "pn9_data_format1" }, + { CCS_R_PN9_DATA_FORMAT2, 1, 0, "pn9_data_format2" }, + { CCS_R_PN9_DATA_FORMAT3, 1, 0, "pn9_data_format3" }, + { CCS_R_PN9_DATA_FORMAT4, 1, 0, "pn9_data_format4" }, + { CCS_R_PN9_MISC_CAPABILITY, 1, 0, "pn9_misc_capability" }, + { CCS_R_TEST_PATTERN_CAPABILITY, 1, 0, "test_pattern_capability" }, + { CCS_R_PATTERN_SIZE_DIV_M1, 1, 0, "pattern_size_div_m1" }, + { CCS_R_FIFO_SUPPORT_CAPABILITY, 1, 0, "fifo_support_capability" }, + { CCS_R_PHY_CTRL_CAPABILITY, 1, 0, "phy_ctrl_capability" }, + { CCS_R_CSI_DPHY_LANE_MODE_CAPABILITY, 1, 0, "csi_dphy_lane_mode_capability" }, + { CCS_R_CSI_SIGNALING_MODE_CAPABILITY, 1, 0, "csi_signaling_mode_capability" }, + { CCS_R_FAST_STANDBY_CAPABILITY, 1, 0, "fast_standby_capability" }, + { CCS_R_CSI_ADDRESS_CONTROL_CAPABILITY, 1, 0, "csi_address_control_capability" }, + { CCS_R_DATA_TYPE_CAPABILITY, 1, 0, "data_type_capability" }, + { CCS_R_CSI_CPHY_LANE_MODE_CAPABILITY, 1, 0, "csi_cphy_lane_mode_capability" }, + { CCS_R_EMB_DATA_CAPABILITY, 1, 0, "emb_data_capability" }, + { CCS_R_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS(0), 16, 0, "max_per_lane_bitrate_lane_d_mode_mbps 0" }, + { CCS_R_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS(4), 16, CCS_L_FL_SAME_REG, "max_per_lane_bitrate_lane_d_mode_mbps 4" }, + { CCS_R_TEMP_SENSOR_CAPABILITY, 1, 0, "temp_sensor_capability" }, + { CCS_R_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS(0), 16, 0, "max_per_lane_bitrate_lane_c_mode_mbps 0" }, + { CCS_R_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS(4), 16, CCS_L_FL_SAME_REG, "max_per_lane_bitrate_lane_c_mode_mbps 4" }, + { CCS_R_DPHY_EQUALIZATION_CAPABILITY, 1, 0, "dphy_equalization_capability" }, + { CCS_R_CPHY_EQUALIZATION_CAPABILITY, 1, 0, "cphy_equalization_capability" }, + { CCS_R_DPHY_PREAMBLE_CAPABILITY, 1, 0, "dphy_preamble_capability" }, + { CCS_R_DPHY_SSC_CAPABILITY, 1, 0, "dphy_ssc_capability" }, + { CCS_R_CPHY_CALIBRATION_CAPABILITY, 1, 0, "cphy_calibration_capability" }, + { CCS_R_DPHY_CALIBRATION_CAPABILITY, 1, 0, "dphy_calibration_capability" }, + { CCS_R_PHY_CTRL_CAPABILITY_2, 1, 0, "phy_ctrl_capability_2" }, + { CCS_R_LRTE_CPHY_CAPABILITY, 1, 0, "lrte_cphy_capability" }, + { CCS_R_LRTE_DPHY_CAPABILITY, 1, 0, "lrte_dphy_capability" }, + { CCS_R_ALPS_CAPABILITY_DPHY, 1, 0, "alps_capability_dphy" }, + { CCS_R_ALPS_CAPABILITY_CPHY, 1, 0, "alps_capability_cphy" }, + { CCS_R_SCRAMBLING_CAPABILITY, 1, 0, "scrambling_capability" }, + { CCS_R_DPHY_MANUAL_CONSTANT, 1, 0, "dphy_manual_constant" }, + { CCS_R_CPHY_MANUAL_CONSTANT, 1, 0, "cphy_manual_constant" }, + { CCS_R_CSI2_INTERFACE_CAPABILITY_MISC, 1, 0, "CSI2_interface_capability_misc" }, + { CCS_R_PHY_CTRL_CAPABILITY_3, 1, 0, "PHY_ctrl_capability_3" }, + { CCS_R_DPHY_SF, 1, 0, "dphy_sf" }, + { CCS_R_CPHY_SF, 1, 0, "cphy_sf" }, + { CCS_R_DPHY_LIMITS_1, 1, 0, "dphy_limits_1" }, + { CCS_R_DPHY_LIMITS_2, 1, 0, "dphy_limits_2" }, + { CCS_R_DPHY_LIMITS_3, 1, 0, "dphy_limits_3" }, + { CCS_R_DPHY_LIMITS_4, 1, 0, "dphy_limits_4" }, + { CCS_R_DPHY_LIMITS_5, 1, 0, "dphy_limits_5" }, + { CCS_R_DPHY_LIMITS_6, 1, 0, "dphy_limits_6" }, + { CCS_R_CPHY_LIMITS_1, 1, 0, "cphy_limits_1" }, + { CCS_R_CPHY_LIMITS_2, 1, 0, "cphy_limits_2" }, + { CCS_R_CPHY_LIMITS_3, 1, 0, "cphy_limits_3" }, + { CCS_R_MIN_FRAME_LENGTH_LINES_BIN, 2, 0, "min_frame_length_lines_bin" }, + { CCS_R_MAX_FRAME_LENGTH_LINES_BIN, 2, 0, "max_frame_length_lines_bin" }, + { CCS_R_MIN_LINE_LENGTH_PCK_BIN, 2, 0, "min_line_length_pck_bin" }, + { CCS_R_MAX_LINE_LENGTH_PCK_BIN, 2, 0, "max_line_length_pck_bin" }, + { CCS_R_MIN_LINE_BLANKING_PCK_BIN, 2, 0, "min_line_blanking_pck_bin" }, + { CCS_R_FINE_INTEGRATION_TIME_MIN_BIN, 2, 0, "fine_integration_time_min_bin" }, + { CCS_R_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN, 2, 0, "fine_integration_time_max_margin_bin" }, + { CCS_R_BINNING_CAPABILITY, 1, 0, "binning_capability" }, + { CCS_R_BINNING_WEIGHTING_CAPABILITY, 1, 0, "binning_weighting_capability" }, + { CCS_R_BINNING_SUB_TYPES, 1, 0, "binning_sub_types" }, + { CCS_R_BINNING_SUB_TYPE(0), 64, 0, "binning_sub_type" }, + { CCS_R_BINNING_WEIGHTING_MONO_CAPABILITY, 1, 0, "binning_weighting_mono_capability" }, + { CCS_R_BINNING_SUB_TYPES_MONO, 1, 0, "binning_sub_types_mono" }, + { CCS_R_BINNING_SUB_TYPE_MONO(0), 64, 0, "binning_sub_type_mono" }, + { CCS_R_DATA_TRANSFER_IF_CAPABILITY, 1, 0, "data_transfer_if_capability" }, + { CCS_R_SHADING_CORRECTION_CAPABILITY, 1, 0, "shading_correction_capability" }, + { CCS_R_GREEN_IMBALANCE_CAPABILITY, 1, 0, "green_imbalance_capability" }, + { CCS_R_MODULE_SPECIFIC_CORRECTION_CAPABILITY, 1, 0, "module_specific_correction_capability" }, + { CCS_R_DEFECT_CORRECTION_CAPABILITY, 2, 0, "defect_correction_capability" }, + { CCS_R_DEFECT_CORRECTION_CAPABILITY_2, 2, 0, "defect_correction_capability_2" }, + { CCS_R_NF_CAPABILITY, 1, 0, "nf_capability" }, + { CCS_R_OB_READOUT_CAPABILITY, 1, 0, "ob_readout_capability" }, + { CCS_R_COLOR_FEEDBACK_CAPABILITY, 1, 0, "color_feedback_capability" }, + { CCS_R_CFA_PATTERN_CAPABILITY, 1, 0, "CFA_pattern_capability" }, + { CCS_R_CFA_PATTERN_CONVERSION_CAPABILITY, 1, 0, "CFA_pattern_conversion_capability" }, + { CCS_R_FLASH_MODE_CAPABILITY, 1, 0, "flash_mode_capability" }, + { CCS_R_SA_STROBE_MODE_CAPABILITY, 1, 0, "sa_strobe_mode_capability" }, + { CCS_R_RESET_MAX_DELAY, 1, 0, "reset_max_delay" }, + { CCS_R_RESET_MIN_TIME, 1, 0, "reset_min_time" }, + { CCS_R_PDAF_CAPABILITY_1, 1, 0, "pdaf_capability_1" }, + { CCS_R_PDAF_CAPABILITY_2, 1, 0, "pdaf_capability_2" }, + { CCS_R_BRACKETING_LUT_CAPABILITY_1, 1, 0, "bracketing_lut_capability_1" }, + { CCS_R_BRACKETING_LUT_CAPABILITY_2, 1, 0, "bracketing_lut_capability_2" }, + { CCS_R_BRACKETING_LUT_SIZE, 1, 0, "bracketing_lut_size" }, + { 0 } /* Guardian */ +}; diff --git a/drivers/media/i2c/ccs/ccs-limits.h b/drivers/media/i2c/ccs/ccs-limits.h new file mode 100644 index 000000000000..1efa43c23a2e --- /dev/null +++ b/drivers/media/i2c/ccs/ccs-limits.h @@ -0,0 +1,259 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */ +/* Copyright (C) 2019--2020 Intel Corporation */ + +#ifndef __CCS_LIMITS_H__ +#define __CCS_LIMITS_H__ + +#include +#include + +struct ccs_limit { + u32 reg; + u16 size; + u16 flags; + const char *name; +}; + +#define CCS_L_FL_SAME_REG BIT(0) + +extern const struct ccs_limit ccs_limits[]; + +#define CCS_L_FRAME_FORMAT_MODEL_TYPE 0 +#define CCS_L_FRAME_FORMAT_MODEL_SUBTYPE 1 +#define CCS_L_FRAME_FORMAT_DESCRIPTOR 2 +#define CCS_L_FRAME_FORMAT_DESCRIPTOR_OFFSET(n) ((n) * 2) +#define CCS_L_FRAME_FORMAT_DESCRIPTOR_4 3 +#define CCS_L_FRAME_FORMAT_DESCRIPTOR_4_OFFSET(n) ((n) * 4) +#define CCS_L_ANALOG_GAIN_CAPABILITY 4 +#define CCS_L_ANALOG_GAIN_CODE_MIN 5 +#define CCS_L_ANALOG_GAIN_CODE_MAX 6 +#define CCS_L_ANALOG_GAIN_CODE_STEP 7 +#define CCS_L_ANALOG_GAIN_TYPE 8 +#define CCS_L_ANALOG_GAIN_M0 9 +#define CCS_L_ANALOG_GAIN_C0 10 +#define CCS_L_ANALOG_GAIN_M1 11 +#define CCS_L_ANALOG_GAIN_C1 12 +#define CCS_L_ANALOG_LINEAR_GAIN_MIN 13 +#define CCS_L_ANALOG_LINEAR_GAIN_MAX 14 +#define CCS_L_ANALOG_LINEAR_GAIN_STEP_SIZE 15 +#define CCS_L_ANALOG_EXPONENTIAL_GAIN_MIN 16 +#define CCS_L_ANALOG_EXPONENTIAL_GAIN_MAX 17 +#define CCS_L_ANALOG_EXPONENTIAL_GAIN_STEP_SIZE 18 +#define CCS_L_DATA_FORMAT_MODEL_TYPE 19 +#define CCS_L_DATA_FORMAT_MODEL_SUBTYPE 20 +#define CCS_L_DATA_FORMAT_DESCRIPTOR 21 +#define CCS_L_DATA_FORMAT_DESCRIPTOR_OFFSET(n) ((n) * 2) +#define CCS_L_INTEGRATION_TIME_CAPABILITY 22 +#define CCS_L_COARSE_INTEGRATION_TIME_MIN 23 +#define CCS_L_COARSE_INTEGRATION_TIME_MAX_MARGIN 24 +#define CCS_L_FINE_INTEGRATION_TIME_MIN 25 +#define CCS_L_FINE_INTEGRATION_TIME_MAX_MARGIN 26 +#define CCS_L_DIGITAL_GAIN_CAPABILITY 27 +#define CCS_L_DIGITAL_GAIN_MIN 28 +#define CCS_L_DIGITAL_GAIN_MAX 29 +#define CCS_L_DIGITAL_GAIN_STEP_SIZE 30 +#define CCS_L_PEDESTAL_CAPABILITY 31 +#define CCS_L_ADC_CAPABILITY 32 +#define CCS_L_ADC_BIT_DEPTH_CAPABILITY 33 +#define CCS_L_MIN_EXT_CLK_FREQ_MHZ 34 +#define CCS_L_MAX_EXT_CLK_FREQ_MHZ 35 +#define CCS_L_MIN_PRE_PLL_CLK_DIV 36 +#define CCS_L_MAX_PRE_PLL_CLK_DIV 37 +#define CCS_L_MIN_PLL_IP_CLK_FREQ_MHZ 38 +#define CCS_L_MAX_PLL_IP_CLK_FREQ_MHZ 39 +#define CCS_L_MIN_PLL_MULTIPLIER 40 +#define CCS_L_MAX_PLL_MULTIPLIER 41 +#define CCS_L_MIN_PLL_OP_CLK_FREQ_MHZ 42 +#define CCS_L_MAX_PLL_OP_CLK_FREQ_MHZ 43 +#define CCS_L_MIN_VT_SYS_CLK_DIV 44 +#define CCS_L_MAX_VT_SYS_CLK_DIV 45 +#define CCS_L_MIN_VT_SYS_CLK_FREQ_MHZ 46 +#define CCS_L_MAX_VT_SYS_CLK_FREQ_MHZ 47 +#define CCS_L_MIN_VT_PIX_CLK_FREQ_MHZ 48 +#define CCS_L_MAX_VT_PIX_CLK_FREQ_MHZ 49 +#define CCS_L_MIN_VT_PIX_CLK_DIV 50 +#define CCS_L_MAX_VT_PIX_CLK_DIV 51 +#define CCS_L_CLOCK_CALCULATION 52 +#define CCS_L_NUM_OF_VT_LANES 53 +#define CCS_L_NUM_OF_OP_LANES 54 +#define CCS_L_OP_BITS_PER_LANE 55 +#define CCS_L_MIN_FRAME_LENGTH_LINES 56 +#define CCS_L_MAX_FRAME_LENGTH_LINES 57 +#define CCS_L_MIN_LINE_LENGTH_PCK 58 +#define CCS_L_MAX_LINE_LENGTH_PCK 59 +#define CCS_L_MIN_LINE_BLANKING_PCK 60 +#define CCS_L_MIN_FRAME_BLANKING_LINES 61 +#define CCS_L_MIN_LINE_LENGTH_PCK_STEP_SIZE 62 +#define CCS_L_TIMING_MODE_CAPABILITY 63 +#define CCS_L_FRAME_MARGIN_MAX_VALUE 64 +#define CCS_L_FRAME_MARGIN_MIN_VALUE 65 +#define CCS_L_GAIN_DELAY_TYPE 66 +#define CCS_L_MIN_OP_SYS_CLK_DIV 67 +#define CCS_L_MAX_OP_SYS_CLK_DIV 68 +#define CCS_L_MIN_OP_SYS_CLK_FREQ_MHZ 69 +#define CCS_L_MAX_OP_SYS_CLK_FREQ_MHZ 70 +#define CCS_L_MIN_OP_PIX_CLK_DIV 71 +#define CCS_L_MAX_OP_PIX_CLK_DIV 72 +#define CCS_L_MIN_OP_PIX_CLK_FREQ_MHZ 73 +#define CCS_L_MAX_OP_PIX_CLK_FREQ_MHZ 74 +#define CCS_L_X_ADDR_MIN 75 +#define CCS_L_Y_ADDR_MIN 76 +#define CCS_L_X_ADDR_MAX 77 +#define CCS_L_Y_ADDR_MAX 78 +#define CCS_L_MIN_X_OUTPUT_SIZE 79 +#define CCS_L_MIN_Y_OUTPUT_SIZE 80 +#define CCS_L_MAX_X_OUTPUT_SIZE 81 +#define CCS_L_MAX_Y_OUTPUT_SIZE 82 +#define CCS_L_X_ADDR_START_DIV_CONSTANT 83 +#define CCS_L_Y_ADDR_START_DIV_CONSTANT 84 +#define CCS_L_X_ADDR_END_DIV_CONSTANT 85 +#define CCS_L_Y_ADDR_END_DIV_CONSTANT 86 +#define CCS_L_X_SIZE_DIV 87 +#define CCS_L_Y_SIZE_DIV 88 +#define CCS_L_X_OUTPUT_DIV 89 +#define CCS_L_Y_OUTPUT_DIV 90 +#define CCS_L_NON_FLEXIBLE_RESOLUTION_SUPPORT 91 +#define CCS_L_MIN_OP_PRE_PLL_CLK_DIV 92 +#define CCS_L_MAX_OP_PRE_PLL_CLK_DIV 93 +#define CCS_L_MIN_OP_PLL_IP_CLK_FREQ_MHZ 94 +#define CCS_L_MAX_OP_PLL_IP_CLK_FREQ_MHZ 95 +#define CCS_L_MIN_OP_PLL_MULTIPLIER 96 +#define CCS_L_MAX_OP_PLL_MULTIPLIER 97 +#define CCS_L_MIN_OP_PLL_OP_CLK_FREQ_MHZ 98 +#define CCS_L_MAX_OP_PLL_OP_CLK_FREQ_MHZ 99 +#define CCS_L_CLOCK_TREE_PLL_CAPABILITY 100 +#define CCS_L_CLOCK_CAPA_TYPE_CAPABILITY 101 +#define CCS_L_MIN_EVEN_INC 102 +#define CCS_L_MIN_ODD_INC 103 +#define CCS_L_MAX_EVEN_INC 104 +#define CCS_L_MAX_ODD_INC 105 +#define CCS_L_AUX_SUBSAMP_CAPABILITY 106 +#define CCS_L_AUX_SUBSAMP_MONO_CAPABILITY 107 +#define CCS_L_MONOCHROME_CAPABILITY 108 +#define CCS_L_PIXEL_READOUT_CAPABILITY 109 +#define CCS_L_MIN_EVEN_INC_MONO 110 +#define CCS_L_MAX_EVEN_INC_MONO 111 +#define CCS_L_MIN_ODD_INC_MONO 112 +#define CCS_L_MAX_ODD_INC_MONO 113 +#define CCS_L_MIN_EVEN_INC_BC2 114 +#define CCS_L_MAX_EVEN_INC_BC2 115 +#define CCS_L_MIN_ODD_INC_BC2 116 +#define CCS_L_MAX_ODD_INC_BC2 117 +#define CCS_L_MIN_EVEN_INC_MONO_BC2 118 +#define CCS_L_MAX_EVEN_INC_MONO_BC2 119 +#define CCS_L_MIN_ODD_INC_MONO_BC2 120 +#define CCS_L_MAX_ODD_INC_MONO_BC2 121 +#define CCS_L_SCALING_CAPABILITY 122 +#define CCS_L_SCALER_M_MIN 123 +#define CCS_L_SCALER_M_MAX 124 +#define CCS_L_SCALER_N_MIN 125 +#define CCS_L_SCALER_N_MAX 126 +#define CCS_L_DIGITAL_CROP_CAPABILITY 127 +#define CCS_L_HDR_CAPABILITY_1 128 +#define CCS_L_MIN_HDR_BIT_DEPTH 129 +#define CCS_L_HDR_RESOLUTION_SUB_TYPES 130 +#define CCS_L_HDR_RESOLUTION_SUB_TYPE 131 +#define CCS_L_HDR_RESOLUTION_SUB_TYPE_OFFSET(n) (n) +#define CCS_L_HDR_CAPABILITY_2 132 +#define CCS_L_MAX_HDR_BIT_DEPTH 133 +#define CCS_L_USL_SUPPORT_CAPABILITY 134 +#define CCS_L_USL_CLOCK_MODE_D_CAPABILITY 135 +#define CCS_L_MIN_OP_SYS_CLK_DIV_REV 136 +#define CCS_L_MAX_OP_SYS_CLK_DIV_REV 137 +#define CCS_L_MIN_OP_PIX_CLK_DIV_REV 138 +#define CCS_L_MAX_OP_PIX_CLK_DIV_REV 139 +#define CCS_L_MIN_OP_SYS_CLK_FREQ_REV_MHZ 140 +#define CCS_L_MAX_OP_SYS_CLK_FREQ_REV_MHZ 141 +#define CCS_L_MIN_OP_PIX_CLK_FREQ_REV_MHZ 142 +#define CCS_L_MAX_OP_PIX_CLK_FREQ_REV_MHZ 143 +#define CCS_L_MAX_BITRATE_REV_D_MODE_MBPS 144 +#define CCS_L_MAX_SYMRATE_REV_C_MODE_MSPS 145 +#define CCS_L_COMPRESSION_CAPABILITY 146 +#define CCS_L_TEST_MODE_CAPABILITY 147 +#define CCS_L_PN9_DATA_FORMAT1 148 +#define CCS_L_PN9_DATA_FORMAT2 149 +#define CCS_L_PN9_DATA_FORMAT3 150 +#define CCS_L_PN9_DATA_FORMAT4 151 +#define CCS_L_PN9_MISC_CAPABILITY 152 +#define CCS_L_TEST_PATTERN_CAPABILITY 153 +#define CCS_L_PATTERN_SIZE_DIV_M1 154 +#define CCS_L_FIFO_SUPPORT_CAPABILITY 155 +#define CCS_L_PHY_CTRL_CAPABILITY 156 +#define CCS_L_CSI_DPHY_LANE_MODE_CAPABILITY 157 +#define CCS_L_CSI_SIGNALING_MODE_CAPABILITY 158 +#define CCS_L_FAST_STANDBY_CAPABILITY 159 +#define CCS_L_CSI_ADDRESS_CONTROL_CAPABILITY 160 +#define CCS_L_DATA_TYPE_CAPABILITY 161 +#define CCS_L_CSI_CPHY_LANE_MODE_CAPABILITY 162 +#define CCS_L_EMB_DATA_CAPABILITY 163 +#define CCS_L_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS 164 +#define CCS_L_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS_OFFSET(n) ((n) * 4) +#define CCS_L_TEMP_SENSOR_CAPABILITY 165 +#define CCS_L_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS 166 +#define CCS_L_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS_OFFSET(n) ((n) * 4) +#define CCS_L_DPHY_EQUALIZATION_CAPABILITY 167 +#define CCS_L_CPHY_EQUALIZATION_CAPABILITY 168 +#define CCS_L_DPHY_PREAMBLE_CAPABILITY 169 +#define CCS_L_DPHY_SSC_CAPABILITY 170 +#define CCS_L_CPHY_CALIBRATION_CAPABILITY 171 +#define CCS_L_DPHY_CALIBRATION_CAPABILITY 172 +#define CCS_L_PHY_CTRL_CAPABILITY_2 173 +#define CCS_L_LRTE_CPHY_CAPABILITY 174 +#define CCS_L_LRTE_DPHY_CAPABILITY 175 +#define CCS_L_ALPS_CAPABILITY_DPHY 176 +#define CCS_L_ALPS_CAPABILITY_CPHY 177 +#define CCS_L_SCRAMBLING_CAPABILITY 178 +#define CCS_L_DPHY_MANUAL_CONSTANT 179 +#define CCS_L_CPHY_MANUAL_CONSTANT 180 +#define CCS_L_CSI2_INTERFACE_CAPABILITY_MISC 181 +#define CCS_L_PHY_CTRL_CAPABILITY_3 182 +#define CCS_L_DPHY_SF 183 +#define CCS_L_CPHY_SF 184 +#define CCS_L_DPHY_LIMITS_1 185 +#define CCS_L_DPHY_LIMITS_2 186 +#define CCS_L_DPHY_LIMITS_3 187 +#define CCS_L_DPHY_LIMITS_4 188 +#define CCS_L_DPHY_LIMITS_5 189 +#define CCS_L_DPHY_LIMITS_6 190 +#define CCS_L_CPHY_LIMITS_1 191 +#define CCS_L_CPHY_LIMITS_2 192 +#define CCS_L_CPHY_LIMITS_3 193 +#define CCS_L_MIN_FRAME_LENGTH_LINES_BIN 194 +#define CCS_L_MAX_FRAME_LENGTH_LINES_BIN 195 +#define CCS_L_MIN_LINE_LENGTH_PCK_BIN 196 +#define CCS_L_MAX_LINE_LENGTH_PCK_BIN 197 +#define CCS_L_MIN_LINE_BLANKING_PCK_BIN 198 +#define CCS_L_FINE_INTEGRATION_TIME_MIN_BIN 199 +#define CCS_L_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN 200 +#define CCS_L_BINNING_CAPABILITY 201 +#define CCS_L_BINNING_WEIGHTING_CAPABILITY 202 +#define CCS_L_BINNING_SUB_TYPES 203 +#define CCS_L_BINNING_SUB_TYPE 204 +#define CCS_L_BINNING_SUB_TYPE_OFFSET(n) (n) +#define CCS_L_BINNING_WEIGHTING_MONO_CAPABILITY 205 +#define CCS_L_BINNING_SUB_TYPES_MONO 206 +#define CCS_L_BINNING_SUB_TYPE_MONO 207 +#define CCS_L_BINNING_SUB_TYPE_MONO_OFFSET(n) (n) +#define CCS_L_DATA_TRANSFER_IF_CAPABILITY 208 +#define CCS_L_SHADING_CORRECTION_CAPABILITY 209 +#define CCS_L_GREEN_IMBALANCE_CAPABILITY 210 +#define CCS_L_MODULE_SPECIFIC_CORRECTION_CAPABILITY 211 +#define CCS_L_DEFECT_CORRECTION_CAPABILITY 212 +#define CCS_L_DEFECT_CORRECTION_CAPABILITY_2 213 +#define CCS_L_NF_CAPABILITY 214 +#define CCS_L_OB_READOUT_CAPABILITY 215 +#define CCS_L_COLOR_FEEDBACK_CAPABILITY 216 +#define CCS_L_CFA_PATTERN_CAPABILITY 217 +#define CCS_L_CFA_PATTERN_CONVERSION_CAPABILITY 218 +#define CCS_L_FLASH_MODE_CAPABILITY 219 +#define CCS_L_SA_STROBE_MODE_CAPABILITY 220 +#define CCS_L_RESET_MAX_DELAY 221 +#define CCS_L_RESET_MIN_TIME 222 +#define CCS_L_PDAF_CAPABILITY_1 223 +#define CCS_L_PDAF_CAPABILITY_2 224 +#define CCS_L_BRACKETING_LUT_CAPABILITY_1 225 +#define CCS_L_BRACKETING_LUT_CAPABILITY_2 226 +#define CCS_L_BRACKETING_LUT_SIZE 227 +#define CCS_L_LAST 228 + +#endif /* __CCS_LIMITS_H__ */ diff --git a/drivers/media/i2c/ccs/ccs-quirk.c b/drivers/media/i2c/ccs/ccs-quirk.c new file mode 100644 index 000000000000..5a24da1d7aa9 --- /dev/null +++ b/drivers/media/i2c/ccs/ccs-quirk.c @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * drivers/media/i2c/ccs/ccs-quirk.c + * + * Generic driver for MIPI CCS/SMIA/SMIA++ compliant camera sensors + * + * Copyright (C) 2020 Intel Corporation + * Copyright (C) 2011--2012 Nokia Corporation + * Contact: Sakari Ailus + */ + +#include + +#include "ccs.h" +#include "ccs-limits.h" + +static int ccs_write_addr_8s(struct ccs_sensor *sensor, + const struct ccs_reg_8 *regs, int len) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int rval; + + for (; len > 0; len--, regs++) { + rval = ccs_write_addr(sensor, regs->reg, regs->val); + if (rval < 0) { + dev_err(&client->dev, + "error %d writing reg 0x%4.4x, val 0x%2.2x", + rval, regs->reg, regs->val); + return rval; + } + } + + return 0; +} + +static int jt8ew9_limits(struct ccs_sensor *sensor) +{ + if (sensor->minfo.revision_number_major < 0x03) + sensor->frame_skip = 1; + + /* Below 24 gain doesn't have effect at all, */ + /* but ~59 is needed for full dynamic range */ + ccs_replace_limit(sensor, CCS_L_ANALOG_GAIN_CODE_MIN, 0, 59); + ccs_replace_limit(sensor, CCS_L_ANALOG_GAIN_CODE_MAX, 0, 6000); + + return 0; +} + +static int jt8ew9_post_poweron(struct ccs_sensor *sensor) +{ + static const struct ccs_reg_8 regs[] = { + { 0x30a3, 0xd8 }, /* Output port control : LVDS ports only */ + { 0x30ae, 0x00 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */ + { 0x30af, 0xd0 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */ + { 0x322d, 0x04 }, /* Adjusting Processing Image Size to Scaler Toshiba Recommendation Setting */ + { 0x3255, 0x0f }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */ + { 0x3256, 0x15 }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */ + { 0x3258, 0x70 }, /* Analog Gain Control Toshiba Recommendation Setting */ + { 0x3259, 0x70 }, /* Analog Gain Control Toshiba Recommendation Setting */ + { 0x325f, 0x7c }, /* Analog Gain Control Toshiba Recommendation Setting */ + { 0x3302, 0x06 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */ + { 0x3304, 0x00 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */ + { 0x3307, 0x22 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */ + { 0x3308, 0x8d }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */ + { 0x331e, 0x0f }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ + { 0x3320, 0x30 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ + { 0x3321, 0x11 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ + { 0x3322, 0x98 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ + { 0x3323, 0x64 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ + { 0x3325, 0x83 }, /* Read Out Timing Control Toshiba Recommendation Setting */ + { 0x3330, 0x18 }, /* Read Out Timing Control Toshiba Recommendation Setting */ + { 0x333c, 0x01 }, /* Read Out Timing Control Toshiba Recommendation Setting */ + { 0x3345, 0x2f }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ + { 0x33de, 0x38 }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */ + /* Taken from v03. No idea what the rest are. */ + { 0x32e0, 0x05 }, + { 0x32e1, 0x05 }, + { 0x32e2, 0x04 }, + { 0x32e5, 0x04 }, + { 0x32e6, 0x04 }, + + }; + + return ccs_write_addr_8s(sensor, regs, ARRAY_SIZE(regs)); +} + +const struct ccs_quirk smiapp_jt8ew9_quirk = { + .limits = jt8ew9_limits, + .post_poweron = jt8ew9_post_poweron, +}; + +static int imx125es_post_poweron(struct ccs_sensor *sensor) +{ + /* Taken from v02. No idea what the other two are. */ + static const struct ccs_reg_8 regs[] = { + /* + * 0x3302: clk during frame blanking: + * 0x00 - HS mode, 0x01 - LP11 + */ + { 0x3302, 0x01 }, + { 0x302d, 0x00 }, + { 0x3b08, 0x8c }, + }; + + return ccs_write_addr_8s(sensor, regs, ARRAY_SIZE(regs)); +} + +const struct ccs_quirk smiapp_imx125es_quirk = { + .post_poweron = imx125es_post_poweron, +}; + +static int jt8ev1_limits(struct ccs_sensor *sensor) +{ + ccs_replace_limit(sensor, CCS_L_X_ADDR_MAX, 0, 4271); + ccs_replace_limit(sensor, CCS_L_MIN_LINE_BLANKING_PCK_BIN, 0, 184); + + return 0; +} + +static int jt8ev1_post_poweron(struct ccs_sensor *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int rval; + static const struct ccs_reg_8 regs[] = { + { 0x3031, 0xcd }, /* For digital binning (EQ_MONI) */ + { 0x30a3, 0xd0 }, /* FLASH STROBE enable */ + { 0x3237, 0x00 }, /* For control of pulse timing for ADC */ + { 0x3238, 0x43 }, + { 0x3301, 0x06 }, /* For analog bias for sensor */ + { 0x3302, 0x06 }, + { 0x3304, 0x00 }, + { 0x3305, 0x88 }, + { 0x332a, 0x14 }, + { 0x332c, 0x6b }, + { 0x3336, 0x01 }, + { 0x333f, 0x1f }, + { 0x3355, 0x00 }, + { 0x3356, 0x20 }, + { 0x33bf, 0x20 }, /* Adjust the FBC speed */ + { 0x33c9, 0x20 }, + { 0x33ce, 0x30 }, /* Adjust the parameter for logic function */ + { 0x33cf, 0xec }, /* For Black sun */ + { 0x3328, 0x80 }, /* Ugh. No idea what's this. */ + }; + static const struct ccs_reg_8 regs_96[] = { + { 0x30ae, 0x00 }, /* For control of ADC clock */ + { 0x30af, 0xd0 }, + { 0x30b0, 0x01 }, + }; + + rval = ccs_write_addr_8s(sensor, regs, ARRAY_SIZE(regs)); + if (rval < 0) + return rval; + + switch (sensor->hwcfg->ext_clk) { + case 9600000: + return ccs_write_addr_8s(sensor, regs_96, + ARRAY_SIZE(regs_96)); + default: + dev_warn(&client->dev, "no MSRs for %d Hz ext_clk\n", + sensor->hwcfg->ext_clk); + return 0; + } +} + +static int jt8ev1_pre_streamon(struct ccs_sensor *sensor) +{ + return ccs_write_addr(sensor, 0x3328, 0x00); +} + +static int jt8ev1_post_streamoff(struct ccs_sensor *sensor) +{ + int rval; + + /* Workaround: allows fast standby to work properly */ + rval = ccs_write_addr(sensor, 0x3205, 0x04); + if (rval < 0) + return rval; + + /* Wait for 1 ms + one line => 2 ms is likely enough */ + usleep_range(2000, 2050); + + /* Restore it */ + rval = ccs_write_addr(sensor, 0x3205, 0x00); + if (rval < 0) + return rval; + + return ccs_write_addr(sensor, 0x3328, 0x80); +} + +static int jt8ev1_init(struct ccs_sensor *sensor) +{ + sensor->pll.flags |= SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE; + + return 0; +} + +const struct ccs_quirk smiapp_jt8ev1_quirk = { + .limits = jt8ev1_limits, + .post_poweron = jt8ev1_post_poweron, + .pre_streamon = jt8ev1_pre_streamon, + .post_streamoff = jt8ev1_post_streamoff, + .init = jt8ev1_init, +}; + +static int tcm8500md_limits(struct ccs_sensor *sensor) +{ + ccs_replace_limit(sensor, CCS_L_MIN_PLL_IP_CLK_FREQ_MHZ, 0, 2700000); + + return 0; +} + +const struct ccs_quirk smiapp_tcm8500md_quirk = { + .limits = tcm8500md_limits, +}; diff --git a/drivers/media/i2c/ccs/ccs-quirk.h b/drivers/media/i2c/ccs/ccs-quirk.h new file mode 100644 index 000000000000..3e7779e2fc4b --- /dev/null +++ b/drivers/media/i2c/ccs/ccs-quirk.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * drivers/media/i2c/ccs/ccs-quirk.h + * + * Generic driver for MIPI CCS/SMIA/SMIA++ compliant camera sensors + * + * Copyright (C) 2020 Intel Corporation + * Copyright (C) 2011--2012 Nokia Corporation + * Contact: Sakari Ailus + */ + +#ifndef __CCS_QUIRK__ +#define __CCS_QUIRK__ + +struct ccs_sensor; + +/** + * struct ccs_quirk - quirks for sensors that deviate from SMIA++ standard + * + * @limits: Replace sensor->limits with values which can't be read from + * sensor registers. Called the first time the sensor is powered up. + * @post_poweron: Called always after the sensor has been fully powered on. + * @pre_streamon: Called just before streaming is enabled. + * @post_streamon: Called right after stopping streaming. + * @pll_flags: Return flags for the PLL calculator. + * @init: Quirk initialisation, called the last in probe(). This is + * also appropriate for adding sensor specific controls, for instance. + * @reg_access: Register access quirk. The quirk may divert the access + * to another register, or no register at all. + * + * @write: Is this read (false) or write (true) access? + * @reg: Pointer to the register to access + * @value: Register value, set by the caller on write, or + * by the quirk on read + * + * @return: 0 on success, -ENOIOCTLCMD if no register + * access may be done by the caller (default read + * value is zero), else negative error code on error + */ +struct ccs_quirk { + int (*limits)(struct ccs_sensor *sensor); + int (*post_poweron)(struct ccs_sensor *sensor); + int (*pre_streamon)(struct ccs_sensor *sensor); + int (*post_streamoff)(struct ccs_sensor *sensor); + unsigned long (*pll_flags)(struct ccs_sensor *sensor); + int (*init)(struct ccs_sensor *sensor); + int (*reg_access)(struct ccs_sensor *sensor, bool write, u32 *reg, + u32 *val); + unsigned long flags; +}; + +#define CCS_QUIRK_FLAG_8BIT_READ_ONLY (1 << 0) + +struct ccs_reg_8 { + u16 reg; + u8 val; +}; + +#define CCS_MK_QUIRK_REG_8(_reg, _val) \ + { \ + .reg = (u16)_reg, \ + .val = _val, \ + } + +#define ccs_call_quirk(sensor, _quirk, ...) \ + ((sensor)->minfo.quirk && \ + (sensor)->minfo.quirk->_quirk ? \ + (sensor)->minfo.quirk->_quirk(sensor, ##__VA_ARGS__) : 0) + +#define ccs_needs_quirk(sensor, _quirk) \ + ((sensor)->minfo.quirk ? \ + (sensor)->minfo.quirk->flags & _quirk : 0) + +extern const struct ccs_quirk smiapp_jt8ev1_quirk; +extern const struct ccs_quirk smiapp_imx125es_quirk; +extern const struct ccs_quirk smiapp_jt8ew9_quirk; +extern const struct ccs_quirk smiapp_tcm8500md_quirk; + +#endif /* __CCS_QUIRK__ */ diff --git a/drivers/media/i2c/ccs/ccs-reg-access.c b/drivers/media/i2c/ccs/ccs-reg-access.c new file mode 100644 index 000000000000..a8e9a235bfb3 --- /dev/null +++ b/drivers/media/i2c/ccs/ccs-reg-access.c @@ -0,0 +1,266 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * drivers/media/i2c/ccs/ccs-reg-access.c + * + * Generic driver for MIPI CCS/SMIA/SMIA++ compliant camera sensors + * + * Copyright (C) 2020 Intel Corporation + * Copyright (C) 2011--2012 Nokia Corporation + * Contact: Sakari Ailus + */ + +#include + +#include +#include + +#include "ccs.h" + +static uint32_t float_to_u32_mul_1000000(struct i2c_client *client, + uint32_t phloat) +{ + int32_t exp; + uint64_t man; + + if (phloat >= 0x80000000) { + dev_err(&client->dev, "this is a negative number\n"); + return 0; + } + + if (phloat == 0x7f800000) + return ~0; /* Inf. */ + + if ((phloat & 0x7f800000) == 0x7f800000) { + dev_err(&client->dev, "NaN or other special number\n"); + return 0; + } + + /* Valid cases begin here */ + if (phloat == 0) + return 0; /* Valid zero */ + + if (phloat > 0x4f800000) + return ~0; /* larger than 4294967295 */ + + /* + * Unbias exponent (note how phloat is now guaranteed to + * have 0 in the high bit) + */ + exp = ((int32_t)phloat >> 23) - 127; + + /* Extract mantissa, add missing '1' bit and it's in MHz */ + man = ((phloat & 0x7fffff) | 0x800000) * 1000000ULL; + + if (exp < 0) + man >>= -exp; + else + man <<= exp; + + man >>= 23; /* Remove mantissa bias */ + + return man & 0xffffffff; +} + + +/* + * Read a 8/16/32-bit i2c register. The value is returned in 'val'. + * Returns zero if successful, or non-zero otherwise. + */ +static int ____ccs_read_addr(struct ccs_sensor *sensor, u16 reg, u16 len, + u32 *val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + struct i2c_msg msg; + unsigned char data_buf[sizeof(u32)] = { 0 }; + unsigned char offset_buf[sizeof(u16)]; + int r; + + if (len > sizeof(data_buf)) + return -EINVAL; + + msg.addr = client->addr; + msg.flags = 0; + msg.len = sizeof(offset_buf); + msg.buf = offset_buf; + put_unaligned_be16(reg, offset_buf); + + r = i2c_transfer(client->adapter, &msg, 1); + if (r != 1) { + if (r >= 0) + r = -EBUSY; + goto err; + } + + msg.len = len; + msg.flags = I2C_M_RD; + msg.buf = &data_buf[sizeof(data_buf) - len]; + + r = i2c_transfer(client->adapter, &msg, 1); + if (r != 1) { + if (r >= 0) + r = -EBUSY; + goto err; + } + + *val = get_unaligned_be32(data_buf); + + return 0; + +err: + dev_err(&client->dev, "read from offset 0x%x error %d\n", reg, r); + + return r; +} + +/* Read a register using 8-bit access only. */ +static int ____ccs_read_addr_8only(struct ccs_sensor *sensor, u16 reg, + u16 len, u32 *val) +{ + unsigned int i; + int rval; + + *val = 0; + + for (i = 0; i < len; i++) { + u32 val8; + + rval = ____ccs_read_addr(sensor, reg + i, 1, &val8); + if (rval < 0) + return rval; + *val |= val8 << ((len - i - 1) << 3); + } + + return 0; +} + +unsigned int ccs_reg_width(u32 reg) +{ + if (reg & CCS_FL_16BIT) + return sizeof(uint16_t); + if (reg & CCS_FL_32BIT) + return sizeof(uint32_t); + + return sizeof(uint8_t); +} + +/* + * Read a 8/16/32-bit i2c register. The value is returned in 'val'. + * Returns zero if successful, or non-zero otherwise. + */ +static int __ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val, + bool only8) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + unsigned int len = ccs_reg_width(reg); + int rval; + + if (!only8) + rval = ____ccs_read_addr(sensor, CCS_REG_ADDR(reg), len, val); + else + rval = ____ccs_read_addr_8only(sensor, CCS_REG_ADDR(reg), len, + val); + if (rval < 0) + return rval; + + if (reg & CCS_FL_FLOAT_IREAL) + *val = float_to_u32_mul_1000000(client, *val); + + return 0; +} + +int ccs_read_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 *val) +{ + return __ccs_read_addr( + sensor, reg, val, + ccs_needs_quirk(sensor, CCS_QUIRK_FLAG_8BIT_READ_ONLY)); +} + +static int ccs_read_addr_quirk(struct ccs_sensor *sensor, u32 reg, u32 *val, + bool force8) +{ + int rval; + + *val = 0; + rval = ccs_call_quirk(sensor, reg_access, false, ®, val); + if (rval == -ENOIOCTLCMD) + return 0; + if (rval < 0) + return rval; + + if (force8) + return __ccs_read_addr(sensor, reg, val, true); + + return ccs_read_addr_no_quirk(sensor, reg, val); +} + +int ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val) +{ + return ccs_read_addr_quirk(sensor, reg, val, false); +} + +int ccs_read_addr_8only(struct ccs_sensor *sensor, u32 reg, u32 *val) +{ + return ccs_read_addr_quirk(sensor, reg, val, true); +} + +int ccs_write_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + struct i2c_msg msg; + unsigned char data[6]; + unsigned int retries; + unsigned int len = ccs_reg_width(reg); + int r; + + if (len > sizeof(data) - 2) + return -EINVAL; + + msg.addr = client->addr; + msg.flags = 0; /* Write */ + msg.len = 2 + len; + msg.buf = data; + + put_unaligned_be16(CCS_REG_ADDR(reg), data); + put_unaligned_be32(val << (8 * (sizeof(val) - len)), data + 2); + + for (retries = 0; retries < 5; retries++) { + /* + * Due to unknown reason sensor stops responding. This + * loop is a temporaty solution until the root cause + * is found. + */ + r = i2c_transfer(client->adapter, &msg, 1); + if (r == 1) { + if (retries) + dev_err(&client->dev, + "sensor i2c stall encountered. retries: %d\n", + retries); + return 0; + } + + usleep_range(2000, 2000); + } + + dev_err(&client->dev, + "wrote 0x%x to offset 0x%x error %d\n", val, + CCS_REG_ADDR(reg), r); + + return r; +} + +/* + * Write to a 8/16-bit register. + * Returns zero if successful, or non-zero otherwise. + */ +int ccs_write_addr(struct ccs_sensor *sensor, u32 reg, u32 val) +{ + int rval; + + rval = ccs_call_quirk(sensor, reg_access, true, ®, &val); + if (rval == -ENOIOCTLCMD) + return 0; + if (rval < 0) + return rval; + + return ccs_write_addr_no_quirk(sensor, reg, val); +} diff --git a/drivers/media/i2c/ccs/ccs-reg-access.h b/drivers/media/i2c/ccs/ccs-reg-access.h new file mode 100644 index 000000000000..9fdf5659ed09 --- /dev/null +++ b/drivers/media/i2c/ccs/ccs-reg-access.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * include/media/ccs/ccs-reg-access.h + * + * Generic driver for MIPI CCS/SMIA/SMIA++ compliant camera sensors + * + * Copyright (C) 2020 Intel Corporation + * Copyright (C) 2011--2012 Nokia Corporation + * Contact: Sakari Ailus + */ + +#ifndef SMIAPP_REGS_H +#define SMIAPP_REGS_H + +#include +#include + +#include "ccs-regs.h" + +#define CCS_REG_ADDR(reg) ((u16)reg) + +struct ccs_sensor; + +int ccs_read_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 *val); +int ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val); +int ccs_read_addr_8only(struct ccs_sensor *sensor, u32 reg, u32 *val); +int ccs_write_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 val); +int ccs_write_addr(struct ccs_sensor *sensor, u32 reg, u32 val); + +unsigned int ccs_reg_width(u32 reg); + +#define ccs_read(sensor, reg_name, val) \ + ccs_read_addr(sensor, CCS_R_##reg_name, val) + +#define ccs_write(sensor, reg_name, val) \ + ccs_write_addr(sensor, CCS_R_##reg_name, val) + +#endif diff --git a/drivers/media/i2c/ccs/ccs-regs.h b/drivers/media/i2c/ccs/ccs-regs.h new file mode 100644 index 000000000000..4b3e5df2121f --- /dev/null +++ b/drivers/media/i2c/ccs/ccs-regs.h @@ -0,0 +1,954 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */ +/* Copyright (C) 2019--2020 Intel Corporation */ + +#ifndef __CCS_REGS_H__ +#define __CCS_REGS_H__ + +#include + +#define CCS_FL_BASE 16 +#define CCS_FL_16BIT BIT(CCS_FL_BASE) +#define CCS_FL_32BIT BIT(CCS_FL_BASE + 1) +#define CCS_FL_FLOAT_IREAL BIT(CCS_FL_BASE + 2) +#define CCS_FL_IREAL BIT(CCS_FL_BASE + 3) +#define CCS_R_ADDR(r) ((r) & 0xffff) + +#define CCS_R_MODULE_MODEL_ID (0x0000 | CCS_FL_16BIT) +#define CCS_R_MODULE_REVISION_NUMBER_MAJOR 0x0002 +#define CCS_R_FRAME_COUNT 0x0005 +#define CCS_R_PIXEL_ORDER 0x0006 +#define CCS_PIXEL_ORDER_GRBG 0U +#define CCS_PIXEL_ORDER_RGGB 1U +#define CCS_PIXEL_ORDER_BGGR 2U +#define CCS_PIXEL_ORDER_GBRG 3U +#define CCS_R_MIPI_CCS_VERSION 0x0007 +#define CCS_MIPI_CCS_VERSION_V1_0 0x10 +#define CCS_MIPI_CCS_VERSION_V1_1 0x11 +#define CCS_MIPI_CCS_VERSION_MAJOR_SHIFT 4U +#define CCS_MIPI_CCS_VERSION_MAJOR_MASK 0xf0 +#define CCS_MIPI_CCS_VERSION_MINOR_SHIFT 0U +#define CCS_MIPI_CCS_VERSION_MINOR_MASK 0xf +#define CCS_R_DATA_PEDESTAL (0x0008 | CCS_FL_16BIT) +#define CCS_R_MODULE_MANUFACTURER_ID (0x000e | CCS_FL_16BIT) +#define CCS_R_MODULE_REVISION_NUMBER_MINOR 0x0010 +#define CCS_R_MODULE_DATE_YEAR 0x0012 +#define CCS_R_MODULE_DATE_MONTH 0x0013 +#define CCS_R_MODULE_DATE_DAY 0x0014 +#define CCS_R_MODULE_DATE_PHASE 0x0015 +#define CCS_MODULE_DATE_PHASE_SHIFT 0U +#define CCS_MODULE_DATE_PHASE_MASK 0x7 +#define CCS_MODULE_DATE_PHASE_TS 0U +#define CCS_MODULE_DATE_PHASE_ES 1U +#define CCS_MODULE_DATE_PHASE_CS 2U +#define CCS_MODULE_DATE_PHASE_MP 3U +#define CCS_R_SENSOR_MODEL_ID (0x0016 | CCS_FL_16BIT) +#define CCS_R_SENSOR_REVISION_NUMBER 0x0018 +#define CCS_R_SENSOR_FIRMWARE_VERSION 0x001a +#define CCS_R_SERIAL_NUMBER (0x001c | CCS_FL_32BIT) +#define CCS_R_SENSOR_MANUFACTURER_ID (0x0020 | CCS_FL_16BIT) +#define CCS_R_SENSOR_REVISION_NUMBER_16 (0x0022 | CCS_FL_16BIT) +#define CCS_R_FRAME_FORMAT_MODEL_TYPE 0x0040 +#define CCS_FRAME_FORMAT_MODEL_TYPE_2_BYTE 1U +#define CCS_FRAME_FORMAT_MODEL_TYPE_4_BYTE 2U +#define CCS_R_FRAME_FORMAT_MODEL_SUBTYPE 0x0041 +#define CCS_FRAME_FORMAT_MODEL_SUBTYPE_ROWS_SHIFT 0U +#define CCS_FRAME_FORMAT_MODEL_SUBTYPE_ROWS_MASK 0xf +#define CCS_FRAME_FORMAT_MODEL_SUBTYPE_COLUMNS_SHIFT 4U +#define CCS_FRAME_FORMAT_MODEL_SUBTYPE_COLUMNS_MASK 0xf0 +#define CCS_R_FRAME_FORMAT_DESCRIPTOR(n) ((0x0042 | CCS_FL_16BIT) + (n) * 2) +#define CCS_LIM_FRAME_FORMAT_DESCRIPTOR_MIN_N 0U +#define CCS_LIM_FRAME_FORMAT_DESCRIPTOR_MAX_N 14U +#define CCS_R_FRAME_FORMAT_DESCRIPTOR_4(n) ((0x0060 | CCS_FL_32BIT) + (n) * 4) +#define CCS_FRAME_FORMAT_DESCRIPTOR_PIXELS_SHIFT 0U +#define CCS_FRAME_FORMAT_DESCRIPTOR_PIXELS_MASK 0xfff +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_SHIFT 12U +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MASK 0xf000 +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_EMBEDDED 1U +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_DUMMY_PIXEL 2U +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_BLACK_PIXEL 3U +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_DARK_PIXEL 4U +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_VISIBLE_PIXEL 5U +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MANUF_SPECIFIC_0 8U +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MANUF_SPECIFIC_1 9U +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MANUF_SPECIFIC_2 10U +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MANUF_SPECIFIC_3 11U +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MANUF_SPECIFIC_4 12U +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MANUF_SPECIFIC_5 13U +#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MANUF_SPECIFIC_6 14U +#define CCS_LIM_FRAME_FORMAT_DESCRIPTOR_4_MIN_N 0U +#define CCS_LIM_FRAME_FORMAT_DESCRIPTOR_4_MAX_N 7U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PIXELS_SHIFT 0U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PIXELS_MASK 0xffff +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_SHIFT 28U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MASK 0xf0000000 +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_EMBEDDED 1U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_DUMMY_PIXEL 2U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_BLACK_PIXEL 3U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_DARK_PIXEL 4U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_VISIBLE_PIXEL 5U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_0 8U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_1 9U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_2 10U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_3 11U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_4 12U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_5 13U +#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_6 14U +#define CCS_R_ANALOG_GAIN_CAPABILITY (0x0080 | CCS_FL_16BIT) +#define CCS_ANALOG_GAIN_CAPABILITY_GLOBAL 0U +#define CCS_ANALOG_GAIN_CAPABILITY_ALTERNATE_GLOBAL 2U +#define CCS_R_ANALOG_GAIN_CODE_MIN (0x0084 | CCS_FL_16BIT) +#define CCS_R_ANALOG_GAIN_CODE_MAX (0x0086 | CCS_FL_16BIT) +#define CCS_R_ANALOG_GAIN_CODE_STEP (0x0088 | CCS_FL_16BIT) +#define CCS_R_ANALOG_GAIN_TYPE (0x008a | CCS_FL_16BIT) +#define CCS_R_ANALOG_GAIN_M0 (0x008c | CCS_FL_16BIT) +#define CCS_R_ANALOG_GAIN_C0 (0x008e | CCS_FL_16BIT) +#define CCS_R_ANALOG_GAIN_M1 (0x0090 | CCS_FL_16BIT) +#define CCS_R_ANALOG_GAIN_C1 (0x0092 | CCS_FL_16BIT) +#define CCS_R_ANALOG_LINEAR_GAIN_MIN (0x0094 | CCS_FL_16BIT) +#define CCS_R_ANALOG_LINEAR_GAIN_MAX (0x0096 | CCS_FL_16BIT) +#define CCS_R_ANALOG_LINEAR_GAIN_STEP_SIZE (0x0098 | CCS_FL_16BIT) +#define CCS_R_ANALOG_EXPONENTIAL_GAIN_MIN (0x009a | CCS_FL_16BIT) +#define CCS_R_ANALOG_EXPONENTIAL_GAIN_MAX (0x009c | CCS_FL_16BIT) +#define CCS_R_ANALOG_EXPONENTIAL_GAIN_STEP_SIZE (0x009e | CCS_FL_16BIT) +#define CCS_R_DATA_FORMAT_MODEL_TYPE 0x00c0 +#define CCS_DATA_FORMAT_MODEL_TYPE_NORMAL 1U +#define CCS_DATA_FORMAT_MODEL_TYPE_EXTENDED 2U +#define CCS_R_DATA_FORMAT_MODEL_SUBTYPE 0x00c1 +#define CCS_DATA_FORMAT_MODEL_SUBTYPE_ROWS_SHIFT 0U +#define CCS_DATA_FORMAT_MODEL_SUBTYPE_ROWS_MASK 0xf +#define CCS_DATA_FORMAT_MODEL_SUBTYPE_COLUMNS_SHIFT 4U +#define CCS_DATA_FORMAT_MODEL_SUBTYPE_COLUMNS_MASK 0xf0 +#define CCS_R_DATA_FORMAT_DESCRIPTOR(n) ((0x00c2 | CCS_FL_16BIT) + (n) * 2) +#define CCS_LIM_DATA_FORMAT_DESCRIPTOR_MIN_N 0U +#define CCS_LIM_DATA_FORMAT_DESCRIPTOR_MAX_N 15U +#define CCS_DATA_FORMAT_DESCRIPTOR_COMPRESSED_SHIFT 0U +#define CCS_DATA_FORMAT_DESCRIPTOR_COMPRESSED_MASK 0xff +#define CCS_DATA_FORMAT_DESCRIPTOR_UNCOMPRESSED_SHIFT 8U +#define CCS_DATA_FORMAT_DESCRIPTOR_UNCOMPRESSED_MASK 0xff00 +#define CCS_R_MODE_SELECT 0x0100 +#define CCS_MODE_SELECT_SOFTWARE_STANDBY 0U +#define CCS_MODE_SELECT_STREAMING 1U +#define CCS_R_IMAGE_ORIENTATION 0x0101 +#define CCS_IMAGE_ORIENTATION_HORIZONTAL_MIRROR BIT(0) +#define CCS_IMAGE_ORIENTATION_VERTICAL_FLIP BIT(1) +#define CCS_R_SOFTWARE_RESET 0x0103 +#define CCS_SOFTWARE_RESET_OFF 0U +#define CCS_SOFTWARE_RESET_ON 1U +#define CCS_R_GROUPED_PARAMETER_HOLD 0x0104 +#define CCS_R_MASK_CORRUPTED_FRAMES 0x0105 +#define CCS_MASK_CORRUPTED_FRAMES_ALLOW 0U +#define CCS_MASK_CORRUPTED_FRAMES_MASK 1U +#define CCS_R_FAST_STANDBY_CTRL 0x0106 +#define CCS_FAST_STANDBY_CTRL_COMPLETE_FRAMES 0U +#define CCS_FAST_STANDBY_CTRL_FRAME_TRUNCATION 1U +#define CCS_R_CCI_ADDRESS_CTRL 0x0107 +#define CCS_R_2ND_CCI_IF_CTRL 0x0108 +#define CCS_2ND_CCI_IF_CTRL_ENABLE BIT(0) +#define CCS_2ND_CCI_IF_CTRL_ACK BIT(1) +#define CCS_R_2ND_CCI_ADDRESS_CTRL 0x0109 +#define CCS_R_CSI_CHANNEL_IDENTIFIER 0x0110 +#define CCS_R_CSI_SIGNALING_MODE 0x0111 +#define CCS_CSI_SIGNALING_MODE_CSI_2_DPHY 2U +#define CCS_CSI_SIGNALING_MODE_CSI_2_CPHY 3U +#define CCS_R_CSI_DATA_FORMAT (0x0112 | CCS_FL_16BIT) +#define CCS_R_CSI_LANE_MODE 0x0114 +#define CCS_R_DPCM_FRAME_DT 0x011d +#define CCS_R_BOTTOM_EMBEDDED_DATA_DT 0x011e +#define CCS_R_BOTTOM_EMBEDDED_DATA_VC 0x011f +#define CCS_R_GAIN_MODE 0x0120 +#define CCS_GAIN_MODE_GLOBAL 0U +#define CCS_GAIN_MODE_ALTERNATE 1U +#define CCS_R_ADC_BIT_DEPTH 0x0121 +#define CCS_R_EMB_DATA_CTRL 0x0122 +#define CCS_EMB_DATA_CTRL_RAW8_PACKING_FOR_RAW16 BIT(0) +#define CCS_EMB_DATA_CTRL_RAW10_PACKING_FOR_RAW20 BIT(1) +#define CCS_EMB_DATA_CTRL_RAW12_PACKING_FOR_RAW24 BIT(2) +#define CCS_R_GPIO_TRIG_MODE 0x0130 +#define CCS_R_EXTCLK_FREQUENCY_MHZ (0x0136 | (CCS_FL_16BIT | CCS_FL_IREAL)) +#define CCS_R_TEMP_SENSOR_CTRL 0x0138 +#define CCS_TEMP_SENSOR_CTRL_ENABLE BIT(0) +#define CCS_R_TEMP_SENSOR_MODE 0x0139 +#define CCS_R_TEMP_SENSOR_OUTPUT 0x013a +#define CCS_R_FINE_INTEGRATION_TIME (0x0200 | CCS_FL_16BIT) +#define CCS_R_COARSE_INTEGRATION_TIME (0x0202 | CCS_FL_16BIT) +#define CCS_R_ANALOG_GAIN_CODE_GLOBAL (0x0204 | CCS_FL_16BIT) +#define CCS_R_ANALOG_LINEAR_GAIN_GLOBAL (0x0206 | CCS_FL_16BIT) +#define CCS_R_ANALOG_EXPONENTIAL_GAIN_GLOBAL (0x0208 | CCS_FL_16BIT) +#define CCS_R_DIGITAL_GAIN_GLOBAL (0x020e | CCS_FL_16BIT) +#define CCS_R_SHORT_ANALOG_GAIN_GLOBAL (0x0216 | CCS_FL_16BIT) +#define CCS_R_SHORT_DIGITAL_GAIN_GLOBAL (0x0218 | CCS_FL_16BIT) +#define CCS_R_HDR_MODE 0x0220 +#define CCS_HDR_MODE_ENABLED BIT(0) +#define CCS_HDR_MODE_SEPARATE_ANALOG_GAIN BIT(1) +#define CCS_HDR_MODE_UPSCALING BIT(2) +#define CCS_HDR_MODE_RESET_SYNC BIT(3) +#define CCS_HDR_MODE_TIMING_MODE BIT(4) +#define CCS_HDR_MODE_EXPOSURE_CTRL_DIRECT BIT(5) +#define CCS_HDR_MODE_SEPARATE_DIGITAL_GAIN BIT(6) +#define CCS_R_HDR_RESOLUTION_REDUCTION 0x0221 +#define CCS_HDR_RESOLUTION_REDUCTION_ROW_SHIFT 0U +#define CCS_HDR_RESOLUTION_REDUCTION_ROW_MASK 0xf +#define CCS_HDR_RESOLUTION_REDUCTION_COLUMN_SHIFT 4U +#define CCS_HDR_RESOLUTION_REDUCTION_COLUMN_MASK 0xf0 +#define CCS_R_EXPOSURE_RATIO 0x0222 +#define CCS_R_HDR_INTERNAL_BIT_DEPTH 0x0223 +#define CCS_R_DIRECT_SHORT_INTEGRATION_TIME (0x0224 | CCS_FL_16BIT) +#define CCS_R_SHORT_ANALOG_LINEAR_GAIN_GLOBAL (0x0226 | CCS_FL_16BIT) +#define CCS_R_SHORT_ANALOG_EXPONENTIAL_GAIN_GLOBAL (0x0228 | CCS_FL_16BIT) +#define CCS_R_VT_PIX_CLK_DIV (0x0300 | CCS_FL_16BIT) +#define CCS_R_VT_SYS_CLK_DIV (0x0302 | CCS_FL_16BIT) +#define CCS_R_PRE_PLL_CLK_DIV (0x0304 | CCS_FL_16BIT) +#define CCS_R_PLL_MULTIPLIER (0x0306 | CCS_FL_16BIT) +#define CCS_R_OP_PIX_CLK_DIV (0x0308 | CCS_FL_16BIT) +#define CCS_R_OP_SYS_CLK_DIV (0x030a | CCS_FL_16BIT) +#define CCS_R_OP_PRE_PLL_CLK_DIV (0x030c | CCS_FL_16BIT) +#define CCS_R_OP_PLL_MULTIPLIER (0x031e | CCS_FL_16BIT) +#define CCS_R_PLL_MODE 0x0310 +#define CCS_PLL_MODE_SHIFT 0U +#define CCS_PLL_MODE_MASK 0x1 +#define CCS_PLL_MODE_SINGLE 0U +#define CCS_PLL_MODE_DUAL 1U +#define CCS_R_OP_PIX_CLK_DIV_REV (0x0312 | CCS_FL_16BIT) +#define CCS_R_OP_SYS_CLK_DIV_REV (0x0314 | CCS_FL_16BIT) +#define CCS_R_FRAME_LENGTH_LINES (0x0340 | CCS_FL_16BIT) +#define CCS_R_LINE_LENGTH_PCK (0x0342 | CCS_FL_16BIT) +#define CCS_R_X_ADDR_START (0x0344 | CCS_FL_16BIT) +#define CCS_R_Y_ADDR_START (0x0346 | CCS_FL_16BIT) +#define CCS_R_X_ADDR_END (0x0348 | CCS_FL_16BIT) +#define CCS_R_Y_ADDR_END (0x034a | CCS_FL_16BIT) +#define CCS_R_X_OUTPUT_SIZE (0x034c | CCS_FL_16BIT) +#define CCS_R_Y_OUTPUT_SIZE (0x034e | CCS_FL_16BIT) +#define CCS_R_FRAME_LENGTH_CTRL 0x0350 +#define CCS_FRAME_LENGTH_CTRL_AUTOMATIC BIT(0) +#define CCS_R_TIMING_MODE_CTRL 0x0352 +#define CCS_TIMING_MODE_CTRL_MANUAL_READOUT BIT(0) +#define CCS_TIMING_MODE_CTRL_DELAYED_EXPOSURE BIT(1) +#define CCS_R_START_READOUT_RS 0x0353 +#define CCS_START_READOUT_RS_MANUAL_READOUT_START BIT(0) +#define CCS_R_FRAME_MARGIN (0x0354 | CCS_FL_16BIT) +#define CCS_R_X_EVEN_INC (0x0380 | CCS_FL_16BIT) +#define CCS_R_X_ODD_INC (0x0382 | CCS_FL_16BIT) +#define CCS_R_Y_EVEN_INC (0x0384 | CCS_FL_16BIT) +#define CCS_R_Y_ODD_INC (0x0386 | CCS_FL_16BIT) +#define CCS_R_MONOCHROME_EN 0x0390 +#define CCS_MONOCHROME_EN_ENABLED 0U +#define CCS_R_SCALING_MODE (0x0400 | CCS_FL_16BIT) +#define CCS_SCALING_MODE_NO_SCALING 0U +#define CCS_SCALING_MODE_HORIZONTAL 1U +#define CCS_R_SCALE_M (0x0404 | CCS_FL_16BIT) +#define CCS_R_SCALE_N (0x0406 | CCS_FL_16BIT) +#define CCS_R_DIGITAL_CROP_X_OFFSET (0x0408 | CCS_FL_16BIT) +#define CCS_R_DIGITAL_CROP_Y_OFFSET (0x040a | CCS_FL_16BIT) +#define CCS_R_DIGITAL_CROP_IMAGE_WIDTH (0x040c | CCS_FL_16BIT) +#define CCS_R_DIGITAL_CROP_IMAGE_HEIGHT (0x040e | CCS_FL_16BIT) +#define CCS_R_COMPRESSION_MODE (0x0500 | CCS_FL_16BIT) +#define CCS_COMPRESSION_MODE_NONE 0U +#define CCS_COMPRESSION_MODE_DPCM_PCM_SIMPLE 1U +#define CCS_R_TEST_PATTERN_MODE (0x0600 | CCS_FL_16BIT) +#define CCS_TEST_PATTERN_MODE_NONE 0U +#define CCS_TEST_PATTERN_MODE_SOLID_COLOR 1U +#define CCS_TEST_PATTERN_MODE_COLOR_BARS 2U +#define CCS_TEST_PATTERN_MODE_FADE_TO_GREY 3U +#define CCS_TEST_PATTERN_MODE_PN9 4U +#define CCS_TEST_PATTERN_MODE_COLOR_TILE 5U +#define CCS_R_TEST_DATA_RED (0x0602 | CCS_FL_16BIT) +#define CCS_R_TEST_DATA_GREENR (0x0604 | CCS_FL_16BIT) +#define CCS_R_TEST_DATA_BLUE (0x0606 | CCS_FL_16BIT) +#define CCS_R_TEST_DATA_GREENB (0x0608 | CCS_FL_16BIT) +#define CCS_R_VALUE_STEP_SIZE_SMOOTH 0x060a +#define CCS_R_VALUE_STEP_SIZE_QUANTISED 0x060b +#define CCS_R_TCLK_POST 0x0800 +#define CCS_R_THS_PREPARE 0x0801 +#define CCS_R_THS_ZERO_MIN 0x0802 +#define CCS_R_THS_TRAIL 0x0803 +#define CCS_R_TCLK_TRAIL_MIN 0x0804 +#define CCS_R_TCLK_PREPARE 0x0805 +#define CCS_R_TCLK_ZERO 0x0806 +#define CCS_R_TLPX 0x0807 +#define CCS_R_PHY_CTRL 0x0808 +#define CCS_PHY_CTRL_AUTO 0U +#define CCS_PHY_CTRL_UI 1U +#define CCS_PHY_CTRL_MANUAL 2U +#define CCS_R_TCLK_POST_EX (0x080a | CCS_FL_16BIT) +#define CCS_R_THS_PREPARE_EX (0x080c | CCS_FL_16BIT) +#define CCS_R_THS_ZERO_MIN_EX (0x080e | CCS_FL_16BIT) +#define CCS_R_THS_TRAIL_EX (0x0810 | CCS_FL_16BIT) +#define CCS_R_TCLK_TRAIL_MIN_EX (0x0812 | CCS_FL_16BIT) +#define CCS_R_TCLK_PREPARE_EX (0x0814 | CCS_FL_16BIT) +#define CCS_R_TCLK_ZERO_EX (0x0816 | CCS_FL_16BIT) +#define CCS_R_TLPX_EX (0x0818 | CCS_FL_16BIT) +#define CCS_R_REQUESTED_LINK_RATE (0x0820 | CCS_FL_32BIT) +#define CCS_R_DPHY_EQUALIZATION_MODE 0x0824 +#define CCS_DPHY_EQUALIZATION_MODE_EQ2 BIT(0) +#define CCS_R_PHY_EQUALIZATION_CTRL 0x0825 +#define CCS_PHY_EQUALIZATION_CTRL_ENABLE BIT(0) +#define CCS_R_DPHY_PREAMBLE_CTRL 0x0826 +#define CCS_DPHY_PREAMBLE_CTRL_ENABLE BIT(0) +#define CCS_R_DPHY_PREAMBLE_LENGTH 0x0826 +#define CCS_R_PHY_SSC_CTRL 0x0828 +#define CCS_PHY_SSC_CTRL_ENABLE BIT(0) +#define CCS_R_MANUAL_LP_CTRL 0x0829 +#define CCS_MANUAL_LP_CTRL_ENABLE BIT(0) +#define CCS_R_TWAKEUP 0x082a +#define CCS_R_TINIT 0x082b +#define CCS_R_THS_EXIT 0x082c +#define CCS_R_THS_EXIT_EX (0x082e | CCS_FL_16BIT) +#define CCS_R_PHY_PERIODIC_CALIBRATION_CTRL 0x0830 +#define CCS_PHY_PERIODIC_CALIBRATION_CTRL_FRAME_BLANKING BIT(0) +#define CCS_R_PHY_PERIODIC_CALIBRATION_INTERVAL 0x0831 +#define CCS_R_PHY_INIT_CALIBRATION_CTRL 0x0832 +#define CCS_PHY_INIT_CALIBRATION_CTRL_STREAM_START BIT(0) +#define CCS_R_DPHY_CALIBRATION_MODE 0x0833 +#define CCS_DPHY_CALIBRATION_MODE_ALSO_ALTERNATE BIT(0) +#define CCS_R_CPHY_CALIBRATION_MODE 0x0834 +#define CCS_CPHY_CALIBRATION_MODE_FORMAT_1 0U +#define CCS_CPHY_CALIBRATION_MODE_FORMAT_2 1U +#define CCS_CPHY_CALIBRATION_MODE_FORMAT_3 2U +#define CCS_R_T3_CALPREAMBLE_LENGTH 0x0835 +#define CCS_R_T3_CALPREAMBLE_LENGTH_PER 0x0836 +#define CCS_R_T3_CALALTSEQ_LENGTH 0x0837 +#define CCS_R_T3_CALALTSEQ_LENGTH_PER 0x0838 +#define CCS_R_FM2_INIT_SEED (0x083a | CCS_FL_16BIT) +#define CCS_R_T3_CALUDEFSEQ_LENGTH (0x083c | CCS_FL_16BIT) +#define CCS_R_T3_CALUDEFSEQ_LENGTH_PER (0x083e | CCS_FL_16BIT) +#define CCS_R_TGR_PREAMBLE_LENGTH 0x0841 +#define CCS_TGR_PREAMBLE_LENGTH_PREAMABLE_PROG_SEQ BIT(7) +#define CCS_TGR_PREAMBLE_LENGTH_BEGIN_PREAMBLE_LENGTH_SHIFT 0U +#define CCS_TGR_PREAMBLE_LENGTH_BEGIN_PREAMBLE_LENGTH_MASK 0x3f +#define CCS_R_TGR_POST_LENGTH 0x0842 +#define CCS_TGR_POST_LENGTH_POST_LENGTH_SHIFT 0U +#define CCS_TGR_POST_LENGTH_POST_LENGTH_MASK 0x1f +#define CCS_R_TGR_PREAMBLE_PROG_SEQUENCE(n2) (0x0843 + (n2)) +#define CCS_LIM_TGR_PREAMBLE_PROG_SEQUENCE_MIN_N2 0U +#define CCS_LIM_TGR_PREAMBLE_PROG_SEQUENCE_MAX_N2 6U +#define CCS_TGR_PREAMBLE_PROG_SEQUENCE_SYMBOL_N_1_SHIFT 3U +#define CCS_TGR_PREAMBLE_PROG_SEQUENCE_SYMBOL_N_1_MASK 0x38 +#define CCS_TGR_PREAMBLE_PROG_SEQUENCE_SYMBOL_N_SHIFT 0U +#define CCS_TGR_PREAMBLE_PROG_SEQUENCE_SYMBOL_N_MASK 0x7 +#define CCS_R_T3_PREPARE (0x084e | CCS_FL_16BIT) +#define CCS_R_T3_LPX (0x0850 | CCS_FL_16BIT) +#define CCS_R_ALPS_CTRL 0x085a +#define CCS_ALPS_CTRL_LVLP_DPHY BIT(0) +#define CCS_ALPS_CTRL_LVLP_CPHY BIT(1) +#define CCS_ALPS_CTRL_ALP_CPHY BIT(2) +#define CCS_R_TX_REG_CSI_EPD_EN_SSP_CPHY (0x0860 | CCS_FL_16BIT) +#define CCS_R_TX_REG_CSI_EPD_OP_SLP_CPHY (0x0862 | CCS_FL_16BIT) +#define CCS_R_TX_REG_CSI_EPD_EN_SSP_DPHY (0x0864 | CCS_FL_16BIT) +#define CCS_R_TX_REG_CSI_EPD_OP_SLP_DPHY (0x0866 | CCS_FL_16BIT) +#define CCS_R_TX_REG_CSI_EPD_MISC_OPTION_CPHY 0x0868 +#define CCS_R_TX_REG_CSI_EPD_MISC_OPTION_DPHY 0x0869 +#define CCS_R_SCRAMBLING_CTRL 0x0870 +#define CCS_SCRAMBLING_CTRL_ENABLED BIT(0) +#define CCS_SCRAMBLING_CTRL_SHIFT 2U +#define CCS_SCRAMBLING_CTRL_MASK 0xc +#define CCS_SCRAMBLING_CTRL_1_SEED_CPHY 0U +#define CCS_SCRAMBLING_CTRL_4_SEED_CPHY 3U +#define CCS_R_LANE_SEED_VALUE(seed, lane) ((0x0872 | CCS_FL_16BIT) + (seed) * 16 + (lane) * 2) +#define CCS_LIM_LANE_SEED_VALUE_MIN_SEED 0U +#define CCS_LIM_LANE_SEED_VALUE_MAX_SEED 3U +#define CCS_LIM_LANE_SEED_VALUE_MIN_LANE 0U +#define CCS_LIM_LANE_SEED_VALUE_MAX_LANE 7U +#define CCS_R_TX_USL_REV_ENTRY (0x08c0 | CCS_FL_16BIT) +#define CCS_R_TX_USL_REV_CLOCK_COUNTER (0x08c2 | CCS_FL_16BIT) +#define CCS_R_TX_USL_REV_LP_COUNTER (0x08c4 | CCS_FL_16BIT) +#define CCS_R_TX_USL_REV_FRAME_COUNTER (0x08c6 | CCS_FL_16BIT) +#define CCS_R_TX_USL_REV_CHRONOLOGICAL_TIMER (0x08c8 | CCS_FL_16BIT) +#define CCS_R_TX_USL_FWD_ENTRY (0x08ca | CCS_FL_16BIT) +#define CCS_R_TX_USL_GPIO (0x08cc | CCS_FL_16BIT) +#define CCS_R_TX_USL_OPERATION (0x08ce | CCS_FL_16BIT) +#define CCS_TX_USL_OPERATION_RESET BIT(0) +#define CCS_R_TX_USL_ALP_CTRL (0x08d0 | CCS_FL_16BIT) +#define CCS_TX_USL_ALP_CTRL_CLOCK_PAUSE BIT(0) +#define CCS_R_TX_USL_APP_BTA_ACK_TIMEOUT (0x08d2 | CCS_FL_16BIT) +#define CCS_R_TX_USL_SNS_BTA_ACK_TIMEOUT (0x08d2 | CCS_FL_16BIT) +#define CCS_R_USL_CLOCK_MODE_D_CTRL 0x08d2 +#define CCS_USL_CLOCK_MODE_D_CTRL_CONT_CLOCK_STANDBY BIT(0) +#define CCS_USL_CLOCK_MODE_D_CTRL_CONT_CLOCK_VBLANK BIT(1) +#define CCS_USL_CLOCK_MODE_D_CTRL_CONT_CLOCK_HBLANK BIT(2) +#define CCS_R_BINNING_MODE 0x0900 +#define CCS_R_BINNING_TYPE 0x0901 +#define CCS_R_BINNING_WEIGHTING 0x0902 +#define CCS_R_DATA_TRANSFER_IF_1_CTRL 0x0a00 +#define CCS_DATA_TRANSFER_IF_1_CTRL_ENABLE BIT(0) +#define CCS_DATA_TRANSFER_IF_1_CTRL_WRITE BIT(1) +#define CCS_DATA_TRANSFER_IF_1_CTRL_CLEAR_ERROR BIT(2) +#define CCS_R_DATA_TRANSFER_IF_1_STATUS 0x0a01 +#define CCS_DATA_TRANSFER_IF_1_STATUS_READ_IF_READY BIT(0) +#define CCS_DATA_TRANSFER_IF_1_STATUS_WRITE_IF_READY BIT(1) +#define CCS_DATA_TRANSFER_IF_1_STATUS_DATA_CORRUPTED BIT(2) +#define CCS_DATA_TRANSFER_IF_1_STATUS_IMPROPER_IF_USAGE BIT(3) +#define CCS_R_DATA_TRANSFER_IF_1_PAGE_SELECT 0x0a02 +#define CCS_R_DATA_TRANSFER_IF_1_DATA(p) (0x0a04 + (p)) +#define CCS_LIM_DATA_TRANSFER_IF_1_DATA_MIN_P 0U +#define CCS_LIM_DATA_TRANSFER_IF_1_DATA_MAX_P 63U +#define CCS_R_SHADING_CORRECTION_EN 0x0b00 +#define CCS_SHADING_CORRECTION_EN_ENABLE BIT(0) +#define CCS_R_LUMINANCE_CORRECTION_LEVEL 0x0b01 +#define CCS_R_GREEN_IMBALANCE_FILTER_EN 0x0b02 +#define CCS_GREEN_IMBALANCE_FILTER_EN_ENABLE BIT(0) +#define CCS_R_MAPPED_DEFECT_CORRECT_EN 0x0b05 +#define CCS_MAPPED_DEFECT_CORRECT_EN_ENABLE BIT(0) +#define CCS_R_SINGLE_DEFECT_CORRECT_EN 0x0b06 +#define CCS_SINGLE_DEFECT_CORRECT_EN_ENABLE BIT(0) +#define CCS_R_DYNAMIC_COUPLET_CORRECT_EN 0x0b08 +#define CCS_DYNAMIC_COUPLET_CORRECT_EN_ENABLE BIT(0) +#define CCS_R_COMBINED_DEFECT_CORRECT_EN 0x0b0a +#define CCS_COMBINED_DEFECT_CORRECT_EN_ENABLE BIT(0) +#define CCS_R_MODULE_SPECIFIC_CORRECTION_EN 0x0b0c +#define CCS_MODULE_SPECIFIC_CORRECTION_EN_ENABLE BIT(0) +#define CCS_R_DYNAMIC_TRIPLET_DEFECT_CORRECT_EN 0x0b13 +#define CCS_DYNAMIC_TRIPLET_DEFECT_CORRECT_EN_ENABLE BIT(0) +#define CCS_R_NF_CTRL 0x0b15 +#define CCS_NF_CTRL_LUMA BIT(0) +#define CCS_NF_CTRL_CHROMA BIT(1) +#define CCS_NF_CTRL_COMBINED BIT(2) +#define CCS_R_OB_READOUT_CONTROL 0x0b30 +#define CCS_OB_READOUT_CONTROL_ENABLE BIT(0) +#define CCS_OB_READOUT_CONTROL_INTERLEAVING BIT(1) +#define CCS_R_OB_VIRTUAL_CHANNEL 0x0b31 +#define CCS_R_OB_DT 0x0b32 +#define CCS_R_OB_DATA_FORMAT 0x0b33 +#define CCS_R_COLOR_TEMPERATURE (0x0b8c | CCS_FL_16BIT) +#define CCS_R_ABSOLUTE_GAIN_GREENR (0x0b8e | CCS_FL_16BIT) +#define CCS_R_ABSOLUTE_GAIN_RED (0x0b90 | CCS_FL_16BIT) +#define CCS_R_ABSOLUTE_GAIN_BLUE (0x0b92 | CCS_FL_16BIT) +#define CCS_R_ABSOLUTE_GAIN_GREENB (0x0b94 | CCS_FL_16BIT) +#define CCS_R_CFA_CONVERSION_CTRL 0x0ba0 +#define CCS_CFA_CONVERSION_CTRL_BAYER_CONVERSION_ENABLE BIT(0) +#define CCS_R_FLASH_STROBE_ADJUSTMENT 0x0c12 +#define CCS_R_FLASH_STROBE_START_POINT (0x0c14 | CCS_FL_16BIT) +#define CCS_R_TFLASH_STROBE_DELAY_RS_CTRL (0x0c16 | CCS_FL_16BIT) +#define CCS_R_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL (0x0c18 | CCS_FL_16BIT) +#define CCS_R_FLASH_MODE_RS 0x0c1a +#define CCS_FLASH_MODE_RS_CONTINUOUS BIT(0) +#define CCS_FLASH_MODE_RS_TRUNCATE BIT(1) +#define CCS_FLASH_MODE_RS_ASYNC BIT(3) +#define CCS_R_FLASH_TRIGGER_RS 0x0c1b +#define CCS_R_FLASH_STATUS 0x0c1c +#define CCS_FLASH_STATUS_RETIMED BIT(0) +#define CCS_R_SA_STROBE_MODE 0x0c1d +#define CCS_SA_STROBE_MODE_CONTINUOUS BIT(0) +#define CCS_SA_STROBE_MODE_TRUNCATE BIT(1) +#define CCS_SA_STROBE_MODE_ASYNC BIT(3) +#define CCS_SA_STROBE_MODE_ADJUST_EDGE BIT(4) +#define CCS_R_SA_STROBE_START_POINT (0x0c1e | CCS_FL_16BIT) +#define CCS_R_TSA_STROBE_DELAY_CTRL (0x0c20 | CCS_FL_16BIT) +#define CCS_R_TSA_STROBE_WIDTH_CTRL (0x0c22 | CCS_FL_16BIT) +#define CCS_R_SA_STROBE_TRIGGER 0x0c24 +#define CCS_R_SA_STROBE_STATUS 0x0c25 +#define CCS_SA_STROBE_STATUS_RETIMED BIT(0) +#define CCS_R_TSA_STROBE_RE_DELAY_CTRL (0x0c30 | CCS_FL_16BIT) +#define CCS_R_TSA_STROBE_FE_DELAY_CTRL (0x0c32 | CCS_FL_16BIT) +#define CCS_R_PDAF_CTRL (0x0d00 | CCS_FL_16BIT) +#define CCS_PDAF_CTRL_ENABLE BIT(0) +#define CCS_PDAF_CTRL_PROCESSED BIT(1) +#define CCS_PDAF_CTRL_INTERLEAVED BIT(2) +#define CCS_PDAF_CTRL_VISIBLE_PDAF_CORRECTION BIT(3) +#define CCS_R_PDAF_VC 0x0d02 +#define CCS_R_PDAF_DT 0x0d03 +#define CCS_R_PD_X_ADDR_START (0x0d04 | CCS_FL_16BIT) +#define CCS_R_PD_Y_ADDR_START (0x0d06 | CCS_FL_16BIT) +#define CCS_R_PD_X_ADDR_END (0x0d08 | CCS_FL_16BIT) +#define CCS_R_PD_Y_ADDR_END (0x0d0a | CCS_FL_16BIT) +#define CCS_R_BRACKETING_LUT_CTRL 0x0e00 +#define CCS_R_BRACKETING_LUT_MODE 0x0e01 +#define CCS_BRACKETING_LUT_MODE_CONTINUE_STREAMING BIT(0) +#define CCS_BRACKETING_LUT_MODE_LOOP_MODE BIT(1) +#define CCS_R_BRACKETING_LUT_ENTRY_CTRL 0x0e02 +#define CCS_R_BRACKETING_LUT_FRAME(n) (0x0e10 + (n)) +#define CCS_LIM_BRACKETING_LUT_FRAME_MIN_N 0U +#define CCS_LIM_BRACKETING_LUT_FRAME_MAX_N 239U +#define CCS_R_INTEGRATION_TIME_CAPABILITY (0x1000 | CCS_FL_16BIT) +#define CCS_INTEGRATION_TIME_CAPABILITY_FINE BIT(0) +#define CCS_R_COARSE_INTEGRATION_TIME_MIN (0x1004 | CCS_FL_16BIT) +#define CCS_R_COARSE_INTEGRATION_TIME_MAX_MARGIN (0x1006 | CCS_FL_16BIT) +#define CCS_R_FINE_INTEGRATION_TIME_MIN (0x1008 | CCS_FL_16BIT) +#define CCS_R_FINE_INTEGRATION_TIME_MAX_MARGIN (0x100a | CCS_FL_16BIT) +#define CCS_R_DIGITAL_GAIN_CAPABILITY 0x1081 +#define CCS_DIGITAL_GAIN_CAPABILITY_NONE 0U +#define CCS_DIGITAL_GAIN_CAPABILITY_GLOBAL 2U +#define CCS_R_DIGITAL_GAIN_MIN (0x1084 | CCS_FL_16BIT) +#define CCS_R_DIGITAL_GAIN_MAX (0x1086 | CCS_FL_16BIT) +#define CCS_R_DIGITAL_GAIN_STEP_SIZE (0x1088 | CCS_FL_16BIT) +#define CCS_R_PEDESTAL_CAPABILITY 0x10e0 +#define CCS_R_ADC_CAPABILITY 0x10f0 +#define CCS_ADC_CAPABILITY_BIT_DEPTH_CTRL BIT(0) +#define CCS_R_ADC_BIT_DEPTH_CAPABILITY (0x10f4 | CCS_FL_32BIT) +#define CCS_R_MIN_EXT_CLK_FREQ_MHZ (0x1100 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MAX_EXT_CLK_FREQ_MHZ (0x1104 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MIN_PRE_PLL_CLK_DIV (0x1108 | CCS_FL_16BIT) +#define CCS_R_MAX_PRE_PLL_CLK_DIV (0x110a | CCS_FL_16BIT) +#define CCS_R_MIN_PLL_IP_CLK_FREQ_MHZ (0x110c | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MAX_PLL_IP_CLK_FREQ_MHZ (0x1110 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MIN_PLL_MULTIPLIER (0x1114 | CCS_FL_16BIT) +#define CCS_R_MAX_PLL_MULTIPLIER (0x1116 | CCS_FL_16BIT) +#define CCS_R_MIN_PLL_OP_CLK_FREQ_MHZ (0x1118 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MAX_PLL_OP_CLK_FREQ_MHZ (0x111c | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MIN_VT_SYS_CLK_DIV (0x1120 | CCS_FL_16BIT) +#define CCS_R_MAX_VT_SYS_CLK_DIV (0x1122 | CCS_FL_16BIT) +#define CCS_R_MIN_VT_SYS_CLK_FREQ_MHZ (0x1124 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MAX_VT_SYS_CLK_FREQ_MHZ (0x1128 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MIN_VT_PIX_CLK_FREQ_MHZ (0x112c | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MAX_VT_PIX_CLK_FREQ_MHZ (0x1130 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MIN_VT_PIX_CLK_DIV (0x1134 | CCS_FL_16BIT) +#define CCS_R_MAX_VT_PIX_CLK_DIV (0x1136 | CCS_FL_16BIT) +#define CCS_R_CLOCK_CALCULATION 0x1138 +#define CCS_CLOCK_CALCULATION_LANE_SPEED BIT(0) +#define CCS_CLOCK_CALCULATION_LINK_DECOUPLED BIT(1) +#define CCS_CLOCK_CALCULATION_DUAL_PLL_OP_SYS_DDR BIT(2) +#define CCS_CLOCK_CALCULATION_DUAL_PLL_OP_PIX_DDR BIT(3) +#define CCS_R_NUM_OF_VT_LANES 0x1139 +#define CCS_R_NUM_OF_OP_LANES 0x113a +#define CCS_R_OP_BITS_PER_LANE 0x113b +#define CCS_R_MIN_FRAME_LENGTH_LINES (0x1140 | CCS_FL_16BIT) +#define CCS_R_MAX_FRAME_LENGTH_LINES (0x1142 | CCS_FL_16BIT) +#define CCS_R_MIN_LINE_LENGTH_PCK (0x1144 | CCS_FL_16BIT) +#define CCS_R_MAX_LINE_LENGTH_PCK (0x1146 | CCS_FL_16BIT) +#define CCS_R_MIN_LINE_BLANKING_PCK (0x1148 | CCS_FL_16BIT) +#define CCS_R_MIN_FRAME_BLANKING_LINES (0x114a | CCS_FL_16BIT) +#define CCS_R_MIN_LINE_LENGTH_PCK_STEP_SIZE 0x114c +#define CCS_R_TIMING_MODE_CAPABILITY 0x114d +#define CCS_TIMING_MODE_CAPABILITY_AUTO_FRAME_LENGTH BIT(0) +#define CCS_TIMING_MODE_CAPABILITY_ROLLING_SHUTTER_MANUAL_READOUT BIT(2) +#define CCS_TIMING_MODE_CAPABILITY_DELAYED_EXPOSURE_START BIT(3) +#define CCS_TIMING_MODE_CAPABILITY_MANUAL_EXPOSURE_EMBEDDED_DATA BIT(4) +#define CCS_R_FRAME_MARGIN_MAX_VALUE (0x114e | CCS_FL_16BIT) +#define CCS_R_FRAME_MARGIN_MIN_VALUE 0x1150 +#define CCS_R_GAIN_DELAY_TYPE 0x1151 +#define CCS_GAIN_DELAY_TYPE_FIXED 0U +#define CCS_GAIN_DELAY_TYPE_VARIABLE 1U +#define CCS_R_MIN_OP_SYS_CLK_DIV (0x1160 | CCS_FL_16BIT) +#define CCS_R_MAX_OP_SYS_CLK_DIV (0x1162 | CCS_FL_16BIT) +#define CCS_R_MIN_OP_SYS_CLK_FREQ_MHZ (0x1164 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MAX_OP_SYS_CLK_FREQ_MHZ (0x1168 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MIN_OP_PIX_CLK_DIV (0x116c | CCS_FL_16BIT) +#define CCS_R_MAX_OP_PIX_CLK_DIV (0x116e | CCS_FL_16BIT) +#define CCS_R_MIN_OP_PIX_CLK_FREQ_MHZ (0x1170 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MAX_OP_PIX_CLK_FREQ_MHZ (0x1174 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_X_ADDR_MIN (0x1180 | CCS_FL_16BIT) +#define CCS_R_Y_ADDR_MIN (0x1182 | CCS_FL_16BIT) +#define CCS_R_X_ADDR_MAX (0x1184 | CCS_FL_16BIT) +#define CCS_R_Y_ADDR_MAX (0x1186 | CCS_FL_16BIT) +#define CCS_R_MIN_X_OUTPUT_SIZE (0x1188 | CCS_FL_16BIT) +#define CCS_R_MIN_Y_OUTPUT_SIZE (0x118a | CCS_FL_16BIT) +#define CCS_R_MAX_X_OUTPUT_SIZE (0x118c | CCS_FL_16BIT) +#define CCS_R_MAX_Y_OUTPUT_SIZE (0x118e | CCS_FL_16BIT) +#define CCS_R_X_ADDR_START_DIV_CONSTANT 0x1190 +#define CCS_R_Y_ADDR_START_DIV_CONSTANT 0x1191 +#define CCS_R_X_ADDR_END_DIV_CONSTANT 0x1192 +#define CCS_R_Y_ADDR_END_DIV_CONSTANT 0x1193 +#define CCS_R_X_SIZE_DIV 0x1194 +#define CCS_R_Y_SIZE_DIV 0x1195 +#define CCS_R_X_OUTPUT_DIV 0x1196 +#define CCS_R_Y_OUTPUT_DIV 0x1197 +#define CCS_R_NON_FLEXIBLE_RESOLUTION_SUPPORT 0x1198 +#define CCS_NON_FLEXIBLE_RESOLUTION_SUPPORT_NEW_PIX_ADDR BIT(0) +#define CCS_NON_FLEXIBLE_RESOLUTION_SUPPORT_NEW_OUTPUT_RES BIT(1) +#define CCS_NON_FLEXIBLE_RESOLUTION_SUPPORT_OUTPUT_CROP_NO_PAD BIT(2) +#define CCS_NON_FLEXIBLE_RESOLUTION_SUPPORT_OUTPUT_SIZE_LANE_DEP BIT(3) +#define CCS_R_MIN_OP_PRE_PLL_CLK_DIV (0x11a0 | CCS_FL_16BIT) +#define CCS_R_MAX_OP_PRE_PLL_CLK_DIV (0x11a2 | CCS_FL_16BIT) +#define CCS_R_MIN_OP_PLL_IP_CLK_FREQ_MHZ (0x11a4 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MAX_OP_PLL_IP_CLK_FREQ_MHZ (0x11a8 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MIN_OP_PLL_MULTIPLIER (0x11ac | CCS_FL_16BIT) +#define CCS_R_MAX_OP_PLL_MULTIPLIER (0x11ae | CCS_FL_16BIT) +#define CCS_R_MIN_OP_PLL_OP_CLK_FREQ_MHZ (0x11b0 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MAX_OP_PLL_OP_CLK_FREQ_MHZ (0x11b4 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_CLOCK_TREE_PLL_CAPABILITY 0x11b8 +#define CCS_CLOCK_TREE_PLL_CAPABILITY_DUAL_PLL BIT(0) +#define CCS_CLOCK_TREE_PLL_CAPABILITY_SINGLE_PLL BIT(1) +#define CCS_CLOCK_TREE_PLL_CAPABILITY_EXT_DIVIDER BIT(2) +#define CCS_CLOCK_TREE_PLL_CAPABILITY_FLEXIBLE_OP_PIX_CLK_DIV BIT(3) +#define CCS_R_CLOCK_CAPA_TYPE_CAPABILITY 0x11b9 +#define CCS_CLOCK_CAPA_TYPE_CAPABILITY_IREAL BIT(0) +#define CCS_R_MIN_EVEN_INC (0x11c0 | CCS_FL_16BIT) +#define CCS_R_MIN_ODD_INC (0x11c2 | CCS_FL_16BIT) +#define CCS_R_MAX_EVEN_INC (0x11c4 | CCS_FL_16BIT) +#define CCS_R_MAX_ODD_INC (0x11c6 | CCS_FL_16BIT) +#define CCS_R_AUX_SUBSAMP_CAPABILITY 0x11c8 +#define CCS_AUX_SUBSAMP_CAPABILITY_FACTOR_POWER_OF_2 BIT(1) +#define CCS_R_AUX_SUBSAMP_MONO_CAPABILITY 0x11c9 +#define CCS_AUX_SUBSAMP_MONO_CAPABILITY_FACTOR_POWER_OF_2 BIT(1) +#define CCS_R_MONOCHROME_CAPABILITY 0x11ca +#define CCS_MONOCHROME_CAPABILITY_INC_ODD 0U +#define CCS_MONOCHROME_CAPABILITY_INC_EVEN 1U +#define CCS_R_PIXEL_READOUT_CAPABILITY 0x11cb +#define CCS_PIXEL_READOUT_CAPABILITY_BAYER 0U +#define CCS_PIXEL_READOUT_CAPABILITY_MONOCHROME 1U +#define CCS_PIXEL_READOUT_CAPABILITY_BAYER_AND_MONO 2U +#define CCS_R_MIN_EVEN_INC_MONO (0x11cc | CCS_FL_16BIT) +#define CCS_R_MAX_EVEN_INC_MONO (0x11ce | CCS_FL_16BIT) +#define CCS_R_MIN_ODD_INC_MONO (0x11d0 | CCS_FL_16BIT) +#define CCS_R_MAX_ODD_INC_MONO (0x11d2 | CCS_FL_16BIT) +#define CCS_R_MIN_EVEN_INC_BC2 (0x11d4 | CCS_FL_16BIT) +#define CCS_R_MAX_EVEN_INC_BC2 (0x11d6 | CCS_FL_16BIT) +#define CCS_R_MIN_ODD_INC_BC2 (0x11d8 | CCS_FL_16BIT) +#define CCS_R_MAX_ODD_INC_BC2 (0x11da | CCS_FL_16BIT) +#define CCS_R_MIN_EVEN_INC_MONO_BC2 (0x11dc | CCS_FL_16BIT) +#define CCS_R_MAX_EVEN_INC_MONO_BC2 (0x11de | CCS_FL_16BIT) +#define CCS_R_MIN_ODD_INC_MONO_BC2 (0x11f0 | CCS_FL_16BIT) +#define CCS_R_MAX_ODD_INC_MONO_BC2 (0x11f2 | CCS_FL_16BIT) +#define CCS_R_SCALING_CAPABILITY (0x1200 | CCS_FL_16BIT) +#define CCS_SCALING_CAPABILITY_NONE 0U +#define CCS_SCALING_CAPABILITY_HORIZONTAL 1U +#define CCS_SCALING_CAPABILITY_RESERVED 2U +#define CCS_R_SCALER_M_MIN (0x1204 | CCS_FL_16BIT) +#define CCS_R_SCALER_M_MAX (0x1206 | CCS_FL_16BIT) +#define CCS_R_SCALER_N_MIN (0x1208 | CCS_FL_16BIT) +#define CCS_R_SCALER_N_MAX (0x120a | CCS_FL_16BIT) +#define CCS_R_DIGITAL_CROP_CAPABILITY 0x120e +#define CCS_DIGITAL_CROP_CAPABILITY_NONE 0U +#define CCS_DIGITAL_CROP_CAPABILITY_INPUT_CROP 1U +#define CCS_R_HDR_CAPABILITY_1 0x1210 +#define CCS_HDR_CAPABILITY_1_2X2_BINNING BIT(0) +#define CCS_HDR_CAPABILITY_1_COMBINED_ANALOG_GAIN BIT(1) +#define CCS_HDR_CAPABILITY_1_SEPARATE_ANALOG_GAIN BIT(2) +#define CCS_HDR_CAPABILITY_1_UPSCALING BIT(3) +#define CCS_HDR_CAPABILITY_1_RESET_SYNC BIT(4) +#define CCS_HDR_CAPABILITY_1_DIRECT_SHORT_EXP_TIMING BIT(5) +#define CCS_HDR_CAPABILITY_1_DIRECT_SHORT_EXP_SYNTHESIS BIT(6) +#define CCS_R_MIN_HDR_BIT_DEPTH 0x1211 +#define CCS_R_HDR_RESOLUTION_SUB_TYPES 0x1212 +#define CCS_R_HDR_RESOLUTION_SUB_TYPE(n) (0x1213 + (n)) +#define CCS_LIM_HDR_RESOLUTION_SUB_TYPE_MIN_N 0U +#define CCS_LIM_HDR_RESOLUTION_SUB_TYPE_MAX_N 1U +#define CCS_HDR_RESOLUTION_SUB_TYPE_ROW_SHIFT 0U +#define CCS_HDR_RESOLUTION_SUB_TYPE_ROW_MASK 0xf +#define CCS_HDR_RESOLUTION_SUB_TYPE_COLUMN_SHIFT 4U +#define CCS_HDR_RESOLUTION_SUB_TYPE_COLUMN_MASK 0xf0 +#define CCS_R_HDR_CAPABILITY_2 0x121b +#define CCS_HDR_CAPABILITY_2_COMBINED_DIGITAL_GAIN BIT(0) +#define CCS_HDR_CAPABILITY_2_SEPARATE_DIGITAL_GAIN BIT(1) +#define CCS_HDR_CAPABILITY_2_TIMING_MODE BIT(3) +#define CCS_HDR_CAPABILITY_2_SYNTHESIS_MODE BIT(4) +#define CCS_R_MAX_HDR_BIT_DEPTH 0x121c +#define CCS_R_USL_SUPPORT_CAPABILITY 0x1230 +#define CCS_USL_SUPPORT_CAPABILITY_CLOCK_TREE BIT(0) +#define CCS_USL_SUPPORT_CAPABILITY_REV_CLOCK_TREE BIT(1) +#define CCS_USL_SUPPORT_CAPABILITY_REV_CLOCK_CALC BIT(2) +#define CCS_R_USL_CLOCK_MODE_D_CAPABILITY 0x1231 +#define CCS_USL_CLOCK_MODE_D_CAPABILITY_CONT_CLOCK_STANDBY BIT(0) +#define CCS_USL_CLOCK_MODE_D_CAPABILITY_CONT_CLOCK_VBLANK BIT(1) +#define CCS_USL_CLOCK_MODE_D_CAPABILITY_CONT_CLOCK_HBLANK BIT(2) +#define CCS_USL_CLOCK_MODE_D_CAPABILITY_NONCONT_CLOCK_STANDBY BIT(3) +#define CCS_USL_CLOCK_MODE_D_CAPABILITY_NONCONT_CLOCK_VBLANK BIT(4) +#define CCS_USL_CLOCK_MODE_D_CAPABILITY_NONCONT_CLOCK_HBLANK BIT(5) +#define CCS_R_MIN_OP_SYS_CLK_DIV_REV 0x1234 +#define CCS_R_MAX_OP_SYS_CLK_DIV_REV 0x1236 +#define CCS_R_MIN_OP_PIX_CLK_DIV_REV 0x1238 +#define CCS_R_MAX_OP_PIX_CLK_DIV_REV 0x123a +#define CCS_R_MIN_OP_SYS_CLK_FREQ_REV_MHZ (0x123c | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MAX_OP_SYS_CLK_FREQ_REV_MHZ (0x1240 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MIN_OP_PIX_CLK_FREQ_REV_MHZ (0x1244 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MAX_OP_PIX_CLK_FREQ_REV_MHZ (0x1248 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) +#define CCS_R_MAX_BITRATE_REV_D_MODE_MBPS (0x124c | (CCS_FL_32BIT | CCS_FL_IREAL)) +#define CCS_R_MAX_SYMRATE_REV_C_MODE_MSPS (0x1250 | (CCS_FL_32BIT | CCS_FL_IREAL)) +#define CCS_R_COMPRESSION_CAPABILITY 0x1300 +#define CCS_COMPRESSION_CAPABILITY_DPCM_PCM_SIMPLE BIT(0) +#define CCS_R_TEST_MODE_CAPABILITY (0x1310 | CCS_FL_16BIT) +#define CCS_TEST_MODE_CAPABILITY_SOLID_COLOR BIT(0) +#define CCS_TEST_MODE_CAPABILITY_COLOR_BARS BIT(1) +#define CCS_TEST_MODE_CAPABILITY_FADE_TO_GREY BIT(2) +#define CCS_TEST_MODE_CAPABILITY_PN9 BIT(3) +#define CCS_TEST_MODE_CAPABILITY_COLOR_TILE BIT(5) +#define CCS_R_PN9_DATA_FORMAT1 0x1312 +#define CCS_R_PN9_DATA_FORMAT2 0x1313 +#define CCS_R_PN9_DATA_FORMAT3 0x1314 +#define CCS_R_PN9_DATA_FORMAT4 0x1315 +#define CCS_R_PN9_MISC_CAPABILITY 0x1316 +#define CCS_PN9_MISC_CAPABILITY_NUM_PIXELS_SHIFT 0U +#define CCS_PN9_MISC_CAPABILITY_NUM_PIXELS_MASK 0x7 +#define CCS_PN9_MISC_CAPABILITY_COMPRESSION BIT(3) +#define CCS_R_TEST_PATTERN_CAPABILITY 0x1317 +#define CCS_TEST_PATTERN_CAPABILITY_NO_REPEAT BIT(1) +#define CCS_R_PATTERN_SIZE_DIV_M1 0x1318 +#define CCS_R_FIFO_SUPPORT_CAPABILITY 0x1502 +#define CCS_FIFO_SUPPORT_CAPABILITY_NONE 0U +#define CCS_FIFO_SUPPORT_CAPABILITY_DERATING 1U +#define CCS_FIFO_SUPPORT_CAPABILITY_DERATING_OVERRATING 2U +#define CCS_R_PHY_CTRL_CAPABILITY 0x1600 +#define CCS_PHY_CTRL_CAPABILITY_AUTO_PHY_CTL BIT(0) +#define CCS_PHY_CTRL_CAPABILITY_UI_PHY_CTL BIT(1) +#define CCS_PHY_CTRL_CAPABILITY_DPHY_TIME_UI_REG_1_CTL BIT(2) +#define CCS_PHY_CTRL_CAPABILITY_DPHY_TIME_UI_REG_2_CTL BIT(3) +#define CCS_PHY_CTRL_CAPABILITY_DPHY_TIME_CTL BIT(4) +#define CCS_PHY_CTRL_CAPABILITY_DPHY_EXT_TIME_UI_REG_1_CTL BIT(5) +#define CCS_PHY_CTRL_CAPABILITY_DPHY_EXT_TIME_UI_REG_2_CTL BIT(6) +#define CCS_PHY_CTRL_CAPABILITY_DPHY_EXT_TIME_CTL BIT(7) +#define CCS_R_CSI_DPHY_LANE_MODE_CAPABILITY 0x1601 +#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_1_LANE BIT(0) +#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_2_LANE BIT(1) +#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_3_LANE BIT(2) +#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_4_LANE BIT(3) +#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_5_LANE BIT(4) +#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_6_LANE BIT(5) +#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_7_LANE BIT(6) +#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_8_LANE BIT(7) +#define CCS_R_CSI_SIGNALING_MODE_CAPABILITY 0x1602 +#define CCS_CSI_SIGNALING_MODE_CAPABILITY_CSI_DPHY BIT(2) +#define CCS_CSI_SIGNALING_MODE_CAPABILITY_CSI_CPHY BIT(3) +#define CCS_R_FAST_STANDBY_CAPABILITY 0x1603 +#define CCS_FAST_STANDBY_CAPABILITY_NO_FRAME_TRUNCATION 0U +#define CCS_FAST_STANDBY_CAPABILITY_FRAME_TRUNCATION 1U +#define CCS_R_CSI_ADDRESS_CONTROL_CAPABILITY 0x1604 +#define CCS_CSI_ADDRESS_CONTROL_CAPABILITY_CCI_ADDR_CHANGE BIT(0) +#define CCS_CSI_ADDRESS_CONTROL_CAPABILITY_2ND_CCI_ADDR BIT(1) +#define CCS_CSI_ADDRESS_CONTROL_CAPABILITY_SW_CHANGEABLE_2ND_CCI_ADDR BIT(2) +#define CCS_R_DATA_TYPE_CAPABILITY 0x1605 +#define CCS_DATA_TYPE_CAPABILITY_DPCM_PROGRAMMABLE BIT(0) +#define CCS_DATA_TYPE_CAPABILITY_BOTTOM_EMBEDDED_DT_PROGRAMMABLE BIT(1) +#define CCS_DATA_TYPE_CAPABILITY_BOTTOM_EMBEDDED_VC_PROGRAMMABLE BIT(2) +#define CCS_DATA_TYPE_CAPABILITY_EXT_VC_RANGE BIT(3) +#define CCS_R_CSI_CPHY_LANE_MODE_CAPABILITY 0x1606 +#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_1_LANE BIT(0) +#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_2_LANE BIT(1) +#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_3_LANE BIT(2) +#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_4_LANE BIT(3) +#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_5_LANE BIT(4) +#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_6_LANE BIT(5) +#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_7_LANE BIT(6) +#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_8_LANE BIT(7) +#define CCS_R_EMB_DATA_CAPABILITY 0x1607 +#define CCS_EMB_DATA_CAPABILITY_TWO_BYTES_PER_RAW16 BIT(0) +#define CCS_EMB_DATA_CAPABILITY_TWO_BYTES_PER_RAW20 BIT(1) +#define CCS_EMB_DATA_CAPABILITY_TWO_BYTES_PER_RAW24 BIT(2) +#define CCS_EMB_DATA_CAPABILITY_NO_ONE_BYTE_PER_RAW16 BIT(3) +#define CCS_EMB_DATA_CAPABILITY_NO_ONE_BYTE_PER_RAW20 BIT(4) +#define CCS_EMB_DATA_CAPABILITY_NO_ONE_BYTE_PER_RAW24 BIT(5) +#define CCS_R_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS(n) ((0x1608 | (CCS_FL_32BIT | CCS_FL_IREAL)) + ((n) < 4 ? (n) * 4 : 0x32 + ((n) - 4) * 4)) +#define CCS_LIM_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS_MIN_N 0U +#define CCS_LIM_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS_MAX_N 7U +#define CCS_R_TEMP_SENSOR_CAPABILITY 0x1618 +#define CCS_TEMP_SENSOR_CAPABILITY_SUPPORTED BIT(0) +#define CCS_TEMP_SENSOR_CAPABILITY_CCS_FORMAT BIT(1) +#define CCS_TEMP_SENSOR_CAPABILITY_RESET_0X80 BIT(2) +#define CCS_R_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS(n) ((0x161a | (CCS_FL_32BIT | CCS_FL_IREAL)) + ((n) < 4 ? (n) * 4 : 0x30 + ((n) - 4) * 4)) +#define CCS_LIM_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS_MIN_N 0U +#define CCS_LIM_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS_MAX_N 7U +#define CCS_R_DPHY_EQUALIZATION_CAPABILITY 0x162b +#define CCS_DPHY_EQUALIZATION_CAPABILITY_EQUALIZATION_CTRL BIT(0) +#define CCS_DPHY_EQUALIZATION_CAPABILITY_EQ1 BIT(1) +#define CCS_DPHY_EQUALIZATION_CAPABILITY_EQ2 BIT(2) +#define CCS_R_CPHY_EQUALIZATION_CAPABILITY 0x162c +#define CCS_CPHY_EQUALIZATION_CAPABILITY_EQUALIZATION_CTRL BIT(0) +#define CCS_R_DPHY_PREAMBLE_CAPABILITY 0x162d +#define CCS_DPHY_PREAMBLE_CAPABILITY_PREAMBLE_SEQ_CTRL BIT(0) +#define CCS_R_DPHY_SSC_CAPABILITY 0x162e +#define CCS_DPHY_SSC_CAPABILITY_SUPPORTED BIT(0) +#define CCS_R_CPHY_CALIBRATION_CAPABILITY 0x162f +#define CCS_CPHY_CALIBRATION_CAPABILITY_MANUAL BIT(0) +#define CCS_CPHY_CALIBRATION_CAPABILITY_MANUAL_STREAMING BIT(1) +#define CCS_CPHY_CALIBRATION_CAPABILITY_FORMAT_1_CTRL BIT(2) +#define CCS_CPHY_CALIBRATION_CAPABILITY_FORMAT_2_CTRL BIT(3) +#define CCS_CPHY_CALIBRATION_CAPABILITY_FORMAT_3_CTRL BIT(4) +#define CCS_R_DPHY_CALIBRATION_CAPABILITY 0x1630 +#define CCS_DPHY_CALIBRATION_CAPABILITY_MANUAL BIT(0) +#define CCS_DPHY_CALIBRATION_CAPABILITY_MANUAL_STREAMING BIT(1) +#define CCS_DPHY_CALIBRATION_CAPABILITY_ALTERNATE_SEQ BIT(2) +#define CCS_R_PHY_CTRL_CAPABILITY_2 0x1631 +#define CCS_PHY_CTRL_CAPABILITY_2_TGR_LENGTH BIT(0) +#define CCS_PHY_CTRL_CAPABILITY_2_TGR_PREAMBLE_PROG_SEQ BIT(1) +#define CCS_PHY_CTRL_CAPABILITY_2_EXTRA_CPHY_MANUAL_TIMING BIT(2) +#define CCS_PHY_CTRL_CAPABILITY_2_CLOCK_BASED_MANUAL_CDPHY BIT(3) +#define CCS_PHY_CTRL_CAPABILITY_2_CLOCK_BASED_MANUAL_DPHY BIT(4) +#define CCS_PHY_CTRL_CAPABILITY_2_CLOCK_BASED_MANUAL_CPHY BIT(5) +#define CCS_PHY_CTRL_CAPABILITY_2_MANUAL_LP_DPHY BIT(6) +#define CCS_PHY_CTRL_CAPABILITY_2_MANUAL_LP_CPHY BIT(7) +#define CCS_R_LRTE_CPHY_CAPABILITY 0x1632 +#define CCS_LRTE_CPHY_CAPABILITY_PDQ_SHORT BIT(0) +#define CCS_LRTE_CPHY_CAPABILITY_SPACER_SHORT BIT(1) +#define CCS_LRTE_CPHY_CAPABILITY_PDQ_LONG BIT(2) +#define CCS_LRTE_CPHY_CAPABILITY_SPACER_LONG BIT(3) +#define CCS_LRTE_CPHY_CAPABILITY_SPACER_NO_PDQ BIT(4) +#define CCS_R_LRTE_DPHY_CAPABILITY 0x1633 +#define CCS_LRTE_DPHY_CAPABILITY_PDQ_SHORT_OPT1 BIT(0) +#define CCS_LRTE_DPHY_CAPABILITY_SPACER_SHORT_OPT1 BIT(1) +#define CCS_LRTE_DPHY_CAPABILITY_PDQ_LONG_OPT1 BIT(2) +#define CCS_LRTE_DPHY_CAPABILITY_SPACER_LONG_OPT1 BIT(3) +#define CCS_LRTE_DPHY_CAPABILITY_SPACER_SHORT_OPT2 BIT(4) +#define CCS_LRTE_DPHY_CAPABILITY_SPACER_LONG_OPT2 BIT(5) +#define CCS_LRTE_DPHY_CAPABILITY_SPACER_NO_PDQ_OPT1 BIT(6) +#define CCS_LRTE_DPHY_CAPABILITY_SPACER_VARIABLE_OPT2 BIT(7) +#define CCS_R_ALPS_CAPABILITY_DPHY 0x1634 +#define CCS_ALPS_CAPABILITY_DPHY_LVLP_NOT_SUPPORTED 0U +#define CCS_ALPS_CAPABILITY_DPHY_LVLP_SUPPORTED 1U +#define CCS_ALPS_CAPABILITY_DPHY_CONTROLLABLE_LVLP 2U +#define CCS_R_ALPS_CAPABILITY_CPHY 0x1635 +#define CCS_ALPS_CAPABILITY_CPHY_LVLP_NOT_SUPPORTED 0U +#define CCS_ALPS_CAPABILITY_CPHY_LVLP_SUPPORTED 1U +#define CCS_ALPS_CAPABILITY_CPHY_CONTROLLABLE_LVLP 2U +#define CCS_ALPS_CAPABILITY_CPHY_ALP_NOT_SUPPORTED 0xc +#define CCS_ALPS_CAPABILITY_CPHY_ALP_SUPPORTED 0xd +#define CCS_ALPS_CAPABILITY_CPHY_CONTROLLABLE_ALP 0xe +#define CCS_R_SCRAMBLING_CAPABILITY 0x1636 +#define CCS_SCRAMBLING_CAPABILITY_SCRAMBLING_SUPPORTED BIT(0) +#define CCS_SCRAMBLING_CAPABILITY_MAX_SEEDS_PER_LANE_C_SHIFT 1U +#define CCS_SCRAMBLING_CAPABILITY_MAX_SEEDS_PER_LANE_C_MASK 0x6 +#define CCS_SCRAMBLING_CAPABILITY_MAX_SEEDS_PER_LANE_C_1 0U +#define CCS_SCRAMBLING_CAPABILITY_MAX_SEEDS_PER_LANE_C_4 3U +#define CCS_SCRAMBLING_CAPABILITY_NUM_SEED_REGS_SHIFT 3U +#define CCS_SCRAMBLING_CAPABILITY_NUM_SEED_REGS_MASK 0x38 +#define CCS_SCRAMBLING_CAPABILITY_NUM_SEED_REGS_0 0U +#define CCS_SCRAMBLING_CAPABILITY_NUM_SEED_REGS_1 1U +#define CCS_SCRAMBLING_CAPABILITY_NUM_SEED_REGS_4 4U +#define CCS_SCRAMBLING_CAPABILITY_NUM_SEED_PER_LANE BIT(6) +#define CCS_R_DPHY_MANUAL_CONSTANT 0x1637 +#define CCS_R_CPHY_MANUAL_CONSTANT 0x1638 +#define CCS_R_CSI2_INTERFACE_CAPABILITY_MISC 0x1639 +#define CCS_CSI2_INTERFACE_CAPABILITY_MISC_EOTP_SHORT_PKT_OPT2 BIT(0) +#define CCS_R_PHY_CTRL_CAPABILITY_3 0x165c +#define CCS_PHY_CTRL_CAPABILITY_3_DPHY_TIMING_NOT_MULTIPLE BIT(0) +#define CCS_PHY_CTRL_CAPABILITY_3_DPHY_MIN_TIMING_VALUE_1 BIT(1) +#define CCS_PHY_CTRL_CAPABILITY_3_TWAKEUP_SUPPORTED BIT(2) +#define CCS_PHY_CTRL_CAPABILITY_3_TINIT_SUPPORTED BIT(3) +#define CCS_PHY_CTRL_CAPABILITY_3_THS_EXIT_SUPPORTED BIT(4) +#define CCS_PHY_CTRL_CAPABILITY_3_CPHY_TIMING_NOT_MULTIPLE BIT(5) +#define CCS_PHY_CTRL_CAPABILITY_3_CPHY_MIN_TIMING_VALUE_1 BIT(6) +#define CCS_R_DPHY_SF 0x165d +#define CCS_R_CPHY_SF 0x165e +#define CCS_CPHY_SF_TWAKEUP_SHIFT 0U +#define CCS_CPHY_SF_TWAKEUP_MASK 0xf +#define CCS_CPHY_SF_TINIT_SHIFT 4U +#define CCS_CPHY_SF_TINIT_MASK 0xf0 +#define CCS_R_DPHY_LIMITS_1 0x165f +#define CCS_DPHY_LIMITS_1_THS_PREPARE_SHIFT 0U +#define CCS_DPHY_LIMITS_1_THS_PREPARE_MASK 0xf +#define CCS_DPHY_LIMITS_1_THS_ZERO_SHIFT 4U +#define CCS_DPHY_LIMITS_1_THS_ZERO_MASK 0xf0 +#define CCS_R_DPHY_LIMITS_2 0x1660 +#define CCS_DPHY_LIMITS_2_THS_TRAIL_SHIFT 0U +#define CCS_DPHY_LIMITS_2_THS_TRAIL_MASK 0xf +#define CCS_DPHY_LIMITS_2_TCLK_TRAIL_MIN_SHIFT 4U +#define CCS_DPHY_LIMITS_2_TCLK_TRAIL_MIN_MASK 0xf0 +#define CCS_R_DPHY_LIMITS_3 0x1661 +#define CCS_DPHY_LIMITS_3_TCLK_PREPARE_SHIFT 0U +#define CCS_DPHY_LIMITS_3_TCLK_PREPARE_MASK 0xf +#define CCS_DPHY_LIMITS_3_TCLK_ZERO_SHIFT 4U +#define CCS_DPHY_LIMITS_3_TCLK_ZERO_MASK 0xf0 +#define CCS_R_DPHY_LIMITS_4 0x1662 +#define CCS_DPHY_LIMITS_4_TCLK_POST_SHIFT 0U +#define CCS_DPHY_LIMITS_4_TCLK_POST_MASK 0xf +#define CCS_DPHY_LIMITS_4_TLPX_SHIFT 4U +#define CCS_DPHY_LIMITS_4_TLPX_MASK 0xf0 +#define CCS_R_DPHY_LIMITS_5 0x1663 +#define CCS_DPHY_LIMITS_5_THS_EXIT_SHIFT 0U +#define CCS_DPHY_LIMITS_5_THS_EXIT_MASK 0xf +#define CCS_DPHY_LIMITS_5_TWAKEUP_SHIFT 4U +#define CCS_DPHY_LIMITS_5_TWAKEUP_MASK 0xf0 +#define CCS_R_DPHY_LIMITS_6 0x1664 +#define CCS_DPHY_LIMITS_6_TINIT_SHIFT 0U +#define CCS_DPHY_LIMITS_6_TINIT_MASK 0xf +#define CCS_R_CPHY_LIMITS_1 0x1665 +#define CCS_CPHY_LIMITS_1_T3_PREPARE_MAX_SHIFT 0U +#define CCS_CPHY_LIMITS_1_T3_PREPARE_MAX_MASK 0xf +#define CCS_CPHY_LIMITS_1_T3_LPX_MAX_SHIFT 4U +#define CCS_CPHY_LIMITS_1_T3_LPX_MAX_MASK 0xf0 +#define CCS_R_CPHY_LIMITS_2 0x1666 +#define CCS_CPHY_LIMITS_2_THS_EXIT_MAX_SHIFT 0U +#define CCS_CPHY_LIMITS_2_THS_EXIT_MAX_MASK 0xf +#define CCS_CPHY_LIMITS_2_TWAKEUP_MAX_SHIFT 4U +#define CCS_CPHY_LIMITS_2_TWAKEUP_MAX_MASK 0xf0 +#define CCS_R_CPHY_LIMITS_3 0x1667 +#define CCS_CPHY_LIMITS_3_TINIT_MAX_SHIFT 0U +#define CCS_CPHY_LIMITS_3_TINIT_MAX_MASK 0xf +#define CCS_R_MIN_FRAME_LENGTH_LINES_BIN (0x1700 | CCS_FL_16BIT) +#define CCS_R_MAX_FRAME_LENGTH_LINES_BIN (0x1702 | CCS_FL_16BIT) +#define CCS_R_MIN_LINE_LENGTH_PCK_BIN (0x1704 | CCS_FL_16BIT) +#define CCS_R_MAX_LINE_LENGTH_PCK_BIN (0x1706 | CCS_FL_16BIT) +#define CCS_R_MIN_LINE_BLANKING_PCK_BIN (0x1708 | CCS_FL_16BIT) +#define CCS_R_FINE_INTEGRATION_TIME_MIN_BIN (0x170a | CCS_FL_16BIT) +#define CCS_R_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN (0x170c | CCS_FL_16BIT) +#define CCS_R_BINNING_CAPABILITY 0x1710 +#define CCS_BINNING_CAPABILITY_UNSUPPORTED 0U +#define CCS_BINNING_CAPABILITY_BINNING_THEN_SUBSAMPLING 1U +#define CCS_BINNING_CAPABILITY_SUBSAMPLING_THEN_BINNING 2U +#define CCS_R_BINNING_WEIGHTING_CAPABILITY 0x1711 +#define CCS_BINNING_WEIGHTING_CAPABILITY_AVERAGED BIT(0) +#define CCS_BINNING_WEIGHTING_CAPABILITY_SUMMED BIT(1) +#define CCS_BINNING_WEIGHTING_CAPABILITY_BAYER_CORRECTED BIT(2) +#define CCS_BINNING_WEIGHTING_CAPABILITY_MODULE_SPECIFIC_WEIGHT BIT(3) +#define CCS_R_BINNING_SUB_TYPES 0x1712 +#define CCS_R_BINNING_SUB_TYPE(n) (0x1713 + (n)) +#define CCS_LIM_BINNING_SUB_TYPE_MIN_N 0U +#define CCS_LIM_BINNING_SUB_TYPE_MAX_N 63U +#define CCS_BINNING_SUB_TYPE_ROW_SHIFT 0U +#define CCS_BINNING_SUB_TYPE_ROW_MASK 0xf +#define CCS_BINNING_SUB_TYPE_COLUMN_SHIFT 4U +#define CCS_BINNING_SUB_TYPE_COLUMN_MASK 0xf0 +#define CCS_R_BINNING_WEIGHTING_MONO_CAPABILITY 0x1771 +#define CCS_BINNING_WEIGHTING_MONO_CAPABILITY_AVERAGED BIT(0) +#define CCS_BINNING_WEIGHTING_MONO_CAPABILITY_SUMMED BIT(1) +#define CCS_BINNING_WEIGHTING_MONO_CAPABILITY_BAYER_CORRECTED BIT(2) +#define CCS_BINNING_WEIGHTING_MONO_CAPABILITY_MODULE_SPECIFIC_WEIGHT BIT(3) +#define CCS_R_BINNING_SUB_TYPES_MONO 0x1772 +#define CCS_R_BINNING_SUB_TYPE_MONO(n) (0x1773 + (n)) +#define CCS_LIM_BINNING_SUB_TYPE_MONO_MIN_N 0U +#define CCS_LIM_BINNING_SUB_TYPE_MONO_MAX_N 63U +#define CCS_R_DATA_TRANSFER_IF_CAPABILITY 0x1800 +#define CCS_DATA_TRANSFER_IF_CAPABILITY_SUPPORTED BIT(0) +#define CCS_DATA_TRANSFER_IF_CAPABILITY_POLLING BIT(2) +#define CCS_R_SHADING_CORRECTION_CAPABILITY 0x1900 +#define CCS_SHADING_CORRECTION_CAPABILITY_COLOR_SHADING BIT(0) +#define CCS_SHADING_CORRECTION_CAPABILITY_LUMINANCE_CORRECTION BIT(1) +#define CCS_R_GREEN_IMBALANCE_CAPABILITY 0x1901 +#define CCS_GREEN_IMBALANCE_CAPABILITY_SUPPORTED BIT(0) +#define CCS_R_MODULE_SPECIFIC_CORRECTION_CAPABILITY 0x1903 +#define CCS_R_DEFECT_CORRECTION_CAPABILITY (0x1904 | CCS_FL_16BIT) +#define CCS_DEFECT_CORRECTION_CAPABILITY_MAPPED_DEFECT BIT(0) +#define CCS_DEFECT_CORRECTION_CAPABILITY_DYNAMIC_COUPLET BIT(2) +#define CCS_DEFECT_CORRECTION_CAPABILITY_DYNAMIC_SINGLE BIT(5) +#define CCS_DEFECT_CORRECTION_CAPABILITY_COMBINED_DYNAMIC BIT(8) +#define CCS_R_DEFECT_CORRECTION_CAPABILITY_2 (0x1906 | CCS_FL_16BIT) +#define CCS_DEFECT_CORRECTION_CAPABILITY_2_DYNAMIC_TRIPLET BIT(3) +#define CCS_R_NF_CAPABILITY 0x1908 +#define CCS_NF_CAPABILITY_LUMA BIT(0) +#define CCS_NF_CAPABILITY_CHROMA BIT(1) +#define CCS_NF_CAPABILITY_COMBINED BIT(2) +#define CCS_R_OB_READOUT_CAPABILITY 0x1980 +#define CCS_OB_READOUT_CAPABILITY_CONTROLLABLE_READOUT BIT(0) +#define CCS_OB_READOUT_CAPABILITY_VISIBLE_PIXEL_READOUT BIT(1) +#define CCS_OB_READOUT_CAPABILITY_DIFFERENT_VC_READOUT BIT(2) +#define CCS_OB_READOUT_CAPABILITY_DIFFERENT_DT_READOUT BIT(3) +#define CCS_OB_READOUT_CAPABILITY_PROG_DATA_FORMAT BIT(4) +#define CCS_R_COLOR_FEEDBACK_CAPABILITY 0x1987 +#define CCS_COLOR_FEEDBACK_CAPABILITY_KELVIN BIT(0) +#define CCS_COLOR_FEEDBACK_CAPABILITY_AWB_GAIN BIT(1) +#define CCS_R_CFA_PATTERN_CAPABILITY 0x1990 +#define CCS_CFA_PATTERN_CAPABILITY_BAYER 0U +#define CCS_CFA_PATTERN_CAPABILITY_MONOCHROME 1U +#define CCS_CFA_PATTERN_CAPABILITY_4X4_QUAD_BAYER 2U +#define CCS_CFA_PATTERN_CAPABILITY_VENDOR_SPECIFIC 3U +#define CCS_R_CFA_PATTERN_CONVERSION_CAPABILITY 0x1991 +#define CCS_CFA_PATTERN_CONVERSION_CAPABILITY_BAYER BIT(0) +#define CCS_R_FLASH_MODE_CAPABILITY 0x1a02 +#define CCS_FLASH_MODE_CAPABILITY_SINGLE_STROBE BIT(0) +#define CCS_R_SA_STROBE_MODE_CAPABILITY 0x1a03 +#define CCS_SA_STROBE_MODE_CAPABILITY_FIXED_WIDTH BIT(0) +#define CCS_SA_STROBE_MODE_CAPABILITY_EDGE_CTRL BIT(1) +#define CCS_R_RESET_MAX_DELAY 0x1a10 +#define CCS_R_RESET_MIN_TIME 0x1a11 +#define CCS_R_PDAF_CAPABILITY_1 0x1b80 +#define CCS_PDAF_CAPABILITY_1_SUPPORTED BIT(0) +#define CCS_PDAF_CAPABILITY_1_PROCESSED_BOTTOM_EMBEDDED BIT(1) +#define CCS_PDAF_CAPABILITY_1_PROCESSED_INTERLEAVED BIT(2) +#define CCS_PDAF_CAPABILITY_1_RAW_BOTTOM_EMBEDDED BIT(3) +#define CCS_PDAF_CAPABILITY_1_RAW_INTERLEAVED BIT(4) +#define CCS_PDAF_CAPABILITY_1_VISIBLE_PDAF_CORRECTION BIT(5) +#define CCS_PDAF_CAPABILITY_1_VC_INTERLEAVING BIT(6) +#define CCS_PDAF_CAPABILITY_1_DT_INTERLEAVING BIT(7) +#define CCS_R_PDAF_CAPABILITY_2 0x1b81 +#define CCS_PDAF_CAPABILITY_2_ROI BIT(0) +#define CCS_PDAF_CAPABILITY_2_AFTER_DIGITAL_CROP BIT(1) +#define CCS_PDAF_CAPABILITY_2_CTRL_RETIMED BIT(2) +#define CCS_R_BRACKETING_LUT_CAPABILITY_1 0x1c00 +#define CCS_BRACKETING_LUT_CAPABILITY_1_COARSE_INTEGRATION BIT(0) +#define CCS_BRACKETING_LUT_CAPABILITY_1_GLOBAL_ANALOG_GAIN BIT(1) +#define CCS_BRACKETING_LUT_CAPABILITY_1_FLASH BIT(4) +#define CCS_BRACKETING_LUT_CAPABILITY_1_GLOBAL_DIGITAL_GAIN BIT(5) +#define CCS_BRACKETING_LUT_CAPABILITY_1_ALTERNATE_GLOBAL_ANALOG_GAIN BIT(6) +#define CCS_R_BRACKETING_LUT_CAPABILITY_2 0x1c01 +#define CCS_BRACKETING_LUT_CAPABILITY_2_SINGLE_BRACKETING_MODE BIT(0) +#define CCS_BRACKETING_LUT_CAPABILITY_2_LOOPED_BRACKETING_MODE BIT(1) +#define CCS_R_BRACKETING_LUT_SIZE 0x1c02 + +#endif /* __CCS_REGS_H__ */ diff --git a/drivers/media/i2c/ccs/ccs.h b/drivers/media/i2c/ccs/ccs.h new file mode 100644 index 000000000000..7f6ed95b7b78 --- /dev/null +++ b/drivers/media/i2c/ccs/ccs.h @@ -0,0 +1,281 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * drivers/media/i2c/smiapp/ccs.h + * + * Generic driver for MIPI CCS/SMIA/SMIA++ compliant camera sensors + * + * Copyright (C) 2020 Intel Corporation + * Copyright (C) 2010--2012 Nokia Corporation + * Contact: Sakari Ailus + */ + +#ifndef __CCS_H__ +#define __CCS_H__ + +#include +#include +#include + +#include "ccs-quirk.h" +#include "ccs-regs.h" +#include "ccs-reg-access.h" +#include "../smiapp-pll.h" +#include "smiapp-reg-defs.h" + +/* + * Standard SMIA++ constants + */ +#define SMIA_VERSION_1 10 +#define SMIAPP_VERSION_0_8 8 /* Draft 0.8 */ +#define SMIAPP_VERSION_0_9 9 /* Draft 0.9 */ +#define SMIAPP_VERSION_1 10 + +#define SMIAPP_PROFILE_0 0 +#define SMIAPP_PROFILE_1 1 +#define SMIAPP_PROFILE_2 2 + +#define SMIAPP_NVM_PAGE_SIZE 64 /* bytes */ + +#define SMIAPP_RESET_DELAY_CLOCKS 2400 +#define SMIAPP_RESET_DELAY(clk) \ + (1000 + (SMIAPP_RESET_DELAY_CLOCKS * 1000 \ + + (clk) / 1000 - 1) / ((clk) / 1000)) + +#define CCS_COLOUR_COMPONENTS 4 + +#define SMIAPP_NAME "smiapp" +#define CCS_NAME "ccs" + +#define CCS_DFL_I2C_ADDR (0x20 >> 1) /* Default I2C Address */ +#define CCS_ALT_I2C_ADDR (0x6e >> 1) /* Alternate I2C Address */ + +/* + * Sometimes due to board layout considerations the camera module can be + * mounted rotated. The typical rotation used is 180 degrees which can be + * corrected by giving a default H-FLIP and V-FLIP in the sensor readout. + * FIXME: rotation also changes the bayer pattern. + */ +enum ccs_module_board_orient { + CCS_MODULE_BOARD_ORIENT_0 = 0, + CCS_MODULE_BOARD_ORIENT_180, +}; + +struct ccs_flash_strobe_parms { + u8 mode; + u32 strobe_width_high_us; + u16 strobe_delay; + u16 stobe_start_point; + u8 trigger; +}; + +struct ccs_hwconfig { + /* + * Change the cci address if i2c_addr_alt is set. + * Both default and alternate cci addr need to be present + */ + unsigned short i2c_addr_dfl; /* Default i2c addr */ + unsigned short i2c_addr_alt; /* Alternate i2c addr */ + + uint32_t ext_clk; /* sensor external clk */ + + unsigned int lanes; /* Number of CSI-2 lanes */ + uint32_t csi_signalling_mode; /* CCS_CSI_SIGNALLING_MODE_* */ + uint64_t *op_sys_clock; + + enum ccs_module_board_orient module_board_orient; + + struct ccs_flash_strobe_parms *strobe_setup; +}; + +struct ccs_quirk; + +#define CCS_MODULE_IDENT_FLAG_REV_LE (1 << 0) + +struct ccs_module_ident { + u16 mipi_manufacturer_id; + u16 model_id; + u8 smia_manufacturer_id; + u8 revision_number_major; + + u8 flags; + + char *name; + const struct ccs_quirk *quirk; +}; + +struct ccs_module_info { + u32 smia_manufacturer_id; + u32 mipi_manufacturer_id; + u32 model_id; + u32 revision_number_major; + u32 revision_number_minor; + + u32 module_year; + u32 module_month; + u32 module_day; + + u32 sensor_smia_manufacturer_id; + u32 sensor_mipi_manufacturer_id; + u32 sensor_model_id; + u32 sensor_revision_number; + u32 sensor_firmware_version; + + u32 smia_version; + u32 smiapp_version; + u32 ccs_version; + + u32 smiapp_profile; + + char *name; + const struct ccs_quirk *quirk; +}; + +#define CCS_IDENT_FQ(manufacturer, model, rev, fl, _name, _quirk) \ + { .smia_manufacturer_id = manufacturer, \ + .model_id = model, \ + .revision_number_major = rev, \ + .flags = fl, \ + .name = _name, \ + .quirk = _quirk, } + +#define CCS_IDENT_LQ(manufacturer, model, rev, _name, _quirk) \ + { .smia_manufacturer_id = manufacturer, \ + .model_id = model, \ + .revision_number_major = rev, \ + .flags = CCS_MODULE_IDENT_FLAG_REV_LE, \ + .name = _name, \ + .quirk = _quirk, } + +#define CCS_IDENT_L(manufacturer, model, rev, _name) \ + { .smia_manufacturer_id = manufacturer, \ + .model_id = model, \ + .revision_number_major = rev, \ + .flags = CCS_MODULE_IDENT_FLAG_REV_LE, \ + .name = _name, } + +#define CCS_IDENT_Q(manufacturer, model, rev, _name, _quirk) \ + { .smia_manufacturer_id = manufacturer, \ + .model_id = model, \ + .revision_number_major = rev, \ + .flags = 0, \ + .name = _name, \ + .quirk = _quirk, } + +#define CCS_IDENT(manufacturer, model, rev, _name) \ + { .smia_manufacturer_id = manufacturer, \ + .model_id = model, \ + .revision_number_major = rev, \ + .flags = 0, \ + .name = _name, } + +struct ccs_csi_data_format { + u32 code; + u8 width; + u8 compressed; + u8 pixel_order; +}; + +#define CCS_SUBDEVS 3 + +#define CCS_PA_PAD_SRC 0 +#define CCS_PAD_SINK 0 +#define CCS_PAD_SRC 1 +#define CCS_PADS 2 + +struct ccs_binning_subtype { + u8 horizontal:4; + u8 vertical:4; +} __packed; + +struct ccs_subdev { + struct v4l2_subdev sd; + struct media_pad pads[CCS_PADS]; + struct v4l2_rect sink_fmt; + struct v4l2_rect crop[CCS_PADS]; + struct v4l2_rect compose; /* compose on sink */ + unsigned short sink_pad; + unsigned short source_pad; + int npads; + struct ccs_sensor *sensor; + struct v4l2_ctrl_handler ctrl_handler; +}; + +/* + * struct ccs_sensor - Main device structure + */ +struct ccs_sensor { + /* + * "mutex" is used to serialise access to all fields here + * except v4l2_ctrls at the end of the struct. "mutex" is also + * used to serialise access to file handle specific + * information. + */ + struct mutex mutex; + struct ccs_subdev ssds[CCS_SUBDEVS]; + u32 ssds_used; + struct ccs_subdev *src; + struct ccs_subdev *binner; + struct ccs_subdev *scaler; + struct ccs_subdev *pixel_array; + struct ccs_hwconfig *hwcfg; + struct regulator *vana; + struct clk *ext_clk; + struct gpio_desc *xshutdown; + void *ccs_limits; + u8 nbinning_subtypes; + struct ccs_binning_subtype binning_subtypes[CCS_LIM_BINNING_SUB_TYPE_MAX_N + 1]; + u32 mbus_frame_fmts; + const struct ccs_csi_data_format *csi_format; + const struct ccs_csi_data_format *internal_csi_format; + u32 default_mbus_frame_fmts; + int default_pixel_order; + + u8 binning_horizontal; + u8 binning_vertical; + + u8 scale_m; + u8 scaling_mode; + + u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */ + u8 frame_skip; + u16 embedded_start; /* embedded data start line */ + u16 embedded_end; + u16 image_start; /* image data start line */ + u16 visible_pixel_start; /* start pixel of the visible image */ + + bool streaming; + bool dev_init_done; + u8 compressed_min_bpp; + + struct ccs_module_info minfo; + + struct smiapp_pll pll; + + /* Is a default format supported for a given BPP? */ + unsigned long *valid_link_freqs; + + /* Pixel array controls */ + struct v4l2_ctrl *analog_gain; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *pixel_rate_parray; + /* src controls */ + struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *pixel_rate_csi; + /* test pattern colour components */ + struct v4l2_ctrl *test_data[CCS_COLOUR_COMPONENTS]; +}; + +#define to_ccs_subdev(_sd) \ + container_of(_sd, struct ccs_subdev, sd) + +#define to_ccs_sensor(_sd) \ + (to_ccs_subdev(_sd)->sensor) + +void ccs_replace_limit(struct ccs_sensor *sensor, + unsigned int limit, unsigned int offset, u32 val); + +#endif /* __CCS_H__ */ diff --git a/drivers/media/i2c/ccs/smiapp-reg-defs.h b/drivers/media/i2c/ccs/smiapp-reg-defs.h new file mode 100644 index 000000000000..e80c110ebf3a --- /dev/null +++ b/drivers/media/i2c/ccs/smiapp-reg-defs.h @@ -0,0 +1,580 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * drivers/media/i2c/smiapp/smiapp-reg-defs.h + * + * Generic driver for MIPI CCS/SMIA/SMIA++ compliant camera sensors + * + * Copyright (C) 2020 Intel Corporation + * Copyright (C) 2011--2012 Nokia Corporation + * Contact: Sakari Ailus + */ + +#ifndef __SMIAPP_REG_DEFS_H__ +#define __SMIAPP_REG_DEFS_H__ + +/* Register addresses */ +#define SMIAPP_REG_U16_MODEL_ID (0x0000 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_REVISION_NUMBER_MAJOR 0x0002 +#define SMIAPP_REG_U8_MANUFACTURER_ID 0x0003 +#define SMIAPP_REG_U8_SMIA_VERSION 0x0004 +#define SMIAPP_REG_U8_FRAME_COUNT 0x0005 +#define SMIAPP_REG_U8_PIXEL_ORDER 0x0006 +#define SMIAPP_REG_U16_DATA_PEDESTAL (0x0008 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_PIXEL_DEPTH 0x000c +#define SMIAPP_REG_U8_REVISION_NUMBER_MINOR 0x0010 +#define SMIAPP_REG_U8_SMIAPP_VERSION 0x0011 +#define SMIAPP_REG_U8_MODULE_DATE_YEAR 0x0012 +#define SMIAPP_REG_U8_MODULE_DATE_MONTH 0x0013 +#define SMIAPP_REG_U8_MODULE_DATE_DAY 0x0014 +#define SMIAPP_REG_U8_MODULE_DATE_PHASE 0x0015 +#define SMIAPP_REG_U16_SENSOR_MODEL_ID (0x0016 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_SENSOR_REVISION_NUMBER 0x0018 +#define SMIAPP_REG_U8_SENSOR_MANUFACTURER_ID 0x0019 +#define SMIAPP_REG_U8_SENSOR_FIRMWARE_VERSION 0x001a +#define SMIAPP_REG_U32_SERIAL_NUMBER (0x001c | CCS_FL_32BIT) +#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_TYPE 0x0040 +#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_SUBTYPE 0x0041 +#define SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(n) ((0x0042 + ((n) << 1)) | CCS_FL_16BIT) /* 0 <= n <= 14 */ +#define SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(n) ((0x0060 + ((n) << 2)) | CCS_FL_32BIT) /* 0 <= n <= 7 */ +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CAPABILITY (0x0080 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MIN (0x0084 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MAX (0x0086 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_STEP (0x0088 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_TYPE (0x008a | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_M0 (0x008c | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_C0 (0x008e | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_M1 (0x0090 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_C1 (0x0092 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_TYPE 0x00c0 +#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_SUBTYPE 0x00c1 +#define SMIAPP_REG_U16_DATA_FORMAT_DESCRIPTOR(n) ((0x00c2 + ((n) << 1)) | CCS_FL_16BIT) +#define SMIAPP_REG_U8_MODE_SELECT 0x0100 +#define SMIAPP_REG_U8_IMAGE_ORIENTATION 0x0101 +#define SMIAPP_REG_U8_SOFTWARE_RESET 0x0103 +#define SMIAPP_REG_U8_GROUPED_PARAMETER_HOLD 0x0104 +#define SMIAPP_REG_U8_MASK_CORRUPTED_FRAMES 0x0105 +#define SMIAPP_REG_U8_FAST_STANDBY_CTRL 0x0106 +#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL 0x0107 +#define SMIAPP_REG_U8_2ND_CCI_IF_CONTROL 0x0108 +#define SMIAPP_REG_U8_2ND_CCI_ADDRESS_CONTROL 0x0109 +#define SMIAPP_REG_U8_CSI_CHANNEL_IDENTIFIER 0x0110 +#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE 0x0111 +#define SMIAPP_REG_U16_CSI_DATA_FORMAT (0x0112 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_CSI_LANE_MODE 0x0114 +#define SMIAPP_REG_U8_CSI2_10_TO_8_DT 0x0115 +#define SMIAPP_REG_U8_CSI2_10_TO_7_DT 0x0116 +#define SMIAPP_REG_U8_CSI2_10_TO_6_DT 0x0117 +#define SMIAPP_REG_U8_CSI2_12_TO_8_DT 0x0118 +#define SMIAPP_REG_U8_CSI2_12_TO_7_DT 0x0119 +#define SMIAPP_REG_U8_CSI2_12_TO_6_DT 0x011a +#define SMIAPP_REG_U8_CSI2_14_TO_10_DT 0x011b +#define SMIAPP_REG_U8_CSI2_14_TO_8_DT 0x011c +#define SMIAPP_REG_U8_CSI2_16_TO_10_DT 0x011d +#define SMIAPP_REG_U8_CSI2_16_TO_8_DT 0x011e +#define SMIAPP_REG_U8_GAIN_MODE 0x0120 +#define SMIAPP_REG_U16_VANA_VOLTAGE (0x0130 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_VDIG_VOLTAGE (0x0132 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_VIO_VOLTAGE (0x0134 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ (0x0136 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_TEMP_SENSOR_CONTROL 0x0138 +#define SMIAPP_REG_U8_TEMP_SENSOR_MODE 0x0139 +#define SMIAPP_REG_U8_TEMP_SENSOR_OUTPUT 0x013a +#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME (0x0200 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME (0x0202 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GLOBAL (0x0204 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENR (0x0206 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_RED (0x0208 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_BLUE (0x020a | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENB (0x020c | CCS_FL_16BIT) +#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENR (0x020e | CCS_FL_16BIT) +#define SMIAPP_REG_U16_DIGITAL_GAIN_RED (0x0210 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_DIGITAL_GAIN_BLUE (0x0212 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENB (0x0214 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_VT_PIX_CLK_DIV (0x0300 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_VT_SYS_CLK_DIV (0x0302 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_PRE_PLL_CLK_DIV (0x0304 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_PLL_MULTIPLIER (0x0306 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_OP_PIX_CLK_DIV (0x0308 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_OP_SYS_CLK_DIV (0x030a | CCS_FL_16BIT) +#define SMIAPP_REG_U16_FRAME_LENGTH_LINES (0x0340 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_LINE_LENGTH_PCK (0x0342 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_X_ADDR_START (0x0344 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_Y_ADDR_START (0x0346 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_X_ADDR_END (0x0348 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_Y_ADDR_END (0x034a | CCS_FL_16BIT) +#define SMIAPP_REG_U16_X_OUTPUT_SIZE (0x034c | CCS_FL_16BIT) +#define SMIAPP_REG_U16_Y_OUTPUT_SIZE (0x034e | CCS_FL_16BIT) +#define SMIAPP_REG_U16_X_EVEN_INC (0x0380 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_X_ODD_INC (0x0382 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_Y_EVEN_INC (0x0384 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_Y_ODD_INC (0x0386 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_SCALING_MODE (0x0400 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_SPATIAL_SAMPLING (0x0402 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_SCALE_M (0x0404 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_SCALE_N (0x0406 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET (0x0408 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_DIGITAL_CROP_Y_OFFSET (0x040a | CCS_FL_16BIT) +#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_WIDTH (0x040c | CCS_FL_16BIT) +#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_HEIGHT (0x040e | CCS_FL_16BIT) +#define SMIAPP_REG_U16_COMPRESSION_MODE (0x0500 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TEST_PATTERN_MODE (0x0600 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TEST_DATA_RED (0x0602 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TEST_DATA_GREENR (0x0604 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TEST_DATA_BLUE (0x0606 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TEST_DATA_GREENB (0x0608 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_WIDTH (0x060a | CCS_FL_16BIT) +#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_POSITION (0x060c | CCS_FL_16BIT) +#define SMIAPP_REG_U16_VERTICAL_CURSOR_WIDTH (0x060e | CCS_FL_16BIT) +#define SMIAPP_REG_U16_VERTICAL_CURSOR_POSITION (0x0610 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_FIFO_WATER_MARK_PIXELS (0x0700 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_TCLK_POST 0x0800 +#define SMIAPP_REG_U8_THS_PREPARE 0x0801 +#define SMIAPP_REG_U8_THS_ZERO_MIN 0x0802 +#define SMIAPP_REG_U8_THS_TRAIL 0x0803 +#define SMIAPP_REG_U8_TCLK_TRAIL_MIN 0x0804 +#define SMIAPP_REG_U8_TCLK_PREPARE 0x0805 +#define SMIAPP_REG_U8_TCLK_ZERO 0x0806 +#define SMIAPP_REG_U8_TLPX 0x0807 +#define SMIAPP_REG_U8_DPHY_CTRL 0x0808 +#define SMIAPP_REG_U32_REQUESTED_LINK_BIT_RATE_MBPS (0x0820 | CCS_FL_32BIT) +#define SMIAPP_REG_U8_BINNING_MODE 0x0900 +#define SMIAPP_REG_U8_BINNING_TYPE 0x0901 +#define SMIAPP_REG_U8_BINNING_WEIGHTING 0x0902 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL 0x0a00 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS 0x0a01 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_PAGE_SELECT 0x0a02 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_0 0x0a04 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_1 0x0a05 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_2 0x0a06 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_3 0x0a07 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_4 0x0a08 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_5 0x0a09 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_12 0x0a10 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_13 0x0a11 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_14 0x0a12 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_15 0x0a13 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_16 0x0a14 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_17 0x0a15 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_18 0x0a16 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_19 0x0a17 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_20 0x0a18 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_21 0x0a19 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_22 0x0a1a +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_23 0x0a1b +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_24 0x0a1c +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_25 0x0a1d +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_26 0x0a1e +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_27 0x0a1f +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_28 0x0a20 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_29 0x0a21 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_30 0x0a22 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_31 0x0a23 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_32 0x0a24 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_33 0x0a25 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_34 0x0a26 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_35 0x0a27 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_36 0x0a28 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_37 0x0a29 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_38 0x0a2a +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_39 0x0a2b +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_40 0x0a2c +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_41 0x0a2d +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_42 0x0a2e +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_43 0x0a2f +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_44 0x0a30 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_45 0x0a31 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_46 0x0a32 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_47 0x0a33 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_48 0x0a34 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_49 0x0a35 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_50 0x0a36 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_51 0x0a37 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_52 0x0a38 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_53 0x0a39 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_54 0x0a3a +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_55 0x0a3b +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_56 0x0a3c +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_57 0x0a3d +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_58 0x0a3e +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_59 0x0a3f +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_60 0x0a40 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_61 0x0a41 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_62 0x0a42 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_63 0x0a43 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_CTRL 0x0a44 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_STATUS 0x0a45 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_PAGE_SELECT 0x0a46 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_0 0x0a48 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_1 0x0a49 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_2 0x0a4a +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_3 0x0a4b +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_4 0x0a4c +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_5 0x0a4d +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_6 0x0a4e +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_7 0x0a4f +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_8 0x0a50 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_9 0x0a51 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_10 0x0a52 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_11 0x0a53 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_12 0x0a54 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_13 0x0a55 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_14 0x0a56 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_15 0x0a57 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_16 0x0a58 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_17 0x0a59 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_18 0x0a5a +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_19 0x0a5b +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_20 0x0a5c +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_21 0x0a5d +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_22 0x0a5e +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_23 0x0a5f +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_24 0x0a60 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_25 0x0a61 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_26 0x0a62 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_27 0x0a63 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_28 0x0a64 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_29 0x0a65 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_30 0x0a66 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_31 0x0a67 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_32 0x0a68 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_33 0x0a69 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_34 0x0a6a +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_35 0x0a6b +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_36 0x0a6c +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_37 0x0a6d +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_38 0x0a6e +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_39 0x0a6f +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_40 0x0a70 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_41 0x0a71 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_42 0x0a72 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_43 0x0a73 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_44 0x0a74 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_45 0x0a75 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_46 0x0a76 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_47 0x0a77 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_48 0x0a78 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_49 0x0a79 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_50 0x0a7a +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_51 0x0a7b +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_52 0x0a7c +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_53 0x0a7d +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_54 0x0a7e +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_55 0x0a7f +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_56 0x0a80 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_57 0x0a81 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_58 0x0a82 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_59 0x0a83 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_60 0x0a84 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_61 0x0a85 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_62 0x0a86 +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_63 0x0a87 +#define SMIAPP_REG_U8_SHADING_CORRECTION_ENABLE 0x0b00 +#define SMIAPP_REG_U8_LUMINANCE_CORRECTION_LEVEL 0x0b01 +#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_ENABLE 0x0b02 +#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_WEIGHT 0x0b03 +#define SMIAPP_REG_U8_BLACK_LEVEL_CORRECTION_ENABLE 0x0b04 +#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ENABLE 0x0b05 +#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_ENABLE 0x0b06 +#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_WEIGHT 0x0b07 +#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_ENABLE 0x0b08 +#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_WEIGHT 0x0b09 +#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_ENABLE 0x0b0a +#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_WEIGHT 0x0b0b +#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_ENABLE 0x0b0c +#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_WEIGHT 0x0b0d +#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ENABLE 0x0b0e +#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ADJUST 0x0b0f +#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ADJUST 0x0b10 +#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ENABLE 0x0b11 +#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ADJUST 0x0b12 +#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ENABLE 0x0b13 +#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ADJUST 0x0b14 +#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ENABLE 0x0b15 +#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ADJUST 0x0b16 +#define SMIAPP_REG_U8_EDOF_MODE 0x0b80 +#define SMIAPP_REG_U8_SHARPNESS 0x0b83 +#define SMIAPP_REG_U8_DENOISING 0x0b84 +#define SMIAPP_REG_U8_MODULE_SPECIFIC 0x0b85 +#define SMIAPP_REG_U16_DEPTH_OF_FIELD (0x0b86 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_FOCUS_DISTANCE (0x0b88 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_ESTIMATION_MODE_CTRL 0x0b8a +#define SMIAPP_REG_U16_COLOUR_TEMPERATURE (0x0b8c | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENR (0x0b8e | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ABSOLUTE_GAIN_RED (0x0b90 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ABSOLUTE_GAIN_BLUE (0x0b92 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENB (0x0b94 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_ESTIMATION_ZONE_MODE 0x0bc0 +#define SMIAPP_REG_U16_FIXED_ZONE_WEIGHTING (0x0bc2 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_CUSTOM_ZONE_X_START (0x0bc4 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_CUSTOM_ZONE_Y_START (0x0bc6 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_CUSTOM_ZONE_WIDTH (0x0bc8 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_CUSTOM_ZONE_HEIGHT (0x0bca | CCS_FL_16BIT) +#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL1 0x0c00 +#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL2 0x0c01 +#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_1 0x0c02 +#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_2 0x0c03 +#define SMIAPP_REG_U16_TRDY_CTRL (0x0c04 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TRDOUT_CTRL (0x0c06 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TSHUTTER_STROBE_DELAY_CTRL (0x0c08 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TSHUTTER_STROBE_WIDTH_CTRL (0x0c0a | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_CTRL (0x0c0c | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_CTRL (0x0c0e | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TGRST_INTERVAL_CTRL (0x0c10 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_FLASH_STROBE_ADJUSTMENT 0x0c12 +#define SMIAPP_REG_U16_FLASH_STROBE_START_POINT (0x0c14 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_RS_CTRL (0x0c16 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL (0x0c18 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_FLASH_MODE_RS 0x0c1a +#define SMIAPP_REG_U8_FLASH_TRIGGER_RS 0x0c1b +#define SMIAPP_REG_U8_FLASH_STATUS 0x0c1c +#define SMIAPP_REG_U8_SA_STROBE_MODE 0x0c1d +#define SMIAPP_REG_U16_SA_STROBE_START_POINT (0x0c1e | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TSA_STROBE_DELAY_CTRL (0x0c20 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TSA_STROBE_WIDTH_CTRL (0x0c22 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_SA_STROBE_TRIGGER 0x0c24 +#define SMIAPP_REG_U8_SPECIAL_ACTUATOR_STATUS 0x0c25 +#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_RS_CTRL (0x0c26 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_RS_CTRL (0x0c28 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_RS_CTRL 0x0c2a +#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_CTRL 0x0c2b +#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_CTRL (0x0c2c | CCS_FL_16BIT) +#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_CTRL (0x0c2e | CCS_FL_16BIT) +#define SMIAPP_REG_U8_LOW_LEVEL_CTRL 0x0c80 +#define SMIAPP_REG_U16_MAIN_TRIGGER_REF_POINT (0x0c82 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAIN_TRIGGER_T3 (0x0c84 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_MAIN_TRIGGER_COUNT 0x0c86 +#define SMIAPP_REG_U16_PHASE1_TRIGGER_T3 (0x0c88 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_PHASE1_TRIGGER_COUNT 0x0c8a +#define SMIAPP_REG_U16_PHASE2_TRIGGER_T3 (0x0c8c | CCS_FL_16BIT) +#define SMIAPP_REG_U8_PHASE2_TRIGGER_COUNT 0x0c8e +#define SMIAPP_REG_U8_MECH_SHUTTER_CTRL 0x0d00 +#define SMIAPP_REG_U8_OPERATION_MODE 0x0d01 +#define SMIAPP_REG_U8_ACT_STATE1 0x0d02 +#define SMIAPP_REG_U8_ACT_STATE2 0x0d03 +#define SMIAPP_REG_U16_FOCUS_CHANGE (0x0d80 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_FOCUS_CHANGE_CONTROL (0x0d82 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE1 (0x0d84 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE2 (0x0d86 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_STROBE_COUNT_PHASE1 0x0d88 +#define SMIAPP_REG_U8_STROBE_COUNT_PHASE2 0x0d89 +#define SMIAPP_REG_U8_POSITION 0x0d8a +#define SMIAPP_REG_U8_BRACKETING_LUT_CONTROL 0x0e00 +#define SMIAPP_REG_U8_BRACKETING_LUT_MODE 0x0e01 +#define SMIAPP_REG_U8_BRACKETING_LUT_ENTRY_CONTROL 0x0e02 +#define SMIAPP_REG_U8_LUT_PARAMETERS_START 0x0e10 +#define SMIAPP_REG_U8_LUT_PARAMETERS_END 0x0eff +#define SMIAPP_REG_U16_INTEGRATION_TIME_CAPABILITY (0x1000 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MIN (0x1004 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MAX_MARGIN (0x1006 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN (0x1008 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN (0x100a | CCS_FL_16BIT) +#define SMIAPP_REG_U16_DIGITAL_GAIN_CAPABILITY (0x1080 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_DIGITAL_GAIN_MIN (0x1084 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_DIGITAL_GAIN_MAX (0x1086 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_DIGITAL_GAIN_STEP_SIZE (0x1088 | CCS_FL_16BIT) +#define SMIAPP_REG_F32_MIN_EXT_CLK_FREQ_HZ (0x1100 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_F32_MAX_EXT_CLK_FREQ_HZ (0x1104 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_U16_MIN_PRE_PLL_CLK_DIV (0x1108 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_PRE_PLL_CLK_DIV (0x110a | CCS_FL_16BIT) +#define SMIAPP_REG_F32_MIN_PLL_IP_FREQ_HZ (0x110c | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_F32_MAX_PLL_IP_FREQ_HZ (0x1110 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_U16_MIN_PLL_MULTIPLIER (0x1114 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_PLL_MULTIPLIER (0x1116 | CCS_FL_16BIT) +#define SMIAPP_REG_F32_MIN_PLL_OP_FREQ_HZ (0x1118 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_F32_MAX_PLL_OP_FREQ_HZ (0x111c | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_U16_MIN_VT_SYS_CLK_DIV (0x1120 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_VT_SYS_CLK_DIV (0x1122 | CCS_FL_16BIT) +#define SMIAPP_REG_F32_MIN_VT_SYS_CLK_FREQ_HZ (0x1124 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_F32_MAX_VT_SYS_CLK_FREQ_HZ (0x1128 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_F32_MIN_VT_PIX_CLK_FREQ_HZ (0x112c | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_F32_MAX_VT_PIX_CLK_FREQ_HZ (0x1130 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_U16_MIN_VT_PIX_CLK_DIV (0x1134 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_VT_PIX_CLK_DIV (0x1136 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES (0x1140 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES (0x1142 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK (0x1144 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK (0x1146 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK (0x1148 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MIN_FRAME_BLANKING_LINES (0x114a | CCS_FL_16BIT) +#define SMIAPP_REG_U8_MIN_LINE_LENGTH_PCK_STEP_SIZE 0x114c +#define SMIAPP_REG_U16_MIN_OP_SYS_CLK_DIV (0x1160 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_OP_SYS_CLK_DIV (0x1162 | CCS_FL_16BIT) +#define SMIAPP_REG_F32_MIN_OP_SYS_CLK_FREQ_HZ (0x1164 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_F32_MAX_OP_SYS_CLK_FREQ_HZ (0x1168 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_U16_MIN_OP_PIX_CLK_DIV (0x116c | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_OP_PIX_CLK_DIV (0x116e | CCS_FL_16BIT) +#define SMIAPP_REG_F32_MIN_OP_PIX_CLK_FREQ_HZ (0x1170 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_F32_MAX_OP_PIX_CLK_FREQ_HZ (0x1174 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) +#define SMIAPP_REG_U16_X_ADDR_MIN (0x1180 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_Y_ADDR_MIN (0x1182 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_X_ADDR_MAX (0x1184 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_Y_ADDR_MAX (0x1186 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MIN_X_OUTPUT_SIZE (0x1188 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MIN_Y_OUTPUT_SIZE (0x118a | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_X_OUTPUT_SIZE (0x118c | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_Y_OUTPUT_SIZE (0x118e | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MIN_EVEN_INC (0x11c0 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_EVEN_INC (0x11c2 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MIN_ODD_INC (0x11c4 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_ODD_INC (0x11c6 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_SCALING_CAPABILITY (0x1200 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_SCALER_M_MIN (0x1204 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_SCALER_M_MAX (0x1206 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_SCALER_N_MIN (0x1208 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_SCALER_N_MAX (0x120a | CCS_FL_16BIT) +#define SMIAPP_REG_U16_SPATIAL_SAMPLING_CAPABILITY (0x120c | CCS_FL_16BIT) +#define SMIAPP_REG_U8_DIGITAL_CROP_CAPABILITY 0x120e +#define SMIAPP_REG_U16_COMPRESSION_CAPABILITY (0x1300 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINRED (0x1400 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINRED (0x1402 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINRED (0x1404 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINGREEN (0x1406 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINGREEN (0x1408 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINGREEN (0x140a | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINBLUE (0x140c | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINBLUE (0x140e | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINBLUE (0x1410 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_FIFO_SIZE_PIXELS (0x1500 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_FIFO_SUPPORT_CAPABILITY 0x1502 +#define SMIAPP_REG_U8_DPHY_CTRL_CAPABILITY 0x1600 +#define SMIAPP_REG_U8_CSI_LANE_MODE_CAPABILITY 0x1601 +#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE_CAPABILITY 0x1602 +#define SMIAPP_REG_U8_FAST_STANDBY_CAPABILITY 0x1603 +#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL_CAPABILITY 0x1604 +#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS (0x1608 | CCS_FL_32BIT) +#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS (0x160c | CCS_FL_32BIT) +#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS (0x1610 | CCS_FL_32BIT) +#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS (0x1614 | CCS_FL_32BIT) +#define SMIAPP_REG_U8_TEMP_SENSOR_CAPABILITY 0x1618 +#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES_BIN (0x1700 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES_BIN (0x1702 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK_BIN (0x1704 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK_BIN (0x1706 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK_BIN (0x1708 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN_BIN (0x170a | CCS_FL_16BIT) +#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN (0x170c | CCS_FL_16BIT) +#define SMIAPP_REG_U8_BINNING_CAPABILITY 0x1710 +#define SMIAPP_REG_U8_BINNING_WEIGHTING_CAPABILITY 0x1711 +#define SMIAPP_REG_U8_BINNING_SUBTYPES 0x1712 +#define SMIAPP_REG_U8_BINNING_TYPE_n(n) (0x1713 + (n)) /* 1 <= n <= 237 */ +#define SMIAPP_REG_U8_DATA_TRANSFER_IF_CAPABILITY 0x1800 +#define SMIAPP_REG_U8_SHADING_CORRECTION_CAPABILITY 0x1900 +#define SMIAPP_REG_U8_GREEN_IMBALANCE_CAPABILITY 0x1901 +#define SMIAPP_REG_U8_BLACK_LEVEL_CAPABILITY 0x1902 +#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_CAPABILITY 0x1903 +#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY (0x1904 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY_2 (0x1906 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_EDOF_CAPABILITY 0x1980 +#define SMIAPP_REG_U8_ESTIMATION_FRAMES 0x1981 +#define SMIAPP_REG_U8_SUPPORTS_SHARPNESS_ADJ 0x1982 +#define SMIAPP_REG_U8_SUPPORTS_DENOISING_ADJ 0x1983 +#define SMIAPP_REG_U8_SUPPORTS_MODULE_SPECIFIC_ADJ 0x1984 +#define SMIAPP_REG_U8_SUPPORTS_DEPTH_OF_FIELD_ADJ 0x1985 +#define SMIAPP_REG_U8_SUPPORTS_FOCUS_DISTANCE_ADJ 0x1986 +#define SMIAPP_REG_U8_COLOUR_FEEDBACK_CAPABILITY 0x1987 +#define SMIAPP_REG_U8_EDOF_SUPPORT_AB_NXM 0x1988 +#define SMIAPP_REG_U8_ESTIMATION_MODE_CAPABILITY 0x19c0 +#define SMIAPP_REG_U8_ESTIMATION_ZONE_CAPABILITY 0x19c1 +#define SMIAPP_REG_U16_EST_DEPTH_OF_FIELD (0x19c2 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_EST_FOCUS_DISTANCE (0x19c4 | CCS_FL_16BIT) +#define SMIAPP_REG_U16_CAPABILITY_TRDY_MIN (0x1a00 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_FLASH_MODE_CAPABILITY 0x1a02 +#define SMIAPP_REG_U16_MECH_SHUT_AND_ACT_START_ADDR (0x1b02 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_ACTUATOR_CAPABILITY 0x1b04 +#define SMIAPP_REG_U16_ACTUATOR_TYPE (0x1b40 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_AF_DEVICE_ADDRESS 0x1b42 +#define SMIAPP_REG_U16_FOCUS_CHANGE_ADDRESS (0x1b44 | CCS_FL_16BIT) +#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_1 0x1c00 +#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_2 0x1c01 +#define SMIAPP_REG_U8_BRACKETING_LUT_SIZE 0x1c02 + +/* Register bit definitions */ +#define SMIAPP_IMAGE_ORIENTATION_HFLIP BIT(0) +#define SMIAPP_IMAGE_ORIENTATION_VFLIP BIT(1) + +#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_EN BIT(0) +#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_WR_EN BIT(1) +#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_ERR_CLEAR BIT(2) +#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY BIT(0) +#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_WR_READY BIT(1) +#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_EDATA BIT(2) +#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_EUSAGE BIT(3) + +#define SMIAPP_DATA_TRANSFER_IF_CAPABILITY_SUPPORTED BIT(0) +#define SMIAPP_DATA_TRANSFER_IF_CAPABILITY_POLL BIT(2) + +#define SMIAPP_SOFTWARE_RESET BIT(0) + +#define SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE BIT(0) +#define SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE BIT(1) + +#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK 0 +#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE 1 +#define SMIAPP_CSI_SIGNALLING_MODE_CSI2 2 + +#define SMIAPP_DPHY_CTRL_AUTOMATIC 0 +/* DPHY control based on REQUESTED_LINK_BIT_RATE_MBPS */ +#define SMIAPP_DPHY_CTRL_UI 1 +#define SMIAPP_DPHY_CTRL_REGISTER 2 + +#define SMIAPP_COMPRESSION_MODE_SIMPLE_PREDICTOR 1 +#define SMIAPP_COMPRESSION_MODE_ADVANCED_PREDICTOR 2 + +#define SMIAPP_MODE_SELECT_SOFTWARE_STANDBY 0 +#define SMIAPP_MODE_SELECT_STREAMING 1 + +#define SMIAPP_SCALING_MODE_NONE 0 +#define SMIAPP_SCALING_MODE_HORIZONTAL 1 +#define SMIAPP_SCALING_MODE_BOTH 2 + +#define SMIAPP_SCALING_CAPABILITY_NONE 0 +#define SMIAPP_SCALING_CAPABILITY_HORIZONTAL 1 +#define SMIAPP_SCALING_CAPABILITY_BOTH 2 /* horizontal/both */ + +/* digital crop right before scaler */ +#define SMIAPP_DIGITAL_CROP_CAPABILITY_NONE 0 +#define SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP 1 + +#define SMIAPP_BINNING_CAPABILITY_NO 0 +#define SMIAPP_BINNING_CAPABILITY_YES 1 + +/* Maximum number of binning subtypes */ +#define SMIAPP_BINNING_SUBTYPES 253 + +#define SMIAPP_PIXEL_ORDER_GRBG 0 +#define SMIAPP_PIXEL_ORDER_RGGB 1 +#define SMIAPP_PIXEL_ORDER_BGGR 2 +#define SMIAPP_PIXEL_ORDER_GBRG 3 + +#define SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL 1 +#define SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED 2 +#define SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL_N 8 +#define SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED_N 16 + +#define SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE 0x01 +#define SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE 0x02 +#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NROWS_MASK 0x0f +#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_MASK 0xf0 +#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_SHIFT 4 + +#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_MASK 0xf000 +#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_SHIFT 12 +#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELS_MASK 0x0fff + +#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_MASK 0xf0000000 +#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_SHIFT 28 +#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELS_MASK 0x0000ffff + +#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED 1 +#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DUMMY 2 +#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_BLACK 3 +#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DARK 4 +#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE 5 + +#define SMIAPP_FAST_STANDBY_CTRL_COMPLETE_FRAMES 0 +#define SMIAPP_FAST_STANDBY_CTRL_IMMEDIATE 1 + +/* Scaling N factor */ +#define SMIAPP_SCALE_N 16 + +#endif /* __SMIAPP_REG_DEFS_H__ */ diff --git a/drivers/media/i2c/smiapp/Kconfig b/drivers/media/i2c/smiapp/Kconfig deleted file mode 100644 index 6893b532824f..000000000000 --- a/drivers/media/i2c/smiapp/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config VIDEO_SMIAPP - tristate "SMIA++/SMIA sensor support" - depends on I2C && VIDEO_V4L2 && HAVE_CLK - select MEDIA_CONTROLLER - select VIDEO_V4L2_SUBDEV_API - select VIDEO_SMIAPP_PLL - select V4L2_FWNODE - help - This is a generic driver for SMIA++/SMIA camera modules. diff --git a/drivers/media/i2c/smiapp/Makefile b/drivers/media/i2c/smiapp/Makefile deleted file mode 100644 index c9d300b5d2bc..000000000000 --- a/drivers/media/i2c/smiapp/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -smiapp-objs += ccs-core.o ccs-reg-access.o \ - ccs-quirk.o ccs-limits.o -obj-$(CONFIG_VIDEO_SMIAPP) += smiapp.o - -ccflags-y += -I $(srctree)/drivers/media/i2c diff --git a/drivers/media/i2c/smiapp/ccs-core.c b/drivers/media/i2c/smiapp/ccs-core.c deleted file mode 100644 index 30c4d8edce9d..000000000000 --- a/drivers/media/i2c/smiapp/ccs-core.c +++ /dev/null @@ -1,3300 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * drivers/media/i2c/smiapp/ccs-core.c - * - * Generic driver for SMIA/SMIA++ compliant camera modules - * - * Copyright (C) 2010--2012 Nokia Corporation - * Contact: Sakari Ailus - * - * Based on smiapp driver by Vimarsh Zutshi - * Based on jt8ev1.c by Vimarsh Zutshi - * Based on smia-sensor.c by Tuukka Toivonen - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ccs.h" -#include "ccs-limits.h" - -#define CCS_ALIGN_DIM(dim, flags) \ - ((flags) & V4L2_SEL_FLAG_GE \ - ? ALIGN((dim), 2) \ - : (dim) & ~1) - -static struct ccs_limit_offset { - u16 lim; - u16 info; -} ccs_limit_offsets[CCS_L_LAST + 1]; - -/* - * ccs_module_idents - supported camera modules - */ -static const struct ccs_module_ident ccs_module_idents[] = { - CCS_IDENT_L(0x01, 0x022b, -1, "vs6555"), - CCS_IDENT_L(0x01, 0x022e, -1, "vw6558"), - CCS_IDENT_L(0x07, 0x7698, -1, "ovm7698"), - CCS_IDENT_L(0x0b, 0x4242, -1, "smiapp-003"), - CCS_IDENT_L(0x0c, 0x208a, -1, "tcm8330md"), - CCS_IDENT_LQ(0x0c, 0x2134, -1, "tcm8500md", &smiapp_tcm8500md_quirk), - CCS_IDENT_L(0x0c, 0x213e, -1, "et8en2"), - CCS_IDENT_L(0x0c, 0x2184, -1, "tcm8580md"), - CCS_IDENT_LQ(0x0c, 0x560f, -1, "jt8ew9", &smiapp_jt8ew9_quirk), - CCS_IDENT_LQ(0x10, 0x4141, -1, "jt8ev1", &smiapp_jt8ev1_quirk), - CCS_IDENT_LQ(0x10, 0x4241, -1, "imx125es", &smiapp_imx125es_quirk), -}; - -/* - * - * Dynamic Capability Identification - * - */ - -static void ccs_assign_limit(void *ptr, unsigned int width, u32 val) -{ - switch (width) { - case sizeof(u8): - *(u8 *)ptr = val; - break; - case sizeof(u16): - *(u16 *)ptr = val; - break; - case sizeof(u32): - *(u32 *)ptr = val; - break; - } -} - -static int ccs_limit_ptr(struct ccs_sensor *sensor, unsigned int limit, - unsigned int offset, void **__ptr) -{ - const struct ccs_limit *linfo; - - if (WARN_ON(limit >= CCS_L_LAST)) - return -EINVAL; - - linfo = &ccs_limits[ccs_limit_offsets[limit].info]; - - if (WARN_ON(!sensor->ccs_limits) || - WARN_ON(offset + ccs_reg_width(linfo->reg) > - ccs_limit_offsets[limit + 1].lim)) - return -EINVAL; - - *__ptr = sensor->ccs_limits + ccs_limit_offsets[limit].lim + offset; - - return 0; -} - -void ccs_replace_limit(struct ccs_sensor *sensor, - unsigned int limit, unsigned int offset, u32 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - const struct ccs_limit *linfo; - void *ptr; - int ret; - - ret = ccs_limit_ptr(sensor, limit, offset, &ptr); - if (ret) - return; - - linfo = &ccs_limits[ccs_limit_offsets[limit].info]; - - dev_dbg(&client->dev, "quirk: 0x%8.8x \"%s\" %u = %d, 0x%x\n", - linfo->reg, linfo->name, offset, val, val); - - ccs_assign_limit(ptr, ccs_reg_width(linfo->reg), val); -} - -static u32 ccs_get_limit(struct ccs_sensor *sensor, - unsigned int limit, unsigned int offset) -{ - void *ptr; - int ret; - - ret = ccs_limit_ptr(sensor, limit, offset, &ptr); - if (ret) - return 0; - - switch (ccs_reg_width(ccs_limits[ccs_limit_offsets[limit].info].reg)) { - case sizeof(u8): - return *(u8 *)ptr; - case sizeof(u16): - return *(u16 *)ptr; - case sizeof(u32): - return *(u32 *)ptr; - } - - WARN_ON(1); - - return 0; -} - -#define CCS_LIM(sensor, limit) \ - ccs_get_limit(sensor, CCS_L_##limit, 0) - -#define CCS_LIM_AT(sensor, limit, offset) \ - ccs_get_limit(sensor, CCS_L_##limit, CCS_L_##limit##_OFFSET(offset)) - -static int ccs_read_all_limits(struct ccs_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - void *ptr, *alloc, *end; - unsigned int i, l; - int ret; - - kfree(sensor->ccs_limits); - sensor->ccs_limits = NULL; - - alloc = kzalloc(ccs_limit_offsets[CCS_L_LAST].lim, GFP_KERNEL); - if (!alloc) - return -ENOMEM; - - end = alloc + ccs_limit_offsets[CCS_L_LAST].lim; - - for (i = 0, l = 0, ptr = alloc; ccs_limits[i].size; i++) { - u32 reg = ccs_limits[i].reg; - unsigned int width = ccs_reg_width(reg); - unsigned int j; - - if (l == CCS_L_LAST) { - dev_err(&client->dev, - "internal error --- end of limit array\n"); - ret = -EINVAL; - goto out_err; - } - - for (j = 0; j < ccs_limits[i].size / width; - j++, reg += width, ptr += width) { - u32 val; - - ret = ccs_read_addr(sensor, reg, &val); - if (ret) - goto out_err; - - if (ptr + width > end) { - dev_err(&client->dev, - "internal error --- no room for regs\n"); - ret = -EINVAL; - goto out_err; - } - - ccs_assign_limit(ptr, width, val); - - dev_dbg(&client->dev, "0x%8.8x \"%s\" = %u, 0x%x\n", - reg, ccs_limits[i].name, val, val); - } - - if (ccs_limits[i].flags & CCS_L_FL_SAME_REG) - continue; - - l++; - ptr = alloc + ccs_limit_offsets[l].lim; - } - - if (l != CCS_L_LAST) { - dev_err(&client->dev, - "internal error --- insufficient limits\n"); - ret = -EINVAL; - goto out_err; - } - - sensor->ccs_limits = alloc; - - if (CCS_LIM(sensor, SCALER_N_MIN) < 16) - ccs_replace_limit(sensor, CCS_L_SCALER_N_MIN, 0, 16); - - return 0; - -out_err: - kfree(alloc); - - return ret; -} - -static int ccs_read_frame_fmt(struct ccs_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - u8 fmt_model_type, fmt_model_subtype, ncol_desc, nrow_desc; - unsigned int i; - int pixel_count = 0; - int line_count = 0; - - fmt_model_type = CCS_LIM(sensor, FRAME_FORMAT_MODEL_TYPE); - fmt_model_subtype = CCS_LIM(sensor, FRAME_FORMAT_MODEL_SUBTYPE); - - ncol_desc = (fmt_model_subtype - & CCS_FRAME_FORMAT_MODEL_SUBTYPE_COLUMNS_MASK) - >> CCS_FRAME_FORMAT_MODEL_SUBTYPE_COLUMNS_SHIFT; - nrow_desc = fmt_model_subtype - & CCS_FRAME_FORMAT_MODEL_SUBTYPE_ROWS_MASK; - - dev_dbg(&client->dev, "format_model_type %s\n", - fmt_model_type == CCS_FRAME_FORMAT_MODEL_TYPE_2_BYTE - ? "2 byte" : - fmt_model_type == CCS_FRAME_FORMAT_MODEL_TYPE_4_BYTE - ? "4 byte" : "is simply bad"); - - dev_dbg(&client->dev, "%u column and %u row descriptors\n", - ncol_desc, nrow_desc); - - for (i = 0; i < ncol_desc + nrow_desc; i++) { - u32 desc; - u32 pixelcode; - u32 pixels; - char *which; - char *what; - u32 reg; - - if (fmt_model_type == CCS_FRAME_FORMAT_MODEL_TYPE_2_BYTE) { - desc = CCS_LIM_AT(sensor, FRAME_FORMAT_DESCRIPTOR, i); - - pixelcode = - (desc - & CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MASK) - >> CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_SHIFT; - pixels = desc & CCS_FRAME_FORMAT_DESCRIPTOR_PIXELS_MASK; - } else if (fmt_model_type - == CCS_FRAME_FORMAT_MODEL_TYPE_4_BYTE) { - desc = CCS_LIM_AT(sensor, FRAME_FORMAT_DESCRIPTOR_4, i); - - pixelcode = - (desc - & CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MASK) - >> CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_SHIFT; - pixels = desc & - CCS_FRAME_FORMAT_DESCRIPTOR_4_PIXELS_MASK; - } else { - dev_dbg(&client->dev, - "invalid frame format model type %d\n", - fmt_model_type); - return -EINVAL; - } - - if (i < ncol_desc) - which = "columns"; - else - which = "rows"; - - switch (pixelcode) { - case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_EMBEDDED: - what = "embedded"; - break; - case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_DUMMY_PIXEL: - what = "dummy"; - break; - case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_BLACK_PIXEL: - what = "black"; - break; - case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_DARK_PIXEL: - what = "dark"; - break; - case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_VISIBLE_PIXEL: - what = "visible"; - break; - default: - what = "invalid"; - break; - } - - dev_dbg(&client->dev, - "0x%8.8x %s pixels: %d %s (pixelcode %u)\n", reg, - what, pixels, which, pixelcode); - - if (i < ncol_desc) { - if (pixelcode == - CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_VISIBLE_PIXEL) - sensor->visible_pixel_start = pixel_count; - pixel_count += pixels; - continue; - } - - /* Handle row descriptors */ - switch (pixelcode) { - case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_EMBEDDED: - if (sensor->embedded_end) - break; - sensor->embedded_start = line_count; - sensor->embedded_end = line_count + pixels; - break; - case CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_VISIBLE_PIXEL: - sensor->image_start = line_count; - break; - } - line_count += pixels; - } - - if (sensor->embedded_end > sensor->image_start) { - dev_dbg(&client->dev, - "adjusting image start line to %u (was %u)\n", - sensor->embedded_end, sensor->image_start); - sensor->image_start = sensor->embedded_end; - } - - dev_dbg(&client->dev, "embedded data from lines %d to %d\n", - sensor->embedded_start, sensor->embedded_end); - dev_dbg(&client->dev, "image data starts at line %d\n", - sensor->image_start); - - return 0; -} - -static int ccs_pll_configure(struct ccs_sensor *sensor) -{ - struct smiapp_pll *pll = &sensor->pll; - int rval; - - rval = ccs_write(sensor, VT_PIX_CLK_DIV, pll->vt.pix_clk_div); - if (rval < 0) - return rval; - - rval = ccs_write(sensor, VT_SYS_CLK_DIV, pll->vt.sys_clk_div); - if (rval < 0) - return rval; - - rval = ccs_write(sensor, PRE_PLL_CLK_DIV, pll->pre_pll_clk_div); - if (rval < 0) - return rval; - - rval = ccs_write(sensor, PLL_MULTIPLIER, pll->pll_multiplier); - if (rval < 0) - return rval; - - /* Lane op clock ratio does not apply here. */ - rval = ccs_write(sensor, REQUESTED_LINK_RATE, - DIV_ROUND_UP(pll->op.sys_clk_freq_hz, - 1000000 / 256 / 256)); - if (rval < 0 || sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) - return rval; - - rval = ccs_write(sensor, OP_PIX_CLK_DIV, pll->op.pix_clk_div); - if (rval < 0) - return rval; - - return ccs_write(sensor, OP_SYS_CLK_DIV, pll->op.sys_clk_div); -} - -static int ccs_pll_try(struct ccs_sensor *sensor, struct smiapp_pll *pll) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - struct smiapp_pll_limits lim = { - .min_pre_pll_clk_div = CCS_LIM(sensor, MIN_PRE_PLL_CLK_DIV), - .max_pre_pll_clk_div = CCS_LIM(sensor, MAX_PRE_PLL_CLK_DIV), - .min_pll_ip_freq_hz = CCS_LIM(sensor, MIN_PLL_IP_CLK_FREQ_MHZ), - .max_pll_ip_freq_hz = CCS_LIM(sensor, MAX_PLL_IP_CLK_FREQ_MHZ), - .min_pll_multiplier = CCS_LIM(sensor, MIN_PLL_MULTIPLIER), - .max_pll_multiplier = CCS_LIM(sensor, MAX_PLL_MULTIPLIER), - .min_pll_op_freq_hz = CCS_LIM(sensor, MIN_PLL_OP_CLK_FREQ_MHZ), - .max_pll_op_freq_hz = CCS_LIM(sensor, MAX_PLL_OP_CLK_FREQ_MHZ), - - .op.min_sys_clk_div = CCS_LIM(sensor, MIN_OP_SYS_CLK_DIV), - .op.max_sys_clk_div = CCS_LIM(sensor, MAX_OP_SYS_CLK_DIV), - .op.min_pix_clk_div = CCS_LIM(sensor, MIN_OP_PIX_CLK_DIV), - .op.max_pix_clk_div = CCS_LIM(sensor, MAX_OP_PIX_CLK_DIV), - .op.min_sys_clk_freq_hz = CCS_LIM(sensor, MIN_OP_SYS_CLK_FREQ_MHZ), - .op.max_sys_clk_freq_hz = CCS_LIM(sensor, MAX_OP_SYS_CLK_FREQ_MHZ), - .op.min_pix_clk_freq_hz = CCS_LIM(sensor, MIN_OP_PIX_CLK_FREQ_MHZ), - .op.max_pix_clk_freq_hz = CCS_LIM(sensor, MAX_OP_PIX_CLK_FREQ_MHZ), - - .vt.min_sys_clk_div = CCS_LIM(sensor, MIN_VT_SYS_CLK_DIV), - .vt.max_sys_clk_div = CCS_LIM(sensor, MAX_VT_SYS_CLK_DIV), - .vt.min_pix_clk_div = CCS_LIM(sensor, MIN_VT_PIX_CLK_DIV), - .vt.max_pix_clk_div = CCS_LIM(sensor, MAX_VT_PIX_CLK_DIV), - .vt.min_sys_clk_freq_hz = CCS_LIM(sensor, MIN_VT_SYS_CLK_FREQ_MHZ), - .vt.max_sys_clk_freq_hz = CCS_LIM(sensor, MAX_VT_SYS_CLK_FREQ_MHZ), - .vt.min_pix_clk_freq_hz = CCS_LIM(sensor, MIN_VT_PIX_CLK_FREQ_MHZ), - .vt.max_pix_clk_freq_hz = CCS_LIM(sensor, MAX_VT_PIX_CLK_FREQ_MHZ), - - .min_line_length_pck_bin = CCS_LIM(sensor, MIN_LINE_LENGTH_PCK_BIN), - .min_line_length_pck = CCS_LIM(sensor, MIN_LINE_LENGTH_PCK), - }; - - return smiapp_pll_calculate(&client->dev, &lim, pll); -} - -static int ccs_pll_update(struct ccs_sensor *sensor) -{ - struct smiapp_pll *pll = &sensor->pll; - int rval; - - pll->binning_horizontal = sensor->binning_horizontal; - pll->binning_vertical = sensor->binning_vertical; - pll->link_freq = - sensor->link_freq->qmenu_int[sensor->link_freq->val]; - pll->scale_m = sensor->scale_m; - pll->bits_per_pixel = sensor->csi_format->compressed; - - rval = ccs_pll_try(sensor, pll); - if (rval < 0) - return rval; - - __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_parray, - pll->pixel_rate_pixel_array); - __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_csi, pll->pixel_rate_csi); - - return 0; -} - - -/* - * - * V4L2 Controls handling - * - */ - -static void __ccs_update_exposure_limits(struct ccs_sensor *sensor) -{ - struct v4l2_ctrl *ctrl = sensor->exposure; - int max; - - max = sensor->pixel_array->crop[CCS_PA_PAD_SRC].height - + sensor->vblank->val - - CCS_LIM(sensor, COARSE_INTEGRATION_TIME_MAX_MARGIN); - - __v4l2_ctrl_modify_range(ctrl, ctrl->minimum, max, ctrl->step, max); -} - -/* - * Order matters. - * - * 1. Bits-per-pixel, descending. - * 2. Bits-per-pixel compressed, descending. - * 3. Pixel order, same as in pixel_order_str. Formats for all four pixel - * orders must be defined. - */ -static const struct ccs_csi_data_format ccs_csi_data_formats[] = { - { MEDIA_BUS_FMT_SGRBG16_1X16, 16, 16, CCS_PIXEL_ORDER_GRBG, }, - { MEDIA_BUS_FMT_SRGGB16_1X16, 16, 16, CCS_PIXEL_ORDER_RGGB, }, - { MEDIA_BUS_FMT_SBGGR16_1X16, 16, 16, CCS_PIXEL_ORDER_BGGR, }, - { MEDIA_BUS_FMT_SGBRG16_1X16, 16, 16, CCS_PIXEL_ORDER_GBRG, }, - { MEDIA_BUS_FMT_SGRBG14_1X14, 14, 14, CCS_PIXEL_ORDER_GRBG, }, - { MEDIA_BUS_FMT_SRGGB14_1X14, 14, 14, CCS_PIXEL_ORDER_RGGB, }, - { MEDIA_BUS_FMT_SBGGR14_1X14, 14, 14, CCS_PIXEL_ORDER_BGGR, }, - { MEDIA_BUS_FMT_SGBRG14_1X14, 14, 14, CCS_PIXEL_ORDER_GBRG, }, - { MEDIA_BUS_FMT_SGRBG12_1X12, 12, 12, CCS_PIXEL_ORDER_GRBG, }, - { MEDIA_BUS_FMT_SRGGB12_1X12, 12, 12, CCS_PIXEL_ORDER_RGGB, }, - { MEDIA_BUS_FMT_SBGGR12_1X12, 12, 12, CCS_PIXEL_ORDER_BGGR, }, - { MEDIA_BUS_FMT_SGBRG12_1X12, 12, 12, CCS_PIXEL_ORDER_GBRG, }, - { MEDIA_BUS_FMT_SGRBG10_1X10, 10, 10, CCS_PIXEL_ORDER_GRBG, }, - { MEDIA_BUS_FMT_SRGGB10_1X10, 10, 10, CCS_PIXEL_ORDER_RGGB, }, - { MEDIA_BUS_FMT_SBGGR10_1X10, 10, 10, CCS_PIXEL_ORDER_BGGR, }, - { MEDIA_BUS_FMT_SGBRG10_1X10, 10, 10, CCS_PIXEL_ORDER_GBRG, }, - { MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, 10, 8, CCS_PIXEL_ORDER_GRBG, }, - { MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, 10, 8, CCS_PIXEL_ORDER_RGGB, }, - { MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, 10, 8, CCS_PIXEL_ORDER_BGGR, }, - { MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, 10, 8, CCS_PIXEL_ORDER_GBRG, }, - { MEDIA_BUS_FMT_SGRBG8_1X8, 8, 8, CCS_PIXEL_ORDER_GRBG, }, - { MEDIA_BUS_FMT_SRGGB8_1X8, 8, 8, CCS_PIXEL_ORDER_RGGB, }, - { MEDIA_BUS_FMT_SBGGR8_1X8, 8, 8, CCS_PIXEL_ORDER_BGGR, }, - { MEDIA_BUS_FMT_SGBRG8_1X8, 8, 8, CCS_PIXEL_ORDER_GBRG, }, -}; - -static const char *pixel_order_str[] = { "GRBG", "RGGB", "BGGR", "GBRG" }; - -#define to_csi_format_idx(fmt) (((unsigned long)(fmt) \ - - (unsigned long)ccs_csi_data_formats) \ - / sizeof(*ccs_csi_data_formats)) - -static u32 ccs_pixel_order(struct ccs_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - int flip = 0; - - if (sensor->hflip) { - if (sensor->hflip->val) - flip |= CCS_IMAGE_ORIENTATION_HORIZONTAL_MIRROR; - - if (sensor->vflip->val) - flip |= CCS_IMAGE_ORIENTATION_VERTICAL_FLIP; - } - - flip ^= sensor->hvflip_inv_mask; - - dev_dbg(&client->dev, "flip %d\n", flip); - return sensor->default_pixel_order ^ flip; -} - -static void ccs_update_mbus_formats(struct ccs_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - unsigned int csi_format_idx = - to_csi_format_idx(sensor->csi_format) & ~3; - unsigned int internal_csi_format_idx = - to_csi_format_idx(sensor->internal_csi_format) & ~3; - unsigned int pixel_order = ccs_pixel_order(sensor); - - sensor->mbus_frame_fmts = - sensor->default_mbus_frame_fmts << pixel_order; - sensor->csi_format = - &ccs_csi_data_formats[csi_format_idx + pixel_order]; - sensor->internal_csi_format = - &ccs_csi_data_formats[internal_csi_format_idx - + pixel_order]; - - BUG_ON(max(internal_csi_format_idx, csi_format_idx) + pixel_order - >= ARRAY_SIZE(ccs_csi_data_formats)); - - dev_dbg(&client->dev, "new pixel order %s\n", - pixel_order_str[pixel_order]); -} - -static const char * const ccs_test_patterns[] = { - "Disabled", - "Solid Colour", - "Eight Vertical Colour Bars", - "Colour Bars With Fade to Grey", - "Pseudorandom Sequence (PN9)", -}; - -static int ccs_set_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ccs_sensor *sensor = - container_of(ctrl->handler, struct ccs_subdev, ctrl_handler) - ->sensor; - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - int pm_status; - u32 orient = 0; - unsigned int i; - int exposure; - int rval; - - switch (ctrl->id) { - case V4L2_CID_HFLIP: - case V4L2_CID_VFLIP: - if (sensor->streaming) - return -EBUSY; - - if (sensor->hflip->val) - orient |= CCS_IMAGE_ORIENTATION_HORIZONTAL_MIRROR; - - if (sensor->vflip->val) - orient |= CCS_IMAGE_ORIENTATION_VERTICAL_FLIP; - - orient ^= sensor->hvflip_inv_mask; - - ccs_update_mbus_formats(sensor); - - break; - case V4L2_CID_VBLANK: - exposure = sensor->exposure->val; - - __ccs_update_exposure_limits(sensor); - - if (exposure > sensor->exposure->maximum) { - sensor->exposure->val = sensor->exposure->maximum; - rval = ccs_set_ctrl(sensor->exposure); - if (rval < 0) - return rval; - } - - break; - case V4L2_CID_LINK_FREQ: - if (sensor->streaming) - return -EBUSY; - - rval = ccs_pll_update(sensor); - if (rval) - return rval; - - return 0; - case V4L2_CID_TEST_PATTERN: - for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) - v4l2_ctrl_activate( - sensor->test_data[i], - ctrl->val == - V4L2_SMIAPP_TEST_PATTERN_MODE_SOLID_COLOUR); - - break; - } - - pm_status = pm_runtime_get_if_active(&client->dev, true); - if (!pm_status) - return 0; - - switch (ctrl->id) { - case V4L2_CID_ANALOGUE_GAIN: - rval = ccs_write(sensor, ANALOG_GAIN_CODE_GLOBAL, ctrl->val); - - break; - case V4L2_CID_EXPOSURE: - rval = ccs_write(sensor, COARSE_INTEGRATION_TIME, ctrl->val); - - break; - case V4L2_CID_HFLIP: - case V4L2_CID_VFLIP: - rval = ccs_write(sensor, IMAGE_ORIENTATION, orient); - - break; - case V4L2_CID_VBLANK: - rval = ccs_write(sensor, FRAME_LENGTH_LINES, - sensor->pixel_array->crop[ - CCS_PA_PAD_SRC].height - + ctrl->val); - - break; - case V4L2_CID_HBLANK: - rval = ccs_write(sensor, LINE_LENGTH_PCK, - sensor->pixel_array->crop[ - CCS_PA_PAD_SRC].width - + ctrl->val); - - break; - case V4L2_CID_TEST_PATTERN: - rval = ccs_write(sensor, TEST_PATTERN_MODE, ctrl->val); - - break; - case V4L2_CID_TEST_PATTERN_RED: - rval = ccs_write(sensor, TEST_DATA_RED, ctrl->val); - - break; - case V4L2_CID_TEST_PATTERN_GREENR: - rval = ccs_write(sensor, TEST_DATA_GREENR, ctrl->val); - - break; - case V4L2_CID_TEST_PATTERN_BLUE: - rval = ccs_write(sensor, TEST_DATA_BLUE, ctrl->val); - - break; - case V4L2_CID_TEST_PATTERN_GREENB: - rval = ccs_write(sensor, TEST_DATA_GREENB, ctrl->val); - - break; - case V4L2_CID_PIXEL_RATE: - /* For v4l2_ctrl_s_ctrl_int64() used internally. */ - rval = 0; - - break; - default: - rval = -EINVAL; - } - - if (pm_status > 0) { - pm_runtime_mark_last_busy(&client->dev); - pm_runtime_put_autosuspend(&client->dev); - } - - return rval; -} - -static const struct v4l2_ctrl_ops ccs_ctrl_ops = { - .s_ctrl = ccs_set_ctrl, -}; - -static int ccs_init_controls(struct ccs_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - int rval; - - rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 12); - if (rval) - return rval; - - sensor->pixel_array->ctrl_handler.lock = &sensor->mutex; - - sensor->analog_gain = v4l2_ctrl_new_std( - &sensor->pixel_array->ctrl_handler, &ccs_ctrl_ops, - V4L2_CID_ANALOGUE_GAIN, - CCS_LIM(sensor, ANALOG_GAIN_CODE_MIN), - CCS_LIM(sensor, ANALOG_GAIN_CODE_MAX), - max(CCS_LIM(sensor, ANALOG_GAIN_CODE_STEP), 1U), - CCS_LIM(sensor, ANALOG_GAIN_CODE_MIN)); - - /* Exposure limits will be updated soon, use just something here. */ - sensor->exposure = v4l2_ctrl_new_std( - &sensor->pixel_array->ctrl_handler, &ccs_ctrl_ops, - V4L2_CID_EXPOSURE, 0, 0, 1, 0); - - sensor->hflip = v4l2_ctrl_new_std( - &sensor->pixel_array->ctrl_handler, &ccs_ctrl_ops, - V4L2_CID_HFLIP, 0, 1, 1, 0); - sensor->vflip = v4l2_ctrl_new_std( - &sensor->pixel_array->ctrl_handler, &ccs_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); - - sensor->vblank = v4l2_ctrl_new_std( - &sensor->pixel_array->ctrl_handler, &ccs_ctrl_ops, - V4L2_CID_VBLANK, 0, 1, 1, 0); - - if (sensor->vblank) - sensor->vblank->flags |= V4L2_CTRL_FLAG_UPDATE; - - sensor->hblank = v4l2_ctrl_new_std( - &sensor->pixel_array->ctrl_handler, &ccs_ctrl_ops, - V4L2_CID_HBLANK, 0, 1, 1, 0); - - if (sensor->hblank) - sensor->hblank->flags |= V4L2_CTRL_FLAG_UPDATE; - - sensor->pixel_rate_parray = v4l2_ctrl_new_std( - &sensor->pixel_array->ctrl_handler, &ccs_ctrl_ops, - V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1); - - v4l2_ctrl_new_std_menu_items(&sensor->pixel_array->ctrl_handler, - &ccs_ctrl_ops, V4L2_CID_TEST_PATTERN, - ARRAY_SIZE(ccs_test_patterns) - 1, - 0, 0, ccs_test_patterns); - - if (sensor->pixel_array->ctrl_handler.error) { - dev_err(&client->dev, - "pixel array controls initialization failed (%d)\n", - sensor->pixel_array->ctrl_handler.error); - return sensor->pixel_array->ctrl_handler.error; - } - - sensor->pixel_array->sd.ctrl_handler = - &sensor->pixel_array->ctrl_handler; - - v4l2_ctrl_cluster(2, &sensor->hflip); - - rval = v4l2_ctrl_handler_init(&sensor->src->ctrl_handler, 0); - if (rval) - return rval; - - sensor->src->ctrl_handler.lock = &sensor->mutex; - - sensor->pixel_rate_csi = v4l2_ctrl_new_std( - &sensor->src->ctrl_handler, &ccs_ctrl_ops, - V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1); - - if (sensor->src->ctrl_handler.error) { - dev_err(&client->dev, - "src controls initialization failed (%d)\n", - sensor->src->ctrl_handler.error); - return sensor->src->ctrl_handler.error; - } - - sensor->src->sd.ctrl_handler = &sensor->src->ctrl_handler; - - return 0; -} - -/* - * For controls that require information on available media bus codes - * and linke frequencies. - */ -static int ccs_init_late_controls(struct ccs_sensor *sensor) -{ - unsigned long *valid_link_freqs = &sensor->valid_link_freqs[ - sensor->csi_format->compressed - sensor->compressed_min_bpp]; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) { - int max_value = (1 << sensor->csi_format->width) - 1; - - sensor->test_data[i] = v4l2_ctrl_new_std( - &sensor->pixel_array->ctrl_handler, - &ccs_ctrl_ops, V4L2_CID_TEST_PATTERN_RED + i, - 0, max_value, 1, max_value); - } - - sensor->link_freq = v4l2_ctrl_new_int_menu( - &sensor->src->ctrl_handler, &ccs_ctrl_ops, - V4L2_CID_LINK_FREQ, __fls(*valid_link_freqs), - __ffs(*valid_link_freqs), sensor->hwcfg->op_sys_clock); - - return sensor->src->ctrl_handler.error; -} - -static void ccs_free_controls(struct ccs_sensor *sensor) -{ - unsigned int i; - - for (i = 0; i < sensor->ssds_used; i++) - v4l2_ctrl_handler_free(&sensor->ssds[i].ctrl_handler); -} - -static int ccs_get_mbus_formats(struct ccs_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - struct smiapp_pll *pll = &sensor->pll; - u8 compressed_max_bpp = 0; - unsigned int type, n; - unsigned int i, pixel_order; - int rval; - - type = CCS_LIM(sensor, DATA_FORMAT_MODEL_TYPE); - - dev_dbg(&client->dev, "data_format_model_type %d\n", type); - - rval = ccs_read(sensor, PIXEL_ORDER, &pixel_order); - if (rval) - return rval; - - if (pixel_order >= ARRAY_SIZE(pixel_order_str)) { - dev_dbg(&client->dev, "bad pixel order %d\n", pixel_order); - return -EINVAL; - } - - dev_dbg(&client->dev, "pixel order %d (%s)\n", pixel_order, - pixel_order_str[pixel_order]); - - switch (type) { - case CCS_DATA_FORMAT_MODEL_TYPE_NORMAL: - n = SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL_N; - break; - case CCS_DATA_FORMAT_MODEL_TYPE_EXTENDED: - n = CCS_LIM_DATA_FORMAT_DESCRIPTOR_MAX_N + 1; - break; - default: - return -EINVAL; - } - - sensor->default_pixel_order = pixel_order; - sensor->mbus_frame_fmts = 0; - - for (i = 0; i < n; i++) { - unsigned int fmt, j; - - fmt = CCS_LIM_AT(sensor, DATA_FORMAT_DESCRIPTOR, i); - - dev_dbg(&client->dev, "%u: bpp %u, compressed %u\n", - i, fmt >> 8, (u8)fmt); - - for (j = 0; j < ARRAY_SIZE(ccs_csi_data_formats); j++) { - const struct ccs_csi_data_format *f = - &ccs_csi_data_formats[j]; - - if (f->pixel_order != CCS_PIXEL_ORDER_GRBG) - continue; - - if (f->width != fmt >> - CCS_DATA_FORMAT_DESCRIPTOR_UNCOMPRESSED_SHIFT || - f->compressed != - (fmt & CCS_DATA_FORMAT_DESCRIPTOR_COMPRESSED_MASK)) - continue; - - dev_dbg(&client->dev, "jolly good! %d\n", j); - - sensor->default_mbus_frame_fmts |= 1 << j; - } - } - - /* Figure out which BPP values can be used with which formats. */ - pll->binning_horizontal = 1; - pll->binning_vertical = 1; - pll->scale_m = sensor->scale_m; - - for (i = 0; i < ARRAY_SIZE(ccs_csi_data_formats); i++) { - sensor->compressed_min_bpp = - min(ccs_csi_data_formats[i].compressed, - sensor->compressed_min_bpp); - compressed_max_bpp = - max(ccs_csi_data_formats[i].compressed, - compressed_max_bpp); - } - - sensor->valid_link_freqs = devm_kcalloc( - &client->dev, - compressed_max_bpp - sensor->compressed_min_bpp + 1, - sizeof(*sensor->valid_link_freqs), GFP_KERNEL); - if (!sensor->valid_link_freqs) - return -ENOMEM; - - for (i = 0; i < ARRAY_SIZE(ccs_csi_data_formats); i++) { - const struct ccs_csi_data_format *f = - &ccs_csi_data_formats[i]; - unsigned long *valid_link_freqs = - &sensor->valid_link_freqs[ - f->compressed - sensor->compressed_min_bpp]; - unsigned int j; - - if (!(sensor->default_mbus_frame_fmts & 1 << i)) - continue; - - pll->bits_per_pixel = f->compressed; - - for (j = 0; sensor->hwcfg->op_sys_clock[j]; j++) { - pll->link_freq = sensor->hwcfg->op_sys_clock[j]; - - rval = ccs_pll_try(sensor, pll); - dev_dbg(&client->dev, "link freq %u Hz, bpp %u %s\n", - pll->link_freq, pll->bits_per_pixel, - rval ? "not ok" : "ok"); - if (rval) - continue; - - set_bit(j, valid_link_freqs); - } - - if (!*valid_link_freqs) { - dev_info(&client->dev, - "no valid link frequencies for %u bpp\n", - f->compressed); - sensor->default_mbus_frame_fmts &= ~BIT(i); - continue; - } - - if (!sensor->csi_format - || f->width > sensor->csi_format->width - || (f->width == sensor->csi_format->width - && f->compressed > sensor->csi_format->compressed)) { - sensor->csi_format = f; - sensor->internal_csi_format = f; - } - } - - if (!sensor->csi_format) { - dev_err(&client->dev, "no supported mbus code found\n"); - return -EINVAL; - } - - ccs_update_mbus_formats(sensor); - - return 0; -} - -static void ccs_update_blanking(struct ccs_sensor *sensor) -{ - struct v4l2_ctrl *vblank = sensor->vblank; - struct v4l2_ctrl *hblank = sensor->hblank; - uint16_t min_fll, max_fll, min_llp, max_llp, min_lbp; - int min, max; - - if (sensor->binning_vertical > 1 || sensor->binning_horizontal > 1) { - min_fll = CCS_LIM(sensor, MIN_FRAME_LENGTH_LINES_BIN); - max_fll = CCS_LIM(sensor, MAX_FRAME_LENGTH_LINES_BIN); - min_llp = CCS_LIM(sensor, MIN_LINE_LENGTH_PCK_BIN); - max_llp = CCS_LIM(sensor, MAX_LINE_LENGTH_PCK_BIN); - min_lbp = CCS_LIM(sensor, MIN_LINE_BLANKING_PCK_BIN); - } else { - min_fll = CCS_LIM(sensor, MIN_FRAME_LENGTH_LINES); - max_fll = CCS_LIM(sensor, MAX_FRAME_LENGTH_LINES); - min_llp = CCS_LIM(sensor, MIN_LINE_LENGTH_PCK); - max_llp = CCS_LIM(sensor, MAX_LINE_LENGTH_PCK); - min_lbp = CCS_LIM(sensor, MIN_LINE_BLANKING_PCK); - } - - min = max_t(int, - CCS_LIM(sensor, MIN_FRAME_BLANKING_LINES), - min_fll - - sensor->pixel_array->crop[CCS_PA_PAD_SRC].height); - max = max_fll - sensor->pixel_array->crop[CCS_PA_PAD_SRC].height; - - __v4l2_ctrl_modify_range(vblank, min, max, vblank->step, min); - - min = max_t(int, - min_llp - - sensor->pixel_array->crop[CCS_PA_PAD_SRC].width, - min_lbp); - max = max_llp - sensor->pixel_array->crop[CCS_PA_PAD_SRC].width; - - __v4l2_ctrl_modify_range(hblank, min, max, hblank->step, min); - - __ccs_update_exposure_limits(sensor); -} - -static int ccs_pll_blanking_update(struct ccs_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - int rval; - - rval = ccs_pll_update(sensor); - if (rval < 0) - return rval; - - /* Output from pixel array, including blanking */ - ccs_update_blanking(sensor); - - dev_dbg(&client->dev, "vblank\t\t%d\n", sensor->vblank->val); - dev_dbg(&client->dev, "hblank\t\t%d\n", sensor->hblank->val); - - dev_dbg(&client->dev, "real timeperframe\t100/%d\n", - sensor->pll.pixel_rate_pixel_array / - ((sensor->pixel_array->crop[CCS_PA_PAD_SRC].width - + sensor->hblank->val) * - (sensor->pixel_array->crop[CCS_PA_PAD_SRC].height - + sensor->vblank->val) / 100)); - - return 0; -} - -/* - * - * SMIA++ NVM handling - * - */ - -static int ccs_read_nvm_page(struct ccs_sensor *sensor, u32 p, u8 *nvm, - u8 *status) -{ - unsigned int i; - int rval; - u32 s; - - *status = 0; - - rval = ccs_write(sensor, DATA_TRANSFER_IF_1_PAGE_SELECT, p); - if (rval) - return rval; - - rval = ccs_write(sensor, DATA_TRANSFER_IF_1_CTRL, - CCS_DATA_TRANSFER_IF_1_CTRL_ENABLE); - if (rval) - return rval; - - rval = ccs_read(sensor, DATA_TRANSFER_IF_1_STATUS, &s); - if (rval) - return rval; - - if (s & CCS_DATA_TRANSFER_IF_1_STATUS_IMPROPER_IF_USAGE) { - *status = s; - return -ENODATA; - } - - if (CCS_LIM(sensor, DATA_TRANSFER_IF_CAPABILITY) & - CCS_DATA_TRANSFER_IF_CAPABILITY_POLLING) { - for (i = 1000; i > 0; i--) { - if (s & CCS_DATA_TRANSFER_IF_1_STATUS_READ_IF_READY) - break; - - rval = ccs_read(sensor, DATA_TRANSFER_IF_1_STATUS, &s); - if (rval) - return rval; - } - - if (!i) - return -ETIMEDOUT; - } - - for (i = 0; i <= CCS_LIM_DATA_TRANSFER_IF_1_DATA_MAX_P; i++) { - u32 v; - - rval = ccs_read(sensor, DATA_TRANSFER_IF_1_DATA(i), &v); - if (rval) - return rval; - - *nvm++ = v; - } - - return 0; -} - -static int ccs_read_nvm(struct ccs_sensor *sensor, unsigned char *nvm, - size_t nvm_size) -{ - u8 status = 0; - u32 p; - int rval = 0, rval2; - - for (p = 0; p < nvm_size / (CCS_LIM_DATA_TRANSFER_IF_1_DATA_MAX_P + 1) - && !rval; p++) { - rval = ccs_read_nvm_page(sensor, p, nvm, &status); - nvm += CCS_LIM_DATA_TRANSFER_IF_1_DATA_MAX_P + 1; - } - - if (rval == -ENODATA && - status & CCS_DATA_TRANSFER_IF_1_STATUS_IMPROPER_IF_USAGE) - rval = 0; - - rval2 = ccs_write(sensor, DATA_TRANSFER_IF_1_CTRL, 0); - if (rval < 0) - return rval; - else - return rval2 ?: p * (CCS_LIM_DATA_TRANSFER_IF_1_DATA_MAX_P + 1); -} - -/* - * - * SMIA++ CCI address control - * - */ -static int ccs_change_cci_addr(struct ccs_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - int rval; - u32 val; - - client->addr = sensor->hwcfg->i2c_addr_dfl; - - rval = ccs_write(sensor, CCI_ADDRESS_CTRL, - sensor->hwcfg->i2c_addr_alt << 1); - if (rval) - return rval; - - client->addr = sensor->hwcfg->i2c_addr_alt; - - /* verify addr change went ok */ - rval = ccs_read(sensor, CCI_ADDRESS_CTRL, &val); - if (rval) - return rval; - - if (val != sensor->hwcfg->i2c_addr_alt << 1) - return -ENODEV; - - return 0; -} - -/* - * - * SMIA++ Mode Control - * - */ -static int ccs_setup_flash_strobe(struct ccs_sensor *sensor) -{ - struct ccs_flash_strobe_parms *strobe_setup; - unsigned int ext_freq = sensor->hwcfg->ext_clk; - u32 tmp; - u32 strobe_adjustment; - u32 strobe_width_high_rs; - int rval; - - strobe_setup = sensor->hwcfg->strobe_setup; - - /* - * How to calculate registers related to strobe length. Please - * do not change, or if you do at least know what you're - * doing. :-) - * - * Sakari Ailus 2010-10-25 - * - * flash_strobe_length [us] / 10^6 = (tFlash_strobe_width_ctrl - * / EXTCLK freq [Hz]) * flash_strobe_adjustment - * - * tFlash_strobe_width_ctrl E N, [1 - 0xffff] - * flash_strobe_adjustment E N, [1 - 0xff] - * - * The formula above is written as below to keep it on one - * line: - * - * l / 10^6 = w / e * a - * - * Let's mark w * a by x: - * - * x = w * a - * - * Thus, we get: - * - * x = l * e / 10^6 - * - * The strobe width must be at least as long as requested, - * thus rounding upwards is needed. - * - * x = (l * e + 10^6 - 1) / 10^6 - * ----------------------------- - * - * Maximum possible accuracy is wanted at all times. Thus keep - * a as small as possible. - * - * Calculate a, assuming maximum w, with rounding upwards: - * - * a = (x + (2^16 - 1) - 1) / (2^16 - 1) - * ------------------------------------- - * - * Thus, we also get w, with that a, with rounding upwards: - * - * w = (x + a - 1) / a - * ------------------- - * - * To get limits: - * - * x E [1, (2^16 - 1) * (2^8 - 1)] - * - * Substituting maximum x to the original formula (with rounding), - * the maximum l is thus - * - * (2^16 - 1) * (2^8 - 1) * 10^6 = l * e + 10^6 - 1 - * - * l = (10^6 * (2^16 - 1) * (2^8 - 1) - 10^6 + 1) / e - * -------------------------------------------------- - * - * flash_strobe_length must be clamped between 1 and - * (10^6 * (2^16 - 1) * (2^8 - 1) - 10^6 + 1) / EXTCLK freq. - * - * Then, - * - * flash_strobe_adjustment = ((flash_strobe_length * - * EXTCLK freq + 10^6 - 1) / 10^6 + (2^16 - 1) - 1) / (2^16 - 1) - * - * tFlash_strobe_width_ctrl = ((flash_strobe_length * - * EXTCLK freq + 10^6 - 1) / 10^6 + - * flash_strobe_adjustment - 1) / flash_strobe_adjustment - */ - tmp = div_u64(1000000ULL * ((1 << 16) - 1) * ((1 << 8) - 1) - - 1000000 + 1, ext_freq); - strobe_setup->strobe_width_high_us = - clamp_t(u32, strobe_setup->strobe_width_high_us, 1, tmp); - - tmp = div_u64(((u64)strobe_setup->strobe_width_high_us * (u64)ext_freq + - 1000000 - 1), 1000000ULL); - strobe_adjustment = (tmp + (1 << 16) - 1 - 1) / ((1 << 16) - 1); - strobe_width_high_rs = (tmp + strobe_adjustment - 1) / - strobe_adjustment; - - rval = ccs_write(sensor, FLASH_MODE_RS, strobe_setup->mode); - if (rval < 0) - goto out; - - rval = ccs_write(sensor, FLASH_STROBE_ADJUSTMENT, strobe_adjustment); - if (rval < 0) - goto out; - - rval = ccs_write(sensor, TFLASH_STROBE_WIDTH_HIGH_RS_CTRL, - strobe_width_high_rs); - if (rval < 0) - goto out; - - rval = ccs_write(sensor, TFLASH_STROBE_DELAY_RS_CTRL, - strobe_setup->strobe_delay); - if (rval < 0) - goto out; - - rval = ccs_write(sensor, FLASH_STROBE_START_POINT, - strobe_setup->stobe_start_point); - if (rval < 0) - goto out; - - rval = ccs_write(sensor, FLASH_TRIGGER_RS, strobe_setup->trigger); - -out: - sensor->hwcfg->strobe_setup->trigger = 0; - - return rval; -} - -/* ----------------------------------------------------------------------------- - * Power management - */ - -static int ccs_power_on(struct device *dev) -{ - struct v4l2_subdev *subdev = dev_get_drvdata(dev); - struct ccs_subdev *ssd = to_ccs_subdev(subdev); - /* - * The sub-device related to the I2C device is always the - * source one, i.e. ssds[0]. - */ - struct ccs_sensor *sensor = - container_of(ssd, struct ccs_sensor, ssds[0]); - unsigned int sleep; - int rval; - - rval = regulator_enable(sensor->vana); - if (rval) { - dev_err(dev, "failed to enable vana regulator\n"); - return rval; - } - usleep_range(1000, 1000); - - rval = clk_prepare_enable(sensor->ext_clk); - if (rval < 0) { - dev_dbg(dev, "failed to enable xclk\n"); - goto out_xclk_fail; - } - usleep_range(1000, 1000); - - gpiod_set_value(sensor->xshutdown, 1); - - sleep = SMIAPP_RESET_DELAY(sensor->hwcfg->ext_clk); - usleep_range(sleep, sleep); - - /* - * Failures to respond to the address change command have been noticed. - * Those failures seem to be caused by the sensor requiring a longer - * boot time than advertised. An additional 10ms delay seems to work - * around the issue, but the SMIA++ I2C write retry hack makes the delay - * unnecessary. The failures need to be investigated to find a proper - * fix, and a delay will likely need to be added here if the I2C write - * retry hack is reverted before the root cause of the boot time issue - * is found. - */ - - if (sensor->hwcfg->i2c_addr_alt) { - rval = ccs_change_cci_addr(sensor); - if (rval) { - dev_err(dev, "cci address change error\n"); - goto out_cci_addr_fail; - } - } - - rval = ccs_write(sensor, SOFTWARE_RESET, CCS_SOFTWARE_RESET_ON); - if (rval < 0) { - dev_err(dev, "software reset failed\n"); - goto out_cci_addr_fail; - } - - if (sensor->hwcfg->i2c_addr_alt) { - rval = ccs_change_cci_addr(sensor); - if (rval) { - dev_err(dev, "cci address change error\n"); - goto out_cci_addr_fail; - } - } - - rval = ccs_write(sensor, COMPRESSION_MODE, - CCS_COMPRESSION_MODE_DPCM_PCM_SIMPLE); - if (rval) { - dev_err(dev, "compression mode set failed\n"); - goto out_cci_addr_fail; - } - - rval = ccs_write(sensor, EXTCLK_FREQUENCY_MHZ, - sensor->hwcfg->ext_clk / (1000000 / (1 << 8))); - if (rval) { - dev_err(dev, "extclk frequency set failed\n"); - goto out_cci_addr_fail; - } - - rval = ccs_write(sensor, CSI_LANE_MODE, sensor->hwcfg->lanes - 1); - if (rval) { - dev_err(dev, "csi lane mode set failed\n"); - goto out_cci_addr_fail; - } - - rval = ccs_write(sensor, FAST_STANDBY_CTRL, - CCS_FAST_STANDBY_CTRL_FRAME_TRUNCATION); - if (rval) { - dev_err(dev, "fast standby set failed\n"); - goto out_cci_addr_fail; - } - - rval = ccs_write(sensor, CSI_SIGNALING_MODE, - sensor->hwcfg->csi_signalling_mode); - if (rval) { - dev_err(dev, "csi signalling mode set failed\n"); - goto out_cci_addr_fail; - } - - /* DPHY control done by sensor based on requested link rate */ - rval = ccs_write(sensor, PHY_CTRL, CCS_PHY_CTRL_UI); - if (rval < 0) - goto out_cci_addr_fail; - - rval = ccs_call_quirk(sensor, post_poweron); - if (rval) { - dev_err(dev, "post_poweron quirks failed\n"); - goto out_cci_addr_fail; - } - - return 0; - -out_cci_addr_fail: - gpiod_set_value(sensor->xshutdown, 0); - clk_disable_unprepare(sensor->ext_clk); - -out_xclk_fail: - regulator_disable(sensor->vana); - - return rval; -} - -static int ccs_power_off(struct device *dev) -{ - struct v4l2_subdev *subdev = dev_get_drvdata(dev); - struct ccs_subdev *ssd = to_ccs_subdev(subdev); - struct ccs_sensor *sensor = - container_of(ssd, struct ccs_sensor, ssds[0]); - - /* - * Currently power/clock to lens are enable/disabled separately - * but they are essentially the same signals. So if the sensor is - * powered off while the lens is powered on the sensor does not - * really see a power off and next time the cci address change - * will fail. So do a soft reset explicitly here. - */ - if (sensor->hwcfg->i2c_addr_alt) - ccs_write(sensor, SOFTWARE_RESET, CCS_SOFTWARE_RESET_ON); - - gpiod_set_value(sensor->xshutdown, 0); - clk_disable_unprepare(sensor->ext_clk); - usleep_range(5000, 5000); - regulator_disable(sensor->vana); - sensor->streaming = false; - - return 0; -} - -/* ----------------------------------------------------------------------------- - * Video stream management - */ - -static int ccs_start_streaming(struct ccs_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - unsigned int binning_mode; - int rval; - - mutex_lock(&sensor->mutex); - - rval = ccs_write(sensor, CSI_DATA_FORMAT, - (sensor->csi_format->width << 8) | - sensor->csi_format->compressed); - if (rval) - goto out; - - /* Binning configuration */ - if (sensor->binning_horizontal == 1 && - sensor->binning_vertical == 1) { - binning_mode = 0; - } else { - u8 binning_type = - (sensor->binning_horizontal << 4) - | sensor->binning_vertical; - - rval = ccs_write(sensor, BINNING_TYPE, binning_type); - if (rval < 0) - goto out; - - binning_mode = 1; - } - rval = ccs_write(sensor, BINNING_MODE, binning_mode); - if (rval < 0) - goto out; - - /* Set up PLL */ - rval = ccs_pll_configure(sensor); - if (rval) - goto out; - - /* Analog crop start coordinates */ - rval = ccs_write(sensor, X_ADDR_START, - sensor->pixel_array->crop[CCS_PA_PAD_SRC].left); - if (rval < 0) - goto out; - - rval = ccs_write(sensor, Y_ADDR_START, - sensor->pixel_array->crop[CCS_PA_PAD_SRC].top); - if (rval < 0) - goto out; - - /* Analog crop end coordinates */ - rval = ccs_write( - sensor, X_ADDR_END, - sensor->pixel_array->crop[CCS_PA_PAD_SRC].left - + sensor->pixel_array->crop[CCS_PA_PAD_SRC].width - 1); - if (rval < 0) - goto out; - - rval = ccs_write( - sensor, Y_ADDR_END, - sensor->pixel_array->crop[CCS_PA_PAD_SRC].top - + sensor->pixel_array->crop[CCS_PA_PAD_SRC].height - 1); - if (rval < 0) - goto out; - - /* - * Output from pixel array, including blanking, is set using - * controls below. No need to set here. - */ - - /* Digital crop */ - if (CCS_LIM(sensor, DIGITAL_CROP_CAPABILITY) - == CCS_DIGITAL_CROP_CAPABILITY_INPUT_CROP) { - rval = ccs_write( - sensor, DIGITAL_CROP_X_OFFSET, - sensor->scaler->crop[CCS_PAD_SINK].left); - if (rval < 0) - goto out; - - rval = ccs_write( - sensor, DIGITAL_CROP_Y_OFFSET, - sensor->scaler->crop[CCS_PAD_SINK].top); - if (rval < 0) - goto out; - - rval = ccs_write( - sensor, DIGITAL_CROP_IMAGE_WIDTH, - sensor->scaler->crop[CCS_PAD_SINK].width); - if (rval < 0) - goto out; - - rval = ccs_write( - sensor, DIGITAL_CROP_IMAGE_HEIGHT, - sensor->scaler->crop[CCS_PAD_SINK].height); - if (rval < 0) - goto out; - } - - /* Scaling */ - if (CCS_LIM(sensor, SCALING_CAPABILITY) - != CCS_SCALING_CAPABILITY_NONE) { - rval = ccs_write(sensor, SCALING_MODE, sensor->scaling_mode); - if (rval < 0) - goto out; - - rval = ccs_write(sensor, SCALE_M, sensor->scale_m); - if (rval < 0) - goto out; - } - - /* Output size from sensor */ - rval = ccs_write(sensor, X_OUTPUT_SIZE, - sensor->src->crop[CCS_PAD_SRC].width); - if (rval < 0) - goto out; - rval = ccs_write(sensor, Y_OUTPUT_SIZE, - sensor->src->crop[CCS_PAD_SRC].height); - if (rval < 0) - goto out; - - if (CCS_LIM(sensor, FLASH_MODE_CAPABILITY) & - (CCS_FLASH_MODE_CAPABILITY_SINGLE_STROBE | - SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE) && - sensor->hwcfg->strobe_setup != NULL && - sensor->hwcfg->strobe_setup->trigger != 0) { - rval = ccs_setup_flash_strobe(sensor); - if (rval) - goto out; - } - - rval = ccs_call_quirk(sensor, pre_streamon); - if (rval) { - dev_err(&client->dev, "pre_streamon quirks failed\n"); - goto out; - } - - rval = ccs_write(sensor, MODE_SELECT, CCS_MODE_SELECT_STREAMING); - -out: - mutex_unlock(&sensor->mutex); - - return rval; -} - -static int ccs_stop_streaming(struct ccs_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - int rval; - - mutex_lock(&sensor->mutex); - rval = ccs_write(sensor, MODE_SELECT, CCS_MODE_SELECT_SOFTWARE_STANDBY); - if (rval) - goto out; - - rval = ccs_call_quirk(sensor, post_streamoff); - if (rval) - dev_err(&client->dev, "post_streamoff quirks failed\n"); - -out: - mutex_unlock(&sensor->mutex); - return rval; -} - -/* ----------------------------------------------------------------------------- - * V4L2 subdev video operations - */ - -static int ccs_pm_get_init(struct ccs_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - int rval; - - rval = pm_runtime_get_sync(&client->dev); - if (rval < 0) { - if (rval != -EBUSY && rval != -EAGAIN) - pm_runtime_set_active(&client->dev); - pm_runtime_put_noidle(&client->dev); - - return rval; - } else if (!rval) { - rval = v4l2_ctrl_handler_setup(&sensor->pixel_array-> - ctrl_handler); - if (rval) - return rval; - - return v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler); - } - - return 0; -} - -static int ccs_set_stream(struct v4l2_subdev *subdev, int enable) -{ - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - int rval; - - if (sensor->streaming == enable) - return 0; - - if (!enable) { - ccs_stop_streaming(sensor); - sensor->streaming = false; - pm_runtime_mark_last_busy(&client->dev); - pm_runtime_put_autosuspend(&client->dev); - - return 0; - } - - rval = ccs_pm_get_init(sensor); - if (rval) - return rval; - - sensor->streaming = true; - - rval = ccs_start_streaming(sensor); - if (rval < 0) { - sensor->streaming = false; - pm_runtime_mark_last_busy(&client->dev); - pm_runtime_put_autosuspend(&client->dev); - } - - return rval; -} - -static int ccs_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - struct i2c_client *client = v4l2_get_subdevdata(subdev); - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - unsigned int i; - int idx = -1; - int rval = -EINVAL; - - mutex_lock(&sensor->mutex); - - dev_err(&client->dev, "subdev %s, pad %d, index %d\n", - subdev->name, code->pad, code->index); - - if (subdev != &sensor->src->sd || code->pad != CCS_PAD_SRC) { - if (code->index) - goto out; - - code->code = sensor->internal_csi_format->code; - rval = 0; - goto out; - } - - for (i = 0; i < ARRAY_SIZE(ccs_csi_data_formats); i++) { - if (sensor->mbus_frame_fmts & (1 << i)) - idx++; - - if (idx == code->index) { - code->code = ccs_csi_data_formats[i].code; - dev_err(&client->dev, "found index %d, i %d, code %x\n", - code->index, i, code->code); - rval = 0; - break; - } - } - -out: - mutex_unlock(&sensor->mutex); - - return rval; -} - -static u32 __ccs_get_mbus_code(struct v4l2_subdev *subdev, unsigned int pad) -{ - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - - if (subdev == &sensor->src->sd && pad == CCS_PAD_SRC) - return sensor->csi_format->code; - else - return sensor->internal_csi_format->code; -} - -static int __ccs_get_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct ccs_subdev *ssd = to_ccs_subdev(subdev); - - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - fmt->format = *v4l2_subdev_get_try_format(subdev, cfg, - fmt->pad); - } else { - struct v4l2_rect *r; - - if (fmt->pad == ssd->source_pad) - r = &ssd->crop[ssd->source_pad]; - else - r = &ssd->sink_fmt; - - fmt->format.code = __ccs_get_mbus_code(subdev, fmt->pad); - fmt->format.width = r->width; - fmt->format.height = r->height; - fmt->format.field = V4L2_FIELD_NONE; - } - - return 0; -} - -static int ccs_get_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - int rval; - - mutex_lock(&sensor->mutex); - rval = __ccs_get_format(subdev, cfg, fmt); - mutex_unlock(&sensor->mutex); - - return rval; -} - -static void ccs_get_crop_compose(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_rect **crops, - struct v4l2_rect **comps, int which) -{ - struct ccs_subdev *ssd = to_ccs_subdev(subdev); - unsigned int i; - - if (which == V4L2_SUBDEV_FORMAT_ACTIVE) { - if (crops) - for (i = 0; i < subdev->entity.num_pads; i++) - crops[i] = &ssd->crop[i]; - if (comps) - *comps = &ssd->compose; - } else { - if (crops) { - for (i = 0; i < subdev->entity.num_pads; i++) { - crops[i] = v4l2_subdev_get_try_crop(subdev, cfg, i); - BUG_ON(!crops[i]); - } - } - if (comps) { - *comps = v4l2_subdev_get_try_compose(subdev, cfg, - CCS_PAD_SINK); - BUG_ON(!*comps); - } - } -} - -/* Changes require propagation only on sink pad. */ -static void ccs_propagate(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, int which, - int target) -{ - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - struct ccs_subdev *ssd = to_ccs_subdev(subdev); - struct v4l2_rect *comp, *crops[CCS_PADS]; - - ccs_get_crop_compose(subdev, cfg, crops, &comp, which); - - switch (target) { - case V4L2_SEL_TGT_CROP: - comp->width = crops[CCS_PAD_SINK]->width; - comp->height = crops[CCS_PAD_SINK]->height; - if (which == V4L2_SUBDEV_FORMAT_ACTIVE) { - if (ssd == sensor->scaler) { - sensor->scale_m = - CCS_LIM(sensor, SCALER_N_MIN); - sensor->scaling_mode = - CCS_SCALING_MODE_NO_SCALING; - } else if (ssd == sensor->binner) { - sensor->binning_horizontal = 1; - sensor->binning_vertical = 1; - } - } - fallthrough; - case V4L2_SEL_TGT_COMPOSE: - *crops[CCS_PAD_SRC] = *comp; - break; - default: - BUG(); - } -} - -static const struct ccs_csi_data_format -*ccs_validate_csi_data_format(struct ccs_sensor *sensor, u32 code) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(ccs_csi_data_formats); i++) { - if (sensor->mbus_frame_fmts & (1 << i) && - ccs_csi_data_formats[i].code == code) - return &ccs_csi_data_formats[i]; - } - - return sensor->csi_format; -} - -static int ccs_set_format_source(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - const struct ccs_csi_data_format *csi_format, - *old_csi_format = sensor->csi_format; - unsigned long *valid_link_freqs; - u32 code = fmt->format.code; - unsigned int i; - int rval; - - rval = __ccs_get_format(subdev, cfg, fmt); - if (rval) - return rval; - - /* - * Media bus code is changeable on src subdev's source pad. On - * other source pads we just get format here. - */ - if (subdev != &sensor->src->sd) - return 0; - - csi_format = ccs_validate_csi_data_format(sensor, code); - - fmt->format.code = csi_format->code; - - if (fmt->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return 0; - - sensor->csi_format = csi_format; - - if (csi_format->width != old_csi_format->width) - for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) - __v4l2_ctrl_modify_range( - sensor->test_data[i], 0, - (1 << csi_format->width) - 1, 1, 0); - - if (csi_format->compressed == old_csi_format->compressed) - return 0; - - valid_link_freqs = - &sensor->valid_link_freqs[sensor->csi_format->compressed - - sensor->compressed_min_bpp]; - - __v4l2_ctrl_modify_range( - sensor->link_freq, 0, - __fls(*valid_link_freqs), ~*valid_link_freqs, - __ffs(*valid_link_freqs)); - - return ccs_pll_update(sensor); -} - -static int ccs_set_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - struct ccs_subdev *ssd = to_ccs_subdev(subdev); - struct v4l2_rect *crops[CCS_PADS]; - - mutex_lock(&sensor->mutex); - - if (fmt->pad == ssd->source_pad) { - int rval; - - rval = ccs_set_format_source(subdev, cfg, fmt); - - mutex_unlock(&sensor->mutex); - - return rval; - } - - /* Sink pad. Width and height are changeable here. */ - fmt->format.code = __ccs_get_mbus_code(subdev, fmt->pad); - fmt->format.width &= ~1; - fmt->format.height &= ~1; - fmt->format.field = V4L2_FIELD_NONE; - - fmt->format.width = - clamp(fmt->format.width, - CCS_LIM(sensor, MIN_X_OUTPUT_SIZE), - CCS_LIM(sensor, MAX_X_OUTPUT_SIZE)); - fmt->format.height = - clamp(fmt->format.height, - CCS_LIM(sensor, MIN_Y_OUTPUT_SIZE), - CCS_LIM(sensor, MAX_Y_OUTPUT_SIZE)); - - ccs_get_crop_compose(subdev, cfg, crops, NULL, fmt->which); - - crops[ssd->sink_pad]->left = 0; - crops[ssd->sink_pad]->top = 0; - crops[ssd->sink_pad]->width = fmt->format.width; - crops[ssd->sink_pad]->height = fmt->format.height; - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) - ssd->sink_fmt = *crops[ssd->sink_pad]; - ccs_propagate(subdev, cfg, fmt->which, V4L2_SEL_TGT_CROP); - - mutex_unlock(&sensor->mutex); - - return 0; -} - -/* - * Calculate goodness of scaled image size compared to expected image - * size and flags provided. - */ -#define SCALING_GOODNESS 100000 -#define SCALING_GOODNESS_EXTREME 100000000 -static int scaling_goodness(struct v4l2_subdev *subdev, int w, int ask_w, - int h, int ask_h, u32 flags) -{ - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - struct i2c_client *client = v4l2_get_subdevdata(subdev); - int val = 0; - - w &= ~1; - ask_w &= ~1; - h &= ~1; - ask_h &= ~1; - - if (flags & V4L2_SEL_FLAG_GE) { - if (w < ask_w) - val -= SCALING_GOODNESS; - if (h < ask_h) - val -= SCALING_GOODNESS; - } - - if (flags & V4L2_SEL_FLAG_LE) { - if (w > ask_w) - val -= SCALING_GOODNESS; - if (h > ask_h) - val -= SCALING_GOODNESS; - } - - val -= abs(w - ask_w); - val -= abs(h - ask_h); - - if (w < CCS_LIM(sensor, MIN_X_OUTPUT_SIZE)) - val -= SCALING_GOODNESS_EXTREME; - - dev_dbg(&client->dev, "w %d ask_w %d h %d ask_h %d goodness %d\n", - w, ask_w, h, ask_h, val); - - return val; -} - -static void ccs_set_compose_binner(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel, - struct v4l2_rect **crops, - struct v4l2_rect *comp) -{ - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - unsigned int i; - unsigned int binh = 1, binv = 1; - int best = scaling_goodness( - subdev, - crops[CCS_PAD_SINK]->width, sel->r.width, - crops[CCS_PAD_SINK]->height, sel->r.height, sel->flags); - - for (i = 0; i < sensor->nbinning_subtypes; i++) { - int this = scaling_goodness( - subdev, - crops[CCS_PAD_SINK]->width - / sensor->binning_subtypes[i].horizontal, - sel->r.width, - crops[CCS_PAD_SINK]->height - / sensor->binning_subtypes[i].vertical, - sel->r.height, sel->flags); - - if (this > best) { - binh = sensor->binning_subtypes[i].horizontal; - binv = sensor->binning_subtypes[i].vertical; - best = this; - } - } - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - sensor->binning_vertical = binv; - sensor->binning_horizontal = binh; - } - - sel->r.width = (crops[CCS_PAD_SINK]->width / binh) & ~1; - sel->r.height = (crops[CCS_PAD_SINK]->height / binv) & ~1; -} - -/* - * Calculate best scaling ratio and mode for given output resolution. - * - * Try all of these: horizontal ratio, vertical ratio and smallest - * size possible (horizontally). - * - * Also try whether horizontal scaler or full scaler gives a better - * result. - */ -static void ccs_set_compose_scaler(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel, - struct v4l2_rect **crops, - struct v4l2_rect *comp) -{ - struct i2c_client *client = v4l2_get_subdevdata(subdev); - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - u32 min, max, a, b, max_m; - u32 scale_m = CCS_LIM(sensor, SCALER_N_MIN); - int mode = CCS_SCALING_MODE_HORIZONTAL; - u32 try[4]; - u32 ntry = 0; - unsigned int i; - int best = INT_MIN; - - sel->r.width = min_t(unsigned int, sel->r.width, - crops[CCS_PAD_SINK]->width); - sel->r.height = min_t(unsigned int, sel->r.height, - crops[CCS_PAD_SINK]->height); - - a = crops[CCS_PAD_SINK]->width - * CCS_LIM(sensor, SCALER_N_MIN) / sel->r.width; - b = crops[CCS_PAD_SINK]->height - * CCS_LIM(sensor, SCALER_N_MIN) / sel->r.height; - max_m = crops[CCS_PAD_SINK]->width - * CCS_LIM(sensor, SCALER_N_MIN) - / CCS_LIM(sensor, MIN_X_OUTPUT_SIZE); - - a = clamp(a, CCS_LIM(sensor, SCALER_M_MIN), - CCS_LIM(sensor, SCALER_M_MAX)); - b = clamp(b, CCS_LIM(sensor, SCALER_M_MIN), - CCS_LIM(sensor, SCALER_M_MAX)); - max_m = clamp(max_m, CCS_LIM(sensor, SCALER_M_MIN), - CCS_LIM(sensor, SCALER_M_MAX)); - - dev_dbg(&client->dev, "scaling: a %d b %d max_m %d\n", a, b, max_m); - - min = min(max_m, min(a, b)); - max = min(max_m, max(a, b)); - - try[ntry] = min; - ntry++; - if (min != max) { - try[ntry] = max; - ntry++; - } - if (max != max_m) { - try[ntry] = min + 1; - ntry++; - if (min != max) { - try[ntry] = max + 1; - ntry++; - } - } - - for (i = 0; i < ntry; i++) { - int this = scaling_goodness( - subdev, - crops[CCS_PAD_SINK]->width - / try[i] * CCS_LIM(sensor, SCALER_N_MIN), - sel->r.width, - crops[CCS_PAD_SINK]->height, - sel->r.height, - sel->flags); - - dev_dbg(&client->dev, "trying factor %d (%d)\n", try[i], i); - - if (this > best) { - scale_m = try[i]; - mode = CCS_SCALING_MODE_HORIZONTAL; - best = this; - } - - if (CCS_LIM(sensor, SCALING_CAPABILITY) - == CCS_SCALING_CAPABILITY_HORIZONTAL) - continue; - - this = scaling_goodness( - subdev, crops[CCS_PAD_SINK]->width - / try[i] - * CCS_LIM(sensor, SCALER_N_MIN), - sel->r.width, - crops[CCS_PAD_SINK]->height - / try[i] - * CCS_LIM(sensor, SCALER_N_MIN), - sel->r.height, - sel->flags); - - if (this > best) { - scale_m = try[i]; - mode = SMIAPP_SCALING_MODE_BOTH; - best = this; - } - } - - sel->r.width = - (crops[CCS_PAD_SINK]->width - / scale_m - * CCS_LIM(sensor, SCALER_N_MIN)) & ~1; - if (mode == SMIAPP_SCALING_MODE_BOTH) - sel->r.height = - (crops[CCS_PAD_SINK]->height - / scale_m - * CCS_LIM(sensor, SCALER_N_MIN)) - & ~1; - else - sel->r.height = crops[CCS_PAD_SINK]->height; - - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - sensor->scale_m = scale_m; - sensor->scaling_mode = mode; - } -} -/* We're only called on source pads. This function sets scaling. */ -static int ccs_set_compose(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - struct ccs_subdev *ssd = to_ccs_subdev(subdev); - struct v4l2_rect *comp, *crops[CCS_PADS]; - - ccs_get_crop_compose(subdev, cfg, crops, &comp, sel->which); - - sel->r.top = 0; - sel->r.left = 0; - - if (ssd == sensor->binner) - ccs_set_compose_binner(subdev, cfg, sel, crops, comp); - else - ccs_set_compose_scaler(subdev, cfg, sel, crops, comp); - - *comp = sel->r; - ccs_propagate(subdev, cfg, sel->which, V4L2_SEL_TGT_COMPOSE); - - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) - return ccs_pll_blanking_update(sensor); - - return 0; -} - -static int __ccs_sel_supported(struct v4l2_subdev *subdev, - struct v4l2_subdev_selection *sel) -{ - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - struct ccs_subdev *ssd = to_ccs_subdev(subdev); - - /* We only implement crop in three places. */ - switch (sel->target) { - case V4L2_SEL_TGT_CROP: - case V4L2_SEL_TGT_CROP_BOUNDS: - if (ssd == sensor->pixel_array && sel->pad == CCS_PA_PAD_SRC) - return 0; - if (ssd == sensor->src && sel->pad == CCS_PAD_SRC) - return 0; - if (ssd == sensor->scaler && sel->pad == CCS_PAD_SINK && - CCS_LIM(sensor, DIGITAL_CROP_CAPABILITY) - == CCS_DIGITAL_CROP_CAPABILITY_INPUT_CROP) - return 0; - return -EINVAL; - case V4L2_SEL_TGT_NATIVE_SIZE: - if (ssd == sensor->pixel_array && sel->pad == CCS_PA_PAD_SRC) - return 0; - return -EINVAL; - case V4L2_SEL_TGT_COMPOSE: - case V4L2_SEL_TGT_COMPOSE_BOUNDS: - if (sel->pad == ssd->source_pad) - return -EINVAL; - if (ssd == sensor->binner) - return 0; - if (ssd == sensor->scaler && CCS_LIM(sensor, SCALING_CAPABILITY) - != CCS_SCALING_CAPABILITY_NONE) - return 0; - fallthrough; - default: - return -EINVAL; - } -} - -static int ccs_set_crop(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - struct ccs_subdev *ssd = to_ccs_subdev(subdev); - struct v4l2_rect *src_size, *crops[CCS_PADS]; - struct v4l2_rect _r; - - ccs_get_crop_compose(subdev, cfg, crops, NULL, sel->which); - - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - if (sel->pad == ssd->sink_pad) - src_size = &ssd->sink_fmt; - else - src_size = &ssd->compose; - } else { - if (sel->pad == ssd->sink_pad) { - _r.left = 0; - _r.top = 0; - _r.width = v4l2_subdev_get_try_format(subdev, cfg, sel->pad) - ->width; - _r.height = v4l2_subdev_get_try_format(subdev, cfg, sel->pad) - ->height; - src_size = &_r; - } else { - src_size = v4l2_subdev_get_try_compose( - subdev, cfg, ssd->sink_pad); - } - } - - if (ssd == sensor->src && sel->pad == CCS_PAD_SRC) { - sel->r.left = 0; - sel->r.top = 0; - } - - sel->r.width = min(sel->r.width, src_size->width); - sel->r.height = min(sel->r.height, src_size->height); - - sel->r.left = min_t(int, sel->r.left, src_size->width - sel->r.width); - sel->r.top = min_t(int, sel->r.top, src_size->height - sel->r.height); - - *crops[sel->pad] = sel->r; - - if (ssd != sensor->pixel_array && sel->pad == CCS_PAD_SINK) - ccs_propagate(subdev, cfg, sel->which, V4L2_SEL_TGT_CROP); - - return 0; -} - -static void ccs_get_native_size(struct ccs_subdev *ssd, struct v4l2_rect *r) -{ - r->top = 0; - r->left = 0; - r->width = CCS_LIM(ssd->sensor, X_ADDR_MAX) + 1; - r->height = CCS_LIM(ssd->sensor, Y_ADDR_MAX) + 1; -} - -static int __ccs_get_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - struct ccs_subdev *ssd = to_ccs_subdev(subdev); - struct v4l2_rect *comp, *crops[CCS_PADS]; - struct v4l2_rect sink_fmt; - int ret; - - ret = __ccs_sel_supported(subdev, sel); - if (ret) - return ret; - - ccs_get_crop_compose(subdev, cfg, crops, &comp, sel->which); - - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - sink_fmt = ssd->sink_fmt; - } else { - struct v4l2_mbus_framefmt *fmt = - v4l2_subdev_get_try_format(subdev, cfg, ssd->sink_pad); - - sink_fmt.left = 0; - sink_fmt.top = 0; - sink_fmt.width = fmt->width; - sink_fmt.height = fmt->height; - } - - switch (sel->target) { - case V4L2_SEL_TGT_CROP_BOUNDS: - case V4L2_SEL_TGT_NATIVE_SIZE: - if (ssd == sensor->pixel_array) - ccs_get_native_size(ssd, &sel->r); - else if (sel->pad == ssd->sink_pad) - sel->r = sink_fmt; - else - sel->r = *comp; - break; - case V4L2_SEL_TGT_CROP: - case V4L2_SEL_TGT_COMPOSE_BOUNDS: - sel->r = *crops[sel->pad]; - break; - case V4L2_SEL_TGT_COMPOSE: - sel->r = *comp; - break; - } - - return 0; -} - -static int ccs_get_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - int rval; - - mutex_lock(&sensor->mutex); - rval = __ccs_get_selection(subdev, cfg, sel); - mutex_unlock(&sensor->mutex); - - return rval; -} - -static int ccs_set_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - int ret; - - ret = __ccs_sel_supported(subdev, sel); - if (ret) - return ret; - - mutex_lock(&sensor->mutex); - - sel->r.left = max(0, sel->r.left & ~1); - sel->r.top = max(0, sel->r.top & ~1); - sel->r.width = CCS_ALIGN_DIM(sel->r.width, sel->flags); - sel->r.height = CCS_ALIGN_DIM(sel->r.height, sel->flags); - - sel->r.width = max_t(unsigned int, - CCS_LIM(sensor, MIN_X_OUTPUT_SIZE), - sel->r.width); - sel->r.height = max_t(unsigned int, - CCS_LIM(sensor, MIN_Y_OUTPUT_SIZE), - sel->r.height); - - switch (sel->target) { - case V4L2_SEL_TGT_CROP: - ret = ccs_set_crop(subdev, cfg, sel); - break; - case V4L2_SEL_TGT_COMPOSE: - ret = ccs_set_compose(subdev, cfg, sel); - break; - default: - ret = -EINVAL; - } - - mutex_unlock(&sensor->mutex); - return ret; -} - -static int ccs_get_skip_frames(struct v4l2_subdev *subdev, u32 *frames) -{ - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - - *frames = sensor->frame_skip; - return 0; -} - -static int ccs_get_skip_top_lines(struct v4l2_subdev *subdev, u32 *lines) -{ - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - - *lines = sensor->image_start; - - return 0; -} - -/* ----------------------------------------------------------------------------- - * sysfs attributes - */ - -static ssize_t -ccs_sysfs_nvm_read(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct v4l2_subdev *subdev = i2c_get_clientdata(to_i2c_client(dev)); - struct i2c_client *client = v4l2_get_subdevdata(subdev); - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - int rval; - - if (!sensor->dev_init_done) - return -EBUSY; - - rval = ccs_pm_get_init(sensor); - if (rval < 0) - return -ENODEV; - - rval = ccs_read_nvm(sensor, buf, PAGE_SIZE); - if (rval < 0) { - pm_runtime_put(&client->dev); - dev_err(&client->dev, "nvm read failed\n"); - return -ENODEV; - } - - pm_runtime_mark_last_busy(&client->dev); - pm_runtime_put_autosuspend(&client->dev); - - /* - * NVM is still way below a PAGE_SIZE, so we can safely - * assume this for now. - */ - return rval; -} -static DEVICE_ATTR(nvm, S_IRUGO, ccs_sysfs_nvm_read, NULL); - -static ssize_t -ccs_sysfs_ident_read(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct v4l2_subdev *subdev = i2c_get_clientdata(to_i2c_client(dev)); - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - struct ccs_module_info *minfo = &sensor->minfo; - - if (minfo->mipi_manufacturer_id) - return snprintf(buf, PAGE_SIZE, "%4.4x%4.4x%2.2x\n", - minfo->mipi_manufacturer_id, minfo->model_id, - minfo->revision_number_major) + 1; - else - return snprintf(buf, PAGE_SIZE, "%2.2x%4.4x%2.2x\n", - minfo->smia_manufacturer_id, minfo->model_id, - minfo->revision_number_major) + 1; -} - -static DEVICE_ATTR(ident, S_IRUGO, ccs_sysfs_ident_read, NULL); - -/* ----------------------------------------------------------------------------- - * V4L2 subdev core operations - */ - -static int ccs_identify_module(struct ccs_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - struct ccs_module_info *minfo = &sensor->minfo; - unsigned int i; - int rval = 0; - - /* Module info */ - rval = ccs_read(sensor, MODULE_MANUFACTURER_ID, - &minfo->mipi_manufacturer_id); - if (!rval && !minfo->mipi_manufacturer_id) - rval = ccs_read_addr_8only(sensor, - SMIAPP_REG_U8_MANUFACTURER_ID, - &minfo->smia_manufacturer_id); - if (!rval) - rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_MODEL_ID, - &minfo->model_id); - if (!rval) - rval = ccs_read_addr_8only(sensor, - CCS_R_MODULE_REVISION_NUMBER_MAJOR, - &minfo->revision_number_major); - if (!rval) - rval = ccs_read_addr_8only(sensor, - CCS_R_MODULE_REVISION_NUMBER_MINOR, - &minfo->revision_number_minor); - if (!rval) - rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_YEAR, - &minfo->module_year); - if (!rval) - rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_MONTH, - &minfo->module_month); - if (!rval) - rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_DAY, - &minfo->module_day); - - /* Sensor info */ - if (!rval) - rval = ccs_read(sensor, SENSOR_MANUFACTURER_ID, - &minfo->sensor_mipi_manufacturer_id); - if (!rval && !minfo->sensor_mipi_manufacturer_id) - rval = ccs_read_addr_8only(sensor, - CCS_R_SENSOR_MANUFACTURER_ID, - &minfo->sensor_smia_manufacturer_id); - if (!rval) - rval = ccs_read_addr_8only(sensor, - CCS_R_SENSOR_MODEL_ID, - &minfo->sensor_model_id); - if (!rval) - rval = ccs_read_addr_8only(sensor, - CCS_R_SENSOR_REVISION_NUMBER, - &minfo->sensor_revision_number); - if (!rval) - rval = ccs_read_addr_8only(sensor, - CCS_R_SENSOR_FIRMWARE_VERSION, - &minfo->sensor_firmware_version); - - /* SMIA */ - if (!rval) - rval = ccs_read(sensor, MIPI_CCS_VERSION, &minfo->ccs_version); - if (!rval && !minfo->ccs_version) - rval = ccs_read_addr_8only(sensor, SMIAPP_REG_U8_SMIA_VERSION, - &minfo->smia_version); - if (!rval && !minfo->ccs_version) - rval = ccs_read_addr_8only(sensor, SMIAPP_REG_U8_SMIAPP_VERSION, - &minfo->smiapp_version); - - if (rval) { - dev_err(&client->dev, "sensor detection failed\n"); - return -ENODEV; - } - - if (minfo->mipi_manufacturer_id) - dev_dbg(&client->dev, "MIPI CCS module 0x%4.4x-0x%4.4x\n", - minfo->mipi_manufacturer_id, minfo->model_id); - else - dev_dbg(&client->dev, "SMIA module 0x%2.2x-0x%4.4x\n", - minfo->smia_manufacturer_id, minfo->model_id); - - dev_dbg(&client->dev, - "module revision 0x%2.2x-0x%2.2x date %2.2d-%2.2d-%2.2d\n", - minfo->revision_number_major, minfo->revision_number_minor, - minfo->module_year, minfo->module_month, minfo->module_day); - - if (minfo->sensor_mipi_manufacturer_id) - dev_dbg(&client->dev, "MIPI CCS sensor 0x%4.4x-0x%4.4x\n", - minfo->sensor_mipi_manufacturer_id, - minfo->sensor_model_id); - else - dev_dbg(&client->dev, "SMIA sensor 0x%2.2x-0x%4.4x\n", - minfo->sensor_smia_manufacturer_id, - minfo->sensor_model_id); - - dev_dbg(&client->dev, - "sensor revision 0x%2.2x firmware version 0x%2.2x\n", - minfo->sensor_revision_number, minfo->sensor_firmware_version); - - if (minfo->ccs_version) { - dev_dbg(&client->dev, "MIPI CCS version %u.%u", - (minfo->ccs_version & CCS_MIPI_CCS_VERSION_MAJOR_MASK) - >> CCS_MIPI_CCS_VERSION_MAJOR_SHIFT, - (minfo->ccs_version & CCS_MIPI_CCS_VERSION_MINOR_MASK)); - minfo->name = CCS_NAME; - } else { - dev_dbg(&client->dev, - "smia version %2.2d smiapp version %2.2d\n", - minfo->smia_version, minfo->smiapp_version); - minfo->name = SMIAPP_NAME; - } - - /* - * Some modules have bad data in the lvalues below. Hope the - * rvalues have better stuff. The lvalues are module - * parameters whereas the rvalues are sensor parameters. - */ - if (minfo->sensor_smia_manufacturer_id && - !minfo->smia_manufacturer_id && !minfo->model_id) { - minfo->smia_manufacturer_id = - minfo->sensor_smia_manufacturer_id; - minfo->model_id = minfo->sensor_model_id; - minfo->revision_number_major = minfo->sensor_revision_number; - } - - for (i = 0; i < ARRAY_SIZE(ccs_module_idents); i++) { - if (ccs_module_idents[i].mipi_manufacturer_id && - ccs_module_idents[i].mipi_manufacturer_id - != minfo->mipi_manufacturer_id) - continue; - if (ccs_module_idents[i].smia_manufacturer_id && - ccs_module_idents[i].smia_manufacturer_id - != minfo->smia_manufacturer_id) - continue; - if (ccs_module_idents[i].model_id != minfo->model_id) - continue; - if (ccs_module_idents[i].flags - & CCS_MODULE_IDENT_FLAG_REV_LE) { - if (ccs_module_idents[i].revision_number_major - < minfo->revision_number_major) - continue; - } else { - if (ccs_module_idents[i].revision_number_major - != minfo->revision_number_major) - continue; - } - - minfo->name = ccs_module_idents[i].name; - minfo->quirk = ccs_module_idents[i].quirk; - break; - } - - if (i >= ARRAY_SIZE(ccs_module_idents)) - dev_warn(&client->dev, - "no quirks for this module; let's hope it's fully compliant\n"); - - dev_dbg(&client->dev, "the sensor is called %s\n", - minfo->name); - - return 0; -} - -static const struct v4l2_subdev_ops ccs_ops; -static const struct v4l2_subdev_internal_ops ccs_internal_ops; -static const struct media_entity_operations ccs_entity_ops; - -static int ccs_register_subdev(struct ccs_sensor *sensor, - struct ccs_subdev *ssd, - struct ccs_subdev *sink_ssd, - u16 source_pad, u16 sink_pad, u32 link_flags) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - int rval; - - if (!sink_ssd) - return 0; - - rval = media_entity_pads_init(&ssd->sd.entity, - ssd->npads, ssd->pads); - if (rval) { - dev_err(&client->dev, - "media_entity_pads_init failed\n"); - return rval; - } - - rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev, - &ssd->sd); - if (rval) { - dev_err(&client->dev, - "v4l2_device_register_subdev failed\n"); - return rval; - } - - rval = media_create_pad_link(&ssd->sd.entity, source_pad, - &sink_ssd->sd.entity, sink_pad, - link_flags); - if (rval) { - dev_err(&client->dev, - "media_create_pad_link failed\n"); - v4l2_device_unregister_subdev(&ssd->sd); - return rval; - } - - return 0; -} - -static void ccs_unregistered(struct v4l2_subdev *subdev) -{ - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - unsigned int i; - - for (i = 1; i < sensor->ssds_used; i++) - v4l2_device_unregister_subdev(&sensor->ssds[i].sd); -} - -static int ccs_registered(struct v4l2_subdev *subdev) -{ - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - int rval; - - if (sensor->scaler) { - rval = ccs_register_subdev(sensor, sensor->binner, - sensor->scaler, - CCS_PAD_SRC, CCS_PAD_SINK, - MEDIA_LNK_FL_ENABLED | - MEDIA_LNK_FL_IMMUTABLE); - if (rval < 0) - return rval; - } - - rval = ccs_register_subdev(sensor, sensor->pixel_array, sensor->binner, - CCS_PA_PAD_SRC, CCS_PAD_SINK, - MEDIA_LNK_FL_ENABLED | - MEDIA_LNK_FL_IMMUTABLE); - if (rval) - goto out_err; - - return 0; - -out_err: - ccs_unregistered(subdev); - - return rval; -} - -static void ccs_cleanup(struct ccs_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - - device_remove_file(&client->dev, &dev_attr_nvm); - device_remove_file(&client->dev, &dev_attr_ident); - - ccs_free_controls(sensor); -} - -static void ccs_create_subdev(struct ccs_sensor *sensor, - struct ccs_subdev *ssd, const char *name, - unsigned short num_pads) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - - if (!ssd) - return; - - if (ssd != sensor->src) - v4l2_subdev_init(&ssd->sd, &ccs_ops); - - ssd->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - ssd->sensor = sensor; - - ssd->npads = num_pads; - ssd->source_pad = num_pads - 1; - - v4l2_i2c_subdev_set_name(&ssd->sd, client, sensor->minfo.name, name); - - ccs_get_native_size(ssd, &ssd->sink_fmt); - - ssd->compose.width = ssd->sink_fmt.width; - ssd->compose.height = ssd->sink_fmt.height; - ssd->crop[ssd->source_pad] = ssd->compose; - ssd->pads[ssd->source_pad].flags = MEDIA_PAD_FL_SOURCE; - if (ssd != sensor->pixel_array) { - ssd->crop[ssd->sink_pad] = ssd->compose; - ssd->pads[ssd->sink_pad].flags = MEDIA_PAD_FL_SINK; - } - - ssd->sd.entity.ops = &ccs_entity_ops; - - if (ssd == sensor->src) - return; - - ssd->sd.internal_ops = &ccs_internal_ops; - ssd->sd.owner = THIS_MODULE; - ssd->sd.dev = &client->dev; - v4l2_set_subdevdata(&ssd->sd, client); -} - -static int ccs_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - struct ccs_subdev *ssd = to_ccs_subdev(sd); - struct ccs_sensor *sensor = ssd->sensor; - unsigned int i; - - mutex_lock(&sensor->mutex); - - for (i = 0; i < ssd->npads; i++) { - struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_get_try_format(sd, fh->pad, i); - struct v4l2_rect *try_crop = - v4l2_subdev_get_try_crop(sd, fh->pad, i); - struct v4l2_rect *try_comp; - - ccs_get_native_size(ssd, try_crop); - - try_fmt->width = try_crop->width; - try_fmt->height = try_crop->height; - try_fmt->code = sensor->internal_csi_format->code; - try_fmt->field = V4L2_FIELD_NONE; - - if (ssd != sensor->pixel_array) - continue; - - try_comp = v4l2_subdev_get_try_compose(sd, fh->pad, i); - *try_comp = *try_crop; - } - - mutex_unlock(&sensor->mutex); - - return 0; -} - -static const struct v4l2_subdev_video_ops ccs_video_ops = { - .s_stream = ccs_set_stream, -}; - -static const struct v4l2_subdev_pad_ops ccs_pad_ops = { - .enum_mbus_code = ccs_enum_mbus_code, - .get_fmt = ccs_get_format, - .set_fmt = ccs_set_format, - .get_selection = ccs_get_selection, - .set_selection = ccs_set_selection, -}; - -static const struct v4l2_subdev_sensor_ops ccs_sensor_ops = { - .g_skip_frames = ccs_get_skip_frames, - .g_skip_top_lines = ccs_get_skip_top_lines, -}; - -static const struct v4l2_subdev_ops ccs_ops = { - .video = &ccs_video_ops, - .pad = &ccs_pad_ops, - .sensor = &ccs_sensor_ops, -}; - -static const struct media_entity_operations ccs_entity_ops = { - .link_validate = v4l2_subdev_link_validate, -}; - -static const struct v4l2_subdev_internal_ops ccs_internal_src_ops = { - .registered = ccs_registered, - .unregistered = ccs_unregistered, - .open = ccs_open, -}; - -static const struct v4l2_subdev_internal_ops ccs_internal_ops = { - .open = ccs_open, -}; - -/* ----------------------------------------------------------------------------- - * I2C Driver - */ - -static int __maybe_unused ccs_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *subdev = i2c_get_clientdata(client); - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - bool streaming = sensor->streaming; - int rval; - - rval = pm_runtime_get_sync(dev); - if (rval < 0) { - if (rval != -EBUSY && rval != -EAGAIN) - pm_runtime_set_active(&client->dev); - pm_runtime_put(dev); - return -EAGAIN; - } - - if (sensor->streaming) - ccs_stop_streaming(sensor); - - /* save state for resume */ - sensor->streaming = streaming; - - return 0; -} - -static int __maybe_unused ccs_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *subdev = i2c_get_clientdata(client); - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - int rval = 0; - - pm_runtime_put(dev); - - if (sensor->streaming) - rval = ccs_start_streaming(sensor); - - return rval; -} - -static struct ccs_hwconfig *ccs_get_hwconfig(struct device *dev) -{ - struct ccs_hwconfig *hwcfg; - struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 }; - struct fwnode_handle *ep; - struct fwnode_handle *fwnode = dev_fwnode(dev); - u32 rotation; - int i; - int rval; - - if (!fwnode) - return dev->platform_data; - - ep = fwnode_graph_get_next_endpoint(fwnode, NULL); - if (!ep) - return NULL; - - bus_cfg.bus_type = V4L2_MBUS_CSI2_DPHY; - rval = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); - if (rval == -ENXIO) { - bus_cfg = (struct v4l2_fwnode_endpoint) - { .bus_type = V4L2_MBUS_CCP2 }; - rval = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); - } - if (rval) - goto out_err; - - hwcfg = devm_kzalloc(dev, sizeof(*hwcfg), GFP_KERNEL); - if (!hwcfg) - goto out_err; - - switch (bus_cfg.bus_type) { - case V4L2_MBUS_CSI2_DPHY: - hwcfg->csi_signalling_mode = CCS_CSI_SIGNALING_MODE_CSI_2_DPHY; - hwcfg->lanes = bus_cfg.bus.mipi_csi2.num_data_lanes; - break; - case V4L2_MBUS_CCP2: - hwcfg->csi_signalling_mode = (bus_cfg.bus.mipi_csi1.strobe) ? - SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE : - SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK; - hwcfg->lanes = 1; - break; - default: - dev_err(dev, "unsupported bus %u\n", bus_cfg.bus_type); - goto out_err; - } - - dev_dbg(dev, "lanes %u\n", hwcfg->lanes); - - rval = fwnode_property_read_u32(fwnode, "rotation", &rotation); - if (!rval) { - switch (rotation) { - case 180: - hwcfg->module_board_orient = - CCS_MODULE_BOARD_ORIENT_180; - fallthrough; - case 0: - break; - default: - dev_err(dev, "invalid rotation %u\n", rotation); - goto out_err; - } - } - - rval = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &hwcfg->ext_clk); - if (rval) - dev_info(dev, "can't get clock-frequency\n"); - - dev_dbg(dev, "clk %d, mode %d\n", hwcfg->ext_clk, - hwcfg->csi_signalling_mode); - - if (!bus_cfg.nr_of_link_frequencies) { - dev_warn(dev, "no link frequencies defined\n"); - goto out_err; - } - - hwcfg->op_sys_clock = devm_kcalloc( - dev, bus_cfg.nr_of_link_frequencies + 1 /* guardian */, - sizeof(*hwcfg->op_sys_clock), GFP_KERNEL); - if (!hwcfg->op_sys_clock) - goto out_err; - - for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) { - hwcfg->op_sys_clock[i] = bus_cfg.link_frequencies[i]; - dev_dbg(dev, "freq %d: %lld\n", i, hwcfg->op_sys_clock[i]); - } - - v4l2_fwnode_endpoint_free(&bus_cfg); - fwnode_handle_put(ep); - return hwcfg; - -out_err: - v4l2_fwnode_endpoint_free(&bus_cfg); - fwnode_handle_put(ep); - return NULL; -} - -static int ccs_probe(struct i2c_client *client) -{ - struct ccs_sensor *sensor; - struct ccs_hwconfig *hwcfg = ccs_get_hwconfig(&client->dev); - unsigned int i; - int rval; - - if (hwcfg == NULL) - return -ENODEV; - - sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL); - if (sensor == NULL) - return -ENOMEM; - - sensor->hwcfg = hwcfg; - sensor->src = &sensor->ssds[sensor->ssds_used]; - - v4l2_i2c_subdev_init(&sensor->src->sd, client, &ccs_ops); - sensor->src->sd.internal_ops = &ccs_internal_src_ops; - - sensor->vana = devm_regulator_get(&client->dev, "vana"); - if (IS_ERR(sensor->vana)) { - dev_err(&client->dev, "could not get regulator for vana\n"); - return PTR_ERR(sensor->vana); - } - - sensor->ext_clk = devm_clk_get(&client->dev, NULL); - if (PTR_ERR(sensor->ext_clk) == -ENOENT) { - dev_info(&client->dev, "no clock defined, continuing...\n"); - sensor->ext_clk = NULL; - } else if (IS_ERR(sensor->ext_clk)) { - dev_err(&client->dev, "could not get clock (%ld)\n", - PTR_ERR(sensor->ext_clk)); - return -EPROBE_DEFER; - } - - if (sensor->ext_clk) { - if (sensor->hwcfg->ext_clk) { - unsigned long rate; - - rval = clk_set_rate(sensor->ext_clk, - sensor->hwcfg->ext_clk); - if (rval < 0) { - dev_err(&client->dev, - "unable to set clock freq to %u\n", - sensor->hwcfg->ext_clk); - return rval; - } - - rate = clk_get_rate(sensor->ext_clk); - if (rate != sensor->hwcfg->ext_clk) { - dev_err(&client->dev, - "can't set clock freq, asked for %u but got %lu\n", - sensor->hwcfg->ext_clk, rate); - return rval; - } - } else { - sensor->hwcfg->ext_clk = clk_get_rate(sensor->ext_clk); - dev_dbg(&client->dev, "obtained clock freq %u\n", - sensor->hwcfg->ext_clk); - } - } else if (sensor->hwcfg->ext_clk) { - dev_dbg(&client->dev, "assuming clock freq %u\n", - sensor->hwcfg->ext_clk); - } else { - dev_err(&client->dev, "unable to obtain clock freq\n"); - return -EINVAL; - } - - sensor->xshutdown = devm_gpiod_get_optional(&client->dev, "xshutdown", - GPIOD_OUT_LOW); - if (IS_ERR(sensor->xshutdown)) - return PTR_ERR(sensor->xshutdown); - - rval = ccs_power_on(&client->dev); - if (rval < 0) - return rval; - - mutex_init(&sensor->mutex); - - rval = ccs_identify_module(sensor); - if (rval) { - rval = -ENODEV; - goto out_power_off; - } - - rval = ccs_read_all_limits(sensor); - if (rval) - goto out_power_off; - - rval = ccs_read_frame_fmt(sensor); - if (rval) { - rval = -ENODEV; - goto out_free_ccs_limits; - } - - /* - * Handle Sensor Module orientation on the board. - * - * The application of H-FLIP and V-FLIP on the sensor is modified by - * the sensor orientation on the board. - * - * For CCS_BOARD_SENSOR_ORIENT_180 the default behaviour is to set - * both H-FLIP and V-FLIP for normal operation which also implies - * that a set/unset operation for user space HFLIP and VFLIP v4l2 - * controls will need to be internally inverted. - * - * Rotation also changes the bayer pattern. - */ - if (sensor->hwcfg->module_board_orient == - CCS_MODULE_BOARD_ORIENT_180) - sensor->hvflip_inv_mask = - CCS_IMAGE_ORIENTATION_HORIZONTAL_MIRROR | - CCS_IMAGE_ORIENTATION_VERTICAL_FLIP; - - rval = ccs_call_quirk(sensor, limits); - if (rval) { - dev_err(&client->dev, "limits quirks failed\n"); - goto out_free_ccs_limits; - } - - if (CCS_LIM(sensor, BINNING_CAPABILITY)) { - sensor->nbinning_subtypes = - min_t(u8, CCS_LIM(sensor, BINNING_SUB_TYPES), - CCS_LIM_BINNING_SUB_TYPE_MAX_N); - - for (i = 0; i < sensor->nbinning_subtypes; i++) { - sensor->binning_subtypes[i].horizontal = - CCS_LIM_AT(sensor, BINNING_SUB_TYPE, i) >> - CCS_BINNING_SUB_TYPE_COLUMN_SHIFT; - sensor->binning_subtypes[i].vertical = - CCS_LIM_AT(sensor, BINNING_SUB_TYPE, i) & - CCS_BINNING_SUB_TYPE_ROW_MASK; - - dev_dbg(&client->dev, "binning %xx%x\n", - sensor->binning_subtypes[i].horizontal, - sensor->binning_subtypes[i].vertical); - } - } - sensor->binning_horizontal = 1; - sensor->binning_vertical = 1; - - if (device_create_file(&client->dev, &dev_attr_ident) != 0) { - dev_err(&client->dev, "sysfs ident entry creation failed\n"); - rval = -ENOENT; - goto out_free_ccs_limits; - } - - if (sensor->minfo.smiapp_version && - CCS_LIM(sensor, DATA_TRANSFER_IF_CAPABILITY) & - CCS_DATA_TRANSFER_IF_CAPABILITY_SUPPORTED) { - if (device_create_file(&client->dev, &dev_attr_nvm) != 0) { - dev_err(&client->dev, "sysfs nvm entry failed\n"); - rval = -EBUSY; - goto out_cleanup; - } - } - - /* We consider this as profile 0 sensor if any of these are zero. */ - if (!CCS_LIM(sensor, MIN_OP_SYS_CLK_DIV) || - !CCS_LIM(sensor, MAX_OP_SYS_CLK_DIV) || - !CCS_LIM(sensor, MIN_OP_PIX_CLK_DIV) || - !CCS_LIM(sensor, MAX_OP_PIX_CLK_DIV)) { - sensor->minfo.smiapp_profile = SMIAPP_PROFILE_0; - } else if (CCS_LIM(sensor, SCALING_CAPABILITY) - != CCS_SCALING_CAPABILITY_NONE) { - if (CCS_LIM(sensor, SCALING_CAPABILITY) - == CCS_SCALING_CAPABILITY_HORIZONTAL) - sensor->minfo.smiapp_profile = SMIAPP_PROFILE_1; - else - sensor->minfo.smiapp_profile = SMIAPP_PROFILE_2; - sensor->scaler = &sensor->ssds[sensor->ssds_used]; - sensor->ssds_used++; - } else if (CCS_LIM(sensor, DIGITAL_CROP_CAPABILITY) - == CCS_DIGITAL_CROP_CAPABILITY_INPUT_CROP) { - sensor->scaler = &sensor->ssds[sensor->ssds_used]; - sensor->ssds_used++; - } - sensor->binner = &sensor->ssds[sensor->ssds_used]; - sensor->ssds_used++; - sensor->pixel_array = &sensor->ssds[sensor->ssds_used]; - sensor->ssds_used++; - - sensor->scale_m = CCS_LIM(sensor, SCALER_N_MIN); - - /* prepare PLL configuration input values */ - sensor->pll.bus_type = SMIAPP_PLL_BUS_TYPE_CSI2; - sensor->pll.csi2.lanes = sensor->hwcfg->lanes; - sensor->pll.ext_clk_freq_hz = sensor->hwcfg->ext_clk; - sensor->pll.scale_n = CCS_LIM(sensor, SCALER_N_MIN); - /* Profile 0 sensors have no separate OP clock branch. */ - if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) - sensor->pll.flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS; - - ccs_create_subdev(sensor, sensor->scaler, " scaler", 2); - ccs_create_subdev(sensor, sensor->binner, " binner", 2); - ccs_create_subdev(sensor, sensor->pixel_array, " pixel_array", 1); - - dev_dbg(&client->dev, "profile %d\n", sensor->minfo.smiapp_profile); - - sensor->pixel_array->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - - rval = ccs_init_controls(sensor); - if (rval < 0) - goto out_cleanup; - - rval = ccs_call_quirk(sensor, init); - if (rval) - goto out_cleanup; - - rval = ccs_get_mbus_formats(sensor); - if (rval) { - rval = -ENODEV; - goto out_cleanup; - } - - rval = ccs_init_late_controls(sensor); - if (rval) { - rval = -ENODEV; - goto out_cleanup; - } - - mutex_lock(&sensor->mutex); - rval = ccs_pll_blanking_update(sensor); - mutex_unlock(&sensor->mutex); - if (rval) { - dev_err(&client->dev, "update mode failed\n"); - goto out_cleanup; - } - - sensor->streaming = false; - sensor->dev_init_done = true; - - rval = media_entity_pads_init(&sensor->src->sd.entity, 2, - sensor->src->pads); - if (rval < 0) - goto out_media_entity_cleanup; - - pm_runtime_set_active(&client->dev); - pm_runtime_get_noresume(&client->dev); - pm_runtime_enable(&client->dev); - - rval = v4l2_async_register_subdev_sensor_common(&sensor->src->sd); - if (rval < 0) - goto out_disable_runtime_pm; - - pm_runtime_set_autosuspend_delay(&client->dev, 1000); - pm_runtime_use_autosuspend(&client->dev); - pm_runtime_put_autosuspend(&client->dev); - - return 0; - -out_disable_runtime_pm: - pm_runtime_put_noidle(&client->dev); - pm_runtime_disable(&client->dev); - -out_media_entity_cleanup: - media_entity_cleanup(&sensor->src->sd.entity); - -out_cleanup: - ccs_cleanup(sensor); - -out_free_ccs_limits: - kfree(sensor->ccs_limits); - -out_power_off: - ccs_power_off(&client->dev); - mutex_destroy(&sensor->mutex); - - return rval; -} - -static int ccs_remove(struct i2c_client *client) -{ - struct v4l2_subdev *subdev = i2c_get_clientdata(client); - struct ccs_sensor *sensor = to_ccs_sensor(subdev); - unsigned int i; - - v4l2_async_unregister_subdev(subdev); - - pm_runtime_disable(&client->dev); - if (!pm_runtime_status_suspended(&client->dev)) - ccs_power_off(&client->dev); - pm_runtime_set_suspended(&client->dev); - - for (i = 0; i < sensor->ssds_used; i++) { - v4l2_device_unregister_subdev(&sensor->ssds[i].sd); - media_entity_cleanup(&sensor->ssds[i].sd.entity); - } - ccs_cleanup(sensor); - mutex_destroy(&sensor->mutex); - kfree(sensor->ccs_limits); - - return 0; -} - -static const struct of_device_id ccs_of_table[] = { - { .compatible = "nokia,smia" }, - { }, -}; -MODULE_DEVICE_TABLE(of, ccs_of_table); - -static const struct i2c_device_id ccs_id_table[] = { - { SMIAPP_NAME, 0 }, - { }, -}; -MODULE_DEVICE_TABLE(i2c, ccs_id_table); - -static const struct dev_pm_ops ccs_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(ccs_suspend, ccs_resume) - SET_RUNTIME_PM_OPS(ccs_power_off, ccs_power_on, NULL) -}; - -static struct i2c_driver ccs_i2c_driver = { - .driver = { - .of_match_table = ccs_of_table, - .name = CCS_NAME, - .pm = &ccs_pm_ops, - }, - .probe_new = ccs_probe, - .remove = ccs_remove, - .id_table = ccs_id_table, -}; - -static int ccs_module_init(void) -{ - unsigned int i, l; - - for (i = 0, l = 0; ccs_limits[i].size && l < CCS_L_LAST; i++) { - if (!(ccs_limits[i].flags & CCS_L_FL_SAME_REG)) { - ccs_limit_offsets[l + 1].lim = - ALIGN(ccs_limit_offsets[l].lim + - ccs_limits[i].size, - ccs_reg_width(ccs_limits[i + 1].reg)); - ccs_limit_offsets[l].info = i; - l++; - } else { - ccs_limit_offsets[l].lim += ccs_limits[i].size; - } - } - - if (WARN_ON(ccs_limits[i].size)) - return -EINVAL; - - if (WARN_ON(l != CCS_L_LAST)) - return -EINVAL; - - return i2c_register_driver(THIS_MODULE, &ccs_i2c_driver); -} - -static void ccs_module_cleanup(void) -{ - i2c_del_driver(&ccs_i2c_driver); -} - -module_init(ccs_module_init); -module_exit(ccs_module_cleanup); - -MODULE_AUTHOR("Sakari Ailus "); -MODULE_DESCRIPTION("Generic MIPI CCS/SMIA/SMIA++ camera sensor driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/smiapp/ccs-limits.c b/drivers/media/i2c/smiapp/ccs-limits.c deleted file mode 100644 index f5511789ac83..000000000000 --- a/drivers/media/i2c/smiapp/ccs-limits.c +++ /dev/null @@ -1,239 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause -/* Copyright (C) 2019--2020 Intel Corporation */ - -#include "ccs-limits.h" -#include "ccs-regs.h" - -const struct ccs_limit ccs_limits[] = { - { CCS_R_FRAME_FORMAT_MODEL_TYPE, 1, 0, "frame_format_model_type" }, - { CCS_R_FRAME_FORMAT_MODEL_SUBTYPE, 1, 0, "frame_format_model_subtype" }, - { CCS_R_FRAME_FORMAT_DESCRIPTOR(0), 30, 0, "frame_format_descriptor" }, - { CCS_R_FRAME_FORMAT_DESCRIPTOR_4(0), 32, 0, "frame_format_descriptor_4" }, - { CCS_R_ANALOG_GAIN_CAPABILITY, 2, 0, "analog_gain_capability" }, - { CCS_R_ANALOG_GAIN_CODE_MIN, 2, 0, "analog_gain_code_min" }, - { CCS_R_ANALOG_GAIN_CODE_MAX, 2, 0, "analog_gain_code_max" }, - { CCS_R_ANALOG_GAIN_CODE_STEP, 2, 0, "analog_gain_code_step" }, - { CCS_R_ANALOG_GAIN_TYPE, 2, 0, "analog_gain_type" }, - { CCS_R_ANALOG_GAIN_M0, 2, 0, "analog_gain_m0" }, - { CCS_R_ANALOG_GAIN_C0, 2, 0, "analog_gain_c0" }, - { CCS_R_ANALOG_GAIN_M1, 2, 0, "analog_gain_m1" }, - { CCS_R_ANALOG_GAIN_C1, 2, 0, "analog_gain_c1" }, - { CCS_R_ANALOG_LINEAR_GAIN_MIN, 2, 0, "analog_linear_gain_min" }, - { CCS_R_ANALOG_LINEAR_GAIN_MAX, 2, 0, "analog_linear_gain_max" }, - { CCS_R_ANALOG_LINEAR_GAIN_STEP_SIZE, 2, 0, "analog_linear_gain_step_size" }, - { CCS_R_ANALOG_EXPONENTIAL_GAIN_MIN, 2, 0, "analog_exponential_gain_min" }, - { CCS_R_ANALOG_EXPONENTIAL_GAIN_MAX, 2, 0, "analog_exponential_gain_max" }, - { CCS_R_ANALOG_EXPONENTIAL_GAIN_STEP_SIZE, 2, 0, "analog_exponential_gain_step_size" }, - { CCS_R_DATA_FORMAT_MODEL_TYPE, 1, 0, "data_format_model_type" }, - { CCS_R_DATA_FORMAT_MODEL_SUBTYPE, 1, 0, "data_format_model_subtype" }, - { CCS_R_DATA_FORMAT_DESCRIPTOR(0), 32, 0, "data_format_descriptor" }, - { CCS_R_INTEGRATION_TIME_CAPABILITY, 2, 0, "integration_time_capability" }, - { CCS_R_COARSE_INTEGRATION_TIME_MIN, 2, 0, "coarse_integration_time_min" }, - { CCS_R_COARSE_INTEGRATION_TIME_MAX_MARGIN, 2, 0, "coarse_integration_time_max_margin" }, - { CCS_R_FINE_INTEGRATION_TIME_MIN, 2, 0, "fine_integration_time_min" }, - { CCS_R_FINE_INTEGRATION_TIME_MAX_MARGIN, 2, 0, "fine_integration_time_max_margin" }, - { CCS_R_DIGITAL_GAIN_CAPABILITY, 1, 0, "digital_gain_capability" }, - { CCS_R_DIGITAL_GAIN_MIN, 2, 0, "digital_gain_min" }, - { CCS_R_DIGITAL_GAIN_MAX, 2, 0, "digital_gain_max" }, - { CCS_R_DIGITAL_GAIN_STEP_SIZE, 2, 0, "digital_gain_step_size" }, - { CCS_R_PEDESTAL_CAPABILITY, 1, 0, "Pedestal_capability" }, - { CCS_R_ADC_CAPABILITY, 1, 0, "ADC_capability" }, - { CCS_R_ADC_BIT_DEPTH_CAPABILITY, 4, 0, "ADC_bit_depth_capability" }, - { CCS_R_MIN_EXT_CLK_FREQ_MHZ, 4, 0, "min_ext_clk_freq_mhz" }, - { CCS_R_MAX_EXT_CLK_FREQ_MHZ, 4, 0, "max_ext_clk_freq_mhz" }, - { CCS_R_MIN_PRE_PLL_CLK_DIV, 2, 0, "min_pre_pll_clk_div" }, - { CCS_R_MAX_PRE_PLL_CLK_DIV, 2, 0, "max_pre_pll_clk_div" }, - { CCS_R_MIN_PLL_IP_CLK_FREQ_MHZ, 4, 0, "min_pll_ip_clk_freq_mhz" }, - { CCS_R_MAX_PLL_IP_CLK_FREQ_MHZ, 4, 0, "max_pll_ip_clk_freq_mhz" }, - { CCS_R_MIN_PLL_MULTIPLIER, 2, 0, "min_pll_multiplier" }, - { CCS_R_MAX_PLL_MULTIPLIER, 2, 0, "max_pll_multiplier" }, - { CCS_R_MIN_PLL_OP_CLK_FREQ_MHZ, 4, 0, "min_pll_op_clk_freq_mhz" }, - { CCS_R_MAX_PLL_OP_CLK_FREQ_MHZ, 4, 0, "max_pll_op_clk_freq_mhz" }, - { CCS_R_MIN_VT_SYS_CLK_DIV, 2, 0, "min_vt_sys_clk_div" }, - { CCS_R_MAX_VT_SYS_CLK_DIV, 2, 0, "max_vt_sys_clk_div" }, - { CCS_R_MIN_VT_SYS_CLK_FREQ_MHZ, 4, 0, "min_vt_sys_clk_freq_mhz" }, - { CCS_R_MAX_VT_SYS_CLK_FREQ_MHZ, 4, 0, "max_vt_sys_clk_freq_mhz" }, - { CCS_R_MIN_VT_PIX_CLK_FREQ_MHZ, 4, 0, "min_vt_pix_clk_freq_mhz" }, - { CCS_R_MAX_VT_PIX_CLK_FREQ_MHZ, 4, 0, "max_vt_pix_clk_freq_mhz" }, - { CCS_R_MIN_VT_PIX_CLK_DIV, 2, 0, "min_vt_pix_clk_div" }, - { CCS_R_MAX_VT_PIX_CLK_DIV, 2, 0, "max_vt_pix_clk_div" }, - { CCS_R_CLOCK_CALCULATION, 1, 0, "clock_calculation" }, - { CCS_R_NUM_OF_VT_LANES, 1, 0, "num_of_vt_lanes" }, - { CCS_R_NUM_OF_OP_LANES, 1, 0, "num_of_op_lanes" }, - { CCS_R_OP_BITS_PER_LANE, 1, 0, "op_bits_per_lane" }, - { CCS_R_MIN_FRAME_LENGTH_LINES, 2, 0, "min_frame_length_lines" }, - { CCS_R_MAX_FRAME_LENGTH_LINES, 2, 0, "max_frame_length_lines" }, - { CCS_R_MIN_LINE_LENGTH_PCK, 2, 0, "min_line_length_pck" }, - { CCS_R_MAX_LINE_LENGTH_PCK, 2, 0, "max_line_length_pck" }, - { CCS_R_MIN_LINE_BLANKING_PCK, 2, 0, "min_line_blanking_pck" }, - { CCS_R_MIN_FRAME_BLANKING_LINES, 2, 0, "min_frame_blanking_lines" }, - { CCS_R_MIN_LINE_LENGTH_PCK_STEP_SIZE, 1, 0, "min_line_length_pck_step_size" }, - { CCS_R_TIMING_MODE_CAPABILITY, 1, 0, "timing_mode_capability" }, - { CCS_R_FRAME_MARGIN_MAX_VALUE, 2, 0, "frame_margin_max_value" }, - { CCS_R_FRAME_MARGIN_MIN_VALUE, 1, 0, "frame_margin_min_value" }, - { CCS_R_GAIN_DELAY_TYPE, 1, 0, "gain_delay_type" }, - { CCS_R_MIN_OP_SYS_CLK_DIV, 2, 0, "min_op_sys_clk_div" }, - { CCS_R_MAX_OP_SYS_CLK_DIV, 2, 0, "max_op_sys_clk_div" }, - { CCS_R_MIN_OP_SYS_CLK_FREQ_MHZ, 4, 0, "min_op_sys_clk_freq_mhz" }, - { CCS_R_MAX_OP_SYS_CLK_FREQ_MHZ, 4, 0, "max_op_sys_clk_freq_mhz" }, - { CCS_R_MIN_OP_PIX_CLK_DIV, 2, 0, "min_op_pix_clk_div" }, - { CCS_R_MAX_OP_PIX_CLK_DIV, 2, 0, "max_op_pix_clk_div" }, - { CCS_R_MIN_OP_PIX_CLK_FREQ_MHZ, 4, 0, "min_op_pix_clk_freq_mhz" }, - { CCS_R_MAX_OP_PIX_CLK_FREQ_MHZ, 4, 0, "max_op_pix_clk_freq_mhz" }, - { CCS_R_X_ADDR_MIN, 2, 0, "x_addr_min" }, - { CCS_R_Y_ADDR_MIN, 2, 0, "y_addr_min" }, - { CCS_R_X_ADDR_MAX, 2, 0, "x_addr_max" }, - { CCS_R_Y_ADDR_MAX, 2, 0, "y_addr_max" }, - { CCS_R_MIN_X_OUTPUT_SIZE, 2, 0, "min_x_output_size" }, - { CCS_R_MIN_Y_OUTPUT_SIZE, 2, 0, "min_y_output_size" }, - { CCS_R_MAX_X_OUTPUT_SIZE, 2, 0, "max_x_output_size" }, - { CCS_R_MAX_Y_OUTPUT_SIZE, 2, 0, "max_y_output_size" }, - { CCS_R_X_ADDR_START_DIV_CONSTANT, 1, 0, "x_addr_start_div_constant" }, - { CCS_R_Y_ADDR_START_DIV_CONSTANT, 1, 0, "y_addr_start_div_constant" }, - { CCS_R_X_ADDR_END_DIV_CONSTANT, 1, 0, "x_addr_end_div_constant" }, - { CCS_R_Y_ADDR_END_DIV_CONSTANT, 1, 0, "y_addr_end_div_constant" }, - { CCS_R_X_SIZE_DIV, 1, 0, "x_size_div" }, - { CCS_R_Y_SIZE_DIV, 1, 0, "y_size_div" }, - { CCS_R_X_OUTPUT_DIV, 1, 0, "x_output_div" }, - { CCS_R_Y_OUTPUT_DIV, 1, 0, "y_output_div" }, - { CCS_R_NON_FLEXIBLE_RESOLUTION_SUPPORT, 1, 0, "non_flexible_resolution_support" }, - { CCS_R_MIN_OP_PRE_PLL_CLK_DIV, 2, 0, "min_op_pre_pll_clk_div" }, - { CCS_R_MAX_OP_PRE_PLL_CLK_DIV, 2, 0, "max_op_pre_pll_clk_div" }, - { CCS_R_MIN_OP_PLL_IP_CLK_FREQ_MHZ, 4, 0, "min_op_pll_ip_clk_freq_mhz" }, - { CCS_R_MAX_OP_PLL_IP_CLK_FREQ_MHZ, 4, 0, "max_op_pll_ip_clk_freq_mhz" }, - { CCS_R_MIN_OP_PLL_MULTIPLIER, 2, 0, "min_op_pll_multiplier" }, - { CCS_R_MAX_OP_PLL_MULTIPLIER, 2, 0, "max_op_pll_multiplier" }, - { CCS_R_MIN_OP_PLL_OP_CLK_FREQ_MHZ, 4, 0, "min_op_pll_op_clk_freq_mhz" }, - { CCS_R_MAX_OP_PLL_OP_CLK_FREQ_MHZ, 4, 0, "max_op_pll_op_clk_freq_mhz" }, - { CCS_R_CLOCK_TREE_PLL_CAPABILITY, 1, 0, "clock_tree_pll_capability" }, - { CCS_R_CLOCK_CAPA_TYPE_CAPABILITY, 1, 0, "clock_capa_type_capability" }, - { CCS_R_MIN_EVEN_INC, 2, 0, "min_even_inc" }, - { CCS_R_MIN_ODD_INC, 2, 0, "min_odd_inc" }, - { CCS_R_MAX_EVEN_INC, 2, 0, "max_even_inc" }, - { CCS_R_MAX_ODD_INC, 2, 0, "max_odd_inc" }, - { CCS_R_AUX_SUBSAMP_CAPABILITY, 1, 0, "aux_subsamp_capability" }, - { CCS_R_AUX_SUBSAMP_MONO_CAPABILITY, 1, 0, "aux_subsamp_mono_capability" }, - { CCS_R_MONOCHROME_CAPABILITY, 1, 0, "monochrome_capability" }, - { CCS_R_PIXEL_READOUT_CAPABILITY, 1, 0, "pixel_readout_capability" }, - { CCS_R_MIN_EVEN_INC_MONO, 2, 0, "min_even_inc_mono" }, - { CCS_R_MAX_EVEN_INC_MONO, 2, 0, "max_even_inc_mono" }, - { CCS_R_MIN_ODD_INC_MONO, 2, 0, "min_odd_inc_mono" }, - { CCS_R_MAX_ODD_INC_MONO, 2, 0, "max_odd_inc_mono" }, - { CCS_R_MIN_EVEN_INC_BC2, 2, 0, "min_even_inc_bc2" }, - { CCS_R_MAX_EVEN_INC_BC2, 2, 0, "max_even_inc_bc2" }, - { CCS_R_MIN_ODD_INC_BC2, 2, 0, "min_odd_inc_bc2" }, - { CCS_R_MAX_ODD_INC_BC2, 2, 0, "max_odd_inc_bc2" }, - { CCS_R_MIN_EVEN_INC_MONO_BC2, 2, 0, "min_even_inc_mono_bc2" }, - { CCS_R_MAX_EVEN_INC_MONO_BC2, 2, 0, "max_even_inc_mono_bc2" }, - { CCS_R_MIN_ODD_INC_MONO_BC2, 2, 0, "min_odd_inc_mono_bc2" }, - { CCS_R_MAX_ODD_INC_MONO_BC2, 2, 0, "max_odd_inc_mono_bc2" }, - { CCS_R_SCALING_CAPABILITY, 2, 0, "scaling_capability" }, - { CCS_R_SCALER_M_MIN, 2, 0, "scaler_m_min" }, - { CCS_R_SCALER_M_MAX, 2, 0, "scaler_m_max" }, - { CCS_R_SCALER_N_MIN, 2, 0, "scaler_n_min" }, - { CCS_R_SCALER_N_MAX, 2, 0, "scaler_n_max" }, - { CCS_R_DIGITAL_CROP_CAPABILITY, 1, 0, "digital_crop_capability" }, - { CCS_R_HDR_CAPABILITY_1, 1, 0, "hdr_capability_1" }, - { CCS_R_MIN_HDR_BIT_DEPTH, 1, 0, "min_hdr_bit_depth" }, - { CCS_R_HDR_RESOLUTION_SUB_TYPES, 1, 0, "hdr_resolution_sub_types" }, - { CCS_R_HDR_RESOLUTION_SUB_TYPE(0), 2, 0, "hdr_resolution_sub_type" }, - { CCS_R_HDR_CAPABILITY_2, 1, 0, "hdr_capability_2" }, - { CCS_R_MAX_HDR_BIT_DEPTH, 1, 0, "max_hdr_bit_depth" }, - { CCS_R_USL_SUPPORT_CAPABILITY, 1, 0, "usl_support_capability" }, - { CCS_R_USL_CLOCK_MODE_D_CAPABILITY, 1, 0, "usl_clock_mode_d_capability" }, - { CCS_R_MIN_OP_SYS_CLK_DIV_REV, 1, 0, "min_op_sys_clk_div_rev" }, - { CCS_R_MAX_OP_SYS_CLK_DIV_REV, 1, 0, "max_op_sys_clk_div_rev" }, - { CCS_R_MIN_OP_PIX_CLK_DIV_REV, 1, 0, "min_op_pix_clk_div_rev" }, - { CCS_R_MAX_OP_PIX_CLK_DIV_REV, 1, 0, "max_op_pix_clk_div_rev" }, - { CCS_R_MIN_OP_SYS_CLK_FREQ_REV_MHZ, 4, 0, "min_op_sys_clk_freq_rev_mhz" }, - { CCS_R_MAX_OP_SYS_CLK_FREQ_REV_MHZ, 4, 0, "max_op_sys_clk_freq_rev_mhz" }, - { CCS_R_MIN_OP_PIX_CLK_FREQ_REV_MHZ, 4, 0, "min_op_pix_clk_freq_rev_mhz" }, - { CCS_R_MAX_OP_PIX_CLK_FREQ_REV_MHZ, 4, 0, "max_op_pix_clk_freq_rev_mhz" }, - { CCS_R_MAX_BITRATE_REV_D_MODE_MBPS, 4, 0, "max_bitrate_rev_d_mode_mbps" }, - { CCS_R_MAX_SYMRATE_REV_C_MODE_MSPS, 4, 0, "max_symrate_rev_c_mode_msps" }, - { CCS_R_COMPRESSION_CAPABILITY, 1, 0, "compression_capability" }, - { CCS_R_TEST_MODE_CAPABILITY, 2, 0, "test_mode_capability" }, - { CCS_R_PN9_DATA_FORMAT1, 1, 0, "pn9_data_format1" }, - { CCS_R_PN9_DATA_FORMAT2, 1, 0, "pn9_data_format2" }, - { CCS_R_PN9_DATA_FORMAT3, 1, 0, "pn9_data_format3" }, - { CCS_R_PN9_DATA_FORMAT4, 1, 0, "pn9_data_format4" }, - { CCS_R_PN9_MISC_CAPABILITY, 1, 0, "pn9_misc_capability" }, - { CCS_R_TEST_PATTERN_CAPABILITY, 1, 0, "test_pattern_capability" }, - { CCS_R_PATTERN_SIZE_DIV_M1, 1, 0, "pattern_size_div_m1" }, - { CCS_R_FIFO_SUPPORT_CAPABILITY, 1, 0, "fifo_support_capability" }, - { CCS_R_PHY_CTRL_CAPABILITY, 1, 0, "phy_ctrl_capability" }, - { CCS_R_CSI_DPHY_LANE_MODE_CAPABILITY, 1, 0, "csi_dphy_lane_mode_capability" }, - { CCS_R_CSI_SIGNALING_MODE_CAPABILITY, 1, 0, "csi_signaling_mode_capability" }, - { CCS_R_FAST_STANDBY_CAPABILITY, 1, 0, "fast_standby_capability" }, - { CCS_R_CSI_ADDRESS_CONTROL_CAPABILITY, 1, 0, "csi_address_control_capability" }, - { CCS_R_DATA_TYPE_CAPABILITY, 1, 0, "data_type_capability" }, - { CCS_R_CSI_CPHY_LANE_MODE_CAPABILITY, 1, 0, "csi_cphy_lane_mode_capability" }, - { CCS_R_EMB_DATA_CAPABILITY, 1, 0, "emb_data_capability" }, - { CCS_R_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS(0), 16, 0, "max_per_lane_bitrate_lane_d_mode_mbps 0" }, - { CCS_R_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS(4), 16, CCS_L_FL_SAME_REG, "max_per_lane_bitrate_lane_d_mode_mbps 4" }, - { CCS_R_TEMP_SENSOR_CAPABILITY, 1, 0, "temp_sensor_capability" }, - { CCS_R_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS(0), 16, 0, "max_per_lane_bitrate_lane_c_mode_mbps 0" }, - { CCS_R_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS(4), 16, CCS_L_FL_SAME_REG, "max_per_lane_bitrate_lane_c_mode_mbps 4" }, - { CCS_R_DPHY_EQUALIZATION_CAPABILITY, 1, 0, "dphy_equalization_capability" }, - { CCS_R_CPHY_EQUALIZATION_CAPABILITY, 1, 0, "cphy_equalization_capability" }, - { CCS_R_DPHY_PREAMBLE_CAPABILITY, 1, 0, "dphy_preamble_capability" }, - { CCS_R_DPHY_SSC_CAPABILITY, 1, 0, "dphy_ssc_capability" }, - { CCS_R_CPHY_CALIBRATION_CAPABILITY, 1, 0, "cphy_calibration_capability" }, - { CCS_R_DPHY_CALIBRATION_CAPABILITY, 1, 0, "dphy_calibration_capability" }, - { CCS_R_PHY_CTRL_CAPABILITY_2, 1, 0, "phy_ctrl_capability_2" }, - { CCS_R_LRTE_CPHY_CAPABILITY, 1, 0, "lrte_cphy_capability" }, - { CCS_R_LRTE_DPHY_CAPABILITY, 1, 0, "lrte_dphy_capability" }, - { CCS_R_ALPS_CAPABILITY_DPHY, 1, 0, "alps_capability_dphy" }, - { CCS_R_ALPS_CAPABILITY_CPHY, 1, 0, "alps_capability_cphy" }, - { CCS_R_SCRAMBLING_CAPABILITY, 1, 0, "scrambling_capability" }, - { CCS_R_DPHY_MANUAL_CONSTANT, 1, 0, "dphy_manual_constant" }, - { CCS_R_CPHY_MANUAL_CONSTANT, 1, 0, "cphy_manual_constant" }, - { CCS_R_CSI2_INTERFACE_CAPABILITY_MISC, 1, 0, "CSI2_interface_capability_misc" }, - { CCS_R_PHY_CTRL_CAPABILITY_3, 1, 0, "PHY_ctrl_capability_3" }, - { CCS_R_DPHY_SF, 1, 0, "dphy_sf" }, - { CCS_R_CPHY_SF, 1, 0, "cphy_sf" }, - { CCS_R_DPHY_LIMITS_1, 1, 0, "dphy_limits_1" }, - { CCS_R_DPHY_LIMITS_2, 1, 0, "dphy_limits_2" }, - { CCS_R_DPHY_LIMITS_3, 1, 0, "dphy_limits_3" }, - { CCS_R_DPHY_LIMITS_4, 1, 0, "dphy_limits_4" }, - { CCS_R_DPHY_LIMITS_5, 1, 0, "dphy_limits_5" }, - { CCS_R_DPHY_LIMITS_6, 1, 0, "dphy_limits_6" }, - { CCS_R_CPHY_LIMITS_1, 1, 0, "cphy_limits_1" }, - { CCS_R_CPHY_LIMITS_2, 1, 0, "cphy_limits_2" }, - { CCS_R_CPHY_LIMITS_3, 1, 0, "cphy_limits_3" }, - { CCS_R_MIN_FRAME_LENGTH_LINES_BIN, 2, 0, "min_frame_length_lines_bin" }, - { CCS_R_MAX_FRAME_LENGTH_LINES_BIN, 2, 0, "max_frame_length_lines_bin" }, - { CCS_R_MIN_LINE_LENGTH_PCK_BIN, 2, 0, "min_line_length_pck_bin" }, - { CCS_R_MAX_LINE_LENGTH_PCK_BIN, 2, 0, "max_line_length_pck_bin" }, - { CCS_R_MIN_LINE_BLANKING_PCK_BIN, 2, 0, "min_line_blanking_pck_bin" }, - { CCS_R_FINE_INTEGRATION_TIME_MIN_BIN, 2, 0, "fine_integration_time_min_bin" }, - { CCS_R_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN, 2, 0, "fine_integration_time_max_margin_bin" }, - { CCS_R_BINNING_CAPABILITY, 1, 0, "binning_capability" }, - { CCS_R_BINNING_WEIGHTING_CAPABILITY, 1, 0, "binning_weighting_capability" }, - { CCS_R_BINNING_SUB_TYPES, 1, 0, "binning_sub_types" }, - { CCS_R_BINNING_SUB_TYPE(0), 64, 0, "binning_sub_type" }, - { CCS_R_BINNING_WEIGHTING_MONO_CAPABILITY, 1, 0, "binning_weighting_mono_capability" }, - { CCS_R_BINNING_SUB_TYPES_MONO, 1, 0, "binning_sub_types_mono" }, - { CCS_R_BINNING_SUB_TYPE_MONO(0), 64, 0, "binning_sub_type_mono" }, - { CCS_R_DATA_TRANSFER_IF_CAPABILITY, 1, 0, "data_transfer_if_capability" }, - { CCS_R_SHADING_CORRECTION_CAPABILITY, 1, 0, "shading_correction_capability" }, - { CCS_R_GREEN_IMBALANCE_CAPABILITY, 1, 0, "green_imbalance_capability" }, - { CCS_R_MODULE_SPECIFIC_CORRECTION_CAPABILITY, 1, 0, "module_specific_correction_capability" }, - { CCS_R_DEFECT_CORRECTION_CAPABILITY, 2, 0, "defect_correction_capability" }, - { CCS_R_DEFECT_CORRECTION_CAPABILITY_2, 2, 0, "defect_correction_capability_2" }, - { CCS_R_NF_CAPABILITY, 1, 0, "nf_capability" }, - { CCS_R_OB_READOUT_CAPABILITY, 1, 0, "ob_readout_capability" }, - { CCS_R_COLOR_FEEDBACK_CAPABILITY, 1, 0, "color_feedback_capability" }, - { CCS_R_CFA_PATTERN_CAPABILITY, 1, 0, "CFA_pattern_capability" }, - { CCS_R_CFA_PATTERN_CONVERSION_CAPABILITY, 1, 0, "CFA_pattern_conversion_capability" }, - { CCS_R_FLASH_MODE_CAPABILITY, 1, 0, "flash_mode_capability" }, - { CCS_R_SA_STROBE_MODE_CAPABILITY, 1, 0, "sa_strobe_mode_capability" }, - { CCS_R_RESET_MAX_DELAY, 1, 0, "reset_max_delay" }, - { CCS_R_RESET_MIN_TIME, 1, 0, "reset_min_time" }, - { CCS_R_PDAF_CAPABILITY_1, 1, 0, "pdaf_capability_1" }, - { CCS_R_PDAF_CAPABILITY_2, 1, 0, "pdaf_capability_2" }, - { CCS_R_BRACKETING_LUT_CAPABILITY_1, 1, 0, "bracketing_lut_capability_1" }, - { CCS_R_BRACKETING_LUT_CAPABILITY_2, 1, 0, "bracketing_lut_capability_2" }, - { CCS_R_BRACKETING_LUT_SIZE, 1, 0, "bracketing_lut_size" }, - { 0 } /* Guardian */ -}; diff --git a/drivers/media/i2c/smiapp/ccs-limits.h b/drivers/media/i2c/smiapp/ccs-limits.h deleted file mode 100644 index 1efa43c23a2e..000000000000 --- a/drivers/media/i2c/smiapp/ccs-limits.h +++ /dev/null @@ -1,259 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */ -/* Copyright (C) 2019--2020 Intel Corporation */ - -#ifndef __CCS_LIMITS_H__ -#define __CCS_LIMITS_H__ - -#include -#include - -struct ccs_limit { - u32 reg; - u16 size; - u16 flags; - const char *name; -}; - -#define CCS_L_FL_SAME_REG BIT(0) - -extern const struct ccs_limit ccs_limits[]; - -#define CCS_L_FRAME_FORMAT_MODEL_TYPE 0 -#define CCS_L_FRAME_FORMAT_MODEL_SUBTYPE 1 -#define CCS_L_FRAME_FORMAT_DESCRIPTOR 2 -#define CCS_L_FRAME_FORMAT_DESCRIPTOR_OFFSET(n) ((n) * 2) -#define CCS_L_FRAME_FORMAT_DESCRIPTOR_4 3 -#define CCS_L_FRAME_FORMAT_DESCRIPTOR_4_OFFSET(n) ((n) * 4) -#define CCS_L_ANALOG_GAIN_CAPABILITY 4 -#define CCS_L_ANALOG_GAIN_CODE_MIN 5 -#define CCS_L_ANALOG_GAIN_CODE_MAX 6 -#define CCS_L_ANALOG_GAIN_CODE_STEP 7 -#define CCS_L_ANALOG_GAIN_TYPE 8 -#define CCS_L_ANALOG_GAIN_M0 9 -#define CCS_L_ANALOG_GAIN_C0 10 -#define CCS_L_ANALOG_GAIN_M1 11 -#define CCS_L_ANALOG_GAIN_C1 12 -#define CCS_L_ANALOG_LINEAR_GAIN_MIN 13 -#define CCS_L_ANALOG_LINEAR_GAIN_MAX 14 -#define CCS_L_ANALOG_LINEAR_GAIN_STEP_SIZE 15 -#define CCS_L_ANALOG_EXPONENTIAL_GAIN_MIN 16 -#define CCS_L_ANALOG_EXPONENTIAL_GAIN_MAX 17 -#define CCS_L_ANALOG_EXPONENTIAL_GAIN_STEP_SIZE 18 -#define CCS_L_DATA_FORMAT_MODEL_TYPE 19 -#define CCS_L_DATA_FORMAT_MODEL_SUBTYPE 20 -#define CCS_L_DATA_FORMAT_DESCRIPTOR 21 -#define CCS_L_DATA_FORMAT_DESCRIPTOR_OFFSET(n) ((n) * 2) -#define CCS_L_INTEGRATION_TIME_CAPABILITY 22 -#define CCS_L_COARSE_INTEGRATION_TIME_MIN 23 -#define CCS_L_COARSE_INTEGRATION_TIME_MAX_MARGIN 24 -#define CCS_L_FINE_INTEGRATION_TIME_MIN 25 -#define CCS_L_FINE_INTEGRATION_TIME_MAX_MARGIN 26 -#define CCS_L_DIGITAL_GAIN_CAPABILITY 27 -#define CCS_L_DIGITAL_GAIN_MIN 28 -#define CCS_L_DIGITAL_GAIN_MAX 29 -#define CCS_L_DIGITAL_GAIN_STEP_SIZE 30 -#define CCS_L_PEDESTAL_CAPABILITY 31 -#define CCS_L_ADC_CAPABILITY 32 -#define CCS_L_ADC_BIT_DEPTH_CAPABILITY 33 -#define CCS_L_MIN_EXT_CLK_FREQ_MHZ 34 -#define CCS_L_MAX_EXT_CLK_FREQ_MHZ 35 -#define CCS_L_MIN_PRE_PLL_CLK_DIV 36 -#define CCS_L_MAX_PRE_PLL_CLK_DIV 37 -#define CCS_L_MIN_PLL_IP_CLK_FREQ_MHZ 38 -#define CCS_L_MAX_PLL_IP_CLK_FREQ_MHZ 39 -#define CCS_L_MIN_PLL_MULTIPLIER 40 -#define CCS_L_MAX_PLL_MULTIPLIER 41 -#define CCS_L_MIN_PLL_OP_CLK_FREQ_MHZ 42 -#define CCS_L_MAX_PLL_OP_CLK_FREQ_MHZ 43 -#define CCS_L_MIN_VT_SYS_CLK_DIV 44 -#define CCS_L_MAX_VT_SYS_CLK_DIV 45 -#define CCS_L_MIN_VT_SYS_CLK_FREQ_MHZ 46 -#define CCS_L_MAX_VT_SYS_CLK_FREQ_MHZ 47 -#define CCS_L_MIN_VT_PIX_CLK_FREQ_MHZ 48 -#define CCS_L_MAX_VT_PIX_CLK_FREQ_MHZ 49 -#define CCS_L_MIN_VT_PIX_CLK_DIV 50 -#define CCS_L_MAX_VT_PIX_CLK_DIV 51 -#define CCS_L_CLOCK_CALCULATION 52 -#define CCS_L_NUM_OF_VT_LANES 53 -#define CCS_L_NUM_OF_OP_LANES 54 -#define CCS_L_OP_BITS_PER_LANE 55 -#define CCS_L_MIN_FRAME_LENGTH_LINES 56 -#define CCS_L_MAX_FRAME_LENGTH_LINES 57 -#define CCS_L_MIN_LINE_LENGTH_PCK 58 -#define CCS_L_MAX_LINE_LENGTH_PCK 59 -#define CCS_L_MIN_LINE_BLANKING_PCK 60 -#define CCS_L_MIN_FRAME_BLANKING_LINES 61 -#define CCS_L_MIN_LINE_LENGTH_PCK_STEP_SIZE 62 -#define CCS_L_TIMING_MODE_CAPABILITY 63 -#define CCS_L_FRAME_MARGIN_MAX_VALUE 64 -#define CCS_L_FRAME_MARGIN_MIN_VALUE 65 -#define CCS_L_GAIN_DELAY_TYPE 66 -#define CCS_L_MIN_OP_SYS_CLK_DIV 67 -#define CCS_L_MAX_OP_SYS_CLK_DIV 68 -#define CCS_L_MIN_OP_SYS_CLK_FREQ_MHZ 69 -#define CCS_L_MAX_OP_SYS_CLK_FREQ_MHZ 70 -#define CCS_L_MIN_OP_PIX_CLK_DIV 71 -#define CCS_L_MAX_OP_PIX_CLK_DIV 72 -#define CCS_L_MIN_OP_PIX_CLK_FREQ_MHZ 73 -#define CCS_L_MAX_OP_PIX_CLK_FREQ_MHZ 74 -#define CCS_L_X_ADDR_MIN 75 -#define CCS_L_Y_ADDR_MIN 76 -#define CCS_L_X_ADDR_MAX 77 -#define CCS_L_Y_ADDR_MAX 78 -#define CCS_L_MIN_X_OUTPUT_SIZE 79 -#define CCS_L_MIN_Y_OUTPUT_SIZE 80 -#define CCS_L_MAX_X_OUTPUT_SIZE 81 -#define CCS_L_MAX_Y_OUTPUT_SIZE 82 -#define CCS_L_X_ADDR_START_DIV_CONSTANT 83 -#define CCS_L_Y_ADDR_START_DIV_CONSTANT 84 -#define CCS_L_X_ADDR_END_DIV_CONSTANT 85 -#define CCS_L_Y_ADDR_END_DIV_CONSTANT 86 -#define CCS_L_X_SIZE_DIV 87 -#define CCS_L_Y_SIZE_DIV 88 -#define CCS_L_X_OUTPUT_DIV 89 -#define CCS_L_Y_OUTPUT_DIV 90 -#define CCS_L_NON_FLEXIBLE_RESOLUTION_SUPPORT 91 -#define CCS_L_MIN_OP_PRE_PLL_CLK_DIV 92 -#define CCS_L_MAX_OP_PRE_PLL_CLK_DIV 93 -#define CCS_L_MIN_OP_PLL_IP_CLK_FREQ_MHZ 94 -#define CCS_L_MAX_OP_PLL_IP_CLK_FREQ_MHZ 95 -#define CCS_L_MIN_OP_PLL_MULTIPLIER 96 -#define CCS_L_MAX_OP_PLL_MULTIPLIER 97 -#define CCS_L_MIN_OP_PLL_OP_CLK_FREQ_MHZ 98 -#define CCS_L_MAX_OP_PLL_OP_CLK_FREQ_MHZ 99 -#define CCS_L_CLOCK_TREE_PLL_CAPABILITY 100 -#define CCS_L_CLOCK_CAPA_TYPE_CAPABILITY 101 -#define CCS_L_MIN_EVEN_INC 102 -#define CCS_L_MIN_ODD_INC 103 -#define CCS_L_MAX_EVEN_INC 104 -#define CCS_L_MAX_ODD_INC 105 -#define CCS_L_AUX_SUBSAMP_CAPABILITY 106 -#define CCS_L_AUX_SUBSAMP_MONO_CAPABILITY 107 -#define CCS_L_MONOCHROME_CAPABILITY 108 -#define CCS_L_PIXEL_READOUT_CAPABILITY 109 -#define CCS_L_MIN_EVEN_INC_MONO 110 -#define CCS_L_MAX_EVEN_INC_MONO 111 -#define CCS_L_MIN_ODD_INC_MONO 112 -#define CCS_L_MAX_ODD_INC_MONO 113 -#define CCS_L_MIN_EVEN_INC_BC2 114 -#define CCS_L_MAX_EVEN_INC_BC2 115 -#define CCS_L_MIN_ODD_INC_BC2 116 -#define CCS_L_MAX_ODD_INC_BC2 117 -#define CCS_L_MIN_EVEN_INC_MONO_BC2 118 -#define CCS_L_MAX_EVEN_INC_MONO_BC2 119 -#define CCS_L_MIN_ODD_INC_MONO_BC2 120 -#define CCS_L_MAX_ODD_INC_MONO_BC2 121 -#define CCS_L_SCALING_CAPABILITY 122 -#define CCS_L_SCALER_M_MIN 123 -#define CCS_L_SCALER_M_MAX 124 -#define CCS_L_SCALER_N_MIN 125 -#define CCS_L_SCALER_N_MAX 126 -#define CCS_L_DIGITAL_CROP_CAPABILITY 127 -#define CCS_L_HDR_CAPABILITY_1 128 -#define CCS_L_MIN_HDR_BIT_DEPTH 129 -#define CCS_L_HDR_RESOLUTION_SUB_TYPES 130 -#define CCS_L_HDR_RESOLUTION_SUB_TYPE 131 -#define CCS_L_HDR_RESOLUTION_SUB_TYPE_OFFSET(n) (n) -#define CCS_L_HDR_CAPABILITY_2 132 -#define CCS_L_MAX_HDR_BIT_DEPTH 133 -#define CCS_L_USL_SUPPORT_CAPABILITY 134 -#define CCS_L_USL_CLOCK_MODE_D_CAPABILITY 135 -#define CCS_L_MIN_OP_SYS_CLK_DIV_REV 136 -#define CCS_L_MAX_OP_SYS_CLK_DIV_REV 137 -#define CCS_L_MIN_OP_PIX_CLK_DIV_REV 138 -#define CCS_L_MAX_OP_PIX_CLK_DIV_REV 139 -#define CCS_L_MIN_OP_SYS_CLK_FREQ_REV_MHZ 140 -#define CCS_L_MAX_OP_SYS_CLK_FREQ_REV_MHZ 141 -#define CCS_L_MIN_OP_PIX_CLK_FREQ_REV_MHZ 142 -#define CCS_L_MAX_OP_PIX_CLK_FREQ_REV_MHZ 143 -#define CCS_L_MAX_BITRATE_REV_D_MODE_MBPS 144 -#define CCS_L_MAX_SYMRATE_REV_C_MODE_MSPS 145 -#define CCS_L_COMPRESSION_CAPABILITY 146 -#define CCS_L_TEST_MODE_CAPABILITY 147 -#define CCS_L_PN9_DATA_FORMAT1 148 -#define CCS_L_PN9_DATA_FORMAT2 149 -#define CCS_L_PN9_DATA_FORMAT3 150 -#define CCS_L_PN9_DATA_FORMAT4 151 -#define CCS_L_PN9_MISC_CAPABILITY 152 -#define CCS_L_TEST_PATTERN_CAPABILITY 153 -#define CCS_L_PATTERN_SIZE_DIV_M1 154 -#define CCS_L_FIFO_SUPPORT_CAPABILITY 155 -#define CCS_L_PHY_CTRL_CAPABILITY 156 -#define CCS_L_CSI_DPHY_LANE_MODE_CAPABILITY 157 -#define CCS_L_CSI_SIGNALING_MODE_CAPABILITY 158 -#define CCS_L_FAST_STANDBY_CAPABILITY 159 -#define CCS_L_CSI_ADDRESS_CONTROL_CAPABILITY 160 -#define CCS_L_DATA_TYPE_CAPABILITY 161 -#define CCS_L_CSI_CPHY_LANE_MODE_CAPABILITY 162 -#define CCS_L_EMB_DATA_CAPABILITY 163 -#define CCS_L_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS 164 -#define CCS_L_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS_OFFSET(n) ((n) * 4) -#define CCS_L_TEMP_SENSOR_CAPABILITY 165 -#define CCS_L_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS 166 -#define CCS_L_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS_OFFSET(n) ((n) * 4) -#define CCS_L_DPHY_EQUALIZATION_CAPABILITY 167 -#define CCS_L_CPHY_EQUALIZATION_CAPABILITY 168 -#define CCS_L_DPHY_PREAMBLE_CAPABILITY 169 -#define CCS_L_DPHY_SSC_CAPABILITY 170 -#define CCS_L_CPHY_CALIBRATION_CAPABILITY 171 -#define CCS_L_DPHY_CALIBRATION_CAPABILITY 172 -#define CCS_L_PHY_CTRL_CAPABILITY_2 173 -#define CCS_L_LRTE_CPHY_CAPABILITY 174 -#define CCS_L_LRTE_DPHY_CAPABILITY 175 -#define CCS_L_ALPS_CAPABILITY_DPHY 176 -#define CCS_L_ALPS_CAPABILITY_CPHY 177 -#define CCS_L_SCRAMBLING_CAPABILITY 178 -#define CCS_L_DPHY_MANUAL_CONSTANT 179 -#define CCS_L_CPHY_MANUAL_CONSTANT 180 -#define CCS_L_CSI2_INTERFACE_CAPABILITY_MISC 181 -#define CCS_L_PHY_CTRL_CAPABILITY_3 182 -#define CCS_L_DPHY_SF 183 -#define CCS_L_CPHY_SF 184 -#define CCS_L_DPHY_LIMITS_1 185 -#define CCS_L_DPHY_LIMITS_2 186 -#define CCS_L_DPHY_LIMITS_3 187 -#define CCS_L_DPHY_LIMITS_4 188 -#define CCS_L_DPHY_LIMITS_5 189 -#define CCS_L_DPHY_LIMITS_6 190 -#define CCS_L_CPHY_LIMITS_1 191 -#define CCS_L_CPHY_LIMITS_2 192 -#define CCS_L_CPHY_LIMITS_3 193 -#define CCS_L_MIN_FRAME_LENGTH_LINES_BIN 194 -#define CCS_L_MAX_FRAME_LENGTH_LINES_BIN 195 -#define CCS_L_MIN_LINE_LENGTH_PCK_BIN 196 -#define CCS_L_MAX_LINE_LENGTH_PCK_BIN 197 -#define CCS_L_MIN_LINE_BLANKING_PCK_BIN 198 -#define CCS_L_FINE_INTEGRATION_TIME_MIN_BIN 199 -#define CCS_L_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN 200 -#define CCS_L_BINNING_CAPABILITY 201 -#define CCS_L_BINNING_WEIGHTING_CAPABILITY 202 -#define CCS_L_BINNING_SUB_TYPES 203 -#define CCS_L_BINNING_SUB_TYPE 204 -#define CCS_L_BINNING_SUB_TYPE_OFFSET(n) (n) -#define CCS_L_BINNING_WEIGHTING_MONO_CAPABILITY 205 -#define CCS_L_BINNING_SUB_TYPES_MONO 206 -#define CCS_L_BINNING_SUB_TYPE_MONO 207 -#define CCS_L_BINNING_SUB_TYPE_MONO_OFFSET(n) (n) -#define CCS_L_DATA_TRANSFER_IF_CAPABILITY 208 -#define CCS_L_SHADING_CORRECTION_CAPABILITY 209 -#define CCS_L_GREEN_IMBALANCE_CAPABILITY 210 -#define CCS_L_MODULE_SPECIFIC_CORRECTION_CAPABILITY 211 -#define CCS_L_DEFECT_CORRECTION_CAPABILITY 212 -#define CCS_L_DEFECT_CORRECTION_CAPABILITY_2 213 -#define CCS_L_NF_CAPABILITY 214 -#define CCS_L_OB_READOUT_CAPABILITY 215 -#define CCS_L_COLOR_FEEDBACK_CAPABILITY 216 -#define CCS_L_CFA_PATTERN_CAPABILITY 217 -#define CCS_L_CFA_PATTERN_CONVERSION_CAPABILITY 218 -#define CCS_L_FLASH_MODE_CAPABILITY 219 -#define CCS_L_SA_STROBE_MODE_CAPABILITY 220 -#define CCS_L_RESET_MAX_DELAY 221 -#define CCS_L_RESET_MIN_TIME 222 -#define CCS_L_PDAF_CAPABILITY_1 223 -#define CCS_L_PDAF_CAPABILITY_2 224 -#define CCS_L_BRACKETING_LUT_CAPABILITY_1 225 -#define CCS_L_BRACKETING_LUT_CAPABILITY_2 226 -#define CCS_L_BRACKETING_LUT_SIZE 227 -#define CCS_L_LAST 228 - -#endif /* __CCS_LIMITS_H__ */ diff --git a/drivers/media/i2c/smiapp/ccs-quirk.c b/drivers/media/i2c/smiapp/ccs-quirk.c deleted file mode 100644 index 6c48d0901952..000000000000 --- a/drivers/media/i2c/smiapp/ccs-quirk.c +++ /dev/null @@ -1,214 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * drivers/media/i2c/smiapp/ccs-quirk.c - * - * Generic driver for SMIA/SMIA++ compliant camera modules - * - * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus - */ - -#include - -#include "ccs.h" -#include "ccs-limits.h" - -static int ccs_write_addr_8s(struct ccs_sensor *sensor, - const struct ccs_reg_8 *regs, int len) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - int rval; - - for (; len > 0; len--, regs++) { - rval = ccs_write_addr(sensor, regs->reg, regs->val); - if (rval < 0) { - dev_err(&client->dev, - "error %d writing reg 0x%4.4x, val 0x%2.2x", - rval, regs->reg, regs->val); - return rval; - } - } - - return 0; -} - -static int jt8ew9_limits(struct ccs_sensor *sensor) -{ - if (sensor->minfo.revision_number_major < 0x03) - sensor->frame_skip = 1; - - /* Below 24 gain doesn't have effect at all, */ - /* but ~59 is needed for full dynamic range */ - ccs_replace_limit(sensor, CCS_L_ANALOG_GAIN_CODE_MIN, 0, 59); - ccs_replace_limit(sensor, CCS_L_ANALOG_GAIN_CODE_MAX, 0, 6000); - - return 0; -} - -static int jt8ew9_post_poweron(struct ccs_sensor *sensor) -{ - static const struct ccs_reg_8 regs[] = { - { 0x30a3, 0xd8 }, /* Output port control : LVDS ports only */ - { 0x30ae, 0x00 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */ - { 0x30af, 0xd0 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */ - { 0x322d, 0x04 }, /* Adjusting Processing Image Size to Scaler Toshiba Recommendation Setting */ - { 0x3255, 0x0f }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */ - { 0x3256, 0x15 }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */ - { 0x3258, 0x70 }, /* Analog Gain Control Toshiba Recommendation Setting */ - { 0x3259, 0x70 }, /* Analog Gain Control Toshiba Recommendation Setting */ - { 0x325f, 0x7c }, /* Analog Gain Control Toshiba Recommendation Setting */ - { 0x3302, 0x06 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */ - { 0x3304, 0x00 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */ - { 0x3307, 0x22 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */ - { 0x3308, 0x8d }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */ - { 0x331e, 0x0f }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ - { 0x3320, 0x30 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ - { 0x3321, 0x11 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ - { 0x3322, 0x98 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ - { 0x3323, 0x64 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ - { 0x3325, 0x83 }, /* Read Out Timing Control Toshiba Recommendation Setting */ - { 0x3330, 0x18 }, /* Read Out Timing Control Toshiba Recommendation Setting */ - { 0x333c, 0x01 }, /* Read Out Timing Control Toshiba Recommendation Setting */ - { 0x3345, 0x2f }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ - { 0x33de, 0x38 }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */ - /* Taken from v03. No idea what the rest are. */ - { 0x32e0, 0x05 }, - { 0x32e1, 0x05 }, - { 0x32e2, 0x04 }, - { 0x32e5, 0x04 }, - { 0x32e6, 0x04 }, - - }; - - return ccs_write_addr_8s(sensor, regs, ARRAY_SIZE(regs)); -} - -const struct ccs_quirk smiapp_jt8ew9_quirk = { - .limits = jt8ew9_limits, - .post_poweron = jt8ew9_post_poweron, -}; - -static int imx125es_post_poweron(struct ccs_sensor *sensor) -{ - /* Taken from v02. No idea what the other two are. */ - static const struct ccs_reg_8 regs[] = { - /* - * 0x3302: clk during frame blanking: - * 0x00 - HS mode, 0x01 - LP11 - */ - { 0x3302, 0x01 }, - { 0x302d, 0x00 }, - { 0x3b08, 0x8c }, - }; - - return ccs_write_addr_8s(sensor, regs, ARRAY_SIZE(regs)); -} - -const struct ccs_quirk smiapp_imx125es_quirk = { - .post_poweron = imx125es_post_poweron, -}; - -static int jt8ev1_limits(struct ccs_sensor *sensor) -{ - ccs_replace_limit(sensor, CCS_L_X_ADDR_MAX, 0, 4271); - ccs_replace_limit(sensor, CCS_L_MIN_LINE_BLANKING_PCK_BIN, 0, 184); - - return 0; -} - -static int jt8ev1_post_poweron(struct ccs_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - int rval; - static const struct ccs_reg_8 regs[] = { - { 0x3031, 0xcd }, /* For digital binning (EQ_MONI) */ - { 0x30a3, 0xd0 }, /* FLASH STROBE enable */ - { 0x3237, 0x00 }, /* For control of pulse timing for ADC */ - { 0x3238, 0x43 }, - { 0x3301, 0x06 }, /* For analog bias for sensor */ - { 0x3302, 0x06 }, - { 0x3304, 0x00 }, - { 0x3305, 0x88 }, - { 0x332a, 0x14 }, - { 0x332c, 0x6b }, - { 0x3336, 0x01 }, - { 0x333f, 0x1f }, - { 0x3355, 0x00 }, - { 0x3356, 0x20 }, - { 0x33bf, 0x20 }, /* Adjust the FBC speed */ - { 0x33c9, 0x20 }, - { 0x33ce, 0x30 }, /* Adjust the parameter for logic function */ - { 0x33cf, 0xec }, /* For Black sun */ - { 0x3328, 0x80 }, /* Ugh. No idea what's this. */ - }; - static const struct ccs_reg_8 regs_96[] = { - { 0x30ae, 0x00 }, /* For control of ADC clock */ - { 0x30af, 0xd0 }, - { 0x30b0, 0x01 }, - }; - - rval = ccs_write_addr_8s(sensor, regs, ARRAY_SIZE(regs)); - if (rval < 0) - return rval; - - switch (sensor->hwcfg->ext_clk) { - case 9600000: - return ccs_write_addr_8s(sensor, regs_96, - ARRAY_SIZE(regs_96)); - default: - dev_warn(&client->dev, "no MSRs for %d Hz ext_clk\n", - sensor->hwcfg->ext_clk); - return 0; - } -} - -static int jt8ev1_pre_streamon(struct ccs_sensor *sensor) -{ - return ccs_write_addr(sensor, 0x3328, 0x00); -} - -static int jt8ev1_post_streamoff(struct ccs_sensor *sensor) -{ - int rval; - - /* Workaround: allows fast standby to work properly */ - rval = ccs_write_addr(sensor, 0x3205, 0x04); - if (rval < 0) - return rval; - - /* Wait for 1 ms + one line => 2 ms is likely enough */ - usleep_range(2000, 2050); - - /* Restore it */ - rval = ccs_write_addr(sensor, 0x3205, 0x00); - if (rval < 0) - return rval; - - return ccs_write_addr(sensor, 0x3328, 0x80); -} - -static int jt8ev1_init(struct ccs_sensor *sensor) -{ - sensor->pll.flags |= SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE; - - return 0; -} - -const struct ccs_quirk smiapp_jt8ev1_quirk = { - .limits = jt8ev1_limits, - .post_poweron = jt8ev1_post_poweron, - .pre_streamon = jt8ev1_pre_streamon, - .post_streamoff = jt8ev1_post_streamoff, - .init = jt8ev1_init, -}; - -static int tcm8500md_limits(struct ccs_sensor *sensor) -{ - ccs_replace_limit(sensor, CCS_L_MIN_PLL_IP_CLK_FREQ_MHZ, 0, 2700000); - - return 0; -} - -const struct ccs_quirk smiapp_tcm8500md_quirk = { - .limits = tcm8500md_limits, -}; diff --git a/drivers/media/i2c/smiapp/ccs-quirk.h b/drivers/media/i2c/smiapp/ccs-quirk.h deleted file mode 100644 index d208379158f2..000000000000 --- a/drivers/media/i2c/smiapp/ccs-quirk.h +++ /dev/null @@ -1,78 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * drivers/media/i2c/smiapp/ccs-quirk.h - * - * Generic driver for SMIA/SMIA++ compliant camera modules - * - * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus - */ - -#ifndef __CCS_QUIRK__ -#define __CCS_QUIRK__ - -struct ccs_sensor; - -/** - * struct ccs_quirk - quirks for sensors that deviate from SMIA++ standard - * - * @limits: Replace sensor->limits with values which can't be read from - * sensor registers. Called the first time the sensor is powered up. - * @post_poweron: Called always after the sensor has been fully powered on. - * @pre_streamon: Called just before streaming is enabled. - * @post_streamon: Called right after stopping streaming. - * @pll_flags: Return flags for the PLL calculator. - * @init: Quirk initialisation, called the last in probe(). This is - * also appropriate for adding sensor specific controls, for instance. - * @reg_access: Register access quirk. The quirk may divert the access - * to another register, or no register at all. - * - * @write: Is this read (false) or write (true) access? - * @reg: Pointer to the register to access - * @value: Register value, set by the caller on write, or - * by the quirk on read - * - * @return: 0 on success, -ENOIOCTLCMD if no register - * access may be done by the caller (default read - * value is zero), else negative error code on error - */ -struct ccs_quirk { - int (*limits)(struct ccs_sensor *sensor); - int (*post_poweron)(struct ccs_sensor *sensor); - int (*pre_streamon)(struct ccs_sensor *sensor); - int (*post_streamoff)(struct ccs_sensor *sensor); - unsigned long (*pll_flags)(struct ccs_sensor *sensor); - int (*init)(struct ccs_sensor *sensor); - int (*reg_access)(struct ccs_sensor *sensor, bool write, u32 *reg, - u32 *val); - unsigned long flags; -}; - -#define CCS_QUIRK_FLAG_8BIT_READ_ONLY (1 << 0) - -struct ccs_reg_8 { - u16 reg; - u8 val; -}; - -#define CCS_MK_QUIRK_REG_8(_reg, _val) \ - { \ - .reg = (u16)_reg, \ - .val = _val, \ - } - -#define ccs_call_quirk(sensor, _quirk, ...) \ - ((sensor)->minfo.quirk && \ - (sensor)->minfo.quirk->_quirk ? \ - (sensor)->minfo.quirk->_quirk(sensor, ##__VA_ARGS__) : 0) - -#define ccs_needs_quirk(sensor, _quirk) \ - ((sensor)->minfo.quirk ? \ - (sensor)->minfo.quirk->flags & _quirk : 0) - -extern const struct ccs_quirk smiapp_jt8ev1_quirk; -extern const struct ccs_quirk smiapp_imx125es_quirk; -extern const struct ccs_quirk smiapp_jt8ew9_quirk; -extern const struct ccs_quirk smiapp_tcm8500md_quirk; - -#endif /* __CCS_QUIRK__ */ diff --git a/drivers/media/i2c/smiapp/ccs-reg-access.c b/drivers/media/i2c/smiapp/ccs-reg-access.c deleted file mode 100644 index 4e6d212473fc..000000000000 --- a/drivers/media/i2c/smiapp/ccs-reg-access.c +++ /dev/null @@ -1,265 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * drivers/media/i2c/smiapp/ccs-regs.c - * - * Generic driver for SMIA/SMIA++ compliant camera modules - * - * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus - */ - -#include - -#include -#include - -#include "ccs.h" - -static uint32_t float_to_u32_mul_1000000(struct i2c_client *client, - uint32_t phloat) -{ - int32_t exp; - uint64_t man; - - if (phloat >= 0x80000000) { - dev_err(&client->dev, "this is a negative number\n"); - return 0; - } - - if (phloat == 0x7f800000) - return ~0; /* Inf. */ - - if ((phloat & 0x7f800000) == 0x7f800000) { - dev_err(&client->dev, "NaN or other special number\n"); - return 0; - } - - /* Valid cases begin here */ - if (phloat == 0) - return 0; /* Valid zero */ - - if (phloat > 0x4f800000) - return ~0; /* larger than 4294967295 */ - - /* - * Unbias exponent (note how phloat is now guaranteed to - * have 0 in the high bit) - */ - exp = ((int32_t)phloat >> 23) - 127; - - /* Extract mantissa, add missing '1' bit and it's in MHz */ - man = ((phloat & 0x7fffff) | 0x800000) * 1000000ULL; - - if (exp < 0) - man >>= -exp; - else - man <<= exp; - - man >>= 23; /* Remove mantissa bias */ - - return man & 0xffffffff; -} - - -/* - * Read a 8/16/32-bit i2c register. The value is returned in 'val'. - * Returns zero if successful, or non-zero otherwise. - */ -static int ____ccs_read_addr(struct ccs_sensor *sensor, u16 reg, u16 len, - u32 *val) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - struct i2c_msg msg; - unsigned char data_buf[sizeof(u32)] = { 0 }; - unsigned char offset_buf[sizeof(u16)]; - int r; - - if (len > sizeof(data_buf)) - return -EINVAL; - - msg.addr = client->addr; - msg.flags = 0; - msg.len = sizeof(offset_buf); - msg.buf = offset_buf; - put_unaligned_be16(reg, offset_buf); - - r = i2c_transfer(client->adapter, &msg, 1); - if (r != 1) { - if (r >= 0) - r = -EBUSY; - goto err; - } - - msg.len = len; - msg.flags = I2C_M_RD; - msg.buf = &data_buf[sizeof(data_buf) - len]; - - r = i2c_transfer(client->adapter, &msg, 1); - if (r != 1) { - if (r >= 0) - r = -EBUSY; - goto err; - } - - *val = get_unaligned_be32(data_buf); - - return 0; - -err: - dev_err(&client->dev, "read from offset 0x%x error %d\n", reg, r); - - return r; -} - -/* Read a register using 8-bit access only. */ -static int ____ccs_read_addr_8only(struct ccs_sensor *sensor, u16 reg, - u16 len, u32 *val) -{ - unsigned int i; - int rval; - - *val = 0; - - for (i = 0; i < len; i++) { - u32 val8; - - rval = ____ccs_read_addr(sensor, reg + i, 1, &val8); - if (rval < 0) - return rval; - *val |= val8 << ((len - i - 1) << 3); - } - - return 0; -} - -unsigned int ccs_reg_width(u32 reg) -{ - if (reg & CCS_FL_16BIT) - return sizeof(uint16_t); - if (reg & CCS_FL_32BIT) - return sizeof(uint32_t); - - return sizeof(uint8_t); -} - -/* - * Read a 8/16/32-bit i2c register. The value is returned in 'val'. - * Returns zero if successful, or non-zero otherwise. - */ -static int __ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val, - bool only8) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - unsigned int len = ccs_reg_width(reg); - int rval; - - if (!only8) - rval = ____ccs_read_addr(sensor, CCS_REG_ADDR(reg), len, val); - else - rval = ____ccs_read_addr_8only(sensor, CCS_REG_ADDR(reg), len, - val); - if (rval < 0) - return rval; - - if (reg & CCS_FL_FLOAT_IREAL) - *val = float_to_u32_mul_1000000(client, *val); - - return 0; -} - -int ccs_read_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 *val) -{ - return __ccs_read_addr( - sensor, reg, val, - ccs_needs_quirk(sensor, CCS_QUIRK_FLAG_8BIT_READ_ONLY)); -} - -static int ccs_read_addr_quirk(struct ccs_sensor *sensor, u32 reg, u32 *val, - bool force8) -{ - int rval; - - *val = 0; - rval = ccs_call_quirk(sensor, reg_access, false, ®, val); - if (rval == -ENOIOCTLCMD) - return 0; - if (rval < 0) - return rval; - - if (force8) - return __ccs_read_addr(sensor, reg, val, true); - - return ccs_read_addr_no_quirk(sensor, reg, val); -} - -int ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val) -{ - return ccs_read_addr_quirk(sensor, reg, val, false); -} - -int ccs_read_addr_8only(struct ccs_sensor *sensor, u32 reg, u32 *val) -{ - return ccs_read_addr_quirk(sensor, reg, val, true); -} - -int ccs_write_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - struct i2c_msg msg; - unsigned char data[6]; - unsigned int retries; - unsigned int len = ccs_reg_width(reg); - int r; - - if (len > sizeof(data) - 2) - return -EINVAL; - - msg.addr = client->addr; - msg.flags = 0; /* Write */ - msg.len = 2 + len; - msg.buf = data; - - put_unaligned_be16(CCS_REG_ADDR(reg), data); - put_unaligned_be32(val << (8 * (sizeof(val) - len)), data + 2); - - for (retries = 0; retries < 5; retries++) { - /* - * Due to unknown reason sensor stops responding. This - * loop is a temporaty solution until the root cause - * is found. - */ - r = i2c_transfer(client->adapter, &msg, 1); - if (r == 1) { - if (retries) - dev_err(&client->dev, - "sensor i2c stall encountered. retries: %d\n", - retries); - return 0; - } - - usleep_range(2000, 2000); - } - - dev_err(&client->dev, - "wrote 0x%x to offset 0x%x error %d\n", val, - CCS_REG_ADDR(reg), r); - - return r; -} - -/* - * Write to a 8/16-bit register. - * Returns zero if successful, or non-zero otherwise. - */ -int ccs_write_addr(struct ccs_sensor *sensor, u32 reg, u32 val) -{ - int rval; - - rval = ccs_call_quirk(sensor, reg_access, true, ®, &val); - if (rval == -ENOIOCTLCMD) - return 0; - if (rval < 0) - return rval; - - return ccs_write_addr_no_quirk(sensor, reg, val); -} diff --git a/drivers/media/i2c/smiapp/ccs-reg-access.h b/drivers/media/i2c/smiapp/ccs-reg-access.h deleted file mode 100644 index 76ac036a9538..000000000000 --- a/drivers/media/i2c/smiapp/ccs-reg-access.h +++ /dev/null @@ -1,37 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * include/media/smiapp/ccs-regs.h - * - * Generic driver for SMIA/SMIA++ compliant camera modules - * - * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus - */ - -#ifndef SMIAPP_REGS_H -#define SMIAPP_REGS_H - -#include -#include - -#include "ccs-regs.h" - -#define CCS_REG_ADDR(reg) ((u16)reg) - -struct ccs_sensor; - -int ccs_read_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 *val); -int ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val); -int ccs_read_addr_8only(struct ccs_sensor *sensor, u32 reg, u32 *val); -int ccs_write_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 val); -int ccs_write_addr(struct ccs_sensor *sensor, u32 reg, u32 val); - -unsigned int ccs_reg_width(u32 reg); - -#define ccs_read(sensor, reg_name, val) \ - ccs_read_addr(sensor, CCS_R_##reg_name, val) - -#define ccs_write(sensor, reg_name, val) \ - ccs_write_addr(sensor, CCS_R_##reg_name, val) - -#endif diff --git a/drivers/media/i2c/smiapp/ccs-regs.h b/drivers/media/i2c/smiapp/ccs-regs.h deleted file mode 100644 index 4b3e5df2121f..000000000000 --- a/drivers/media/i2c/smiapp/ccs-regs.h +++ /dev/null @@ -1,954 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */ -/* Copyright (C) 2019--2020 Intel Corporation */ - -#ifndef __CCS_REGS_H__ -#define __CCS_REGS_H__ - -#include - -#define CCS_FL_BASE 16 -#define CCS_FL_16BIT BIT(CCS_FL_BASE) -#define CCS_FL_32BIT BIT(CCS_FL_BASE + 1) -#define CCS_FL_FLOAT_IREAL BIT(CCS_FL_BASE + 2) -#define CCS_FL_IREAL BIT(CCS_FL_BASE + 3) -#define CCS_R_ADDR(r) ((r) & 0xffff) - -#define CCS_R_MODULE_MODEL_ID (0x0000 | CCS_FL_16BIT) -#define CCS_R_MODULE_REVISION_NUMBER_MAJOR 0x0002 -#define CCS_R_FRAME_COUNT 0x0005 -#define CCS_R_PIXEL_ORDER 0x0006 -#define CCS_PIXEL_ORDER_GRBG 0U -#define CCS_PIXEL_ORDER_RGGB 1U -#define CCS_PIXEL_ORDER_BGGR 2U -#define CCS_PIXEL_ORDER_GBRG 3U -#define CCS_R_MIPI_CCS_VERSION 0x0007 -#define CCS_MIPI_CCS_VERSION_V1_0 0x10 -#define CCS_MIPI_CCS_VERSION_V1_1 0x11 -#define CCS_MIPI_CCS_VERSION_MAJOR_SHIFT 4U -#define CCS_MIPI_CCS_VERSION_MAJOR_MASK 0xf0 -#define CCS_MIPI_CCS_VERSION_MINOR_SHIFT 0U -#define CCS_MIPI_CCS_VERSION_MINOR_MASK 0xf -#define CCS_R_DATA_PEDESTAL (0x0008 | CCS_FL_16BIT) -#define CCS_R_MODULE_MANUFACTURER_ID (0x000e | CCS_FL_16BIT) -#define CCS_R_MODULE_REVISION_NUMBER_MINOR 0x0010 -#define CCS_R_MODULE_DATE_YEAR 0x0012 -#define CCS_R_MODULE_DATE_MONTH 0x0013 -#define CCS_R_MODULE_DATE_DAY 0x0014 -#define CCS_R_MODULE_DATE_PHASE 0x0015 -#define CCS_MODULE_DATE_PHASE_SHIFT 0U -#define CCS_MODULE_DATE_PHASE_MASK 0x7 -#define CCS_MODULE_DATE_PHASE_TS 0U -#define CCS_MODULE_DATE_PHASE_ES 1U -#define CCS_MODULE_DATE_PHASE_CS 2U -#define CCS_MODULE_DATE_PHASE_MP 3U -#define CCS_R_SENSOR_MODEL_ID (0x0016 | CCS_FL_16BIT) -#define CCS_R_SENSOR_REVISION_NUMBER 0x0018 -#define CCS_R_SENSOR_FIRMWARE_VERSION 0x001a -#define CCS_R_SERIAL_NUMBER (0x001c | CCS_FL_32BIT) -#define CCS_R_SENSOR_MANUFACTURER_ID (0x0020 | CCS_FL_16BIT) -#define CCS_R_SENSOR_REVISION_NUMBER_16 (0x0022 | CCS_FL_16BIT) -#define CCS_R_FRAME_FORMAT_MODEL_TYPE 0x0040 -#define CCS_FRAME_FORMAT_MODEL_TYPE_2_BYTE 1U -#define CCS_FRAME_FORMAT_MODEL_TYPE_4_BYTE 2U -#define CCS_R_FRAME_FORMAT_MODEL_SUBTYPE 0x0041 -#define CCS_FRAME_FORMAT_MODEL_SUBTYPE_ROWS_SHIFT 0U -#define CCS_FRAME_FORMAT_MODEL_SUBTYPE_ROWS_MASK 0xf -#define CCS_FRAME_FORMAT_MODEL_SUBTYPE_COLUMNS_SHIFT 4U -#define CCS_FRAME_FORMAT_MODEL_SUBTYPE_COLUMNS_MASK 0xf0 -#define CCS_R_FRAME_FORMAT_DESCRIPTOR(n) ((0x0042 | CCS_FL_16BIT) + (n) * 2) -#define CCS_LIM_FRAME_FORMAT_DESCRIPTOR_MIN_N 0U -#define CCS_LIM_FRAME_FORMAT_DESCRIPTOR_MAX_N 14U -#define CCS_R_FRAME_FORMAT_DESCRIPTOR_4(n) ((0x0060 | CCS_FL_32BIT) + (n) * 4) -#define CCS_FRAME_FORMAT_DESCRIPTOR_PIXELS_SHIFT 0U -#define CCS_FRAME_FORMAT_DESCRIPTOR_PIXELS_MASK 0xfff -#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_SHIFT 12U -#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MASK 0xf000 -#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_EMBEDDED 1U -#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_DUMMY_PIXEL 2U -#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_BLACK_PIXEL 3U -#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_DARK_PIXEL 4U -#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_VISIBLE_PIXEL 5U -#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MANUF_SPECIFIC_0 8U -#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MANUF_SPECIFIC_1 9U -#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MANUF_SPECIFIC_2 10U -#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MANUF_SPECIFIC_3 11U -#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MANUF_SPECIFIC_4 12U -#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MANUF_SPECIFIC_5 13U -#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_MANUF_SPECIFIC_6 14U -#define CCS_LIM_FRAME_FORMAT_DESCRIPTOR_4_MIN_N 0U -#define CCS_LIM_FRAME_FORMAT_DESCRIPTOR_4_MAX_N 7U -#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PIXELS_SHIFT 0U -#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PIXELS_MASK 0xffff -#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_SHIFT 28U -#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MASK 0xf0000000 -#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_EMBEDDED 1U -#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_DUMMY_PIXEL 2U -#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_BLACK_PIXEL 3U -#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_DARK_PIXEL 4U -#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_VISIBLE_PIXEL 5U -#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_0 8U -#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_1 9U -#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_2 10U -#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_3 11U -#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_4 12U -#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_5 13U -#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_6 14U -#define CCS_R_ANALOG_GAIN_CAPABILITY (0x0080 | CCS_FL_16BIT) -#define CCS_ANALOG_GAIN_CAPABILITY_GLOBAL 0U -#define CCS_ANALOG_GAIN_CAPABILITY_ALTERNATE_GLOBAL 2U -#define CCS_R_ANALOG_GAIN_CODE_MIN (0x0084 | CCS_FL_16BIT) -#define CCS_R_ANALOG_GAIN_CODE_MAX (0x0086 | CCS_FL_16BIT) -#define CCS_R_ANALOG_GAIN_CODE_STEP (0x0088 | CCS_FL_16BIT) -#define CCS_R_ANALOG_GAIN_TYPE (0x008a | CCS_FL_16BIT) -#define CCS_R_ANALOG_GAIN_M0 (0x008c | CCS_FL_16BIT) -#define CCS_R_ANALOG_GAIN_C0 (0x008e | CCS_FL_16BIT) -#define CCS_R_ANALOG_GAIN_M1 (0x0090 | CCS_FL_16BIT) -#define CCS_R_ANALOG_GAIN_C1 (0x0092 | CCS_FL_16BIT) -#define CCS_R_ANALOG_LINEAR_GAIN_MIN (0x0094 | CCS_FL_16BIT) -#define CCS_R_ANALOG_LINEAR_GAIN_MAX (0x0096 | CCS_FL_16BIT) -#define CCS_R_ANALOG_LINEAR_GAIN_STEP_SIZE (0x0098 | CCS_FL_16BIT) -#define CCS_R_ANALOG_EXPONENTIAL_GAIN_MIN (0x009a | CCS_FL_16BIT) -#define CCS_R_ANALOG_EXPONENTIAL_GAIN_MAX (0x009c | CCS_FL_16BIT) -#define CCS_R_ANALOG_EXPONENTIAL_GAIN_STEP_SIZE (0x009e | CCS_FL_16BIT) -#define CCS_R_DATA_FORMAT_MODEL_TYPE 0x00c0 -#define CCS_DATA_FORMAT_MODEL_TYPE_NORMAL 1U -#define CCS_DATA_FORMAT_MODEL_TYPE_EXTENDED 2U -#define CCS_R_DATA_FORMAT_MODEL_SUBTYPE 0x00c1 -#define CCS_DATA_FORMAT_MODEL_SUBTYPE_ROWS_SHIFT 0U -#define CCS_DATA_FORMAT_MODEL_SUBTYPE_ROWS_MASK 0xf -#define CCS_DATA_FORMAT_MODEL_SUBTYPE_COLUMNS_SHIFT 4U -#define CCS_DATA_FORMAT_MODEL_SUBTYPE_COLUMNS_MASK 0xf0 -#define CCS_R_DATA_FORMAT_DESCRIPTOR(n) ((0x00c2 | CCS_FL_16BIT) + (n) * 2) -#define CCS_LIM_DATA_FORMAT_DESCRIPTOR_MIN_N 0U -#define CCS_LIM_DATA_FORMAT_DESCRIPTOR_MAX_N 15U -#define CCS_DATA_FORMAT_DESCRIPTOR_COMPRESSED_SHIFT 0U -#define CCS_DATA_FORMAT_DESCRIPTOR_COMPRESSED_MASK 0xff -#define CCS_DATA_FORMAT_DESCRIPTOR_UNCOMPRESSED_SHIFT 8U -#define CCS_DATA_FORMAT_DESCRIPTOR_UNCOMPRESSED_MASK 0xff00 -#define CCS_R_MODE_SELECT 0x0100 -#define CCS_MODE_SELECT_SOFTWARE_STANDBY 0U -#define CCS_MODE_SELECT_STREAMING 1U -#define CCS_R_IMAGE_ORIENTATION 0x0101 -#define CCS_IMAGE_ORIENTATION_HORIZONTAL_MIRROR BIT(0) -#define CCS_IMAGE_ORIENTATION_VERTICAL_FLIP BIT(1) -#define CCS_R_SOFTWARE_RESET 0x0103 -#define CCS_SOFTWARE_RESET_OFF 0U -#define CCS_SOFTWARE_RESET_ON 1U -#define CCS_R_GROUPED_PARAMETER_HOLD 0x0104 -#define CCS_R_MASK_CORRUPTED_FRAMES 0x0105 -#define CCS_MASK_CORRUPTED_FRAMES_ALLOW 0U -#define CCS_MASK_CORRUPTED_FRAMES_MASK 1U -#define CCS_R_FAST_STANDBY_CTRL 0x0106 -#define CCS_FAST_STANDBY_CTRL_COMPLETE_FRAMES 0U -#define CCS_FAST_STANDBY_CTRL_FRAME_TRUNCATION 1U -#define CCS_R_CCI_ADDRESS_CTRL 0x0107 -#define CCS_R_2ND_CCI_IF_CTRL 0x0108 -#define CCS_2ND_CCI_IF_CTRL_ENABLE BIT(0) -#define CCS_2ND_CCI_IF_CTRL_ACK BIT(1) -#define CCS_R_2ND_CCI_ADDRESS_CTRL 0x0109 -#define CCS_R_CSI_CHANNEL_IDENTIFIER 0x0110 -#define CCS_R_CSI_SIGNALING_MODE 0x0111 -#define CCS_CSI_SIGNALING_MODE_CSI_2_DPHY 2U -#define CCS_CSI_SIGNALING_MODE_CSI_2_CPHY 3U -#define CCS_R_CSI_DATA_FORMAT (0x0112 | CCS_FL_16BIT) -#define CCS_R_CSI_LANE_MODE 0x0114 -#define CCS_R_DPCM_FRAME_DT 0x011d -#define CCS_R_BOTTOM_EMBEDDED_DATA_DT 0x011e -#define CCS_R_BOTTOM_EMBEDDED_DATA_VC 0x011f -#define CCS_R_GAIN_MODE 0x0120 -#define CCS_GAIN_MODE_GLOBAL 0U -#define CCS_GAIN_MODE_ALTERNATE 1U -#define CCS_R_ADC_BIT_DEPTH 0x0121 -#define CCS_R_EMB_DATA_CTRL 0x0122 -#define CCS_EMB_DATA_CTRL_RAW8_PACKING_FOR_RAW16 BIT(0) -#define CCS_EMB_DATA_CTRL_RAW10_PACKING_FOR_RAW20 BIT(1) -#define CCS_EMB_DATA_CTRL_RAW12_PACKING_FOR_RAW24 BIT(2) -#define CCS_R_GPIO_TRIG_MODE 0x0130 -#define CCS_R_EXTCLK_FREQUENCY_MHZ (0x0136 | (CCS_FL_16BIT | CCS_FL_IREAL)) -#define CCS_R_TEMP_SENSOR_CTRL 0x0138 -#define CCS_TEMP_SENSOR_CTRL_ENABLE BIT(0) -#define CCS_R_TEMP_SENSOR_MODE 0x0139 -#define CCS_R_TEMP_SENSOR_OUTPUT 0x013a -#define CCS_R_FINE_INTEGRATION_TIME (0x0200 | CCS_FL_16BIT) -#define CCS_R_COARSE_INTEGRATION_TIME (0x0202 | CCS_FL_16BIT) -#define CCS_R_ANALOG_GAIN_CODE_GLOBAL (0x0204 | CCS_FL_16BIT) -#define CCS_R_ANALOG_LINEAR_GAIN_GLOBAL (0x0206 | CCS_FL_16BIT) -#define CCS_R_ANALOG_EXPONENTIAL_GAIN_GLOBAL (0x0208 | CCS_FL_16BIT) -#define CCS_R_DIGITAL_GAIN_GLOBAL (0x020e | CCS_FL_16BIT) -#define CCS_R_SHORT_ANALOG_GAIN_GLOBAL (0x0216 | CCS_FL_16BIT) -#define CCS_R_SHORT_DIGITAL_GAIN_GLOBAL (0x0218 | CCS_FL_16BIT) -#define CCS_R_HDR_MODE 0x0220 -#define CCS_HDR_MODE_ENABLED BIT(0) -#define CCS_HDR_MODE_SEPARATE_ANALOG_GAIN BIT(1) -#define CCS_HDR_MODE_UPSCALING BIT(2) -#define CCS_HDR_MODE_RESET_SYNC BIT(3) -#define CCS_HDR_MODE_TIMING_MODE BIT(4) -#define CCS_HDR_MODE_EXPOSURE_CTRL_DIRECT BIT(5) -#define CCS_HDR_MODE_SEPARATE_DIGITAL_GAIN BIT(6) -#define CCS_R_HDR_RESOLUTION_REDUCTION 0x0221 -#define CCS_HDR_RESOLUTION_REDUCTION_ROW_SHIFT 0U -#define CCS_HDR_RESOLUTION_REDUCTION_ROW_MASK 0xf -#define CCS_HDR_RESOLUTION_REDUCTION_COLUMN_SHIFT 4U -#define CCS_HDR_RESOLUTION_REDUCTION_COLUMN_MASK 0xf0 -#define CCS_R_EXPOSURE_RATIO 0x0222 -#define CCS_R_HDR_INTERNAL_BIT_DEPTH 0x0223 -#define CCS_R_DIRECT_SHORT_INTEGRATION_TIME (0x0224 | CCS_FL_16BIT) -#define CCS_R_SHORT_ANALOG_LINEAR_GAIN_GLOBAL (0x0226 | CCS_FL_16BIT) -#define CCS_R_SHORT_ANALOG_EXPONENTIAL_GAIN_GLOBAL (0x0228 | CCS_FL_16BIT) -#define CCS_R_VT_PIX_CLK_DIV (0x0300 | CCS_FL_16BIT) -#define CCS_R_VT_SYS_CLK_DIV (0x0302 | CCS_FL_16BIT) -#define CCS_R_PRE_PLL_CLK_DIV (0x0304 | CCS_FL_16BIT) -#define CCS_R_PLL_MULTIPLIER (0x0306 | CCS_FL_16BIT) -#define CCS_R_OP_PIX_CLK_DIV (0x0308 | CCS_FL_16BIT) -#define CCS_R_OP_SYS_CLK_DIV (0x030a | CCS_FL_16BIT) -#define CCS_R_OP_PRE_PLL_CLK_DIV (0x030c | CCS_FL_16BIT) -#define CCS_R_OP_PLL_MULTIPLIER (0x031e | CCS_FL_16BIT) -#define CCS_R_PLL_MODE 0x0310 -#define CCS_PLL_MODE_SHIFT 0U -#define CCS_PLL_MODE_MASK 0x1 -#define CCS_PLL_MODE_SINGLE 0U -#define CCS_PLL_MODE_DUAL 1U -#define CCS_R_OP_PIX_CLK_DIV_REV (0x0312 | CCS_FL_16BIT) -#define CCS_R_OP_SYS_CLK_DIV_REV (0x0314 | CCS_FL_16BIT) -#define CCS_R_FRAME_LENGTH_LINES (0x0340 | CCS_FL_16BIT) -#define CCS_R_LINE_LENGTH_PCK (0x0342 | CCS_FL_16BIT) -#define CCS_R_X_ADDR_START (0x0344 | CCS_FL_16BIT) -#define CCS_R_Y_ADDR_START (0x0346 | CCS_FL_16BIT) -#define CCS_R_X_ADDR_END (0x0348 | CCS_FL_16BIT) -#define CCS_R_Y_ADDR_END (0x034a | CCS_FL_16BIT) -#define CCS_R_X_OUTPUT_SIZE (0x034c | CCS_FL_16BIT) -#define CCS_R_Y_OUTPUT_SIZE (0x034e | CCS_FL_16BIT) -#define CCS_R_FRAME_LENGTH_CTRL 0x0350 -#define CCS_FRAME_LENGTH_CTRL_AUTOMATIC BIT(0) -#define CCS_R_TIMING_MODE_CTRL 0x0352 -#define CCS_TIMING_MODE_CTRL_MANUAL_READOUT BIT(0) -#define CCS_TIMING_MODE_CTRL_DELAYED_EXPOSURE BIT(1) -#define CCS_R_START_READOUT_RS 0x0353 -#define CCS_START_READOUT_RS_MANUAL_READOUT_START BIT(0) -#define CCS_R_FRAME_MARGIN (0x0354 | CCS_FL_16BIT) -#define CCS_R_X_EVEN_INC (0x0380 | CCS_FL_16BIT) -#define CCS_R_X_ODD_INC (0x0382 | CCS_FL_16BIT) -#define CCS_R_Y_EVEN_INC (0x0384 | CCS_FL_16BIT) -#define CCS_R_Y_ODD_INC (0x0386 | CCS_FL_16BIT) -#define CCS_R_MONOCHROME_EN 0x0390 -#define CCS_MONOCHROME_EN_ENABLED 0U -#define CCS_R_SCALING_MODE (0x0400 | CCS_FL_16BIT) -#define CCS_SCALING_MODE_NO_SCALING 0U -#define CCS_SCALING_MODE_HORIZONTAL 1U -#define CCS_R_SCALE_M (0x0404 | CCS_FL_16BIT) -#define CCS_R_SCALE_N (0x0406 | CCS_FL_16BIT) -#define CCS_R_DIGITAL_CROP_X_OFFSET (0x0408 | CCS_FL_16BIT) -#define CCS_R_DIGITAL_CROP_Y_OFFSET (0x040a | CCS_FL_16BIT) -#define CCS_R_DIGITAL_CROP_IMAGE_WIDTH (0x040c | CCS_FL_16BIT) -#define CCS_R_DIGITAL_CROP_IMAGE_HEIGHT (0x040e | CCS_FL_16BIT) -#define CCS_R_COMPRESSION_MODE (0x0500 | CCS_FL_16BIT) -#define CCS_COMPRESSION_MODE_NONE 0U -#define CCS_COMPRESSION_MODE_DPCM_PCM_SIMPLE 1U -#define CCS_R_TEST_PATTERN_MODE (0x0600 | CCS_FL_16BIT) -#define CCS_TEST_PATTERN_MODE_NONE 0U -#define CCS_TEST_PATTERN_MODE_SOLID_COLOR 1U -#define CCS_TEST_PATTERN_MODE_COLOR_BARS 2U -#define CCS_TEST_PATTERN_MODE_FADE_TO_GREY 3U -#define CCS_TEST_PATTERN_MODE_PN9 4U -#define CCS_TEST_PATTERN_MODE_COLOR_TILE 5U -#define CCS_R_TEST_DATA_RED (0x0602 | CCS_FL_16BIT) -#define CCS_R_TEST_DATA_GREENR (0x0604 | CCS_FL_16BIT) -#define CCS_R_TEST_DATA_BLUE (0x0606 | CCS_FL_16BIT) -#define CCS_R_TEST_DATA_GREENB (0x0608 | CCS_FL_16BIT) -#define CCS_R_VALUE_STEP_SIZE_SMOOTH 0x060a -#define CCS_R_VALUE_STEP_SIZE_QUANTISED 0x060b -#define CCS_R_TCLK_POST 0x0800 -#define CCS_R_THS_PREPARE 0x0801 -#define CCS_R_THS_ZERO_MIN 0x0802 -#define CCS_R_THS_TRAIL 0x0803 -#define CCS_R_TCLK_TRAIL_MIN 0x0804 -#define CCS_R_TCLK_PREPARE 0x0805 -#define CCS_R_TCLK_ZERO 0x0806 -#define CCS_R_TLPX 0x0807 -#define CCS_R_PHY_CTRL 0x0808 -#define CCS_PHY_CTRL_AUTO 0U -#define CCS_PHY_CTRL_UI 1U -#define CCS_PHY_CTRL_MANUAL 2U -#define CCS_R_TCLK_POST_EX (0x080a | CCS_FL_16BIT) -#define CCS_R_THS_PREPARE_EX (0x080c | CCS_FL_16BIT) -#define CCS_R_THS_ZERO_MIN_EX (0x080e | CCS_FL_16BIT) -#define CCS_R_THS_TRAIL_EX (0x0810 | CCS_FL_16BIT) -#define CCS_R_TCLK_TRAIL_MIN_EX (0x0812 | CCS_FL_16BIT) -#define CCS_R_TCLK_PREPARE_EX (0x0814 | CCS_FL_16BIT) -#define CCS_R_TCLK_ZERO_EX (0x0816 | CCS_FL_16BIT) -#define CCS_R_TLPX_EX (0x0818 | CCS_FL_16BIT) -#define CCS_R_REQUESTED_LINK_RATE (0x0820 | CCS_FL_32BIT) -#define CCS_R_DPHY_EQUALIZATION_MODE 0x0824 -#define CCS_DPHY_EQUALIZATION_MODE_EQ2 BIT(0) -#define CCS_R_PHY_EQUALIZATION_CTRL 0x0825 -#define CCS_PHY_EQUALIZATION_CTRL_ENABLE BIT(0) -#define CCS_R_DPHY_PREAMBLE_CTRL 0x0826 -#define CCS_DPHY_PREAMBLE_CTRL_ENABLE BIT(0) -#define CCS_R_DPHY_PREAMBLE_LENGTH 0x0826 -#define CCS_R_PHY_SSC_CTRL 0x0828 -#define CCS_PHY_SSC_CTRL_ENABLE BIT(0) -#define CCS_R_MANUAL_LP_CTRL 0x0829 -#define CCS_MANUAL_LP_CTRL_ENABLE BIT(0) -#define CCS_R_TWAKEUP 0x082a -#define CCS_R_TINIT 0x082b -#define CCS_R_THS_EXIT 0x082c -#define CCS_R_THS_EXIT_EX (0x082e | CCS_FL_16BIT) -#define CCS_R_PHY_PERIODIC_CALIBRATION_CTRL 0x0830 -#define CCS_PHY_PERIODIC_CALIBRATION_CTRL_FRAME_BLANKING BIT(0) -#define CCS_R_PHY_PERIODIC_CALIBRATION_INTERVAL 0x0831 -#define CCS_R_PHY_INIT_CALIBRATION_CTRL 0x0832 -#define CCS_PHY_INIT_CALIBRATION_CTRL_STREAM_START BIT(0) -#define CCS_R_DPHY_CALIBRATION_MODE 0x0833 -#define CCS_DPHY_CALIBRATION_MODE_ALSO_ALTERNATE BIT(0) -#define CCS_R_CPHY_CALIBRATION_MODE 0x0834 -#define CCS_CPHY_CALIBRATION_MODE_FORMAT_1 0U -#define CCS_CPHY_CALIBRATION_MODE_FORMAT_2 1U -#define CCS_CPHY_CALIBRATION_MODE_FORMAT_3 2U -#define CCS_R_T3_CALPREAMBLE_LENGTH 0x0835 -#define CCS_R_T3_CALPREAMBLE_LENGTH_PER 0x0836 -#define CCS_R_T3_CALALTSEQ_LENGTH 0x0837 -#define CCS_R_T3_CALALTSEQ_LENGTH_PER 0x0838 -#define CCS_R_FM2_INIT_SEED (0x083a | CCS_FL_16BIT) -#define CCS_R_T3_CALUDEFSEQ_LENGTH (0x083c | CCS_FL_16BIT) -#define CCS_R_T3_CALUDEFSEQ_LENGTH_PER (0x083e | CCS_FL_16BIT) -#define CCS_R_TGR_PREAMBLE_LENGTH 0x0841 -#define CCS_TGR_PREAMBLE_LENGTH_PREAMABLE_PROG_SEQ BIT(7) -#define CCS_TGR_PREAMBLE_LENGTH_BEGIN_PREAMBLE_LENGTH_SHIFT 0U -#define CCS_TGR_PREAMBLE_LENGTH_BEGIN_PREAMBLE_LENGTH_MASK 0x3f -#define CCS_R_TGR_POST_LENGTH 0x0842 -#define CCS_TGR_POST_LENGTH_POST_LENGTH_SHIFT 0U -#define CCS_TGR_POST_LENGTH_POST_LENGTH_MASK 0x1f -#define CCS_R_TGR_PREAMBLE_PROG_SEQUENCE(n2) (0x0843 + (n2)) -#define CCS_LIM_TGR_PREAMBLE_PROG_SEQUENCE_MIN_N2 0U -#define CCS_LIM_TGR_PREAMBLE_PROG_SEQUENCE_MAX_N2 6U -#define CCS_TGR_PREAMBLE_PROG_SEQUENCE_SYMBOL_N_1_SHIFT 3U -#define CCS_TGR_PREAMBLE_PROG_SEQUENCE_SYMBOL_N_1_MASK 0x38 -#define CCS_TGR_PREAMBLE_PROG_SEQUENCE_SYMBOL_N_SHIFT 0U -#define CCS_TGR_PREAMBLE_PROG_SEQUENCE_SYMBOL_N_MASK 0x7 -#define CCS_R_T3_PREPARE (0x084e | CCS_FL_16BIT) -#define CCS_R_T3_LPX (0x0850 | CCS_FL_16BIT) -#define CCS_R_ALPS_CTRL 0x085a -#define CCS_ALPS_CTRL_LVLP_DPHY BIT(0) -#define CCS_ALPS_CTRL_LVLP_CPHY BIT(1) -#define CCS_ALPS_CTRL_ALP_CPHY BIT(2) -#define CCS_R_TX_REG_CSI_EPD_EN_SSP_CPHY (0x0860 | CCS_FL_16BIT) -#define CCS_R_TX_REG_CSI_EPD_OP_SLP_CPHY (0x0862 | CCS_FL_16BIT) -#define CCS_R_TX_REG_CSI_EPD_EN_SSP_DPHY (0x0864 | CCS_FL_16BIT) -#define CCS_R_TX_REG_CSI_EPD_OP_SLP_DPHY (0x0866 | CCS_FL_16BIT) -#define CCS_R_TX_REG_CSI_EPD_MISC_OPTION_CPHY 0x0868 -#define CCS_R_TX_REG_CSI_EPD_MISC_OPTION_DPHY 0x0869 -#define CCS_R_SCRAMBLING_CTRL 0x0870 -#define CCS_SCRAMBLING_CTRL_ENABLED BIT(0) -#define CCS_SCRAMBLING_CTRL_SHIFT 2U -#define CCS_SCRAMBLING_CTRL_MASK 0xc -#define CCS_SCRAMBLING_CTRL_1_SEED_CPHY 0U -#define CCS_SCRAMBLING_CTRL_4_SEED_CPHY 3U -#define CCS_R_LANE_SEED_VALUE(seed, lane) ((0x0872 | CCS_FL_16BIT) + (seed) * 16 + (lane) * 2) -#define CCS_LIM_LANE_SEED_VALUE_MIN_SEED 0U -#define CCS_LIM_LANE_SEED_VALUE_MAX_SEED 3U -#define CCS_LIM_LANE_SEED_VALUE_MIN_LANE 0U -#define CCS_LIM_LANE_SEED_VALUE_MAX_LANE 7U -#define CCS_R_TX_USL_REV_ENTRY (0x08c0 | CCS_FL_16BIT) -#define CCS_R_TX_USL_REV_CLOCK_COUNTER (0x08c2 | CCS_FL_16BIT) -#define CCS_R_TX_USL_REV_LP_COUNTER (0x08c4 | CCS_FL_16BIT) -#define CCS_R_TX_USL_REV_FRAME_COUNTER (0x08c6 | CCS_FL_16BIT) -#define CCS_R_TX_USL_REV_CHRONOLOGICAL_TIMER (0x08c8 | CCS_FL_16BIT) -#define CCS_R_TX_USL_FWD_ENTRY (0x08ca | CCS_FL_16BIT) -#define CCS_R_TX_USL_GPIO (0x08cc | CCS_FL_16BIT) -#define CCS_R_TX_USL_OPERATION (0x08ce | CCS_FL_16BIT) -#define CCS_TX_USL_OPERATION_RESET BIT(0) -#define CCS_R_TX_USL_ALP_CTRL (0x08d0 | CCS_FL_16BIT) -#define CCS_TX_USL_ALP_CTRL_CLOCK_PAUSE BIT(0) -#define CCS_R_TX_USL_APP_BTA_ACK_TIMEOUT (0x08d2 | CCS_FL_16BIT) -#define CCS_R_TX_USL_SNS_BTA_ACK_TIMEOUT (0x08d2 | CCS_FL_16BIT) -#define CCS_R_USL_CLOCK_MODE_D_CTRL 0x08d2 -#define CCS_USL_CLOCK_MODE_D_CTRL_CONT_CLOCK_STANDBY BIT(0) -#define CCS_USL_CLOCK_MODE_D_CTRL_CONT_CLOCK_VBLANK BIT(1) -#define CCS_USL_CLOCK_MODE_D_CTRL_CONT_CLOCK_HBLANK BIT(2) -#define CCS_R_BINNING_MODE 0x0900 -#define CCS_R_BINNING_TYPE 0x0901 -#define CCS_R_BINNING_WEIGHTING 0x0902 -#define CCS_R_DATA_TRANSFER_IF_1_CTRL 0x0a00 -#define CCS_DATA_TRANSFER_IF_1_CTRL_ENABLE BIT(0) -#define CCS_DATA_TRANSFER_IF_1_CTRL_WRITE BIT(1) -#define CCS_DATA_TRANSFER_IF_1_CTRL_CLEAR_ERROR BIT(2) -#define CCS_R_DATA_TRANSFER_IF_1_STATUS 0x0a01 -#define CCS_DATA_TRANSFER_IF_1_STATUS_READ_IF_READY BIT(0) -#define CCS_DATA_TRANSFER_IF_1_STATUS_WRITE_IF_READY BIT(1) -#define CCS_DATA_TRANSFER_IF_1_STATUS_DATA_CORRUPTED BIT(2) -#define CCS_DATA_TRANSFER_IF_1_STATUS_IMPROPER_IF_USAGE BIT(3) -#define CCS_R_DATA_TRANSFER_IF_1_PAGE_SELECT 0x0a02 -#define CCS_R_DATA_TRANSFER_IF_1_DATA(p) (0x0a04 + (p)) -#define CCS_LIM_DATA_TRANSFER_IF_1_DATA_MIN_P 0U -#define CCS_LIM_DATA_TRANSFER_IF_1_DATA_MAX_P 63U -#define CCS_R_SHADING_CORRECTION_EN 0x0b00 -#define CCS_SHADING_CORRECTION_EN_ENABLE BIT(0) -#define CCS_R_LUMINANCE_CORRECTION_LEVEL 0x0b01 -#define CCS_R_GREEN_IMBALANCE_FILTER_EN 0x0b02 -#define CCS_GREEN_IMBALANCE_FILTER_EN_ENABLE BIT(0) -#define CCS_R_MAPPED_DEFECT_CORRECT_EN 0x0b05 -#define CCS_MAPPED_DEFECT_CORRECT_EN_ENABLE BIT(0) -#define CCS_R_SINGLE_DEFECT_CORRECT_EN 0x0b06 -#define CCS_SINGLE_DEFECT_CORRECT_EN_ENABLE BIT(0) -#define CCS_R_DYNAMIC_COUPLET_CORRECT_EN 0x0b08 -#define CCS_DYNAMIC_COUPLET_CORRECT_EN_ENABLE BIT(0) -#define CCS_R_COMBINED_DEFECT_CORRECT_EN 0x0b0a -#define CCS_COMBINED_DEFECT_CORRECT_EN_ENABLE BIT(0) -#define CCS_R_MODULE_SPECIFIC_CORRECTION_EN 0x0b0c -#define CCS_MODULE_SPECIFIC_CORRECTION_EN_ENABLE BIT(0) -#define CCS_R_DYNAMIC_TRIPLET_DEFECT_CORRECT_EN 0x0b13 -#define CCS_DYNAMIC_TRIPLET_DEFECT_CORRECT_EN_ENABLE BIT(0) -#define CCS_R_NF_CTRL 0x0b15 -#define CCS_NF_CTRL_LUMA BIT(0) -#define CCS_NF_CTRL_CHROMA BIT(1) -#define CCS_NF_CTRL_COMBINED BIT(2) -#define CCS_R_OB_READOUT_CONTROL 0x0b30 -#define CCS_OB_READOUT_CONTROL_ENABLE BIT(0) -#define CCS_OB_READOUT_CONTROL_INTERLEAVING BIT(1) -#define CCS_R_OB_VIRTUAL_CHANNEL 0x0b31 -#define CCS_R_OB_DT 0x0b32 -#define CCS_R_OB_DATA_FORMAT 0x0b33 -#define CCS_R_COLOR_TEMPERATURE (0x0b8c | CCS_FL_16BIT) -#define CCS_R_ABSOLUTE_GAIN_GREENR (0x0b8e | CCS_FL_16BIT) -#define CCS_R_ABSOLUTE_GAIN_RED (0x0b90 | CCS_FL_16BIT) -#define CCS_R_ABSOLUTE_GAIN_BLUE (0x0b92 | CCS_FL_16BIT) -#define CCS_R_ABSOLUTE_GAIN_GREENB (0x0b94 | CCS_FL_16BIT) -#define CCS_R_CFA_CONVERSION_CTRL 0x0ba0 -#define CCS_CFA_CONVERSION_CTRL_BAYER_CONVERSION_ENABLE BIT(0) -#define CCS_R_FLASH_STROBE_ADJUSTMENT 0x0c12 -#define CCS_R_FLASH_STROBE_START_POINT (0x0c14 | CCS_FL_16BIT) -#define CCS_R_TFLASH_STROBE_DELAY_RS_CTRL (0x0c16 | CCS_FL_16BIT) -#define CCS_R_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL (0x0c18 | CCS_FL_16BIT) -#define CCS_R_FLASH_MODE_RS 0x0c1a -#define CCS_FLASH_MODE_RS_CONTINUOUS BIT(0) -#define CCS_FLASH_MODE_RS_TRUNCATE BIT(1) -#define CCS_FLASH_MODE_RS_ASYNC BIT(3) -#define CCS_R_FLASH_TRIGGER_RS 0x0c1b -#define CCS_R_FLASH_STATUS 0x0c1c -#define CCS_FLASH_STATUS_RETIMED BIT(0) -#define CCS_R_SA_STROBE_MODE 0x0c1d -#define CCS_SA_STROBE_MODE_CONTINUOUS BIT(0) -#define CCS_SA_STROBE_MODE_TRUNCATE BIT(1) -#define CCS_SA_STROBE_MODE_ASYNC BIT(3) -#define CCS_SA_STROBE_MODE_ADJUST_EDGE BIT(4) -#define CCS_R_SA_STROBE_START_POINT (0x0c1e | CCS_FL_16BIT) -#define CCS_R_TSA_STROBE_DELAY_CTRL (0x0c20 | CCS_FL_16BIT) -#define CCS_R_TSA_STROBE_WIDTH_CTRL (0x0c22 | CCS_FL_16BIT) -#define CCS_R_SA_STROBE_TRIGGER 0x0c24 -#define CCS_R_SA_STROBE_STATUS 0x0c25 -#define CCS_SA_STROBE_STATUS_RETIMED BIT(0) -#define CCS_R_TSA_STROBE_RE_DELAY_CTRL (0x0c30 | CCS_FL_16BIT) -#define CCS_R_TSA_STROBE_FE_DELAY_CTRL (0x0c32 | CCS_FL_16BIT) -#define CCS_R_PDAF_CTRL (0x0d00 | CCS_FL_16BIT) -#define CCS_PDAF_CTRL_ENABLE BIT(0) -#define CCS_PDAF_CTRL_PROCESSED BIT(1) -#define CCS_PDAF_CTRL_INTERLEAVED BIT(2) -#define CCS_PDAF_CTRL_VISIBLE_PDAF_CORRECTION BIT(3) -#define CCS_R_PDAF_VC 0x0d02 -#define CCS_R_PDAF_DT 0x0d03 -#define CCS_R_PD_X_ADDR_START (0x0d04 | CCS_FL_16BIT) -#define CCS_R_PD_Y_ADDR_START (0x0d06 | CCS_FL_16BIT) -#define CCS_R_PD_X_ADDR_END (0x0d08 | CCS_FL_16BIT) -#define CCS_R_PD_Y_ADDR_END (0x0d0a | CCS_FL_16BIT) -#define CCS_R_BRACKETING_LUT_CTRL 0x0e00 -#define CCS_R_BRACKETING_LUT_MODE 0x0e01 -#define CCS_BRACKETING_LUT_MODE_CONTINUE_STREAMING BIT(0) -#define CCS_BRACKETING_LUT_MODE_LOOP_MODE BIT(1) -#define CCS_R_BRACKETING_LUT_ENTRY_CTRL 0x0e02 -#define CCS_R_BRACKETING_LUT_FRAME(n) (0x0e10 + (n)) -#define CCS_LIM_BRACKETING_LUT_FRAME_MIN_N 0U -#define CCS_LIM_BRACKETING_LUT_FRAME_MAX_N 239U -#define CCS_R_INTEGRATION_TIME_CAPABILITY (0x1000 | CCS_FL_16BIT) -#define CCS_INTEGRATION_TIME_CAPABILITY_FINE BIT(0) -#define CCS_R_COARSE_INTEGRATION_TIME_MIN (0x1004 | CCS_FL_16BIT) -#define CCS_R_COARSE_INTEGRATION_TIME_MAX_MARGIN (0x1006 | CCS_FL_16BIT) -#define CCS_R_FINE_INTEGRATION_TIME_MIN (0x1008 | CCS_FL_16BIT) -#define CCS_R_FINE_INTEGRATION_TIME_MAX_MARGIN (0x100a | CCS_FL_16BIT) -#define CCS_R_DIGITAL_GAIN_CAPABILITY 0x1081 -#define CCS_DIGITAL_GAIN_CAPABILITY_NONE 0U -#define CCS_DIGITAL_GAIN_CAPABILITY_GLOBAL 2U -#define CCS_R_DIGITAL_GAIN_MIN (0x1084 | CCS_FL_16BIT) -#define CCS_R_DIGITAL_GAIN_MAX (0x1086 | CCS_FL_16BIT) -#define CCS_R_DIGITAL_GAIN_STEP_SIZE (0x1088 | CCS_FL_16BIT) -#define CCS_R_PEDESTAL_CAPABILITY 0x10e0 -#define CCS_R_ADC_CAPABILITY 0x10f0 -#define CCS_ADC_CAPABILITY_BIT_DEPTH_CTRL BIT(0) -#define CCS_R_ADC_BIT_DEPTH_CAPABILITY (0x10f4 | CCS_FL_32BIT) -#define CCS_R_MIN_EXT_CLK_FREQ_MHZ (0x1100 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MAX_EXT_CLK_FREQ_MHZ (0x1104 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MIN_PRE_PLL_CLK_DIV (0x1108 | CCS_FL_16BIT) -#define CCS_R_MAX_PRE_PLL_CLK_DIV (0x110a | CCS_FL_16BIT) -#define CCS_R_MIN_PLL_IP_CLK_FREQ_MHZ (0x110c | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MAX_PLL_IP_CLK_FREQ_MHZ (0x1110 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MIN_PLL_MULTIPLIER (0x1114 | CCS_FL_16BIT) -#define CCS_R_MAX_PLL_MULTIPLIER (0x1116 | CCS_FL_16BIT) -#define CCS_R_MIN_PLL_OP_CLK_FREQ_MHZ (0x1118 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MAX_PLL_OP_CLK_FREQ_MHZ (0x111c | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MIN_VT_SYS_CLK_DIV (0x1120 | CCS_FL_16BIT) -#define CCS_R_MAX_VT_SYS_CLK_DIV (0x1122 | CCS_FL_16BIT) -#define CCS_R_MIN_VT_SYS_CLK_FREQ_MHZ (0x1124 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MAX_VT_SYS_CLK_FREQ_MHZ (0x1128 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MIN_VT_PIX_CLK_FREQ_MHZ (0x112c | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MAX_VT_PIX_CLK_FREQ_MHZ (0x1130 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MIN_VT_PIX_CLK_DIV (0x1134 | CCS_FL_16BIT) -#define CCS_R_MAX_VT_PIX_CLK_DIV (0x1136 | CCS_FL_16BIT) -#define CCS_R_CLOCK_CALCULATION 0x1138 -#define CCS_CLOCK_CALCULATION_LANE_SPEED BIT(0) -#define CCS_CLOCK_CALCULATION_LINK_DECOUPLED BIT(1) -#define CCS_CLOCK_CALCULATION_DUAL_PLL_OP_SYS_DDR BIT(2) -#define CCS_CLOCK_CALCULATION_DUAL_PLL_OP_PIX_DDR BIT(3) -#define CCS_R_NUM_OF_VT_LANES 0x1139 -#define CCS_R_NUM_OF_OP_LANES 0x113a -#define CCS_R_OP_BITS_PER_LANE 0x113b -#define CCS_R_MIN_FRAME_LENGTH_LINES (0x1140 | CCS_FL_16BIT) -#define CCS_R_MAX_FRAME_LENGTH_LINES (0x1142 | CCS_FL_16BIT) -#define CCS_R_MIN_LINE_LENGTH_PCK (0x1144 | CCS_FL_16BIT) -#define CCS_R_MAX_LINE_LENGTH_PCK (0x1146 | CCS_FL_16BIT) -#define CCS_R_MIN_LINE_BLANKING_PCK (0x1148 | CCS_FL_16BIT) -#define CCS_R_MIN_FRAME_BLANKING_LINES (0x114a | CCS_FL_16BIT) -#define CCS_R_MIN_LINE_LENGTH_PCK_STEP_SIZE 0x114c -#define CCS_R_TIMING_MODE_CAPABILITY 0x114d -#define CCS_TIMING_MODE_CAPABILITY_AUTO_FRAME_LENGTH BIT(0) -#define CCS_TIMING_MODE_CAPABILITY_ROLLING_SHUTTER_MANUAL_READOUT BIT(2) -#define CCS_TIMING_MODE_CAPABILITY_DELAYED_EXPOSURE_START BIT(3) -#define CCS_TIMING_MODE_CAPABILITY_MANUAL_EXPOSURE_EMBEDDED_DATA BIT(4) -#define CCS_R_FRAME_MARGIN_MAX_VALUE (0x114e | CCS_FL_16BIT) -#define CCS_R_FRAME_MARGIN_MIN_VALUE 0x1150 -#define CCS_R_GAIN_DELAY_TYPE 0x1151 -#define CCS_GAIN_DELAY_TYPE_FIXED 0U -#define CCS_GAIN_DELAY_TYPE_VARIABLE 1U -#define CCS_R_MIN_OP_SYS_CLK_DIV (0x1160 | CCS_FL_16BIT) -#define CCS_R_MAX_OP_SYS_CLK_DIV (0x1162 | CCS_FL_16BIT) -#define CCS_R_MIN_OP_SYS_CLK_FREQ_MHZ (0x1164 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MAX_OP_SYS_CLK_FREQ_MHZ (0x1168 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MIN_OP_PIX_CLK_DIV (0x116c | CCS_FL_16BIT) -#define CCS_R_MAX_OP_PIX_CLK_DIV (0x116e | CCS_FL_16BIT) -#define CCS_R_MIN_OP_PIX_CLK_FREQ_MHZ (0x1170 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MAX_OP_PIX_CLK_FREQ_MHZ (0x1174 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_X_ADDR_MIN (0x1180 | CCS_FL_16BIT) -#define CCS_R_Y_ADDR_MIN (0x1182 | CCS_FL_16BIT) -#define CCS_R_X_ADDR_MAX (0x1184 | CCS_FL_16BIT) -#define CCS_R_Y_ADDR_MAX (0x1186 | CCS_FL_16BIT) -#define CCS_R_MIN_X_OUTPUT_SIZE (0x1188 | CCS_FL_16BIT) -#define CCS_R_MIN_Y_OUTPUT_SIZE (0x118a | CCS_FL_16BIT) -#define CCS_R_MAX_X_OUTPUT_SIZE (0x118c | CCS_FL_16BIT) -#define CCS_R_MAX_Y_OUTPUT_SIZE (0x118e | CCS_FL_16BIT) -#define CCS_R_X_ADDR_START_DIV_CONSTANT 0x1190 -#define CCS_R_Y_ADDR_START_DIV_CONSTANT 0x1191 -#define CCS_R_X_ADDR_END_DIV_CONSTANT 0x1192 -#define CCS_R_Y_ADDR_END_DIV_CONSTANT 0x1193 -#define CCS_R_X_SIZE_DIV 0x1194 -#define CCS_R_Y_SIZE_DIV 0x1195 -#define CCS_R_X_OUTPUT_DIV 0x1196 -#define CCS_R_Y_OUTPUT_DIV 0x1197 -#define CCS_R_NON_FLEXIBLE_RESOLUTION_SUPPORT 0x1198 -#define CCS_NON_FLEXIBLE_RESOLUTION_SUPPORT_NEW_PIX_ADDR BIT(0) -#define CCS_NON_FLEXIBLE_RESOLUTION_SUPPORT_NEW_OUTPUT_RES BIT(1) -#define CCS_NON_FLEXIBLE_RESOLUTION_SUPPORT_OUTPUT_CROP_NO_PAD BIT(2) -#define CCS_NON_FLEXIBLE_RESOLUTION_SUPPORT_OUTPUT_SIZE_LANE_DEP BIT(3) -#define CCS_R_MIN_OP_PRE_PLL_CLK_DIV (0x11a0 | CCS_FL_16BIT) -#define CCS_R_MAX_OP_PRE_PLL_CLK_DIV (0x11a2 | CCS_FL_16BIT) -#define CCS_R_MIN_OP_PLL_IP_CLK_FREQ_MHZ (0x11a4 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MAX_OP_PLL_IP_CLK_FREQ_MHZ (0x11a8 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MIN_OP_PLL_MULTIPLIER (0x11ac | CCS_FL_16BIT) -#define CCS_R_MAX_OP_PLL_MULTIPLIER (0x11ae | CCS_FL_16BIT) -#define CCS_R_MIN_OP_PLL_OP_CLK_FREQ_MHZ (0x11b0 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MAX_OP_PLL_OP_CLK_FREQ_MHZ (0x11b4 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_CLOCK_TREE_PLL_CAPABILITY 0x11b8 -#define CCS_CLOCK_TREE_PLL_CAPABILITY_DUAL_PLL BIT(0) -#define CCS_CLOCK_TREE_PLL_CAPABILITY_SINGLE_PLL BIT(1) -#define CCS_CLOCK_TREE_PLL_CAPABILITY_EXT_DIVIDER BIT(2) -#define CCS_CLOCK_TREE_PLL_CAPABILITY_FLEXIBLE_OP_PIX_CLK_DIV BIT(3) -#define CCS_R_CLOCK_CAPA_TYPE_CAPABILITY 0x11b9 -#define CCS_CLOCK_CAPA_TYPE_CAPABILITY_IREAL BIT(0) -#define CCS_R_MIN_EVEN_INC (0x11c0 | CCS_FL_16BIT) -#define CCS_R_MIN_ODD_INC (0x11c2 | CCS_FL_16BIT) -#define CCS_R_MAX_EVEN_INC (0x11c4 | CCS_FL_16BIT) -#define CCS_R_MAX_ODD_INC (0x11c6 | CCS_FL_16BIT) -#define CCS_R_AUX_SUBSAMP_CAPABILITY 0x11c8 -#define CCS_AUX_SUBSAMP_CAPABILITY_FACTOR_POWER_OF_2 BIT(1) -#define CCS_R_AUX_SUBSAMP_MONO_CAPABILITY 0x11c9 -#define CCS_AUX_SUBSAMP_MONO_CAPABILITY_FACTOR_POWER_OF_2 BIT(1) -#define CCS_R_MONOCHROME_CAPABILITY 0x11ca -#define CCS_MONOCHROME_CAPABILITY_INC_ODD 0U -#define CCS_MONOCHROME_CAPABILITY_INC_EVEN 1U -#define CCS_R_PIXEL_READOUT_CAPABILITY 0x11cb -#define CCS_PIXEL_READOUT_CAPABILITY_BAYER 0U -#define CCS_PIXEL_READOUT_CAPABILITY_MONOCHROME 1U -#define CCS_PIXEL_READOUT_CAPABILITY_BAYER_AND_MONO 2U -#define CCS_R_MIN_EVEN_INC_MONO (0x11cc | CCS_FL_16BIT) -#define CCS_R_MAX_EVEN_INC_MONO (0x11ce | CCS_FL_16BIT) -#define CCS_R_MIN_ODD_INC_MONO (0x11d0 | CCS_FL_16BIT) -#define CCS_R_MAX_ODD_INC_MONO (0x11d2 | CCS_FL_16BIT) -#define CCS_R_MIN_EVEN_INC_BC2 (0x11d4 | CCS_FL_16BIT) -#define CCS_R_MAX_EVEN_INC_BC2 (0x11d6 | CCS_FL_16BIT) -#define CCS_R_MIN_ODD_INC_BC2 (0x11d8 | CCS_FL_16BIT) -#define CCS_R_MAX_ODD_INC_BC2 (0x11da | CCS_FL_16BIT) -#define CCS_R_MIN_EVEN_INC_MONO_BC2 (0x11dc | CCS_FL_16BIT) -#define CCS_R_MAX_EVEN_INC_MONO_BC2 (0x11de | CCS_FL_16BIT) -#define CCS_R_MIN_ODD_INC_MONO_BC2 (0x11f0 | CCS_FL_16BIT) -#define CCS_R_MAX_ODD_INC_MONO_BC2 (0x11f2 | CCS_FL_16BIT) -#define CCS_R_SCALING_CAPABILITY (0x1200 | CCS_FL_16BIT) -#define CCS_SCALING_CAPABILITY_NONE 0U -#define CCS_SCALING_CAPABILITY_HORIZONTAL 1U -#define CCS_SCALING_CAPABILITY_RESERVED 2U -#define CCS_R_SCALER_M_MIN (0x1204 | CCS_FL_16BIT) -#define CCS_R_SCALER_M_MAX (0x1206 | CCS_FL_16BIT) -#define CCS_R_SCALER_N_MIN (0x1208 | CCS_FL_16BIT) -#define CCS_R_SCALER_N_MAX (0x120a | CCS_FL_16BIT) -#define CCS_R_DIGITAL_CROP_CAPABILITY 0x120e -#define CCS_DIGITAL_CROP_CAPABILITY_NONE 0U -#define CCS_DIGITAL_CROP_CAPABILITY_INPUT_CROP 1U -#define CCS_R_HDR_CAPABILITY_1 0x1210 -#define CCS_HDR_CAPABILITY_1_2X2_BINNING BIT(0) -#define CCS_HDR_CAPABILITY_1_COMBINED_ANALOG_GAIN BIT(1) -#define CCS_HDR_CAPABILITY_1_SEPARATE_ANALOG_GAIN BIT(2) -#define CCS_HDR_CAPABILITY_1_UPSCALING BIT(3) -#define CCS_HDR_CAPABILITY_1_RESET_SYNC BIT(4) -#define CCS_HDR_CAPABILITY_1_DIRECT_SHORT_EXP_TIMING BIT(5) -#define CCS_HDR_CAPABILITY_1_DIRECT_SHORT_EXP_SYNTHESIS BIT(6) -#define CCS_R_MIN_HDR_BIT_DEPTH 0x1211 -#define CCS_R_HDR_RESOLUTION_SUB_TYPES 0x1212 -#define CCS_R_HDR_RESOLUTION_SUB_TYPE(n) (0x1213 + (n)) -#define CCS_LIM_HDR_RESOLUTION_SUB_TYPE_MIN_N 0U -#define CCS_LIM_HDR_RESOLUTION_SUB_TYPE_MAX_N 1U -#define CCS_HDR_RESOLUTION_SUB_TYPE_ROW_SHIFT 0U -#define CCS_HDR_RESOLUTION_SUB_TYPE_ROW_MASK 0xf -#define CCS_HDR_RESOLUTION_SUB_TYPE_COLUMN_SHIFT 4U -#define CCS_HDR_RESOLUTION_SUB_TYPE_COLUMN_MASK 0xf0 -#define CCS_R_HDR_CAPABILITY_2 0x121b -#define CCS_HDR_CAPABILITY_2_COMBINED_DIGITAL_GAIN BIT(0) -#define CCS_HDR_CAPABILITY_2_SEPARATE_DIGITAL_GAIN BIT(1) -#define CCS_HDR_CAPABILITY_2_TIMING_MODE BIT(3) -#define CCS_HDR_CAPABILITY_2_SYNTHESIS_MODE BIT(4) -#define CCS_R_MAX_HDR_BIT_DEPTH 0x121c -#define CCS_R_USL_SUPPORT_CAPABILITY 0x1230 -#define CCS_USL_SUPPORT_CAPABILITY_CLOCK_TREE BIT(0) -#define CCS_USL_SUPPORT_CAPABILITY_REV_CLOCK_TREE BIT(1) -#define CCS_USL_SUPPORT_CAPABILITY_REV_CLOCK_CALC BIT(2) -#define CCS_R_USL_CLOCK_MODE_D_CAPABILITY 0x1231 -#define CCS_USL_CLOCK_MODE_D_CAPABILITY_CONT_CLOCK_STANDBY BIT(0) -#define CCS_USL_CLOCK_MODE_D_CAPABILITY_CONT_CLOCK_VBLANK BIT(1) -#define CCS_USL_CLOCK_MODE_D_CAPABILITY_CONT_CLOCK_HBLANK BIT(2) -#define CCS_USL_CLOCK_MODE_D_CAPABILITY_NONCONT_CLOCK_STANDBY BIT(3) -#define CCS_USL_CLOCK_MODE_D_CAPABILITY_NONCONT_CLOCK_VBLANK BIT(4) -#define CCS_USL_CLOCK_MODE_D_CAPABILITY_NONCONT_CLOCK_HBLANK BIT(5) -#define CCS_R_MIN_OP_SYS_CLK_DIV_REV 0x1234 -#define CCS_R_MAX_OP_SYS_CLK_DIV_REV 0x1236 -#define CCS_R_MIN_OP_PIX_CLK_DIV_REV 0x1238 -#define CCS_R_MAX_OP_PIX_CLK_DIV_REV 0x123a -#define CCS_R_MIN_OP_SYS_CLK_FREQ_REV_MHZ (0x123c | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MAX_OP_SYS_CLK_FREQ_REV_MHZ (0x1240 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MIN_OP_PIX_CLK_FREQ_REV_MHZ (0x1244 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MAX_OP_PIX_CLK_FREQ_REV_MHZ (0x1248 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL)) -#define CCS_R_MAX_BITRATE_REV_D_MODE_MBPS (0x124c | (CCS_FL_32BIT | CCS_FL_IREAL)) -#define CCS_R_MAX_SYMRATE_REV_C_MODE_MSPS (0x1250 | (CCS_FL_32BIT | CCS_FL_IREAL)) -#define CCS_R_COMPRESSION_CAPABILITY 0x1300 -#define CCS_COMPRESSION_CAPABILITY_DPCM_PCM_SIMPLE BIT(0) -#define CCS_R_TEST_MODE_CAPABILITY (0x1310 | CCS_FL_16BIT) -#define CCS_TEST_MODE_CAPABILITY_SOLID_COLOR BIT(0) -#define CCS_TEST_MODE_CAPABILITY_COLOR_BARS BIT(1) -#define CCS_TEST_MODE_CAPABILITY_FADE_TO_GREY BIT(2) -#define CCS_TEST_MODE_CAPABILITY_PN9 BIT(3) -#define CCS_TEST_MODE_CAPABILITY_COLOR_TILE BIT(5) -#define CCS_R_PN9_DATA_FORMAT1 0x1312 -#define CCS_R_PN9_DATA_FORMAT2 0x1313 -#define CCS_R_PN9_DATA_FORMAT3 0x1314 -#define CCS_R_PN9_DATA_FORMAT4 0x1315 -#define CCS_R_PN9_MISC_CAPABILITY 0x1316 -#define CCS_PN9_MISC_CAPABILITY_NUM_PIXELS_SHIFT 0U -#define CCS_PN9_MISC_CAPABILITY_NUM_PIXELS_MASK 0x7 -#define CCS_PN9_MISC_CAPABILITY_COMPRESSION BIT(3) -#define CCS_R_TEST_PATTERN_CAPABILITY 0x1317 -#define CCS_TEST_PATTERN_CAPABILITY_NO_REPEAT BIT(1) -#define CCS_R_PATTERN_SIZE_DIV_M1 0x1318 -#define CCS_R_FIFO_SUPPORT_CAPABILITY 0x1502 -#define CCS_FIFO_SUPPORT_CAPABILITY_NONE 0U -#define CCS_FIFO_SUPPORT_CAPABILITY_DERATING 1U -#define CCS_FIFO_SUPPORT_CAPABILITY_DERATING_OVERRATING 2U -#define CCS_R_PHY_CTRL_CAPABILITY 0x1600 -#define CCS_PHY_CTRL_CAPABILITY_AUTO_PHY_CTL BIT(0) -#define CCS_PHY_CTRL_CAPABILITY_UI_PHY_CTL BIT(1) -#define CCS_PHY_CTRL_CAPABILITY_DPHY_TIME_UI_REG_1_CTL BIT(2) -#define CCS_PHY_CTRL_CAPABILITY_DPHY_TIME_UI_REG_2_CTL BIT(3) -#define CCS_PHY_CTRL_CAPABILITY_DPHY_TIME_CTL BIT(4) -#define CCS_PHY_CTRL_CAPABILITY_DPHY_EXT_TIME_UI_REG_1_CTL BIT(5) -#define CCS_PHY_CTRL_CAPABILITY_DPHY_EXT_TIME_UI_REG_2_CTL BIT(6) -#define CCS_PHY_CTRL_CAPABILITY_DPHY_EXT_TIME_CTL BIT(7) -#define CCS_R_CSI_DPHY_LANE_MODE_CAPABILITY 0x1601 -#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_1_LANE BIT(0) -#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_2_LANE BIT(1) -#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_3_LANE BIT(2) -#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_4_LANE BIT(3) -#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_5_LANE BIT(4) -#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_6_LANE BIT(5) -#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_7_LANE BIT(6) -#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_8_LANE BIT(7) -#define CCS_R_CSI_SIGNALING_MODE_CAPABILITY 0x1602 -#define CCS_CSI_SIGNALING_MODE_CAPABILITY_CSI_DPHY BIT(2) -#define CCS_CSI_SIGNALING_MODE_CAPABILITY_CSI_CPHY BIT(3) -#define CCS_R_FAST_STANDBY_CAPABILITY 0x1603 -#define CCS_FAST_STANDBY_CAPABILITY_NO_FRAME_TRUNCATION 0U -#define CCS_FAST_STANDBY_CAPABILITY_FRAME_TRUNCATION 1U -#define CCS_R_CSI_ADDRESS_CONTROL_CAPABILITY 0x1604 -#define CCS_CSI_ADDRESS_CONTROL_CAPABILITY_CCI_ADDR_CHANGE BIT(0) -#define CCS_CSI_ADDRESS_CONTROL_CAPABILITY_2ND_CCI_ADDR BIT(1) -#define CCS_CSI_ADDRESS_CONTROL_CAPABILITY_SW_CHANGEABLE_2ND_CCI_ADDR BIT(2) -#define CCS_R_DATA_TYPE_CAPABILITY 0x1605 -#define CCS_DATA_TYPE_CAPABILITY_DPCM_PROGRAMMABLE BIT(0) -#define CCS_DATA_TYPE_CAPABILITY_BOTTOM_EMBEDDED_DT_PROGRAMMABLE BIT(1) -#define CCS_DATA_TYPE_CAPABILITY_BOTTOM_EMBEDDED_VC_PROGRAMMABLE BIT(2) -#define CCS_DATA_TYPE_CAPABILITY_EXT_VC_RANGE BIT(3) -#define CCS_R_CSI_CPHY_LANE_MODE_CAPABILITY 0x1606 -#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_1_LANE BIT(0) -#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_2_LANE BIT(1) -#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_3_LANE BIT(2) -#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_4_LANE BIT(3) -#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_5_LANE BIT(4) -#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_6_LANE BIT(5) -#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_7_LANE BIT(6) -#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_8_LANE BIT(7) -#define CCS_R_EMB_DATA_CAPABILITY 0x1607 -#define CCS_EMB_DATA_CAPABILITY_TWO_BYTES_PER_RAW16 BIT(0) -#define CCS_EMB_DATA_CAPABILITY_TWO_BYTES_PER_RAW20 BIT(1) -#define CCS_EMB_DATA_CAPABILITY_TWO_BYTES_PER_RAW24 BIT(2) -#define CCS_EMB_DATA_CAPABILITY_NO_ONE_BYTE_PER_RAW16 BIT(3) -#define CCS_EMB_DATA_CAPABILITY_NO_ONE_BYTE_PER_RAW20 BIT(4) -#define CCS_EMB_DATA_CAPABILITY_NO_ONE_BYTE_PER_RAW24 BIT(5) -#define CCS_R_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS(n) ((0x1608 | (CCS_FL_32BIT | CCS_FL_IREAL)) + ((n) < 4 ? (n) * 4 : 0x32 + ((n) - 4) * 4)) -#define CCS_LIM_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS_MIN_N 0U -#define CCS_LIM_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS_MAX_N 7U -#define CCS_R_TEMP_SENSOR_CAPABILITY 0x1618 -#define CCS_TEMP_SENSOR_CAPABILITY_SUPPORTED BIT(0) -#define CCS_TEMP_SENSOR_CAPABILITY_CCS_FORMAT BIT(1) -#define CCS_TEMP_SENSOR_CAPABILITY_RESET_0X80 BIT(2) -#define CCS_R_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS(n) ((0x161a | (CCS_FL_32BIT | CCS_FL_IREAL)) + ((n) < 4 ? (n) * 4 : 0x30 + ((n) - 4) * 4)) -#define CCS_LIM_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS_MIN_N 0U -#define CCS_LIM_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS_MAX_N 7U -#define CCS_R_DPHY_EQUALIZATION_CAPABILITY 0x162b -#define CCS_DPHY_EQUALIZATION_CAPABILITY_EQUALIZATION_CTRL BIT(0) -#define CCS_DPHY_EQUALIZATION_CAPABILITY_EQ1 BIT(1) -#define CCS_DPHY_EQUALIZATION_CAPABILITY_EQ2 BIT(2) -#define CCS_R_CPHY_EQUALIZATION_CAPABILITY 0x162c -#define CCS_CPHY_EQUALIZATION_CAPABILITY_EQUALIZATION_CTRL BIT(0) -#define CCS_R_DPHY_PREAMBLE_CAPABILITY 0x162d -#define CCS_DPHY_PREAMBLE_CAPABILITY_PREAMBLE_SEQ_CTRL BIT(0) -#define CCS_R_DPHY_SSC_CAPABILITY 0x162e -#define CCS_DPHY_SSC_CAPABILITY_SUPPORTED BIT(0) -#define CCS_R_CPHY_CALIBRATION_CAPABILITY 0x162f -#define CCS_CPHY_CALIBRATION_CAPABILITY_MANUAL BIT(0) -#define CCS_CPHY_CALIBRATION_CAPABILITY_MANUAL_STREAMING BIT(1) -#define CCS_CPHY_CALIBRATION_CAPABILITY_FORMAT_1_CTRL BIT(2) -#define CCS_CPHY_CALIBRATION_CAPABILITY_FORMAT_2_CTRL BIT(3) -#define CCS_CPHY_CALIBRATION_CAPABILITY_FORMAT_3_CTRL BIT(4) -#define CCS_R_DPHY_CALIBRATION_CAPABILITY 0x1630 -#define CCS_DPHY_CALIBRATION_CAPABILITY_MANUAL BIT(0) -#define CCS_DPHY_CALIBRATION_CAPABILITY_MANUAL_STREAMING BIT(1) -#define CCS_DPHY_CALIBRATION_CAPABILITY_ALTERNATE_SEQ BIT(2) -#define CCS_R_PHY_CTRL_CAPABILITY_2 0x1631 -#define CCS_PHY_CTRL_CAPABILITY_2_TGR_LENGTH BIT(0) -#define CCS_PHY_CTRL_CAPABILITY_2_TGR_PREAMBLE_PROG_SEQ BIT(1) -#define CCS_PHY_CTRL_CAPABILITY_2_EXTRA_CPHY_MANUAL_TIMING BIT(2) -#define CCS_PHY_CTRL_CAPABILITY_2_CLOCK_BASED_MANUAL_CDPHY BIT(3) -#define CCS_PHY_CTRL_CAPABILITY_2_CLOCK_BASED_MANUAL_DPHY BIT(4) -#define CCS_PHY_CTRL_CAPABILITY_2_CLOCK_BASED_MANUAL_CPHY BIT(5) -#define CCS_PHY_CTRL_CAPABILITY_2_MANUAL_LP_DPHY BIT(6) -#define CCS_PHY_CTRL_CAPABILITY_2_MANUAL_LP_CPHY BIT(7) -#define CCS_R_LRTE_CPHY_CAPABILITY 0x1632 -#define CCS_LRTE_CPHY_CAPABILITY_PDQ_SHORT BIT(0) -#define CCS_LRTE_CPHY_CAPABILITY_SPACER_SHORT BIT(1) -#define CCS_LRTE_CPHY_CAPABILITY_PDQ_LONG BIT(2) -#define CCS_LRTE_CPHY_CAPABILITY_SPACER_LONG BIT(3) -#define CCS_LRTE_CPHY_CAPABILITY_SPACER_NO_PDQ BIT(4) -#define CCS_R_LRTE_DPHY_CAPABILITY 0x1633 -#define CCS_LRTE_DPHY_CAPABILITY_PDQ_SHORT_OPT1 BIT(0) -#define CCS_LRTE_DPHY_CAPABILITY_SPACER_SHORT_OPT1 BIT(1) -#define CCS_LRTE_DPHY_CAPABILITY_PDQ_LONG_OPT1 BIT(2) -#define CCS_LRTE_DPHY_CAPABILITY_SPACER_LONG_OPT1 BIT(3) -#define CCS_LRTE_DPHY_CAPABILITY_SPACER_SHORT_OPT2 BIT(4) -#define CCS_LRTE_DPHY_CAPABILITY_SPACER_LONG_OPT2 BIT(5) -#define CCS_LRTE_DPHY_CAPABILITY_SPACER_NO_PDQ_OPT1 BIT(6) -#define CCS_LRTE_DPHY_CAPABILITY_SPACER_VARIABLE_OPT2 BIT(7) -#define CCS_R_ALPS_CAPABILITY_DPHY 0x1634 -#define CCS_ALPS_CAPABILITY_DPHY_LVLP_NOT_SUPPORTED 0U -#define CCS_ALPS_CAPABILITY_DPHY_LVLP_SUPPORTED 1U -#define CCS_ALPS_CAPABILITY_DPHY_CONTROLLABLE_LVLP 2U -#define CCS_R_ALPS_CAPABILITY_CPHY 0x1635 -#define CCS_ALPS_CAPABILITY_CPHY_LVLP_NOT_SUPPORTED 0U -#define CCS_ALPS_CAPABILITY_CPHY_LVLP_SUPPORTED 1U -#define CCS_ALPS_CAPABILITY_CPHY_CONTROLLABLE_LVLP 2U -#define CCS_ALPS_CAPABILITY_CPHY_ALP_NOT_SUPPORTED 0xc -#define CCS_ALPS_CAPABILITY_CPHY_ALP_SUPPORTED 0xd -#define CCS_ALPS_CAPABILITY_CPHY_CONTROLLABLE_ALP 0xe -#define CCS_R_SCRAMBLING_CAPABILITY 0x1636 -#define CCS_SCRAMBLING_CAPABILITY_SCRAMBLING_SUPPORTED BIT(0) -#define CCS_SCRAMBLING_CAPABILITY_MAX_SEEDS_PER_LANE_C_SHIFT 1U -#define CCS_SCRAMBLING_CAPABILITY_MAX_SEEDS_PER_LANE_C_MASK 0x6 -#define CCS_SCRAMBLING_CAPABILITY_MAX_SEEDS_PER_LANE_C_1 0U -#define CCS_SCRAMBLING_CAPABILITY_MAX_SEEDS_PER_LANE_C_4 3U -#define CCS_SCRAMBLING_CAPABILITY_NUM_SEED_REGS_SHIFT 3U -#define CCS_SCRAMBLING_CAPABILITY_NUM_SEED_REGS_MASK 0x38 -#define CCS_SCRAMBLING_CAPABILITY_NUM_SEED_REGS_0 0U -#define CCS_SCRAMBLING_CAPABILITY_NUM_SEED_REGS_1 1U -#define CCS_SCRAMBLING_CAPABILITY_NUM_SEED_REGS_4 4U -#define CCS_SCRAMBLING_CAPABILITY_NUM_SEED_PER_LANE BIT(6) -#define CCS_R_DPHY_MANUAL_CONSTANT 0x1637 -#define CCS_R_CPHY_MANUAL_CONSTANT 0x1638 -#define CCS_R_CSI2_INTERFACE_CAPABILITY_MISC 0x1639 -#define CCS_CSI2_INTERFACE_CAPABILITY_MISC_EOTP_SHORT_PKT_OPT2 BIT(0) -#define CCS_R_PHY_CTRL_CAPABILITY_3 0x165c -#define CCS_PHY_CTRL_CAPABILITY_3_DPHY_TIMING_NOT_MULTIPLE BIT(0) -#define CCS_PHY_CTRL_CAPABILITY_3_DPHY_MIN_TIMING_VALUE_1 BIT(1) -#define CCS_PHY_CTRL_CAPABILITY_3_TWAKEUP_SUPPORTED BIT(2) -#define CCS_PHY_CTRL_CAPABILITY_3_TINIT_SUPPORTED BIT(3) -#define CCS_PHY_CTRL_CAPABILITY_3_THS_EXIT_SUPPORTED BIT(4) -#define CCS_PHY_CTRL_CAPABILITY_3_CPHY_TIMING_NOT_MULTIPLE BIT(5) -#define CCS_PHY_CTRL_CAPABILITY_3_CPHY_MIN_TIMING_VALUE_1 BIT(6) -#define CCS_R_DPHY_SF 0x165d -#define CCS_R_CPHY_SF 0x165e -#define CCS_CPHY_SF_TWAKEUP_SHIFT 0U -#define CCS_CPHY_SF_TWAKEUP_MASK 0xf -#define CCS_CPHY_SF_TINIT_SHIFT 4U -#define CCS_CPHY_SF_TINIT_MASK 0xf0 -#define CCS_R_DPHY_LIMITS_1 0x165f -#define CCS_DPHY_LIMITS_1_THS_PREPARE_SHIFT 0U -#define CCS_DPHY_LIMITS_1_THS_PREPARE_MASK 0xf -#define CCS_DPHY_LIMITS_1_THS_ZERO_SHIFT 4U -#define CCS_DPHY_LIMITS_1_THS_ZERO_MASK 0xf0 -#define CCS_R_DPHY_LIMITS_2 0x1660 -#define CCS_DPHY_LIMITS_2_THS_TRAIL_SHIFT 0U -#define CCS_DPHY_LIMITS_2_THS_TRAIL_MASK 0xf -#define CCS_DPHY_LIMITS_2_TCLK_TRAIL_MIN_SHIFT 4U -#define CCS_DPHY_LIMITS_2_TCLK_TRAIL_MIN_MASK 0xf0 -#define CCS_R_DPHY_LIMITS_3 0x1661 -#define CCS_DPHY_LIMITS_3_TCLK_PREPARE_SHIFT 0U -#define CCS_DPHY_LIMITS_3_TCLK_PREPARE_MASK 0xf -#define CCS_DPHY_LIMITS_3_TCLK_ZERO_SHIFT 4U -#define CCS_DPHY_LIMITS_3_TCLK_ZERO_MASK 0xf0 -#define CCS_R_DPHY_LIMITS_4 0x1662 -#define CCS_DPHY_LIMITS_4_TCLK_POST_SHIFT 0U -#define CCS_DPHY_LIMITS_4_TCLK_POST_MASK 0xf -#define CCS_DPHY_LIMITS_4_TLPX_SHIFT 4U -#define CCS_DPHY_LIMITS_4_TLPX_MASK 0xf0 -#define CCS_R_DPHY_LIMITS_5 0x1663 -#define CCS_DPHY_LIMITS_5_THS_EXIT_SHIFT 0U -#define CCS_DPHY_LIMITS_5_THS_EXIT_MASK 0xf -#define CCS_DPHY_LIMITS_5_TWAKEUP_SHIFT 4U -#define CCS_DPHY_LIMITS_5_TWAKEUP_MASK 0xf0 -#define CCS_R_DPHY_LIMITS_6 0x1664 -#define CCS_DPHY_LIMITS_6_TINIT_SHIFT 0U -#define CCS_DPHY_LIMITS_6_TINIT_MASK 0xf -#define CCS_R_CPHY_LIMITS_1 0x1665 -#define CCS_CPHY_LIMITS_1_T3_PREPARE_MAX_SHIFT 0U -#define CCS_CPHY_LIMITS_1_T3_PREPARE_MAX_MASK 0xf -#define CCS_CPHY_LIMITS_1_T3_LPX_MAX_SHIFT 4U -#define CCS_CPHY_LIMITS_1_T3_LPX_MAX_MASK 0xf0 -#define CCS_R_CPHY_LIMITS_2 0x1666 -#define CCS_CPHY_LIMITS_2_THS_EXIT_MAX_SHIFT 0U -#define CCS_CPHY_LIMITS_2_THS_EXIT_MAX_MASK 0xf -#define CCS_CPHY_LIMITS_2_TWAKEUP_MAX_SHIFT 4U -#define CCS_CPHY_LIMITS_2_TWAKEUP_MAX_MASK 0xf0 -#define CCS_R_CPHY_LIMITS_3 0x1667 -#define CCS_CPHY_LIMITS_3_TINIT_MAX_SHIFT 0U -#define CCS_CPHY_LIMITS_3_TINIT_MAX_MASK 0xf -#define CCS_R_MIN_FRAME_LENGTH_LINES_BIN (0x1700 | CCS_FL_16BIT) -#define CCS_R_MAX_FRAME_LENGTH_LINES_BIN (0x1702 | CCS_FL_16BIT) -#define CCS_R_MIN_LINE_LENGTH_PCK_BIN (0x1704 | CCS_FL_16BIT) -#define CCS_R_MAX_LINE_LENGTH_PCK_BIN (0x1706 | CCS_FL_16BIT) -#define CCS_R_MIN_LINE_BLANKING_PCK_BIN (0x1708 | CCS_FL_16BIT) -#define CCS_R_FINE_INTEGRATION_TIME_MIN_BIN (0x170a | CCS_FL_16BIT) -#define CCS_R_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN (0x170c | CCS_FL_16BIT) -#define CCS_R_BINNING_CAPABILITY 0x1710 -#define CCS_BINNING_CAPABILITY_UNSUPPORTED 0U -#define CCS_BINNING_CAPABILITY_BINNING_THEN_SUBSAMPLING 1U -#define CCS_BINNING_CAPABILITY_SUBSAMPLING_THEN_BINNING 2U -#define CCS_R_BINNING_WEIGHTING_CAPABILITY 0x1711 -#define CCS_BINNING_WEIGHTING_CAPABILITY_AVERAGED BIT(0) -#define CCS_BINNING_WEIGHTING_CAPABILITY_SUMMED BIT(1) -#define CCS_BINNING_WEIGHTING_CAPABILITY_BAYER_CORRECTED BIT(2) -#define CCS_BINNING_WEIGHTING_CAPABILITY_MODULE_SPECIFIC_WEIGHT BIT(3) -#define CCS_R_BINNING_SUB_TYPES 0x1712 -#define CCS_R_BINNING_SUB_TYPE(n) (0x1713 + (n)) -#define CCS_LIM_BINNING_SUB_TYPE_MIN_N 0U -#define CCS_LIM_BINNING_SUB_TYPE_MAX_N 63U -#define CCS_BINNING_SUB_TYPE_ROW_SHIFT 0U -#define CCS_BINNING_SUB_TYPE_ROW_MASK 0xf -#define CCS_BINNING_SUB_TYPE_COLUMN_SHIFT 4U -#define CCS_BINNING_SUB_TYPE_COLUMN_MASK 0xf0 -#define CCS_R_BINNING_WEIGHTING_MONO_CAPABILITY 0x1771 -#define CCS_BINNING_WEIGHTING_MONO_CAPABILITY_AVERAGED BIT(0) -#define CCS_BINNING_WEIGHTING_MONO_CAPABILITY_SUMMED BIT(1) -#define CCS_BINNING_WEIGHTING_MONO_CAPABILITY_BAYER_CORRECTED BIT(2) -#define CCS_BINNING_WEIGHTING_MONO_CAPABILITY_MODULE_SPECIFIC_WEIGHT BIT(3) -#define CCS_R_BINNING_SUB_TYPES_MONO 0x1772 -#define CCS_R_BINNING_SUB_TYPE_MONO(n) (0x1773 + (n)) -#define CCS_LIM_BINNING_SUB_TYPE_MONO_MIN_N 0U -#define CCS_LIM_BINNING_SUB_TYPE_MONO_MAX_N 63U -#define CCS_R_DATA_TRANSFER_IF_CAPABILITY 0x1800 -#define CCS_DATA_TRANSFER_IF_CAPABILITY_SUPPORTED BIT(0) -#define CCS_DATA_TRANSFER_IF_CAPABILITY_POLLING BIT(2) -#define CCS_R_SHADING_CORRECTION_CAPABILITY 0x1900 -#define CCS_SHADING_CORRECTION_CAPABILITY_COLOR_SHADING BIT(0) -#define CCS_SHADING_CORRECTION_CAPABILITY_LUMINANCE_CORRECTION BIT(1) -#define CCS_R_GREEN_IMBALANCE_CAPABILITY 0x1901 -#define CCS_GREEN_IMBALANCE_CAPABILITY_SUPPORTED BIT(0) -#define CCS_R_MODULE_SPECIFIC_CORRECTION_CAPABILITY 0x1903 -#define CCS_R_DEFECT_CORRECTION_CAPABILITY (0x1904 | CCS_FL_16BIT) -#define CCS_DEFECT_CORRECTION_CAPABILITY_MAPPED_DEFECT BIT(0) -#define CCS_DEFECT_CORRECTION_CAPABILITY_DYNAMIC_COUPLET BIT(2) -#define CCS_DEFECT_CORRECTION_CAPABILITY_DYNAMIC_SINGLE BIT(5) -#define CCS_DEFECT_CORRECTION_CAPABILITY_COMBINED_DYNAMIC BIT(8) -#define CCS_R_DEFECT_CORRECTION_CAPABILITY_2 (0x1906 | CCS_FL_16BIT) -#define CCS_DEFECT_CORRECTION_CAPABILITY_2_DYNAMIC_TRIPLET BIT(3) -#define CCS_R_NF_CAPABILITY 0x1908 -#define CCS_NF_CAPABILITY_LUMA BIT(0) -#define CCS_NF_CAPABILITY_CHROMA BIT(1) -#define CCS_NF_CAPABILITY_COMBINED BIT(2) -#define CCS_R_OB_READOUT_CAPABILITY 0x1980 -#define CCS_OB_READOUT_CAPABILITY_CONTROLLABLE_READOUT BIT(0) -#define CCS_OB_READOUT_CAPABILITY_VISIBLE_PIXEL_READOUT BIT(1) -#define CCS_OB_READOUT_CAPABILITY_DIFFERENT_VC_READOUT BIT(2) -#define CCS_OB_READOUT_CAPABILITY_DIFFERENT_DT_READOUT BIT(3) -#define CCS_OB_READOUT_CAPABILITY_PROG_DATA_FORMAT BIT(4) -#define CCS_R_COLOR_FEEDBACK_CAPABILITY 0x1987 -#define CCS_COLOR_FEEDBACK_CAPABILITY_KELVIN BIT(0) -#define CCS_COLOR_FEEDBACK_CAPABILITY_AWB_GAIN BIT(1) -#define CCS_R_CFA_PATTERN_CAPABILITY 0x1990 -#define CCS_CFA_PATTERN_CAPABILITY_BAYER 0U -#define CCS_CFA_PATTERN_CAPABILITY_MONOCHROME 1U -#define CCS_CFA_PATTERN_CAPABILITY_4X4_QUAD_BAYER 2U -#define CCS_CFA_PATTERN_CAPABILITY_VENDOR_SPECIFIC 3U -#define CCS_R_CFA_PATTERN_CONVERSION_CAPABILITY 0x1991 -#define CCS_CFA_PATTERN_CONVERSION_CAPABILITY_BAYER BIT(0) -#define CCS_R_FLASH_MODE_CAPABILITY 0x1a02 -#define CCS_FLASH_MODE_CAPABILITY_SINGLE_STROBE BIT(0) -#define CCS_R_SA_STROBE_MODE_CAPABILITY 0x1a03 -#define CCS_SA_STROBE_MODE_CAPABILITY_FIXED_WIDTH BIT(0) -#define CCS_SA_STROBE_MODE_CAPABILITY_EDGE_CTRL BIT(1) -#define CCS_R_RESET_MAX_DELAY 0x1a10 -#define CCS_R_RESET_MIN_TIME 0x1a11 -#define CCS_R_PDAF_CAPABILITY_1 0x1b80 -#define CCS_PDAF_CAPABILITY_1_SUPPORTED BIT(0) -#define CCS_PDAF_CAPABILITY_1_PROCESSED_BOTTOM_EMBEDDED BIT(1) -#define CCS_PDAF_CAPABILITY_1_PROCESSED_INTERLEAVED BIT(2) -#define CCS_PDAF_CAPABILITY_1_RAW_BOTTOM_EMBEDDED BIT(3) -#define CCS_PDAF_CAPABILITY_1_RAW_INTERLEAVED BIT(4) -#define CCS_PDAF_CAPABILITY_1_VISIBLE_PDAF_CORRECTION BIT(5) -#define CCS_PDAF_CAPABILITY_1_VC_INTERLEAVING BIT(6) -#define CCS_PDAF_CAPABILITY_1_DT_INTERLEAVING BIT(7) -#define CCS_R_PDAF_CAPABILITY_2 0x1b81 -#define CCS_PDAF_CAPABILITY_2_ROI BIT(0) -#define CCS_PDAF_CAPABILITY_2_AFTER_DIGITAL_CROP BIT(1) -#define CCS_PDAF_CAPABILITY_2_CTRL_RETIMED BIT(2) -#define CCS_R_BRACKETING_LUT_CAPABILITY_1 0x1c00 -#define CCS_BRACKETING_LUT_CAPABILITY_1_COARSE_INTEGRATION BIT(0) -#define CCS_BRACKETING_LUT_CAPABILITY_1_GLOBAL_ANALOG_GAIN BIT(1) -#define CCS_BRACKETING_LUT_CAPABILITY_1_FLASH BIT(4) -#define CCS_BRACKETING_LUT_CAPABILITY_1_GLOBAL_DIGITAL_GAIN BIT(5) -#define CCS_BRACKETING_LUT_CAPABILITY_1_ALTERNATE_GLOBAL_ANALOG_GAIN BIT(6) -#define CCS_R_BRACKETING_LUT_CAPABILITY_2 0x1c01 -#define CCS_BRACKETING_LUT_CAPABILITY_2_SINGLE_BRACKETING_MODE BIT(0) -#define CCS_BRACKETING_LUT_CAPABILITY_2_LOOPED_BRACKETING_MODE BIT(1) -#define CCS_R_BRACKETING_LUT_SIZE 0x1c02 - -#endif /* __CCS_REGS_H__ */ diff --git a/drivers/media/i2c/smiapp/ccs.h b/drivers/media/i2c/smiapp/ccs.h deleted file mode 100644 index 20b1125d87dc..000000000000 --- a/drivers/media/i2c/smiapp/ccs.h +++ /dev/null @@ -1,280 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * drivers/media/i2c/smiapp/ccs.h - * - * Generic driver for SMIA/SMIA++ compliant camera modules - * - * Copyright (C) 2010--2012 Nokia Corporation - * Contact: Sakari Ailus - */ - -#ifndef __CCS_H__ -#define __CCS_H__ - -#include -#include -#include - -#include "ccs-quirk.h" -#include "ccs-regs.h" -#include "ccs-reg-access.h" -#include "../smiapp-pll.h" -#include "smiapp-reg-defs.h" - -/* - * Standard SMIA++ constants - */ -#define SMIA_VERSION_1 10 -#define SMIAPP_VERSION_0_8 8 /* Draft 0.8 */ -#define SMIAPP_VERSION_0_9 9 /* Draft 0.9 */ -#define SMIAPP_VERSION_1 10 - -#define SMIAPP_PROFILE_0 0 -#define SMIAPP_PROFILE_1 1 -#define SMIAPP_PROFILE_2 2 - -#define SMIAPP_NVM_PAGE_SIZE 64 /* bytes */ - -#define SMIAPP_RESET_DELAY_CLOCKS 2400 -#define SMIAPP_RESET_DELAY(clk) \ - (1000 + (SMIAPP_RESET_DELAY_CLOCKS * 1000 \ - + (clk) / 1000 - 1) / ((clk) / 1000)) - -#define CCS_COLOUR_COMPONENTS 4 - -#define SMIAPP_NAME "smiapp" -#define CCS_NAME "ccs" - -#define CCS_DFL_I2C_ADDR (0x20 >> 1) /* Default I2C Address */ -#define CCS_ALT_I2C_ADDR (0x6e >> 1) /* Alternate I2C Address */ - -/* - * Sometimes due to board layout considerations the camera module can be - * mounted rotated. The typical rotation used is 180 degrees which can be - * corrected by giving a default H-FLIP and V-FLIP in the sensor readout. - * FIXME: rotation also changes the bayer pattern. - */ -enum ccs_module_board_orient { - CCS_MODULE_BOARD_ORIENT_0 = 0, - CCS_MODULE_BOARD_ORIENT_180, -}; - -struct ccs_flash_strobe_parms { - u8 mode; - u32 strobe_width_high_us; - u16 strobe_delay; - u16 stobe_start_point; - u8 trigger; -}; - -struct ccs_hwconfig { - /* - * Change the cci address if i2c_addr_alt is set. - * Both default and alternate cci addr need to be present - */ - unsigned short i2c_addr_dfl; /* Default i2c addr */ - unsigned short i2c_addr_alt; /* Alternate i2c addr */ - - uint32_t ext_clk; /* sensor external clk */ - - unsigned int lanes; /* Number of CSI-2 lanes */ - uint32_t csi_signalling_mode; /* CCS_CSI_SIGNALLING_MODE_* */ - uint64_t *op_sys_clock; - - enum ccs_module_board_orient module_board_orient; - - struct ccs_flash_strobe_parms *strobe_setup; -}; - -struct ccs_quirk; - -#define CCS_MODULE_IDENT_FLAG_REV_LE (1 << 0) - -struct ccs_module_ident { - u16 mipi_manufacturer_id; - u16 model_id; - u8 smia_manufacturer_id; - u8 revision_number_major; - - u8 flags; - - char *name; - const struct ccs_quirk *quirk; -}; - -struct ccs_module_info { - u32 smia_manufacturer_id; - u32 mipi_manufacturer_id; - u32 model_id; - u32 revision_number_major; - u32 revision_number_minor; - - u32 module_year; - u32 module_month; - u32 module_day; - - u32 sensor_smia_manufacturer_id; - u32 sensor_mipi_manufacturer_id; - u32 sensor_model_id; - u32 sensor_revision_number; - u32 sensor_firmware_version; - - u32 smia_version; - u32 smiapp_version; - u32 ccs_version; - - u32 smiapp_profile; - - char *name; - const struct ccs_quirk *quirk; -}; - -#define CCS_IDENT_FQ(manufacturer, model, rev, fl, _name, _quirk) \ - { .smia_manufacturer_id = manufacturer, \ - .model_id = model, \ - .revision_number_major = rev, \ - .flags = fl, \ - .name = _name, \ - .quirk = _quirk, } - -#define CCS_IDENT_LQ(manufacturer, model, rev, _name, _quirk) \ - { .smia_manufacturer_id = manufacturer, \ - .model_id = model, \ - .revision_number_major = rev, \ - .flags = CCS_MODULE_IDENT_FLAG_REV_LE, \ - .name = _name, \ - .quirk = _quirk, } - -#define CCS_IDENT_L(manufacturer, model, rev, _name) \ - { .smia_manufacturer_id = manufacturer, \ - .model_id = model, \ - .revision_number_major = rev, \ - .flags = CCS_MODULE_IDENT_FLAG_REV_LE, \ - .name = _name, } - -#define CCS_IDENT_Q(manufacturer, model, rev, _name, _quirk) \ - { .smia_manufacturer_id = manufacturer, \ - .model_id = model, \ - .revision_number_major = rev, \ - .flags = 0, \ - .name = _name, \ - .quirk = _quirk, } - -#define CCS_IDENT(manufacturer, model, rev, _name) \ - { .smia_manufacturer_id = manufacturer, \ - .model_id = model, \ - .revision_number_major = rev, \ - .flags = 0, \ - .name = _name, } - -struct ccs_csi_data_format { - u32 code; - u8 width; - u8 compressed; - u8 pixel_order; -}; - -#define CCS_SUBDEVS 3 - -#define CCS_PA_PAD_SRC 0 -#define CCS_PAD_SINK 0 -#define CCS_PAD_SRC 1 -#define CCS_PADS 2 - -struct ccs_binning_subtype { - u8 horizontal:4; - u8 vertical:4; -} __packed; - -struct ccs_subdev { - struct v4l2_subdev sd; - struct media_pad pads[CCS_PADS]; - struct v4l2_rect sink_fmt; - struct v4l2_rect crop[CCS_PADS]; - struct v4l2_rect compose; /* compose on sink */ - unsigned short sink_pad; - unsigned short source_pad; - int npads; - struct ccs_sensor *sensor; - struct v4l2_ctrl_handler ctrl_handler; -}; - -/* - * struct ccs_sensor - Main device structure - */ -struct ccs_sensor { - /* - * "mutex" is used to serialise access to all fields here - * except v4l2_ctrls at the end of the struct. "mutex" is also - * used to serialise access to file handle specific - * information. - */ - struct mutex mutex; - struct ccs_subdev ssds[CCS_SUBDEVS]; - u32 ssds_used; - struct ccs_subdev *src; - struct ccs_subdev *binner; - struct ccs_subdev *scaler; - struct ccs_subdev *pixel_array; - struct ccs_hwconfig *hwcfg; - struct regulator *vana; - struct clk *ext_clk; - struct gpio_desc *xshutdown; - void *ccs_limits; - u8 nbinning_subtypes; - struct ccs_binning_subtype binning_subtypes[CCS_LIM_BINNING_SUB_TYPE_MAX_N + 1]; - u32 mbus_frame_fmts; - const struct ccs_csi_data_format *csi_format; - const struct ccs_csi_data_format *internal_csi_format; - u32 default_mbus_frame_fmts; - int default_pixel_order; - - u8 binning_horizontal; - u8 binning_vertical; - - u8 scale_m; - u8 scaling_mode; - - u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */ - u8 frame_skip; - u16 embedded_start; /* embedded data start line */ - u16 embedded_end; - u16 image_start; /* image data start line */ - u16 visible_pixel_start; /* start pixel of the visible image */ - - bool streaming; - bool dev_init_done; - u8 compressed_min_bpp; - - struct ccs_module_info minfo; - - struct smiapp_pll pll; - - /* Is a default format supported for a given BPP? */ - unsigned long *valid_link_freqs; - - /* Pixel array controls */ - struct v4l2_ctrl *analog_gain; - struct v4l2_ctrl *exposure; - struct v4l2_ctrl *hflip; - struct v4l2_ctrl *vflip; - struct v4l2_ctrl *vblank; - struct v4l2_ctrl *hblank; - struct v4l2_ctrl *pixel_rate_parray; - /* src controls */ - struct v4l2_ctrl *link_freq; - struct v4l2_ctrl *pixel_rate_csi; - /* test pattern colour components */ - struct v4l2_ctrl *test_data[CCS_COLOUR_COMPONENTS]; -}; - -#define to_ccs_subdev(_sd) \ - container_of(_sd, struct ccs_subdev, sd) - -#define to_ccs_sensor(_sd) \ - (to_ccs_subdev(_sd)->sensor) - -void ccs_replace_limit(struct ccs_sensor *sensor, - unsigned int limit, unsigned int offset, u32 val); - -#endif /* __CCS_H__ */ diff --git a/drivers/media/i2c/smiapp/smiapp-reg-defs.h b/drivers/media/i2c/smiapp/smiapp-reg-defs.h deleted file mode 100644 index 06b69b1ab55f..000000000000 --- a/drivers/media/i2c/smiapp/smiapp-reg-defs.h +++ /dev/null @@ -1,579 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * drivers/media/i2c/smiapp/smiapp-reg-defs.h - * - * Generic driver for SMIA/SMIA++ compliant camera modules - * - * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus - */ - -#ifndef __SMIAPP_REG_DEFS_H__ -#define __SMIAPP_REG_DEFS_H__ - -/* Register addresses */ -#define SMIAPP_REG_U16_MODEL_ID (0x0000 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_REVISION_NUMBER_MAJOR 0x0002 -#define SMIAPP_REG_U8_MANUFACTURER_ID 0x0003 -#define SMIAPP_REG_U8_SMIA_VERSION 0x0004 -#define SMIAPP_REG_U8_FRAME_COUNT 0x0005 -#define SMIAPP_REG_U8_PIXEL_ORDER 0x0006 -#define SMIAPP_REG_U16_DATA_PEDESTAL (0x0008 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_PIXEL_DEPTH 0x000c -#define SMIAPP_REG_U8_REVISION_NUMBER_MINOR 0x0010 -#define SMIAPP_REG_U8_SMIAPP_VERSION 0x0011 -#define SMIAPP_REG_U8_MODULE_DATE_YEAR 0x0012 -#define SMIAPP_REG_U8_MODULE_DATE_MONTH 0x0013 -#define SMIAPP_REG_U8_MODULE_DATE_DAY 0x0014 -#define SMIAPP_REG_U8_MODULE_DATE_PHASE 0x0015 -#define SMIAPP_REG_U16_SENSOR_MODEL_ID (0x0016 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_SENSOR_REVISION_NUMBER 0x0018 -#define SMIAPP_REG_U8_SENSOR_MANUFACTURER_ID 0x0019 -#define SMIAPP_REG_U8_SENSOR_FIRMWARE_VERSION 0x001a -#define SMIAPP_REG_U32_SERIAL_NUMBER (0x001c | CCS_FL_32BIT) -#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_TYPE 0x0040 -#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_SUBTYPE 0x0041 -#define SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(n) ((0x0042 + ((n) << 1)) | CCS_FL_16BIT) /* 0 <= n <= 14 */ -#define SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(n) ((0x0060 + ((n) << 2)) | CCS_FL_32BIT) /* 0 <= n <= 7 */ -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CAPABILITY (0x0080 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MIN (0x0084 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MAX (0x0086 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_STEP (0x0088 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_TYPE (0x008a | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_M0 (0x008c | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_C0 (0x008e | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_M1 (0x0090 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_C1 (0x0092 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_TYPE 0x00c0 -#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_SUBTYPE 0x00c1 -#define SMIAPP_REG_U16_DATA_FORMAT_DESCRIPTOR(n) ((0x00c2 + ((n) << 1)) | CCS_FL_16BIT) -#define SMIAPP_REG_U8_MODE_SELECT 0x0100 -#define SMIAPP_REG_U8_IMAGE_ORIENTATION 0x0101 -#define SMIAPP_REG_U8_SOFTWARE_RESET 0x0103 -#define SMIAPP_REG_U8_GROUPED_PARAMETER_HOLD 0x0104 -#define SMIAPP_REG_U8_MASK_CORRUPTED_FRAMES 0x0105 -#define SMIAPP_REG_U8_FAST_STANDBY_CTRL 0x0106 -#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL 0x0107 -#define SMIAPP_REG_U8_2ND_CCI_IF_CONTROL 0x0108 -#define SMIAPP_REG_U8_2ND_CCI_ADDRESS_CONTROL 0x0109 -#define SMIAPP_REG_U8_CSI_CHANNEL_IDENTIFIER 0x0110 -#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE 0x0111 -#define SMIAPP_REG_U16_CSI_DATA_FORMAT (0x0112 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_CSI_LANE_MODE 0x0114 -#define SMIAPP_REG_U8_CSI2_10_TO_8_DT 0x0115 -#define SMIAPP_REG_U8_CSI2_10_TO_7_DT 0x0116 -#define SMIAPP_REG_U8_CSI2_10_TO_6_DT 0x0117 -#define SMIAPP_REG_U8_CSI2_12_TO_8_DT 0x0118 -#define SMIAPP_REG_U8_CSI2_12_TO_7_DT 0x0119 -#define SMIAPP_REG_U8_CSI2_12_TO_6_DT 0x011a -#define SMIAPP_REG_U8_CSI2_14_TO_10_DT 0x011b -#define SMIAPP_REG_U8_CSI2_14_TO_8_DT 0x011c -#define SMIAPP_REG_U8_CSI2_16_TO_10_DT 0x011d -#define SMIAPP_REG_U8_CSI2_16_TO_8_DT 0x011e -#define SMIAPP_REG_U8_GAIN_MODE 0x0120 -#define SMIAPP_REG_U16_VANA_VOLTAGE (0x0130 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_VDIG_VOLTAGE (0x0132 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_VIO_VOLTAGE (0x0134 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ (0x0136 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_TEMP_SENSOR_CONTROL 0x0138 -#define SMIAPP_REG_U8_TEMP_SENSOR_MODE 0x0139 -#define SMIAPP_REG_U8_TEMP_SENSOR_OUTPUT 0x013a -#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME (0x0200 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME (0x0202 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GLOBAL (0x0204 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENR (0x0206 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_RED (0x0208 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_BLUE (0x020a | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENB (0x020c | CCS_FL_16BIT) -#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENR (0x020e | CCS_FL_16BIT) -#define SMIAPP_REG_U16_DIGITAL_GAIN_RED (0x0210 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_DIGITAL_GAIN_BLUE (0x0212 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENB (0x0214 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_VT_PIX_CLK_DIV (0x0300 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_VT_SYS_CLK_DIV (0x0302 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_PRE_PLL_CLK_DIV (0x0304 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_PLL_MULTIPLIER (0x0306 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_OP_PIX_CLK_DIV (0x0308 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_OP_SYS_CLK_DIV (0x030a | CCS_FL_16BIT) -#define SMIAPP_REG_U16_FRAME_LENGTH_LINES (0x0340 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_LINE_LENGTH_PCK (0x0342 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_X_ADDR_START (0x0344 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_Y_ADDR_START (0x0346 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_X_ADDR_END (0x0348 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_Y_ADDR_END (0x034a | CCS_FL_16BIT) -#define SMIAPP_REG_U16_X_OUTPUT_SIZE (0x034c | CCS_FL_16BIT) -#define SMIAPP_REG_U16_Y_OUTPUT_SIZE (0x034e | CCS_FL_16BIT) -#define SMIAPP_REG_U16_X_EVEN_INC (0x0380 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_X_ODD_INC (0x0382 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_Y_EVEN_INC (0x0384 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_Y_ODD_INC (0x0386 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_SCALING_MODE (0x0400 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_SPATIAL_SAMPLING (0x0402 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_SCALE_M (0x0404 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_SCALE_N (0x0406 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET (0x0408 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_DIGITAL_CROP_Y_OFFSET (0x040a | CCS_FL_16BIT) -#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_WIDTH (0x040c | CCS_FL_16BIT) -#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_HEIGHT (0x040e | CCS_FL_16BIT) -#define SMIAPP_REG_U16_COMPRESSION_MODE (0x0500 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TEST_PATTERN_MODE (0x0600 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TEST_DATA_RED (0x0602 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TEST_DATA_GREENR (0x0604 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TEST_DATA_BLUE (0x0606 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TEST_DATA_GREENB (0x0608 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_WIDTH (0x060a | CCS_FL_16BIT) -#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_POSITION (0x060c | CCS_FL_16BIT) -#define SMIAPP_REG_U16_VERTICAL_CURSOR_WIDTH (0x060e | CCS_FL_16BIT) -#define SMIAPP_REG_U16_VERTICAL_CURSOR_POSITION (0x0610 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_FIFO_WATER_MARK_PIXELS (0x0700 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_TCLK_POST 0x0800 -#define SMIAPP_REG_U8_THS_PREPARE 0x0801 -#define SMIAPP_REG_U8_THS_ZERO_MIN 0x0802 -#define SMIAPP_REG_U8_THS_TRAIL 0x0803 -#define SMIAPP_REG_U8_TCLK_TRAIL_MIN 0x0804 -#define SMIAPP_REG_U8_TCLK_PREPARE 0x0805 -#define SMIAPP_REG_U8_TCLK_ZERO 0x0806 -#define SMIAPP_REG_U8_TLPX 0x0807 -#define SMIAPP_REG_U8_DPHY_CTRL 0x0808 -#define SMIAPP_REG_U32_REQUESTED_LINK_BIT_RATE_MBPS (0x0820 | CCS_FL_32BIT) -#define SMIAPP_REG_U8_BINNING_MODE 0x0900 -#define SMIAPP_REG_U8_BINNING_TYPE 0x0901 -#define SMIAPP_REG_U8_BINNING_WEIGHTING 0x0902 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL 0x0a00 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS 0x0a01 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_PAGE_SELECT 0x0a02 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_0 0x0a04 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_1 0x0a05 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_2 0x0a06 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_3 0x0a07 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_4 0x0a08 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_5 0x0a09 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_12 0x0a10 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_13 0x0a11 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_14 0x0a12 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_15 0x0a13 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_16 0x0a14 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_17 0x0a15 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_18 0x0a16 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_19 0x0a17 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_20 0x0a18 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_21 0x0a19 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_22 0x0a1a -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_23 0x0a1b -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_24 0x0a1c -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_25 0x0a1d -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_26 0x0a1e -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_27 0x0a1f -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_28 0x0a20 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_29 0x0a21 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_30 0x0a22 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_31 0x0a23 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_32 0x0a24 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_33 0x0a25 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_34 0x0a26 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_35 0x0a27 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_36 0x0a28 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_37 0x0a29 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_38 0x0a2a -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_39 0x0a2b -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_40 0x0a2c -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_41 0x0a2d -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_42 0x0a2e -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_43 0x0a2f -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_44 0x0a30 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_45 0x0a31 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_46 0x0a32 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_47 0x0a33 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_48 0x0a34 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_49 0x0a35 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_50 0x0a36 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_51 0x0a37 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_52 0x0a38 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_53 0x0a39 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_54 0x0a3a -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_55 0x0a3b -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_56 0x0a3c -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_57 0x0a3d -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_58 0x0a3e -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_59 0x0a3f -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_60 0x0a40 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_61 0x0a41 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_62 0x0a42 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_63 0x0a43 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_CTRL 0x0a44 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_STATUS 0x0a45 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_PAGE_SELECT 0x0a46 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_0 0x0a48 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_1 0x0a49 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_2 0x0a4a -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_3 0x0a4b -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_4 0x0a4c -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_5 0x0a4d -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_6 0x0a4e -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_7 0x0a4f -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_8 0x0a50 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_9 0x0a51 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_10 0x0a52 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_11 0x0a53 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_12 0x0a54 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_13 0x0a55 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_14 0x0a56 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_15 0x0a57 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_16 0x0a58 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_17 0x0a59 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_18 0x0a5a -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_19 0x0a5b -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_20 0x0a5c -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_21 0x0a5d -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_22 0x0a5e -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_23 0x0a5f -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_24 0x0a60 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_25 0x0a61 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_26 0x0a62 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_27 0x0a63 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_28 0x0a64 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_29 0x0a65 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_30 0x0a66 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_31 0x0a67 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_32 0x0a68 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_33 0x0a69 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_34 0x0a6a -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_35 0x0a6b -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_36 0x0a6c -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_37 0x0a6d -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_38 0x0a6e -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_39 0x0a6f -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_40 0x0a70 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_41 0x0a71 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_42 0x0a72 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_43 0x0a73 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_44 0x0a74 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_45 0x0a75 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_46 0x0a76 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_47 0x0a77 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_48 0x0a78 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_49 0x0a79 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_50 0x0a7a -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_51 0x0a7b -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_52 0x0a7c -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_53 0x0a7d -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_54 0x0a7e -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_55 0x0a7f -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_56 0x0a80 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_57 0x0a81 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_58 0x0a82 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_59 0x0a83 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_60 0x0a84 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_61 0x0a85 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_62 0x0a86 -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_63 0x0a87 -#define SMIAPP_REG_U8_SHADING_CORRECTION_ENABLE 0x0b00 -#define SMIAPP_REG_U8_LUMINANCE_CORRECTION_LEVEL 0x0b01 -#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_ENABLE 0x0b02 -#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_WEIGHT 0x0b03 -#define SMIAPP_REG_U8_BLACK_LEVEL_CORRECTION_ENABLE 0x0b04 -#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ENABLE 0x0b05 -#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_ENABLE 0x0b06 -#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_WEIGHT 0x0b07 -#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_ENABLE 0x0b08 -#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_WEIGHT 0x0b09 -#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_ENABLE 0x0b0a -#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_WEIGHT 0x0b0b -#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_ENABLE 0x0b0c -#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_WEIGHT 0x0b0d -#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ENABLE 0x0b0e -#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ADJUST 0x0b0f -#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ADJUST 0x0b10 -#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ENABLE 0x0b11 -#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ADJUST 0x0b12 -#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ENABLE 0x0b13 -#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ADJUST 0x0b14 -#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ENABLE 0x0b15 -#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ADJUST 0x0b16 -#define SMIAPP_REG_U8_EDOF_MODE 0x0b80 -#define SMIAPP_REG_U8_SHARPNESS 0x0b83 -#define SMIAPP_REG_U8_DENOISING 0x0b84 -#define SMIAPP_REG_U8_MODULE_SPECIFIC 0x0b85 -#define SMIAPP_REG_U16_DEPTH_OF_FIELD (0x0b86 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_FOCUS_DISTANCE (0x0b88 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_ESTIMATION_MODE_CTRL 0x0b8a -#define SMIAPP_REG_U16_COLOUR_TEMPERATURE (0x0b8c | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENR (0x0b8e | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ABSOLUTE_GAIN_RED (0x0b90 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ABSOLUTE_GAIN_BLUE (0x0b92 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENB (0x0b94 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_ESTIMATION_ZONE_MODE 0x0bc0 -#define SMIAPP_REG_U16_FIXED_ZONE_WEIGHTING (0x0bc2 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_CUSTOM_ZONE_X_START (0x0bc4 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_CUSTOM_ZONE_Y_START (0x0bc6 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_CUSTOM_ZONE_WIDTH (0x0bc8 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_CUSTOM_ZONE_HEIGHT (0x0bca | CCS_FL_16BIT) -#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL1 0x0c00 -#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL2 0x0c01 -#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_1 0x0c02 -#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_2 0x0c03 -#define SMIAPP_REG_U16_TRDY_CTRL (0x0c04 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TRDOUT_CTRL (0x0c06 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TSHUTTER_STROBE_DELAY_CTRL (0x0c08 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TSHUTTER_STROBE_WIDTH_CTRL (0x0c0a | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_CTRL (0x0c0c | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_CTRL (0x0c0e | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TGRST_INTERVAL_CTRL (0x0c10 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_FLASH_STROBE_ADJUSTMENT 0x0c12 -#define SMIAPP_REG_U16_FLASH_STROBE_START_POINT (0x0c14 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_RS_CTRL (0x0c16 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL (0x0c18 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_FLASH_MODE_RS 0x0c1a -#define SMIAPP_REG_U8_FLASH_TRIGGER_RS 0x0c1b -#define SMIAPP_REG_U8_FLASH_STATUS 0x0c1c -#define SMIAPP_REG_U8_SA_STROBE_MODE 0x0c1d -#define SMIAPP_REG_U16_SA_STROBE_START_POINT (0x0c1e | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TSA_STROBE_DELAY_CTRL (0x0c20 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TSA_STROBE_WIDTH_CTRL (0x0c22 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_SA_STROBE_TRIGGER 0x0c24 -#define SMIAPP_REG_U8_SPECIAL_ACTUATOR_STATUS 0x0c25 -#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_RS_CTRL (0x0c26 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_RS_CTRL (0x0c28 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_RS_CTRL 0x0c2a -#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_CTRL 0x0c2b -#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_CTRL (0x0c2c | CCS_FL_16BIT) -#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_CTRL (0x0c2e | CCS_FL_16BIT) -#define SMIAPP_REG_U8_LOW_LEVEL_CTRL 0x0c80 -#define SMIAPP_REG_U16_MAIN_TRIGGER_REF_POINT (0x0c82 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAIN_TRIGGER_T3 (0x0c84 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_MAIN_TRIGGER_COUNT 0x0c86 -#define SMIAPP_REG_U16_PHASE1_TRIGGER_T3 (0x0c88 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_PHASE1_TRIGGER_COUNT 0x0c8a -#define SMIAPP_REG_U16_PHASE2_TRIGGER_T3 (0x0c8c | CCS_FL_16BIT) -#define SMIAPP_REG_U8_PHASE2_TRIGGER_COUNT 0x0c8e -#define SMIAPP_REG_U8_MECH_SHUTTER_CTRL 0x0d00 -#define SMIAPP_REG_U8_OPERATION_MODE 0x0d01 -#define SMIAPP_REG_U8_ACT_STATE1 0x0d02 -#define SMIAPP_REG_U8_ACT_STATE2 0x0d03 -#define SMIAPP_REG_U16_FOCUS_CHANGE (0x0d80 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_FOCUS_CHANGE_CONTROL (0x0d82 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE1 (0x0d84 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE2 (0x0d86 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_STROBE_COUNT_PHASE1 0x0d88 -#define SMIAPP_REG_U8_STROBE_COUNT_PHASE2 0x0d89 -#define SMIAPP_REG_U8_POSITION 0x0d8a -#define SMIAPP_REG_U8_BRACKETING_LUT_CONTROL 0x0e00 -#define SMIAPP_REG_U8_BRACKETING_LUT_MODE 0x0e01 -#define SMIAPP_REG_U8_BRACKETING_LUT_ENTRY_CONTROL 0x0e02 -#define SMIAPP_REG_U8_LUT_PARAMETERS_START 0x0e10 -#define SMIAPP_REG_U8_LUT_PARAMETERS_END 0x0eff -#define SMIAPP_REG_U16_INTEGRATION_TIME_CAPABILITY (0x1000 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MIN (0x1004 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MAX_MARGIN (0x1006 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN (0x1008 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN (0x100a | CCS_FL_16BIT) -#define SMIAPP_REG_U16_DIGITAL_GAIN_CAPABILITY (0x1080 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_DIGITAL_GAIN_MIN (0x1084 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_DIGITAL_GAIN_MAX (0x1086 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_DIGITAL_GAIN_STEP_SIZE (0x1088 | CCS_FL_16BIT) -#define SMIAPP_REG_F32_MIN_EXT_CLK_FREQ_HZ (0x1100 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_F32_MAX_EXT_CLK_FREQ_HZ (0x1104 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_U16_MIN_PRE_PLL_CLK_DIV (0x1108 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_PRE_PLL_CLK_DIV (0x110a | CCS_FL_16BIT) -#define SMIAPP_REG_F32_MIN_PLL_IP_FREQ_HZ (0x110c | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_F32_MAX_PLL_IP_FREQ_HZ (0x1110 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_U16_MIN_PLL_MULTIPLIER (0x1114 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_PLL_MULTIPLIER (0x1116 | CCS_FL_16BIT) -#define SMIAPP_REG_F32_MIN_PLL_OP_FREQ_HZ (0x1118 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_F32_MAX_PLL_OP_FREQ_HZ (0x111c | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_U16_MIN_VT_SYS_CLK_DIV (0x1120 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_VT_SYS_CLK_DIV (0x1122 | CCS_FL_16BIT) -#define SMIAPP_REG_F32_MIN_VT_SYS_CLK_FREQ_HZ (0x1124 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_F32_MAX_VT_SYS_CLK_FREQ_HZ (0x1128 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_F32_MIN_VT_PIX_CLK_FREQ_HZ (0x112c | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_F32_MAX_VT_PIX_CLK_FREQ_HZ (0x1130 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_U16_MIN_VT_PIX_CLK_DIV (0x1134 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_VT_PIX_CLK_DIV (0x1136 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES (0x1140 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES (0x1142 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK (0x1144 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK (0x1146 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK (0x1148 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MIN_FRAME_BLANKING_LINES (0x114a | CCS_FL_16BIT) -#define SMIAPP_REG_U8_MIN_LINE_LENGTH_PCK_STEP_SIZE 0x114c -#define SMIAPP_REG_U16_MIN_OP_SYS_CLK_DIV (0x1160 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_OP_SYS_CLK_DIV (0x1162 | CCS_FL_16BIT) -#define SMIAPP_REG_F32_MIN_OP_SYS_CLK_FREQ_HZ (0x1164 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_F32_MAX_OP_SYS_CLK_FREQ_HZ (0x1168 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_U16_MIN_OP_PIX_CLK_DIV (0x116c | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_OP_PIX_CLK_DIV (0x116e | CCS_FL_16BIT) -#define SMIAPP_REG_F32_MIN_OP_PIX_CLK_FREQ_HZ (0x1170 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_F32_MAX_OP_PIX_CLK_FREQ_HZ (0x1174 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT) -#define SMIAPP_REG_U16_X_ADDR_MIN (0x1180 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_Y_ADDR_MIN (0x1182 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_X_ADDR_MAX (0x1184 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_Y_ADDR_MAX (0x1186 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MIN_X_OUTPUT_SIZE (0x1188 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MIN_Y_OUTPUT_SIZE (0x118a | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_X_OUTPUT_SIZE (0x118c | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_Y_OUTPUT_SIZE (0x118e | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MIN_EVEN_INC (0x11c0 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_EVEN_INC (0x11c2 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MIN_ODD_INC (0x11c4 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_ODD_INC (0x11c6 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_SCALING_CAPABILITY (0x1200 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_SCALER_M_MIN (0x1204 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_SCALER_M_MAX (0x1206 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_SCALER_N_MIN (0x1208 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_SCALER_N_MAX (0x120a | CCS_FL_16BIT) -#define SMIAPP_REG_U16_SPATIAL_SAMPLING_CAPABILITY (0x120c | CCS_FL_16BIT) -#define SMIAPP_REG_U8_DIGITAL_CROP_CAPABILITY 0x120e -#define SMIAPP_REG_U16_COMPRESSION_CAPABILITY (0x1300 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINRED (0x1400 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINRED (0x1402 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINRED (0x1404 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINGREEN (0x1406 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINGREEN (0x1408 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINGREEN (0x140a | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINBLUE (0x140c | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINBLUE (0x140e | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINBLUE (0x1410 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_FIFO_SIZE_PIXELS (0x1500 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_FIFO_SUPPORT_CAPABILITY 0x1502 -#define SMIAPP_REG_U8_DPHY_CTRL_CAPABILITY 0x1600 -#define SMIAPP_REG_U8_CSI_LANE_MODE_CAPABILITY 0x1601 -#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE_CAPABILITY 0x1602 -#define SMIAPP_REG_U8_FAST_STANDBY_CAPABILITY 0x1603 -#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL_CAPABILITY 0x1604 -#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS (0x1608 | CCS_FL_32BIT) -#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS (0x160c | CCS_FL_32BIT) -#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS (0x1610 | CCS_FL_32BIT) -#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS (0x1614 | CCS_FL_32BIT) -#define SMIAPP_REG_U8_TEMP_SENSOR_CAPABILITY 0x1618 -#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES_BIN (0x1700 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES_BIN (0x1702 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK_BIN (0x1704 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK_BIN (0x1706 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK_BIN (0x1708 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN_BIN (0x170a | CCS_FL_16BIT) -#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN (0x170c | CCS_FL_16BIT) -#define SMIAPP_REG_U8_BINNING_CAPABILITY 0x1710 -#define SMIAPP_REG_U8_BINNING_WEIGHTING_CAPABILITY 0x1711 -#define SMIAPP_REG_U8_BINNING_SUBTYPES 0x1712 -#define SMIAPP_REG_U8_BINNING_TYPE_n(n) (0x1713 + (n)) /* 1 <= n <= 237 */ -#define SMIAPP_REG_U8_DATA_TRANSFER_IF_CAPABILITY 0x1800 -#define SMIAPP_REG_U8_SHADING_CORRECTION_CAPABILITY 0x1900 -#define SMIAPP_REG_U8_GREEN_IMBALANCE_CAPABILITY 0x1901 -#define SMIAPP_REG_U8_BLACK_LEVEL_CAPABILITY 0x1902 -#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_CAPABILITY 0x1903 -#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY (0x1904 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY_2 (0x1906 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_EDOF_CAPABILITY 0x1980 -#define SMIAPP_REG_U8_ESTIMATION_FRAMES 0x1981 -#define SMIAPP_REG_U8_SUPPORTS_SHARPNESS_ADJ 0x1982 -#define SMIAPP_REG_U8_SUPPORTS_DENOISING_ADJ 0x1983 -#define SMIAPP_REG_U8_SUPPORTS_MODULE_SPECIFIC_ADJ 0x1984 -#define SMIAPP_REG_U8_SUPPORTS_DEPTH_OF_FIELD_ADJ 0x1985 -#define SMIAPP_REG_U8_SUPPORTS_FOCUS_DISTANCE_ADJ 0x1986 -#define SMIAPP_REG_U8_COLOUR_FEEDBACK_CAPABILITY 0x1987 -#define SMIAPP_REG_U8_EDOF_SUPPORT_AB_NXM 0x1988 -#define SMIAPP_REG_U8_ESTIMATION_MODE_CAPABILITY 0x19c0 -#define SMIAPP_REG_U8_ESTIMATION_ZONE_CAPABILITY 0x19c1 -#define SMIAPP_REG_U16_EST_DEPTH_OF_FIELD (0x19c2 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_EST_FOCUS_DISTANCE (0x19c4 | CCS_FL_16BIT) -#define SMIAPP_REG_U16_CAPABILITY_TRDY_MIN (0x1a00 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_FLASH_MODE_CAPABILITY 0x1a02 -#define SMIAPP_REG_U16_MECH_SHUT_AND_ACT_START_ADDR (0x1b02 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_ACTUATOR_CAPABILITY 0x1b04 -#define SMIAPP_REG_U16_ACTUATOR_TYPE (0x1b40 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_AF_DEVICE_ADDRESS 0x1b42 -#define SMIAPP_REG_U16_FOCUS_CHANGE_ADDRESS (0x1b44 | CCS_FL_16BIT) -#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_1 0x1c00 -#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_2 0x1c01 -#define SMIAPP_REG_U8_BRACKETING_LUT_SIZE 0x1c02 - -/* Register bit definitions */ -#define SMIAPP_IMAGE_ORIENTATION_HFLIP BIT(0) -#define SMIAPP_IMAGE_ORIENTATION_VFLIP BIT(1) - -#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_EN BIT(0) -#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_WR_EN BIT(1) -#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_ERR_CLEAR BIT(2) -#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY BIT(0) -#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_WR_READY BIT(1) -#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_EDATA BIT(2) -#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_EUSAGE BIT(3) - -#define SMIAPP_DATA_TRANSFER_IF_CAPABILITY_SUPPORTED BIT(0) -#define SMIAPP_DATA_TRANSFER_IF_CAPABILITY_POLL BIT(2) - -#define SMIAPP_SOFTWARE_RESET BIT(0) - -#define SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE BIT(0) -#define SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE BIT(1) - -#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK 0 -#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE 1 -#define SMIAPP_CSI_SIGNALLING_MODE_CSI2 2 - -#define SMIAPP_DPHY_CTRL_AUTOMATIC 0 -/* DPHY control based on REQUESTED_LINK_BIT_RATE_MBPS */ -#define SMIAPP_DPHY_CTRL_UI 1 -#define SMIAPP_DPHY_CTRL_REGISTER 2 - -#define SMIAPP_COMPRESSION_MODE_SIMPLE_PREDICTOR 1 -#define SMIAPP_COMPRESSION_MODE_ADVANCED_PREDICTOR 2 - -#define SMIAPP_MODE_SELECT_SOFTWARE_STANDBY 0 -#define SMIAPP_MODE_SELECT_STREAMING 1 - -#define SMIAPP_SCALING_MODE_NONE 0 -#define SMIAPP_SCALING_MODE_HORIZONTAL 1 -#define SMIAPP_SCALING_MODE_BOTH 2 - -#define SMIAPP_SCALING_CAPABILITY_NONE 0 -#define SMIAPP_SCALING_CAPABILITY_HORIZONTAL 1 -#define SMIAPP_SCALING_CAPABILITY_BOTH 2 /* horizontal/both */ - -/* digital crop right before scaler */ -#define SMIAPP_DIGITAL_CROP_CAPABILITY_NONE 0 -#define SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP 1 - -#define SMIAPP_BINNING_CAPABILITY_NO 0 -#define SMIAPP_BINNING_CAPABILITY_YES 1 - -/* Maximum number of binning subtypes */ -#define SMIAPP_BINNING_SUBTYPES 253 - -#define SMIAPP_PIXEL_ORDER_GRBG 0 -#define SMIAPP_PIXEL_ORDER_RGGB 1 -#define SMIAPP_PIXEL_ORDER_BGGR 2 -#define SMIAPP_PIXEL_ORDER_GBRG 3 - -#define SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL 1 -#define SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED 2 -#define SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL_N 8 -#define SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED_N 16 - -#define SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE 0x01 -#define SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE 0x02 -#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NROWS_MASK 0x0f -#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_MASK 0xf0 -#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_SHIFT 4 - -#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_MASK 0xf000 -#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_SHIFT 12 -#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELS_MASK 0x0fff - -#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_MASK 0xf0000000 -#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_SHIFT 28 -#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELS_MASK 0x0000ffff - -#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED 1 -#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DUMMY 2 -#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_BLACK 3 -#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DARK 4 -#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE 5 - -#define SMIAPP_FAST_STANDBY_CTRL_COMPLETE_FRAMES 0 -#define SMIAPP_FAST_STANDBY_CTRL_IMMEDIATE 1 - -/* Scaling N factor */ -#define SMIAPP_SCALE_N 16 - -#endif /* __SMIAPP_REG_DEFS_H__ */ -- cgit v1.2.3 From ae7855a4f927cb7362926123851399073a7d54c2 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 11 Feb 2020 20:22:26 +0100 Subject: media: ccs: Remove profile concept The driver doesn't do anything tangible with profiles. Remove the notion, and use the capabilities directly. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 23 ++++++----------------- drivers/media/i2c/ccs/ccs.h | 2 -- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 2dfb26cb3a40..cc3a81200050 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -377,7 +377,7 @@ static int ccs_pll_configure(struct ccs_sensor *sensor) rval = ccs_write(sensor, REQUESTED_LINK_RATE, DIV_ROUND_UP(pll->op.sys_clk_freq_hz, 1000000 / 256 / 256)); - if (rval < 0 || sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) + if (rval < 0 || sensor->pll.flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS) return rval; rval = ccs_write(sensor, OP_PIX_CLK_DIV, pll->op.pix_clk_div); @@ -3096,23 +3096,17 @@ static int ccs_probe(struct i2c_client *client) } } - /* We consider this as profile 0 sensor if any of these are zero. */ if (!CCS_LIM(sensor, MIN_OP_SYS_CLK_DIV) || !CCS_LIM(sensor, MAX_OP_SYS_CLK_DIV) || !CCS_LIM(sensor, MIN_OP_PIX_CLK_DIV) || !CCS_LIM(sensor, MAX_OP_PIX_CLK_DIV)) { - sensor->minfo.smiapp_profile = SMIAPP_PROFILE_0; + /* No OP clock branch */ + sensor->pll.flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS; } else if (CCS_LIM(sensor, SCALING_CAPABILITY) - != CCS_SCALING_CAPABILITY_NONE) { - if (CCS_LIM(sensor, SCALING_CAPABILITY) - == CCS_SCALING_CAPABILITY_HORIZONTAL) - sensor->minfo.smiapp_profile = SMIAPP_PROFILE_1; - else - sensor->minfo.smiapp_profile = SMIAPP_PROFILE_2; - sensor->scaler = &sensor->ssds[sensor->ssds_used]; - sensor->ssds_used++; - } else if (CCS_LIM(sensor, DIGITAL_CROP_CAPABILITY) + != CCS_SCALING_CAPABILITY_NONE || + CCS_LIM(sensor, DIGITAL_CROP_CAPABILITY) == CCS_DIGITAL_CROP_CAPABILITY_INPUT_CROP) { + /* We have a scaler or digital crop. */ sensor->scaler = &sensor->ssds[sensor->ssds_used]; sensor->ssds_used++; } @@ -3128,16 +3122,11 @@ static int ccs_probe(struct i2c_client *client) sensor->pll.csi2.lanes = sensor->hwcfg->lanes; sensor->pll.ext_clk_freq_hz = sensor->hwcfg->ext_clk; sensor->pll.scale_n = CCS_LIM(sensor, SCALER_N_MIN); - /* Profile 0 sensors have no separate OP clock branch. */ - if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) - sensor->pll.flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS; ccs_create_subdev(sensor, sensor->scaler, " scaler", 2); ccs_create_subdev(sensor, sensor->binner, " binner", 2); ccs_create_subdev(sensor, sensor->pixel_array, " pixel_array", 1); - dev_dbg(&client->dev, "profile %d\n", sensor->minfo.smiapp_profile); - sensor->pixel_array->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; rval = ccs_init_controls(sensor); diff --git a/drivers/media/i2c/ccs/ccs.h b/drivers/media/i2c/ccs/ccs.h index 7f6ed95b7b78..8933f3d40fa5 100644 --- a/drivers/media/i2c/ccs/ccs.h +++ b/drivers/media/i2c/ccs/ccs.h @@ -124,8 +124,6 @@ struct ccs_module_info { u32 smiapp_version; u32 ccs_version; - u32 smiapp_profile; - char *name; const struct ccs_quirk *quirk; }; -- cgit v1.2.3 From 9ec2ac9bd0f91caa0fc4b04bbc221b36220096ae Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 11 Feb 2020 22:01:14 +0100 Subject: media: ccs: Give all subdevs a function This removes a warning at driver probe time telling that one or two entities have no function set. The function used for both the binner and scaler is the scaler. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index cc3a81200050..bddfee637f33 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -2685,7 +2685,7 @@ static void ccs_cleanup(struct ccs_sensor *sensor) static void ccs_create_subdev(struct ccs_sensor *sensor, struct ccs_subdev *ssd, const char *name, - unsigned short num_pads) + unsigned short num_pads, u32 function) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); @@ -2696,6 +2696,7 @@ static void ccs_create_subdev(struct ccs_sensor *sensor, v4l2_subdev_init(&ssd->sd, &ccs_ops); ssd->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + ssd->sd.entity.function = function; ssd->sensor = sensor; ssd->npads = num_pads; @@ -3123,11 +3124,12 @@ static int ccs_probe(struct i2c_client *client) sensor->pll.ext_clk_freq_hz = sensor->hwcfg->ext_clk; sensor->pll.scale_n = CCS_LIM(sensor, SCALER_N_MIN); - ccs_create_subdev(sensor, sensor->scaler, " scaler", 2); - ccs_create_subdev(sensor, sensor->binner, " binner", 2); - ccs_create_subdev(sensor, sensor->pixel_array, " pixel_array", 1); - - sensor->pixel_array->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ccs_create_subdev(sensor, sensor->scaler, " scaler", 2, + MEDIA_ENT_F_CAM_SENSOR); + ccs_create_subdev(sensor, sensor->binner, " binner", 2, + MEDIA_ENT_F_PROC_VIDEO_SCALER); + ccs_create_subdev(sensor, sensor->pixel_array, " pixel_array", 1, + MEDIA_ENT_F_PROC_VIDEO_SCALER); rval = ccs_init_controls(sensor); if (rval < 0) -- cgit v1.2.3 From bbe5062e27ddac05216263b519bd2d163c798a33 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 29 Sep 2020 13:14:00 +0200 Subject: media: dt-bindings: nokia,smia: Fix link-frequencies documentation The link-frequencies property belongs to the endpoint, not to the node representing the device. Signed-off-by: Sakari Ailus Acked-by: Rob Herring Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/i2c/nokia,smia.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt b/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt index 10ece8108081..6c45c79ef91f 100644 --- a/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt +++ b/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt @@ -20,8 +20,6 @@ Mandatory properties dependent). - clocks: External clock to the sensor - clock-frequency: Frequency of the external clock to the sensor -- link-frequencies: List of allowed data link frequencies. An array of - 64-bit elements. Optional properties @@ -39,6 +37,8 @@ Endpoint node mandatory properties ---------------------------------- - data-lanes: <1..n> +- link-frequencies: List of allowed data link frequencies. An array of + 64-bit elements. Example @@ -55,11 +55,13 @@ Example clocks = <&omap3_isp 0>; clock-frequency = <9600000>; nokia,nvm-size = <512>; /* 8 * 64 */ - link-frequencies = /bits/ 64 <199200000 210000000 499200000>; port { smiapp_ep: endpoint { data-lanes = <1 2>; remote-endpoint = <&csi2a_ep>; + link-frequencies = + /bits/ 64 <199200000 210000000 + 499200000>; }; }; }; -- cgit v1.2.3 From 2d720d365bc1f438e860452735c5350e3cf136e1 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 29 Sep 2020 13:28:28 +0200 Subject: media: dt-bindings: nokia,smia: Make vana-supply optional vana-supply is optional in the spec, therefore make it optional in bindings, too. Signed-off-by: Sakari Ailus Acked-by: Rob Herring Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/i2c/nokia,smia.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt b/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt index 6c45c79ef91f..5ea4f799877b 100644 --- a/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt +++ b/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt @@ -16,8 +16,6 @@ Mandatory properties - compatible: "nokia,smia" - reg: I2C address (0x10, or an alternative address) -- vana-supply: Analogue voltage supply (VANA), typically 2,8 volts (sensor - dependent). - clocks: External clock to the sensor - clock-frequency: Frequency of the external clock to the sensor @@ -31,6 +29,8 @@ Optional properties - rotation: Integer property; valid values are 0 (sensor mounted upright) and 180 (sensor mounted upside down). See ../video-interfaces.txt . +- vana-supply: Analogue voltage supply (VANA), typically 2,8 volts (sensor + dependent). Endpoint node mandatory properties -- cgit v1.2.3 From 390bb477ebd54f2e286936682eea3a590e0538cd Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 1 Oct 2020 13:50:44 +0200 Subject: media: dt-bindings: nokia,smia: Remove nokia,nvm-size property nokia,nvm-size property was removed from the bindings but it was left in the example. Remove it from the example, too. Signed-off-by: Sakari Ailus Acked-by: Rob Herring Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/i2c/nokia,smia.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt b/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt index 5ea4f799877b..5f39a7070c51 100644 --- a/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt +++ b/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt @@ -54,7 +54,6 @@ Example vana-supply = <&vaux3>; clocks = <&omap3_isp 0>; clock-frequency = <9600000>; - nokia,nvm-size = <512>; /* 8 * 64 */ port { smiapp_ep: endpoint { data-lanes = <1 2>; -- cgit v1.2.3 From 8265d427eddcfcfe01cd98f6fa3a5acb79f76fe8 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 29 Sep 2020 13:32:17 +0200 Subject: media: dt-bindings: nokia,smia: Convert to YAML Convert nokia,smia DT bindings to YAML. Also add explicit license to bindings. Signed-off-by: Sakari Ailus Reviewed-by: Rob Herring Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/i2c/nokia,smia.txt | 67 ------------- .../devicetree/bindings/media/i2c/nokia,smia.yaml | 106 +++++++++++++++++++++ MAINTAINERS | 2 +- 3 files changed, 107 insertions(+), 68 deletions(-) delete mode 100644 Documentation/devicetree/bindings/media/i2c/nokia,smia.txt create mode 100644 Documentation/devicetree/bindings/media/i2c/nokia,smia.yaml diff --git a/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt b/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt deleted file mode 100644 index 5f39a7070c51..000000000000 --- a/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt +++ /dev/null @@ -1,67 +0,0 @@ -SMIA/SMIA++ sensor - -SMIA (Standard Mobile Imaging Architecture) is an image sensor standard -defined jointly by Nokia and ST. SMIA++, defined by Nokia, is an extension -of that. These definitions are valid for both types of sensors. - -More detailed documentation can be found in -Documentation/devicetree/bindings/media/video-interfaces.txt . - -The device node should contain a "port" node which may contain one or more -endpoint nodes, in accordance with video interface bindings defined in -Documentation/devicetree/bindings/media/video-interfaces.txt . - -Mandatory properties --------------------- - -- compatible: "nokia,smia" -- reg: I2C address (0x10, or an alternative address) -- clocks: External clock to the sensor -- clock-frequency: Frequency of the external clock to the sensor - - -Optional properties -------------------- - -- reset-gpios: XSHUTDOWN GPIO -- flash-leds: See ../video-interfaces.txt -- lens-focus: See ../video-interfaces.txt -- rotation: Integer property; valid values are 0 (sensor mounted upright) - and 180 (sensor mounted upside down). See - ../video-interfaces.txt . -- vana-supply: Analogue voltage supply (VANA), typically 2,8 volts (sensor - dependent). - - -Endpoint node mandatory properties ----------------------------------- - -- data-lanes: <1..n> -- link-frequencies: List of allowed data link frequencies. An array of - 64-bit elements. - - -Example -------- - -&i2c2 { - clock-frequency = <400000>; - - camera-sensor@10 { - compatible = "nokia,smia"; - reg = <0x10>; - reset-gpios = <&gpio3 20 0>; - vana-supply = <&vaux3>; - clocks = <&omap3_isp 0>; - clock-frequency = <9600000>; - port { - smiapp_ep: endpoint { - data-lanes = <1 2>; - remote-endpoint = <&csi2a_ep>; - link-frequencies = - /bits/ 64 <199200000 210000000 - 499200000>; - }; - }; - }; -}; diff --git a/Documentation/devicetree/bindings/media/i2c/nokia,smia.yaml b/Documentation/devicetree/bindings/media/i2c/nokia,smia.yaml new file mode 100644 index 000000000000..ee552489fa2b --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/nokia,smia.yaml @@ -0,0 +1,106 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2014--2020 Intel Corporation + +$id: http://devicetree.org/schemas/media/i2c/nokia,smia.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: SMIA/SMIA++ sensor + +maintainers: + - Sakari Ailus + +description: + + SMIA (Standard Mobile Imaging Architecture) is an image sensor standard + defined jointly by Nokia and ST. SMIA++, defined by Nokia, is an extension of + that. These definitions are valid for both types of sensors. + + More detailed documentation can be found in + Documentation/devicetree/bindings/media/video-interfaces.txt . + +properties: + compatible: + const: nokia,smia + + reg: + maxItems: 1 + + vana-supply: + description: Analogue voltage supply (VANA), typically 2,8 volts (sensor + dependent). + maxItems: 1 + + clocks: + description: External clock to the sensor. + maxItems: 1 + + clock-frequency: + description: Frequency of the external clock to the sensor in Hz. + + reset-gpios: + description: Reset GPIO. Also commonly called XSHUTDOWN in hardware + documentation. + maxItems: 1 + + flash-leds: + description: Flash LED phandles. See ../video-interfaces.txt for details. + + lens-focus: + description: Lens focus controller phandles. See ../video-interfaces.txt + for details. + + rotation: + description: Rotation of the sensor. See ../video-interfaces.txt for + details. + enum: [ 0, 180 ] + + port: + type: object + properties: + endpoint: + type: object + properties: + link-frequencies: + $ref: /schemas/types.yaml#/definitions/uint64-array + description: List of allowed data link frequencies. + data-lanes: + minItems: 1 + maxItems: 8 + required: + - link-frequencies + - data-lanes + +required: + - compatible + - reg + - clock-frequency + - clocks + +additionalProperties: false + +examples: + - | + i2c2 { + #address-cells = <1>; + #size-cells = <0>; + + clock-frequency = <400000>; + + camera-sensor@10 { + compatible = "nokia,smia"; + reg = <0x10>; + reset-gpios = <&gpio3 20 0>; + vana-supply = <&vaux3>; + clocks = <&omap3_isp 0>; + clock-frequency = <9600000>; + port { + smiapp_ep: endpoint { + data-lanes = <1 2>; + remote-endpoint = <&csi2a_ep>; + link-frequencies = /bits/ 64 <199200000 210000000 + 499200000>; + }; + }; + }; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index e23b3e4d9a9d..38faf82ef766 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11634,7 +11634,7 @@ MIPI CCS, SMIA AND SMIA++ IMAGE SENSOR DRIVER M: Sakari Ailus L: linux-media@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/media/i2c/nokia,smia.txt +F: Documentation/devicetree/bindings/media/i2c/nokia,smia.yaml F: Documentation/driver-api/media/drivers/ccs/ F: drivers/media/i2c/ccs/ F: drivers/media/i2c/smiapp-pll.c -- cgit v1.2.3 From 701b8c2c750b830e0508b8435d94f34ad0426918 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 29 Sep 2020 14:40:40 +0200 Subject: media: dt-bindings: nokia,smia: Use better active polarity for reset Generally reset signal is active low on camera sensors. The example had it high. Make it low, and use GPIO_ACTIVE_LOW in gpio.h for that. Signed-off-by: Sakari Ailus Acked-by: Rob Herring Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/i2c/nokia,smia.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/media/i2c/nokia,smia.yaml b/Documentation/devicetree/bindings/media/i2c/nokia,smia.yaml index ee552489fa2b..47df08338a42 100644 --- a/Documentation/devicetree/bindings/media/i2c/nokia,smia.yaml +++ b/Documentation/devicetree/bindings/media/i2c/nokia,smia.yaml @@ -80,6 +80,8 @@ additionalProperties: false examples: - | + #include + i2c2 { #address-cells = <1>; #size-cells = <0>; @@ -89,7 +91,7 @@ examples: camera-sensor@10 { compatible = "nokia,smia"; reg = <0x10>; - reset-gpios = <&gpio3 20 0>; + reset-gpios = <&gpio3 20 GPIO_ACTIVE_LOW>; vana-supply = <&vaux3>; clocks = <&omap3_isp 0>; clock-frequency = <9600000>; -- cgit v1.2.3 From 72051783cd736d82711fe6fd1df2b71a0d4d6e82 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 11 Feb 2020 22:26:25 +0100 Subject: media: dt-bindings: nokia,smia: Amend SMIA bindings with MIPI CCS support Amend the existing SMIA bindings by adding MIPI CCS support, with separate compatible strings for CCS 1.0 and CCS 1.1. Rename the old bindings accordingly as CCS is the current standard. Signed-off-by: Sakari Ailus Reviewed-by: Rob Herring Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/i2c/mipi-ccs.yaml | 119 +++++++++++++++++++++ .../devicetree/bindings/media/i2c/nokia,smia.yaml | 108 ------------------- MAINTAINERS | 2 +- 3 files changed, 120 insertions(+), 109 deletions(-) create mode 100644 Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml delete mode 100644 Documentation/devicetree/bindings/media/i2c/nokia,smia.yaml diff --git a/Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml b/Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml new file mode 100644 index 000000000000..a386ee246956 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml @@ -0,0 +1,119 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2014--2020 Intel Corporation + +$id: http://devicetree.org/schemas/media/i2c/mipi-ccs.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MIPI CCS, SMIA++ and SMIA compliant camera sensors + +maintainers: + - Sakari Ailus + +description: + + CCS (Camera Command Set) is a raw Bayer camera sensor standard defined by the + MIPI Alliance; see + . + + SMIA (Standard Mobile Imaging Architecture) is an image sensor standard + defined jointly by Nokia and ST. SMIA++, defined by Nokia, is an extension of + that. + + More detailed documentation can be found in + Documentation/devicetree/bindings/media/video-interfaces.txt . + +properties: + compatible: + oneOf: + - items: + - const: mipi-ccs-1.1 + - const: mipi-ccs + - items: + - const: mipi-ccs-1.0 + - const: mipi-ccs + - const: nokia,smia + + reg: + maxItems: 1 + + vana-supply: + description: Analogue voltage supply (VANA), typically 2,8 volts (sensor + dependent). + maxItems: 1 + + clocks: + description: External clock to the sensor. + maxItems: 1 + + clock-frequency: + description: Frequency of the external clock to the sensor in Hz. + + reset-gpios: + description: Reset GPIO. Also commonly called XSHUTDOWN in hardware + documentation. + maxItems: 1 + + flash-leds: + description: Flash LED phandles. See ../video-interfaces.txt for details. + + lens-focus: + description: Lens focus controller phandles. See ../video-interfaces.txt + for details. + + rotation: + description: Rotation of the sensor. See ../video-interfaces.txt for + details. + enum: [ 0, 180 ] + + port: + type: object + properties: + endpoint: + type: object + properties: + link-frequencies: + $ref: /schemas/types.yaml#/definitions/uint64-array + description: List of allowed data link frequencies. + data-lanes: + minItems: 1 + maxItems: 8 + required: + - link-frequencies + - data-lanes + +required: + - compatible + - reg + - clock-frequency + - clocks + +additionalProperties: false + +examples: + - | + #include + + i2c2 { + #address-cells = <1>; + #size-cells = <0>; + + clock-frequency = <400000>; + + camera-sensor@10 { + compatible = "mipi-ccs-1.0", "mipi-ccs"; + reg = <0x10>; + reset-gpios = <&gpio3 20 GPIO_ACTIVE_LOW>; + vana-supply = <&vaux3>; + clocks = <&omap3_isp 0>; + clock-frequency = <9600000>; + port { + ccs_ep: endpoint { + data-lanes = <1 2>; + remote-endpoint = <&csi2a_ep>; + link-frequencies = /bits/ 64 <199200000 210000000 + 499200000>; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/media/i2c/nokia,smia.yaml b/Documentation/devicetree/bindings/media/i2c/nokia,smia.yaml deleted file mode 100644 index 47df08338a42..000000000000 --- a/Documentation/devicetree/bindings/media/i2c/nokia,smia.yaml +++ /dev/null @@ -1,108 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -# Copyright (C) 2014--2020 Intel Corporation - -$id: http://devicetree.org/schemas/media/i2c/nokia,smia.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: SMIA/SMIA++ sensor - -maintainers: - - Sakari Ailus - -description: - - SMIA (Standard Mobile Imaging Architecture) is an image sensor standard - defined jointly by Nokia and ST. SMIA++, defined by Nokia, is an extension of - that. These definitions are valid for both types of sensors. - - More detailed documentation can be found in - Documentation/devicetree/bindings/media/video-interfaces.txt . - -properties: - compatible: - const: nokia,smia - - reg: - maxItems: 1 - - vana-supply: - description: Analogue voltage supply (VANA), typically 2,8 volts (sensor - dependent). - maxItems: 1 - - clocks: - description: External clock to the sensor. - maxItems: 1 - - clock-frequency: - description: Frequency of the external clock to the sensor in Hz. - - reset-gpios: - description: Reset GPIO. Also commonly called XSHUTDOWN in hardware - documentation. - maxItems: 1 - - flash-leds: - description: Flash LED phandles. See ../video-interfaces.txt for details. - - lens-focus: - description: Lens focus controller phandles. See ../video-interfaces.txt - for details. - - rotation: - description: Rotation of the sensor. See ../video-interfaces.txt for - details. - enum: [ 0, 180 ] - - port: - type: object - properties: - endpoint: - type: object - properties: - link-frequencies: - $ref: /schemas/types.yaml#/definitions/uint64-array - description: List of allowed data link frequencies. - data-lanes: - minItems: 1 - maxItems: 8 - required: - - link-frequencies - - data-lanes - -required: - - compatible - - reg - - clock-frequency - - clocks - -additionalProperties: false - -examples: - - | - #include - - i2c2 { - #address-cells = <1>; - #size-cells = <0>; - - clock-frequency = <400000>; - - camera-sensor@10 { - compatible = "nokia,smia"; - reg = <0x10>; - reset-gpios = <&gpio3 20 GPIO_ACTIVE_LOW>; - vana-supply = <&vaux3>; - clocks = <&omap3_isp 0>; - clock-frequency = <9600000>; - port { - smiapp_ep: endpoint { - data-lanes = <1 2>; - remote-endpoint = <&csi2a_ep>; - link-frequencies = /bits/ 64 <199200000 210000000 - 499200000>; - }; - }; - }; - }; -... diff --git a/MAINTAINERS b/MAINTAINERS index 38faf82ef766..5c05e7bf7ffd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11634,7 +11634,7 @@ MIPI CCS, SMIA AND SMIA++ IMAGE SENSOR DRIVER M: Sakari Ailus L: linux-media@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/media/i2c/nokia,smia.yaml +F: Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml F: Documentation/driver-api/media/drivers/ccs/ F: drivers/media/i2c/ccs/ F: drivers/media/i2c/smiapp-pll.c -- cgit v1.2.3 From aab402ea9b4827f6d8d4a7c58d7492124b493e02 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 29 Sep 2020 14:51:29 +0200 Subject: media: dt-bindings: mipi-ccs: Add bus-type for C-PHY support The bus-type property is required for C-PHY support. Add it, including values for CCP2 and CSI-2 D-PHY. Also require the bus-type property. Effectively all new sensors are MIPI D-PHY or C-PHY that cannot be told apart without the bus-type property. Signed-off-by: Sakari Ailus Reviewed-by: Rob Herring Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml b/Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml index a386ee246956..1d90767a6196 100644 --- a/Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml +++ b/Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml @@ -77,9 +77,17 @@ properties: data-lanes: minItems: 1 maxItems: 8 + bus-type: + description: The type of the data bus. + oneOf: + - const: 1 # CSI-2 C-PHY + - const: 3 # CCP2 + - const: 4 # CSI-2 D-PHY + required: - link-frequencies - data-lanes + - bus-type required: - compatible @@ -112,6 +120,7 @@ examples: remote-endpoint = <&csi2a_ep>; link-frequencies = /bits/ 64 <199200000 210000000 499200000>; + bus-type = <4>; }; }; }; -- cgit v1.2.3 From d0fbdcbe75950a4f93edcece34622888c4395133 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 18 Jun 2020 13:12:51 +0200 Subject: media: ccs: Request for "reset" GPIO The DT bindings documented "reset-gpios" property but the driver never made use of it. Instead it used a GPIO called "xshutdown", with apprently wrong polarity. Fix this by requesting "reset" GPIO with the right polarity first, and if that fails, then request "xshutdown" GPIO with the old polarity. This way it works for new users as expected while if someone, somewhere, depended on "xshutdown" GPIO, that continues to work as well. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 14 ++++++++++++-- drivers/media/i2c/ccs/ccs.h | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index bddfee637f33..69e7990c65f3 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -1295,6 +1295,7 @@ static int ccs_power_on(struct device *dev) } usleep_range(1000, 1000); + gpiod_set_value(sensor->reset, 0); gpiod_set_value(sensor->xshutdown, 1); sleep = SMIAPP_RESET_DELAY(sensor->hwcfg->ext_clk); @@ -1381,6 +1382,7 @@ static int ccs_power_on(struct device *dev) return 0; out_cci_addr_fail: + gpiod_set_value(sensor->reset, 1); gpiod_set_value(sensor->xshutdown, 0); clk_disable_unprepare(sensor->ext_clk); @@ -1407,6 +1409,7 @@ static int ccs_power_off(struct device *dev) if (sensor->hwcfg->i2c_addr_alt) ccs_write(sensor, SOFTWARE_RESET, CCS_SOFTWARE_RESET_ON); + gpiod_set_value(sensor->reset, 1); gpiod_set_value(sensor->xshutdown, 0); clk_disable_unprepare(sensor->ext_clk); usleep_range(5000, 5000); @@ -3008,8 +3011,15 @@ static int ccs_probe(struct i2c_client *client) return -EINVAL; } - sensor->xshutdown = devm_gpiod_get_optional(&client->dev, "xshutdown", - GPIOD_OUT_LOW); + sensor->reset = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(sensor->reset)) + return PTR_ERR(sensor->reset); + /* Support old users that may have used "xshutdown" property. */ + if (!sensor->reset) + sensor->xshutdown = devm_gpiod_get_optional(&client->dev, + "xshutdown", + GPIOD_OUT_LOW); if (IS_ERR(sensor->xshutdown)) return PTR_ERR(sensor->xshutdown); diff --git a/drivers/media/i2c/ccs/ccs.h b/drivers/media/i2c/ccs/ccs.h index 8933f3d40fa5..bfe39e02f5e9 100644 --- a/drivers/media/i2c/ccs/ccs.h +++ b/drivers/media/i2c/ccs/ccs.h @@ -219,6 +219,7 @@ struct ccs_sensor { struct regulator *vana; struct clk *ext_clk; struct gpio_desc *xshutdown; + struct gpio_desc *reset; void *ccs_limits; u8 nbinning_subtypes; struct ccs_binning_subtype binning_subtypes[CCS_LIM_BINNING_SUB_TYPE_MAX_N + 1]; -- cgit v1.2.3 From 7daaf0bc24ad81ec13b444a047cf4f66827ba96e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 13 Nov 2020 15:28:31 +0100 Subject: media: omap3isp: Remove misleading comment in_interrupt() covers hard and soft interrupt servicing and bottom half disabled contexts, which is semantically undefined and useless. The comment for __ccdc_lsc_configure() "Context: in_interrupt()" is therefore as useful as "Context: unknown'. Remove it. Signed-off-by: Thomas Gleixner Signed-off-by: Sebastian Andrzej Siewior Reviewed-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispccdc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 0fbb2aa6dd2c..4e8905ef362f 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -299,11 +299,10 @@ static int ccdc_lsc_busy(struct isp_ccdc_device *ccdc) ISPCCDC_LSC_BUSY; } -/* __ccdc_lsc_configure - Apply a new configuration to the LSC engine +/* + * __ccdc_lsc_configure - Apply a new configuration to the LSC engine * @ccdc: Pointer to ISP CCDC device * @req: New configuration request - * - * context: in_interrupt() */ static int __ccdc_lsc_configure(struct isp_ccdc_device *ccdc, struct ispccdc_lsc_config_req *req) -- cgit v1.2.3 From 989bea48915861171421bd6e1367bf4c9407513d Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 15 Aug 2019 09:36:49 +0200 Subject: media: v4l: subdev: Set sd->devnode before registering the subdev The subdev's video device node was only assigned after registering the device node in the system. While it is unlikely that a driver needed to use this field in handling system calls to its file handle, there remains a slim chance the devnode field remains NULL while the driver expects to find a video node there. Assign the devnode field before registering the device, and assign it back to NULL if the registration failed. Signed-off-by: Sakari Ailus Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-device.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c index de4287251a89..d2e58ae91f9b 100644 --- a/drivers/media/v4l2-core/v4l2-device.c +++ b/drivers/media/v4l2-core/v4l2-device.c @@ -218,13 +218,14 @@ int __v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev, vdev->ctrl_handler = sd->ctrl_handler; if (read_only) set_bit(V4L2_FL_SUBDEV_RO_DEVNODE, &vdev->flags); + sd->devnode = vdev; err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1, sd->owner); if (err < 0) { + sd->devnode = NULL; kfree(vdev); goto clean_up; } - sd->devnode = vdev; #if defined(CONFIG_MEDIA_CONTROLLER) sd->entity.info.dev.major = VIDEO_MAJOR; sd->entity.info.dev.minor = vdev->minor; -- cgit v1.2.3 From 9677958d1d3d21923ca26cb5e989edc18ecf2786 Mon Sep 17 00:00:00 2001 From: Bingbu Cao Date: Fri, 27 Nov 2020 04:48:12 +0100 Subject: media: ov9734: hold lock to check streaming state The lock in ov9734 is used to protect the streaming state and serialize the stream on and off callbacks, it should be hold before checking the streaming state in ov9734_set_stream(). Reported-by: Tomasz Figa Reported-by: Sergey Senozhatsky Signed-off-by: Bingbu Cao Reviewed-by: Sergey Senozhatsky Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov9734.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ov9734.c b/drivers/media/i2c/ov9734.c index 4b9a2e9288e7..e212465489e8 100644 --- a/drivers/media/i2c/ov9734.c +++ b/drivers/media/i2c/ov9734.c @@ -637,10 +637,12 @@ static int ov9734_set_stream(struct v4l2_subdev *sd, int enable) struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; - if (ov9734->streaming == enable) + mutex_lock(&ov9734->mutex); + if (ov9734->streaming == enable) { + mutex_unlock(&ov9734->mutex); return 0; + } - mutex_lock(&ov9734->mutex); if (enable) { ret = pm_runtime_get_sync(&client->dev); if (ret < 0) { -- cgit v1.2.3 From 34487ad0c0aedc32ab18a25a274025e73ea00834 Mon Sep 17 00:00:00 2001 From: Dongchun Zhu Date: Wed, 25 Nov 2020 15:17:55 +0100 Subject: media: dt-bindings: media: i2c: document OV02A10 DT bindings Add device-tree binding documentation for OV02A10 image sensor driver, and the relevant MAINTAINERS entries. Signed-off-by: Dongchun Zhu Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/i2c/ovti,ov02a10.yaml | 159 +++++++++++++++++++++ MAINTAINERS | 7 + 2 files changed, 166 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/i2c/ovti,ov02a10.yaml diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov02a10.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov02a10.yaml new file mode 100644 index 000000000000..1c3879ec4122 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov02a10.yaml @@ -0,0 +1,159 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright (c) 2020 MediaTek Inc. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/ovti,ov02a10.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Omnivision OV02A10 CMOS Sensor Device Tree Bindings + +maintainers: + - Dongchun Zhu + +description: |- + The Omnivision OV02A10 is a low-cost, high performance, 1/5-inch, 2 megapixel + image sensor, which is the latest production derived from Omnivision's CMOS + image sensor technology. Ihis chip supports high frame rate speeds up to 30fps + @ 1600x1200 (UXGA) resolution transferred over a 1-lane MIPI interface. The + sensor output is available via CSI-2 serial data output. + +properties: + compatible: + const: ovti,ov02a10 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + description: + External clock for the sensor. + items: + - const: eclk + + clock-frequency: + description: + Frequency of the eclk clock in Hz. + + dovdd-supply: + description: + Definition of the regulator used as Digital I/O voltage supply. + + avdd-supply: + description: + Definition of the regulator used as Analog voltage supply. + + dvdd-supply: + description: + Definition of the regulator used as Digital core voltage supply. + + powerdown-gpios: + description: + Must be the device tree identifier of the GPIO connected to the + PD_PAD pin. This pin is used to place the OV02A10 into standby mode + or shutdown mode. As the line needs to be high for the powerdown mode + to be active, it should be marked GPIO_ACTIVE_HIGH. + maxItems: 1 + + reset-gpios: + description: + Must be the device tree identifier of the GPIO connected to the + RST_PD pin. If specified, it will be asserted during driver probe. + As the line needs to be low for the reset to be active, it should be + marked GPIO_ACTIVE_LOW. + maxItems: 1 + + rotation: + description: + Definition of the sensor's placement. + allOf: + - $ref: "/schemas/types.yaml#/definitions/uint32" + - enum: + - 0 # Sensor Mounted Upright + - 180 # Sensor Mounted Upside Down + default: 0 + + # See ../video-interfaces.txt for details + port: + type: object + additionalProperties: false + description: + Output port node, single endpoint describing the CSI-2 transmitter. + + properties: + endpoint: + type: object + additionalProperties: false + + properties: + link-frequencies: true + ovti,mipi-clock-voltage: + allOf: + - $ref: "/schemas/types.yaml#/definitions/uint32" + description: + Definition of MIPI clock voltage unit. This entry corresponds to + the link speed defined by the 'link-frequencies' property. + If present, the value shall be in the range of 0-4. + default: 4 + remote-endpoint: true + + required: + - link-frequencies + - remote-endpoint + + required: + - endpoint + +required: + - compatible + - reg + - clocks + - clock-names + - clock-frequency + - dovdd-supply + - avdd-supply + - dvdd-supply + - powerdown-gpios + - reset-gpios + - port + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + ov02a10: camera-sensor@3d { + compatible = "ovti,ov02a10"; + reg = <0x3d>; + + powerdown-gpios = <&pio 107 GPIO_ACTIVE_HIGH>; + reset-gpios = <&pio 109 GPIO_ACTIVE_LOW>; + + clocks = <&ov02a10_clk>; + clock-names = "eclk"; + clock-frequency = <24000000>; + + rotation = <180>; + + dovdd-supply = <&ov02a10_dovdd>; + avdd-supply = <&ov02a10_avdd>; + dvdd-supply = <&ov02a10_dvdd>; + + port { + wcam_out: endpoint { + link-frequencies = /bits/ 64 <390000000>; + ovti,mipi-clock-voltage = <3>; + remote-endpoint = <&mipi_in_wcam>; + }; + }; + }; + }; + +... diff --git a/MAINTAINERS b/MAINTAINERS index 5c05e7bf7ffd..b3ee9d9cc976 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12856,6 +12856,13 @@ M: Harald Welte S: Maintained F: drivers/char/pcmcia/cm4040_cs.* +OMNIVISION OV02A10 SENSOR DRIVER +M: Dongchun Zhu +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/ovti,ov02a10.yaml + OMNIVISION OV13858 SENSOR DRIVER M: Sakari Ailus L: linux-media@vger.kernel.org -- cgit v1.2.3 From 91807efbe8ec7f591085067d9f96a112e015274b Mon Sep 17 00:00:00 2001 From: Dongchun Zhu Date: Wed, 25 Nov 2020 15:17:56 +0100 Subject: media: i2c: add OV02A10 image sensor driver Add a V4L2 sub-device driver for OmniVision OV02A10 image sensor. Signed-off-by: Dongchun Zhu Reviewed-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 1 + drivers/media/i2c/Kconfig | 13 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/ov02a10.c | 1013 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1028 insertions(+) create mode 100644 drivers/media/i2c/ov02a10.c diff --git a/MAINTAINERS b/MAINTAINERS index b3ee9d9cc976..02437abc94c9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12862,6 +12862,7 @@ L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/ovti,ov02a10.yaml +F: drivers/media/i2c/ov02a10.c OMNIVISION OV13858 SENSOR DRIVER M: Sakari Ailus diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 3787c22767d9..92ff66c34f93 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -825,6 +825,19 @@ config VIDEO_IMX355 To compile this driver as a module, choose M here: the module will be called imx355. +config VIDEO_OV02A10 + tristate "OmniVision OV02A10 sensor support" + depends on VIDEO_V4L2 && I2C + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + select V4L2_FWNODE + help + This is a Video4Linux2 sensor driver for the OmniVision + OV02A10 camera. + + To compile this driver as a module, choose M here: the + module will be called ov02a10. + config VIDEO_OV2640 tristate "OmniVision OV2640 sensor support" depends on VIDEO_V4L2 && I2C diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 5c733394171d..bf9fd1bb6bc9 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -64,6 +64,7 @@ obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o obj-$(CONFIG_VIDEO_SONY_BTF_MPX) += sony-btf-mpx.o obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o +obj-$(CONFIG_VIDEO_OV02A10) += ov02a10.o obj-$(CONFIG_VIDEO_OV2640) += ov2640.o obj-$(CONFIG_VIDEO_OV2680) += ov2680.o obj-$(CONFIG_VIDEO_OV2685) += ov2685.o diff --git a/drivers/media/i2c/ov02a10.c b/drivers/media/i2c/ov02a10.c new file mode 100644 index 000000000000..391718136ade --- /dev/null +++ b/drivers/media/i2c/ov02a10.c @@ -0,0 +1,1013 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2020 MediaTek Inc. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OV02A10_ID 0x2509 +#define OV02A10_ID_MASK GENMASK(15, 0) + +#define OV02A10_REG_CHIP_ID 0x02 + +/* Bit[1] vertical upside down */ +/* Bit[0] horizontal mirror */ +#define REG_MIRROR_FLIP_CONTROL 0x3f + +/* Orientation */ +#define REG_MIRROR_FLIP_ENABLE 0x03 + +/* Bit[2:0] MIPI transmission speed select */ +#define TX_SPEED_AREA_SEL 0xa1 +#define OV02A10_MIPI_TX_SPEED_DEFAULT 0x04 + +#define REG_PAGE_SWITCH 0xfd +#define REG_GLOBAL_EFFECTIVE 0x01 +#define REG_ENABLE BIT(0) + +#define REG_SC_CTRL_MODE 0xac +#define SC_CTRL_MODE_STANDBY 0x00 +#define SC_CTRL_MODE_STREAMING 0x01 + +/* Exposure control */ +#define OV02A10_EXP_SHIFT 8 +#define OV02A10_REG_EXPOSURE_H 0x03 +#define OV02A10_REG_EXPOSURE_L 0x04 +#define OV02A10_EXPOSURE_MIN 4 +#define OV02A10_EXPOSURE_MAX_MARGIN 4 +#define OV02A10_EXPOSURE_STEP 1 + +/* Vblanking control */ +#define OV02A10_VTS_SHIFT 8 +#define OV02A10_REG_VTS_H 0x05 +#define OV02A10_REG_VTS_L 0x06 +#define OV02A10_VTS_MAX 0x209f +#define OV02A10_BASE_LINES 1224 + +/* Analog gain control */ +#define OV02A10_REG_GAIN 0x24 +#define OV02A10_GAIN_MIN 0x10 +#define OV02A10_GAIN_MAX 0xf8 +#define OV02A10_GAIN_STEP 0x01 +#define OV02A10_GAIN_DEFAULT 0x40 + +/* Test pattern control */ +#define OV02A10_REG_TEST_PATTERN 0xb6 + +#define HZ_PER_MHZ 1000000L +#define OV02A10_LINK_FREQ_390MHZ (390 * HZ_PER_MHZ) +#define OV02A10_ECLK_FREQ (24 * HZ_PER_MHZ) + +/* Number of lanes supported by this driver */ +#define OV02A10_DATA_LANES 1 + +/* Bits per sample of sensor output */ +#define OV02A10_BITS_PER_SAMPLE 10 + +static const char * const ov02a10_supply_names[] = { + "dovdd", /* Digital I/O power */ + "avdd", /* Analog power */ + "dvdd", /* Digital core power */ +}; + +struct ov02a10_reg { + u8 addr; + u8 val; +}; + +struct ov02a10_reg_list { + u32 num_of_regs; + const struct ov02a10_reg *regs; +}; + +struct ov02a10_mode { + u32 width; + u32 height; + u32 exp_def; + u32 hts_def; + u32 vts_def; + const struct ov02a10_reg_list reg_list; +}; + +struct ov02a10 { + u32 eclk_freq; + /* Indication of MIPI transmission speed select */ + u32 mipi_clock_voltage; + + struct clk *eclk; + struct gpio_desc *pd_gpio; + struct gpio_desc *rst_gpio; + struct regulator_bulk_data supplies[ARRAY_SIZE(ov02a10_supply_names)]; + + bool streaming; + bool upside_down; + + /* + * Serialize control access, get/set format, get selection + * and start streaming. + */ + struct mutex mutex; + struct v4l2_subdev subdev; + struct media_pad pad; + struct v4l2_mbus_framefmt fmt; + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl *exposure; + + const struct ov02a10_mode *cur_mode; +}; + +static inline struct ov02a10 *to_ov02a10(struct v4l2_subdev *sd) +{ + return container_of(sd, struct ov02a10, subdev); +} + +/* + * eclk 24Mhz + * pclk 39Mhz + * linelength 934(0x3a6) + * framelength 1390(0x56E) + * grabwindow_width 1600 + * grabwindow_height 1200 + * max_framerate 30fps + * mipi_datarate per lane 780Mbps + */ +static const struct ov02a10_reg ov02a10_1600x1200_regs[] = { + {0xfd, 0x01}, + {0xac, 0x00}, + {0xfd, 0x00}, + {0x2f, 0x29}, + {0x34, 0x00}, + {0x35, 0x21}, + {0x30, 0x15}, + {0x33, 0x01}, + {0xfd, 0x01}, + {0x44, 0x00}, + {0x2a, 0x4c}, + {0x2b, 0x1e}, + {0x2c, 0x60}, + {0x25, 0x11}, + {0x03, 0x01}, + {0x04, 0xae}, + {0x09, 0x00}, + {0x0a, 0x02}, + {0x06, 0xa6}, + {0x31, 0x00}, + {0x24, 0x40}, + {0x01, 0x01}, + {0xfb, 0x73}, + {0xfd, 0x01}, + {0x16, 0x04}, + {0x1c, 0x09}, + {0x21, 0x42}, + {0x12, 0x04}, + {0x13, 0x10}, + {0x11, 0x40}, + {0x33, 0x81}, + {0xd0, 0x00}, + {0xd1, 0x01}, + {0xd2, 0x00}, + {0x50, 0x10}, + {0x51, 0x23}, + {0x52, 0x20}, + {0x53, 0x10}, + {0x54, 0x02}, + {0x55, 0x20}, + {0x56, 0x02}, + {0x58, 0x48}, + {0x5d, 0x15}, + {0x5e, 0x05}, + {0x66, 0x66}, + {0x68, 0x68}, + {0x6b, 0x00}, + {0x6c, 0x00}, + {0x6f, 0x40}, + {0x70, 0x40}, + {0x71, 0x0a}, + {0x72, 0xf0}, + {0x73, 0x10}, + {0x75, 0x80}, + {0x76, 0x10}, + {0x84, 0x00}, + {0x85, 0x10}, + {0x86, 0x10}, + {0x87, 0x00}, + {0x8a, 0x22}, + {0x8b, 0x22}, + {0x19, 0xf1}, + {0x29, 0x01}, + {0xfd, 0x01}, + {0x9d, 0x16}, + {0xa0, 0x29}, + {0xa1, 0x04}, + {0xad, 0x62}, + {0xae, 0x00}, + {0xaf, 0x85}, + {0xb1, 0x01}, + {0x8e, 0x06}, + {0x8f, 0x40}, + {0x90, 0x04}, + {0x91, 0xb0}, + {0x45, 0x01}, + {0x46, 0x00}, + {0x47, 0x6c}, + {0x48, 0x03}, + {0x49, 0x8b}, + {0x4a, 0x00}, + {0x4b, 0x07}, + {0x4c, 0x04}, + {0x4d, 0xb7}, + {0xf0, 0x40}, + {0xf1, 0x40}, + {0xf2, 0x40}, + {0xf3, 0x40}, + {0x3f, 0x00}, + {0xfd, 0x01}, + {0x05, 0x00}, + {0x06, 0xa6}, + {0xfd, 0x01}, +}; + +static const char * const ov02a10_test_pattern_menu[] = { + "Disabled", + "Eight Vertical Colour Bars", +}; + +static const s64 link_freq_menu_items[] = { + OV02A10_LINK_FREQ_390MHZ, +}; + +static u64 to_pixel_rate(u32 f_index) +{ + u64 pixel_rate = link_freq_menu_items[f_index] * 2 * OV02A10_DATA_LANES; + + do_div(pixel_rate, OV02A10_BITS_PER_SAMPLE); + + return pixel_rate; +} + +static const struct ov02a10_mode supported_modes[] = { + { + .width = 1600, + .height = 1200, + .exp_def = 0x01ae, + .hts_def = 0x03a6, + .vts_def = 0x056e, + .reg_list = { + .num_of_regs = ARRAY_SIZE(ov02a10_1600x1200_regs), + .regs = ov02a10_1600x1200_regs, + }, + }, +}; + +static int ov02a10_write_array(struct ov02a10 *ov02a10, + const struct ov02a10_reg_list *r_list) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); + unsigned int i; + int ret; + + for (i = 0; i < r_list->num_of_regs; i++) { + ret = i2c_smbus_write_byte_data(client, r_list->regs[i].addr, + r_list->regs[i].val); + if (ret < 0) + return ret; + } + + return 0; +} + +static void ov02a10_fill_fmt(const struct ov02a10_mode *mode, + struct v4l2_mbus_framefmt *fmt) +{ + fmt->width = mode->width; + fmt->height = mode->height; + fmt->field = V4L2_FIELD_NONE; +} + +static int ov02a10_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ov02a10 *ov02a10 = to_ov02a10(sd); + struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format; + struct v4l2_mbus_framefmt *frame_fmt; + int ret = 0; + + mutex_lock(&ov02a10->mutex); + + if (ov02a10->streaming && fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + ret = -EBUSY; + goto out_unlock; + } + + /* Only one sensor mode supported */ + mbus_fmt->code = ov02a10->fmt.code; + ov02a10_fill_fmt(ov02a10->cur_mode, mbus_fmt); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) + frame_fmt = v4l2_subdev_get_try_format(sd, cfg, 0); + else + frame_fmt = &ov02a10->fmt; + + *frame_fmt = *mbus_fmt; + +out_unlock: + mutex_unlock(&ov02a10->mutex); + return ret; +} + +static int ov02a10_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ov02a10 *ov02a10 = to_ov02a10(sd); + struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format; + + mutex_lock(&ov02a10->mutex); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad); + } else { + fmt->format = ov02a10->fmt; + mbus_fmt->code = ov02a10->fmt.code; + ov02a10_fill_fmt(ov02a10->cur_mode, mbus_fmt); + } + + mutex_unlock(&ov02a10->mutex); + + return 0; +} + +static int ov02a10_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct ov02a10 *ov02a10 = to_ov02a10(sd); + + if (code->index != 0) + return -EINVAL; + + code->code = ov02a10->fmt.code; + + return 0; +} + +static int ov02a10_enum_frame_sizes(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + + fse->min_width = supported_modes[fse->index].width; + fse->max_width = supported_modes[fse->index].width; + fse->max_height = supported_modes[fse->index].height; + fse->min_height = supported_modes[fse->index].height; + + return 0; +} + +static int ov02a10_check_sensor_id(struct ov02a10 *ov02a10) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); + u16 chip_id; + int ret; + + /* Validate the chip ID */ + ret = i2c_smbus_read_word_swapped(client, OV02A10_REG_CHIP_ID); + if (ret < 0) + return ret; + + chip_id = le16_to_cpu(ret); + + if ((chip_id & OV02A10_ID_MASK) != OV02A10_ID) { + dev_err(&client->dev, "unexpected sensor id(0x%04x)\n", chip_id); + return -EINVAL; + } + + return 0; +} + +static int ov02a10_power_on(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov02a10 *ov02a10 = to_ov02a10(sd); + int ret; + + gpiod_set_value_cansleep(ov02a10->rst_gpio, 1); + gpiod_set_value_cansleep(ov02a10->pd_gpio, 1); + + ret = clk_prepare_enable(ov02a10->eclk); + if (ret < 0) { + dev_err(dev, "failed to enable eclk\n"); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(ov02a10_supply_names), + ov02a10->supplies); + if (ret < 0) { + dev_err(dev, "failed to enable regulators\n"); + goto disable_clk; + } + usleep_range(5000, 6000); + + gpiod_set_value_cansleep(ov02a10->pd_gpio, 0); + usleep_range(5000, 6000); + + gpiod_set_value_cansleep(ov02a10->rst_gpio, 0); + usleep_range(5000, 6000); + + ret = ov02a10_check_sensor_id(ov02a10); + if (ret) + goto disable_regulator; + + return 0; + +disable_regulator: + regulator_bulk_disable(ARRAY_SIZE(ov02a10_supply_names), + ov02a10->supplies); +disable_clk: + clk_disable_unprepare(ov02a10->eclk); + + return ret; +} + +static int ov02a10_power_off(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov02a10 *ov02a10 = to_ov02a10(sd); + + gpiod_set_value_cansleep(ov02a10->rst_gpio, 1); + clk_disable_unprepare(ov02a10->eclk); + gpiod_set_value_cansleep(ov02a10->pd_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(ov02a10_supply_names), + ov02a10->supplies); + + return 0; +} + +static int __ov02a10_start_stream(struct ov02a10 *ov02a10) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); + const struct ov02a10_reg_list *reg_list; + int ret; + + /* Apply default values of current mode */ + reg_list = &ov02a10->cur_mode->reg_list; + ret = ov02a10_write_array(ov02a10, reg_list); + if (ret) + return ret; + + /* Apply customized values from user */ + ret = __v4l2_ctrl_handler_setup(ov02a10->subdev.ctrl_handler); + if (ret) + return ret; + + /* Set orientation to 180 degree */ + if (ov02a10->upside_down) { + ret = i2c_smbus_write_byte_data(client, REG_MIRROR_FLIP_CONTROL, + REG_MIRROR_FLIP_ENABLE); + if (ret < 0) { + dev_err(&client->dev, "failed to set orientation\n"); + return ret; + } + ret = i2c_smbus_write_byte_data(client, REG_GLOBAL_EFFECTIVE, + REG_ENABLE); + if (ret < 0) + return ret; + } + + /* Set MIPI TX speed according to DT property */ + if (ov02a10->mipi_clock_voltage != OV02A10_MIPI_TX_SPEED_DEFAULT) { + ret = i2c_smbus_write_byte_data(client, TX_SPEED_AREA_SEL, + ov02a10->mipi_clock_voltage); + if (ret < 0) + return ret; + } + + /* Set stream on register */ + return i2c_smbus_write_byte_data(client, REG_SC_CTRL_MODE, + SC_CTRL_MODE_STREAMING); +} + +static int __ov02a10_stop_stream(struct ov02a10 *ov02a10) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); + + return i2c_smbus_write_byte_data(client, REG_SC_CTRL_MODE, + SC_CTRL_MODE_STANDBY); +} + +static int ov02a10_entity_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg) +{ + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_TRY, + .format = { + .width = 1600, + .height = 1200, + } + }; + + ov02a10_set_fmt(sd, cfg, &fmt); + + return 0; +} + +static int ov02a10_s_stream(struct v4l2_subdev *sd, int on) +{ + struct ov02a10 *ov02a10 = to_ov02a10(sd); + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); + int ret; + + mutex_lock(&ov02a10->mutex); + + if (ov02a10->streaming == on) + goto unlock_and_return; + + if (on) { + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) { + pm_runtime_put_noidle(&client->dev); + goto unlock_and_return; + } + + ret = __ov02a10_start_stream(ov02a10); + if (ret) { + __ov02a10_stop_stream(ov02a10); + ov02a10->streaming = !on; + goto err_rpm_put; + } + } else { + __ov02a10_stop_stream(ov02a10); + pm_runtime_put(&client->dev); + } + + ov02a10->streaming = on; + mutex_unlock(&ov02a10->mutex); + + return 0; + +err_rpm_put: + pm_runtime_put(&client->dev); +unlock_and_return: + mutex_unlock(&ov02a10->mutex); + + return ret; +} + +static const struct dev_pm_ops ov02a10_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(ov02a10_power_off, ov02a10_power_on, NULL) +}; + +static int ov02a10_set_exposure(struct ov02a10 *ov02a10, int val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); + int ret; + + ret = i2c_smbus_write_byte_data(client, REG_PAGE_SWITCH, REG_ENABLE); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(client, OV02A10_REG_EXPOSURE_H, + val >> OV02A10_EXP_SHIFT); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(client, OV02A10_REG_EXPOSURE_L, val); + if (ret < 0) + return ret; + + return i2c_smbus_write_byte_data(client, REG_GLOBAL_EFFECTIVE, + REG_ENABLE); +} + +static int ov02a10_set_gain(struct ov02a10 *ov02a10, int val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); + int ret; + + ret = i2c_smbus_write_byte_data(client, REG_PAGE_SWITCH, REG_ENABLE); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(client, OV02A10_REG_GAIN, val); + if (ret < 0) + return ret; + + return i2c_smbus_write_byte_data(client, REG_GLOBAL_EFFECTIVE, + REG_ENABLE); +} + +static int ov02a10_set_vblank(struct ov02a10 *ov02a10, int val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); + u32 vts = val + ov02a10->cur_mode->height - OV02A10_BASE_LINES; + int ret; + + ret = i2c_smbus_write_byte_data(client, REG_PAGE_SWITCH, REG_ENABLE); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(client, OV02A10_REG_VTS_H, + vts >> OV02A10_VTS_SHIFT); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(client, OV02A10_REG_VTS_L, vts); + if (ret < 0) + return ret; + + return i2c_smbus_write_byte_data(client, REG_GLOBAL_EFFECTIVE, + REG_ENABLE); +} + +static int ov02a10_set_test_pattern(struct ov02a10 *ov02a10, int pattern) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); + int ret; + + ret = i2c_smbus_write_byte_data(client, REG_PAGE_SWITCH, REG_ENABLE); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(client, OV02A10_REG_TEST_PATTERN, + pattern); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(client, REG_GLOBAL_EFFECTIVE, + REG_ENABLE); + if (ret < 0) + return ret; + + return i2c_smbus_write_byte_data(client, REG_SC_CTRL_MODE, + SC_CTRL_MODE_STREAMING); +} + +static int ov02a10_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov02a10 *ov02a10 = container_of(ctrl->handler, + struct ov02a10, ctrl_handler); + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); + s64 max_expo; + int ret; + + /* Propagate change of current control to all related controls */ + if (ctrl->id == V4L2_CID_VBLANK) { + /* Update max exposure while meeting expected vblanking */ + max_expo = ov02a10->cur_mode->height + ctrl->val - + OV02A10_EXPOSURE_MAX_MARGIN; + __v4l2_ctrl_modify_range(ov02a10->exposure, + ov02a10->exposure->minimum, max_expo, + ov02a10->exposure->step, + ov02a10->exposure->default_value); + } + + /* V4L2 controls values will be applied only when power is already up */ + if (!pm_runtime_get_if_in_use(&client->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + ret = ov02a10_set_exposure(ov02a10, ctrl->val); + break; + case V4L2_CID_ANALOGUE_GAIN: + ret = ov02a10_set_gain(ov02a10, ctrl->val); + break; + case V4L2_CID_VBLANK: + ret = ov02a10_set_vblank(ov02a10, ctrl->val); + break; + case V4L2_CID_TEST_PATTERN: + ret = ov02a10_set_test_pattern(ov02a10, ctrl->val); + break; + default: + ret = -EINVAL; + break; + }; + + pm_runtime_put(&client->dev); + + return ret; +} + +static const struct v4l2_subdev_video_ops ov02a10_video_ops = { + .s_stream = ov02a10_s_stream, +}; + +static const struct v4l2_subdev_pad_ops ov02a10_pad_ops = { + .init_cfg = ov02a10_entity_init_cfg, + .enum_mbus_code = ov02a10_enum_mbus_code, + .enum_frame_size = ov02a10_enum_frame_sizes, + .get_fmt = ov02a10_get_fmt, + .set_fmt = ov02a10_set_fmt, +}; + +static const struct v4l2_subdev_ops ov02a10_subdev_ops = { + .video = &ov02a10_video_ops, + .pad = &ov02a10_pad_ops, +}; + +static const struct media_entity_operations ov02a10_subdev_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static const struct v4l2_ctrl_ops ov02a10_ctrl_ops = { + .s_ctrl = ov02a10_set_ctrl, +}; + +static int ov02a10_initialize_controls(struct ov02a10 *ov02a10) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); + const struct ov02a10_mode *mode; + struct v4l2_ctrl_handler *handler; + struct v4l2_ctrl *ctrl; + s64 exposure_max; + s64 vblank_def; + s64 pixel_rate; + s64 h_blank; + int ret; + + handler = &ov02a10->ctrl_handler; + mode = ov02a10->cur_mode; + ret = v4l2_ctrl_handler_init(handler, 7); + if (ret) + return ret; + + handler->lock = &ov02a10->mutex; + + ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ, 0, 0, + link_freq_menu_items); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + pixel_rate = to_pixel_rate(0); + v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, 0, pixel_rate, 1, + pixel_rate); + + h_blank = mode->hts_def - mode->width; + v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK, h_blank, h_blank, 1, + h_blank); + + vblank_def = mode->vts_def - mode->height; + v4l2_ctrl_new_std(handler, &ov02a10_ctrl_ops, V4L2_CID_VBLANK, + vblank_def, OV02A10_VTS_MAX - mode->height, 1, + vblank_def); + + exposure_max = mode->vts_def - 4; + ov02a10->exposure = v4l2_ctrl_new_std(handler, &ov02a10_ctrl_ops, + V4L2_CID_EXPOSURE, + OV02A10_EXPOSURE_MIN, + exposure_max, + OV02A10_EXPOSURE_STEP, + mode->exp_def); + + v4l2_ctrl_new_std(handler, &ov02a10_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, OV02A10_GAIN_MIN, + OV02A10_GAIN_MAX, OV02A10_GAIN_STEP, + OV02A10_GAIN_DEFAULT); + + v4l2_ctrl_new_std_menu_items(handler, &ov02a10_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov02a10_test_pattern_menu) - 1, + 0, 0, ov02a10_test_pattern_menu); + + if (handler->error) { + ret = handler->error; + dev_err(&client->dev, "failed to init controls(%d)\n", ret); + goto err_free_handler; + } + + ov02a10->subdev.ctrl_handler = handler; + + return 0; + +err_free_handler: + v4l2_ctrl_handler_free(handler); + + return ret; +} + +static int ov02a10_check_hwcfg(struct device *dev, struct ov02a10 *ov02a10) +{ + struct fwnode_handle *ep; + struct fwnode_handle *fwnode = dev_fwnode(dev); + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY, + }; + unsigned int i, j; + u32 clk_volt; + int ret; + + if (!fwnode) + return -EINVAL; + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) + return -ENXIO; + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + fwnode_handle_put(ep); + if (ret) + return ret; + + /* Optional indication of MIPI clock voltage unit */ + ret = fwnode_property_read_u32(ep, "ovti,mipi-clock-voltage", + &clk_volt); + + if (!ret) + ov02a10->mipi_clock_voltage = clk_volt; + + for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) { + for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) { + if (link_freq_menu_items[i] == + bus_cfg.link_frequencies[j]) + break; + } + + if (j == bus_cfg.nr_of_link_frequencies) { + dev_err(dev, "no link frequency %lld supported\n", + link_freq_menu_items[i]); + ret = -EINVAL; + break; + } + } + + v4l2_fwnode_endpoint_free(&bus_cfg); + + return ret; +} + +static int ov02a10_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct ov02a10 *ov02a10; + unsigned int i; + unsigned int rotation; + int ret; + + ov02a10 = devm_kzalloc(dev, sizeof(*ov02a10), GFP_KERNEL); + if (!ov02a10) + return -ENOMEM; + + ret = ov02a10_check_hwcfg(dev, ov02a10); + if (ret) + return dev_err_probe(dev, ret, + "failed to check HW configuration\n"); + + v4l2_i2c_subdev_init(&ov02a10->subdev, client, &ov02a10_subdev_ops); + + ov02a10->mipi_clock_voltage = OV02A10_MIPI_TX_SPEED_DEFAULT; + ov02a10->fmt.code = MEDIA_BUS_FMT_SBGGR10_1X10; + + /* Optional indication of physical rotation of sensor */ + rotation = 0; + device_property_read_u32(dev, "rotation", &rotation); + if (rotation == 180) { + ov02a10->upside_down = true; + ov02a10->fmt.code = MEDIA_BUS_FMT_SRGGB10_1X10; + } + + ov02a10->eclk = devm_clk_get(dev, "eclk"); + if (IS_ERR(ov02a10->eclk)) + return dev_err_probe(dev, PTR_ERR(ov02a10->eclk), + "failed to get eclk\n"); + + ret = device_property_read_u32(dev, "clock-frequency", + &ov02a10->eclk_freq); + if (ret < 0) + return dev_err_probe(dev, ret, + "failed to get eclk frequency\n"); + + ret = clk_set_rate(ov02a10->eclk, ov02a10->eclk_freq); + if (ret < 0) + return dev_err_probe(dev, ret, + "failed to set eclk frequency (24MHz)\n"); + + if (clk_get_rate(ov02a10->eclk) != OV02A10_ECLK_FREQ) + dev_warn(dev, "eclk mismatched, mode is based on 24MHz\n"); + + ov02a10->pd_gpio = devm_gpiod_get(dev, "powerdown", GPIOD_OUT_HIGH); + if (IS_ERR(ov02a10->pd_gpio)) + return dev_err_probe(dev, PTR_ERR(ov02a10->pd_gpio), + "failed to get powerdown-gpios\n"); + + ov02a10->rst_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ov02a10->rst_gpio)) + return dev_err_probe(dev, PTR_ERR(ov02a10->rst_gpio), + "failed to get reset-gpios\n"); + + for (i = 0; i < ARRAY_SIZE(ov02a10_supply_names); i++) + ov02a10->supplies[i].supply = ov02a10_supply_names[i]; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ov02a10_supply_names), + ov02a10->supplies); + if (ret) + return dev_err_probe(dev, ret, "failed to get regulators\n"); + + mutex_init(&ov02a10->mutex); + + /* Set default mode */ + ov02a10->cur_mode = &supported_modes[0]; + + ret = ov02a10_initialize_controls(ov02a10); + if (ret) { + dev_err_probe(dev, ret, "failed to initialize controls\n"); + goto err_destroy_mutex; + } + + /* Initialize subdev */ + ov02a10->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + ov02a10->subdev.entity.ops = &ov02a10_subdev_entity_ops; + ov02a10->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ov02a10->pad.flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&ov02a10->subdev.entity, 1, &ov02a10->pad); + if (ret < 0) { + dev_err_probe(dev, ret, "failed to initialize entity pads\n"); + goto err_free_handler; + } + + pm_runtime_enable(dev); + if (!pm_runtime_enabled(dev)) { + ret = ov02a10_power_on(dev); + if (ret < 0) { + dev_err_probe(dev, ret, "failed to power on\n"); + goto err_clean_entity; + } + } + + ret = v4l2_async_register_subdev(&ov02a10->subdev); + if (ret) { + dev_err_probe(dev, ret, "failed to register V4L2 subdev\n"); + goto err_power_off; + } + + return 0; + +err_power_off: + if (pm_runtime_enabled(dev)) + pm_runtime_disable(dev); + else + ov02a10_power_off(dev); +err_clean_entity: + media_entity_cleanup(&ov02a10->subdev.entity); +err_free_handler: + v4l2_ctrl_handler_free(ov02a10->subdev.ctrl_handler); +err_destroy_mutex: + mutex_destroy(&ov02a10->mutex); + + return ret; +} + +static int ov02a10_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov02a10 *ov02a10 = to_ov02a10(sd); + + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + ov02a10_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); + mutex_destroy(&ov02a10->mutex); + + return 0; +} + +static const struct of_device_id ov02a10_of_match[] = { + { .compatible = "ovti,ov02a10" }, + {} +}; +MODULE_DEVICE_TABLE(of, ov02a10_of_match); + +static struct i2c_driver ov02a10_i2c_driver = { + .driver = { + .name = "ov02a10", + .pm = &ov02a10_pm_ops, + .of_match_table = ov02a10_of_match, + }, + .probe_new = &ov02a10_probe, + .remove = &ov02a10_remove, +}; +module_i2c_driver(ov02a10_i2c_driver); + +MODULE_AUTHOR("Dongchun Zhu "); +MODULE_DESCRIPTION("OmniVision OV02A10 sensor driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From cf10e09b9a4b28fe6df3fe8fc851fb2c4bd18a14 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 26 Nov 2020 12:49:32 +0100 Subject: media: ov2740: fix dereference before null check on pointer nvm Currently pointer nvm is being dereferenced before it is being null checked. Fix this by moving the assignments of pointers client and ov2740 so that are after the null check hence avoiding any potential null pointer dereferences on pointer nvm. Fixes: 5e6fd339b68d ("media: ov2740: allow OTP data access during streaming") Signed-off-by: Colin Ian King Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov2740.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c index 99016546cbec..b41a90c2aed5 100644 --- a/drivers/media/i2c/ov2740.c +++ b/drivers/media/i2c/ov2740.c @@ -600,8 +600,8 @@ static void ov2740_update_pad_format(const struct ov2740_mode *mode, static int ov2740_load_otp_data(struct nvm_data *nvm) { - struct i2c_client *client = nvm->client; - struct ov2740 *ov2740 = to_ov2740(i2c_get_clientdata(client)); + struct i2c_client *client; + struct ov2740 *ov2740; u32 isp_ctrl00 = 0; u32 isp_ctrl01 = 0; int ret; @@ -612,6 +612,9 @@ static int ov2740_load_otp_data(struct nvm_data *nvm) if (nvm->nvm_buffer) return 0; + client = nvm->client; + ov2740 = to_ov2740(i2c_get_clientdata(client)); + nvm->nvm_buffer = kzalloc(CUSTOMER_USE_OTP_SIZE, GFP_KERNEL); if (!nvm->nvm_buffer) return -ENOMEM; -- cgit v1.2.3 From d7592b2ec9441f44dd055623288fa5a258b5a07f Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Wed, 25 Nov 2020 17:44:46 +0100 Subject: media: rcar-vin: Only dynamically allocate v4l2_async_subdev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation of removing the usage of the old helper v4l2_async_notifier_parse_fwnode_endpoints_by_port() do not dynamically allocate the whole structure containing the parameters for the parallel interface, instead only allocate the v4l2_async_subdev structure. There is no functional change. Signed-off-by: Niklas Söderlund Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-core.c | 45 ++++++++++++++--------------- drivers/media/platform/rcar-vin/rcar-dma.c | 16 +++++----- drivers/media/platform/rcar-vin/rcar-v4l2.c | 12 ++++---- drivers/media/platform/rcar-vin/rcar-vin.h | 6 ++-- 4 files changed, 39 insertions(+), 40 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 518813456194..07f250bfc005 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -185,8 +185,8 @@ static int rvin_group_link_notify(struct media_link *link, u32 flags, */ sd = media_entity_to_v4l2_subdev(link->source->entity); for (i = 0; i < RCAR_VIN_NUM; i++) { - if (group->vin[i] && group->vin[i]->parallel && - group->vin[i]->parallel->subdev == sd) { + if (group->vin[i] && + group->vin[i]->parallel.subdev == sd) { group->vin[i]->is_csi = false; ret = 0; goto out; @@ -440,20 +440,20 @@ static int rvin_parallel_subdevice_attach(struct rvin_dev *vin, ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SOURCE); if (ret < 0) return ret; - vin->parallel->source_pad = ret; + vin->parallel.source_pad = ret; ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SINK); - vin->parallel->sink_pad = ret < 0 ? 0 : ret; + vin->parallel.sink_pad = ret < 0 ? 0 : ret; if (vin->info->use_mc) { - vin->parallel->subdev = subdev; + vin->parallel.subdev = subdev; return 0; } /* Find compatible subdevices mbus format */ vin->mbus_code = 0; code.index = 0; - code.pad = vin->parallel->source_pad; + code.pad = vin->parallel.source_pad; while (!vin->mbus_code && !v4l2_subdev_call(subdev, pad, enum_mbus_code, NULL, &code)) { code.index++; @@ -512,7 +512,7 @@ static int rvin_parallel_subdevice_attach(struct rvin_dev *vin, vin->vdev.ctrl_handler = &vin->ctrl_handler; - vin->parallel->subdev = subdev; + vin->parallel.subdev = subdev; return 0; } @@ -520,7 +520,7 @@ static int rvin_parallel_subdevice_attach(struct rvin_dev *vin, static void rvin_parallel_subdevice_detach(struct rvin_dev *vin) { rvin_v4l2_unregister(vin); - vin->parallel->subdev = NULL; + vin->parallel.subdev = NULL; if (!vin->info->use_mc) { v4l2_ctrl_handler_free(&vin->ctrl_handler); @@ -551,11 +551,11 @@ static int rvin_parallel_notify_complete(struct v4l2_async_notifier *notifier) return 0; /* If we're running with media-controller, link the subdevs. */ - source = &vin->parallel->subdev->entity; + source = &vin->parallel.subdev->entity; sink = &vin->vdev.entity; - ret = media_create_pad_link(source, vin->parallel->source_pad, - sink, vin->parallel->sink_pad, 0); + ret = media_create_pad_link(source, vin->parallel.source_pad, + sink, vin->parallel.sink_pad, 0); if (ret) vin_err(vin, "Error adding link from %s to %s: %d\n", source->name, sink->name, ret); @@ -592,8 +592,8 @@ static int rvin_parallel_notify_bound(struct v4l2_async_notifier *notifier, v4l2_set_subdev_hostdata(subdev, vin); vin_dbg(vin, "bound subdev %s source pad: %u sink pad: %u\n", - subdev->name, vin->parallel->source_pad, - vin->parallel->sink_pad); + subdev->name, vin->parallel.source_pad, + vin->parallel.sink_pad); return 0; } @@ -609,28 +609,27 @@ static int rvin_parallel_parse_v4l2(struct device *dev, struct v4l2_async_subdev *asd) { struct rvin_dev *vin = dev_get_drvdata(dev); - struct rvin_parallel_entity *rvpe = - container_of(asd, struct rvin_parallel_entity, asd); if (vep->base.port || vep->base.id) return -ENOTCONN; - vin->parallel = rvpe; - vin->parallel->mbus_type = vep->bus_type; + vin->parallel.mbus_type = vep->bus_type; - switch (vin->parallel->mbus_type) { + switch (vin->parallel.mbus_type) { case V4L2_MBUS_PARALLEL: case V4L2_MBUS_BT656: vin_dbg(vin, "Found %s media bus\n", - vin->parallel->mbus_type == V4L2_MBUS_PARALLEL ? + vin->parallel.mbus_type == V4L2_MBUS_PARALLEL ? "PARALLEL" : "BT656"); - vin->parallel->bus = vep->bus.parallel; + vin->parallel.bus = vep->bus.parallel; break; default: vin_err(vin, "Unknown media bus type\n"); return -EINVAL; } + vin->parallel.asd = asd; + return 0; } @@ -641,17 +640,17 @@ static int rvin_parallel_init(struct rvin_dev *vin) v4l2_async_notifier_init(&vin->notifier); ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port( - vin->dev, &vin->notifier, sizeof(struct rvin_parallel_entity), + vin->dev, &vin->notifier, sizeof(*vin->parallel.asd), 0, rvin_parallel_parse_v4l2); if (ret) return ret; /* If using mc, it's fine not to have any input registered. */ - if (!vin->parallel) + if (!vin->parallel.asd) return vin->info->use_mc ? 0 : -ENODEV; vin_dbg(vin, "Found parallel subdevice %pOF\n", - to_of_node(vin->parallel->asd.match.fwnode)); + to_of_node(vin->parallel.asd->match.fwnode)); vin->notifier.ops = &rvin_parallel_notify_ops; ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier); diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c index 5a5f0e500747..95b7828ee352 100644 --- a/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/rcar-vin/rcar-dma.c @@ -672,7 +672,7 @@ static int rvin_setup(struct rvin_dev *vin) case MEDIA_BUS_FMT_UYVY8_2X8: /* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */ if (!vin->is_csi && - vin->parallel->mbus_type == V4L2_MBUS_BT656) + vin->parallel.mbus_type == V4L2_MBUS_BT656) vnmc |= VNMC_INF_YUV8_BT656; else vnmc |= VNMC_INF_YUV8_BT601; @@ -685,7 +685,7 @@ static int rvin_setup(struct rvin_dev *vin) case MEDIA_BUS_FMT_UYVY10_2X10: /* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */ if (!vin->is_csi && - vin->parallel->mbus_type == V4L2_MBUS_BT656) + vin->parallel.mbus_type == V4L2_MBUS_BT656) vnmc |= VNMC_INF_YUV10_BT656; else vnmc |= VNMC_INF_YUV10_BT601; @@ -710,21 +710,21 @@ static int rvin_setup(struct rvin_dev *vin) if (!vin->is_csi) { /* Hsync Signal Polarity Select */ - if (!(vin->parallel->bus.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) + if (!(vin->parallel.bus.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) dmr2 |= VNDMR2_HPS; /* Vsync Signal Polarity Select */ - if (!(vin->parallel->bus.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) + if (!(vin->parallel.bus.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) dmr2 |= VNDMR2_VPS; /* Data Enable Polarity Select */ - if (vin->parallel->bus.flags & V4L2_MBUS_DATA_ENABLE_LOW) + if (vin->parallel.bus.flags & V4L2_MBUS_DATA_ENABLE_LOW) dmr2 |= VNDMR2_CES; switch (vin->mbus_code) { case MEDIA_BUS_FMT_UYVY8_2X8: - if (vin->parallel->bus.bus_width == 8 && - vin->parallel->bus.data_shift == 8) + if (vin->parallel.bus.bus_width == 8 && + vin->parallel.bus.data_shift == 8) dmr2 |= VNDMR2_YDS; break; default: @@ -1203,7 +1203,7 @@ static int rvin_set_stream(struct rvin_dev *vin, int on) /* No media controller used, simply pass operation to subdevice. */ if (!vin->info->use_mc) { - ret = v4l2_subdev_call(vin->parallel->subdev, video, s_stream, + ret = v4l2_subdev_call(vin->parallel.subdev, video, s_stream, on); return ret == -ENOIOCTLCMD ? 0 : ret; diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c index 3e7a3ae2a6b9..e6ea2b7991b8 100644 --- a/drivers/media/platform/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c @@ -205,7 +205,7 @@ static int rvin_reset_format(struct rvin_dev *vin) { struct v4l2_subdev_format fmt = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, - .pad = vin->parallel->source_pad, + .pad = vin->parallel.source_pad, }; int ret; @@ -246,7 +246,7 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which, struct v4l2_subdev_pad_config *pad_cfg; struct v4l2_subdev_format format = { .which = which, - .pad = vin->parallel->source_pad, + .pad = vin->parallel.source_pad, }; enum v4l2_field field; u32 width, height; @@ -632,7 +632,7 @@ static int rvin_enum_dv_timings(struct file *file, void *priv_fh, if (timings->pad) return -EINVAL; - timings->pad = vin->parallel->sink_pad; + timings->pad = vin->parallel.sink_pad; ret = v4l2_subdev_call(sd, pad, enum_dv_timings, timings); @@ -684,7 +684,7 @@ static int rvin_dv_timings_cap(struct file *file, void *priv_fh, if (cap->pad) return -EINVAL; - cap->pad = vin->parallel->sink_pad; + cap->pad = vin->parallel.sink_pad; ret = v4l2_subdev_call(sd, pad, dv_timings_cap, cap); @@ -702,7 +702,7 @@ static int rvin_g_edid(struct file *file, void *fh, struct v4l2_edid *edid) if (edid->pad) return -EINVAL; - edid->pad = vin->parallel->sink_pad; + edid->pad = vin->parallel.sink_pad; ret = v4l2_subdev_call(sd, pad, get_edid, edid); @@ -720,7 +720,7 @@ static int rvin_s_edid(struct file *file, void *fh, struct v4l2_edid *edid) if (edid->pad) return -EINVAL; - edid->pad = vin->parallel->sink_pad; + edid->pad = vin->parallel.sink_pad; ret = v4l2_subdev_call(sd, pad, set_edid, edid); diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h index 4539bd53d9d4..34e3979acf93 100644 --- a/drivers/media/platform/rcar-vin/rcar-vin.h +++ b/drivers/media/platform/rcar-vin/rcar-vin.h @@ -101,7 +101,7 @@ struct rvin_video_format { * */ struct rvin_parallel_entity { - struct v4l2_async_subdev asd; + struct v4l2_async_subdev *asd; struct v4l2_subdev *subdev; enum v4l2_mbus_type mbus_type; @@ -213,7 +213,7 @@ struct rvin_dev { struct v4l2_ctrl_handler ctrl_handler; struct v4l2_async_notifier notifier; - struct rvin_parallel_entity *parallel; + struct rvin_parallel_entity parallel; struct rvin_group *group; unsigned int id; @@ -248,7 +248,7 @@ struct rvin_dev { unsigned int alpha; }; -#define vin_to_source(vin) ((vin)->parallel->subdev) +#define vin_to_source(vin) ((vin)->parallel.subdev) /* Debug */ #define vin_dbg(d, fmt, arg...) dev_dbg(d->dev, fmt, ##arg) -- cgit v1.2.3 From b9ad52aafe38f8c54f344f30a3698de8e72315c2 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Wed, 25 Nov 2020 17:44:47 +0100 Subject: media: rcar-vin: Rework parallel firmware parsing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rework the parallel firmware parsing code to not use the soon to be removed v4l2_async_notifier_parse_fwnode_endpoints_by_port() helper. The change only aims to prepare for the removing of the old helper and there are no functional change. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-core.c | 50 +++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 07f250bfc005..396ff5531359 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -604,32 +604,56 @@ static const struct v4l2_async_notifier_operations rvin_parallel_notify_ops = { .complete = rvin_parallel_notify_complete, }; -static int rvin_parallel_parse_v4l2(struct device *dev, - struct v4l2_fwnode_endpoint *vep, - struct v4l2_async_subdev *asd) +static int rvin_parallel_parse_of(struct rvin_dev *vin) { - struct rvin_dev *vin = dev_get_drvdata(dev); + struct fwnode_handle *ep, *fwnode; + struct v4l2_fwnode_endpoint vep = { + .bus_type = V4L2_MBUS_UNKNOWN, + }; + struct v4l2_async_subdev *asd; + int ret; - if (vep->base.port || vep->base.id) - return -ENOTCONN; + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(vin->dev), 0, 0, 0); + if (!ep) + return 0; - vin->parallel.mbus_type = vep->bus_type; + fwnode = fwnode_graph_get_remote_endpoint(ep); + ret = v4l2_fwnode_endpoint_parse(ep, &vep); + fwnode_handle_put(ep); + if (ret) { + vin_err(vin, "Failed to parse %pOF\n", to_of_node(fwnode)); + ret = -EINVAL; + goto out; + } - switch (vin->parallel.mbus_type) { + switch (vep.bus_type) { case V4L2_MBUS_PARALLEL: case V4L2_MBUS_BT656: vin_dbg(vin, "Found %s media bus\n", - vin->parallel.mbus_type == V4L2_MBUS_PARALLEL ? + vep.bus_type == V4L2_MBUS_PARALLEL ? "PARALLEL" : "BT656"); - vin->parallel.bus = vep->bus.parallel; + vin->parallel.mbus_type = vep.bus_type; + vin->parallel.bus = vep.bus.parallel; break; default: vin_err(vin, "Unknown media bus type\n"); - return -EINVAL; + ret = -EINVAL; + goto out; + } + + asd = v4l2_async_notifier_add_fwnode_subdev(&vin->notifier, fwnode, + sizeof(*asd)); + if (IS_ERR(asd)) { + ret = PTR_ERR(asd); + goto out; } vin->parallel.asd = asd; + vin_dbg(vin, "Add parallel OF device %pOF\n", to_of_node(fwnode)); +out: + fwnode_handle_put(fwnode); + return 0; } @@ -639,9 +663,7 @@ static int rvin_parallel_init(struct rvin_dev *vin) v4l2_async_notifier_init(&vin->notifier); - ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port( - vin->dev, &vin->notifier, sizeof(*vin->parallel.asd), - 0, rvin_parallel_parse_v4l2); + ret = rvin_parallel_parse_of(vin); if (ret) return ret; -- cgit v1.2.3 From 497d574d9b498aa34b0071e381c23cfc34805f14 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Wed, 25 Nov 2020 17:44:48 +0100 Subject: media: rcar-vin: Use v4l2_async_subdev instead of fwnode_handle to match subdevices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation of removing the usage of the old helper v4l2_async_notifier_parse_fwnode_endpoints_by_port() use the v4l2_async_subdev instead of fwnode_handle to match subdevices. Signed-off-by: Niklas Söderlund Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-core.c | 8 ++++---- drivers/media/platform/rcar-vin/rcar-vin.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 396ff5531359..830ab0865967 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -772,7 +772,7 @@ static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier, mutex_lock(&vin->group->lock); for (i = 0; i < RVIN_CSI_MAX; i++) { - if (vin->group->csi[i].fwnode != asd->match.fwnode) + if (vin->group->csi[i].asd != asd) continue; vin->group->csi[i].subdev = NULL; vin_dbg(vin, "Unbind CSI-2 %s from slot %u\n", subdev->name, i); @@ -794,7 +794,7 @@ static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier, mutex_lock(&vin->group->lock); for (i = 0; i < RVIN_CSI_MAX; i++) { - if (vin->group->csi[i].fwnode != asd->match.fwnode) + if (vin->group->csi[i].asd != asd) continue; vin->group->csi[i].subdev = subdev; vin_dbg(vin, "Bound CSI-2 %s to slot %u\n", subdev->name, i); @@ -830,14 +830,14 @@ static int rvin_mc_parse_of_endpoint(struct device *dev, mutex_lock(&vin->group->lock); - if (vin->group->csi[vep->base.id].fwnode) { + if (vin->group->csi[vep->base.id].asd) { vin_dbg(vin, "OF device %pOF already handled\n", to_of_node(asd->match.fwnode)); ret = -ENOTCONN; goto out; } - vin->group->csi[vep->base.id].fwnode = asd->match.fwnode; + vin->group->csi[vep->base.id].asd = asd; vin_dbg(vin, "Add group OF device %pOF to slot %u\n", to_of_node(asd->match.fwnode), vep->base.id); diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h index 34e3979acf93..0ee9d402f5ac 100644 --- a/drivers/media/platform/rcar-vin/rcar-vin.h +++ b/drivers/media/platform/rcar-vin/rcar-vin.h @@ -280,7 +280,7 @@ struct rvin_group { struct rvin_dev *vin[RCAR_VIN_NUM]; struct { - struct fwnode_handle *fwnode; + struct v4l2_async_subdev *asd; struct v4l2_subdev *subdev; } csi[RVIN_CSI_MAX]; }; -- cgit v1.2.3 From e8117de78b2c5b2035dd25fe25d16403c477370b Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Wed, 25 Nov 2020 17:44:49 +0100 Subject: media: rcar-vin: Rework CSI-2 firmware parsing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rework the CSI-2 firmware parsing code to not use the soon to be removed v4l2_async_notifier_parse_fwnode_endpoints_by_port() helper. The change only aims to prepare for the removing of the old helper and there are no functional change. Signed-off-by: Niklas Söderlund Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-core.c | 65 +++++++++++++++++------------ 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 830ab0865967..98bff765b02e 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -812,37 +812,48 @@ static const struct v4l2_async_notifier_operations rvin_group_notify_ops = { .complete = rvin_group_notify_complete, }; -static int rvin_mc_parse_of_endpoint(struct device *dev, - struct v4l2_fwnode_endpoint *vep, - struct v4l2_async_subdev *asd) +static int rvin_mc_parse_of(struct rvin_dev *vin, unsigned int id) { - struct rvin_dev *vin = dev_get_drvdata(dev); - int ret = 0; + struct fwnode_handle *ep, *fwnode; + struct v4l2_fwnode_endpoint vep = { + .bus_type = V4L2_MBUS_CSI2_DPHY, + }; + struct v4l2_async_subdev *asd; + int ret; - if (vep->base.port != 1 || vep->base.id >= RVIN_CSI_MAX) - return -EINVAL; + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(vin->dev), 1, id, 0); + if (!ep) + return 0; - if (!of_device_is_available(to_of_node(asd->match.fwnode))) { - vin_dbg(vin, "OF device %pOF disabled, ignoring\n", - to_of_node(asd->match.fwnode)); - return -ENOTCONN; + fwnode = fwnode_graph_get_remote_endpoint(ep); + ret = v4l2_fwnode_endpoint_parse(ep, &vep); + fwnode_handle_put(ep); + if (ret) { + vin_err(vin, "Failed to parse %pOF\n", to_of_node(fwnode)); + ret = -EINVAL; + goto out; } - mutex_lock(&vin->group->lock); - - if (vin->group->csi[vep->base.id].asd) { - vin_dbg(vin, "OF device %pOF already handled\n", - to_of_node(asd->match.fwnode)); + if (!of_device_is_available(to_of_node(fwnode))) { + vin_dbg(vin, "OF device %pOF disabled, ignoring\n", + to_of_node(fwnode)); ret = -ENOTCONN; goto out; } - vin->group->csi[vep->base.id].asd = asd; + asd = v4l2_async_notifier_add_fwnode_subdev(&vin->group->notifier, + fwnode, sizeof(*asd)); + if (IS_ERR(asd)) { + ret = PTR_ERR(asd); + goto out; + } + + vin->group->csi[vep.base.id].asd = asd; vin_dbg(vin, "Add group OF device %pOF to slot %u\n", - to_of_node(asd->match.fwnode), vep->base.id); + to_of_node(fwnode), vep.base.id); out: - mutex_unlock(&vin->group->lock); + fwnode_handle_put(fwnode); return ret; } @@ -850,7 +861,7 @@ out: static int rvin_mc_parse_of_graph(struct rvin_dev *vin) { unsigned int count = 0, vin_mask = 0; - unsigned int i; + unsigned int i, id; int ret; mutex_lock(&vin->group->lock); @@ -881,12 +892,14 @@ static int rvin_mc_parse_of_graph(struct rvin_dev *vin) if (!(vin_mask & BIT(i))) continue; - ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port( - vin->group->vin[i]->dev, &vin->group->notifier, - sizeof(struct v4l2_async_subdev), 1, - rvin_mc_parse_of_endpoint); - if (ret) - return ret; + for (id = 0; id < RVIN_CSI_MAX; id++) { + if (vin->group->csi[id].asd) + continue; + + ret = rvin_mc_parse_of(vin->group->vin[i], id); + if (ret) + return ret; + } } if (list_empty(&vin->group->notifier.asd_list)) -- cgit v1.2.3 From 0ae426ebd0dcef811a012b33345e6f7ca56256f4 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Wed, 25 Nov 2020 17:44:50 +0100 Subject: media: v4l2-fwnode: Remove v4l2_async_notifier_parse_fwnode_endpoints_by_port() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are no users left of this helper and as it implements an undesirable and too simple behaviour that should instead be implemented directly by drivers remove it to prevent future uses of it. Suggested-by: Sakari Ailus Signed-off-by: Niklas Söderlund Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-fwnode.c | 14 --------- include/media/v4l2-fwnode.h | 53 ----------------------------------- 2 files changed, 67 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index 44dd04b05e29..5353e37eb950 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -911,20 +911,6 @@ v4l2_async_notifier_parse_fwnode_endpoints(struct device *dev, } EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints); -int -v4l2_async_notifier_parse_fwnode_endpoints_by_port(struct device *dev, - struct v4l2_async_notifier *notifier, - size_t asd_struct_size, - unsigned int port, - parse_endpoint_func parse_endpoint) -{ - return __v4l2_async_notifier_parse_fwnode_ep(dev, notifier, - asd_struct_size, - port, true, - parse_endpoint); -} -EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port); - /* * v4l2_fwnode_reference_parse - parse references for async sub-devices * @dev: the device node the properties of which are parsed for references diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h index 4e1f6e1d847e..4365430eea6f 100644 --- a/include/media/v4l2-fwnode.h +++ b/include/media/v4l2-fwnode.h @@ -484,59 +484,6 @@ v4l2_async_notifier_parse_fwnode_endpoints(struct device *dev, size_t asd_struct_size, parse_endpoint_func parse_endpoint); -/** - * v4l2_async_notifier_parse_fwnode_endpoints_by_port - Parse V4L2 fwnode - * endpoints of a port in a - * device node - * @dev: the device the endpoints of which are to be parsed - * @notifier: notifier for @dev - * @asd_struct_size: size of the driver's async sub-device struct, including - * sizeof(struct v4l2_async_subdev). The &struct - * v4l2_async_subdev shall be the first member of - * the driver's async sub-device struct, i.e. both - * begin at the same memory address. - * @port: port number where endpoints are to be parsed - * @parse_endpoint: Driver's callback function called on each V4L2 fwnode - * endpoint. Optional. - * - * This function is just like v4l2_async_notifier_parse_fwnode_endpoints() with - * the exception that it only parses endpoints in a given port. This is useful - * on devices that have both sinks and sources: the async sub-devices connected - * to sources have already been configured by another driver (on capture - * devices). In this case the driver must know which ports to parse. - * - * Parse the fwnode endpoints of the @dev device on a given @port and populate - * the async sub-devices list of the notifier. The @parse_endpoint callback - * function is called for each endpoint with the corresponding async sub-device - * pointer to let the caller initialize the driver-specific part of the async - * sub-device structure. - * - * The notifier memory shall be zeroed before this function is called on the - * notifier the first time. - * - * This function may not be called on a registered notifier and may be called on - * a notifier only once per port. - * - * The &struct v4l2_fwnode_endpoint passed to the callback function - * @parse_endpoint is released once the function is finished. If there is a need - * to retain that configuration, the user needs to allocate memory for it. - * - * Any notifier populated using this function must be released with a call to - * v4l2_async_notifier_cleanup() after it has been unregistered and the async - * sub-devices are no longer in use, even if the function returned an error. - * - * Return: %0 on success, including when no async sub-devices are found - * %-ENOMEM if memory allocation failed - * %-EINVAL if graph or endpoint parsing failed - * Other error codes as returned by @parse_endpoint - */ -int -v4l2_async_notifier_parse_fwnode_endpoints_by_port(struct device *dev, - struct v4l2_async_notifier *notifier, - size_t asd_struct_size, - unsigned int port, - parse_endpoint_func parse_endpoint); - /** * v4l2_async_notifier_parse_fwnode_sensor_common - parse common references on * sensors for async sub-devices -- cgit v1.2.3 From 909a0a189c677307edd461e21fd962784370d27f Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Fri, 20 Nov 2020 17:15:28 +0100 Subject: media: max9271: Fix GPIO enable/disable Fix GPIO enable/disable operations which wrongly read the 0x0f register to obtain the current mask of the enabled lines instead of using the correct 0x0e register. Also fix access to bit 0 of the register which is marked as reserved. Fixes: 34009bffc1c6 ("media: i2c: Add RDACM20 driver") Signed-off-by: Jacopo Mondi Reviewed-by: Geert Uytterhoeven Reviewed-by: Kieran Bingham Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/max9271.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/max9271.c b/drivers/media/i2c/max9271.c index 0f6f7a092a46..c247db569bab 100644 --- a/drivers/media/i2c/max9271.c +++ b/drivers/media/i2c/max9271.c @@ -223,12 +223,12 @@ int max9271_enable_gpios(struct max9271_device *dev, u8 gpio_mask) { int ret; - ret = max9271_read(dev, 0x0f); + ret = max9271_read(dev, 0x0e); if (ret < 0) return 0; /* BIT(0) reserved: GPO is always enabled. */ - ret |= gpio_mask | BIT(0); + ret |= (gpio_mask & ~BIT(0)); ret = max9271_write(dev, 0x0e, ret); if (ret < 0) { dev_err(&dev->client->dev, "Failed to enable gpio (%d)\n", ret); @@ -245,12 +245,12 @@ int max9271_disable_gpios(struct max9271_device *dev, u8 gpio_mask) { int ret; - ret = max9271_read(dev, 0x0f); + ret = max9271_read(dev, 0x0e); if (ret < 0) return 0; /* BIT(0) reserved: GPO cannot be disabled */ - ret &= (~gpio_mask | BIT(0)); + ret &= ~(gpio_mask | BIT(0)); ret = max9271_write(dev, 0x0e, ret); if (ret < 0) { dev_err(&dev->client->dev, "Failed to disable gpio (%d)\n", ret); -- cgit v1.2.3 From 7fe1d4453fb6bf103d668a19d957a7b2fc21887c Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Fri, 20 Nov 2020 17:15:29 +0100 Subject: media: rdacm20: Enable GPIO1 explicitly The MAX9271 GPIO1 line that controls the sensor reset is by default enabled after a serializer chip reset. As rdacm20 does not go through an explicit serializer reset, make sure GPIO1 is enabled to make the camera module driver more robust. Fixes: 34009bffc1c6 ("media: i2c: Add RDACM20 driver") Signed-off-by: Jacopo Mondi Reviewed-by: Kieran Bingham Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/rdacm20.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/rdacm20.c b/drivers/media/i2c/rdacm20.c index 1ed928c4ca70..16bcb764b0e0 100644 --- a/drivers/media/i2c/rdacm20.c +++ b/drivers/media/i2c/rdacm20.c @@ -487,9 +487,18 @@ static int rdacm20_initialize(struct rdacm20_device *dev) * Reset the sensor by cycling the OV10635 reset signal connected to the * MAX9271 GPIO1 and verify communication with the OV10635. */ - max9271_clear_gpios(dev->serializer, MAX9271_GPIO1OUT); + ret = max9271_enable_gpios(dev->serializer, MAX9271_GPIO1OUT); + if (ret) + return ret; + + ret = max9271_clear_gpios(dev->serializer, MAX9271_GPIO1OUT); + if (ret) + return ret; usleep_range(10000, 15000); - max9271_set_gpios(dev->serializer, MAX9271_GPIO1OUT); + + ret = max9271_set_gpios(dev->serializer, MAX9271_GPIO1OUT); + if (ret) + return ret; usleep_range(10000, 15000); again: -- cgit v1.2.3 From f61eb7bc9256aeb173d2d730f59cdd569d261c52 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 17 Nov 2020 02:39:47 +0100 Subject: media: dt-bindings: media: Use OF graph schema Now that we have a graph schema, rework the media related schemas to use it. Mostly this is adding a reference to graph.yaml and dropping duplicate parts from schemas. Cc: Maxime Ripard Cc: Jacopo Mondi Cc: Laurent Pinchart Signed-off-by: Rob Herring Acked-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/allwinner,sun4i-a10-csi.yaml | 1 + .../bindings/media/allwinner,sun6i-a31-csi.yaml | 1 + .../devicetree/bindings/media/i2c/adv7180.yaml | 31 ++------- .../devicetree/bindings/media/i2c/adv7604.yaml | 32 ++------- .../bindings/media/i2c/aptina,mt9v111.yaml | 2 +- .../bindings/media/i2c/imi,rdacm2x-gmsl.yaml | 25 +------ .../devicetree/bindings/media/i2c/imx219.yaml | 4 ++ .../bindings/media/i2c/maxim,max9286.yaml | 76 +++++----------------- .../devicetree/bindings/media/i2c/ov5647.yaml | 5 +- .../devicetree/bindings/media/i2c/ov8856.yaml | 5 +- .../devicetree/bindings/media/i2c/ovti,ov772x.yaml | 1 + .../devicetree/bindings/media/i2c/sony,imx214.yaml | 1 + .../devicetree/bindings/media/i2c/sony,imx274.yaml | 3 +- .../bindings/media/marvell,mmp2-ccic.yaml | 1 + .../devicetree/bindings/media/renesas,ceu.yaml | 1 + .../devicetree/bindings/media/renesas,csi2.yaml | 36 ++-------- .../devicetree/bindings/media/renesas,vin.yaml | 7 +- .../devicetree/bindings/media/st,stm32-dcmi.yaml | 7 +- .../devicetree/bindings/media/ti,cal.yaml | 15 ++--- .../bindings/media/xilinx/xlnx,csi2rxss.yaml | 21 +----- 20 files changed, 61 insertions(+), 214 deletions(-) diff --git a/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml b/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml index 09318830db47..0205f7dd7fdb 100644 --- a/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml +++ b/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml @@ -70,6 +70,7 @@ properties: # See ./video-interfaces.txt for details port: type: object + $ref: /schemas/graph.yaml#/properties/port additionalProperties: false properties: diff --git a/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml b/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml index 1fd9b5532a21..48d8f73ce7ab 100644 --- a/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml +++ b/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml @@ -43,6 +43,7 @@ properties: # See ./video-interfaces.txt for details port: type: object + $ref: /schemas/graph.yaml#/properties/port properties: endpoint: diff --git a/Documentation/devicetree/bindings/media/i2c/adv7180.yaml b/Documentation/devicetree/bindings/media/i2c/adv7180.yaml index d8c54f9d9506..7f28954a4508 100644 --- a/Documentation/devicetree/bindings/media/i2c/adv7180.yaml +++ b/Documentation/devicetree/bindings/media/i2c/adv7180.yaml @@ -36,17 +36,9 @@ properties: maxItems: 1 port: - type: object - description: - A node containing a single endpoint as doucmented in - Documentation/devicetree/bindings/media/video-interfaces.txt - - ports: - type: object - description: - A node containing input and output port nodes with endpoint definitions - as documented in - Documentation/devicetree/bindings/media/video-interfaces.txt + $ref: /schemas/graph.yaml#/properties/port + + ports: true additionalProperties: false @@ -80,24 +72,19 @@ allOf: then: properties: ports: + $ref: /schemas/graph.yaml#/properties/ports properties: - '#address-cells': - const: 1 - '#size-cells': - const: 0 port@3: - type: object description: Output port patternProperties: "^port@[0-2]$": - type: object description: Input port required: - port@3 - additionalProperties: false + unevaluatedProperties: false required: - ports @@ -110,24 +97,20 @@ allOf: then: properties: ports: + $ref: /schemas/graph.yaml#/properties/ports properties: - '#address-cells': - const: 1 - '#size-cells': - const: 0 port@6: type: object description: Output port patternProperties: "^port@[0-5]$": - type: object description: Input port required: - port@6 - additionalProperties: false + unevaluatedProperties: false required: - ports diff --git a/Documentation/devicetree/bindings/media/i2c/adv7604.yaml b/Documentation/devicetree/bindings/media/i2c/adv7604.yaml index 3897af540ddd..81f17e719d87 100644 --- a/Documentation/devicetree/bindings/media/i2c/adv7604.yaml +++ b/Documentation/devicetree/bindings/media/i2c/adv7604.yaml @@ -64,16 +64,12 @@ properties: description: Select which input is selected after reset. - ports: - type: object - description: - A node containing input and output port nodes with endpoint definitions - as documented in - Documentation/devicetree/bindings/media/video-interfaces.txt + ports: true required: - compatible - reg + - ports additionalProperties: false @@ -86,25 +82,17 @@ allOf: then: properties: ports: + $ref: /schemas/graph.yaml#/properties/ports properties: - '#address-cells': - const: 1 - '#size-cells': - const: 0 port@0: - type: object description: Input port port@1: - type: object description: Output port required: - port@1 - additionalProperties: false - - required: - - ports + unevaluatedProperties: false - if: properties: @@ -114,27 +102,19 @@ allOf: then: properties: ports: + $ref: /schemas/graph.yaml#/properties/ports properties: - '#address-cells': - const: 1 - '#size-cells': - const: 0 port@2: - type: object description: Output port patternProperties: "^port@[0-1]$": - type: object description: Input port required: - port@2 - additionalProperties: false - - required: - - ports + unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/media/i2c/aptina,mt9v111.yaml b/Documentation/devicetree/bindings/media/i2c/aptina,mt9v111.yaml index ff9546e95d05..17ec4ab1dbd0 100644 --- a/Documentation/devicetree/bindings/media/i2c/aptina,mt9v111.yaml +++ b/Documentation/devicetree/bindings/media/i2c/aptina,mt9v111.yaml @@ -41,7 +41,7 @@ properties: maxItems: 1 port: - type: object + $ref: /schemas/graph.yaml#/properties/port description: | Output video port. See ../video-interfaces.txt. diff --git a/Documentation/devicetree/bindings/media/i2c/imi,rdacm2x-gmsl.yaml b/Documentation/devicetree/bindings/media/i2c/imi,rdacm2x-gmsl.yaml index 3dc06c628e64..e0ea3acca89a 100644 --- a/Documentation/devicetree/bindings/media/i2c/imi,rdacm2x-gmsl.yaml +++ b/Documentation/devicetree/bindings/media/i2c/imi,rdacm2x-gmsl.yaml @@ -86,33 +86,12 @@ properties: maxItems: 3 port: - type: object - additionalProperties: false - description: -| + $ref: /schemas/graph.yaml#/properties/port + description: Connection to the remote GMSL endpoint are modelled using the OF graph bindings in accordance with the video interface bindings defined in Documentation/devicetree/bindings/media/video-interfaces.txt. - The device node contains a single "port" child node with a single - "endpoint" sub-device. - - properties: - endpoint: - type: object - additionalProperties: false - - properties: - remote-endpoint: - description: -| - phandle to the remote GMSL endpoint sub-node in the remote node - port. - maxItems: 1 - - required: - - remote-endpoint - - required: - - endpoint required: - compatible diff --git a/Documentation/devicetree/bindings/media/i2c/imx219.yaml b/Documentation/devicetree/bindings/media/i2c/imx219.yaml index dfc4d29a4f04..bba42e015c98 100644 --- a/Documentation/devicetree/bindings/media/i2c/imx219.yaml +++ b/Documentation/devicetree/bindings/media/i2c/imx219.yaml @@ -47,6 +47,8 @@ properties: # See ../video-interfaces.txt for more details port: type: object + $ref: /schemas/graph.yaml#/properties/port + properties: endpoint: type: object @@ -74,6 +76,8 @@ properties: required: - link-frequencies + additionalProperties: false + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/media/i2c/maxim,max9286.yaml b/Documentation/devicetree/bindings/media/i2c/maxim,max9286.yaml index 9ea827092fdd..2e89a5458afe 100644 --- a/Documentation/devicetree/bindings/media/i2c/maxim,max9286.yaml +++ b/Documentation/devicetree/bindings/media/i2c/maxim,max9286.yaml @@ -53,56 +53,25 @@ properties: ports: type: object - description: | - The connections to the MAX9286 GMSL and its endpoint nodes are modelled - using the OF graph bindings in accordance with the video interface - bindings defined in - Documentation/devicetree/bindings/media/video-interfaces.txt. - - The following table lists the port number corresponding to each device - port. - - Port Description - ---------------------------------------- - Port 0 GMSL Input 0 - Port 1 GMSL Input 1 - Port 2 GMSL Input 2 - Port 3 GMSL Input 3 - Port 4 CSI-2 Output + $ref: /schemas/graph.yaml#/properties/ports properties: - '#address-cells': - const: 1 - - '#size-cells': - const: 0 + port@0: + description: GMSL Input 0 - port@[0-3]: - type: object - properties: - reg: - enum: [ 0, 1, 2, 3 ] + port@1: + description: GMSL Input 1 - endpoint: - type: object + port@2: + description: GMSL Input 2 - properties: - remote-endpoint: - description: | - phandle to the remote GMSL source endpoint subnode in the - remote node port. - - required: - - remote-endpoint - - required: - - reg - - endpoint - - additionalProperties: false + port@3: + description: GMSL Input 3 port@4: type: object + description: CSI-2 Output + properties: reg: const: 4 @@ -130,6 +99,8 @@ properties: required: - port@4 + unevaluatedProperties: false + i2c-mux: type: object description: | @@ -184,25 +155,8 @@ properties: requirements of the currently connected remote device. port: - type: object - - properties: - endpoint: - type: object - - properties: - remote-endpoint: - description: phandle to the MAX9286 sink endpoint. - - required: - - remote-endpoint - - additionalProperties: false - - required: - - endpoint - - additionalProperties: false + $ref: /schemas/graph.yaml#/properties/port + description: Connection to the MAX9286 sink. required: - compatible diff --git a/Documentation/devicetree/bindings/media/i2c/ov5647.yaml b/Documentation/devicetree/bindings/media/i2c/ov5647.yaml index 280c62afae13..cd5291602a70 100644 --- a/Documentation/devicetree/bindings/media/i2c/ov5647.yaml +++ b/Documentation/devicetree/bindings/media/i2c/ov5647.yaml @@ -32,10 +32,7 @@ properties: port: type: object - description: |- - Should contain one endpoint sub-node used to model connection to the - video receiver according to the specification defined in - Documentation/devicetree/bindings/media/video-interfaces.txt. + $ref: /schemas/graph.yaml#/properties/port properties: endpoint: diff --git a/Documentation/devicetree/bindings/media/i2c/ov8856.yaml b/Documentation/devicetree/bindings/media/i2c/ov8856.yaml index cde85553fd01..2611eb69b3b2 100644 --- a/Documentation/devicetree/bindings/media/i2c/ov8856.yaml +++ b/Documentation/devicetree/bindings/media/i2c/ov8856.yaml @@ -58,11 +58,8 @@ properties: port: type: object + $ref: /schemas/graph.yaml#/properties/port additionalProperties: false - description: - A node containing an output port node with an endpoint definition - as documented in - Documentation/devicetree/bindings/media/video-interfaces.txt properties: endpoint: diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml index 63b3779d7289..450e5bd64312 100644 --- a/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml @@ -38,6 +38,7 @@ properties: port: type: object + $ref: /schemas/graph.yaml#/properties/port description: | Video output port. See ../video-interfaces.txt. diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml index 0f5e25fa4e9d..884bd3527e0a 100644 --- a/Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml @@ -55,6 +55,7 @@ properties: port: type: object + $ref: /schemas/graph.yaml#/properties/port description: | Video output port. See ../video-interfaces.txt. diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx274.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx274.yaml index f697e1a20beb..90828020e42a 100644 --- a/Documentation/devicetree/bindings/media/i2c/sony,imx274.yaml +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx274.yaml @@ -44,8 +44,7 @@ properties: maxItems: 1 port: - type: object - description: Output video port. See ../video-interfaces.txt. + $ref: /schemas/graph.yaml#/properties/port required: - compatible diff --git a/Documentation/devicetree/bindings/media/marvell,mmp2-ccic.yaml b/Documentation/devicetree/bindings/media/marvell,mmp2-ccic.yaml index 49bff738aca5..4832f55654cc 100644 --- a/Documentation/devicetree/bindings/media/marvell,mmp2-ccic.yaml +++ b/Documentation/devicetree/bindings/media/marvell,mmp2-ccic.yaml @@ -25,6 +25,7 @@ properties: port: type: object + $ref: /schemas/graph.yaml#/properties/port additionalProperties: false properties: diff --git a/Documentation/devicetree/bindings/media/renesas,ceu.yaml b/Documentation/devicetree/bindings/media/renesas,ceu.yaml index c7e1e4fe67e6..2d493d503d07 100644 --- a/Documentation/devicetree/bindings/media/renesas,ceu.yaml +++ b/Documentation/devicetree/bindings/media/renesas,ceu.yaml @@ -35,6 +35,7 @@ properties: port: type: object + $ref: /schemas/graph.yaml#/properties/port additionalProperties: false properties: diff --git a/Documentation/devicetree/bindings/media/renesas,csi2.yaml b/Documentation/devicetree/bindings/media/renesas,csi2.yaml index 533c2f181db7..e34dfbef25a2 100644 --- a/Documentation/devicetree/bindings/media/renesas,csi2.yaml +++ b/Documentation/devicetree/bindings/media/renesas,csi2.yaml @@ -47,10 +47,7 @@ properties: ports: type: object - description: - A node containing input and output port nodes with endpoint definitions - as documented in - Documentation/devicetree/bindings/media/video-interfaces.txt + $ref: /schemas/graph.yaml#/properties/ports properties: port@0: @@ -84,38 +81,15 @@ properties: additionalProperties: false port@1: - type: object description: Output port node, multiple endpoints describing all the R-Car VIN modules connected the CSI-2 receiver. - properties: - '#address-cells': - const: 1 - - '#size-cells': - const: 0 - - reg: - const: 1 - - patternProperties: - "^endpoint@[0-9a-f]$": - type: object + required: + - port@0 + - port@1 - properties: - reg: - maxItems: 1 - - remote-endpoint: true - - required: - - reg - - remote-endpoint - - additionalProperties: false - - additionalProperties: false + unevaluatedProperties: false required: - compatible diff --git a/Documentation/devicetree/bindings/media/renesas,vin.yaml b/Documentation/devicetree/bindings/media/renesas,vin.yaml index ad2fe660364b..25a70dc89a4c 100644 --- a/Documentation/devicetree/bindings/media/renesas,vin.yaml +++ b/Documentation/devicetree/bindings/media/renesas,vin.yaml @@ -70,6 +70,7 @@ properties: #The per-board settings for Gen2 and RZ/G1 platforms: port: type: object + $ref: /schemas/graph.yaml#/properties/port description: A node containing a parallel input with a single endpoint definitions as documented in @@ -124,9 +125,7 @@ properties: ports: type: object - description: - A node containing input nodes with endpoint definitions as documented in - Documentation/devicetree/bindings/media/video-interfaces.txt + $ref: /schemas/graph.yaml#/properties/ports properties: port@0: @@ -272,6 +271,8 @@ properties: additionalProperties: false + unevaluatedProperties: false + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml b/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml index c18574bb3e81..e3152c8fdfea 100644 --- a/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml +++ b/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml @@ -37,12 +37,9 @@ properties: maxItems: 1 port: - type: object + $ref: /schemas/graph.yaml#/properties/port description: - DCMI supports a single port node with parallel bus. It should contain - one 'port' child node with child 'endpoint' node. Please refer to the - bindings defined in - Documentation/devicetree/bindings/media/video-interfaces.txt. + DCMI supports a single port node with parallel bus. properties: endpoint: diff --git a/Documentation/devicetree/bindings/media/ti,cal.yaml b/Documentation/devicetree/bindings/media/ti,cal.yaml index 5e066629287d..dc2c6be4fa4d 100644 --- a/Documentation/devicetree/bindings/media/ti,cal.yaml +++ b/Documentation/devicetree/bindings/media/ti,cal.yaml @@ -70,23 +70,18 @@ properties: # See ./video-interfaces.txt for details ports: type: object - additionalProperties: false + $ref: /schemas/graph.yaml#/properties/ports + unevaluatedProperties: false properties: - "#address-cells": - const: 1 - - "#size-cells": - const: 0 - port@0: type: object + description: CSI2 Port #0 additionalProperties: false properties: reg: const: 0 - description: CSI2 Port #0 patternProperties: endpoint: @@ -108,12 +103,12 @@ properties: port@1: type: object + description: CSI2 Port #1 additionalProperties: false properties: reg: const: 1 - description: CSI2 Port #1 patternProperties: endpoint: @@ -134,8 +129,6 @@ properties: - reg required: - - "#address-cells" - - "#size-cells" - port@0 required: diff --git a/Documentation/devicetree/bindings/media/xilinx/xlnx,csi2rxss.yaml b/Documentation/devicetree/bindings/media/xilinx/xlnx,csi2rxss.yaml index 2961a5b6872f..0868718c3691 100644 --- a/Documentation/devicetree/bindings/media/xilinx/xlnx,csi2rxss.yaml +++ b/Documentation/devicetree/bindings/media/xilinx/xlnx,csi2rxss.yaml @@ -98,6 +98,7 @@ properties: ports: type: object + $ref: /schemas/graph.yaml#/properties/ports properties: port@0: @@ -141,29 +142,11 @@ properties: additionalProperties: false port@1: - type: object description: | Output / source port node, endpoint describing modules connected the CSI-2 receiver. - properties: - - reg: - const: 1 - - endpoint: - type: object - - properties: - - remote-endpoint: true - - required: - - remote-endpoint - - additionalProperties: false - - additionalProperties: false + unevaluatedProperties: false required: - compatible -- cgit v1.2.3 From 1ed36ecd1459b653cced8929bfb37dba94b64c5d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 5 Aug 2020 12:57:21 +0200 Subject: media: i2c: imx219: Selection compliance fixes To comply with the intended usage of the V4L2 selection target when used to retrieve a sensor image properties, adjust the rectangles returned by the imx219 driver. The top/left crop coordinates of the TGT_CROP rectangle were set to (0, 0) instead of (8, 8) which is the offset from the larger physical pixel array rectangle. This was also a mismatch with the default values crop rectangle value, so this is corrected. Found with v4l2-compliance. While at it, add V4L2_SEL_TGT_CROP_BOUNDS support: CROP_DEFAULT and CROP_BOUNDS have the same size as the non-active pixels are not readable using the selection API. Found with v4l2-compliance. [reword commit message, use macros for pixel offsets] Fixes: e6d4ef7d58aa7 ("media: i2c: imx219: Implement get_selection") Signed-off-by: Hans Verkuil Signed-off-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx219.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 982828d19d64..e7791a0848b3 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -471,8 +471,8 @@ static const struct imx219_mode supported_modes[] = { .width = 3280, .height = 2464, .crop = { - .left = 0, - .top = 0, + .left = IMX219_PIXEL_ARRAY_LEFT, + .top = IMX219_PIXEL_ARRAY_TOP, .width = 3280, .height = 2464 }, @@ -487,8 +487,8 @@ static const struct imx219_mode supported_modes[] = { .width = 1920, .height = 1080, .crop = { - .left = 680, - .top = 692, + .left = 688, + .top = 700, .width = 1920, .height = 1080 }, @@ -503,8 +503,8 @@ static const struct imx219_mode supported_modes[] = { .width = 1640, .height = 1232, .crop = { - .left = 0, - .top = 0, + .left = IMX219_PIXEL_ARRAY_LEFT, + .top = IMX219_PIXEL_ARRAY_TOP, .width = 3280, .height = 2464 }, @@ -519,8 +519,8 @@ static const struct imx219_mode supported_modes[] = { .width = 640, .height = 480, .crop = { - .left = 1000, - .top = 752, + .left = 1008, + .top = 760, .width = 1280, .height = 960 }, @@ -1006,6 +1006,7 @@ static int imx219_get_selection(struct v4l2_subdev *sd, return 0; case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: sel->r.top = IMX219_PIXEL_ARRAY_TOP; sel->r.left = IMX219_PIXEL_ARRAY_LEFT; sel->r.width = IMX219_PIXEL_ARRAY_WIDTH; -- cgit v1.2.3 From a109073bb9ec69ed9ec6eb541485e1dae63c13b4 Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Thu, 19 Nov 2020 23:18:49 +0100 Subject: media: rockchip: rkisp1: Constify static structs These 'ops' structs are never modified, so make them const to allow the compiler to put them in read-only memory. Signed-off-by: Rikard Falkeborn Reviewed-by: Dafna Hirschfeld Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c | 6 +++--- drivers/media/platform/rockchip/rkisp1/rkisp1-common.h | 2 +- drivers/media/platform/rockchip/rkisp1/rkisp1-params.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c index b81235afd053..380582f68ace 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c @@ -565,7 +565,7 @@ static void rkisp1_sp_set_data_path(struct rkisp1_capture *cap) rkisp1_write(cap->rkisp1, dpcl, RKISP1_CIF_VI_DPCL); } -static struct rkisp1_capture_ops rkisp1_capture_ops_mp = { +static const struct rkisp1_capture_ops rkisp1_capture_ops_mp = { .config = rkisp1_mp_config, .enable = rkisp1_mp_enable, .disable = rkisp1_mp_disable, @@ -574,7 +574,7 @@ static struct rkisp1_capture_ops rkisp1_capture_ops_mp = { .is_stopped = rkisp1_mp_is_stopped, }; -static struct rkisp1_capture_ops rkisp1_capture_ops_sp = { +static const struct rkisp1_capture_ops rkisp1_capture_ops_sp = { .config = rkisp1_sp_config, .enable = rkisp1_sp_enable, .disable = rkisp1_sp_disable, @@ -1038,7 +1038,7 @@ err_ret_buffers: return ret; } -static struct vb2_ops rkisp1_vb2_ops = { +static const struct vb2_ops rkisp1_vb2_ops = { .queue_setup = rkisp1_vb2_queue_setup, .buf_queue = rkisp1_vb2_buf_queue, .buf_prepare = rkisp1_vb2_buf_prepare, diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h index 3a134e97161c..038c303a8aed 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h @@ -214,7 +214,7 @@ struct rkisp1_capture { struct rkisp1_vdev_node vnode; struct rkisp1_device *rkisp1; enum rkisp1_stream_id id; - struct rkisp1_capture_ops *ops; + const struct rkisp1_capture_ops *ops; const struct rkisp1_capture_config *config; bool is_streaming; bool is_stopping; diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c index 03f9a81df440..6af4d551ffb5 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c @@ -1469,7 +1469,7 @@ static void rkisp1_params_vb2_stop_streaming(struct vb2_queue *vq) vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); } -static struct vb2_ops rkisp1_params_vb2_ops = { +static const struct vb2_ops rkisp1_params_vb2_ops = { .queue_setup = rkisp1_params_vb2_queue_setup, .wait_prepare = vb2_ops_wait_prepare, .wait_finish = vb2_ops_wait_finish, @@ -1479,7 +1479,7 @@ static struct vb2_ops rkisp1_params_vb2_ops = { }; -static struct v4l2_file_operations rkisp1_params_fops = { +static const struct v4l2_file_operations rkisp1_params_fops = { .mmap = vb2_fop_mmap, .unlocked_ioctl = video_ioctl2, .poll = vb2_fop_poll, -- cgit v1.2.3 From dbf0b3a7b719eb3f72cb53c2ce7d34a012a9c261 Mon Sep 17 00:00:00 2001 From: Daniel Lee Kruse Date: Wed, 30 Sep 2020 05:36:35 +0200 Subject: media: cx23885: add more quirks for reset DMA on some AMD IOMMU On AMD Family 15h (Models 30h-3fh), I/O Memory Management Unit RiSC engine sometimes stalls, requiring a reset. As result, MythTV and w-scan won't scan channels on the AMD Kaveri APU with the Hauppauge QuadHD TV tuner card. For the solution I added the Input/Output Memory Management Unit's PCI Identity of 0x1423 to the broken_dev_id[] array, which is used by a quirks logic meant to fix similar problems with other AMD chipsets. Signed-off-by: Daniel Lee Kruse Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 16eb4ab0e73e..22f55a7840a6 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -2073,6 +2073,10 @@ static struct { * 0x1451 is PCI ID for the IOMMU found on Ryzen */ { PCI_VENDOR_ID_AMD, 0x1451 }, + /* According to sudo lspci -nn, + * 0x1423 is the PCI ID for the IOMMU found on Kaveri + */ + { PCI_VENDOR_ID_AMD, 0x1423 }, }; static bool cx23885_does_need_dma_reset(void) -- cgit v1.2.3 From 503dab0b8a56e21a4397668e525273e3b528c78a Mon Sep 17 00:00:00 2001 From: Martin Cerveny Date: Mon, 16 Nov 2020 13:56:12 +0100 Subject: media: cedrus: Register all codecs as capability All codecs should have capabilities. For example "Allwinner V3s" does not support "MPEG2". Signed-off-by: Martin Cerveny Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/sunxi/cedrus/cedrus.c | 22 ++++++++++++++++++++-- drivers/staging/media/sunxi/cedrus/cedrus.h | 2 ++ drivers/staging/media/sunxi/cedrus/cedrus_video.c | 2 ++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index 9a102b7c1bb9..3487554fab68 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -486,47 +486,65 @@ static int cedrus_remove(struct platform_device *pdev) } static const struct cedrus_variant sun4i_a10_cedrus_variant = { + .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC | + CEDRUS_CAPABILITY_H264_DEC, .mod_rate = 320000000, }; static const struct cedrus_variant sun5i_a13_cedrus_variant = { + .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC | + CEDRUS_CAPABILITY_H264_DEC, .mod_rate = 320000000, }; static const struct cedrus_variant sun7i_a20_cedrus_variant = { + .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC | + CEDRUS_CAPABILITY_H264_DEC, .mod_rate = 320000000, }; static const struct cedrus_variant sun8i_a33_cedrus_variant = { - .capabilities = CEDRUS_CAPABILITY_UNTILED, + .capabilities = CEDRUS_CAPABILITY_UNTILED | + CEDRUS_CAPABILITY_MPEG2_DEC | + CEDRUS_CAPABILITY_H264_DEC, .mod_rate = 320000000, }; static const struct cedrus_variant sun8i_h3_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_UNTILED | + CEDRUS_CAPABILITY_MPEG2_DEC | + CEDRUS_CAPABILITY_H264_DEC | CEDRUS_CAPABILITY_H265_DEC, .mod_rate = 402000000, }; static const struct cedrus_variant sun8i_r40_cedrus_variant = { - .capabilities = CEDRUS_CAPABILITY_UNTILED, + .capabilities = CEDRUS_CAPABILITY_UNTILED | + CEDRUS_CAPABILITY_MPEG2_DEC | + CEDRUS_CAPABILITY_H264_DEC, .mod_rate = 297000000, }; static const struct cedrus_variant sun50i_a64_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_UNTILED | + CEDRUS_CAPABILITY_MPEG2_DEC | + CEDRUS_CAPABILITY_H264_DEC | CEDRUS_CAPABILITY_H265_DEC, .mod_rate = 402000000, }; static const struct cedrus_variant sun50i_h5_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_UNTILED | + CEDRUS_CAPABILITY_MPEG2_DEC | + CEDRUS_CAPABILITY_H264_DEC | CEDRUS_CAPABILITY_H265_DEC, .mod_rate = 402000000, }; static const struct cedrus_variant sun50i_h6_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_UNTILED | + CEDRUS_CAPABILITY_MPEG2_DEC | + CEDRUS_CAPABILITY_H264_DEC | CEDRUS_CAPABILITY_H265_DEC, .quirks = CEDRUS_QUIRK_NO_DMA_OFFSET, .mod_rate = 600000000, diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h index 93c843ae14bb..30cdb15d6800 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h @@ -28,6 +28,8 @@ #define CEDRUS_CAPABILITY_UNTILED BIT(0) #define CEDRUS_CAPABILITY_H265_DEC BIT(1) +#define CEDRUS_CAPABILITY_H264_DEC BIT(2) +#define CEDRUS_CAPABILITY_MPEG2_DEC BIT(3) #define CEDRUS_QUIRK_NO_DMA_OFFSET BIT(0) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c index 911f607d9b09..bdca23fc214b 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c @@ -38,10 +38,12 @@ static struct cedrus_format cedrus_formats[] = { { .pixelformat = V4L2_PIX_FMT_MPEG2_SLICE, .directions = CEDRUS_DECODE_SRC, + .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC, }, { .pixelformat = V4L2_PIX_FMT_H264_SLICE, .directions = CEDRUS_DECODE_SRC, + .capabilities = CEDRUS_CAPABILITY_H264_DEC, }, { .pixelformat = V4L2_PIX_FMT_HEVC_SLICE, -- cgit v1.2.3 From 4c7047b7dc90d212fb09bee23275f53750f6a2c1 Mon Sep 17 00:00:00 2001 From: Martin Cerveny Date: Mon, 16 Nov 2020 13:56:16 +0100 Subject: media: dt-bindings: media: cedrus: Add V3s compatible Allwinner V3s SoC contains video engine. Add compatible for it. Signed-off-by: Martin Cerveny Acked-by: Chen-Yu Tsai Acked-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/allwinner,sun4i-a10-video-engine.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-video-engine.yaml b/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-video-engine.yaml index 0d58bbcd24d3..2f7058f7760c 100644 --- a/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-video-engine.yaml +++ b/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-video-engine.yaml @@ -18,6 +18,7 @@ properties: - allwinner,sun7i-a20-video-engine - allwinner,sun8i-a33-video-engine - allwinner,sun8i-h3-video-engine + - allwinner,sun8i-v3s-video-engine - allwinner,sun8i-r40-video-engine - allwinner,sun50i-a64-video-engine - allwinner,sun50i-h5-video-engine -- cgit v1.2.3 From 5cc794be382bba529677352a1f5fd0be08208915 Mon Sep 17 00:00:00 2001 From: Martin Cerveny Date: Mon, 16 Nov 2020 13:56:15 +0100 Subject: media: cedrus: Add support for V3s V3s video engine runs at lower speed and support video decoder for H.264 and JPEG/MJPEG only. Signed-off-by: Martin Cerveny Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/sunxi/cedrus/cedrus.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index 3487554fab68..ee4e21b29374 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -518,6 +518,12 @@ static const struct cedrus_variant sun8i_h3_cedrus_variant = { .mod_rate = 402000000, }; +static const struct cedrus_variant sun8i_v3s_cedrus_variant = { + .capabilities = CEDRUS_CAPABILITY_UNTILED | + CEDRUS_CAPABILITY_H264_DEC, + .mod_rate = 297000000, +}; + static const struct cedrus_variant sun8i_r40_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_UNTILED | CEDRUS_CAPABILITY_MPEG2_DEC | @@ -571,6 +577,10 @@ static const struct of_device_id cedrus_dt_match[] = { .compatible = "allwinner,sun8i-h3-video-engine", .data = &sun8i_h3_cedrus_variant, }, + { + .compatible = "allwinner,sun8i-v3s-video-engine", + .data = &sun8i_v3s_cedrus_variant, + }, { .compatible = "allwinner,sun8i-r40-video-engine", .data = &sun8i_r40_cedrus_variant, -- cgit v1.2.3 From ca1cfc3fa2d32960bbf55e5c4785151b7034feb0 Mon Sep 17 00:00:00 2001 From: Xu Wang Date: Fri, 13 Nov 2020 08:21:11 +0100 Subject: media: cx88: use ARRAY_SIZE Use ARRAY_SIZE instead of dividing sizeof array with sizeof an element Signed-off-by: Xu Wang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx88/cx88-mpeg.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c index a57c991b165b..a3edb548afde 100644 --- a/drivers/media/pci/cx88/cx88-mpeg.c +++ b/drivers/media/pci/cx88/cx88-mpeg.c @@ -524,8 +524,7 @@ static int cx8802_request_acquire(struct cx8802_driver *drv) core->last_analog_input = core->input; core->input = 0; for (i = 0; - i < (sizeof(core->board.input) / - sizeof(struct cx88_input)); + i < ARRAY_SIZE(core->board.input); i++) { if (core->board.input[i].type == CX88_VMUX_DVB) { core->input = i; -- cgit v1.2.3 From eb08c48132a1f594478ab9fa2b6ee646c3513a49 Mon Sep 17 00:00:00 2001 From: Zhang Xiaoxu Date: Mon, 16 Nov 2020 15:18:01 +0100 Subject: media: tvp5150: Fix wrong return value of tvp5150_parse_dt() If of_graph_get_endpoint_by_regs() return NULL, it will return 0 rather than an errno, because we doesn't initialize the return value. Fixes: 0556f1d580d4 ("media: tvp5150: add input source selection of_graph support") Reported-by: Hulk Robot Signed-off-by: Zhang Xiaoxu Reviewed-by: Marco Felsch Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvp5150.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 29f65bb6103d..e26e3f544054 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -2080,6 +2080,7 @@ static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np) ep_np = of_graph_get_endpoint_by_regs(np, TVP5150_PAD_VID_OUT, 0); if (!ep_np) { + ret = -EINVAL; dev_err(dev, "Error no output endpoint available\n"); goto err_free; } -- cgit v1.2.3 From 41a340941854c4606a9b71b9d68db412747e7c84 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 2 Dec 2020 15:13:26 +0100 Subject: media: coda: Convert the driver to DT-only Since 5.10-rc1 i.MX is a devicetree-only platform, so simplify the code by removing the unused non-DT support. Signed-off-by: Fabio Estevam Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 2 +- drivers/media/platform/coda/coda-common.c | 27 ++------------------------- include/linux/platform_data/media/coda.h | 14 -------------- 3 files changed, 3 insertions(+), 40 deletions(-) delete mode 100644 include/linux/platform_data/media/coda.h diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index ffffef2267f4..9fdbfea06087 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -201,7 +201,7 @@ if V4L_MEM2MEM_DRIVERS config VIDEO_CODA tristate "Chips&Media Coda multi-standard codec IP" - depends on VIDEO_DEV && VIDEO_V4L2 && (ARCH_MXC || COMPILE_TEST) + depends on VIDEO_DEV && VIDEO_V4L2 && OF && (ARCH_MXC || COMPILE_TEST) select SRAM select VIDEOBUF2_DMA_CONTIG select VIDEOBUF2_VMALLOC diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index d30eafea701d..995e95272e51 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include @@ -3102,13 +3101,6 @@ static const struct coda_devtype coda_devdata[] = { }, }; -static const struct platform_device_id coda_platform_ids[] = { - { .name = "coda-imx27", .driver_data = CODA_IMX27 }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(platform, coda_platform_ids); - -#ifdef CONFIG_OF static const struct of_device_id coda_dt_ids[] = { { .compatible = "fsl,imx27-vpu", .data = &coda_devdata[CODA_IMX27] }, { .compatible = "fsl,imx51-vpu", .data = &coda_devdata[CODA_IMX51] }, @@ -3118,14 +3110,9 @@ static const struct of_device_id coda_dt_ids[] = { { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, coda_dt_ids); -#endif static int coda_probe(struct platform_device *pdev) { - const struct of_device_id *of_id = - of_match_device(of_match_ptr(coda_dt_ids), &pdev->dev); - const struct platform_device_id *pdev_id; - struct coda_platform_data *pdata = pdev->dev.platform_data; struct device_node *np = pdev->dev.of_node; struct gen_pool *pool; struct coda_dev *dev; @@ -3135,14 +3122,7 @@ static int coda_probe(struct platform_device *pdev) if (!dev) return -ENOMEM; - pdev_id = of_id ? of_id->data : platform_get_device_id(pdev); - - if (of_id) - dev->devtype = of_id->data; - else if (pdev_id) - dev->devtype = &coda_devdata[pdev_id->driver_data]; - else - return -EINVAL; + dev->devtype = of_device_get_match_data(&pdev->dev); dev->dev = &pdev->dev; dev->clk_per = devm_clk_get(&pdev->dev, "per"); @@ -3200,10 +3180,8 @@ static int coda_probe(struct platform_device *pdev) return ret; } - /* Get IRAM pool from device tree or platform data */ + /* Get IRAM pool from device tree */ pool = of_gen_pool_get(np, "iram", 0); - if (!pool && pdata) - pool = gen_pool_get(pdata->iram_dev, NULL); if (!pool) { dev_err(&pdev->dev, "iram pool not available\n"); return -ENOMEM; @@ -3342,7 +3320,6 @@ static struct platform_driver coda_driver = { .of_match_table = of_match_ptr(coda_dt_ids), .pm = &coda_pm_ops, }, - .id_table = coda_platform_ids, }; module_platform_driver(coda_driver); diff --git a/include/linux/platform_data/media/coda.h b/include/linux/platform_data/media/coda.h deleted file mode 100644 index 293b61b60c9d..000000000000 --- a/include/linux/platform_data/media/coda.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2013 Philipp Zabel, Pengutronix - */ -#ifndef PLATFORM_CODA_H -#define PLATFORM_CODA_H - -struct device; - -struct coda_platform_data { - struct device *iram_dev; -}; - -#endif -- cgit v1.2.3 From 1f565e263c3e95ccd79fececc51ae7d55ccbddb6 Mon Sep 17 00:00:00 2001 From: Irui Wang Date: Thu, 29 Oct 2020 02:17:20 +0100 Subject: media: mtk-vpu: VPU should be in idle state before system is suspended VPU should be in idle state before system is suspended or it will work abnormally like VPU program counter not in a correct address or VPU reset Signed-off-by: Irui Wang Reviewed-by: Alexandre Courbot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vpu/mtk_vpu.c | 68 ++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.c b/drivers/media/platform/mtk-vpu/mtk_vpu.c index 36cb9b6131f7..86ab808ba877 100644 --- a/drivers/media/platform/mtk-vpu/mtk_vpu.c +++ b/drivers/media/platform/mtk-vpu/mtk_vpu.c @@ -27,6 +27,7 @@ #define INIT_TIMEOUT_MS 2000U #define IPI_TIMEOUT_MS 2000U +#define VPU_IDLE_TIMEOUT_MS 1000U #define VPU_FW_VER_LEN 16 /* maximum program/data TCM (Tightly-Coupled Memory) size */ @@ -57,11 +58,15 @@ #define VPU_DMEM_EXT0_ADDR 0x0014 #define VPU_DMEM_EXT1_ADDR 0x0018 #define HOST_TO_VPU 0x0024 +#define VPU_IDLE_REG 0x002C +#define VPU_INT_STATUS 0x0034 #define VPU_PC_REG 0x0060 #define VPU_WDT_REG 0x0084 /* vpu inter-processor communication interrupt */ #define VPU_IPC_INT BIT(8) +/* vpu idle state */ +#define VPU_IDLE_STATE BIT(23) /** * enum vpu_fw_type - VPU firmware type @@ -945,11 +950,74 @@ static int mtk_vpu_remove(struct platform_device *pdev) return 0; } +static int mtk_vpu_suspend(struct device *dev) +{ + struct mtk_vpu *vpu = dev_get_drvdata(dev); + unsigned long timeout; + int ret; + + ret = vpu_clock_enable(vpu); + if (ret) { + dev_err(dev, "failed to enable vpu clock\n"); + return ret; + } + + mutex_lock(&vpu->vpu_mutex); + /* disable vpu timer interrupt */ + vpu_cfg_writel(vpu, vpu_cfg_readl(vpu, VPU_INT_STATUS) | VPU_IDLE_STATE, + VPU_INT_STATUS); + /* check if vpu is idle for system suspend */ + timeout = jiffies + msecs_to_jiffies(VPU_IDLE_TIMEOUT_MS); + do { + if (time_after(jiffies, timeout)) { + dev_err(dev, "vpu idle timeout\n"); + mutex_unlock(&vpu->vpu_mutex); + vpu_clock_disable(vpu); + return -EIO; + } + } while (!vpu_cfg_readl(vpu, VPU_IDLE_REG)); + + mutex_unlock(&vpu->vpu_mutex); + vpu_clock_disable(vpu); + clk_unprepare(vpu->clk); + + return 0; +} + +static int mtk_vpu_resume(struct device *dev) +{ + struct mtk_vpu *vpu = dev_get_drvdata(dev); + int ret; + + clk_prepare(vpu->clk); + ret = vpu_clock_enable(vpu); + if (ret) { + dev_err(dev, "failed to enable vpu clock\n"); + return ret; + } + + mutex_lock(&vpu->vpu_mutex); + /* enable vpu timer interrupt */ + vpu_cfg_writel(vpu, + vpu_cfg_readl(vpu, VPU_INT_STATUS) & ~(VPU_IDLE_STATE), + VPU_INT_STATUS); + mutex_unlock(&vpu->vpu_mutex); + vpu_clock_disable(vpu); + + return 0; +} + +static const struct dev_pm_ops mtk_vpu_pm = { + .suspend = mtk_vpu_suspend, + .resume = mtk_vpu_resume, +}; + static struct platform_driver mtk_vpu_driver = { .probe = mtk_vpu_probe, .remove = mtk_vpu_remove, .driver = { .name = "mtk_vpu", + .pm = &mtk_vpu_pm, .of_match_table = mtk_vpu_match, }, }; -- cgit v1.2.3 From 040d31ccf2bd873b32961eb1cf4a0a78423caca8 Mon Sep 17 00:00:00 2001 From: Irui Wang Date: Thu, 29 Oct 2020 02:17:21 +0100 Subject: media: mtk-vpu: dump VPU status when IPI times out when IPI time out, dump VPU status to get more debug information Signed-off-by: Irui Wang Reviewed-by: Alexandre Courbot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vpu/mtk_vpu.c | 33 ++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.c b/drivers/media/platform/mtk-vpu/mtk_vpu.c index 86ab808ba877..043894f7188c 100644 --- a/drivers/media/platform/mtk-vpu/mtk_vpu.c +++ b/drivers/media/platform/mtk-vpu/mtk_vpu.c @@ -61,6 +61,8 @@ #define VPU_IDLE_REG 0x002C #define VPU_INT_STATUS 0x0034 #define VPU_PC_REG 0x0060 +#define VPU_SP_REG 0x0064 +#define VPU_RA_REG 0x0068 #define VPU_WDT_REG 0x0084 /* vpu inter-processor communication interrupt */ @@ -268,6 +270,20 @@ static int vpu_clock_enable(struct mtk_vpu *vpu) return ret; } +static void vpu_dump_status(struct mtk_vpu *vpu) +{ + dev_info(vpu->dev, + "vpu: run %x, pc = 0x%x, ra = 0x%x, sp = 0x%x, idle = 0x%x\n" + "vpu: int %x, hv = 0x%x, vh = 0x%x, wdt = 0x%x\n", + vpu_running(vpu), vpu_cfg_readl(vpu, VPU_PC_REG), + vpu_cfg_readl(vpu, VPU_RA_REG), vpu_cfg_readl(vpu, VPU_SP_REG), + vpu_cfg_readl(vpu, VPU_IDLE_REG), + vpu_cfg_readl(vpu, VPU_INT_STATUS), + vpu_cfg_readl(vpu, HOST_TO_VPU), + vpu_cfg_readl(vpu, VPU_TO_HOST), + vpu_cfg_readl(vpu, VPU_WDT_REG)); +} + int vpu_ipi_register(struct platform_device *pdev, enum ipi_id id, ipi_handler_t handler, const char *name, void *priv) @@ -328,6 +344,7 @@ int vpu_ipi_send(struct platform_device *pdev, if (time_after(jiffies, timeout)) { dev_err(vpu->dev, "vpu_ipi_send: IPI timeout!\n"); ret = -EIO; + vpu_dump_status(vpu); goto mut_unlock; } } while (vpu_cfg_readl(vpu, HOST_TO_VPU)); @@ -347,8 +364,9 @@ int vpu_ipi_send(struct platform_device *pdev, ret = wait_event_timeout(vpu->ack_wq, vpu->ipi_id_ack[id], timeout); vpu->ipi_id_ack[id] = false; if (ret == 0) { - dev_err(vpu->dev, "vpu ipi %d ack time out !", id); + dev_err(vpu->dev, "vpu ipi %d ack time out !\n", id); ret = -EIO; + vpu_dump_status(vpu); goto clock_disable; } vpu_clock_disable(vpu); @@ -633,7 +651,7 @@ static ssize_t vpu_debug_read(struct file *file, char __user *user_buf, { char buf[256]; unsigned int len; - unsigned int running, pc, vpu_to_host, host_to_vpu, wdt; + unsigned int running, pc, vpu_to_host, host_to_vpu, wdt, idle, ra, sp; int ret; struct device *dev = file->private_data; struct mtk_vpu *vpu = dev_get_drvdata(dev); @@ -650,6 +668,10 @@ static ssize_t vpu_debug_read(struct file *file, char __user *user_buf, wdt = vpu_cfg_readl(vpu, VPU_WDT_REG); host_to_vpu = vpu_cfg_readl(vpu, HOST_TO_VPU); vpu_to_host = vpu_cfg_readl(vpu, VPU_TO_HOST); + ra = vpu_cfg_readl(vpu, VPU_RA_REG); + sp = vpu_cfg_readl(vpu, VPU_SP_REG); + idle = vpu_cfg_readl(vpu, VPU_IDLE_REG); + vpu_clock_disable(vpu); if (running) { @@ -658,9 +680,12 @@ static ssize_t vpu_debug_read(struct file *file, char __user *user_buf, "PC: 0x%x\n" "WDT: 0x%x\n" "Host to VPU: 0x%x\n" - "VPU to Host: 0x%x\n", + "VPU to Host: 0x%x\n" + "SP: 0x%x\n" + "RA: 0x%x\n" + "idle: 0x%x\n", vpu->run.fw_ver, pc, wdt, - host_to_vpu, vpu_to_host); + host_to_vpu, vpu_to_host, sp, ra, idle); } else { len = snprintf(buf, sizeof(buf), "VPU not running\n"); } -- cgit v1.2.3 From 8d48b611685cd64e8df366d6ccbaad8cf1a4260c Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Mon, 9 Nov 2020 17:22:43 +0100 Subject: media: uapi: Expose VP8 probability lengths as defines These values will be used by various drivers implementing the VP8 stateless API. This had been suggested by Ezequiel Garcia for the Cedrus VP8 driver. Signed-off-by: Emmanuel Gil Peyrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/media/vp8-ctrls.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/media/vp8-ctrls.h b/include/media/vp8-ctrls.h index 53cba826e482..a920493361dc 100644 --- a/include/media/vp8-ctrls.h +++ b/include/media/vp8-ctrls.h @@ -53,11 +53,13 @@ struct v4l2_vp8_quantization_header { __u16 padding; }; +#define V4L2_VP8_COEFF_PROB_CNT 11 +#define V4L2_VP8_MV_PROB_CNT 19 struct v4l2_vp8_entropy_header { - __u8 coeff_probs[4][8][3][11]; + __u8 coeff_probs[4][8][3][V4L2_VP8_COEFF_PROB_CNT]; __u8 y_mode_probs[4]; __u8 uv_mode_probs[3]; - __u8 mv_probs[2][19]; + __u8 mv_probs[2][V4L2_VP8_MV_PROB_CNT]; __u8 padding[3]; }; -- cgit v1.2.3 From b4b3564c5646ee190e637bbf95424719d831e1b2 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Mon, 9 Nov 2020 17:22:44 +0100 Subject: media: hantro: Use VP8 lengths defined in uapi Use the new defines instead of hardcoding the VP8 lengths. [hverkuil: add commit log] Signed-off-by: Emmanuel Gil Peyrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/hantro_vp8.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/hantro/hantro_vp8.c b/drivers/staging/media/hantro/hantro_vp8.c index 0e02d147b189..91ec9a05645b 100644 --- a/drivers/staging/media/hantro/hantro_vp8.c +++ b/drivers/staging/media/hantro/hantro_vp8.c @@ -23,11 +23,11 @@ struct vp8_prob_tbl_packed { u8 padding1; /* mv prob */ - u8 prob_mv_context[2][19]; + u8 prob_mv_context[2][V4L2_VP8_MV_PROB_CNT]; u8 padding2[2]; /* coeff probs */ - u8 prob_coeffs[4][8][3][11]; + u8 prob_coeffs[4][8][3][V4L2_VP8_COEFF_PROB_CNT]; u8 padding3[96]; }; -- cgit v1.2.3 From 3c39a16d30d8d1bcbd3602a967735b98318c0993 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Tue, 10 Nov 2020 23:35:40 +0100 Subject: media: cedrus: Add support for VP8 decoding VP8 in Cedrus shares same engine as H264. Note that it seems necessary to call bitstream parsing functions, to parse frame header, otherwise decoded image is garbage. This is contrary to what is driver supposed to do. However, values are not really used, so this might be acceptable. It's possible that bitstream parsing functions set some internal VPU state, which is later necessary for proper decoding. Biggest suspect is "VP8 probs update" trigger. Signed-off-by: Jernej Skrabec Signed-off-by: Emmanuel Gil Peyrot Reviewed-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/sunxi/cedrus/Makefile | 3 +- drivers/staging/media/sunxi/cedrus/cedrus.c | 8 + drivers/staging/media/sunxi/cedrus/cedrus.h | 24 + drivers/staging/media/sunxi/cedrus/cedrus_dec.c | 5 + drivers/staging/media/sunxi/cedrus/cedrus_hw.c | 2 + drivers/staging/media/sunxi/cedrus/cedrus_regs.h | 80 ++ drivers/staging/media/sunxi/cedrus/cedrus_video.c | 9 + drivers/staging/media/sunxi/cedrus/cedrus_vp8.c | 907 ++++++++++++++++++++++ 8 files changed, 1037 insertions(+), 1 deletion(-) create mode 100644 drivers/staging/media/sunxi/cedrus/cedrus_vp8.c diff --git a/drivers/staging/media/sunxi/cedrus/Makefile b/drivers/staging/media/sunxi/cedrus/Makefile index 1bce49d3e7e2..a647b3690bf8 100644 --- a/drivers/staging/media/sunxi/cedrus/Makefile +++ b/drivers/staging/media/sunxi/cedrus/Makefile @@ -2,4 +2,5 @@ obj-$(CONFIG_VIDEO_SUNXI_CEDRUS) += sunxi-cedrus.o sunxi-cedrus-y = cedrus.o cedrus_video.o cedrus_hw.o cedrus_dec.o \ - cedrus_mpeg2.o cedrus_h264.o cedrus_h265.o + cedrus_mpeg2.o cedrus_h264.o cedrus_h265.o \ + cedrus_vp8.o diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index ee4e21b29374..dce7cbc95872 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -142,6 +142,13 @@ static const struct cedrus_control cedrus_controls[] = { .codec = CEDRUS_CODEC_H265, .required = false, }, + { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER, + }, + .codec = CEDRUS_CODEC_VP8, + .required = true, + }, }; #define CEDRUS_CONTROLS_COUNT ARRAY_SIZE(cedrus_controls) @@ -393,6 +400,7 @@ static int cedrus_probe(struct platform_device *pdev) dev->dec_ops[CEDRUS_CODEC_MPEG2] = &cedrus_dec_ops_mpeg2; dev->dec_ops[CEDRUS_CODEC_H264] = &cedrus_dec_ops_h264; dev->dec_ops[CEDRUS_CODEC_H265] = &cedrus_dec_ops_h265; + dev->dec_ops[CEDRUS_CODEC_VP8] = &cedrus_dec_ops_vp8; mutex_init(&dev->dev_mutex); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h index 30cdb15d6800..0bf1cbddac9c 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h @@ -22,6 +22,7 @@ #include #include +#include #include #define CEDRUS_NAME "cedrus" @@ -37,6 +38,7 @@ enum cedrus_codec { CEDRUS_CODEC_MPEG2, CEDRUS_CODEC_H264, CEDRUS_CODEC_H265, + CEDRUS_CODEC_VP8, CEDRUS_CODEC_LAST, }; @@ -78,6 +80,10 @@ struct cedrus_h265_run { const struct v4l2_ctrl_hevc_slice_params *slice_params; }; +struct cedrus_vp8_run { + const struct v4l2_ctrl_vp8_frame_header *frame_params; +}; + struct cedrus_run { struct vb2_v4l2_buffer *src; struct vb2_v4l2_buffer *dst; @@ -86,6 +92,7 @@ struct cedrus_run { struct cedrus_h264_run h264; struct cedrus_mpeg2_run mpeg2; struct cedrus_h265_run h265; + struct cedrus_vp8_run vp8; }; }; @@ -137,6 +144,14 @@ struct cedrus_ctx { void *neighbor_info_buf; dma_addr_t neighbor_info_buf_addr; } h265; + struct { + unsigned int last_frame_p_type; + unsigned int last_filter_type; + unsigned int last_sharpness_level; + + u8 *entropy_probs_buf; + dma_addr_t entropy_probs_buf_dma; + } vp8; } codec; }; @@ -183,6 +198,7 @@ struct cedrus_dev { extern struct cedrus_dec_ops cedrus_dec_ops_mpeg2; extern struct cedrus_dec_ops cedrus_dec_ops_h264; extern struct cedrus_dec_ops cedrus_dec_ops_h265; +extern struct cedrus_dec_ops cedrus_dec_ops_vp8; static inline void cedrus_write(struct cedrus_dev *dev, u32 reg, u32 val) { @@ -194,6 +210,14 @@ static inline u32 cedrus_read(struct cedrus_dev *dev, u32 reg) return readl(dev->base + reg); } +static inline u32 cedrus_wait_for(struct cedrus_dev *dev, u32 reg, u32 flag) +{ + u32 value; + + return readl_poll_timeout_atomic(dev->base + reg, value, + (value & flag) == 0, 10, 1000); +} + static inline dma_addr_t cedrus_buf_addr(struct vb2_buffer *buf, struct v4l2_pix_format *pix_fmt, unsigned int plane) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c index 6385026d1b6b..1810fb6cc8da 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c @@ -70,6 +70,11 @@ void cedrus_device_run(void *priv) V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS); break; + case V4L2_PIX_FMT_VP8_FRAME: + run.vp8.frame_params = cedrus_find_control_data(ctx, + V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER); + break; + default: break; } diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c index bcf050a04ffc..111cb91f8fc2 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c @@ -47,7 +47,9 @@ int cedrus_engine_enable(struct cedrus_ctx *ctx, enum cedrus_codec codec) reg |= VE_MODE_DEC_MPEG; break; + /* H.264 and VP8 both use the same decoding mode bit. */ case CEDRUS_CODEC_H264: + case CEDRUS_CODEC_VP8: reg |= VE_MODE_DEC_H264; break; diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h index 66b152f18d17..7718c561823f 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h @@ -546,6 +546,7 @@ #define VE_H264_SHS_QP_SCALING_MATRIX_DEFAULT BIT(24) #define VE_H264_CTRL 0x220 +#define VE_H264_CTRL_VP8 BIT(29) #define VE_H264_CTRL_VLD_DATA_REQ_INT BIT(2) #define VE_H264_CTRL_DECODE_ERR_INT BIT(1) #define VE_H264_CTRL_SLICE_DECODE_INT BIT(0) @@ -555,7 +556,12 @@ VE_H264_CTRL_SLICE_DECODE_INT) #define VE_H264_TRIGGER_TYPE 0x224 +#define VE_H264_TRIGGER_TYPE_PROBABILITY(x) SHIFT_AND_MASK_BITS(x, 31, 24) +#define VE_H264_TRIGGER_TYPE_BIN_LENS(x) SHIFT_AND_MASK_BITS((x) - 1, 18, 16) #define VE_H264_TRIGGER_TYPE_N_BITS(x) (((x) & 0x3f) << 8) +#define VE_H264_TRIGGER_TYPE_VP8_GET_BITS (15 << 0) +#define VE_H264_TRIGGER_TYPE_VP8_UPDATE_COEF (14 << 0) +#define VE_H264_TRIGGER_TYPE_VP8_SLICE_DECODE (10 << 0) #define VE_H264_TRIGGER_TYPE_AVC_SLICE_DECODE (8 << 0) #define VE_H264_TRIGGER_TYPE_INIT_SWDEC (7 << 0) #define VE_H264_TRIGGER_TYPE_FLUSH_BITS (3 << 0) @@ -565,6 +571,7 @@ #define VE_H264_STATUS_DECODE_ERR_INT VE_H264_CTRL_DECODE_ERR_INT #define VE_H264_STATUS_SLICE_DECODE_INT VE_H264_CTRL_SLICE_DECODE_INT #define VE_H264_STATUS_VLD_BUSY BIT(8) +#define VE_H264_STATUS_VP8_UPPROB_BUSY BIT(17) #define VE_H264_STATUS_INT_MASK VE_H264_CTRL_INT_MASK @@ -583,10 +590,83 @@ #define VE_H264_OUTPUT_FRAME_IDX 0x24c #define VE_H264_EXTRA_BUFFER1 0x250 #define VE_H264_EXTRA_BUFFER2 0x254 +#define VE_H264_MB_ADDR 0x260 +#define VE_H264_ERROR_CASE 0x2b8 #define VE_H264_BASIC_BITS 0x2dc #define VE_AVC_SRAM_PORT_OFFSET 0x2e0 #define VE_AVC_SRAM_PORT_DATA 0x2e4 +#define VE_VP8_PPS 0x214 +#define VE_VP8_PPS_PIC_TYPE_P_FRAME BIT(31) +#define VE_VP8_PPS_LAST_SHARPNESS_LEVEL(v) SHIFT_AND_MASK_BITS(v, 30, 28) +#define VE_VP8_PPS_LAST_PIC_TYPE_P_FRAME BIT(27) +#define VE_VP8_PPS_ALTREF_SIGN_BIAS BIT(26) +#define VE_VP8_PPS_GOLDEN_SIGN_BIAS BIT(25) +#define VE_VP8_PPS_RELOAD_ENTROPY_PROBS BIT(24) +#define VE_VP8_PPS_REFRESH_ENTROPY_PROBS BIT(23) +#define VE_VP8_PPS_MB_NO_COEFF_SKIP BIT(22) +#define VE_VP8_PPS_TOKEN_PARTITION(v) SHIFT_AND_MASK_BITS(v, 21, 20) +#define VE_VP8_PPS_MODE_REF_LF_DELTA_UPDATE BIT(19) +#define VE_VP8_PPS_MODE_REF_LF_DELTA_ENABLE BIT(18) +#define VE_VP8_PPS_LOOP_FILTER_LEVEL(v) SHIFT_AND_MASK_BITS(v, 17, 12) +#define VE_VP8_PPS_LOOP_FILTER_SIMPLE BIT(11) +#define VE_VP8_PPS_SHARPNESS_LEVEL(v) SHIFT_AND_MASK_BITS(v, 10, 8) +#define VE_VP8_PPS_LAST_LOOP_FILTER_SIMPLE BIT(7) +#define VE_VP8_PPS_SEGMENTATION_ENABLE BIT(6) +#define VE_VP8_PPS_MB_SEGMENT_ABS_DELTA BIT(5) +#define VE_VP8_PPS_UPDATE_MB_SEGMENTATION_MAP BIT(4) +#define VE_VP8_PPS_FULL_PIXEL BIT(3) +#define VE_VP8_PPS_BILINEAR_MC_FILTER BIT(2) +#define VE_VP8_PPS_FILTER_TYPE_SIMPLE BIT(1) +#define VE_VP8_PPS_LPF_DISABLE BIT(0) + +#define VE_VP8_QP_INDEX_DELTA 0x218 +#define VE_VP8_QP_INDEX_DELTA_UVAC(v) SHIFT_AND_MASK_BITS(v, 31, 27) +#define VE_VP8_QP_INDEX_DELTA_UVDC(v) SHIFT_AND_MASK_BITS(v, 26, 22) +#define VE_VP8_QP_INDEX_DELTA_Y2AC(v) SHIFT_AND_MASK_BITS(v, 21, 17) +#define VE_VP8_QP_INDEX_DELTA_Y2DC(v) SHIFT_AND_MASK_BITS(v, 16, 12) +#define VE_VP8_QP_INDEX_DELTA_Y1DC(v) SHIFT_AND_MASK_BITS(v, 11, 7) +#define VE_VP8_QP_INDEX_DELTA_BASE_QINDEX(v) SHIFT_AND_MASK_BITS(v, 6, 0) + +#define VE_VP8_PART_SIZE_OFFSET 0x21c +#define VE_VP8_ENTROPY_PROBS_ADDR 0x250 +#define VE_VP8_FIRST_DATA_PART_LEN 0x254 + +#define VE_VP8_FSIZE 0x258 +#define VE_VP8_FSIZE_WIDTH(w) \ + SHIFT_AND_MASK_BITS(DIV_ROUND_UP(w, 16), 15, 8) +#define VE_VP8_FSIZE_HEIGHT(h) \ + SHIFT_AND_MASK_BITS(DIV_ROUND_UP(h, 16), 7, 0) + +#define VE_VP8_PICSIZE 0x25c +#define VE_VP8_PICSIZE_WIDTH(w) SHIFT_AND_MASK_BITS(w, 27, 16) +#define VE_VP8_PICSIZE_HEIGHT(h) SHIFT_AND_MASK_BITS(h, 11, 0) + +#define VE_VP8_REC_LUMA 0x2ac +#define VE_VP8_FWD_LUMA 0x2b0 +#define VE_VP8_BWD_LUMA 0x2b4 +#define VE_VP8_REC_CHROMA 0x2d0 +#define VE_VP8_FWD_CHROMA 0x2d4 +#define VE_VP8_BWD_CHROMA 0x2d8 +#define VE_VP8_ALT_LUMA 0x2e8 +#define VE_VP8_ALT_CHROMA 0x2ec + +#define VE_VP8_SEGMENT_FEAT_MB_LV0 0x2f0 +#define VE_VP8_SEGMENT_FEAT_MB_LV1 0x2f4 + +#define VE_VP8_SEGMENT3(v) SHIFT_AND_MASK_BITS(v, 31, 24) +#define VE_VP8_SEGMENT2(v) SHIFT_AND_MASK_BITS(v, 23, 16) +#define VE_VP8_SEGMENT1(v) SHIFT_AND_MASK_BITS(v, 15, 8) +#define VE_VP8_SEGMENT0(v) SHIFT_AND_MASK_BITS(v, 7, 0) + +#define VE_VP8_REF_LF_DELTA 0x2f8 +#define VE_VP8_MODE_LF_DELTA 0x2fc + +#define VE_VP8_LF_DELTA3(v) SHIFT_AND_MASK_BITS(v, 30, 24) +#define VE_VP8_LF_DELTA2(v) SHIFT_AND_MASK_BITS(v, 22, 16) +#define VE_VP8_LF_DELTA1(v) SHIFT_AND_MASK_BITS(v, 14, 8) +#define VE_VP8_LF_DELTA0(v) SHIFT_AND_MASK_BITS(v, 6, 0) + #define VE_ISP_INPUT_SIZE 0xa00 #define VE_ISP_INPUT_STRIDE 0xa04 #define VE_ISP_CTRL 0xa08 diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c index bdca23fc214b..8a01e6b9bebb 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c @@ -50,6 +50,10 @@ static struct cedrus_format cedrus_formats[] = { .directions = CEDRUS_DECODE_SRC, .capabilities = CEDRUS_CAPABILITY_H265_DEC, }, + { + .pixelformat = V4L2_PIX_FMT_VP8_FRAME, + .directions = CEDRUS_DECODE_SRC, + }, { .pixelformat = V4L2_PIX_FMT_SUNXI_TILED_NV12, .directions = CEDRUS_DECODE_DST, @@ -112,6 +116,7 @@ void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt) case V4L2_PIX_FMT_MPEG2_SLICE: case V4L2_PIX_FMT_H264_SLICE: case V4L2_PIX_FMT_HEVC_SLICE: + case V4L2_PIX_FMT_VP8_FRAME: /* Zero bytes per line for encoded source. */ bytesperline = 0; /* Choose some minimum size since this can't be 0 */ @@ -475,6 +480,10 @@ static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count) ctx->current_codec = CEDRUS_CODEC_H265; break; + case V4L2_PIX_FMT_VP8_FRAME: + ctx->current_codec = CEDRUS_CODEC_VP8; + break; + default: return -EINVAL; } diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c b/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c new file mode 100644 index 000000000000..ff613ebd1180 --- /dev/null +++ b/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c @@ -0,0 +1,907 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Cedrus VPU driver + * + * Copyright (c) 2019 Jernej Skrabec + */ + +/* + * VP8 in Cedrus shares same engine as H264. + * + * Note that it seems necessary to call bitstream parsing functions, + * to parse frame header, otherwise decoded image is garbage. This is + * contrary to what is driver supposed to do. However, values are not + * really used, so this might be acceptable. It's possible that bitstream + * parsing functions set some internal VPU state, which is later necessary + * for proper decoding. Biggest suspect is "VP8 probs update" trigger. + */ + +#include +#include + +#include + +#include "cedrus.h" +#include "cedrus_hw.h" +#include "cedrus_regs.h" + +#define CEDRUS_ENTROPY_PROBS_SIZE 0x2400 +#define VP8_PROB_HALF 128 +#define QUANT_DELTA_COUNT 5 + +/* + * This table comes from the concatenation of k_coeff_entropy_update_probs, + * kf_ymode_prob, default_mv_context, etc. It is provided in this form in + * order to avoid computing it every time the driver is initialised, and is + * suitable for direct consumption by the hardware. + */ +static const u8 prob_table_init[] = { + /* k_coeff_entropy_update_probs */ + /* block 0 */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xB0, 0xF6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xDF, 0xF1, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF9, 0xFD, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xF4, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEA, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xF6, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEF, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xF8, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFB, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFB, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFE, 0xFD, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFA, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* block 1 */ + 0xD9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xE1, 0xFC, 0xF1, 0xFD, 0xFF, 0xFF, 0xFE, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEA, 0xFA, 0xF1, 0xFA, 0xFD, 0xFF, 0xFD, 0xFE, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xDF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEE, 0xFD, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xF8, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF9, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF7, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFE, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* block 2 */ + 0xBA, 0xFB, 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEA, 0xFB, 0xF4, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFB, 0xFB, 0xF3, 0xFD, 0xFE, 0xFF, 0xFE, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEC, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFB, 0xFD, 0xFD, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* block 3 */ + 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFA, 0xFE, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF8, 0xFE, 0xF9, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFD, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF6, 0xFD, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFC, 0xFE, 0xFB, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFE, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF8, 0xFE, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFD, 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFB, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF5, 0xFB, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFD, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFC, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF9, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* kf_y_mode_probs */ + 0x91, 0x9C, 0xA3, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* split_mv_probs */ + 0x6E, 0x6F, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* bmode_prob */ + 0x78, 0x5A, 0x4F, 0x85, 0x57, 0x55, 0x50, 0x6F, + 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* sub_mv_ref_prob */ + 0x93, 0x88, 0x12, 0x00, + 0x6A, 0x91, 0x01, 0x00, + 0xB3, 0x79, 0x01, 0x00, + 0xDF, 0x01, 0x22, 0x00, + 0xD0, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* mv_counts_to_probs */ + 0x07, 0x01, 0x01, 0x8F, + 0x0E, 0x12, 0x0E, 0x6B, + 0x87, 0x40, 0x39, 0x44, + 0x3C, 0x38, 0x80, 0x41, + 0x9F, 0x86, 0x80, 0x22, + 0xEA, 0xBC, 0x80, 0x1C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* kf_y_mode_tree */ + 0x84, 0x02, 0x04, 0x06, 0x80, 0x81, 0x82, 0x83, + + /* y_mode_tree */ + 0x80, 0x02, 0x04, 0x06, 0x81, 0x82, 0x83, 0x84, + + /* uv_mode_tree */ + 0x80, 0x02, 0x81, 0x04, 0x82, 0x83, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, + + /* small_mv_tree */ + 0x02, 0x08, 0x04, 0x06, 0x80, 0x81, 0x82, 0x83, + 0x0A, 0x0C, 0x84, 0x85, 0x86, 0x87, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* small_mv_tree again */ + 0x02, 0x08, 0x04, 0x06, 0x80, 0x81, 0x82, 0x83, + 0x0A, 0x0C, 0x84, 0x85, 0x86, 0x87, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* split_mv_tree */ + 0x83, 0x02, 0x82, 0x04, 0x80, 0x81, 0x00, 0x00, + + /* b_mode_tree */ + 0x80, 0x02, 0x81, 0x04, 0x82, 0x06, 0x08, 0x0C, + 0x83, 0x0A, 0x85, 0x86, 0x84, 0x0E, 0x87, 0x10, + 0x88, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* submv_ref_tree */ + 0x8A, 0x02, 0x8B, 0x04, 0x8C, 0x8D, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* mv_ref_tree */ + 0x87, 0x02, 0x85, 0x04, 0x86, 0x06, 0x88, 0x89, +}; + +/* + * This table is a copy of k_mv_entropy_update_probs from the VP8 + * specification. + * + * FIXME: If any other driver uses it, move this table to media/vp8-ctrls.h + */ +static const u8 k_mv_entropy_update_probs[2][V4L2_VP8_MV_PROB_CNT] = { + { 237, 246, 253, 253, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 250, 250, 252, 254, 254 }, + { 231, 243, 245, 253, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 251, 251, 254, 254, 254 } +}; + +static uint8_t read_bits(struct cedrus_dev *dev, unsigned int bits_count, + unsigned int probability) +{ + cedrus_write(dev, VE_H264_TRIGGER_TYPE, + VE_H264_TRIGGER_TYPE_VP8_GET_BITS | + VE_H264_TRIGGER_TYPE_BIN_LENS(bits_count) | + VE_H264_TRIGGER_TYPE_PROBABILITY(probability)); + + cedrus_wait_for(dev, VE_H264_STATUS, VE_H264_STATUS_VLD_BUSY); + + return cedrus_read(dev, VE_H264_BASIC_BITS); +} + +static void get_delta_q(struct cedrus_dev *dev) +{ + if (read_bits(dev, 1, VP8_PROB_HALF)) { + read_bits(dev, 4, VP8_PROB_HALF); + read_bits(dev, 1, VP8_PROB_HALF); + } +} + +static void process_segmentation_info(struct cedrus_dev *dev) +{ + int update, i; + + update = read_bits(dev, 1, VP8_PROB_HALF); + + if (read_bits(dev, 1, VP8_PROB_HALF)) { + read_bits(dev, 1, VP8_PROB_HALF); + + for (i = 0; i < 4; i++) + if (read_bits(dev, 1, VP8_PROB_HALF)) { + read_bits(dev, 7, VP8_PROB_HALF); + read_bits(dev, 1, VP8_PROB_HALF); + } + + for (i = 0; i < 4; i++) + if (read_bits(dev, 1, VP8_PROB_HALF)) { + read_bits(dev, 6, VP8_PROB_HALF); + read_bits(dev, 1, VP8_PROB_HALF); + } + } + + if (update) + for (i = 0; i < 3; i++) + if (read_bits(dev, 1, VP8_PROB_HALF)) + read_bits(dev, 8, VP8_PROB_HALF); +} + +static void process_ref_lf_delta_info(struct cedrus_dev *dev) +{ + if (read_bits(dev, 1, VP8_PROB_HALF)) { + int i; + + for (i = 0; i < 4; i++) + if (read_bits(dev, 1, VP8_PROB_HALF)) { + read_bits(dev, 6, VP8_PROB_HALF); + read_bits(dev, 1, VP8_PROB_HALF); + } + + for (i = 0; i < 4; i++) + if (read_bits(dev, 1, VP8_PROB_HALF)) { + read_bits(dev, 6, VP8_PROB_HALF); + read_bits(dev, 1, VP8_PROB_HALF); + } + } +} + +static void process_ref_frame_info(struct cedrus_dev *dev) +{ + u8 refresh_golden_frame = read_bits(dev, 1, VP8_PROB_HALF); + u8 refresh_alt_ref_frame = read_bits(dev, 1, VP8_PROB_HALF); + + if (!refresh_golden_frame) + read_bits(dev, 2, VP8_PROB_HALF); + + if (!refresh_alt_ref_frame) + read_bits(dev, 2, VP8_PROB_HALF); + + read_bits(dev, 1, VP8_PROB_HALF); + read_bits(dev, 1, VP8_PROB_HALF); +} + +static void cedrus_irq_clear(struct cedrus_dev *dev) +{ + cedrus_write(dev, VE_H264_STATUS, + VE_H264_STATUS_INT_MASK); +} + +static void cedrus_read_header(struct cedrus_dev *dev, + const struct v4l2_ctrl_vp8_frame_header *slice) +{ + int i, j; + + if (VP8_FRAME_IS_KEY_FRAME(slice)) { + read_bits(dev, 1, VP8_PROB_HALF); + read_bits(dev, 1, VP8_PROB_HALF); + } + + if (read_bits(dev, 1, VP8_PROB_HALF)) + process_segmentation_info(dev); + + read_bits(dev, 1, VP8_PROB_HALF); + read_bits(dev, 6, VP8_PROB_HALF); + read_bits(dev, 3, VP8_PROB_HALF); + + if (read_bits(dev, 1, VP8_PROB_HALF)) + process_ref_lf_delta_info(dev); + + read_bits(dev, 2, VP8_PROB_HALF); + + /* y_ac_qi */ + read_bits(dev, 7, VP8_PROB_HALF); + + /* Parses y_dc_delta, y2_dc_delta, etc. */ + for (i = 0; i < QUANT_DELTA_COUNT; i++) + get_delta_q(dev); + + if (!VP8_FRAME_IS_KEY_FRAME(slice)) + process_ref_frame_info(dev); + + read_bits(dev, 1, VP8_PROB_HALF); + + if (!VP8_FRAME_IS_KEY_FRAME(slice)) + read_bits(dev, 1, VP8_PROB_HALF); + + cedrus_write(dev, VE_H264_TRIGGER_TYPE, VE_H264_TRIGGER_TYPE_VP8_UPDATE_COEF); + cedrus_wait_for(dev, VE_H264_STATUS, VE_H264_STATUS_VP8_UPPROB_BUSY); + cedrus_irq_clear(dev); + + if (read_bits(dev, 1, VP8_PROB_HALF)) + read_bits(dev, 8, VP8_PROB_HALF); + + if (!VP8_FRAME_IS_KEY_FRAME(slice)) { + read_bits(dev, 8, VP8_PROB_HALF); + read_bits(dev, 8, VP8_PROB_HALF); + read_bits(dev, 8, VP8_PROB_HALF); + + if (read_bits(dev, 1, VP8_PROB_HALF)) { + read_bits(dev, 8, VP8_PROB_HALF); + read_bits(dev, 8, VP8_PROB_HALF); + read_bits(dev, 8, VP8_PROB_HALF); + read_bits(dev, 8, VP8_PROB_HALF); + } + + if (read_bits(dev, 1, VP8_PROB_HALF)) { + read_bits(dev, 8, VP8_PROB_HALF); + read_bits(dev, 8, VP8_PROB_HALF); + read_bits(dev, 8, VP8_PROB_HALF); + } + + for (i = 0; i < 2; i++) + for (j = 0; j < V4L2_VP8_MV_PROB_CNT; j++) + if (read_bits(dev, 1, k_mv_entropy_update_probs[i][j])) + read_bits(dev, 7, VP8_PROB_HALF); + } +} + +static void cedrus_vp8_update_probs(const struct v4l2_ctrl_vp8_frame_header *slice, + u8 *prob_table) +{ + int i, j, k; + + memcpy(&prob_table[0x1008], slice->entropy_header.y_mode_probs, + sizeof(slice->entropy_header.y_mode_probs)); + memcpy(&prob_table[0x1010], slice->entropy_header.uv_mode_probs, + sizeof(slice->entropy_header.uv_mode_probs)); + + memcpy(&prob_table[0x1018], slice->segment_header.segment_probs, + sizeof(slice->segment_header.segment_probs)); + + prob_table[0x101c] = slice->prob_skip_false; + prob_table[0x101d] = slice->prob_intra; + prob_table[0x101e] = slice->prob_last; + prob_table[0x101f] = slice->prob_gf; + + memcpy(&prob_table[0x1020], slice->entropy_header.mv_probs[0], + V4L2_VP8_MV_PROB_CNT); + memcpy(&prob_table[0x1040], slice->entropy_header.mv_probs[1], + V4L2_VP8_MV_PROB_CNT); + + for (i = 0; i < 4; ++i) + for (j = 0; j < 8; ++j) + for (k = 0; k < 3; ++k) + memcpy(&prob_table[i * 512 + j * 64 + k * 16], + slice->entropy_header.coeff_probs[i][j][k], 11); +} + +static enum cedrus_irq_status +cedrus_vp8_irq_status(struct cedrus_ctx *ctx) +{ + struct cedrus_dev *dev = ctx->dev; + u32 reg = cedrus_read(dev, VE_H264_STATUS); + + if (reg & (VE_H264_STATUS_DECODE_ERR_INT | + VE_H264_STATUS_VLD_DATA_REQ_INT)) + return CEDRUS_IRQ_ERROR; + + if (reg & VE_H264_CTRL_SLICE_DECODE_INT) + return CEDRUS_IRQ_OK; + + return CEDRUS_IRQ_NONE; +} + +static void cedrus_vp8_irq_clear(struct cedrus_ctx *ctx) +{ + cedrus_irq_clear(ctx->dev); +} + +static void cedrus_vp8_irq_disable(struct cedrus_ctx *ctx) +{ + struct cedrus_dev *dev = ctx->dev; + u32 reg = cedrus_read(dev, VE_H264_CTRL); + + cedrus_write(dev, VE_H264_CTRL, + reg & ~VE_H264_CTRL_INT_MASK); +} + +static void cedrus_vp8_setup(struct cedrus_ctx *ctx, + struct cedrus_run *run) +{ + const struct v4l2_ctrl_vp8_frame_header *slice = run->vp8.frame_params; + struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q; + struct vb2_buffer *src_buf = &run->src->vb2_buf; + struct cedrus_dev *dev = ctx->dev; + dma_addr_t luma_addr, chroma_addr; + dma_addr_t src_buf_addr; + int header_size; + int qindex; + u32 reg; + + cedrus_engine_enable(ctx, CEDRUS_CODEC_VP8); + + cedrus_write(dev, VE_H264_CTRL, VE_H264_CTRL_VP8); + + cedrus_vp8_update_probs(slice, ctx->codec.vp8.entropy_probs_buf); + + reg = slice->first_part_size * 8; + cedrus_write(dev, VE_VP8_FIRST_DATA_PART_LEN, reg); + + header_size = VP8_FRAME_IS_KEY_FRAME(slice) ? 10 : 3; + + reg = slice->first_part_size + header_size; + cedrus_write(dev, VE_VP8_PART_SIZE_OFFSET, reg); + + reg = vb2_plane_size(src_buf, 0) * 8; + cedrus_write(dev, VE_H264_VLD_LEN, reg); + + /* + * FIXME: There is a problem if frame header is skipped (adding + * first_part_header_bits to offset). It seems that functions + * for parsing bitstreams change internal state of VPU in some + * way that can't be otherwise set. Maybe this can be bypassed + * by somehow fixing probability table buffer? + */ + reg = header_size * 8; + cedrus_write(dev, VE_H264_VLD_OFFSET, reg); + + src_buf_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); + cedrus_write(dev, VE_H264_VLD_END, + src_buf_addr + vb2_get_plane_payload(src_buf, 0)); + cedrus_write(dev, VE_H264_VLD_ADDR, + VE_H264_VLD_ADDR_VAL(src_buf_addr) | + VE_H264_VLD_ADDR_FIRST | VE_H264_VLD_ADDR_VALID | + VE_H264_VLD_ADDR_LAST); + + cedrus_write(dev, VE_H264_TRIGGER_TYPE, + VE_H264_TRIGGER_TYPE_INIT_SWDEC); + + cedrus_write(dev, VE_VP8_ENTROPY_PROBS_ADDR, + ctx->codec.vp8.entropy_probs_buf_dma); + + reg = 0; + switch (slice->version) { + case 1: + reg |= VE_VP8_PPS_FILTER_TYPE_SIMPLE; + reg |= VE_VP8_PPS_BILINEAR_MC_FILTER; + break; + case 2: + reg |= VE_VP8_PPS_LPF_DISABLE; + reg |= VE_VP8_PPS_BILINEAR_MC_FILTER; + break; + case 3: + reg |= VE_VP8_PPS_LPF_DISABLE; + reg |= VE_VP8_PPS_FULL_PIXEL; + break; + } + if (slice->segment_header.flags & V4L2_VP8_SEGMENT_HEADER_FLAG_UPDATE_MAP) + reg |= VE_VP8_PPS_UPDATE_MB_SEGMENTATION_MAP; + if (!(slice->segment_header.flags & V4L2_VP8_SEGMENT_HEADER_FLAG_DELTA_VALUE_MODE)) + reg |= VE_VP8_PPS_MB_SEGMENT_ABS_DELTA; + if (slice->segment_header.flags & V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED) + reg |= VE_VP8_PPS_SEGMENTATION_ENABLE; + if (ctx->codec.vp8.last_filter_type) + reg |= VE_VP8_PPS_LAST_LOOP_FILTER_SIMPLE; + reg |= VE_VP8_PPS_SHARPNESS_LEVEL(slice->lf_header.sharpness_level); + if (slice->lf_header.flags & V4L2_VP8_LF_FILTER_TYPE_SIMPLE) + reg |= VE_VP8_PPS_LOOP_FILTER_SIMPLE; + reg |= VE_VP8_PPS_LOOP_FILTER_LEVEL(slice->lf_header.level); + if (slice->lf_header.flags & V4L2_VP8_LF_HEADER_ADJ_ENABLE) + reg |= VE_VP8_PPS_MODE_REF_LF_DELTA_ENABLE; + if (slice->lf_header.flags & V4L2_VP8_LF_HEADER_DELTA_UPDATE) + reg |= VE_VP8_PPS_MODE_REF_LF_DELTA_UPDATE; + reg |= VE_VP8_PPS_TOKEN_PARTITION(ilog2(slice->num_dct_parts)); + if (slice->flags & V4L2_VP8_FRAME_HEADER_FLAG_MB_NO_SKIP_COEFF) + reg |= VE_VP8_PPS_MB_NO_COEFF_SKIP; + reg |= VE_VP8_PPS_RELOAD_ENTROPY_PROBS; + if (slice->flags & V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_GOLDEN) + reg |= VE_VP8_PPS_GOLDEN_SIGN_BIAS; + if (slice->flags & V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_ALT) + reg |= VE_VP8_PPS_ALTREF_SIGN_BIAS; + if (ctx->codec.vp8.last_frame_p_type) + reg |= VE_VP8_PPS_LAST_PIC_TYPE_P_FRAME; + reg |= VE_VP8_PPS_LAST_SHARPNESS_LEVEL(ctx->codec.vp8.last_sharpness_level); + if (!(slice->flags & V4L2_VP8_FRAME_HEADER_FLAG_KEY_FRAME)) + reg |= VE_VP8_PPS_PIC_TYPE_P_FRAME; + cedrus_write(dev, VE_VP8_PPS, reg); + + cedrus_read_header(dev, slice); + + /* reset registers changed by HW */ + cedrus_write(dev, VE_H264_CUR_MB_NUM, 0); + cedrus_write(dev, VE_H264_MB_ADDR, 0); + cedrus_write(dev, VE_H264_ERROR_CASE, 0); + + reg = 0; + reg |= VE_VP8_QP_INDEX_DELTA_UVAC(slice->quant_header.uv_ac_delta); + reg |= VE_VP8_QP_INDEX_DELTA_UVDC(slice->quant_header.uv_dc_delta); + reg |= VE_VP8_QP_INDEX_DELTA_Y2AC(slice->quant_header.y2_ac_delta); + reg |= VE_VP8_QP_INDEX_DELTA_Y2DC(slice->quant_header.y2_dc_delta); + reg |= VE_VP8_QP_INDEX_DELTA_Y1DC(slice->quant_header.y_dc_delta); + reg |= VE_VP8_QP_INDEX_DELTA_BASE_QINDEX(slice->quant_header.y_ac_qi); + cedrus_write(dev, VE_VP8_QP_INDEX_DELTA, reg); + + reg = 0; + reg |= VE_VP8_FSIZE_WIDTH(slice->width); + reg |= VE_VP8_FSIZE_HEIGHT(slice->height); + cedrus_write(dev, VE_VP8_FSIZE, reg); + + reg = 0; + reg |= VE_VP8_PICSIZE_WIDTH(slice->width); + reg |= VE_VP8_PICSIZE_HEIGHT(slice->height); + cedrus_write(dev, VE_VP8_PICSIZE, reg); + + reg = 0; + reg |= VE_VP8_SEGMENT3(slice->segment_header.quant_update[3]); + reg |= VE_VP8_SEGMENT2(slice->segment_header.quant_update[2]); + reg |= VE_VP8_SEGMENT1(slice->segment_header.quant_update[1]); + reg |= VE_VP8_SEGMENT0(slice->segment_header.quant_update[0]); + cedrus_write(dev, VE_VP8_SEGMENT_FEAT_MB_LV0, reg); + + reg = 0; + reg |= VE_VP8_SEGMENT3(slice->segment_header.lf_update[3]); + reg |= VE_VP8_SEGMENT2(slice->segment_header.lf_update[2]); + reg |= VE_VP8_SEGMENT1(slice->segment_header.lf_update[1]); + reg |= VE_VP8_SEGMENT0(slice->segment_header.lf_update[0]); + cedrus_write(dev, VE_VP8_SEGMENT_FEAT_MB_LV1, reg); + + reg = 0; + reg |= VE_VP8_LF_DELTA3(slice->lf_header.ref_frm_delta[3]); + reg |= VE_VP8_LF_DELTA2(slice->lf_header.ref_frm_delta[2]); + reg |= VE_VP8_LF_DELTA1(slice->lf_header.ref_frm_delta[1]); + reg |= VE_VP8_LF_DELTA0(slice->lf_header.ref_frm_delta[0]); + cedrus_write(dev, VE_VP8_REF_LF_DELTA, reg); + + reg = 0; + reg |= VE_VP8_LF_DELTA3(slice->lf_header.mb_mode_delta[3]); + reg |= VE_VP8_LF_DELTA2(slice->lf_header.mb_mode_delta[2]); + reg |= VE_VP8_LF_DELTA1(slice->lf_header.mb_mode_delta[1]); + reg |= VE_VP8_LF_DELTA0(slice->lf_header.mb_mode_delta[0]); + cedrus_write(dev, VE_VP8_MODE_LF_DELTA, reg); + + luma_addr = cedrus_dst_buf_addr(ctx, run->dst->vb2_buf.index, 0); + chroma_addr = cedrus_dst_buf_addr(ctx, run->dst->vb2_buf.index, 1); + cedrus_write(dev, VE_VP8_REC_LUMA, luma_addr); + cedrus_write(dev, VE_VP8_REC_CHROMA, chroma_addr); + + qindex = vb2_find_timestamp(cap_q, slice->last_frame_ts, 0); + if (qindex >= 0) { + luma_addr = cedrus_dst_buf_addr(ctx, qindex, 0); + chroma_addr = cedrus_dst_buf_addr(ctx, qindex, 1); + cedrus_write(dev, VE_VP8_FWD_LUMA, luma_addr); + cedrus_write(dev, VE_VP8_FWD_CHROMA, chroma_addr); + } else { + cedrus_write(dev, VE_VP8_FWD_LUMA, 0); + cedrus_write(dev, VE_VP8_FWD_CHROMA, 0); + } + + qindex = vb2_find_timestamp(cap_q, slice->golden_frame_ts, 0); + if (qindex >= 0) { + luma_addr = cedrus_dst_buf_addr(ctx, qindex, 0); + chroma_addr = cedrus_dst_buf_addr(ctx, qindex, 1); + cedrus_write(dev, VE_VP8_BWD_LUMA, luma_addr); + cedrus_write(dev, VE_VP8_BWD_CHROMA, chroma_addr); + } else { + cedrus_write(dev, VE_VP8_BWD_LUMA, 0); + cedrus_write(dev, VE_VP8_BWD_CHROMA, 0); + } + + qindex = vb2_find_timestamp(cap_q, slice->alt_frame_ts, 0); + if (qindex >= 0) { + luma_addr = cedrus_dst_buf_addr(ctx, qindex, 0); + chroma_addr = cedrus_dst_buf_addr(ctx, qindex, 1); + cedrus_write(dev, VE_VP8_ALT_LUMA, luma_addr); + cedrus_write(dev, VE_VP8_ALT_CHROMA, chroma_addr); + } else { + cedrus_write(dev, VE_VP8_ALT_LUMA, 0); + cedrus_write(dev, VE_VP8_ALT_CHROMA, 0); + } + + cedrus_write(dev, VE_H264_CTRL, VE_H264_CTRL_VP8 | + VE_H264_CTRL_DECODE_ERR_INT | + VE_H264_CTRL_SLICE_DECODE_INT); + + if (slice->lf_header.level) { + ctx->codec.vp8.last_filter_type = + !!(slice->lf_header.flags & V4L2_VP8_LF_FILTER_TYPE_SIMPLE); + ctx->codec.vp8.last_frame_p_type = + !VP8_FRAME_IS_KEY_FRAME(slice); + ctx->codec.vp8.last_sharpness_level = + slice->lf_header.sharpness_level; + } +} + +static int cedrus_vp8_start(struct cedrus_ctx *ctx) +{ + struct cedrus_dev *dev = ctx->dev; + + ctx->codec.vp8.entropy_probs_buf = + dma_alloc_coherent(dev->dev, CEDRUS_ENTROPY_PROBS_SIZE, + &ctx->codec.vp8.entropy_probs_buf_dma, + GFP_KERNEL); + if (!ctx->codec.vp8.entropy_probs_buf) + return -ENOMEM; + + /* + * This offset has been discovered by reverse engineering, we don’t know + * what it actually means. + */ + memcpy(&ctx->codec.vp8.entropy_probs_buf[2048], + prob_table_init, sizeof(prob_table_init)); + + return 0; +} + +static void cedrus_vp8_stop(struct cedrus_ctx *ctx) +{ + struct cedrus_dev *dev = ctx->dev; + + cedrus_engine_disable(dev); + + dma_free_coherent(dev->dev, CEDRUS_ENTROPY_PROBS_SIZE, + ctx->codec.vp8.entropy_probs_buf, + ctx->codec.vp8.entropy_probs_buf_dma); +} + +static void cedrus_vp8_trigger(struct cedrus_ctx *ctx) +{ + struct cedrus_dev *dev = ctx->dev; + + cedrus_write(dev, VE_H264_TRIGGER_TYPE, + VE_H264_TRIGGER_TYPE_VP8_SLICE_DECODE); +} + +struct cedrus_dec_ops cedrus_dec_ops_vp8 = { + .irq_clear = cedrus_vp8_irq_clear, + .irq_disable = cedrus_vp8_irq_disable, + .irq_status = cedrus_vp8_irq_status, + .setup = cedrus_vp8_setup, + .start = cedrus_vp8_start, + .stop = cedrus_vp8_stop, + .trigger = cedrus_vp8_trigger, +}; -- cgit v1.2.3 From 0862d95b437b7687622bfc274e410549853825c3 Mon Sep 17 00:00:00 2001 From: Baskov Evgeniy Date: Fri, 13 Nov 2020 17:06:25 +0100 Subject: media: s5p-jpeg: handle error condition in s5p_jpeg_probe If an error happens in jpeg_get_drv_data(), i.e. match fails, jpeg->variant field is NULL, so we cannot access it. Consider device probe failed if jpeg->variant is NULL. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Baskov Evgeniy Acked-by: Andrzej Pietrasiewicz Acked-by: Jacek Anaszewski Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-jpeg/jpeg-core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index 9b22dd8e34f4..026111505f5a 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -2862,6 +2862,8 @@ static int s5p_jpeg_probe(struct platform_device *pdev) return -ENOMEM; jpeg->variant = jpeg_get_drv_data(&pdev->dev); + if (!jpeg->variant) + return -ENODEV; mutex_init(&jpeg->lock); spin_lock_init(&jpeg->slock); -- cgit v1.2.3 From 28c1e371c2ff445162ca6de9a81463351d9e137d Mon Sep 17 00:00:00 2001 From: Christian Hewitt Date: Mon, 16 Nov 2020 05:30:55 +0100 Subject: media: meson: vdec: add G12/SM1 to module description The meson vdec driver also supports Amlogic G12/SM1 hardware. Signed-off-by: Christian Hewitt Reviewed-by: Neil Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/meson/vdec/vdec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c index 5ccb3846c879..5d4db7a5b4b5 100644 --- a/drivers/staging/media/meson/vdec/vdec.c +++ b/drivers/staging/media/meson/vdec/vdec.c @@ -1131,6 +1131,6 @@ static struct platform_driver meson_vdec_driver = { }; module_platform_driver(meson_vdec_driver); -MODULE_DESCRIPTION("Meson video decoder driver for GXBB/GXL/GXM"); +MODULE_DESCRIPTION("Meson video decoder driver for GXBB/GXL/GXM/G12/SM1"); MODULE_AUTHOR("Maxime Jourdan "); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 8e4d86e241cf035d6d3467cd346e7ce490681937 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 17 Nov 2020 08:23:40 +0100 Subject: media: saa7146: fix array overflow in vidioc_s_audio() The "a->index" value comes from the user via the ioctl. The problem is that the shift can wrap resulting in setting "mxb->cur_audinput" to an invalid value, which later results in an array overflow. Fixes: 6680427791c9 ("[media] mxb: fix audio handling") Signed-off-by: Dan Carpenter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7146/mxb.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c index 129a1f8ebe1a..73fc901ecf3d 100644 --- a/drivers/media/pci/saa7146/mxb.c +++ b/drivers/media/pci/saa7146/mxb.c @@ -641,16 +641,17 @@ static int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio * struct mxb *mxb = (struct mxb *)dev->ext_priv; DEB_D("VIDIOC_S_AUDIO %d\n", a->index); - if (mxb_inputs[mxb->cur_input].audioset & (1 << a->index)) { - if (mxb->cur_audinput != a->index) { - mxb->cur_audinput = a->index; - tea6420_route(mxb, a->index); - if (mxb->cur_audinput == 0) - mxb_update_audmode(mxb); - } - return 0; + if (a->index >= 32 || + !(mxb_inputs[mxb->cur_input].audioset & (1 << a->index))) + return -EINVAL; + + if (mxb->cur_audinput != a->index) { + mxb->cur_audinput = a->index; + tea6420_route(mxb, a->index); + if (mxb->cur_audinput == 0) + mxb_update_audmode(mxb); } - return -EINVAL; + return 0; } #ifdef CONFIG_VIDEO_ADV_DEBUG -- cgit v1.2.3 From 4deff542d70aa8ffe83cf6de0e14b4e0cb24b95b Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Sun, 22 Nov 2020 17:30:48 +0100 Subject: media: adv748x: Only set i2c addresses once during probe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During probe the i2c slave addresses are set two times in a row, once in adv748x_initialise_clients() and once directly after in adv748x_reset(). Remove the call to adv748x_set_slave_addresses() in adv748x_initialise_clients() as it's only called during probe while adv748x_reset() is called during probe and normal operation. Signed-off-by: Niklas Söderlund Reviewed-by: Kieran Bingham Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv748x/adv748x-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c index ae8b7ebf3830..00966fe10488 100644 --- a/drivers/media/i2c/adv748x/adv748x-core.c +++ b/drivers/media/i2c/adv748x/adv748x-core.c @@ -198,7 +198,7 @@ static int adv748x_initialise_clients(struct adv748x_state *state) return ret; } - return adv748x_set_slave_addresses(state); + return 0; } /** -- cgit v1.2.3 From c30ed81afe890eb021cb4737fa82c127817b5e69 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Sun, 22 Nov 2020 17:36:35 +0100 Subject: media: adv748x: afe: Select input port when device is reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's not enough to select the AFE input port during probe: it also needs to be set when the device is reset. Move the port selection to adv748x_reset() that is called during probe and when the device needs to be reset. Signed-off-by: Niklas Söderlund Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv748x/adv748x-afe.c | 6 +----- drivers/media/i2c/adv748x/adv748x-core.c | 4 ++++ drivers/media/i2c/adv748x/adv748x.h | 1 + 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/adv748x/adv748x-afe.c b/drivers/media/i2c/adv748x/adv748x-afe.c index dbbb1e4d6363..4052cf67bf16 100644 --- a/drivers/media/i2c/adv748x/adv748x-afe.c +++ b/drivers/media/i2c/adv748x/adv748x-afe.c @@ -154,7 +154,7 @@ static void adv748x_afe_set_video_standard(struct adv748x_state *state, (sdpstd & 0xf) << ADV748X_SDP_VID_SEL_SHIFT); } -static int adv748x_afe_s_input(struct adv748x_afe *afe, unsigned int input) +int adv748x_afe_s_input(struct adv748x_afe *afe, unsigned int input) { struct adv748x_state *state = adv748x_afe_to_state(afe); @@ -520,10 +520,6 @@ int adv748x_afe_init(struct adv748x_afe *afe) } } - adv748x_afe_s_input(afe, afe->input); - - adv_dbg(state, "AFE Default input set to %d\n", afe->input); - /* Entity pads and sinks are 0-indexed to match the pads */ for (i = ADV748X_AFE_SINK_AIN0; i <= ADV748X_AFE_SINK_AIN7; i++) afe->pads[i].flags = MEDIA_PAD_FL_SINK; diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c index 00966fe10488..8676ad242885 100644 --- a/drivers/media/i2c/adv748x/adv748x-core.c +++ b/drivers/media/i2c/adv748x/adv748x-core.c @@ -516,6 +516,10 @@ static int adv748x_reset(struct adv748x_state *state) if (ret) return ret; + adv748x_afe_s_input(&state->afe, state->afe.input); + + adv_dbg(state, "AFE Default input set to %d\n", state->afe.input); + /* Reset TXA and TXB */ adv748x_tx_power(&state->txa, 1); adv748x_tx_power(&state->txa, 0); diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h index 1061f425ece5..747947ea3e31 100644 --- a/drivers/media/i2c/adv748x/adv748x.h +++ b/drivers/media/i2c/adv748x/adv748x.h @@ -435,6 +435,7 @@ int adv748x_tx_power(struct adv748x_csi2 *tx, bool on); int adv748x_afe_init(struct adv748x_afe *afe); void adv748x_afe_cleanup(struct adv748x_afe *afe); +int adv748x_afe_s_input(struct adv748x_afe *afe, unsigned int input); int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx); void adv748x_csi2_cleanup(struct adv748x_csi2 *tx); -- cgit v1.2.3 From 42bff048f4055f2865b77f4cdd8a0b0e209a9397 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Sun, 22 Nov 2020 17:36:36 +0100 Subject: media: adv748x: csi2: Set virtual channel when device is reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's not enough to set the CSI-2 virtual channel for TXA and TXB during probe: it also needs to be set when the device is reset. Move the virtual channel selection to adv748x_reset() that is called during probe and when the device needs to be reset. Signed-off-by: Niklas Söderlund Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv748x/adv748x-core.c | 8 ++++++-- drivers/media/i2c/adv748x/adv748x-csi2.c | 6 +----- drivers/media/i2c/adv748x/adv748x.h | 1 + 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c index 8676ad242885..b578a01cfebe 100644 --- a/drivers/media/i2c/adv748x/adv748x-core.c +++ b/drivers/media/i2c/adv748x/adv748x-core.c @@ -530,10 +530,14 @@ static int adv748x_reset(struct adv748x_state *state) io_write(state, ADV748X_IO_PD, ADV748X_IO_PD_RX_EN); /* Conditionally enable TXa and TXb. */ - if (is_tx_enabled(&state->txa)) + if (is_tx_enabled(&state->txa)) { regval |= ADV748X_IO_10_CSI4_EN; - if (is_tx_enabled(&state->txb)) + adv748x_csi2_set_virtual_channel(&state->txa, 0); + } + if (is_tx_enabled(&state->txb)) { regval |= ADV748X_IO_10_CSI1_EN; + adv748x_csi2_set_virtual_channel(&state->txb, 0); + } io_write(state, ADV748X_IO_10, regval); /* Use vid_std and v_freq as freerun resolution for CP */ diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c index 99bb63d05eef..fa9278a08fde 100644 --- a/drivers/media/i2c/adv748x/adv748x-csi2.c +++ b/drivers/media/i2c/adv748x/adv748x-csi2.c @@ -14,8 +14,7 @@ #include "adv748x.h" -static int adv748x_csi2_set_virtual_channel(struct adv748x_csi2 *tx, - unsigned int vc) +int adv748x_csi2_set_virtual_channel(struct adv748x_csi2 *tx, unsigned int vc) { return tx_write(tx, ADV748X_CSI_VC_REF, vc << ADV748X_CSI_VC_REF_SHIFT); } @@ -313,9 +312,6 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx) if (!is_tx_enabled(tx)) return 0; - /* Initialise the virtual channel */ - adv748x_csi2_set_virtual_channel(tx, 0); - adv748x_subdev_init(&tx->sd, state, &adv748x_csi2_ops, MEDIA_ENT_F_VID_IF_BRIDGE, is_txa(tx) ? "txa" : "txb"); diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h index 747947ea3e31..56256c1e8b0d 100644 --- a/drivers/media/i2c/adv748x/adv748x.h +++ b/drivers/media/i2c/adv748x/adv748x.h @@ -439,6 +439,7 @@ int adv748x_afe_s_input(struct adv748x_afe *afe, unsigned int input); int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx); void adv748x_csi2_cleanup(struct adv748x_csi2 *tx); +int adv748x_csi2_set_virtual_channel(struct adv748x_csi2 *tx, unsigned int vc); int adv748x_csi2_set_pixelrate(struct v4l2_subdev *sd, s64 rate); int adv748x_hdmi_init(struct adv748x_hdmi *hdmi); -- cgit v1.2.3 From 5e67276638765f8dc2327dcf33c0e1f4d5726b7b Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Sun, 22 Nov 2020 17:36:37 +0100 Subject: media: adv748x: Configure device when resuming from sleep MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the device is powered off (for example during system suspend to ram) the devices loses its configuration, especially the slave i2c mappings and other configuration set at probe time. This renders the device unusable and the only way to recover is to unbind and rebind the device to the driver to run the probe setup again. Add an early resume callback that reinitializes the device and setup the slave i2c address mappings and other probe time configuration. Signed-off-by: Niklas Söderlund Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv748x/adv748x-core.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c index b578a01cfebe..4e54148147b9 100644 --- a/drivers/media/i2c/adv748x/adv748x-core.c +++ b/drivers/media/i2c/adv748x/adv748x-core.c @@ -565,6 +565,18 @@ static int adv748x_identify_chip(struct adv748x_state *state) return 0; } +/* ----------------------------------------------------------------------------- + * Suspend / Resume + */ + +static int __maybe_unused adv748x_resume_early(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adv748x_state *state = i2c_get_clientdata(client); + + return adv748x_reset(state); +} + /* ----------------------------------------------------------------------------- * i2c driver */ @@ -827,10 +839,15 @@ static const struct of_device_id adv748x_of_table[] = { }; MODULE_DEVICE_TABLE(of, adv748x_of_table); +static const struct dev_pm_ops adv748x_pm_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS(NULL, adv748x_resume_early) +}; + static struct i2c_driver adv748x_driver = { .driver = { .name = "adv748x", .of_match_table = adv748x_of_table, + .pm = &adv748x_pm_ops, }, .probe_new = adv748x_probe, .remove = adv748x_remove, -- cgit v1.2.3 From db47622c13ae8e164505866d1f251de64d68e66a Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Tue, 24 Nov 2020 09:41:28 +0100 Subject: media: platform: exynos4-is: remove all references to physical addresses This driver always operates on the DMA/IOVA addresses, so calling them physical addresses is misleading, although when no IOMMU is used they equal each other. Fix this by renaming all such entries to 'addr' and adjusting comments. Signed-off-by: Marek Szyprowski Reviewed-by: Sylwester Nawrocki Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-capture.c | 6 ++--- drivers/media/platform/exynos4-is/fimc-core.c | 28 +++++++++++------------ drivers/media/platform/exynos4-is/fimc-core.h | 18 +++++++-------- drivers/media/platform/exynos4-is/fimc-is.c | 20 ++++++++-------- drivers/media/platform/exynos4-is/fimc-is.h | 6 ++--- drivers/media/platform/exynos4-is/fimc-lite-reg.c | 4 ++-- drivers/media/platform/exynos4-is/fimc-lite.c | 2 +- drivers/media/platform/exynos4-is/fimc-lite.h | 4 ++-- drivers/media/platform/exynos4-is/fimc-m2m.c | 8 +++---- drivers/media/platform/exynos4-is/fimc-reg.c | 18 +++++++-------- drivers/media/platform/exynos4-is/fimc-reg.h | 4 ++-- 11 files changed, 58 insertions(+), 60 deletions(-) diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index 6000a4e789ad..13c838d3f947 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c @@ -201,7 +201,7 @@ void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf) if (!list_empty(&cap->pending_buf_q)) { v_buf = fimc_pending_queue_pop(cap); - fimc_hw_set_output_addr(fimc, &v_buf->paddr, cap->buf_index); + fimc_hw_set_output_addr(fimc, &v_buf->addr, cap->buf_index); v_buf->index = cap->buf_index; /* Move the buffer to the capture active queue */ @@ -410,7 +410,7 @@ static void buffer_queue(struct vb2_buffer *vb) int min_bufs; spin_lock_irqsave(&fimc->slock, flags); - fimc_prepare_addr(ctx, &buf->vb.vb2_buf, &ctx->d_frame, &buf->paddr); + fimc_prepare_addr(ctx, &buf->vb.vb2_buf, &ctx->d_frame, &buf->addr); if (!test_bit(ST_CAPT_SUSPENDED, &fimc->state) && !test_bit(ST_CAPT_STREAM, &fimc->state) && @@ -419,7 +419,7 @@ static void buffer_queue(struct vb2_buffer *vb) int buf_id = (vid_cap->reqbufs_count == 1) ? -1 : vid_cap->buf_index; - fimc_hw_set_output_addr(fimc, &buf->paddr, buf_id); + fimc_hw_set_output_addr(fimc, &buf->addr, buf_id); buf->index = vid_cap->buf_index; fimc_active_queue_add(vid_cap, buf); diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c index db6e548fe08e..bfdee771cef9 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.c +++ b/drivers/media/platform/exynos4-is/fimc-core.c @@ -327,7 +327,7 @@ out: /* The color format (colplanes, memplanes) must be already configured. */ int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, - struct fimc_frame *frame, struct fimc_addr *paddr) + struct fimc_frame *frame, struct fimc_addr *addr) { int ret = 0; u32 pix_size; @@ -340,42 +340,40 @@ int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, dbg("memplanes= %d, colplanes= %d, pix_size= %d", frame->fmt->memplanes, frame->fmt->colplanes, pix_size); - paddr->y = vb2_dma_contig_plane_dma_addr(vb, 0); + addr->y = vb2_dma_contig_plane_dma_addr(vb, 0); if (frame->fmt->memplanes == 1) { switch (frame->fmt->colplanes) { case 1: - paddr->cb = 0; - paddr->cr = 0; + addr->cb = 0; + addr->cr = 0; break; case 2: /* decompose Y into Y/Cb */ - paddr->cb = (u32)(paddr->y + pix_size); - paddr->cr = 0; + addr->cb = (u32)(addr->y + pix_size); + addr->cr = 0; break; case 3: - paddr->cb = (u32)(paddr->y + pix_size); + addr->cb = (u32)(addr->y + pix_size); /* decompose Y into Y/Cb/Cr */ if (FIMC_FMT_YCBCR420 == frame->fmt->color) - paddr->cr = (u32)(paddr->cb - + (pix_size >> 2)); + addr->cr = (u32)(addr->cb + (pix_size >> 2)); else /* 422 */ - paddr->cr = (u32)(paddr->cb - + (pix_size >> 1)); + addr->cr = (u32)(addr->cb + (pix_size >> 1)); break; default: return -EINVAL; } } else if (!frame->fmt->mdataplanes) { if (frame->fmt->memplanes >= 2) - paddr->cb = vb2_dma_contig_plane_dma_addr(vb, 1); + addr->cb = vb2_dma_contig_plane_dma_addr(vb, 1); if (frame->fmt->memplanes == 3) - paddr->cr = vb2_dma_contig_plane_dma_addr(vb, 2); + addr->cr = vb2_dma_contig_plane_dma_addr(vb, 2); } - dbg("PHYS_ADDR: y= 0x%X cb= 0x%X cr= 0x%X ret= %d", - paddr->y, paddr->cb, paddr->cr, ret); + dbg("DMA ADDR: y= 0x%X cb= 0x%X cr= 0x%X ret= %d", + addr->y, addr->cb, addr->cr, ret); return ret; } diff --git a/drivers/media/platform/exynos4-is/fimc-core.h b/drivers/media/platform/exynos4-is/fimc-core.h index e4a56232907a..58b72a052cef 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.h +++ b/drivers/media/platform/exynos4-is/fimc-core.h @@ -202,10 +202,10 @@ struct fimc_scaler { }; /** - * struct fimc_addr - the FIMC physical address set for DMA - * @y: luminance plane physical address - * @cb: Cb plane physical address - * @cr: Cr plane physical address + * struct fimc_addr - the FIMC address set for DMA + * @y: luminance plane address + * @cb: Cb plane address + * @cr: Cr plane address */ struct fimc_addr { u32 y; @@ -217,13 +217,13 @@ struct fimc_addr { * struct fimc_vid_buffer - the driver's video buffer * @vb: v4l videobuf buffer * @list: linked list structure for buffer queue - * @paddr: precalculated physical address set + * @addr: precalculated DMA address set * @index: buffer index for the output DMA engine */ struct fimc_vid_buffer { struct vb2_v4l2_buffer vb; struct list_head list; - struct fimc_addr paddr; + struct fimc_addr addr; int index; }; @@ -239,7 +239,7 @@ struct fimc_vid_buffer { * @height: image pixel weight * @payload: image size in bytes (w x h x bpp) * @bytesperline: bytesperline value for each plane - * @paddr: image frame buffer physical addresses + * @addr: image frame buffer DMA addresses * @dma_offset: DMA offset in bytes * @fmt: fimc color format pointer */ @@ -254,7 +254,7 @@ struct fimc_frame { u32 height; unsigned int payload[VIDEO_MAX_PLANES]; unsigned int bytesperline[VIDEO_MAX_PLANES]; - struct fimc_addr paddr; + struct fimc_addr addr; struct fimc_dma_offset dma_offset; struct fimc_fmt *fmt; u8 alpha; @@ -626,7 +626,7 @@ int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh, int fimc_set_scaler_info(struct fimc_ctx *ctx); int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags); int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, - struct fimc_frame *frame, struct fimc_addr *paddr); + struct fimc_frame *frame, struct fimc_addr *addr); void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f); void fimc_set_yuv_order(struct fimc_ctx *ctx); void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf); diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index 32ab01e89196..972d9601d236 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c @@ -268,7 +268,7 @@ int fimc_is_cpu_set_power(struct fimc_is *is, int on) mcuctl_write(0, is, REG_WDT_ISP); /* Cortex-A5 start address setting */ - mcuctl_write(is->memory.paddr, is, MCUCTL_REG_BBOAR); + mcuctl_write(is->memory.addr, is, MCUCTL_REG_BBOAR); /* Enable and start Cortex-A5 */ pmuisp_write(0x18000, is, REG_PMU_ISP_ARM_OPTION); @@ -335,26 +335,26 @@ static int fimc_is_alloc_cpu_memory(struct fimc_is *is) struct device *dev = &is->pdev->dev; is->memory.vaddr = dma_alloc_coherent(dev, FIMC_IS_CPU_MEM_SIZE, - &is->memory.paddr, GFP_KERNEL); + &is->memory.addr, GFP_KERNEL); if (is->memory.vaddr == NULL) return -ENOMEM; is->memory.size = FIMC_IS_CPU_MEM_SIZE; - dev_info(dev, "FIMC-IS CPU memory base: %#x\n", (u32)is->memory.paddr); + dev_info(dev, "FIMC-IS CPU memory base: %pad\n", &is->memory.addr); - if (((u32)is->memory.paddr) & FIMC_IS_FW_ADDR_MASK) { + if (((u32)is->memory.addr) & FIMC_IS_FW_ADDR_MASK) { dev_err(dev, "invalid firmware memory alignment: %#x\n", - (u32)is->memory.paddr); + (u32)is->memory.addr); dma_free_coherent(dev, is->memory.size, is->memory.vaddr, - is->memory.paddr); + is->memory.addr); return -EIO; } is->is_p_region = (struct is_region *)(is->memory.vaddr + FIMC_IS_CPU_MEM_SIZE - FIMC_IS_REGION_SIZE); - is->is_dma_p_region = is->memory.paddr + + is->is_dma_p_region = is->memory.addr + FIMC_IS_CPU_MEM_SIZE - FIMC_IS_REGION_SIZE; is->is_shared_region = (struct is_share_region *)(is->memory.vaddr + @@ -370,7 +370,7 @@ static void fimc_is_free_cpu_memory(struct fimc_is *is) return; dma_free_coherent(dev, is->memory.size, is->memory.vaddr, - is->memory.paddr); + is->memory.addr); } static void fimc_is_load_firmware(const struct firmware *fw, void *context) @@ -415,7 +415,7 @@ static void fimc_is_load_firmware(const struct firmware *fw, void *context) dev_info(dev, "loaded firmware: %s, rev. %s\n", is->fw.info, is->fw.version); - dev_dbg(dev, "FW size: %zu, paddr: %pad\n", fw->size, &is->memory.paddr); + dev_dbg(dev, "FW size: %zu, DMA addr: %pad\n", fw->size, &is->memory.addr); is->is_shared_region->chip_id = 0xe4412; is->is_shared_region->chip_rev_no = 1; @@ -698,7 +698,7 @@ int fimc_is_hw_initialize(struct fimc_is *is) } pr_debug("shared region: %pad, parameter region: %pad\n", - &is->memory.paddr + FIMC_IS_SHARED_REGION_OFFSET, + &is->memory.addr + FIMC_IS_SHARED_REGION_OFFSET, &is->is_dma_p_region); is->setfile.sub_index = 0; diff --git a/drivers/media/platform/exynos4-is/fimc-is.h b/drivers/media/platform/exynos4-is/fimc-is.h index 7ee96a058d40..ce30b007bc55 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.h +++ b/drivers/media/platform/exynos4-is/fimc-is.h @@ -174,7 +174,7 @@ struct is_af_info { struct fimc_is_firmware { const struct firmware *f_w; - dma_addr_t paddr; + dma_addr_t addr; void *vaddr; unsigned int size; @@ -185,8 +185,8 @@ struct fimc_is_firmware { }; struct fimc_is_memory { - /* physical base address */ - dma_addr_t paddr; + /* DMA base address */ + dma_addr_t addr; /* virtual base address */ void *vaddr; /* total length */ diff --git a/drivers/media/platform/exynos4-is/fimc-lite-reg.c b/drivers/media/platform/exynos4-is/fimc-lite-reg.c index 85f765e0f4e1..57996b4104b4 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite-reg.c +++ b/drivers/media/platform/exynos4-is/fimc-lite-reg.c @@ -272,9 +272,9 @@ void flite_hw_set_dma_buffer(struct fimc_lite *dev, struct flite_buffer *buf) index = buf->index; if (index == 0) - writel(buf->paddr, dev->regs + FLITE_REG_CIOSA); + writel(buf->addr, dev->regs + FLITE_REG_CIOSA); else - writel(buf->paddr, dev->regs + FLITE_REG_CIOSAN(index - 1)); + writel(buf->addr, dev->regs + FLITE_REG_CIOSAN(index - 1)); cfg = readl(dev->regs + FLITE_REG_CIFCNTSEQ); cfg |= BIT(index); diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index fdd0d369b192..fe20af3a7178 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -409,7 +409,7 @@ static void buffer_queue(struct vb2_buffer *vb) unsigned long flags; spin_lock_irqsave(&fimc->slock, flags); - buf->paddr = vb2_dma_contig_plane_dma_addr(vb, 0); + buf->addr = vb2_dma_contig_plane_dma_addr(vb, 0); buf->index = fimc->buf_index++; if (fimc->buf_index >= fimc->reqbufs_count) diff --git a/drivers/media/platform/exynos4-is/fimc-lite.h b/drivers/media/platform/exynos4-is/fimc-lite.h index e6846c5fc9ac..e2d4d628b5aa 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.h +++ b/drivers/media/platform/exynos4-is/fimc-lite.h @@ -93,13 +93,13 @@ struct flite_frame { * struct flite_buffer - video buffer structure * @vb: vb2 buffer * @list: list head for the buffers queue - * @paddr: DMA buffer start address + * @addr: DMA buffer start address * @index: DMA start address register's index */ struct flite_buffer { struct vb2_v4l2_buffer vb; struct list_head list; - dma_addr_t paddr; + dma_addr_t addr; unsigned short index; }; diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c index 4acb179556c4..c9704a147e5c 100644 --- a/drivers/media/platform/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/exynos4-is/fimc-m2m.c @@ -115,12 +115,12 @@ static void fimc_device_run(void *priv) } src_vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - ret = fimc_prepare_addr(ctx, &src_vb->vb2_buf, sf, &sf->paddr); + ret = fimc_prepare_addr(ctx, &src_vb->vb2_buf, sf, &sf->addr); if (ret) goto dma_unlock; dst_vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - ret = fimc_prepare_addr(ctx, &dst_vb->vb2_buf, df, &df->paddr); + ret = fimc_prepare_addr(ctx, &dst_vb->vb2_buf, df, &df->addr); if (ret) goto dma_unlock; @@ -152,8 +152,8 @@ static void fimc_device_run(void *priv) fimc_hw_set_rgb_alpha(ctx); fimc_hw_set_output_path(ctx); } - fimc_hw_set_input_addr(fimc, &sf->paddr); - fimc_hw_set_output_addr(fimc, &df->paddr, -1); + fimc_hw_set_input_addr(fimc, &sf->addr); + fimc_hw_set_output_addr(fimc, &df->addr, -1); fimc_activate_capture(ctx); ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP); diff --git a/drivers/media/platform/exynos4-is/fimc-reg.c b/drivers/media/platform/exynos4-is/fimc-reg.c index 8764999a5fd7..95165a2cc7d1 100644 --- a/drivers/media/platform/exynos4-is/fimc-reg.c +++ b/drivers/media/platform/exynos4-is/fimc-reg.c @@ -526,30 +526,30 @@ void fimc_hw_set_output_path(struct fimc_ctx *ctx) writel(cfg, dev->regs + FIMC_REG_CISCCTRL); } -void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *paddr) +void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *addr) { u32 cfg = readl(dev->regs + FIMC_REG_CIREAL_ISIZE); cfg |= FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS; writel(cfg, dev->regs + FIMC_REG_CIREAL_ISIZE); - writel(paddr->y, dev->regs + FIMC_REG_CIIYSA(0)); - writel(paddr->cb, dev->regs + FIMC_REG_CIICBSA(0)); - writel(paddr->cr, dev->regs + FIMC_REG_CIICRSA(0)); + writel(addr->y, dev->regs + FIMC_REG_CIIYSA(0)); + writel(addr->cb, dev->regs + FIMC_REG_CIICBSA(0)); + writel(addr->cr, dev->regs + FIMC_REG_CIICRSA(0)); cfg &= ~FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS; writel(cfg, dev->regs + FIMC_REG_CIREAL_ISIZE); } void fimc_hw_set_output_addr(struct fimc_dev *dev, - struct fimc_addr *paddr, int index) + struct fimc_addr *addr, int index) { int i = (index == -1) ? 0 : index; do { - writel(paddr->y, dev->regs + FIMC_REG_CIOYSA(i)); - writel(paddr->cb, dev->regs + FIMC_REG_CIOCBSA(i)); - writel(paddr->cr, dev->regs + FIMC_REG_CIOCRSA(i)); + writel(addr->y, dev->regs + FIMC_REG_CIOYSA(i)); + writel(addr->cb, dev->regs + FIMC_REG_CIOCBSA(i)); + writel(addr->cr, dev->regs + FIMC_REG_CIOCRSA(i)); dbg("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X", - i, paddr->y, paddr->cb, paddr->cr); + i, addr->y, addr->cb, addr->cr); } while (index == -1 && ++i < FIMC_MAX_OUT_BUFS); } diff --git a/drivers/media/platform/exynos4-is/fimc-reg.h b/drivers/media/platform/exynos4-is/fimc-reg.h index b81826d04936..d7a62465c14e 100644 --- a/drivers/media/platform/exynos4-is/fimc-reg.h +++ b/drivers/media/platform/exynos4-is/fimc-reg.h @@ -302,8 +302,8 @@ void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx); void fimc_hw_set_in_dma(struct fimc_ctx *ctx); void fimc_hw_set_input_path(struct fimc_ctx *ctx); void fimc_hw_set_output_path(struct fimc_ctx *ctx); -void fimc_hw_set_input_addr(struct fimc_dev *fimc, struct fimc_addr *paddr); -void fimc_hw_set_output_addr(struct fimc_dev *fimc, struct fimc_addr *paddr, +void fimc_hw_set_input_addr(struct fimc_dev *fimc, struct fimc_addr *addr); +void fimc_hw_set_output_addr(struct fimc_dev *fimc, struct fimc_addr *addr, int index); int fimc_hw_set_camera_source(struct fimc_dev *fimc, struct fimc_source_info *cam); -- cgit v1.2.3 From 8e06053d339af3caae1c68435cfdb9ac95b0ff25 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 25 Nov 2020 13:04:47 +0100 Subject: media: fsl-viu: Use the ioread/write32be() accessors Since commit 29d750686331 ("media: fsl-viu: allow building it with COMPILE_TEST") there were several attempts to fix build failures on PPC, MICROBLAZE and M68K. However, such errors are still present as reported by kbuild robot. Fix the problem by using the ioread/write32be() accessors, which build fine on all platforms. Reported-by: kernel test robot Suggested-by: Michael Ellerman Signed-off-by: Fabio Estevam Reviewed-by: Michael Ellerman Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/fsl-viu.c | 119 ++++++++++++++++++--------------------- 1 file changed, 55 insertions(+), 64 deletions(-) diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c index ff625301e777..1f1042d5c865 100644 --- a/drivers/media/platform/fsl-viu.c +++ b/drivers/media/platform/fsl-viu.c @@ -31,12 +31,6 @@ #define DRV_NAME "fsl_viu" #define VIU_VERSION "0.5.1" -/* Allow building this driver with COMPILE_TEST */ -#if !defined(CONFIG_PPC) && !defined(CONFIG_MICROBLAZE) && !defined(CONFIG_M68K) -#define out_be32(v, a) iowrite32be(a, (void __iomem *)v) -#define in_be32(a) ioread32be((void __iomem *)a) -#endif - #define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ #define VIU_VID_MEM_LIMIT 4 /* Video memory limit, in Mb */ @@ -250,8 +244,8 @@ static void viu_start_dma(struct viu_dev *dev) dev->field = 0; /* Enable DMA operation */ - out_be32(&vr->status_cfg, SOFT_RST); - out_be32(&vr->status_cfg, INT_FIELD_EN); + iowrite32be(SOFT_RST, &vr->status_cfg); + iowrite32be(INT_FIELD_EN, &vr->status_cfg); } static void viu_stop_dma(struct viu_dev *dev) @@ -260,27 +254,27 @@ static void viu_stop_dma(struct viu_dev *dev) int cnt = 100; u32 status_cfg; - out_be32(&vr->status_cfg, 0); + iowrite32be(0, &vr->status_cfg); /* Clear pending interrupts */ - status_cfg = in_be32(&vr->status_cfg); + status_cfg = ioread32be(&vr->status_cfg); if (status_cfg & 0x3f0000) - out_be32(&vr->status_cfg, status_cfg & 0x3f0000); + iowrite32be(status_cfg & 0x3f0000, &vr->status_cfg); if (status_cfg & DMA_ACT) { do { - status_cfg = in_be32(&vr->status_cfg); + status_cfg = ioread32be(&vr->status_cfg); if (status_cfg & INT_DMA_END_STATUS) break; } while (cnt--); if (cnt < 0) { /* timed out, issue soft reset */ - out_be32(&vr->status_cfg, SOFT_RST); - out_be32(&vr->status_cfg, 0); + iowrite32be(SOFT_RST, &vr->status_cfg); + iowrite32be(0, &vr->status_cfg); } else { /* clear DMA_END and other pending irqs */ - out_be32(&vr->status_cfg, status_cfg & 0x3f0000); + iowrite32be(status_cfg & 0x3f0000, &vr->status_cfg); } } @@ -434,9 +428,9 @@ inline int buffer_activate(struct viu_dev *dev, struct viu_buf *buf) if (!V4L2_FIELD_HAS_BOTH(buf->vb.field)) reg_val.dma_inc = 0; - out_be32(&vr->dma_inc, reg_val.dma_inc); - out_be32(&vr->picture_count, reg_val.picture_count); - out_be32(&vr->field_base_addr, reg_val.field_base_addr); + iowrite32be(reg_val.dma_inc, &vr->dma_inc); + iowrite32be(reg_val.picture_count, &vr->picture_count); + iowrite32be(reg_val.field_base_addr, &vr->field_base_addr); mod_timer(&dev->vidq.timeout, jiffies + BUFFER_TIMEOUT); return 0; } @@ -696,9 +690,9 @@ static int verify_preview(struct viu_dev *dev, struct v4l2_window *win) inline void viu_activate_overlay(struct viu_reg __iomem *vr) { - out_be32(&vr->field_base_addr, reg_val.field_base_addr); - out_be32(&vr->dma_inc, reg_val.dma_inc); - out_be32(&vr->picture_count, reg_val.picture_count); + iowrite32be(reg_val.field_base_addr, &vr->field_base_addr); + iowrite32be(reg_val.dma_inc, &vr->dma_inc); + iowrite32be(reg_val.picture_count, &vr->picture_count); } static int viu_setup_preview(struct viu_dev *dev, struct viu_fh *fh) @@ -976,14 +970,14 @@ inline void viu_activate_next_buf(struct viu_dev *dev, inline void viu_default_settings(struct viu_reg __iomem *vr) { - out_be32(&vr->luminance, 0x9512A254); - out_be32(&vr->chroma_r, 0x03310000); - out_be32(&vr->chroma_g, 0x06600F38); - out_be32(&vr->chroma_b, 0x00000409); - out_be32(&vr->alpha, 0x000000ff); - out_be32(&vr->req_alarm, 0x00000090); + iowrite32be(0x9512A254, &vr->luminance); + iowrite32be(0x03310000, &vr->chroma_r); + iowrite32be(0x06600F38, &vr->chroma_g); + iowrite32be(0x00000409, &vr->chroma_b); + iowrite32be(0x000000ff, &vr->alpha); + iowrite32be(0x00000090, &vr->req_alarm); dprintk(1, "status reg: 0x%08x, field base: 0x%08x\n", - in_be32(&vr->status_cfg), in_be32(&vr->field_base_addr)); + ioread32be(&vr->status_cfg), ioread32be(&vr->field_base_addr)); } static void viu_overlay_intr(struct viu_dev *dev, u32 status) @@ -1001,17 +995,15 @@ static void viu_overlay_intr(struct viu_dev *dev, u32 status) if (status & FIELD_NO) addr += reg_val.dma_inc; - out_be32(&vr->field_base_addr, addr); - out_be32(&vr->dma_inc, reg_val.dma_inc); - out_be32(&vr->status_cfg, - (status & 0xffc0ffff) | + iowrite32be(addr, &vr->field_base_addr); + iowrite32be(reg_val.dma_inc, &vr->dma_inc); + iowrite32be((status & 0xffc0ffff) | (status & INT_ALL_STATUS) | - reg_val.status_cfg); + reg_val.status_cfg, &vr->status_cfg); } else if (status & INT_VSYNC_STATUS) { - out_be32(&vr->status_cfg, - (status & 0xffc0ffff) | + iowrite32be((status & 0xffc0ffff) | (status & INT_ALL_STATUS) | - reg_val.status_cfg); + reg_val.status_cfg, &vr->status_cfg); } } } @@ -1057,12 +1049,11 @@ static void viu_capture_intr(struct viu_dev *dev, u32 status) dprintk(1, "field 1, 0x%lx, dev field %d\n", (unsigned long)addr, dev->field); } - out_be32(&vr->field_base_addr, addr); - out_be32(&vr->dma_inc, reg_val.dma_inc); - out_be32(&vr->status_cfg, - (status & 0xffc0ffff) | + iowrite32be(addr, &vr->field_base_addr); + iowrite32be(reg_val.dma_inc, &vr->dma_inc); + iowrite32be((status & 0xffc0ffff) | (status & INT_ALL_STATUS) | - reg_val.status_cfg); + reg_val.status_cfg, &vr->status_cfg); return; } } @@ -1074,7 +1065,7 @@ static void viu_capture_intr(struct viu_dev *dev, u32 status) dprintk(1, "viu/0: [%p/%d] 0x%lx/0x%lx: dma complete\n", buf, buf->vb.i, (unsigned long)videobuf_to_dma_contig(&buf->vb), - (unsigned long)in_be32(&vr->field_base_addr)); + (unsigned long)ioread32be(&vr->field_base_addr)); if (waitqueue_active(&buf->vb.done)) { list_del(&buf->vb.queue); @@ -1095,7 +1086,7 @@ static irqreturn_t viu_intr(int irq, void *dev_id) u32 status; u32 error; - status = in_be32(&vr->status_cfg); + status = ioread32be(&vr->status_cfg); if (status & INT_ERROR_STATUS) { dev->irqs.error_irq++; @@ -1104,8 +1095,8 @@ static irqreturn_t viu_intr(int irq, void *dev_id) dprintk(1, "Err: error(%d), times:%d!\n", error >> 4, dev->irqs.error_irq); /* Clear interrupt error bit and error flags */ - out_be32(&vr->status_cfg, - (status & 0xffc0ffff) | INT_ERROR_STATUS); + iowrite32be((status & 0xffc0ffff) | INT_ERROR_STATUS, + &vr->status_cfg); } if (status & INT_DMA_END_STATUS) { @@ -1134,9 +1125,9 @@ static irqreturn_t viu_intr(int irq, void *dev_id) } /* clear all pending irqs */ - status = in_be32(&vr->status_cfg); - out_be32(&vr->status_cfg, - (status & 0xffc0ffff) | (status & INT_ALL_STATUS)); + status = ioread32be(&vr->status_cfg); + iowrite32be((status & 0xffc0ffff) | (status & INT_ALL_STATUS), + &vr->status_cfg); if (dev->ovenable) { viu_overlay_intr(dev, status); @@ -1205,14 +1196,14 @@ static int viu_open(struct file *file) viu_default_settings(vr); - status_cfg = in_be32(&vr->status_cfg); - out_be32(&vr->status_cfg, - status_cfg & ~(INT_VSYNC_EN | INT_HSYNC_EN | + status_cfg = ioread32be(&vr->status_cfg); + iowrite32be(status_cfg & ~(INT_VSYNC_EN | INT_HSYNC_EN | INT_FIELD_EN | INT_VSTART_EN | - INT_DMA_END_EN | INT_ERROR_EN | INT_ECC_EN)); + INT_DMA_END_EN | INT_ERROR_EN | INT_ECC_EN), + &vr->status_cfg); - status_cfg = in_be32(&vr->status_cfg); - out_be32(&vr->status_cfg, status_cfg | INT_ALL_STATUS); + status_cfg = ioread32be(&vr->status_cfg); + iowrite32be(status_cfg | INT_ALL_STATUS, &vr->status_cfg); spin_lock_init(&fh->vbq_lock); videobuf_queue_dma_contig_init(&fh->vb_vidq, &viu_video_qops, @@ -1292,16 +1283,16 @@ static int viu_release(struct file *file) static void viu_reset(struct viu_reg __iomem *reg) { - out_be32(®->status_cfg, 0); - out_be32(®->luminance, 0x9512a254); - out_be32(®->chroma_r, 0x03310000); - out_be32(®->chroma_g, 0x06600f38); - out_be32(®->chroma_b, 0x00000409); - out_be32(®->field_base_addr, 0); - out_be32(®->dma_inc, 0); - out_be32(®->picture_count, 0x01e002d0); - out_be32(®->req_alarm, 0x00000090); - out_be32(®->alpha, 0x000000ff); + iowrite32be(0, ®->status_cfg); + iowrite32be(0x9512a254, ®->luminance); + iowrite32be(0x03310000, ®->chroma_r); + iowrite32be(0x06600f38, ®->chroma_g); + iowrite32be(0x00000409, ®->chroma_b); + iowrite32be(0, ®->field_base_addr); + iowrite32be(0, ®->dma_inc); + iowrite32be(0x01e002d0, ®->picture_count); + iowrite32be(0x00000090, ®->req_alarm); + iowrite32be(0x000000ff, ®->alpha); } static int viu_mmap(struct file *file, struct vm_area_struct *vma) -- cgit v1.2.3 From 7aad6a73cb6256040cef7ec5c8bb6534e44a3f80 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Thu, 26 Nov 2020 08:47:56 +0100 Subject: media: rcar-vin: Remove unused macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VNCSI_IFMD_CSI_CHSEL_MASK is not used: remove it. Signed-off-by: Jacopo Mondi Reviewed-by: Niklas Söderlund Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-dma.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c index 95b7828ee352..7dd91de958ec 100644 --- a/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/rcar-vin/rcar-dma.c @@ -133,7 +133,6 @@ #define VNCSI_IFMD_DES1 (1 << 26) #define VNCSI_IFMD_DES0 (1 << 25) #define VNCSI_IFMD_CSI_CHSEL(n) (((n) & 0xf) << 0) -#define VNCSI_IFMD_CSI_CHSEL_MASK 0xf struct rvin_buffer { struct vb2_v4l2_buffer vb; -- cgit v1.2.3 From 6b94c09f820d6a34d45d9397e99000444fe41cfb Mon Sep 17 00:00:00 2001 From: Peilin Ye Date: Thu, 26 Nov 2020 13:21:48 +0100 Subject: media: rockchip: rkisp1: Fix typos in comments and macro definitions Fix 4 typos under drivers/media/platform/rockchip/rkisp1/ found by checkpatch, including the RKISP1_CIF_MI_{M,S}P_PINGPONG_ENABLE macro definitions. Signed-off-by: Peilin Ye Acked-by: Helen Koike Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c | 4 ++-- drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c index 380582f68ace..5f6c9d1623e4 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c @@ -46,7 +46,7 @@ enum rkisp1_plane { /* * @fourcc: pixel format * @fmt_type: helper filed for pixel format - * @uv_swap: if cb cr swaped, for yuv + * @uv_swap: if cb cr swapped, for yuv * @write_format: defines how YCbCr self picture data is written to memory * @output_format: defines sp output format * @mbus: the mbus code on the src resizer pad that matches the pixel format @@ -870,7 +870,7 @@ static void rkisp1_cap_stream_disable(struct rkisp1_capture *cap) { int ret; - /* Stream should stop in interrupt. If it dosn't, stop it by force. */ + /* Stream should stop in interrupt. If it doesn't, stop it by force. */ cap->is_stopping = true; ret = wait_event_timeout(cap->done, !cap->is_streaming, diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h index 049f6c3a11df..8a8d960a679c 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h @@ -106,8 +106,8 @@ #define RKISP1_CIF_MI_SP_Y_FULL_YUV2RGB BIT(8) #define RKISP1_CIF_MI_SP_CBCR_FULL_YUV2RGB BIT(9) #define RKISP1_CIF_MI_SP_422NONCOSITEED BIT(10) -#define RKISP1_CIF_MI_MP_PINGPONG_ENABEL BIT(11) -#define RKISP1_CIF_MI_SP_PINGPONG_ENABEL BIT(12) +#define RKISP1_CIF_MI_MP_PINGPONG_ENABLE BIT(11) +#define RKISP1_CIF_MI_SP_PINGPONG_ENABLE BIT(12) #define RKISP1_CIF_MI_MP_AUTOUPDATE_ENABLE BIT(13) #define RKISP1_CIF_MI_SP_AUTOUPDATE_ENABLE BIT(14) #define RKISP1_CIF_MI_LAST_PIXEL_SIG_ENABLE BIT(15) -- cgit v1.2.3 From a3d412d4b9f3e1d016cd7c49dfa31a4711c7db90 Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Thu, 26 Nov 2020 16:01:56 +0100 Subject: media: Revert "media: camss: Make use of V4L2_CAP_IO_MC" This reverts commit c90f1178dcac30dee5ddd29ec0513e7589aa866e. The assumption of "Each entry in formats[] table has unique mbus_code" is valid for the RDI entities, but not for the PIX ones. Reverting this patch and creating a new one which handles the PIX entities correctly results in smaller and more straightforward patch than doing the changes on top of the current version. Signed-off-by: Andrey Konovalov Reviewed-by: Robert Foss Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/camss/camss-video.c | 67 +++++-------------------- 1 file changed, 13 insertions(+), 54 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index fbba9e45d732..2dbe6b6e4f40 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -535,16 +535,17 @@ static int video_querycap(struct file *file, void *fh, return 0; } -/* - * Returns the index in the video->formats[] array of the element which - * has the "ndx"th unique value of pixelformat field. - * If not found (no more unique pixelformat's) returns -EINVAL. - */ -static int video_get_unique_pixelformat_by_index(struct camss_video *video, - int ndx) +static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) { + struct camss_video *video = video_drvdata(file); int i, j, k; + if (f->type != video->type) + return -EINVAL; + + if (f->index >= video->nformats) + return -EINVAL; + /* find index "i" of "k"th unique pixelformat in formats array */ k = -1; for (i = 0; i < video->nformats; i++) { @@ -557,53 +558,11 @@ static int video_get_unique_pixelformat_by_index(struct camss_video *video, if (j == i) k++; - if (k == ndx) - return i; - } - - return -EINVAL; -} - -/* - * Returns the index in the video->formats[] array of the element which - * has code equal to mcode. - * If not found returns -EINVAL. - */ -static int video_get_pixelformat_by_mbus_code(struct camss_video *video, - u32 mcode) -{ - int i; - - for (i = 0; i < video->nformats; i++) { - if (video->formats[i].code == mcode) - return i; - } - - return -EINVAL; -} - -static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) -{ - struct camss_video *video = video_drvdata(file); - int i; - - if (f->type != video->type) - return -EINVAL; - - if (f->index >= video->nformats) - return -EINVAL; - - if (f->mbus_code) { - /* Each entry in formats[] table has unique mbus_code */ - if (f->index > 0) - return -EINVAL; - - i = video_get_pixelformat_by_mbus_code(video, f->mbus_code); - } else { - i = video_get_unique_pixelformat_by_index(video, f->index); + if (k == f->index) + break; } - if (i < 0) + if (k < f->index) return -EINVAL; f->pixelformat = video->formats[i].pixelformat; @@ -990,8 +949,8 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev, } vdev->fops = &msm_vid_fops; - vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING - | V4L2_CAP_READWRITE | V4L2_CAP_IO_MC; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE; vdev->ioctl_ops = &msm_vid_ioctl_ops; vdev->release = msm_video_release; vdev->v4l2_dev = v4l2_dev; -- cgit v1.2.3 From dfb5d32897167cc4e6c833d3d360b48cd9343d5e Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Thu, 26 Nov 2020 16:01:57 +0100 Subject: media: camss: Make use of V4L2_CAP_IO_MC Implement mbus_code filtering for format enumeration. Without this patch libcamera errors out with: "ERROR V4L2 v4l2_videodevice.cpp:982 /dev/video0[cap]: Media bus code filtering not supported by the device" This is the second version of this change which handles the case of several pixel formats corresponding to one media bus format correctly. Signed-off-by: Andrey Konovalov Reviewed-by: Robert Foss Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/camss/camss-video.c | 28 ++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index 2dbe6b6e4f40..bd9334af1c73 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -539,6 +539,7 @@ static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) { struct camss_video *video = video_drvdata(file); int i, j, k; + u32 mcode = f->mbus_code; if (f->type != video->type) return -EINVAL; @@ -546,10 +547,26 @@ static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) if (f->index >= video->nformats) return -EINVAL; - /* find index "i" of "k"th unique pixelformat in formats array */ + /* + * Find index "i" of "k"th unique pixelformat in formats array. + * + * If f->mbus_code passed to video_enum_fmt() is not zero, a device + * with V4L2_CAP_IO_MC capability restricts enumeration to only the + * pixel formats that can be produced from that media bus code. + * This is implemented by skipping video->formats[] entries with + * code != f->mbus_code (if f->mbus_code is not zero). + * If the f->mbus_code passed to video_enum_fmt() is not supported, + * -EINVAL is returned. + * If f->mbus_code is zero, all the pixel formats are enumerated. + */ k = -1; for (i = 0; i < video->nformats; i++) { + if (mcode != 0 && video->formats[i].code != mcode) + continue; + for (j = 0; j < i; j++) { + if (mcode != 0 && video->formats[j].code != mcode) + continue; if (video->formats[i].pixelformat == video->formats[j].pixelformat) break; @@ -563,6 +580,11 @@ static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) } if (k < f->index) + /* + * All the unique pixel formats matching the arguments + * have been enumerated (k >= 0 and f->index > 0), or + * no pixel formats match the non-zero f->mbus_code (k == -1). + */ return -EINVAL; f->pixelformat = video->formats[i].pixelformat; @@ -949,8 +971,8 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev, } vdev->fops = &msm_vid_fops; - vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING + | V4L2_CAP_READWRITE | V4L2_CAP_IO_MC; vdev->ioctl_ops = &msm_vid_ioctl_ops; vdev->release = msm_video_release; vdev->v4l2_dev = v4l2_dev; -- cgit v1.2.3 From 9fe46e7946fca0e9444c1481fec01e7bdcf636ea Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 27 Nov 2020 17:09:45 +0100 Subject: media: staging/imx: Increase IMX_MEDIA_EOF_TIMEOUT When trying to capture video on a imx6dl-based board with an ADV7280, the following timeout error is observed: v4l2-ctl --stream-mmap -d /dev/video2 [ 22.792049] ipu1_csi1: EOF timeout VIDIOC_DQBUF: failed: Input/output error Increase the IMX_MEDIA_EOF_TIMEOUT to avoid such problem. Signed-off-by: Fabio Estevam Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx-media.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/imx/imx-media.h b/drivers/staging/media/imx/imx-media.h index f17135158029..c8b6a43d0d7c 100644 --- a/drivers/staging/media/imx/imx-media.h +++ b/drivers/staging/media/imx/imx-media.h @@ -65,7 +65,7 @@ enum { }; /* How long to wait for EOF interrupts in the buffer-capture subdevs */ -#define IMX_MEDIA_EOF_TIMEOUT 1000 +#define IMX_MEDIA_EOF_TIMEOUT 2000 struct imx_media_pixfmt { /* the in-memory FourCC pixel format */ -- cgit v1.2.3 From 5049c15e41c6abceef614810cf2b9454ba5facaa Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Fri, 27 Nov 2020 17:44:08 +0100 Subject: media: si4713: remove trailing semicolon in macro definition The macro use will already have a semicolon. [hverkuil: also add () around p in the macro] Signed-off-by: Tom Rix Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/si4713/si4713.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/radio/si4713/si4713.c b/drivers/media/radio/si4713/si4713.c index 6afa7c3464ab..adbf43ff6a21 100644 --- a/drivers/media/radio/si4713/si4713.c +++ b/drivers/media/radio/si4713/si4713.c @@ -86,7 +86,7 @@ MODULE_VERSION("0.0.1"); #define check_command_failed(status) (!(status & SI4713_CTS) || \ (status & SI4713_ERR)) /* mute definition */ -#define set_mute(p) ((p & 1) | ((p & 1) << 1)); +#define set_mute(p) (((p) & 1) | (((p) & 1) << 1)) #ifdef DEBUG #define DBG_BUFFER(device, message, buffer, size) \ -- cgit v1.2.3 From 0c5a71dc6b8c037b51ad07e0267b9e4eca41652c Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Fri, 27 Nov 2020 21:34:40 +0100 Subject: media: solo6x10: switch from 'pci_' to 'dma_' API The wrappers in include/linux/pci-dma-compat.h should go away. The patch has been generated with the coccinelle script below and has been hand modified to replace GFP_ with a correct flag. It has been compile tested. When memory is allocated in 'snd_solo_pcm_open()' (solo6x10-g723.c) GFP_KERNEL can be used because this flag is already used jew a few lines above. When memory is allocated in 'solo_enc_alloc()' (solo6x10-v4l2-enc.c) GFP_KERNEL can be used because this flag is already used jew a few lines above. When memory is allocated in 'solo_enc_v4l2_init()' (solo6x10-v4l2-enc.c) GFP_KERNEL can be used because calls 'solo_enc_alloc()' which already uses this flag. @@ @@ - PCI_DMA_BIDIRECTIONAL + DMA_BIDIRECTIONAL @@ @@ - PCI_DMA_TODEVICE + DMA_TO_DEVICE @@ @@ - PCI_DMA_FROMDEVICE + DMA_FROM_DEVICE @@ @@ - PCI_DMA_NONE + DMA_NONE @@ expression e1, e2, e3; @@ - pci_alloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3; @@ - pci_zalloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3, e4; @@ - pci_free_consistent(e1, e2, e3, e4) + dma_free_coherent(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_single(e1, e2, e3, e4) + dma_map_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_single(e1, e2, e3, e4) + dma_unmap_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4, e5; @@ - pci_map_page(e1, e2, e3, e4, e5) + dma_map_page(&e1->dev, e2, e3, e4, e5) @@ expression e1, e2, e3, e4; @@ - pci_unmap_page(e1, e2, e3, e4) + dma_unmap_page(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_sg(e1, e2, e3, e4) + dma_map_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_sg(e1, e2, e3, e4) + dma_unmap_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_cpu(e1, e2, e3, e4) + dma_sync_single_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_device(e1, e2, e3, e4) + dma_sync_single_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_cpu(e1, e2, e3, e4) + dma_sync_sg_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_device(e1, e2, e3, e4) + dma_sync_sg_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2; @@ - pci_dma_mapping_error(e1, e2) + dma_mapping_error(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_dma_mask(e1, e2) + dma_set_mask(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_consistent_dma_mask(e1, e2) + dma_set_coherent_mask(&e1->dev, e2) Signed-off-by: Christophe JAILLET Signed-off-by: Ismael Luceno Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/solo6x10/solo6x10-g723.c | 11 ++++---- drivers/media/pci/solo6x10/solo6x10-p2m.c | 10 ++++---- drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c | 35 +++++++++++++------------- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/drivers/media/pci/solo6x10/solo6x10-g723.c b/drivers/media/pci/solo6x10/solo6x10-g723.c index d137b94869d8..6cebad665565 100644 --- a/drivers/media/pci/solo6x10/solo6x10-g723.c +++ b/drivers/media/pci/solo6x10/solo6x10-g723.c @@ -124,9 +124,10 @@ static int snd_solo_pcm_open(struct snd_pcm_substream *ss) if (solo_pcm == NULL) goto oom; - solo_pcm->g723_buf = pci_alloc_consistent(solo_dev->pdev, - G723_PERIOD_BYTES, - &solo_pcm->g723_dma); + solo_pcm->g723_buf = dma_alloc_coherent(&solo_dev->pdev->dev, + G723_PERIOD_BYTES, + &solo_pcm->g723_dma, + GFP_KERNEL); if (solo_pcm->g723_buf == NULL) goto oom; @@ -148,8 +149,8 @@ static int snd_solo_pcm_close(struct snd_pcm_substream *ss) struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss); snd_pcm_substream_chip(ss) = solo_pcm->solo_dev; - pci_free_consistent(solo_pcm->solo_dev->pdev, G723_PERIOD_BYTES, - solo_pcm->g723_buf, solo_pcm->g723_dma); + dma_free_coherent(&solo_pcm->solo_dev->pdev->dev, G723_PERIOD_BYTES, + solo_pcm->g723_buf, solo_pcm->g723_dma); kfree(solo_pcm); return 0; diff --git a/drivers/media/pci/solo6x10/solo6x10-p2m.c b/drivers/media/pci/solo6x10/solo6x10-p2m.c index db2afc6a5fcb..ca70a864a3ef 100644 --- a/drivers/media/pci/solo6x10/solo6x10-p2m.c +++ b/drivers/media/pci/solo6x10/solo6x10-p2m.c @@ -37,16 +37,16 @@ int solo_p2m_dma(struct solo_dev *solo_dev, int wr, if (WARN_ON_ONCE(!size)) return -EINVAL; - dma_addr = pci_map_single(solo_dev->pdev, sys_addr, size, - wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(solo_dev->pdev, dma_addr)) + dma_addr = dma_map_single(&solo_dev->pdev->dev, sys_addr, size, + wr ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + if (dma_mapping_error(&solo_dev->pdev->dev, dma_addr)) return -ENOMEM; ret = solo_p2m_dma_t(solo_dev, wr, dma_addr, ext_addr, size, repeat, ext_size); - pci_unmap_single(solo_dev->pdev, dma_addr, size, - wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); + dma_unmap_single(&solo_dev->pdev->dev, dma_addr, size, + wr ? DMA_TO_DEVICE : DMA_FROM_DEVICE); return ret; } diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c index 3cf7bd6186aa..0abcad4e84fa 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c @@ -1286,10 +1286,11 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, memcpy(solo_enc->jpeg_header, jpeg_header, solo_enc->jpeg_len); solo_enc->desc_nelts = 32; - solo_enc->desc_items = pci_alloc_consistent(solo_dev->pdev, - sizeof(struct solo_p2m_desc) * - solo_enc->desc_nelts, - &solo_enc->desc_dma); + solo_enc->desc_items = dma_alloc_coherent(&solo_dev->pdev->dev, + sizeof(struct solo_p2m_desc) * + solo_enc->desc_nelts, + &solo_enc->desc_dma, + GFP_KERNEL); ret = -ENOMEM; if (solo_enc->desc_items == NULL) goto hdl_free; @@ -1317,9 +1318,9 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, vdev_release: video_device_release(solo_enc->vfd); pci_free: - pci_free_consistent(solo_enc->solo_dev->pdev, - sizeof(struct solo_p2m_desc) * solo_enc->desc_nelts, - solo_enc->desc_items, solo_enc->desc_dma); + dma_free_coherent(&solo_enc->solo_dev->pdev->dev, + sizeof(struct solo_p2m_desc) * solo_enc->desc_nelts, + solo_enc->desc_items, solo_enc->desc_dma); hdl_free: v4l2_ctrl_handler_free(hdl); kfree(solo_enc); @@ -1331,9 +1332,9 @@ static void solo_enc_free(struct solo_enc_dev *solo_enc) if (solo_enc == NULL) return; - pci_free_consistent(solo_enc->solo_dev->pdev, - sizeof(struct solo_p2m_desc) * solo_enc->desc_nelts, - solo_enc->desc_items, solo_enc->desc_dma); + dma_free_coherent(&solo_enc->solo_dev->pdev->dev, + sizeof(struct solo_p2m_desc) * solo_enc->desc_nelts, + solo_enc->desc_items, solo_enc->desc_dma); video_unregister_device(solo_enc->vfd); v4l2_ctrl_handler_free(&solo_enc->hdl); kfree(solo_enc); @@ -1346,9 +1347,9 @@ int solo_enc_v4l2_init(struct solo_dev *solo_dev, unsigned nr) init_waitqueue_head(&solo_dev->ring_thread_wait); solo_dev->vh_size = sizeof(vop_header); - solo_dev->vh_buf = pci_alloc_consistent(solo_dev->pdev, - solo_dev->vh_size, - &solo_dev->vh_dma); + solo_dev->vh_buf = dma_alloc_coherent(&solo_dev->pdev->dev, + solo_dev->vh_size, + &solo_dev->vh_dma, GFP_KERNEL); if (solo_dev->vh_buf == NULL) return -ENOMEM; @@ -1363,8 +1364,8 @@ int solo_enc_v4l2_init(struct solo_dev *solo_dev, unsigned nr) while (i--) solo_enc_free(solo_dev->v4l2_enc[i]); - pci_free_consistent(solo_dev->pdev, solo_dev->vh_size, - solo_dev->vh_buf, solo_dev->vh_dma); + dma_free_coherent(&solo_dev->pdev->dev, solo_dev->vh_size, + solo_dev->vh_buf, solo_dev->vh_dma); solo_dev->vh_buf = NULL; return ret; } @@ -1391,6 +1392,6 @@ void solo_enc_v4l2_exit(struct solo_dev *solo_dev) solo_enc_free(solo_dev->v4l2_enc[i]); if (solo_dev->vh_buf) - pci_free_consistent(solo_dev->pdev, solo_dev->vh_size, - solo_dev->vh_buf, solo_dev->vh_dma); + dma_free_coherent(&solo_dev->pdev->dev, solo_dev->vh_size, + solo_dev->vh_buf, solo_dev->vh_dma); } -- cgit v1.2.3 From 8a9e71e05a22ff22589e1e60c6fb433c96c79e43 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Fri, 27 Nov 2020 21:58:01 +0100 Subject: media: ttpci: switch from 'pci_' to 'dma_' API The wrappers in include/linux/pci-dma-compat.h should go away. The patch has been generated with the coccinelle script below and has been hand modified to replace GFP_ with a correct flag. It has been compile tested. When memory is allocated in 'av7110_attach()' GFP_KERNEL can be used because this flag is already used above in the same function and no lock is taken in the between. @@ @@ - PCI_DMA_BIDIRECTIONAL + DMA_BIDIRECTIONAL @@ @@ - PCI_DMA_TODEVICE + DMA_TO_DEVICE @@ @@ - PCI_DMA_FROMDEVICE + DMA_FROM_DEVICE @@ @@ - PCI_DMA_NONE + DMA_NONE @@ expression e1, e2, e3; @@ - pci_alloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3; @@ - pci_zalloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3, e4; @@ - pci_free_consistent(e1, e2, e3, e4) + dma_free_coherent(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_single(e1, e2, e3, e4) + dma_map_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_single(e1, e2, e3, e4) + dma_unmap_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4, e5; @@ - pci_map_page(e1, e2, e3, e4, e5) + dma_map_page(&e1->dev, e2, e3, e4, e5) @@ expression e1, e2, e3, e4; @@ - pci_unmap_page(e1, e2, e3, e4) + dma_unmap_page(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_sg(e1, e2, e3, e4) + dma_map_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_sg(e1, e2, e3, e4) + dma_unmap_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_cpu(e1, e2, e3, e4) + dma_sync_single_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_device(e1, e2, e3, e4) + dma_sync_single_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_cpu(e1, e2, e3, e4) + dma_sync_sg_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_device(e1, e2, e3, e4) + dma_sync_sg_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2; @@ - pci_dma_mapping_error(e1, e2) + dma_mapping_error(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_dma_mask(e1, e2) + dma_set_mask(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_consistent_dma_mask(e1, e2) + dma_set_coherent_mask(&e1->dev, e2) Signed-off-by: Christophe JAILLET Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ttpci/av7110.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c index 2f7069e19b78..d74ee0ecfb36 100644 --- a/drivers/media/pci/ttpci/av7110.c +++ b/drivers/media/pci/ttpci/av7110.c @@ -1250,7 +1250,8 @@ static void vpeirq(struct tasklet_struct *t) return; /* Ensure streamed PCI data is synced to CPU */ - pci_dma_sync_sg_for_cpu(budget->dev->pci, budget->pt.slist, budget->pt.nents, PCI_DMA_FROMDEVICE); + dma_sync_sg_for_cpu(&budget->dev->pci->dev, budget->pt.slist, + budget->pt.nents, DMA_FROM_DEVICE); #if 0 /* track rps1 activity */ @@ -2637,7 +2638,8 @@ static int av7110_attach(struct saa7146_dev* dev, av7110->arm_thread = NULL; /* allocate and init buffers */ - av7110->debi_virt = pci_alloc_consistent(pdev, 8192, &av7110->debi_bus); + av7110->debi_virt = dma_alloc_coherent(&pdev->dev, 8192, + &av7110->debi_bus, GFP_KERNEL); if (!av7110->debi_virt) goto err_saa71466_vfree_4; @@ -2726,7 +2728,8 @@ err_av7110_av_exit_7: err_iobuf_vfree_6: vfree(av7110->iobuf); err_pci_free_5: - pci_free_consistent(pdev, 8192, av7110->debi_virt, av7110->debi_bus); + dma_free_coherent(&pdev->dev, 8192, av7110->debi_virt, + av7110->debi_bus); err_saa71466_vfree_4: if (av7110->grabbing) saa7146_vfree_destroy_pgtable(pdev, av7110->grabbing, &av7110->pt); @@ -2779,8 +2782,8 @@ static int av7110_detach(struct saa7146_dev* saa) av7110_av_exit(av7110); vfree(av7110->iobuf); - pci_free_consistent(saa->pci, 8192, av7110->debi_virt, - av7110->debi_bus); + dma_free_coherent(&saa->pci->dev, 8192, av7110->debi_virt, + av7110->debi_bus); i2c_del_adapter(&av7110->i2c_adap); -- cgit v1.2.3 From 9c0660e4477a0d33341f8ae6f208db30c57d60bd Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 29 Nov 2020 13:30:11 +0100 Subject: media: saa7146: switch from 'pci_' to 'dma_' API The wrappers in include/linux/pci-dma-compat.h should go away. The patch has been generated with the coccinelle script below and has been hand modified to replace GFP_ with a correct flag. It has been compile tested. When memory is allocated in 'saa7146_pgtable_alloc()' GFP_KERNEL can be used because the callers are either .buf_prepare functions or function that already use GFP_KERNEL (hidden in a 'vmalloc_32()' call). When memory is allocated in 'saa7146_init_one()' GFP_KERNEL can be used because it is probe function and no lock is taken in the between. When memory is allocated in 'saa7146_vv_init()' GFP_KERNEL can be used because this function already uses GFP_KERNEL and no lock is taken in the between. When memory is allocated in 'vbi_workaround()' GFP_KERNEL can be used because it is only called from a .open function. @@ @@ - PCI_DMA_BIDIRECTIONAL + DMA_BIDIRECTIONAL @@ @@ - PCI_DMA_TODEVICE + DMA_TO_DEVICE @@ @@ - PCI_DMA_FROMDEVICE + DMA_FROM_DEVICE @@ @@ - PCI_DMA_NONE + DMA_NONE @@ expression e1, e2, e3; @@ - pci_alloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3; @@ - pci_zalloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3, e4; @@ - pci_free_consistent(e1, e2, e3, e4) + dma_free_coherent(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_single(e1, e2, e3, e4) + dma_map_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_single(e1, e2, e3, e4) + dma_unmap_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4, e5; @@ - pci_map_page(e1, e2, e3, e4, e5) + dma_map_page(&e1->dev, e2, e3, e4, e5) @@ expression e1, e2, e3, e4; @@ - pci_unmap_page(e1, e2, e3, e4) + dma_unmap_page(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_sg(e1, e2, e3, e4) + dma_map_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_sg(e1, e2, e3, e4) + dma_unmap_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_cpu(e1, e2, e3, e4) + dma_sync_single_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_device(e1, e2, e3, e4) + dma_sync_single_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_cpu(e1, e2, e3, e4) + dma_sync_sg_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_device(e1, e2, e3, e4) + dma_sync_sg_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2; @@ - pci_dma_mapping_error(e1, e2) + dma_mapping_error(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_dma_mask(e1, e2) + dma_set_mask(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_consistent_dma_mask(e1, e2) + dma_set_coherent_mask(&e1->dev, e2) Signed-off-by: Christophe JAILLET Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146/saa7146_core.c | 39 ++++++++++++++++------------- drivers/media/common/saa7146/saa7146_fops.c | 7 +++--- drivers/media/common/saa7146/saa7146_vbi.c | 6 ++--- 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/drivers/media/common/saa7146/saa7146_core.c b/drivers/media/common/saa7146/saa7146_core.c index 21fb16cc5ca1..f2d13b71416c 100644 --- a/drivers/media/common/saa7146/saa7146_core.c +++ b/drivers/media/common/saa7146/saa7146_core.c @@ -177,7 +177,7 @@ void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa goto err_free_slist; pt->nents = pages; - slen = pci_map_sg(pci,pt->slist,pt->nents,PCI_DMA_FROMDEVICE); + slen = dma_map_sg(&pci->dev, pt->slist, pt->nents, DMA_FROM_DEVICE); if (0 == slen) goto err_free_pgtable; @@ -187,7 +187,7 @@ void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa return mem; err_unmap_sg: - pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE); + dma_unmap_sg(&pci->dev, pt->slist, pt->nents, DMA_FROM_DEVICE); err_free_pgtable: saa7146_pgtable_free(pci, pt); err_free_slist: @@ -201,7 +201,7 @@ err_null: void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt) { - pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE); + dma_unmap_sg(&pci->dev, pt->slist, pt->nents, DMA_FROM_DEVICE); saa7146_pgtable_free(pci, pt); kfree(pt->slist); pt->slist = NULL; @@ -212,7 +212,7 @@ void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt) { if (NULL == pt->cpu) return; - pci_free_consistent(pci, pt->size, pt->cpu, pt->dma); + dma_free_coherent(&pci->dev, pt->size, pt->cpu, pt->dma); pt->cpu = NULL; } @@ -221,7 +221,7 @@ int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt) __le32 *cpu; dma_addr_t dma_addr = 0; - cpu = pci_alloc_consistent(pci, PAGE_SIZE, &dma_addr); + cpu = dma_alloc_coherent(&pci->dev, PAGE_SIZE, &dma_addr, GFP_KERNEL); if (NULL == cpu) { return -ENOMEM; } @@ -412,18 +412,20 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent err = -ENOMEM; /* get memory for various stuff */ - dev->d_rps0.cpu_addr = pci_zalloc_consistent(pci, SAA7146_RPS_MEM, - &dev->d_rps0.dma_handle); + dev->d_rps0.cpu_addr = dma_alloc_coherent(&pci->dev, SAA7146_RPS_MEM, + &dev->d_rps0.dma_handle, + GFP_KERNEL); if (!dev->d_rps0.cpu_addr) goto err_free_irq; - dev->d_rps1.cpu_addr = pci_zalloc_consistent(pci, SAA7146_RPS_MEM, - &dev->d_rps1.dma_handle); + dev->d_rps1.cpu_addr = dma_alloc_coherent(&pci->dev, SAA7146_RPS_MEM, + &dev->d_rps1.dma_handle, + GFP_KERNEL); if (!dev->d_rps1.cpu_addr) goto err_free_rps0; - dev->d_i2c.cpu_addr = pci_zalloc_consistent(pci, SAA7146_RPS_MEM, - &dev->d_i2c.dma_handle); + dev->d_i2c.cpu_addr = dma_alloc_coherent(&pci->dev, SAA7146_RPS_MEM, + &dev->d_i2c.dma_handle, GFP_KERNEL); if (!dev->d_i2c.cpu_addr) goto err_free_rps1; @@ -471,14 +473,14 @@ out: return err; err_free_i2c: - pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr, - dev->d_i2c.dma_handle); + dma_free_coherent(&pci->dev, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr, + dev->d_i2c.dma_handle); err_free_rps1: - pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps1.cpu_addr, - dev->d_rps1.dma_handle); + dma_free_coherent(&pci->dev, SAA7146_RPS_MEM, dev->d_rps1.cpu_addr, + dev->d_rps1.dma_handle); err_free_rps0: - pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps0.cpu_addr, - dev->d_rps0.dma_handle); + dma_free_coherent(&pci->dev, SAA7146_RPS_MEM, dev->d_rps0.cpu_addr, + dev->d_rps0.dma_handle); err_free_irq: free_irq(pci->irq, (void *)dev); err_unmap: @@ -519,7 +521,8 @@ static void saa7146_remove_one(struct pci_dev *pdev) free_irq(pdev->irq, dev); for (p = dev_map; p->addr; p++) - pci_free_consistent(pdev, SAA7146_RPS_MEM, p->addr, p->dma); + dma_free_coherent(&pdev->dev, SAA7146_RPS_MEM, p->addr, + p->dma); iounmap(dev->mem); pci_release_region(pdev, 0); diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c index e936c56b0378..baf5772c52a9 100644 --- a/drivers/media/common/saa7146/saa7146_fops.c +++ b/drivers/media/common/saa7146/saa7146_fops.c @@ -515,8 +515,8 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv) dev->ext_vv_data = ext_vv; vv->d_clipping.cpu_addr = - pci_zalloc_consistent(dev->pci, SAA7146_CLIPPING_MEM, - &vv->d_clipping.dma_handle); + dma_alloc_coherent(&dev->pci->dev, SAA7146_CLIPPING_MEM, + &vv->d_clipping.dma_handle, GFP_KERNEL); if( NULL == vv->d_clipping.cpu_addr ) { ERR("out of memory. aborting.\n"); kfree(vv); @@ -574,7 +574,8 @@ int saa7146_vv_release(struct saa7146_dev* dev) DEB_EE("dev:%p\n", dev); v4l2_device_unregister(&dev->v4l2_dev); - pci_free_consistent(dev->pci, SAA7146_CLIPPING_MEM, vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle); + dma_free_coherent(&dev->pci->dev, SAA7146_CLIPPING_MEM, + vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle); v4l2_ctrl_handler_free(&dev->ctrl_handler); kfree(vv); dev->vv_data = NULL; diff --git a/drivers/media/common/saa7146/saa7146_vbi.c b/drivers/media/common/saa7146/saa7146_vbi.c index e1d369b976ed..bd442b984423 100644 --- a/drivers/media/common/saa7146/saa7146_vbi.c +++ b/drivers/media/common/saa7146/saa7146_vbi.c @@ -22,7 +22,7 @@ static int vbi_workaround(struct saa7146_dev *dev) as specified. there is this workaround, but please don't let me explain it. ;-) */ - cpu = pci_alloc_consistent(dev->pci, 4096, &dma_addr); + cpu = dma_alloc_coherent(&dev->pci->dev, 4096, &dma_addr, GFP_KERNEL); if (NULL == cpu) return -ENOMEM; @@ -123,12 +123,12 @@ static int vbi_workaround(struct saa7146_dev *dev) /* stop rps1 for sure */ saa7146_write(dev, MC1, MASK_29); - pci_free_consistent(dev->pci, 4096, cpu, dma_addr); + dma_free_coherent(&dev->pci->dev, 4096, cpu, dma_addr); return -EINTR; } } - pci_free_consistent(dev->pci, 4096, cpu, dma_addr); + dma_free_coherent(&dev->pci->dev, 4096, cpu, dma_addr); return 0; } -- cgit v1.2.3 From 0b6a3bf8f5630eced6bf04b3416ebaadc8d153cf Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Mon, 30 Nov 2020 23:52:21 +0100 Subject: media: stop pretending to maintain cafe and ov7670 It's been a long time since I could credibly claim to be maintaining these drivers; I'm not even sure my hardware works anymore. Mark them orphan. Signed-off-by: Jonathan Corbet Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 02437abc94c9..dce790484d29 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3862,9 +3862,8 @@ T: git git://linuxtv.org/media_tree.git F: drivers/media/radio/radio-cadet* CAFE CMOS INTEGRATED CAMERA CONTROLLER DRIVER -M: Jonathan Corbet L: linux-media@vger.kernel.org -S: Maintained +S: Orphan T: git git://linuxtv.org/media_tree.git F: Documentation/admin-guide/media/cafe_ccic* F: drivers/media/platform/marvell-ccic/ @@ -12934,9 +12933,8 @@ T: git git://linuxtv.org/media_tree.git F: drivers/media/i2c/ov5695.c OMNIVISION OV7670 SENSOR DRIVER -M: Jonathan Corbet L: linux-media@vger.kernel.org -S: Maintained +S: Orphan T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/ov7670.txt F: drivers/media/i2c/ov7670.c -- cgit v1.2.3 From 42ad70c469665387e8f7b53cb6d4581492dff906 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 1 Dec 2020 15:30:58 +0100 Subject: media: rockchip: rkisp1: remove useless debugfs checks The debugfs_create_dir() function never returns NULLs so this code will never be executed. It's not intended that callers will check for debugfs errors in the normal case and it's not necessary in this driver, so we can just delete this code. Signed-off-by: Dan Carpenter Acked-by: Helen Koike Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c index 9af137e4967f..68da1eed753d 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c @@ -430,10 +430,6 @@ static void rkisp1_debug_init(struct rkisp1_device *rkisp1) struct rkisp1_debug *debug = &rkisp1->debug; debug->debugfs_dir = debugfs_create_dir(RKISP1_DRIVER_NAME, NULL); - if (!debug->debugfs_dir) { - dev_dbg(rkisp1->dev, "failed to create debugfs directory\n"); - return; - } debugfs_create_ulong("data_loss", 0444, debug->debugfs_dir, &debug->data_loss); debugfs_create_ulong("outform_size_err", 0444, debug->debugfs_dir, -- cgit v1.2.3 From 3bf10ebc6d12503edb3430234341491bdc9fff09 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 2 Dec 2020 15:16:57 +0100 Subject: media: Documentation: ccs: Rename ccs-regs.txt as ccs-regs.asc As documentation used to be in .txt files before converting to ReST, rename ccs-regs.txt to avoid it being taken as documentation that pre-dates ReST conversion and so target for further conversion to ReST. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../driver-api/media/drivers/ccs/ccs-regs.asc | 1041 ++++++++++++++++++++ .../driver-api/media/drivers/ccs/ccs-regs.txt | 1041 -------------------- Documentation/driver-api/media/drivers/ccs/ccs.rst | 4 +- .../driver-api/media/drivers/ccs/mk-ccs-regs | 4 +- 4 files changed, 1045 insertions(+), 1045 deletions(-) create mode 100644 Documentation/driver-api/media/drivers/ccs/ccs-regs.asc delete mode 100644 Documentation/driver-api/media/drivers/ccs/ccs-regs.txt diff --git a/Documentation/driver-api/media/drivers/ccs/ccs-regs.asc b/Documentation/driver-api/media/drivers/ccs/ccs-regs.asc new file mode 100644 index 000000000000..93f0131aa304 --- /dev/null +++ b/Documentation/driver-api/media/drivers/ccs/ccs-regs.asc @@ -0,0 +1,1041 @@ +# Copyright (C) 2019--2020 Intel Corporation +# SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause + +# register rflags +# - f field LSB MSB rflags +# - e enum value # after a field +# - e enum value [LSB MSB] +# - b bool bit +# - l arg name min max elsize [discontig...] +# +# rflags +# 8, 16, 32 register bits (default is 8) +# v1.1 defined in version 1.1 +# f formula +# float_ireal iReal or IEEE 754; 32 bits +# ireal unsigned iReal + +# general status registers +module_model_id 0x0000 16 +module_revision_number_major 0x0002 8 +frame_count 0x0005 8 +pixel_order 0x0006 8 +- e GRBG 0 +- e RGGB 1 +- e BGGR 2 +- e GBRG 3 +MIPI_CCS_version 0x0007 8 +- e v1_0 0x10 +- e v1_1 0x11 +- f major 4 7 +- f minor 0 3 +data_pedestal 0x0008 16 +module_manufacturer_id 0x000e 16 +module_revision_number_minor 0x0010 8 +module_date_year 0x0012 8 +module_date_month 0x0013 8 +module_date_day 0x0014 8 +module_date_phase 0x0015 8 +- f 0 2 +- e ts 0 +- e es 1 +- e cs 2 +- e mp 3 +sensor_model_id 0x0016 16 +sensor_revision_number 0x0018 8 +sensor_firmware_version 0x001a 8 +serial_number 0x001c 32 +sensor_manufacturer_id 0x0020 16 +sensor_revision_number_16 0x0022 16 + +# frame format description registers +frame_format_model_type 0x0040 8 +- e 2-byte 1 +- e 4-byte 2 +frame_format_model_subtype 0x0041 8 +- f rows 0 3 +- f columns 4 7 +frame_format_descriptor(n) 0x0042 16 f +- l n 0 14 2 +- f pixels 0 11 +- f pcode 12 15 +- e embedded 1 +- e dummy_pixel 2 +- e black_pixel 3 +- e dark_pixel 4 +- e visible_pixel 5 +- e manuf_specific_0 8 +- e manuf_specific_1 9 +- e manuf_specific_2 10 +- e manuf_specific_3 11 +- e manuf_specific_4 12 +- e manuf_specific_5 13 +- e manuf_specific_6 14 +frame_format_descriptor_4(n) 0x0060 32 f +- l n 0 7 4 +- f pixels 0 15 +- f pcode 28 31 +- e embedded 1 +- e dummy_pixel 2 +- e black_pixel 3 +- e dark_pixel 4 +- e visible_pixel 5 +- e manuf_specific_0 8 +- e manuf_specific_1 9 +- e manuf_specific_2 10 +- e manuf_specific_3 11 +- e manuf_specific_4 12 +- e manuf_specific_5 13 +- e manuf_specific_6 14 + +# analog gain description registers +analog_gain_capability 0x0080 16 +- e global 0 +- e alternate_global 2 +analog_gain_code_min 0x0084 16 +analog_gain_code_max 0x0086 16 +analog_gain_code_step 0x0088 16 +analog_gain_type 0x008a 16 +analog_gain_m0 0x008c 16 +analog_gain_c0 0x008e 16 +analog_gain_m1 0x0090 16 +analog_gain_c1 0x0092 16 +analog_linear_gain_min 0x0094 16 v1.1 +analog_linear_gain_max 0x0096 16 v1.1 +analog_linear_gain_step_size 0x0098 16 v1.1 +analog_exponential_gain_min 0x009a 16 v1.1 +analog_exponential_gain_max 0x009c 16 v1.1 +analog_exponential_gain_step_size 0x009e 16 v1.1 + +# data format description registers +data_format_model_type 0x00c0 8 +- e normal 1 +- e extended 2 +data_format_model_subtype 0x00c1 8 +- f rows 0 3 +- f columns 4 7 +data_format_descriptor(n) 0x00c2 16 f +- l n 0 15 2 +- f compressed 0 7 +- f uncompressed 8 15 + +# general set-up registers +mode_select 0x0100 8 +- e software_standby 0 +- e streaming 1 +image_orientation 0x0101 8 +- b horizontal_mirror 0 +- b vertical_flip 1 +software_reset 0x0103 8 +- e off 0 +- e on 1 +grouped_parameter_hold 0x0104 8 +mask_corrupted_frames 0x0105 8 +- e allow 0 +- e mask 1 +fast_standby_ctrl 0x0106 8 +- e complete_frames 0 +- e frame_truncation 1 +CCI_address_ctrl 0x0107 8 +2nd_CCI_if_ctrl 0x0108 8 +- b enable 0 +- b ack 1 +2nd_CCI_address_ctrl 0x0109 8 +CSI_channel_identifier 0x0110 8 +CSI_signaling_mode 0x0111 8 +- e csi_2_dphy 2 +- e csi_2_cphy 3 +CSI_data_format 0x0112 16 +CSI_lane_mode 0x0114 8 +DPCM_Frame_DT 0x011d 8 +Bottom_embedded_data_DT 0x011e 8 +Bottom_embedded_data_VC 0x011f 8 + +gain_mode 0x0120 8 +- e global 0 +- e alternate 1 +ADC_bit_depth 0x0121 8 +emb_data_ctrl 0x0122 v1.1 +- b raw8_packing_for_raw16 0 +- b raw10_packing_for_raw20 1 +- b raw12_packing_for_raw24 2 + +GPIO_TRIG_mode 0x0130 8 +extclk_frequency_mhz 0x0136 16 ireal +temp_sensor_ctrl 0x0138 8 +- b enable 0 +temp_sensor_mode 0x0139 8 +temp_sensor_output 0x013a 8 + +# integration time registers +fine_integration_time 0x0200 16 +coarse_integration_time 0x0202 16 + +# analog gain registers +analog_gain_code_global 0x0204 16 +analog_linear_gain_global 0x0206 16 v1.1 +analog_exponential_gain_global 0x0208 16 v1.1 + +# digital gain registers +digital_gain_global 0x020e 16 + +# hdr control registers +Short_analog_gain_global 0x0216 16 +Short_digital_gain_global 0x0218 16 + +HDR_mode 0x0220 8 +- b enabled 0 +- b separate_analog_gain 1 +- b upscaling 2 +- b reset_sync 3 +- b timing_mode 4 +- b exposure_ctrl_direct 5 +- b separate_digital_gain 6 +HDR_resolution_reduction 0x0221 8 +- f row 0 3 +- f column 4 7 +Exposure_ratio 0x0222 8 +HDR_internal_bit_depth 0x0223 8 +Direct_short_integration_time 0x0224 16 +Short_analog_linear_gain_global 0x0226 16 v1.1 +Short_analog_exponential_gain_global 0x0228 16 v1.1 + +# clock set-up registers +vt_pix_clk_div 0x0300 16 +vt_sys_clk_div 0x0302 16 +pre_pll_clk_div 0x0304 16 +#vt_pre_pll_clk_div 0x0304 16 +pll_multiplier 0x0306 16 +#vt_pll_multiplier 0x0306 16 +op_pix_clk_div 0x0308 16 +op_sys_clk_div 0x030a 16 +op_pre_pll_clk_div 0x030c 16 +op_pll_multiplier 0x031e 16 +pll_mode 0x0310 8 +- f 0 0 +- e single 0 +- e dual 1 +op_pix_clk_div_rev 0x0312 16 v1.1 +op_sys_clk_div_rev 0x0314 16 v1.1 + +# frame timing registers +frame_length_lines 0x0340 16 +line_length_pck 0x0342 16 + +# image size registers +x_addr_start 0x0344 16 +y_addr_start 0x0346 16 +x_addr_end 0x0348 16 +y_addr_end 0x034a 16 +x_output_size 0x034c 16 +y_output_size 0x034e 16 + +# timing mode registers +Frame_length_ctrl 0x0350 8 +- b automatic 0 +Timing_mode_ctrl 0x0352 8 +- b manual_readout 0 +- b delayed_exposure 1 +Start_readout_rs 0x0353 8 +- b manual_readout_start 0 +Frame_margin 0x0354 16 + +# sub-sampling registers +x_even_inc 0x0380 16 +x_odd_inc 0x0382 16 +y_even_inc 0x0384 16 +y_odd_inc 0x0386 16 + +# monochrome readout registers +monochrome_en 0x0390 v1.1 +- e enabled 0 + +# image scaling registers +Scaling_mode 0x0400 16 +- e no_scaling 0 +- e horizontal 1 +scale_m 0x0404 16 +scale_n 0x0406 16 +digital_crop_x_offset 0x0408 16 +digital_crop_y_offset 0x040a 16 +digital_crop_image_width 0x040c 16 +digital_crop_image_height 0x040e 16 + +# image compression registers +compression_mode 0x0500 16 +- e none 0 +- e dpcm_pcm_simple 1 + +# test pattern registers +test_pattern_mode 0x0600 16 +- e none 0 +- e solid_color 1 +- e color_bars 2 +- e fade_to_grey 3 +- e pn9 4 +- e color_tile 5 +test_data_red 0x0602 16 +test_data_greenR 0x0604 16 +test_data_blue 0x0606 16 +test_data_greenB 0x0608 16 +value_step_size_smooth 0x060a 8 +value_step_size_quantised 0x060b 8 + +# phy configuration registers +tclk_post 0x0800 8 +ths_prepare 0x0801 8 +ths_zero_min 0x0802 8 +ths_trail 0x0803 8 +tclk_trail_min 0x0804 8 +tclk_prepare 0x0805 8 +tclk_zero 0x0806 8 +tlpx 0x0807 8 +phy_ctrl 0x0808 8 +- e auto 0 +- e UI 1 +- e manual 2 +tclk_post_ex 0x080a 16 +ths_prepare_ex 0x080c 16 +ths_zero_min_ex 0x080e 16 +ths_trail_ex 0x0810 16 +tclk_trail_min_ex 0x0812 16 +tclk_prepare_ex 0x0814 16 +tclk_zero_ex 0x0816 16 +tlpx_ex 0x0818 16 + +# link rate register +requested_link_rate 0x0820 32 u16.16 + +# equalization control registers +DPHY_equalization_mode 0x0824 8 v1.1 +- b eq2 0 +PHY_equalization_ctrl 0x0825 8 v1.1 +- b enable 0 + +# d-phy preamble control registers +DPHY_preamble_ctrl 0x0826 8 v1.1 +- b enable 0 +DPHY_preamble_length 0x0826 8 v1.1 + +# d-phy spread spectrum control registers +PHY_SSC_ctrl 0x0828 8 v1.1 +- b enable 0 + +# manual lp control register +manual_LP_ctrl 0x0829 8 v1.1 +- b enable 0 + +# additional phy configuration registers +twakeup 0x082a v1.1 +tinit 0x082b v1.1 +ths_exit 0x082c v1.1 +ths_exit_ex 0x082e 16 v1.1 + +# phy calibration configuration registers +PHY_periodic_calibration_ctrl 0x0830 8 +- b frame_blanking 0 +PHY_periodic_calibration_interval 0x0831 8 +PHY_init_calibration_ctrl 0x0832 8 +- b stream_start 0 +DPHY_calibration_mode 0x0833 8 v1.1 +- b also_alternate 0 +CPHY_calibration_mode 0x0834 8 v1.1 +- e format_1 0 +- e format_2 1 +- e format_3 2 +t3_calpreamble_length 0x0835 8 v1.1 +t3_calpreamble_length_per 0x0836 8 v1.1 +t3_calaltseq_length 0x0837 8 v1.1 +t3_calaltseq_length_per 0x0838 8 v1.1 +FM2_init_seed 0x083a 16 v1.1 +t3_caludefseq_length 0x083c 16 v1.1 +t3_caludefseq_length_per 0x083e 16 v1.1 + +# c-phy manual control registers +TGR_Preamble_Length 0x0841 8 +- b preamable_prog_seq 7 +- f begin_preamble_length 0 5 +TGR_Post_Length 0x0842 8 +- f post_length 0 4 +TGR_Preamble_Prog_Sequence(n2) 0x0843 +- l n2 0 6 1 +- f symbol_n_1 3 5 +- f symbol_n 0 2 +t3_prepare 0x084e 16 +t3_lpx 0x0850 16 + +# alps control register +ALPS_ctrl 0x085a 8 +- b lvlp_dphy 0 +- b lvlp_cphy 1 +- b alp_cphy 2 + +# lrte control registers +TX_REG_CSI_EPD_EN_SSP_cphy 0x0860 16 +TX_REG_CSI_EPD_OP_SLP_cphy 0x0862 16 +TX_REG_CSI_EPD_EN_SSP_dphy 0x0864 16 +TX_REG_CSI_EPD_OP_SLP_dphy 0x0866 16 +TX_REG_CSI_EPD_MISC_OPTION_cphy 0x0868 v1.1 +TX_REG_CSI_EPD_MISC_OPTION_dphy 0x0869 v1.1 + +# scrambling control registers +Scrambling_ctrl 0x0870 +- b enabled 0 +- f 2 3 +- e 1_seed_cphy 0 +- e 4_seed_cphy 3 +lane_seed_value(seed, lane) 0x0872 16 +- l seed 0 3 0x10 +- l lane 0 7 0x2 + +# usl control registers +TX_USL_REV_ENTRY 0x08c0 16 v1.1 +TX_USL_REV_Clock_Counter 0x08c2 16 v1.1 +TX_USL_REV_LP_Counter 0x08c4 16 v1.1 +TX_USL_REV_Frame_Counter 0x08c6 16 v1.1 +TX_USL_REV_Chronological_Timer 0x08c8 16 v1.1 +TX_USL_FWD_ENTRY 0x08ca 16 v1.1 +TX_USL_GPIO 0x08cc 16 v1.1 +TX_USL_Operation 0x08ce 16 v1.1 +- b reset 0 +TX_USL_ALP_ctrl 0x08d0 16 v1.1 +- b clock_pause 0 +TX_USL_APP_BTA_ACK_TIMEOUT 0x08d2 16 v1.1 +TX_USL_SNS_BTA_ACK_TIMEOUT 0x08d2 16 v1.1 +USL_Clock_Mode_d_ctrl 0x08d2 v1.1 +- b cont_clock_standby 0 +- b cont_clock_vblank 1 +- b cont_clock_hblank 2 + +# binning configuration registers +binning_mode 0x0900 8 +binning_type 0x0901 8 +binning_weighting 0x0902 8 + +# data transfer interface registers +data_transfer_if_1_ctrl 0x0a00 8 +- b enable 0 +- b write 1 +- b clear_error 2 +data_transfer_if_1_status 0x0a01 8 +- b read_if_ready 0 +- b write_if_ready 1 +- b data_corrupted 2 +- b improper_if_usage 3 +data_transfer_if_1_page_select 0x0a02 8 +data_transfer_if_1_data(p) 0x0a04 8 f +- l p 0 63 1 + +# image processing and sensor correction configuration registers +shading_correction_en 0x0b00 8 +- b enable 0 +luminance_correction_level 0x0b01 8 +green_imbalance_filter_en 0x0b02 8 +- b enable 0 +mapped_defect_correct_en 0x0b05 8 +- b enable 0 +single_defect_correct_en 0x0b06 8 +- b enable 0 +dynamic_couplet_correct_en 0x0b08 8 +- b enable 0 +combined_defect_correct_en 0x0b0a 8 +- b enable 0 +module_specific_correction_en 0x0b0c 8 +- b enable 0 +dynamic_triplet_defect_correct_en 0x0b13 8 +- b enable 0 +NF_ctrl 0x0b15 8 +- b luma 0 +- b chroma 1 +- b combined 2 + +# optical black pixel readout registers +OB_readout_control 0x0b30 8 +- b enable 0 +- b interleaving 1 +OB_virtual_channel 0x0b31 8 +OB_DT 0x0b32 8 +OB_data_format 0x0b33 8 + +# color temperature feedback registers +color_temperature 0x0b8c 16 +absolute_gain_greenr 0x0b8e 16 +absolute_gain_red 0x0b90 16 +absolute_gain_blue 0x0b92 16 +absolute_gain_greenb 0x0b94 16 + +# cfa conversion registers +CFA_conversion_ctrl 0x0ba0 v1.1 +- b bayer_conversion_enable 0 + +# flash strobe and sa strobe control registers +flash_strobe_adjustment 0x0c12 8 +flash_strobe_start_point 0x0c14 16 +tflash_strobe_delay_rs_ctrl 0x0c16 16 +tflash_strobe_width_high_rs_ctrl 0x0c18 16 +flash_mode_rs 0x0c1a 8 +- b continuous 0 +- b truncate 1 +- b async 3 +flash_trigger_rs 0x0c1b 8 +flash_status 0x0c1c 8 +- b retimed 0 +sa_strobe_mode 0x0c1d 8 +- b continuous 0 +- b truncate 1 +- b async 3 +- b adjust_edge 4 +sa_strobe_start_point 0x0c1e 16 +tsa_strobe_delay_ctrl 0x0c20 16 +tsa_strobe_width_ctrl 0x0c22 16 +sa_strobe_trigger 0x0c24 8 +sa_strobe_status 0x0c25 8 +- b retimed 0 +tSA_strobe_re_delay_ctrl 0x0c30 16 +tSA_strobe_fe_delay_ctrl 0x0c32 16 + +# pdaf control registers +PDAF_ctrl 0x0d00 16 +- b enable 0 +- b processed 1 +- b interleaved 2 +- b visible_pdaf_correction 3 +PDAF_VC 0x0d02 8 +PDAF_DT 0x0d03 8 +pd_x_addr_start 0x0d04 16 +pd_y_addr_start 0x0d06 16 +pd_x_addr_end 0x0d08 16 +pd_y_addr_end 0x0d0a 16 + +# bracketing interface configuration registers +bracketing_LUT_ctrl 0x0e00 8 +bracketing_LUT_mode 0x0e01 8 +- b continue_streaming 0 +- b loop_mode 1 +bracketing_LUT_entry_ctrl 0x0e02 8 +bracketing_LUT_frame(n) 0x0e10 v1.1 f +- l n 0 0xef 1 + +# integration time and gain parameter limit registers +integration_time_capability 0x1000 16 +- b fine 0 +coarse_integration_time_min 0x1004 16 +coarse_integration_time_max_margin 0x1006 16 +fine_integration_time_min 0x1008 16 +fine_integration_time_max_margin 0x100a 16 + +# digital gain parameter limit registers +digital_gain_capability 0x1081 +- e none 0 +- e global 2 +digital_gain_min 0x1084 16 +digital_gain_max 0x1086 16 +digital_gain_step_size 0x1088 16 + +# data pedestal capability registers +Pedestal_capability 0x10e0 8 v1.1 + +# adc capability registers +ADC_capability 0x10f0 8 +- b bit_depth_ctrl 0 +ADC_bit_depth_capability 0x10f4 32 v1.1 + +# video timing parameter limit registers +min_ext_clk_freq_mhz 0x1100 32 float_ireal +max_ext_clk_freq_mhz 0x1104 32 float_ireal +min_pre_pll_clk_div 0x1108 16 +# min_vt_pre_pll_clk_div 0x1108 16 +max_pre_pll_clk_div 0x110a 16 +# max_vt_pre_pll_clk_div 0x110a 16 +min_pll_ip_clk_freq_mhz 0x110c 32 float_ireal +# min_vt_pll_ip_clk_freq_mhz 0x110c 32 float_ireal +max_pll_ip_clk_freq_mhz 0x1110 32 float_ireal +# max_vt_pll_ip_clk_freq_mhz 0x1110 32 float_ireal +min_pll_multiplier 0x1114 16 +# min_vt_pll_multiplier 0x1114 16 +max_pll_multiplier 0x1116 16 +# max_vt_pll_multiplier 0x1116 16 +min_pll_op_clk_freq_mhz 0x1118 32 float_ireal +max_pll_op_clk_freq_mhz 0x111c 32 float_ireal + +# video timing set-up capability registers +min_vt_sys_clk_div 0x1120 16 +max_vt_sys_clk_div 0x1122 16 +min_vt_sys_clk_freq_mhz 0x1124 32 float_ireal +max_vt_sys_clk_freq_mhz 0x1128 32 float_ireal +min_vt_pix_clk_freq_mhz 0x112c 32 float_ireal +max_vt_pix_clk_freq_mhz 0x1130 32 float_ireal +min_vt_pix_clk_div 0x1134 16 +max_vt_pix_clk_div 0x1136 16 +clock_calculation 0x1138 +- b lane_speed 0 +- b link_decoupled 1 +- b dual_pll_op_sys_ddr 2 +- b dual_pll_op_pix_ddr 3 +num_of_vt_lanes 0x1139 +num_of_op_lanes 0x113a +op_bits_per_lane 0x113b 8 v1.1 + +# frame timing parameter limits +min_frame_length_lines 0x1140 16 +max_frame_length_lines 0x1142 16 +min_line_length_pck 0x1144 16 +max_line_length_pck 0x1146 16 +min_line_blanking_pck 0x1148 16 +min_frame_blanking_lines 0x114a 16 +min_line_length_pck_step_size 0x114c +timing_mode_capability 0x114d +- b auto_frame_length 0 +- b rolling_shutter_manual_readout 2 +- b delayed_exposure_start 3 +- b manual_exposure_embedded_data 4 +frame_margin_max_value 0x114e 16 +frame_margin_min_value 0x1150 +gain_delay_type 0x1151 +- e fixed 0 +- e variable 1 + +# output clock set-up capability registers +min_op_sys_clk_div 0x1160 16 +max_op_sys_clk_div 0x1162 16 +min_op_sys_clk_freq_mhz 0x1164 32 float_ireal +max_op_sys_clk_freq_mhz 0x1168 32 float_ireal +min_op_pix_clk_div 0x116c 16 +max_op_pix_clk_div 0x116e 16 +min_op_pix_clk_freq_mhz 0x1170 32 float_ireal +max_op_pix_clk_freq_mhz 0x1174 32 float_ireal + +# image size parameter limit registers +x_addr_min 0x1180 16 +y_addr_min 0x1182 16 +x_addr_max 0x1184 16 +y_addr_max 0x1186 16 +min_x_output_size 0x1188 16 +min_y_output_size 0x118a 16 +max_x_output_size 0x118c 16 +max_y_output_size 0x118e 16 + +x_addr_start_div_constant 0x1190 v1.1 +y_addr_start_div_constant 0x1191 v1.1 +x_addr_end_div_constant 0x1192 v1.1 +y_addr_end_div_constant 0x1193 v1.1 +x_size_div 0x1194 v1.1 +y_size_div 0x1195 v1.1 +x_output_div 0x1196 v1.1 +y_output_div 0x1197 v1.1 +non_flexible_resolution_support 0x1198 v1.1 +- b new_pix_addr 0 +- b new_output_res 1 +- b output_crop_no_pad 2 +- b output_size_lane_dep 3 + +min_op_pre_pll_clk_div 0x11a0 16 +max_op_pre_pll_clk_div 0x11a2 16 +min_op_pll_ip_clk_freq_mhz 0x11a4 32 float_ireal +max_op_pll_ip_clk_freq_mhz 0x11a8 32 float_ireal +min_op_pll_multiplier 0x11ac 16 +max_op_pll_multiplier 0x11ae 16 +min_op_pll_op_clk_freq_mhz 0x11b0 32 float_ireal +max_op_pll_op_clk_freq_mhz 0x11b4 32 float_ireal +clock_tree_pll_capability 0x11b8 8 +- b dual_pll 0 +- b single_pll 1 +- b ext_divider 2 +- b flexible_op_pix_clk_div 3 +clock_capa_type_capability 0x11b9 v1.1 +- b ireal 0 + +# sub-sampling parameters limit registers +min_even_inc 0x11c0 16 +min_odd_inc 0x11c2 16 +max_even_inc 0x11c4 16 +max_odd_inc 0x11c6 16 +aux_subsamp_capability 0x11c8 v1.1 +- b factor_power_of_2 1 +aux_subsamp_mono_capability 0x11c9 v1.1 +- b factor_power_of_2 1 +monochrome_capability 0x11ca v1.1 +- e inc_odd 0 +- e inc_even 1 +pixel_readout_capability 0x11cb v1.1 +- e bayer 0 +- e monochrome 1 +- e bayer_and_mono 2 +min_even_inc_mono 0x11cc 16 v1.1 +max_even_inc_mono 0x11ce 16 v1.1 +min_odd_inc_mono 0x11d0 16 v1.1 +max_odd_inc_mono 0x11d2 16 v1.1 +min_even_inc_bc2 0x11d4 16 v1.1 +max_even_inc_bc2 0x11d6 16 v1.1 +min_odd_inc_bc2 0x11d8 16 v1.1 +max_odd_inc_bc2 0x11da 16 v1.1 +min_even_inc_mono_bc2 0x11dc 16 v1.1 +max_even_inc_mono_bc2 0x11de 16 v1.1 +min_odd_inc_mono_bc2 0x11f0 16 v1.1 +max_odd_inc_mono_bc2 0x11f2 16 v1.1 + +# image scaling limit parameters +scaling_capability 0x1200 16 +- e none 0 +- e horizontal 1 +- e reserved 2 +scaler_m_min 0x1204 16 +scaler_m_max 0x1206 16 +scaler_n_min 0x1208 16 +scaler_n_max 0x120a 16 +digital_crop_capability 0x120e +- e none 0 +- e input_crop 1 + +# hdr limit registers +hdr_capability_1 0x1210 +- b 2x2_binning 0 +- b combined_analog_gain 1 +- b separate_analog_gain 2 +- b upscaling 3 +- b reset_sync 4 +- b direct_short_exp_timing 5 +- b direct_short_exp_synthesis 6 +min_hdr_bit_depth 0x1211 +hdr_resolution_sub_types 0x1212 +hdr_resolution_sub_type(n) 0x1213 +- l n 0 1 1 +- f row 0 3 +- f column 4 7 +hdr_capability_2 0x121b +- b combined_digital_gain 0 +- b separate_digital_gain 1 +- b timing_mode 3 +- b synthesis_mode 4 +max_hdr_bit_depth 0x121c + +# usl capability register +usl_support_capability 0x1230 v1.1 +- b clock_tree 0 +- b rev_clock_tree 1 +- b rev_clock_calc 2 +usl_clock_mode_d_capability 0x1231 v1.1 +- b cont_clock_standby 0 +- b cont_clock_vblank 1 +- b cont_clock_hblank 2 +- b noncont_clock_standby 3 +- b noncont_clock_vblank 4 +- b noncont_clock_hblank 5 +min_op_sys_clk_div_rev 0x1234 v1.1 +max_op_sys_clk_div_rev 0x1236 v1.1 +min_op_pix_clk_div_rev 0x1238 v1.1 +max_op_pix_clk_div_rev 0x123a v1.1 +min_op_sys_clk_freq_rev_mhz 0x123c 32 v1.1 float_ireal +max_op_sys_clk_freq_rev_mhz 0x1240 32 v1.1 float_ireal +min_op_pix_clk_freq_rev_mhz 0x1244 32 v1.1 float_ireal +max_op_pix_clk_freq_rev_mhz 0x1248 32 v1.1 float_ireal +max_bitrate_rev_d_mode_mbps 0x124c 32 v1.1 ireal +max_symrate_rev_c_mode_msps 0x1250 32 v1.1 ireal + +# image compression capability registers +compression_capability 0x1300 +- b dpcm_pcm_simple 0 + +# test mode capability registers +test_mode_capability 0x1310 16 +- b solid_color 0 +- b color_bars 1 +- b fade_to_grey 2 +- b pn9 3 +- b color_tile 5 +pn9_data_format1 0x1312 +pn9_data_format2 0x1313 +pn9_data_format3 0x1314 +pn9_data_format4 0x1315 +pn9_misc_capability 0x1316 +- f num_pixels 0 2 +- b compression 3 +test_pattern_capability 0x1317 v1.1 +- b no_repeat 1 +pattern_size_div_m1 0x1318 v1.1 + +# fifo capability registers +fifo_support_capability 0x1502 +- e none 0 +- e derating 1 +- e derating_overrating 2 + +# csi-2 capability registers +phy_ctrl_capability 0x1600 +- b auto_phy_ctl 0 +- b ui_phy_ctl 1 +- b dphy_time_ui_reg_1_ctl 2 +- b dphy_time_ui_reg_2_ctl 3 +- b dphy_time_ctl 4 +- b dphy_ext_time_ui_reg_1_ctl 5 +- b dphy_ext_time_ui_reg_2_ctl 6 +- b dphy_ext_time_ctl 7 +csi_dphy_lane_mode_capability 0x1601 +- b 1_lane 0 +- b 2_lane 1 +- b 3_lane 2 +- b 4_lane 3 +- b 5_lane 4 +- b 6_lane 5 +- b 7_lane 6 +- b 8_lane 7 +csi_signaling_mode_capability 0x1602 +- b csi_dphy 2 +- b csi_cphy 3 +fast_standby_capability 0x1603 +- e no_frame_truncation 0 +- e frame_truncation 1 +csi_address_control_capability 0x1604 +- b cci_addr_change 0 +- b 2nd_cci_addr 1 +- b sw_changeable_2nd_cci_addr 2 +data_type_capability 0x1605 +- b dpcm_programmable 0 +- b bottom_embedded_dt_programmable 1 +- b bottom_embedded_vc_programmable 2 +- b ext_vc_range 3 +csi_cphy_lane_mode_capability 0x1606 +- b 1_lane 0 +- b 2_lane 1 +- b 3_lane 2 +- b 4_lane 3 +- b 5_lane 4 +- b 6_lane 5 +- b 7_lane 6 +- b 8_lane 7 +emb_data_capability 0x1607 v1.1 +- b two_bytes_per_raw16 0 +- b two_bytes_per_raw20 1 +- b two_bytes_per_raw24 2 +- b no_one_byte_per_raw16 3 +- b no_one_byte_per_raw20 4 +- b no_one_byte_per_raw24 5 +max_per_lane_bitrate_lane_d_mode_mbps(n) 0x1608 32 ireal +- l n 0 7 4 4,0x32 +temp_sensor_capability 0x1618 +- b supported 0 +- b CCS_format 1 +- b reset_0x80 2 +max_per_lane_bitrate_lane_c_mode_mbps(n) 0x161a 32 ireal +- l n 0 7 4 4,0x30 +dphy_equalization_capability 0x162b +- b equalization_ctrl 0 +- b eq1 1 +- b eq2 2 +cphy_equalization_capability 0x162c +- b equalization_ctrl 0 +dphy_preamble_capability 0x162d +- b preamble_seq_ctrl 0 +dphy_ssc_capability 0x162e +- b supported 0 +cphy_calibration_capability 0x162f +- b manual 0 +- b manual_streaming 1 +- b format_1_ctrl 2 +- b format_2_ctrl 3 +- b format_3_ctrl 4 +dphy_calibration_capability 0x1630 +- b manual 0 +- b manual_streaming 1 +- b alternate_seq 2 +phy_ctrl_capability_2 0x1631 +- b tgr_length 0 +- b tgr_preamble_prog_seq 1 +- b extra_cphy_manual_timing 2 +- b clock_based_manual_cdphy 3 +- b clock_based_manual_dphy 4 +- b clock_based_manual_cphy 5 +- b manual_lp_dphy 6 +- b manual_lp_cphy 7 +lrte_cphy_capability 0x1632 +- b pdq_short 0 +- b spacer_short 1 +- b pdq_long 2 +- b spacer_long 3 +- b spacer_no_pdq 4 +lrte_dphy_capability 0x1633 +- b pdq_short_opt1 0 +- b spacer_short_opt1 1 +- b pdq_long_opt1 2 +- b spacer_long_opt1 3 +- b spacer_short_opt2 4 +- b spacer_long_opt2 5 +- b spacer_no_pdq_opt1 6 +- b spacer_variable_opt2 7 +alps_capability_dphy 0x1634 +- e lvlp_not_supported 0 0x3 +- e lvlp_supported 1 0x3 +- e controllable_lvlp 2 0x3 +alps_capability_cphy 0x1635 +- e lvlp_not_supported 0 0x3 +- e lvlp_supported 1 0x3 +- e controllable_lvlp 2 0x3 +- e alp_not_supported 0xc 0xc +- e alp_supported 0xd 0xc +- e controllable_alp 0xe 0xc +scrambling_capability 0x1636 +- b scrambling_supported 0 +- f max_seeds_per_lane_c 1 2 +- e 1 0 +- e 4 3 +- f num_seed_regs 3 5 +- e 0 0 +- e 1 1 +- e 4 4 +- b num_seed_per_lane 6 +dphy_manual_constant 0x1637 +cphy_manual_constant 0x1638 +CSI2_interface_capability_misc 0x1639 v1.1 +- b eotp_short_pkt_opt2 0 +PHY_ctrl_capability_3 0x165c v1.1 +- b dphy_timing_not_multiple 0 +- b dphy_min_timing_value_1 1 +- b twakeup_supported 2 +- b tinit_supported 3 +- b ths_exit_supported 4 +- b cphy_timing_not_multiple 5 +- b cphy_min_timing_value_1 6 +dphy_sf 0x165d v1.1 +cphy_sf 0x165e v1.1 +- f twakeup 0 3 +- f tinit 4 7 +dphy_limits_1 0x165f v1.1 +- f ths_prepare 0 3 +- f ths_zero 4 7 +dphy_limits_2 0x1660 v1.1 +- f ths_trail 0 3 +- f tclk_trail_min 4 7 +dphy_limits_3 0x1661 v1.1 +- f tclk_prepare 0 3 +- f tclk_zero 4 7 +dphy_limits_4 0x1662 v1.1 +- f tclk_post 0 3 +- f tlpx 4 7 +dphy_limits_5 0x1663 v1.1 +- f ths_exit 0 3 +- f twakeup 4 7 +dphy_limits_6 0x1664 v1.1 +- f tinit 0 3 +cphy_limits_1 0x1665 v1.1 +- f t3_prepare_max 0 3 +- f t3_lpx_max 4 7 +cphy_limits_2 0x1666 v1.1 +- f ths_exit_max 0 3 +- f twakeup_max 4 7 +cphy_limits_3 0x1667 v1.1 +- f tinit_max 0 3 + +# binning capability registers +min_frame_length_lines_bin 0x1700 16 +max_frame_length_lines_bin 0x1702 16 +min_line_length_pck_bin 0x1704 16 +max_line_length_pck_bin 0x1706 16 +min_line_blanking_pck_bin 0x1708 16 +fine_integration_time_min_bin 0x170a 16 +fine_integration_time_max_margin_bin 0x170c 16 +binning_capability 0x1710 +- e unsupported 0 +- e binning_then_subsampling 1 +- e subsampling_then_binning 2 +binning_weighting_capability 0x1711 +- b averaged 0 +- b summed 1 +- b bayer_corrected 2 +- b module_specific_weight 3 +binning_sub_types 0x1712 +binning_sub_type(n) 0x1713 +- l n 0 63 1 +- f row 0 3 +- f column 4 7 +binning_weighting_mono_capability 0x1771 v1.1 +- b averaged 0 +- b summed 1 +- b bayer_corrected 2 +- b module_specific_weight 3 +binning_sub_types_mono 0x1772 v1.1 +binning_sub_type_mono(n) 0x1773 v1.1 f +- l n 0 63 1 + +# data transfer interface capability registers +data_transfer_if_capability 0x1800 +- b supported 0 +- b polling 2 + +# sensor correction capability registers +shading_correction_capability 0x1900 +- b color_shading 0 +- b luminance_correction 1 +green_imbalance_capability 0x1901 +- b supported 0 +module_specific_correction_capability 0x1903 +defect_correction_capability 0x1904 16 +- b mapped_defect 0 +- b dynamic_couplet 2 +- b dynamic_single 5 +- b combined_dynamic 8 +defect_correction_capability_2 0x1906 16 +- b dynamic_triplet 3 +nf_capability 0x1908 +- b luma 0 +- b chroma 1 +- b combined 2 + +# optical black readout capability registers +ob_readout_capability 0x1980 +- b controllable_readout 0 +- b visible_pixel_readout 1 +- b different_vc_readout 2 +- b different_dt_readout 3 +- b prog_data_format 4 + +# color feedback capability registers +color_feedback_capability 0x1987 +- b kelvin 0 +- b awb_gain 1 + +# cfa pattern capability registers +CFA_pattern_capability 0x1990 v1.1 +- e bayer 0 +- e monochrome 1 +- e 4x4_quad_bayer 2 +- e vendor_specific 3 +CFA_pattern_conversion_capability 0x1991 v1.1 +- b bayer 0 + +# timer capability registers +flash_mode_capability 0x1a02 +- b single_strobe 0 +sa_strobe_mode_capability 0x1a03 +- b fixed_width 0 +- b edge_ctrl 1 + +# soft reset capability registers +reset_max_delay 0x1a10 v1.1 +reset_min_time 0x1a11 v1.1 + +# pdaf capability registers +pdaf_capability_1 0x1b80 +- b supported 0 +- b processed_bottom_embedded 1 +- b processed_interleaved 2 +- b raw_bottom_embedded 3 +- b raw_interleaved 4 +- b visible_pdaf_correction 5 +- b vc_interleaving 6 +- b dt_interleaving 7 +pdaf_capability_2 0x1b81 +- b ROI 0 +- b after_digital_crop 1 +- b ctrl_retimed 2 + +# bracketing interface capability registers +bracketing_lut_capability_1 0x1c00 +- b coarse_integration 0 +- b global_analog_gain 1 +- b flash 4 +- b global_digital_gain 5 +- b alternate_global_analog_gain 6 +bracketing_lut_capability_2 0x1c01 +- b single_bracketing_mode 0 +- b looped_bracketing_mode 1 +bracketing_lut_size 0x1c02 diff --git a/Documentation/driver-api/media/drivers/ccs/ccs-regs.txt b/Documentation/driver-api/media/drivers/ccs/ccs-regs.txt deleted file mode 100644 index 93f0131aa304..000000000000 --- a/Documentation/driver-api/media/drivers/ccs/ccs-regs.txt +++ /dev/null @@ -1,1041 +0,0 @@ -# Copyright (C) 2019--2020 Intel Corporation -# SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause - -# register rflags -# - f field LSB MSB rflags -# - e enum value # after a field -# - e enum value [LSB MSB] -# - b bool bit -# - l arg name min max elsize [discontig...] -# -# rflags -# 8, 16, 32 register bits (default is 8) -# v1.1 defined in version 1.1 -# f formula -# float_ireal iReal or IEEE 754; 32 bits -# ireal unsigned iReal - -# general status registers -module_model_id 0x0000 16 -module_revision_number_major 0x0002 8 -frame_count 0x0005 8 -pixel_order 0x0006 8 -- e GRBG 0 -- e RGGB 1 -- e BGGR 2 -- e GBRG 3 -MIPI_CCS_version 0x0007 8 -- e v1_0 0x10 -- e v1_1 0x11 -- f major 4 7 -- f minor 0 3 -data_pedestal 0x0008 16 -module_manufacturer_id 0x000e 16 -module_revision_number_minor 0x0010 8 -module_date_year 0x0012 8 -module_date_month 0x0013 8 -module_date_day 0x0014 8 -module_date_phase 0x0015 8 -- f 0 2 -- e ts 0 -- e es 1 -- e cs 2 -- e mp 3 -sensor_model_id 0x0016 16 -sensor_revision_number 0x0018 8 -sensor_firmware_version 0x001a 8 -serial_number 0x001c 32 -sensor_manufacturer_id 0x0020 16 -sensor_revision_number_16 0x0022 16 - -# frame format description registers -frame_format_model_type 0x0040 8 -- e 2-byte 1 -- e 4-byte 2 -frame_format_model_subtype 0x0041 8 -- f rows 0 3 -- f columns 4 7 -frame_format_descriptor(n) 0x0042 16 f -- l n 0 14 2 -- f pixels 0 11 -- f pcode 12 15 -- e embedded 1 -- e dummy_pixel 2 -- e black_pixel 3 -- e dark_pixel 4 -- e visible_pixel 5 -- e manuf_specific_0 8 -- e manuf_specific_1 9 -- e manuf_specific_2 10 -- e manuf_specific_3 11 -- e manuf_specific_4 12 -- e manuf_specific_5 13 -- e manuf_specific_6 14 -frame_format_descriptor_4(n) 0x0060 32 f -- l n 0 7 4 -- f pixels 0 15 -- f pcode 28 31 -- e embedded 1 -- e dummy_pixel 2 -- e black_pixel 3 -- e dark_pixel 4 -- e visible_pixel 5 -- e manuf_specific_0 8 -- e manuf_specific_1 9 -- e manuf_specific_2 10 -- e manuf_specific_3 11 -- e manuf_specific_4 12 -- e manuf_specific_5 13 -- e manuf_specific_6 14 - -# analog gain description registers -analog_gain_capability 0x0080 16 -- e global 0 -- e alternate_global 2 -analog_gain_code_min 0x0084 16 -analog_gain_code_max 0x0086 16 -analog_gain_code_step 0x0088 16 -analog_gain_type 0x008a 16 -analog_gain_m0 0x008c 16 -analog_gain_c0 0x008e 16 -analog_gain_m1 0x0090 16 -analog_gain_c1 0x0092 16 -analog_linear_gain_min 0x0094 16 v1.1 -analog_linear_gain_max 0x0096 16 v1.1 -analog_linear_gain_step_size 0x0098 16 v1.1 -analog_exponential_gain_min 0x009a 16 v1.1 -analog_exponential_gain_max 0x009c 16 v1.1 -analog_exponential_gain_step_size 0x009e 16 v1.1 - -# data format description registers -data_format_model_type 0x00c0 8 -- e normal 1 -- e extended 2 -data_format_model_subtype 0x00c1 8 -- f rows 0 3 -- f columns 4 7 -data_format_descriptor(n) 0x00c2 16 f -- l n 0 15 2 -- f compressed 0 7 -- f uncompressed 8 15 - -# general set-up registers -mode_select 0x0100 8 -- e software_standby 0 -- e streaming 1 -image_orientation 0x0101 8 -- b horizontal_mirror 0 -- b vertical_flip 1 -software_reset 0x0103 8 -- e off 0 -- e on 1 -grouped_parameter_hold 0x0104 8 -mask_corrupted_frames 0x0105 8 -- e allow 0 -- e mask 1 -fast_standby_ctrl 0x0106 8 -- e complete_frames 0 -- e frame_truncation 1 -CCI_address_ctrl 0x0107 8 -2nd_CCI_if_ctrl 0x0108 8 -- b enable 0 -- b ack 1 -2nd_CCI_address_ctrl 0x0109 8 -CSI_channel_identifier 0x0110 8 -CSI_signaling_mode 0x0111 8 -- e csi_2_dphy 2 -- e csi_2_cphy 3 -CSI_data_format 0x0112 16 -CSI_lane_mode 0x0114 8 -DPCM_Frame_DT 0x011d 8 -Bottom_embedded_data_DT 0x011e 8 -Bottom_embedded_data_VC 0x011f 8 - -gain_mode 0x0120 8 -- e global 0 -- e alternate 1 -ADC_bit_depth 0x0121 8 -emb_data_ctrl 0x0122 v1.1 -- b raw8_packing_for_raw16 0 -- b raw10_packing_for_raw20 1 -- b raw12_packing_for_raw24 2 - -GPIO_TRIG_mode 0x0130 8 -extclk_frequency_mhz 0x0136 16 ireal -temp_sensor_ctrl 0x0138 8 -- b enable 0 -temp_sensor_mode 0x0139 8 -temp_sensor_output 0x013a 8 - -# integration time registers -fine_integration_time 0x0200 16 -coarse_integration_time 0x0202 16 - -# analog gain registers -analog_gain_code_global 0x0204 16 -analog_linear_gain_global 0x0206 16 v1.1 -analog_exponential_gain_global 0x0208 16 v1.1 - -# digital gain registers -digital_gain_global 0x020e 16 - -# hdr control registers -Short_analog_gain_global 0x0216 16 -Short_digital_gain_global 0x0218 16 - -HDR_mode 0x0220 8 -- b enabled 0 -- b separate_analog_gain 1 -- b upscaling 2 -- b reset_sync 3 -- b timing_mode 4 -- b exposure_ctrl_direct 5 -- b separate_digital_gain 6 -HDR_resolution_reduction 0x0221 8 -- f row 0 3 -- f column 4 7 -Exposure_ratio 0x0222 8 -HDR_internal_bit_depth 0x0223 8 -Direct_short_integration_time 0x0224 16 -Short_analog_linear_gain_global 0x0226 16 v1.1 -Short_analog_exponential_gain_global 0x0228 16 v1.1 - -# clock set-up registers -vt_pix_clk_div 0x0300 16 -vt_sys_clk_div 0x0302 16 -pre_pll_clk_div 0x0304 16 -#vt_pre_pll_clk_div 0x0304 16 -pll_multiplier 0x0306 16 -#vt_pll_multiplier 0x0306 16 -op_pix_clk_div 0x0308 16 -op_sys_clk_div 0x030a 16 -op_pre_pll_clk_div 0x030c 16 -op_pll_multiplier 0x031e 16 -pll_mode 0x0310 8 -- f 0 0 -- e single 0 -- e dual 1 -op_pix_clk_div_rev 0x0312 16 v1.1 -op_sys_clk_div_rev 0x0314 16 v1.1 - -# frame timing registers -frame_length_lines 0x0340 16 -line_length_pck 0x0342 16 - -# image size registers -x_addr_start 0x0344 16 -y_addr_start 0x0346 16 -x_addr_end 0x0348 16 -y_addr_end 0x034a 16 -x_output_size 0x034c 16 -y_output_size 0x034e 16 - -# timing mode registers -Frame_length_ctrl 0x0350 8 -- b automatic 0 -Timing_mode_ctrl 0x0352 8 -- b manual_readout 0 -- b delayed_exposure 1 -Start_readout_rs 0x0353 8 -- b manual_readout_start 0 -Frame_margin 0x0354 16 - -# sub-sampling registers -x_even_inc 0x0380 16 -x_odd_inc 0x0382 16 -y_even_inc 0x0384 16 -y_odd_inc 0x0386 16 - -# monochrome readout registers -monochrome_en 0x0390 v1.1 -- e enabled 0 - -# image scaling registers -Scaling_mode 0x0400 16 -- e no_scaling 0 -- e horizontal 1 -scale_m 0x0404 16 -scale_n 0x0406 16 -digital_crop_x_offset 0x0408 16 -digital_crop_y_offset 0x040a 16 -digital_crop_image_width 0x040c 16 -digital_crop_image_height 0x040e 16 - -# image compression registers -compression_mode 0x0500 16 -- e none 0 -- e dpcm_pcm_simple 1 - -# test pattern registers -test_pattern_mode 0x0600 16 -- e none 0 -- e solid_color 1 -- e color_bars 2 -- e fade_to_grey 3 -- e pn9 4 -- e color_tile 5 -test_data_red 0x0602 16 -test_data_greenR 0x0604 16 -test_data_blue 0x0606 16 -test_data_greenB 0x0608 16 -value_step_size_smooth 0x060a 8 -value_step_size_quantised 0x060b 8 - -# phy configuration registers -tclk_post 0x0800 8 -ths_prepare 0x0801 8 -ths_zero_min 0x0802 8 -ths_trail 0x0803 8 -tclk_trail_min 0x0804 8 -tclk_prepare 0x0805 8 -tclk_zero 0x0806 8 -tlpx 0x0807 8 -phy_ctrl 0x0808 8 -- e auto 0 -- e UI 1 -- e manual 2 -tclk_post_ex 0x080a 16 -ths_prepare_ex 0x080c 16 -ths_zero_min_ex 0x080e 16 -ths_trail_ex 0x0810 16 -tclk_trail_min_ex 0x0812 16 -tclk_prepare_ex 0x0814 16 -tclk_zero_ex 0x0816 16 -tlpx_ex 0x0818 16 - -# link rate register -requested_link_rate 0x0820 32 u16.16 - -# equalization control registers -DPHY_equalization_mode 0x0824 8 v1.1 -- b eq2 0 -PHY_equalization_ctrl 0x0825 8 v1.1 -- b enable 0 - -# d-phy preamble control registers -DPHY_preamble_ctrl 0x0826 8 v1.1 -- b enable 0 -DPHY_preamble_length 0x0826 8 v1.1 - -# d-phy spread spectrum control registers -PHY_SSC_ctrl 0x0828 8 v1.1 -- b enable 0 - -# manual lp control register -manual_LP_ctrl 0x0829 8 v1.1 -- b enable 0 - -# additional phy configuration registers -twakeup 0x082a v1.1 -tinit 0x082b v1.1 -ths_exit 0x082c v1.1 -ths_exit_ex 0x082e 16 v1.1 - -# phy calibration configuration registers -PHY_periodic_calibration_ctrl 0x0830 8 -- b frame_blanking 0 -PHY_periodic_calibration_interval 0x0831 8 -PHY_init_calibration_ctrl 0x0832 8 -- b stream_start 0 -DPHY_calibration_mode 0x0833 8 v1.1 -- b also_alternate 0 -CPHY_calibration_mode 0x0834 8 v1.1 -- e format_1 0 -- e format_2 1 -- e format_3 2 -t3_calpreamble_length 0x0835 8 v1.1 -t3_calpreamble_length_per 0x0836 8 v1.1 -t3_calaltseq_length 0x0837 8 v1.1 -t3_calaltseq_length_per 0x0838 8 v1.1 -FM2_init_seed 0x083a 16 v1.1 -t3_caludefseq_length 0x083c 16 v1.1 -t3_caludefseq_length_per 0x083e 16 v1.1 - -# c-phy manual control registers -TGR_Preamble_Length 0x0841 8 -- b preamable_prog_seq 7 -- f begin_preamble_length 0 5 -TGR_Post_Length 0x0842 8 -- f post_length 0 4 -TGR_Preamble_Prog_Sequence(n2) 0x0843 -- l n2 0 6 1 -- f symbol_n_1 3 5 -- f symbol_n 0 2 -t3_prepare 0x084e 16 -t3_lpx 0x0850 16 - -# alps control register -ALPS_ctrl 0x085a 8 -- b lvlp_dphy 0 -- b lvlp_cphy 1 -- b alp_cphy 2 - -# lrte control registers -TX_REG_CSI_EPD_EN_SSP_cphy 0x0860 16 -TX_REG_CSI_EPD_OP_SLP_cphy 0x0862 16 -TX_REG_CSI_EPD_EN_SSP_dphy 0x0864 16 -TX_REG_CSI_EPD_OP_SLP_dphy 0x0866 16 -TX_REG_CSI_EPD_MISC_OPTION_cphy 0x0868 v1.1 -TX_REG_CSI_EPD_MISC_OPTION_dphy 0x0869 v1.1 - -# scrambling control registers -Scrambling_ctrl 0x0870 -- b enabled 0 -- f 2 3 -- e 1_seed_cphy 0 -- e 4_seed_cphy 3 -lane_seed_value(seed, lane) 0x0872 16 -- l seed 0 3 0x10 -- l lane 0 7 0x2 - -# usl control registers -TX_USL_REV_ENTRY 0x08c0 16 v1.1 -TX_USL_REV_Clock_Counter 0x08c2 16 v1.1 -TX_USL_REV_LP_Counter 0x08c4 16 v1.1 -TX_USL_REV_Frame_Counter 0x08c6 16 v1.1 -TX_USL_REV_Chronological_Timer 0x08c8 16 v1.1 -TX_USL_FWD_ENTRY 0x08ca 16 v1.1 -TX_USL_GPIO 0x08cc 16 v1.1 -TX_USL_Operation 0x08ce 16 v1.1 -- b reset 0 -TX_USL_ALP_ctrl 0x08d0 16 v1.1 -- b clock_pause 0 -TX_USL_APP_BTA_ACK_TIMEOUT 0x08d2 16 v1.1 -TX_USL_SNS_BTA_ACK_TIMEOUT 0x08d2 16 v1.1 -USL_Clock_Mode_d_ctrl 0x08d2 v1.1 -- b cont_clock_standby 0 -- b cont_clock_vblank 1 -- b cont_clock_hblank 2 - -# binning configuration registers -binning_mode 0x0900 8 -binning_type 0x0901 8 -binning_weighting 0x0902 8 - -# data transfer interface registers -data_transfer_if_1_ctrl 0x0a00 8 -- b enable 0 -- b write 1 -- b clear_error 2 -data_transfer_if_1_status 0x0a01 8 -- b read_if_ready 0 -- b write_if_ready 1 -- b data_corrupted 2 -- b improper_if_usage 3 -data_transfer_if_1_page_select 0x0a02 8 -data_transfer_if_1_data(p) 0x0a04 8 f -- l p 0 63 1 - -# image processing and sensor correction configuration registers -shading_correction_en 0x0b00 8 -- b enable 0 -luminance_correction_level 0x0b01 8 -green_imbalance_filter_en 0x0b02 8 -- b enable 0 -mapped_defect_correct_en 0x0b05 8 -- b enable 0 -single_defect_correct_en 0x0b06 8 -- b enable 0 -dynamic_couplet_correct_en 0x0b08 8 -- b enable 0 -combined_defect_correct_en 0x0b0a 8 -- b enable 0 -module_specific_correction_en 0x0b0c 8 -- b enable 0 -dynamic_triplet_defect_correct_en 0x0b13 8 -- b enable 0 -NF_ctrl 0x0b15 8 -- b luma 0 -- b chroma 1 -- b combined 2 - -# optical black pixel readout registers -OB_readout_control 0x0b30 8 -- b enable 0 -- b interleaving 1 -OB_virtual_channel 0x0b31 8 -OB_DT 0x0b32 8 -OB_data_format 0x0b33 8 - -# color temperature feedback registers -color_temperature 0x0b8c 16 -absolute_gain_greenr 0x0b8e 16 -absolute_gain_red 0x0b90 16 -absolute_gain_blue 0x0b92 16 -absolute_gain_greenb 0x0b94 16 - -# cfa conversion registers -CFA_conversion_ctrl 0x0ba0 v1.1 -- b bayer_conversion_enable 0 - -# flash strobe and sa strobe control registers -flash_strobe_adjustment 0x0c12 8 -flash_strobe_start_point 0x0c14 16 -tflash_strobe_delay_rs_ctrl 0x0c16 16 -tflash_strobe_width_high_rs_ctrl 0x0c18 16 -flash_mode_rs 0x0c1a 8 -- b continuous 0 -- b truncate 1 -- b async 3 -flash_trigger_rs 0x0c1b 8 -flash_status 0x0c1c 8 -- b retimed 0 -sa_strobe_mode 0x0c1d 8 -- b continuous 0 -- b truncate 1 -- b async 3 -- b adjust_edge 4 -sa_strobe_start_point 0x0c1e 16 -tsa_strobe_delay_ctrl 0x0c20 16 -tsa_strobe_width_ctrl 0x0c22 16 -sa_strobe_trigger 0x0c24 8 -sa_strobe_status 0x0c25 8 -- b retimed 0 -tSA_strobe_re_delay_ctrl 0x0c30 16 -tSA_strobe_fe_delay_ctrl 0x0c32 16 - -# pdaf control registers -PDAF_ctrl 0x0d00 16 -- b enable 0 -- b processed 1 -- b interleaved 2 -- b visible_pdaf_correction 3 -PDAF_VC 0x0d02 8 -PDAF_DT 0x0d03 8 -pd_x_addr_start 0x0d04 16 -pd_y_addr_start 0x0d06 16 -pd_x_addr_end 0x0d08 16 -pd_y_addr_end 0x0d0a 16 - -# bracketing interface configuration registers -bracketing_LUT_ctrl 0x0e00 8 -bracketing_LUT_mode 0x0e01 8 -- b continue_streaming 0 -- b loop_mode 1 -bracketing_LUT_entry_ctrl 0x0e02 8 -bracketing_LUT_frame(n) 0x0e10 v1.1 f -- l n 0 0xef 1 - -# integration time and gain parameter limit registers -integration_time_capability 0x1000 16 -- b fine 0 -coarse_integration_time_min 0x1004 16 -coarse_integration_time_max_margin 0x1006 16 -fine_integration_time_min 0x1008 16 -fine_integration_time_max_margin 0x100a 16 - -# digital gain parameter limit registers -digital_gain_capability 0x1081 -- e none 0 -- e global 2 -digital_gain_min 0x1084 16 -digital_gain_max 0x1086 16 -digital_gain_step_size 0x1088 16 - -# data pedestal capability registers -Pedestal_capability 0x10e0 8 v1.1 - -# adc capability registers -ADC_capability 0x10f0 8 -- b bit_depth_ctrl 0 -ADC_bit_depth_capability 0x10f4 32 v1.1 - -# video timing parameter limit registers -min_ext_clk_freq_mhz 0x1100 32 float_ireal -max_ext_clk_freq_mhz 0x1104 32 float_ireal -min_pre_pll_clk_div 0x1108 16 -# min_vt_pre_pll_clk_div 0x1108 16 -max_pre_pll_clk_div 0x110a 16 -# max_vt_pre_pll_clk_div 0x110a 16 -min_pll_ip_clk_freq_mhz 0x110c 32 float_ireal -# min_vt_pll_ip_clk_freq_mhz 0x110c 32 float_ireal -max_pll_ip_clk_freq_mhz 0x1110 32 float_ireal -# max_vt_pll_ip_clk_freq_mhz 0x1110 32 float_ireal -min_pll_multiplier 0x1114 16 -# min_vt_pll_multiplier 0x1114 16 -max_pll_multiplier 0x1116 16 -# max_vt_pll_multiplier 0x1116 16 -min_pll_op_clk_freq_mhz 0x1118 32 float_ireal -max_pll_op_clk_freq_mhz 0x111c 32 float_ireal - -# video timing set-up capability registers -min_vt_sys_clk_div 0x1120 16 -max_vt_sys_clk_div 0x1122 16 -min_vt_sys_clk_freq_mhz 0x1124 32 float_ireal -max_vt_sys_clk_freq_mhz 0x1128 32 float_ireal -min_vt_pix_clk_freq_mhz 0x112c 32 float_ireal -max_vt_pix_clk_freq_mhz 0x1130 32 float_ireal -min_vt_pix_clk_div 0x1134 16 -max_vt_pix_clk_div 0x1136 16 -clock_calculation 0x1138 -- b lane_speed 0 -- b link_decoupled 1 -- b dual_pll_op_sys_ddr 2 -- b dual_pll_op_pix_ddr 3 -num_of_vt_lanes 0x1139 -num_of_op_lanes 0x113a -op_bits_per_lane 0x113b 8 v1.1 - -# frame timing parameter limits -min_frame_length_lines 0x1140 16 -max_frame_length_lines 0x1142 16 -min_line_length_pck 0x1144 16 -max_line_length_pck 0x1146 16 -min_line_blanking_pck 0x1148 16 -min_frame_blanking_lines 0x114a 16 -min_line_length_pck_step_size 0x114c -timing_mode_capability 0x114d -- b auto_frame_length 0 -- b rolling_shutter_manual_readout 2 -- b delayed_exposure_start 3 -- b manual_exposure_embedded_data 4 -frame_margin_max_value 0x114e 16 -frame_margin_min_value 0x1150 -gain_delay_type 0x1151 -- e fixed 0 -- e variable 1 - -# output clock set-up capability registers -min_op_sys_clk_div 0x1160 16 -max_op_sys_clk_div 0x1162 16 -min_op_sys_clk_freq_mhz 0x1164 32 float_ireal -max_op_sys_clk_freq_mhz 0x1168 32 float_ireal -min_op_pix_clk_div 0x116c 16 -max_op_pix_clk_div 0x116e 16 -min_op_pix_clk_freq_mhz 0x1170 32 float_ireal -max_op_pix_clk_freq_mhz 0x1174 32 float_ireal - -# image size parameter limit registers -x_addr_min 0x1180 16 -y_addr_min 0x1182 16 -x_addr_max 0x1184 16 -y_addr_max 0x1186 16 -min_x_output_size 0x1188 16 -min_y_output_size 0x118a 16 -max_x_output_size 0x118c 16 -max_y_output_size 0x118e 16 - -x_addr_start_div_constant 0x1190 v1.1 -y_addr_start_div_constant 0x1191 v1.1 -x_addr_end_div_constant 0x1192 v1.1 -y_addr_end_div_constant 0x1193 v1.1 -x_size_div 0x1194 v1.1 -y_size_div 0x1195 v1.1 -x_output_div 0x1196 v1.1 -y_output_div 0x1197 v1.1 -non_flexible_resolution_support 0x1198 v1.1 -- b new_pix_addr 0 -- b new_output_res 1 -- b output_crop_no_pad 2 -- b output_size_lane_dep 3 - -min_op_pre_pll_clk_div 0x11a0 16 -max_op_pre_pll_clk_div 0x11a2 16 -min_op_pll_ip_clk_freq_mhz 0x11a4 32 float_ireal -max_op_pll_ip_clk_freq_mhz 0x11a8 32 float_ireal -min_op_pll_multiplier 0x11ac 16 -max_op_pll_multiplier 0x11ae 16 -min_op_pll_op_clk_freq_mhz 0x11b0 32 float_ireal -max_op_pll_op_clk_freq_mhz 0x11b4 32 float_ireal -clock_tree_pll_capability 0x11b8 8 -- b dual_pll 0 -- b single_pll 1 -- b ext_divider 2 -- b flexible_op_pix_clk_div 3 -clock_capa_type_capability 0x11b9 v1.1 -- b ireal 0 - -# sub-sampling parameters limit registers -min_even_inc 0x11c0 16 -min_odd_inc 0x11c2 16 -max_even_inc 0x11c4 16 -max_odd_inc 0x11c6 16 -aux_subsamp_capability 0x11c8 v1.1 -- b factor_power_of_2 1 -aux_subsamp_mono_capability 0x11c9 v1.1 -- b factor_power_of_2 1 -monochrome_capability 0x11ca v1.1 -- e inc_odd 0 -- e inc_even 1 -pixel_readout_capability 0x11cb v1.1 -- e bayer 0 -- e monochrome 1 -- e bayer_and_mono 2 -min_even_inc_mono 0x11cc 16 v1.1 -max_even_inc_mono 0x11ce 16 v1.1 -min_odd_inc_mono 0x11d0 16 v1.1 -max_odd_inc_mono 0x11d2 16 v1.1 -min_even_inc_bc2 0x11d4 16 v1.1 -max_even_inc_bc2 0x11d6 16 v1.1 -min_odd_inc_bc2 0x11d8 16 v1.1 -max_odd_inc_bc2 0x11da 16 v1.1 -min_even_inc_mono_bc2 0x11dc 16 v1.1 -max_even_inc_mono_bc2 0x11de 16 v1.1 -min_odd_inc_mono_bc2 0x11f0 16 v1.1 -max_odd_inc_mono_bc2 0x11f2 16 v1.1 - -# image scaling limit parameters -scaling_capability 0x1200 16 -- e none 0 -- e horizontal 1 -- e reserved 2 -scaler_m_min 0x1204 16 -scaler_m_max 0x1206 16 -scaler_n_min 0x1208 16 -scaler_n_max 0x120a 16 -digital_crop_capability 0x120e -- e none 0 -- e input_crop 1 - -# hdr limit registers -hdr_capability_1 0x1210 -- b 2x2_binning 0 -- b combined_analog_gain 1 -- b separate_analog_gain 2 -- b upscaling 3 -- b reset_sync 4 -- b direct_short_exp_timing 5 -- b direct_short_exp_synthesis 6 -min_hdr_bit_depth 0x1211 -hdr_resolution_sub_types 0x1212 -hdr_resolution_sub_type(n) 0x1213 -- l n 0 1 1 -- f row 0 3 -- f column 4 7 -hdr_capability_2 0x121b -- b combined_digital_gain 0 -- b separate_digital_gain 1 -- b timing_mode 3 -- b synthesis_mode 4 -max_hdr_bit_depth 0x121c - -# usl capability register -usl_support_capability 0x1230 v1.1 -- b clock_tree 0 -- b rev_clock_tree 1 -- b rev_clock_calc 2 -usl_clock_mode_d_capability 0x1231 v1.1 -- b cont_clock_standby 0 -- b cont_clock_vblank 1 -- b cont_clock_hblank 2 -- b noncont_clock_standby 3 -- b noncont_clock_vblank 4 -- b noncont_clock_hblank 5 -min_op_sys_clk_div_rev 0x1234 v1.1 -max_op_sys_clk_div_rev 0x1236 v1.1 -min_op_pix_clk_div_rev 0x1238 v1.1 -max_op_pix_clk_div_rev 0x123a v1.1 -min_op_sys_clk_freq_rev_mhz 0x123c 32 v1.1 float_ireal -max_op_sys_clk_freq_rev_mhz 0x1240 32 v1.1 float_ireal -min_op_pix_clk_freq_rev_mhz 0x1244 32 v1.1 float_ireal -max_op_pix_clk_freq_rev_mhz 0x1248 32 v1.1 float_ireal -max_bitrate_rev_d_mode_mbps 0x124c 32 v1.1 ireal -max_symrate_rev_c_mode_msps 0x1250 32 v1.1 ireal - -# image compression capability registers -compression_capability 0x1300 -- b dpcm_pcm_simple 0 - -# test mode capability registers -test_mode_capability 0x1310 16 -- b solid_color 0 -- b color_bars 1 -- b fade_to_grey 2 -- b pn9 3 -- b color_tile 5 -pn9_data_format1 0x1312 -pn9_data_format2 0x1313 -pn9_data_format3 0x1314 -pn9_data_format4 0x1315 -pn9_misc_capability 0x1316 -- f num_pixels 0 2 -- b compression 3 -test_pattern_capability 0x1317 v1.1 -- b no_repeat 1 -pattern_size_div_m1 0x1318 v1.1 - -# fifo capability registers -fifo_support_capability 0x1502 -- e none 0 -- e derating 1 -- e derating_overrating 2 - -# csi-2 capability registers -phy_ctrl_capability 0x1600 -- b auto_phy_ctl 0 -- b ui_phy_ctl 1 -- b dphy_time_ui_reg_1_ctl 2 -- b dphy_time_ui_reg_2_ctl 3 -- b dphy_time_ctl 4 -- b dphy_ext_time_ui_reg_1_ctl 5 -- b dphy_ext_time_ui_reg_2_ctl 6 -- b dphy_ext_time_ctl 7 -csi_dphy_lane_mode_capability 0x1601 -- b 1_lane 0 -- b 2_lane 1 -- b 3_lane 2 -- b 4_lane 3 -- b 5_lane 4 -- b 6_lane 5 -- b 7_lane 6 -- b 8_lane 7 -csi_signaling_mode_capability 0x1602 -- b csi_dphy 2 -- b csi_cphy 3 -fast_standby_capability 0x1603 -- e no_frame_truncation 0 -- e frame_truncation 1 -csi_address_control_capability 0x1604 -- b cci_addr_change 0 -- b 2nd_cci_addr 1 -- b sw_changeable_2nd_cci_addr 2 -data_type_capability 0x1605 -- b dpcm_programmable 0 -- b bottom_embedded_dt_programmable 1 -- b bottom_embedded_vc_programmable 2 -- b ext_vc_range 3 -csi_cphy_lane_mode_capability 0x1606 -- b 1_lane 0 -- b 2_lane 1 -- b 3_lane 2 -- b 4_lane 3 -- b 5_lane 4 -- b 6_lane 5 -- b 7_lane 6 -- b 8_lane 7 -emb_data_capability 0x1607 v1.1 -- b two_bytes_per_raw16 0 -- b two_bytes_per_raw20 1 -- b two_bytes_per_raw24 2 -- b no_one_byte_per_raw16 3 -- b no_one_byte_per_raw20 4 -- b no_one_byte_per_raw24 5 -max_per_lane_bitrate_lane_d_mode_mbps(n) 0x1608 32 ireal -- l n 0 7 4 4,0x32 -temp_sensor_capability 0x1618 -- b supported 0 -- b CCS_format 1 -- b reset_0x80 2 -max_per_lane_bitrate_lane_c_mode_mbps(n) 0x161a 32 ireal -- l n 0 7 4 4,0x30 -dphy_equalization_capability 0x162b -- b equalization_ctrl 0 -- b eq1 1 -- b eq2 2 -cphy_equalization_capability 0x162c -- b equalization_ctrl 0 -dphy_preamble_capability 0x162d -- b preamble_seq_ctrl 0 -dphy_ssc_capability 0x162e -- b supported 0 -cphy_calibration_capability 0x162f -- b manual 0 -- b manual_streaming 1 -- b format_1_ctrl 2 -- b format_2_ctrl 3 -- b format_3_ctrl 4 -dphy_calibration_capability 0x1630 -- b manual 0 -- b manual_streaming 1 -- b alternate_seq 2 -phy_ctrl_capability_2 0x1631 -- b tgr_length 0 -- b tgr_preamble_prog_seq 1 -- b extra_cphy_manual_timing 2 -- b clock_based_manual_cdphy 3 -- b clock_based_manual_dphy 4 -- b clock_based_manual_cphy 5 -- b manual_lp_dphy 6 -- b manual_lp_cphy 7 -lrte_cphy_capability 0x1632 -- b pdq_short 0 -- b spacer_short 1 -- b pdq_long 2 -- b spacer_long 3 -- b spacer_no_pdq 4 -lrte_dphy_capability 0x1633 -- b pdq_short_opt1 0 -- b spacer_short_opt1 1 -- b pdq_long_opt1 2 -- b spacer_long_opt1 3 -- b spacer_short_opt2 4 -- b spacer_long_opt2 5 -- b spacer_no_pdq_opt1 6 -- b spacer_variable_opt2 7 -alps_capability_dphy 0x1634 -- e lvlp_not_supported 0 0x3 -- e lvlp_supported 1 0x3 -- e controllable_lvlp 2 0x3 -alps_capability_cphy 0x1635 -- e lvlp_not_supported 0 0x3 -- e lvlp_supported 1 0x3 -- e controllable_lvlp 2 0x3 -- e alp_not_supported 0xc 0xc -- e alp_supported 0xd 0xc -- e controllable_alp 0xe 0xc -scrambling_capability 0x1636 -- b scrambling_supported 0 -- f max_seeds_per_lane_c 1 2 -- e 1 0 -- e 4 3 -- f num_seed_regs 3 5 -- e 0 0 -- e 1 1 -- e 4 4 -- b num_seed_per_lane 6 -dphy_manual_constant 0x1637 -cphy_manual_constant 0x1638 -CSI2_interface_capability_misc 0x1639 v1.1 -- b eotp_short_pkt_opt2 0 -PHY_ctrl_capability_3 0x165c v1.1 -- b dphy_timing_not_multiple 0 -- b dphy_min_timing_value_1 1 -- b twakeup_supported 2 -- b tinit_supported 3 -- b ths_exit_supported 4 -- b cphy_timing_not_multiple 5 -- b cphy_min_timing_value_1 6 -dphy_sf 0x165d v1.1 -cphy_sf 0x165e v1.1 -- f twakeup 0 3 -- f tinit 4 7 -dphy_limits_1 0x165f v1.1 -- f ths_prepare 0 3 -- f ths_zero 4 7 -dphy_limits_2 0x1660 v1.1 -- f ths_trail 0 3 -- f tclk_trail_min 4 7 -dphy_limits_3 0x1661 v1.1 -- f tclk_prepare 0 3 -- f tclk_zero 4 7 -dphy_limits_4 0x1662 v1.1 -- f tclk_post 0 3 -- f tlpx 4 7 -dphy_limits_5 0x1663 v1.1 -- f ths_exit 0 3 -- f twakeup 4 7 -dphy_limits_6 0x1664 v1.1 -- f tinit 0 3 -cphy_limits_1 0x1665 v1.1 -- f t3_prepare_max 0 3 -- f t3_lpx_max 4 7 -cphy_limits_2 0x1666 v1.1 -- f ths_exit_max 0 3 -- f twakeup_max 4 7 -cphy_limits_3 0x1667 v1.1 -- f tinit_max 0 3 - -# binning capability registers -min_frame_length_lines_bin 0x1700 16 -max_frame_length_lines_bin 0x1702 16 -min_line_length_pck_bin 0x1704 16 -max_line_length_pck_bin 0x1706 16 -min_line_blanking_pck_bin 0x1708 16 -fine_integration_time_min_bin 0x170a 16 -fine_integration_time_max_margin_bin 0x170c 16 -binning_capability 0x1710 -- e unsupported 0 -- e binning_then_subsampling 1 -- e subsampling_then_binning 2 -binning_weighting_capability 0x1711 -- b averaged 0 -- b summed 1 -- b bayer_corrected 2 -- b module_specific_weight 3 -binning_sub_types 0x1712 -binning_sub_type(n) 0x1713 -- l n 0 63 1 -- f row 0 3 -- f column 4 7 -binning_weighting_mono_capability 0x1771 v1.1 -- b averaged 0 -- b summed 1 -- b bayer_corrected 2 -- b module_specific_weight 3 -binning_sub_types_mono 0x1772 v1.1 -binning_sub_type_mono(n) 0x1773 v1.1 f -- l n 0 63 1 - -# data transfer interface capability registers -data_transfer_if_capability 0x1800 -- b supported 0 -- b polling 2 - -# sensor correction capability registers -shading_correction_capability 0x1900 -- b color_shading 0 -- b luminance_correction 1 -green_imbalance_capability 0x1901 -- b supported 0 -module_specific_correction_capability 0x1903 -defect_correction_capability 0x1904 16 -- b mapped_defect 0 -- b dynamic_couplet 2 -- b dynamic_single 5 -- b combined_dynamic 8 -defect_correction_capability_2 0x1906 16 -- b dynamic_triplet 3 -nf_capability 0x1908 -- b luma 0 -- b chroma 1 -- b combined 2 - -# optical black readout capability registers -ob_readout_capability 0x1980 -- b controllable_readout 0 -- b visible_pixel_readout 1 -- b different_vc_readout 2 -- b different_dt_readout 3 -- b prog_data_format 4 - -# color feedback capability registers -color_feedback_capability 0x1987 -- b kelvin 0 -- b awb_gain 1 - -# cfa pattern capability registers -CFA_pattern_capability 0x1990 v1.1 -- e bayer 0 -- e monochrome 1 -- e 4x4_quad_bayer 2 -- e vendor_specific 3 -CFA_pattern_conversion_capability 0x1991 v1.1 -- b bayer 0 - -# timer capability registers -flash_mode_capability 0x1a02 -- b single_strobe 0 -sa_strobe_mode_capability 0x1a03 -- b fixed_width 0 -- b edge_ctrl 1 - -# soft reset capability registers -reset_max_delay 0x1a10 v1.1 -reset_min_time 0x1a11 v1.1 - -# pdaf capability registers -pdaf_capability_1 0x1b80 -- b supported 0 -- b processed_bottom_embedded 1 -- b processed_interleaved 2 -- b raw_bottom_embedded 3 -- b raw_interleaved 4 -- b visible_pdaf_correction 5 -- b vc_interleaving 6 -- b dt_interleaving 7 -pdaf_capability_2 0x1b81 -- b ROI 0 -- b after_digital_crop 1 -- b ctrl_retimed 2 - -# bracketing interface capability registers -bracketing_lut_capability_1 0x1c00 -- b coarse_integration 0 -- b global_analog_gain 1 -- b flash 4 -- b global_digital_gain 5 -- b alternate_global_analog_gain 6 -bracketing_lut_capability_2 0x1c01 -- b single_bracketing_mode 0 -- b looped_bracketing_mode 1 -bracketing_lut_size 0x1c02 diff --git a/Documentation/driver-api/media/drivers/ccs/ccs.rst b/Documentation/driver-api/media/drivers/ccs/ccs.rst index 9164c9fa8b42..f49e971f2d92 100644 --- a/Documentation/driver-api/media/drivers/ccs/ccs.rst +++ b/Documentation/driver-api/media/drivers/ccs/ccs.rst @@ -59,7 +59,7 @@ effect in device timing and likely also in power consumption. Register definition generator ----------------------------- -The ccs-regs.txt file contains MIPI CCS register definitions that are used +The ccs-regs.asc file contains MIPI CCS register definitions that are used to produce C source code files for definitions that can be better used by programs written in C language. As there are many dependencies between the produced files, please do not modify them manually as it's error-prone and @@ -77,6 +77,6 @@ definitions: -e drivers/media/i2c/ccs/ccs-regs.h \ -L drivers/media/i2c/ccs/ccs-limits.h \ -l drivers/media/i2c/ccs/ccs-limits.c \ - -c Documentation/driver-api/media/drivers/ccs/ccs-regs.txt + -c Documentation/driver-api/media/drivers/ccs/ccs-regs.asc **Copyright** |copy| 2020 Intel Corporation diff --git a/Documentation/driver-api/media/drivers/ccs/mk-ccs-regs b/Documentation/driver-api/media/drivers/ccs/mk-ccs-regs index 3d6a2a7aac3a..6668deaf2f19 100755 --- a/Documentation/driver-api/media/drivers/ccs/mk-ccs-regs +++ b/Documentation/driver-api/media/drivers/ccs/mk-ccs-regs @@ -5,7 +5,7 @@ use Getopt::Long qw(:config no_ignore_case); use File::Basename; -my $ccsregs = "ccs-regs.txt"; +my $ccsregs = "ccs-regs.asc"; my $header; my $regarray; my $limitc; @@ -27,7 +27,7 @@ if (defined $help) { print < Date: Wed, 2 Dec 2020 15:18:19 +0100 Subject: media: Documentation: ccs: Reorder SPDX and copyright notice lines Move the SPDX tag to the top, placing the copyright notice after that. This aligns the file with existing practices. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- Documentation/driver-api/media/drivers/ccs/ccs-regs.asc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/driver-api/media/drivers/ccs/ccs-regs.asc b/Documentation/driver-api/media/drivers/ccs/ccs-regs.asc index 93f0131aa304..f2042acc8a45 100644 --- a/Documentation/driver-api/media/drivers/ccs/ccs-regs.asc +++ b/Documentation/driver-api/media/drivers/ccs/ccs-regs.asc @@ -1,5 +1,5 @@ -# Copyright (C) 2019--2020 Intel Corporation # SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause +# Copyright (C) 2019--2020 Intel Corporation # register rflags # - f field LSB MSB rflags -- cgit v1.2.3 From adc00b457937233b4f392e7fcc6d20ab0227e414 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 11 Feb 2020 22:31:51 +0100 Subject: media: ccs: Add MIPI CCS compatible strings Add "mipi-ccs-1.0" and "mipi-ccs-1.1" compatible strings to the CCS driver. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 69e7990c65f3..64bad5b678a3 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -3236,6 +3236,9 @@ static int ccs_remove(struct i2c_client *client) } static const struct of_device_id ccs_of_table[] = { + { .compatible = "mipi-ccs-1.1" }, + { .compatible = "mipi-ccs-1.0" }, + { .compatible = "mipi-ccs" }, { .compatible = "nokia,smia" }, { }, }; -- cgit v1.2.3 From ca21c45a86ff07e11c7b753072f4e4cc6cd6e093 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 21 Sep 2020 18:04:47 +0200 Subject: media: ccs: Add device compatible identifiers for telling SMIA and CCS apart Add device data specific to DT compatible ID to tell SMIA and CCS devices apart already in power-up. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 64bad5b678a3..1d365da570a6 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -58,6 +58,12 @@ static const struct ccs_module_ident ccs_module_idents[] = { CCS_IDENT_LQ(0x10, 0x4241, -1, "imx125es", &smiapp_imx125es_quirk), }; +#define CCS_DEVICE_FLAG_IS_SMIA BIT(0) + +struct ccs_device { + unsigned char flags; +}; + /* * * Dynamic Capability Identification @@ -3235,11 +3241,17 @@ static int ccs_remove(struct i2c_client *client) return 0; } +static const struct ccs_device smia_device = { + .flags = CCS_DEVICE_FLAG_IS_SMIA, +}; + +static const struct ccs_device ccs_device = {}; + static const struct of_device_id ccs_of_table[] = { - { .compatible = "mipi-ccs-1.1" }, - { .compatible = "mipi-ccs-1.0" }, - { .compatible = "mipi-ccs" }, - { .compatible = "nokia,smia" }, + { .compatible = "mipi-ccs-1.1", .data = &ccs_device }, + { .compatible = "mipi-ccs-1.0", .data = &ccs_device }, + { .compatible = "mipi-ccs", .data = &ccs_device }, + { .compatible = "nokia,smia", .data = &smia_device }, { }, }; MODULE_DEVICE_TABLE(of, ccs_of_table); -- cgit v1.2.3 From 67b8dc1d0c4a82a8001e36f8763aba5b754e6601 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 3 Feb 2020 12:44:35 +0100 Subject: media: ccs: Add CCS ACPI device ID The CCS compliant sensors use device ID "MIPI0200". Use this id for ACPI device matching. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 1d365da570a6..bb712d71b8c8 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -3247,6 +3247,12 @@ static const struct ccs_device smia_device = { static const struct ccs_device ccs_device = {}; +static const struct acpi_device_id ccs_acpi_table[] = { + { .id = "MIPI0200", .driver_data = (unsigned long)&ccs_device }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, ccs_acpi_table); + static const struct of_device_id ccs_of_table[] = { { .compatible = "mipi-ccs-1.1", .data = &ccs_device }, { .compatible = "mipi-ccs-1.0", .data = &ccs_device }, @@ -3269,6 +3275,7 @@ static const struct dev_pm_ops ccs_pm_ops = { static struct i2c_driver ccs_i2c_driver = { .driver = { + .acpi_match_table = ccs_acpi_table, .of_match_table = ccs_of_table, .name = CCS_NAME, .pm = &ccs_pm_ops, -- cgit v1.2.3 From af1eed0ccd8691b8eb25dcc659fbea7c07730ce5 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 11 Feb 2020 22:32:36 +0100 Subject: media: ccs: Remove the I²C ID table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The I²C ID table is no longer needed; remove it. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index bb712d71b8c8..bb3759e2534c 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -3262,12 +3262,6 @@ static const struct of_device_id ccs_of_table[] = { }; MODULE_DEVICE_TABLE(of, ccs_of_table); -static const struct i2c_device_id ccs_id_table[] = { - { SMIAPP_NAME, 0 }, - { }, -}; -MODULE_DEVICE_TABLE(i2c, ccs_id_table); - static const struct dev_pm_ops ccs_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(ccs_suspend, ccs_resume) SET_RUNTIME_PM_OPS(ccs_power_off, ccs_power_on, NULL) @@ -3282,7 +3276,6 @@ static struct i2c_driver ccs_i2c_driver = { }, .probe_new = ccs_probe, .remove = ccs_remove, - .id_table = ccs_id_table, }; static int ccs_module_init(void) -- cgit v1.2.3 From 5323aaf19e6c0e184edb23eb70cfe5da38f2c1fb Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 11 Feb 2020 22:35:40 +0100 Subject: media: ccs: Remove remaining support for platform data No need to support platform data; remove support for conveying hardware configuration that way. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index bb3759e2534c..af79d80ebb59 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -2860,9 +2860,6 @@ static struct ccs_hwconfig *ccs_get_hwconfig(struct device *dev) int i; int rval; - if (!fwnode) - return dev->platform_data; - ep = fwnode_graph_get_next_endpoint(fwnode, NULL); if (!ep) return NULL; -- cgit v1.2.3 From 7b1dd0f85013c33d5eba1f69503bf29c8e17131e Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 11 Feb 2020 22:41:39 +0100 Subject: media: ccs: Make hwcfg part of the device specific struct There's no need to allocate the hardware configuration struct separately. Put it in struct ccs_sensor. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 94 ++++++++++++++++++++------------------- drivers/media/i2c/ccs/ccs-quirk.c | 4 +- drivers/media/i2c/ccs/ccs.h | 2 +- 3 files changed, 51 insertions(+), 49 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index af79d80ebb59..dcc71c8fe075 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -809,7 +809,7 @@ static int ccs_init_late_controls(struct ccs_sensor *sensor) sensor->link_freq = v4l2_ctrl_new_int_menu( &sensor->src->ctrl_handler, &ccs_ctrl_ops, V4L2_CID_LINK_FREQ, __fls(*valid_link_freqs), - __ffs(*valid_link_freqs), sensor->hwcfg->op_sys_clock); + __ffs(*valid_link_freqs), sensor->hwcfg.op_sys_clock); return sensor->src->ctrl_handler.error; } @@ -922,8 +922,8 @@ static int ccs_get_mbus_formats(struct ccs_sensor *sensor) pll->bits_per_pixel = f->compressed; - for (j = 0; sensor->hwcfg->op_sys_clock[j]; j++) { - pll->link_freq = sensor->hwcfg->op_sys_clock[j]; + for (j = 0; sensor->hwcfg.op_sys_clock[j]; j++) { + pll->link_freq = sensor->hwcfg.op_sys_clock[j]; rval = ccs_pll_try(sensor, pll); dev_dbg(&client->dev, "link freq %u Hz, bpp %u %s\n", @@ -1123,21 +1123,21 @@ static int ccs_change_cci_addr(struct ccs_sensor *sensor) int rval; u32 val; - client->addr = sensor->hwcfg->i2c_addr_dfl; + client->addr = sensor->hwcfg.i2c_addr_dfl; rval = ccs_write(sensor, CCI_ADDRESS_CTRL, - sensor->hwcfg->i2c_addr_alt << 1); + sensor->hwcfg.i2c_addr_alt << 1); if (rval) return rval; - client->addr = sensor->hwcfg->i2c_addr_alt; + client->addr = sensor->hwcfg.i2c_addr_alt; /* verify addr change went ok */ rval = ccs_read(sensor, CCI_ADDRESS_CTRL, &val); if (rval) return rval; - if (val != sensor->hwcfg->i2c_addr_alt << 1) + if (val != sensor->hwcfg.i2c_addr_alt << 1) return -ENODEV; return 0; @@ -1151,13 +1151,13 @@ static int ccs_change_cci_addr(struct ccs_sensor *sensor) static int ccs_setup_flash_strobe(struct ccs_sensor *sensor) { struct ccs_flash_strobe_parms *strobe_setup; - unsigned int ext_freq = sensor->hwcfg->ext_clk; + unsigned int ext_freq = sensor->hwcfg.ext_clk; u32 tmp; u32 strobe_adjustment; u32 strobe_width_high_rs; int rval; - strobe_setup = sensor->hwcfg->strobe_setup; + strobe_setup = sensor->hwcfg.strobe_setup; /* * How to calculate registers related to strobe length. Please @@ -1265,7 +1265,7 @@ static int ccs_setup_flash_strobe(struct ccs_sensor *sensor) rval = ccs_write(sensor, FLASH_TRIGGER_RS, strobe_setup->trigger); out: - sensor->hwcfg->strobe_setup->trigger = 0; + sensor->hwcfg.strobe_setup->trigger = 0; return rval; } @@ -1304,7 +1304,7 @@ static int ccs_power_on(struct device *dev) gpiod_set_value(sensor->reset, 0); gpiod_set_value(sensor->xshutdown, 1); - sleep = SMIAPP_RESET_DELAY(sensor->hwcfg->ext_clk); + sleep = SMIAPP_RESET_DELAY(sensor->hwcfg.ext_clk); usleep_range(sleep, sleep); /* @@ -1318,7 +1318,7 @@ static int ccs_power_on(struct device *dev) * is found. */ - if (sensor->hwcfg->i2c_addr_alt) { + if (sensor->hwcfg.i2c_addr_alt) { rval = ccs_change_cci_addr(sensor); if (rval) { dev_err(dev, "cci address change error\n"); @@ -1332,7 +1332,7 @@ static int ccs_power_on(struct device *dev) goto out_cci_addr_fail; } - if (sensor->hwcfg->i2c_addr_alt) { + if (sensor->hwcfg.i2c_addr_alt) { rval = ccs_change_cci_addr(sensor); if (rval) { dev_err(dev, "cci address change error\n"); @@ -1348,13 +1348,13 @@ static int ccs_power_on(struct device *dev) } rval = ccs_write(sensor, EXTCLK_FREQUENCY_MHZ, - sensor->hwcfg->ext_clk / (1000000 / (1 << 8))); + sensor->hwcfg.ext_clk / (1000000 / (1 << 8))); if (rval) { dev_err(dev, "extclk frequency set failed\n"); goto out_cci_addr_fail; } - rval = ccs_write(sensor, CSI_LANE_MODE, sensor->hwcfg->lanes - 1); + rval = ccs_write(sensor, CSI_LANE_MODE, sensor->hwcfg.lanes - 1); if (rval) { dev_err(dev, "csi lane mode set failed\n"); goto out_cci_addr_fail; @@ -1368,7 +1368,7 @@ static int ccs_power_on(struct device *dev) } rval = ccs_write(sensor, CSI_SIGNALING_MODE, - sensor->hwcfg->csi_signalling_mode); + sensor->hwcfg.csi_signalling_mode); if (rval) { dev_err(dev, "csi signalling mode set failed\n"); goto out_cci_addr_fail; @@ -1412,7 +1412,7 @@ static int ccs_power_off(struct device *dev) * really see a power off and next time the cci address change * will fail. So do a soft reset explicitly here. */ - if (sensor->hwcfg->i2c_addr_alt) + if (sensor->hwcfg.i2c_addr_alt) ccs_write(sensor, SOFTWARE_RESET, CCS_SOFTWARE_RESET_ON); gpiod_set_value(sensor->reset, 1); @@ -1551,8 +1551,8 @@ static int ccs_start_streaming(struct ccs_sensor *sensor) if (CCS_LIM(sensor, FLASH_MODE_CAPABILITY) & (CCS_FLASH_MODE_CAPABILITY_SINGLE_STROBE | SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE) && - sensor->hwcfg->strobe_setup != NULL && - sensor->hwcfg->strobe_setup->trigger != 0) { + sensor->hwcfg.strobe_setup != NULL && + sensor->hwcfg.strobe_setup->trigger != 0) { rval = ccs_setup_flash_strobe(sensor); if (rval) goto out; @@ -2850,9 +2850,9 @@ static int __maybe_unused ccs_resume(struct device *dev) return rval; } -static struct ccs_hwconfig *ccs_get_hwconfig(struct device *dev) +static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev) { - struct ccs_hwconfig *hwcfg; + struct ccs_hwconfig *hwcfg = &sensor->hwcfg; struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 }; struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); @@ -2862,7 +2862,7 @@ static struct ccs_hwconfig *ccs_get_hwconfig(struct device *dev) ep = fwnode_graph_get_next_endpoint(fwnode, NULL); if (!ep) - return NULL; + return -ENODEV; bus_cfg.bus_type = V4L2_MBUS_CSI2_DPHY; rval = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); @@ -2874,10 +2874,6 @@ static struct ccs_hwconfig *ccs_get_hwconfig(struct device *dev) if (rval) goto out_err; - hwcfg = devm_kzalloc(dev, sizeof(*hwcfg), GFP_KERNEL); - if (!hwcfg) - goto out_err; - switch (bus_cfg.bus_type) { case V4L2_MBUS_CSI2_DPHY: hwcfg->csi_signalling_mode = CCS_CSI_SIGNALING_MODE_CSI_2_DPHY; @@ -2891,6 +2887,7 @@ static struct ccs_hwconfig *ccs_get_hwconfig(struct device *dev) break; default: dev_err(dev, "unsupported bus %u\n", bus_cfg.bus_type); + rval = -EINVAL; goto out_err; } @@ -2907,6 +2904,7 @@ static struct ccs_hwconfig *ccs_get_hwconfig(struct device *dev) break; default: dev_err(dev, "invalid rotation %u\n", rotation); + rval = -EINVAL; goto out_err; } } @@ -2921,14 +2919,17 @@ static struct ccs_hwconfig *ccs_get_hwconfig(struct device *dev) if (!bus_cfg.nr_of_link_frequencies) { dev_warn(dev, "no link frequencies defined\n"); + rval = -EINVAL; goto out_err; } hwcfg->op_sys_clock = devm_kcalloc( dev, bus_cfg.nr_of_link_frequencies + 1 /* guardian */, sizeof(*hwcfg->op_sys_clock), GFP_KERNEL); - if (!hwcfg->op_sys_clock) + if (!hwcfg->op_sys_clock) { + rval = -ENOMEM; goto out_err; + } for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) { hwcfg->op_sys_clock[i] = bus_cfg.link_frequencies[i]; @@ -2937,29 +2938,30 @@ static struct ccs_hwconfig *ccs_get_hwconfig(struct device *dev) v4l2_fwnode_endpoint_free(&bus_cfg); fwnode_handle_put(ep); - return hwcfg; + + return 0; out_err: v4l2_fwnode_endpoint_free(&bus_cfg); fwnode_handle_put(ep); - return NULL; + + return rval; } static int ccs_probe(struct i2c_client *client) { struct ccs_sensor *sensor; - struct ccs_hwconfig *hwcfg = ccs_get_hwconfig(&client->dev); unsigned int i; int rval; - if (hwcfg == NULL) - return -ENODEV; - sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL); if (sensor == NULL) return -ENOMEM; - sensor->hwcfg = hwcfg; + rval = ccs_get_hwconfig(sensor, &client->dev); + if (rval) + return rval; + sensor->src = &sensor->ssds[sensor->ssds_used]; v4l2_i2c_subdev_init(&sensor->src->sd, client, &ccs_ops); @@ -2982,33 +2984,33 @@ static int ccs_probe(struct i2c_client *client) } if (sensor->ext_clk) { - if (sensor->hwcfg->ext_clk) { + if (sensor->hwcfg.ext_clk) { unsigned long rate; rval = clk_set_rate(sensor->ext_clk, - sensor->hwcfg->ext_clk); + sensor->hwcfg.ext_clk); if (rval < 0) { dev_err(&client->dev, "unable to set clock freq to %u\n", - sensor->hwcfg->ext_clk); + sensor->hwcfg.ext_clk); return rval; } rate = clk_get_rate(sensor->ext_clk); - if (rate != sensor->hwcfg->ext_clk) { + if (rate != sensor->hwcfg.ext_clk) { dev_err(&client->dev, "can't set clock freq, asked for %u but got %lu\n", - sensor->hwcfg->ext_clk, rate); + sensor->hwcfg.ext_clk, rate); return rval; } } else { - sensor->hwcfg->ext_clk = clk_get_rate(sensor->ext_clk); + sensor->hwcfg.ext_clk = clk_get_rate(sensor->ext_clk); dev_dbg(&client->dev, "obtained clock freq %u\n", - sensor->hwcfg->ext_clk); + sensor->hwcfg.ext_clk); } - } else if (sensor->hwcfg->ext_clk) { + } else if (sensor->hwcfg.ext_clk) { dev_dbg(&client->dev, "assuming clock freq %u\n", - sensor->hwcfg->ext_clk); + sensor->hwcfg.ext_clk); } else { dev_err(&client->dev, "unable to obtain clock freq\n"); return -EINVAL; @@ -3061,7 +3063,7 @@ static int ccs_probe(struct i2c_client *client) * * Rotation also changes the bayer pattern. */ - if (sensor->hwcfg->module_board_orient == + if (sensor->hwcfg.module_board_orient == CCS_MODULE_BOARD_ORIENT_180) sensor->hvflip_inv_mask = CCS_IMAGE_ORIENTATION_HORIZONTAL_MIRROR | @@ -3133,8 +3135,8 @@ static int ccs_probe(struct i2c_client *client) /* prepare PLL configuration input values */ sensor->pll.bus_type = SMIAPP_PLL_BUS_TYPE_CSI2; - sensor->pll.csi2.lanes = sensor->hwcfg->lanes; - sensor->pll.ext_clk_freq_hz = sensor->hwcfg->ext_clk; + sensor->pll.csi2.lanes = sensor->hwcfg.lanes; + sensor->pll.ext_clk_freq_hz = sensor->hwcfg.ext_clk; sensor->pll.scale_n = CCS_LIM(sensor, SCALER_N_MIN); ccs_create_subdev(sensor, sensor->scaler, " scaler", 2, diff --git a/drivers/media/i2c/ccs/ccs-quirk.c b/drivers/media/i2c/ccs/ccs-quirk.c index 5a24da1d7aa9..facec28f8447 100644 --- a/drivers/media/i2c/ccs/ccs-quirk.c +++ b/drivers/media/i2c/ccs/ccs-quirk.c @@ -152,13 +152,13 @@ static int jt8ev1_post_poweron(struct ccs_sensor *sensor) if (rval < 0) return rval; - switch (sensor->hwcfg->ext_clk) { + switch (sensor->hwcfg.ext_clk) { case 9600000: return ccs_write_addr_8s(sensor, regs_96, ARRAY_SIZE(regs_96)); default: dev_warn(&client->dev, "no MSRs for %d Hz ext_clk\n", - sensor->hwcfg->ext_clk); + sensor->hwcfg.ext_clk); return 0; } } diff --git a/drivers/media/i2c/ccs/ccs.h b/drivers/media/i2c/ccs/ccs.h index bfe39e02f5e9..2d1e8339f663 100644 --- a/drivers/media/i2c/ccs/ccs.h +++ b/drivers/media/i2c/ccs/ccs.h @@ -215,7 +215,7 @@ struct ccs_sensor { struct ccs_subdev *binner; struct ccs_subdev *scaler; struct ccs_subdev *pixel_array; - struct ccs_hwconfig *hwcfg; + struct ccs_hwconfig hwcfg; struct regulator *vana; struct clk *ext_clk; struct gpio_desc *xshutdown; -- cgit v1.2.3 From 9f65192d8d256dcac99a81c8129234b999704772 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 30 Sep 2020 18:20:42 +0200 Subject: media: ccs: Fix obtaining bus information from firmware Let v4l2_fwnode_endpoint_alloc_parse to figure out the type of the data bus. As the old bindings did not require the "bus-type" property, we need to rely on guessing between CSI-2 D-PHY and CCP2. Setting the type to CSI-2 D-PHY will parse just that and succeed even if no data-lanes are set. Also add a comment on the matter to the driver to avoid breaking this in the future. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index dcc71c8fe075..6fb546ca08f3 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -2853,7 +2853,7 @@ static int __maybe_unused ccs_resume(struct device *dev) static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev) { struct ccs_hwconfig *hwcfg = &sensor->hwcfg; - struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 }; + struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_UNKNOWN }; struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); u32 rotation; @@ -2864,13 +2864,11 @@ static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev) if (!ep) return -ENODEV; - bus_cfg.bus_type = V4L2_MBUS_CSI2_DPHY; + /* + * Note that we do need to rely on detecting the bus type between CSI-2 + * D-PHY and CCP2 as the old bindings did not require it. + */ rval = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); - if (rval == -ENXIO) { - bus_cfg = (struct v4l2_fwnode_endpoint) - { .bus_type = V4L2_MBUS_CCP2 }; - rval = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); - } if (rval) goto out_err; @@ -2879,6 +2877,7 @@ static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev) hwcfg->csi_signalling_mode = CCS_CSI_SIGNALING_MODE_CSI_2_DPHY; hwcfg->lanes = bus_cfg.bus.mipi_csi2.num_data_lanes; break; + case V4L2_MBUS_CSI1: case V4L2_MBUS_CCP2: hwcfg->csi_signalling_mode = (bus_cfg.bus.mipi_csi1.strobe) ? SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE : -- cgit v1.2.3 From a6b396f410b1e77e567dc7ca6f581c3f91e6e7cf Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 14 Feb 2020 10:00:35 +0100 Subject: media: ccs: Add CCS static data parser library Add a parser library for parsing the CCS static data format. The library may be also compiled in user space as the format has uses also in the user space. Therefore it is dual licensed under the 3-clause BSD license as well. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/Makefile | 2 +- drivers/media/i2c/ccs/ccs-data-defs.h | 221 ++++++++ drivers/media/i2c/ccs/ccs-data.c | 953 ++++++++++++++++++++++++++++++++++ drivers/media/i2c/ccs/ccs-data.h | 228 ++++++++ 4 files changed, 1403 insertions(+), 1 deletion(-) create mode 100644 drivers/media/i2c/ccs/ccs-data-defs.h create mode 100644 drivers/media/i2c/ccs/ccs-data.c create mode 100644 drivers/media/i2c/ccs/ccs-data.h diff --git a/drivers/media/i2c/ccs/Makefile b/drivers/media/i2c/ccs/Makefile index 08dd4e948fb0..44601ba8cd53 100644 --- a/drivers/media/i2c/ccs/Makefile +++ b/drivers/media/i2c/ccs/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only ccs-objs += ccs-core.o ccs-reg-access.o \ - ccs-quirk.o ccs-limits.o + ccs-quirk.o ccs-limits.o ccs-data.o obj-$(CONFIG_VIDEO_CCS) += ccs.o ccflags-y += -I $(srctree)/drivers/media/i2c diff --git a/drivers/media/i2c/ccs/ccs-data-defs.h b/drivers/media/i2c/ccs/ccs-data-defs.h new file mode 100644 index 000000000000..1c9b1d1acd50 --- /dev/null +++ b/drivers/media/i2c/ccs/ccs-data-defs.h @@ -0,0 +1,221 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* + * CCS static data binary format definitions + * + * Copyright 2019--2020 Intel Corporation + */ + +#ifndef __CCS_DATA_DEFS_H__ +#define __CCS_DATA_DEFS_H__ + +#include "ccs-data.h" + +#define CCS_STATIC_DATA_VERSION 0 + +enum __ccs_data_length_specifier_id { + CCS_DATA_LENGTH_SPECIFIER_1 = 0, + CCS_DATA_LENGTH_SPECIFIER_2 = 1, + CCS_DATA_LENGTH_SPECIFIER_3 = 2 +}; + +#define CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT 6 + +struct __ccs_data_length_specifier { + u8 length; +} __packed; + +struct __ccs_data_length_specifier2 { + u8 length[2]; +} __packed; + +struct __ccs_data_length_specifier3 { + u8 length[3]; +} __packed; + +struct __ccs_data_block { + u8 id; + struct __ccs_data_length_specifier length; +} __packed; + +#define CCS_DATA_BLOCK_HEADER_ID_VERSION_SHIFT 5 + +struct __ccs_data_block3 { + u8 id; + struct __ccs_data_length_specifier2 length; +} __packed; + +struct __ccs_data_block4 { + u8 id; + struct __ccs_data_length_specifier3 length; +} __packed; + +enum __ccs_data_block_id { + CCS_DATA_BLOCK_ID_DUMMY = 1, + CCS_DATA_BLOCK_ID_DATA_VERSION = 2, + CCS_DATA_BLOCK_ID_SENSOR_READ_ONLY_REGS = 3, + CCS_DATA_BLOCK_ID_MODULE_READ_ONLY_REGS = 4, + CCS_DATA_BLOCK_ID_SENSOR_MANUFACTURER_REGS = 5, + CCS_DATA_BLOCK_ID_MODULE_MANUFACTURER_REGS = 6, + CCS_DATA_BLOCK_ID_SENSOR_RULE_BASED_BLOCK = 32, + CCS_DATA_BLOCK_ID_MODULE_RULE_BASED_BLOCK = 33, + CCS_DATA_BLOCK_ID_SENSOR_PDAF_PIXEL_LOCATION = 36, + CCS_DATA_BLOCK_ID_MODULE_PDAF_PIXEL_LOCATION = 37, + CCS_DATA_BLOCK_ID_LICENSE = 40, + CCS_DATA_BLOCK_ID_END = 127, +}; + +struct __ccs_data_block_version { + u8 static_data_version_major[2]; + u8 static_data_version_minor[2]; + u8 year[2]; + u8 month; + u8 day; +} __packed; + +struct __ccs_data_block_regs { + u8 reg_len; +} __packed; + +#define CCS_DATA_BLOCK_REGS_ADDR_MASK 0x07 +#define CCS_DATA_BLOCK_REGS_LEN_SHIFT 3 +#define CCS_DATA_BLOCK_REGS_LEN_MASK 0x38 +#define CCS_DATA_BLOCK_REGS_SEL_SHIFT 6 + +enum ccs_data_block_regs_sel { + CCS_DATA_BLOCK_REGS_SEL_REGS = 0, + CCS_DATA_BLOCK_REGS_SEL_REGS2 = 1, + CCS_DATA_BLOCK_REGS_SEL_REGS3 = 2, +}; + +struct __ccs_data_block_regs2 { + u8 reg_len; + u8 addr; +} __packed; + +#define CCS_DATA_BLOCK_REGS_2_ADDR_MASK 0x01 +#define CCS_DATA_BLOCK_REGS_2_LEN_SHIFT 1 +#define CCS_DATA_BLOCK_REGS_2_LEN_MASK 0x3e + +struct __ccs_data_block_regs3 { + u8 reg_len; + u8 addr[2]; +} __packed; + +#define CCS_DATA_BLOCK_REGS_3_LEN_MASK 0x3f + +enum __ccs_data_ffd_pixelcode { + CCS_DATA_BLOCK_FFD_PIXELCODE_EMBEDDED = 1, + CCS_DATA_BLOCK_FFD_PIXELCODE_DUMMY = 2, + CCS_DATA_BLOCK_FFD_PIXELCODE_BLACK = 3, + CCS_DATA_BLOCK_FFD_PIXELCODE_DARK = 4, + CCS_DATA_BLOCK_FFD_PIXELCODE_VISIBLE = 5, + CCS_DATA_BLOCK_FFD_PIXELCODE_MS_0 = 8, + CCS_DATA_BLOCK_FFD_PIXELCODE_MS_1 = 9, + CCS_DATA_BLOCK_FFD_PIXELCODE_MS_2 = 10, + CCS_DATA_BLOCK_FFD_PIXELCODE_MS_3 = 11, + CCS_DATA_BLOCK_FFD_PIXELCODE_MS_4 = 12, + CCS_DATA_BLOCK_FFD_PIXELCODE_MS_5 = 13, + CCS_DATA_BLOCK_FFD_PIXELCODE_MS_6 = 14, + CCS_DATA_BLOCK_FFD_PIXELCODE_TOP_OB = 16, + CCS_DATA_BLOCK_FFD_PIXELCODE_BOTTOM_OB = 17, + CCS_DATA_BLOCK_FFD_PIXELCODE_LEFT_OB = 18, + CCS_DATA_BLOCK_FFD_PIXELCODE_RIGHT_OB = 19, + CCS_DATA_BLOCK_FFD_PIXELCODE_TOP_LEFT_OB = 20, + CCS_DATA_BLOCK_FFD_PIXELCODE_TOP_RIGHT_OB = 21, + CCS_DATA_BLOCK_FFD_PIXELCODE_BOTTOM_LEFT_OB = 22, + CCS_DATA_BLOCK_FFD_PIXELCODE_BOTTOM_RIGHT_OB = 23, + CCS_DATA_BLOCK_FFD_PIXELCODE_TOTAL = 24, + CCS_DATA_BLOCK_FFD_PIXELCODE_TOP_PDAF = 32, + CCS_DATA_BLOCK_FFD_PIXELCODE_BOTTOM_PDAF = 33, + CCS_DATA_BLOCK_FFD_PIXELCODE_LEFT_PDAF = 34, + CCS_DATA_BLOCK_FFD_PIXELCODE_RIGHT_PDAF = 35, + CCS_DATA_BLOCK_FFD_PIXELCODE_TOP_LEFT_PDAF = 36, + CCS_DATA_BLOCK_FFD_PIXELCODE_TOP_RIGHT_PDAF = 37, + CCS_DATA_BLOCK_FFD_PIXELCODE_BOTTOM_LEFT_PDAF = 38, + CCS_DATA_BLOCK_FFD_PIXELCODE_BOTTOM_RIGHT_PDAF = 39, + CCS_DATA_BLOCK_FFD_PIXELCODE_SEPARATED_PDAF = 40, + CCS_DATA_BLOCK_FFD_PIXELCODE_ORIGINAL_ORDER_PDAF = 41, + CCS_DATA_BLOCK_FFD_PIXELCODE_VENDOR_PDAF = 41, +}; + +struct __ccs_data_block_ffd_entry { + u8 pixelcode; + u8 reserved; + u8 value[2]; +} __packed; + +struct __ccs_data_block_ffd { + u8 num_column_descs; + u8 num_row_descs; +} __packed; + +enum __ccs_data_block_rule_id { + CCS_DATA_BLOCK_RULE_ID_IF = 1, + CCS_DATA_BLOCK_RULE_ID_READ_ONLY_REGS = 2, + CCS_DATA_BLOCK_RULE_ID_FFD = 3, + CCS_DATA_BLOCK_RULE_ID_MSR = 4, + CCS_DATA_BLOCK_RULE_ID_PDAF_READOUT = 5, +}; + +struct __ccs_data_block_rule_if { + u8 addr[2]; + u8 value; + u8 mask; +} __packed; + +enum __ccs_data_block_pdaf_readout_order { + CCS_DATA_BLOCK_PDAF_READOUT_ORDER_ORIGINAL = 1, + CCS_DATA_BLOCK_PDAF_READOUT_ORDER_SEPARATE_WITHIN_LINE = 2, + CCS_DATA_BLOCK_PDAF_READOUT_ORDER_SEPARATE_TYPES_SEPARATE_LINES = 3, +}; + +struct __ccs_data_block_pdaf_readout { + u8 pdaf_readout_info_reserved; + u8 pdaf_readout_info_order; +} __packed; + +struct __ccs_data_block_pdaf_pix_loc_block_desc { + u8 block_type_id; + u8 repeat_x[2]; +} __packed; + +struct __ccs_data_block_pdaf_pix_loc_block_desc_group { + u8 num_block_descs[2]; + u8 repeat_y; +} __packed; + +enum __ccs_data_block_pdaf_pix_loc_pixel_type { + CCS_DATA_PDAF_PIXEL_TYPE_LEFT_SEPARATED = 0, + CCS_DATA_PDAF_PIXEL_TYPE_RIGHT_SEPARATED = 1, + CCS_DATA_PDAF_PIXEL_TYPE_TOP_SEPARATED = 2, + CCS_DATA_PDAF_PIXEL_TYPE_BOTTOM_SEPARATED = 3, + CCS_DATA_PDAF_PIXEL_TYPE_LEFT_SIDE_BY_SIDE = 4, + CCS_DATA_PDAF_PIXEL_TYPE_RIGHT_SIDE_BY_SIDE = 5, + CCS_DATA_PDAF_PIXEL_TYPE_TOP_SIDE_BY_SIDE = 6, + CCS_DATA_PDAF_PIXEL_TYPE_BOTTOM_SIDE_BY_SIDE = 7, + CCS_DATA_PDAF_PIXEL_TYPE_TOP_LEFT = 8, + CCS_DATA_PDAF_PIXEL_TYPE_TOP_RIGHT = 9, + CCS_DATA_PDAF_PIXEL_TYPE_BOTTOM_LEFT = 10, + CCS_DATA_PDAF_PIXEL_TYPE_BOTTOM_RIGHT = 11, +}; + +struct __ccs_data_block_pdaf_pix_loc_pixel_desc { + u8 pixel_type; + u8 small_offset_x; + u8 small_offset_y; +} __packed; + +struct __ccs_data_block_pdaf_pix_loc { + u8 main_offset_x[2]; + u8 main_offset_y[2]; + u8 global_pdaf_type; + u8 block_width; + u8 block_height; + u8 num_block_desc_groups[2]; +} __packed; + +struct __ccs_data_block_end { + u8 crc[4]; +} __packed; + +#endif /* __CCS_DATA_DEFS_H__ */ diff --git a/drivers/media/i2c/ccs/ccs-data.c b/drivers/media/i2c/ccs/ccs-data.c new file mode 100644 index 000000000000..9a6097b088bd --- /dev/null +++ b/drivers/media/i2c/ccs/ccs-data.c @@ -0,0 +1,953 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * CCS static data binary parser library + * + * Copyright 2019--2020 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include + +#include "ccs-data-defs.h" + +struct bin_container { + void *base; + void *now; + void *end; + size_t size; +}; + +static void *bin_alloc(struct bin_container *bin, size_t len) +{ + void *ptr; + + len = ALIGN(len, 8); + + if (bin->end - bin->now < len) + return NULL; + + ptr = bin->now; + bin->now += len; + + return ptr; +} + +static void bin_reserve(struct bin_container *bin, size_t len) +{ + bin->size += ALIGN(len, 8); +} + +static int bin_backing_alloc(struct bin_container *bin) +{ + bin->base = bin->now = kvzalloc(bin->size, GFP_KERNEL); + if (!bin->base) + return -ENOMEM; + + bin->end = bin->base + bin->size; + + return 0; +} + +#define is_contained(var, endp) \ + (sizeof(*var) <= (endp) - (void *)(var)) +#define has_headroom(ptr, headroom, endp) \ + ((headroom) <= (endp) - (void *)(ptr)) +#define is_contained_with_headroom(var, headroom, endp) \ + (sizeof(*var) + (headroom) <= (endp) - (void *)(var)) + +static int +ccs_data_parse_length_specifier(const struct __ccs_data_length_specifier *__len, + size_t *__hlen, size_t *__plen, + const void *endp) +{ + size_t hlen, plen; + + if (!is_contained(__len, endp)) + return -ENODATA; + + switch (__len->length >> CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) { + case CCS_DATA_LENGTH_SPECIFIER_1: + hlen = sizeof(*__len); + plen = __len->length & + ((1 << CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) - 1); + break; + case CCS_DATA_LENGTH_SPECIFIER_2: { + struct __ccs_data_length_specifier2 *__len2 = (void *)__len; + + if (!is_contained(__len2, endp)) + return -ENODATA; + + hlen = sizeof(*__len2); + plen = ((size_t) + (__len2->length[0] & + ((1 << CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) - 1)) + << 8) + __len2->length[1]; + break; + } + case CCS_DATA_LENGTH_SPECIFIER_3: { + struct __ccs_data_length_specifier3 *__len3 = (void *)__len; + + if (!is_contained(__len3, endp)) + return -ENODATA; + + hlen = sizeof(*__len3); + plen = ((size_t) + (__len3->length[0] & + ((1 << CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) - 1)) + << 16) + (__len3->length[0] << 8) + __len3->length[1]; + break; + } + default: + return -EINVAL; + } + + if (!has_headroom(__len, hlen + plen, endp)) + return -ENODATA; + + *__hlen = hlen; + *__plen = plen; + + return 0; +} + +static u8 +ccs_data_parse_format_version(const struct __ccs_data_block *block) +{ + return block->id >> CCS_DATA_BLOCK_HEADER_ID_VERSION_SHIFT; +} + +static u8 ccs_data_parse_block_id(const struct __ccs_data_block *block, + bool is_first) +{ + if (!is_first) + return block->id; + + return block->id & ((1 << CCS_DATA_BLOCK_HEADER_ID_VERSION_SHIFT) - 1); +} + +static int ccs_data_parse_version(struct bin_container *bin, + struct ccs_data_container *ccsdata, + const void *payload, const void *endp) +{ + const struct __ccs_data_block_version *v = payload; + struct ccs_data_block_version *vv; + + if (v + 1 != endp) + return -ENODATA; + + if (!bin->base) { + bin_reserve(bin, sizeof(*ccsdata->version)); + return 0; + } + + ccsdata->version = bin_alloc(bin, sizeof(*ccsdata->version)); + if (!ccsdata->version) + return -ENOMEM; + + vv = ccsdata->version; + vv->version_major = ((u16)v->static_data_version_major[0] << 8) + + v->static_data_version_major[1]; + vv->version_minor = ((u16)v->static_data_version_minor[0] << 8) + + v->static_data_version_major[1]; + vv->date_year = ((u16)v->year[0] << 8) + v->year[1]; + vv->date_month = v->month; + vv->date_day = v->day; + + return 0; +} + +static void print_ccs_data_version(struct device *dev, + struct ccs_data_block_version *v) +{ + dev_dbg(dev, + "static data version %4.4x.%4.4x, date %4.4u-%2.2u-%2.2u\n", + v->version_major, v->version_minor, + v->date_year, v->date_month, v->date_day); +} + +static int ccs_data_block_parse_header(const struct __ccs_data_block *block, + bool is_first, unsigned int *__block_id, + const void **payload, + const struct __ccs_data_block **next_block, + const void *endp, struct device *dev, + bool verbose) +{ + size_t plen, hlen; + u8 block_id; + int rval; + + if (!is_contained(block, endp)) + return -ENODATA; + + rval = ccs_data_parse_length_specifier(&block->length, &hlen, &plen, + endp); + if (rval < 0) + return rval; + + block_id = ccs_data_parse_block_id(block, is_first); + + if (verbose) + dev_dbg(dev, + "Block ID 0x%2.2x, header length %zu, payload length %zu\n", + block_id, hlen, plen); + + if (!has_headroom(&block->length, hlen + plen, endp)) + return -ENODATA; + + if (__block_id) + *__block_id = block_id; + + if (payload) + *payload = (void *)&block->length + hlen; + + if (next_block) + *next_block = (void *)&block->length + hlen + plen; + + return 0; +} + +static int ccs_data_parse_regs(struct bin_container *bin, + struct ccs_reg **__regs, + size_t *__num_regs, const void *payload, + const void *endp, struct device *dev) +{ + struct ccs_reg *regs_base, *regs; + size_t num_regs = 0; + u16 addr = 0; + + if (bin->base && __regs) { + regs = regs_base = bin_alloc(bin, sizeof(*regs) * *__num_regs); + if (!regs) + return -ENOMEM; + } + + while (payload < endp && num_regs < INT_MAX) { + const struct __ccs_data_block_regs *r = payload; + size_t len; + const void *data; + + if (!is_contained(r, endp)) + return -ENODATA; + + switch (r->reg_len >> CCS_DATA_BLOCK_REGS_SEL_SHIFT) { + case CCS_DATA_BLOCK_REGS_SEL_REGS: + addr += r->reg_len & CCS_DATA_BLOCK_REGS_ADDR_MASK; + len = ((r->reg_len & CCS_DATA_BLOCK_REGS_LEN_MASK) + >> CCS_DATA_BLOCK_REGS_LEN_SHIFT) + 1; + + if (!is_contained_with_headroom(r, len, endp)) + return -ENODATA; + + data = r + 1; + break; + case CCS_DATA_BLOCK_REGS_SEL_REGS2: { + const struct __ccs_data_block_regs2 *r2 = payload; + + if (!is_contained(r2, endp)) + return -ENODATA; + + addr += ((u16)(r2->reg_len & + CCS_DATA_BLOCK_REGS_2_ADDR_MASK) << 8) + + r2->addr; + len = ((r2->reg_len & CCS_DATA_BLOCK_REGS_2_LEN_MASK) + >> CCS_DATA_BLOCK_REGS_2_LEN_SHIFT) + 1; + + if (!is_contained_with_headroom(r2, len, endp)) + return -ENODATA; + + data = r2 + 1; + break; + } + case CCS_DATA_BLOCK_REGS_SEL_REGS3: { + const struct __ccs_data_block_regs3 *r3 = payload; + + if (!is_contained(r3, endp)) + return -ENODATA; + + addr = ((u16)r3->addr[0] << 8) + r3->addr[1]; + len = (r3->reg_len & CCS_DATA_BLOCK_REGS_3_LEN_MASK) + 1; + + if (!is_contained_with_headroom(r3, len, endp)) + return -ENODATA; + + data = r3 + 1; + break; + } + default: + return -EINVAL; + } + + num_regs++; + + if (!bin->base) { + bin_reserve(bin, len); + } else if (__regs) { + regs->addr = addr; + regs->len = len; + regs->value = bin_alloc(bin, len); + if (!regs->value) + return -ENOMEM; + + memcpy(regs->value, data, len); + regs++; + } + + addr += len; + payload = data + len; + } + + if (!bin->base) + bin_reserve(bin, sizeof(*regs) * num_regs); + + if (__num_regs) + *__num_regs = num_regs; + + if (bin->base && __regs) + *__regs = regs_base; + + return 0; +} + +static int ccs_data_parse_reg_rules(struct bin_container *bin, + struct ccs_reg **__regs, + size_t *__num_regs, + const void *payload, + const void *endp, struct device *dev) +{ + int rval; + + if (!bin->base) + return ccs_data_parse_regs(bin, NULL, NULL, payload, endp, dev); + + rval = ccs_data_parse_regs(bin, NULL, __num_regs, payload, endp, dev); + if (rval) + return rval; + + return ccs_data_parse_regs(bin, __regs, __num_regs, payload, endp, + dev); +} + +static void assign_ffd_entry(struct ccs_frame_format_desc *desc, + const struct __ccs_data_block_ffd_entry *ent) +{ + desc->pixelcode = ent->pixelcode; + desc->value = ((u16)ent->value[0] << 8) + ent->value[1]; +} + +static int ccs_data_parse_ffd(struct bin_container *bin, + struct ccs_frame_format_descs **ffd, + const void *payload, + const void *endp, struct device *dev) +{ + const struct __ccs_data_block_ffd *__ffd = payload; + const struct __ccs_data_block_ffd_entry *__entry; + unsigned int i; + + if (!is_contained(__ffd, endp)) + return -ENODATA; + + if ((void *)__ffd + sizeof(*__ffd) + + ((u32)__ffd->num_column_descs + + (u32)__ffd->num_row_descs) * + sizeof(struct __ccs_data_block_ffd_entry) != endp) + return -ENODATA; + + if (!bin->base) { + bin_reserve(bin, sizeof(**ffd)); + bin_reserve(bin, __ffd->num_column_descs * + sizeof(struct ccs_frame_format_desc)); + bin_reserve(bin, __ffd->num_row_descs * + sizeof(struct ccs_frame_format_desc)); + + return 0; + } + + *ffd = bin_alloc(bin, sizeof(**ffd)); + if (!*ffd) + return -ENOMEM; + + (*ffd)->num_column_descs = __ffd->num_column_descs; + (*ffd)->num_row_descs = __ffd->num_row_descs; + __entry = (void *)(__ffd + 1); + + (*ffd)->column_descs = bin_alloc(bin, __ffd->num_column_descs * + sizeof(*(*ffd)->column_descs)); + if (!(*ffd)->column_descs) + return -ENOMEM; + + for (i = 0; i < __ffd->num_column_descs; i++, __entry++) + assign_ffd_entry(&(*ffd)->column_descs[i], __entry); + + (*ffd)->row_descs = bin_alloc(bin, __ffd->num_row_descs * + sizeof(*(*ffd)->row_descs)); + if (!(*ffd)->row_descs) + return -ENOMEM; + + for (i = 0; i < __ffd->num_row_descs; i++, __entry++) + assign_ffd_entry(&(*ffd)->row_descs[i], __entry); + + if (__entry != endp) + return -EPROTO; + + return 0; +} + +static int ccs_data_parse_pdaf_readout(struct bin_container *bin, + struct ccs_pdaf_readout **pdaf_readout, + const void *payload, + const void *endp, struct device *dev) +{ + const struct __ccs_data_block_pdaf_readout *__pdaf = payload; + + if (!is_contained(__pdaf, endp)) + return -ENODATA; + + if (!bin->base) { + bin_reserve(bin, sizeof(**pdaf_readout)); + } else { + *pdaf_readout = bin_alloc(bin, sizeof(**pdaf_readout)); + if (!*pdaf_readout) + return -ENOMEM; + + (*pdaf_readout)->pdaf_readout_info_order = + __pdaf->pdaf_readout_info_order; + } + + return ccs_data_parse_ffd(bin, !bin->base ? NULL : &(*pdaf_readout)->ffd, + __pdaf + 1, endp, dev); +} + +static int ccs_data_parse_rules(struct bin_container *bin, + struct ccs_rule **__rules, + size_t *__num_rules, const void *payload, + const void *endp, struct device *dev) +{ + struct ccs_rule *rules_base, *rules = NULL, *next_rule; + size_t num_rules = 0; + const void *__next_rule = payload; + int rval; + + if (bin->base) { + rules_base = next_rule = + bin_alloc(bin, sizeof(*rules) * *__num_rules); + if (!rules_base) + return -ENOMEM; + } + + while (__next_rule < endp) { + size_t rule_hlen, rule_plen, rule_plen2; + const u8 *__rule_type; + const void *rule_payload; + + /* Size of a single rule */ + rval = ccs_data_parse_length_specifier(__next_rule, &rule_hlen, + &rule_plen, endp); + + if (rval < 0) + return rval; + + __rule_type = __next_rule + rule_hlen; + + if (!is_contained(__rule_type, endp)) + return -ENODATA; + + rule_payload = __rule_type + 1; + rule_plen2 = rule_plen - sizeof(*__rule_type); + + switch (*__rule_type) { + case CCS_DATA_BLOCK_RULE_ID_IF: { + const struct __ccs_data_block_rule_if *__if_rules = + rule_payload; + const size_t __num_if_rules = + rule_plen2 / sizeof(*__if_rules); + struct ccs_if_rule *if_rule; + + if (!has_headroom(__if_rules, + sizeof(*__if_rules) * __num_if_rules, + rule_payload + rule_plen2)) + return -ENODATA; + + /* Also check there is no extra data */ + if (__if_rules + __num_if_rules != + rule_payload + rule_plen2) + return -EINVAL; + + if (!bin->base) { + bin_reserve(bin, + sizeof(*if_rule) * + __num_if_rules); + num_rules++; + } else { + unsigned int i; + + rules = next_rule; + next_rule++; + + if_rule = bin_alloc(bin, + sizeof(*if_rule) * + __num_if_rules); + if (!if_rule) + return -ENOMEM; + + for (i = 0; i < __num_if_rules; i++) { + if_rule[i].addr = + ((u16)__if_rules[i].addr[0] + << 8) + + __if_rules[i].addr[1]; + if_rule[i].value = __if_rules[i].value; + if_rule[i].mask = __if_rules[i].mask; + } + + rules->if_rules = if_rule; + rules->num_if_rules = __num_if_rules; + } + break; + } + case CCS_DATA_BLOCK_RULE_ID_READ_ONLY_REGS: + rval = ccs_data_parse_reg_rules(bin, &rules->read_only_regs, + &rules->num_read_only_regs, + rule_payload, + rule_payload + rule_plen2, + dev); + if (rval) + return rval; + break; + case CCS_DATA_BLOCK_RULE_ID_FFD: + rval = ccs_data_parse_ffd(bin, &rules->frame_format, + rule_payload, + rule_payload + rule_plen2, + dev); + if (rval) + return rval; + break; + case CCS_DATA_BLOCK_RULE_ID_MSR: + rval = ccs_data_parse_reg_rules(bin, + &rules->manufacturer_regs, + &rules->num_manufacturer_regs, + rule_payload, + rule_payload + rule_plen2, + dev); + if (rval) + return rval; + break; + case CCS_DATA_BLOCK_RULE_ID_PDAF_READOUT: + rval = ccs_data_parse_pdaf_readout(bin, + &rules->pdaf_readout, + rule_payload, + rule_payload + rule_plen2, + dev); + if (rval) + return rval; + break; + default: + dev_dbg(dev, + "Don't know how to handle rule type %u!\n", + *__rule_type); + return -EINVAL; + } + __next_rule = __next_rule + rule_hlen + rule_plen; + } + + if (!bin->base) { + bin_reserve(bin, sizeof(*rules) * num_rules); + *__num_rules = num_rules; + } else { + *__rules = rules_base; + } + + return 0; +} + +static int ccs_data_parse_pdaf(struct bin_container *bin, struct ccs_pdaf_pix_loc **pdaf, + const void *payload, const void *endp, + struct device *dev) +{ + const struct __ccs_data_block_pdaf_pix_loc *__pdaf = payload; + const struct __ccs_data_block_pdaf_pix_loc_block_desc_group *__bdesc_group; + const struct __ccs_data_block_pdaf_pix_loc_pixel_desc *__pixel_desc; + unsigned int i; + u16 num_block_desc_groups; + u8 max_block_type_id = 0; + const u8 *__num_pixel_descs; + + if (!is_contained(__pdaf, endp)) + return -ENODATA; + + if (bin->base) { + *pdaf = bin_alloc(bin, sizeof(**pdaf)); + if (!*pdaf) + return -ENOMEM; + } else { + bin_reserve(bin, sizeof(**pdaf)); + } + + num_block_desc_groups = + ((u16)__pdaf->num_block_desc_groups[0] << 8) + + __pdaf->num_block_desc_groups[1]; + + if (bin->base) { + (*pdaf)->main_offset_x = + ((u16)__pdaf->main_offset_x[0] << 8) + + __pdaf->main_offset_x[1]; + (*pdaf)->main_offset_y = + ((u16)__pdaf->main_offset_y[0] << 8) + + __pdaf->main_offset_y[1]; + (*pdaf)->global_pdaf_type = __pdaf->global_pdaf_type; + (*pdaf)->block_width = __pdaf->block_width; + (*pdaf)->block_height = __pdaf->block_height; + (*pdaf)->num_block_desc_groups = num_block_desc_groups; + } + + __bdesc_group = (const void *)(__pdaf + 1); + + if (bin->base) { + (*pdaf)->block_desc_groups = + bin_alloc(bin, + sizeof(struct ccs_pdaf_pix_loc_block_desc_group) * + num_block_desc_groups); + if (!(*pdaf)->block_desc_groups) + return -ENOMEM; + } else { + bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_block_desc_group) * + num_block_desc_groups); + } + + for (i = 0; i < num_block_desc_groups; i++) { + const struct __ccs_data_block_pdaf_pix_loc_block_desc *__bdesc; + u16 num_block_descs; + unsigned int j; + + if (!is_contained(__bdesc_group, endp)) + return -ENODATA; + + num_block_descs = + ((u16)__bdesc_group->num_block_descs[0] << 8) + + __bdesc_group->num_block_descs[1]; + + if (bin->base) { + (*pdaf)->block_desc_groups[i].repeat_y = + __bdesc_group->repeat_y; + (*pdaf)->block_desc_groups[i].num_block_descs = + num_block_descs; + } + + __bdesc = (const void *)(__bdesc_group + 1); + + if (bin->base) { + (*pdaf)->block_desc_groups[i].block_descs = + bin_alloc(bin, + sizeof(struct ccs_pdaf_pix_loc_block_desc) * + num_block_descs); + if (!(*pdaf)->block_desc_groups[i].block_descs) + return -ENOMEM; + } else { + bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_block_desc) * + num_block_descs); + } + + for (j = 0; j < num_block_descs; j++, __bdesc++) { + struct ccs_pdaf_pix_loc_block_desc *bdesc; + + if (!is_contained(__bdesc, endp)) + return -ENODATA; + + if (max_block_type_id <= __bdesc->block_type_id) + max_block_type_id = __bdesc->block_type_id + 1; + + if (!bin->base) + continue; + + bdesc = &(*pdaf)->block_desc_groups[i].block_descs[j]; + + bdesc->repeat_x = ((u16)__bdesc->repeat_x[0] << 8) + + __bdesc->repeat_x[1]; + + if (__bdesc->block_type_id >= num_block_descs) + return -EINVAL; + + bdesc->block_type_id = __bdesc->block_type_id; + } + + __bdesc_group = (const void *)__bdesc; + } + + __num_pixel_descs = (const void *)__bdesc_group; + + if (bin->base) { + (*pdaf)->pixel_desc_groups = + bin_alloc(bin, + sizeof(struct ccs_pdaf_pix_loc_pixel_desc_group) * + max_block_type_id); + if (!(*pdaf)->pixel_desc_groups) + return -ENOMEM; + (*pdaf)->num_pixel_desc_grups = max_block_type_id; + } else { + bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_pixel_desc_group) * + max_block_type_id); + } + + for (i = 0; i < max_block_type_id; i++) { + struct ccs_pdaf_pix_loc_pixel_desc_group *pdgroup; + unsigned int j; + + if (!is_contained(__num_pixel_descs, endp)) + return -ENODATA; + + if (bin->base) { + pdgroup = &(*pdaf)->pixel_desc_groups[i]; + pdgroup->descs = + bin_alloc(bin, + sizeof(struct ccs_pdaf_pix_loc_pixel_desc) * + *__num_pixel_descs); + if (!pdgroup->descs) + return -ENOMEM; + pdgroup->num_descs = *__num_pixel_descs; + } else { + bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_pixel_desc) * + *__num_pixel_descs); + } + + __pixel_desc = (const void *)(__num_pixel_descs + 1); + + for (j = 0; j < *__num_pixel_descs; j++, __pixel_desc++) { + struct ccs_pdaf_pix_loc_pixel_desc *pdesc; + + if (!is_contained(__pixel_desc, endp)) + return -ENODATA; + + if (!bin->base) + continue; + + pdesc = &pdgroup->descs[j]; + pdesc->pixel_type = __pixel_desc->pixel_type; + pdesc->small_offset_x = __pixel_desc->small_offset_x; + pdesc->small_offset_y = __pixel_desc->small_offset_y; + } + + __num_pixel_descs = (const void *)(__pixel_desc + 1); + } + + return 0; +} + +static int ccs_data_parse_license(struct bin_container *bin, + char **__license, + size_t *__license_length, + const void *payload, const void *endp) +{ + size_t size = endp - payload; + char *license; + + if (!bin->base) { + bin_reserve(bin, size); + return 0; + } + + license = bin_alloc(bin, size); + if (!license) + return -ENOMEM; + + memcpy(license, payload, size); + + *__license = license; + *__license_length = size; + + return 0; +} + +static int ccs_data_parse_end(bool *end, const void *payload, const void *endp, + struct device *dev) +{ + const struct __ccs_data_block_end *__end = payload; + + if (__end + 1 != endp) { + dev_dbg(dev, "Invalid end block length %u\n", + (unsigned int)(endp - payload)); + return -ENODATA; + } + + *end = true; + + return 0; +} + +static int __ccs_data_parse(struct bin_container *bin, + struct ccs_data_container *ccsdata, + const void *data, size_t len, struct device *dev, + bool verbose) +{ + const struct __ccs_data_block *block = data; + const struct __ccs_data_block *endp = data + len; + unsigned int version; + bool is_first = true; + int rval; + + version = ccs_data_parse_format_version(block); + if (version != CCS_STATIC_DATA_VERSION) { + dev_dbg(dev, "Don't know how to handle version %u\n", version); + return -EINVAL; + } + + if (verbose) + dev_dbg(dev, "Parsing CCS static data version %u\n", version); + + if (!bin->base) + *ccsdata = (struct ccs_data_container){ 0 }; + + while (block < endp) { + const struct __ccs_data_block *next_block; + unsigned int block_id; + const void *payload; + + rval = ccs_data_block_parse_header(block, is_first, &block_id, + &payload, &next_block, endp, + dev, + bin->base ? false : verbose); + + if (rval < 0) + return rval; + + switch (block_id) { + case CCS_DATA_BLOCK_ID_DUMMY: + break; + case CCS_DATA_BLOCK_ID_DATA_VERSION: + rval = ccs_data_parse_version(bin, ccsdata, payload, + next_block); + if (rval < 0) + return rval; + break; + case CCS_DATA_BLOCK_ID_SENSOR_READ_ONLY_REGS: + rval = ccs_data_parse_regs( + bin, &ccsdata->sensor_read_only_regs, + &ccsdata->num_sensor_read_only_regs, payload, + next_block, dev); + if (rval < 0) + return rval; + break; + case CCS_DATA_BLOCK_ID_SENSOR_MANUFACTURER_REGS: + rval = ccs_data_parse_regs( + bin, &ccsdata->sensor_manufacturer_regs, + &ccsdata->num_sensor_manufacturer_regs, payload, + next_block, dev); + if (rval < 0) + return rval; + break; + case CCS_DATA_BLOCK_ID_MODULE_READ_ONLY_REGS: + rval = ccs_data_parse_regs( + bin, &ccsdata->module_read_only_regs, + &ccsdata->num_module_read_only_regs, payload, + next_block, dev); + if (rval < 0) + return rval; + break; + case CCS_DATA_BLOCK_ID_MODULE_MANUFACTURER_REGS: + rval = ccs_data_parse_regs( + bin, &ccsdata->module_manufacturer_regs, + &ccsdata->num_module_manufacturer_regs, payload, + next_block, dev); + if (rval < 0) + return rval; + break; + case CCS_DATA_BLOCK_ID_SENSOR_PDAF_PIXEL_LOCATION: + rval = ccs_data_parse_pdaf(bin, &ccsdata->sensor_pdaf, + payload, next_block, dev); + if (rval < 0) + return rval; + break; + case CCS_DATA_BLOCK_ID_MODULE_PDAF_PIXEL_LOCATION: + rval = ccs_data_parse_pdaf(bin, &ccsdata->module_pdaf, + payload, next_block, dev); + if (rval < 0) + return rval; + break; + case CCS_DATA_BLOCK_ID_SENSOR_RULE_BASED_BLOCK: + rval = ccs_data_parse_rules( + bin, &ccsdata->sensor_rules, + &ccsdata->num_sensor_rules, payload, next_block, + dev); + if (rval < 0) + return rval; + break; + case CCS_DATA_BLOCK_ID_MODULE_RULE_BASED_BLOCK: + rval = ccs_data_parse_rules( + bin, &ccsdata->module_rules, + &ccsdata->num_module_rules, payload, next_block, + dev); + if (rval < 0) + return rval; + break; + case CCS_DATA_BLOCK_ID_LICENSE: + rval = ccs_data_parse_license(bin, &ccsdata->license, + &ccsdata->license_length, + payload, next_block); + if (rval < 0) + return rval; + break; + case CCS_DATA_BLOCK_ID_END: + rval = ccs_data_parse_end(&ccsdata->end, payload, + next_block, dev); + if (rval < 0) + return rval; + break; + default: + dev_dbg(dev, "WARNING: not handling block ID 0x%2.2x\n", + block_id); + } + + block = next_block; + is_first = false; + } + + return 0; +} + +/** + * ccs_data_parse - Parse a CCS static data file into a usable in-memory + * data structure + * @ccsdata: CCS static data in-memory data structure + * @data: CCS static data binary + * @len: Length of @data + * @dev: Device the data is related to (used for printing debug messages) + * @verbose: Whether to be verbose or not + */ +int ccs_data_parse(struct ccs_data_container *ccsdata, const void *data, + size_t len, struct device *dev, bool verbose) +{ + struct bin_container bin = { 0 }; + int rval; + + rval = __ccs_data_parse(&bin, ccsdata, data, len, dev, verbose); + if (rval) + return rval; + + rval = bin_backing_alloc(&bin); + if (rval) + return rval; + + rval = __ccs_data_parse(&bin, ccsdata, data, len, dev, false); + if (rval) + goto out_free; + + if (verbose && ccsdata->version) + print_ccs_data_version(dev, ccsdata->version); + + if (bin.now != bin.end) { + rval = -EPROTO; + dev_dbg(dev, "parsing mismatch; base %p; now %p; end %p\n", + bin.base, bin.now, bin.end); + goto out_free; + } + + ccsdata->backing = bin.base; + + return 0; + +out_free: + kvfree(bin.base); + + return rval; +} diff --git a/drivers/media/i2c/ccs/ccs-data.h b/drivers/media/i2c/ccs/ccs-data.h new file mode 100644 index 000000000000..50d6508b24f3 --- /dev/null +++ b/drivers/media/i2c/ccs/ccs-data.h @@ -0,0 +1,228 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* + * CCS static data in-memory data structure definitions + * + * Copyright 2019--2020 Intel Corporation + */ + +#ifndef __CCS_DATA_H__ +#define __CCS_DATA_H__ + +#include + +/** + * struct ccs_data_block_version - CCS static data version + * @version_major: Major version number + * @version_minor: Minor version number + * @date_year: Year + * @date_month: Month + * @date_day: Day + */ +struct ccs_data_block_version { + u16 version_major; + u16 version_minor; + u16 date_year; + u8 date_month; + u8 date_day; +}; + +/** + * struct ccs_reg - CCS register value + * @addr: The 16-bit address of the register + * @len: Length of the data + * @value: Data + */ +struct ccs_reg { + u16 addr; + u16 len; + u8 *value; +}; + +/** + * struct ccs_if_rule - CCS static data if rule + * @addr: Register address + * @value: Register value + * @mask: Value applied to both actual register value and @value + */ +struct ccs_if_rule { + u16 addr; + u8 value; + u8 mask; +}; + +/** + * struct ccs_frame_format_desc - CCS frame format descriptor + * @pixelcode: The pixelcode; CCS_DATA_BLOCK_FFD_PIXELCODE_* + * @value: Value related to the pixelcode + */ +struct ccs_frame_format_desc { + u8 pixelcode; + u16 value; +}; + +/** + * struct ccs_frame_format_descs - A series of CCS frame format descriptors + * @num_column_descs: Number of column descriptors + * @num_row_descs: Number of row descriptors + * @column_descs: Column descriptors + * @row_descs: Row descriptors + */ +struct ccs_frame_format_descs { + u8 num_column_descs; + u8 num_row_descs; + struct ccs_frame_format_desc *column_descs; + struct ccs_frame_format_desc *row_descs; +}; + +/** + * struct ccs_pdaf_readout - CCS PDAF data readout descriptor + * @pdaf_readout_info_order: PDAF readout order + * @ffd: Frame format of PDAF data + */ +struct ccs_pdaf_readout { + u8 pdaf_readout_info_order; + struct ccs_frame_format_descs *ffd; +}; + +/** + * struct ccs_rule - A CCS static data rule + * @num_if_rules: Number of if rules + * @if_rules: If rules + * @num_read_only_regs: Number of read-only registers + * @read_only_regs: Read-only registers + * @num_manufacturer_regs: Number of manufacturer-specific registers + * @manufacturer_regs: Manufacturer-specific registers + * @frame_format: Frame format + * @pdaf_readout: PDAF readout + */ +struct ccs_rule { + size_t num_if_rules; + struct ccs_if_rule *if_rules; + size_t num_read_only_regs; + struct ccs_reg *read_only_regs; + size_t num_manufacturer_regs; + struct ccs_reg *manufacturer_regs; + struct ccs_frame_format_descs *frame_format; + struct ccs_pdaf_readout *pdaf_readout; +}; + +/** + * struct ccs_pdaf_pix_loc_block_desc - PDAF pixel location block descriptor + * @block_type_id: Block type identifier, from 0 to n + * @repeat_x: Number of times this block is repeated to right + */ +struct ccs_pdaf_pix_loc_block_desc { + u8 block_type_id; + u16 repeat_x; +}; + +/** + * struct ccs_pdaf_pix_loc_block_desc_group - PDAF pixel location block + * descriptor group + * @repeat_y: Number of times the group is repeated down + * @num_block_descs: Number of block descriptors in @block_descs + * @block_descs: Block descriptors + */ +struct ccs_pdaf_pix_loc_block_desc_group { + u8 repeat_y; + u16 num_block_descs; + struct ccs_pdaf_pix_loc_block_desc *block_descs; +}; + +/** + * struct ccs_pdaf_pix_loc_block_desc - PDAF pixel location block descriptor + * @pixel_type: Type of the pixel; CCS_DATA_PDAF_PIXEL_TYPE_* + * @small_offset_x: offset X coordinate + * @small_offset_y: offset Y coordinate + */ +struct ccs_pdaf_pix_loc_pixel_desc { + u8 pixel_type; + u8 small_offset_x; + u8 small_offset_y; +}; + +/** + * struct ccs_pdaf_pix_loc_pixel_desc_group - PDAF pixel location pixel + * descriptor group + * @num_descs: Number of descriptors in @descs + * @descs: PDAF pixel location pixel descriptors + */ +struct ccs_pdaf_pix_loc_pixel_desc_group { + u8 num_descs; + struct ccs_pdaf_pix_loc_pixel_desc *descs; +}; + +/** + * struct ccs_pdaf_pix_loc - PDAF pixel locations + * @main_offset_x: Start X coordinate of PDAF pixel blocks + * @main_offset_y: Start Y coordinate of PDAF pixel blocks + * @global_pdaf_type: PDAF pattern type + * @block_width: Width of a block in pixels + * @block_height: Heigth of a block in pixels + * @num_block_desc_groups: Number of block descriptor groups + * @block_desc_groups: Block descriptor groups + * @num_pixel_desc_grups: Number of pixel descriptor groups + * @pixel_desc_groups: Pixel descriptor groups + */ +struct ccs_pdaf_pix_loc { + u16 main_offset_x; + u16 main_offset_y; + u8 global_pdaf_type; + u8 block_width; + u8 block_height; + u16 num_block_desc_groups; + struct ccs_pdaf_pix_loc_block_desc_group *block_desc_groups; + u8 num_pixel_desc_grups; + struct ccs_pdaf_pix_loc_pixel_desc_group *pixel_desc_groups; +}; + +/** + * struct ccs_data_container - In-memory CCS static data + * @version: CCS static data version + * @num_sensor_read_only_regs: Number of the read-only registers for the sensor + * @sensor_read_only_regs: Read-only registers for the sensor + * @num_sensor_manufacturer_regs: Number of the manufacturer-specific registers + * for the sensor + * @sensor_manufacturer_regs: Manufacturer-specific registers for the sensor + * @num_sensor_rules: Number of rules for the sensor + * @sensor_rules: Rules for the sensor + * @num_module_read_only_regs: Number of the read-only registers for the module + * @module_read_only_regs: Read-only registers for the module + * @num_module_manufacturer_regs: Number of the manufacturer-specific registers + * for the module + * @module_manufacturer_regs: Manufacturer-specific registers for the module + * @num_module_rules: Number of rules for the module + * @module_rules: Rules for the module + * @sensor_pdaf: PDAF data for the sensor + * @module_pdaf: PDAF data for the module + * @license_length: Lenght of the license data + * @license: License data + * @end: Whether or not there's an end block + * @backing: Raw data, pointed to from elsewhere so keep it around + */ +struct ccs_data_container { + struct ccs_data_block_version *version; + size_t num_sensor_read_only_regs; + struct ccs_reg *sensor_read_only_regs; + size_t num_sensor_manufacturer_regs; + struct ccs_reg *sensor_manufacturer_regs; + size_t num_sensor_rules; + struct ccs_rule *sensor_rules; + size_t num_module_read_only_regs; + struct ccs_reg *module_read_only_regs; + size_t num_module_manufacturer_regs; + struct ccs_reg *module_manufacturer_regs; + size_t num_module_rules; + struct ccs_rule *module_rules; + struct ccs_pdaf_pix_loc *sensor_pdaf; + struct ccs_pdaf_pix_loc *module_pdaf; + size_t license_length; + char *license; + bool end; + void *backing; +}; + +int ccs_data_parse(struct ccs_data_container *ccsdata, const void *data, + size_t len, struct device *dev, bool verbose); + +#endif /* __CCS_DATA_H__ */ -- cgit v1.2.3 From f86ae91627f13f8e1231a782c25c00f4dc08e0c9 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 14 Feb 2020 14:14:18 +0100 Subject: media: ccs: Combine revision number major and minor into one The module revision number major and minor are both 8 bits while the sensor revision number is 16 bits. Combine the module revision into one number. This also adds printing the lowest 8 bits of the module version through the sysfs attribute. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 25 ++++++++++++++----------- drivers/media/i2c/ccs/ccs-quirk.c | 2 +- drivers/media/i2c/ccs/ccs.h | 3 +-- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 6fb546ca08f3..17287a8f539c 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -2427,11 +2427,11 @@ ccs_sysfs_ident_read(struct device *dev, struct device_attribute *attr, if (minfo->mipi_manufacturer_id) return snprintf(buf, PAGE_SIZE, "%4.4x%4.4x%2.2x\n", minfo->mipi_manufacturer_id, minfo->model_id, - minfo->revision_number_major) + 1; + minfo->revision_number) + 1; else return snprintf(buf, PAGE_SIZE, "%2.2x%4.4x%2.2x\n", minfo->smia_manufacturer_id, minfo->model_id, - minfo->revision_number_major) + 1; + minfo->revision_number) + 1; } static DEVICE_ATTR(ident, S_IRUGO, ccs_sysfs_ident_read, NULL); @@ -2445,6 +2445,7 @@ static int ccs_identify_module(struct ccs_sensor *sensor) struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); struct ccs_module_info *minfo = &sensor->minfo; unsigned int i; + u32 rev; int rval = 0; /* Module info */ @@ -2460,11 +2461,13 @@ static int ccs_identify_module(struct ccs_sensor *sensor) if (!rval) rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_REVISION_NUMBER_MAJOR, - &minfo->revision_number_major); - if (!rval) + &rev); + if (!rval) { rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_REVISION_NUMBER_MINOR, - &minfo->revision_number_minor); + &minfo->revision_number); + minfo->revision_number |= rev << 8; + } if (!rval) rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_YEAR, &minfo->module_year); @@ -2519,9 +2522,9 @@ static int ccs_identify_module(struct ccs_sensor *sensor) minfo->smia_manufacturer_id, minfo->model_id); dev_dbg(&client->dev, - "module revision 0x%2.2x-0x%2.2x date %2.2d-%2.2d-%2.2d\n", - minfo->revision_number_major, minfo->revision_number_minor, - minfo->module_year, minfo->module_month, minfo->module_day); + "module revision 0x%4.4x date %2.2d-%2.2d-%2.2d\n", + minfo->revision_number, minfo->module_year, minfo->module_month, + minfo->module_day); if (minfo->sensor_mipi_manufacturer_id) dev_dbg(&client->dev, "MIPI CCS sensor 0x%4.4x-0x%4.4x\n", @@ -2559,7 +2562,7 @@ static int ccs_identify_module(struct ccs_sensor *sensor) minfo->smia_manufacturer_id = minfo->sensor_smia_manufacturer_id; minfo->model_id = minfo->sensor_model_id; - minfo->revision_number_major = minfo->sensor_revision_number; + minfo->revision_number = minfo->sensor_revision_number; } for (i = 0; i < ARRAY_SIZE(ccs_module_idents); i++) { @@ -2576,11 +2579,11 @@ static int ccs_identify_module(struct ccs_sensor *sensor) if (ccs_module_idents[i].flags & CCS_MODULE_IDENT_FLAG_REV_LE) { if (ccs_module_idents[i].revision_number_major - < minfo->revision_number_major) + < (minfo->revision_number >> 8)) continue; } else { if (ccs_module_idents[i].revision_number_major - != minfo->revision_number_major) + != (minfo->revision_number >> 8)) continue; } diff --git a/drivers/media/i2c/ccs/ccs-quirk.c b/drivers/media/i2c/ccs/ccs-quirk.c index facec28f8447..07c5733b4244 100644 --- a/drivers/media/i2c/ccs/ccs-quirk.c +++ b/drivers/media/i2c/ccs/ccs-quirk.c @@ -35,7 +35,7 @@ static int ccs_write_addr_8s(struct ccs_sensor *sensor, static int jt8ew9_limits(struct ccs_sensor *sensor) { - if (sensor->minfo.revision_number_major < 0x03) + if (sensor->minfo.revision_number < 0x0300) sensor->frame_skip = 1; /* Below 24 gain doesn't have effect at all, */ diff --git a/drivers/media/i2c/ccs/ccs.h b/drivers/media/i2c/ccs/ccs.h index 2d1e8339f663..ad2ff5a74424 100644 --- a/drivers/media/i2c/ccs/ccs.h +++ b/drivers/media/i2c/ccs/ccs.h @@ -107,8 +107,7 @@ struct ccs_module_info { u32 smia_manufacturer_id; u32 mipi_manufacturer_id; u32 model_id; - u32 revision_number_major; - u32 revision_number_minor; + u32 revision_number; u32 module_year; u32 module_month; -- cgit v1.2.3 From a11d3d6891f042b3537b7f113462bcac8088ba70 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 14 Feb 2020 14:49:42 +0100 Subject: media: ccs: Read CCS static data from firmware binaries Read the CCS static data for sensors and modules. The files are expected to be found in "ccs" directory. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 47 +++++++++++++++++++++++++++++++++++++++- drivers/media/i2c/ccs/ccs.h | 2 ++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 17287a8f539c..be27b002a772 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -2953,6 +2954,8 @@ out_err: static int ccs_probe(struct i2c_client *client) { struct ccs_sensor *sensor; + const struct firmware *fw; + char filename[40]; unsigned int i; int rval; @@ -3042,9 +3045,43 @@ static int ccs_probe(struct i2c_client *client) goto out_power_off; } + rval = snprintf(filename, sizeof(filename), + "ccs/ccs-sensor-%4.4x-%4.4x-%4.4x.fw", + sensor->minfo.sensor_mipi_manufacturer_id, + sensor->minfo.sensor_model_id, + sensor->minfo.sensor_revision_number); + if (rval >= sizeof(filename)) { + rval = -ENOMEM; + goto out_power_off; + } + + rval = request_firmware(&fw, filename, &client->dev); + if (!rval) { + ccs_data_parse(&sensor->sdata, fw->data, fw->size, &client->dev, + true); + release_firmware(fw); + } + + rval = snprintf(filename, sizeof(filename), + "ccs/ccs-module-%4.4x-%4.4x-%4.4x.fw", + sensor->minfo.mipi_manufacturer_id, + sensor->minfo.model_id, + sensor->minfo.revision_number); + if (rval >= sizeof(filename)) { + rval = -ENOMEM; + goto out_release_sdata; + } + + rval = request_firmware(&fw, filename, &client->dev); + if (!rval) { + ccs_data_parse(&sensor->mdata, fw->data, fw->size, &client->dev, + true); + release_firmware(fw); + } + rval = ccs_read_all_limits(sensor); if (rval) - goto out_power_off; + goto out_release_mdata; rval = ccs_read_frame_fmt(sensor); if (rval) { @@ -3208,6 +3245,12 @@ out_media_entity_cleanup: out_cleanup: ccs_cleanup(sensor); +out_release_mdata: + kvfree(sensor->mdata.backing); + +out_release_sdata: + kvfree(sensor->sdata.backing); + out_free_ccs_limits: kfree(sensor->ccs_limits); @@ -3238,6 +3281,8 @@ static int ccs_remove(struct i2c_client *client) ccs_cleanup(sensor); mutex_destroy(&sensor->mutex); kfree(sensor->ccs_limits); + kvfree(sensor->sdata.backing); + kvfree(sensor->mdata.backing); return 0; } diff --git a/drivers/media/i2c/ccs/ccs.h b/drivers/media/i2c/ccs/ccs.h index ad2ff5a74424..cbcd93b519da 100644 --- a/drivers/media/i2c/ccs/ccs.h +++ b/drivers/media/i2c/ccs/ccs.h @@ -16,6 +16,7 @@ #include #include +#include "ccs-data.h" #include "ccs-quirk.h" #include "ccs-regs.h" #include "ccs-reg-access.h" @@ -227,6 +228,7 @@ struct ccs_sensor { const struct ccs_csi_data_format *internal_csi_format; u32 default_mbus_frame_fmts; int default_pixel_order; + struct ccs_data_container sdata, mdata; u8 binning_horizontal; u8 binning_vertical; -- cgit v1.2.3 From 6a0970986e425f5750b081542c340c855d8890e5 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 27 May 2020 10:35:01 +0200 Subject: media: ccs: Stop reading arrays after the first zero The register arrays have a certain size but not all the entries will be relevant. In practice reading can be stopped after encountering a zero value in the array. Do that to avoid extra reads. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index be27b002a772..dec248fe7cc1 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -199,6 +199,9 @@ static int ccs_read_all_limits(struct ccs_sensor *sensor) goto out_err; } + if (!val && j) + break; + ccs_assign_limit(ptr, width, val); dev_dbg(&client->dev, "0x%8.8x \"%s\" = %u, 0x%x\n", -- cgit v1.2.3 From 7d8d59f260bad0b3b11dc94e88b4195a2d1798af Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 28 May 2020 01:02:07 +0200 Subject: media: ccs: The functions to get compose or crop rectangle never return NULL The NULL check is not needed as the functions do not return NULL. Remove the check (and BUG). Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index dec248fe7cc1..25b4c84524ff 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -1766,16 +1766,12 @@ static void ccs_get_crop_compose(struct v4l2_subdev *subdev, *comps = &ssd->compose; } else { if (crops) { - for (i = 0; i < subdev->entity.num_pads; i++) { + for (i = 0; i < subdev->entity.num_pads; i++) crops[i] = v4l2_subdev_get_try_crop(subdev, cfg, i); - BUG_ON(!crops[i]); - } } - if (comps) { + if (comps) *comps = v4l2_subdev_get_try_compose(subdev, cfg, CCS_PAD_SINK); - BUG_ON(!*comps); - } } } -- cgit v1.2.3 From e40f1bcbeea6482bae1e077bb57a21ef5db2b499 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 28 May 2020 01:00:29 +0200 Subject: media: ccs: Replace somewhat harsh internal checks based on BUG with WARN_ON If an internal driver error was encountered, BUG was issued. Instead, do less harsh WARN_ON_ONCE and try to manage with the consequences. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 25b4c84524ff..70b4d2180971 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -546,6 +546,10 @@ static void ccs_update_mbus_formats(struct ccs_sensor *sensor) to_csi_format_idx(sensor->internal_csi_format) & ~3; unsigned int pixel_order = ccs_pixel_order(sensor); + if (WARN_ON_ONCE(max(internal_csi_format_idx, csi_format_idx) + + pixel_order >= ARRAY_SIZE(ccs_csi_data_formats))) + return; + sensor->mbus_frame_fmts = sensor->default_mbus_frame_fmts << pixel_order; sensor->csi_format = @@ -554,9 +558,6 @@ static void ccs_update_mbus_formats(struct ccs_sensor *sensor) &ccs_csi_data_formats[internal_csi_format_idx + pixel_order]; - BUG_ON(max(internal_csi_format_idx, csi_format_idx) + pixel_order - >= ARRAY_SIZE(ccs_csi_data_formats)); - dev_dbg(&client->dev, "new pixel order %s\n", pixel_order_str[pixel_order]); } @@ -1806,7 +1807,7 @@ static void ccs_propagate(struct v4l2_subdev *subdev, *crops[CCS_PAD_SRC] = *comp; break; default: - BUG(); + WARN_ON_ONCE(1); } } -- cgit v1.2.3 From 2989a457171d2b1d457bd378450fe3909eb02623 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 2 Sep 2020 12:09:03 +0200 Subject: media: ccs: Refactor register reading a little Rework quirk and 8-bit only access functions with a single function that takes arguments. This is later extensible to support yet more flags. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-reg-access.c | 37 ++++++++++++++++------------------ 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-reg-access.c b/drivers/media/i2c/ccs/ccs-reg-access.c index a8e9a235bfb3..abec746f3c93 100644 --- a/drivers/media/i2c/ccs/ccs-reg-access.c +++ b/drivers/media/i2c/ccs/ccs-reg-access.c @@ -168,39 +168,36 @@ static int __ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val, return 0; } -int ccs_read_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 *val) -{ - return __ccs_read_addr( - sensor, reg, val, - ccs_needs_quirk(sensor, CCS_QUIRK_FLAG_8BIT_READ_ONLY)); -} - -static int ccs_read_addr_quirk(struct ccs_sensor *sensor, u32 reg, u32 *val, - bool force8) +static int ccs_read_addr_raw(struct ccs_sensor *sensor, u32 reg, u32 *val, + bool force8, bool quirk) { int rval; - *val = 0; - rval = ccs_call_quirk(sensor, reg_access, false, ®, val); - if (rval == -ENOIOCTLCMD) - return 0; - if (rval < 0) - return rval; + if (quirk) { + *val = 0; + rval = ccs_call_quirk(sensor, reg_access, false, ®, val); + if (rval == -ENOIOCTLCMD) + return 0; + if (rval < 0) + return rval; - if (force8) - return __ccs_read_addr(sensor, reg, val, true); + if (force8) + return __ccs_read_addr(sensor, reg, val, true); + } - return ccs_read_addr_no_quirk(sensor, reg, val); + return __ccs_read_addr(sensor, reg, val, + ccs_needs_quirk(sensor, + CCS_QUIRK_FLAG_8BIT_READ_ONLY)); } int ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val) { - return ccs_read_addr_quirk(sensor, reg, val, false); + return ccs_read_addr_raw(sensor, reg, val, false, true); } int ccs_read_addr_8only(struct ccs_sensor *sensor, u32 reg, u32 *val) { - return ccs_read_addr_quirk(sensor, reg, val, true); + return ccs_read_addr_raw(sensor, reg, val, true, true); } int ccs_write_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 val) -- cgit v1.2.3 From 7d2f8ddaac2c1d938302022d40b057b5f31c4e9d Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 2 Sep 2020 12:23:40 +0200 Subject: media: ccs: Make real to integer number conversion optional The limit values will be raw soon, and the conversion takes place later on. Prepare for that. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-reg-access.c | 35 +++++++++++++++++++++++++--------- drivers/media/i2c/ccs/ccs-reg-access.h | 2 ++ 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-reg-access.c b/drivers/media/i2c/ccs/ccs-reg-access.c index abec746f3c93..fe6112cba6be 100644 --- a/drivers/media/i2c/ccs/ccs-reg-access.c +++ b/drivers/media/i2c/ccs/ccs-reg-access.c @@ -143,14 +143,23 @@ unsigned int ccs_reg_width(u32 reg) return sizeof(uint8_t); } +u32 ccs_reg_conv(struct ccs_sensor *sensor, u32 reg, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + + if (reg & CCS_FL_FLOAT_IREAL) + val = float_to_u32_mul_1000000(client, val); + + return val; +} + /* * Read a 8/16/32-bit i2c register. The value is returned in 'val'. * Returns zero if successful, or non-zero otherwise. */ static int __ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val, - bool only8) + bool only8, bool conv) { - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); unsigned int len = ccs_reg_width(reg); int rval; @@ -162,14 +171,16 @@ static int __ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val, if (rval < 0) return rval; - if (reg & CCS_FL_FLOAT_IREAL) - *val = float_to_u32_mul_1000000(client, *val); + if (!conv) + return 0; + + *val = ccs_reg_conv(sensor, reg, *val); return 0; } static int ccs_read_addr_raw(struct ccs_sensor *sensor, u32 reg, u32 *val, - bool force8, bool quirk) + bool force8, bool quirk, bool conv) { int rval; @@ -182,22 +193,28 @@ static int ccs_read_addr_raw(struct ccs_sensor *sensor, u32 reg, u32 *val, return rval; if (force8) - return __ccs_read_addr(sensor, reg, val, true); + return __ccs_read_addr(sensor, reg, val, true, conv); } return __ccs_read_addr(sensor, reg, val, ccs_needs_quirk(sensor, - CCS_QUIRK_FLAG_8BIT_READ_ONLY)); + CCS_QUIRK_FLAG_8BIT_READ_ONLY), + conv); } int ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val) { - return ccs_read_addr_raw(sensor, reg, val, false, true); + return ccs_read_addr_raw(sensor, reg, val, false, true, true); } int ccs_read_addr_8only(struct ccs_sensor *sensor, u32 reg, u32 *val) { - return ccs_read_addr_raw(sensor, reg, val, true, true); + return ccs_read_addr_raw(sensor, reg, val, true, true, true); +} + +int ccs_read_addr_noconv(struct ccs_sensor *sensor, u32 reg, u32 *val) +{ + return ccs_read_addr_raw(sensor, reg, val, false, true, false); } int ccs_write_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 val) diff --git a/drivers/media/i2c/ccs/ccs-reg-access.h b/drivers/media/i2c/ccs/ccs-reg-access.h index 9fdf5659ed09..5f6ff9c57698 100644 --- a/drivers/media/i2c/ccs/ccs-reg-access.h +++ b/drivers/media/i2c/ccs/ccs-reg-access.h @@ -24,10 +24,12 @@ struct ccs_sensor; int ccs_read_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 *val); int ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val); int ccs_read_addr_8only(struct ccs_sensor *sensor, u32 reg, u32 *val); +int ccs_read_addr_noconv(struct ccs_sensor *sensor, u32 reg, u32 *val); int ccs_write_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 val); int ccs_write_addr(struct ccs_sensor *sensor, u32 reg, u32 val); unsigned int ccs_reg_width(u32 reg); +u32 ccs_reg_conv(struct ccs_sensor *sensor, u32 reg, u32 val); #define ccs_read(sensor, reg_name, val) \ ccs_read_addr(sensor, CCS_R_##reg_name, val) -- cgit v1.2.3 From 5017f8b4e0ed9ec39c04ac85de6ce49603f5f02b Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 2 Sep 2020 12:46:59 +0200 Subject: media: ccs: Move limit value real to integer conversion from read to access time Instead of converting the limit values at register read time, do that at access time instead. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 70b4d2180971..57efc34fc67d 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -130,6 +130,7 @@ static u32 ccs_get_limit(struct ccs_sensor *sensor, unsigned int limit, unsigned int offset) { void *ptr; + u32 val; int ret; ret = ccs_limit_ptr(sensor, limit, offset, &ptr); @@ -138,16 +139,20 @@ static u32 ccs_get_limit(struct ccs_sensor *sensor, switch (ccs_reg_width(ccs_limits[ccs_limit_offsets[limit].info].reg)) { case sizeof(u8): - return *(u8 *)ptr; + val = *(u8 *)ptr; + break; case sizeof(u16): - return *(u16 *)ptr; + val = *(u16 *)ptr; + break; case sizeof(u32): - return *(u32 *)ptr; + val = *(u32 *)ptr; + break; + default: + WARN_ON(1); + return 0; } - WARN_ON(1); - - return 0; + return ccs_reg_conv(sensor, ccs_limits[limit].reg, val); } #define CCS_LIM(sensor, limit) \ @@ -188,7 +193,7 @@ static int ccs_read_all_limits(struct ccs_sensor *sensor) j++, reg += width, ptr += width) { u32 val; - ret = ccs_read_addr(sensor, reg, &val); + ret = ccs_read_addr_noconv(sensor, reg, &val); if (ret) goto out_err; -- cgit v1.2.3 From fe652254e243a58daf50aa0ddb938885ae2ba565 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 24 Jun 2020 15:39:05 +0200 Subject: media: ccs: Read ireal numbers correctly Some limit values are available in q16.q16 format, referred to as 32-bit unsigned ireal in CCS. Read these correctly. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 10 ++-------- drivers/media/i2c/ccs/ccs-reg-access.c | 23 +++++++++++++++++++++-- drivers/media/i2c/ccs/ccs.h | 9 +++++++++ 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 57efc34fc67d..074b246538d2 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -126,8 +126,8 @@ void ccs_replace_limit(struct ccs_sensor *sensor, ccs_assign_limit(ptr, ccs_reg_width(linfo->reg), val); } -static u32 ccs_get_limit(struct ccs_sensor *sensor, - unsigned int limit, unsigned int offset) +u32 ccs_get_limit(struct ccs_sensor *sensor, unsigned int limit, + unsigned int offset) { void *ptr; u32 val; @@ -155,12 +155,6 @@ static u32 ccs_get_limit(struct ccs_sensor *sensor, return ccs_reg_conv(sensor, ccs_limits[limit].reg, val); } -#define CCS_LIM(sensor, limit) \ - ccs_get_limit(sensor, CCS_L_##limit, 0) - -#define CCS_LIM_AT(sensor, limit, offset) \ - ccs_get_limit(sensor, CCS_L_##limit, CCS_L_##limit##_OFFSET(offset)) - static int ccs_read_all_limits(struct ccs_sensor *sensor) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); diff --git a/drivers/media/i2c/ccs/ccs-reg-access.c b/drivers/media/i2c/ccs/ccs-reg-access.c index fe6112cba6be..91ccbca11577 100644 --- a/drivers/media/i2c/ccs/ccs-reg-access.c +++ b/drivers/media/i2c/ccs/ccs-reg-access.c @@ -15,6 +15,7 @@ #include #include "ccs.h" +#include "ccs-limits.h" static uint32_t float_to_u32_mul_1000000(struct i2c_client *client, uint32_t phloat) @@ -143,12 +144,30 @@ unsigned int ccs_reg_width(u32 reg) return sizeof(uint8_t); } +static u32 ireal32_to_u32_mul_1000000(struct i2c_client *client, u32 val) +{ + if (val >> 10 > U32_MAX / 15625) { + dev_warn(&client->dev, "value %u overflows!\n", val); + return U32_MAX; + } + + return ((val >> 10) * 15625) + + (val & GENMASK(9, 0)) * 15625 / 1024; +} + u32 ccs_reg_conv(struct ccs_sensor *sensor, u32 reg, u32 val) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - if (reg & CCS_FL_FLOAT_IREAL) - val = float_to_u32_mul_1000000(client, val); + if (reg & CCS_FL_FLOAT_IREAL) { + if (CCS_LIM(sensor, CLOCK_CAPA_TYPE_CAPABILITY) & + CCS_CLOCK_CAPA_TYPE_CAPABILITY_IREAL) + val = ireal32_to_u32_mul_1000000(client, val); + else + val = float_to_u32_mul_1000000(client, val); + } else if (reg & CCS_FL_IREAL) { + val = ireal32_to_u32_mul_1000000(client, val); + } return val; } diff --git a/drivers/media/i2c/ccs/ccs.h b/drivers/media/i2c/ccs/ccs.h index cbcd93b519da..f60d1801c469 100644 --- a/drivers/media/i2c/ccs/ccs.h +++ b/drivers/media/i2c/ccs/ccs.h @@ -17,6 +17,7 @@ #include #include "ccs-data.h" +#include "ccs-limits.h" #include "ccs-quirk.h" #include "ccs-regs.h" #include "ccs-reg-access.h" @@ -50,6 +51,12 @@ #define CCS_DFL_I2C_ADDR (0x20 >> 1) /* Default I2C Address */ #define CCS_ALT_I2C_ADDR (0x6e >> 1) /* Alternate I2C Address */ +#define CCS_LIM(sensor, limit) \ + ccs_get_limit(sensor, CCS_L_##limit, 0) + +#define CCS_LIM_AT(sensor, limit, offset) \ + ccs_get_limit(sensor, CCS_L_##limit, CCS_L_##limit##_OFFSET(offset)) + /* * Sometimes due to board layout considerations the camera module can be * mounted rotated. The typical rotation used is 180 degrees which can be @@ -277,5 +284,7 @@ struct ccs_sensor { void ccs_replace_limit(struct ccs_sensor *sensor, unsigned int limit, unsigned int offset, u32 val); +u32 ccs_get_limit(struct ccs_sensor *sensor, unsigned int limit, + unsigned int offset); #endif /* __CCS_H__ */ -- cgit v1.2.3 From 9e05bbac43ebfc2fd1ff95e072730ceed807d149 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 27 May 2020 23:59:40 +0200 Subject: media: smiapp-pll: Rename as ccs-pll MIPI CCS replaces SMIA and SMIA++ as the current standard. CCS brings new features while existing functionality will be supported. Rename the smiapp-pll as ccs-pll accordingly. Also add Intel copyright to the files. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 4 +- drivers/media/i2c/Kconfig | 2 +- drivers/media/i2c/Makefile | 2 +- drivers/media/i2c/ccs-pll.c | 480 +++++++++++++++++++++++++++++++++++++ drivers/media/i2c/ccs-pll.h | 99 ++++++++ drivers/media/i2c/ccs/Kconfig | 2 +- drivers/media/i2c/ccs/ccs-core.c | 18 +- drivers/media/i2c/ccs/ccs-quirk.c | 2 +- drivers/media/i2c/ccs/ccs.h | 4 +- drivers/media/i2c/smiapp-pll.c | 482 -------------------------------------- drivers/media/i2c/smiapp-pll.h | 99 -------- 11 files changed, 596 insertions(+), 598 deletions(-) create mode 100644 drivers/media/i2c/ccs-pll.c create mode 100644 drivers/media/i2c/ccs-pll.h delete mode 100644 drivers/media/i2c/smiapp-pll.c delete mode 100644 drivers/media/i2c/smiapp-pll.h diff --git a/MAINTAINERS b/MAINTAINERS index dce790484d29..6380b54bf726 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11635,9 +11635,9 @@ L: linux-media@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml F: Documentation/driver-api/media/drivers/ccs/ +F: drivers/media/i2c/ccs-pll.c +F: drivers/media/i2c/ccs-pll.h F: drivers/media/i2c/ccs/ -F: drivers/media/i2c/smiapp-pll.c -F: drivers/media/i2c/smiapp-pll.h F: include/uapi/linux/smiapp.h MIPS diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 92ff66c34f93..2b9d81e4794a 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -722,7 +722,7 @@ menu "Camera sensor devices" config VIDEO_APTINA_PLL tristate -config VIDEO_SMIAPP_PLL +config VIDEO_CCS_PLL tristate config VIDEO_HI556 diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index bf9fd1bb6bc9..a3149dce21bb 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -106,7 +106,7 @@ obj-$(CONFIG_VIDEO_S5C73M3) += s5c73m3/ obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o obj-$(CONFIG_VIDEO_LM3560) += lm3560.o obj-$(CONFIG_VIDEO_LM3646) += lm3646.o -obj-$(CONFIG_VIDEO_SMIAPP_PLL) += smiapp-pll.o +obj-$(CONFIG_VIDEO_CCS_PLL) += ccs-pll.o obj-$(CONFIG_VIDEO_AK881X) += ak881x.o obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o obj-$(CONFIG_VIDEO_I2C) += video-i2c.o diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c new file mode 100644 index 000000000000..d2f0f7375f5c --- /dev/null +++ b/drivers/media/i2c/ccs-pll.c @@ -0,0 +1,480 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * drivers/media/i2c/ccs-pll.c + * + * Generic MIPI CCS/SMIA/SMIA++ PLL calculator + * + * Copyright (C) 2020 Intel Corporation + * Copyright (C) 2011--2012 Nokia Corporation + * Contact: Sakari Ailus + */ + +#include +#include +#include +#include + +#include "ccs-pll.h" + +/* Return an even number or one. */ +static inline uint32_t clk_div_even(uint32_t a) +{ + return max_t(uint32_t, 1, a & ~1); +} + +/* Return an even number or one. */ +static inline uint32_t clk_div_even_up(uint32_t a) +{ + if (a == 1) + return 1; + return (a + 1) & ~1; +} + +static inline uint32_t is_one_or_even(uint32_t a) +{ + if (a == 1) + return 1; + if (a & 1) + return 0; + + return 1; +} + +static int bounds_check(struct device *dev, uint32_t val, + uint32_t min, uint32_t max, char *str) +{ + if (val >= min && val <= max) + return 0; + + dev_dbg(dev, "%s out of bounds: %d (%d--%d)\n", str, val, min, max); + + return -EINVAL; +} + +static void print_pll(struct device *dev, struct ccs_pll *pll) +{ + dev_dbg(dev, "pre_pll_clk_div\t%u\n", pll->pre_pll_clk_div); + dev_dbg(dev, "pll_multiplier \t%u\n", pll->pll_multiplier); + if (!(pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS)) { + dev_dbg(dev, "op_sys_clk_div \t%u\n", pll->op.sys_clk_div); + dev_dbg(dev, "op_pix_clk_div \t%u\n", pll->op.pix_clk_div); + } + dev_dbg(dev, "vt_sys_clk_div \t%u\n", pll->vt.sys_clk_div); + dev_dbg(dev, "vt_pix_clk_div \t%u\n", pll->vt.pix_clk_div); + + dev_dbg(dev, "ext_clk_freq_hz \t%u\n", pll->ext_clk_freq_hz); + dev_dbg(dev, "pll_ip_clk_freq_hz \t%u\n", pll->pll_ip_clk_freq_hz); + dev_dbg(dev, "pll_op_clk_freq_hz \t%u\n", pll->pll_op_clk_freq_hz); + if (!(pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS)) { + dev_dbg(dev, "op_sys_clk_freq_hz \t%u\n", + pll->op.sys_clk_freq_hz); + dev_dbg(dev, "op_pix_clk_freq_hz \t%u\n", + pll->op.pix_clk_freq_hz); + } + dev_dbg(dev, "vt_sys_clk_freq_hz \t%u\n", pll->vt.sys_clk_freq_hz); + dev_dbg(dev, "vt_pix_clk_freq_hz \t%u\n", pll->vt.pix_clk_freq_hz); +} + +static int check_all_bounds(struct device *dev, + const struct ccs_pll_limits *limits, + const struct ccs_pll_branch_limits *op_limits, + struct ccs_pll *pll, struct ccs_pll_branch *op_pll) +{ + int rval; + + rval = bounds_check(dev, pll->pll_ip_clk_freq_hz, + limits->min_pll_ip_freq_hz, + limits->max_pll_ip_freq_hz, + "pll_ip_clk_freq_hz"); + if (!rval) + rval = bounds_check( + dev, pll->pll_multiplier, + limits->min_pll_multiplier, limits->max_pll_multiplier, + "pll_multiplier"); + if (!rval) + rval = bounds_check( + dev, pll->pll_op_clk_freq_hz, + limits->min_pll_op_freq_hz, limits->max_pll_op_freq_hz, + "pll_op_clk_freq_hz"); + if (!rval) + rval = bounds_check( + dev, op_pll->sys_clk_div, + op_limits->min_sys_clk_div, op_limits->max_sys_clk_div, + "op_sys_clk_div"); + if (!rval) + rval = bounds_check( + dev, op_pll->sys_clk_freq_hz, + op_limits->min_sys_clk_freq_hz, + op_limits->max_sys_clk_freq_hz, + "op_sys_clk_freq_hz"); + if (!rval) + rval = bounds_check( + dev, op_pll->pix_clk_freq_hz, + op_limits->min_pix_clk_freq_hz, + op_limits->max_pix_clk_freq_hz, + "op_pix_clk_freq_hz"); + + /* + * If there are no OP clocks, the VT clocks are contained in + * the OP clock struct. + */ + if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS) + return rval; + + if (!rval) + rval = bounds_check( + dev, pll->vt.sys_clk_freq_hz, + limits->vt.min_sys_clk_freq_hz, + limits->vt.max_sys_clk_freq_hz, + "vt_sys_clk_freq_hz"); + if (!rval) + rval = bounds_check( + dev, pll->vt.pix_clk_freq_hz, + limits->vt.min_pix_clk_freq_hz, + limits->vt.max_pix_clk_freq_hz, + "vt_pix_clk_freq_hz"); + + return rval; +} + +/* + * Heuristically guess the PLL tree for a given common multiplier and + * divisor. Begin with the operational timing and continue to video + * timing once operational timing has been verified. + * + * @mul is the PLL multiplier and @div is the common divisor + * (pre_pll_clk_div and op_sys_clk_div combined). The final PLL + * multiplier will be a multiple of @mul. + * + * @return Zero on success, error code on error. + */ +static int +__ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *limits, + const struct ccs_pll_branch_limits *op_limits, + struct ccs_pll *pll, struct ccs_pll_branch *op_pll, + uint32_t mul, uint32_t div, uint32_t lane_op_clock_ratio) +{ + uint32_t sys_div; + uint32_t best_pix_div = INT_MAX >> 1; + uint32_t vt_op_binning_div; + /* + * Higher multipliers (and divisors) are often required than + * necessitated by the external clock and the output clocks. + * There are limits for all values in the clock tree. These + * are the minimum and maximum multiplier for mul. + */ + uint32_t more_mul_min, more_mul_max; + uint32_t more_mul_factor; + uint32_t min_vt_div, max_vt_div, vt_div; + uint32_t min_sys_div, max_sys_div; + unsigned int i; + + /* + * Get pre_pll_clk_div so that our pll_op_clk_freq_hz won't be + * too high. + */ + dev_dbg(dev, "pre_pll_clk_div %u\n", pll->pre_pll_clk_div); + + /* Don't go above max pll multiplier. */ + more_mul_max = limits->max_pll_multiplier / mul; + dev_dbg(dev, "more_mul_max: max_pll_multiplier check: %u\n", + more_mul_max); + /* Don't go above max pll op frequency. */ + more_mul_max = + min_t(uint32_t, + more_mul_max, + limits->max_pll_op_freq_hz + / (pll->ext_clk_freq_hz / pll->pre_pll_clk_div * mul)); + dev_dbg(dev, "more_mul_max: max_pll_op_freq_hz check: %u\n", + more_mul_max); + /* Don't go above the division capability of op sys clock divider. */ + more_mul_max = min(more_mul_max, + op_limits->max_sys_clk_div * pll->pre_pll_clk_div + / div); + dev_dbg(dev, "more_mul_max: max_op_sys_clk_div check: %u\n", + more_mul_max); + /* Ensure we won't go above min_pll_multiplier. */ + more_mul_max = min(more_mul_max, + DIV_ROUND_UP(limits->max_pll_multiplier, mul)); + dev_dbg(dev, "more_mul_max: min_pll_multiplier check: %u\n", + more_mul_max); + + /* Ensure we won't go below min_pll_op_freq_hz. */ + more_mul_min = DIV_ROUND_UP(limits->min_pll_op_freq_hz, + pll->ext_clk_freq_hz / pll->pre_pll_clk_div + * mul); + dev_dbg(dev, "more_mul_min: min_pll_op_freq_hz check: %u\n", + more_mul_min); + /* Ensure we won't go below min_pll_multiplier. */ + more_mul_min = max(more_mul_min, + DIV_ROUND_UP(limits->min_pll_multiplier, mul)); + dev_dbg(dev, "more_mul_min: min_pll_multiplier check: %u\n", + more_mul_min); + + if (more_mul_min > more_mul_max) { + dev_dbg(dev, + "unable to compute more_mul_min and more_mul_max\n"); + return -EINVAL; + } + + more_mul_factor = lcm(div, pll->pre_pll_clk_div) / div; + dev_dbg(dev, "more_mul_factor: %u\n", more_mul_factor); + more_mul_factor = lcm(more_mul_factor, op_limits->min_sys_clk_div); + dev_dbg(dev, "more_mul_factor: min_op_sys_clk_div: %d\n", + more_mul_factor); + i = roundup(more_mul_min, more_mul_factor); + if (!is_one_or_even(i)) + i <<= 1; + + dev_dbg(dev, "final more_mul: %u\n", i); + if (i > more_mul_max) { + dev_dbg(dev, "final more_mul is bad, max %u\n", more_mul_max); + return -EINVAL; + } + + pll->pll_multiplier = mul * i; + op_pll->sys_clk_div = div * i / pll->pre_pll_clk_div; + dev_dbg(dev, "op_sys_clk_div: %u\n", op_pll->sys_clk_div); + + pll->pll_ip_clk_freq_hz = pll->ext_clk_freq_hz + / pll->pre_pll_clk_div; + + pll->pll_op_clk_freq_hz = pll->pll_ip_clk_freq_hz + * pll->pll_multiplier; + + /* Derive pll_op_clk_freq_hz. */ + op_pll->sys_clk_freq_hz = + pll->pll_op_clk_freq_hz / op_pll->sys_clk_div; + + op_pll->pix_clk_div = pll->bits_per_pixel; + dev_dbg(dev, "op_pix_clk_div: %u\n", op_pll->pix_clk_div); + + op_pll->pix_clk_freq_hz = + op_pll->sys_clk_freq_hz / op_pll->pix_clk_div; + + if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS) { + /* No OP clocks --- VT clocks are used instead. */ + goto out_skip_vt_calc; + } + + /* + * Some sensors perform analogue binning and some do this + * digitally. The ones doing this digitally can be roughly be + * found out using this formula. The ones doing this digitally + * should run at higher clock rate, so smaller divisor is used + * on video timing side. + */ + if (limits->min_line_length_pck_bin > limits->min_line_length_pck + / pll->binning_horizontal) + vt_op_binning_div = pll->binning_horizontal; + else + vt_op_binning_div = 1; + dev_dbg(dev, "vt_op_binning_div: %u\n", vt_op_binning_div); + + /* + * Profile 2 supports vt_pix_clk_div E [4, 10] + * + * Horizontal binning can be used as a base for difference in + * divisors. One must make sure that horizontal blanking is + * enough to accommodate the CSI-2 sync codes. + * + * Take scaling factor into account as well. + * + * Find absolute limits for the factor of vt divider. + */ + dev_dbg(dev, "scale_m: %u\n", pll->scale_m); + min_vt_div = DIV_ROUND_UP(op_pll->pix_clk_div * op_pll->sys_clk_div + * pll->scale_n, + lane_op_clock_ratio * vt_op_binning_div + * pll->scale_m); + + /* Find smallest and biggest allowed vt divisor. */ + dev_dbg(dev, "min_vt_div: %u\n", min_vt_div); + min_vt_div = max(min_vt_div, + DIV_ROUND_UP(pll->pll_op_clk_freq_hz, + limits->vt.max_pix_clk_freq_hz)); + dev_dbg(dev, "min_vt_div: max_vt_pix_clk_freq_hz: %u\n", + min_vt_div); + min_vt_div = max_t(uint32_t, min_vt_div, + limits->vt.min_pix_clk_div + * limits->vt.min_sys_clk_div); + dev_dbg(dev, "min_vt_div: min_vt_clk_div: %u\n", min_vt_div); + + max_vt_div = limits->vt.max_sys_clk_div * limits->vt.max_pix_clk_div; + dev_dbg(dev, "max_vt_div: %u\n", max_vt_div); + max_vt_div = min(max_vt_div, + DIV_ROUND_UP(pll->pll_op_clk_freq_hz, + limits->vt.min_pix_clk_freq_hz)); + dev_dbg(dev, "max_vt_div: min_vt_pix_clk_freq_hz: %u\n", + max_vt_div); + + /* + * Find limitsits for sys_clk_div. Not all values are possible + * with all values of pix_clk_div. + */ + min_sys_div = limits->vt.min_sys_clk_div; + dev_dbg(dev, "min_sys_div: %u\n", min_sys_div); + min_sys_div = max(min_sys_div, + DIV_ROUND_UP(min_vt_div, + limits->vt.max_pix_clk_div)); + dev_dbg(dev, "min_sys_div: max_vt_pix_clk_div: %u\n", min_sys_div); + min_sys_div = max(min_sys_div, + pll->pll_op_clk_freq_hz + / limits->vt.max_sys_clk_freq_hz); + dev_dbg(dev, "min_sys_div: max_pll_op_clk_freq_hz: %u\n", min_sys_div); + min_sys_div = clk_div_even_up(min_sys_div); + dev_dbg(dev, "min_sys_div: one or even: %u\n", min_sys_div); + + max_sys_div = limits->vt.max_sys_clk_div; + dev_dbg(dev, "max_sys_div: %u\n", max_sys_div); + max_sys_div = min(max_sys_div, + DIV_ROUND_UP(max_vt_div, + limits->vt.min_pix_clk_div)); + dev_dbg(dev, "max_sys_div: min_vt_pix_clk_div: %u\n", max_sys_div); + max_sys_div = min(max_sys_div, + DIV_ROUND_UP(pll->pll_op_clk_freq_hz, + limits->vt.min_pix_clk_freq_hz)); + dev_dbg(dev, "max_sys_div: min_vt_pix_clk_freq_hz: %u\n", max_sys_div); + + /* + * Find pix_div such that a legal pix_div * sys_div results + * into a value which is not smaller than div, the desired + * divisor. + */ + for (vt_div = min_vt_div; vt_div <= max_vt_div; + vt_div += 2 - (vt_div & 1)) { + for (sys_div = min_sys_div; + sys_div <= max_sys_div; + sys_div += 2 - (sys_div & 1)) { + uint16_t pix_div = DIV_ROUND_UP(vt_div, sys_div); + + if (pix_div < limits->vt.min_pix_clk_div + || pix_div > limits->vt.max_pix_clk_div) { + dev_dbg(dev, + "pix_div %u too small or too big (%u--%u)\n", + pix_div, + limits->vt.min_pix_clk_div, + limits->vt.max_pix_clk_div); + continue; + } + + /* Check if this one is better. */ + if (pix_div * sys_div + <= roundup(min_vt_div, best_pix_div)) + best_pix_div = pix_div; + } + if (best_pix_div < INT_MAX >> 1) + break; + } + + pll->vt.sys_clk_div = DIV_ROUND_UP(min_vt_div, best_pix_div); + pll->vt.pix_clk_div = best_pix_div; + + pll->vt.sys_clk_freq_hz = + pll->pll_op_clk_freq_hz / pll->vt.sys_clk_div; + pll->vt.pix_clk_freq_hz = + pll->vt.sys_clk_freq_hz / pll->vt.pix_clk_div; + +out_skip_vt_calc: + pll->pixel_rate_csi = + op_pll->pix_clk_freq_hz * lane_op_clock_ratio; + pll->pixel_rate_pixel_array = pll->vt.pix_clk_freq_hz; + + return check_all_bounds(dev, limits, op_limits, pll, op_pll); +} + +int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *limits, + struct ccs_pll *pll) +{ + const struct ccs_pll_branch_limits *op_limits = &limits->op; + struct ccs_pll_branch *op_pll = &pll->op; + uint16_t min_pre_pll_clk_div; + uint16_t max_pre_pll_clk_div; + uint32_t lane_op_clock_ratio; + uint32_t mul, div; + unsigned int i; + int rval = -EINVAL; + + if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS) { + /* + * If there's no OP PLL at all, use the VT values + * instead. The OP values are ignored for the rest of + * the PLL calculation. + */ + op_limits = &limits->vt; + op_pll = &pll->vt; + } + + if (pll->flags & CCS_PLL_FLAG_OP_PIX_CLOCK_PER_LANE) + lane_op_clock_ratio = pll->csi2.lanes; + else + lane_op_clock_ratio = 1; + dev_dbg(dev, "lane_op_clock_ratio: %u\n", lane_op_clock_ratio); + + dev_dbg(dev, "binning: %ux%u\n", pll->binning_horizontal, + pll->binning_vertical); + + switch (pll->bus_type) { + case CCS_PLL_BUS_TYPE_CSI2: + /* CSI transfers 2 bits per clock per lane; thus times 2 */ + pll->pll_op_clk_freq_hz = pll->link_freq * 2 + * (pll->csi2.lanes / lane_op_clock_ratio); + break; + case CCS_PLL_BUS_TYPE_PARALLEL: + pll->pll_op_clk_freq_hz = pll->link_freq * pll->bits_per_pixel + / DIV_ROUND_UP(pll->bits_per_pixel, + pll->parallel.bus_width); + break; + default: + return -EINVAL; + } + + /* Figure out limits for pre-pll divider based on extclk */ + dev_dbg(dev, "min / max pre_pll_clk_div: %u / %u\n", + limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div); + max_pre_pll_clk_div = + min_t(uint16_t, limits->max_pre_pll_clk_div, + clk_div_even(pll->ext_clk_freq_hz / + limits->min_pll_ip_freq_hz)); + min_pre_pll_clk_div = + max_t(uint16_t, limits->min_pre_pll_clk_div, + clk_div_even_up( + DIV_ROUND_UP(pll->ext_clk_freq_hz, + limits->max_pll_ip_freq_hz))); + dev_dbg(dev, "pre-pll check: min / max pre_pll_clk_div: %u / %u\n", + min_pre_pll_clk_div, max_pre_pll_clk_div); + + i = gcd(pll->pll_op_clk_freq_hz, pll->ext_clk_freq_hz); + mul = div_u64(pll->pll_op_clk_freq_hz, i); + div = pll->ext_clk_freq_hz / i; + dev_dbg(dev, "mul %u / div %u\n", mul, div); + + min_pre_pll_clk_div = + max_t(uint16_t, min_pre_pll_clk_div, + clk_div_even_up( + DIV_ROUND_UP(mul * pll->ext_clk_freq_hz, + limits->max_pll_op_freq_hz))); + dev_dbg(dev, "pll_op check: min / max pre_pll_clk_div: %u / %u\n", + min_pre_pll_clk_div, max_pre_pll_clk_div); + + for (pll->pre_pll_clk_div = min_pre_pll_clk_div; + pll->pre_pll_clk_div <= max_pre_pll_clk_div; + pll->pre_pll_clk_div += 2 - (pll->pre_pll_clk_div & 1)) { + rval = __ccs_pll_calculate(dev, limits, op_limits, pll, op_pll, + mul, div, lane_op_clock_ratio); + if (rval) + continue; + + print_pll(dev, pll); + return 0; + } + + dev_dbg(dev, "unable to compute pre_pll divisor\n"); + + return rval; +} +EXPORT_SYMBOL_GPL(ccs_pll_calculate); + +MODULE_AUTHOR("Sakari Ailus "); +MODULE_DESCRIPTION("Generic MIPI CCS/SMIA/SMIA++ PLL calculator"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/ccs-pll.h b/drivers/media/i2c/ccs-pll.h new file mode 100644 index 000000000000..88d641ee3fa1 --- /dev/null +++ b/drivers/media/i2c/ccs-pll.h @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * drivers/media/i2c/ccs-pll.h + * + * Generic MIPI CCS/SMIA/SMIA++ PLL calculator + * + * Copyright (C) 2020 Intel Corporation + * Copyright (C) 2012 Nokia Corporation + * Contact: Sakari Ailus + */ + +#ifndef CCS_PLL_H +#define CCS_PLL_H + +/* CSI-2 or CCP-2 */ +#define CCS_PLL_BUS_TYPE_CSI2 0x00 +#define CCS_PLL_BUS_TYPE_PARALLEL 0x01 + +/* op pix clock is for all lanes in total normally */ +#define CCS_PLL_FLAG_OP_PIX_CLOCK_PER_LANE (1 << 0) +#define CCS_PLL_FLAG_NO_OP_CLOCKS (1 << 1) + +struct ccs_pll_branch { + uint16_t sys_clk_div; + uint16_t pix_clk_div; + uint32_t sys_clk_freq_hz; + uint32_t pix_clk_freq_hz; +}; + +struct ccs_pll { + /* input values */ + uint8_t bus_type; + union { + struct { + uint8_t lanes; + } csi2; + struct { + uint8_t bus_width; + } parallel; + }; + unsigned long flags; + uint8_t binning_horizontal; + uint8_t binning_vertical; + uint8_t scale_m; + uint8_t scale_n; + uint8_t bits_per_pixel; + uint32_t link_freq; + uint32_t ext_clk_freq_hz; + + /* output values */ + uint16_t pre_pll_clk_div; + uint16_t pll_multiplier; + uint32_t pll_ip_clk_freq_hz; + uint32_t pll_op_clk_freq_hz; + struct ccs_pll_branch vt; + struct ccs_pll_branch op; + + uint32_t pixel_rate_csi; + uint32_t pixel_rate_pixel_array; +}; + +struct ccs_pll_branch_limits { + uint16_t min_sys_clk_div; + uint16_t max_sys_clk_div; + uint32_t min_sys_clk_freq_hz; + uint32_t max_sys_clk_freq_hz; + uint16_t min_pix_clk_div; + uint16_t max_pix_clk_div; + uint32_t min_pix_clk_freq_hz; + uint32_t max_pix_clk_freq_hz; +}; + +struct ccs_pll_limits { + /* Strict PLL limits */ + uint32_t min_ext_clk_freq_hz; + uint32_t max_ext_clk_freq_hz; + uint16_t min_pre_pll_clk_div; + uint16_t max_pre_pll_clk_div; + uint32_t min_pll_ip_freq_hz; + uint32_t max_pll_ip_freq_hz; + uint16_t min_pll_multiplier; + uint16_t max_pll_multiplier; + uint32_t min_pll_op_freq_hz; + uint32_t max_pll_op_freq_hz; + + struct ccs_pll_branch_limits vt; + struct ccs_pll_branch_limits op; + + /* Other relevant limits */ + uint32_t min_line_length_pck_bin; + uint32_t min_line_length_pck; +}; + +struct device; + +int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *limits, + struct ccs_pll *pll); + +#endif /* CCS_PLL_H */ diff --git a/drivers/media/i2c/ccs/Kconfig b/drivers/media/i2c/ccs/Kconfig index b4f8b10da420..59f35b33ddc1 100644 --- a/drivers/media/i2c/ccs/Kconfig +++ b/drivers/media/i2c/ccs/Kconfig @@ -4,7 +4,7 @@ config VIDEO_CCS depends on I2C && VIDEO_V4L2 && HAVE_CLK select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API - select VIDEO_SMIAPP_PLL + select VIDEO_CCS_PLL select V4L2_FWNODE help This is a generic driver for MIPI CCS, SMIA++ and SMIA compliant diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 074b246538d2..6c8528e6ac96 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -363,7 +363,7 @@ static int ccs_read_frame_fmt(struct ccs_sensor *sensor) static int ccs_pll_configure(struct ccs_sensor *sensor) { - struct smiapp_pll *pll = &sensor->pll; + struct ccs_pll *pll = &sensor->pll; int rval; rval = ccs_write(sensor, VT_PIX_CLK_DIV, pll->vt.pix_clk_div); @@ -386,7 +386,7 @@ static int ccs_pll_configure(struct ccs_sensor *sensor) rval = ccs_write(sensor, REQUESTED_LINK_RATE, DIV_ROUND_UP(pll->op.sys_clk_freq_hz, 1000000 / 256 / 256)); - if (rval < 0 || sensor->pll.flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS) + if (rval < 0 || sensor->pll.flags & CCS_PLL_FLAG_NO_OP_CLOCKS) return rval; rval = ccs_write(sensor, OP_PIX_CLK_DIV, pll->op.pix_clk_div); @@ -396,10 +396,10 @@ static int ccs_pll_configure(struct ccs_sensor *sensor) return ccs_write(sensor, OP_SYS_CLK_DIV, pll->op.sys_clk_div); } -static int ccs_pll_try(struct ccs_sensor *sensor, struct smiapp_pll *pll) +static int ccs_pll_try(struct ccs_sensor *sensor, struct ccs_pll *pll) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - struct smiapp_pll_limits lim = { + struct ccs_pll_limits lim = { .min_pre_pll_clk_div = CCS_LIM(sensor, MIN_PRE_PLL_CLK_DIV), .max_pre_pll_clk_div = CCS_LIM(sensor, MAX_PRE_PLL_CLK_DIV), .min_pll_ip_freq_hz = CCS_LIM(sensor, MIN_PLL_IP_CLK_FREQ_MHZ), @@ -431,12 +431,12 @@ static int ccs_pll_try(struct ccs_sensor *sensor, struct smiapp_pll *pll) .min_line_length_pck = CCS_LIM(sensor, MIN_LINE_LENGTH_PCK), }; - return smiapp_pll_calculate(&client->dev, &lim, pll); + return ccs_pll_calculate(&client->dev, &lim, pll); } static int ccs_pll_update(struct ccs_sensor *sensor) { - struct smiapp_pll *pll = &sensor->pll; + struct ccs_pll *pll = &sensor->pll; int rval; pll->binning_horizontal = sensor->binning_horizontal; @@ -829,7 +829,7 @@ static void ccs_free_controls(struct ccs_sensor *sensor) static int ccs_get_mbus_formats(struct ccs_sensor *sensor) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - struct smiapp_pll *pll = &sensor->pll; + struct ccs_pll *pll = &sensor->pll; u8 compressed_max_bpp = 0; unsigned int type, n; unsigned int i, pixel_order; @@ -3155,7 +3155,7 @@ static int ccs_probe(struct i2c_client *client) !CCS_LIM(sensor, MIN_OP_PIX_CLK_DIV) || !CCS_LIM(sensor, MAX_OP_PIX_CLK_DIV)) { /* No OP clock branch */ - sensor->pll.flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS; + sensor->pll.flags |= CCS_PLL_FLAG_NO_OP_CLOCKS; } else if (CCS_LIM(sensor, SCALING_CAPABILITY) != CCS_SCALING_CAPABILITY_NONE || CCS_LIM(sensor, DIGITAL_CROP_CAPABILITY) @@ -3172,7 +3172,7 @@ static int ccs_probe(struct i2c_client *client) sensor->scale_m = CCS_LIM(sensor, SCALER_N_MIN); /* prepare PLL configuration input values */ - sensor->pll.bus_type = SMIAPP_PLL_BUS_TYPE_CSI2; + sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2; sensor->pll.csi2.lanes = sensor->hwcfg.lanes; sensor->pll.ext_clk_freq_hz = sensor->hwcfg.ext_clk; sensor->pll.scale_n = CCS_LIM(sensor, SCALER_N_MIN); diff --git a/drivers/media/i2c/ccs/ccs-quirk.c b/drivers/media/i2c/ccs/ccs-quirk.c index 07c5733b4244..8b4fa60044b2 100644 --- a/drivers/media/i2c/ccs/ccs-quirk.c +++ b/drivers/media/i2c/ccs/ccs-quirk.c @@ -190,7 +190,7 @@ static int jt8ev1_post_streamoff(struct ccs_sensor *sensor) static int jt8ev1_init(struct ccs_sensor *sensor) { - sensor->pll.flags |= SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE; + sensor->pll.flags |= CCS_PLL_FLAG_OP_PIX_CLOCK_PER_LANE; return 0; } diff --git a/drivers/media/i2c/ccs/ccs.h b/drivers/media/i2c/ccs/ccs.h index f60d1801c469..c8a9f4ee093e 100644 --- a/drivers/media/i2c/ccs/ccs.h +++ b/drivers/media/i2c/ccs/ccs.h @@ -21,7 +21,7 @@ #include "ccs-quirk.h" #include "ccs-regs.h" #include "ccs-reg-access.h" -#include "../smiapp-pll.h" +#include "../ccs-pll.h" #include "smiapp-reg-defs.h" /* @@ -256,7 +256,7 @@ struct ccs_sensor { struct ccs_module_info minfo; - struct smiapp_pll pll; + struct ccs_pll pll; /* Is a default format supported for a given BPP? */ unsigned long *valid_link_freqs; diff --git a/drivers/media/i2c/smiapp-pll.c b/drivers/media/i2c/smiapp-pll.c deleted file mode 100644 index 690abe8cbdb2..000000000000 --- a/drivers/media/i2c/smiapp-pll.c +++ /dev/null @@ -1,482 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * drivers/media/i2c/smiapp-pll.c - * - * Generic driver for SMIA/SMIA++ compliant camera modules - * - * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus - */ - -#include -#include -#include -#include - -#include "smiapp-pll.h" - -/* Return an even number or one. */ -static inline uint32_t clk_div_even(uint32_t a) -{ - return max_t(uint32_t, 1, a & ~1); -} - -/* Return an even number or one. */ -static inline uint32_t clk_div_even_up(uint32_t a) -{ - if (a == 1) - return 1; - return (a + 1) & ~1; -} - -static inline uint32_t is_one_or_even(uint32_t a) -{ - if (a == 1) - return 1; - if (a & 1) - return 0; - - return 1; -} - -static int bounds_check(struct device *dev, uint32_t val, - uint32_t min, uint32_t max, char *str) -{ - if (val >= min && val <= max) - return 0; - - dev_dbg(dev, "%s out of bounds: %d (%d--%d)\n", str, val, min, max); - - return -EINVAL; -} - -static void print_pll(struct device *dev, struct smiapp_pll *pll) -{ - dev_dbg(dev, "pre_pll_clk_div\t%u\n", pll->pre_pll_clk_div); - dev_dbg(dev, "pll_multiplier \t%u\n", pll->pll_multiplier); - if (!(pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS)) { - dev_dbg(dev, "op_sys_clk_div \t%u\n", pll->op.sys_clk_div); - dev_dbg(dev, "op_pix_clk_div \t%u\n", pll->op.pix_clk_div); - } - dev_dbg(dev, "vt_sys_clk_div \t%u\n", pll->vt.sys_clk_div); - dev_dbg(dev, "vt_pix_clk_div \t%u\n", pll->vt.pix_clk_div); - - dev_dbg(dev, "ext_clk_freq_hz \t%u\n", pll->ext_clk_freq_hz); - dev_dbg(dev, "pll_ip_clk_freq_hz \t%u\n", pll->pll_ip_clk_freq_hz); - dev_dbg(dev, "pll_op_clk_freq_hz \t%u\n", pll->pll_op_clk_freq_hz); - if (!(pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS)) { - dev_dbg(dev, "op_sys_clk_freq_hz \t%u\n", - pll->op.sys_clk_freq_hz); - dev_dbg(dev, "op_pix_clk_freq_hz \t%u\n", - pll->op.pix_clk_freq_hz); - } - dev_dbg(dev, "vt_sys_clk_freq_hz \t%u\n", pll->vt.sys_clk_freq_hz); - dev_dbg(dev, "vt_pix_clk_freq_hz \t%u\n", pll->vt.pix_clk_freq_hz); -} - -static int check_all_bounds(struct device *dev, - const struct smiapp_pll_limits *limits, - const struct smiapp_pll_branch_limits *op_limits, - struct smiapp_pll *pll, - struct smiapp_pll_branch *op_pll) -{ - int rval; - - rval = bounds_check(dev, pll->pll_ip_clk_freq_hz, - limits->min_pll_ip_freq_hz, - limits->max_pll_ip_freq_hz, - "pll_ip_clk_freq_hz"); - if (!rval) - rval = bounds_check( - dev, pll->pll_multiplier, - limits->min_pll_multiplier, limits->max_pll_multiplier, - "pll_multiplier"); - if (!rval) - rval = bounds_check( - dev, pll->pll_op_clk_freq_hz, - limits->min_pll_op_freq_hz, limits->max_pll_op_freq_hz, - "pll_op_clk_freq_hz"); - if (!rval) - rval = bounds_check( - dev, op_pll->sys_clk_div, - op_limits->min_sys_clk_div, op_limits->max_sys_clk_div, - "op_sys_clk_div"); - if (!rval) - rval = bounds_check( - dev, op_pll->sys_clk_freq_hz, - op_limits->min_sys_clk_freq_hz, - op_limits->max_sys_clk_freq_hz, - "op_sys_clk_freq_hz"); - if (!rval) - rval = bounds_check( - dev, op_pll->pix_clk_freq_hz, - op_limits->min_pix_clk_freq_hz, - op_limits->max_pix_clk_freq_hz, - "op_pix_clk_freq_hz"); - - /* - * If there are no OP clocks, the VT clocks are contained in - * the OP clock struct. - */ - if (pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS) - return rval; - - if (!rval) - rval = bounds_check( - dev, pll->vt.sys_clk_freq_hz, - limits->vt.min_sys_clk_freq_hz, - limits->vt.max_sys_clk_freq_hz, - "vt_sys_clk_freq_hz"); - if (!rval) - rval = bounds_check( - dev, pll->vt.pix_clk_freq_hz, - limits->vt.min_pix_clk_freq_hz, - limits->vt.max_pix_clk_freq_hz, - "vt_pix_clk_freq_hz"); - - return rval; -} - -/* - * Heuristically guess the PLL tree for a given common multiplier and - * divisor. Begin with the operational timing and continue to video - * timing once operational timing has been verified. - * - * @mul is the PLL multiplier and @div is the common divisor - * (pre_pll_clk_div and op_sys_clk_div combined). The final PLL - * multiplier will be a multiple of @mul. - * - * @return Zero on success, error code on error. - */ -static int __smiapp_pll_calculate( - struct device *dev, const struct smiapp_pll_limits *limits, - const struct smiapp_pll_branch_limits *op_limits, - struct smiapp_pll *pll, struct smiapp_pll_branch *op_pll, uint32_t mul, - uint32_t div, uint32_t lane_op_clock_ratio) -{ - uint32_t sys_div; - uint32_t best_pix_div = INT_MAX >> 1; - uint32_t vt_op_binning_div; - /* - * Higher multipliers (and divisors) are often required than - * necessitated by the external clock and the output clocks. - * There are limits for all values in the clock tree. These - * are the minimum and maximum multiplier for mul. - */ - uint32_t more_mul_min, more_mul_max; - uint32_t more_mul_factor; - uint32_t min_vt_div, max_vt_div, vt_div; - uint32_t min_sys_div, max_sys_div; - unsigned int i; - - /* - * Get pre_pll_clk_div so that our pll_op_clk_freq_hz won't be - * too high. - */ - dev_dbg(dev, "pre_pll_clk_div %u\n", pll->pre_pll_clk_div); - - /* Don't go above max pll multiplier. */ - more_mul_max = limits->max_pll_multiplier / mul; - dev_dbg(dev, "more_mul_max: max_pll_multiplier check: %u\n", - more_mul_max); - /* Don't go above max pll op frequency. */ - more_mul_max = - min_t(uint32_t, - more_mul_max, - limits->max_pll_op_freq_hz - / (pll->ext_clk_freq_hz / pll->pre_pll_clk_div * mul)); - dev_dbg(dev, "more_mul_max: max_pll_op_freq_hz check: %u\n", - more_mul_max); - /* Don't go above the division capability of op sys clock divider. */ - more_mul_max = min(more_mul_max, - op_limits->max_sys_clk_div * pll->pre_pll_clk_div - / div); - dev_dbg(dev, "more_mul_max: max_op_sys_clk_div check: %u\n", - more_mul_max); - /* Ensure we won't go above min_pll_multiplier. */ - more_mul_max = min(more_mul_max, - DIV_ROUND_UP(limits->max_pll_multiplier, mul)); - dev_dbg(dev, "more_mul_max: min_pll_multiplier check: %u\n", - more_mul_max); - - /* Ensure we won't go below min_pll_op_freq_hz. */ - more_mul_min = DIV_ROUND_UP(limits->min_pll_op_freq_hz, - pll->ext_clk_freq_hz / pll->pre_pll_clk_div - * mul); - dev_dbg(dev, "more_mul_min: min_pll_op_freq_hz check: %u\n", - more_mul_min); - /* Ensure we won't go below min_pll_multiplier. */ - more_mul_min = max(more_mul_min, - DIV_ROUND_UP(limits->min_pll_multiplier, mul)); - dev_dbg(dev, "more_mul_min: min_pll_multiplier check: %u\n", - more_mul_min); - - if (more_mul_min > more_mul_max) { - dev_dbg(dev, - "unable to compute more_mul_min and more_mul_max\n"); - return -EINVAL; - } - - more_mul_factor = lcm(div, pll->pre_pll_clk_div) / div; - dev_dbg(dev, "more_mul_factor: %u\n", more_mul_factor); - more_mul_factor = lcm(more_mul_factor, op_limits->min_sys_clk_div); - dev_dbg(dev, "more_mul_factor: min_op_sys_clk_div: %d\n", - more_mul_factor); - i = roundup(more_mul_min, more_mul_factor); - if (!is_one_or_even(i)) - i <<= 1; - - dev_dbg(dev, "final more_mul: %u\n", i); - if (i > more_mul_max) { - dev_dbg(dev, "final more_mul is bad, max %u\n", more_mul_max); - return -EINVAL; - } - - pll->pll_multiplier = mul * i; - op_pll->sys_clk_div = div * i / pll->pre_pll_clk_div; - dev_dbg(dev, "op_sys_clk_div: %u\n", op_pll->sys_clk_div); - - pll->pll_ip_clk_freq_hz = pll->ext_clk_freq_hz - / pll->pre_pll_clk_div; - - pll->pll_op_clk_freq_hz = pll->pll_ip_clk_freq_hz - * pll->pll_multiplier; - - /* Derive pll_op_clk_freq_hz. */ - op_pll->sys_clk_freq_hz = - pll->pll_op_clk_freq_hz / op_pll->sys_clk_div; - - op_pll->pix_clk_div = pll->bits_per_pixel; - dev_dbg(dev, "op_pix_clk_div: %u\n", op_pll->pix_clk_div); - - op_pll->pix_clk_freq_hz = - op_pll->sys_clk_freq_hz / op_pll->pix_clk_div; - - if (pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS) { - /* No OP clocks --- VT clocks are used instead. */ - goto out_skip_vt_calc; - } - - /* - * Some sensors perform analogue binning and some do this - * digitally. The ones doing this digitally can be roughly be - * found out using this formula. The ones doing this digitally - * should run at higher clock rate, so smaller divisor is used - * on video timing side. - */ - if (limits->min_line_length_pck_bin > limits->min_line_length_pck - / pll->binning_horizontal) - vt_op_binning_div = pll->binning_horizontal; - else - vt_op_binning_div = 1; - dev_dbg(dev, "vt_op_binning_div: %u\n", vt_op_binning_div); - - /* - * Profile 2 supports vt_pix_clk_div E [4, 10] - * - * Horizontal binning can be used as a base for difference in - * divisors. One must make sure that horizontal blanking is - * enough to accommodate the CSI-2 sync codes. - * - * Take scaling factor into account as well. - * - * Find absolute limits for the factor of vt divider. - */ - dev_dbg(dev, "scale_m: %u\n", pll->scale_m); - min_vt_div = DIV_ROUND_UP(op_pll->pix_clk_div * op_pll->sys_clk_div - * pll->scale_n, - lane_op_clock_ratio * vt_op_binning_div - * pll->scale_m); - - /* Find smallest and biggest allowed vt divisor. */ - dev_dbg(dev, "min_vt_div: %u\n", min_vt_div); - min_vt_div = max(min_vt_div, - DIV_ROUND_UP(pll->pll_op_clk_freq_hz, - limits->vt.max_pix_clk_freq_hz)); - dev_dbg(dev, "min_vt_div: max_vt_pix_clk_freq_hz: %u\n", - min_vt_div); - min_vt_div = max_t(uint32_t, min_vt_div, - limits->vt.min_pix_clk_div - * limits->vt.min_sys_clk_div); - dev_dbg(dev, "min_vt_div: min_vt_clk_div: %u\n", min_vt_div); - - max_vt_div = limits->vt.max_sys_clk_div * limits->vt.max_pix_clk_div; - dev_dbg(dev, "max_vt_div: %u\n", max_vt_div); - max_vt_div = min(max_vt_div, - DIV_ROUND_UP(pll->pll_op_clk_freq_hz, - limits->vt.min_pix_clk_freq_hz)); - dev_dbg(dev, "max_vt_div: min_vt_pix_clk_freq_hz: %u\n", - max_vt_div); - - /* - * Find limitsits for sys_clk_div. Not all values are possible - * with all values of pix_clk_div. - */ - min_sys_div = limits->vt.min_sys_clk_div; - dev_dbg(dev, "min_sys_div: %u\n", min_sys_div); - min_sys_div = max(min_sys_div, - DIV_ROUND_UP(min_vt_div, - limits->vt.max_pix_clk_div)); - dev_dbg(dev, "min_sys_div: max_vt_pix_clk_div: %u\n", min_sys_div); - min_sys_div = max(min_sys_div, - pll->pll_op_clk_freq_hz - / limits->vt.max_sys_clk_freq_hz); - dev_dbg(dev, "min_sys_div: max_pll_op_clk_freq_hz: %u\n", min_sys_div); - min_sys_div = clk_div_even_up(min_sys_div); - dev_dbg(dev, "min_sys_div: one or even: %u\n", min_sys_div); - - max_sys_div = limits->vt.max_sys_clk_div; - dev_dbg(dev, "max_sys_div: %u\n", max_sys_div); - max_sys_div = min(max_sys_div, - DIV_ROUND_UP(max_vt_div, - limits->vt.min_pix_clk_div)); - dev_dbg(dev, "max_sys_div: min_vt_pix_clk_div: %u\n", max_sys_div); - max_sys_div = min(max_sys_div, - DIV_ROUND_UP(pll->pll_op_clk_freq_hz, - limits->vt.min_pix_clk_freq_hz)); - dev_dbg(dev, "max_sys_div: min_vt_pix_clk_freq_hz: %u\n", max_sys_div); - - /* - * Find pix_div such that a legal pix_div * sys_div results - * into a value which is not smaller than div, the desired - * divisor. - */ - for (vt_div = min_vt_div; vt_div <= max_vt_div; - vt_div += 2 - (vt_div & 1)) { - for (sys_div = min_sys_div; - sys_div <= max_sys_div; - sys_div += 2 - (sys_div & 1)) { - uint16_t pix_div = DIV_ROUND_UP(vt_div, sys_div); - - if (pix_div < limits->vt.min_pix_clk_div - || pix_div > limits->vt.max_pix_clk_div) { - dev_dbg(dev, - "pix_div %u too small or too big (%u--%u)\n", - pix_div, - limits->vt.min_pix_clk_div, - limits->vt.max_pix_clk_div); - continue; - } - - /* Check if this one is better. */ - if (pix_div * sys_div - <= roundup(min_vt_div, best_pix_div)) - best_pix_div = pix_div; - } - if (best_pix_div < INT_MAX >> 1) - break; - } - - pll->vt.sys_clk_div = DIV_ROUND_UP(min_vt_div, best_pix_div); - pll->vt.pix_clk_div = best_pix_div; - - pll->vt.sys_clk_freq_hz = - pll->pll_op_clk_freq_hz / pll->vt.sys_clk_div; - pll->vt.pix_clk_freq_hz = - pll->vt.sys_clk_freq_hz / pll->vt.pix_clk_div; - -out_skip_vt_calc: - pll->pixel_rate_csi = - op_pll->pix_clk_freq_hz * lane_op_clock_ratio; - pll->pixel_rate_pixel_array = pll->vt.pix_clk_freq_hz; - - return check_all_bounds(dev, limits, op_limits, pll, op_pll); -} - -int smiapp_pll_calculate(struct device *dev, - const struct smiapp_pll_limits *limits, - struct smiapp_pll *pll) -{ - const struct smiapp_pll_branch_limits *op_limits = &limits->op; - struct smiapp_pll_branch *op_pll = &pll->op; - uint16_t min_pre_pll_clk_div; - uint16_t max_pre_pll_clk_div; - uint32_t lane_op_clock_ratio; - uint32_t mul, div; - unsigned int i; - int rval = -EINVAL; - - if (pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS) { - /* - * If there's no OP PLL at all, use the VT values - * instead. The OP values are ignored for the rest of - * the PLL calculation. - */ - op_limits = &limits->vt; - op_pll = &pll->vt; - } - - if (pll->flags & SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE) - lane_op_clock_ratio = pll->csi2.lanes; - else - lane_op_clock_ratio = 1; - dev_dbg(dev, "lane_op_clock_ratio: %u\n", lane_op_clock_ratio); - - dev_dbg(dev, "binning: %ux%u\n", pll->binning_horizontal, - pll->binning_vertical); - - switch (pll->bus_type) { - case SMIAPP_PLL_BUS_TYPE_CSI2: - /* CSI transfers 2 bits per clock per lane; thus times 2 */ - pll->pll_op_clk_freq_hz = pll->link_freq * 2 - * (pll->csi2.lanes / lane_op_clock_ratio); - break; - case SMIAPP_PLL_BUS_TYPE_PARALLEL: - pll->pll_op_clk_freq_hz = pll->link_freq * pll->bits_per_pixel - / DIV_ROUND_UP(pll->bits_per_pixel, - pll->parallel.bus_width); - break; - default: - return -EINVAL; - } - - /* Figure out limits for pre-pll divider based on extclk */ - dev_dbg(dev, "min / max pre_pll_clk_div: %u / %u\n", - limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div); - max_pre_pll_clk_div = - min_t(uint16_t, limits->max_pre_pll_clk_div, - clk_div_even(pll->ext_clk_freq_hz / - limits->min_pll_ip_freq_hz)); - min_pre_pll_clk_div = - max_t(uint16_t, limits->min_pre_pll_clk_div, - clk_div_even_up( - DIV_ROUND_UP(pll->ext_clk_freq_hz, - limits->max_pll_ip_freq_hz))); - dev_dbg(dev, "pre-pll check: min / max pre_pll_clk_div: %u / %u\n", - min_pre_pll_clk_div, max_pre_pll_clk_div); - - i = gcd(pll->pll_op_clk_freq_hz, pll->ext_clk_freq_hz); - mul = div_u64(pll->pll_op_clk_freq_hz, i); - div = pll->ext_clk_freq_hz / i; - dev_dbg(dev, "mul %u / div %u\n", mul, div); - - min_pre_pll_clk_div = - max_t(uint16_t, min_pre_pll_clk_div, - clk_div_even_up( - DIV_ROUND_UP(mul * pll->ext_clk_freq_hz, - limits->max_pll_op_freq_hz))); - dev_dbg(dev, "pll_op check: min / max pre_pll_clk_div: %u / %u\n", - min_pre_pll_clk_div, max_pre_pll_clk_div); - - for (pll->pre_pll_clk_div = min_pre_pll_clk_div; - pll->pre_pll_clk_div <= max_pre_pll_clk_div; - pll->pre_pll_clk_div += 2 - (pll->pre_pll_clk_div & 1)) { - rval = __smiapp_pll_calculate(dev, limits, op_limits, pll, - op_pll, mul, div, - lane_op_clock_ratio); - if (rval) - continue; - - print_pll(dev, pll); - return 0; - } - - dev_dbg(dev, "unable to compute pre_pll divisor\n"); - - return rval; -} -EXPORT_SYMBOL_GPL(smiapp_pll_calculate); - -MODULE_AUTHOR("Sakari Ailus "); -MODULE_DESCRIPTION("Generic SMIA/SMIA++ PLL calculator"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/smiapp-pll.h b/drivers/media/i2c/smiapp-pll.h deleted file mode 100644 index bd6902f54539..000000000000 --- a/drivers/media/i2c/smiapp-pll.h +++ /dev/null @@ -1,99 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * drivers/media/i2c/smiapp-pll.h - * - * Generic driver for SMIA/SMIA++ compliant camera modules - * - * Copyright (C) 2012 Nokia Corporation - * Contact: Sakari Ailus - */ - -#ifndef SMIAPP_PLL_H -#define SMIAPP_PLL_H - -/* CSI-2 or CCP-2 */ -#define SMIAPP_PLL_BUS_TYPE_CSI2 0x00 -#define SMIAPP_PLL_BUS_TYPE_PARALLEL 0x01 - -/* op pix clock is for all lanes in total normally */ -#define SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE (1 << 0) -#define SMIAPP_PLL_FLAG_NO_OP_CLOCKS (1 << 1) - -struct smiapp_pll_branch { - uint16_t sys_clk_div; - uint16_t pix_clk_div; - uint32_t sys_clk_freq_hz; - uint32_t pix_clk_freq_hz; -}; - -struct smiapp_pll { - /* input values */ - uint8_t bus_type; - union { - struct { - uint8_t lanes; - } csi2; - struct { - uint8_t bus_width; - } parallel; - }; - unsigned long flags; - uint8_t binning_horizontal; - uint8_t binning_vertical; - uint8_t scale_m; - uint8_t scale_n; - uint8_t bits_per_pixel; - uint32_t link_freq; - uint32_t ext_clk_freq_hz; - - /* output values */ - uint16_t pre_pll_clk_div; - uint16_t pll_multiplier; - uint32_t pll_ip_clk_freq_hz; - uint32_t pll_op_clk_freq_hz; - struct smiapp_pll_branch vt; - struct smiapp_pll_branch op; - - uint32_t pixel_rate_csi; - uint32_t pixel_rate_pixel_array; -}; - -struct smiapp_pll_branch_limits { - uint16_t min_sys_clk_div; - uint16_t max_sys_clk_div; - uint32_t min_sys_clk_freq_hz; - uint32_t max_sys_clk_freq_hz; - uint16_t min_pix_clk_div; - uint16_t max_pix_clk_div; - uint32_t min_pix_clk_freq_hz; - uint32_t max_pix_clk_freq_hz; -}; - -struct smiapp_pll_limits { - /* Strict PLL limits */ - uint32_t min_ext_clk_freq_hz; - uint32_t max_ext_clk_freq_hz; - uint16_t min_pre_pll_clk_div; - uint16_t max_pre_pll_clk_div; - uint32_t min_pll_ip_freq_hz; - uint32_t max_pll_ip_freq_hz; - uint16_t min_pll_multiplier; - uint16_t max_pll_multiplier; - uint32_t min_pll_op_freq_hz; - uint32_t max_pll_op_freq_hz; - - struct smiapp_pll_branch_limits vt; - struct smiapp_pll_branch_limits op; - - /* Other relevant limits */ - uint32_t min_line_length_pck_bin; - uint32_t min_line_length_pck; -}; - -struct device; - -int smiapp_pll_calculate(struct device *dev, - const struct smiapp_pll_limits *limits, - struct smiapp_pll *pll); - -#endif /* SMIAPP_PLL_H */ -- cgit v1.2.3 From b3c0115e34adcabe12fce8845e24ca6f04c1554e Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 2 Oct 2020 13:36:14 +0200 Subject: media: ccs-pll: Fix MODULE_LICENSE Change MODULE_LICENSE to "GPL v2" as indicated by the SPDX tag. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index d2f0f7375f5c..58f5fe7062ae 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -477,4 +477,4 @@ EXPORT_SYMBOL_GPL(ccs_pll_calculate); MODULE_AUTHOR("Sakari Ailus "); MODULE_DESCRIPTION("Generic MIPI CCS/SMIA/SMIA++ PLL calculator"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 7389d01cc5d7cac6920f28e04afdf85c287e25a1 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 24 Jun 2020 23:57:46 +0200 Subject: media: ccs: Change my e-mail address Use my @linux.intel.com e-mail address in the CCS driver. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 4 ++-- drivers/media/i2c/ccs-pll.h | 2 +- drivers/media/i2c/ccs/ccs-core.c | 6 +++--- drivers/media/i2c/ccs/ccs-quirk.c | 2 +- drivers/media/i2c/ccs/ccs-quirk.h | 2 +- drivers/media/i2c/ccs/ccs-reg-access.c | 2 +- drivers/media/i2c/ccs/ccs-reg-access.h | 2 +- drivers/media/i2c/ccs/ccs.h | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index 58f5fe7062ae..0d57bac1599a 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -6,7 +6,7 @@ * * Copyright (C) 2020 Intel Corporation * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus + * Contact: Sakari Ailus */ #include @@ -475,6 +475,6 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *limits, } EXPORT_SYMBOL_GPL(ccs_pll_calculate); -MODULE_AUTHOR("Sakari Ailus "); +MODULE_AUTHOR("Sakari Ailus "); MODULE_DESCRIPTION("Generic MIPI CCS/SMIA/SMIA++ PLL calculator"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/ccs-pll.h b/drivers/media/i2c/ccs-pll.h index 88d641ee3fa1..07f7f9e8a1cc 100644 --- a/drivers/media/i2c/ccs-pll.h +++ b/drivers/media/i2c/ccs-pll.h @@ -6,7 +6,7 @@ * * Copyright (C) 2020 Intel Corporation * Copyright (C) 2012 Nokia Corporation - * Contact: Sakari Ailus + * Contact: Sakari Ailus */ #ifndef CCS_PLL_H diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 6c8528e6ac96..c53911b1c78b 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -6,7 +6,7 @@ * * Copyright (C) 2020 Intel Corporation * Copyright (C) 2010--2012 Nokia Corporation - * Contact: Sakari Ailus + * Contact: Sakari Ailus * * Based on smiapp driver by Vimarsh Zutshi * Based on jt8ev1.c by Vimarsh Zutshi @@ -1168,7 +1168,7 @@ static int ccs_setup_flash_strobe(struct ccs_sensor *sensor) * do not change, or if you do at least know what you're * doing. :-) * - * Sakari Ailus 2010-10-25 + * Sakari Ailus 2010-10-25 * * flash_strobe_length [us] / 10^6 = (tFlash_strobe_width_ctrl * / EXTCLK freq [Hz]) * flash_strobe_adjustment @@ -3357,7 +3357,7 @@ static void ccs_module_cleanup(void) module_init(ccs_module_init); module_exit(ccs_module_cleanup); -MODULE_AUTHOR("Sakari Ailus "); +MODULE_AUTHOR("Sakari Ailus "); MODULE_DESCRIPTION("Generic MIPI CCS/SMIA/SMIA++ camera sensor driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("smiapp"); diff --git a/drivers/media/i2c/ccs/ccs-quirk.c b/drivers/media/i2c/ccs/ccs-quirk.c index 8b4fa60044b2..4fe8c6f70579 100644 --- a/drivers/media/i2c/ccs/ccs-quirk.c +++ b/drivers/media/i2c/ccs/ccs-quirk.c @@ -6,7 +6,7 @@ * * Copyright (C) 2020 Intel Corporation * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus + * Contact: Sakari Ailus */ #include diff --git a/drivers/media/i2c/ccs/ccs-quirk.h b/drivers/media/i2c/ccs/ccs-quirk.h index 3e7779e2fc4b..6b4ec4beaba0 100644 --- a/drivers/media/i2c/ccs/ccs-quirk.h +++ b/drivers/media/i2c/ccs/ccs-quirk.h @@ -6,7 +6,7 @@ * * Copyright (C) 2020 Intel Corporation * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus + * Contact: Sakari Ailus */ #ifndef __CCS_QUIRK__ diff --git a/drivers/media/i2c/ccs/ccs-reg-access.c b/drivers/media/i2c/ccs/ccs-reg-access.c index 91ccbca11577..aad2727570ec 100644 --- a/drivers/media/i2c/ccs/ccs-reg-access.c +++ b/drivers/media/i2c/ccs/ccs-reg-access.c @@ -6,7 +6,7 @@ * * Copyright (C) 2020 Intel Corporation * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus + * Contact: Sakari Ailus */ #include diff --git a/drivers/media/i2c/ccs/ccs-reg-access.h b/drivers/media/i2c/ccs/ccs-reg-access.h index 5f6ff9c57698..cfad2e520fe2 100644 --- a/drivers/media/i2c/ccs/ccs-reg-access.h +++ b/drivers/media/i2c/ccs/ccs-reg-access.h @@ -6,7 +6,7 @@ * * Copyright (C) 2020 Intel Corporation * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus + * Contact: Sakari Ailus */ #ifndef SMIAPP_REGS_H diff --git a/drivers/media/i2c/ccs/ccs.h b/drivers/media/i2c/ccs/ccs.h index c8a9f4ee093e..6b07e4143ff0 100644 --- a/drivers/media/i2c/ccs/ccs.h +++ b/drivers/media/i2c/ccs/ccs.h @@ -6,7 +6,7 @@ * * Copyright (C) 2020 Intel Corporation * Copyright (C) 2010--2012 Nokia Corporation - * Contact: Sakari Ailus + * Contact: Sakari Ailus */ #ifndef __CCS_H__ -- cgit v1.2.3 From 2dd4b57944cc49b0693e17e6169b6c6ca0166abd Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 13 Nov 2020 16:07:28 +0100 Subject: media: ccs: Allow range in between I²C retries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the delay between I²C access retries a range between 1 and 2 ms. Also make the number of retries 10 instead of 5, in order not to reduce the total amount of time. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-reg-access.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-reg-access.c b/drivers/media/i2c/ccs/ccs-reg-access.c index aad2727570ec..79efed5e0dad 100644 --- a/drivers/media/i2c/ccs/ccs-reg-access.c +++ b/drivers/media/i2c/ccs/ccs-reg-access.c @@ -256,7 +256,7 @@ int ccs_write_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 val) put_unaligned_be16(CCS_REG_ADDR(reg), data); put_unaligned_be32(val << (8 * (sizeof(val) - len)), data + 2); - for (retries = 0; retries < 5; retries++) { + for (retries = 0; retries < 10; retries++) { /* * Due to unknown reason sensor stops responding. This * loop is a temporaty solution until the root cause @@ -271,7 +271,7 @@ int ccs_write_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 val) return 0; } - usleep_range(2000, 2000); + usleep_range(1000, 2000); } dev_err(&client->dev, -- cgit v1.2.3 From 2538d322108309c4738d0a3c12ef78b98aeb9d00 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 3 Sep 2020 11:32:56 +0200 Subject: media: ccs: Add support for manufacturer regs from sensor and module files Write manufacturer specific registers (MSRs) from file to the sensor on sensor power-on. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 23 +++++++++ drivers/media/i2c/ccs/ccs-reg-access.c | 94 ++++++++++++++++++++++++++-------- drivers/media/i2c/ccs/ccs-reg-access.h | 2 + 3 files changed, 97 insertions(+), 22 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index c53911b1c78b..5e01f22608d7 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -1278,6 +1278,21 @@ out: * Power management */ +static int ccs_write_msr_regs(struct ccs_sensor *sensor) +{ + int rval; + + rval = ccs_write_data_regs(sensor, + sensor->sdata.sensor_manufacturer_regs, + sensor->sdata.num_sensor_manufacturer_regs); + if (rval) + return rval; + + return ccs_write_data_regs(sensor, + sensor->mdata.module_manufacturer_regs, + sensor->mdata.num_module_manufacturer_regs); +} + static int ccs_power_on(struct device *dev) { struct v4l2_subdev *subdev = dev_get_drvdata(dev); @@ -1383,6 +1398,10 @@ static int ccs_power_on(struct device *dev) if (rval < 0) goto out_cci_addr_fail; + rval = ccs_write_msr_regs(sensor); + if (rval) + goto out_cci_addr_fail; + rval = ccs_call_quirk(sensor, post_poweron); if (rval) { dev_err(dev, "post_poweron quirks failed\n"); @@ -3220,6 +3239,10 @@ static int ccs_probe(struct i2c_client *client) if (rval < 0) goto out_media_entity_cleanup; + rval = ccs_write_msr_regs(sensor); + if (rval) + goto out_media_entity_cleanup; + pm_runtime_set_active(&client->dev); pm_runtime_get_noresume(&client->dev); pm_runtime_enable(&client->dev); diff --git a/drivers/media/i2c/ccs/ccs-reg-access.c b/drivers/media/i2c/ccs/ccs-reg-access.c index 79efed5e0dad..918bc98c226f 100644 --- a/drivers/media/i2c/ccs/ccs-reg-access.c +++ b/drivers/media/i2c/ccs/ccs-reg-access.c @@ -236,12 +236,38 @@ int ccs_read_addr_noconv(struct ccs_sensor *sensor, u32 reg, u32 *val) return ccs_read_addr_raw(sensor, reg, val, false, true, false); } +static int ccs_write_retry(struct i2c_client *client, struct i2c_msg *msg) +{ + unsigned int retries; + int r; + + for (retries = 0; retries < 10; retries++) { + /* + * Due to unknown reason sensor stops responding. This + * loop is a temporaty solution until the root cause + * is found. + */ + r = i2c_transfer(client->adapter, msg, 1); + if (r != 1) { + usleep_range(1000, 2000); + continue; + } + + if (retries) + dev_err(&client->dev, + "sensor i2c stall encountered. retries: %d\n", + retries); + return 0; + } + + return r; +} + int ccs_write_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 val) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); struct i2c_msg msg; unsigned char data[6]; - unsigned int retries; unsigned int len = ccs_reg_width(reg); int r; @@ -256,27 +282,11 @@ int ccs_write_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 val) put_unaligned_be16(CCS_REG_ADDR(reg), data); put_unaligned_be32(val << (8 * (sizeof(val) - len)), data + 2); - for (retries = 0; retries < 10; retries++) { - /* - * Due to unknown reason sensor stops responding. This - * loop is a temporaty solution until the root cause - * is found. - */ - r = i2c_transfer(client->adapter, &msg, 1); - if (r == 1) { - if (retries) - dev_err(&client->dev, - "sensor i2c stall encountered. retries: %d\n", - retries); - return 0; - } - - usleep_range(1000, 2000); - } - - dev_err(&client->dev, - "wrote 0x%x to offset 0x%x error %d\n", val, - CCS_REG_ADDR(reg), r); + r = ccs_write_retry(client, &msg); + if (r) + dev_err(&client->dev, + "wrote 0x%x to offset 0x%x error %d\n", val, + CCS_REG_ADDR(reg), r); return r; } @@ -297,3 +307,43 @@ int ccs_write_addr(struct ccs_sensor *sensor, u32 reg, u32 val) return ccs_write_addr_no_quirk(sensor, reg, val); } + +#define MAX_WRITE_LEN 32U + +int ccs_write_data_regs(struct ccs_sensor *sensor, struct ccs_reg *regs, + size_t num_regs) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + unsigned char buf[2 + MAX_WRITE_LEN]; + struct i2c_msg msg = { + .addr = client->addr, + .buf = buf, + }; + size_t i; + + for (i = 0; i < num_regs; i++, regs++) { + unsigned char *regdata = regs->value; + unsigned int j; + + for (j = 0; j < regs->len; + j += msg.len - 2, regdata += msg.len - 2) { + int rval; + + msg.len = min(regs->len - j, MAX_WRITE_LEN); + + put_unaligned_be16(regs->addr + j, buf); + memcpy(buf + 2, regdata, msg.len); + msg.len += 2; + + rval = ccs_write_retry(client, &msg); + if (rval) { + dev_err(&client->dev, + "error writing %u octets to address 0x%4.4x\n", + msg.len, regs->addr + j); + return rval; + } + } + } + + return 0; +} diff --git a/drivers/media/i2c/ccs/ccs-reg-access.h b/drivers/media/i2c/ccs/ccs-reg-access.h index cfad2e520fe2..78c43f92d99a 100644 --- a/drivers/media/i2c/ccs/ccs-reg-access.h +++ b/drivers/media/i2c/ccs/ccs-reg-access.h @@ -27,6 +27,8 @@ int ccs_read_addr_8only(struct ccs_sensor *sensor, u32 reg, u32 *val); int ccs_read_addr_noconv(struct ccs_sensor *sensor, u32 reg, u32 *val); int ccs_write_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 val); int ccs_write_addr(struct ccs_sensor *sensor, u32 reg, u32 val); +int ccs_write_data_regs(struct ccs_sensor *sensor, struct ccs_reg *regs, + size_t num_regs); unsigned int ccs_reg_width(u32 reg); u32 ccs_reg_conv(struct ccs_sensor *sensor, u32 reg, u32 val); -- cgit v1.2.3 From 1b398012cee8d6c9fff15d74e462a5ace6f9ef7c Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 3 Sep 2020 21:52:29 +0200 Subject: media: ccs: Use static data read-only registers Access read-only registers from CCS static data. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-reg-access.c | 64 +++++++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-reg-access.c b/drivers/media/i2c/ccs/ccs-reg-access.c index 918bc98c226f..3de863e3bf26 100644 --- a/drivers/media/i2c/ccs/ccs-reg-access.c +++ b/drivers/media/i2c/ccs/ccs-reg-access.c @@ -198,11 +198,67 @@ static int __ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val, return 0; } +static int __ccs_read_data(struct ccs_reg *regs, size_t num_regs, + u32 reg, u32 *val) +{ + unsigned int width = ccs_reg_width(reg); + size_t i; + + for (i = 0; i < num_regs; i++, regs++) { + uint8_t *data; + + if (regs->addr + regs->len < CCS_REG_ADDR(reg) + width) + continue; + + if (regs->addr > CCS_REG_ADDR(reg)) + break; + + data = ®s->value[CCS_REG_ADDR(reg) - regs->addr]; + + switch (width) { + case sizeof(uint8_t): + *val = *data; + break; + case sizeof(uint16_t): + *val = get_unaligned_be16(data); + break; + case sizeof(uint32_t): + *val = get_unaligned_be32(data); + break; + default: + WARN_ON(1); + return -EINVAL; + } + + return 0; + } + + return -ENOENT; +} + +static int ccs_read_data(struct ccs_sensor *sensor, u32 reg, u32 *val) +{ + if (!__ccs_read_data(sensor->sdata.sensor_read_only_regs, + sensor->sdata.num_sensor_read_only_regs, + reg, val)) + return 0; + + return __ccs_read_data(sensor->mdata.module_read_only_regs, + sensor->mdata.num_module_read_only_regs, + reg, val); +} + static int ccs_read_addr_raw(struct ccs_sensor *sensor, u32 reg, u32 *val, - bool force8, bool quirk, bool conv) + bool force8, bool quirk, bool conv, bool data) { int rval; + if (data) { + rval = ccs_read_data(sensor, reg, val); + if (!rval) + return 0; + } + if (quirk) { *val = 0; rval = ccs_call_quirk(sensor, reg_access, false, ®, val); @@ -223,17 +279,17 @@ static int ccs_read_addr_raw(struct ccs_sensor *sensor, u32 reg, u32 *val, int ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val) { - return ccs_read_addr_raw(sensor, reg, val, false, true, true); + return ccs_read_addr_raw(sensor, reg, val, false, true, true, true); } int ccs_read_addr_8only(struct ccs_sensor *sensor, u32 reg, u32 *val) { - return ccs_read_addr_raw(sensor, reg, val, true, true, true); + return ccs_read_addr_raw(sensor, reg, val, true, true, true, true); } int ccs_read_addr_noconv(struct ccs_sensor *sensor, u32 reg, u32 *val) { - return ccs_read_addr_raw(sensor, reg, val, false, true, false); + return ccs_read_addr_raw(sensor, reg, val, false, true, false, true); } static int ccs_write_retry(struct i2c_client *client, struct i2c_msg *msg) -- cgit v1.2.3 From fd5cfde331f86e7712a037e68e9e66b29eaea9fa Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 18 Sep 2020 11:23:39 +0200 Subject: media: ccs: Clean up runtime PM usage If pm_runtime_get_sync() fails, there's no need to set the device active again. Also, in the same case to return the usage_count to zero, pm_runtime_put_noidle() is enough. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 5e01f22608d7..c3023570a620 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -1625,8 +1625,6 @@ static int ccs_pm_get_init(struct ccs_sensor *sensor) rval = pm_runtime_get_sync(&client->dev); if (rval < 0) { - if (rval != -EBUSY && rval != -EAGAIN) - pm_runtime_set_active(&client->dev); pm_runtime_put_noidle(&client->dev); return rval; @@ -2842,9 +2840,8 @@ static int __maybe_unused ccs_suspend(struct device *dev) rval = pm_runtime_get_sync(dev); if (rval < 0) { - if (rval != -EBUSY && rval != -EAGAIN) - pm_runtime_set_active(&client->dev); - pm_runtime_put(dev); + pm_runtime_put_noidle(dev); + return -EAGAIN; } -- cgit v1.2.3 From 2b5b9af811ae0b1376d5ac87cac26757d773c317 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 18 Sep 2020 11:36:38 +0200 Subject: media: ccs: Wrap long lines, unwrap short ones Over the years (and renaming) some lines that may well be wrapped ended up being over 80 characters, likewise there are shorter lines that can be merged. Do that. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 45 ++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index c3023570a620..863295b8fb5c 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -657,8 +657,7 @@ static int ccs_set_ctrl(struct v4l2_ctrl *ctrl) break; case V4L2_CID_HBLANK: rval = ccs_write(sensor, LINE_LENGTH_PCK, - sensor->pixel_array->crop[ - CCS_PA_PAD_SRC].width + sensor->pixel_array->crop[CCS_PA_PAD_SRC].width + ctrl->val); break; @@ -989,15 +988,13 @@ static void ccs_update_blanking(struct ccs_sensor *sensor) min = max_t(int, CCS_LIM(sensor, MIN_FRAME_BLANKING_LINES), - min_fll - - sensor->pixel_array->crop[CCS_PA_PAD_SRC].height); + min_fll - sensor->pixel_array->crop[CCS_PA_PAD_SRC].height); max = max_fll - sensor->pixel_array->crop[CCS_PA_PAD_SRC].height; __v4l2_ctrl_modify_range(vblank, min, max, vblank->step, min); min = max_t(int, - min_llp - - sensor->pixel_array->crop[CCS_PA_PAD_SRC].width, + min_llp - sensor->pixel_array->crop[CCS_PA_PAD_SRC].width, min_lbp); max = max_llp - sensor->pixel_array->crop[CCS_PA_PAD_SRC].width; @@ -1784,7 +1781,8 @@ static void ccs_get_crop_compose(struct v4l2_subdev *subdev, } else { if (crops) { for (i = 0; i < subdev->entity.num_pads; i++) - crops[i] = v4l2_subdev_get_try_crop(subdev, cfg, i); + crops[i] = v4l2_subdev_get_try_crop(subdev, + cfg, i); } if (comps) *comps = v4l2_subdev_get_try_compose(subdev, cfg, @@ -1809,8 +1807,7 @@ static void ccs_propagate(struct v4l2_subdev *subdev, comp->height = crops[CCS_PAD_SINK]->height; if (which == V4L2_SUBDEV_FORMAT_ACTIVE) { if (ssd == sensor->scaler) { - sensor->scale_m = - CCS_LIM(sensor, SCALER_N_MIN); + sensor->scale_m = CCS_LIM(sensor, SCALER_N_MIN); sensor->scaling_mode = CCS_SCALING_MODE_NO_SCALING; } else if (ssd == sensor->binner) { @@ -2236,9 +2233,11 @@ static int ccs_set_crop(struct v4l2_subdev *subdev, if (sel->pad == ssd->sink_pad) { _r.left = 0; _r.top = 0; - _r.width = v4l2_subdev_get_try_format(subdev, cfg, sel->pad) + _r.width = v4l2_subdev_get_try_format(subdev, cfg, + sel->pad) ->width; - _r.height = v4l2_subdev_get_try_format(subdev, cfg, sel->pad) + _r.height = v4l2_subdev_get_try_format(subdev, cfg, + sel->pad) ->height; src_size = &_r; } else { @@ -2356,11 +2355,9 @@ static int ccs_set_selection(struct v4l2_subdev *subdev, sel->r.width = CCS_ALIGN_DIM(sel->r.width, sel->flags); sel->r.height = CCS_ALIGN_DIM(sel->r.height, sel->flags); - sel->r.width = max_t(unsigned int, - CCS_LIM(sensor, MIN_X_OUTPUT_SIZE), + sel->r.width = max_t(unsigned int, CCS_LIM(sensor, MIN_X_OUTPUT_SIZE), sel->r.width); - sel->r.height = max_t(unsigned int, - CCS_LIM(sensor, MIN_Y_OUTPUT_SIZE), + sel->r.height = max_t(unsigned int, CCS_LIM(sensor, MIN_Y_OUTPUT_SIZE), sel->r.height); switch (sel->target) { @@ -2613,8 +2610,7 @@ static int ccs_identify_module(struct ccs_sensor *sensor) dev_warn(&client->dev, "no quirks for this module; let's hope it's fully compliant\n"); - dev_dbg(&client->dev, "the sensor is called %s\n", - minfo->name); + dev_dbg(&client->dev, "the sensor is called %s\n", minfo->name); return 0; } @@ -2634,19 +2630,15 @@ static int ccs_register_subdev(struct ccs_sensor *sensor, if (!sink_ssd) return 0; - rval = media_entity_pads_init(&ssd->sd.entity, - ssd->npads, ssd->pads); + rval = media_entity_pads_init(&ssd->sd.entity, ssd->npads, ssd->pads); if (rval) { - dev_err(&client->dev, - "media_entity_pads_init failed\n"); + dev_err(&client->dev, "media_entity_pads_init failed\n"); return rval; } - rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev, - &ssd->sd); + rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev, &ssd->sd); if (rval) { - dev_err(&client->dev, - "v4l2_device_register_subdev failed\n"); + dev_err(&client->dev, "v4l2_device_register_subdev failed\n"); return rval; } @@ -2654,8 +2646,7 @@ static int ccs_register_subdev(struct ccs_sensor *sensor, &sink_ssd->sd.entity, sink_pad, link_flags); if (rval) { - dev_err(&client->dev, - "media_create_pad_link failed\n"); + dev_err(&client->dev, "media_create_pad_link failed\n"); v4l2_device_unregister_subdev(&ssd->sd); return rval; } -- cgit v1.2.3 From ebc0bc270e09671b245ebc0bd3e99138bd16e2be Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 21 Sep 2020 18:08:20 +0200 Subject: media: ccs: Use longer pre-I²C sleep for CCS compliant devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Longer idle period is required on I²C bus before the first transaction after lifting xshutdown. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 863295b8fb5c..5014aa0d7969 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -1300,6 +1300,7 @@ static int ccs_power_on(struct device *dev) */ struct ccs_sensor *sensor = container_of(ssd, struct ccs_sensor, ssds[0]); + const struct ccs_device *ccsdev = device_get_match_data(dev); unsigned int sleep; int rval; @@ -1320,7 +1321,11 @@ static int ccs_power_on(struct device *dev) gpiod_set_value(sensor->reset, 0); gpiod_set_value(sensor->xshutdown, 1); - sleep = SMIAPP_RESET_DELAY(sensor->hwcfg.ext_clk); + if (ccsdev->flags & CCS_DEVICE_FLAG_IS_SMIA) + sleep = SMIAPP_RESET_DELAY(sensor->hwcfg.ext_clk); + else + sleep = 5000; + usleep_range(sleep, sleep); /* -- cgit v1.2.3 From f9947ed66a87d019144675d43be548954ea36510 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 5 Oct 2020 23:17:12 +0200 Subject: media: ccs: Remove unnecessary delays from power-up sequence SMIA nor CCS need these delays; remove them. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 5014aa0d7969..89dc09587211 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -1309,14 +1309,12 @@ static int ccs_power_on(struct device *dev) dev_err(dev, "failed to enable vana regulator\n"); return rval; } - usleep_range(1000, 1000); rval = clk_prepare_enable(sensor->ext_clk); if (rval < 0) { dev_dbg(dev, "failed to enable xclk\n"); goto out_xclk_fail; } - usleep_range(1000, 1000); gpiod_set_value(sensor->reset, 0); gpiod_set_value(sensor->xshutdown, 1); -- cgit v1.2.3 From 87e4b53f8aba0d45b1c52677e74d7fcf9f56d7d0 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 5 Oct 2020 23:36:00 +0200 Subject: media: dt-bindings: mipi,ccs: Don't mention vana voltage It was mentioned vana voltage is typically 2,8 volts. This is truly sensor dependent, and nowadays 2,8 volts is a lot. Signed-off-by: Sakari Ailus Reviewed-by: Rob Herring Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml b/Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml index 1d90767a6196..51426a950414 100644 --- a/Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml +++ b/Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml @@ -37,8 +37,7 @@ properties: maxItems: 1 vana-supply: - description: Analogue voltage supply (VANA), typically 2,8 volts (sensor - dependent). + description: Analogue voltage supply (VANA), sensor dependent. maxItems: 1 clocks: -- cgit v1.2.3 From 6904d4a988d65d1bc373740cda0940fb1a2f665e Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 5 Oct 2020 23:36:52 +0200 Subject: media: dt-bindings: mipi,ccs: Add vcore and vio supplies Vcore and vio supplies are also part of the spec and used by many sensors. Do not specify the voltages as they are generally sensor dependent. Signed-off-by: Sakari Ailus Reviewed-by: Rob Herring Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml b/Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml index 51426a950414..d94bd67ccea1 100644 --- a/Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml +++ b/Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml @@ -40,6 +40,14 @@ properties: description: Analogue voltage supply (VANA), sensor dependent. maxItems: 1 + vcore-supply: + description: Core voltage supply (VCore), sensor dependent. + maxItems: 1 + + vio-supply: + description: I/O voltage supply (VIO), sensor dependent. + maxItems: 1 + clocks: description: External clock to the sensor. maxItems: 1 -- cgit v1.2.3 From 621214c36e84643bc104e030ef1e1422ff45156c Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 6 Oct 2020 15:05:25 +0200 Subject: media: ccs: Use all regulators Use regulators vio and vcore besides vana. The regulators were always there but on many boards they've been hard wired. Control them explicitly now. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 30 +++++++++++++++++++++++------- drivers/media/i2c/ccs/ccs.h | 2 +- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 89dc09587211..4447ca367a84 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -65,6 +65,8 @@ struct ccs_device { unsigned char flags; }; +static const char * const ccs_regulators[] = { "vcore", "vio", "vana" }; + /* * * Dynamic Capability Identification @@ -1304,7 +1306,8 @@ static int ccs_power_on(struct device *dev) unsigned int sleep; int rval; - rval = regulator_enable(sensor->vana); + rval = regulator_bulk_enable(ARRAY_SIZE(ccs_regulators), + sensor->regulators); if (rval) { dev_err(dev, "failed to enable vana regulator\n"); return rval; @@ -1416,7 +1419,8 @@ out_cci_addr_fail: clk_disable_unprepare(sensor->ext_clk); out_xclk_fail: - regulator_disable(sensor->vana); + regulator_bulk_disable(ARRAY_SIZE(ccs_regulators), + sensor->regulators); return rval; } @@ -1442,7 +1446,8 @@ static int ccs_power_off(struct device *dev) gpiod_set_value(sensor->xshutdown, 0); clk_disable_unprepare(sensor->ext_clk); usleep_range(5000, 5000); - regulator_disable(sensor->vana); + regulator_bulk_disable(ARRAY_SIZE(ccs_regulators), + sensor->regulators); sensor->streaming = false; return 0; @@ -2981,10 +2986,21 @@ static int ccs_probe(struct i2c_client *client) v4l2_i2c_subdev_init(&sensor->src->sd, client, &ccs_ops); sensor->src->sd.internal_ops = &ccs_internal_src_ops; - sensor->vana = devm_regulator_get(&client->dev, "vana"); - if (IS_ERR(sensor->vana)) { - dev_err(&client->dev, "could not get regulator for vana\n"); - return PTR_ERR(sensor->vana); + sensor->regulators = devm_kcalloc(&client->dev, + ARRAY_SIZE(ccs_regulators), + sizeof(*sensor->regulators), + GFP_KERNEL); + if (!sensor->regulators) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(ccs_regulators); i++) + sensor->regulators[i].supply = ccs_regulators[i]; + + rval = devm_regulator_bulk_get(&client->dev, ARRAY_SIZE(ccs_regulators), + sensor->regulators); + if (rval) { + dev_err(&client->dev, "could not get regulators\n"); + return rval; } sensor->ext_clk = devm_clk_get(&client->dev, NULL); diff --git a/drivers/media/i2c/ccs/ccs.h b/drivers/media/i2c/ccs/ccs.h index 6b07e4143ff0..356b87c33405 100644 --- a/drivers/media/i2c/ccs/ccs.h +++ b/drivers/media/i2c/ccs/ccs.h @@ -223,7 +223,7 @@ struct ccs_sensor { struct ccs_subdev *scaler; struct ccs_subdev *pixel_array; struct ccs_hwconfig hwcfg; - struct regulator *vana; + struct regulator_bulk_data *regulators; struct clk *ext_clk; struct gpio_desc *xshutdown; struct gpio_desc *reset; -- cgit v1.2.3 From 67f577b4d4f78168a4981235917f322e24c6d05e Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 23 Nov 2020 16:00:19 +0100 Subject: media: controls: Add VP8 stateless type initialization The VP8_FRAME_HEADER control type is validated, so it needs a corresponding initialization to produce default legal values. For now, only add the minimum required initialization to satisfy current validation. Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index ad47d00e28d6..7febfbb256a6 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1621,6 +1621,7 @@ static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 idx, union v4l2_ctrl_ptr ptr) { struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; + struct v4l2_ctrl_vp8_frame_header *p_vp8_frame_header; void *p = ptr.p + idx * ctrl->elem_size; if (ctrl->p_def.p_const) @@ -1643,6 +1644,10 @@ static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 idx, p_mpeg2_slice_params->picture.picture_coding_type = V4L2_MPEG2_PICTURE_CODING_TYPE_I; break; + case V4L2_CTRL_TYPE_VP8_FRAME_HEADER: + p_vp8_frame_header = p; + p_vp8_frame_header->num_dct_parts = 1; + break; } } -- cgit v1.2.3 From df23e0c12582ee18074975b7916b1a0ce620decd Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 26 Nov 2020 10:36:05 +0100 Subject: media: vidioc-g-ext-ctrls.rst: document V4L2_CTRL_CLASS_DETECT V4L2_CTRL_CLASS_DETECT was never documented here, add it. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst index a8d12bd50d22..9d28ac3fc237 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst @@ -358,6 +358,10 @@ still cause this situation. - 0xa20000 - The class containing RF tuner controls. These controls are described in :ref:`rf-tuner-controls`. + * - ``V4L2_CTRL_CLASS_DETECT`` + - 0xa30000 + - The class containing motion or object detection controls. These controls + are described in :ref:`detect-controls`. Return Value ============ -- cgit v1.2.3 From 32143c583870365ff6f1d1558e7833bffe49a820 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 26 Nov 2020 10:36:06 +0100 Subject: media: controls: Add validate failure debug message Add a debug message for control validation (validate_new) failures. This is useful to debug issues with ioctls such as VIDIOC_TRY_EXT_CTRLS and VIDIOC_S_EXT_CTRLS. Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 7febfbb256a6..3979e7924007 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -4112,8 +4112,13 @@ static int try_set_ext_ctrls_common(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl = helpers[idx].ref->ctrl; ret = user_to_new(cs->controls + idx, ctrl); - if (!ret && ctrl->is_ptr) + if (!ret && ctrl->is_ptr) { ret = validate_new(ctrl, ctrl->p_new); + if (ret) + dprintk(vdev, + "failed to validate control %s (%d)\n", + v4l2_ctrl_get_name(ctrl->id), ret); + } idx = helpers[idx].next; } while (!ret && idx); -- cgit v1.2.3 From b74593ebb4829ab82787437c77fb9e1ed7150538 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Thu, 26 Nov 2020 10:36:07 +0100 Subject: media: rkvdec: h264: Support profile and level controls The Rockchip Video Decoder used in RK3399 supports H.264 profiles from Baseline to High 4:2:2 up to Level 5.1, except for the Extended profile. Expose the V4L2_CID_MPEG_VIDEO_H264_PROFILE and the V4L2_CID_MPEG_VIDEO_H264_LEVEL control, so that userspace can query the driver for the list of supported profiles and level. For now, we don't expose 4:2:2 since the driver doesn't implement the required support. [Ezequiel: Don't expose 4:2:2 profile for now] Signed-off-by: Jonas Karlman Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/rkvdec/rkvdec.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c index 552e0bd12ecf..fe65f55d3b49 100644 --- a/drivers/staging/media/rkvdec/rkvdec.c +++ b/drivers/staging/media/rkvdec/rkvdec.c @@ -82,6 +82,19 @@ static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = { .cfg.def = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B, .cfg.max = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B, }, + { + .cfg.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, + .cfg.min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .cfg.max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + .cfg.menu_skip_mask = + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED), + .cfg.def = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN, + }, + { + .cfg.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL, + .cfg.min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .cfg.max = V4L2_MPEG_VIDEO_H264_LEVEL_5_1, + }, }; static const struct rkvdec_ctrls rkvdec_h264_ctrls = { -- cgit v1.2.3 From c8363ff21b5168f2252aa8b8447173ce48ff0149 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 26 Nov 2020 10:36:08 +0100 Subject: media: cedrus: h264: Support profile controls Cedrus supports H.264 profiles from Baseline to High, except for the Extended profile Expose the V4L2_CID_MPEG_VIDEO_H264_PROFILE so that userspace can query the driver for the supported profiles and levels. Signed-off-by: Ezequiel Garcia Reviewed-by: Jernej Skrabec Tested-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/sunxi/cedrus/cedrus.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index dce7cbc95872..68548424985d 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -103,6 +103,25 @@ static const struct cedrus_control cedrus_controls[] = { .codec = CEDRUS_CODEC_H264, .required = false, }, + /* + * We only expose supported profiles information, + * and not levels as it's not clear what is supported + * for each hardware/core version. + * In any case, TRY/S_FMT will clamp the format resolution + * to the maximum supported. + */ + { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, + .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .def = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN, + .max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + .menu_skip_mask = + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED), + }, + .codec = CEDRUS_CODEC_H264, + .required = false, + }, { .cfg = { .id = V4L2_CID_MPEG_VIDEO_HEVC_SPS, -- cgit v1.2.3 From 35aaa6e650c24212316781b63005f52c1988cd4e Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 26 Nov 2020 10:36:09 +0100 Subject: media: Rename stateful codec control macros For historical reasons, stateful codec controls are named as {}_MPEG_{}. While we can't at this point sanely change all control IDs (such as V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER), we can least change the more meaningful macros such as classes macros. Signed-off-by: Ezequiel Garcia Tested-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/dev-mem2mem.rst | 2 +- .../userspace-api/media/v4l/ext-ctrls-codec.rst | 4 +- .../userspace-api/media/v4l/extended-controls.rst | 8 +- .../userspace-api/media/v4l/vidioc-g-ext-ctrls.rst | 6 +- drivers/media/common/cx2341x.c | 4 +- drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 2 +- drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 2 +- drivers/media/v4l2-core/v4l2-ctrls.c | 4 +- include/media/fwht-ctrls.h | 2 +- include/media/h264-ctrls.h | 16 +- include/media/hevc-ctrls.h | 10 +- include/media/mpeg2-ctrls.h | 4 +- include/media/vp8-ctrls.h | 2 +- include/uapi/linux/v4l2-controls.h | 409 +++++++++++---------- 14 files changed, 242 insertions(+), 233 deletions(-) diff --git a/Documentation/userspace-api/media/v4l/dev-mem2mem.rst b/Documentation/userspace-api/media/v4l/dev-mem2mem.rst index d8db46886555..7041bb3d5b8d 100644 --- a/Documentation/userspace-api/media/v4l/dev-mem2mem.rst +++ b/Documentation/userspace-api/media/v4l/dev-mem2mem.rst @@ -32,7 +32,7 @@ file handle is visible through another file handle). One of the most common memory-to-memory device is the codec. Codecs are more complicated than most and require additional setup for their codec parameters. This is done through codec controls. -See :ref:`mpeg-controls`. More details on how to use codec memory-to-memory +See :ref:`codec-controls`. More details on how to use codec memory-to-memory devices are given in the following sections. .. toctree:: diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst index ce728c757eaf..b31c52d9b1da 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst @@ -1,6 +1,6 @@ .. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later -.. _mpeg-controls: +.. _codec-controls: *********************** Codec Control Reference @@ -26,7 +26,7 @@ Generic Codec Controls Codec Control IDs ----------------- -``V4L2_CID_MPEG_CLASS (class)`` +``V4L2_CID_CODEC_CLASS (class)`` The Codec class descriptor. Calling :ref:`VIDIOC_QUERYCTRL` for this control will return a description of this control class. This description can be diff --git a/Documentation/userspace-api/media/v4l/extended-controls.rst b/Documentation/userspace-api/media/v4l/extended-controls.rst index 70301538d222..44fcd67f20bf 100644 --- a/Documentation/userspace-api/media/v4l/extended-controls.rst +++ b/Documentation/userspace-api/media/v4l/extended-controls.rst @@ -55,8 +55,8 @@ controls in that array and a control class. Control classes are used to group similar controls into a single class. For example, control class ``V4L2_CTRL_CLASS_USER`` contains all user controls (i. e. all controls that can also be set using the old :ref:`VIDIOC_S_CTRL ` -ioctl). Control class ``V4L2_CTRL_CLASS_MPEG`` contains all controls -relating to MPEG encoding, etc. +ioctl). Control class ``V4L2_CTRL_CLASS_CODEC`` contains controls +relating to codecs. All controls in the control array must belong to the specified control class. An error is returned if this is not the case. @@ -130,9 +130,9 @@ control class is found: .. code-block:: c - qctrl.id = V4L2_CTRL_CLASS_MPEG | V4L2_CTRL_FLAG_NEXT_CTRL; + qctrl.id = V4L2_CTRL_CLASS_CODEC | V4L2_CTRL_FLAG_NEXT_CTRL; while (0 == ioctl(fd, VIDIOC_QUERYCTRL, &qctrl)) { - if (V4L2_CTRL_ID2CLASS(qctrl.id) != V4L2_CTRL_CLASS_MPEG) + if (V4L2_CTRL_ID2CLASS(qctrl.id) != V4L2_CTRL_CLASS_CODEC) break; /* ... */ qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL; diff --git a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst index 9d28ac3fc237..2196cdf61ca0 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst @@ -322,10 +322,10 @@ still cause this situation. :ref:`VIDIOC_S_CTRL ` and :ref:`VIDIOC_G_CTRL ` ioctl belong to this class. - * - ``V4L2_CTRL_CLASS_MPEG`` + * - ``V4L2_CTRL_CLASS_CODEC`` - 0x990000 - - The class containing MPEG compression controls. These controls are - described in :ref:`mpeg-controls`. + - The class containing stateful codec controls. These controls are + described in :ref:`codec-controls`. * - ``V4L2_CTRL_CLASS_CAMERA`` - 0x9a0000 - The class containing camera controls. These controls are described diff --git a/drivers/media/common/cx2341x.c b/drivers/media/common/cx2341x.c index 1f67e021138f..1392bd6b0026 100644 --- a/drivers/media/common/cx2341x.c +++ b/drivers/media/common/cx2341x.c @@ -166,7 +166,7 @@ static void cx2341x_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *ty /* Must be sorted from low to high control ID! */ const u32 cx2341x_mpeg_ctrls[] = { - V4L2_CID_MPEG_CLASS, + V4L2_CID_CODEC_CLASS, V4L2_CID_MPEG_STREAM_TYPE, V4L2_CID_MPEG_STREAM_VBI_FMT, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, @@ -574,7 +574,7 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params, int err; switch (qctrl->id) { - case V4L2_CID_MPEG_CLASS: + case V4L2_CID_CODEC_CLASS: return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0); case V4L2_CID_MPEG_STREAM_TYPE: return v4l2_ctrl_query_fill(qctrl, diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 61e144a35201..a71753d459ba 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -1109,7 +1109,7 @@ const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void) return &s5p_mfc_dec_ioctl_ops; } -#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2WHICH(x) == V4L2_CTRL_CLASS_MPEG) \ +#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2WHICH(x) == V4L2_CTRL_CLASS_CODEC) \ && V4L2_CTRL_DRIVER_PRIV(x)) int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index acc2217dd7e9..1fad99edb091 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -2614,7 +2614,7 @@ const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void) return &s5p_mfc_enc_ioctl_ops; } -#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2WHICH(x) == V4L2_CTRL_CLASS_MPEG) \ +#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2WHICH(x) == V4L2_CTRL_CLASS_CODEC) \ && V4L2_CTRL_DRIVER_PRIV(x)) int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx) diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 3979e7924007..88ad475bd716 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -830,7 +830,7 @@ const char *v4l2_ctrl_get_name(u32 id) /* The MPEG controls are applicable to all codec controls * and the 'MPEG' part of the define is historical */ /* Keep the order of the 'case's the same as in videodev2.h! */ - case V4L2_CID_MPEG_CLASS: return "Codec Controls"; + case V4L2_CID_CODEC_CLASS: return "Codec Controls"; case V4L2_CID_MPEG_STREAM_TYPE: return "Stream Type"; case V4L2_CID_MPEG_STREAM_PID_PMT: return "Stream PMT Program ID"; case V4L2_CID_MPEG_STREAM_PID_AUDIO: return "Stream Audio Program ID"; @@ -1358,7 +1358,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, break; case V4L2_CID_USER_CLASS: case V4L2_CID_CAMERA_CLASS: - case V4L2_CID_MPEG_CLASS: + case V4L2_CID_CODEC_CLASS: case V4L2_CID_FM_TX_CLASS: case V4L2_CID_FLASH_CLASS: case V4L2_CID_JPEG_CLASS: diff --git a/include/media/fwht-ctrls.h b/include/media/fwht-ctrls.h index 615027410e47..a918b49609e1 100644 --- a/include/media/fwht-ctrls.h +++ b/include/media/fwht-ctrls.h @@ -13,7 +13,7 @@ #define V4L2_CTRL_TYPE_FWHT_PARAMS 0x0105 -#define V4L2_CID_MPEG_VIDEO_FWHT_PARAMS (V4L2_CID_MPEG_BASE + 292) +#define V4L2_CID_MPEG_VIDEO_FWHT_PARAMS (V4L2_CID_CODEC_BASE + 292) struct v4l2_ctrl_fwht_params { __u64 backward_ref_ts; diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h index 893e21354a9b..f86345b8efd1 100644 --- a/include/media/h264-ctrls.h +++ b/include/media/h264-ctrls.h @@ -29,14 +29,14 @@ * would be added during the phase where those controls are not * stable. It should be fixed eventually. */ -#define V4L2_CID_MPEG_VIDEO_H264_SPS (V4L2_CID_MPEG_BASE+1000) -#define V4L2_CID_MPEG_VIDEO_H264_PPS (V4L2_CID_MPEG_BASE+1001) -#define V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX (V4L2_CID_MPEG_BASE+1002) -#define V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS (V4L2_CID_MPEG_BASE+1003) -#define V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS (V4L2_CID_MPEG_BASE+1004) -#define V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE (V4L2_CID_MPEG_BASE+1005) -#define V4L2_CID_MPEG_VIDEO_H264_START_CODE (V4L2_CID_MPEG_BASE+1006) -#define V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS (V4L2_CID_MPEG_BASE+1007) +#define V4L2_CID_MPEG_VIDEO_H264_SPS (V4L2_CID_CODEC_BASE+1000) +#define V4L2_CID_MPEG_VIDEO_H264_PPS (V4L2_CID_CODEC_BASE+1001) +#define V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX (V4L2_CID_CODEC_BASE+1002) +#define V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS (V4L2_CID_CODEC_BASE+1003) +#define V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS (V4L2_CID_CODEC_BASE+1004) +#define V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE (V4L2_CID_CODEC_BASE+1005) +#define V4L2_CID_MPEG_VIDEO_H264_START_CODE (V4L2_CID_CODEC_BASE+1006) +#define V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS (V4L2_CID_CODEC_BASE+1007) /* enum v4l2_ctrl_type type values */ #define V4L2_CTRL_TYPE_H264_SPS 0x0110 diff --git a/include/media/hevc-ctrls.h b/include/media/hevc-ctrls.h index 1009cf0891cc..b4cb2ef02f17 100644 --- a/include/media/hevc-ctrls.h +++ b/include/media/hevc-ctrls.h @@ -16,11 +16,11 @@ /* The pixel format isn't stable at the moment and will likely be renamed. */ #define V4L2_PIX_FMT_HEVC_SLICE v4l2_fourcc('S', '2', '6', '5') /* HEVC parsed slices */ -#define V4L2_CID_MPEG_VIDEO_HEVC_SPS (V4L2_CID_MPEG_BASE + 1008) -#define V4L2_CID_MPEG_VIDEO_HEVC_PPS (V4L2_CID_MPEG_BASE + 1009) -#define V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS (V4L2_CID_MPEG_BASE + 1010) -#define V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE (V4L2_CID_MPEG_BASE + 1015) -#define V4L2_CID_MPEG_VIDEO_HEVC_START_CODE (V4L2_CID_MPEG_BASE + 1016) +#define V4L2_CID_MPEG_VIDEO_HEVC_SPS (V4L2_CID_CODEC_BASE + 1008) +#define V4L2_CID_MPEG_VIDEO_HEVC_PPS (V4L2_CID_CODEC_BASE + 1009) +#define V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS (V4L2_CID_CODEC_BASE + 1010) +#define V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE (V4L2_CID_CODEC_BASE + 1015) +#define V4L2_CID_MPEG_VIDEO_HEVC_START_CODE (V4L2_CID_CODEC_BASE + 1016) /* enum v4l2_ctrl_type type values */ #define V4L2_CTRL_TYPE_HEVC_SPS 0x0120 diff --git a/include/media/mpeg2-ctrls.h b/include/media/mpeg2-ctrls.h index 6601455b3d5e..2a4ae6701166 100644 --- a/include/media/mpeg2-ctrls.h +++ b/include/media/mpeg2-ctrls.h @@ -11,8 +11,8 @@ #ifndef _MPEG2_CTRLS_H_ #define _MPEG2_CTRLS_H_ -#define V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS (V4L2_CID_MPEG_BASE+250) -#define V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION (V4L2_CID_MPEG_BASE+251) +#define V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS (V4L2_CID_CODEC_BASE+250) +#define V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION (V4L2_CID_CODEC_BASE+251) /* enum v4l2_ctrl_type type values */ #define V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS 0x0103 diff --git a/include/media/vp8-ctrls.h b/include/media/vp8-ctrls.h index a920493361dc..3969550df148 100644 --- a/include/media/vp8-ctrls.h +++ b/include/media/vp8-ctrls.h @@ -15,7 +15,7 @@ #define V4L2_PIX_FMT_VP8_FRAME v4l2_fourcc('V', 'P', '8', 'F') -#define V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER (V4L2_CID_MPEG_BASE + 2000) +#define V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER (V4L2_CID_CODEC_BASE + 2000) #define V4L2_CTRL_TYPE_VP8_FRAME_HEADER 0x301 #define V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED 0x01 diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 7035f4fb182c..75cf87b9a377 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -54,7 +54,7 @@ /* Control classes */ #define V4L2_CTRL_CLASS_USER 0x00980000 /* Old-style 'user' controls */ -#define V4L2_CTRL_CLASS_MPEG 0x00990000 /* MPEG-compression controls */ +#define V4L2_CTRL_CLASS_CODEC 0x00990000 /* Stateful codec controls */ #define V4L2_CTRL_CLASS_CAMERA 0x009a0000 /* Camera class controls */ #define V4L2_CTRL_CLASS_FM_TX 0x009b0000 /* FM Modulator controls */ #define V4L2_CTRL_CLASS_FLASH 0x009c0000 /* Camera flash controls */ @@ -208,11 +208,11 @@ enum v4l2_colorfx { /* The MPEG controls are applicable to all codec controls * and the 'MPEG' part of the define is historical */ -#define V4L2_CID_MPEG_BASE (V4L2_CTRL_CLASS_MPEG | 0x900) -#define V4L2_CID_MPEG_CLASS (V4L2_CTRL_CLASS_MPEG | 1) +#define V4L2_CID_CODEC_BASE (V4L2_CTRL_CLASS_CODEC | 0x900) +#define V4L2_CID_CODEC_CLASS (V4L2_CTRL_CLASS_CODEC | 1) /* MPEG streams, specific to multiplexed streams */ -#define V4L2_CID_MPEG_STREAM_TYPE (V4L2_CID_MPEG_BASE+0) +#define V4L2_CID_MPEG_STREAM_TYPE (V4L2_CID_CODEC_BASE+0) enum v4l2_mpeg_stream_type { V4L2_MPEG_STREAM_TYPE_MPEG2_PS = 0, /* MPEG-2 program stream */ V4L2_MPEG_STREAM_TYPE_MPEG2_TS = 1, /* MPEG-2 transport stream */ @@ -221,26 +221,26 @@ enum v4l2_mpeg_stream_type { V4L2_MPEG_STREAM_TYPE_MPEG1_VCD = 4, /* MPEG-1 VCD-compatible stream */ V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD = 5, /* MPEG-2 SVCD-compatible stream */ }; -#define V4L2_CID_MPEG_STREAM_PID_PMT (V4L2_CID_MPEG_BASE+1) -#define V4L2_CID_MPEG_STREAM_PID_AUDIO (V4L2_CID_MPEG_BASE+2) -#define V4L2_CID_MPEG_STREAM_PID_VIDEO (V4L2_CID_MPEG_BASE+3) -#define V4L2_CID_MPEG_STREAM_PID_PCR (V4L2_CID_MPEG_BASE+4) -#define V4L2_CID_MPEG_STREAM_PES_ID_AUDIO (V4L2_CID_MPEG_BASE+5) -#define V4L2_CID_MPEG_STREAM_PES_ID_VIDEO (V4L2_CID_MPEG_BASE+6) -#define V4L2_CID_MPEG_STREAM_VBI_FMT (V4L2_CID_MPEG_BASE+7) +#define V4L2_CID_MPEG_STREAM_PID_PMT (V4L2_CID_CODEC_BASE+1) +#define V4L2_CID_MPEG_STREAM_PID_AUDIO (V4L2_CID_CODEC_BASE+2) +#define V4L2_CID_MPEG_STREAM_PID_VIDEO (V4L2_CID_CODEC_BASE+3) +#define V4L2_CID_MPEG_STREAM_PID_PCR (V4L2_CID_CODEC_BASE+4) +#define V4L2_CID_MPEG_STREAM_PES_ID_AUDIO (V4L2_CID_CODEC_BASE+5) +#define V4L2_CID_MPEG_STREAM_PES_ID_VIDEO (V4L2_CID_CODEC_BASE+6) +#define V4L2_CID_MPEG_STREAM_VBI_FMT (V4L2_CID_CODEC_BASE+7) enum v4l2_mpeg_stream_vbi_fmt { V4L2_MPEG_STREAM_VBI_FMT_NONE = 0, /* No VBI in the MPEG stream */ V4L2_MPEG_STREAM_VBI_FMT_IVTV = 1, /* VBI in private packets, IVTV format */ }; /* MPEG audio controls specific to multiplexed streams */ -#define V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ (V4L2_CID_MPEG_BASE+100) +#define V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ (V4L2_CID_CODEC_BASE+100) enum v4l2_mpeg_audio_sampling_freq { V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100 = 0, V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000 = 1, V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000 = 2, }; -#define V4L2_CID_MPEG_AUDIO_ENCODING (V4L2_CID_MPEG_BASE+101) +#define V4L2_CID_MPEG_AUDIO_ENCODING (V4L2_CID_CODEC_BASE+101) enum v4l2_mpeg_audio_encoding { V4L2_MPEG_AUDIO_ENCODING_LAYER_1 = 0, V4L2_MPEG_AUDIO_ENCODING_LAYER_2 = 1, @@ -248,7 +248,7 @@ enum v4l2_mpeg_audio_encoding { V4L2_MPEG_AUDIO_ENCODING_AAC = 3, V4L2_MPEG_AUDIO_ENCODING_AC3 = 4, }; -#define V4L2_CID_MPEG_AUDIO_L1_BITRATE (V4L2_CID_MPEG_BASE+102) +#define V4L2_CID_MPEG_AUDIO_L1_BITRATE (V4L2_CID_CODEC_BASE+102) enum v4l2_mpeg_audio_l1_bitrate { V4L2_MPEG_AUDIO_L1_BITRATE_32K = 0, V4L2_MPEG_AUDIO_L1_BITRATE_64K = 1, @@ -265,7 +265,7 @@ enum v4l2_mpeg_audio_l1_bitrate { V4L2_MPEG_AUDIO_L1_BITRATE_416K = 12, V4L2_MPEG_AUDIO_L1_BITRATE_448K = 13, }; -#define V4L2_CID_MPEG_AUDIO_L2_BITRATE (V4L2_CID_MPEG_BASE+103) +#define V4L2_CID_MPEG_AUDIO_L2_BITRATE (V4L2_CID_CODEC_BASE+103) enum v4l2_mpeg_audio_l2_bitrate { V4L2_MPEG_AUDIO_L2_BITRATE_32K = 0, V4L2_MPEG_AUDIO_L2_BITRATE_48K = 1, @@ -282,7 +282,7 @@ enum v4l2_mpeg_audio_l2_bitrate { V4L2_MPEG_AUDIO_L2_BITRATE_320K = 12, V4L2_MPEG_AUDIO_L2_BITRATE_384K = 13, }; -#define V4L2_CID_MPEG_AUDIO_L3_BITRATE (V4L2_CID_MPEG_BASE+104) +#define V4L2_CID_MPEG_AUDIO_L3_BITRATE (V4L2_CID_CODEC_BASE+104) enum v4l2_mpeg_audio_l3_bitrate { V4L2_MPEG_AUDIO_L3_BITRATE_32K = 0, V4L2_MPEG_AUDIO_L3_BITRATE_40K = 1, @@ -299,34 +299,34 @@ enum v4l2_mpeg_audio_l3_bitrate { V4L2_MPEG_AUDIO_L3_BITRATE_256K = 12, V4L2_MPEG_AUDIO_L3_BITRATE_320K = 13, }; -#define V4L2_CID_MPEG_AUDIO_MODE (V4L2_CID_MPEG_BASE+105) +#define V4L2_CID_MPEG_AUDIO_MODE (V4L2_CID_CODEC_BASE+105) enum v4l2_mpeg_audio_mode { V4L2_MPEG_AUDIO_MODE_STEREO = 0, V4L2_MPEG_AUDIO_MODE_JOINT_STEREO = 1, V4L2_MPEG_AUDIO_MODE_DUAL = 2, V4L2_MPEG_AUDIO_MODE_MONO = 3, }; -#define V4L2_CID_MPEG_AUDIO_MODE_EXTENSION (V4L2_CID_MPEG_BASE+106) +#define V4L2_CID_MPEG_AUDIO_MODE_EXTENSION (V4L2_CID_CODEC_BASE+106) enum v4l2_mpeg_audio_mode_extension { V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4 = 0, V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_8 = 1, V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_12 = 2, V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16 = 3, }; -#define V4L2_CID_MPEG_AUDIO_EMPHASIS (V4L2_CID_MPEG_BASE+107) +#define V4L2_CID_MPEG_AUDIO_EMPHASIS (V4L2_CID_CODEC_BASE+107) enum v4l2_mpeg_audio_emphasis { V4L2_MPEG_AUDIO_EMPHASIS_NONE = 0, V4L2_MPEG_AUDIO_EMPHASIS_50_DIV_15_uS = 1, V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17 = 2, }; -#define V4L2_CID_MPEG_AUDIO_CRC (V4L2_CID_MPEG_BASE+108) +#define V4L2_CID_MPEG_AUDIO_CRC (V4L2_CID_CODEC_BASE+108) enum v4l2_mpeg_audio_crc { V4L2_MPEG_AUDIO_CRC_NONE = 0, V4L2_MPEG_AUDIO_CRC_CRC16 = 1, }; -#define V4L2_CID_MPEG_AUDIO_MUTE (V4L2_CID_MPEG_BASE+109) -#define V4L2_CID_MPEG_AUDIO_AAC_BITRATE (V4L2_CID_MPEG_BASE+110) -#define V4L2_CID_MPEG_AUDIO_AC3_BITRATE (V4L2_CID_MPEG_BASE+111) +#define V4L2_CID_MPEG_AUDIO_MUTE (V4L2_CID_CODEC_BASE+109) +#define V4L2_CID_MPEG_AUDIO_AAC_BITRATE (V4L2_CID_CODEC_BASE+110) +#define V4L2_CID_MPEG_AUDIO_AC3_BITRATE (V4L2_CID_CODEC_BASE+111) enum v4l2_mpeg_audio_ac3_bitrate { V4L2_MPEG_AUDIO_AC3_BITRATE_32K = 0, V4L2_MPEG_AUDIO_AC3_BITRATE_40K = 1, @@ -348,7 +348,7 @@ enum v4l2_mpeg_audio_ac3_bitrate { V4L2_MPEG_AUDIO_AC3_BITRATE_576K = 17, V4L2_MPEG_AUDIO_AC3_BITRATE_640K = 18, }; -#define V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK (V4L2_CID_MPEG_BASE+112) +#define V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK (V4L2_CID_CODEC_BASE+112) enum v4l2_mpeg_audio_dec_playback { V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO = 0, V4L2_MPEG_AUDIO_DEC_PLAYBACK_STEREO = 1, @@ -357,52 +357,52 @@ enum v4l2_mpeg_audio_dec_playback { V4L2_MPEG_AUDIO_DEC_PLAYBACK_MONO = 4, V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO = 5, }; -#define V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK (V4L2_CID_MPEG_BASE+113) +#define V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK (V4L2_CID_CODEC_BASE+113) /* MPEG video controls specific to multiplexed streams */ -#define V4L2_CID_MPEG_VIDEO_ENCODING (V4L2_CID_MPEG_BASE+200) +#define V4L2_CID_MPEG_VIDEO_ENCODING (V4L2_CID_CODEC_BASE+200) enum v4l2_mpeg_video_encoding { V4L2_MPEG_VIDEO_ENCODING_MPEG_1 = 0, V4L2_MPEG_VIDEO_ENCODING_MPEG_2 = 1, V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC = 2, }; -#define V4L2_CID_MPEG_VIDEO_ASPECT (V4L2_CID_MPEG_BASE+201) +#define V4L2_CID_MPEG_VIDEO_ASPECT (V4L2_CID_CODEC_BASE+201) enum v4l2_mpeg_video_aspect { V4L2_MPEG_VIDEO_ASPECT_1x1 = 0, V4L2_MPEG_VIDEO_ASPECT_4x3 = 1, V4L2_MPEG_VIDEO_ASPECT_16x9 = 2, V4L2_MPEG_VIDEO_ASPECT_221x100 = 3, }; -#define V4L2_CID_MPEG_VIDEO_B_FRAMES (V4L2_CID_MPEG_BASE+202) -#define V4L2_CID_MPEG_VIDEO_GOP_SIZE (V4L2_CID_MPEG_BASE+203) -#define V4L2_CID_MPEG_VIDEO_GOP_CLOSURE (V4L2_CID_MPEG_BASE+204) -#define V4L2_CID_MPEG_VIDEO_PULLDOWN (V4L2_CID_MPEG_BASE+205) -#define V4L2_CID_MPEG_VIDEO_BITRATE_MODE (V4L2_CID_MPEG_BASE+206) +#define V4L2_CID_MPEG_VIDEO_B_FRAMES (V4L2_CID_CODEC_BASE+202) +#define V4L2_CID_MPEG_VIDEO_GOP_SIZE (V4L2_CID_CODEC_BASE+203) +#define V4L2_CID_MPEG_VIDEO_GOP_CLOSURE (V4L2_CID_CODEC_BASE+204) +#define V4L2_CID_MPEG_VIDEO_PULLDOWN (V4L2_CID_CODEC_BASE+205) +#define V4L2_CID_MPEG_VIDEO_BITRATE_MODE (V4L2_CID_CODEC_BASE+206) enum v4l2_mpeg_video_bitrate_mode { V4L2_MPEG_VIDEO_BITRATE_MODE_VBR = 0, V4L2_MPEG_VIDEO_BITRATE_MODE_CBR = 1, V4L2_MPEG_VIDEO_BITRATE_MODE_CQ = 2, }; -#define V4L2_CID_MPEG_VIDEO_BITRATE (V4L2_CID_MPEG_BASE+207) -#define V4L2_CID_MPEG_VIDEO_BITRATE_PEAK (V4L2_CID_MPEG_BASE+208) -#define V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION (V4L2_CID_MPEG_BASE+209) -#define V4L2_CID_MPEG_VIDEO_MUTE (V4L2_CID_MPEG_BASE+210) -#define V4L2_CID_MPEG_VIDEO_MUTE_YUV (V4L2_CID_MPEG_BASE+211) -#define V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE (V4L2_CID_MPEG_BASE+212) -#define V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER (V4L2_CID_MPEG_BASE+213) -#define V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB (V4L2_CID_MPEG_BASE+214) -#define V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE (V4L2_CID_MPEG_BASE+215) -#define V4L2_CID_MPEG_VIDEO_HEADER_MODE (V4L2_CID_MPEG_BASE+216) +#define V4L2_CID_MPEG_VIDEO_BITRATE (V4L2_CID_CODEC_BASE+207) +#define V4L2_CID_MPEG_VIDEO_BITRATE_PEAK (V4L2_CID_CODEC_BASE+208) +#define V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION (V4L2_CID_CODEC_BASE+209) +#define V4L2_CID_MPEG_VIDEO_MUTE (V4L2_CID_CODEC_BASE+210) +#define V4L2_CID_MPEG_VIDEO_MUTE_YUV (V4L2_CID_CODEC_BASE+211) +#define V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE (V4L2_CID_CODEC_BASE+212) +#define V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER (V4L2_CID_CODEC_BASE+213) +#define V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB (V4L2_CID_CODEC_BASE+214) +#define V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE (V4L2_CID_CODEC_BASE+215) +#define V4L2_CID_MPEG_VIDEO_HEADER_MODE (V4L2_CID_CODEC_BASE+216) enum v4l2_mpeg_video_header_mode { V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE = 0, V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME = 1, }; -#define V4L2_CID_MPEG_VIDEO_MAX_REF_PIC (V4L2_CID_MPEG_BASE+217) -#define V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE (V4L2_CID_MPEG_BASE+218) -#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES (V4L2_CID_MPEG_BASE+219) -#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB (V4L2_CID_MPEG_BASE+220) -#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE (V4L2_CID_MPEG_BASE+221) +#define V4L2_CID_MPEG_VIDEO_MAX_REF_PIC (V4L2_CID_CODEC_BASE+217) +#define V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE (V4L2_CID_CODEC_BASE+218) +#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES (V4L2_CID_CODEC_BASE+219) +#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB (V4L2_CID_CODEC_BASE+220) +#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE (V4L2_CID_CODEC_BASE+221) enum v4l2_mpeg_video_multi_slice_mode { V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE = 0, V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB = 1, @@ -413,24 +413,24 @@ enum v4l2_mpeg_video_multi_slice_mode { V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES = 2, #endif }; -#define V4L2_CID_MPEG_VIDEO_VBV_SIZE (V4L2_CID_MPEG_BASE+222) -#define V4L2_CID_MPEG_VIDEO_DEC_PTS (V4L2_CID_MPEG_BASE+223) -#define V4L2_CID_MPEG_VIDEO_DEC_FRAME (V4L2_CID_MPEG_BASE+224) -#define V4L2_CID_MPEG_VIDEO_VBV_DELAY (V4L2_CID_MPEG_BASE+225) -#define V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER (V4L2_CID_MPEG_BASE+226) -#define V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE (V4L2_CID_MPEG_BASE+227) -#define V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE (V4L2_CID_MPEG_BASE+228) -#define V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME (V4L2_CID_MPEG_BASE+229) +#define V4L2_CID_MPEG_VIDEO_VBV_SIZE (V4L2_CID_CODEC_BASE+222) +#define V4L2_CID_MPEG_VIDEO_DEC_PTS (V4L2_CID_CODEC_BASE+223) +#define V4L2_CID_MPEG_VIDEO_DEC_FRAME (V4L2_CID_CODEC_BASE+224) +#define V4L2_CID_MPEG_VIDEO_VBV_DELAY (V4L2_CID_CODEC_BASE+225) +#define V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER (V4L2_CID_CODEC_BASE+226) +#define V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE (V4L2_CID_CODEC_BASE+227) +#define V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE (V4L2_CID_CODEC_BASE+228) +#define V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME (V4L2_CID_CODEC_BASE+229) /* CIDs for the MPEG-2 Part 2 (H.262) codec */ -#define V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL (V4L2_CID_MPEG_BASE+270) +#define V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL (V4L2_CID_CODEC_BASE+270) enum v4l2_mpeg_video_mpeg2_level { V4L2_MPEG_VIDEO_MPEG2_LEVEL_LOW = 0, V4L2_MPEG_VIDEO_MPEG2_LEVEL_MAIN = 1, V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH_1440 = 2, V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH = 3, }; -#define V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE (V4L2_CID_MPEG_BASE+271) +#define V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE (V4L2_CID_CODEC_BASE+271) enum v4l2_mpeg_video_mpeg2_profile { V4L2_MPEG_VIDEO_MPEG2_PROFILE_SIMPLE = 0, V4L2_MPEG_VIDEO_MPEG2_PROFILE_MAIN = 1, @@ -441,28 +441,28 @@ enum v4l2_mpeg_video_mpeg2_profile { }; /* CIDs for the FWHT codec as used by the vicodec driver. */ -#define V4L2_CID_FWHT_I_FRAME_QP (V4L2_CID_MPEG_BASE + 290) -#define V4L2_CID_FWHT_P_FRAME_QP (V4L2_CID_MPEG_BASE + 291) - -#define V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP (V4L2_CID_MPEG_BASE+300) -#define V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP (V4L2_CID_MPEG_BASE+301) -#define V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP (V4L2_CID_MPEG_BASE+302) -#define V4L2_CID_MPEG_VIDEO_H263_MIN_QP (V4L2_CID_MPEG_BASE+303) -#define V4L2_CID_MPEG_VIDEO_H263_MAX_QP (V4L2_CID_MPEG_BASE+304) -#define V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP (V4L2_CID_MPEG_BASE+350) -#define V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP (V4L2_CID_MPEG_BASE+351) -#define V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP (V4L2_CID_MPEG_BASE+352) -#define V4L2_CID_MPEG_VIDEO_H264_MIN_QP (V4L2_CID_MPEG_BASE+353) -#define V4L2_CID_MPEG_VIDEO_H264_MAX_QP (V4L2_CID_MPEG_BASE+354) -#define V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM (V4L2_CID_MPEG_BASE+355) -#define V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE (V4L2_CID_MPEG_BASE+356) -#define V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE (V4L2_CID_MPEG_BASE+357) +#define V4L2_CID_FWHT_I_FRAME_QP (V4L2_CID_CODEC_BASE + 290) +#define V4L2_CID_FWHT_P_FRAME_QP (V4L2_CID_CODEC_BASE + 291) + +#define V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP (V4L2_CID_CODEC_BASE+300) +#define V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP (V4L2_CID_CODEC_BASE+301) +#define V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP (V4L2_CID_CODEC_BASE+302) +#define V4L2_CID_MPEG_VIDEO_H263_MIN_QP (V4L2_CID_CODEC_BASE+303) +#define V4L2_CID_MPEG_VIDEO_H263_MAX_QP (V4L2_CID_CODEC_BASE+304) +#define V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP (V4L2_CID_CODEC_BASE+350) +#define V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP (V4L2_CID_CODEC_BASE+351) +#define V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP (V4L2_CID_CODEC_BASE+352) +#define V4L2_CID_MPEG_VIDEO_H264_MIN_QP (V4L2_CID_CODEC_BASE+353) +#define V4L2_CID_MPEG_VIDEO_H264_MAX_QP (V4L2_CID_CODEC_BASE+354) +#define V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM (V4L2_CID_CODEC_BASE+355) +#define V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE (V4L2_CID_CODEC_BASE+356) +#define V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE (V4L2_CID_CODEC_BASE+357) enum v4l2_mpeg_video_h264_entropy_mode { V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC = 0, V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC = 1, }; -#define V4L2_CID_MPEG_VIDEO_H264_I_PERIOD (V4L2_CID_MPEG_BASE+358) -#define V4L2_CID_MPEG_VIDEO_H264_LEVEL (V4L2_CID_MPEG_BASE+359) +#define V4L2_CID_MPEG_VIDEO_H264_I_PERIOD (V4L2_CID_CODEC_BASE+358) +#define V4L2_CID_MPEG_VIDEO_H264_LEVEL (V4L2_CID_CODEC_BASE+359) enum v4l2_mpeg_video_h264_level { V4L2_MPEG_VIDEO_H264_LEVEL_1_0 = 0, V4L2_MPEG_VIDEO_H264_LEVEL_1B = 1, @@ -485,15 +485,15 @@ enum v4l2_mpeg_video_h264_level { V4L2_MPEG_VIDEO_H264_LEVEL_6_1 = 18, V4L2_MPEG_VIDEO_H264_LEVEL_6_2 = 19, }; -#define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA (V4L2_CID_MPEG_BASE+360) -#define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA (V4L2_CID_MPEG_BASE+361) -#define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE (V4L2_CID_MPEG_BASE+362) +#define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA (V4L2_CID_CODEC_BASE+360) +#define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA (V4L2_CID_CODEC_BASE+361) +#define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE (V4L2_CID_CODEC_BASE+362) enum v4l2_mpeg_video_h264_loop_filter_mode { V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED = 0, V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED = 1, V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY = 2, }; -#define V4L2_CID_MPEG_VIDEO_H264_PROFILE (V4L2_CID_MPEG_BASE+363) +#define V4L2_CID_MPEG_VIDEO_H264_PROFILE (V4L2_CID_CODEC_BASE+363) enum v4l2_mpeg_video_h264_profile { V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE = 0, V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE = 1, @@ -514,10 +514,10 @@ enum v4l2_mpeg_video_h264_profile { V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH = 16, V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH = 17, }; -#define V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT (V4L2_CID_MPEG_BASE+364) -#define V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH (V4L2_CID_MPEG_BASE+365) -#define V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE (V4L2_CID_MPEG_BASE+366) -#define V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC (V4L2_CID_MPEG_BASE+367) +#define V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT (V4L2_CID_CODEC_BASE+364) +#define V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH (V4L2_CID_CODEC_BASE+365) +#define V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE (V4L2_CID_CODEC_BASE+366) +#define V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC (V4L2_CID_CODEC_BASE+367) enum v4l2_mpeg_video_h264_vui_sar_idc { V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED = 0, V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1 = 1, @@ -538,9 +538,9 @@ enum v4l2_mpeg_video_h264_vui_sar_idc { V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1 = 16, V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED = 17, }; -#define V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING (V4L2_CID_MPEG_BASE+368) -#define V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0 (V4L2_CID_MPEG_BASE+369) -#define V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE (V4L2_CID_MPEG_BASE+370) +#define V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING (V4L2_CID_CODEC_BASE+368) +#define V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0 (V4L2_CID_CODEC_BASE+369) +#define V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE (V4L2_CID_CODEC_BASE+370) enum v4l2_mpeg_video_h264_sei_fp_arrangement_type { V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_CHECKERBOARD = 0, V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_COLUMN = 1, @@ -549,8 +549,8 @@ enum v4l2_mpeg_video_h264_sei_fp_arrangement_type { V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TOP_BOTTOM = 4, V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TEMPORAL = 5, }; -#define V4L2_CID_MPEG_VIDEO_H264_FMO (V4L2_CID_MPEG_BASE+371) -#define V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE (V4L2_CID_MPEG_BASE+372) +#define V4L2_CID_MPEG_VIDEO_H264_FMO (V4L2_CID_CODEC_BASE+371) +#define V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE (V4L2_CID_CODEC_BASE+372) enum v4l2_mpeg_video_h264_fmo_map_type { V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES = 0, V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_SCATTERED_SLICES = 1, @@ -560,36 +560,36 @@ enum v4l2_mpeg_video_h264_fmo_map_type { V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN = 5, V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_EXPLICIT = 6, }; -#define V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP (V4L2_CID_MPEG_BASE+373) -#define V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION (V4L2_CID_MPEG_BASE+374) +#define V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP (V4L2_CID_CODEC_BASE+373) +#define V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION (V4L2_CID_CODEC_BASE+374) enum v4l2_mpeg_video_h264_fmo_change_dir { V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_RIGHT = 0, V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_LEFT = 1, }; -#define V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE (V4L2_CID_MPEG_BASE+375) -#define V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH (V4L2_CID_MPEG_BASE+376) -#define V4L2_CID_MPEG_VIDEO_H264_ASO (V4L2_CID_MPEG_BASE+377) -#define V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER (V4L2_CID_MPEG_BASE+378) -#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING (V4L2_CID_MPEG_BASE+379) -#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE (V4L2_CID_MPEG_BASE+380) +#define V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE (V4L2_CID_CODEC_BASE+375) +#define V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH (V4L2_CID_CODEC_BASE+376) +#define V4L2_CID_MPEG_VIDEO_H264_ASO (V4L2_CID_CODEC_BASE+377) +#define V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER (V4L2_CID_CODEC_BASE+378) +#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING (V4L2_CID_CODEC_BASE+379) +#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE (V4L2_CID_CODEC_BASE+380) enum v4l2_mpeg_video_h264_hierarchical_coding_type { V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B = 0, V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P = 1, }; -#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER (V4L2_CID_MPEG_BASE+381) -#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP (V4L2_CID_MPEG_BASE+382) -#define V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION (V4L2_CID_MPEG_BASE+383) -#define V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET (V4L2_CID_MPEG_BASE+384) -#define V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP (V4L2_CID_MPEG_BASE+385) -#define V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP (V4L2_CID_MPEG_BASE+386) -#define V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP (V4L2_CID_MPEG_BASE+387) -#define V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP (V4L2_CID_MPEG_BASE+388) -#define V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP (V4L2_CID_MPEG_BASE+400) -#define V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP (V4L2_CID_MPEG_BASE+401) -#define V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP (V4L2_CID_MPEG_BASE+402) -#define V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP (V4L2_CID_MPEG_BASE+403) -#define V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP (V4L2_CID_MPEG_BASE+404) -#define V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL (V4L2_CID_MPEG_BASE+405) +#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER (V4L2_CID_CODEC_BASE+381) +#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP (V4L2_CID_CODEC_BASE+382) +#define V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION (V4L2_CID_CODEC_BASE+383) +#define V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET (V4L2_CID_CODEC_BASE+384) +#define V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP (V4L2_CID_CODEC_BASE+385) +#define V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP (V4L2_CID_CODEC_BASE+386) +#define V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP (V4L2_CID_CODEC_BASE+387) +#define V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP (V4L2_CID_CODEC_BASE+388) +#define V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP (V4L2_CID_CODEC_BASE+400) +#define V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP (V4L2_CID_CODEC_BASE+401) +#define V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP (V4L2_CID_CODEC_BASE+402) +#define V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP (V4L2_CID_CODEC_BASE+403) +#define V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP (V4L2_CID_CODEC_BASE+404) +#define V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL (V4L2_CID_CODEC_BASE+405) enum v4l2_mpeg_video_mpeg4_level { V4L2_MPEG_VIDEO_MPEG4_LEVEL_0 = 0, V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B = 1, @@ -600,7 +600,7 @@ enum v4l2_mpeg_video_mpeg4_level { V4L2_MPEG_VIDEO_MPEG4_LEVEL_4 = 6, V4L2_MPEG_VIDEO_MPEG4_LEVEL_5 = 7, }; -#define V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE (V4L2_CID_MPEG_BASE+406) +#define V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE (V4L2_CID_CODEC_BASE+406) enum v4l2_mpeg_video_mpeg4_profile { V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE = 0, V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE = 1, @@ -608,40 +608,40 @@ enum v4l2_mpeg_video_mpeg4_profile { V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE_SCALABLE = 3, V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY = 4, }; -#define V4L2_CID_MPEG_VIDEO_MPEG4_QPEL (V4L2_CID_MPEG_BASE+407) +#define V4L2_CID_MPEG_VIDEO_MPEG4_QPEL (V4L2_CID_CODEC_BASE+407) /* Control IDs for VP8 streams * Although VP8 is not part of MPEG we add these controls to the MPEG class * as that class is already handling other video compression standards */ -#define V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS (V4L2_CID_MPEG_BASE+500) +#define V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS (V4L2_CID_CODEC_BASE+500) enum v4l2_vp8_num_partitions { V4L2_CID_MPEG_VIDEO_VPX_1_PARTITION = 0, V4L2_CID_MPEG_VIDEO_VPX_2_PARTITIONS = 1, V4L2_CID_MPEG_VIDEO_VPX_4_PARTITIONS = 2, V4L2_CID_MPEG_VIDEO_VPX_8_PARTITIONS = 3, }; -#define V4L2_CID_MPEG_VIDEO_VPX_IMD_DISABLE_4X4 (V4L2_CID_MPEG_BASE+501) -#define V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES (V4L2_CID_MPEG_BASE+502) +#define V4L2_CID_MPEG_VIDEO_VPX_IMD_DISABLE_4X4 (V4L2_CID_CODEC_BASE+501) +#define V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES (V4L2_CID_CODEC_BASE+502) enum v4l2_vp8_num_ref_frames { V4L2_CID_MPEG_VIDEO_VPX_1_REF_FRAME = 0, V4L2_CID_MPEG_VIDEO_VPX_2_REF_FRAME = 1, V4L2_CID_MPEG_VIDEO_VPX_3_REF_FRAME = 2, }; -#define V4L2_CID_MPEG_VIDEO_VPX_FILTER_LEVEL (V4L2_CID_MPEG_BASE+503) -#define V4L2_CID_MPEG_VIDEO_VPX_FILTER_SHARPNESS (V4L2_CID_MPEG_BASE+504) -#define V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD (V4L2_CID_MPEG_BASE+505) -#define V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL (V4L2_CID_MPEG_BASE+506) +#define V4L2_CID_MPEG_VIDEO_VPX_FILTER_LEVEL (V4L2_CID_CODEC_BASE+503) +#define V4L2_CID_MPEG_VIDEO_VPX_FILTER_SHARPNESS (V4L2_CID_CODEC_BASE+504) +#define V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD (V4L2_CID_CODEC_BASE+505) +#define V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL (V4L2_CID_CODEC_BASE+506) enum v4l2_vp8_golden_frame_sel { V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_PREV = 0, V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_REF_PERIOD = 1, }; -#define V4L2_CID_MPEG_VIDEO_VPX_MIN_QP (V4L2_CID_MPEG_BASE+507) -#define V4L2_CID_MPEG_VIDEO_VPX_MAX_QP (V4L2_CID_MPEG_BASE+508) -#define V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP (V4L2_CID_MPEG_BASE+509) -#define V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP (V4L2_CID_MPEG_BASE+510) +#define V4L2_CID_MPEG_VIDEO_VPX_MIN_QP (V4L2_CID_CODEC_BASE+507) +#define V4L2_CID_MPEG_VIDEO_VPX_MAX_QP (V4L2_CID_CODEC_BASE+508) +#define V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP (V4L2_CID_CODEC_BASE+509) +#define V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP (V4L2_CID_CODEC_BASE+510) -#define V4L2_CID_MPEG_VIDEO_VP8_PROFILE (V4L2_CID_MPEG_BASE+511) +#define V4L2_CID_MPEG_VIDEO_VP8_PROFILE (V4L2_CID_CODEC_BASE+511) enum v4l2_mpeg_video_vp8_profile { V4L2_MPEG_VIDEO_VP8_PROFILE_0 = 0, V4L2_MPEG_VIDEO_VP8_PROFILE_1 = 1, @@ -650,14 +650,14 @@ enum v4l2_mpeg_video_vp8_profile { }; /* Deprecated alias for compatibility reasons. */ #define V4L2_CID_MPEG_VIDEO_VPX_PROFILE V4L2_CID_MPEG_VIDEO_VP8_PROFILE -#define V4L2_CID_MPEG_VIDEO_VP9_PROFILE (V4L2_CID_MPEG_BASE+512) +#define V4L2_CID_MPEG_VIDEO_VP9_PROFILE (V4L2_CID_CODEC_BASE+512) enum v4l2_mpeg_video_vp9_profile { V4L2_MPEG_VIDEO_VP9_PROFILE_0 = 0, V4L2_MPEG_VIDEO_VP9_PROFILE_1 = 1, V4L2_MPEG_VIDEO_VP9_PROFILE_2 = 2, V4L2_MPEG_VIDEO_VP9_PROFILE_3 = 3, }; -#define V4L2_CID_MPEG_VIDEO_VP9_LEVEL (V4L2_CID_MPEG_BASE+513) +#define V4L2_CID_MPEG_VIDEO_VP9_LEVEL (V4L2_CID_CODEC_BASE+513) enum v4l2_mpeg_video_vp9_level { V4L2_MPEG_VIDEO_VP9_LEVEL_1_0 = 0, V4L2_MPEG_VIDEO_VP9_LEVEL_1_1 = 1, @@ -677,32 +677,32 @@ enum v4l2_mpeg_video_vp9_level { /* CIDs for HEVC encoding. */ -#define V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP (V4L2_CID_MPEG_BASE + 600) -#define V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP (V4L2_CID_MPEG_BASE + 601) -#define V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP (V4L2_CID_MPEG_BASE + 602) -#define V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP (V4L2_CID_MPEG_BASE + 603) -#define V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP (V4L2_CID_MPEG_BASE + 604) -#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP (V4L2_CID_MPEG_BASE + 605) -#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE (V4L2_CID_MPEG_BASE + 606) +#define V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP (V4L2_CID_CODEC_BASE + 600) +#define V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP (V4L2_CID_CODEC_BASE + 601) +#define V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP (V4L2_CID_CODEC_BASE + 602) +#define V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP (V4L2_CID_CODEC_BASE + 603) +#define V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP (V4L2_CID_CODEC_BASE + 604) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP (V4L2_CID_CODEC_BASE + 605) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE (V4L2_CID_CODEC_BASE + 606) enum v4l2_mpeg_video_hevc_hier_coding_type { V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B = 0, V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P = 1, }; -#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER (V4L2_CID_MPEG_BASE + 607) -#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP (V4L2_CID_MPEG_BASE + 608) -#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP (V4L2_CID_MPEG_BASE + 609) -#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP (V4L2_CID_MPEG_BASE + 610) -#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP (V4L2_CID_MPEG_BASE + 611) -#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP (V4L2_CID_MPEG_BASE + 612) -#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP (V4L2_CID_MPEG_BASE + 613) -#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP (V4L2_CID_MPEG_BASE + 614) -#define V4L2_CID_MPEG_VIDEO_HEVC_PROFILE (V4L2_CID_MPEG_BASE + 615) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER (V4L2_CID_CODEC_BASE + 607) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP (V4L2_CID_CODEC_BASE + 608) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP (V4L2_CID_CODEC_BASE + 609) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP (V4L2_CID_CODEC_BASE + 610) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP (V4L2_CID_CODEC_BASE + 611) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP (V4L2_CID_CODEC_BASE + 612) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP (V4L2_CID_CODEC_BASE + 613) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP (V4L2_CID_CODEC_BASE + 614) +#define V4L2_CID_MPEG_VIDEO_HEVC_PROFILE (V4L2_CID_CODEC_BASE + 615) enum v4l2_mpeg_video_hevc_profile { V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN = 0, V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE = 1, V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10 = 2, }; -#define V4L2_CID_MPEG_VIDEO_HEVC_LEVEL (V4L2_CID_MPEG_BASE + 616) +#define V4L2_CID_MPEG_VIDEO_HEVC_LEVEL (V4L2_CID_CODEC_BASE + 616) enum v4l2_mpeg_video_hevc_level { V4L2_MPEG_VIDEO_HEVC_LEVEL_1 = 0, V4L2_MPEG_VIDEO_HEVC_LEVEL_2 = 1, @@ -718,56 +718,56 @@ enum v4l2_mpeg_video_hevc_level { V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1 = 11, V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2 = 12, }; -#define V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION (V4L2_CID_MPEG_BASE + 617) -#define V4L2_CID_MPEG_VIDEO_HEVC_TIER (V4L2_CID_MPEG_BASE + 618) +#define V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION (V4L2_CID_CODEC_BASE + 617) +#define V4L2_CID_MPEG_VIDEO_HEVC_TIER (V4L2_CID_CODEC_BASE + 618) enum v4l2_mpeg_video_hevc_tier { V4L2_MPEG_VIDEO_HEVC_TIER_MAIN = 0, V4L2_MPEG_VIDEO_HEVC_TIER_HIGH = 1, }; -#define V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH (V4L2_CID_MPEG_BASE + 619) -#define V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE (V4L2_CID_MPEG_BASE + 620) +#define V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH (V4L2_CID_CODEC_BASE + 619) +#define V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE (V4L2_CID_CODEC_BASE + 620) enum v4l2_cid_mpeg_video_hevc_loop_filter_mode { V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED = 0, V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED = 1, V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY = 2, }; -#define V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2 (V4L2_CID_MPEG_BASE + 621) -#define V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2 (V4L2_CID_MPEG_BASE + 622) -#define V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE (V4L2_CID_MPEG_BASE + 623) +#define V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2 (V4L2_CID_CODEC_BASE + 621) +#define V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2 (V4L2_CID_CODEC_BASE + 622) +#define V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE (V4L2_CID_CODEC_BASE + 623) enum v4l2_cid_mpeg_video_hevc_refresh_type { V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE = 0, V4L2_MPEG_VIDEO_HEVC_REFRESH_CRA = 1, V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR = 2, }; -#define V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD (V4L2_CID_MPEG_BASE + 624) -#define V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU (V4L2_CID_MPEG_BASE + 625) -#define V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED (V4L2_CID_MPEG_BASE + 626) -#define V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT (V4L2_CID_MPEG_BASE + 627) -#define V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB (V4L2_CID_MPEG_BASE + 628) -#define V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID (V4L2_CID_MPEG_BASE + 629) -#define V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING (V4L2_CID_MPEG_BASE + 630) -#define V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1 (V4L2_CID_MPEG_BASE + 631) -#define V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT (V4L2_CID_MPEG_BASE + 632) -#define V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION (V4L2_CID_MPEG_BASE + 633) -#define V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE (V4L2_CID_MPEG_BASE + 634) -#define V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD (V4L2_CID_MPEG_BASE + 635) +#define V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD (V4L2_CID_CODEC_BASE + 624) +#define V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU (V4L2_CID_CODEC_BASE + 625) +#define V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED (V4L2_CID_CODEC_BASE + 626) +#define V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT (V4L2_CID_CODEC_BASE + 627) +#define V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB (V4L2_CID_CODEC_BASE + 628) +#define V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID (V4L2_CID_CODEC_BASE + 629) +#define V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING (V4L2_CID_CODEC_BASE + 630) +#define V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1 (V4L2_CID_CODEC_BASE + 631) +#define V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT (V4L2_CID_CODEC_BASE + 632) +#define V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION (V4L2_CID_CODEC_BASE + 633) +#define V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE (V4L2_CID_CODEC_BASE + 634) +#define V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD (V4L2_CID_CODEC_BASE + 635) enum v4l2_cid_mpeg_video_hevc_size_of_length_field { V4L2_MPEG_VIDEO_HEVC_SIZE_0 = 0, V4L2_MPEG_VIDEO_HEVC_SIZE_1 = 1, V4L2_MPEG_VIDEO_HEVC_SIZE_2 = 2, V4L2_MPEG_VIDEO_HEVC_SIZE_4 = 3, }; -#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR (V4L2_CID_MPEG_BASE + 636) -#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR (V4L2_CID_MPEG_BASE + 637) -#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR (V4L2_CID_MPEG_BASE + 638) -#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR (V4L2_CID_MPEG_BASE + 639) -#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR (V4L2_CID_MPEG_BASE + 640) -#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR (V4L2_CID_MPEG_BASE + 641) -#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR (V4L2_CID_MPEG_BASE + 642) -#define V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES (V4L2_CID_MPEG_BASE + 643) -#define V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR (V4L2_CID_MPEG_BASE + 644) -#define V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY (V4L2_CID_MPEG_BASE + 645) -#define V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE (V4L2_CID_MPEG_BASE + 646) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR (V4L2_CID_CODEC_BASE + 636) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR (V4L2_CID_CODEC_BASE + 637) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR (V4L2_CID_CODEC_BASE + 638) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR (V4L2_CID_CODEC_BASE + 639) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR (V4L2_CID_CODEC_BASE + 640) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR (V4L2_CID_CODEC_BASE + 641) +#define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR (V4L2_CID_CODEC_BASE + 642) +#define V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES (V4L2_CID_CODEC_BASE + 643) +#define V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR (V4L2_CID_CODEC_BASE + 644) +#define V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY (V4L2_CID_CODEC_BASE + 645) +#define V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE (V4L2_CID_CODEC_BASE + 646) enum v4l2_mpeg_video_frame_skip_mode { V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED = 0, V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT = 1, @@ -775,14 +775,14 @@ enum v4l2_mpeg_video_frame_skip_mode { }; /* MPEG-class control IDs specific to the CX2341x driver as defined by V4L2 */ -#define V4L2_CID_MPEG_CX2341X_BASE (V4L2_CTRL_CLASS_MPEG | 0x1000) -#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE (V4L2_CID_MPEG_CX2341X_BASE+0) +#define V4L2_CID_CODEC_CX2341X_BASE (V4L2_CTRL_CLASS_CODEC | 0x1000) +#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE (V4L2_CID_CODEC_CX2341X_BASE+0) enum v4l2_mpeg_cx2341x_video_spatial_filter_mode { V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL = 0, V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO = 1, }; -#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER (V4L2_CID_MPEG_CX2341X_BASE+1) -#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE (V4L2_CID_MPEG_CX2341X_BASE+2) +#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER (V4L2_CID_CODEC_CX2341X_BASE+1) +#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE (V4L2_CID_CODEC_CX2341X_BASE+2) enum v4l2_mpeg_cx2341x_video_luma_spatial_filter_type { V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF = 0, V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR = 1, @@ -790,18 +790,18 @@ enum v4l2_mpeg_cx2341x_video_luma_spatial_filter_type { V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE = 3, V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE = 4, }; -#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE (V4L2_CID_MPEG_CX2341X_BASE+3) +#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE (V4L2_CID_CODEC_CX2341X_BASE+3) enum v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type { V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF = 0, V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR = 1, }; -#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE (V4L2_CID_MPEG_CX2341X_BASE+4) +#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE (V4L2_CID_CODEC_CX2341X_BASE+4) enum v4l2_mpeg_cx2341x_video_temporal_filter_mode { V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL = 0, V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO = 1, }; -#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER (V4L2_CID_MPEG_CX2341X_BASE+5) -#define V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE (V4L2_CID_MPEG_CX2341X_BASE+6) +#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER (V4L2_CID_CODEC_CX2341X_BASE+5) +#define V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE (V4L2_CID_CODEC_CX2341X_BASE+6) enum v4l2_mpeg_cx2341x_video_median_filter_type { V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF = 0, V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR = 1, @@ -809,38 +809,38 @@ enum v4l2_mpeg_cx2341x_video_median_filter_type { V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT = 3, V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG = 4, }; -#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM (V4L2_CID_MPEG_CX2341X_BASE+7) -#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP (V4L2_CID_MPEG_CX2341X_BASE+8) -#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM (V4L2_CID_MPEG_CX2341X_BASE+9) -#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP (V4L2_CID_MPEG_CX2341X_BASE+10) -#define V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS (V4L2_CID_MPEG_CX2341X_BASE+11) +#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM (V4L2_CID_CODEC_CX2341X_BASE+7) +#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP (V4L2_CID_CODEC_CX2341X_BASE+8) +#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM (V4L2_CID_CODEC_CX2341X_BASE+9) +#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP (V4L2_CID_CODEC_CX2341X_BASE+10) +#define V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS (V4L2_CID_CODEC_CX2341X_BASE+11) /* MPEG-class control IDs specific to the Samsung MFC 5.1 driver as defined by V4L2 */ -#define V4L2_CID_MPEG_MFC51_BASE (V4L2_CTRL_CLASS_MPEG | 0x1100) +#define V4L2_CID_CODEC_MFC51_BASE (V4L2_CTRL_CLASS_CODEC | 0x1100) -#define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY (V4L2_CID_MPEG_MFC51_BASE+0) -#define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE (V4L2_CID_MPEG_MFC51_BASE+1) -#define V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE (V4L2_CID_MPEG_MFC51_BASE+2) +#define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY (V4L2_CID_CODEC_MFC51_BASE+0) +#define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE (V4L2_CID_CODEC_MFC51_BASE+1) +#define V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE (V4L2_CID_CODEC_MFC51_BASE+2) enum v4l2_mpeg_mfc51_video_frame_skip_mode { V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED = 0, V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT = 1, V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT = 2, }; -#define V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE (V4L2_CID_MPEG_MFC51_BASE+3) +#define V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE (V4L2_CID_CODEC_MFC51_BASE+3) enum v4l2_mpeg_mfc51_video_force_frame_type { V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED = 0, V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME = 1, V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_NOT_CODED = 2, }; -#define V4L2_CID_MPEG_MFC51_VIDEO_PADDING (V4L2_CID_MPEG_MFC51_BASE+4) -#define V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV (V4L2_CID_MPEG_MFC51_BASE+5) -#define V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT (V4L2_CID_MPEG_MFC51_BASE+6) -#define V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF (V4L2_CID_MPEG_MFC51_BASE+7) -#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY (V4L2_CID_MPEG_MFC51_BASE+50) -#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK (V4L2_CID_MPEG_MFC51_BASE+51) -#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH (V4L2_CID_MPEG_MFC51_BASE+52) -#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC (V4L2_CID_MPEG_MFC51_BASE+53) -#define V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P (V4L2_CID_MPEG_MFC51_BASE+54) +#define V4L2_CID_MPEG_MFC51_VIDEO_PADDING (V4L2_CID_CODEC_MFC51_BASE+4) +#define V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV (V4L2_CID_CODEC_MFC51_BASE+5) +#define V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT (V4L2_CID_CODEC_MFC51_BASE+6) +#define V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF (V4L2_CID_CODEC_MFC51_BASE+7) +#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY (V4L2_CID_CODEC_MFC51_BASE+50) +#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK (V4L2_CID_CODEC_MFC51_BASE+51) +#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH (V4L2_CID_CODEC_MFC51_BASE+52) +#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC (V4L2_CID_CODEC_MFC51_BASE+53) +#define V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P (V4L2_CID_CODEC_MFC51_BASE+54) /* Camera class control IDs */ @@ -1177,4 +1177,13 @@ enum v4l2_detect_md_mode { #define V4L2_CID_DETECT_MD_THRESHOLD_GRID (V4L2_CID_DETECT_CLASS_BASE + 3) #define V4L2_CID_DETECT_MD_REGION_GRID (V4L2_CID_DETECT_CLASS_BASE + 4) +/* MPEG-compression definitions kept for backwards compatibility */ +#ifndef __KERNEL__ +#define V4L2_CTRL_CLASS_MPEG V4L2_CTRL_CLASS_CODEC +#define V4L2_CID_MPEG_CLASS V4L2_CID_CODEC_CLASS +#define V4L2_CID_MPEG_BASE V4L2_CID_CODEC_BASE +#define V4L2_CID_MPEG_CX2341X_BASE V4L2_CID_CODEC_CX2341X_BASE +#define V4L2_CID_MPEG_MFC51_BASE V4L2_CID_CODEC_MFC51_BASE +#endif + #endif -- cgit v1.2.3 From 8917a5f61e4614d6f073cfe59e59c5faa58c026c Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 26 Nov 2020 10:36:10 +0100 Subject: media: Clean stateless control includes Avoid including h264-ctrls.h, vp8-ctrls.h, etc, and instead just include v4l2-ctrls.h which does the right thing. This is in preparation for moving the stateless controls out of staging, which will mean removing some of these headers. Signed-off-by: Ezequiel Garcia Tested-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/hantro_hw.h | 4 +--- include/media/v4l2-h264.h | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h index 219283a06f52..34c9e4649a25 100644 --- a/drivers/staging/media/hantro/hantro_hw.h +++ b/drivers/staging/media/hantro/hantro_hw.h @@ -11,9 +11,7 @@ #include #include -#include -#include -#include +#include #include #define DEC_8190_ALIGN_MASK 0x07U diff --git a/include/media/v4l2-h264.h b/include/media/v4l2-h264.h index f08ba181263d..d2314f4d4490 100644 --- a/include/media/v4l2-h264.h +++ b/include/media/v4l2-h264.h @@ -10,7 +10,7 @@ #ifndef _MEDIA_V4L2_H264_H #define _MEDIA_V4L2_H264_H -#include +#include /** * struct v4l2_h264_reflist_builder - Reference list builder object -- cgit v1.2.3 From b32e48503df05bd1ca95dc1a07824afc2c7c9c4e Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 26 Nov 2020 10:36:11 +0100 Subject: media: controls: Validate H264 stateless controls Check that all the fields that correspond or are related to a H264 specification syntax element have legal values. Signed-off-by: Ezequiel Garcia Tested-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 134 +++++++++++++++++++++++++++++++++++ include/media/h264-ctrls.h | 9 +++ 2 files changed, 143 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 88ad475bd716..6a17a7487459 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1775,6 +1775,9 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, { struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; struct v4l2_ctrl_vp8_frame_header *p_vp8_frame_header; + struct v4l2_ctrl_h264_sps *p_h264_sps; + struct v4l2_ctrl_h264_pps *p_h264_pps; + struct v4l2_ctrl_h264_pred_weights *p_h264_pred_weights; struct v4l2_ctrl_h264_slice_params *p_h264_slice_params; struct v4l2_ctrl_h264_decode_params *p_h264_dec_params; struct v4l2_ctrl_hevc_sps *p_hevc_sps; @@ -1834,20 +1837,151 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, break; case V4L2_CTRL_TYPE_H264_SPS: + p_h264_sps = p; + + /* Some syntax elements are only conditionally valid */ + if (p_h264_sps->pic_order_cnt_type != 0) { + p_h264_sps->log2_max_pic_order_cnt_lsb_minus4 = 0; + } else if (p_h264_sps->pic_order_cnt_type != 1) { + p_h264_sps->num_ref_frames_in_pic_order_cnt_cycle = 0; + p_h264_sps->offset_for_non_ref_pic = 0; + p_h264_sps->offset_for_top_to_bottom_field = 0; + memset(&p_h264_sps->offset_for_ref_frame, 0, + sizeof(p_h264_sps->offset_for_ref_frame)); + } + + if (!V4L2_H264_SPS_HAS_CHROMA_FORMAT(p_h264_sps)) { + p_h264_sps->chroma_format_idc = 1; + p_h264_sps->bit_depth_luma_minus8 = 0; + p_h264_sps->bit_depth_chroma_minus8 = 0; + + p_h264_sps->flags &= + ~V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS; + + if (p_h264_sps->chroma_format_idc < 3) + p_h264_sps->flags &= + ~V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE; + } + + if (p_h264_sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY) + p_h264_sps->flags &= + ~V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD; + + /* + * Chroma 4:2:2 format require at least High 4:2:2 profile. + * + * The H264 specification and well-known parser implementations + * use profile-idc values directly, as that is clearer and + * less ambiguous. We do the same here. + */ + if (p_h264_sps->profile_idc < 122 && + p_h264_sps->chroma_format_idc > 1) + return -EINVAL; + /* Chroma 4:4:4 format require at least High 4:2:2 profile */ + if (p_h264_sps->profile_idc < 244 && + p_h264_sps->chroma_format_idc > 2) + return -EINVAL; + if (p_h264_sps->chroma_format_idc > 3) + return -EINVAL; + + if (p_h264_sps->bit_depth_luma_minus8 > 6) + return -EINVAL; + if (p_h264_sps->bit_depth_chroma_minus8 > 6) + return -EINVAL; + if (p_h264_sps->log2_max_frame_num_minus4 > 12) + return -EINVAL; + if (p_h264_sps->pic_order_cnt_type > 2) + return -EINVAL; + if (p_h264_sps->log2_max_pic_order_cnt_lsb_minus4 > 12) + return -EINVAL; + if (p_h264_sps->max_num_ref_frames > V4L2_H264_REF_LIST_LEN) + return -EINVAL; + break; + case V4L2_CTRL_TYPE_H264_PPS: + p_h264_pps = p; + + if (p_h264_pps->num_slice_groups_minus1 > 7) + return -EINVAL; + if (p_h264_pps->num_ref_idx_l0_default_active_minus1 > + (V4L2_H264_REF_LIST_LEN - 1)) + return -EINVAL; + if (p_h264_pps->num_ref_idx_l1_default_active_minus1 > + (V4L2_H264_REF_LIST_LEN - 1)) + return -EINVAL; + if (p_h264_pps->weighted_bipred_idc > 2) + return -EINVAL; + /* + * pic_init_qp_minus26 shall be in the range of + * -(26 + QpBdOffset_y) to +25, inclusive, + * where QpBdOffset_y is 6 * bit_depth_luma_minus8 + */ + if (p_h264_pps->pic_init_qp_minus26 < -62 || + p_h264_pps->pic_init_qp_minus26 > 25) + return -EINVAL; + if (p_h264_pps->pic_init_qs_minus26 < -26 || + p_h264_pps->pic_init_qs_minus26 > 25) + return -EINVAL; + if (p_h264_pps->chroma_qp_index_offset < -12 || + p_h264_pps->chroma_qp_index_offset > 12) + return -EINVAL; + if (p_h264_pps->second_chroma_qp_index_offset < -12 || + p_h264_pps->second_chroma_qp_index_offset > 12) + return -EINVAL; + break; + case V4L2_CTRL_TYPE_H264_SCALING_MATRIX: + break; + case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS: + p_h264_pred_weights = p; + + if (p_h264_pred_weights->luma_log2_weight_denom > 7) + return -EINVAL; + if (p_h264_pred_weights->chroma_log2_weight_denom > 7) + return -EINVAL; break; case V4L2_CTRL_TYPE_H264_SLICE_PARAMS: p_h264_slice_params = p; + if (p_h264_slice_params->slice_type != V4L2_H264_SLICE_TYPE_B) + p_h264_slice_params->flags &= + ~V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED; + + if (p_h264_slice_params->colour_plane_id > 2) + return -EINVAL; + if (p_h264_slice_params->cabac_init_idc > 2) + return -EINVAL; + if (p_h264_slice_params->disable_deblocking_filter_idc > 2) + return -EINVAL; + if (p_h264_slice_params->slice_alpha_c0_offset_div2 < -6 || + p_h264_slice_params->slice_alpha_c0_offset_div2 > 6) + return -EINVAL; + if (p_h264_slice_params->slice_beta_offset_div2 < -6 || + p_h264_slice_params->slice_beta_offset_div2 > 6) + return -EINVAL; + + if (p_h264_slice_params->slice_type == V4L2_H264_SLICE_TYPE_I || + p_h264_slice_params->slice_type == V4L2_H264_SLICE_TYPE_SI) + p_h264_slice_params->num_ref_idx_l0_active_minus1 = 0; + if (p_h264_slice_params->slice_type != V4L2_H264_SLICE_TYPE_B) + p_h264_slice_params->num_ref_idx_l1_active_minus1 = 0; + + if (p_h264_slice_params->num_ref_idx_l0_active_minus1 > + (V4L2_H264_REF_LIST_LEN - 1)) + return -EINVAL; + if (p_h264_slice_params->num_ref_idx_l1_active_minus1 > + (V4L2_H264_REF_LIST_LEN - 1)) + return -EINVAL; zero_reserved(*p_h264_slice_params); break; case V4L2_CTRL_TYPE_H264_DECODE_PARAMS: p_h264_dec_params = p; + if (p_h264_dec_params->nal_ref_idc > 3) + return -EINVAL; for (i = 0; i < V4L2_H264_NUM_DPB_ENTRIES; i++) { struct v4l2_h264_dpb_entry *dpb_entry = &p_h264_dec_params->dpb[i]; diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h index f86345b8efd1..083899c3ea19 100644 --- a/include/media/h264-ctrls.h +++ b/include/media/h264-ctrls.h @@ -98,6 +98,15 @@ enum v4l2_mpeg_video_h264_start_code { #define V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD 0x20 #define V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE 0x40 +#define V4L2_H264_SPS_HAS_CHROMA_FORMAT(sps) \ + ((sps)->profile_idc == 100 || (sps)->profile_idc == 110 || \ + (sps)->profile_idc == 122 || (sps)->profile_idc == 244 || \ + (sps)->profile_idc == 44 || (sps)->profile_idc == 83 || \ + (sps)->profile_idc == 86 || (sps)->profile_idc == 118 || \ + (sps)->profile_idc == 128 || (sps)->profile_idc == 138 || \ + (sps)->profile_idc == 139 || (sps)->profile_idc == 134 || \ + (sps)->profile_idc == 135) + /** * struct v4l2_ctrl_h264_sps - H264 sequence parameter set * -- cgit v1.2.3 From 008d2bd6e96b5a7e80dacfb02cd182c3839ce819 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 26 Nov 2020 10:36:12 +0100 Subject: media: controls: Add the stateless codec control class Add a new control class to hold the stateless codecs controls that are ready to be moved out of staging. Signed-off-by: Ezequiel Garcia Tested-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst | 4 ++++ drivers/media/v4l2-core/v4l2-ctrls.c | 5 +++++ include/uapi/linux/v4l2-controls.h | 7 +++++++ 3 files changed, 16 insertions(+) diff --git a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst index 2196cdf61ca0..06a5b175a75d 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst @@ -362,6 +362,10 @@ still cause this situation. - 0xa30000 - The class containing motion or object detection controls. These controls are described in :ref:`detect-controls`. + * - ``V4L2_CTRL_CLASS_CODEC_STATELESS`` + - 0xa40000 + - The class containing stateless codec controls. These controls are + described in :ref:`codec-stateless-controls`. Return Value ============ diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 6a17a7487459..fa96e6aa0a86 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1181,6 +1181,10 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD: return "MD Global Threshold"; case V4L2_CID_DETECT_MD_THRESHOLD_GRID: return "MD Threshold Grid"; case V4L2_CID_DETECT_MD_REGION_GRID: return "MD Region Grid"; + + /* Stateless Codec controls */ + /* Keep the order of the 'case's the same as in v4l2-controls.h! */ + case V4L2_CID_CODEC_STATELESS_CLASS: return "Stateless Codec Controls"; default: return NULL; } @@ -1368,6 +1372,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_FM_RX_CLASS: case V4L2_CID_RF_TUNER_CLASS: case V4L2_CID_DETECT_CLASS: + case V4L2_CID_CODEC_STATELESS_CLASS: *type = V4L2_CTRL_TYPE_CTRL_CLASS; /* You can neither read not write these */ *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY; diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 75cf87b9a377..90478ecc2f81 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -65,6 +65,7 @@ #define V4L2_CTRL_CLASS_FM_RX 0x00a10000 /* FM Receiver controls */ #define V4L2_CTRL_CLASS_RF_TUNER 0x00a20000 /* RF tuner controls */ #define V4L2_CTRL_CLASS_DETECT 0x00a30000 /* Detection controls */ +#define V4L2_CTRL_CLASS_CODEC_STATELESS 0x00a40000 /* Stateless codecs controls */ /* User-class control IDs */ @@ -1177,6 +1178,12 @@ enum v4l2_detect_md_mode { #define V4L2_CID_DETECT_MD_THRESHOLD_GRID (V4L2_CID_DETECT_CLASS_BASE + 3) #define V4L2_CID_DETECT_MD_REGION_GRID (V4L2_CID_DETECT_CLASS_BASE + 4) + +/* Stateless CODECs controls */ +#define V4L2_CID_CODEC_STATELESS_BASE (V4L2_CTRL_CLASS_CODEC_STATELESS | 0x900) +#define V4L2_CID_CODEC_STATELESS_CLASS (V4L2_CTRL_CLASS_CODEC_STATELESS | 1) + + /* MPEG-compression definitions kept for backwards compatibility */ #ifndef __KERNEL__ #define V4L2_CTRL_CLASS_MPEG V4L2_CTRL_CLASS_CODEC -- cgit v1.2.3 From 95e95ebe9119dcdf04e8aa9e1d9e8de4f1150c67 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 26 Nov 2020 10:36:13 +0100 Subject: media: uapi: Move parsed H264 pixel format out of staging Since we are ready to stabilize the H264 stateless API, start by first moving the parsed H264 pixel format. Signed-off-by: Ezequiel Garcia Tested-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/media/h264-ctrls.h | 3 --- include/uapi/linux/videodev2.h | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h index 083899c3ea19..d98c5b885379 100644 --- a/include/media/h264-ctrls.h +++ b/include/media/h264-ctrls.h @@ -21,9 +21,6 @@ #define V4L2_H264_REF_LIST_LEN (2 * V4L2_H264_NUM_DPB_ENTRIES) -/* Our pixel format isn't stable at the moment */ -#define V4L2_PIX_FMT_H264_SLICE v4l2_fourcc('S', '2', '6', '4') /* H264 parsed slices */ - /* * This is put insanely high to avoid conflicting with controls that * would be added during the phase where those controls are not diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 761ac9da3ffd..ed6a85f1442e 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -703,6 +703,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_HEVC v4l2_fourcc('H', 'E', 'V', 'C') /* HEVC aka H.265 */ #define V4L2_PIX_FMT_FWHT v4l2_fourcc('F', 'W', 'H', 'T') /* Fast Walsh Hadamard Transform (vicodec) */ #define V4L2_PIX_FMT_FWHT_STATELESS v4l2_fourcc('S', 'F', 'W', 'H') /* Stateless FWHT (vicodec) */ +#define V4L2_PIX_FMT_H264_SLICE v4l2_fourcc('S', '2', '6', '4') /* H264 parsed slices */ /* Vendor-specific formats */ #define V4L2_PIX_FMT_CPIA1 v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */ -- cgit v1.2.3 From ee6fcc67db54f699c1ab53a3939fcf62d7cfb311 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 26 Nov 2020 10:36:14 +0100 Subject: media: doc: Replace symbol for V4L2_CTRL_TYPE_H264_PRED_WEIGHTS When V4L2_CTRL_TYPE_H264_PRED_WEIGHTS was added, adding a replace symbol directive in videodev2.h.rst.exceptions was missed. Now that the control type is destaged, it's important to fix this. Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/videodev2.h.rst.exceptions | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/userspace-api/media/videodev2.h.rst.exceptions b/Documentation/userspace-api/media/videodev2.h.rst.exceptions index 121e396a2779..7f6a4cc2ac4e 100644 --- a/Documentation/userspace-api/media/videodev2.h.rst.exceptions +++ b/Documentation/userspace-api/media/videodev2.h.rst.exceptions @@ -139,6 +139,7 @@ replace symbol V4L2_CTRL_TYPE_MPEG2_QUANTIZATION :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_H264_SPS :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_H264_PPS :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_H264_SCALING_MATRIX :c:type:`v4l2_ctrl_type` +replace symbol V4L2_CTRL_TYPE_H264_PRED_WEIGHTS :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_H264_SLICE_PARAMS :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_H264_DECODE_PARAMS :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_HEVC_SPS :c:type:`v4l2_ctrl_type` -- cgit v1.2.3 From a7ead39700e10df7aaadc13c72e3a0cefcbb7f4e Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 26 Nov 2020 10:36:15 +0100 Subject: media: uapi: Move the H264 stateless control types out of staging Move the H264 stateless control types out of staging, and re-number them to avoid any confusion. Signed-off-by: Ezequiel Garcia Tested-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/media/h264-ctrls.h | 8 -------- include/uapi/linux/videodev2.h | 7 +++++++ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h index d98c5b885379..c15fed956bf5 100644 --- a/include/media/h264-ctrls.h +++ b/include/media/h264-ctrls.h @@ -35,14 +35,6 @@ #define V4L2_CID_MPEG_VIDEO_H264_START_CODE (V4L2_CID_CODEC_BASE+1006) #define V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS (V4L2_CID_CODEC_BASE+1007) -/* enum v4l2_ctrl_type type values */ -#define V4L2_CTRL_TYPE_H264_SPS 0x0110 -#define V4L2_CTRL_TYPE_H264_PPS 0x0111 -#define V4L2_CTRL_TYPE_H264_SCALING_MATRIX 0x0112 -#define V4L2_CTRL_TYPE_H264_SLICE_PARAMS 0x0113 -#define V4L2_CTRL_TYPE_H264_DECODE_PARAMS 0x0114 -#define V4L2_CTRL_TYPE_H264_PRED_WEIGHTS 0x0115 - /** * enum v4l2_mpeg_video_h264_decode_mode - Decoding mode * diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index ed6a85f1442e..485654fd2a7e 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1780,6 +1780,13 @@ enum v4l2_ctrl_type { V4L2_CTRL_TYPE_U16 = 0x0101, V4L2_CTRL_TYPE_U32 = 0x0102, V4L2_CTRL_TYPE_AREA = 0x0106, + + V4L2_CTRL_TYPE_H264_SPS = 0x0200, + V4L2_CTRL_TYPE_H264_PPS = 0x0201, + V4L2_CTRL_TYPE_H264_SCALING_MATRIX = 0x0202, + V4L2_CTRL_TYPE_H264_SLICE_PARAMS = 0x0203, + V4L2_CTRL_TYPE_H264_DECODE_PARAMS = 0x0204, + V4L2_CTRL_TYPE_H264_PRED_WEIGHTS = 0x0205, }; /* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */ -- cgit v1.2.3 From afc5329ea76d0706d0db6d26ff98b890bba1d112 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 26 Nov 2020 10:36:16 +0100 Subject: media: controls: Log H264 stateless controls in .std_log For now, only print the type of the control. In the future, we might want to be able to print the values of all the stateless codec controls currently set in the control handler, which should be useful for debugging reasons. Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index fa96e6aa0a86..2a5e3d3cc756 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1737,6 +1737,24 @@ static void std_log(const struct v4l2_ctrl *ctrl) case V4L2_CTRL_TYPE_U32: pr_cont("%u", (unsigned)*ptr.p_u32); break; + case V4L2_CTRL_TYPE_H264_SPS: + pr_cont("H264_SPS"); + break; + case V4L2_CTRL_TYPE_H264_PPS: + pr_cont("H264_PPS"); + break; + case V4L2_CTRL_TYPE_H264_SCALING_MATRIX: + pr_cont("H264_SCALING_MATRIX"); + break; + case V4L2_CTRL_TYPE_H264_SLICE_PARAMS: + pr_cont("H264_SLICE_PARAMS"); + break; + case V4L2_CTRL_TYPE_H264_DECODE_PARAMS: + pr_cont("H264_DECODE_PARAMS"); + break; + case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS: + pr_cont("H264_PRED_WEIGHTS"); + break; default: pr_cont("unknown type %d", ctrl->type); break; -- cgit v1.2.3 From 46a309d27517873b7cd5cd6b81da3a84b48162bc Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 26 Nov 2020 10:36:17 +0100 Subject: media: uapi: move H264 stateless controls out of staging The H.264 stateless 'uAPI' was staging and marked explicitly in the V4L2 specification that it will change and is unstable. Note that these control IDs were never exported as a public API, they were only defined in kernel-local headers (h264-ctrls.h). Now, the H264 stateless controls is ready to be part of the stable uAPI. While not too late, let's rename them and re-number their control IDs, moving them to the newly created stateless control class, and updating all the drivers accordingly. Signed-off-by: Ezequiel Garcia Tested-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 36 +-- drivers/staging/media/hantro/hantro_drv.c | 26 +- drivers/staging/media/hantro/hantro_h264.c | 8 +- drivers/staging/media/rkvdec/rkvdec-h264.c | 8 +- drivers/staging/media/rkvdec/rkvdec.c | 26 +- drivers/staging/media/sunxi/cedrus/cedrus.c | 24 +- drivers/staging/media/sunxi/cedrus/cedrus_dec.c | 12 +- include/media/h264-ctrls.h | 404 ------------------------ include/media/v4l2-ctrls.h | 1 - include/uapi/linux/v4l2-controls.h | 381 ++++++++++++++++++++++ include/uapi/linux/videodev2.h | 6 + 11 files changed, 457 insertions(+), 475 deletions(-) delete mode 100644 include/media/h264-ctrls.h diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 2a5e3d3cc756..88231ba7b0fa 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -693,9 +693,9 @@ const char * const *v4l2_ctrl_get_menu(u32 id) return h264_fp_arrangement_type; case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: return h264_fmo_map_type; - case V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE: + case V4L2_CID_STATELESS_H264_DECODE_MODE: return h264_decode_mode; - case V4L2_CID_MPEG_VIDEO_H264_START_CODE: + case V4L2_CID_STATELESS_H264_START_CODE: return h264_start_code; case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: return mpeg_mpeg2_level; @@ -920,14 +920,6 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP: return "H264 I-Frame Maximum QP Value"; case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP: return "H264 P-Frame Minimum QP Value"; case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP: return "H264 P-Frame Maximum QP Value"; - case V4L2_CID_MPEG_VIDEO_H264_SPS: return "H264 Sequence Parameter Set"; - case V4L2_CID_MPEG_VIDEO_H264_PPS: return "H264 Picture Parameter Set"; - case V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX: return "H264 Scaling Matrix"; - case V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS: return "H264 Slice Parameters"; - case V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS: return "H264 Decode Parameters"; - case V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE: return "H264 Decode Mode"; - case V4L2_CID_MPEG_VIDEO_H264_START_CODE: return "H264 Start Code"; - case V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS: return "H264 Prediction Weight Table"; case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: return "MPEG2 Level"; case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: return "MPEG2 Profile"; case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: return "MPEG4 I-Frame QP Value"; @@ -1185,6 +1177,14 @@ const char *v4l2_ctrl_get_name(u32 id) /* Stateless Codec controls */ /* Keep the order of the 'case's the same as in v4l2-controls.h! */ case V4L2_CID_CODEC_STATELESS_CLASS: return "Stateless Codec Controls"; + case V4L2_CID_STATELESS_H264_DECODE_MODE: return "H264 Decode Mode"; + case V4L2_CID_STATELESS_H264_START_CODE: return "H264 Start Code"; + case V4L2_CID_STATELESS_H264_SPS: return "H264 Sequence Parameter Set"; + case V4L2_CID_STATELESS_H264_PPS: return "H264 Picture Parameter Set"; + case V4L2_CID_STATELESS_H264_SCALING_MATRIX: return "H264 Scaling Matrix"; + case V4L2_CID_STATELESS_H264_PRED_WEIGHTS: return "H264 Prediction Weight Table"; + case V4L2_CID_STATELESS_H264_SLICE_PARAMS: return "H264 Slice Parameters"; + case V4L2_CID_STATELESS_H264_DECODE_PARAMS: return "H264 Decode Parameters"; default: return NULL; } @@ -1310,8 +1310,6 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE: case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: - case V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE: - case V4L2_CID_MPEG_VIDEO_H264_START_CODE: case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: @@ -1342,6 +1340,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE: case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE: + case V4L2_CID_STATELESS_H264_DECODE_MODE: + case V4L2_CID_STATELESS_H264_START_CODE: case V4L2_CID_CAMERA_ORIENTATION: *type = V4L2_CTRL_TYPE_MENU; break; @@ -1436,22 +1436,22 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_FWHT_PARAMS: *type = V4L2_CTRL_TYPE_FWHT_PARAMS; break; - case V4L2_CID_MPEG_VIDEO_H264_SPS: + case V4L2_CID_STATELESS_H264_SPS: *type = V4L2_CTRL_TYPE_H264_SPS; break; - case V4L2_CID_MPEG_VIDEO_H264_PPS: + case V4L2_CID_STATELESS_H264_PPS: *type = V4L2_CTRL_TYPE_H264_PPS; break; - case V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX: + case V4L2_CID_STATELESS_H264_SCALING_MATRIX: *type = V4L2_CTRL_TYPE_H264_SCALING_MATRIX; break; - case V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS: + case V4L2_CID_STATELESS_H264_SLICE_PARAMS: *type = V4L2_CTRL_TYPE_H264_SLICE_PARAMS; break; - case V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS: + case V4L2_CID_STATELESS_H264_DECODE_PARAMS: *type = V4L2_CTRL_TYPE_H264_DECODE_PARAMS; break; - case V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS: + case V4L2_CID_STATELESS_H264_PRED_WEIGHTS: *type = V4L2_CTRL_TYPE_H264_PRED_WEIGHTS; break; case V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER: diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index 3cd00cc0a364..e5f200e64993 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -231,7 +231,7 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) static int hantro_try_ctrl(struct v4l2_ctrl *ctrl) { - if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_SPS) { + if (ctrl->id == V4L2_CID_STATELESS_H264_SPS) { const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps; if (sps->chroma_format_idc > 1) @@ -304,39 +304,39 @@ static const struct hantro_ctrl controls[] = { }, { .codec = HANTRO_H264_DECODER, .cfg = { - .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS, + .id = V4L2_CID_STATELESS_H264_DECODE_PARAMS, }, }, { .codec = HANTRO_H264_DECODER, .cfg = { - .id = V4L2_CID_MPEG_VIDEO_H264_SPS, + .id = V4L2_CID_STATELESS_H264_SPS, .ops = &hantro_ctrl_ops, }, }, { .codec = HANTRO_H264_DECODER, .cfg = { - .id = V4L2_CID_MPEG_VIDEO_H264_PPS, + .id = V4L2_CID_STATELESS_H264_PPS, }, }, { .codec = HANTRO_H264_DECODER, .cfg = { - .id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX, + .id = V4L2_CID_STATELESS_H264_SCALING_MATRIX, }, }, { .codec = HANTRO_H264_DECODER, .cfg = { - .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE, - .min = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED, - .def = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED, - .max = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED, + .id = V4L2_CID_STATELESS_H264_DECODE_MODE, + .min = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, + .def = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, + .max = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, }, }, { .codec = HANTRO_H264_DECODER, .cfg = { - .id = V4L2_CID_MPEG_VIDEO_H264_START_CODE, - .min = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B, - .def = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B, - .max = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B, + .id = V4L2_CID_STATELESS_H264_START_CODE, + .min = V4L2_STATELESS_H264_START_CODE_ANNEX_B, + .def = V4L2_STATELESS_H264_START_CODE_ANNEX_B, + .max = V4L2_STATELESS_H264_START_CODE_ANNEX_B, }, }, { .codec = HANTRO_H264_DECODER, diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c index b1bdc00ac262..ed6eaf11d96f 100644 --- a/drivers/staging/media/hantro/hantro_h264.c +++ b/drivers/staging/media/hantro/hantro_h264.c @@ -344,22 +344,22 @@ int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx) hantro_start_prepare_run(ctx); ctrls->scaling = - hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX); + hantro_get_ctrl(ctx, V4L2_CID_STATELESS_H264_SCALING_MATRIX); if (WARN_ON(!ctrls->scaling)) return -EINVAL; ctrls->decode = - hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS); + hantro_get_ctrl(ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS); if (WARN_ON(!ctrls->decode)) return -EINVAL; ctrls->sps = - hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_H264_SPS); + hantro_get_ctrl(ctx, V4L2_CID_STATELESS_H264_SPS); if (WARN_ON(!ctrls->sps)) return -EINVAL; ctrls->pps = - hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_H264_PPS); + hantro_get_ctrl(ctx, V4L2_CID_STATELESS_H264_PPS); if (WARN_ON(!ctrls->pps)) return -EINVAL; diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c index 7cc3b478a5f4..76e97cbe2512 100644 --- a/drivers/staging/media/rkvdec/rkvdec-h264.c +++ b/drivers/staging/media/rkvdec/rkvdec-h264.c @@ -1067,16 +1067,16 @@ static void rkvdec_h264_run_preamble(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl; ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, - V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS); + V4L2_CID_STATELESS_H264_DECODE_PARAMS); run->decode_params = ctrl ? ctrl->p_cur.p : NULL; ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, - V4L2_CID_MPEG_VIDEO_H264_SPS); + V4L2_CID_STATELESS_H264_SPS); run->sps = ctrl ? ctrl->p_cur.p : NULL; ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, - V4L2_CID_MPEG_VIDEO_H264_PPS); + V4L2_CID_STATELESS_H264_PPS); run->pps = ctrl ? ctrl->p_cur.p : NULL; ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, - V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX); + V4L2_CID_STATELESS_H264_SCALING_MATRIX); run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL; rkvdec_run_preamble(ctx, &run->base); diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c index fe65f55d3b49..aa4f8c287618 100644 --- a/drivers/staging/media/rkvdec/rkvdec.c +++ b/drivers/staging/media/rkvdec/rkvdec.c @@ -29,7 +29,7 @@ static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl) { - if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_SPS) { + if (ctrl->id == V4L2_CID_STATELESS_H264_SPS) { const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps; /* * TODO: The hardware supports 10-bit and 4:2:2 profiles, @@ -56,31 +56,31 @@ static const struct v4l2_ctrl_ops rkvdec_ctrl_ops = { static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = { { .mandatory = true, - .cfg.id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS, + .cfg.id = V4L2_CID_STATELESS_H264_DECODE_PARAMS, }, { .mandatory = true, - .cfg.id = V4L2_CID_MPEG_VIDEO_H264_SPS, + .cfg.id = V4L2_CID_STATELESS_H264_SPS, .cfg.ops = &rkvdec_ctrl_ops, }, { .mandatory = true, - .cfg.id = V4L2_CID_MPEG_VIDEO_H264_PPS, + .cfg.id = V4L2_CID_STATELESS_H264_PPS, }, { - .cfg.id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX, + .cfg.id = V4L2_CID_STATELESS_H264_SCALING_MATRIX, }, { - .cfg.id = V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE, - .cfg.min = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED, - .cfg.max = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED, - .cfg.def = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED, + .cfg.id = V4L2_CID_STATELESS_H264_DECODE_MODE, + .cfg.min = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, + .cfg.max = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, + .cfg.def = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, }, { - .cfg.id = V4L2_CID_MPEG_VIDEO_H264_START_CODE, - .cfg.min = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B, - .cfg.def = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B, - .cfg.max = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B, + .cfg.id = V4L2_CID_STATELESS_H264_START_CODE, + .cfg.min = V4L2_STATELESS_H264_START_CODE_ANNEX_B, + .cfg.def = V4L2_STATELESS_H264_START_CODE_ANNEX_B, + .cfg.max = V4L2_STATELESS_H264_START_CODE_ANNEX_B, }, { .cfg.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index 68548424985d..b1fc6b672a9b 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -45,60 +45,60 @@ static const struct cedrus_control cedrus_controls[] = { }, { .cfg = { - .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS, + .id = V4L2_CID_STATELESS_H264_DECODE_PARAMS, }, .codec = CEDRUS_CODEC_H264, .required = true, }, { .cfg = { - .id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS, + .id = V4L2_CID_STATELESS_H264_SLICE_PARAMS, }, .codec = CEDRUS_CODEC_H264, .required = true, }, { .cfg = { - .id = V4L2_CID_MPEG_VIDEO_H264_SPS, + .id = V4L2_CID_STATELESS_H264_SPS, }, .codec = CEDRUS_CODEC_H264, .required = true, }, { .cfg = { - .id = V4L2_CID_MPEG_VIDEO_H264_PPS, + .id = V4L2_CID_STATELESS_H264_PPS, }, .codec = CEDRUS_CODEC_H264, .required = true, }, { .cfg = { - .id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX, + .id = V4L2_CID_STATELESS_H264_SCALING_MATRIX, }, .codec = CEDRUS_CODEC_H264, .required = false, }, { .cfg = { - .id = V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS, + .id = V4L2_CID_STATELESS_H264_PRED_WEIGHTS, }, .codec = CEDRUS_CODEC_H264, .required = false, }, { .cfg = { - .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE, - .max = V4L2_MPEG_VIDEO_H264_DECODE_MODE_SLICE_BASED, - .def = V4L2_MPEG_VIDEO_H264_DECODE_MODE_SLICE_BASED, + .id = V4L2_CID_STATELESS_H264_DECODE_MODE, + .max = V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED, + .def = V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED, }, .codec = CEDRUS_CODEC_H264, .required = false, }, { .cfg = { - .id = V4L2_CID_MPEG_VIDEO_H264_START_CODE, - .max = V4L2_MPEG_VIDEO_H264_START_CODE_NONE, - .def = V4L2_MPEG_VIDEO_H264_START_CODE_NONE, + .id = V4L2_CID_STATELESS_H264_START_CODE, + .max = V4L2_STATELESS_H264_START_CODE_NONE, + .def = V4L2_STATELESS_H264_START_CODE_NONE, }, .codec = CEDRUS_CODEC_H264, .required = false, diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c index 1810fb6cc8da..a9090daf626a 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c @@ -48,17 +48,17 @@ void cedrus_device_run(void *priv) case V4L2_PIX_FMT_H264_SLICE: run.h264.decode_params = cedrus_find_control_data(ctx, - V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS); + V4L2_CID_STATELESS_H264_DECODE_PARAMS); run.h264.pps = cedrus_find_control_data(ctx, - V4L2_CID_MPEG_VIDEO_H264_PPS); + V4L2_CID_STATELESS_H264_PPS); run.h264.scaling_matrix = cedrus_find_control_data(ctx, - V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX); + V4L2_CID_STATELESS_H264_SCALING_MATRIX); run.h264.slice_params = cedrus_find_control_data(ctx, - V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS); + V4L2_CID_STATELESS_H264_SLICE_PARAMS); run.h264.sps = cedrus_find_control_data(ctx, - V4L2_CID_MPEG_VIDEO_H264_SPS); + V4L2_CID_STATELESS_H264_SPS); run.h264.pred_weights = cedrus_find_control_data(ctx, - V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS); + V4L2_CID_STATELESS_H264_PRED_WEIGHTS); break; case V4L2_PIX_FMT_HEVC_SLICE: diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h deleted file mode 100644 index c15fed956bf5..000000000000 --- a/include/media/h264-ctrls.h +++ /dev/null @@ -1,404 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * These are the H.264 state controls for use with stateless H.264 - * codec drivers. - * - * It turns out that these structs are not stable yet and will undergo - * more changes. So keep them private until they are stable and ready to - * become part of the official public API. - */ - -#ifndef _H264_CTRLS_H_ -#define _H264_CTRLS_H_ - -#include - -/* - * Maximum DPB size, as specified by section 'A.3.1 Level limits - * common to the Baseline, Main, and Extended profiles'. - */ -#define V4L2_H264_NUM_DPB_ENTRIES 16 - -#define V4L2_H264_REF_LIST_LEN (2 * V4L2_H264_NUM_DPB_ENTRIES) - -/* - * This is put insanely high to avoid conflicting with controls that - * would be added during the phase where those controls are not - * stable. It should be fixed eventually. - */ -#define V4L2_CID_MPEG_VIDEO_H264_SPS (V4L2_CID_CODEC_BASE+1000) -#define V4L2_CID_MPEG_VIDEO_H264_PPS (V4L2_CID_CODEC_BASE+1001) -#define V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX (V4L2_CID_CODEC_BASE+1002) -#define V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS (V4L2_CID_CODEC_BASE+1003) -#define V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS (V4L2_CID_CODEC_BASE+1004) -#define V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE (V4L2_CID_CODEC_BASE+1005) -#define V4L2_CID_MPEG_VIDEO_H264_START_CODE (V4L2_CID_CODEC_BASE+1006) -#define V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS (V4L2_CID_CODEC_BASE+1007) - -/** - * enum v4l2_mpeg_video_h264_decode_mode - Decoding mode - * - * @V4L2_MPEG_VIDEO_H264_DECODE_MODE_SLICE_BASED: indicates that decoding - * is performed one slice at a time. In this mode, - * V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS must contain the parsed slice - * parameters and the OUTPUT buffer must contain a single slice. - * V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF feature is used - * in order to support multislice frames. - * @V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED: indicates that - * decoding is performed per frame. The OUTPUT buffer must contain - * all slices and also both fields. This mode is typically supported - * by device drivers that are able to parse the slice(s) header(s) - * in hardware. When this mode is selected, - * V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS is not used. - */ -enum v4l2_mpeg_video_h264_decode_mode { - V4L2_MPEG_VIDEO_H264_DECODE_MODE_SLICE_BASED, - V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED, -}; - -/** - * enum v4l2_mpeg_video_h264_start_code - Start code - * - * @V4L2_MPEG_VIDEO_H264_START_CODE_NONE: slices are passed - * to the driver without any start code. - * @V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B: slices are passed - * to the driver with an Annex B start code prefix - * (legal start codes can be 3-bytes 0x000001 or 4-bytes 0x00000001). - * This mode is typically supported by device drivers that parse - * the start code in hardware. - */ -enum v4l2_mpeg_video_h264_start_code { - V4L2_MPEG_VIDEO_H264_START_CODE_NONE, - V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B, -}; - -#define V4L2_H264_SPS_CONSTRAINT_SET0_FLAG 0x01 -#define V4L2_H264_SPS_CONSTRAINT_SET1_FLAG 0x02 -#define V4L2_H264_SPS_CONSTRAINT_SET2_FLAG 0x04 -#define V4L2_H264_SPS_CONSTRAINT_SET3_FLAG 0x08 -#define V4L2_H264_SPS_CONSTRAINT_SET4_FLAG 0x10 -#define V4L2_H264_SPS_CONSTRAINT_SET5_FLAG 0x20 - -#define V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE 0x01 -#define V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS 0x02 -#define V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO 0x04 -#define V4L2_H264_SPS_FLAG_GAPS_IN_FRAME_NUM_VALUE_ALLOWED 0x08 -#define V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY 0x10 -#define V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD 0x20 -#define V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE 0x40 - -#define V4L2_H264_SPS_HAS_CHROMA_FORMAT(sps) \ - ((sps)->profile_idc == 100 || (sps)->profile_idc == 110 || \ - (sps)->profile_idc == 122 || (sps)->profile_idc == 244 || \ - (sps)->profile_idc == 44 || (sps)->profile_idc == 83 || \ - (sps)->profile_idc == 86 || (sps)->profile_idc == 118 || \ - (sps)->profile_idc == 128 || (sps)->profile_idc == 138 || \ - (sps)->profile_idc == 139 || (sps)->profile_idc == 134 || \ - (sps)->profile_idc == 135) - -/** - * struct v4l2_ctrl_h264_sps - H264 sequence parameter set - * - * All the members on this sequence parameter set structure match the - * sequence parameter set syntax as specified by the H264 specification. - * - * @profile_idc: see H264 specification. - * @constraint_set_flags: see H264 specification. - * @level_idc: see H264 specification. - * @seq_parameter_set_id: see H264 specification. - * @chroma_format_idc: see H264 specification. - * @bit_depth_luma_minus8: see H264 specification. - * @bit_depth_chroma_minus8: see H264 specification. - * @log2_max_frame_num_minus4: see H264 specification. - * @pic_order_cnt_type: see H264 specification. - * @log2_max_pic_order_cnt_lsb_minus4: see H264 specification. - * @max_num_ref_frames: see H264 specification. - * @num_ref_frames_in_pic_order_cnt_cycle: see H264 specification. - * @offset_for_ref_frame: see H264 specification. - * @offset_for_non_ref_pic: see H264 specification. - * @offset_for_top_to_bottom_field: see H264 specification. - * @pic_width_in_mbs_minus1: see H264 specification. - * @pic_height_in_map_units_minus1: see H264 specification. - * @flags: see V4L2_H264_SPS_FLAG_{}. - */ -struct v4l2_ctrl_h264_sps { - __u8 profile_idc; - __u8 constraint_set_flags; - __u8 level_idc; - __u8 seq_parameter_set_id; - __u8 chroma_format_idc; - __u8 bit_depth_luma_minus8; - __u8 bit_depth_chroma_minus8; - __u8 log2_max_frame_num_minus4; - __u8 pic_order_cnt_type; - __u8 log2_max_pic_order_cnt_lsb_minus4; - __u8 max_num_ref_frames; - __u8 num_ref_frames_in_pic_order_cnt_cycle; - __s32 offset_for_ref_frame[255]; - __s32 offset_for_non_ref_pic; - __s32 offset_for_top_to_bottom_field; - __u16 pic_width_in_mbs_minus1; - __u16 pic_height_in_map_units_minus1; - __u32 flags; -}; - -#define V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE 0x0001 -#define V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT 0x0002 -#define V4L2_H264_PPS_FLAG_WEIGHTED_PRED 0x0004 -#define V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT 0x0008 -#define V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED 0x0010 -#define V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT 0x0020 -#define V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE 0x0040 -#define V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT 0x0080 - -/** - * struct v4l2_ctrl_h264_pps - H264 picture parameter set - * - * Except where noted, all the members on this picture parameter set - * structure match the sequence parameter set syntax as specified - * by the H264 specification. - * - * In particular, V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT flag - * has a specific meaning. This flag should be set if a non-flat - * scaling matrix applies to the picture. In this case, applications - * are expected to use V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX, - * to pass the values of the non-flat matrices. - * - * @pic_parameter_set_id: see H264 specification. - * @seq_parameter_set_id: see H264 specification. - * @num_slice_groups_minus1: see H264 specification. - * @num_ref_idx_l0_default_active_minus1: see H264 specification. - * @num_ref_idx_l1_default_active_minus1: see H264 specification. - * @weighted_bipred_idc: see H264 specification. - * @pic_init_qp_minus26: see H264 specification. - * @pic_init_qs_minus26: see H264 specification. - * @chroma_qp_index_offset: see H264 specification. - * @second_chroma_qp_index_offset: see H264 specification. - * @flags: see V4L2_H264_PPS_FLAG_{}. - */ -struct v4l2_ctrl_h264_pps { - __u8 pic_parameter_set_id; - __u8 seq_parameter_set_id; - __u8 num_slice_groups_minus1; - __u8 num_ref_idx_l0_default_active_minus1; - __u8 num_ref_idx_l1_default_active_minus1; - __u8 weighted_bipred_idc; - __s8 pic_init_qp_minus26; - __s8 pic_init_qs_minus26; - __s8 chroma_qp_index_offset; - __s8 second_chroma_qp_index_offset; - __u16 flags; -}; - -/** - * struct v4l2_ctrl_h264_scaling_matrix - H264 scaling matrices - * - * @scaling_list_4x4: scaling matrix after applying the inverse - * scanning process. Expected list order is Intra Y, Intra Cb, - * Intra Cr, Inter Y, Inter Cb, Inter Cr. The values on each - * scaling list are expected in raster scan order. - * @scaling_list_8x8: scaling matrix after applying the inverse - * scanning process. Expected list order is Intra Y, Inter Y, - * Intra Cb, Inter Cb, Intra Cr, Inter Cr. The values on each - * scaling list are expected in raster scan order. - * - * Note that the list order is different for the 4x4 and 8x8 - * matrices as per the H264 specification, see table 7-2 "Assignment - * of mnemonic names to scaling list indices and specification of - * fall-back rule". - */ -struct v4l2_ctrl_h264_scaling_matrix { - __u8 scaling_list_4x4[6][16]; - __u8 scaling_list_8x8[6][64]; -}; - -struct v4l2_h264_weight_factors { - __s16 luma_weight[32]; - __s16 luma_offset[32]; - __s16 chroma_weight[32][2]; - __s16 chroma_offset[32][2]; -}; - -#define V4L2_H264_CTRL_PRED_WEIGHTS_REQUIRED(pps, slice) \ - ((((pps)->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED) && \ - ((slice)->slice_type == V4L2_H264_SLICE_TYPE_P || \ - (slice)->slice_type == V4L2_H264_SLICE_TYPE_SP)) || \ - ((pps)->weighted_bipred_idc == 1 && \ - (slice)->slice_type == V4L2_H264_SLICE_TYPE_B)) - -/** - * struct v4l2_ctrl_h264_pred_weights - Prediction weight table - * - * Prediction weight table, which matches the syntax specified - * by the H264 specification. - * - * @luma_log2_weight_denom: see H264 specification. - * @chroma_log2_weight_denom: see H264 specification. - * @weight_factors: luma and chroma weight factors. - */ -struct v4l2_ctrl_h264_pred_weights { - __u16 luma_log2_weight_denom; - __u16 chroma_log2_weight_denom; - struct v4l2_h264_weight_factors weight_factors[2]; -}; - -#define V4L2_H264_SLICE_TYPE_P 0 -#define V4L2_H264_SLICE_TYPE_B 1 -#define V4L2_H264_SLICE_TYPE_I 2 -#define V4L2_H264_SLICE_TYPE_SP 3 -#define V4L2_H264_SLICE_TYPE_SI 4 - -#define V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED 0x01 -#define V4L2_H264_SLICE_FLAG_SP_FOR_SWITCH 0x02 - -#define V4L2_H264_TOP_FIELD_REF 0x1 -#define V4L2_H264_BOTTOM_FIELD_REF 0x2 -#define V4L2_H264_FRAME_REF 0x3 - -/** - * struct v4l2_h264_reference - H264 picture reference - * - * @fields: indicates how the picture is referenced. - * Valid values are V4L2_H264_{}_REF. - * @index: index into v4l2_ctrl_h264_decode_params.dpb[]. - */ -struct v4l2_h264_reference { - __u8 fields; - __u8 index; -}; - -/** - * struct v4l2_ctrl_h264_slice_params - H264 slice parameters - * - * This structure holds the H264 syntax elements that are specified - * as non-invariant for the slices in a given frame. - * - * Slice invariant syntax elements are contained in struct - * v4l2_ctrl_h264_decode_params. This is done to reduce the API surface - * on frame-based decoders, where slice header parsing is done by the - * hardware. - * - * Slice invariant syntax elements are specified in specification section - * "7.4.3 Slice header semantics". - * - * Except where noted, the members on this struct match the slice header syntax. - * - * @header_bit_size: offset in bits to slice_data() from the beginning of this slice. - * @first_mb_in_slice: see H264 specification. - * @slice_type: see H264 specification. - * @colour_plane_id: see H264 specification. - * @redundant_pic_cnt: see H264 specification. - * @cabac_init_idc: see H264 specification. - * @slice_qp_delta: see H264 specification. - * @slice_qs_delta: see H264 specification. - * @disable_deblocking_filter_idc: see H264 specification. - * @slice_alpha_c0_offset_div2: see H264 specification. - * @slice_beta_offset_div2: see H264 specification. - * @num_ref_idx_l0_active_minus1: see H264 specification. - * @num_ref_idx_l1_active_minus1: see H264 specification. - * @reserved: padding field. Should be zeroed by applications. - * @ref_pic_list0: reference picture list 0 after applying the per-slice modifications. - * @ref_pic_list1: reference picture list 1 after applying the per-slice modifications. - * @flags: see V4L2_H264_SLICE_FLAG_{}. - */ -struct v4l2_ctrl_h264_slice_params { - __u32 header_bit_size; - __u32 first_mb_in_slice; - __u8 slice_type; - __u8 colour_plane_id; - __u8 redundant_pic_cnt; - __u8 cabac_init_idc; - __s8 slice_qp_delta; - __s8 slice_qs_delta; - __u8 disable_deblocking_filter_idc; - __s8 slice_alpha_c0_offset_div2; - __s8 slice_beta_offset_div2; - __u8 num_ref_idx_l0_active_minus1; - __u8 num_ref_idx_l1_active_minus1; - - __u8 reserved; - - struct v4l2_h264_reference ref_pic_list0[V4L2_H264_REF_LIST_LEN]; - struct v4l2_h264_reference ref_pic_list1[V4L2_H264_REF_LIST_LEN]; - - __u32 flags; -}; - -#define V4L2_H264_DPB_ENTRY_FLAG_VALID 0x01 -#define V4L2_H264_DPB_ENTRY_FLAG_ACTIVE 0x02 -#define V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM 0x04 -#define V4L2_H264_DPB_ENTRY_FLAG_FIELD 0x08 - -/** - * struct v4l2_h264_dpb_entry - H264 decoded picture buffer entry - * - * @reference_ts: timestamp of the V4L2 capture buffer to use as reference. - * The timestamp refers to the timestamp field in struct v4l2_buffer. - * Use v4l2_timeval_to_ns() to convert the struct timeval to a __u64. - * @pic_num: matches PicNum variable assigned during the reference - * picture lists construction process. - * @frame_num: frame identifier which matches frame_num syntax element. - * @fields: indicates how the DPB entry is referenced. Valid values are - * V4L2_H264_{}_REF. - * @reserved: padding field. Should be zeroed by applications. - * @top_field_order_cnt: matches TopFieldOrderCnt picture value. - * @bottom_field_order_cnt: matches BottomFieldOrderCnt picture value. - * Note that picture field is indicated by v4l2_buffer.field. - * @flags: see V4L2_H264_DPB_ENTRY_FLAG_{}. - */ -struct v4l2_h264_dpb_entry { - __u64 reference_ts; - __u32 pic_num; - __u16 frame_num; - __u8 fields; - __u8 reserved[5]; - __s32 top_field_order_cnt; - __s32 bottom_field_order_cnt; - __u32 flags; -}; - -#define V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC 0x01 -#define V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC 0x02 -#define V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD 0x04 - -/** - * struct v4l2_ctrl_h264_decode_params - H264 decoding parameters - * - * @dpb: decoded picture buffer. - * @nal_ref_idc: slice header syntax element. - * @frame_num: slice header syntax element. - * @top_field_order_cnt: matches TopFieldOrderCnt picture value. - * @bottom_field_order_cnt: matches BottomFieldOrderCnt picture value. - * Note that picture field is indicated by v4l2_buffer.field. - * @idr_pic_id: slice header syntax element. - * @pic_order_cnt_lsb: slice header syntax element. - * @delta_pic_order_cnt_bottom: slice header syntax element. - * @delta_pic_order_cnt0: slice header syntax element. - * @delta_pic_order_cnt1: slice header syntax element. - * @dec_ref_pic_marking_bit_size: size in bits of dec_ref_pic_marking() - * syntax element. - * @pic_order_cnt_bit_size: size in bits of pic order count syntax. - * @slice_group_change_cycle: slice header syntax element. - * @reserved: padding field. Should be zeroed by applications. - * @flags: see V4L2_H264_DECODE_PARAM_FLAG_{}. - */ -struct v4l2_ctrl_h264_decode_params { - struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]; - __u16 nal_ref_idc; - __u16 frame_num; - __s32 top_field_order_cnt; - __s32 bottom_field_order_cnt; - __u16 idr_pic_id; - __u16 pic_order_cnt_lsb; - __s32 delta_pic_order_cnt_bottom; - __s32 delta_pic_order_cnt0; - __s32 delta_pic_order_cnt1; - __u32 dec_ref_pic_marking_bit_size; - __u32 pic_order_cnt_bit_size; - __u32 slice_group_change_cycle; - - __u32 reserved; - __u32 flags; -}; - -#endif diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index 4fbace0fc7e5..d25b38f78229 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -19,7 +19,6 @@ */ #include #include -#include #include #include diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 90478ecc2f81..3f24663fba4a 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -1183,6 +1183,387 @@ enum v4l2_detect_md_mode { #define V4L2_CID_CODEC_STATELESS_BASE (V4L2_CTRL_CLASS_CODEC_STATELESS | 0x900) #define V4L2_CID_CODEC_STATELESS_CLASS (V4L2_CTRL_CLASS_CODEC_STATELESS | 1) +#define V4L2_CID_STATELESS_H264_DECODE_MODE (V4L2_CID_CODEC_STATELESS_BASE + 0) +/** + * enum v4l2_stateless_h264_decode_mode - Decoding mode + * + * @V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED: indicates that decoding + * is performed one slice at a time. In this mode, + * V4L2_CID_STATELESS_H264_SLICE_PARAMS must contain the parsed slice + * parameters and the OUTPUT buffer must contain a single slice. + * V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF feature is used + * in order to support multislice frames. + * @V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED: indicates that + * decoding is performed per frame. The OUTPUT buffer must contain + * all slices and also both fields. This mode is typically supported + * by device drivers that are able to parse the slice(s) header(s) + * in hardware. When this mode is selected, + * V4L2_CID_STATELESS_H264_SLICE_PARAMS is not used. + */ +enum v4l2_stateless_h264_decode_mode { + V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED, + V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, +}; + +#define V4L2_CID_STATELESS_H264_START_CODE (V4L2_CID_CODEC_STATELESS_BASE + 1) +/** + * enum v4l2_stateless_h264_start_code - Start code + * + * @V4L2_STATELESS_H264_START_CODE_NONE: slices are passed + * to the driver without any start code. + * @V4L2_STATELESS_H264_START_CODE_ANNEX_B: slices are passed + * to the driver with an Annex B start code prefix + * (legal start codes can be 3-bytes 0x000001 or 4-bytes 0x00000001). + * This mode is typically supported by device drivers that parse + * the start code in hardware. + */ +enum v4l2_stateless_h264_start_code { + V4L2_STATELESS_H264_START_CODE_NONE, + V4L2_STATELESS_H264_START_CODE_ANNEX_B, +}; + +#define V4L2_H264_SPS_CONSTRAINT_SET0_FLAG 0x01 +#define V4L2_H264_SPS_CONSTRAINT_SET1_FLAG 0x02 +#define V4L2_H264_SPS_CONSTRAINT_SET2_FLAG 0x04 +#define V4L2_H264_SPS_CONSTRAINT_SET3_FLAG 0x08 +#define V4L2_H264_SPS_CONSTRAINT_SET4_FLAG 0x10 +#define V4L2_H264_SPS_CONSTRAINT_SET5_FLAG 0x20 + +#define V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE 0x01 +#define V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS 0x02 +#define V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO 0x04 +#define V4L2_H264_SPS_FLAG_GAPS_IN_FRAME_NUM_VALUE_ALLOWED 0x08 +#define V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY 0x10 +#define V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD 0x20 +#define V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE 0x40 + +#define V4L2_H264_SPS_HAS_CHROMA_FORMAT(sps) \ + ((sps)->profile_idc == 100 || (sps)->profile_idc == 110 || \ + (sps)->profile_idc == 122 || (sps)->profile_idc == 244 || \ + (sps)->profile_idc == 44 || (sps)->profile_idc == 83 || \ + (sps)->profile_idc == 86 || (sps)->profile_idc == 118 || \ + (sps)->profile_idc == 128 || (sps)->profile_idc == 138 || \ + (sps)->profile_idc == 139 || (sps)->profile_idc == 134 || \ + (sps)->profile_idc == 135) + +#define V4L2_CID_STATELESS_H264_SPS (V4L2_CID_CODEC_STATELESS_BASE + 2) +/** + * struct v4l2_ctrl_h264_sps - H264 sequence parameter set + * + * All the members on this sequence parameter set structure match the + * sequence parameter set syntax as specified by the H264 specification. + * + * @profile_idc: see H264 specification. + * @constraint_set_flags: see H264 specification. + * @level_idc: see H264 specification. + * @seq_parameter_set_id: see H264 specification. + * @chroma_format_idc: see H264 specification. + * @bit_depth_luma_minus8: see H264 specification. + * @bit_depth_chroma_minus8: see H264 specification. + * @log2_max_frame_num_minus4: see H264 specification. + * @pic_order_cnt_type: see H264 specification. + * @log2_max_pic_order_cnt_lsb_minus4: see H264 specification. + * @max_num_ref_frames: see H264 specification. + * @num_ref_frames_in_pic_order_cnt_cycle: see H264 specification. + * @offset_for_ref_frame: see H264 specification. + * @offset_for_non_ref_pic: see H264 specification. + * @offset_for_top_to_bottom_field: see H264 specification. + * @pic_width_in_mbs_minus1: see H264 specification. + * @pic_height_in_map_units_minus1: see H264 specification. + * @flags: see V4L2_H264_SPS_FLAG_{}. + */ +struct v4l2_ctrl_h264_sps { + __u8 profile_idc; + __u8 constraint_set_flags; + __u8 level_idc; + __u8 seq_parameter_set_id; + __u8 chroma_format_idc; + __u8 bit_depth_luma_minus8; + __u8 bit_depth_chroma_minus8; + __u8 log2_max_frame_num_minus4; + __u8 pic_order_cnt_type; + __u8 log2_max_pic_order_cnt_lsb_minus4; + __u8 max_num_ref_frames; + __u8 num_ref_frames_in_pic_order_cnt_cycle; + __s32 offset_for_ref_frame[255]; + __s32 offset_for_non_ref_pic; + __s32 offset_for_top_to_bottom_field; + __u16 pic_width_in_mbs_minus1; + __u16 pic_height_in_map_units_minus1; + __u32 flags; +}; + +#define V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE 0x0001 +#define V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT 0x0002 +#define V4L2_H264_PPS_FLAG_WEIGHTED_PRED 0x0004 +#define V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT 0x0008 +#define V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED 0x0010 +#define V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT 0x0020 +#define V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE 0x0040 +#define V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT 0x0080 + +#define V4L2_CID_STATELESS_H264_PPS (V4L2_CID_CODEC_STATELESS_BASE + 3) +/** + * struct v4l2_ctrl_h264_pps - H264 picture parameter set + * + * Except where noted, all the members on this picture parameter set + * structure match the sequence parameter set syntax as specified + * by the H264 specification. + * + * In particular, V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT flag + * has a specific meaning. This flag should be set if a non-flat + * scaling matrix applies to the picture. In this case, applications + * are expected to use V4L2_CID_STATELESS_H264_SCALING_MATRIX, + * to pass the values of the non-flat matrices. + * + * @pic_parameter_set_id: see H264 specification. + * @seq_parameter_set_id: see H264 specification. + * @num_slice_groups_minus1: see H264 specification. + * @num_ref_idx_l0_default_active_minus1: see H264 specification. + * @num_ref_idx_l1_default_active_minus1: see H264 specification. + * @weighted_bipred_idc: see H264 specification. + * @pic_init_qp_minus26: see H264 specification. + * @pic_init_qs_minus26: see H264 specification. + * @chroma_qp_index_offset: see H264 specification. + * @second_chroma_qp_index_offset: see H264 specification. + * @flags: see V4L2_H264_PPS_FLAG_{}. + */ +struct v4l2_ctrl_h264_pps { + __u8 pic_parameter_set_id; + __u8 seq_parameter_set_id; + __u8 num_slice_groups_minus1; + __u8 num_ref_idx_l0_default_active_minus1; + __u8 num_ref_idx_l1_default_active_minus1; + __u8 weighted_bipred_idc; + __s8 pic_init_qp_minus26; + __s8 pic_init_qs_minus26; + __s8 chroma_qp_index_offset; + __s8 second_chroma_qp_index_offset; + __u16 flags; +}; + +#define V4L2_CID_STATELESS_H264_SCALING_MATRIX (V4L2_CID_CODEC_STATELESS_BASE + 4) +/** + * struct v4l2_ctrl_h264_scaling_matrix - H264 scaling matrices + * + * @scaling_list_4x4: scaling matrix after applying the inverse + * scanning process. Expected list order is Intra Y, Intra Cb, + * Intra Cr, Inter Y, Inter Cb, Inter Cr. The values on each + * scaling list are expected in raster scan order. + * @scaling_list_8x8: scaling matrix after applying the inverse + * scanning process. Expected list order is Intra Y, Inter Y, + * Intra Cb, Inter Cb, Intra Cr, Inter Cr. The values on each + * scaling list are expected in raster scan order. + * + * Note that the list order is different for the 4x4 and 8x8 + * matrices as per the H264 specification, see table 7-2 "Assignment + * of mnemonic names to scaling list indices and specification of + * fall-back rule". + */ +struct v4l2_ctrl_h264_scaling_matrix { + __u8 scaling_list_4x4[6][16]; + __u8 scaling_list_8x8[6][64]; +}; + +struct v4l2_h264_weight_factors { + __s16 luma_weight[32]; + __s16 luma_offset[32]; + __s16 chroma_weight[32][2]; + __s16 chroma_offset[32][2]; +}; + +#define V4L2_H264_CTRL_PRED_WEIGHTS_REQUIRED(pps, slice) \ + ((((pps)->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED) && \ + ((slice)->slice_type == V4L2_H264_SLICE_TYPE_P || \ + (slice)->slice_type == V4L2_H264_SLICE_TYPE_SP)) || \ + ((pps)->weighted_bipred_idc == 1 && \ + (slice)->slice_type == V4L2_H264_SLICE_TYPE_B)) + +#define V4L2_CID_STATELESS_H264_PRED_WEIGHTS (V4L2_CID_CODEC_STATELESS_BASE + 5) +/** + * struct v4l2_ctrl_h264_pred_weights - Prediction weight table + * + * Prediction weight table, which matches the syntax specified + * by the H264 specification. + * + * @luma_log2_weight_denom: see H264 specification. + * @chroma_log2_weight_denom: see H264 specification. + * @weight_factors: luma and chroma weight factors. + */ +struct v4l2_ctrl_h264_pred_weights { + __u16 luma_log2_weight_denom; + __u16 chroma_log2_weight_denom; + struct v4l2_h264_weight_factors weight_factors[2]; +}; + +#define V4L2_H264_SLICE_TYPE_P 0 +#define V4L2_H264_SLICE_TYPE_B 1 +#define V4L2_H264_SLICE_TYPE_I 2 +#define V4L2_H264_SLICE_TYPE_SP 3 +#define V4L2_H264_SLICE_TYPE_SI 4 + +#define V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED 0x01 +#define V4L2_H264_SLICE_FLAG_SP_FOR_SWITCH 0x02 + +#define V4L2_H264_TOP_FIELD_REF 0x1 +#define V4L2_H264_BOTTOM_FIELD_REF 0x2 +#define V4L2_H264_FRAME_REF 0x3 + +/** + * struct v4l2_h264_reference - H264 picture reference + * + * @fields: indicates how the picture is referenced. + * Valid values are V4L2_H264_{}_REF. + * @index: index into v4l2_ctrl_h264_decode_params.dpb[]. + */ +struct v4l2_h264_reference { + __u8 fields; + __u8 index; +}; + +/* + * Maximum DPB size, as specified by section 'A.3.1 Level limits + * common to the Baseline, Main, and Extended profiles'. + */ +#define V4L2_H264_NUM_DPB_ENTRIES 16 +#define V4L2_H264_REF_LIST_LEN (2 * V4L2_H264_NUM_DPB_ENTRIES) + +#define V4L2_CID_STATELESS_H264_SLICE_PARAMS (V4L2_CID_CODEC_STATELESS_BASE + 6) +/** + * struct v4l2_ctrl_h264_slice_params - H264 slice parameters + * + * This structure holds the H264 syntax elements that are specified + * as non-invariant for the slices in a given frame. + * + * Slice invariant syntax elements are contained in struct + * v4l2_ctrl_h264_decode_params. This is done to reduce the API surface + * on frame-based decoders, where slice header parsing is done by the + * hardware. + * + * Slice invariant syntax elements are specified in specification section + * "7.4.3 Slice header semantics". + * + * Except where noted, the members on this struct match the slice header syntax. + * + * @header_bit_size: offset in bits to slice_data() from the beginning of this slice. + * @first_mb_in_slice: see H264 specification. + * @slice_type: see H264 specification. + * @colour_plane_id: see H264 specification. + * @redundant_pic_cnt: see H264 specification. + * @cabac_init_idc: see H264 specification. + * @slice_qp_delta: see H264 specification. + * @slice_qs_delta: see H264 specification. + * @disable_deblocking_filter_idc: see H264 specification. + * @slice_alpha_c0_offset_div2: see H264 specification. + * @slice_beta_offset_div2: see H264 specification. + * @num_ref_idx_l0_active_minus1: see H264 specification. + * @num_ref_idx_l1_active_minus1: see H264 specification. + * @reserved: padding field. Should be zeroed by applications. + * @ref_pic_list0: reference picture list 0 after applying the per-slice modifications. + * @ref_pic_list1: reference picture list 1 after applying the per-slice modifications. + * @flags: see V4L2_H264_SLICE_FLAG_{}. + */ +struct v4l2_ctrl_h264_slice_params { + __u32 header_bit_size; + __u32 first_mb_in_slice; + __u8 slice_type; + __u8 colour_plane_id; + __u8 redundant_pic_cnt; + __u8 cabac_init_idc; + __s8 slice_qp_delta; + __s8 slice_qs_delta; + __u8 disable_deblocking_filter_idc; + __s8 slice_alpha_c0_offset_div2; + __s8 slice_beta_offset_div2; + __u8 num_ref_idx_l0_active_minus1; + __u8 num_ref_idx_l1_active_minus1; + + __u8 reserved; + + struct v4l2_h264_reference ref_pic_list0[V4L2_H264_REF_LIST_LEN]; + struct v4l2_h264_reference ref_pic_list1[V4L2_H264_REF_LIST_LEN]; + + __u32 flags; +}; + +#define V4L2_H264_DPB_ENTRY_FLAG_VALID 0x01 +#define V4L2_H264_DPB_ENTRY_FLAG_ACTIVE 0x02 +#define V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM 0x04 +#define V4L2_H264_DPB_ENTRY_FLAG_FIELD 0x08 + +/** + * struct v4l2_h264_dpb_entry - H264 decoded picture buffer entry + * + * @reference_ts: timestamp of the V4L2 capture buffer to use as reference. + * The timestamp refers to the timestamp field in struct v4l2_buffer. + * Use v4l2_timeval_to_ns() to convert the struct timeval to a __u64. + * @pic_num: matches PicNum variable assigned during the reference + * picture lists construction process. + * @frame_num: frame identifier which matches frame_num syntax element. + * @fields: indicates how the DPB entry is referenced. Valid values are + * V4L2_H264_{}_REF. + * @reserved: padding field. Should be zeroed by applications. + * @top_field_order_cnt: matches TopFieldOrderCnt picture value. + * @bottom_field_order_cnt: matches BottomFieldOrderCnt picture value. + * Note that picture field is indicated by v4l2_buffer.field. + * @flags: see V4L2_H264_DPB_ENTRY_FLAG_{}. + */ +struct v4l2_h264_dpb_entry { + __u64 reference_ts; + __u32 pic_num; + __u16 frame_num; + __u8 fields; + __u8 reserved[5]; + __s32 top_field_order_cnt; + __s32 bottom_field_order_cnt; + __u32 flags; +}; + +#define V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC 0x01 +#define V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC 0x02 +#define V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD 0x04 + +#define V4L2_CID_STATELESS_H264_DECODE_PARAMS (V4L2_CID_CODEC_STATELESS_BASE + 7) +/** + * struct v4l2_ctrl_h264_decode_params - H264 decoding parameters + * + * @dpb: decoded picture buffer. + * @nal_ref_idc: slice header syntax element. + * @frame_num: slice header syntax element. + * @top_field_order_cnt: matches TopFieldOrderCnt picture value. + * @bottom_field_order_cnt: matches BottomFieldOrderCnt picture value. + * Note that picture field is indicated by v4l2_buffer.field. + * @idr_pic_id: slice header syntax element. + * @pic_order_cnt_lsb: slice header syntax element. + * @delta_pic_order_cnt_bottom: slice header syntax element. + * @delta_pic_order_cnt0: slice header syntax element. + * @delta_pic_order_cnt1: slice header syntax element. + * @dec_ref_pic_marking_bit_size: size in bits of dec_ref_pic_marking() + * syntax element. + * @pic_order_cnt_bit_size: size in bits of pic order count syntax. + * @slice_group_change_cycle: slice header syntax element. + * @reserved: padding field. Should be zeroed by applications. + * @flags: see V4L2_H264_DECODE_PARAM_FLAG_{}. + */ +struct v4l2_ctrl_h264_decode_params { + struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]; + __u16 nal_ref_idc; + __u16 frame_num; + __s32 top_field_order_cnt; + __s32 bottom_field_order_cnt; + __u16 idr_pic_id; + __u16 pic_order_cnt_lsb; + __s32 delta_pic_order_cnt_bottom; + __s32 delta_pic_order_cnt0; + __s32 delta_pic_order_cnt1; + __u32 dec_ref_pic_marking_bit_size; + __u32 pic_order_cnt_bit_size; + __u32 slice_group_change_cycle; + + __u32 reserved; + __u32 flags; +}; + /* MPEG-compression definitions kept for backwards compatibility */ #ifndef __KERNEL__ diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 485654fd2a7e..76231ca6e101 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1734,6 +1734,12 @@ struct v4l2_ext_control { __u16 __user *p_u16; __u32 __user *p_u32; struct v4l2_area __user *p_area; + struct v4l2_ctrl_h264_sps __user *p_h264_sps; + struct v4l2_ctrl_h264_pps *p_h264_pps; + struct v4l2_ctrl_h264_scaling_matrix __user *p_h264_scaling_matrix; + struct v4l2_ctrl_h264_pred_weights __user *p_h264_pred_weights; + struct v4l2_ctrl_h264_slice_params __user *p_h264_slice_params; + struct v4l2_ctrl_h264_decode_params __user *p_h264_decode_params; void __user *ptr; }; } __attribute__ ((packed)); -- cgit v1.2.3 From 81c6892d5b87a937968725426b1edb2fb5296ca8 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 26 Nov 2020 10:36:18 +0100 Subject: media: docs: Move the H264 stateless codec uAPI Now that we've destaged the H264 stateless codec controls, and with all the pieces in place, update the documentation and move it to its own section. Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/v4l/common.rst | 1 + .../media/v4l/ext-ctrls-codec-stateless.rst | 673 ++++++++++++++++++++ .../userspace-api/media/v4l/ext-ctrls-codec.rst | 692 --------------------- .../userspace-api/media/v4l/pixfmt-compressed.rst | 25 +- .../userspace-api/media/v4l/vidioc-g-ext-ctrls.rst | 24 + 5 files changed, 708 insertions(+), 707 deletions(-) create mode 100644 Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst diff --git a/Documentation/userspace-api/media/v4l/common.rst b/Documentation/userspace-api/media/v4l/common.rst index d84aeb703165..8c263c5a85d8 100644 --- a/Documentation/userspace-api/media/v4l/common.rst +++ b/Documentation/userspace-api/media/v4l/common.rst @@ -44,6 +44,7 @@ applicable to all devices. ext-ctrls-image-source ext-ctrls-image-process ext-ctrls-codec + ext-ctrls-codec-stateless ext-ctrls-jpeg ext-ctrls-dv ext-ctrls-rf-tuner diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst new file mode 100644 index 000000000000..12f3308fd2b3 --- /dev/null +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst @@ -0,0 +1,673 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later + +.. _codec-stateless-controls: + +********************************* +Stateless Codec Control Reference +********************************* + +The Stateless Codec control class is intended to support +stateless decoder and encoders (i.e. hardware accelerators). + +These drivers are typically supported by the :ref:`stateless_decoder`, +and deal with parsed pixel formats such as V4L2_PIX_FMT_H264_SLICE. + +Stateless Codec Control ID +========================== + +.. _codec-stateless-control-id: + +``V4L2_CID_CODEC_STATELESS_CLASS (class)`` + The Stateless Codec class descriptor. + +.. _v4l2-codec-stateless-h264: + +``V4L2_CID_STATELESS_H264_SPS (struct)`` + Specifies the sequence parameter set (as extracted from the + bitstream) for the associated H264 slice data. This includes the + necessary parameters for configuring a stateless hardware decoding + pipeline for H264. The bitstream parameters are defined according + to :ref:`h264`, section 7.4.2.1.1 "Sequence Parameter Set Data + Semantics". For further documentation, refer to the above + specification, unless there is an explicit comment stating + otherwise. + +.. c:type:: v4l2_ctrl_h264_sps + +.. cssclass:: longtable + +.. flat-table:: struct v4l2_ctrl_h264_sps + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u8 + - ``profile_idc`` + - + * - __u8 + - ``constraint_set_flags`` + - See :ref:`Sequence Parameter Set Constraints Set Flags ` + * - __u8 + - ``level_idc`` + - + * - __u8 + - ``seq_parameter_set_id`` + - + * - __u8 + - ``chroma_format_idc`` + - + * - __u8 + - ``bit_depth_luma_minus8`` + - + * - __u8 + - ``bit_depth_chroma_minus8`` + - + * - __u8 + - ``log2_max_frame_num_minus4`` + - + * - __u8 + - ``pic_order_cnt_type`` + - + * - __u8 + - ``log2_max_pic_order_cnt_lsb_minus4`` + - + * - __u8 + - ``max_num_ref_frames`` + - + * - __u8 + - ``num_ref_frames_in_pic_order_cnt_cycle`` + - + * - __s32 + - ``offset_for_ref_frame[255]`` + - + * - __s32 + - ``offset_for_non_ref_pic`` + - + * - __s32 + - ``offset_for_top_to_bottom_field`` + - + * - __u16 + - ``pic_width_in_mbs_minus1`` + - + * - __u16 + - ``pic_height_in_map_units_minus1`` + - + * - __u32 + - ``flags`` + - See :ref:`Sequence Parameter Set Flags ` + +.. _h264_sps_constraints_set_flags: + +``Sequence Parameter Set Constraints Set Flags`` + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_H264_SPS_CONSTRAINT_SET0_FLAG`` + - 0x00000001 + - + * - ``V4L2_H264_SPS_CONSTRAINT_SET1_FLAG`` + - 0x00000002 + - + * - ``V4L2_H264_SPS_CONSTRAINT_SET2_FLAG`` + - 0x00000004 + - + * - ``V4L2_H264_SPS_CONSTRAINT_SET3_FLAG`` + - 0x00000008 + - + * - ``V4L2_H264_SPS_CONSTRAINT_SET4_FLAG`` + - 0x00000010 + - + * - ``V4L2_H264_SPS_CONSTRAINT_SET5_FLAG`` + - 0x00000020 + - + +.. _h264_sps_flags: + +``Sequence Parameter Set Flags`` + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE`` + - 0x00000001 + - + * - ``V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS`` + - 0x00000002 + - + * - ``V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO`` + - 0x00000004 + - + * - ``V4L2_H264_SPS_FLAG_GAPS_IN_FRAME_NUM_VALUE_ALLOWED`` + - 0x00000008 + - + * - ``V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY`` + - 0x00000010 + - + * - ``V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD`` + - 0x00000020 + - + * - ``V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE`` + - 0x00000040 + - + +``V4L2_CID_STATELESS_H264_PPS (struct)`` + Specifies the picture parameter set (as extracted from the + bitstream) for the associated H264 slice data. This includes the + necessary parameters for configuring a stateless hardware decoding + pipeline for H264. The bitstream parameters are defined according + to :ref:`h264`, section 7.4.2.2 "Picture Parameter Set RBSP + Semantics". For further documentation, refer to the above + specification, unless there is an explicit comment stating + otherwise. + +.. c:type:: v4l2_ctrl_h264_pps + +.. cssclass:: longtable + +.. flat-table:: struct v4l2_ctrl_h264_pps + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u8 + - ``pic_parameter_set_id`` + - + * - __u8 + - ``seq_parameter_set_id`` + - + * - __u8 + - ``num_slice_groups_minus1`` + - + * - __u8 + - ``num_ref_idx_l0_default_active_minus1`` + - + * - __u8 + - ``num_ref_idx_l1_default_active_minus1`` + - + * - __u8 + - ``weighted_bipred_idc`` + - + * - __s8 + - ``pic_init_qp_minus26`` + - + * - __s8 + - ``pic_init_qs_minus26`` + - + * - __s8 + - ``chroma_qp_index_offset`` + - + * - __s8 + - ``second_chroma_qp_index_offset`` + - + * - __u16 + - ``flags`` + - See :ref:`Picture Parameter Set Flags ` + +.. _h264_pps_flags: + +``Picture Parameter Set Flags`` + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE`` + - 0x00000001 + - + * - ``V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT`` + - 0x00000002 + - + * - ``V4L2_H264_PPS_FLAG_WEIGHTED_PRED`` + - 0x00000004 + - + * - ``V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT`` + - 0x00000008 + - + * - ``V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED`` + - 0x00000010 + - + * - ``V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT`` + - 0x00000020 + - + * - ``V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE`` + - 0x00000040 + - + * - ``V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT`` + - 0x00000080 + - Indicates that ``V4L2_CID_STATELESS_H264_SCALING_MATRIX`` + must be used for this picture. + +``V4L2_CID_STATELESS_H264_SCALING_MATRIX (struct)`` + Specifies the scaling matrix (as extracted from the bitstream) for + the associated H264 slice data. The bitstream parameters are + defined according to :ref:`h264`, section 7.4.2.1.1.1 "Scaling + List Semantics". For further documentation, refer to the above + specification, unless there is an explicit comment stating + otherwise. + +.. c:type:: v4l2_ctrl_h264_scaling_matrix + +.. cssclass:: longtable + +.. flat-table:: struct v4l2_ctrl_h264_scaling_matrix + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u8 + - ``scaling_list_4x4[6][16]`` + - Scaling matrix after applying the inverse scanning process. + Expected list order is Intra Y, Intra Cb, Intra Cr, Inter Y, + Inter Cb, Inter Cr. The values on each scaling list are + expected in raster scan order. + * - __u8 + - ``scaling_list_8x8[6][64]`` + - Scaling matrix after applying the inverse scanning process. + Expected list order is Intra Y, Inter Y, Intra Cb, Inter Cb, + Intra Cr, Inter Cr. The values on each scaling list are + expected in raster scan order. + +``V4L2_CID_STATELESS_H264_SLICE_PARAMS (struct)`` + Specifies the slice parameters (as extracted from the bitstream) + for the associated H264 slice data. This includes the necessary + parameters for configuring a stateless hardware decoding pipeline + for H264. The bitstream parameters are defined according to + :ref:`h264`, section 7.4.3 "Slice Header Semantics". For further + documentation, refer to the above specification, unless there is + an explicit comment stating otherwise. + +.. c:type:: v4l2_ctrl_h264_slice_params + +.. cssclass:: longtable + +.. flat-table:: struct v4l2_ctrl_h264_slice_params + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u32 + - ``header_bit_size`` + - Offset in bits to slice_data() from the beginning of this slice. + * - __u32 + - ``first_mb_in_slice`` + - + * - __u8 + - ``slice_type`` + - + * - __u8 + - ``colour_plane_id`` + - + * - __u8 + - ``redundant_pic_cnt`` + - + * - __u8 + - ``cabac_init_idc`` + - + * - __s8 + - ``slice_qp_delta`` + - + * - __s8 + - ``slice_qs_delta`` + - + * - __u8 + - ``disable_deblocking_filter_idc`` + - + * - __s8 + - ``slice_alpha_c0_offset_div2`` + - + * - __s8 + - ``slice_beta_offset_div2`` + - + * - __u8 + - ``num_ref_idx_l0_active_minus1`` + - If num_ref_idx_active_override_flag is not set, this field must be + set to the value of num_ref_idx_l0_default_active_minus1. + * - __u8 + - ``num_ref_idx_l1_active_minus1`` + - If num_ref_idx_active_override_flag is not set, this field must be + set to the value of num_ref_idx_l1_default_active_minus1. + * - __u8 + - ``reserved`` + - Applications and drivers must set this to zero. + * - struct :c:type:`v4l2_h264_reference` + - ``ref_pic_list0[32]`` + - Reference picture list after applying the per-slice modifications + * - struct :c:type:`v4l2_h264_reference` + - ``ref_pic_list1[32]`` + - Reference picture list after applying the per-slice modifications + * - __u32 + - ``flags`` + - See :ref:`Slice Parameter Flags ` + +.. _h264_slice_flags: + +``Slice Parameter Set Flags`` + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED`` + - 0x00000001 + - + * - ``V4L2_H264_SLICE_FLAG_SP_FOR_SWITCH`` + - 0x00000002 + - + +``V4L2_CID_STATELESS_H264_PRED_WEIGHTS (struct)`` + Prediction weight table defined according to :ref:`h264`, + section 7.4.3.2 "Prediction Weight Table Semantics". + The prediction weight table must be passed by applications + under the conditions explained in section 7.3.3 "Slice header + syntax". + +.. c:type:: v4l2_ctrl_h264_pred_weights + +.. cssclass:: longtable + +.. flat-table:: struct v4l2_ctrl_h264_pred_weights + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u16 + - ``luma_log2_weight_denom`` + - + * - __u16 + - ``chroma_log2_weight_denom`` + - + * - struct :c:type:`v4l2_h264_weight_factors` + - ``weight_factors[2]`` + - The weight factors at index 0 are the weight factors for the reference + list 0, the one at index 1 for the reference list 1. + +.. c:type:: v4l2_h264_weight_factors + +.. cssclass:: longtable + +.. flat-table:: struct v4l2_h264_weight_factors + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __s16 + - ``luma_weight[32]`` + - + * - __s16 + - ``luma_offset[32]`` + - + * - __s16 + - ``chroma_weight[32][2]`` + - + * - __s16 + - ``chroma_offset[32][2]`` + - + +``Picture Reference`` + +.. c:type:: v4l2_h264_reference + +.. cssclass:: longtable + +.. flat-table:: struct v4l2_h264_reference + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u8 + - ``fields`` + - Specifies how the picture is referenced. See :ref:`Reference Fields ` + * - __u8 + - ``index`` + - Index into the :c:type:`v4l2_ctrl_h264_decode_params`.dpb array. + +.. _h264_ref_fields: + +``Reference Fields`` + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_H264_TOP_FIELD_REF`` + - 0x1 + - The top field in field pair is used for short-term reference. + * - ``V4L2_H264_BOTTOM_FIELD_REF`` + - 0x2 + - The bottom field in field pair is used for short-term reference. + * - ``V4L2_H264_FRAME_REF`` + - 0x3 + - The frame (or the top/bottom fields, if it's a field pair) + is used for short-term reference. + +``V4L2_CID_STATELESS_H264_DECODE_PARAMS (struct)`` + Specifies the decode parameters (as extracted from the bitstream) + for the associated H264 slice data. This includes the necessary + parameters for configuring a stateless hardware decoding pipeline + for H264. The bitstream parameters are defined according to + :ref:`h264`. For further documentation, refer to the above + specification, unless there is an explicit comment stating + otherwise. + +.. c:type:: v4l2_ctrl_h264_decode_params + +.. cssclass:: longtable + +.. flat-table:: struct v4l2_ctrl_h264_decode_params + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - struct :c:type:`v4l2_h264_dpb_entry` + - ``dpb[16]`` + - + * - __u16 + - ``nal_ref_idc`` + - NAL reference ID value coming from the NAL Unit header + * - __u16 + - ``frame_num`` + - + * - __s32 + - ``top_field_order_cnt`` + - Picture Order Count for the coded top field + * - __s32 + - ``bottom_field_order_cnt`` + - Picture Order Count for the coded bottom field + * - __u16 + - ``idr_pic_id`` + - + * - __u16 + - ``pic_order_cnt_lsb`` + - + * - __s32 + - ``delta_pic_order_cnt_bottom`` + - + * - __s32 + - ``delta_pic_order_cnt0`` + - + * - __s32 + - ``delta_pic_order_cnt1`` + - + * - __u32 + - ``dec_ref_pic_marking_bit_size`` + - Size in bits of the dec_ref_pic_marking() syntax element. + * - __u32 + - ``pic_order_cnt_bit_size`` + - Combined size in bits of the picture order count related syntax + elements: pic_order_cnt_lsb, delta_pic_order_cnt_bottom, + delta_pic_order_cnt0, and delta_pic_order_cnt1. + * - __u32 + - ``slice_group_change_cycle`` + - + * - __u32 + - ``reserved`` + - Applications and drivers must set this to zero. + * - __u32 + - ``flags`` + - See :ref:`Decode Parameters Flags ` + +.. _h264_decode_params_flags: + +``Decode Parameters Flags`` + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC`` + - 0x00000001 + - That picture is an IDR picture + * - ``V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC`` + - 0x00000002 + - + * - ``V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD`` + - 0x00000004 + - + +.. c:type:: v4l2_h264_dpb_entry + +.. cssclass:: longtable + +.. flat-table:: struct v4l2_h264_dpb_entry + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u64 + - ``reference_ts`` + - Timestamp of the V4L2 capture buffer to use as reference, used + with B-coded and P-coded frames. The timestamp refers to the + ``timestamp`` field in struct :c:type:`v4l2_buffer`. Use the + :c:func:`v4l2_timeval_to_ns()` function to convert the struct + :c:type:`timeval` in struct :c:type:`v4l2_buffer` to a __u64. + * - __u32 + - ``pic_num`` + - + * - __u16 + - ``frame_num`` + - + * - __u8 + - ``fields`` + - Specifies how the DPB entry is referenced. See :ref:`Reference Fields ` + * - __u8 + - ``reserved[5]`` + - Applications and drivers must set this to zero. + * - __s32 + - ``top_field_order_cnt`` + - + * - __s32 + - ``bottom_field_order_cnt`` + - + * - __u32 + - ``flags`` + - See :ref:`DPB Entry Flags ` + +.. _h264_dpb_flags: + +``DPB Entries Flags`` + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_H264_DPB_ENTRY_FLAG_VALID`` + - 0x00000001 + - The DPB entry is valid (non-empty) and should be considered. + * - ``V4L2_H264_DPB_ENTRY_FLAG_ACTIVE`` + - 0x00000002 + - The DPB entry is used for reference. + * - ``V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM`` + - 0x00000004 + - The DPB entry is used for long-term reference. + * - ``V4L2_H264_DPB_ENTRY_FLAG_FIELD`` + - 0x00000008 + - The DPB entry is a single field or a complementary field pair. + +``V4L2_CID_STATELESS_H264_DECODE_MODE (enum)`` + Specifies the decoding mode to use. Currently exposes slice-based and + frame-based decoding but new modes might be added later on. + This control is used as a modifier for V4L2_PIX_FMT_H264_SLICE + pixel format. Applications that support V4L2_PIX_FMT_H264_SLICE + are required to set this control in order to specify the decoding mode + that is expected for the buffer. + Drivers may expose a single or multiple decoding modes, depending + on what they can support. + +.. c:type:: v4l2_stateless_h264_decode_mode + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED`` + - 0 + - Decoding is done at the slice granularity. + The OUTPUT buffer must contain a single slice. + When this mode is selected, the ``V4L2_CID_STATELESS_H264_SLICE_PARAMS`` + control shall be set. When multiple slices compose a frame, + use of ``V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF`` flag + is required. + * - ``V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED`` + - 1 + - Decoding is done at the frame granularity, + The OUTPUT buffer must contain all slices needed to decode the + frame. The OUTPUT buffer must also contain both fields. + This mode will be supported by devices that + parse the slice(s) header(s) in hardware. When this mode is + selected, the ``V4L2_CID_STATELESS_H264_SLICE_PARAMS`` + control shall not be set. + +``V4L2_CID_STATELESS_H264_START_CODE (enum)`` + Specifies the H264 slice start code expected for each slice. + This control is used as a modifier for V4L2_PIX_FMT_H264_SLICE + pixel format. Applications that support V4L2_PIX_FMT_H264_SLICE + are required to set this control in order to specify the start code + that is expected for the buffer. + Drivers may expose a single or multiple start codes, depending + on what they can support. + +.. c:type:: v4l2_stateless_h264_start_code + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_STATELESS_H264_START_CODE_NONE`` + - 0 + - Selecting this value specifies that H264 slices are passed + to the driver without any start code. + * - ``V4L2_STATELESS_H264_START_CODE_ANNEX_B`` + - 1 + - Selecting this value specifies that H264 slices are expected + to be prefixed by Annex B start codes. According to :ref:`h264` + valid start codes can be 3-bytes 0x000001 or 4-bytes 0x00000001. diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst index b31c52d9b1da..e815fffd1cd8 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst @@ -1502,698 +1502,6 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - - Layer number -.. _v4l2-mpeg-h264: - -``V4L2_CID_MPEG_VIDEO_H264_SPS (struct)`` - Specifies the sequence parameter set (as extracted from the - bitstream) for the associated H264 slice data. This includes the - necessary parameters for configuring a stateless hardware decoding - pipeline for H264. The bitstream parameters are defined according - to :ref:`h264`, section 7.4.2.1.1 "Sequence Parameter Set Data - Semantics". For further documentation, refer to the above - specification, unless there is an explicit comment stating - otherwise. - - .. note:: - - This compound control is not yet part of the public kernel API and - it is expected to change. - -.. c:type:: v4l2_ctrl_h264_sps - -.. cssclass:: longtable - -.. flat-table:: struct v4l2_ctrl_h264_sps - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - __u8 - - ``profile_idc`` - - - * - __u8 - - ``constraint_set_flags`` - - See :ref:`Sequence Parameter Set Constraints Set Flags ` - * - __u8 - - ``level_idc`` - - - * - __u8 - - ``seq_parameter_set_id`` - - - * - __u8 - - ``chroma_format_idc`` - - - * - __u8 - - ``bit_depth_luma_minus8`` - - - * - __u8 - - ``bit_depth_chroma_minus8`` - - - * - __u8 - - ``log2_max_frame_num_minus4`` - - - * - __u8 - - ``pic_order_cnt_type`` - - - * - __u8 - - ``log2_max_pic_order_cnt_lsb_minus4`` - - - * - __u8 - - ``max_num_ref_frames`` - - - * - __u8 - - ``num_ref_frames_in_pic_order_cnt_cycle`` - - - * - __s32 - - ``offset_for_ref_frame[255]`` - - - * - __s32 - - ``offset_for_non_ref_pic`` - - - * - __s32 - - ``offset_for_top_to_bottom_field`` - - - * - __u16 - - ``pic_width_in_mbs_minus1`` - - - * - __u16 - - ``pic_height_in_map_units_minus1`` - - - * - __u32 - - ``flags`` - - See :ref:`Sequence Parameter Set Flags ` - -.. _h264_sps_constraints_set_flags: - -``Sequence Parameter Set Constraints Set Flags`` - -.. cssclass:: longtable - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - ``V4L2_H264_SPS_CONSTRAINT_SET0_FLAG`` - - 0x00000001 - - - * - ``V4L2_H264_SPS_CONSTRAINT_SET1_FLAG`` - - 0x00000002 - - - * - ``V4L2_H264_SPS_CONSTRAINT_SET2_FLAG`` - - 0x00000004 - - - * - ``V4L2_H264_SPS_CONSTRAINT_SET3_FLAG`` - - 0x00000008 - - - * - ``V4L2_H264_SPS_CONSTRAINT_SET4_FLAG`` - - 0x00000010 - - - * - ``V4L2_H264_SPS_CONSTRAINT_SET5_FLAG`` - - 0x00000020 - - - -.. _h264_sps_flags: - -``Sequence Parameter Set Flags`` - -.. cssclass:: longtable - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - ``V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE`` - - 0x00000001 - - - * - ``V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS`` - - 0x00000002 - - - * - ``V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO`` - - 0x00000004 - - - * - ``V4L2_H264_SPS_FLAG_GAPS_IN_FRAME_NUM_VALUE_ALLOWED`` - - 0x00000008 - - - * - ``V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY`` - - 0x00000010 - - - * - ``V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD`` - - 0x00000020 - - - * - ``V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE`` - - 0x00000040 - - - -``V4L2_CID_MPEG_VIDEO_H264_PPS (struct)`` - Specifies the picture parameter set (as extracted from the - bitstream) for the associated H264 slice data. This includes the - necessary parameters for configuring a stateless hardware decoding - pipeline for H264. The bitstream parameters are defined according - to :ref:`h264`, section 7.4.2.2 "Picture Parameter Set RBSP - Semantics". For further documentation, refer to the above - specification, unless there is an explicit comment stating - otherwise. - - .. note:: - - This compound control is not yet part of the public kernel API and - it is expected to change. - -.. c:type:: v4l2_ctrl_h264_pps - -.. cssclass:: longtable - -.. flat-table:: struct v4l2_ctrl_h264_pps - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - __u8 - - ``pic_parameter_set_id`` - - - * - __u8 - - ``seq_parameter_set_id`` - - - * - __u8 - - ``num_slice_groups_minus1`` - - - * - __u8 - - ``num_ref_idx_l0_default_active_minus1`` - - - * - __u8 - - ``num_ref_idx_l1_default_active_minus1`` - - - * - __u8 - - ``weighted_bipred_idc`` - - - * - __s8 - - ``pic_init_qp_minus26`` - - - * - __s8 - - ``pic_init_qs_minus26`` - - - * - __s8 - - ``chroma_qp_index_offset`` - - - * - __s8 - - ``second_chroma_qp_index_offset`` - - - * - __u16 - - ``flags`` - - See :ref:`Picture Parameter Set Flags ` - -.. _h264_pps_flags: - -``Picture Parameter Set Flags`` - -.. cssclass:: longtable - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - ``V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE`` - - 0x00000001 - - - * - ``V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT`` - - 0x00000002 - - - * - ``V4L2_H264_PPS_FLAG_WEIGHTED_PRED`` - - 0x00000004 - - - * - ``V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT`` - - 0x00000008 - - - * - ``V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED`` - - 0x00000010 - - - * - ``V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT`` - - 0x00000020 - - - * - ``V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE`` - - 0x00000040 - - - * - ``V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT`` - - 0x00000080 - - Indicates that ``V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX`` - must be used for this picture. - -``V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX (struct)`` - Specifies the scaling matrix (as extracted from the bitstream) for - the associated H264 slice data. The bitstream parameters are - defined according to :ref:`h264`, section 7.4.2.1.1.1 "Scaling - List Semantics". For further documentation, refer to the above - specification, unless there is an explicit comment stating - otherwise. - - .. note:: - - This compound control is not yet part of the public kernel API and - it is expected to change. - -.. c:type:: v4l2_ctrl_h264_scaling_matrix - -.. cssclass:: longtable - -.. flat-table:: struct v4l2_ctrl_h264_scaling_matrix - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - __u8 - - ``scaling_list_4x4[6][16]`` - - Scaling matrix after applying the inverse scanning process. - Expected list order is Intra Y, Intra Cb, Intra Cr, Inter Y, - Inter Cb, Inter Cr. The values on each scaling list are - expected in raster scan order. - * - __u8 - - ``scaling_list_8x8[6][64]`` - - Scaling matrix after applying the inverse scanning process. - Expected list order is Intra Y, Inter Y, Intra Cb, Inter Cb, - Intra Cr, Inter Cr. The values on each scaling list are - expected in raster scan order. - -``V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS (struct)`` - Specifies the slice parameters (as extracted from the bitstream) - for the associated H264 slice data. This includes the necessary - parameters for configuring a stateless hardware decoding pipeline - for H264. The bitstream parameters are defined according to - :ref:`h264`, section 7.4.3 "Slice Header Semantics". For further - documentation, refer to the above specification, unless there is - an explicit comment stating otherwise. - - .. note:: - - This compound control is not yet part of the public kernel API - and it is expected to change. - -.. c:type:: v4l2_ctrl_h264_slice_params - -.. cssclass:: longtable - -.. flat-table:: struct v4l2_ctrl_h264_slice_params - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - __u32 - - ``header_bit_size`` - - Offset in bits to slice_data() from the beginning of this slice. - * - __u32 - - ``first_mb_in_slice`` - - - * - __u8 - - ``slice_type`` - - - * - __u8 - - ``colour_plane_id`` - - - * - __u8 - - ``redundant_pic_cnt`` - - - * - __u8 - - ``cabac_init_idc`` - - - * - __s8 - - ``slice_qp_delta`` - - - * - __s8 - - ``slice_qs_delta`` - - - * - __u8 - - ``disable_deblocking_filter_idc`` - - - * - __s8 - - ``slice_alpha_c0_offset_div2`` - - - * - __s8 - - ``slice_beta_offset_div2`` - - - * - __u8 - - ``num_ref_idx_l0_active_minus1`` - - If num_ref_idx_active_override_flag is not set, this field must be - set to the value of num_ref_idx_l0_default_active_minus1. - * - __u8 - - ``num_ref_idx_l1_active_minus1`` - - If num_ref_idx_active_override_flag is not set, this field must be - set to the value of num_ref_idx_l1_default_active_minus1. - * - __u8 - - ``reserved`` - - Applications and drivers must set this to zero. - * - struct :c:type:`v4l2_h264_reference` - - ``ref_pic_list0[32]`` - - Reference picture list after applying the per-slice modifications - * - struct :c:type:`v4l2_h264_reference` - - ``ref_pic_list1[32]`` - - Reference picture list after applying the per-slice modifications - * - __u32 - - ``flags`` - - See :ref:`Slice Parameter Flags ` - -.. _h264_slice_flags: - -``Slice Parameter Set Flags`` - -.. cssclass:: longtable - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - ``V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED`` - - 0x00000001 - - - * - ``V4L2_H264_SLICE_FLAG_SP_FOR_SWITCH`` - - 0x00000002 - - - -``V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS (struct)`` - Prediction weight table defined according to :ref:`h264`, - section 7.4.3.2 "Prediction Weight Table Semantics". - The prediction weight table must be passed by applications - under the conditions explained in section 7.3.3 "Slice header - syntax". - - .. note:: - - This compound control is not yet part of the public kernel API and - it is expected to change. - -.. c:type:: v4l2_ctrl_h264_pred_weights - -.. cssclass:: longtable - -.. flat-table:: struct v4l2_ctrl_h264_pred_weights - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - __u16 - - ``luma_log2_weight_denom`` - - - * - __u16 - - ``chroma_log2_weight_denom`` - - - * - struct :c:type:`v4l2_h264_weight_factors` - - ``weight_factors[2]`` - - The weight factors at index 0 are the weight factors for the reference - list 0, the one at index 1 for the reference list 1. - -.. c:type:: v4l2_h264_weight_factors - -.. cssclass:: longtable - -.. flat-table:: struct v4l2_h264_weight_factors - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - __s16 - - ``luma_weight[32]`` - - - * - __s16 - - ``luma_offset[32]`` - - - * - __s16 - - ``chroma_weight[32][2]`` - - - * - __s16 - - ``chroma_offset[32][2]`` - - - -``Picture Reference`` - -.. c:type:: v4l2_h264_reference - -.. cssclass:: longtable - -.. flat-table:: struct v4l2_h264_reference - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - __u8 - - ``fields`` - - Specifies how the picture is referenced. See :ref:`Reference Fields ` - * - __u8 - - ``index`` - - Index into the :c:type:`v4l2_ctrl_h264_decode_params`.dpb array. - -.. _h264_ref_fields: - -``Reference Fields`` - -.. cssclass:: longtable - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - ``V4L2_H264_TOP_FIELD_REF`` - - 0x1 - - The top field in field pair is used for short-term reference. - * - ``V4L2_H264_BOTTOM_FIELD_REF`` - - 0x2 - - The bottom field in field pair is used for short-term reference. - * - ``V4L2_H264_FRAME_REF`` - - 0x3 - - The frame (or the top/bottom fields, if it's a field pair) - is used for short-term reference. - -``V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS (struct)`` - Specifies the decode parameters (as extracted from the bitstream) - for the associated H264 slice data. This includes the necessary - parameters for configuring a stateless hardware decoding pipeline - for H264. The bitstream parameters are defined according to - :ref:`h264`. For further documentation, refer to the above - specification, unless there is an explicit comment stating - otherwise. - - .. note:: - - This compound control is not yet part of the public kernel API and - it is expected to change. - -.. c:type:: v4l2_ctrl_h264_decode_params - -.. cssclass:: longtable - -.. flat-table:: struct v4l2_ctrl_h264_decode_params - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - struct :c:type:`v4l2_h264_dpb_entry` - - ``dpb[16]`` - - - * - __u16 - - ``nal_ref_idc`` - - NAL reference ID value coming from the NAL Unit header - * - __u16 - - ``frame_num`` - - - * - __s32 - - ``top_field_order_cnt`` - - Picture Order Count for the coded top field - * - __s32 - - ``bottom_field_order_cnt`` - - Picture Order Count for the coded bottom field - * - __u16 - - ``idr_pic_id`` - - - * - __u16 - - ``pic_order_cnt_lsb`` - - - * - __s32 - - ``delta_pic_order_cnt_bottom`` - - - * - __s32 - - ``delta_pic_order_cnt0`` - - - * - __s32 - - ``delta_pic_order_cnt1`` - - - * - __u32 - - ``dec_ref_pic_marking_bit_size`` - - Size in bits of the dec_ref_pic_marking() syntax element. - * - __u32 - - ``pic_order_cnt_bit_size`` - - Combined size in bits of the picture order count related syntax - elements: pic_order_cnt_lsb, delta_pic_order_cnt_bottom, - delta_pic_order_cnt0, and delta_pic_order_cnt1. - * - __u32 - - ``slice_group_change_cycle`` - - - * - __u32 - - ``reserved`` - - Applications and drivers must set this to zero. - * - __u32 - - ``flags`` - - See :ref:`Decode Parameters Flags ` - -.. _h264_decode_params_flags: - -``Decode Parameters Flags`` - -.. cssclass:: longtable - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - ``V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC`` - - 0x00000001 - - That picture is an IDR picture - * - ``V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC`` - - 0x00000002 - - - * - ``V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD`` - - 0x00000004 - - - -.. c:type:: v4l2_h264_dpb_entry - -.. cssclass:: longtable - -.. flat-table:: struct v4l2_h264_dpb_entry - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - __u64 - - ``reference_ts`` - - Timestamp of the V4L2 capture buffer to use as reference, used - with B-coded and P-coded frames. The timestamp refers to the - ``timestamp`` field in struct :c:type:`v4l2_buffer`. Use the - :c:func:`v4l2_timeval_to_ns()` function to convert the struct - :c:type:`timeval` in struct :c:type:`v4l2_buffer` to a __u64. - * - __u32 - - ``pic_num`` - - - * - __u16 - - ``frame_num`` - - - * - __u8 - - ``fields`` - - Specifies how the DPB entry is referenced. See :ref:`Reference Fields ` - * - __u8 - - ``reserved[5]`` - - Applications and drivers must set this to zero. - * - __s32 - - ``top_field_order_cnt`` - - - * - __s32 - - ``bottom_field_order_cnt`` - - - * - __u32 - - ``flags`` - - See :ref:`DPB Entry Flags ` - -.. _h264_dpb_flags: - -``DPB Entries Flags`` - -.. cssclass:: longtable - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - ``V4L2_H264_DPB_ENTRY_FLAG_VALID`` - - 0x00000001 - - The DPB entry is valid (non-empty) and should be considered. - * - ``V4L2_H264_DPB_ENTRY_FLAG_ACTIVE`` - - 0x00000002 - - The DPB entry is used for reference. - * - ``V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM`` - - 0x00000004 - - The DPB entry is used for long-term reference. - * - ``V4L2_H264_DPB_ENTRY_FLAG_FIELD`` - - 0x00000008 - - The DPB entry is a single field or a complementary field pair. - -``V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE (enum)`` - Specifies the decoding mode to use. Currently exposes slice-based and - frame-based decoding but new modes might be added later on. - This control is used as a modifier for V4L2_PIX_FMT_H264_SLICE - pixel format. Applications that support V4L2_PIX_FMT_H264_SLICE - are required to set this control in order to specify the decoding mode - that is expected for the buffer. - Drivers may expose a single or multiple decoding modes, depending - on what they can support. - - .. note:: - - This menu control is not yet part of the public kernel API and - it is expected to change. - -.. c:type:: v4l2_mpeg_video_h264_decode_mode - -.. cssclass:: longtable - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - ``V4L2_MPEG_VIDEO_H264_DECODE_MODE_SLICE_BASED`` - - 0 - - Decoding is done at the slice granularity. - The OUTPUT buffer must contain a single slice. - When this mode is selected, the ``V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS`` - control shall be set. When multiple slices compose a frame, - use of ``V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF`` flag - is required. - * - ``V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED`` - - 1 - - Decoding is done at the frame granularity, - The OUTPUT buffer must contain all slices needed to decode the - frame. The OUTPUT buffer must also contain both fields. - This mode will be supported by devices that - parse the slice(s) header(s) in hardware. When this mode is - selected, the ``V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS`` - control shall not be set. - -``V4L2_CID_MPEG_VIDEO_H264_START_CODE (enum)`` - Specifies the H264 slice start code expected for each slice. - This control is used as a modifier for V4L2_PIX_FMT_H264_SLICE - pixel format. Applications that support V4L2_PIX_FMT_H264_SLICE - are required to set this control in order to specify the start code - that is expected for the buffer. - Drivers may expose a single or multiple start codes, depending - on what they can support. - - .. note:: - - This menu control is not yet part of the public kernel API and - it is expected to change. - -.. c:type:: v4l2_mpeg_video_h264_start_code - -.. cssclass:: longtable - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - ``V4L2_MPEG_VIDEO_H264_START_CODE_NONE`` - - 0 - - Selecting this value specifies that H264 slices are passed - to the driver without any start code. - * - ``V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B`` - - 1 - - Selecting this value specifies that H264 slices are expected - to be prefixed by Annex B start codes. According to :ref:`h264` - valid start codes can be 3-bytes 0x000001 or 4-bytes 0x00000001. - .. _v4l2-mpeg-mpeg2: ``V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS (struct)`` diff --git a/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst b/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst index d585909bc4e2..b8899262d8de 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst @@ -57,18 +57,18 @@ Compressed Formats - H264 parsed slice data, including slice headers, either with or without the start code, as extracted from the H264 bitstream. This format is adapted for stateless video decoders that implement an - H264 pipeline (using the :ref:`mem2mem` and :ref:`media-request-api`). + H264 pipeline with the :ref:`stateless_decoder`. This pixelformat has two modifiers that must be set at least once - through the ``V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE`` - and ``V4L2_CID_MPEG_VIDEO_H264_START_CODE`` controls. + through the ``V4L2_CID_STATELESS_H264_DECODE_MODE`` + and ``V4L2_CID_STATELESS_H264_START_CODE`` controls. In addition, metadata associated with the frame to decode are - required to be passed through the ``V4L2_CID_MPEG_VIDEO_H264_SPS``, - ``V4L2_CID_MPEG_VIDEO_H264_PPS``, - ``V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX``, - ``V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS`` and - ``V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS`` controls. See the - :ref:`associated Codec Control IDs `. Exactly - one output and one capture buffer must be provided for use + required to be passed through the ``V4L2_CID_STATELESS_H264_SPS``, + ``V4L2_CID_STATELESS_H264_PPS``, + ``V4L2_CID_STATELESS_H264_SCALING_MATRIX``, + ``V4L2_CID_STATELESS_H264_SLICE_PARAMS`` and + ``V4L2_CID_STATELESS_H264_DECODE_PARAMS`` controls. See the + :ref:`associated Codec Control IDs `. + Exactly one output and one capture buffer must be provided for use with this pixel format. The output buffer must contain the appropriate number of macroblocks to decode a full corresponding frame to the matching capture buffer. @@ -77,11 +77,6 @@ Compressed Formats 7.3.2.8 "Slice layer without partitioning RBSP syntax" and the following sections. - .. note:: - - This format is not yet part of the public kernel API and it - is expected to change. - * .. _V4L2-PIX-FMT-H263: - ``V4L2_PIX_FMT_H263`` diff --git a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst index 06a5b175a75d..a4e7e67cd8ce 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst @@ -184,6 +184,30 @@ still cause this situation. - ``p_area`` - A pointer to a struct :c:type:`v4l2_area`. Valid if this control is of type ``V4L2_CTRL_TYPE_AREA``. + * - :c:type:`v4l2_ctrl_h264_sps` * + - ``p_h264_sps`` + - A pointer to a struct :c:type:`v4l2_ctrl_h264_sps`. Valid if this control is + of type ``V4L2_CTRL_TYPE_H264_SPS``. + * - :c:type:`v4l2_ctrl_h264_pps` * + - ``p_h264_pps`` + - A pointer to a struct :c:type:`v4l2_ctrl_h264_pps`. Valid if this control is + of type ``V4L2_CTRL_TYPE_H264_PPS``. + * - :c:type:`v4l2_ctrl_h264_scaling_matrix` * + - ``p_h264_scaling_matrix`` + - A pointer to a struct :c:type:`v4l2_ctrl_h264_scaling_matrix`. Valid if this control is + of type ``V4L2_CTRL_TYPE_H264_SCALING_MATRIX``. + * - :c:type:`v4l2_ctrl_h264_pred_weights` * + - ``p_h264_pred_weights`` + - A pointer to a struct :c:type:`v4l2_ctrl_h264_pred_weights`. Valid if this control is + of type ``V4L2_CTRL_TYPE_H264_PRED_WEIGHTS``. + * - :c:type:`v4l2_ctrl_h264_slice_params` * + - ``p_h264_slice_params`` + - A pointer to a struct :c:type:`v4l2_ctrl_h264_slice_params`. Valid if this control is + of type ``V4L2_CTRL_TYPE_H264_SLICE_PARAMS``. + * - :c:type:`v4l2_ctrl_h264_decode_params` * + - ``p_h264_decode_params`` + - A pointer to a struct :c:type:`v4l2_ctrl_h264_decode_params`. Valid if this control is + of type ``V4L2_CTRL_TYPE_H264_DECODE_PARAMS``. * - void * - ``ptr`` - A pointer to a compound type which can be an N-dimensional array -- cgit v1.2.3 From 3f46cac6787f371c89d13d6cdd611f81a93ca2b3 Mon Sep 17 00:00:00 2001 From: Helen Koike Date: Wed, 18 Nov 2020 15:24:00 +0100 Subject: media: admin-guide/pixfmt-meta-rkisp1.rst: pixfmt reference conforming with macro Fix warnings from make htmlddocs: Documentation/output/videodev2.h.rst:6: WARNING: undefined label: v4l2-meta-fmt-rk-isp1-params (if the link has no caption the label must precede a section header) Documentation/output/videodev2.h.rst:6: WARNING: undefined label: v4l2-meta-fmt-rk-isp1-stat-3a (if the link has no caption the label must precede a section header) Fixes: df22026aebd8 ("media: videodev2.h, v4l2-ioctl: add rkisp1 meta buffer format") Signed-off-by: Helen Koike Reported-by: Stephen Rothwell Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/admin-guide/media/rkisp1.rst | 4 ++-- Documentation/userspace-api/media/v4l/pixfmt-meta-rkisp1.rst | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/admin-guide/media/rkisp1.rst b/Documentation/admin-guide/media/rkisp1.rst index 42e37ed255f6..2267e4fb475e 100644 --- a/Documentation/admin-guide/media/rkisp1.rst +++ b/Documentation/admin-guide/media/rkisp1.rst @@ -86,7 +86,7 @@ the driver through the rkisp_params node to improve image quality during a video stream. The buffer format is defined by struct :c:type:`rkisp1_stat_buffer`, and userspace should set -:ref:`V4L2_META_FMT_RK_ISP1_STAT_3A ` as the +:ref:`V4L2_META_FMT_RK_ISP1_STAT_3A ` as the dataformat. .. _rkisp1_params: @@ -100,7 +100,7 @@ and others. The buffer format is defined by struct :c:type:`rkisp1_params_cfg`, and userspace should set -:ref:`V4L2_META_FMT_RK_ISP1_PARAMS ` as the +:ref:`V4L2_META_FMT_RK_ISP1_PARAMS ` as the dataformat. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-meta-rkisp1.rst b/Documentation/userspace-api/media/v4l/pixfmt-meta-rkisp1.rst index f3671472d410..922fa1d59898 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-meta-rkisp1.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-meta-rkisp1.rst @@ -1,7 +1,7 @@ .. SPDX-License-Identifier: GPL-2.0 -.. _v4l2-meta-fmt-params-rkisp1: -.. _v4l2-meta-fmt-stat-rkisp1: +.. _v4l2-meta-fmt-rk-isp1-params: +.. _v4l2-meta-fmt-rk-isp1-stat-3a: ***************************************************************************** V4L2_META_FMT_RK_ISP1_PARAMS ('rk1p'), V4L2_META_FMT_RK_ISP1_STAT_3A ('rk1s') -- cgit v1.2.3 From 7403fa17c5dfc141291293cdd9d39161031ff995 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 25 Nov 2020 11:19:06 +0100 Subject: media: ext-ctrls-image-source.rst: document v4l2_area The v4l2_area struct was not documented in the media documentation, which meant that references to that struct elsewhere in the documentation never linked to anything. [mchehab: remove .. cssclass:: longtable] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/ext-ctrls-image-source.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-image-source.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-image-source.rst index 9457dc340c31..de43f5c8486d 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-image-source.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-image-source.rst @@ -58,3 +58,17 @@ Image Source Control IDs The unit cell consists of the whole area of the pixel, sensitive and non-sensitive. This control is required for automatic calibration of sensors/cameras. + +.. c:type:: v4l2_area + +.. flat-table:: struct v4l2_area + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u32 + - ``width`` + - Width of the area. + * - __u32 + - ``height`` + - Height of the area. -- cgit v1.2.3 From 3abfc314c5e60a54973a6f3cefd591bfdad8adf6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 26 Nov 2020 13:58:20 +0100 Subject: media: vicodec: add V4L2_ prefix before FWHT_VERSION and FWHT_FL_* The FWHT stateless 'uAPI' was staging and marked explicitly in the V4L2 specification that it will change and is unstable. Note that these control IDs were never exported as a public API, they were only defined at the driver's code. While not too late, let's rename them is preparation for promoting the stateless FWHT codec API as a public API. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/ext-ctrls-codec.rst | 32 ++++---- drivers/media/test-drivers/vicodec/codec-fwht.c | 12 +-- drivers/media/test-drivers/vicodec/codec-fwht.h | 40 +++++----- .../media/test-drivers/vicodec/codec-v4l2-fwht.c | 88 +++++++++++----------- drivers/media/test-drivers/vicodec/vicodec-core.c | 40 +++++----- 5 files changed, 106 insertions(+), 106 deletions(-) diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst index e815fffd1cd8..34173ed326fc 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst @@ -2284,52 +2284,52 @@ FWHT Flags :stub-columns: 0 :widths: 3 1 4 - * - ``FWHT_FL_IS_INTERLACED`` + * - ``V4L2_FWHT_FL_IS_INTERLACED`` - 0x00000001 - Set if this is an interlaced format - * - ``FWHT_FL_IS_BOTTOM_FIRST`` + * - ``V4L2_FWHT_FL_IS_BOTTOM_FIRST`` - 0x00000002 - Set if this is a bottom-first (NTSC) interlaced format - * - ``FWHT_FL_IS_ALTERNATE`` + * - ``V4L2_FWHT_FL_IS_ALTERNATE`` - 0x00000004 - Set if each 'frame' contains just one field - * - ``FWHT_FL_IS_BOTTOM_FIELD`` + * - ``V4L2_FWHT_FL_IS_BOTTOM_FIELD`` - 0x00000008 - - If FWHT_FL_IS_ALTERNATE was set, then this is set if this 'frame' is the + - If V4L2_FWHT_FL_IS_ALTERNATE was set, then this is set if this 'frame' is the bottom field, else it is the top field. - * - ``FWHT_FL_LUMA_IS_UNCOMPRESSED`` + * - ``V4L2_FWHT_FL_LUMA_IS_UNCOMPRESSED`` - 0x00000010 - Set if the luma plane is uncompressed - * - ``FWHT_FL_CB_IS_UNCOMPRESSED`` + * - ``V4L2_FWHT_FL_CB_IS_UNCOMPRESSED`` - 0x00000020 - Set if the cb plane is uncompressed - * - ``FWHT_FL_CR_IS_UNCOMPRESSED`` + * - ``V4L2_FWHT_FL_CR_IS_UNCOMPRESSED`` - 0x00000040 - Set if the cr plane is uncompressed - * - ``FWHT_FL_CHROMA_FULL_HEIGHT`` + * - ``V4L2_FWHT_FL_CHROMA_FULL_HEIGHT`` - 0x00000080 - Set if the chroma plane has the same height as the luma plane, else the chroma plane is half the height of the luma plane - * - ``FWHT_FL_CHROMA_FULL_WIDTH`` + * - ``V4L2_FWHT_FL_CHROMA_FULL_WIDTH`` - 0x00000100 - Set if the chroma plane has the same width as the luma plane, else the chroma plane is half the width of the luma plane - * - ``FWHT_FL_ALPHA_IS_UNCOMPRESSED`` + * - ``V4L2_FWHT_FL_ALPHA_IS_UNCOMPRESSED`` - 0x00000200 - Set if the alpha plane is uncompressed - * - ``FWHT_FL_I_FRAME`` + * - ``V4L2_FWHT_FL_I_FRAME`` - 0x00000400 - Set if this is an I-frame - * - ``FWHT_FL_COMPONENTS_NUM_MSK`` + * - ``V4L2_FWHT_FL_COMPONENTS_NUM_MSK`` - 0x00070000 - A 4-values flag - the number of components - 1 - * - ``FWHT_FL_PIXENC_YUV`` + * - ``V4L2_FWHT_FL_PIXENC_YUV`` - 0x00080000 - Set if the pixel encoding is YUV - * - ``FWHT_FL_PIXENC_RGB`` + * - ``V4L2_FWHT_FL_PIXENC_RGB`` - 0x00100000 - Set if the pixel encoding is RGB - * - ``FWHT_FL_PIXENC_HSV`` + * - ``V4L2_FWHT_FL_PIXENC_HSV`` - 0x00180000 - Set if the pixel encoding is HSV diff --git a/drivers/media/test-drivers/vicodec/codec-fwht.c b/drivers/media/test-drivers/vicodec/codec-fwht.c index 31faf319e508..5dbf76fd8185 100644 --- a/drivers/media/test-drivers/vicodec/codec-fwht.c +++ b/drivers/media/test-drivers/vicodec/codec-fwht.c @@ -920,7 +920,7 @@ bool fwht_decode_frame(struct fwht_cframe *cf, u32 hdr_flags, if (!decode_plane(cf, &rlco, height, width, ref->luma, ref_stride, ref->luma_alpha_step, dst->luma, dst_stride, dst->luma_alpha_step, - hdr_flags & FWHT_FL_LUMA_IS_UNCOMPRESSED, + hdr_flags & V4L2_FWHT_FL_LUMA_IS_UNCOMPRESSED, end_of_rlco_buf)) return false; @@ -928,21 +928,21 @@ bool fwht_decode_frame(struct fwht_cframe *cf, u32 hdr_flags, u32 h = height; u32 w = width; - if (!(hdr_flags & FWHT_FL_CHROMA_FULL_HEIGHT)) + if (!(hdr_flags & V4L2_FWHT_FL_CHROMA_FULL_HEIGHT)) h /= 2; - if (!(hdr_flags & FWHT_FL_CHROMA_FULL_WIDTH)) + if (!(hdr_flags & V4L2_FWHT_FL_CHROMA_FULL_WIDTH)) w /= 2; if (!decode_plane(cf, &rlco, h, w, ref->cb, ref_chroma_stride, ref->chroma_step, dst->cb, dst_chroma_stride, dst->chroma_step, - hdr_flags & FWHT_FL_CB_IS_UNCOMPRESSED, + hdr_flags & V4L2_FWHT_FL_CB_IS_UNCOMPRESSED, end_of_rlco_buf)) return false; if (!decode_plane(cf, &rlco, h, w, ref->cr, ref_chroma_stride, ref->chroma_step, dst->cr, dst_chroma_stride, dst->chroma_step, - hdr_flags & FWHT_FL_CR_IS_UNCOMPRESSED, + hdr_flags & V4L2_FWHT_FL_CR_IS_UNCOMPRESSED, end_of_rlco_buf)) return false; } @@ -951,7 +951,7 @@ bool fwht_decode_frame(struct fwht_cframe *cf, u32 hdr_flags, if (!decode_plane(cf, &rlco, height, width, ref->alpha, ref_stride, ref->luma_alpha_step, dst->alpha, dst_stride, dst->luma_alpha_step, - hdr_flags & FWHT_FL_ALPHA_IS_UNCOMPRESSED, + hdr_flags & V4L2_FWHT_FL_ALPHA_IS_UNCOMPRESSED, end_of_rlco_buf)) return false; return true; diff --git a/drivers/media/test-drivers/vicodec/codec-fwht.h b/drivers/media/test-drivers/vicodec/codec-fwht.h index b6fec2b1cbca..78e2841762fb 100644 --- a/drivers/media/test-drivers/vicodec/codec-fwht.h +++ b/drivers/media/test-drivers/vicodec/codec-fwht.h @@ -56,37 +56,37 @@ #define FWHT_MAGIC1 0x4f4f4f4f #define FWHT_MAGIC2 0xffffffff -#define FWHT_VERSION 3 +#define V4L2_FWHT_VERSION 3 /* Set if this is an interlaced format */ -#define FWHT_FL_IS_INTERLACED BIT(0) +#define V4L2_FWHT_FL_IS_INTERLACED BIT(0) /* Set if this is a bottom-first (NTSC) interlaced format */ -#define FWHT_FL_IS_BOTTOM_FIRST BIT(1) +#define V4L2_FWHT_FL_IS_BOTTOM_FIRST BIT(1) /* Set if each 'frame' contains just one field */ -#define FWHT_FL_IS_ALTERNATE BIT(2) +#define V4L2_FWHT_FL_IS_ALTERNATE BIT(2) /* - * If FWHT_FL_IS_ALTERNATE was set, then this is set if this + * If V4L2_FWHT_FL_IS_ALTERNATE was set, then this is set if this * 'frame' is the bottom field, else it is the top field. */ -#define FWHT_FL_IS_BOTTOM_FIELD BIT(3) +#define V4L2_FWHT_FL_IS_BOTTOM_FIELD BIT(3) /* Set if this frame is uncompressed */ -#define FWHT_FL_LUMA_IS_UNCOMPRESSED BIT(4) -#define FWHT_FL_CB_IS_UNCOMPRESSED BIT(5) -#define FWHT_FL_CR_IS_UNCOMPRESSED BIT(6) -#define FWHT_FL_CHROMA_FULL_HEIGHT BIT(7) -#define FWHT_FL_CHROMA_FULL_WIDTH BIT(8) -#define FWHT_FL_ALPHA_IS_UNCOMPRESSED BIT(9) -#define FWHT_FL_I_FRAME BIT(10) +#define V4L2_FWHT_FL_LUMA_IS_UNCOMPRESSED BIT(4) +#define V4L2_FWHT_FL_CB_IS_UNCOMPRESSED BIT(5) +#define V4L2_FWHT_FL_CR_IS_UNCOMPRESSED BIT(6) +#define V4L2_FWHT_FL_CHROMA_FULL_HEIGHT BIT(7) +#define V4L2_FWHT_FL_CHROMA_FULL_WIDTH BIT(8) +#define V4L2_FWHT_FL_ALPHA_IS_UNCOMPRESSED BIT(9) +#define V4L2_FWHT_FL_I_FRAME BIT(10) /* A 4-values flag - the number of components - 1 */ -#define FWHT_FL_COMPONENTS_NUM_MSK GENMASK(18, 16) -#define FWHT_FL_COMPONENTS_NUM_OFFSET 16 +#define V4L2_FWHT_FL_COMPONENTS_NUM_MSK GENMASK(18, 16) +#define V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET 16 -#define FWHT_FL_PIXENC_MSK GENMASK(20, 19) -#define FWHT_FL_PIXENC_OFFSET 19 -#define FWHT_FL_PIXENC_YUV (1 << FWHT_FL_PIXENC_OFFSET) -#define FWHT_FL_PIXENC_RGB (2 << FWHT_FL_PIXENC_OFFSET) -#define FWHT_FL_PIXENC_HSV (3 << FWHT_FL_PIXENC_OFFSET) +#define V4L2_FWHT_FL_PIXENC_MSK GENMASK(20, 19) +#define V4L2_FWHT_FL_PIXENC_OFFSET 19 +#define V4L2_FWHT_FL_PIXENC_YUV (1 << V4L2_FWHT_FL_PIXENC_OFFSET) +#define V4L2_FWHT_FL_PIXENC_RGB (2 << V4L2_FWHT_FL_PIXENC_OFFSET) +#define V4L2_FWHT_FL_PIXENC_HSV (3 << V4L2_FWHT_FL_PIXENC_OFFSET) /* * A macro to calculate the needed padding in order to make sure diff --git a/drivers/media/test-drivers/vicodec/codec-v4l2-fwht.c b/drivers/media/test-drivers/vicodec/codec-v4l2-fwht.c index b6e39fbd8ad5..0c83678fcdad 100644 --- a/drivers/media/test-drivers/vicodec/codec-v4l2-fwht.c +++ b/drivers/media/test-drivers/vicodec/codec-v4l2-fwht.c @@ -11,34 +11,34 @@ #include "codec-v4l2-fwht.h" static const struct v4l2_fwht_pixfmt_info v4l2_fwht_pixfmts[] = { - { V4L2_PIX_FMT_YUV420, 1, 3, 2, 1, 1, 2, 2, 3, 3, FWHT_FL_PIXENC_YUV}, - { V4L2_PIX_FMT_YVU420, 1, 3, 2, 1, 1, 2, 2, 3, 3, FWHT_FL_PIXENC_YUV}, - { V4L2_PIX_FMT_YUV422P, 1, 2, 1, 1, 1, 2, 1, 3, 3, FWHT_FL_PIXENC_YUV}, - { V4L2_PIX_FMT_NV12, 1, 3, 2, 1, 2, 2, 2, 3, 2, FWHT_FL_PIXENC_YUV}, - { V4L2_PIX_FMT_NV21, 1, 3, 2, 1, 2, 2, 2, 3, 2, FWHT_FL_PIXENC_YUV}, - { V4L2_PIX_FMT_NV16, 1, 2, 1, 1, 2, 2, 1, 3, 2, FWHT_FL_PIXENC_YUV}, - { V4L2_PIX_FMT_NV61, 1, 2, 1, 1, 2, 2, 1, 3, 2, FWHT_FL_PIXENC_YUV}, - { V4L2_PIX_FMT_NV24, 1, 3, 1, 1, 2, 1, 1, 3, 2, FWHT_FL_PIXENC_YUV}, - { V4L2_PIX_FMT_NV42, 1, 3, 1, 1, 2, 1, 1, 3, 2, FWHT_FL_PIXENC_YUV}, - { V4L2_PIX_FMT_YUYV, 2, 2, 1, 2, 4, 2, 1, 3, 1, FWHT_FL_PIXENC_YUV}, - { V4L2_PIX_FMT_YVYU, 2, 2, 1, 2, 4, 2, 1, 3, 1, FWHT_FL_PIXENC_YUV}, - { V4L2_PIX_FMT_UYVY, 2, 2, 1, 2, 4, 2, 1, 3, 1, FWHT_FL_PIXENC_YUV}, - { V4L2_PIX_FMT_VYUY, 2, 2, 1, 2, 4, 2, 1, 3, 1, FWHT_FL_PIXENC_YUV}, - { V4L2_PIX_FMT_BGR24, 3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB}, - { V4L2_PIX_FMT_RGB24, 3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB}, - { V4L2_PIX_FMT_HSV24, 3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_HSV}, - { V4L2_PIX_FMT_BGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, - { V4L2_PIX_FMT_XBGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, - { V4L2_PIX_FMT_ABGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, - { V4L2_PIX_FMT_RGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, - { V4L2_PIX_FMT_XRGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, - { V4L2_PIX_FMT_ARGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, - { V4L2_PIX_FMT_BGRX32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, - { V4L2_PIX_FMT_BGRA32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, - { V4L2_PIX_FMT_RGBX32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, - { V4L2_PIX_FMT_RGBA32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, - { V4L2_PIX_FMT_HSV32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_HSV}, - { V4L2_PIX_FMT_GREY, 1, 1, 1, 1, 0, 1, 1, 1, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_YUV420, 1, 3, 2, 1, 1, 2, 2, 3, 3, V4L2_FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_YVU420, 1, 3, 2, 1, 1, 2, 2, 3, 3, V4L2_FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_YUV422P, 1, 2, 1, 1, 1, 2, 1, 3, 3, V4L2_FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_NV12, 1, 3, 2, 1, 2, 2, 2, 3, 2, V4L2_FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_NV21, 1, 3, 2, 1, 2, 2, 2, 3, 2, V4L2_FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_NV16, 1, 2, 1, 1, 2, 2, 1, 3, 2, V4L2_FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_NV61, 1, 2, 1, 1, 2, 2, 1, 3, 2, V4L2_FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_NV24, 1, 3, 1, 1, 2, 1, 1, 3, 2, V4L2_FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_NV42, 1, 3, 1, 1, 2, 1, 1, 3, 2, V4L2_FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_YUYV, 2, 2, 1, 2, 4, 2, 1, 3, 1, V4L2_FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_YVYU, 2, 2, 1, 2, 4, 2, 1, 3, 1, V4L2_FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_UYVY, 2, 2, 1, 2, 4, 2, 1, 3, 1, V4L2_FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_VYUY, 2, 2, 1, 2, 4, 2, 1, 3, 1, V4L2_FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_BGR24, 3, 3, 1, 3, 3, 1, 1, 3, 1, V4L2_FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_RGB24, 3, 3, 1, 3, 3, 1, 1, 3, 1, V4L2_FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_HSV24, 3, 3, 1, 3, 3, 1, 1, 3, 1, V4L2_FWHT_FL_PIXENC_HSV}, + { V4L2_PIX_FMT_BGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_XBGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_ABGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_RGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_XRGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_ARGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_BGRX32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_BGRA32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_RGBX32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_RGBA32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_HSV32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_HSV}, + { V4L2_PIX_FMT_GREY, 1, 1, 1, 1, 0, 1, 1, 1, 1, V4L2_FWHT_FL_PIXENC_RGB}, }; bool v4l2_fwht_validate_fmt(const struct v4l2_fwht_pixfmt_info *info, @@ -251,25 +251,25 @@ int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) p_hdr = (struct fwht_cframe_hdr *)p_out; p_hdr->magic1 = FWHT_MAGIC1; p_hdr->magic2 = FWHT_MAGIC2; - p_hdr->version = htonl(FWHT_VERSION); + p_hdr->version = htonl(V4L2_FWHT_VERSION); p_hdr->width = htonl(state->visible_width); p_hdr->height = htonl(state->visible_height); - flags |= (info->components_num - 1) << FWHT_FL_COMPONENTS_NUM_OFFSET; + flags |= (info->components_num - 1) << V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET; flags |= info->pixenc; if (encoding & FWHT_LUMA_UNENCODED) - flags |= FWHT_FL_LUMA_IS_UNCOMPRESSED; + flags |= V4L2_FWHT_FL_LUMA_IS_UNCOMPRESSED; if (encoding & FWHT_CB_UNENCODED) - flags |= FWHT_FL_CB_IS_UNCOMPRESSED; + flags |= V4L2_FWHT_FL_CB_IS_UNCOMPRESSED; if (encoding & FWHT_CR_UNENCODED) - flags |= FWHT_FL_CR_IS_UNCOMPRESSED; + flags |= V4L2_FWHT_FL_CR_IS_UNCOMPRESSED; if (encoding & FWHT_ALPHA_UNENCODED) - flags |= FWHT_FL_ALPHA_IS_UNCOMPRESSED; + flags |= V4L2_FWHT_FL_ALPHA_IS_UNCOMPRESSED; if (!(encoding & FWHT_FRAME_PCODED)) - flags |= FWHT_FL_I_FRAME; + flags |= V4L2_FWHT_FL_I_FRAME; if (rf.height_div == 1) - flags |= FWHT_FL_CHROMA_FULL_HEIGHT; + flags |= V4L2_FWHT_FL_CHROMA_FULL_HEIGHT; if (rf.width_div == 1) - flags |= FWHT_FL_CHROMA_FULL_WIDTH; + flags |= V4L2_FWHT_FL_CHROMA_FULL_WIDTH; p_hdr->flags = htonl(flags); p_hdr->colorspace = htonl(state->colorspace); p_hdr->xfer_func = htonl(state->xfer_func); @@ -299,9 +299,9 @@ int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) info = state->info; version = ntohl(state->header.version); - if (!version || version > FWHT_VERSION) { + if (!version || version > V4L2_FWHT_VERSION) { pr_err("version %d is not supported, current version is %d\n", - version, FWHT_VERSION); + version, V4L2_FWHT_VERSION); return -EINVAL; } @@ -317,10 +317,10 @@ int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) flags = ntohl(state->header.flags); if (version >= 2) { - if ((flags & FWHT_FL_PIXENC_MSK) != info->pixenc) + if ((flags & V4L2_FWHT_FL_PIXENC_MSK) != info->pixenc) return -EINVAL; - components_num = 1 + ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >> - FWHT_FL_COMPONENTS_NUM_OFFSET); + components_num = 1 + ((flags & V4L2_FWHT_FL_COMPONENTS_NUM_MSK) >> + V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET); } if (components_num != info->components_num) @@ -333,8 +333,8 @@ int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) cf.rlc_data = (__be16 *)p_in; cf.size = ntohl(state->header.size); - hdr_width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; - hdr_height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; + hdr_width_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; + hdr_height_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; if (hdr_width_div != info->width_div || hdr_height_div != info->height_div) return -EINVAL; diff --git a/drivers/media/test-drivers/vicodec/vicodec-core.c b/drivers/media/test-drivers/vicodec/vicodec-core.c index 0e115683f8da..084b75c226c5 100644 --- a/drivers/media/test-drivers/vicodec/vicodec-core.c +++ b/drivers/media/test-drivers/vicodec/vicodec-core.c @@ -200,14 +200,14 @@ static void copy_cap_to_ref(const u8 *cap, const struct v4l2_fwht_pixfmt_info *i static bool validate_by_version(unsigned int flags, unsigned int version) { - if (!version || version > FWHT_VERSION) + if (!version || version > V4L2_FWHT_VERSION) return false; if (version >= 2) { unsigned int components_num = 1 + - ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >> - FWHT_FL_COMPONENTS_NUM_OFFSET); - unsigned int pixenc = flags & FWHT_FL_PIXENC_MSK; + ((flags & V4L2_FWHT_FL_COMPONENTS_NUM_MSK) >> + V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET); + unsigned int pixenc = flags & V4L2_FWHT_FL_PIXENC_MSK; if (components_num == 0 || components_num > 4 || !pixenc) return false; @@ -219,18 +219,18 @@ static bool validate_stateless_params_flags(const struct v4l2_ctrl_fwht_params * const struct v4l2_fwht_pixfmt_info *cur_info) { unsigned int width_div = - (params->flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; + (params->flags & V4L2_FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; unsigned int height_div = - (params->flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; + (params->flags & V4L2_FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; unsigned int components_num = 3; unsigned int pixenc = 0; if (params->version < 3) return false; - components_num = 1 + ((params->flags & FWHT_FL_COMPONENTS_NUM_MSK) >> - FWHT_FL_COMPONENTS_NUM_OFFSET); - pixenc = (params->flags & FWHT_FL_PIXENC_MSK); + components_num = 1 + ((params->flags & V4L2_FWHT_FL_COMPONENTS_NUM_MSK) >> + V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET); + pixenc = (params->flags & V4L2_FWHT_FL_PIXENC_MSK); if (v4l2_fwht_validate_fmt(cur_info, width_div, height_div, components_num, pixenc)) return true; @@ -278,7 +278,7 @@ static int device_process(struct vicodec_ctx *ctx, * set the reference buffer from the reference timestamp * only if this is a P-frame */ - if (!(ntohl(ctx->state.header.flags) & FWHT_FL_I_FRAME)) { + if (!(ntohl(ctx->state.header.flags) & V4L2_FWHT_FL_I_FRAME)) { struct vb2_buffer *ref_vb2_buf; int ref_buf_idx; struct vb2_queue *vq_cap = @@ -331,7 +331,7 @@ static int device_process(struct vicodec_ctx *ctx, copy_cap_to_ref(p_dst, ctx->state.info, &ctx->state); vb2_set_plane_payload(&dst_vb->vb2_buf, 0, q_dst->sizeimage); - if (ntohl(ctx->state.header.flags) & FWHT_FL_I_FRAME) + if (ntohl(ctx->state.header.flags) & V4L2_FWHT_FL_I_FRAME) dst_vb->flags |= V4L2_BUF_FLAG_KEYFRAME; else dst_vb->flags |= V4L2_BUF_FLAG_PFRAME; @@ -480,16 +480,16 @@ static const struct v4l2_fwht_pixfmt_info * info_from_header(const struct fwht_cframe_hdr *p_hdr) { unsigned int flags = ntohl(p_hdr->flags); - unsigned int width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; - unsigned int height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; + unsigned int width_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; + unsigned int height_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; unsigned int components_num = 3; unsigned int pixenc = 0; unsigned int version = ntohl(p_hdr->version); if (version >= 2) { - components_num = 1 + ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >> - FWHT_FL_COMPONENTS_NUM_OFFSET); - pixenc = (flags & FWHT_FL_PIXENC_MSK); + components_num = 1 + ((flags & V4L2_FWHT_FL_COMPONENTS_NUM_MSK) >> + V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET); + pixenc = (flags & V4L2_FWHT_FL_PIXENC_MSK); } return v4l2_fwht_find_nth_fmt(width_div, height_div, components_num, pixenc, 0); @@ -522,8 +522,8 @@ static void update_capture_data_from_header(struct vicodec_ctx *ctx) const struct fwht_cframe_hdr *p_hdr = &ctx->state.header; const struct v4l2_fwht_pixfmt_info *info = info_from_header(p_hdr); unsigned int flags = ntohl(p_hdr->flags); - unsigned int hdr_width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; - unsigned int hdr_height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; + unsigned int hdr_width_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; + unsigned int hdr_height_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; /* * This function should not be used by a stateless codec since @@ -657,8 +657,8 @@ restart: if (!is_header_valid(&ctx->state.header) && ctx->comp_has_frame) return 1; flags = ntohl(ctx->state.header.flags); - hdr_width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; - hdr_height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; + hdr_width_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; + hdr_height_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; if (ntohl(ctx->state.header.width) != q_dst->visible_width || ntohl(ctx->state.header.height) != q_dst->visible_height || -- cgit v1.2.3 From 206bc0f6fb945e90cfea677339ef8adfaedc4b4f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 26 Nov 2020 14:02:18 +0100 Subject: media: vicodec: mark the stateless FWHT API as stable The FWHT stateless 'uAPI' was staging and marked explicitly in the V4L2 specification that it will change and is unstable. Note that these control IDs were never exported as a public API, they were only defined in kernel-local headers (fwht-ctrls.h). Now, the FWHT stateless controls is ready to be part of the stable uAPI. While not too late: - Rename V4L2_CID_MPEG_VIDEO_FWHT_PARAMS to V4L2_CID_STATELESS_FWHT_PARAMS. - Move the contents of fwht-ctrls.h to v4l2-controls.h. - Move the public parts of drivers/media/test-drivers/vicodec/codec-fwht.h to v4l2-controls.h. - Add V4L2_CTRL_TYPE_FWHT_PARAMS control initialization and validation. - Add p_fwht_params to struct v4l2_ext_control. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/test-drivers/vicodec/codec-fwht.c | 1 + drivers/media/test-drivers/vicodec/codec-fwht.h | 32 ----------- drivers/media/test-drivers/vicodec/vicodec-core.c | 6 +- drivers/media/v4l2-core/v4l2-ctrls.c | 20 ++++++- include/media/fwht-ctrls.h | 31 ---------- include/media/v4l2-ctrls.h | 1 - include/uapi/linux/v4l2-controls.h | 70 +++++++++++++++++++++++ include/uapi/linux/videodev2.h | 3 + 8 files changed, 95 insertions(+), 69 deletions(-) delete mode 100644 include/media/fwht-ctrls.h diff --git a/drivers/media/test-drivers/vicodec/codec-fwht.c b/drivers/media/test-drivers/vicodec/codec-fwht.c index 5dbf76fd8185..1ce682e1b85c 100644 --- a/drivers/media/test-drivers/vicodec/codec-fwht.c +++ b/drivers/media/test-drivers/vicodec/codec-fwht.c @@ -11,6 +11,7 @@ #include #include +#include #include "codec-fwht.h" #define OVERFLOW_BIT BIT(14) diff --git a/drivers/media/test-drivers/vicodec/codec-fwht.h b/drivers/media/test-drivers/vicodec/codec-fwht.h index 78e2841762fb..0eab24020e9e 100644 --- a/drivers/media/test-drivers/vicodec/codec-fwht.h +++ b/drivers/media/test-drivers/vicodec/codec-fwht.h @@ -56,38 +56,6 @@ #define FWHT_MAGIC1 0x4f4f4f4f #define FWHT_MAGIC2 0xffffffff -#define V4L2_FWHT_VERSION 3 - -/* Set if this is an interlaced format */ -#define V4L2_FWHT_FL_IS_INTERLACED BIT(0) -/* Set if this is a bottom-first (NTSC) interlaced format */ -#define V4L2_FWHT_FL_IS_BOTTOM_FIRST BIT(1) -/* Set if each 'frame' contains just one field */ -#define V4L2_FWHT_FL_IS_ALTERNATE BIT(2) -/* - * If V4L2_FWHT_FL_IS_ALTERNATE was set, then this is set if this - * 'frame' is the bottom field, else it is the top field. - */ -#define V4L2_FWHT_FL_IS_BOTTOM_FIELD BIT(3) -/* Set if this frame is uncompressed */ -#define V4L2_FWHT_FL_LUMA_IS_UNCOMPRESSED BIT(4) -#define V4L2_FWHT_FL_CB_IS_UNCOMPRESSED BIT(5) -#define V4L2_FWHT_FL_CR_IS_UNCOMPRESSED BIT(6) -#define V4L2_FWHT_FL_CHROMA_FULL_HEIGHT BIT(7) -#define V4L2_FWHT_FL_CHROMA_FULL_WIDTH BIT(8) -#define V4L2_FWHT_FL_ALPHA_IS_UNCOMPRESSED BIT(9) -#define V4L2_FWHT_FL_I_FRAME BIT(10) - -/* A 4-values flag - the number of components - 1 */ -#define V4L2_FWHT_FL_COMPONENTS_NUM_MSK GENMASK(18, 16) -#define V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET 16 - -#define V4L2_FWHT_FL_PIXENC_MSK GENMASK(20, 19) -#define V4L2_FWHT_FL_PIXENC_OFFSET 19 -#define V4L2_FWHT_FL_PIXENC_YUV (1 << V4L2_FWHT_FL_PIXENC_OFFSET) -#define V4L2_FWHT_FL_PIXENC_RGB (2 << V4L2_FWHT_FL_PIXENC_OFFSET) -#define V4L2_FWHT_FL_PIXENC_HSV (3 << V4L2_FWHT_FL_PIXENC_OFFSET) - /* * A macro to calculate the needed padding in order to make sure * both luma and chroma components resolutions are rounded up to diff --git a/drivers/media/test-drivers/vicodec/vicodec-core.c b/drivers/media/test-drivers/vicodec/vicodec-core.c index 084b75c226c5..025f3ff77302 100644 --- a/drivers/media/test-drivers/vicodec/vicodec-core.c +++ b/drivers/media/test-drivers/vicodec/vicodec-core.c @@ -1746,7 +1746,7 @@ static int vicodec_try_ctrl(struct v4l2_ctrl *ctrl) V4L2_BUF_TYPE_VIDEO_CAPTURE); switch (ctrl->id) { - case V4L2_CID_MPEG_VIDEO_FWHT_PARAMS: + case V4L2_CID_STATELESS_FWHT_PARAMS: if (!q_dst->info) return -EINVAL; params = ctrl->p_new.p_fwht_params; @@ -1799,7 +1799,7 @@ static int vicodec_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_FWHT_P_FRAME_QP: ctx->state.p_frame_qp = ctrl->val; return 0; - case V4L2_CID_MPEG_VIDEO_FWHT_PARAMS: + case V4L2_CID_STATELESS_FWHT_PARAMS: params = ctrl->p_new.p_fwht_params; update_header_from_stateless_params(ctx, params); ctx->state.ref_frame_ts = params->backward_ref_ts; @@ -1815,7 +1815,7 @@ static const struct v4l2_ctrl_ops vicodec_ctrl_ops = { static const struct v4l2_ctrl_config vicodec_ctrl_stateless_state = { .ops = &vicodec_ctrl_ops, - .id = V4L2_CID_MPEG_VIDEO_FWHT_PARAMS, + .id = V4L2_CID_STATELESS_FWHT_PARAMS, .elem_size = sizeof(struct v4l2_ctrl_fwht_params), }; diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 88231ba7b0fa..5cbe0ffbf501 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -943,7 +943,6 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: return "Force Key Frame"; case V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS: return "MPEG-2 Slice Parameters"; case V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION: return "MPEG-2 Quantization Matrices"; - case V4L2_CID_MPEG_VIDEO_FWHT_PARAMS: return "FWHT Stateless Parameters"; case V4L2_CID_FWHT_I_FRAME_QP: return "FWHT I-Frame QP Value"; case V4L2_CID_FWHT_P_FRAME_QP: return "FWHT P-Frame QP Value"; @@ -1185,6 +1184,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_STATELESS_H264_PRED_WEIGHTS: return "H264 Prediction Weight Table"; case V4L2_CID_STATELESS_H264_SLICE_PARAMS: return "H264 Slice Parameters"; case V4L2_CID_STATELESS_H264_DECODE_PARAMS: return "H264 Decode Parameters"; + case V4L2_CID_STATELESS_FWHT_PARAMS: return "FWHT Stateless Parameters"; default: return NULL; } @@ -1433,7 +1433,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION: *type = V4L2_CTRL_TYPE_MPEG2_QUANTIZATION; break; - case V4L2_CID_MPEG_VIDEO_FWHT_PARAMS: + case V4L2_CID_STATELESS_FWHT_PARAMS: *type = V4L2_CTRL_TYPE_FWHT_PARAMS; break; case V4L2_CID_STATELESS_H264_SPS: @@ -1627,6 +1627,7 @@ static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 idx, { struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; struct v4l2_ctrl_vp8_frame_header *p_vp8_frame_header; + struct v4l2_ctrl_fwht_params *p_fwht_params; void *p = ptr.p + idx * ctrl->elem_size; if (ctrl->p_def.p_const) @@ -1653,6 +1654,12 @@ static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 idx, p_vp8_frame_header = p; p_vp8_frame_header->num_dct_parts = 1; break; + case V4L2_CTRL_TYPE_FWHT_PARAMS: + p_fwht_params = p; + p_fwht_params->version = V4L2_FWHT_VERSION; + p_fwht_params->width = 1280; + p_fwht_params->height = 720; + break; } } @@ -1755,6 +1762,9 @@ static void std_log(const struct v4l2_ctrl *ctrl) case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS: pr_cont("H264_PRED_WEIGHTS"); break; + case V4L2_CTRL_TYPE_FWHT_PARAMS: + pr_cont("FWHT_PARAMS"); + break; default: pr_cont("unknown type %d", ctrl->type); break; @@ -1798,6 +1808,7 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, { struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; struct v4l2_ctrl_vp8_frame_header *p_vp8_frame_header; + struct v4l2_ctrl_fwht_params *p_fwht_params; struct v4l2_ctrl_h264_sps *p_h264_sps; struct v4l2_ctrl_h264_pps *p_h264_pps; struct v4l2_ctrl_h264_pred_weights *p_h264_pred_weights; @@ -1857,6 +1868,11 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, break; case V4L2_CTRL_TYPE_FWHT_PARAMS: + p_fwht_params = p; + if (p_fwht_params->version < V4L2_FWHT_VERSION) + return -EINVAL; + if (!p_fwht_params->width || !p_fwht_params->height) + return -EINVAL; break; case V4L2_CTRL_TYPE_H264_SPS: diff --git a/include/media/fwht-ctrls.h b/include/media/fwht-ctrls.h deleted file mode 100644 index a918b49609e1..000000000000 --- a/include/media/fwht-ctrls.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * These are the FWHT state controls for use with stateless FWHT - * codec drivers. - * - * It turns out that these structs are not stable yet and will undergo - * more changes. So keep them private until they are stable and ready to - * become part of the official public API. - */ - -#ifndef _FWHT_CTRLS_H_ -#define _FWHT_CTRLS_H_ - -#define V4L2_CTRL_TYPE_FWHT_PARAMS 0x0105 - -#define V4L2_CID_MPEG_VIDEO_FWHT_PARAMS (V4L2_CID_CODEC_BASE + 292) - -struct v4l2_ctrl_fwht_params { - __u64 backward_ref_ts; - __u32 version; - __u32 width; - __u32 height; - __u32 flags; - __u32 colorspace; - __u32 xfer_func; - __u32 ycbcr_enc; - __u32 quantization; -}; - - -#endif diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index d25b38f78229..167ca8c8424f 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -18,7 +18,6 @@ * This will move to the public headers once this API is fully stable. */ #include -#include #include #include diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 3f24663fba4a..823b214aac0c 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -1565,6 +1565,76 @@ struct v4l2_ctrl_h264_decode_params { }; +/* Stateless FWHT control, used by the vicodec driver */ + +/* Current FWHT version */ +#define V4L2_FWHT_VERSION 3 + +/* Set if this is an interlaced format */ +#define V4L2_FWHT_FL_IS_INTERLACED BIT(0) +/* Set if this is a bottom-first (NTSC) interlaced format */ +#define V4L2_FWHT_FL_IS_BOTTOM_FIRST BIT(1) +/* Set if each 'frame' contains just one field */ +#define V4L2_FWHT_FL_IS_ALTERNATE BIT(2) +/* + * If V4L2_FWHT_FL_IS_ALTERNATE was set, then this is set if this + * 'frame' is the bottom field, else it is the top field. + */ +#define V4L2_FWHT_FL_IS_BOTTOM_FIELD BIT(3) +/* Set if the Y' plane is uncompressed */ +#define V4L2_FWHT_FL_LUMA_IS_UNCOMPRESSED BIT(4) +/* Set if the Cb plane is uncompressed */ +#define V4L2_FWHT_FL_CB_IS_UNCOMPRESSED BIT(5) +/* Set if the Cr plane is uncompressed */ +#define V4L2_FWHT_FL_CR_IS_UNCOMPRESSED BIT(6) +/* Set if the chroma plane is full height, if cleared it is half height */ +#define V4L2_FWHT_FL_CHROMA_FULL_HEIGHT BIT(7) +/* Set if the chroma plane is full width, if cleared it is half width */ +#define V4L2_FWHT_FL_CHROMA_FULL_WIDTH BIT(8) +/* Set if the alpha plane is uncompressed */ +#define V4L2_FWHT_FL_ALPHA_IS_UNCOMPRESSED BIT(9) +/* Set if this is an I Frame */ +#define V4L2_FWHT_FL_I_FRAME BIT(10) + +/* A 4-values flag - the number of components - 1 */ +#define V4L2_FWHT_FL_COMPONENTS_NUM_MSK GENMASK(18, 16) +#define V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET 16 + +/* A 4-values flag - the pixel encoding type */ +#define V4L2_FWHT_FL_PIXENC_MSK GENMASK(20, 19) +#define V4L2_FWHT_FL_PIXENC_OFFSET 19 +#define V4L2_FWHT_FL_PIXENC_YUV (1 << V4L2_FWHT_FL_PIXENC_OFFSET) +#define V4L2_FWHT_FL_PIXENC_RGB (2 << V4L2_FWHT_FL_PIXENC_OFFSET) +#define V4L2_FWHT_FL_PIXENC_HSV (3 << V4L2_FWHT_FL_PIXENC_OFFSET) + +#define V4L2_CID_STATELESS_FWHT_PARAMS (V4L2_CID_CODEC_STATELESS_BASE + 100) +/** + * struct v4l2_ctrl_fwht_params - FWHT parameters + * + * @backward_ref_ts: timestamp of the V4L2 capture buffer to use as reference. + * The timestamp refers to the timestamp field in struct v4l2_buffer. + * Use v4l2_timeval_to_ns() to convert the struct timeval to a __u64. + * @version: must be V4L2_FWHT_VERSION. + * @width: width of frame. + * @height: height of frame. + * @flags: FWHT flags (see V4L2_FWHT_FL_*). + * @colorspace: the colorspace (enum v4l2_colorspace). + * @xfer_func: the transfer function (enum v4l2_xfer_func). + * @ycbcr_enc: the Y'CbCr encoding (enum v4l2_ycbcr_encoding). + * @quantization: the quantization (enum v4l2_quantization). + */ +struct v4l2_ctrl_fwht_params { + __u64 backward_ref_ts; + __u32 version; + __u32 width; + __u32 height; + __u32 flags; + __u32 colorspace; + __u32 xfer_func; + __u32 ycbcr_enc; + __u32 quantization; +}; + /* MPEG-compression definitions kept for backwards compatibility */ #ifndef __KERNEL__ #define V4L2_CTRL_CLASS_MPEG V4L2_CTRL_CLASS_CODEC diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 76231ca6e101..e40e95be79f9 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1740,6 +1740,7 @@ struct v4l2_ext_control { struct v4l2_ctrl_h264_pred_weights __user *p_h264_pred_weights; struct v4l2_ctrl_h264_slice_params __user *p_h264_slice_params; struct v4l2_ctrl_h264_decode_params __user *p_h264_decode_params; + struct v4l2_ctrl_fwht_params __user *p_fwht_params; void __user *ptr; }; } __attribute__ ((packed)); @@ -1793,6 +1794,8 @@ enum v4l2_ctrl_type { V4L2_CTRL_TYPE_H264_SLICE_PARAMS = 0x0203, V4L2_CTRL_TYPE_H264_DECODE_PARAMS = 0x0204, V4L2_CTRL_TYPE_H264_PRED_WEIGHTS = 0x0205, + + V4L2_CTRL_TYPE_FWHT_PARAMS = 0x0220, }; /* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */ -- cgit v1.2.3 From d98c34beb8fe539fa872245da76ce2c600180af8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 26 Nov 2020 14:08:36 +0100 Subject: media: ext-ctrls-codec.rst: move FWHT docs to ext-ctrls-codec-stateless.rst Move the documentation for the stateless FWHT codec to ext-ctrls-codec-stateless.rst since that is the proper place for the stable stateless API documentation. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../media/v4l/ext-ctrls-codec-stateless.rst | 120 ++++++++++++++++++++ .../userspace-api/media/v4l/ext-ctrls-codec.rst | 121 --------------------- 2 files changed, 120 insertions(+), 121 deletions(-) diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst index 12f3308fd2b3..01e3b1a3fb99 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst @@ -671,3 +671,123 @@ Stateless Codec Control ID - Selecting this value specifies that H264 slices are expected to be prefixed by Annex B start codes. According to :ref:`h264` valid start codes can be 3-bytes 0x000001 or 4-bytes 0x00000001. + + +.. _codec-stateless-fwht: + +``V4L2_CID_STATELESS_FWHT_PARAMS (struct)`` + Specifies the FWHT (Fast Walsh Hadamard Transform) parameters (as extracted + from the bitstream) for the associated FWHT data. This includes the necessary + parameters for configuring a stateless hardware decoding pipeline for FWHT. + This codec is specific to the vicodec test driver. + +.. c:type:: v4l2_ctrl_fwht_params + +.. cssclass:: longtable + +.. tabularcolumns:: |p{1.4cm}|p{4.3cm}|p{11.8cm}| + +.. flat-table:: struct v4l2_ctrl_fwht_params + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u64 + - ``backward_ref_ts`` + - Timestamp of the V4L2 capture buffer to use as backward reference, used + with P-coded frames. The timestamp refers to the + ``timestamp`` field in struct :c:type:`v4l2_buffer`. Use the + :c:func:`v4l2_timeval_to_ns()` function to convert the struct + :c:type:`timeval` in struct :c:type:`v4l2_buffer` to a __u64. + * - __u32 + - ``version`` + - The version of the codec. Set to ``V4L2_FWHT_VERSION``. + * - __u32 + - ``width`` + - The width of the frame. + * - __u32 + - ``height`` + - The height of the frame. + * - __u32 + - ``flags`` + - The flags of the frame, see :ref:`fwht-flags`. + * - __u32 + - ``colorspace`` + - The colorspace of the frame, from enum :c:type:`v4l2_colorspace`. + * - __u32 + - ``xfer_func`` + - The transfer function, from enum :c:type:`v4l2_xfer_func`. + * - __u32 + - ``ycbcr_enc`` + - The Y'CbCr encoding, from enum :c:type:`v4l2_ycbcr_encoding`. + * - __u32 + - ``quantization`` + - The quantization range, from enum :c:type:`v4l2_quantization`. + + + +.. _fwht-flags: + +FWHT Flags +========== + +.. cssclass:: longtable + +.. tabularcolumns:: |p{6.8cm}|p{2.4cm}|p{8.3cm}| + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 3 1 4 + + * - ``V4L2_FWHT_FL_IS_INTERLACED`` + - 0x00000001 + - Set if this is an interlaced format. + * - ``V4L2_FWHT_FL_IS_BOTTOM_FIRST`` + - 0x00000002 + - Set if this is a bottom-first (NTSC) interlaced format. + * - ``V4L2_FWHT_FL_IS_ALTERNATE`` + - 0x00000004 + - Set if each 'frame' contains just one field. + * - ``V4L2_FWHT_FL_IS_BOTTOM_FIELD`` + - 0x00000008 + - If V4L2_FWHT_FL_IS_ALTERNATE was set, then this is set if this 'frame' is the + bottom field, else it is the top field. + * - ``V4L2_FWHT_FL_LUMA_IS_UNCOMPRESSED`` + - 0x00000010 + - Set if the Y' (luma) plane is uncompressed. + * - ``V4L2_FWHT_FL_CB_IS_UNCOMPRESSED`` + - 0x00000020 + - Set if the Cb plane is uncompressed. + * - ``V4L2_FWHT_FL_CR_IS_UNCOMPRESSED`` + - 0x00000040 + - Set if the Cr plane is uncompressed. + * - ``V4L2_FWHT_FL_CHROMA_FULL_HEIGHT`` + - 0x00000080 + - Set if the chroma plane has the same height as the luma plane, + else the chroma plane is half the height of the luma plane. + * - ``V4L2_FWHT_FL_CHROMA_FULL_WIDTH`` + - 0x00000100 + - Set if the chroma plane has the same width as the luma plane, + else the chroma plane is half the width of the luma plane. + * - ``V4L2_FWHT_FL_ALPHA_IS_UNCOMPRESSED`` + - 0x00000200 + - Set if the alpha plane is uncompressed. + * - ``V4L2_FWHT_FL_I_FRAME`` + - 0x00000400 + - Set if this is an I-frame. + * - ``V4L2_FWHT_FL_COMPONENTS_NUM_MSK`` + - 0x00070000 + - The number of color components - 1. + * - ``V4L2_FWHT_FL_PIXENC_MSK`` + - 0x00180000 + - The mask for the pixel encoding. + * - ``V4L2_FWHT_FL_PIXENC_YUV`` + - 0x00080000 + - Set if the pixel encoding is YUV. + * - ``V4L2_FWHT_FL_PIXENC_RGB`` + - 0x00100000 + - Set if the pixel encoding is RGB. + * - ``V4L2_FWHT_FL_PIXENC_HSV`` + - 0x00180000 + - Set if the pixel encoding is HSV. diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst index 34173ed326fc..454ecd9a0f83 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst @@ -2213,127 +2213,6 @@ enum v4l2_mpeg_mfc51_video_force_frame_type - - Force a non-coded frame. -.. _v4l2-mpeg-fwht: - -``V4L2_CID_MPEG_VIDEO_FWHT_PARAMS (struct)`` - Specifies the fwht parameters (as extracted from the bitstream) for the - associated FWHT data. This includes the necessary parameters for - configuring a stateless hardware decoding pipeline for FWHT. - - .. note:: - - This compound control is not yet part of the public kernel API and - it is expected to change. - -.. c:type:: v4l2_ctrl_fwht_params - -.. cssclass:: longtable - -.. tabularcolumns:: |p{1.4cm}|p{4.3cm}|p{11.8cm}| - -.. flat-table:: struct v4l2_ctrl_fwht_params - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - __u64 - - ``backward_ref_ts`` - - Timestamp of the V4L2 capture buffer to use as backward reference, used - with P-coded frames. The timestamp refers to the - ``timestamp`` field in struct :c:type:`v4l2_buffer`. Use the - :c:func:`v4l2_timeval_to_ns()` function to convert the struct - :c:type:`timeval` in struct :c:type:`v4l2_buffer` to a __u64. - * - __u32 - - ``version`` - - The version of the codec - * - __u32 - - ``width`` - - The width of the frame - * - __u32 - - ``height`` - - The height of the frame - * - __u32 - - ``flags`` - - The flags of the frame, see :ref:`fwht-flags`. - * - __u32 - - ``colorspace`` - - The colorspace of the frame, from enum :c:type:`v4l2_colorspace`. - * - __u32 - - ``xfer_func`` - - The transfer function, from enum :c:type:`v4l2_xfer_func`. - * - __u32 - - ``ycbcr_enc`` - - The Y'CbCr encoding, from enum :c:type:`v4l2_ycbcr_encoding`. - * - __u32 - - ``quantization`` - - The quantization range, from enum :c:type:`v4l2_quantization`. - - - -.. _fwht-flags: - -FWHT Flags -============ - -.. cssclass:: longtable - -.. tabularcolumns:: |p{6.8cm}|p{2.4cm}|p{8.3cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 3 1 4 - - * - ``V4L2_FWHT_FL_IS_INTERLACED`` - - 0x00000001 - - Set if this is an interlaced format - * - ``V4L2_FWHT_FL_IS_BOTTOM_FIRST`` - - 0x00000002 - - Set if this is a bottom-first (NTSC) interlaced format - * - ``V4L2_FWHT_FL_IS_ALTERNATE`` - - 0x00000004 - - Set if each 'frame' contains just one field - * - ``V4L2_FWHT_FL_IS_BOTTOM_FIELD`` - - 0x00000008 - - If V4L2_FWHT_FL_IS_ALTERNATE was set, then this is set if this 'frame' is the - bottom field, else it is the top field. - * - ``V4L2_FWHT_FL_LUMA_IS_UNCOMPRESSED`` - - 0x00000010 - - Set if the luma plane is uncompressed - * - ``V4L2_FWHT_FL_CB_IS_UNCOMPRESSED`` - - 0x00000020 - - Set if the cb plane is uncompressed - * - ``V4L2_FWHT_FL_CR_IS_UNCOMPRESSED`` - - 0x00000040 - - Set if the cr plane is uncompressed - * - ``V4L2_FWHT_FL_CHROMA_FULL_HEIGHT`` - - 0x00000080 - - Set if the chroma plane has the same height as the luma plane, - else the chroma plane is half the height of the luma plane - * - ``V4L2_FWHT_FL_CHROMA_FULL_WIDTH`` - - 0x00000100 - - Set if the chroma plane has the same width as the luma plane, - else the chroma plane is half the width of the luma plane - * - ``V4L2_FWHT_FL_ALPHA_IS_UNCOMPRESSED`` - - 0x00000200 - - Set if the alpha plane is uncompressed - * - ``V4L2_FWHT_FL_I_FRAME`` - - 0x00000400 - - Set if this is an I-frame - * - ``V4L2_FWHT_FL_COMPONENTS_NUM_MSK`` - - 0x00070000 - - A 4-values flag - the number of components - 1 - * - ``V4L2_FWHT_FL_PIXENC_YUV`` - - 0x00080000 - - Set if the pixel encoding is YUV - * - ``V4L2_FWHT_FL_PIXENC_RGB`` - - 0x00100000 - - Set if the pixel encoding is RGB - * - ``V4L2_FWHT_FL_PIXENC_HSV`` - - 0x00180000 - - Set if the pixel encoding is HSV - - CX2341x MPEG Controls ===================== -- cgit v1.2.3 From 63288c829b1a5991d8f8c15cab596108ed206ba6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 26 Nov 2020 14:12:03 +0100 Subject: media: pixfmt-compressed.rst: fix 'bullet' formatting Drop the 'bullets' for the HEVC stateless codec documentation. It doesn't work, and they just show up as asterisks. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/v4l/pixfmt-compressed.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst b/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst index b8899262d8de..4ae737520925 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst @@ -191,10 +191,10 @@ Compressed Formats through the ``V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE`` and ``V4L2_CID_MPEG_VIDEO_HEVC_START_CODE`` controls. Metadata associated with the frame to decode is required to be passed - through the following controls : - * ``V4L2_CID_MPEG_VIDEO_HEVC_SPS`` - * ``V4L2_CID_MPEG_VIDEO_HEVC_PPS`` - * ``V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS`` + through the following controls: + ``V4L2_CID_MPEG_VIDEO_HEVC_SPS``, + ``V4L2_CID_MPEG_VIDEO_HEVC_PPS``, and + ``V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS``. See the :ref:`associated Codec Control IDs `. Buffers associated with this pixel format must contain the appropriate number of macroblocks to decode a full corresponding frame. -- cgit v1.2.3 From 63e799b98042e06bec191d2e2079d04590a18a1e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 26 Nov 2020 14:27:16 +0100 Subject: media: vidioc-g-ext-ctrls.rst: add missing 'struct' before the types Add 'struct' to clarify that these are pointers to structs. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/vidioc-g-ext-ctrls.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst index a4e7e67cd8ce..5dea5bce0632 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst @@ -180,31 +180,31 @@ still cause this situation. - ``p_u32`` - A pointer to a matrix control of unsigned 32-bit values. Valid if this control is of type ``V4L2_CTRL_TYPE_U32``. - * - :c:type:`v4l2_area` * + * - struct :c:type:`v4l2_area` * - ``p_area`` - A pointer to a struct :c:type:`v4l2_area`. Valid if this control is of type ``V4L2_CTRL_TYPE_AREA``. - * - :c:type:`v4l2_ctrl_h264_sps` * + * - struct :c:type:`v4l2_ctrl_h264_sps` * - ``p_h264_sps`` - A pointer to a struct :c:type:`v4l2_ctrl_h264_sps`. Valid if this control is of type ``V4L2_CTRL_TYPE_H264_SPS``. - * - :c:type:`v4l2_ctrl_h264_pps` * + * - struct :c:type:`v4l2_ctrl_h264_pps` * - ``p_h264_pps`` - A pointer to a struct :c:type:`v4l2_ctrl_h264_pps`. Valid if this control is of type ``V4L2_CTRL_TYPE_H264_PPS``. - * - :c:type:`v4l2_ctrl_h264_scaling_matrix` * + * - struct :c:type:`v4l2_ctrl_h264_scaling_matrix` * - ``p_h264_scaling_matrix`` - A pointer to a struct :c:type:`v4l2_ctrl_h264_scaling_matrix`. Valid if this control is of type ``V4L2_CTRL_TYPE_H264_SCALING_MATRIX``. - * - :c:type:`v4l2_ctrl_h264_pred_weights` * + * - struct :c:type:`v4l2_ctrl_h264_pred_weights` * - ``p_h264_pred_weights`` - A pointer to a struct :c:type:`v4l2_ctrl_h264_pred_weights`. Valid if this control is of type ``V4L2_CTRL_TYPE_H264_PRED_WEIGHTS``. - * - :c:type:`v4l2_ctrl_h264_slice_params` * + * - struct :c:type:`v4l2_ctrl_h264_slice_params` * - ``p_h264_slice_params`` - A pointer to a struct :c:type:`v4l2_ctrl_h264_slice_params`. Valid if this control is of type ``V4L2_CTRL_TYPE_H264_SLICE_PARAMS``. - * - :c:type:`v4l2_ctrl_h264_decode_params` * + * - struct :c:type:`v4l2_ctrl_h264_decode_params` * - ``p_h264_decode_params`` - A pointer to a struct :c:type:`v4l2_ctrl_h264_decode_params`. Valid if this control is of type ``V4L2_CTRL_TYPE_H264_DECODE_PARAMS``. -- cgit v1.2.3 From 4a85d1cbaa284c518a3748115759fe1dfe036a23 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 26 Nov 2020 14:27:17 +0100 Subject: media: userspace-api/media: finalize stateless FWHT codec docs Document V4L2_CTRL_TYPE_FWHT_PARAMS and p_fwht_params. Also improve the V4L2_PIX_FMT_FWHT_STATELESS description. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/v4l/pixfmt-compressed.rst | 4 +++- Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst | 4 ++++ Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst | 6 ++++++ Documentation/userspace-api/media/videodev2.h.rst.exceptions | 1 + 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst b/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst index 4ae737520925..acad5f3ca0c1 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-compressed.rst @@ -217,4 +217,6 @@ Compressed Formats - ``V4L2_PIX_FMT_FWHT_STATELESS`` - 'SFWH' - Same format as V4L2_PIX_FMT_FWHT but requires stateless codec implementation. - See the :ref:`associated Codec Control IDs `. + Metadata associated with the frame to decode is required to be passed + through the ``V4L2_CID_STATELESS_FWHT_PARAMS`` control. + See the :ref:`associated Codec Control ID `. diff --git a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst index 5dea5bce0632..b9c62affbb5a 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst @@ -208,6 +208,10 @@ still cause this situation. - ``p_h264_decode_params`` - A pointer to a struct :c:type:`v4l2_ctrl_h264_decode_params`. Valid if this control is of type ``V4L2_CTRL_TYPE_H264_DECODE_PARAMS``. + * - struct :c:type:`v4l2_ctrl_fwht_params` * + - ``p_fwht_params`` + - A pointer to a struct :c:type:`v4l2_ctrl_fwht_params`. Valid if this control is + of type ``V4L2_CTRL_TYPE_FWHT_PARAMS``. * - void * - ``ptr`` - A pointer to a compound type which can be an N-dimensional array diff --git a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst index 9b8716f90f12..82f61f1e2fb8 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst @@ -462,6 +462,12 @@ See also the examples in :ref:`control`. - n/a - A struct :c:type:`v4l2_ctrl_h264_decode_params`, containing H264 decode parameters for stateless video decoders. + * - ``V4L2_CTRL_TYPE_FWHT_PARAMS`` + - n/a + - n/a + - n/a + - A struct :c:type:`v4l2_ctrl_fwht_params`, containing FWHT + parameters for stateless video decoders. * - ``V4L2_CTRL_TYPE_HEVC_SPS`` - n/a - n/a diff --git a/Documentation/userspace-api/media/videodev2.h.rst.exceptions b/Documentation/userspace-api/media/videodev2.h.rst.exceptions index 7f6a4cc2ac4e..0ed170c6e720 100644 --- a/Documentation/userspace-api/media/videodev2.h.rst.exceptions +++ b/Documentation/userspace-api/media/videodev2.h.rst.exceptions @@ -146,6 +146,7 @@ replace symbol V4L2_CTRL_TYPE_HEVC_SPS :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_HEVC_PPS :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_AREA :c:type:`v4l2_ctrl_type` +replace symbol V4L2_CTRL_TYPE_FWHT_PARAMS :c:type:`v4l2_ctrl_type` # V4L2 capability defines replace define V4L2_CAP_VIDEO_CAPTURE device-capabilities -- cgit v1.2.3 From 38d8dfe0a9e16c2260d1325afd7465215e4fd278 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 3 Dec 2020 13:50:33 +0100 Subject: media: pixfmt-meta-rkisp1.rst: fix two build warnings With Sphinx 2.x: those two warnings are produced: /devel/v4l/docs/sphinx2/Documentation/output/videodev2.h.rst:6: WARNING: undefined label: v4l2-meta-fmt-rk-isp1-params (if the link has no caption the label must precede a section header) /devel/v4l/docs/sphinx2/Documentation/output/videodev2.h.rst:6: WARNING: undefined label: v4l2-meta-fmt-rk-isp1-stat-3a (if the link has no caption the label must precede a section header) The reason is that there's no blank line between the two identifiers. Fixes: 3f46cac6787f ("media: admin-guide/pixfmt-meta-rkisp1.rst: pixfmt reference conforming with macro") Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/v4l/pixfmt-meta-rkisp1.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/userspace-api/media/v4l/pixfmt-meta-rkisp1.rst b/Documentation/userspace-api/media/v4l/pixfmt-meta-rkisp1.rst index 922fa1d59898..fa04f00bcd2e 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-meta-rkisp1.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-meta-rkisp1.rst @@ -1,6 +1,7 @@ .. SPDX-License-Identifier: GPL-2.0 .. _v4l2-meta-fmt-rk-isp1-params: + .. _v4l2-meta-fmt-rk-isp1-stat-3a: ***************************************************************************** -- cgit v1.2.3 From d5da31f902feb3c53c1e79eb3bf9792a761c8d84 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Fri, 27 Nov 2020 05:56:27 +0100 Subject: media: rc: add keymap for pine64 remote Add a keymap for the pine64 IR remote [0]. The mouse key has been mapped to KEY_EPG to provide a more useful remote. [0] http://files.pine64.org/doc/Pine%20A64%20Schematic/remote-wit-logo.jpg Signed-off-by: Jonas Karlman Signed-off-by: Christian Hewitt Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/rc.yaml | 1 + drivers/media/rc/keymaps/Makefile | 1 + drivers/media/rc/keymaps/rc-pine64.c | 65 +++++++++++++++++++++++++ include/media/rc-map.h | 1 + 4 files changed, 68 insertions(+) create mode 100644 drivers/media/rc/keymaps/rc-pine64.c diff --git a/Documentation/devicetree/bindings/media/rc.yaml b/Documentation/devicetree/bindings/media/rc.yaml index 03cf40f91d6c..946441b4e1a5 100644 --- a/Documentation/devicetree/bindings/media/rc.yaml +++ b/Documentation/devicetree/bindings/media/rc.yaml @@ -103,6 +103,7 @@ properties: - rc-npgtech - rc-odroid - rc-pctv-sedna + - rc-pine64 - rc-pinnacle-color - rc-pinnacle-grey - rc-pinnacle-pctv-hd diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index 1c4d6bec0ae4..b252a1d2ebd6 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -80,6 +80,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-npgtech.o \ rc-odroid.o \ rc-pctv-sedna.o \ + rc-pine64.o \ rc-pinnacle-color.o \ rc-pinnacle-grey.o \ rc-pinnacle-pctv-hd.o \ diff --git a/drivers/media/rc/keymaps/rc-pine64.c b/drivers/media/rc/keymaps/rc-pine64.c new file mode 100644 index 000000000000..9b2bdbbce04e --- /dev/null +++ b/drivers/media/rc/keymaps/rc-pine64.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0+ + +// Keytable for the Pine64 IR Remote Controller +// Copyright (c) 2017 Jonas Karlman + +#include +#include + +static struct rc_map_table pine64[] = { + { 0x40404d, KEY_POWER }, + { 0x40401f, KEY_WWW }, + { 0x40400a, KEY_MUTE }, + + { 0x404017, KEY_VOLUMEDOWN }, + { 0x404018, KEY_VOLUMEUP }, + + { 0x404010, KEY_LEFT }, + { 0x404011, KEY_RIGHT }, + { 0x40400b, KEY_UP }, + { 0x40400e, KEY_DOWN }, + { 0x40400d, KEY_OK }, + + { 0x40401d, KEY_MENU }, + { 0x40401a, KEY_HOME }, + + { 0x404045, KEY_BACK }, + + { 0x404001, KEY_NUMERIC_1 }, + { 0x404002, KEY_NUMERIC_2 }, + { 0x404003, KEY_NUMERIC_3 }, + { 0x404004, KEY_NUMERIC_4 }, + { 0x404005, KEY_NUMERIC_5 }, + { 0x404006, KEY_NUMERIC_6 }, + { 0x404007, KEY_NUMERIC_7 }, + { 0x404008, KEY_NUMERIC_8 }, + { 0x404009, KEY_NUMERIC_9 }, + { 0x40400c, KEY_BACKSPACE }, + { 0x404000, KEY_NUMERIC_0 }, + { 0x404047, KEY_EPG }, // mouse +}; + +static struct rc_map_list pine64_map = { + .map = { + .scan = pine64, + .size = ARRAY_SIZE(pine64), + .rc_proto = RC_PROTO_NECX, + .name = RC_MAP_PINE64, + } +}; + +static int __init init_rc_map_pine64(void) +{ + return rc_map_register(&pine64_map); +} + +static void __exit exit_rc_map_pine64(void) +{ + rc_map_unregister(&pine64_map); +} + +module_init(init_rc_map_pine64) +module_exit(exit_rc_map_pine64) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jonas Karlman"); diff --git a/include/media/rc-map.h b/include/media/rc-map.h index fa270f16a97b..999b750bc6b8 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -283,6 +283,7 @@ struct rc_map *rc_map_get(const char *name); #define RC_MAP_NPGTECH "rc-npgtech" #define RC_MAP_ODROID "rc-odroid" #define RC_MAP_PCTV_SEDNA "rc-pctv-sedna" +#define RC_MAP_PINE64 "rc-pine64" #define RC_MAP_PINNACLE_COLOR "rc-pinnacle-color" #define RC_MAP_PINNACLE_GREY "rc-pinnacle-grey" #define RC_MAP_PINNACLE_PCTV_HD "rc-pinnacle-pctv-hd" -- cgit v1.2.3 From f0f547272079a8ee2a3929909e1a7ae374b61e38 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 2 Dec 2020 19:09:54 +0100 Subject: media: Revert "media: dt-bindings: media: Use OF graph schema" This reverts commit f61eb7bc9256aeb173d2d730f59cdd569d261c52. While aligning with the OF graph schema will be done for the media DT bindings, this patch got merged a little too hastily. Revert it for now. Suggested-by: Rob Herring Signed-off-by: Sakari Ailus Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/allwinner,sun4i-a10-csi.yaml | 1 - .../bindings/media/allwinner,sun6i-a31-csi.yaml | 1 - .../devicetree/bindings/media/i2c/adv7180.yaml | 31 +++++++-- .../devicetree/bindings/media/i2c/adv7604.yaml | 32 +++++++-- .../bindings/media/i2c/aptina,mt9v111.yaml | 2 +- .../bindings/media/i2c/imi,rdacm2x-gmsl.yaml | 25 ++++++- .../devicetree/bindings/media/i2c/imx219.yaml | 4 -- .../bindings/media/i2c/maxim,max9286.yaml | 76 +++++++++++++++++----- .../devicetree/bindings/media/i2c/ov5647.yaml | 5 +- .../devicetree/bindings/media/i2c/ov8856.yaml | 5 +- .../devicetree/bindings/media/i2c/ovti,ov772x.yaml | 1 - .../devicetree/bindings/media/i2c/sony,imx214.yaml | 1 - .../devicetree/bindings/media/i2c/sony,imx274.yaml | 3 +- .../bindings/media/marvell,mmp2-ccic.yaml | 1 - .../devicetree/bindings/media/renesas,ceu.yaml | 1 - .../devicetree/bindings/media/renesas,csi2.yaml | 36 ++++++++-- .../devicetree/bindings/media/renesas,vin.yaml | 7 +- .../devicetree/bindings/media/st,stm32-dcmi.yaml | 7 +- .../devicetree/bindings/media/ti,cal.yaml | 15 +++-- .../bindings/media/xilinx/xlnx,csi2rxss.yaml | 21 +++++- 20 files changed, 214 insertions(+), 61 deletions(-) diff --git a/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml b/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml index 0205f7dd7fdb..09318830db47 100644 --- a/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml +++ b/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml @@ -70,7 +70,6 @@ properties: # See ./video-interfaces.txt for details port: type: object - $ref: /schemas/graph.yaml#/properties/port additionalProperties: false properties: diff --git a/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml b/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml index 48d8f73ce7ab..1fd9b5532a21 100644 --- a/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml +++ b/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml @@ -43,7 +43,6 @@ properties: # See ./video-interfaces.txt for details port: type: object - $ref: /schemas/graph.yaml#/properties/port properties: endpoint: diff --git a/Documentation/devicetree/bindings/media/i2c/adv7180.yaml b/Documentation/devicetree/bindings/media/i2c/adv7180.yaml index 7f28954a4508..d8c54f9d9506 100644 --- a/Documentation/devicetree/bindings/media/i2c/adv7180.yaml +++ b/Documentation/devicetree/bindings/media/i2c/adv7180.yaml @@ -36,9 +36,17 @@ properties: maxItems: 1 port: - $ref: /schemas/graph.yaml#/properties/port - - ports: true + type: object + description: + A node containing a single endpoint as doucmented in + Documentation/devicetree/bindings/media/video-interfaces.txt + + ports: + type: object + description: + A node containing input and output port nodes with endpoint definitions + as documented in + Documentation/devicetree/bindings/media/video-interfaces.txt additionalProperties: false @@ -72,19 +80,24 @@ allOf: then: properties: ports: - $ref: /schemas/graph.yaml#/properties/ports properties: + '#address-cells': + const: 1 + '#size-cells': + const: 0 port@3: + type: object description: Output port patternProperties: "^port@[0-2]$": + type: object description: Input port required: - port@3 - unevaluatedProperties: false + additionalProperties: false required: - ports @@ -97,20 +110,24 @@ allOf: then: properties: ports: - $ref: /schemas/graph.yaml#/properties/ports properties: + '#address-cells': + const: 1 + '#size-cells': + const: 0 port@6: type: object description: Output port patternProperties: "^port@[0-5]$": + type: object description: Input port required: - port@6 - unevaluatedProperties: false + additionalProperties: false required: - ports diff --git a/Documentation/devicetree/bindings/media/i2c/adv7604.yaml b/Documentation/devicetree/bindings/media/i2c/adv7604.yaml index 81f17e719d87..3897af540ddd 100644 --- a/Documentation/devicetree/bindings/media/i2c/adv7604.yaml +++ b/Documentation/devicetree/bindings/media/i2c/adv7604.yaml @@ -64,12 +64,16 @@ properties: description: Select which input is selected after reset. - ports: true + ports: + type: object + description: + A node containing input and output port nodes with endpoint definitions + as documented in + Documentation/devicetree/bindings/media/video-interfaces.txt required: - compatible - reg - - ports additionalProperties: false @@ -82,17 +86,25 @@ allOf: then: properties: ports: - $ref: /schemas/graph.yaml#/properties/ports properties: + '#address-cells': + const: 1 + '#size-cells': + const: 0 port@0: + type: object description: Input port port@1: + type: object description: Output port required: - port@1 - unevaluatedProperties: false + additionalProperties: false + + required: + - ports - if: properties: @@ -102,19 +114,27 @@ allOf: then: properties: ports: - $ref: /schemas/graph.yaml#/properties/ports properties: + '#address-cells': + const: 1 + '#size-cells': + const: 0 port@2: + type: object description: Output port patternProperties: "^port@[0-1]$": + type: object description: Input port required: - port@2 - unevaluatedProperties: false + additionalProperties: false + + required: + - ports examples: - | diff --git a/Documentation/devicetree/bindings/media/i2c/aptina,mt9v111.yaml b/Documentation/devicetree/bindings/media/i2c/aptina,mt9v111.yaml index 17ec4ab1dbd0..ff9546e95d05 100644 --- a/Documentation/devicetree/bindings/media/i2c/aptina,mt9v111.yaml +++ b/Documentation/devicetree/bindings/media/i2c/aptina,mt9v111.yaml @@ -41,7 +41,7 @@ properties: maxItems: 1 port: - $ref: /schemas/graph.yaml#/properties/port + type: object description: | Output video port. See ../video-interfaces.txt. diff --git a/Documentation/devicetree/bindings/media/i2c/imi,rdacm2x-gmsl.yaml b/Documentation/devicetree/bindings/media/i2c/imi,rdacm2x-gmsl.yaml index e0ea3acca89a..3dc06c628e64 100644 --- a/Documentation/devicetree/bindings/media/i2c/imi,rdacm2x-gmsl.yaml +++ b/Documentation/devicetree/bindings/media/i2c/imi,rdacm2x-gmsl.yaml @@ -86,12 +86,33 @@ properties: maxItems: 3 port: - $ref: /schemas/graph.yaml#/properties/port - description: + type: object + additionalProperties: false + description: -| Connection to the remote GMSL endpoint are modelled using the OF graph bindings in accordance with the video interface bindings defined in Documentation/devicetree/bindings/media/video-interfaces.txt. + The device node contains a single "port" child node with a single + "endpoint" sub-device. + + properties: + endpoint: + type: object + additionalProperties: false + + properties: + remote-endpoint: + description: -| + phandle to the remote GMSL endpoint sub-node in the remote node + port. + maxItems: 1 + + required: + - remote-endpoint + + required: + - endpoint required: - compatible diff --git a/Documentation/devicetree/bindings/media/i2c/imx219.yaml b/Documentation/devicetree/bindings/media/i2c/imx219.yaml index bba42e015c98..dfc4d29a4f04 100644 --- a/Documentation/devicetree/bindings/media/i2c/imx219.yaml +++ b/Documentation/devicetree/bindings/media/i2c/imx219.yaml @@ -47,8 +47,6 @@ properties: # See ../video-interfaces.txt for more details port: type: object - $ref: /schemas/graph.yaml#/properties/port - properties: endpoint: type: object @@ -76,8 +74,6 @@ properties: required: - link-frequencies - additionalProperties: false - required: - compatible - reg diff --git a/Documentation/devicetree/bindings/media/i2c/maxim,max9286.yaml b/Documentation/devicetree/bindings/media/i2c/maxim,max9286.yaml index 2e89a5458afe..9ea827092fdd 100644 --- a/Documentation/devicetree/bindings/media/i2c/maxim,max9286.yaml +++ b/Documentation/devicetree/bindings/media/i2c/maxim,max9286.yaml @@ -53,25 +53,56 @@ properties: ports: type: object - $ref: /schemas/graph.yaml#/properties/ports + description: | + The connections to the MAX9286 GMSL and its endpoint nodes are modelled + using the OF graph bindings in accordance with the video interface + bindings defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. + + The following table lists the port number corresponding to each device + port. + + Port Description + ---------------------------------------- + Port 0 GMSL Input 0 + Port 1 GMSL Input 1 + Port 2 GMSL Input 2 + Port 3 GMSL Input 3 + Port 4 CSI-2 Output properties: - port@0: - description: GMSL Input 0 + '#address-cells': + const: 1 + + '#size-cells': + const: 0 - port@1: - description: GMSL Input 1 + port@[0-3]: + type: object + properties: + reg: + enum: [ 0, 1, 2, 3 ] - port@2: - description: GMSL Input 2 + endpoint: + type: object - port@3: - description: GMSL Input 3 + properties: + remote-endpoint: + description: | + phandle to the remote GMSL source endpoint subnode in the + remote node port. + + required: + - remote-endpoint + + required: + - reg + - endpoint + + additionalProperties: false port@4: type: object - description: CSI-2 Output - properties: reg: const: 4 @@ -99,8 +130,6 @@ properties: required: - port@4 - unevaluatedProperties: false - i2c-mux: type: object description: | @@ -155,8 +184,25 @@ properties: requirements of the currently connected remote device. port: - $ref: /schemas/graph.yaml#/properties/port - description: Connection to the MAX9286 sink. + type: object + + properties: + endpoint: + type: object + + properties: + remote-endpoint: + description: phandle to the MAX9286 sink endpoint. + + required: + - remote-endpoint + + additionalProperties: false + + required: + - endpoint + + additionalProperties: false required: - compatible diff --git a/Documentation/devicetree/bindings/media/i2c/ov5647.yaml b/Documentation/devicetree/bindings/media/i2c/ov5647.yaml index cd5291602a70..280c62afae13 100644 --- a/Documentation/devicetree/bindings/media/i2c/ov5647.yaml +++ b/Documentation/devicetree/bindings/media/i2c/ov5647.yaml @@ -32,7 +32,10 @@ properties: port: type: object - $ref: /schemas/graph.yaml#/properties/port + description: |- + Should contain one endpoint sub-node used to model connection to the + video receiver according to the specification defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. properties: endpoint: diff --git a/Documentation/devicetree/bindings/media/i2c/ov8856.yaml b/Documentation/devicetree/bindings/media/i2c/ov8856.yaml index 2611eb69b3b2..cde85553fd01 100644 --- a/Documentation/devicetree/bindings/media/i2c/ov8856.yaml +++ b/Documentation/devicetree/bindings/media/i2c/ov8856.yaml @@ -58,8 +58,11 @@ properties: port: type: object - $ref: /schemas/graph.yaml#/properties/port additionalProperties: false + description: + A node containing an output port node with an endpoint definition + as documented in + Documentation/devicetree/bindings/media/video-interfaces.txt properties: endpoint: diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml index 450e5bd64312..63b3779d7289 100644 --- a/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml @@ -38,7 +38,6 @@ properties: port: type: object - $ref: /schemas/graph.yaml#/properties/port description: | Video output port. See ../video-interfaces.txt. diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml index 884bd3527e0a..0f5e25fa4e9d 100644 --- a/Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml @@ -55,7 +55,6 @@ properties: port: type: object - $ref: /schemas/graph.yaml#/properties/port description: | Video output port. See ../video-interfaces.txt. diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx274.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx274.yaml index 90828020e42a..f697e1a20beb 100644 --- a/Documentation/devicetree/bindings/media/i2c/sony,imx274.yaml +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx274.yaml @@ -44,7 +44,8 @@ properties: maxItems: 1 port: - $ref: /schemas/graph.yaml#/properties/port + type: object + description: Output video port. See ../video-interfaces.txt. required: - compatible diff --git a/Documentation/devicetree/bindings/media/marvell,mmp2-ccic.yaml b/Documentation/devicetree/bindings/media/marvell,mmp2-ccic.yaml index 4832f55654cc..49bff738aca5 100644 --- a/Documentation/devicetree/bindings/media/marvell,mmp2-ccic.yaml +++ b/Documentation/devicetree/bindings/media/marvell,mmp2-ccic.yaml @@ -25,7 +25,6 @@ properties: port: type: object - $ref: /schemas/graph.yaml#/properties/port additionalProperties: false properties: diff --git a/Documentation/devicetree/bindings/media/renesas,ceu.yaml b/Documentation/devicetree/bindings/media/renesas,ceu.yaml index 2d493d503d07..c7e1e4fe67e6 100644 --- a/Documentation/devicetree/bindings/media/renesas,ceu.yaml +++ b/Documentation/devicetree/bindings/media/renesas,ceu.yaml @@ -35,7 +35,6 @@ properties: port: type: object - $ref: /schemas/graph.yaml#/properties/port additionalProperties: false properties: diff --git a/Documentation/devicetree/bindings/media/renesas,csi2.yaml b/Documentation/devicetree/bindings/media/renesas,csi2.yaml index e34dfbef25a2..533c2f181db7 100644 --- a/Documentation/devicetree/bindings/media/renesas,csi2.yaml +++ b/Documentation/devicetree/bindings/media/renesas,csi2.yaml @@ -47,7 +47,10 @@ properties: ports: type: object - $ref: /schemas/graph.yaml#/properties/ports + description: + A node containing input and output port nodes with endpoint definitions + as documented in + Documentation/devicetree/bindings/media/video-interfaces.txt properties: port@0: @@ -81,15 +84,38 @@ properties: additionalProperties: false port@1: + type: object description: Output port node, multiple endpoints describing all the R-Car VIN modules connected the CSI-2 receiver. - required: - - port@0 - - port@1 + properties: + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + + reg: + const: 1 + + patternProperties: + "^endpoint@[0-9a-f]$": + type: object - unevaluatedProperties: false + properties: + reg: + maxItems: 1 + + remote-endpoint: true + + required: + - reg + - remote-endpoint + + additionalProperties: false + + additionalProperties: false required: - compatible diff --git a/Documentation/devicetree/bindings/media/renesas,vin.yaml b/Documentation/devicetree/bindings/media/renesas,vin.yaml index 25a70dc89a4c..ad2fe660364b 100644 --- a/Documentation/devicetree/bindings/media/renesas,vin.yaml +++ b/Documentation/devicetree/bindings/media/renesas,vin.yaml @@ -70,7 +70,6 @@ properties: #The per-board settings for Gen2 and RZ/G1 platforms: port: type: object - $ref: /schemas/graph.yaml#/properties/port description: A node containing a parallel input with a single endpoint definitions as documented in @@ -125,7 +124,9 @@ properties: ports: type: object - $ref: /schemas/graph.yaml#/properties/ports + description: + A node containing input nodes with endpoint definitions as documented in + Documentation/devicetree/bindings/media/video-interfaces.txt properties: port@0: @@ -271,8 +272,6 @@ properties: additionalProperties: false - unevaluatedProperties: false - required: - compatible - reg diff --git a/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml b/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml index e3152c8fdfea..c18574bb3e81 100644 --- a/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml +++ b/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml @@ -37,9 +37,12 @@ properties: maxItems: 1 port: - $ref: /schemas/graph.yaml#/properties/port + type: object description: - DCMI supports a single port node with parallel bus. + DCMI supports a single port node with parallel bus. It should contain + one 'port' child node with child 'endpoint' node. Please refer to the + bindings defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. properties: endpoint: diff --git a/Documentation/devicetree/bindings/media/ti,cal.yaml b/Documentation/devicetree/bindings/media/ti,cal.yaml index dc2c6be4fa4d..5e066629287d 100644 --- a/Documentation/devicetree/bindings/media/ti,cal.yaml +++ b/Documentation/devicetree/bindings/media/ti,cal.yaml @@ -70,18 +70,23 @@ properties: # See ./video-interfaces.txt for details ports: type: object - $ref: /schemas/graph.yaml#/properties/ports - unevaluatedProperties: false + additionalProperties: false properties: + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + port@0: type: object - description: CSI2 Port #0 additionalProperties: false properties: reg: const: 0 + description: CSI2 Port #0 patternProperties: endpoint: @@ -103,12 +108,12 @@ properties: port@1: type: object - description: CSI2 Port #1 additionalProperties: false properties: reg: const: 1 + description: CSI2 Port #1 patternProperties: endpoint: @@ -129,6 +134,8 @@ properties: - reg required: + - "#address-cells" + - "#size-cells" - port@0 required: diff --git a/Documentation/devicetree/bindings/media/xilinx/xlnx,csi2rxss.yaml b/Documentation/devicetree/bindings/media/xilinx/xlnx,csi2rxss.yaml index 0868718c3691..2961a5b6872f 100644 --- a/Documentation/devicetree/bindings/media/xilinx/xlnx,csi2rxss.yaml +++ b/Documentation/devicetree/bindings/media/xilinx/xlnx,csi2rxss.yaml @@ -98,7 +98,6 @@ properties: ports: type: object - $ref: /schemas/graph.yaml#/properties/ports properties: port@0: @@ -142,11 +141,29 @@ properties: additionalProperties: false port@1: + type: object description: | Output / source port node, endpoint describing modules connected the CSI-2 receiver. - unevaluatedProperties: false + properties: + + reg: + const: 1 + + endpoint: + type: object + + properties: + + remote-endpoint: true + + required: + - remote-endpoint + + additionalProperties: false + + additionalProperties: false required: - compatible -- cgit v1.2.3 From cc17afa2e84f5017bae646a7240b6a43e847a2d7 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 4 Dec 2020 09:20:14 +0100 Subject: media: i2c: fix an uninitialized error code Clang points out that the error handling in ov02a10_s_stream() is broken, and just returns a random error code: drivers/media/i2c/ov02a10.c:537:6: warning: variable 'ret' is used uninitialized whenever 'if' condition is true [-Wsometimes-uninitialized] if (ov02a10->streaming == on) ^~~~~~~~~~~~~~~~~~~~~~~~ drivers/media/i2c/ov02a10.c:568:9: note: uninitialized use occurs here return ret; ^~~ drivers/media/i2c/ov02a10.c:537:2: note: remove the 'if' if its condition is always false if (ov02a10->streaming == on) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If streaming is already on, leave it that way and return success. Suggested-by: Dongchun Zhu Fixes: 91807efbe8ec ("media: i2c: add OV02A10 image sensor driver") Signed-off-by: Arnd Bergmann Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov02a10.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov02a10.c b/drivers/media/i2c/ov02a10.c index 391718136ade..8683ffd3287a 100644 --- a/drivers/media/i2c/ov02a10.c +++ b/drivers/media/i2c/ov02a10.c @@ -534,8 +534,10 @@ static int ov02a10_s_stream(struct v4l2_subdev *sd, int on) mutex_lock(&ov02a10->mutex); - if (ov02a10->streaming == on) + if (ov02a10->streaming == on) { + ret = 0; goto unlock_and_return; + } if (on) { ret = pm_runtime_get_sync(&client->dev); -- cgit v1.2.3 From 747d2305029ab9a47eb01beb9d537b69f5a51a94 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 3 Dec 2020 23:28:16 +0100 Subject: media: ccs: avoid printing an uninitialized variable There is no intialization for the 'reg' variable, so printing it produces undefined behavior as well as a compile-time warning: drivers/media/i2c/ccs/ccs-core.c:314:49: error: variable 'reg' is uninitialized when used here [-Werror,-Wuninitialized] "0x%8.8x %s pixels: %d %s (pixelcode %u)\n", reg, Remove the variable and stop printing it. Fixes: fd9065812c7b ("media: smiapp: Obtain frame descriptor from CCS limits") Signed-off-by: Arnd Bergmann Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 4447ca367a84..7a461c0a730d 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -268,7 +268,6 @@ static int ccs_read_frame_fmt(struct ccs_sensor *sensor) u32 pixels; char *which; char *what; - u32 reg; if (fmt_model_type == CCS_FRAME_FORMAT_MODEL_TYPE_2_BYTE) { desc = CCS_LIM_AT(sensor, FRAME_FORMAT_DESCRIPTOR, i); @@ -322,7 +321,7 @@ static int ccs_read_frame_fmt(struct ccs_sensor *sensor) } dev_dbg(&client->dev, - "0x%8.8x %s pixels: %d %s (pixelcode %u)\n", reg, + "%s pixels: %d %s (pixelcode %u)\n", what, pixels, which, pixelcode); if (i < ncol_desc) { -- cgit v1.2.3 From bd1ed17d19eba00792cb29f369b8c29da1008d38 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 4 Dec 2020 12:46:56 +0100 Subject: media: ccs: Fix return value from probe rval wasn't set, resulting in probe returning zero instead of an error. Fixes: de10c1619c48 ("[media] smiapp: Get clock rate if it's not available through DT") Reported-by: Zhang Changzhong Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 7a461c0a730d..5f69e4c44533 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -3030,7 +3030,7 @@ static int ccs_probe(struct i2c_client *client) dev_err(&client->dev, "can't set clock freq, asked for %u but got %lu\n", sensor->hwcfg.ext_clk, rate); - return rval; + return -EINVAL; } } else { sensor->hwcfg.ext_clk = clk_get_rate(sensor->ext_clk); -- cgit v1.2.3 From 3771c031d60f790aba18f16b058ed23a5ac20bd6 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 7 Dec 2020 00:03:01 +0100 Subject: media: videodev2.h: Remove unneeded comment about 4CC value The V4L2_PIX_FMT_BGRA444 format has a comment that explains why its 4CC value is GA12. This explains the development history and isn't of much interest to readers, it should have been part of a commit message instead. Drop the comment, anyone interested in history can turn to git. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/videodev2.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index e40e95be79f9..3f58ab463f6c 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -524,12 +524,6 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_RGBX444 v4l2_fourcc('R', 'X', '1', '2') /* 16 rrrrgggg bbbbxxxx */ #define V4L2_PIX_FMT_ABGR444 v4l2_fourcc('A', 'B', '1', '2') /* 16 aaaabbbb ggggrrrr */ #define V4L2_PIX_FMT_XBGR444 v4l2_fourcc('X', 'B', '1', '2') /* 16 xxxxbbbb ggggrrrr */ - -/* - * Originally this had 'BA12' as fourcc, but this clashed with the older - * V4L2_PIX_FMT_SGRBG12 which inexplicably used that same fourcc. - * So use 'GA12' instead for V4L2_PIX_FMT_BGRA444. - */ #define V4L2_PIX_FMT_BGRA444 v4l2_fourcc('G', 'A', '1', '2') /* 16 bbbbgggg rrrraaaa */ #define V4L2_PIX_FMT_BGRX444 v4l2_fourcc('B', 'X', '1', '2') /* 16 bbbbgggg rrrrxxxx */ #define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R', 'G', 'B', 'O') /* 16 RGB-5-5-5 */ -- cgit v1.2.3 From 0a078e0d8ecb0ca0296755399c3a8f38b60c7b23 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 7 Dec 2020 00:03:02 +0100 Subject: media: videodev2.h: Move HI240 format to vendor-specific section V4L2_PIX_FMT_HI240 is a 8-bit dithered RGB format specific to BTTV. Move it from the packed YUV formats section where it was misplaced to the vendor-specific formats section. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/videodev2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 3f58ab463f6c..01140ac57be2 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -589,7 +589,6 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_XYUV32 v4l2_fourcc('X', 'Y', 'U', 'V') /* 32 XYUV-8-8-8-8 */ #define V4L2_PIX_FMT_VUYA32 v4l2_fourcc('V', 'U', 'Y', 'A') /* 32 VUYA-8-8-8-8 */ #define V4L2_PIX_FMT_VUYX32 v4l2_fourcc('V', 'U', 'Y', 'X') /* 32 VUYX-8-8-8-8 */ -#define V4L2_PIX_FMT_HI240 v4l2_fourcc('H', 'I', '2', '4') /* 8 8-bit color */ #define V4L2_PIX_FMT_HM12 v4l2_fourcc('H', 'M', '1', '2') /* 8 YUV 4:2:0 16x16 macroblocks */ #define V4L2_PIX_FMT_M420 v4l2_fourcc('M', '4', '2', '0') /* 12 YUV 4:2:0 2 lines y, 1 line uv interleaved */ @@ -733,6 +732,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_INZI v4l2_fourcc('I', 'N', 'Z', 'I') /* Intel Planar Greyscale 10-bit and Depth 16-bit */ #define V4L2_PIX_FMT_SUNXI_TILED_NV12 v4l2_fourcc('S', 'T', '1', '2') /* Sunxi Tiled NV12 Format */ #define V4L2_PIX_FMT_CNF4 v4l2_fourcc('C', 'N', 'F', '4') /* Intel 4-bit packed depth confidence information */ +#define V4L2_PIX_FMT_HI240 v4l2_fourcc('H', 'I', '2', '4') /* BTTV 8-bit dithered RGB */ /* 10bit raw bayer packed, 32 bytes for every 25 pixels, last LSB 6 bits unused */ #define V4L2_PIX_FMT_IPU3_SBGGR10 v4l2_fourcc('i', 'p', '3', 'b') /* IPU3 packed 10-bit BGGR bayer */ -- cgit v1.2.3 From 473dbed54fdbac0e8671c2e0d0fa5f3bad281a31 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 7 Dec 2020 00:03:03 +0100 Subject: media: videodev2.h: Move HM12 format to YUV semi-planar section V4L2_PIX_FMT_HM12 is a YUV semi-planar macro-block format. Move it from the packed YUV formats section where it was misplaced to the YUV semi-planar formats section. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/videodev2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 01140ac57be2..be07bb01d936 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -589,7 +589,6 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_XYUV32 v4l2_fourcc('X', 'Y', 'U', 'V') /* 32 XYUV-8-8-8-8 */ #define V4L2_PIX_FMT_VUYA32 v4l2_fourcc('V', 'U', 'Y', 'A') /* 32 VUYA-8-8-8-8 */ #define V4L2_PIX_FMT_VUYX32 v4l2_fourcc('V', 'U', 'Y', 'X') /* 32 VUYX-8-8-8-8 */ -#define V4L2_PIX_FMT_HM12 v4l2_fourcc('H', 'M', '1', '2') /* 8 YUV 4:2:0 16x16 macroblocks */ #define V4L2_PIX_FMT_M420 v4l2_fourcc('M', '4', '2', '0') /* 12 YUV 4:2:0 2 lines y, 1 line uv interleaved */ /* two planes -- one Y, one Cr + Cb interleaved */ @@ -599,6 +598,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_NV61 v4l2_fourcc('N', 'V', '6', '1') /* 16 Y/CrCb 4:2:2 */ #define V4L2_PIX_FMT_NV24 v4l2_fourcc('N', 'V', '2', '4') /* 24 Y/CbCr 4:4:4 */ #define V4L2_PIX_FMT_NV42 v4l2_fourcc('N', 'V', '4', '2') /* 24 Y/CrCb 4:4:4 */ +#define V4L2_PIX_FMT_HM12 v4l2_fourcc('H', 'M', '1', '2') /* 8 YUV 4:2:0 16x16 macroblocks */ /* two non contiguous planes - one Y, one Cr + Cb interleaved */ #define V4L2_PIX_FMT_NV12M v4l2_fourcc('N', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 */ -- cgit v1.2.3 From 3747115f85bb73b69ec345f518bec3a5f8e7838d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 7 Dec 2020 00:03:04 +0100 Subject: media: doc: pixfmt-rgb: Remove layout table for packed RGB formats The packed RGB formats documentation includes a layout table without any context. This doesn't bring much useful information, and is confusing at best. Remove it. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/pixfmt-rgb.rst | 71 ---------------------- 1 file changed, 71 deletions(-) diff --git a/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst b/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst index 9d827097c1d9..731bde23e055 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst @@ -999,77 +999,6 @@ The XRGB and XBGR formats contain undefined bits (-). Applications, devices and drivers must ignore those bits, for both :ref:`capture` and :ref:`output` devices. -**Byte Order.** -Each cell is one byte. - - -.. raw:: latex - - \small - -.. tabularcolumns:: |p{3.1cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}| - -.. flat-table:: RGB byte order - :header-rows: 0 - :stub-columns: 0 - :widths: 11 3 3 3 3 3 3 3 3 3 3 3 3 - - * - start + 0: - - B\ :sub:`00` - - G\ :sub:`00` - - R\ :sub:`00` - - B\ :sub:`01` - - G\ :sub:`01` - - R\ :sub:`01` - - B\ :sub:`02` - - G\ :sub:`02` - - R\ :sub:`02` - - B\ :sub:`03` - - G\ :sub:`03` - - R\ :sub:`03` - * - start + 12: - - B\ :sub:`10` - - G\ :sub:`10` - - R\ :sub:`10` - - B\ :sub:`11` - - G\ :sub:`11` - - R\ :sub:`11` - - B\ :sub:`12` - - G\ :sub:`12` - - R\ :sub:`12` - - B\ :sub:`13` - - G\ :sub:`13` - - R\ :sub:`13` - * - start + 24: - - B\ :sub:`20` - - G\ :sub:`20` - - R\ :sub:`20` - - B\ :sub:`21` - - G\ :sub:`21` - - R\ :sub:`21` - - B\ :sub:`22` - - G\ :sub:`22` - - R\ :sub:`22` - - B\ :sub:`23` - - G\ :sub:`23` - - R\ :sub:`23` - * - start + 36: - - B\ :sub:`30` - - G\ :sub:`30` - - R\ :sub:`30` - - B\ :sub:`31` - - G\ :sub:`31` - - R\ :sub:`31` - - B\ :sub:`32` - - G\ :sub:`32` - - R\ :sub:`32` - - B\ :sub:`33` - - G\ :sub:`33` - - R\ :sub:`33` - -.. raw:: latex - - \normalsize Formats defined in :ref:`pixfmt-rgb-deprecated` are deprecated and must not be used by new drivers. They are documented here for reference. -- cgit v1.2.3 From 67c2a10bff74e938279bb519d2853babbd52c1d7 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 7 Dec 2020 00:03:05 +0100 Subject: media: doc: pixfmt-rgb: Add title for deprecated formats Improve readability of the documentation by adding a section title for the deprecated formats. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/v4l/pixfmt-rgb.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst b/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst index 731bde23e055..5045895e85e1 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst @@ -1000,12 +1000,14 @@ devices and drivers must ignore those bits, for both :ref:`capture` and :ref:`output` devices. +Deprecated RGB Formats +====================== + Formats defined in :ref:`pixfmt-rgb-deprecated` are deprecated and must not be used by new drivers. They are documented here for reference. The meaning of their alpha bits ``(a)`` are ill-defined and interpreted as in either the corresponding ARGB or XRGB format, depending on the driver. - .. raw:: latex \begingroup -- cgit v1.2.3 From e9a66489c383bc11f786db1d79e952e89cb137fe Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 7 Dec 2020 00:03:06 +0100 Subject: media: doc: pixfmt-rgb: Clarify naming scheme for RGB formats The naming scheme for the RGB pixel formats has been developed organically, and isn't consistent between formats using less than 8 bits per pixels (mostly stored in 1 or 2 bytes per pixel, except for RGB666 that uses 4 bytes per pixel) and formats with 8 bits per pixel (stored in 3 or 4 bytes). For the latter category, the names use a components order convention that is the opposite of the first category, and the opposite of DRM pixel formats. This has led to lots of confusion in the past, and would really benefit from being explained more precisely. Do so, which also prepares for the addition of additional RGB pixels formats. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/pixfmt-rgb.rst | 255 ++++++++++++++------- include/uapi/linux/videodev2.h | 4 +- 2 files changed, 180 insertions(+), 79 deletions(-) diff --git a/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst b/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst index 5045895e85e1..36236e6ba55a 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst @@ -6,13 +6,62 @@ RGB Formats *********** -Description -=========== - -These formats are designed to match the pixel formats of typical PC -graphics frame buffers. They occupy 8, 16, 24 or 32 bits per pixel. -These are all packed-pixel formats, meaning all the data for a pixel lie -next to each other in memory. +These formats encode each pixel as a triplet of RGB values. They are packed +formats, meaning that the RGB values for one pixel are stored consecutively in +memory and each pixel consumes an integer number of bytes. When the number of +bits required to store a pixel is not aligned to a byte boundary, the data is +padded with additional bits to fill the remaining byte. + +The formats differ by the number of bits per RGB component (typically but not +always the same for all components), the order of components in memory, and the +presence of an alpha component or additional padding bits. + +The usage and value of the alpha bits in formats that support them (named ARGB +or a permutation thereof, collectively referred to as alpha formats) depend on +the device type and hardware operation. :ref:`Capture ` devices +(including capture queues of mem-to-mem devices) fill the alpha component in +memory. When the device captures an alpha channel the alpha component will have +a meaningful value. Otherwise, when the device doesn't capture an alpha channel +but can set the alpha bit to a user-configurable value, the +:ref:`V4L2_CID_ALPHA_COMPONENT ` control is used to +specify that alpha value, and the alpha component of all pixels will be set to +the value specified by that control. Otherwise a corresponding format without +an alpha component (XRGB or XBGR) must be used instead of an alpha format. + +:ref:`Output ` devices (including output queues of mem-to-mem devices +and :ref:`video output overlay ` devices) read the alpha component from +memory. When the device processes the alpha channel the alpha component must be +filled with meaningful values by applications. Otherwise a corresponding format +without an alpha component (XRGB or XBGR) must be used instead of an alpha +format. + +Formats that contain padding bits are named XRGB (or a permutation thereof). +The padding bits contain undefined values and must be ignored by applications, +devices and drivers, for both :ref:`capture` and :ref:`output` devices. + +.. note:: + + - In all the tables that follow, bit 7 is the most significant bit in a byte. + - 'r', 'g' and 'b' denote bits of the red, green and blue components + respectively. 'a' denotes bits of the alpha component (if supported by the + format), and '-' denotes padding bits. + + +Less Than 8 Bits Per Component +============================== + +These formats store an RGB triplet in one, two or four bytes. They are named +based on the order of the RGB components as seen in a 8-, 16- or 32-bit word, +which is then stored in memory in little endian byte order (unless otherwise +noted by the presence of bit 31 in the 4CC value), and on the number of bits +for each component. For instance, the RGB565 format stores a pixel in a 16-bit +word [15:0] laid out at as [R\ :sub:`4` R\ :sub:`3` R\ :sub:`2` R\ :sub:`1` +R\ :sub:`0` G\ :sub:`5` G\ :sub:`4` G\ :sub:`3` G\ :sub:`2` G\ :sub:`1` +G\ :sub:`0` B\ :sub:`4` B\ :sub:`3` B\ :sub:`2` B\ :sub:`1` B\ :sub:`0`], and +stored in memory in two bytes, [R\ :sub:`4` R\ :sub:`3` R\ :sub:`2` R\ :sub:`1` +R\ :sub:`0` G\ :sub:`5` G\ :sub:`4` G\ :sub:`3`] followed by [G\ :sub:`2` +G\ :sub:`1` G\ :sub:`0` B\ :sub:`4` B\ :sub:`3` B\ :sub:`2` B\ :sub:`1` +B\ :sub:`0`]. .. raw:: latex @@ -23,7 +72,7 @@ next to each other in memory. .. tabularcolumns:: |p{2.8cm}|p{2.0cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}| -.. flat-table:: RGB Image Formats +.. flat-table:: RGB Formats With Less Than 8 Bits Per Component :header-rows: 2 :stub-columns: 0 @@ -544,6 +593,122 @@ next to each other in memory. - b\ :sub:`1` - b\ :sub:`0` - + * .. _V4L2-PIX-FMT-BGR666: + + - ``V4L2_PIX_FMT_BGR666`` + - 'BGRH' + + - b\ :sub:`5` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - g\ :sub:`5` + - g\ :sub:`4` + + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - r\ :sub:`5` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + + - r\ :sub:`1` + - r\ :sub:`0` + - `-` + - `-` + - `-` + - `-` + - `-` + - `-` + + - `-` + - `-` + - `-` + - `-` + - `-` + - `-` + - `-` + - `-` + +.. raw:: latex + + \endgroup + + +8 Bits Per Component +==================== + +These formats store an RGB triplet in three or four bytes. They are named based +on the order of the RGB components as stored in memory, and on the total number +of bits per pixel. For instance, RGB24 format stores a pixel with [R\ :sub:`7` +R\ :sub:`6` R\ :sub:`5` R\ :sub:`4` R\ :sub:`3` R\ :sub:`2` R\ :sub:`1` +R\ :sub:`0`] in the first byte, [G\ :sub:`7` G\ :sub:`6` G\ :sub:`5` G\ :sub:`4` +G\ :sub:`3` G\ :sub:`2` G\ :sub:`1` G\ :sub:`0`] in the second byte and +[B\ :sub:`7` B\ :sub:`6` B\ :sub:`5` B\ :sub:`4` B\ :sub:`3` B\ :sub:`2` +B\ :sub:`1` B\ :sub:`0`] in the third byte. This differs from the DRM format +nomenclature that instead use the order of components as seen in a 24- or +32-bit little endian word. + +.. raw:: latex + + \begingroup + \tiny + \setlength{\tabcolsep}{2pt} + +.. tabularcolumns:: |p{2.8cm}|p{2.0cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}| + + +.. flat-table:: RGB Formats With 8 Bits Per Component + :header-rows: 2 + :stub-columns: 0 + + * - Identifier + - Code + - :cspan:`7` Byte 0 in memory + - :cspan:`7` Byte 1 + - :cspan:`7` Byte 2 + - :cspan:`7` Byte 3 + * - + - + - 7 + - 6 + - 5 + - 4 + - 3 + - 2 + - 1 + - 0 + + - 7 + - 6 + - 5 + - 4 + - 3 + - 2 + - 1 + - 0 + + - 7 + - 6 + - 5 + - 4 + - 3 + - 2 + - 1 + - 0 + + - 7 + - 6 + - 5 + - 4 + - 3 + - 2 + - 1 + - 0 * .. _V4L2-PIX-FMT-BGR24: - ``V4L2_PIX_FMT_BGR24`` @@ -608,46 +773,6 @@ next to each other in memory. - b\ :sub:`1` - b\ :sub:`0` - - * .. _V4L2-PIX-FMT-BGR666: - - - ``V4L2_PIX_FMT_BGR666`` - - 'BGRH' - - - b\ :sub:`5` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - g\ :sub:`5` - - g\ :sub:`4` - - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - r\ :sub:`5` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - - r\ :sub:`1` - - r\ :sub:`0` - - `-` - - `-` - - `-` - - `-` - - `-` - - `-` - - - `-` - - `-` - - `-` - - `-` - - `-` - - `-` - - `-` - - `-` * .. _V4L2-PIX-FMT-ABGR32: - ``V4L2_PIX_FMT_ABGR32`` @@ -973,40 +1098,14 @@ next to each other in memory. \endgroup -.. note:: Bit 7 is the most significant bit. - -The usage and value of the alpha bits (a) in the ARGB and ABGR formats -(collectively referred to as alpha formats) depend on the device type -and hardware operation. :ref:`Capture ` devices (including -capture queues of mem-to-mem devices) fill the alpha component in -memory. When the device outputs an alpha channel the alpha component -will have a meaningful value. Otherwise, when the device doesn't output -an alpha channel but can set the alpha bit to a user-configurable value, -the :ref:`V4L2_CID_ALPHA_COMPONENT ` control -is used to specify that alpha value, and the alpha component of all -pixels will be set to the value specified by that control. Otherwise a -corresponding format without an alpha component (XRGB or XBGR) must be -used instead of an alpha format. - -:ref:`Output ` devices (including output queues of mem-to-mem -devices and :ref:`video output overlay ` devices) read the alpha -component from memory. When the device processes the alpha channel the -alpha component must be filled with meaningful values by applications. -Otherwise a corresponding format without an alpha component (XRGB or -XBGR) must be used instead of an alpha format. - -The XRGB and XBGR formats contain undefined bits (-). Applications, -devices and drivers must ignore those bits, for both -:ref:`capture` and :ref:`output` devices. - Deprecated RGB Formats ====================== -Formats defined in :ref:`pixfmt-rgb-deprecated` are deprecated and -must not be used by new drivers. They are documented here for reference. -The meaning of their alpha bits ``(a)`` are ill-defined and interpreted as in -either the corresponding ARGB or XRGB format, depending on the driver. +Formats defined in :ref:`pixfmt-rgb-deprecated` are deprecated and must not be +used by new drivers. They are documented here for reference. The meaning of +their alpha bits ``(a)`` is ill-defined and they are interpreted as in either +the corresponding ARGB or XRGB format, depending on the driver. .. raw:: latex diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index be07bb01d936..79dbde3bcf8d 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -515,7 +515,7 @@ struct v4l2_pix_format { /* Pixel format FOURCC depth Description */ -/* RGB formats */ +/* RGB formats (1 or 2 bytes per pixel) */ #define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R', 'G', 'B', '1') /* 8 RGB-3-3-2 */ #define V4L2_PIX_FMT_RGB444 v4l2_fourcc('R', '4', '4', '4') /* 16 xxxxrrrr ggggbbbb */ #define V4L2_PIX_FMT_ARGB444 v4l2_fourcc('A', 'R', '1', '2') /* 16 aaaarrrr ggggbbbb */ @@ -540,6 +540,8 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_ARGB555X v4l2_fourcc_be('A', 'R', '1', '5') /* 16 ARGB-5-5-5 BE */ #define V4L2_PIX_FMT_XRGB555X v4l2_fourcc_be('X', 'R', '1', '5') /* 16 XRGB-5-5-5 BE */ #define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R', 'G', 'B', 'R') /* 16 RGB-5-6-5 BE */ + +/* RGB formats (3 or 4 bytes per pixel) */ #define V4L2_PIX_FMT_BGR666 v4l2_fourcc('B', 'G', 'R', 'H') /* 18 BGR-6-6-6 */ #define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B', 'G', 'R', '3') /* 24 BGR-8-8-8 */ #define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R', 'G', 'B', '3') /* 24 RGB-8-8-8 */ -- cgit v1.2.3 From 2ac9280cb459a7d00d7c432453b208865301f1d9 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 7 Dec 2020 00:03:07 +0100 Subject: media: doc: pixfmt-rgb: Make 8 bits per component table more compact All formats using 8 bits per component can be described with a byte granularity instead of a bit granularity without loss of precision. This makes the corresponding table more compact and easier to read. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/pixfmt-rgb.rst | 411 ++------------------- 1 file changed, 40 insertions(+), 371 deletions(-) diff --git a/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst b/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst index 36236e6ba55a..d1ddc7a251da 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst @@ -659,440 +659,109 @@ nomenclature that instead use the order of components as seen in a 24- or \tiny \setlength{\tabcolsep}{2pt} -.. tabularcolumns:: |p{2.8cm}|p{2.0cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}| +.. tabularcolumns:: |p{2.8cm}|p{2.0cm}|p{2.0cm}|p{2.0cm}|p{2.0cm}|p{2.0cm}|p{2.0cm}|p{2.0cm}| .. flat-table:: RGB Formats With 8 Bits Per Component - :header-rows: 2 + :header-rows: 1 :stub-columns: 0 * - Identifier - Code - - :cspan:`7` Byte 0 in memory - - :cspan:`7` Byte 1 - - :cspan:`7` Byte 2 - - :cspan:`7` Byte 3 - * - - - - - 7 - - 6 - - 5 - - 4 - - 3 - - 2 - - 1 - - 0 - - - 7 - - 6 - - 5 - - 4 - - 3 - - 2 - - 1 - - 0 - - - 7 - - 6 - - 5 - - 4 - - 3 - - 2 - - 1 - - 0 - - - 7 - - 6 - - 5 - - 4 - - 3 - - 2 - - 1 - - 0 + - Byte 0 in memory + - Byte 1 + - Byte 2 + - Byte 3 * .. _V4L2-PIX-FMT-BGR24: - ``V4L2_PIX_FMT_BGR24`` - 'BGR3' - - b\ :sub:`7` - - b\ :sub:`6` - - b\ :sub:`5` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - g\ :sub:`7` - - g\ :sub:`6` - - g\ :sub:`5` - - g\ :sub:`4` - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - - r\ :sub:`7` - - r\ :sub:`6` - - r\ :sub:`5` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` + - G\ :sub:`7-0` + - B\ :sub:`7-0` + - R\ :sub:`7-0` - * .. _V4L2-PIX-FMT-RGB24: - ``V4L2_PIX_FMT_RGB24`` - 'RGB3' - - r\ :sub:`7` - - r\ :sub:`6` - - r\ :sub:`5` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - - g\ :sub:`7` - - g\ :sub:`6` - - g\ :sub:`5` - - g\ :sub:`4` - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - - b\ :sub:`7` - - b\ :sub:`6` - - b\ :sub:`5` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` + - R\ :sub:`7-0` + - G\ :sub:`7-0` + - B\ :sub:`7-0` - * .. _V4L2-PIX-FMT-ABGR32: - ``V4L2_PIX_FMT_ABGR32`` - 'AR24' - - b\ :sub:`7` - - b\ :sub:`6` - - b\ :sub:`5` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - g\ :sub:`7` - - g\ :sub:`6` - - g\ :sub:`5` - - g\ :sub:`4` - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - - r\ :sub:`7` - - r\ :sub:`6` - - r\ :sub:`5` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - - a\ :sub:`7` - - a\ :sub:`6` - - a\ :sub:`5` - - a\ :sub:`4` - - a\ :sub:`3` - - a\ :sub:`2` - - a\ :sub:`1` - - a\ :sub:`0` + - B\ :sub:`7-0` + - G\ :sub:`7-0` + - R\ :sub:`7-0` + - A\ :sub:`7-0` * .. _V4L2-PIX-FMT-XBGR32: - ``V4L2_PIX_FMT_XBGR32`` - 'XR24' - - b\ :sub:`7` - - b\ :sub:`6` - - b\ :sub:`5` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - g\ :sub:`7` - - g\ :sub:`6` - - g\ :sub:`5` - - g\ :sub:`4` - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - - r\ :sub:`7` - - r\ :sub:`6` - - r\ :sub:`5` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - - `-` - - `-` - - `-` - - `-` - - `-` - - `-` - - `-` + - B\ :sub:`7-0` + - G\ :sub:`7-0` + - R\ :sub:`7-0` - `-` * .. _V4L2-PIX-FMT-BGRA32: - ``V4L2_PIX_FMT_BGRA32`` - 'RA24' - - a\ :sub:`7` - - a\ :sub:`6` - - a\ :sub:`5` - - a\ :sub:`4` - - a\ :sub:`3` - - a\ :sub:`2` - - a\ :sub:`1` - - a\ :sub:`0` - - - b\ :sub:`7` - - b\ :sub:`6` - - b\ :sub:`5` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - g\ :sub:`7` - - g\ :sub:`6` - - g\ :sub:`5` - - g\ :sub:`4` - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - - r\ :sub:`7` - - r\ :sub:`6` - - r\ :sub:`5` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` + - A\ :sub:`7-0` + - B\ :sub:`7-0` + - G\ :sub:`7-0` + - R\ :sub:`7-0` * .. _V4L2-PIX-FMT-BGRX32: - ``V4L2_PIX_FMT_BGRX32`` - 'RX24' - `-` - - `-` - - `-` - - `-` - - `-` - - `-` - - `-` - - `-` - - - b\ :sub:`7` - - b\ :sub:`6` - - b\ :sub:`5` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - g\ :sub:`7` - - g\ :sub:`6` - - g\ :sub:`5` - - g\ :sub:`4` - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - - r\ :sub:`7` - - r\ :sub:`6` - - r\ :sub:`5` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` + - B\ :sub:`7-0` + - G\ :sub:`7-0` + - R\ :sub:`7-0` * .. _V4L2-PIX-FMT-RGBA32: - ``V4L2_PIX_FMT_RGBA32`` - 'AB24' - - r\ :sub:`7` - - r\ :sub:`6` - - r\ :sub:`5` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - - g\ :sub:`7` - - g\ :sub:`6` - - g\ :sub:`5` - - g\ :sub:`4` - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - - b\ :sub:`7` - - b\ :sub:`6` - - b\ :sub:`5` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - a\ :sub:`7` - - a\ :sub:`6` - - a\ :sub:`5` - - a\ :sub:`4` - - a\ :sub:`3` - - a\ :sub:`2` - - a\ :sub:`1` - - a\ :sub:`0` + - R\ :sub:`7-0` + - G\ :sub:`7-0` + - B\ :sub:`7-0` + - A\ :sub:`7-0` * .. _V4L2-PIX-FMT-RGBX32: - ``V4L2_PIX_FMT_RGBX32`` - 'XB24' - - r\ :sub:`7` - - r\ :sub:`6` - - r\ :sub:`5` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - - g\ :sub:`7` - - g\ :sub:`6` - - g\ :sub:`5` - - g\ :sub:`4` - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - - b\ :sub:`7` - - b\ :sub:`6` - - b\ :sub:`5` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` - - - `-` - - `-` - - `-` - - `-` - - `-` - - `-` - - `-` + - R\ :sub:`7-0` + - G\ :sub:`7-0` + - B\ :sub:`7-0` - `-` * .. _V4L2-PIX-FMT-ARGB32: - ``V4L2_PIX_FMT_ARGB32`` - 'BA24' - - a\ :sub:`7` - - a\ :sub:`6` - - a\ :sub:`5` - - a\ :sub:`4` - - a\ :sub:`3` - - a\ :sub:`2` - - a\ :sub:`1` - - a\ :sub:`0` - - - r\ :sub:`7` - - r\ :sub:`6` - - r\ :sub:`5` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - - g\ :sub:`7` - - g\ :sub:`6` - - g\ :sub:`5` - - g\ :sub:`4` - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - - b\ :sub:`7` - - b\ :sub:`6` - - b\ :sub:`5` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` + - A\ :sub:`7-0` + - R\ :sub:`7-0` + - G\ :sub:`7-0` + - B\ :sub:`7-0` * .. _V4L2-PIX-FMT-XRGB32: - ``V4L2_PIX_FMT_XRGB32`` - 'BX24' - `-` - - `-` - - `-` - - `-` - - `-` - - `-` - - `-` - - `-` - - - r\ :sub:`7` - - r\ :sub:`6` - - r\ :sub:`5` - - r\ :sub:`4` - - r\ :sub:`3` - - r\ :sub:`2` - - r\ :sub:`1` - - r\ :sub:`0` - - - g\ :sub:`7` - - g\ :sub:`6` - - g\ :sub:`5` - - g\ :sub:`4` - - g\ :sub:`3` - - g\ :sub:`2` - - g\ :sub:`1` - - g\ :sub:`0` - - - b\ :sub:`7` - - b\ :sub:`6` - - b\ :sub:`5` - - b\ :sub:`4` - - b\ :sub:`3` - - b\ :sub:`2` - - b\ :sub:`1` - - b\ :sub:`0` + - R\ :sub:`7-0` + - G\ :sub:`7-0` + - B\ :sub:`7-0` .. raw:: latex -- cgit v1.2.3 From a1bcf9b9a7066e605ab36e4db560b6fa5c3e85a3 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 7 Dec 2020 00:03:08 +0100 Subject: media: doc: pixfmt-rgb: Replace '-' with 'X' to denote padding Using '-' to represent padding bits and bytes make text and tables more difficult to read. Use 'x' and 'X' instead. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/pixfmt-rgb.rst | 82 +++++++++++----------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst b/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst index d1ddc7a251da..897676ee2c9d 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst @@ -44,7 +44,7 @@ devices and drivers, for both :ref:`capture` and :ref:`output` devices. - In all the tables that follow, bit 7 is the most significant bit in a byte. - 'r', 'g' and 'b' denote bits of the red, green and blue components respectively. 'a' denotes bits of the alpha component (if supported by the - format), and '-' denotes padding bits. + format), and 'x' denotes padding bits. Less Than 8 Bits Per Component @@ -170,10 +170,10 @@ B\ :sub:`0`]. - b\ :sub:`1` - b\ :sub:`0` - - `-` - - `-` - - `-` - - `-` + - x + - x + - x + - x - r\ :sub:`3` - r\ :sub:`2` - r\ :sub:`1` @@ -211,10 +211,10 @@ B\ :sub:`0`]. - b\ :sub:`2` - b\ :sub:`1` - b\ :sub:`0` - - `-` - - `-` - - `-` - - `-` + - x + - x + - x + - x - r\ :sub:`3` - r\ :sub:`2` @@ -262,10 +262,10 @@ B\ :sub:`0`]. - r\ :sub:`1` - r\ :sub:`0` - - `-` - - `-` - - `-` - - `-` + - x + - x + - x + - x - b\ :sub:`3` - b\ :sub:`2` - b\ :sub:`1` @@ -303,10 +303,10 @@ B\ :sub:`0`]. - r\ :sub:`2` - r\ :sub:`1` - r\ :sub:`0` - - `-` - - `-` - - `-` - - `-` + - x + - x + - x + - x - b\ :sub:`3` - b\ :sub:`2` @@ -354,7 +354,7 @@ B\ :sub:`0`]. - b\ :sub:`1` - b\ :sub:`0` - - `-` + - x - r\ :sub:`4` - r\ :sub:`3` - r\ :sub:`2` @@ -398,7 +398,7 @@ B\ :sub:`0`]. - b\ :sub:`2` - b\ :sub:`1` - b\ :sub:`0` - - `-` + - x - r\ :sub:`4` - r\ :sub:`3` @@ -446,7 +446,7 @@ B\ :sub:`0`]. - r\ :sub:`1` - r\ :sub:`0` - - `-` + - x - b\ :sub:`4` - b\ :sub:`3` - b\ :sub:`2` @@ -490,7 +490,7 @@ B\ :sub:`0`]. - r\ :sub:`2` - r\ :sub:`1` - r\ :sub:`0` - - `-` + - x - b\ :sub:`4` - b\ :sub:`3` @@ -552,7 +552,7 @@ B\ :sub:`0`]. - ``V4L2_PIX_FMT_XRGB555X`` - 'XR15' | (1 << 31) - - `-` + - x - r\ :sub:`4` - r\ :sub:`3` - r\ :sub:`2` @@ -618,21 +618,21 @@ B\ :sub:`0`]. - r\ :sub:`1` - r\ :sub:`0` - - `-` - - `-` - - `-` - - `-` - - `-` - - `-` - - - `-` - - `-` - - `-` - - `-` - - `-` - - `-` - - `-` - - `-` + - x + - x + - x + - x + - x + - x + + - x + - x + - x + - x + - x + - x + - x + - x .. raw:: latex @@ -707,7 +707,7 @@ nomenclature that instead use the order of components as seen in a 24- or - B\ :sub:`7-0` - G\ :sub:`7-0` - R\ :sub:`7-0` - - `-` + - X\ :sub:`7-0` * .. _V4L2-PIX-FMT-BGRA32: - ``V4L2_PIX_FMT_BGRA32`` @@ -722,7 +722,7 @@ nomenclature that instead use the order of components as seen in a 24- or - ``V4L2_PIX_FMT_BGRX32`` - 'RX24' - - `-` + - X\ :sub:`7-0` - B\ :sub:`7-0` - G\ :sub:`7-0` - R\ :sub:`7-0` @@ -743,7 +743,7 @@ nomenclature that instead use the order of components as seen in a 24- or - R\ :sub:`7-0` - G\ :sub:`7-0` - B\ :sub:`7-0` - - `-` + - X\ :sub:`7-0` * .. _V4L2-PIX-FMT-ARGB32: - ``V4L2_PIX_FMT_ARGB32`` @@ -758,7 +758,7 @@ nomenclature that instead use the order of components as seen in a 24- or - ``V4L2_PIX_FMT_XRGB32`` - 'BX24' - - `-` + - X\ :sub:`7-0` - R\ :sub:`7-0` - G\ :sub:`7-0` - B\ :sub:`7-0` -- cgit v1.2.3 From e3ae4c204d1f00c4366b4beeae62b3414761c6f8 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 7 Dec 2020 00:03:09 +0100 Subject: media: doc: pixfmt-yuv: Document subsampling in more details Document YUV subsampling, including chroma spatial siting, and replace the siting examples in individual formats by references to the common documentation. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/pixfmt-m420.rst | 59 +---- .../userspace-api/media/v4l/pixfmt-nv12.rst | 57 +---- .../userspace-api/media/v4l/pixfmt-nv12m.rst | 60 +---- .../userspace-api/media/v4l/pixfmt-nv16.rst | 73 +----- .../userspace-api/media/v4l/pixfmt-nv16m.rst | 73 +----- .../userspace-api/media/v4l/pixfmt-uyvy.rst | 44 +--- .../userspace-api/media/v4l/pixfmt-vyuy.rst | 42 +--- .../userspace-api/media/v4l/pixfmt-y41p.rst | 62 +---- .../userspace-api/media/v4l/pixfmt-yuv410.rst | 59 +---- .../userspace-api/media/v4l/pixfmt-yuv411p.rst | 39 +--- .../userspace-api/media/v4l/pixfmt-yuv420.rst | 66 +----- .../userspace-api/media/v4l/pixfmt-yuv420m.rst | 66 +----- .../userspace-api/media/v4l/pixfmt-yuv422m.rst | 44 +--- .../userspace-api/media/v4l/pixfmt-yuv422p.rst | 44 +--- .../userspace-api/media/v4l/pixfmt-yuv444m.rst | 33 +-- .../userspace-api/media/v4l/pixfmt-yuyv.rst | 49 +--- .../userspace-api/media/v4l/pixfmt-yvyu.rst | 42 +--- .../userspace-api/media/v4l/yuv-formats.rst | 250 ++++++++++++++++++++- 18 files changed, 278 insertions(+), 884 deletions(-) diff --git a/Documentation/userspace-api/media/v4l/pixfmt-m420.rst b/Documentation/userspace-api/media/v4l/pixfmt-m420.rst index 13cf36a8cd5c..c01a949e7c11 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-m420.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-m420.rst @@ -67,60 +67,5 @@ Each cell is one byte. **Color Sample Location:** - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - - - 0 - - - - 1 - - 2 - - - - 3 - * - 0 - - Y - - - - Y - - Y - - - - Y - * - - - - - C - - - - - - C - - - * - 1 - - Y - - - - Y - - Y - - - - Y - * - - * - 2 - - Y - - - - Y - - Y - - - - Y - * - - - - - C - - - - - - C - - - * - 3 - - Y - - - - Y - - Y - - - - Y +Chroma samples are :ref:`interstitially sited` +horizontally and vertically. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-nv12.rst b/Documentation/userspace-api/media/v4l/pixfmt-nv12.rst index dd2f38129fe6..692117bf83ad 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-nv12.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-nv12.rst @@ -72,58 +72,5 @@ Each cell is one byte. **Color Sample Location:** - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - - - 0 - - - - 1 - - 2 - - - - 3 - * - 0 - - Y - - - - Y - - Y - - - - Y - * - - - - - C - - - - - - C - - - * - 1 - - Y - - - - Y - - Y - - - - Y - * - - * - 2 - - Y - - - - Y - - Y - - - - Y - * - - - - - C - - - - - - C - - - * - 3 - - Y - - - - Y - - Y - - - - Y +Chroma samples are :ref:`interstitially sited` +horizontally and vertically. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-nv12m.rst b/Documentation/userspace-api/media/v4l/pixfmt-nv12m.rst index 250f8b977605..002b361d5a9b 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-nv12m.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-nv12m.rst @@ -84,61 +84,5 @@ Each cell is one byte. **Color Sample Location:** - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - - - 0 - - - - 1 - - 2 - - - - 3 - * - 0 - - Y - - - - Y - - Y - - - - Y - * - - - - - C - - - - - - C - - - * - 1 - - Y - - - - Y - - Y - - - - Y - * - - * - 2 - - Y - - - - Y - - Y - - - - Y - * - - - - - C - - - - - - - - C - - - * - 3 - - Y - - - - Y - - Y - - - - Y +Chroma samples are :ref:`interstitially sited` +horizontally and vertically. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-nv16.rst b/Documentation/userspace-api/media/v4l/pixfmt-nv16.rst index 22295fc0c359..e6307843d848 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-nv16.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-nv16.rst @@ -80,74 +80,5 @@ Each cell is one byte. **Color Sample Location:** - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - - - 0 - - - - 1 - - 2 - - - - 3 - * - 0 - - Y - - - - Y - - Y - - - - Y - * - - - - - C - - - - - - C - - - * - 1 - - Y - - - - Y - - Y - - - - Y - * - - - - - C - - - - - - C - - - * - - * - 2 - - Y - - - - Y - - Y - - - - Y - * - - - - - C - - - - - - C - - - * - 3 - - Y - - - - Y - - Y - - - - Y - * - - - - - C - - - - - - C - - +Chroma samples are :ref:`interstitially sited` +horizontally. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-nv16m.rst b/Documentation/userspace-api/media/v4l/pixfmt-nv16m.rst index 812bf2ccabf0..58e97205d41f 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-nv16m.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-nv16m.rst @@ -84,74 +84,5 @@ Each cell is one byte. **Color Sample Location:** - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - - - 0 - - - - 1 - - 2 - - - - 3 - * - 0 - - Y - - - - Y - - Y - - - - Y - * - - - - - C - - - - - - C - - - * - 1 - - Y - - - - Y - - Y - - - - Y - * - - - - - C - - - - - - C - - - * - - * - 2 - - Y - - - - Y - - Y - - - - Y - * - - - - - C - - - - - - C - - - * - 3 - - Y - - - - Y - - Y - - - - Y - * - - - - - C - - - - - - C - - +Chroma samples are :ref:`interstitially sited` +horizontally. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-uyvy.rst b/Documentation/userspace-api/media/v4l/pixfmt-uyvy.rst index bae975fb14f6..1abc3066b712 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-uyvy.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-uyvy.rst @@ -66,45 +66,5 @@ Each cell is one byte. **Color Sample Location:** - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - - - 0 - - - - 1 - - 2 - - - - 3 - * - 0 - - Y - - C - - Y - - Y - - C - - Y - * - 1 - - Y - - C - - Y - - Y - - C - - Y - * - 2 - - Y - - C - - Y - - Y - - C - - Y - * - 3 - - Y - - C - - Y - - Y - - C - - Y +Chroma samples are :ref:`interstitially sited` +horizontally. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-vyuy.rst b/Documentation/userspace-api/media/v4l/pixfmt-vyuy.rst index aff8588b67a9..4fd0630a83a4 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-vyuy.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-vyuy.rst @@ -66,43 +66,5 @@ Each cell is one byte. **Color Sample Location:** - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - - - 0 - - - - 1 - - - - 2 - - 3 - * - 0 - - Y - - C - - Y - - Y - - C - - Y - * - 1 - - Y - - C - - Y - - Y - - C - - Y - * - 2 - - Y - - C - - Y - - Y - - C - - Y - * - 3 - - Y - - C - - Y - - Y - - C - - Y +Chroma samples are :ref:`interstitially sited` +horizontally. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-y41p.rst b/Documentation/userspace-api/media/v4l/pixfmt-y41p.rst index d14cedf8f317..bb83eb6db3e5 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-y41p.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-y41p.rst @@ -89,63 +89,5 @@ Each cell is one byte. **Color Sample Location:** - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - - - 0 - - 1 - - - - 2 - - 3 - - 4 - - 5 - - - - 6 - - 7 - * - 0 - - Y - - Y - - C - - Y - - Y - - Y - - Y - - C - - Y - - Y - * - 1 - - Y - - Y - - C - - Y - - Y - - Y - - Y - - C - - Y - - Y - * - 2 - - Y - - Y - - C - - Y - - Y - - Y - - Y - - C - - Y - - Y - * - 3 - - Y - - Y - - C - - Y - - Y - - Y - - Y - - C - - Y - - Y +Chroma samples are :ref:`interstitially sited` +horizontally. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv410.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv410.rst index de2e519adc60..d79cd46d5055 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-yuv410.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-yuv410.rst @@ -68,60 +68,5 @@ Each cell is one byte. **Color Sample Location:** - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - - - 0 - - - - 1 - - - - 2 - - - - 3 - * - 0 - - Y - - - - Y - - - - Y - - - - Y - * - - * - 1 - - Y - - - - Y - - - - Y - - - - Y - * - - - - - - - - - C - - - - - - - * - 2 - - Y - - - - Y - - - - Y - - - - Y - * - - * - 3 - - Y - - - - Y - - - - Y - - - - Y +Chroma samples are :ref:`interstitially sited` +horizontally and vertically. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv411p.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv411p.rst index 998aa9b1328f..8a70eeca8d83 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-yuv411p.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-yuv411p.rst @@ -76,40 +76,5 @@ Each cell is one byte. **Color Sample Location:** - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - - - 0 - - 1 - - - - 2 - - 3 - * - 0 - - Y - - Y - - C - - Y - - Y - * - 1 - - Y - - Y - - C - - Y - - Y - * - 2 - - Y - - Y - - C - - Y - - Y - * - 3 - - Y - - Y - - C - - Y - - Y +Chroma samples are :ref:`interstitially sited` +horizontally. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv420.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv420.rst index f1c7baf32685..a36ec8d6d8a4 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-yuv420.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-yuv420.rst @@ -77,67 +77,5 @@ Each cell is one byte. **Color Sample Location:** - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - - - 0 - - - - 1 - - - - 2 - - - - 3 - * - 0 - - Y - - - - Y - - - - Y - - - - Y - * - - - - - C - - - - - - - - C - - - * - 1 - - Y - - - - Y - - - - Y - - - - Y - * - - * - 2 - - Y - - - - Y - - - - Y - - - - Y - * - - - - - C - - - - - - - - C - - - * - 3 - - Y - - - - Y - - - - Y - - - - Y +Chroma samples are :ref:`interstitially sited` +horizontally and vertically. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv420m.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv420m.rst index cd20a57e0621..c2cf17b9743c 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-yuv420m.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-yuv420m.rst @@ -86,67 +86,5 @@ Each cell is one byte. **Color Sample Location:** - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - - - 0 - - - - 1 - - - - 2 - - - - 3 - * - 0 - - Y - - - - Y - - - - Y - - - - Y - * - - - - - C - - - - - - - - C - - - * - 1 - - Y - - - - Y - - - - Y - - - - Y - * - - * - 2 - - Y - - - - Y - - - - Y - - - - Y - * - - - - - C - - - - - - - - C - - - * - 3 - - Y - - - - Y - - - - Y - - - - Y +Chroma samples are :ref:`interstitially sited` +horizontally and vertically. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv422m.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv422m.rst index 32bf15e1426e..f92b54853fc9 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-yuv422m.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-yuv422m.rst @@ -97,45 +97,5 @@ Each cell is one byte. **Color Sample Location:** - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - - - 0 - - - - 1 - - 2 - - - - 3 - * - 0 - - Y - - C - - Y - - Y - - C - - Y - * - 1 - - Y - - C - - Y - - Y - - C - - Y - * - 2 - - Y - - C - - Y - - Y - - C - - Y - * - 3 - - Y - - C - - Y - - Y - - C - - Y +Chroma samples are :ref:`interstitially sited` +horizontally. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv422p.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv422p.rst index b178be558361..33e6b923e325 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-yuv422p.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-yuv422p.rst @@ -85,45 +85,5 @@ Each cell is one byte. **Color Sample Location:** - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - - - 0 - - - - 1 - - 2 - - - - 3 - * - 0 - - Y - - C - - Y - - Y - - C - - Y - * - 1 - - Y - - C - - Y - - Y - - C - - Y - * - 2 - - Y - - C - - Y - - Y - - C - - Y - * - 3 - - Y - - C - - Y - - Y - - C - - Y +Chroma samples are :ref:`interstitially sited` +horizontally. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv444m.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv444m.rst index 90bdee2e2b0d..7c03cc5b07d9 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-yuv444m.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-yuv444m.rst @@ -107,35 +107,4 @@ Each cell is one byte. **Color Sample Location:** - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - - - 0 - - 1 - - 2 - - 3 - * - 0 - - YC - - YC - - YC - - YC - * - 1 - - YC - - YC - - YC - - YC - * - 2 - - YC - - YC - - YC - - YC - * - 3 - - YC - - YC - - YC - - YC +Chroma samples are :ref:`co-sited`. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuyv.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuyv.rst index ca073a5098a9..4d5773922ba1 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-yuyv.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-yuyv.rst @@ -69,50 +69,5 @@ Each cell is one byte. **Color Sample Location:** - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - - - 0 - - - - 1 - - - - 2 - - - - 3 - * - 0 - - Y - - C - - Y - - - - Y - - C - - Y - * - 1 - - Y - - C - - Y - - - - Y - - C - - Y - * - 2 - - Y - - C - - Y - - - - Y - - C - - Y - * - 3 - - Y - - C - - Y - - - - Y - - C - - Y +Chroma samples are :ref:`interstitially sited` +horizontally. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yvyu.rst b/Documentation/userspace-api/media/v4l/pixfmt-yvyu.rst index 81ebec525ae5..14b56b611349 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-yvyu.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-yvyu.rst @@ -66,43 +66,5 @@ Each cell is one byte. **Color Sample Location:** - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - - - 0 - - - - 1 - - 2 - - - - 3 - * - 0 - - Y - - C - - Y - - Y - - C - - Y - * - 1 - - Y - - C - - Y - - Y - - C - - Y - * - 2 - - Y - - C - - Y - - Y - - C - - Y - * - 3 - - Y - - C - - Y - - Y - - C - - Y +Chroma samples are :ref:`interstitially sited` +horizontally. diff --git a/Documentation/userspace-api/media/v4l/yuv-formats.rst b/Documentation/userspace-api/media/v4l/yuv-formats.rst index 4a05a105a9e6..79a4fda566c6 100644 --- a/Documentation/userspace-api/media/v4l/yuv-formats.rst +++ b/Documentation/userspace-api/media/v4l/yuv-formats.rst @@ -14,11 +14,251 @@ reconstructed by subtracting from the brightness component. See :ref:`colorspaces` for conversion examples. YUV was chosen because early television would only transmit brightness information. To add color in a way compatible with existing receivers a new signal carrier -was added to transmit the color difference signals. Secondary in the YUV -format the U and V components usually have lower resolution than the Y -component. This is an analog video compression technique taking -advantage of a property of the human visual system, being more sensitive -to brightness information. +was added to transmit the color difference signals. + + +Subsampling +=========== + +YUV formats commonly encode images with a lower resolution for the chroma +components than for the luma component. This compression technique, taking +advantage of the human eye being more sensitive to luminance than color +differences, is called chroma subsampling. + +While many combinations of subsampling factors in the horizontal and vertical +direction are possible, common factors are 1 (no subsampling), 2 and 4, with +horizontal subsampling always larger than or equal to vertical subsampling. +Common combinations are named as follows. + +- `4:4:4`: No subsampling +- `4:2:2`: Horizontal subsampling by 2, no vertical subsampling +- `4:2:0`: Horizontal subsampling by 2, vertical subsampling by 2 +- `4:1:1`: Horizontal subsampling by 4, no vertical subsampling +- `4:1:0`: Horizontal subsampling by 4, vertical subsampling by 4 + +Subsampling the chroma component effectively creates chroma values that can be +located in different spatial locations: + +- .. _yuv-chroma-centered: + + The subsampled chroma value may be calculated by simply averaging the chroma + value of two consecutive pixels. It effectively models the chroma of a pixel + sited between the two original pixels. This is referred to as centered or + interstitially sited chroma. + +- .. _yuv-chroma-cosited: + + The other option is to subsample chroma values in a way that place them in + the same spatial sites as the pixels. This may be performed by skipping every + other chroma sample (creating aliasing artifacts), or with filters using an + odd number of taps. This is referred to as co-sited chroma. + +The following examples show different combination of chroma siting in a 4x4 +image. + +.. flat-table:: 4:2:2 subsampling, interstitially sited + :header-rows: 1 + :stub-columns: 1 + + * - + - 0 + - + - 1 + - + - 2 + - + - 3 + * - 0 + - Y + - C + - Y + - + - Y + - C + - Y + * - 1 + - Y + - C + - Y + - + - Y + - C + - Y + * - 2 + - Y + - C + - Y + - + - Y + - C + - Y + * - 3 + - Y + - C + - Y + - + - Y + - C + - Y + +.. flat-table:: 4:2:2 subsampling, co-sited + :header-rows: 1 + :stub-columns: 1 + + * - + - 0 + - + - 1 + - + - 2 + - + - 3 + * - 0 + - Y/C + - + - Y + - + - Y/C + - + - Y + * - 1 + - Y/C + - + - Y + - + - Y/C + - + - Y + * - 2 + - Y/C + - + - Y + - + - Y/C + - + - Y + * - 3 + - Y/C + - + - Y + - + - Y/C + - + - Y + +.. flat-table:: 4:2:0 subsampling, horizontally interstitially sited, vertically co-sited + :header-rows: 1 + :stub-columns: 1 + + * - + - 0 + - + - 1 + - + - 2 + - + - 3 + * - 0 + - Y + - C + - Y + - + - Y + - C + - Y + * - 1 + - Y + - + - Y + - + - Y + - + - Y + * - 2 + - Y + - C + - Y + - + - Y + - C + - Y + * - 3 + - Y + - + - Y + - + - Y + - + - Y + +.. flat-table:: 4:1:0 subsampling, horizontally and vertically interstitially sited + :header-rows: 1 + :stub-columns: 1 + + * - + - 0 + - + - 1 + - + - 2 + - + - 3 + * - 0 + - Y + - + - Y + - + - Y + - + - Y + * - + - + - + - + - + - + - + - + * - 1 + - Y + - + - Y + - + - Y + - + - Y + * - + - + - + - + - C + - + - + - + * - 2 + - Y + - + - Y + - + - Y + - + - Y + * - + - + - + - + - + - + - + - + * - 3 + - Y + - + - Y + - + - Y + - + - Y .. toctree:: -- cgit v1.2.3 From 7cb8bd292ba0e3823cf31f8cd247c5557f3b7c67 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 7 Dec 2020 00:03:10 +0100 Subject: media: doc: pixfmt-yuv: Move all packed YUV formats to common file The pixfmt-packed-yuv.rst file documents packed YUV 4:4:4 formats, but is titled generically as "Packed YUV formats". 4:2:2 and 4:1:1 packed YUV formats are documented in separate files, which can be confusing. Group all packed YUV formats in pixfmt-packed-yuv.rst, which allows documenting the 4:2:2 formats in a more concise way. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/pixfmt-packed-yuv.rst | 147 ++++++++++++++++++++- .../userspace-api/media/v4l/pixfmt-uyvy.rst | 70 ---------- .../userspace-api/media/v4l/pixfmt-vyuy.rst | 70 ---------- .../userspace-api/media/v4l/pixfmt-y41p.rst | 93 ------------- .../userspace-api/media/v4l/pixfmt-yuyv.rst | 73 ---------- .../userspace-api/media/v4l/pixfmt-yvyu.rst | 70 ---------- .../userspace-api/media/v4l/yuv-formats.rst | 5 - 7 files changed, 140 insertions(+), 388 deletions(-) delete mode 100644 Documentation/userspace-api/media/v4l/pixfmt-uyvy.rst delete mode 100644 Documentation/userspace-api/media/v4l/pixfmt-vyuy.rst delete mode 100644 Documentation/userspace-api/media/v4l/pixfmt-y41p.rst delete mode 100644 Documentation/userspace-api/media/v4l/pixfmt-yuyv.rst delete mode 100644 Documentation/userspace-api/media/v4l/pixfmt-yvyu.rst diff --git a/Documentation/userspace-api/media/v4l/pixfmt-packed-yuv.rst b/Documentation/userspace-api/media/v4l/pixfmt-packed-yuv.rst index 84262208dd1c..8ed1a6aff3a6 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-packed-yuv.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-packed-yuv.rst @@ -6,12 +6,16 @@ Packed YUV formats ****************** -Description -=========== +Similarly to the packed RGB formats, the packed YUV formats store the Y, Cb and +Cr components consecutively in memory. They may apply subsampling to the chroma +components and thus differ in how they interlave the three components. -Similar to the packed RGB formats these formats store the Y, Cb and Cr -component of each pixel in one 16 or 32 bit word. +4:4:4 Subsampling +================= + +These formats do not subsample the chroma components and store each pixels as a +full triplet of Y, Cb and Cr values. .. raw:: latex @@ -19,11 +23,9 @@ component of each pixel in one 16 or 32 bit word. \tiny \setlength{\tabcolsep}{2pt} -.. _packed-yuv-formats: - .. tabularcolumns:: |p{2.5cm}|p{0.69cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}| -.. flat-table:: Packed YUV Image Formats +.. flat-table:: Packed YUV 4:4:4 Image Formats :header-rows: 2 :stub-columns: 0 @@ -371,3 +373,134 @@ component of each pixel in one 16 or 32 bit word. expected to contain a meaningful value that can be used by drivers and applications. And, the formats XYUV32 and VUYX32 contain undefined alpha values that must be ignored by all applications and drivers. + + +4:2:2 Subsampling +================= + +These formats, commonly referred to as YUYV or YUY2, subsample the chroma +components horizontally by 2, storing 2 pixels in 4 bytes. + +.. flat-table:: Packed YUV 4:2:2 Formats + :header-rows: 1 + :stub-columns: 0 + + * - Identifier + - Code + - Byte 0 + - Byte 1 + - Byte 2 + - Byte 3 + - Byte 4 + - Byte 5 + - Byte 6 + - Byte 7 + * .. _V4L2-PIX-FMT-UYVY: + + - ``V4L2_PIX_FMT_UYVY`` + - 'UYVY' + + - Cb\ :sub:`0` + - Y'\ :sub:`0` + - Cr\ :sub:`0` + - Y'\ :sub:`1` + - Cb\ :sub:`2` + - Y'\ :sub:`2` + - Cr\ :sub:`2` + - Y'\ :sub:`3` + * .. _V4L2-PIX-FMT-VYUY: + + - ``V4L2_PIX_FMT_VYUY`` + - 'VYUY' + + - Cr\ :sub:`0` + - Y'\ :sub:`0` + - Cb\ :sub:`0` + - Y'\ :sub:`1` + - Cr\ :sub:`2` + - Y'\ :sub:`2` + - Cb\ :sub:`2` + - Y'\ :sub:`3` + * .. _V4L2-PIX-FMT-YUYV: + + - ``V4L2_PIX_FMT_YUYV`` + - 'YUYV' + + - Y'\ :sub:`0` + - Cb\ :sub:`0` + - Y'\ :sub:`1` + - Cr\ :sub:`0` + - Y'\ :sub:`2` + - Cb\ :sub:`2` + - Y'\ :sub:`3` + - Cr\ :sub:`2` + * .. _V4L2-PIX-FMT-YVYU: + + - ``V4L2_PIX_FMT_YVYU`` + - 'YVYU' + + - Y'\ :sub:`0` + - Cr\ :sub:`0` + - Y'\ :sub:`1` + - Cb\ :sub:`0` + - Y'\ :sub:`2` + - Cr\ :sub:`2` + - Y'\ :sub:`3` + - Cb\ :sub:`2` + +**Color Sample Location:** +Chroma samples are :ref:`interstitially sited` +horizontally. + + +4:1:1 Subsampling +================= + +This format subsamples the chroma components horizontally by 4, storing 8 +pixels in 12 bytes. + +.. flat-table:: Packed YUV 4:1:1 Formats + :header-rows: 1 + :stub-columns: 0 + + * - Identifier + - Code + - Byte 0 + - Byte 1 + - Byte 2 + - Byte 3 + - Byte 4 + - Byte 5 + - Byte 6 + - Byte 7 + - Byte 8 + - Byte 9 + - Byte 10 + - Byte 11 + * .. _V4L2-PIX-FMT-Y41P: + + - ``V4L2_PIX_FMT_Y41P`` + - 'Y41P' + + - Cb\ :sub:`0` + - Y'\ :sub:`0` + - Cr\ :sub:`0` + - Y'\ :sub:`1` + - Cb\ :sub:`4` + - Y'\ :sub:`2` + - Cr\ :sub:`4` + - Y'\ :sub:`3` + - Y'\ :sub:`4` + - Y'\ :sub:`5` + - Y'\ :sub:`6` + - Y'\ :sub:`7` + +.. note:: + + Do not confuse ``V4L2_PIX_FMT_Y41P`` with + :ref:`V4L2_PIX_FMT_YUV411P `. Y41P is derived from + "YUV 4:1:1 *packed*", while YUV411P stands for "YUV 4:1:1 *planar*". + +**Color Sample Location:** +Chroma samples are :ref:`interstitially sited` +horizontally. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-uyvy.rst b/Documentation/userspace-api/media/v4l/pixfmt-uyvy.rst deleted file mode 100644 index 1abc3066b712..000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-uyvy.rst +++ /dev/null @@ -1,70 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _V4L2-PIX-FMT-UYVY: - -************************** -V4L2_PIX_FMT_UYVY ('UYVY') -************************** - - -Variation of ``V4L2_PIX_FMT_YUYV`` with different order of samples in -memory - - -Description -=========== - -In this format each four bytes is two pixels. Each four bytes is two -Y's, a Cb and a Cr. Each Y goes to one of the pixels, and the Cb and Cr -belong to both pixels. As you can see, the Cr and Cb components have -half the horizontal resolution of the Y component. - -**Byte Order.** -Each cell is one byte. - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - start + 0: - - Cb\ :sub:`00` - - Y'\ :sub:`00` - - Cr\ :sub:`00` - - Y'\ :sub:`01` - - Cb\ :sub:`01` - - Y'\ :sub:`02` - - Cr\ :sub:`01` - - Y'\ :sub:`03` - * - start + 8: - - Cb\ :sub:`10` - - Y'\ :sub:`10` - - Cr\ :sub:`10` - - Y'\ :sub:`11` - - Cb\ :sub:`11` - - Y'\ :sub:`12` - - Cr\ :sub:`11` - - Y'\ :sub:`13` - * - start + 16: - - Cb\ :sub:`20` - - Y'\ :sub:`20` - - Cr\ :sub:`20` - - Y'\ :sub:`21` - - Cb\ :sub:`21` - - Y'\ :sub:`22` - - Cr\ :sub:`21` - - Y'\ :sub:`23` - * - start + 24: - - Cb\ :sub:`30` - - Y'\ :sub:`30` - - Cr\ :sub:`30` - - Y'\ :sub:`31` - - Cb\ :sub:`31` - - Y'\ :sub:`32` - - Cr\ :sub:`31` - - Y'\ :sub:`33` - - -**Color Sample Location:** -Chroma samples are :ref:`interstitially sited` -horizontally. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-vyuy.rst b/Documentation/userspace-api/media/v4l/pixfmt-vyuy.rst deleted file mode 100644 index 4fd0630a83a4..000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-vyuy.rst +++ /dev/null @@ -1,70 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _V4L2-PIX-FMT-VYUY: - -************************** -V4L2_PIX_FMT_VYUY ('VYUY') -************************** - - -Variation of ``V4L2_PIX_FMT_YUYV`` with different order of samples in -memory - - -Description -=========== - -In this format each four bytes is two pixels. Each four bytes is two -Y's, a Cb and a Cr. Each Y goes to one of the pixels, and the Cb and Cr -belong to both pixels. As you can see, the Cr and Cb components have -half the horizontal resolution of the Y component. - -**Byte Order.** -Each cell is one byte. - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - start + 0: - - Cr\ :sub:`00` - - Y'\ :sub:`00` - - Cb\ :sub:`00` - - Y'\ :sub:`01` - - Cr\ :sub:`01` - - Y'\ :sub:`02` - - Cb\ :sub:`01` - - Y'\ :sub:`03` - * - start + 8: - - Cr\ :sub:`10` - - Y'\ :sub:`10` - - Cb\ :sub:`10` - - Y'\ :sub:`11` - - Cr\ :sub:`11` - - Y'\ :sub:`12` - - Cb\ :sub:`11` - - Y'\ :sub:`13` - * - start + 16: - - Cr\ :sub:`20` - - Y'\ :sub:`20` - - Cb\ :sub:`20` - - Y'\ :sub:`21` - - Cr\ :sub:`21` - - Y'\ :sub:`22` - - Cb\ :sub:`21` - - Y'\ :sub:`23` - * - start + 24: - - Cr\ :sub:`30` - - Y'\ :sub:`30` - - Cb\ :sub:`30` - - Y'\ :sub:`31` - - Cr\ :sub:`31` - - Y'\ :sub:`32` - - Cb\ :sub:`31` - - Y'\ :sub:`33` - - -**Color Sample Location:** -Chroma samples are :ref:`interstitially sited` -horizontally. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-y41p.rst b/Documentation/userspace-api/media/v4l/pixfmt-y41p.rst deleted file mode 100644 index bb83eb6db3e5..000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-y41p.rst +++ /dev/null @@ -1,93 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _V4L2-PIX-FMT-Y41P: - -************************** -V4L2_PIX_FMT_Y41P ('Y41P') -************************** - - -Format with ¼ horizontal chroma resolution, also known as YUV 4:1:1 - - -Description -=========== - -In this format each 12 bytes is eight pixels. In the twelve bytes are -two CbCr pairs and eight Y's. The first CbCr pair goes with the first -four Y's, and the second CbCr pair goes with the other four Y's. The Cb -and Cr components have one fourth the horizontal resolution of the Y -component. - -Do not confuse this format with -:ref:`V4L2_PIX_FMT_YUV411P `. Y41P is derived -from "YUV 4:1:1 *packed*", while YUV411P stands for "YUV 4:1:1 -*planar*". - -**Byte Order.** -Each cell is one byte. - - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - start + 0: - - Cb\ :sub:`00` - - Y'\ :sub:`00` - - Cr\ :sub:`00` - - Y'\ :sub:`01` - - Cb\ :sub:`01` - - Y'\ :sub:`02` - - Cr\ :sub:`01` - - Y'\ :sub:`03` - - Y'\ :sub:`04` - - Y'\ :sub:`05` - - Y'\ :sub:`06` - - Y'\ :sub:`07` - * - start + 12: - - Cb\ :sub:`10` - - Y'\ :sub:`10` - - Cr\ :sub:`10` - - Y'\ :sub:`11` - - Cb\ :sub:`11` - - Y'\ :sub:`12` - - Cr\ :sub:`11` - - Y'\ :sub:`13` - - Y'\ :sub:`14` - - Y'\ :sub:`15` - - Y'\ :sub:`16` - - Y'\ :sub:`17` - * - start + 24: - - Cb\ :sub:`20` - - Y'\ :sub:`20` - - Cr\ :sub:`20` - - Y'\ :sub:`21` - - Cb\ :sub:`21` - - Y'\ :sub:`22` - - Cr\ :sub:`21` - - Y'\ :sub:`23` - - Y'\ :sub:`24` - - Y'\ :sub:`25` - - Y'\ :sub:`26` - - Y'\ :sub:`27` - * - start + 36: - - Cb\ :sub:`30` - - Y'\ :sub:`30` - - Cr\ :sub:`30` - - Y'\ :sub:`31` - - Cb\ :sub:`31` - - Y'\ :sub:`32` - - Cr\ :sub:`31` - - Y'\ :sub:`33` - - Y'\ :sub:`34` - - Y'\ :sub:`35` - - Y'\ :sub:`36` - - Y'\ :sub:`37` - - -**Color Sample Location:** -Chroma samples are :ref:`interstitially sited` -horizontally. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuyv.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuyv.rst deleted file mode 100644 index 4d5773922ba1..000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-yuyv.rst +++ /dev/null @@ -1,73 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _V4L2-PIX-FMT-YUYV: - -************************** -V4L2_PIX_FMT_YUYV ('YUYV') -************************** - - -Packed format with ½ horizontal chroma resolution, also known as YUV -4:2:2 - - -Description -=========== - -In this format each four bytes is two pixels. Each four bytes is two -Y's, a Cb and a Cr. Each Y goes to one of the pixels, and the Cb and Cr -belong to both pixels. As you can see, the Cr and Cb components have -half the horizontal resolution of the Y component. ``V4L2_PIX_FMT_YUYV`` -is known in the Windows environment as YUY2. - -**Byte Order.** -Each cell is one byte. - - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - start + 0: - - Y'\ :sub:`00` - - Cb\ :sub:`00` - - Y'\ :sub:`01` - - Cr\ :sub:`00` - - Y'\ :sub:`02` - - Cb\ :sub:`01` - - Y'\ :sub:`03` - - Cr\ :sub:`01` - * - start + 8: - - Y'\ :sub:`10` - - Cb\ :sub:`10` - - Y'\ :sub:`11` - - Cr\ :sub:`10` - - Y'\ :sub:`12` - - Cb\ :sub:`11` - - Y'\ :sub:`13` - - Cr\ :sub:`11` - * - start + 16: - - Y'\ :sub:`20` - - Cb\ :sub:`20` - - Y'\ :sub:`21` - - Cr\ :sub:`20` - - Y'\ :sub:`22` - - Cb\ :sub:`21` - - Y'\ :sub:`23` - - Cr\ :sub:`21` - * - start + 24: - - Y'\ :sub:`30` - - Cb\ :sub:`30` - - Y'\ :sub:`31` - - Cr\ :sub:`30` - - Y'\ :sub:`32` - - Cb\ :sub:`31` - - Y'\ :sub:`33` - - Cr\ :sub:`31` - - -**Color Sample Location:** -Chroma samples are :ref:`interstitially sited` -horizontally. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yvyu.rst b/Documentation/userspace-api/media/v4l/pixfmt-yvyu.rst deleted file mode 100644 index 14b56b611349..000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-yvyu.rst +++ /dev/null @@ -1,70 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _V4L2-PIX-FMT-YVYU: - -************************** -V4L2_PIX_FMT_YVYU ('YVYU') -************************** - - -Variation of ``V4L2_PIX_FMT_YUYV`` with different order of samples in -memory - - -Description -=========== - -In this format each four bytes is two pixels. Each four bytes is two -Y's, a Cb and a Cr. Each Y goes to one of the pixels, and the Cb and Cr -belong to both pixels. As you can see, the Cr and Cb components have -half the horizontal resolution of the Y component. - -**Byte Order.** -Each cell is one byte. - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - start + 0: - - Y'\ :sub:`00` - - Cr\ :sub:`00` - - Y'\ :sub:`01` - - Cb\ :sub:`00` - - Y'\ :sub:`02` - - Cr\ :sub:`01` - - Y'\ :sub:`03` - - Cb\ :sub:`01` - * - start + 8: - - Y'\ :sub:`10` - - Cr\ :sub:`10` - - Y'\ :sub:`11` - - Cb\ :sub:`10` - - Y'\ :sub:`12` - - Cr\ :sub:`11` - - Y'\ :sub:`13` - - Cb\ :sub:`11` - * - start + 16: - - Y'\ :sub:`20` - - Cr\ :sub:`20` - - Y'\ :sub:`21` - - Cb\ :sub:`20` - - Y'\ :sub:`22` - - Cr\ :sub:`21` - - Y'\ :sub:`23` - - Cb\ :sub:`21` - * - start + 24: - - Y'\ :sub:`30` - - Cr\ :sub:`30` - - Y'\ :sub:`31` - - Cb\ :sub:`30` - - Y'\ :sub:`32` - - Cr\ :sub:`31` - - Y'\ :sub:`33` - - Cb\ :sub:`31` - - -**Color Sample Location:** -Chroma samples are :ref:`interstitially sited` -horizontally. diff --git a/Documentation/userspace-api/media/v4l/yuv-formats.rst b/Documentation/userspace-api/media/v4l/yuv-formats.rst index 79a4fda566c6..a5b17040679e 100644 --- a/Documentation/userspace-api/media/v4l/yuv-formats.rst +++ b/Documentation/userspace-api/media/v4l/yuv-formats.rst @@ -276,11 +276,6 @@ image. pixfmt-y8i pixfmt-y12i pixfmt-uv8 - pixfmt-yuyv - pixfmt-uyvy - pixfmt-yvyu - pixfmt-vyuy - pixfmt-y41p pixfmt-yuv420 pixfmt-yuv420m pixfmt-yuv422m -- cgit v1.2.3 From 4578d936b4ba694d79909f3f4f2deaed4b64f2c5 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 7 Dec 2020 00:03:11 +0100 Subject: media: doc: pixfmt-packed-yuv: Fill padding bits with 'X' The padding bits are left blank, which look weird in the XYUV format, and, worse, may lead to the VUYX format to be understand as consuming 3 bytes per pixel. Add 'X' for padding bits as we do for RGB formats. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/pixfmt-packed-yuv.rst | 32 +++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Documentation/userspace-api/media/v4l/pixfmt-packed-yuv.rst b/Documentation/userspace-api/media/v4l/pixfmt-packed-yuv.rst index 8ed1a6aff3a6..fbd9b412388c 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-packed-yuv.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-packed-yuv.rst @@ -239,14 +239,14 @@ full triplet of Y, Cb and Cr values. - ``V4L2_PIX_FMT_XYUV32`` - 'XYUV' - - - - - - - - - - - - - - - - + - X\ :sub:`7` + - X\ :sub:`6` + - X\ :sub:`5` + - X\ :sub:`4` + - X\ :sub:`3` + - X\ :sub:`2` + - X\ :sub:`1` + - X\ :sub:`0` - Y'\ :sub:`7` - Y'\ :sub:`6` @@ -348,14 +348,14 @@ full triplet of Y, Cb and Cr values. - Y'\ :sub:`1` - Y'\ :sub:`0` - - - - - - - - - - - - - - - - + - X\ :sub:`7` + - X\ :sub:`6` + - X\ :sub:`5` + - X\ :sub:`4` + - X\ :sub:`3` + - X\ :sub:`2` + - X\ :sub:`1` + - X\ :sub:`0` .. raw:: latex -- cgit v1.2.3 From 2f2a387e9fa495ec7ab4fcb29e0d93c7be022f97 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 7 Dec 2020 00:03:12 +0100 Subject: media: doc: pixfmt-packed-yuv: Express 4:4:4 formats in a more compact way The 4:4:4 packed YUV formats are documented with a bit-level representation, which creates a wide table. Switch to a byte-oriented representation to make it more compact. This prepares for the addition of formats with more than 8 bits per component, that would make the table way too wide. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/pixfmt-packed-yuv.rst | 273 +++++---------------- 1 file changed, 56 insertions(+), 217 deletions(-) diff --git a/Documentation/userspace-api/media/v4l/pixfmt-packed-yuv.rst b/Documentation/userspace-api/media/v4l/pixfmt-packed-yuv.rst index fbd9b412388c..6f9f9d63a4ad 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-packed-yuv.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-packed-yuv.rst @@ -10,6 +10,14 @@ Similarly to the packed RGB formats, the packed YUV formats store the Y, Cb and Cr components consecutively in memory. They may apply subsampling to the chroma components and thus differ in how they interlave the three components. +.. note:: + + - In all the tables that follow, bit 7 is the most significant bit in a byte. + - 'Y', 'Cb' and 'Cr' denote bits of the luma, blue chroma (also known as + 'U') and red chroma (also known as 'V') components respectively. 'A' + denotes bits of the alpha component (if supported by the format), and 'X' + denotes padding bits. + 4:4:4 Subsampling ================= @@ -23,9 +31,9 @@ full triplet of Y, Cb and Cr values. \tiny \setlength{\tabcolsep}{2pt} -.. tabularcolumns:: |p{2.5cm}|p{0.69cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}| +.. tabularcolumns:: |p{2.5cm}|p{0.69cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}| -.. flat-table:: Packed YUV 4:4:4 Image Formats +.. flat-table:: Packed YUV 4:4:4 Image Formats (less than 8bpc) :header-rows: 2 :stub-columns: 0 @@ -36,10 +44,6 @@ full triplet of Y, Cb and Cr values. - :cspan:`7` Byte 1 - - :cspan:`7` Byte 2 - - - :cspan:`7` Byte 3 - * - - - 7 @@ -60,24 +64,6 @@ full triplet of Y, Cb and Cr values. - 1 - 0 - - 7 - - 6 - - 5 - - 4 - - 3 - - 2 - - 1 - - 0 - - - 7 - - 6 - - 5 - - 4 - - 3 - - 2 - - 1 - - 0 - * .. _V4L2-PIX-FMT-YUV444: - ``V4L2_PIX_FMT_YUV444`` @@ -101,8 +87,6 @@ full triplet of Y, Cb and Cr values. - Y'\ :sub:`1` - Y'\ :sub:`0` - - :cspan:`15` - * .. _V4L2-PIX-FMT-YUV555: - ``V4L2_PIX_FMT_YUV555`` @@ -126,7 +110,6 @@ full triplet of Y, Cb and Cr values. - Cb\ :sub:`4` - Cb\ :sub:`3` - - :cspan:`15` * .. _V4L2-PIX-FMT-YUV565: - ``V4L2_PIX_FMT_YUV565`` @@ -150,229 +133,85 @@ full triplet of Y, Cb and Cr values. - Cb\ :sub:`4` - Cb\ :sub:`3` - - :cspan:`15` +.. raw:: latex - * .. _V4L2-PIX-FMT-YUV32: + \endgroup - - ``V4L2_PIX_FMT_YUV32`` - - 'YUV4' +.. note:: - - a\ :sub:`7` - - a\ :sub:`6` - - a\ :sub:`5` - - a\ :sub:`4` - - a\ :sub:`3` - - a\ :sub:`2` - - a\ :sub:`1` - - a\ :sub:`0` + For the YUV444 and YUV555 formats, the value of alpha bits is undefined + when reading from the driver, ignored when writing to the driver, except + when alpha blending has been negotiated for a :ref:`Video Overlay + ` or :ref:`Video Output Overlay `. - - Y'\ :sub:`7` - - Y'\ :sub:`6` - - Y'\ :sub:`5` - - Y'\ :sub:`4` - - Y'\ :sub:`3` - - Y'\ :sub:`2` - - Y'\ :sub:`1` - - Y'\ :sub:`0` - - Cb\ :sub:`7` - - Cb\ :sub:`6` - - Cb\ :sub:`5` - - Cb\ :sub:`4` - - Cb\ :sub:`3` - - Cb\ :sub:`2` - - Cb\ :sub:`1` - - Cb\ :sub:`0` +.. flat-table:: Packed YUV Image Formats (8bpc) + :header-rows: 1 + :stub-columns: 0 - - Cr\ :sub:`7` - - Cr\ :sub:`6` - - Cr\ :sub:`5` - - Cr\ :sub:`4` - - Cr\ :sub:`3` - - Cr\ :sub:`2` - - Cr\ :sub:`1` - - Cr\ :sub:`0` + * - Identifier + - Code + - Byte 0 + - Byte 1 + - Byte 2 + - Byte 3 - * .. _V4L2-PIX-FMT-AYUV32: + * .. _V4L2-PIX-FMT-YUV32: - - ``V4L2_PIX_FMT_AYUV32`` - - 'AYUV' + - ``V4L2_PIX_FMT_YUV32`` + - 'YUV4' - - a\ :sub:`7` - - a\ :sub:`6` - - a\ :sub:`5` - - a\ :sub:`4` - - a\ :sub:`3` - - a\ :sub:`2` - - a\ :sub:`1` - - a\ :sub:`0` + - A\ :sub:`7-0` + - Y'\ :sub:`7-0` + - Cb\ :sub:`7-0` + - Cr\ :sub:`7-0` - - Y'\ :sub:`7` - - Y'\ :sub:`6` - - Y'\ :sub:`5` - - Y'\ :sub:`4` - - Y'\ :sub:`3` - - Y'\ :sub:`2` - - Y'\ :sub:`1` - - Y'\ :sub:`0` + * .. _V4L2-PIX-FMT-AYUV32: - - Cb\ :sub:`7` - - Cb\ :sub:`6` - - Cb\ :sub:`5` - - Cb\ :sub:`4` - - Cb\ :sub:`3` - - Cb\ :sub:`2` - - Cb\ :sub:`1` - - Cb\ :sub:`0` + - ``V4L2_PIX_FMT_AYUV32`` + - 'AYUV' - - Cr\ :sub:`7` - - Cr\ :sub:`6` - - Cr\ :sub:`5` - - Cr\ :sub:`4` - - Cr\ :sub:`3` - - Cr\ :sub:`2` - - Cr\ :sub:`1` - - Cr\ :sub:`0` + - A\ :sub:`7-0` + - Y'\ :sub:`7-0` + - Cb\ :sub:`7-0` + - Cr\ :sub:`7-0` * .. _V4L2-PIX-FMT-XYUV32: - ``V4L2_PIX_FMT_XYUV32`` - 'XYUV' - - X\ :sub:`7` - - X\ :sub:`6` - - X\ :sub:`5` - - X\ :sub:`4` - - X\ :sub:`3` - - X\ :sub:`2` - - X\ :sub:`1` - - X\ :sub:`0` - - - Y'\ :sub:`7` - - Y'\ :sub:`6` - - Y'\ :sub:`5` - - Y'\ :sub:`4` - - Y'\ :sub:`3` - - Y'\ :sub:`2` - - Y'\ :sub:`1` - - Y'\ :sub:`0` - - - Cb\ :sub:`7` - - Cb\ :sub:`6` - - Cb\ :sub:`5` - - Cb\ :sub:`4` - - Cb\ :sub:`3` - - Cb\ :sub:`2` - - Cb\ :sub:`1` - - Cb\ :sub:`0` - - - Cr\ :sub:`7` - - Cr\ :sub:`6` - - Cr\ :sub:`5` - - Cr\ :sub:`4` - - Cr\ :sub:`3` - - Cr\ :sub:`2` - - Cr\ :sub:`1` - - Cr\ :sub:`0` + - X\ :sub:`7-0` + - Y'\ :sub:`7-0` + - Cb\ :sub:`7-0` + - Cr\ :sub:`7-0` * .. _V4L2-PIX-FMT-VUYA32: - ``V4L2_PIX_FMT_VUYA32`` - 'VUYA' - - Cr\ :sub:`7` - - Cr\ :sub:`6` - - Cr\ :sub:`5` - - Cr\ :sub:`4` - - Cr\ :sub:`3` - - Cr\ :sub:`2` - - Cr\ :sub:`1` - - Cr\ :sub:`0` - - - Cb\ :sub:`7` - - Cb\ :sub:`6` - - Cb\ :sub:`5` - - Cb\ :sub:`4` - - Cb\ :sub:`3` - - Cb\ :sub:`2` - - Cb\ :sub:`1` - - Cb\ :sub:`0` - - - Y'\ :sub:`7` - - Y'\ :sub:`6` - - Y'\ :sub:`5` - - Y'\ :sub:`4` - - Y'\ :sub:`3` - - Y'\ :sub:`2` - - Y'\ :sub:`1` - - Y'\ :sub:`0` - - - a\ :sub:`7` - - a\ :sub:`6` - - a\ :sub:`5` - - a\ :sub:`4` - - a\ :sub:`3` - - a\ :sub:`2` - - a\ :sub:`1` - - a\ :sub:`0` + - Cr\ :sub:`7-0` + - Cb\ :sub:`7-0` + - Y'\ :sub:`7-0` + - A\ :sub:`7-0` * .. _V4L2-PIX-FMT-VUYX32: - ``V4L2_PIX_FMT_VUYX32`` - 'VUYX' - - Cr\ :sub:`7` - - Cr\ :sub:`6` - - Cr\ :sub:`5` - - Cr\ :sub:`4` - - Cr\ :sub:`3` - - Cr\ :sub:`2` - - Cr\ :sub:`1` - - Cr\ :sub:`0` - - - Cb\ :sub:`7` - - Cb\ :sub:`6` - - Cb\ :sub:`5` - - Cb\ :sub:`4` - - Cb\ :sub:`3` - - Cb\ :sub:`2` - - Cb\ :sub:`1` - - Cb\ :sub:`0` - - - Y'\ :sub:`7` - - Y'\ :sub:`6` - - Y'\ :sub:`5` - - Y'\ :sub:`4` - - Y'\ :sub:`3` - - Y'\ :sub:`2` - - Y'\ :sub:`1` - - Y'\ :sub:`0` - - - X\ :sub:`7` - - X\ :sub:`6` - - X\ :sub:`5` - - X\ :sub:`4` - - X\ :sub:`3` - - X\ :sub:`2` - - X\ :sub:`1` - - X\ :sub:`0` - -.. raw:: latex - - \endgroup + - Cr\ :sub:`7-0` + - Cb\ :sub:`7-0` + - Y'\ :sub:`7-0` + - X\ :sub:`7-0` .. note:: - #) Bit 7 is the most significant bit; - - #) The value of a = alpha bits is undefined when reading from the driver, - ignored when writing to the driver, except when alpha blending has - been negotiated for a :ref:`Video Overlay ` or - :ref:`Video Output Overlay ` for the formats Y444, YUV555 and - YUV4. However, for formats AYUV32 and VUYA32, the alpha component is - expected to contain a meaningful value that can be used by drivers - and applications. And, the formats XYUV32 and VUYX32 contain undefined - alpha values that must be ignored by all applications and drivers. + - The alpha component is expected to contain a meaningful value that can be + used by drivers and applications. + - The padding bits contain undefined values that must be ignored by all + applications and drivers. 4:2:2 Subsampling -- cgit v1.2.3 From 4bfc1688e10248f163b8dc83c47bada2073f241b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 7 Dec 2020 00:03:13 +0100 Subject: media: doc: pixfmt-packed-yuv: Clarify naming scheme for 4:4:4 formats Document the naming scheme for the existing packed YUV 4:4:4 formats, as previously done for the RGB formats. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/pixfmt-packed-yuv.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Documentation/userspace-api/media/v4l/pixfmt-packed-yuv.rst b/Documentation/userspace-api/media/v4l/pixfmt-packed-yuv.rst index 6f9f9d63a4ad..eb551b57557e 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-packed-yuv.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-packed-yuv.rst @@ -25,6 +25,14 @@ components and thus differ in how they interlave the three components. These formats do not subsample the chroma components and store each pixels as a full triplet of Y, Cb and Cr values. +The next table lists the packed YUV 4:4:4 formats with less than 8 bits per +component. They are named based on the order of the Y, Cb and Cr components as +seen in a 16-bit word, which is then stored in memory in little endian byte +order, and on the number of bits for each component. For instance the YUV565 +format stores a pixel in a 16-bit word [15:0] laid out at as [Y'\ :sub:`4-0` +Cb\ :sub:`5-0` Cr\ :sub:`4-0`], and stored in memory in two bytes, +[Cb\ :sub:`2-0` Cr\ :sub:`4-0`] followed by [Y'\ :sub:`4-0` Cb\ :sub:`5-3`]. + .. raw:: latex \begingroup @@ -145,6 +153,12 @@ full triplet of Y, Cb and Cr values. ` or :ref:`Video Output Overlay `. +The next table lists the packed YUV 4:4:4 formats with 8 bits per component. +They are named based on the order of the Y, Cb and Cr components as stored in +memory, and on the total number of bits per pixel. For instance, the VUYX32 +format stores a pixel with Cr\ :sub:`7-0` in the first byte, Cb\ :sub:`7-0` in +the second byte and Y'\ :sub:`7-0` in the third byte. + .. flat-table:: Packed YUV Image Formats (8bpc) :header-rows: 1 :stub-columns: 0 -- cgit v1.2.3 From af4f450576958cbb462c9805362d898662051e26 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 7 Dec 2020 00:03:14 +0100 Subject: media: doc: pixfmt-yuv: Move all luma-only YUV formats to common file Luma-only pixel formats are documented in separate files. This duplicates information, as those formats share comon traits. Consolidate them in a single file and describe them in a single table. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/pixfmt-grey.rst | 44 ------- .../userspace-api/media/v4l/pixfmt-y10.rst | 65 ----------- .../userspace-api/media/v4l/pixfmt-y10b.rst | 33 ------ .../userspace-api/media/v4l/pixfmt-y10p.rst | 43 ------- .../userspace-api/media/v4l/pixfmt-y12.rst | 65 ----------- .../userspace-api/media/v4l/pixfmt-y14.rst | 65 ----------- .../userspace-api/media/v4l/pixfmt-y16-be.rst | 69 ----------- .../userspace-api/media/v4l/pixfmt-y16.rst | 69 ----------- .../userspace-api/media/v4l/pixfmt-yuv-luma.rst | 126 +++++++++++++++++++++ .../userspace-api/media/v4l/yuv-formats.rst | 9 +- 10 files changed, 127 insertions(+), 461 deletions(-) delete mode 100644 Documentation/userspace-api/media/v4l/pixfmt-grey.rst delete mode 100644 Documentation/userspace-api/media/v4l/pixfmt-y10.rst delete mode 100644 Documentation/userspace-api/media/v4l/pixfmt-y10b.rst delete mode 100644 Documentation/userspace-api/media/v4l/pixfmt-y10p.rst delete mode 100644 Documentation/userspace-api/media/v4l/pixfmt-y12.rst delete mode 100644 Documentation/userspace-api/media/v4l/pixfmt-y14.rst delete mode 100644 Documentation/userspace-api/media/v4l/pixfmt-y16-be.rst delete mode 100644 Documentation/userspace-api/media/v4l/pixfmt-y16.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-yuv-luma.rst diff --git a/Documentation/userspace-api/media/v4l/pixfmt-grey.rst b/Documentation/userspace-api/media/v4l/pixfmt-grey.rst deleted file mode 100644 index 121365b03c57..000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-grey.rst +++ /dev/null @@ -1,44 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _V4L2-PIX-FMT-GREY: - -************************** -V4L2_PIX_FMT_GREY ('GREY') -************************** - -Grey-scale image - - -Description -=========== - -This is a grey-scale image. It is really a degenerate Y'CbCr format -which simply contains no Cb or Cr data. - -**Byte Order.** -Each cell is one byte. - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - start + 0: - - Y'\ :sub:`00` - - Y'\ :sub:`01` - - Y'\ :sub:`02` - - Y'\ :sub:`03` - * - start + 4: - - Y'\ :sub:`10` - - Y'\ :sub:`11` - - Y'\ :sub:`12` - - Y'\ :sub:`13` - * - start + 8: - - Y'\ :sub:`20` - - Y'\ :sub:`21` - - Y'\ :sub:`22` - - Y'\ :sub:`23` - * - start + 12: - - Y'\ :sub:`30` - - Y'\ :sub:`31` - - Y'\ :sub:`32` - - Y'\ :sub:`33` diff --git a/Documentation/userspace-api/media/v4l/pixfmt-y10.rst b/Documentation/userspace-api/media/v4l/pixfmt-y10.rst deleted file mode 100644 index 05f018dd883f..000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-y10.rst +++ /dev/null @@ -1,65 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _V4L2-PIX-FMT-Y10: - -************************* -V4L2_PIX_FMT_Y10 ('Y10 ') -************************* - - -Grey-scale image - - -Description -=========== - -This is a grey-scale image with a depth of 10 bits per pixel. Pixels are -stored in 16-bit words with unused high bits padded with 0. The least -significant byte is stored at lower memory addresses (little-endian). - -**Byte Order.** -Each cell is one byte. - - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - start + 0: - - Y'\ :sub:`00low` - - Y'\ :sub:`00high` - - Y'\ :sub:`01low` - - Y'\ :sub:`01high` - - Y'\ :sub:`02low` - - Y'\ :sub:`02high` - - Y'\ :sub:`03low` - - Y'\ :sub:`03high` - * - start + 8: - - Y'\ :sub:`10low` - - Y'\ :sub:`10high` - - Y'\ :sub:`11low` - - Y'\ :sub:`11high` - - Y'\ :sub:`12low` - - Y'\ :sub:`12high` - - Y'\ :sub:`13low` - - Y'\ :sub:`13high` - * - start + 16: - - Y'\ :sub:`20low` - - Y'\ :sub:`20high` - - Y'\ :sub:`21low` - - Y'\ :sub:`21high` - - Y'\ :sub:`22low` - - Y'\ :sub:`22high` - - Y'\ :sub:`23low` - - Y'\ :sub:`23high` - * - start + 24: - - Y'\ :sub:`30low` - - Y'\ :sub:`30high` - - Y'\ :sub:`31low` - - Y'\ :sub:`31high` - - Y'\ :sub:`32low` - - Y'\ :sub:`32high` - - Y'\ :sub:`33low` - - Y'\ :sub:`33high` diff --git a/Documentation/userspace-api/media/v4l/pixfmt-y10b.rst b/Documentation/userspace-api/media/v4l/pixfmt-y10b.rst deleted file mode 100644 index 38d353b37df9..000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-y10b.rst +++ /dev/null @@ -1,33 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _V4L2-PIX-FMT-Y10BPACK: - -****************************** -V4L2_PIX_FMT_Y10BPACK ('Y10B') -****************************** - -Grey-scale image as a bit-packed array - - -Description -=========== - -This is a packed grey-scale image format with a depth of 10 bits per -pixel. Pixels are stored in a bit-packed array of 10bit bits per pixel, -with no padding between them and with the most significant bits coming -first from the left. - -**Bit-packed representation.** - -pixels cross the byte boundary and have a ratio of 5 bytes for each 4 -pixels. - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - Y'\ :sub:`00[9:2]` - - Y'\ :sub:`00[1:0]`\ Y'\ :sub:`01[9:4]` - - Y'\ :sub:`01[3:0]`\ Y'\ :sub:`02[9:6]` - - Y'\ :sub:`02[5:0]`\ Y'\ :sub:`03[9:8]` - - Y'\ :sub:`03[7:0]` diff --git a/Documentation/userspace-api/media/v4l/pixfmt-y10p.rst b/Documentation/userspace-api/media/v4l/pixfmt-y10p.rst deleted file mode 100644 index dd20d3438732..000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-y10p.rst +++ /dev/null @@ -1,43 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _V4L2-PIX-FMT-Y10P: - -****************************** -V4L2_PIX_FMT_Y10P ('Y10P') -****************************** - -Grey-scale image as a MIPI RAW10 packed array - - -Description -=========== - -This is a packed grey-scale image format with a depth of 10 bits per -pixel. Every four consecutive pixels are packed into 5 bytes. Each of -the first 4 bytes contain the 8 high order bits of the pixels, and -the 5th byte contains the 2 least significants bits of each pixel, -in the same order. - -**Bit-packed representation.** - -.. raw:: latex - - \small - -.. tabularcolumns:: |p{1.2cm}||p{1.2cm}||p{1.2cm}||p{1.2cm}|p{3.2cm}|p{3.2cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 8 8 8 8 64 - - * - Y'\ :sub:`00[9:2]` - - Y'\ :sub:`01[9:2]` - - Y'\ :sub:`02[9:2]` - - Y'\ :sub:`03[9:2]` - - Y'\ :sub:`03[1:0]`\ (bits 7--6) Y'\ :sub:`02[1:0]`\ (bits 5--4) - Y'\ :sub:`01[1:0]`\ (bits 3--2) Y'\ :sub:`00[1:0]`\ (bits 1--0) - -.. raw:: latex - - \normalsize diff --git a/Documentation/userspace-api/media/v4l/pixfmt-y12.rst b/Documentation/userspace-api/media/v4l/pixfmt-y12.rst deleted file mode 100644 index 20e12a18da72..000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-y12.rst +++ /dev/null @@ -1,65 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _V4L2-PIX-FMT-Y12: - -************************* -V4L2_PIX_FMT_Y12 ('Y12 ') -************************* - - -Grey-scale image - - -Description -=========== - -This is a grey-scale image with a depth of 12 bits per pixel. Pixels are -stored in 16-bit words with unused high bits padded with 0. The least -significant byte is stored at lower memory addresses (little-endian). - -**Byte Order.** -Each cell is one byte. - - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - start + 0: - - Y'\ :sub:`00low` - - Y'\ :sub:`00high` - - Y'\ :sub:`01low` - - Y'\ :sub:`01high` - - Y'\ :sub:`02low` - - Y'\ :sub:`02high` - - Y'\ :sub:`03low` - - Y'\ :sub:`03high` - * - start + 8: - - Y'\ :sub:`10low` - - Y'\ :sub:`10high` - - Y'\ :sub:`11low` - - Y'\ :sub:`11high` - - Y'\ :sub:`12low` - - Y'\ :sub:`12high` - - Y'\ :sub:`13low` - - Y'\ :sub:`13high` - * - start + 16: - - Y'\ :sub:`20low` - - Y'\ :sub:`20high` - - Y'\ :sub:`21low` - - Y'\ :sub:`21high` - - Y'\ :sub:`22low` - - Y'\ :sub:`22high` - - Y'\ :sub:`23low` - - Y'\ :sub:`23high` - * - start + 24: - - Y'\ :sub:`30low` - - Y'\ :sub:`30high` - - Y'\ :sub:`31low` - - Y'\ :sub:`31high` - - Y'\ :sub:`32low` - - Y'\ :sub:`32high` - - Y'\ :sub:`33low` - - Y'\ :sub:`33high` diff --git a/Documentation/userspace-api/media/v4l/pixfmt-y14.rst b/Documentation/userspace-api/media/v4l/pixfmt-y14.rst deleted file mode 100644 index 2a4826b77105..000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-y14.rst +++ /dev/null @@ -1,65 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _V4L2-PIX-FMT-Y14: - -************************* -V4L2_PIX_FMT_Y14 ('Y14 ') -************************* - - -Grey-scale image - - -Description -=========== - -This is a grey-scale image with a depth of 14 bits per pixel. Pixels are -stored in 16-bit words with unused high bits padded with 0. The least -significant byte is stored at lower memory addresses (little-endian). - -**Byte Order.** -Each cell is one byte. - - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - start + 0: - - Y'\ :sub:`00low` - - Y'\ :sub:`00high` - - Y'\ :sub:`01low` - - Y'\ :sub:`01high` - - Y'\ :sub:`02low` - - Y'\ :sub:`02high` - - Y'\ :sub:`03low` - - Y'\ :sub:`03high` - * - start + 8: - - Y'\ :sub:`10low` - - Y'\ :sub:`10high` - - Y'\ :sub:`11low` - - Y'\ :sub:`11high` - - Y'\ :sub:`12low` - - Y'\ :sub:`12high` - - Y'\ :sub:`13low` - - Y'\ :sub:`13high` - * - start + 16: - - Y'\ :sub:`20low` - - Y'\ :sub:`20high` - - Y'\ :sub:`21low` - - Y'\ :sub:`21high` - - Y'\ :sub:`22low` - - Y'\ :sub:`22high` - - Y'\ :sub:`23low` - - Y'\ :sub:`23high` - * - start + 24: - - Y'\ :sub:`30low` - - Y'\ :sub:`30high` - - Y'\ :sub:`31low` - - Y'\ :sub:`31high` - - Y'\ :sub:`32low` - - Y'\ :sub:`32high` - - Y'\ :sub:`33low` - - Y'\ :sub:`33high` diff --git a/Documentation/userspace-api/media/v4l/pixfmt-y16-be.rst b/Documentation/userspace-api/media/v4l/pixfmt-y16-be.rst deleted file mode 100644 index 6d70cd78cbf6..000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-y16-be.rst +++ /dev/null @@ -1,69 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _V4L2-PIX-FMT-Y16-BE: - -**************************************** -V4L2_PIX_FMT_Y16_BE ('Y16 ' | (1 << 31)) -**************************************** - - -Grey-scale image - - -Description -=========== - -This is a grey-scale image with a depth of 16 bits per pixel. The most -significant byte is stored at lower memory addresses (big-endian). - -.. note:: - - The actual sampling precision may be lower than 16 bits, for - example 10 bits per pixel with values in range 0 to 1023. - -**Byte Order.** -Each cell is one byte. - - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - start + 0: - - Y'\ :sub:`00high` - - Y'\ :sub:`00low` - - Y'\ :sub:`01high` - - Y'\ :sub:`01low` - - Y'\ :sub:`02high` - - Y'\ :sub:`02low` - - Y'\ :sub:`03high` - - Y'\ :sub:`03low` - * - start + 8: - - Y'\ :sub:`10high` - - Y'\ :sub:`10low` - - Y'\ :sub:`11high` - - Y'\ :sub:`11low` - - Y'\ :sub:`12high` - - Y'\ :sub:`12low` - - Y'\ :sub:`13high` - - Y'\ :sub:`13low` - * - start + 16: - - Y'\ :sub:`20high` - - Y'\ :sub:`20low` - - Y'\ :sub:`21high` - - Y'\ :sub:`21low` - - Y'\ :sub:`22high` - - Y'\ :sub:`22low` - - Y'\ :sub:`23high` - - Y'\ :sub:`23low` - * - start + 24: - - Y'\ :sub:`30high` - - Y'\ :sub:`30low` - - Y'\ :sub:`31high` - - Y'\ :sub:`31low` - - Y'\ :sub:`32high` - - Y'\ :sub:`32low` - - Y'\ :sub:`33high` - - Y'\ :sub:`33low` diff --git a/Documentation/userspace-api/media/v4l/pixfmt-y16.rst b/Documentation/userspace-api/media/v4l/pixfmt-y16.rst deleted file mode 100644 index 398ad8ba5d64..000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-y16.rst +++ /dev/null @@ -1,69 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _V4L2-PIX-FMT-Y16: - -************************* -V4L2_PIX_FMT_Y16 ('Y16 ') -************************* - - -Grey-scale image - - -Description -=========== - -This is a grey-scale image with a depth of 16 bits per pixel. The least -significant byte is stored at lower memory addresses (little-endian). - -.. note:: - - The actual sampling precision may be lower than 16 bits, for - example 10 bits per pixel with values in range 0 to 1023. - -**Byte Order.** -Each cell is one byte. - - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - start + 0: - - Y'\ :sub:`00low` - - Y'\ :sub:`00high` - - Y'\ :sub:`01low` - - Y'\ :sub:`01high` - - Y'\ :sub:`02low` - - Y'\ :sub:`02high` - - Y'\ :sub:`03low` - - Y'\ :sub:`03high` - * - start + 8: - - Y'\ :sub:`10low` - - Y'\ :sub:`10high` - - Y'\ :sub:`11low` - - Y'\ :sub:`11high` - - Y'\ :sub:`12low` - - Y'\ :sub:`12high` - - Y'\ :sub:`13low` - - Y'\ :sub:`13high` - * - start + 16: - - Y'\ :sub:`20low` - - Y'\ :sub:`20high` - - Y'\ :sub:`21low` - - Y'\ :sub:`21high` - - Y'\ :sub:`22low` - - Y'\ :sub:`22high` - - Y'\ :sub:`23low` - - Y'\ :sub:`23high` - * - start + 24: - - Y'\ :sub:`30low` - - Y'\ :sub:`30high` - - Y'\ :sub:`31low` - - Y'\ :sub:`31high` - - Y'\ :sub:`32low` - - Y'\ :sub:`32high` - - Y'\ :sub:`33low` - - Y'\ :sub:`33high` diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv-luma.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv-luma.rst new file mode 100644 index 000000000000..0c8c5e0a380e --- /dev/null +++ b/Documentation/userspace-api/media/v4l/pixfmt-yuv-luma.rst @@ -0,0 +1,126 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later + +.. _yuv-luma-only: + +***************** +Luma-Only Formats +***************** + +This family of formats only store the luma component of a Y'CbCr image. They +are often referred to as greyscale formats. + +.. note:: + + - In all the tables that follow, bit 7 is the most significant bit in a byte. + - Formats are described with the minimum number of pixels needed to create a + byte-aligned repeating pattern. `...` indicates repetition of the pattern. + - Y'\ :sub:`x`\ [9:2] denotes bits 9 to 2 of the Y' value for pixel at colum + `x`. + - `0` denotes padding bits set to 0. + + +.. flat-table:: Luma-Only Image Formats + :header-rows: 1 + :stub-columns: 0 + + * - Identifier + - Code + - Byte 0 + - Byte 1 + - Byte 2 + - Byte 3 + - Byte 4 + + * .. _V4L2-PIX-FMT-GREY: + + - ``V4L2_PIX_FMT_GREY`` + - 'GREY' + + - Y'\ :sub:`0`\ [7:0] + - ... + - ... + - ... + - ... + + * .. _V4L2-PIX-FMT-Y10: + + - ``V4L2_PIX_FMT_Y10`` + - 'Y10 ' + + - Y'\ :sub:`0`\ [7:0] + - `000000` Y'\ :sub:`0`\ [9:8] + - ... + - ... + - ... + + * .. _V4L2-PIX-FMT-Y10BPACK: + + - ``V4L2_PIX_FMT_Y10BPACK`` + - 'Y10B' + + - Y'\ :sub:`0`\ [9:2] + - Y'\ :sub:`0`\ [1:0] Y'\ :sub:`1`\ [9:4] + - Y'\ :sub:`1`\ [3:0] Y'\ :sub:`2`\ [9:6] + - Y'\ :sub:`2`\ [5:0] Y'\ :sub:`3`\ [9:8] + - Y'\ :sub:`3`\ [7:0] + + * .. _V4L2-PIX-FMT-Y10P: + + - ``V4L2_PIX_FMT_Y10P`` + - 'Y10P' + + - Y'\ :sub:`0`\ [7:0] + - Y'\ :sub:`1`\ [9:8] + - Y'\ :sub:`2`\ [9:2] + - Y'\ :sub:`3`\ [9:2] + - Y'\ :sub:`3`\ [1:0] Y'\ :sub:`2`\ [1:0] Y'\ :sub:`1`\ [1:0] Y'\ :sub:`0`\ [1:0] + + * .. _V4L2-PIX-FMT-Y12: + + - ``V4L2_PIX_FMT_Y12`` + - 'Y12 ' + + - Y'\ :sub:`0`\ [7:0] + - `0000` Y'\ :sub:`0`\ [11:8] + - ... + - ... + - ... + + * .. _V4L2-PIX-FMT-Y14: + + - ``V4L2_PIX_FMT_Y14`` + - 'Y14 ' + + - Y'\ :sub:`0`\ [7:0] + - `00` Y'\ :sub:`0`\ [13:8] + - ... + - ... + - ... + + * .. _V4L2-PIX-FMT-Y16: + + - ``V4L2_PIX_FMT_Y16`` + - 'Y16 ' + + - Y'\ :sub:`0`\ [7:0] + - Y'\ :sub:`0`\ [15:8] + - ... + - ... + - ... + + * .. _V4L2-PIX-FMT-Y16-BE: + + - ``V4L2_PIX_FMT_Y16_BE`` + - 'Y16 ' | (1U << 31) + + - Y'\ :sub:`0`\ [15:8] + - Y'\ :sub:`0`\ [7:0] + - ... + - ... + - ... + +.. note:: + + For the Y16 and Y16_BE formats, the actual sampling precision may be lower + than 16 bits. For example, 10 bits per pixel uses values in the range 0 to + 1023. diff --git a/Documentation/userspace-api/media/v4l/yuv-formats.rst b/Documentation/userspace-api/media/v4l/yuv-formats.rst index a5b17040679e..7179d715f8a7 100644 --- a/Documentation/userspace-api/media/v4l/yuv-formats.rst +++ b/Documentation/userspace-api/media/v4l/yuv-formats.rst @@ -265,14 +265,7 @@ image. :maxdepth: 1 pixfmt-packed-yuv - pixfmt-grey - pixfmt-y10 - pixfmt-y12 - pixfmt-y14 - pixfmt-y10b - pixfmt-y10p - pixfmt-y16 - pixfmt-y16-be + pixfmt-yuv-luma pixfmt-y8i pixfmt-y12i pixfmt-uv8 -- cgit v1.2.3 From da785536e0072b196e721ae64d96fdcc8ef318fc Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 7 Dec 2020 00:03:15 +0100 Subject: media: doc: pixfmt-yuv: Move all semi-planar YUV formats to common file Semi-planar pixel formats are documented in separate files. This duplicates information, as those formats share comon traits. Consolidate them in a single file and summarize their descriptions in a single table. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/pixfmt-nv12.rst | 76 ---- .../userspace-api/media/v4l/pixfmt-nv12m.rst | 88 ---- .../userspace-api/media/v4l/pixfmt-nv12mt.rst | 60 --- .../userspace-api/media/v4l/pixfmt-nv16.rst | 84 ---- .../userspace-api/media/v4l/pixfmt-nv16m.rst | 88 ---- .../userspace-api/media/v4l/pixfmt-nv24.rst | 95 ----- .../userspace-api/media/v4l/pixfmt-yuv-planar.rst | 463 +++++++++++++++++++++ .../userspace-api/media/v4l/yuv-formats.rst | 7 +- 8 files changed, 464 insertions(+), 497 deletions(-) delete mode 100644 Documentation/userspace-api/media/v4l/pixfmt-nv12.rst delete mode 100644 Documentation/userspace-api/media/v4l/pixfmt-nv12m.rst delete mode 100644 Documentation/userspace-api/media/v4l/pixfmt-nv12mt.rst delete mode 100644 Documentation/userspace-api/media/v4l/pixfmt-nv16.rst delete mode 100644 Documentation/userspace-api/media/v4l/pixfmt-nv16m.rst delete mode 100644 Documentation/userspace-api/media/v4l/pixfmt-nv24.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst diff --git a/Documentation/userspace-api/media/v4l/pixfmt-nv12.rst b/Documentation/userspace-api/media/v4l/pixfmt-nv12.rst deleted file mode 100644 index 692117bf83ad..000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-nv12.rst +++ /dev/null @@ -1,76 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _V4L2-PIX-FMT-NV12: -.. _V4L2-PIX-FMT-NV21: - -****************************************************** -V4L2_PIX_FMT_NV12 ('NV12'), V4L2_PIX_FMT_NV21 ('NV21') -****************************************************** - - -V4L2_PIX_FMT_NV21 -Formats with ½ horizontal and vertical chroma resolution, also known as -YUV 4:2:0. One luminance and one chrominance plane with alternating -chroma samples as opposed to ``V4L2_PIX_FMT_YVU420`` - - -Description -=========== - -These are two-plane versions of the YUV 4:2:0 format. The three -components are separated into two sub-images or planes. The Y plane is -first. The Y plane has one byte per pixel. For ``V4L2_PIX_FMT_NV12``, a -combined CbCr plane immediately follows the Y plane in memory. The CbCr -plane is the same width, in bytes, as the Y plane (and of the image), -but is half as tall in pixels. Each CbCr pair belongs to four pixels. -For example, Cb\ :sub:`0`/Cr\ :sub:`0` belongs to Y'\ :sub:`00`, -Y'\ :sub:`01`, Y'\ :sub:`10`, Y'\ :sub:`11`. ``V4L2_PIX_FMT_NV21`` is -the same except the Cb and Cr bytes are swapped, the CrCb plane starts -with a Cr byte. - -If the Y plane has pad bytes after each row, then the CbCr plane has as -many pad bytes after its rows. - -**Byte Order.** -Each cell is one byte. - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - start + 0: - - Y'\ :sub:`00` - - Y'\ :sub:`01` - - Y'\ :sub:`02` - - Y'\ :sub:`03` - * - start + 4: - - Y'\ :sub:`10` - - Y'\ :sub:`11` - - Y'\ :sub:`12` - - Y'\ :sub:`13` - * - start + 8: - - Y'\ :sub:`20` - - Y'\ :sub:`21` - - Y'\ :sub:`22` - - Y'\ :sub:`23` - * - start + 12: - - Y'\ :sub:`30` - - Y'\ :sub:`31` - - Y'\ :sub:`32` - - Y'\ :sub:`33` - * - start + 16: - - Cb\ :sub:`00` - - Cr\ :sub:`00` - - Cb\ :sub:`01` - - Cr\ :sub:`01` - * - start + 20: - - Cb\ :sub:`10` - - Cr\ :sub:`10` - - Cb\ :sub:`11` - - Cr\ :sub:`11` - - -**Color Sample Location:** -Chroma samples are :ref:`interstitially sited` -horizontally and vertically. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-nv12m.rst b/Documentation/userspace-api/media/v4l/pixfmt-nv12m.rst deleted file mode 100644 index 002b361d5a9b..000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-nv12m.rst +++ /dev/null @@ -1,88 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _V4L2-PIX-FMT-NV12M: -.. _v4l2-pix-fmt-nv12mt-16x16: -.. _V4L2-PIX-FMT-NV21M: - -*********************************************************************************** -V4L2_PIX_FMT_NV12M ('NM12'), V4L2_PIX_FMT_NV21M ('NM21'), V4L2_PIX_FMT_NV12MT_16X16 -*********************************************************************************** - - -V4L2_PIX_FMT_NV21M -V4L2_PIX_FMT_NV12MT_16X16 -Variation of ``V4L2_PIX_FMT_NV12`` and ``V4L2_PIX_FMT_NV21`` with planes -non contiguous in memory. - - -Description -=========== - -This is a multi-planar, two-plane version of the YUV 4:2:0 format. The -three components are separated into two sub-images or planes. -``V4L2_PIX_FMT_NV12M`` differs from ``V4L2_PIX_FMT_NV12`` in that the -two planes are non-contiguous in memory, i.e. the chroma plane do not -necessarily immediately follows the luma plane. The luminance data -occupies the first plane. The Y plane has one byte per pixel. In the -second plane there is a chrominance data with alternating chroma -samples. The CbCr plane is the same width, in bytes, as the Y plane (and -of the image), but is half as tall in pixels. Each CbCr pair belongs to -four pixels. For example, Cb\ :sub:`0`/Cr\ :sub:`0` belongs to -Y'\ :sub:`00`, Y'\ :sub:`01`, Y'\ :sub:`10`, Y'\ :sub:`11`. -``V4L2_PIX_FMT_NV12MT_16X16`` is the tiled version of -``V4L2_PIX_FMT_NV12M`` with 16x16 macroblock tiles. Here pixels are -arranged in 16x16 2D tiles and tiles are arranged in linear order in -memory. ``V4L2_PIX_FMT_NV21M`` is the same as ``V4L2_PIX_FMT_NV12M`` -except the Cb and Cr bytes are swapped, the CrCb plane starts with a Cr -byte. - -``V4L2_PIX_FMT_NV12M`` is intended to be used only in drivers and -applications that support the multi-planar API, described in -:ref:`planar-apis`. - -If the Y plane has pad bytes after each row, then the CbCr plane has as -many pad bytes after its rows. - -**Byte Order.** -Each cell is one byte. - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - start0 + 0: - - Y'\ :sub:`00` - - Y'\ :sub:`01` - - Y'\ :sub:`02` - - Y'\ :sub:`03` - * - start0 + 4: - - Y'\ :sub:`10` - - Y'\ :sub:`11` - - Y'\ :sub:`12` - - Y'\ :sub:`13` - * - start0 + 8: - - Y'\ :sub:`20` - - Y'\ :sub:`21` - - Y'\ :sub:`22` - - Y'\ :sub:`23` - * - start0 + 12: - - Y'\ :sub:`30` - - Y'\ :sub:`31` - - Y'\ :sub:`32` - - Y'\ :sub:`33` - * - - * - start1 + 0: - - Cb\ :sub:`00` - - Cr\ :sub:`00` - - Cb\ :sub:`01` - - Cr\ :sub:`01` - * - start1 + 4: - - Cb\ :sub:`10` - - Cr\ :sub:`10` - - Cb\ :sub:`11` - - Cr\ :sub:`11` - - -**Color Sample Location:** -Chroma samples are :ref:`interstitially sited` -horizontally and vertically. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-nv12mt.rst b/Documentation/userspace-api/media/v4l/pixfmt-nv12mt.rst deleted file mode 100644 index 46f63d793ec5..000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-nv12mt.rst +++ /dev/null @@ -1,60 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _V4L2-PIX-FMT-NV12MT: - -**************************** -V4L2_PIX_FMT_NV12MT ('TM12') -**************************** - -Formats with ½ horizontal and vertical chroma resolution. This format -has two planes - one for luminance and one for chrominance. Chroma -samples are interleaved. The difference to ``V4L2_PIX_FMT_NV12`` is the -memory layout. Pixels are grouped in macroblocks of 64x32 size. The -order of macroblocks in memory is also not standard. - - -Description -=========== - -This is the two-plane versions of the YUV 4:2:0 format where data is -grouped into 64x32 macroblocks. The three components are separated into -two sub-images or planes. The Y plane has one byte per pixel and pixels -are grouped into 64x32 macroblocks. The CbCr plane has the same width, -in bytes, as the Y plane (and the image), but is half as tall in pixels. -The chroma plane is also grouped into 64x32 macroblocks. - -Width of the buffer has to be aligned to the multiple of 128, and height -alignment is 32. Every four adjacent buffers - two horizontally and two -vertically are grouped together and are located in memory in Z or -flipped Z order. - -Layout of macroblocks in memory is presented in the following figure. - - -.. _nv12mt: - -.. kernel-figure:: nv12mt.svg - :alt: nv12mt.svg - :align: center - - V4L2_PIX_FMT_NV12MT macroblock Z shape memory layout - -The requirement that width is multiple of 128 is implemented because, -the Z shape cannot be cut in half horizontally. In case the vertical -resolution of macroblocks is odd then the last row of macroblocks is -arranged in a linear order. - -In case of chroma the layout is identical. Cb and Cr samples are -interleaved. Height of the buffer is aligned to 32. - - -.. _nv12mt_ex: - -.. kernel-figure:: nv12mt_example.svg - :alt: nv12mt_example.svg - :align: center - - Example V4L2_PIX_FMT_NV12MT memory layout of macroblocks - -Memory layout of macroblocks of ``V4L2_PIX_FMT_NV12MT`` format in most -extreme case. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-nv16.rst b/Documentation/userspace-api/media/v4l/pixfmt-nv16.rst deleted file mode 100644 index e6307843d848..000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-nv16.rst +++ /dev/null @@ -1,84 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _V4L2-PIX-FMT-NV16: -.. _V4L2-PIX-FMT-NV61: - -****************************************************** -V4L2_PIX_FMT_NV16 ('NV16'), V4L2_PIX_FMT_NV61 ('NV61') -****************************************************** - -V4L2_PIX_FMT_NV61 -Formats with ½ horizontal chroma resolution, also known as YUV 4:2:2. -One luminance and one chrominance plane with alternating chroma samples -as opposed to ``V4L2_PIX_FMT_YVU420`` - - -Description -=========== - -These are two-plane versions of the YUV 4:2:2 format. The three -components are separated into two sub-images or planes. The Y plane is -first. The Y plane has one byte per pixel. For ``V4L2_PIX_FMT_NV16``, a -combined CbCr plane immediately follows the Y plane in memory. The CbCr -plane is the same width and height, in bytes, as the Y plane (and of the -image). Each CbCr pair belongs to two pixels. For example, -Cb\ :sub:`0`/Cr\ :sub:`0` belongs to Y'\ :sub:`00`, Y'\ :sub:`01`. -``V4L2_PIX_FMT_NV61`` is the same except the Cb and Cr bytes are -swapped, the CrCb plane starts with a Cr byte. - -If the Y plane has pad bytes after each row, then the CbCr plane has as -many pad bytes after its rows. - -**Byte Order.** -Each cell is one byte. - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - start + 0: - - Y'\ :sub:`00` - - Y'\ :sub:`01` - - Y'\ :sub:`02` - - Y'\ :sub:`03` - * - start + 4: - - Y'\ :sub:`10` - - Y'\ :sub:`11` - - Y'\ :sub:`12` - - Y'\ :sub:`13` - * - start + 8: - - Y'\ :sub:`20` - - Y'\ :sub:`21` - - Y'\ :sub:`22` - - Y'\ :sub:`23` - * - start + 12: - - Y'\ :sub:`30` - - Y'\ :sub:`31` - - Y'\ :sub:`32` - - Y'\ :sub:`33` - * - start + 16: - - Cb\ :sub:`00` - - Cr\ :sub:`00` - - Cb\ :sub:`01` - - Cr\ :sub:`01` - * - start + 20: - - Cb\ :sub:`10` - - Cr\ :sub:`10` - - Cb\ :sub:`11` - - Cr\ :sub:`11` - * - start + 24: - - Cb\ :sub:`20` - - Cr\ :sub:`20` - - Cb\ :sub:`21` - - Cr\ :sub:`21` - * - start + 28: - - Cb\ :sub:`30` - - Cr\ :sub:`30` - - Cb\ :sub:`31` - - Cr\ :sub:`31` - - -**Color Sample Location:** -Chroma samples are :ref:`interstitially sited` -horizontally. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-nv16m.rst b/Documentation/userspace-api/media/v4l/pixfmt-nv16m.rst deleted file mode 100644 index 58e97205d41f..000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-nv16m.rst +++ /dev/null @@ -1,88 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _V4L2-PIX-FMT-NV16M: -.. _v4l2-pix-fmt-nv61m: - -******************************************************** -V4L2_PIX_FMT_NV16M ('NM16'), V4L2_PIX_FMT_NV61M ('NM61') -******************************************************** - -V4L2_PIX_FMT_NV61M -Variation of ``V4L2_PIX_FMT_NV16`` and ``V4L2_PIX_FMT_NV61`` with planes -non contiguous in memory. - - -Description -=========== - -This is a multi-planar, two-plane version of the YUV 4:2:2 format. The -three components are separated into two sub-images or planes. -``V4L2_PIX_FMT_NV16M`` differs from ``V4L2_PIX_FMT_NV16`` in that the -two planes are non-contiguous in memory, i.e. the chroma plane does not -necessarily immediately follow the luma plane. The luminance data -occupies the first plane. The Y plane has one byte per pixel. In the -second plane there is chrominance data with alternating chroma samples. -The CbCr plane is the same width and height, in bytes, as the Y plane. -Each CbCr pair belongs to two pixels. For example, -Cb\ :sub:`0`/Cr\ :sub:`0` belongs to Y'\ :sub:`00`, Y'\ :sub:`01`. -``V4L2_PIX_FMT_NV61M`` is the same as ``V4L2_PIX_FMT_NV16M`` except the -Cb and Cr bytes are swapped, the CrCb plane starts with a Cr byte. - -``V4L2_PIX_FMT_NV16M`` and ``V4L2_PIX_FMT_NV61M`` are intended to be -used only in drivers and applications that support the multi-planar API, -described in :ref:`planar-apis`. - -**Byte Order.** -Each cell is one byte. - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - start0 + 0: - - Y'\ :sub:`00` - - Y'\ :sub:`01` - - Y'\ :sub:`02` - - Y'\ :sub:`03` - * - start0 + 4: - - Y'\ :sub:`10` - - Y'\ :sub:`11` - - Y'\ :sub:`12` - - Y'\ :sub:`13` - * - start0 + 8: - - Y'\ :sub:`20` - - Y'\ :sub:`21` - - Y'\ :sub:`22` - - Y'\ :sub:`23` - * - start0 + 12: - - Y'\ :sub:`30` - - Y'\ :sub:`31` - - Y'\ :sub:`32` - - Y'\ :sub:`33` - * - - * - start1 + 0: - - Cb\ :sub:`00` - - Cr\ :sub:`00` - - Cb\ :sub:`02` - - Cr\ :sub:`02` - * - start1 + 4: - - Cb\ :sub:`10` - - Cr\ :sub:`10` - - Cb\ :sub:`12` - - Cr\ :sub:`12` - * - start1 + 8: - - Cb\ :sub:`20` - - Cr\ :sub:`20` - - Cb\ :sub:`22` - - Cr\ :sub:`22` - * - start1 + 12: - - Cb\ :sub:`30` - - Cr\ :sub:`30` - - Cb\ :sub:`32` - - Cr\ :sub:`32` - - -**Color Sample Location:** -Chroma samples are :ref:`interstitially sited` -horizontally. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-nv24.rst b/Documentation/userspace-api/media/v4l/pixfmt-nv24.rst deleted file mode 100644 index bf1b94062fc2..000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-nv24.rst +++ /dev/null @@ -1,95 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _V4L2-PIX-FMT-NV24: -.. _V4L2-PIX-FMT-NV42: - -****************************************************** -V4L2_PIX_FMT_NV24 ('NV24'), V4L2_PIX_FMT_NV42 ('NV42') -****************************************************** - -V4L2_PIX_FMT_NV42 -Formats with full horizontal and vertical chroma resolutions, also known -as YUV 4:4:4. One luminance and one chrominance plane with alternating -chroma samples as opposed to ``V4L2_PIX_FMT_YVU420`` - - -Description -=========== - -These are two-plane versions of the YUV 4:4:4 format. The three -components are separated into two sub-images or planes. The Y plane is -first, with each Y sample stored in one byte per pixel. For -``V4L2_PIX_FMT_NV24``, a combined CbCr plane immediately follows the Y -plane in memory. The CbCr plane has the same width and height, in -pixels, as the Y plane (and the image). Each line contains one CbCr pair -per pixel, with each Cb and Cr sample stored in one byte. -``V4L2_PIX_FMT_NV42`` is the same except that the Cb and Cr samples are -swapped, the CrCb plane starts with a Cr sample. - -If the Y plane has pad bytes after each row, then the CbCr plane has -twice as many pad bytes after its rows. - -**Byte Order.** -Each cell is one byte. - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - start + 0: - - Y'\ :sub:`00` - - Y'\ :sub:`01` - - Y'\ :sub:`02` - - Y'\ :sub:`03` - * - start + 4: - - Y'\ :sub:`10` - - Y'\ :sub:`11` - - Y'\ :sub:`12` - - Y'\ :sub:`13` - * - start + 8: - - Y'\ :sub:`20` - - Y'\ :sub:`21` - - Y'\ :sub:`22` - - Y'\ :sub:`23` - * - start + 12: - - Y'\ :sub:`30` - - Y'\ :sub:`31` - - Y'\ :sub:`32` - - Y'\ :sub:`33` - * - start + 16: - - Cb\ :sub:`00` - - Cr\ :sub:`00` - - Cb\ :sub:`01` - - Cr\ :sub:`01` - - Cb\ :sub:`02` - - Cr\ :sub:`02` - - Cb\ :sub:`03` - - Cr\ :sub:`03` - * - start + 24: - - Cb\ :sub:`10` - - Cr\ :sub:`10` - - Cb\ :sub:`11` - - Cr\ :sub:`11` - - Cb\ :sub:`12` - - Cr\ :sub:`12` - - Cb\ :sub:`13` - - Cr\ :sub:`13` - * - start + 32: - - Cb\ :sub:`20` - - Cr\ :sub:`20` - - Cb\ :sub:`21` - - Cr\ :sub:`21` - - Cb\ :sub:`22` - - Cr\ :sub:`22` - - Cb\ :sub:`23` - - Cr\ :sub:`23` - * - start + 40: - - Cb\ :sub:`30` - - Cr\ :sub:`30` - - Cb\ :sub:`31` - - Cr\ :sub:`31` - - Cb\ :sub:`32` - - Cr\ :sub:`32` - - Cb\ :sub:`33` - - Cr\ :sub:`33` diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst new file mode 100644 index 000000000000..0ca01270bde5 --- /dev/null +++ b/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst @@ -0,0 +1,463 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later + +.. planar-yuv: + +****************** +Planar YUV formats +****************** + +Planar formats split luma and chroma data in separate memory regions. They +exist in two variants: + +- Semi-planar formats use two planes. The first plane is the luma plane and + stores the Y components. The second plane is the chroma plane and stores the + Cb and Cr components interleaved. + +- Fully planar formats use three planes to store the Y, Cb and Cr components + separately. + +Within a plane, components are stored in pixel order, which may be linear or +tiled. Padding may be supported at the end of the lines, and the line stride of +the chroma planes may be constrained by the line stride of the luma plane. + +Some planar formats allow planes to be placed in independent memory locations. +They are identified by an 'M' suffix in their name (such as in +``V4L2_PIX_FMT_NV12M``). Those formats are intended to be used only in drivers +and applications that support the multi-planar API, described in +:ref:`planar-apis`. Unless explicitly documented as supporting non-contiguous +planes, formats require the planes to follow each other immediately in memory. + + +Semi-Planar YUV Formats +======================= + +These formats are commonly referred to as NV formats (NV12, NV16, ...). They +use two planes, and store the luma components in the first plane and the chroma +components in the second plane. The Cb and Cr components are interleaved in the +chroma plane, with Cb and Cr always stored in pairs. The chroma order is +exposed as different formats. + +For memory contiguous formats, the number of padding pixels at the end of the +chroma lines is identical to the padding of the luma lines. Without horizontal +subsampling, the chroma line stride (in bytes) is thus equal to twice the luma +line stride. With horizontal subsampling by 2, the chroma line stride is equal +to the luma line stride. Vertical subsampling doesn't affect the line stride. + +For non-contiguous formats, no constraints are enforced by the format on the +relationship between the luma and chroma line padding and stride. + +All components are stored with the same number of bits per component. + +.. flat-table:: Overview of Semi-Planar YUV Formats + :header-rows: 1 + :stub-columns: 0 + + * - Identifier + - Code + - Bits per component + - Subsampling + - Chroma order [1]_ + - Contiguous [2]_ + - Tiling [3]_ + * - V4L2_PIX_FMT_NV12 + - 'NV12' + - 8 + - 4:2:0 + - Cb, Cr + - Yes + - Linear + * - V4L2_PIX_FMT_NV21 + - 'NV21' + - 8 + - 4:2:0 + - Cr, Cr + - Yes + - Linear + * - V4L2_PIX_FMT_NV12M + - 'NM12' + - 8 + - 4:2:0 + - Cb, Cr + - No + - Linear + * - V4L2_PIX_FMT_NV21M + - 'NM21' + - 8 + - 4:2:0 + - Cr, Cr + - No + - Linear + * - V4L2_PIX_FMT_NV12MT + - 'TM12' + - 8 + - 4:2:0 + - Cb, Cr + - No + - 64x32 macroblocks + + Horizontal Z order + * - V4L2_PIX_FMT_NV12MT_16X16 + - 'VM12' + - 8 + - 4:2:2 + - Cb, Cr + - No + - 16x16 macroblocks + * - V4L2_PIX_FMT_NV16 + - 'NV16' + - 8 + - 4:2:2 + - Cb, Cr + - Yes + - Linear + * - V4L2_PIX_FMT_NV61 + - 'NV61' + - 8 + - 4:2:2 + - Cr, Cr + - Yes + - Linear + * - V4L2_PIX_FMT_NV16M + - 'NM16' + - 8 + - 4:2:2 + - Cb, Cr + - No + - Linear + * - V4L2_PIX_FMT_NV61M + - 'NM61' + - 8 + - 4:2:2 + - Cr, Cr + - No + - Linear + * - V4L2_PIX_FMT_NV24 + - 'NV24' + - 8 + - 4:4:4 + - Cb, Cr + - Yes + - Linear + * - V4L2_PIX_FMT_NV42 + - 'NV42' + - 8 + - 4:4:4 + - Cr, Cr + - Yes + - Linear + +.. note:: + + .. [1] Order of chroma samples in the second plane + .. [2] Indicates if planes have to be contiguous in memory or can be + disjoint + .. [3] Macroblock size in pixels + + +**Color Sample Location:** +Chroma samples are :ref:`interstitially sited` +horizontally. + + +.. _V4L2-PIX-FMT-NV12: +.. _V4L2-PIX-FMT-NV21: +.. _V4L2-PIX-FMT-NV12M: +.. _V4L2-PIX-FMT-NV21M: + +NV12, NV21, NV12M and NV21M +--------------------------- + +Semi-planar YUV 4:2:0 formats. The chroma plane is subsampled by 2 in each +direction. Chroma lines contain half the number of pixels and the same number +of bytes as luma lines, and the chroma plane contains half the number of lines +of the luma plane. + +.. flat-table:: Sample 4x4 NV12 Image + :header-rows: 0 + :stub-columns: 0 + + * - start + 0: + - Y'\ :sub:`00` + - Y'\ :sub:`01` + - Y'\ :sub:`02` + - Y'\ :sub:`03` + * - start + 4: + - Y'\ :sub:`10` + - Y'\ :sub:`11` + - Y'\ :sub:`12` + - Y'\ :sub:`13` + * - start + 8: + - Y'\ :sub:`20` + - Y'\ :sub:`21` + - Y'\ :sub:`22` + - Y'\ :sub:`23` + * - start + 12: + - Y'\ :sub:`30` + - Y'\ :sub:`31` + - Y'\ :sub:`32` + - Y'\ :sub:`33` + * - start + 16: + - Cb\ :sub:`00` + - Cr\ :sub:`00` + - Cb\ :sub:`01` + - Cr\ :sub:`01` + * - start + 20: + - Cb\ :sub:`10` + - Cr\ :sub:`10` + - Cb\ :sub:`11` + - Cr\ :sub:`11` + +.. flat-table:: Sample 4x4 NV12M Image + :header-rows: 0 + :stub-columns: 0 + + * - start0 + 0: + - Y'\ :sub:`00` + - Y'\ :sub:`01` + - Y'\ :sub:`02` + - Y'\ :sub:`03` + * - start0 + 4: + - Y'\ :sub:`10` + - Y'\ :sub:`11` + - Y'\ :sub:`12` + - Y'\ :sub:`13` + * - start0 + 8: + - Y'\ :sub:`20` + - Y'\ :sub:`21` + - Y'\ :sub:`22` + - Y'\ :sub:`23` + * - start0 + 12: + - Y'\ :sub:`30` + - Y'\ :sub:`31` + - Y'\ :sub:`32` + - Y'\ :sub:`33` + * - + * - start1 + 0: + - Cb\ :sub:`00` + - Cr\ :sub:`00` + - Cb\ :sub:`01` + - Cr\ :sub:`01` + * - start1 + 4: + - Cb\ :sub:`10` + - Cr\ :sub:`10` + - Cb\ :sub:`11` + - Cr\ :sub:`11` + + +.. _V4L2-PIX-FMT-NV12MT: +.. _V4L2-PIX-FMT-NV12MT-16X16: + +NV12MT and MV12MT_16X16 +----------------------- + +Semi-planar YUV 4:2:0 formats, using macroblock tiling. The chroma plane is +subsampled by 2 in each direction. Chroma lines contain half the number of +pixels and the same number of bytes as luma lines, and the chroma plane +contains half the number of lines of the luma plane. + +``V4L2_PIX_FMT_NV12MT_16X16`` stores pixel in 2D 16x16 macroblocks, and stores +macroblocks linearly in memory. The line stride and image height must be +aligned to a multiple of 16. The layouts of the luma and chroma planes are +identical. + +``V4L2_PIX_FMT_NV12MT`` stores pixels in 2D 64x32 macroblocks, and stores 2x2 +groups of macroblocks in Z-order in memory, alternating Z and mirrored Z shapes +horizontally. The line stride must be a multiple of 128 pixels to ensure an +integer number of Z shapes. The image height must be a multiple of 32 pixels. +If the vertical resolution is an odd number of macroblocks, the last row of +macroblocks is stored in linear order. The layouts of the luma and chroma +planes are identical. + +.. _nv12mt: + +.. kernel-figure:: nv12mt.svg + :alt: nv12mt.svg + :align: center + + V4L2_PIX_FMT_NV12MT macroblock Z shape memory layout + +.. _nv12mt_ex: + +.. kernel-figure:: nv12mt_example.svg + :alt: nv12mt_example.svg + :align: center + + Example V4L2_PIX_FMT_NV12MT memory layout of macroblocks + + +.. _V4L2-PIX-FMT-NV16: +.. _V4L2-PIX-FMT-NV61: +.. _V4L2-PIX-FMT-NV16M: +.. _V4L2-PIX-FMT-NV61M: + +NV16, NV61, NV16M and NV61M +--------------------------- + +Semi-planar YUV 4:2:2 formats. The chroma plane is subsampled by 2 in the +horizontal direction. Chroma lines contain half the number of pixels and the +same number of bytes as luma lines, and the chroma plane contains the same +number of lines as the luma plane. + +.. flat-table:: Sample 4x4 NV16 Image + :header-rows: 0 + :stub-columns: 0 + + * - start + 0: + - Y'\ :sub:`00` + - Y'\ :sub:`01` + - Y'\ :sub:`02` + - Y'\ :sub:`03` + * - start + 4: + - Y'\ :sub:`10` + - Y'\ :sub:`11` + - Y'\ :sub:`12` + - Y'\ :sub:`13` + * - start + 8: + - Y'\ :sub:`20` + - Y'\ :sub:`21` + - Y'\ :sub:`22` + - Y'\ :sub:`23` + * - start + 12: + - Y'\ :sub:`30` + - Y'\ :sub:`31` + - Y'\ :sub:`32` + - Y'\ :sub:`33` + * - start + 16: + - Cb\ :sub:`00` + - Cr\ :sub:`00` + - Cb\ :sub:`01` + - Cr\ :sub:`01` + * - start + 20: + - Cb\ :sub:`10` + - Cr\ :sub:`10` + - Cb\ :sub:`11` + - Cr\ :sub:`11` + * - start + 24: + - Cb\ :sub:`20` + - Cr\ :sub:`20` + - Cb\ :sub:`21` + - Cr\ :sub:`21` + * - start + 28: + - Cb\ :sub:`30` + - Cr\ :sub:`30` + - Cb\ :sub:`31` + - Cr\ :sub:`31` + +.. flat-table:: Sample 4x4 NV16M Image + :header-rows: 0 + :stub-columns: 0 + + * - start0 + 0: + - Y'\ :sub:`00` + - Y'\ :sub:`01` + - Y'\ :sub:`02` + - Y'\ :sub:`03` + * - start0 + 4: + - Y'\ :sub:`10` + - Y'\ :sub:`11` + - Y'\ :sub:`12` + - Y'\ :sub:`13` + * - start0 + 8: + - Y'\ :sub:`20` + - Y'\ :sub:`21` + - Y'\ :sub:`22` + - Y'\ :sub:`23` + * - start0 + 12: + - Y'\ :sub:`30` + - Y'\ :sub:`31` + - Y'\ :sub:`32` + - Y'\ :sub:`33` + * - + * - start1 + 0: + - Cb\ :sub:`00` + - Cr\ :sub:`00` + - Cb\ :sub:`02` + - Cr\ :sub:`02` + * - start1 + 4: + - Cb\ :sub:`10` + - Cr\ :sub:`10` + - Cb\ :sub:`12` + - Cr\ :sub:`12` + * - start1 + 8: + - Cb\ :sub:`20` + - Cr\ :sub:`20` + - Cb\ :sub:`22` + - Cr\ :sub:`22` + * - start1 + 12: + - Cb\ :sub:`30` + - Cr\ :sub:`30` + - Cb\ :sub:`32` + - Cr\ :sub:`32` + + +.. _V4L2-PIX-FMT-NV24: +.. _V4L2-PIX-FMT-NV42: + +NV24 and NV42 +------------- + +Semi-planar YUV 4:4:4 formats. The chroma plane is subsampled by 2 in the +horizontal direction. Chroma lines contain half the number of pixels and the +same number of bytes as luma lines, and the chroma plane contains the same +number of lines as the luma plane. + +.. flat-table:: Sample 4x4 NV24 Image + :header-rows: 0 + :stub-columns: 0 + + * - start + 0: + - Y'\ :sub:`00` + - Y'\ :sub:`01` + - Y'\ :sub:`02` + - Y'\ :sub:`03` + * - start + 4: + - Y'\ :sub:`10` + - Y'\ :sub:`11` + - Y'\ :sub:`12` + - Y'\ :sub:`13` + * - start + 8: + - Y'\ :sub:`20` + - Y'\ :sub:`21` + - Y'\ :sub:`22` + - Y'\ :sub:`23` + * - start + 12: + - Y'\ :sub:`30` + - Y'\ :sub:`31` + - Y'\ :sub:`32` + - Y'\ :sub:`33` + * - start + 16: + - Cb\ :sub:`00` + - Cr\ :sub:`00` + - Cb\ :sub:`01` + - Cr\ :sub:`01` + - Cb\ :sub:`02` + - Cr\ :sub:`02` + - Cb\ :sub:`03` + - Cr\ :sub:`03` + * - start + 24: + - Cb\ :sub:`10` + - Cr\ :sub:`10` + - Cb\ :sub:`11` + - Cr\ :sub:`11` + - Cb\ :sub:`12` + - Cr\ :sub:`12` + - Cb\ :sub:`13` + - Cr\ :sub:`13` + * - start + 32: + - Cb\ :sub:`20` + - Cr\ :sub:`20` + - Cb\ :sub:`21` + - Cr\ :sub:`21` + - Cb\ :sub:`22` + - Cr\ :sub:`22` + - Cb\ :sub:`23` + - Cr\ :sub:`23` + * - start + 40: + - Cb\ :sub:`30` + - Cr\ :sub:`30` + - Cb\ :sub:`31` + - Cr\ :sub:`31` + - Cb\ :sub:`32` + - Cr\ :sub:`32` + - Cb\ :sub:`33` + - Cr\ :sub:`33` diff --git a/Documentation/userspace-api/media/v4l/yuv-formats.rst b/Documentation/userspace-api/media/v4l/yuv-formats.rst index 7179d715f8a7..517499056f3b 100644 --- a/Documentation/userspace-api/media/v4l/yuv-formats.rst +++ b/Documentation/userspace-api/media/v4l/yuv-formats.rst @@ -265,6 +265,7 @@ image. :maxdepth: 1 pixfmt-packed-yuv + pixfmt-yuv-planar pixfmt-yuv-luma pixfmt-y8i pixfmt-y12i @@ -276,10 +277,4 @@ image. pixfmt-yuv410 pixfmt-yuv422p pixfmt-yuv411p - pixfmt-nv12 - pixfmt-nv12m - pixfmt-nv12mt - pixfmt-nv16 - pixfmt-nv16m - pixfmt-nv24 pixfmt-m420 -- cgit v1.2.3 From 2b006e748c81da1b32029257d003f9b2af7435a5 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 7 Dec 2020 00:03:16 +0100 Subject: media: doc: pixfmt-yuv: Move all planar YUV formats to common file Planar pixel formats are documented in separate files. This duplicates information, as those formats share comon traits. Consolidate them in a single file and summarize their descriptions in a single table. Signed-off-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/pixfmt-yuv-planar.rst | 487 +++++++++++++++++++++ .../userspace-api/media/v4l/pixfmt-yuv410.rst | 72 --- .../userspace-api/media/v4l/pixfmt-yuv411p.rst | 80 ---- .../userspace-api/media/v4l/pixfmt-yuv420.rst | 81 ---- .../userspace-api/media/v4l/pixfmt-yuv420m.rst | 90 ---- .../userspace-api/media/v4l/pixfmt-yuv422m.rst | 101 ----- .../userspace-api/media/v4l/pixfmt-yuv422p.rst | 89 ---- .../userspace-api/media/v4l/pixfmt-yuv444m.rst | 110 ----- .../userspace-api/media/v4l/yuv-formats.rst | 7 - 9 files changed, 487 insertions(+), 630 deletions(-) delete mode 100644 Documentation/userspace-api/media/v4l/pixfmt-yuv410.rst delete mode 100644 Documentation/userspace-api/media/v4l/pixfmt-yuv411p.rst delete mode 100644 Documentation/userspace-api/media/v4l/pixfmt-yuv420.rst delete mode 100644 Documentation/userspace-api/media/v4l/pixfmt-yuv420m.rst delete mode 100644 Documentation/userspace-api/media/v4l/pixfmt-yuv422m.rst delete mode 100644 Documentation/userspace-api/media/v4l/pixfmt-yuv422p.rst delete mode 100644 Documentation/userspace-api/media/v4l/pixfmt-yuv444m.rst diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst index 0ca01270bde5..7d4d39201a3f 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst @@ -461,3 +461,490 @@ number of lines as the luma plane. - Cr\ :sub:`32` - Cb\ :sub:`33` - Cr\ :sub:`33` + + +Fully Planar YUV Formats +======================== + +These formats store the Y, Cb and Cr components in three separate planes. The +luma plane comes first, and the order of the two chroma planes varies between +formats. The two chroma planes always use the same subsampling. + +For memory contiguous formats, the number of padding pixels at the end of the +chroma lines is identical to the padding of the luma lines. The chroma line +stride (in bytes) is thus equal to the luma line stride divided by the +horizontal subsampling factor. Vertical subsampling doesn't affect the line +stride. + +For non-contiguous formats, no constraints are enforced by the format on the +relationship between the luma and chroma line padding and stride. + +All components are stored with the same number of bits per component. + +.. flat-table:: Overview of Fully Planar YUV Formats + :header-rows: 1 + :stub-columns: 0 + + * - Identifier + - Code + - Bits per component + - Subsampling + - Planes order [4]_ + - Contiguous [5]_ + + * - V4L2_PIX_FMT_YUV410 + - 'YUV9' + - 8 + - 4:1:0 + - Y, Cb, Cr + - Yes + * - V4L2_PIX_FMT_YVU410 + - 'YVU9' + - 8 + - 4:1:0 + - Y, Cr, Cb + - Yes + * - V4L2_PIX_FMT_YUV411P + - '411P' + - 8 + - 4:1:1 + - Y, Cb, Cr + - Yes + * - V4L2_PIX_FMT_YUV420M + - 'YM12' + - 8 + - 4:2:0 + - Y, Cb, Cr + - No + * - V4L2_PIX_FMT_YVU420M + - 'YM21' + - 8 + - 4:2:0 + - Y, Cr, Cb + - No + * - V4L2_PIX_FMT_YUV420 + - 'YU12' + - 8 + - 4:2:0 + - Y, Cb, Cr + - Yes + * - V4L2_PIX_FMT_YVU420 + - 'YV12' + - 8 + - 4:2:0 + - Y, Cr, Cb + - Yes + * - V4L2_PIX_FMT_YUV422P + - '422P' + - 8 + - 4:2:2 + - Y, Cb, Cr + - Yes + * - V4L2_PIX_FMT_YUV422M + - 'YM16' + - 8 + - 4:2:2 + - Y, Cb, Cr + - No + * - V4L2_PIX_FMT_YVU422M + - 'YM61' + - 8 + - 4:2:2 + - Y, Cr, Cb + - No + * - V4L2_PIX_FMT_YUV444M + - 'YM24' + - 8 + - 4:4:4 + - Y, Cb, Cr + - No + * - V4L2_PIX_FMT_YVU444M + - 'YM42' + - 8 + - 4:4:4 + - Y, Cr, Cb + - No + +.. note:: + + .. [4] Order of luma and chroma planes + .. [5] Indicates if planes have to be contiguous in memory or can be + disjoint + + +**Color Sample Location:** +Chroma samples are :ref:`interstitially sited` +horizontally. + +.. _V4L2-PIX-FMT-YUV410: +.. _V4L2-PIX-FMT-YVU410: + +YUV410 and YVU410 +----------------- + +Planar YUV 4:1:0 formats. The chroma planes are subsampled by 4 in each +direction. Chroma lines contain a quarter of the number of pixels and bytes of +the luma lines, and the chroma planes contain a quarter of the number of lines +of the luma plane. + +.. flat-table:: Sample 4x4 YUV410 Image + :header-rows: 0 + :stub-columns: 0 + + * - start + 0: + - Y'\ :sub:`00` + - Y'\ :sub:`01` + - Y'\ :sub:`02` + - Y'\ :sub:`03` + * - start + 4: + - Y'\ :sub:`10` + - Y'\ :sub:`11` + - Y'\ :sub:`12` + - Y'\ :sub:`13` + * - start + 8: + - Y'\ :sub:`20` + - Y'\ :sub:`21` + - Y'\ :sub:`22` + - Y'\ :sub:`23` + * - start + 12: + - Y'\ :sub:`30` + - Y'\ :sub:`31` + - Y'\ :sub:`32` + - Y'\ :sub:`33` + * - start + 16: + - Cr\ :sub:`00` + * - start + 17: + - Cb\ :sub:`00` + + +.. _V4L2-PIX-FMT-YUV411P: + +YUV411P +------- + +Planar YUV 4:1:1 formats. The chroma planes are subsampled by 4 in the +horizontal direction. Chroma lines contain a quarter of the number of pixels +and bytes of the luma lines, and the chroma planes contain the same number of +lines as the luma plane. + +.. flat-table:: Sample 4x4 YUV411P Image + :header-rows: 0 + :stub-columns: 0 + + * - start + 0: + - Y'\ :sub:`00` + - Y'\ :sub:`01` + - Y'\ :sub:`02` + - Y'\ :sub:`03` + * - start + 4: + - Y'\ :sub:`10` + - Y'\ :sub:`11` + - Y'\ :sub:`12` + - Y'\ :sub:`13` + * - start + 8: + - Y'\ :sub:`20` + - Y'\ :sub:`21` + - Y'\ :sub:`22` + - Y'\ :sub:`23` + * - start + 12: + - Y'\ :sub:`30` + - Y'\ :sub:`31` + - Y'\ :sub:`32` + - Y'\ :sub:`33` + * - start + 16: + - Cb\ :sub:`00` + * - start + 17: + - Cb\ :sub:`10` + * - start + 18: + - Cb\ :sub:`20` + * - start + 19: + - Cb\ :sub:`30` + * - start + 20: + - Cr\ :sub:`00` + * - start + 21: + - Cr\ :sub:`10` + * - start + 22: + - Cr\ :sub:`20` + * - start + 23: + - Cr\ :sub:`30` + + +.. _V4L2-PIX-FMT-YUV420: +.. _V4L2-PIX-FMT-YVU420: +.. _V4L2-PIX-FMT-YUV420M: +.. _V4L2-PIX-FMT-YVU420M: + +YUV420, YVU420, YUV420M and YVU420M +----------------------------------- + +Planar YUV 4:2:0 formats. The chroma planes are subsampled by 2 in each +direction. Chroma lines contain half of the number of pixels and bytes of the +luma lines, and the chroma planes contain half of the number of lines of the +luma plane. + +.. flat-table:: Sample 4x4 YUV420 Image + :header-rows: 0 + :stub-columns: 0 + + * - start + 0: + - Y'\ :sub:`00` + - Y'\ :sub:`01` + - Y'\ :sub:`02` + - Y'\ :sub:`03` + * - start + 4: + - Y'\ :sub:`10` + - Y'\ :sub:`11` + - Y'\ :sub:`12` + - Y'\ :sub:`13` + * - start + 8: + - Y'\ :sub:`20` + - Y'\ :sub:`21` + - Y'\ :sub:`22` + - Y'\ :sub:`23` + * - start + 12: + - Y'\ :sub:`30` + - Y'\ :sub:`31` + - Y'\ :sub:`32` + - Y'\ :sub:`33` + * - start + 16: + - Cr\ :sub:`00` + - Cr\ :sub:`01` + * - start + 18: + - Cr\ :sub:`10` + - Cr\ :sub:`11` + * - start + 20: + - Cb\ :sub:`00` + - Cb\ :sub:`01` + * - start + 22: + - Cb\ :sub:`10` + - Cb\ :sub:`11` + +.. flat-table:: Sample 4x4 YUV420M Image + :header-rows: 0 + :stub-columns: 0 + + * - start0 + 0: + - Y'\ :sub:`00` + - Y'\ :sub:`01` + - Y'\ :sub:`02` + - Y'\ :sub:`03` + * - start0 + 4: + - Y'\ :sub:`10` + - Y'\ :sub:`11` + - Y'\ :sub:`12` + - Y'\ :sub:`13` + * - start0 + 8: + - Y'\ :sub:`20` + - Y'\ :sub:`21` + - Y'\ :sub:`22` + - Y'\ :sub:`23` + * - start0 + 12: + - Y'\ :sub:`30` + - Y'\ :sub:`31` + - Y'\ :sub:`32` + - Y'\ :sub:`33` + * - + * - start1 + 0: + - Cb\ :sub:`00` + - Cb\ :sub:`01` + * - start1 + 2: + - Cb\ :sub:`10` + - Cb\ :sub:`11` + * - + * - start2 + 0: + - Cr\ :sub:`00` + - Cr\ :sub:`01` + * - start2 + 2: + - Cr\ :sub:`10` + - Cr\ :sub:`11` + + +.. _V4L2-PIX-FMT-YUV422P: +.. _V4L2-PIX-FMT-YUV422M: +.. _V4L2-PIX-FMT-YVU422M: + +YUV422P, YUV422M and YVU422M +---------------------------- + +Planar YUV 4:2:2 formats. The chroma planes are subsampled by 2 in the +horizontal direction. Chroma lines contain half of the number of pixels and +bytes of the luma lines, and the chroma planes contain the same number of lines +as the luma plane. + +.. flat-table:: Sample 4x4 YUV422P Image + :header-rows: 0 + :stub-columns: 0 + + * - start + 0: + - Y'\ :sub:`00` + - Y'\ :sub:`01` + - Y'\ :sub:`02` + - Y'\ :sub:`03` + * - start + 4: + - Y'\ :sub:`10` + - Y'\ :sub:`11` + - Y'\ :sub:`12` + - Y'\ :sub:`13` + * - start + 8: + - Y'\ :sub:`20` + - Y'\ :sub:`21` + - Y'\ :sub:`22` + - Y'\ :sub:`23` + * - start + 12: + - Y'\ :sub:`30` + - Y'\ :sub:`31` + - Y'\ :sub:`32` + - Y'\ :sub:`33` + * - start + 16: + - Cb\ :sub:`00` + - Cb\ :sub:`01` + * - start + 18: + - Cb\ :sub:`10` + - Cb\ :sub:`11` + * - start + 20: + - Cb\ :sub:`20` + - Cb\ :sub:`21` + * - start + 22: + - Cb\ :sub:`30` + - Cb\ :sub:`31` + * - start + 24: + - Cr\ :sub:`00` + - Cr\ :sub:`01` + * - start + 26: + - Cr\ :sub:`10` + - Cr\ :sub:`11` + * - start + 28: + - Cr\ :sub:`20` + - Cr\ :sub:`21` + * - start + 30: + - Cr\ :sub:`30` + - Cr\ :sub:`31` + +.. flat-table:: Sample 4x4 YUV422M Image + :header-rows: 0 + :stub-columns: 0 + + * - start0 + 0: + - Y'\ :sub:`00` + - Y'\ :sub:`01` + - Y'\ :sub:`02` + - Y'\ :sub:`03` + * - start0 + 4: + - Y'\ :sub:`10` + - Y'\ :sub:`11` + - Y'\ :sub:`12` + - Y'\ :sub:`13` + * - start0 + 8: + - Y'\ :sub:`20` + - Y'\ :sub:`21` + - Y'\ :sub:`22` + - Y'\ :sub:`23` + * - start0 + 12: + - Y'\ :sub:`30` + - Y'\ :sub:`31` + - Y'\ :sub:`32` + - Y'\ :sub:`33` + * - + * - start1 + 0: + - Cb\ :sub:`00` + - Cb\ :sub:`01` + * - start1 + 2: + - Cb\ :sub:`10` + - Cb\ :sub:`11` + * - start1 + 4: + - Cb\ :sub:`20` + - Cb\ :sub:`21` + * - start1 + 6: + - Cb\ :sub:`30` + - Cb\ :sub:`31` + * - + * - start2 + 0: + - Cr\ :sub:`00` + - Cr\ :sub:`01` + * - start2 + 2: + - Cr\ :sub:`10` + - Cr\ :sub:`11` + * - start2 + 4: + - Cr\ :sub:`20` + - Cr\ :sub:`21` + * - start2 + 6: + - Cr\ :sub:`30` + - Cr\ :sub:`31` + + +.. _V4L2-PIX-FMT-YUV444M: +.. _V4L2-PIX-FMT-YVU444M: + +YUV444M and YVU444M +------------------- + +Planar YUV 4:4:4 formats. The chroma planes are no subsampled. Chroma lines +contain the same number of pixels and bytes of the luma lines, and the chroma +planes contain the same number of lines as the luma plane. + +.. flat-table:: Sample 4x4 YUV444M Image + :header-rows: 0 + :stub-columns: 0 + + * - start0 + 0: + - Y'\ :sub:`00` + - Y'\ :sub:`01` + - Y'\ :sub:`02` + - Y'\ :sub:`03` + * - start0 + 4: + - Y'\ :sub:`10` + - Y'\ :sub:`11` + - Y'\ :sub:`12` + - Y'\ :sub:`13` + * - start0 + 8: + - Y'\ :sub:`20` + - Y'\ :sub:`21` + - Y'\ :sub:`22` + - Y'\ :sub:`23` + * - start0 + 12: + - Y'\ :sub:`30` + - Y'\ :sub:`31` + - Y'\ :sub:`32` + - Y'\ :sub:`33` + * - + * - start1 + 0: + - Cb\ :sub:`00` + - Cb\ :sub:`01` + - Cb\ :sub:`02` + - Cb\ :sub:`03` + * - start1 + 4: + - Cb\ :sub:`10` + - Cb\ :sub:`11` + - Cb\ :sub:`12` + - Cb\ :sub:`13` + * - start1 + 8: + - Cb\ :sub:`20` + - Cb\ :sub:`21` + - Cb\ :sub:`22` + - Cb\ :sub:`23` + * - start1 + 12: + - Cb\ :sub:`20` + - Cb\ :sub:`21` + - Cb\ :sub:`32` + - Cb\ :sub:`33` + * - + * - start2 + 0: + - Cr\ :sub:`00` + - Cr\ :sub:`01` + - Cr\ :sub:`02` + - Cr\ :sub:`03` + * - start2 + 4: + - Cr\ :sub:`10` + - Cr\ :sub:`11` + - Cr\ :sub:`12` + - Cr\ :sub:`13` + * - start2 + 8: + - Cr\ :sub:`20` + - Cr\ :sub:`21` + - Cr\ :sub:`22` + - Cr\ :sub:`23` + * - start2 + 12: + - Cr\ :sub:`30` + - Cr\ :sub:`31` + - Cr\ :sub:`32` + - Cr\ :sub:`33` diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv410.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv410.rst deleted file mode 100644 index d79cd46d5055..000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-yuv410.rst +++ /dev/null @@ -1,72 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _V4L2-PIX-FMT-YVU410: -.. _v4l2-pix-fmt-yuv410: - -********************************************************** -V4L2_PIX_FMT_YVU410 ('YVU9'), V4L2_PIX_FMT_YUV410 ('YUV9') -********************************************************** - - -V4L2_PIX_FMT_YUV410 -Planar formats with ¼ horizontal and vertical chroma resolution, also -known as YUV 4:1:0 - - -Description -=========== - -These are planar formats, as opposed to a packed format. The three -components are separated into three sub-images or planes. The Y plane is -first. The Y plane has one byte per pixel. For ``V4L2_PIX_FMT_YVU410``, -the Cr plane immediately follows the Y plane in memory. The Cr plane is -¼ the width and ¼ the height of the Y plane (and of the image). Each Cr -belongs to 16 pixels, a four-by-four square of the image. Following the -Cr plane is the Cb plane, just like the Cr plane. -``V4L2_PIX_FMT_YUV410`` is the same, except the Cb plane comes first, -then the Cr plane. - -If the Y plane has pad bytes after each row, then the Cr and Cb planes -have ¼ as many pad bytes after their rows. In other words, four Cx rows -(including padding) are exactly as long as one Y row (including -padding). - -**Byte Order.** -Each cell is one byte. - - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - start + 0: - - Y'\ :sub:`00` - - Y'\ :sub:`01` - - Y'\ :sub:`02` - - Y'\ :sub:`03` - * - start + 4: - - Y'\ :sub:`10` - - Y'\ :sub:`11` - - Y'\ :sub:`12` - - Y'\ :sub:`13` - * - start + 8: - - Y'\ :sub:`20` - - Y'\ :sub:`21` - - Y'\ :sub:`22` - - Y'\ :sub:`23` - * - start + 12: - - Y'\ :sub:`30` - - Y'\ :sub:`31` - - Y'\ :sub:`32` - - Y'\ :sub:`33` - * - start + 16: - - Cr\ :sub:`00` - * - start + 17: - - Cb\ :sub:`00` - - -**Color Sample Location:** -Chroma samples are :ref:`interstitially sited` -horizontally and vertically. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv411p.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv411p.rst deleted file mode 100644 index 8a70eeca8d83..000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-yuv411p.rst +++ /dev/null @@ -1,80 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _V4L2-PIX-FMT-YUV411P: - -***************************** -V4L2_PIX_FMT_YUV411P ('411P') -***************************** - - -Format with ¼ horizontal chroma resolution, also known as YUV 4:1:1. -Planar layout as opposed to ``V4L2_PIX_FMT_Y41P`` - - -Description -=========== - -This format is not commonly used. This is a planar format similar to the -4:2:2 planar format except with half as many chroma. The three -components are separated into three sub-images or planes. The Y plane is -first. The Y plane has one byte per pixel. The Cb plane immediately -follows the Y plane in memory. The Cb plane is ¼ the width of the Y -plane (and of the image). Each Cb belongs to 4 pixels all on the same -row. For example, Cb\ :sub:`0` belongs to Y'\ :sub:`00`, Y'\ :sub:`01`, -Y'\ :sub:`02` and Y'\ :sub:`03`. Following the Cb plane is the Cr plane, -just like the Cb plane. - -If the Y plane has pad bytes after each row, then the Cr and Cb planes -have ¼ as many pad bytes after their rows. In other words, four C x rows -(including padding) is exactly as long as one Y row (including padding). - -**Byte Order.** -Each cell is one byte. - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - start + 0: - - Y'\ :sub:`00` - - Y'\ :sub:`01` - - Y'\ :sub:`02` - - Y'\ :sub:`03` - * - start + 4: - - Y'\ :sub:`10` - - Y'\ :sub:`11` - - Y'\ :sub:`12` - - Y'\ :sub:`13` - * - start + 8: - - Y'\ :sub:`20` - - Y'\ :sub:`21` - - Y'\ :sub:`22` - - Y'\ :sub:`23` - * - start + 12: - - Y'\ :sub:`30` - - Y'\ :sub:`31` - - Y'\ :sub:`32` - - Y'\ :sub:`33` - * - start + 16: - - Cb\ :sub:`00` - * - start + 17: - - Cb\ :sub:`10` - * - start + 18: - - Cb\ :sub:`20` - * - start + 19: - - Cb\ :sub:`30` - * - start + 20: - - Cr\ :sub:`00` - * - start + 21: - - Cr\ :sub:`10` - * - start + 22: - - Cr\ :sub:`20` - * - start + 23: - - Cr\ :sub:`30` - - -**Color Sample Location:** -Chroma samples are :ref:`interstitially sited` -horizontally. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv420.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv420.rst deleted file mode 100644 index a36ec8d6d8a4..000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-yuv420.rst +++ /dev/null @@ -1,81 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _V4L2-PIX-FMT-YVU420: -.. _V4L2-PIX-FMT-YUV420: - -********************************************************** -V4L2_PIX_FMT_YVU420 ('YV12'), V4L2_PIX_FMT_YUV420 ('YU12') -********************************************************** - - -V4L2_PIX_FMT_YUV420 -Planar formats with ½ horizontal and vertical chroma resolution, also -known as YUV 4:2:0 - - -Description -=========== - -These are planar formats, as opposed to a packed format. The three -components are separated into three sub- images or planes. The Y plane -is first. The Y plane has one byte per pixel. For -``V4L2_PIX_FMT_YVU420``, the Cr plane immediately follows the Y plane in -memory. The Cr plane is half the width and half the height of the Y -plane (and of the image). Each Cr belongs to four pixels, a two-by-two -square of the image. For example, Cr\ :sub:`0` belongs to Y'\ :sub:`00`, -Y'\ :sub:`01`, Y'\ :sub:`10`, and Y'\ :sub:`11`. Following the Cr plane -is the Cb plane, just like the Cr plane. ``V4L2_PIX_FMT_YUV420`` is the -same except the Cb plane comes first, then the Cr plane. - -If the Y plane has pad bytes after each row, then the Cr and Cb planes -have half as many pad bytes after their rows. In other words, two Cx -rows (including padding) is exactly as long as one Y row (including -padding). - -**Byte Order.** -Each cell is one byte. - - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - start + 0: - - Y'\ :sub:`00` - - Y'\ :sub:`01` - - Y'\ :sub:`02` - - Y'\ :sub:`03` - * - start + 4: - - Y'\ :sub:`10` - - Y'\ :sub:`11` - - Y'\ :sub:`12` - - Y'\ :sub:`13` - * - start + 8: - - Y'\ :sub:`20` - - Y'\ :sub:`21` - - Y'\ :sub:`22` - - Y'\ :sub:`23` - * - start + 12: - - Y'\ :sub:`30` - - Y'\ :sub:`31` - - Y'\ :sub:`32` - - Y'\ :sub:`33` - * - start + 16: - - Cr\ :sub:`00` - - Cr\ :sub:`01` - * - start + 18: - - Cr\ :sub:`10` - - Cr\ :sub:`11` - * - start + 20: - - Cb\ :sub:`00` - - Cb\ :sub:`01` - * - start + 22: - - Cb\ :sub:`10` - - Cb\ :sub:`11` - - -**Color Sample Location:** -Chroma samples are :ref:`interstitially sited` -horizontally and vertically. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv420m.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv420m.rst deleted file mode 100644 index c2cf17b9743c..000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-yuv420m.rst +++ /dev/null @@ -1,90 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _V4L2-PIX-FMT-YUV420M: -.. _v4l2-pix-fmt-yvu420m: - -************************************************************ -V4L2_PIX_FMT_YUV420M ('YM12'), V4L2_PIX_FMT_YVU420M ('YM21') -************************************************************ - - -V4L2_PIX_FMT_YVU420M -Variation of ``V4L2_PIX_FMT_YUV420`` and ``V4L2_PIX_FMT_YVU420`` with -planes non contiguous in memory. - - -Description -=========== - -This is a multi-planar format, as opposed to a packed format. The three -components are separated into three sub-images or planes. - -The Y plane is first. The Y plane has one byte per pixel. For -``V4L2_PIX_FMT_YUV420M`` the Cb data constitutes the second plane which -is half the width and half the height of the Y plane (and of the image). -Each Cb belongs to four pixels, a two-by-two square of the image. For -example, Cb\ :sub:`0` belongs to Y'\ :sub:`00`, Y'\ :sub:`01`, -Y'\ :sub:`10`, and Y'\ :sub:`11`. The Cr data, just like the Cb plane, -is in the third plane. - -``V4L2_PIX_FMT_YVU420M`` is the same except the Cr data is stored in the -second plane and the Cb data in the third plane. - -If the Y plane has pad bytes after each row, then the Cb and Cr planes -have half as many pad bytes after their rows. In other words, two Cx -rows (including padding) is exactly as long as one Y row (including -padding). - -``V4L2_PIX_FMT_YUV420M`` and ``V4L2_PIX_FMT_YVU420M`` are intended to be -used only in drivers and applications that support the multi-planar API, -described in :ref:`planar-apis`. - -**Byte Order.** -Each cell is one byte. - - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - start0 + 0: - - Y'\ :sub:`00` - - Y'\ :sub:`01` - - Y'\ :sub:`02` - - Y'\ :sub:`03` - * - start0 + 4: - - Y'\ :sub:`10` - - Y'\ :sub:`11` - - Y'\ :sub:`12` - - Y'\ :sub:`13` - * - start0 + 8: - - Y'\ :sub:`20` - - Y'\ :sub:`21` - - Y'\ :sub:`22` - - Y'\ :sub:`23` - * - start0 + 12: - - Y'\ :sub:`30` - - Y'\ :sub:`31` - - Y'\ :sub:`32` - - Y'\ :sub:`33` - * - - * - start1 + 0: - - Cb\ :sub:`00` - - Cb\ :sub:`01` - * - start1 + 2: - - Cb\ :sub:`10` - - Cb\ :sub:`11` - * - - * - start2 + 0: - - Cr\ :sub:`00` - - Cr\ :sub:`01` - * - start2 + 2: - - Cr\ :sub:`10` - - Cr\ :sub:`11` - - -**Color Sample Location:** -Chroma samples are :ref:`interstitially sited` -horizontally and vertically. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv422m.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv422m.rst deleted file mode 100644 index f92b54853fc9..000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-yuv422m.rst +++ /dev/null @@ -1,101 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _V4L2-PIX-FMT-YUV422M: -.. _v4l2-pix-fmt-yvu422m: - -************************************************************ -V4L2_PIX_FMT_YUV422M ('YM16'), V4L2_PIX_FMT_YVU422M ('YM61') -************************************************************ - - -V4L2_PIX_FMT_YVU422M -Planar formats with ½ horizontal resolution, also known as YUV and YVU -4:2:2 - - -Description -=========== - -This is a multi-planar format, as opposed to a packed format. The three -components are separated into three sub-images or planes. - -The Y plane is first. The Y plane has one byte per pixel. For -``V4L2_PIX_FMT_YUV422M`` the Cb data constitutes the second plane which -is half the width of the Y plane (and of the image). Each Cb belongs to -two pixels. For example, Cb\ :sub:`0` belongs to Y'\ :sub:`00`, -Y'\ :sub:`01`. The Cr data, just like the Cb plane, is in the third -plane. - -``V4L2_PIX_FMT_YVU422M`` is the same except the Cr data is stored in the -second plane and the Cb data in the third plane. - -If the Y plane has pad bytes after each row, then the Cb and Cr planes -have half as many pad bytes after their rows. In other words, two Cx -rows (including padding) is exactly as long as one Y row (including -padding). - -``V4L2_PIX_FMT_YUV422M`` and ``V4L2_PIX_FMT_YVU422M`` are intended to be -used only in drivers and applications that support the multi-planar API, -described in :ref:`planar-apis`. - -**Byte Order.** -Each cell is one byte. - - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - start0 + 0: - - Y'\ :sub:`00` - - Y'\ :sub:`01` - - Y'\ :sub:`02` - - Y'\ :sub:`03` - * - start0 + 4: - - Y'\ :sub:`10` - - Y'\ :sub:`11` - - Y'\ :sub:`12` - - Y'\ :sub:`13` - * - start0 + 8: - - Y'\ :sub:`20` - - Y'\ :sub:`21` - - Y'\ :sub:`22` - - Y'\ :sub:`23` - * - start0 + 12: - - Y'\ :sub:`30` - - Y'\ :sub:`31` - - Y'\ :sub:`32` - - Y'\ :sub:`33` - * - - * - start1 + 0: - - Cb\ :sub:`00` - - Cb\ :sub:`01` - * - start1 + 2: - - Cb\ :sub:`10` - - Cb\ :sub:`11` - * - start1 + 4: - - Cb\ :sub:`20` - - Cb\ :sub:`21` - * - start1 + 6: - - Cb\ :sub:`30` - - Cb\ :sub:`31` - * - - * - start2 + 0: - - Cr\ :sub:`00` - - Cr\ :sub:`01` - * - start2 + 2: - - Cr\ :sub:`10` - - Cr\ :sub:`11` - * - start2 + 4: - - Cr\ :sub:`20` - - Cr\ :sub:`21` - * - start2 + 6: - - Cr\ :sub:`30` - - Cr\ :sub:`31` - - -**Color Sample Location:** -Chroma samples are :ref:`interstitially sited` -horizontally. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv422p.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv422p.rst deleted file mode 100644 index 33e6b923e325..000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-yuv422p.rst +++ /dev/null @@ -1,89 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _V4L2-PIX-FMT-YUV422P: - -***************************** -V4L2_PIX_FMT_YUV422P ('422P') -***************************** - - -Format with ½ horizontal chroma resolution, also known as YUV 4:2:2. -Planar layout as opposed to ``V4L2_PIX_FMT_YUYV`` - - -Description -=========== - -This format is not commonly used. This is a planar version of the YUYV -format. The three components are separated into three sub-images or -planes. The Y plane is first. The Y plane has one byte per pixel. The Cb -plane immediately follows the Y plane in memory. The Cb plane is half -the width of the Y plane (and of the image). Each Cb belongs to two -pixels. For example, Cb\ :sub:`0` belongs to Y'\ :sub:`00`, -Y'\ :sub:`01`. Following the Cb plane is the Cr plane, just like the Cb -plane. - -If the Y plane has pad bytes after each row, then the Cr and Cb planes -have half as many pad bytes after their rows. In other words, two Cx -rows (including padding) is exactly as long as one Y row (including -padding). - -**Byte Order.** -Each cell is one byte. - - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - start + 0: - - Y'\ :sub:`00` - - Y'\ :sub:`01` - - Y'\ :sub:`02` - - Y'\ :sub:`03` - * - start + 4: - - Y'\ :sub:`10` - - Y'\ :sub:`11` - - Y'\ :sub:`12` - - Y'\ :sub:`13` - * - start + 8: - - Y'\ :sub:`20` - - Y'\ :sub:`21` - - Y'\ :sub:`22` - - Y'\ :sub:`23` - * - start + 12: - - Y'\ :sub:`30` - - Y'\ :sub:`31` - - Y'\ :sub:`32` - - Y'\ :sub:`33` - * - start + 16: - - Cb\ :sub:`00` - - Cb\ :sub:`01` - * - start + 18: - - Cb\ :sub:`10` - - Cb\ :sub:`11` - * - start + 20: - - Cb\ :sub:`20` - - Cb\ :sub:`21` - * - start + 22: - - Cb\ :sub:`30` - - Cb\ :sub:`31` - * - start + 24: - - Cr\ :sub:`00` - - Cr\ :sub:`01` - * - start + 26: - - Cr\ :sub:`10` - - Cr\ :sub:`11` - * - start + 28: - - Cr\ :sub:`20` - - Cr\ :sub:`21` - * - start + 30: - - Cr\ :sub:`30` - - Cr\ :sub:`31` - - -**Color Sample Location:** -Chroma samples are :ref:`interstitially sited` -horizontally. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv444m.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv444m.rst deleted file mode 100644 index 7c03cc5b07d9..000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-yuv444m.rst +++ /dev/null @@ -1,110 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _V4L2-PIX-FMT-YUV444M: -.. _v4l2-pix-fmt-yvu444m: - -************************************************************ -V4L2_PIX_FMT_YUV444M ('YM24'), V4L2_PIX_FMT_YVU444M ('YM42') -************************************************************ - - -V4L2_PIX_FMT_YVU444M -Planar formats with full horizontal resolution, also known as YUV and -YVU 4:4:4 - - -Description -=========== - -This is a multi-planar format, as opposed to a packed format. The three -components are separated into three sub-images or planes. - -The Y plane is first. The Y plane has one byte per pixel. For -``V4L2_PIX_FMT_YUV444M`` the Cb data constitutes the second plane which -is the same width and height as the Y plane (and as the image). The Cr -data, just like the Cb plane, is in the third plane. - -``V4L2_PIX_FMT_YVU444M`` is the same except the Cr data is stored in the -second plane and the Cb data in the third plane. - -If the Y plane has pad bytes after each row, then the Cb and Cr planes -have the same number of pad bytes after their rows. - -``V4L2_PIX_FMT_YUV444M`` and ``V4L2_PIX_FMT_YUV444M`` are intended to be -used only in drivers and applications that support the multi-planar API, -described in :ref:`planar-apis`. - -**Byte Order.** -Each cell is one byte. - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - start0 + 0: - - Y'\ :sub:`00` - - Y'\ :sub:`01` - - Y'\ :sub:`02` - - Y'\ :sub:`03` - * - start0 + 4: - - Y'\ :sub:`10` - - Y'\ :sub:`11` - - Y'\ :sub:`12` - - Y'\ :sub:`13` - * - start0 + 8: - - Y'\ :sub:`20` - - Y'\ :sub:`21` - - Y'\ :sub:`22` - - Y'\ :sub:`23` - * - start0 + 12: - - Y'\ :sub:`30` - - Y'\ :sub:`31` - - Y'\ :sub:`32` - - Y'\ :sub:`33` - * - - * - start1 + 0: - - Cb\ :sub:`00` - - Cb\ :sub:`01` - - Cb\ :sub:`02` - - Cb\ :sub:`03` - * - start1 + 4: - - Cb\ :sub:`10` - - Cb\ :sub:`11` - - Cb\ :sub:`12` - - Cb\ :sub:`13` - * - start1 + 8: - - Cb\ :sub:`20` - - Cb\ :sub:`21` - - Cb\ :sub:`22` - - Cb\ :sub:`23` - * - start1 + 12: - - Cb\ :sub:`20` - - Cb\ :sub:`21` - - Cb\ :sub:`32` - - Cb\ :sub:`33` - * - - * - start2 + 0: - - Cr\ :sub:`00` - - Cr\ :sub:`01` - - Cr\ :sub:`02` - - Cr\ :sub:`03` - * - start2 + 4: - - Cr\ :sub:`10` - - Cr\ :sub:`11` - - Cr\ :sub:`12` - - Cr\ :sub:`13` - * - start2 + 8: - - Cr\ :sub:`20` - - Cr\ :sub:`21` - - Cr\ :sub:`22` - - Cr\ :sub:`23` - * - start2 + 12: - - Cr\ :sub:`30` - - Cr\ :sub:`31` - - Cr\ :sub:`32` - - Cr\ :sub:`33` - - -**Color Sample Location:** -Chroma samples are :ref:`co-sited`. diff --git a/Documentation/userspace-api/media/v4l/yuv-formats.rst b/Documentation/userspace-api/media/v4l/yuv-formats.rst index 517499056f3b..24b34cdfa6fe 100644 --- a/Documentation/userspace-api/media/v4l/yuv-formats.rst +++ b/Documentation/userspace-api/media/v4l/yuv-formats.rst @@ -270,11 +270,4 @@ image. pixfmt-y8i pixfmt-y12i pixfmt-uv8 - pixfmt-yuv420 - pixfmt-yuv420m - pixfmt-yuv422m - pixfmt-yuv444m - pixfmt-yuv410 - pixfmt-yuv422p - pixfmt-yuv411p pixfmt-m420 -- cgit v1.2.3 From e469d0b09a19496e1972a20974bbf55b728151eb Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 2 Dec 2020 18:20:04 +0100 Subject: media: gspca: Fix memory leak in probe The gspca driver leaks memory when a probe fails. gspca_dev_probe2() calls v4l2_device_register(), which takes a reference to the underlying device node (in this case, a USB interface). But the failure pathway neglects to call v4l2_device_unregister(), the routine responsible for dropping this reference. Consequently the memory for the USB interface and its device never gets released. This patch adds the missing function call. Reported-and-tested-by: syzbot+44e64397bd81d5e84cba@syzkaller.appspotmail.com Signed-off-by: Alan Stern CC: Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/gspca.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index c295f642d352..158c8e28ed2c 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -1575,6 +1575,7 @@ out: input_unregister_device(gspca_dev->input_dev); #endif v4l2_ctrl_handler_free(gspca_dev->vdev.ctrl_handler); + v4l2_device_unregister(&gspca_dev->v4l2_dev); kfree(gspca_dev->usb_buf); kfree(gspca_dev); return ret; -- cgit v1.2.3 From 68b4a01f88af32ae677e142c204595e847f897b8 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Wed, 2 Dec 2020 18:44:13 +0100 Subject: media: cedrus: Make VP8 codec as capability Commit 31d9b9ef8564 ("media: cedrus: Register all codecs as capability") makes separate capability flags for each codec. However, VP8 codec was merged at the same time as mentioned patch, so there is no capability flag for it. This patch adds capability flag for VP8 and enables it for all variants except for V3s. Signed-off-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/sunxi/cedrus/cedrus.c | 27 +++++++++++++++-------- drivers/staging/media/sunxi/cedrus/cedrus.h | 1 + drivers/staging/media/sunxi/cedrus/cedrus_video.c | 1 + 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index b1fc6b672a9b..18d54f9fd715 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -514,26 +514,30 @@ static int cedrus_remove(struct platform_device *pdev) static const struct cedrus_variant sun4i_a10_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC | - CEDRUS_CAPABILITY_H264_DEC, + CEDRUS_CAPABILITY_H264_DEC | + CEDRUS_CAPABILITY_VP8_DEC, .mod_rate = 320000000, }; static const struct cedrus_variant sun5i_a13_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC | - CEDRUS_CAPABILITY_H264_DEC, + CEDRUS_CAPABILITY_H264_DEC | + CEDRUS_CAPABILITY_VP8_DEC, .mod_rate = 320000000, }; static const struct cedrus_variant sun7i_a20_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC | - CEDRUS_CAPABILITY_H264_DEC, + CEDRUS_CAPABILITY_H264_DEC | + CEDRUS_CAPABILITY_VP8_DEC, .mod_rate = 320000000, }; static const struct cedrus_variant sun8i_a33_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_UNTILED | CEDRUS_CAPABILITY_MPEG2_DEC | - CEDRUS_CAPABILITY_H264_DEC, + CEDRUS_CAPABILITY_H264_DEC | + CEDRUS_CAPABILITY_VP8_DEC, .mod_rate = 320000000, }; @@ -541,7 +545,8 @@ static const struct cedrus_variant sun8i_h3_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_UNTILED | CEDRUS_CAPABILITY_MPEG2_DEC | CEDRUS_CAPABILITY_H264_DEC | - CEDRUS_CAPABILITY_H265_DEC, + CEDRUS_CAPABILITY_H265_DEC | + CEDRUS_CAPABILITY_VP8_DEC, .mod_rate = 402000000, }; @@ -554,7 +559,8 @@ static const struct cedrus_variant sun8i_v3s_cedrus_variant = { static const struct cedrus_variant sun8i_r40_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_UNTILED | CEDRUS_CAPABILITY_MPEG2_DEC | - CEDRUS_CAPABILITY_H264_DEC, + CEDRUS_CAPABILITY_H264_DEC | + CEDRUS_CAPABILITY_VP8_DEC, .mod_rate = 297000000, }; @@ -562,7 +568,8 @@ static const struct cedrus_variant sun50i_a64_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_UNTILED | CEDRUS_CAPABILITY_MPEG2_DEC | CEDRUS_CAPABILITY_H264_DEC | - CEDRUS_CAPABILITY_H265_DEC, + CEDRUS_CAPABILITY_H265_DEC | + CEDRUS_CAPABILITY_VP8_DEC, .mod_rate = 402000000, }; @@ -570,7 +577,8 @@ static const struct cedrus_variant sun50i_h5_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_UNTILED | CEDRUS_CAPABILITY_MPEG2_DEC | CEDRUS_CAPABILITY_H264_DEC | - CEDRUS_CAPABILITY_H265_DEC, + CEDRUS_CAPABILITY_H265_DEC | + CEDRUS_CAPABILITY_VP8_DEC, .mod_rate = 402000000, }; @@ -578,7 +586,8 @@ static const struct cedrus_variant sun50i_h6_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_UNTILED | CEDRUS_CAPABILITY_MPEG2_DEC | CEDRUS_CAPABILITY_H264_DEC | - CEDRUS_CAPABILITY_H265_DEC, + CEDRUS_CAPABILITY_H265_DEC | + CEDRUS_CAPABILITY_VP8_DEC, .quirks = CEDRUS_QUIRK_NO_DMA_OFFSET, .mod_rate = 600000000, }; diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h index 0bf1cbddac9c..e61c41853ba2 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h @@ -31,6 +31,7 @@ #define CEDRUS_CAPABILITY_H265_DEC BIT(1) #define CEDRUS_CAPABILITY_H264_DEC BIT(2) #define CEDRUS_CAPABILITY_MPEG2_DEC BIT(3) +#define CEDRUS_CAPABILITY_VP8_DEC BIT(4) #define CEDRUS_QUIRK_NO_DMA_OFFSET BIT(0) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c index 8a01e6b9bebb..b62eb8e84057 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c @@ -53,6 +53,7 @@ static struct cedrus_format cedrus_formats[] = { { .pixelformat = V4L2_PIX_FMT_VP8_FRAME, .directions = CEDRUS_DECODE_SRC, + .capabilities = CEDRUS_CAPABILITY_VP8_DEC, }, { .pixelformat = V4L2_PIX_FMT_SUNXI_TILED_NV12, -- cgit v1.2.3 From 635e51f14476525577f906a998ca8ddf6f252dbb Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 2 Dec 2020 18:44:14 +0100 Subject: media: dt-bindings: media: Add bindings for the Amlogic GE2D Accelerator Unit The GE2D is a 2D accelerator with various features like configurable blitter with alpha blending, frame rotation, scaling, format conversion and colorspace conversion. This adds the bindings for the GE2D version found in the AXG SoCs Family. Signed-off-by: Neil Armstrong Reviewed-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/amlogic,axg-ge2d.yaml | 47 ++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/amlogic,axg-ge2d.yaml diff --git a/Documentation/devicetree/bindings/media/amlogic,axg-ge2d.yaml b/Documentation/devicetree/bindings/media/amlogic,axg-ge2d.yaml new file mode 100644 index 000000000000..bee93bd84771 --- /dev/null +++ b/Documentation/devicetree/bindings/media/amlogic,axg-ge2d.yaml @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright 2020 BayLibre, SAS +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/media/amlogic,axg-ge2d.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Amlogic GE2D Acceleration Unit + +maintainers: + - Neil Armstrong + +properties: + compatible: + enum: + - amlogic,axg-ge2d + + interrupts: + minItems: 1 + + reg: + minItems: 1 + + resets: + maxItems: 1 + + clocks: + minItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + - resets + +additionalProperties: false + +examples: + - | + ge2d: ge2d@ff940000 { + compatible = "amlogic,axg-ge2d"; + reg = <0xff940000 0x10000>; + interrupts = <150>; + clocks = <&clk_ge2d>; + resets = <&reset_ge2d>; + }; -- cgit v1.2.3 From 59a635327ca70de540b4083eeb954ffc7ce9ff94 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 2 Dec 2020 18:44:15 +0100 Subject: media: meson: Add M2M driver for the Amlogic GE2D Accelerator Unit The GE2D is a 2D accelerator with various features like configurable blitter with alpha blending, frame rotation, scaling, format conversion and colorspace conversion. The driver implements a Memory2Memory VB2 V4L2 streaming device permitting: - 0, 90, 180, 270deg rotation - horizontal/vertical flipping - source cropping - destination compositing - 32bit/24bit/16bit format conversion This adds the support for the GE2D version found in the AXG SoCs Family. The missing features are: - Source scaling - Colorspace conversion - Advanced alpha blending & blitting options Is passes v4l2-compliance: SHA: ea16a7ef13a902793a5c2626b0cefc4d956147f3, 64 bits, 64-bit time_t [hverkuil: add missing linux/bitfield.h include] Signed-off-by: Neil Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 13 + drivers/media/platform/Makefile | 2 + drivers/media/platform/meson/ge2d/Makefile | 3 + drivers/media/platform/meson/ge2d/ge2d-regs.h | 360 +++++++++ drivers/media/platform/meson/ge2d/ge2d.c | 1067 +++++++++++++++++++++++++ 5 files changed, 1445 insertions(+) create mode 100644 drivers/media/platform/meson/ge2d/Makefile create mode 100644 drivers/media/platform/meson/ge2d/ge2d-regs.h create mode 100644 drivers/media/platform/meson/ge2d/ge2d.c diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 9fdbfea06087..35a18d388f3f 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -306,6 +306,19 @@ config VIDEO_MEM2MEM_DEINTERLACE help Generic deinterlacing V4L2 driver. +config VIDEO_MESON_GE2D + tristate "Amlogic 2D Graphic Acceleration Unit" + depends on VIDEO_DEV && VIDEO_V4L2 + depends on ARCH_MESON || COMPILE_TEST + select VIDEOBUF2_DMA_CONTIG + select V4L2_MEM2MEM_DEV + help + This is a v4l2 driver for Amlogic GE2D 2D graphics accelerator. + GE2D is a standalone 2D graphic acceleration unit, with color converter, + image scaling, BitBLT & alpha blending operations. + + To compile this driver as a module choose m here. + config VIDEO_SAMSUNG_S5P_G2D tristate "Samsung S5P and EXYNOS4 G2D 2d graphics accelerator driver" depends on VIDEO_DEV && VIDEO_V4L2 diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index b342714228db..1d63aa956bcd 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -81,3 +81,5 @@ obj-$(CONFIG_VIDEO_QCOM_CAMSS) += qcom/camss/ obj-$(CONFIG_VIDEO_QCOM_VENUS) += qcom/venus/ obj-y += sunxi/ + +obj-$(CONFIG_VIDEO_MESON_GE2D) += meson/ge2d/ diff --git a/drivers/media/platform/meson/ge2d/Makefile b/drivers/media/platform/meson/ge2d/Makefile new file mode 100644 index 000000000000..450586df27d7 --- /dev/null +++ b/drivers/media/platform/meson/ge2d/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-$(CONFIG_VIDEO_MESON_GE2D) += ge2d.o diff --git a/drivers/media/platform/meson/ge2d/ge2d-regs.h b/drivers/media/platform/meson/ge2d/ge2d-regs.h new file mode 100644 index 000000000000..2a76dd4c0ccb --- /dev/null +++ b/drivers/media/platform/meson/ge2d/ge2d-regs.h @@ -0,0 +1,360 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020 BayLibre, SAS + * Author: Neil Armstrong + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + */ + +#ifndef __GE2D_REGS__ +#define __GE2D_REGS__ + +/* Registers starts at (GE2D_REG(0x8a0 * 4) */ +#define GE2D_REG(x) ((0x8a0 + (x)) * 4) + +#define GE2D_GEN_CTRL0 GE2D_REG(0x00) + +#define GE2D_DST_BYTEMASK_ONLY BIT(31) +#define GE2D_DST_BITMASK_EN BIT(30) +#define GE2D_SRC2_KEY_EN BIT(29) +#define GE2D_SRC2_KEY_MODE BIT(28) +#define GE2D_SRC1_KEY_EN BIT(27) +#define GE2D_SRC1_KEY_MODE BIT(26) +#define GE2D_DST1_8B_MODE_SEL GENMASK(25, 24) +#define GE2D_DST_CLIP_MODE BIT(23) +#define GE2D_SRC2_8B_MODE_SEL GENMASK(16, 15) +#define GE2D_SRC2_FILL_MODE BIT(14) +#define GE2D_SRC2_PIC_STRUCT GENMASK(13, 12) +#define GE2D_SRC2_X_YC_RATIO BIT(11) +#define GE2D_SRC1_8B_MODE_SEL GENMASK(6, 5) +#define GE2D_SRC1_FILL_MODE BIT(4) +#define GE2D_SRC1_LUT_EN BIT(3) +#define GE2D_SRC1_PIC_STRUCT GENMASK(2, 1) + +#define GE2D_GEN_CTRL1 GE2D_REG(0x01) + +#define GE2D_SOFT_RST BIT(31) +#define GE2D_DST_WRITE_RESP_CNT_RST BIT(30) +#define GE2D_DST_WRITE_RESP_CNT_ADD_DIS BIT(29) +#define GE2D_COLOR_CONVERSION_MODE1 BIT(26) +#define GE2D_INTERRUPT_CTRL GENMASK(25, 24) +#define GE2D_SRC2_BURST_SIZE_CTRL GENMASK(23, 22) +#define GE2D_SRC1_BURST_SIZE_CTRL GENMASK(21, 16) +#define GE2D_DST1_PIC_STRUCT GENMASK(15, 14) +#define GE2D_SRC_RD_CTRL GENMASK(13, 12) +#define GE2D_DST2_URGENT_EN BIT(11) +#define GE2D_SRC1_URGENT_EN BIT(10) +#define GE2D_SRC2_URGENT_EN BIT(9) +#define GE2D_DST1_URGENT_EN BIT(8) +#define GE2D_SRC1_GB_ALPHA GENMASK(7, 0) + +#define GE2D_GEN_CTRL2 GE2D_REG(0x02) + +#define GE2D_ALPHA_CONVERSION_MODE0 BIT(31) +#define GE2D_COLOR_CONVERSION_MODE0 BIT(30) +#define GE2D_SRC1_GB_ALPHA_EN BIT(29) +#define GE2D_DST1_COLOR_ROUND_MODE BIT(28) +#define GE2D_SRC2_COLOR_EXPAND_MODE BIT(27) +#define GE2D_SRC2_ALPHA_EXPAND_MODE BIT(26) +#define GE2D_SRC1_COLOR_EXPAND_MODE BIT(25) +#define GE2D_SRC1_ALPHA_EXPAND_MODE BIT(24) +#define GE2D_DST_LITTLE_ENDIAN BIT(23) +#define GE2D_DST1_COLOR_MAP GENMASK(22, 19) +#define GE2D_ALU_MULT_MODE BIT(18) +#define GE2D_DST1_FORMAT GENMASK(17, 16) +#define GE2D_SRC2_LITTLE_ENDIAN BIT(15) +#define GE2D_SRC2_COLOR_MAP GENMASK(14, 11) +#define GE2D_ALPHA_CONVERSION_MODE1 BIT(10) +#define GE2D_SRC2_FORMAT GENMASK(9, 8) +#define GE2D_SRC1_LITTLE_ENDIAN BIT(7) +#define GE2D_SRC1_COLOR_MAP GENMASK(6, 3) +#define GE2D_SRC1_DEEPCOLOR BIT(2) +#define GE2D_SRC1_FORMAT GENMASK(1, 0) + +#define GE2D_FORMAT_8BIT 0 +#define GE2D_FORMAT_16BIT 1 +#define GE2D_FORMAT_24BIT 2 +#define GE2D_FORMAT_32BIT 3 + +/* 16 bit */ +#define GE2D_COLOR_MAP_YUV422 0 +#define GE2D_COLOR_MAP_RGB655 1 +#define GE2D_COLOR_MAP_YUV655 1 +#define GE2D_COLOR_MAP_RGB844 2 +#define GE2D_COLOR_MAP_YUV844 2 +#define GE2D_COLOR_MAP_RGBA6442 3 +#define GE2D_COLOR_MAP_YUVA6442 3 +#define GE2D_COLOR_MAP_RGBA4444 4 +#define GE2D_COLOR_MAP_YUVA4444 4 +#define GE2D_COLOR_MAP_RGB565 5 +#define GE2D_COLOR_MAP_YUV565 5 +#define GE2D_COLOR_MAP_ARGB4444 6 +#define GE2D_COLOR_MAP_AYUV4444 6 +#define GE2D_COLOR_MAP_ARGB1555 7 +#define GE2D_COLOR_MAP_AYUV1555 7 +#define GE2D_COLOR_MAP_RGBA4642 8 +#define GE2D_COLOR_MAP_YUVA4642 8 + +/* 24 bit */ +#define GE2D_COLOR_MAP_RGB888 0 +#define GE2D_COLOR_MAP_YUV444 0 +#define GE2D_COLOR_MAP_RGBA5658 1 +#define GE2D_COLOR_MAP_YUVA5658 1 +#define GE2D_COLOR_MAP_ARGB8565 2 +#define GE2D_COLOR_MAP_AYUV8565 2 +#define GE2D_COLOR_MAP_RGBA6666 3 +#define GE2D_COLOR_MAP_YUVA6666 3 +#define GE2D_COLOR_MAP_ARGB6666 4 +#define GE2D_COLOR_MAP_AYUV6666 4 +#define GE2D_COLOR_MAP_BGR888 5 +#define GE2D_COLOR_MAP_VUY888 5 + +/* 32 bit */ +#define GE2D_COLOR_MAP_RGBA8888 0 +#define GE2D_COLOR_MAP_YUVA8888 0 +#define GE2D_COLOR_MAP_ARGB8888 1 +#define GE2D_COLOR_MAP_AYUV8888 1 +#define GE2D_COLOR_MAP_ABGR8888 2 +#define GE2D_COLOR_MAP_AVUY8888 2 +#define GE2D_COLOR_MAP_BGRA8888 3 +#define GE2D_COLOR_MAP_VUYA8888 3 + +#define GE2D_CMD_CTRL GE2D_REG(0x03) + +#define GE2D_SRC2_FILL_COLOR_EN BIT(9) +#define GE2D_SRC1_FILL_COLOR_EN BIT(8) +#define GE2D_DST_XY_SWAP BIT(7) +#define GE2D_DST_X_REV BIT(6) +#define GE2D_DST_Y_REV BIT(5) +#define GE2D_SRC2_X_REV BIT(4) +#define GE2D_SRC2_Y_REV BIT(3) +#define GE2D_SRC1_X_REV BIT(2) +#define GE2D_SRC1_Y_REV BIT(1) +#define GE2D_CBUS_CMD_WR BIT(0) + +#define GE2D_STATUS0 GE2D_REG(0x04) + +#define GE2D_DST_WRITE_RSP_CNT GENMASK(28, 17) +#define GE2D_DP_STATUS GENMASK(16, 7) +#define GE2D_R1CMD_RDY BIT(6) +#define GE2D_R2CMD_RDY BIT(5) +#define GE2D_PDPCMD_VALID BIT(4) +#define GE2D_DPCMD_RDY BIT(3) +#define GE2D_BUF_CMD_VALID BIT(2) +#define GE2D_CURR_CMD_VALID BIT(1) +#define GE2D_GE2D_BUSY BIT(0) + +#define GE2D_STATUS1 GE2D_REG(0x05) + +#define GE2D_WR_DST1_STATUS GENMASK(29, 16) +#define GE2D_RD_SRC2_FIFO_EMPTY BIT(15) +#define GE2D_RD_SRC2_FIFO_OVERFLOW BIT(14) +#define GE2D_RD_SRC2_STATE_Y GENMASK(13, 12) +#define GE2D_RD_SRC2_WIN_ERR BIT(11) +#define GE2D_RD_SRC2_CMD_BUSY BIT(10) +#define GE2D_RD_SRC1_FIFO_EMPTY BIT(9) +#define GE2D_RD_SRC1_FIFO_OVERFLOW BIT(8) +#define GE2D_RD_SRC1_STATE_CR GENMASK(7, 6) +#define GE2D_RD_SRC1_STATE_CB GENMASK(5, 4) +#define GE2D_RD_SRC1_STATE_Y GENMASK(3, 2) +#define GE2D_RD_SRC1_WIN_ERR BIT(1) +#define GE2D_RD_SRC1_CMD_BUSY BIT(0) + +#define GE2D_SRC1_DEF_COLOR GE2D_REG(0x06) + +#define GE2D_COLOR_R_Y GENMASK(31, 24) +#define GE2D_COLOR_B_CB GENMASK(23, 16) +#define GE2D_COLOR_B_CR GENMASK(15, 8) +#define GE2D_COLOR_ALPHA GENMASK(7, 0) + +#define GE2D_SRC1_CLIPX_START_END GE2D_REG(0x07) + +#define GE2D_START_EXTRA BIT(31) /* For GE2D_SRC1_CLIPX/Y_START_END */ +#define GE2D_START_EXTRA0 BIT(30) /* For GE2D_SRC1_X/Y_START_END */ +#define GE2D_START GENMASK(28, 16) +#define GE2D_END_EXTRA BIT(15) /* For GE2D_SRC1_CLIPX/Y_START_END */ +#define GE2D_END_EXTRA0 BIT(14) /* For GE2D_SRC1_X/Y_START_END */ +#define GE2D_END GENMASK(12, 0) + +#define GE2D_SRC1_CLIPY_START_END GE2D_REG(0x08) +#define GE2D_SRC1_CANVAS GE2D_REG(0x09) + +#define GE2D_SRC1_CANVAS_ADDR GENMASK(31, 24) + +#define GE2D_SRC1_X_START_END GE2D_REG(0x0a) +#define GE2D_SRC1_Y_START_END GE2D_REG(0x0b) +#define GE2D_SRC1_LUT_ADDR GE2D_REG(0x0c) + +#define GE2D_LUT_READ BIT(8) +#define GE2D_LUT_ADDR GENMASK(7, 0) + +#define GE2D_SRC1_LUT_DAT GE2D_REG(0x0d) +#define GE2D_SRC1_FMT_CTRL GE2D_REG(0x0e) +#define GE2D_SRC2_DEF_COLOR GE2D_REG(0x0f) +#define GE2D_SRC2_CLIPX_START_END GE2D_REG(0x10) +#define GE2D_SRC2_CLIPY_START_END GE2D_REG(0x11) +#define GE2D_SRC2_X_START_END GE2D_REG(0x12) +#define GE2D_SRC2_Y_START_END GE2D_REG(0x13) +#define GE2D_DST_CLIPX_START_END GE2D_REG(0x14) +#define GE2D_DST_CLIPY_START_END GE2D_REG(0x15) +#define GE2D_DST_X_START_END GE2D_REG(0x16) +#define GE2D_DST_Y_START_END GE2D_REG(0x17) +#define GE2D_SRC2_DST_CANVAS GE2D_REG(0x18) + +#define GE2D_DST2_CANVAS_ADDR GENMASK(23, 16) +#define GE2D_SRC2_CANVAS_ADDR GENMASK(15, 8) +#define GE2D_DST1_CANVAS_ADDR GENMASK(7, 0) + +#define GE2D_VSC_START_PHASE_STEP GE2D_REG(0x19) +#define GE2D_VSC_PHASE_SLOPE GE2D_REG(0x1a) +#define GE2D_VSC_INI_CTRL GE2D_REG(0x1b) +#define GE2D_HSC_START_PHASE_STEP GE2D_REG(0x1c) +#define GE2D_HSC_PHASE_SLOPE GE2D_REG(0x1d) +#define GE2D_HSC_INI_CTRL GE2D_REG(0x1e) +#define GE2D_HSC_ADV_CTRL GE2D_REG(0x1f) +#define GE2D_SC_MISC_CTRL GE2D_REG(0x20) +#define GE2D_VSC_NRND_POINT GE2D_REG(0x21) +#define GE2D_VSC_NRND_PHASE GE2D_REG(0x22) +#define GE2D_HSC_NRND_POINT GE2D_REG(0x23) +#define GE2D_HSC_NRND_PHASE GE2D_REG(0x24) +#define GE2D_MATRIX_PRE_OFFSET GE2D_REG(0x25) +#define GE2D_MATRIX_COEF00_01 GE2D_REG(0x26) +#define GE2D_MATRIX_COEF02_10 GE2D_REG(0x27) +#define GE2D_MATRIX_COEF11_12 GE2D_REG(0x28) +#define GE2D_MATRIX_COEF20_21 GE2D_REG(0x29) +#define GE2D_MATRIX_COEF22_CTRL GE2D_REG(0x2a) +#define GE2D_MATRIX_OFFSET GE2D_REG(0x2b) +#define GE2D_ALU_OP_CTRL GE2D_REG(0x2c) + +#define GE2D_SRC1_COLOR_MULT_ALPHA_SEL GENMASK(26, 25) +#define GE2D_SRC2_COLOR_MULT_ALPHA_SEL BIT(24) +#define GE2D_ALU_BLEND_MODE GENMASK(22, 20) + +#define OPERATION_ADD 0 /* Cd = Cs*Fs+Cd*Fd */ +#define OPERATION_SUB 1 /* Cd = Cs*Fs-Cd*Fd */ +#define OPERATION_REVERSE_SUB 2 /* Cd = Cd*Fd-Cs*Fs */ +#define OPERATION_MIN 3 /* Cd = Min(Cd*Fd,Cs*Fs) */ +#define OPERATION_MAX 4 /* Cd = Max(Cd*Fd,Cs*Fs) */ +#define OPERATION_LOGIC 5 + +#define GE2D_ALU_SRC_COLOR_BLEND_FACTOR GENMASK(19, 16) +#define GE2D_ALU_DST_COLOR_BLEND_FACTOR GENMASK(15, 12) + +#define COLOR_FACTOR_ZERO 0 +#define COLOR_FACTOR_ONE 1 +#define COLOR_FACTOR_SRC_COLOR 2 +#define COLOR_FACTOR_ONE_MINUS_SRC_COLOR 3 +#define COLOR_FACTOR_DST_COLOR 4 +#define COLOR_FACTOR_ONE_MINUS_DST_COLOR 5 +#define COLOR_FACTOR_SRC_ALPHA 6 +#define COLOR_FACTOR_ONE_MINUS_SRC_ALPHA 7 +#define COLOR_FACTOR_DST_ALPHA 8 +#define COLOR_FACTOR_ONE_MINUS_DST_ALPHA 9 +#define COLOR_FACTOR_CONST_COLOR 10 +#define COLOR_FACTOR_ONE_MINUS_CONST_COLOR 11 +#define COLOR_FACTOR_CONST_ALPHA 12 +#define COLOR_FACTOR_ONE_MINUS_CONST_ALPHA 13 +#define COLOR_FACTOR_SRC_ALPHA_SATURATE 14 + +#define GE2D_ALU_OPERATION_LOGIC GENMASK(15, 12) + +#define LOGIC_OPERATION_CLEAR 0 +#define LOGIC_OPERATION_COPY 1 +#define LOGIC_OPERATION_NOOP 2 +#define LOGIC_OPERATION_SET 3 +#define LOGIC_OPERATION_COPY_INVERT 4 +#define LOGIC_OPERATION_INVERT 5 +#define LOGIC_OPERATION_AND_REVERSE 6 +#define LOGIC_OPERATION_OR_REVERSE 7 +#define LOGIC_OPERATION_AND 8 +#define LOGIC_OPERATION_OR 9 +#define LOGIC_OPERATION_NAND 10 +#define LOGIC_OPERATION_NOR 11 +#define LOGIC_OPERATION_XOR 12 +#define LOGIC_OPERATION_EQUIV 13 +#define LOGIC_OPERATION_AND_INVERT 14 +#define LOGIC_OPERATION_OR_INVERT 15 + +#define GE2D_ALU_ALPHA_BLEND_MODE GENMASK(10, 8) +#define GE2D_ALU_SRC_ALPHA_BLEND_FACTOR GENMASK(7, 4) +#define GE2D_ALU_DST_ALPHA_BLEND_FACTOR GENMASK(3, 0) + +#define ALPHA_FACTOR_ZERO 0 +#define ALPHA_FACTOR_ONE 1 +#define ALPHA_FACTOR_SRC_ALPHA 2 +#define ALPHA_FACTOR_ONE_MINUS_SRC_ALPHA 3 +#define ALPHA_FACTOR_DST_ALPHA 4 +#define ALPHA_FACTOR_ONE_MINUS_DST_ALPHA 5 +#define ALPHA_FACTOR_CONST_ALPHA 6 +#define ALPHA_FACTOR_ONE_MINUS_CONST_ALPHA 7 + +#define GE2D_ALU_ALPHA_OPERATION_LOGIC GENMASK(3, 0) + +#define GE2D_ALU_COLOR_OP(__op, __src_factor, __dst_factor) \ + (FIELD_PREP(GE2D_ALU_BLEND_MODE, __op) | \ + FIELD_PREP(GE2D_ALU_SRC_COLOR_BLEND_FACTOR, __src_factor) | \ + FIELD_PREP(GE2D_ALU_DST_COLOR_BLEND_FACTOR, __dst_factor)) + +#define GE2D_ALU_DO_COLOR_OPERATION_LOGIC(__op, __src_factor) \ + GE2D_ALU_COLOR_OP(OPERATION_LOGIC, __src_factor, __op) + +#define GE2D_ALU_ALPHA_OP(__op, __src_factor, __dst_factor) \ + (FIELD_PREP(GE2D_ALU_ALPHA_BLEND_MODE, __op) | \ + FIELD_PREP(GE2D_ALU_SRC_ALPHA_BLEND_FACTOR, __src_factor) | \ + FIELD_PREP(GE2D_ALU_DST_ALPHA_BLEND_FACTOR, __dst_factor)) + +#define GE2D_ALU_DO_ALPHA_OPERATION_LOGIC(__op, __src_factor) \ + GE2D_ALU_ALPHA_OP(OPERATION_LOGIC, __src_factor, __op) + +#define GE2D_ALU_CONST_COLOR GE2D_REG(0x2d) +#define GE2D_SRC1_KEY GE2D_REG(0x2e) +#define GE2D_SRC1_KEY_MASK GE2D_REG(0x2f) +#define GE2D_SRC2_KEY GE2D_REG(0x30) +#define GE2D_SRC2_KEY_MASK GE2D_REG(0x31) +#define GE2D_DST_BITMASK GE2D_REG(0x32) +#define GE2D_DP_ONOFF_CTRL GE2D_REG(0x33) +#define GE2D_SCALE_COEF_IDX GE2D_REG(0x34) +#define GE2D_SCALE_COEF GE2D_REG(0x35) +#define GE2D_SRC_OUTSIDE_ALPHA GE2D_REG(0x36) +#define GE2D_ANTIFLICK_CTRL0 GE2D_REG(0x38) +#define GE2D_ANTIFLICK_CTRL1 GE2D_REG(0x39) +#define GE2D_ANTIFLICK_COLOR_FILT0 GE2D_REG(0x3a) +#define GE2D_ANTIFLICK_COLOR_FILT1 GE2D_REG(0x3b) +#define GE2D_ANTIFLICK_COLOR_FILT2 GE2D_REG(0x3c) +#define GE2D_ANTIFLICK_COLOR_FILT3 GE2D_REG(0x3d) +#define GE2D_ANTIFLICK_ALPHA_FILT0 GE2D_REG(0x3e) +#define GE2D_ANTIFLICK_ALPHA_FILT1 GE2D_REG(0x3f) +#define GE2D_ANTIFLICK_ALPHA_FILT2 GE2D_REG(0x40) +#define GE2D_ANTIFLICK_ALPHA_FILT3 GE2D_REG(0x41) +#define GE2D_SRC1_RANGE_MAP_Y_CTRL GE2D_REG(0x43) +#define GE2D_SRC1_RANGE_MAP_CB_CTRL GE2D_REG(0x44) +#define GE2D_SRC1_RANGE_MAP_CR_CTRL GE2D_REG(0x45) +#define GE2D_ARB_BURST_NUM GE2D_REG(0x46) +#define GE2D_TID_TOKEN GE2D_REG(0x47) +#define GE2D_GEN_CTRL3 GE2D_REG(0x48) + +#define GE2D_DST2_BYTEMASK_VAL GENMASK(31, 28) +#define GE2D_DST2_PIC_STRUCT GENMASK(27, 26) +#define GE2D_DST2_8B_MODE_SEL GENMASK(25, 24) +#define GE2D_DST2_COLOR_MAP GENMASK(22, 19) +#define GE2D_DST2_FORMAT GENMASK(17, 16) +#define GE2D_DST2_COLOR_ROUND_MODE BIT(14) +#define GE2D_DST2_X_DISCARD_MODE GENMASK(13, 12) +#define GE2D_DST2_Y_DISCARD_MODE GENMASK(11, 10) +#define GE2D_DST2_ENABLE BIT(8) +#define GE2D_DST1_X_DISCARD_MODE GENMASK(5, 4) +#define GE2D_DST1_Y_DISCARD_MODE GENMASK(3, 2) +#define GE2D_DST1_ENABLE BIT(0) + +#define GE2D_STATUS2 GE2D_REG(0x49) +#define GE2D_GEN_CTRL4 GE2D_REG(0x4a) +#define GE2D_DST1_BADDR_CTRL GE2D_REG(0x51) +#define GE2D_DST1_STRIDE_CTRL GE2D_REG(0x52) + +#define GE2D_STRIDE_SIZE GENMASK(19, 0) + +#define GE2D_SRC1_BADDR_CTRL GE2D_REG(0x53) +#define GE2D_SRC1_STRIDE_CTRL GE2D_REG(0x54) +#define GE2D_SRC2_BADDR_CTRL GE2D_REG(0x55) +#define GE2D_SRC2_STRIDE_CTRL GE2D_REG(0x56) + +#endif /* __GE2D_REGS__ */ diff --git a/drivers/media/platform/meson/ge2d/ge2d.c b/drivers/media/platform/meson/ge2d/ge2d.c new file mode 100644 index 000000000000..f526501bd473 --- /dev/null +++ b/drivers/media/platform/meson/ge2d/ge2d.c @@ -0,0 +1,1067 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 BayLibre, SAS + * Author: Neil Armstrong + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ge2d-regs.h" + +#define GE2D_NAME "meson-ge2d" + +#define DEFAULT_WIDTH 128 +#define DEFAULT_HEIGHT 128 +#define DEFAULT_STRIDE 512 + +#define MAX_WIDTH 8191 +#define MAX_HEIGHT 8191 + +/* + * Missing features: + * - Scaling + * - Simple 1/2 vertical scaling + * - YUV input support + * - Source global alpha + * - Colorspace conversion + */ + +struct ge2d_fmt { + u32 fourcc; + bool alpha; + bool le; + unsigned int depth; + unsigned int hw_fmt; + unsigned int hw_map; +}; + +struct ge2d_frame { + struct vb2_v4l2_buffer *buf; + + /* Image Format */ + struct v4l2_pix_format pix_fmt; + + /* Crop */ + struct v4l2_rect crop; + + /* Image format */ + const struct ge2d_fmt *fmt; +}; + +struct ge2d_ctx { + struct v4l2_fh fh; + struct meson_ge2d *ge2d; + struct ge2d_frame in; + struct ge2d_frame out; + struct v4l2_ctrl_handler ctrl_handler; + + unsigned long sequence_out, sequence_cap; + + /* Control values */ + u32 hflip; + u32 vflip; + u32 xy_swap; +}; + +struct meson_ge2d { + struct v4l2_device v4l2_dev; + struct v4l2_m2m_dev *m2m_dev; + struct video_device *vfd; + + struct device *dev; + struct regmap *map; + struct clk *clk; + + /* vb2 queue lock */ + struct mutex mutex; + + struct ge2d_ctx *curr; +}; + +#define FMT(_fourcc, _alpha, _depth, _map) \ +{ \ + .fourcc = _fourcc, \ + .alpha = (_alpha), \ + .depth = (_depth), \ + .hw_fmt = GE2D_FORMAT_ ## _depth ## BIT, \ + .hw_map = GE2D_COLOR_MAP_ ## _map, \ +} + +/* TOFIX Handle the YUV input formats */ +static const struct ge2d_fmt formats[] = { + /* FOURCC Alpha HW FMT HW MAP */ + FMT(V4L2_PIX_FMT_XRGB32, false, 32, BGRA8888), + FMT(V4L2_PIX_FMT_RGB32, true, 32, BGRA8888), + FMT(V4L2_PIX_FMT_ARGB32, true, 32, BGRA8888), + FMT(V4L2_PIX_FMT_RGBX32, false, 32, ABGR8888), + FMT(V4L2_PIX_FMT_RGBA32, true, 32, ABGR8888), + FMT(V4L2_PIX_FMT_BGRX32, false, 32, RGBA8888), + FMT(V4L2_PIX_FMT_BGRA32, true, 32, RGBA8888), + FMT(V4L2_PIX_FMT_BGR32, true, 32, ARGB8888), + FMT(V4L2_PIX_FMT_ABGR32, true, 32, ARGB8888), + FMT(V4L2_PIX_FMT_XBGR32, false, 32, ARGB8888), + + FMT(V4L2_PIX_FMT_RGB24, false, 24, BGR888), + FMT(V4L2_PIX_FMT_BGR24, false, 24, RGB888), + + FMT(V4L2_PIX_FMT_XRGB555X, false, 16, ARGB1555), + FMT(V4L2_PIX_FMT_ARGB555X, true, 16, ARGB1555), + FMT(V4L2_PIX_FMT_RGB565, false, 16, RGB565), + FMT(V4L2_PIX_FMT_RGBX444, false, 16, RGBA4444), + FMT(V4L2_PIX_FMT_RGBA444, true, 16, RGBA4444), + FMT(V4L2_PIX_FMT_XRGB444, false, 16, ARGB4444), + FMT(V4L2_PIX_FMT_ARGB444, true, 16, ARGB4444), +}; + +#define NUM_FORMATS ARRAY_SIZE(formats) + +static const struct ge2d_fmt *find_fmt(struct v4l2_format *f) +{ + unsigned int i; + + for (i = 0; i < NUM_FORMATS; i++) { + if (formats[i].fourcc == f->fmt.pix.pixelformat) + return &formats[i]; + } + + /* + * TRY_FMT/S_FMT should never return an error when the requested format + * is not supported. Drivers should always return a valid format, + * preferably a format that is as widely supported by applications as + * possible. + */ + return &formats[0]; +} + +static struct ge2d_frame *get_frame(struct ge2d_ctx *ctx, + enum v4l2_buf_type type) +{ + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + return &ctx->in; + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return &ctx->out; + default: + /* This should never happen, warn and return OUTPUT frame */ + dev_warn(ctx->ge2d->dev, "%s: invalid buffer type\n", __func__); + return &ctx->in; + } +} + +static void ge2d_hw_start(struct meson_ge2d *ge2d) +{ + struct ge2d_ctx *ctx = ge2d->curr; + u32 reg; + + /* Reset */ + regmap_update_bits(ge2d->map, GE2D_GEN_CTRL1, + GE2D_SOFT_RST, GE2D_SOFT_RST); + regmap_update_bits(ge2d->map, GE2D_GEN_CTRL1, + GE2D_SOFT_RST, 0); + + usleep_range(100, 200); + + /* Implement CANVAS for non-AXG */ + regmap_write(ge2d->map, GE2D_SRC1_BADDR_CTRL, + (vb2_dma_contig_plane_dma_addr(&ctx->in.buf->vb2_buf, 0) + 7) >> 3); + regmap_write(ge2d->map, GE2D_SRC1_STRIDE_CTRL, + (ctx->in.pix_fmt.bytesperline + 7) >> 3); + regmap_write(ge2d->map, GE2D_SRC2_BADDR_CTRL, + (vb2_dma_contig_plane_dma_addr(&ctx->out.buf->vb2_buf, 0) + 7) >> 3); + regmap_write(ge2d->map, GE2D_SRC2_STRIDE_CTRL, + (ctx->out.pix_fmt.bytesperline + 7) >> 3); + regmap_write(ge2d->map, GE2D_DST1_BADDR_CTRL, + (vb2_dma_contig_plane_dma_addr(&ctx->out.buf->vb2_buf, 0) + 7) >> 3); + regmap_write(ge2d->map, GE2D_DST1_STRIDE_CTRL, + (ctx->out.pix_fmt.bytesperline + 7) >> 3); + + regmap_write(ge2d->map, GE2D_GEN_CTRL0, 0); + regmap_write(ge2d->map, GE2D_GEN_CTRL1, + FIELD_PREP(GE2D_INTERRUPT_CTRL, 2) | + FIELD_PREP(GE2D_SRC2_BURST_SIZE_CTRL, 3) | + FIELD_PREP(GE2D_SRC1_BURST_SIZE_CTRL, 0x3f)); + + regmap_write(ge2d->map, GE2D_GEN_CTRL2, + GE2D_SRC1_LITTLE_ENDIAN | + GE2D_SRC2_LITTLE_ENDIAN | + GE2D_DST_LITTLE_ENDIAN | + FIELD_PREP(GE2D_DST1_COLOR_MAP, ctx->out.fmt->hw_map) | + FIELD_PREP(GE2D_DST1_FORMAT, ctx->out.fmt->hw_fmt) | + FIELD_PREP(GE2D_SRC2_COLOR_MAP, ctx->out.fmt->hw_map) | + FIELD_PREP(GE2D_SRC2_FORMAT, ctx->out.fmt->hw_fmt) | + FIELD_PREP(GE2D_SRC1_COLOR_MAP, ctx->in.fmt->hw_map) | + FIELD_PREP(GE2D_SRC1_FORMAT, ctx->in.fmt->hw_fmt)); + regmap_write(ge2d->map, GE2D_GEN_CTRL3, + GE2D_DST1_ENABLE); + + regmap_write(ge2d->map, GE2D_SRC1_CLIPY_START_END, + FIELD_PREP(GE2D_START, ctx->in.crop.top) | + FIELD_PREP(GE2D_END, ctx->in.crop.top + ctx->in.crop.height)); + regmap_write(ge2d->map, GE2D_SRC1_CLIPX_START_END, + FIELD_PREP(GE2D_START, ctx->in.crop.left) | + FIELD_PREP(GE2D_END, ctx->in.crop.left + ctx->in.crop.width)); + regmap_write(ge2d->map, GE2D_SRC2_CLIPY_START_END, + FIELD_PREP(GE2D_START, ctx->out.crop.top) | + FIELD_PREP(GE2D_END, ctx->out.crop.top + ctx->out.crop.height)); + regmap_write(ge2d->map, GE2D_SRC2_CLIPX_START_END, + FIELD_PREP(GE2D_START, ctx->out.crop.left) | + FIELD_PREP(GE2D_END, ctx->out.crop.left + ctx->out.crop.width)); + regmap_write(ge2d->map, GE2D_DST_CLIPY_START_END, + FIELD_PREP(GE2D_START, ctx->out.crop.top) | + FIELD_PREP(GE2D_END, ctx->out.crop.top + ctx->out.crop.height)); + regmap_write(ge2d->map, GE2D_DST_CLIPX_START_END, + FIELD_PREP(GE2D_START, ctx->out.crop.left) | + FIELD_PREP(GE2D_END, ctx->out.crop.left + ctx->out.crop.width)); + + regmap_write(ge2d->map, GE2D_SRC1_Y_START_END, + FIELD_PREP(GE2D_END, ctx->in.pix_fmt.height)); + regmap_write(ge2d->map, GE2D_SRC1_X_START_END, + FIELD_PREP(GE2D_END, ctx->in.pix_fmt.width)); + regmap_write(ge2d->map, GE2D_SRC2_Y_START_END, + FIELD_PREP(GE2D_END, ctx->out.pix_fmt.height)); + regmap_write(ge2d->map, GE2D_SRC2_X_START_END, + FIELD_PREP(GE2D_END, ctx->out.pix_fmt.width)); + regmap_write(ge2d->map, GE2D_DST_Y_START_END, + FIELD_PREP(GE2D_END, ctx->out.pix_fmt.height)); + regmap_write(ge2d->map, GE2D_DST_X_START_END, + FIELD_PREP(GE2D_END, ctx->out.pix_fmt.width)); + + /* Color, no blend, use source color */ + reg = GE2D_ALU_DO_COLOR_OPERATION_LOGIC(LOGIC_OPERATION_COPY, + COLOR_FACTOR_SRC_COLOR); + + if (ctx->in.fmt->alpha && ctx->out.fmt->alpha) + /* Take source alpha */ + reg |= GE2D_ALU_DO_ALPHA_OPERATION_LOGIC(LOGIC_OPERATION_COPY, + COLOR_FACTOR_SRC_ALPHA); + else if (!ctx->out.fmt->alpha) + /* Set alpha to 0 */ + reg |= GE2D_ALU_DO_ALPHA_OPERATION_LOGIC(LOGIC_OPERATION_SET, + COLOR_FACTOR_ZERO); + else + /* Keep original alpha */ + reg |= GE2D_ALU_DO_ALPHA_OPERATION_LOGIC(LOGIC_OPERATION_COPY, + COLOR_FACTOR_DST_ALPHA); + + regmap_write(ge2d->map, GE2D_ALU_OP_CTRL, reg); + + /* Start */ + regmap_write(ge2d->map, GE2D_CMD_CTRL, + (ctx->xy_swap ? GE2D_DST_XY_SWAP : 0) | + (ctx->hflip ? GE2D_SRC1_Y_REV : 0) | + (ctx->vflip ? GE2D_SRC1_X_REV : 0) | + GE2D_CBUS_CMD_WR); +} + +static void device_run(void *priv) +{ + struct ge2d_ctx *ctx = priv; + struct meson_ge2d *ge2d = ctx->ge2d; + + ge2d->curr = ctx; + + ctx->in.buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + ctx->out.buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + + ge2d_hw_start(ge2d); +} + +static irqreturn_t ge2d_isr(int irq, void *priv) +{ + struct meson_ge2d *ge2d = priv; + u32 intr; + + regmap_read(ge2d->map, GE2D_STATUS0, &intr); + + if (!(intr & GE2D_GE2D_BUSY)) { + struct vb2_v4l2_buffer *src, *dst; + struct ge2d_ctx *ctx = ge2d->curr; + + ge2d->curr = NULL; + + src = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + dst = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + + src->sequence = ctx->sequence_out++; + dst->sequence = ctx->sequence_cap++; + + dst->timecode = src->timecode; + dst->vb2_buf.timestamp = src->vb2_buf.timestamp; + dst->flags = src->flags; + + v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE); + v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE); + v4l2_m2m_job_finish(ge2d->m2m_dev, ctx->fh.m2m_ctx); + } + + return IRQ_HANDLED; +} + +static const struct v4l2_m2m_ops ge2d_m2m_ops = { + .device_run = device_run, +}; + +static int ge2d_queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], struct device *alloc_devs[]) +{ + struct ge2d_ctx *ctx = vb2_get_drv_priv(vq); + struct ge2d_frame *f = get_frame(ctx, vq->type); + + if (*nplanes) + return sizes[0] < f->pix_fmt.sizeimage ? -EINVAL : 0; + + sizes[0] = f->pix_fmt.sizeimage; + *nplanes = 1; + + return 0; +} + +static int ge2d_buf_prepare(struct vb2_buffer *vb) +{ + struct ge2d_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct ge2d_frame *f = get_frame(ctx, vb->vb2_queue->type); + + vbuf->field = V4L2_FIELD_NONE; + + vb2_set_plane_payload(vb, 0, f->pix_fmt.sizeimage); + + return 0; +} + +static void ge2d_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct ge2d_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); +} + +static int ge2d_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct ge2d_ctx *ctx = vb2_get_drv_priv(vq); + + if (V4L2_TYPE_IS_OUTPUT(vq->type)) + ctx->sequence_out = 0; + else + ctx->sequence_cap = 0; + + return 0; +} + +static void ge2d_stop_streaming(struct vb2_queue *vq) +{ + struct ge2d_ctx *ctx = vb2_get_drv_priv(vq); + struct vb2_v4l2_buffer *vbuf; + + for (;;) { + if (V4L2_TYPE_IS_OUTPUT(vq->type)) + vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + else + vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + if (!vbuf) + break; + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); + } +} + +static const struct vb2_ops ge2d_qops = { + .queue_setup = ge2d_queue_setup, + .buf_prepare = ge2d_buf_prepare, + .buf_queue = ge2d_buf_queue, + .start_streaming = ge2d_start_streaming, + .stop_streaming = ge2d_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static int +queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) +{ + struct ge2d_ctx *ctx = priv; + int ret; + + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->drv_priv = ctx; + src_vq->ops = &ge2d_qops; + src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->lock = &ctx->ge2d->mutex; + src_vq->dev = ctx->ge2d->v4l2_dev.dev; + + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; + dst_vq->drv_priv = ctx; + dst_vq->ops = &ge2d_qops; + dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->lock = &ctx->ge2d->mutex; + dst_vq->dev = ctx->ge2d->v4l2_dev.dev; + + return vb2_queue_init(dst_vq); +} + +static int +vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) +{ + strscpy(cap->driver, GE2D_NAME, sizeof(cap->driver)); + strscpy(cap->card, GE2D_NAME, sizeof(cap->card)); + strscpy(cap->bus_info, "platform:" GE2D_NAME, sizeof(cap->bus_info)); + + return 0; +} + +static int vidioc_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) +{ + const struct ge2d_fmt *fmt; + + if (f->index >= NUM_FORMATS) + return -EINVAL; + + fmt = &formats[f->index]; + f->pixelformat = fmt->fourcc; + + return 0; +} + +static int vidioc_g_selection(struct file *file, void *priv, + struct v4l2_selection *s) +{ + struct ge2d_ctx *ctx = priv; + struct ge2d_frame *f; + bool use_frame = false; + + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && + s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + f = get_frame(ctx, s->type); + + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + break; + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + break; + case V4L2_SEL_TGT_COMPOSE: + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + use_frame = true; + break; + case V4L2_SEL_TGT_CROP: + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + use_frame = true; + break; + default: + return -EINVAL; + } + + if (use_frame) { + s->r = f->crop; + } else { + s->r.left = 0; + s->r.top = 0; + s->r.width = f->pix_fmt.width; + s->r.height = f->pix_fmt.height; + } + + return 0; +} + +static int vidioc_s_selection(struct file *file, void *priv, + struct v4l2_selection *s) +{ + struct ge2d_ctx *ctx = priv; + struct meson_ge2d *ge2d = ctx->ge2d; + struct ge2d_frame *f; + int ret = 0; + + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && + s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + f = get_frame(ctx, s->type); + + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE: + /* + * COMPOSE target is only valid for capture buffer type, return + * error for output buffer type + */ + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + break; + case V4L2_SEL_TGT_CROP: + /* + * CROP target is only valid for output buffer type, return + * error for capture buffer type + */ + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + break; + /* + * bound and default crop/compose targets are invalid targets to + * try/set + */ + default: + return -EINVAL; + } + + if (s->r.top < 0 || s->r.left < 0) { + v4l2_err(&ge2d->v4l2_dev, + "doesn't support negative values for top & left.\n"); + return -EINVAL; + } + + if (s->r.left + s->r.width > f->pix_fmt.width || + s->r.top + s->r.height > f->pix_fmt.height) { + v4l2_err(&ge2d->v4l2_dev, "unsupported rectangle value.\n"); + return -EINVAL; + } + + f->crop = s->r; + + return ret; +} + +static void vidioc_setup_cap_fmt(struct ge2d_ctx *ctx, struct v4l2_pix_format *f) +{ + struct ge2d_frame *frm_out = get_frame(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + + *f = frm_out->pix_fmt; + + if (ctx->xy_swap) { + f->width = frm_out->pix_fmt.height; + f->height = frm_out->pix_fmt.width; + } +} + +static int vidioc_try_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) +{ + const struct ge2d_fmt *fmt = find_fmt(f); + struct ge2d_ctx *ctx = priv; + struct v4l2_pix_format fmt_cap; + + vidioc_setup_cap_fmt(ctx, &fmt_cap); + + fmt_cap.pixelformat = fmt->fourcc; + + fmt_cap.bytesperline = max(f->fmt.pix.bytesperline, + ALIGN((fmt_cap.width * fmt->depth) >> 3, 8)); + + fmt_cap.sizeimage = max(f->fmt.pix.sizeimage, + fmt_cap.height * fmt_cap.bytesperline); + + f->fmt.pix = fmt_cap; + + return 0; +} + +static int vidioc_s_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) +{ + struct ge2d_ctx *ctx = priv; + struct meson_ge2d *ge2d = ctx->ge2d; + struct vb2_queue *vq; + struct ge2d_frame *frm; + int ret = 0; + + /* Adjust all values accordingly to the hardware capabilities + * and chosen format. + */ + ret = vidioc_try_fmt_cap(file, priv, f); + if (ret) + return ret; + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (vb2_is_busy(vq)) { + v4l2_err(&ge2d->v4l2_dev, "queue (%d) bust\n", f->type); + return -EBUSY; + } + + frm = get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + + frm->pix_fmt = f->fmt.pix; + frm->fmt = find_fmt(f); + f->fmt.pix.pixelformat = frm->fmt->fourcc; + + /* Reset crop settings */ + frm->crop.left = 0; + frm->crop.top = 0; + frm->crop.width = frm->pix_fmt.width; + frm->crop.height = frm->pix_fmt.height; + + return 0; +} + +static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct ge2d_ctx *ctx = priv; + struct vb2_queue *vq; + struct ge2d_frame *frm; + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (!vq) + return -EINVAL; + + frm = get_frame(ctx, f->type); + + f->fmt.pix = frm->pix_fmt; + f->fmt.pix.pixelformat = frm->fmt->fourcc; + + return 0; +} + +static int vidioc_try_fmt_out(struct file *file, void *priv, struct v4l2_format *f) +{ + const struct ge2d_fmt *fmt = find_fmt(f); + + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.pixelformat = fmt->fourcc; + + if (f->fmt.pix.width > MAX_WIDTH) + f->fmt.pix.width = MAX_WIDTH; + if (f->fmt.pix.height > MAX_HEIGHT) + f->fmt.pix.height = MAX_HEIGHT; + + f->fmt.pix.bytesperline = max(f->fmt.pix.bytesperline, + ALIGN((f->fmt.pix.width * fmt->depth) >> 3, 8)); + + f->fmt.pix.sizeimage = max(f->fmt.pix.sizeimage, + f->fmt.pix.height * f->fmt.pix.bytesperline); + + return 0; +} + +static int vidioc_s_fmt_out(struct file *file, void *priv, struct v4l2_format *f) +{ + struct ge2d_ctx *ctx = priv; + struct meson_ge2d *ge2d = ctx->ge2d; + struct vb2_queue *vq; + struct ge2d_frame *frm, *frm_cap; + int ret = 0; + + /* Adjust all values accordingly to the hardware capabilities + * and chosen format. + */ + ret = vidioc_try_fmt_out(file, priv, f); + if (ret) + return ret; + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (vb2_is_busy(vq)) { + v4l2_err(&ge2d->v4l2_dev, "queue (%d) bust\n", f->type); + return -EBUSY; + } + + frm = get_frame(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + frm_cap = get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + + frm->pix_fmt = f->fmt.pix; + frm->fmt = find_fmt(f); + f->fmt.pix.pixelformat = frm->fmt->fourcc; + + /* Reset crop settings */ + frm->crop.left = 0; + frm->crop.top = 0; + frm->crop.width = frm->pix_fmt.width; + frm->crop.height = frm->pix_fmt.height; + + /* Propagate settings to capture */ + vidioc_setup_cap_fmt(ctx, &frm_cap->pix_fmt); + + return 0; +} + +static const struct v4l2_ioctl_ops ge2d_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_cap, + + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt, + .vidioc_g_fmt_vid_out = vidioc_g_fmt, + .vidioc_try_fmt_vid_out = vidioc_try_fmt_out, + .vidioc_s_fmt_vid_out = vidioc_s_fmt_out, + + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + + .vidioc_g_selection = vidioc_g_selection, + .vidioc_s_selection = vidioc_s_selection, +}; + +static int ge2d_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ge2d_ctx *ctx = container_of(ctrl->handler, struct ge2d_ctx, + ctrl_handler); + struct v4l2_pix_format fmt; + struct vb2_queue *vq; + + switch (ctrl->id) { + case V4L2_CID_HFLIP: + ctx->hflip = ctrl->val; + break; + case V4L2_CID_VFLIP: + ctx->vflip = ctrl->val; + break; + case V4L2_CID_ROTATE: + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (vb2_is_busy(vq)) + return -EBUSY; + + if (ctrl->val == 90) { + ctx->hflip = 0; + ctx->vflip = 0; + ctx->xy_swap = 1; + } else if (ctrl->val == 180) { + ctx->hflip = 1; + ctx->vflip = 1; + ctx->xy_swap = 0; + } else if (ctrl->val == 270) { + ctx->hflip = 1; + ctx->vflip = 1; + ctx->xy_swap = 1; + } else { + ctx->hflip = 0; + ctx->vflip = 0; + ctx->xy_swap = 0; + } + + vidioc_setup_cap_fmt(ctx, &fmt); + + /* + * If the rotation parameter changes the OUTPUT frames + * parameters, take them in account + */ + if (fmt.width != ctx->out.pix_fmt.width || + fmt.height != ctx->out.pix_fmt.width || + fmt.bytesperline > ctx->out.pix_fmt.bytesperline || + fmt.sizeimage > ctx->out.pix_fmt.sizeimage) + ctx->out.pix_fmt = fmt; + + break; + } + + return 0; +} + +static const struct v4l2_ctrl_ops ge2d_ctrl_ops = { + .s_ctrl = ge2d_s_ctrl, +}; + +static int ge2d_setup_ctrls(struct ge2d_ctx *ctx) +{ + struct meson_ge2d *ge2d = ctx->ge2d; + + v4l2_ctrl_handler_init(&ctx->ctrl_handler, 4); + + v4l2_ctrl_new_std(&ctx->ctrl_handler, &ge2d_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + + v4l2_ctrl_new_std(&ctx->ctrl_handler, &ge2d_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + + v4l2_ctrl_new_std(&ctx->ctrl_handler, &ge2d_ctrl_ops, + V4L2_CID_ROTATE, 0, 270, 90, 0); + + if (ctx->ctrl_handler.error) { + int err = ctx->ctrl_handler.error; + + v4l2_err(&ge2d->v4l2_dev, "%s failed\n", __func__); + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + return err; + } + + return 0; +} + +static const struct ge2d_frame def_frame = { + .pix_fmt = { + .width = DEFAULT_WIDTH, + .height = DEFAULT_HEIGHT, + .bytesperline = DEFAULT_STRIDE, + .sizeimage = DEFAULT_STRIDE * DEFAULT_HEIGHT, + .field = V4L2_FIELD_NONE, + }, + .crop.width = DEFAULT_WIDTH, + .crop.height = DEFAULT_HEIGHT, + .fmt = &formats[0], +}; + +static int ge2d_open(struct file *file) +{ + struct meson_ge2d *ge2d = video_drvdata(file); + struct ge2d_ctx *ctx = NULL; + int ret = 0; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + ctx->ge2d = ge2d; + + /* Set default formats */ + ctx->in = def_frame; + ctx->out = def_frame; + + if (mutex_lock_interruptible(&ge2d->mutex)) { + kfree(ctx); + return -ERESTARTSYS; + } + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(ge2d->m2m_dev, ctx, &queue_init); + if (IS_ERR(ctx->fh.m2m_ctx)) { + ret = PTR_ERR(ctx->fh.m2m_ctx); + mutex_unlock(&ge2d->mutex); + kfree(ctx); + return ret; + } + v4l2_fh_init(&ctx->fh, video_devdata(file)); + file->private_data = &ctx->fh; + v4l2_fh_add(&ctx->fh); + + ge2d_setup_ctrls(ctx); + + /* Write the default values to the ctx struct */ + v4l2_ctrl_handler_setup(&ctx->ctrl_handler); + + ctx->fh.ctrl_handler = &ctx->ctrl_handler; + mutex_unlock(&ge2d->mutex); + + return 0; +} + +static int ge2d_release(struct file *file) +{ + struct ge2d_ctx *ctx = + container_of(file->private_data, struct ge2d_ctx, fh); + struct meson_ge2d *ge2d = ctx->ge2d; + + mutex_lock(&ge2d->mutex); + + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + kfree(ctx); + + mutex_unlock(&ge2d->mutex); + + return 0; +} + +static const struct v4l2_file_operations ge2d_fops = { + .owner = THIS_MODULE, + .open = ge2d_open, + .release = ge2d_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, +}; + +static const struct video_device ge2d_videodev = { + .name = "meson-ge2d", + .fops = &ge2d_fops, + .ioctl_ops = &ge2d_ioctl_ops, + .minor = -1, + .release = video_device_release, + .vfl_dir = VFL_DIR_M2M, + .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING, +}; + +static const struct regmap_config meson_ge2d_regmap_conf = { + .reg_bits = 8, + .val_bits = 32, + .reg_stride = 4, + .max_register = GE2D_SRC2_STRIDE_CTRL, +}; + +static int ge2d_probe(struct platform_device *pdev) +{ + struct reset_control *rst; + struct video_device *vfd; + struct meson_ge2d *ge2d; + struct resource *res; + void __iomem *regs; + int ret = 0; + int irq; + + if (!pdev->dev.of_node) + return -ENODEV; + + ge2d = devm_kzalloc(&pdev->dev, sizeof(*ge2d), GFP_KERNEL); + if (!ge2d) + return -ENOMEM; + + ge2d->dev = &pdev->dev; + mutex_init(&ge2d->mutex); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(ge2d->dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + ge2d->map = devm_regmap_init_mmio(ge2d->dev, regs, + &meson_ge2d_regmap_conf); + if (IS_ERR(ge2d->map)) + return PTR_ERR(ge2d->map); + + irq = platform_get_irq(pdev, 0); + ret = devm_request_irq(ge2d->dev, irq, ge2d_isr, 0, + dev_name(ge2d->dev), ge2d); + if (ret < 0) { + dev_err(ge2d->dev, "failed to request irq\n"); + return ret; + } + + rst = devm_reset_control_get(ge2d->dev, NULL); + if (IS_ERR(rst)) { + dev_err(ge2d->dev, "failed to get core reset controller\n"); + return PTR_ERR(rst); + } + + ge2d->clk = devm_clk_get(ge2d->dev, NULL); + if (IS_ERR(ge2d->clk)) { + dev_err(ge2d->dev, "failed to get clock\n"); + return PTR_ERR(ge2d->clk); + } + + reset_control_assert(rst); + udelay(1); + reset_control_deassert(rst); + + ret = clk_prepare_enable(ge2d->clk); + if (ret) { + dev_err(ge2d->dev, "Cannot enable ge2d sclk: %d\n", ret); + return ret; + } + + ret = v4l2_device_register(&pdev->dev, &ge2d->v4l2_dev); + if (ret) + goto disable_clks; + + vfd = video_device_alloc(); + if (!vfd) { + v4l2_err(&ge2d->v4l2_dev, "Failed to allocate video device\n"); + goto unreg_v4l2_dev; + } + + *vfd = ge2d_videodev; + vfd->lock = &ge2d->mutex; + vfd->v4l2_dev = &ge2d->v4l2_dev; + + video_set_drvdata(vfd, ge2d); + ge2d->vfd = vfd; + + platform_set_drvdata(pdev, ge2d); + ge2d->m2m_dev = v4l2_m2m_init(&ge2d_m2m_ops); + if (IS_ERR(ge2d->m2m_dev)) { + v4l2_err(&ge2d->v4l2_dev, "Failed to init mem2mem device\n"); + ret = PTR_ERR(ge2d->m2m_dev); + goto rel_vdev; + } + + ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1); + if (ret) { + v4l2_err(&ge2d->v4l2_dev, "Failed to register video device\n"); + goto rel_m2m; + } + + v4l2_info(&ge2d->v4l2_dev, "Registered %s as /dev/%s\n", + vfd->name, video_device_node_name(vfd)); + + return 0; + +rel_m2m: + v4l2_m2m_release(ge2d->m2m_dev); +rel_vdev: + video_device_release(ge2d->vfd); +unreg_v4l2_dev: + v4l2_device_unregister(&ge2d->v4l2_dev); +disable_clks: + clk_disable_unprepare(ge2d->clk); + + return ret; +} + +static int ge2d_remove(struct platform_device *pdev) +{ + struct meson_ge2d *ge2d = platform_get_drvdata(pdev); + + video_unregister_device(ge2d->vfd); + v4l2_m2m_release(ge2d->m2m_dev); + video_device_release(ge2d->vfd); + v4l2_device_unregister(&ge2d->v4l2_dev); + clk_disable_unprepare(ge2d->clk); + + return 0; +} + +static const struct of_device_id meson_ge2d_match[] = { + { + .compatible = "amlogic,axg-ge2d", + }, + {}, +}; + +MODULE_DEVICE_TABLE(of, meson_ge2d_match); + +static struct platform_driver ge2d_drv = { + .probe = ge2d_probe, + .remove = ge2d_remove, + .driver = { + .name = "meson-ge2d", + .of_match_table = meson_ge2d_match, + }, +}; + +module_platform_driver(ge2d_drv); + +MODULE_AUTHOR("Neil Armstrong "); +MODULE_DESCRIPTION("Amlogic 2D Graphic Acceleration Unit"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From aa821b2b92699692d7479567481bd807fc8a6d2d Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 2 Dec 2020 18:44:16 +0100 Subject: media: MAINTAINERS: Add myself as maintainer of the Amlogic GE2D driver Add new entry to MAINTAINERS. [hverkuil: added changelog] Signed-off-by: Neil Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 6380b54bf726..e97d4d9d741e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11380,6 +11380,15 @@ F: Documentation/devicetree/bindings/media/amlogic,meson-gx-ao-cec.yaml F: drivers/media/cec/platform/meson/ao-cec-g12a.c F: drivers/media/cec/platform/meson/ao-cec.c +MESON GE2D DRIVER FOR AMLOGIC SOCS +M: Neil Armstrong +L: linux-media@vger.kernel.org +L: linux-amlogic@lists.infradead.org +S: Supported +T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/amlogic,axg-ge2d.yaml +F: drivers/media/meson/ge2d/ + MESON NAND CONTROLLER DRIVER FOR AMLOGIC SOCS M: Liang Yang L: linux-mtd@lists.infradead.org -- cgit v1.2.3 From fb25ca37317200fa97ea6b8952e07958f06da7a6 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Thu, 26 Nov 2020 08:47:57 +0100 Subject: media: rcar-vin: Mask VNCSI_IFMD register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VNCSI_IFMD register controls the data expansion mode and the channel routing between the CSI-2 receivers and VIN instances. According to the chip manual revision 2.20 not all fields are available for all the SoCs: - V3M, V3H and E3 do not support the DES1 field has they do not feature a CSI20 receiver. - D3 only supports parallel input, and the whole register shall always be written as 0. Inspect the per-SoC channel routing table where the available CSI-2 instances are reported and configure VNCSI_IFMD accordingly. This patch supports this BSP change commit: https://github.com/renesas-rcar/linux-bsp/commit/f54697394457 ("media: rcar-vin: Fix VnCSI_IFMD register access for r8a77990") [hverkuil: replace BSP commit ID with BSP URL] Reviewed-by: Niklas Söderlund Suggested-by: Niklas Söderlund Signed-off-by: Jacopo Mondi Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-dma.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c index 7dd91de958ec..48280ddb15b9 100644 --- a/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/rcar-vin/rcar-dma.c @@ -1448,7 +1448,9 @@ error: */ int rvin_set_channel_routing(struct rvin_dev *vin, u8 chsel) { - u32 ifmd, vnmc; + const struct rvin_group_route *route; + u32 ifmd = 0; + u32 vnmc; int ret; ret = pm_runtime_get_sync(vin->dev); @@ -1461,9 +1463,26 @@ int rvin_set_channel_routing(struct rvin_dev *vin, u8 chsel) vnmc = rvin_read(vin, VNMC_REG); rvin_write(vin, vnmc & ~VNMC_VUP, VNMC_REG); - ifmd = VNCSI_IFMD_DES1 | VNCSI_IFMD_DES0 | VNCSI_IFMD_CSI_CHSEL(chsel); + /* + * Set data expansion mode to "pad with 0s" by inspecting the routes + * table to find out which bit fields are available in the IFMD + * register. IFMD_DES1 controls data expansion mode for CSI20/21, + * IFMD_DES0 controls data expansion mode for CSI40/41. + */ + for (route = vin->info->routes; route->mask; route++) { + if (route->csi == RVIN_CSI20 || route->csi == RVIN_CSI21) + ifmd |= VNCSI_IFMD_DES1; + else + ifmd |= VNCSI_IFMD_DES0; - rvin_write(vin, ifmd, VNCSI_IFMD_REG); + if (ifmd == (VNCSI_IFMD_DES0 | VNCSI_IFMD_DES1)) + break; + } + + if (ifmd) { + ifmd |= VNCSI_IFMD_CSI_CHSEL(chsel); + rvin_write(vin, ifmd, VNCSI_IFMD_REG); + } vin_dbg(vin, "Set IFMD 0x%x\n", ifmd); -- cgit v1.2.3 From 9e5f21d656cbf0407189114f0d418b095271a36e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 1 Dec 2020 13:44:40 +0100 Subject: media: vivid: fix 'disconnect' error injection The 'disconnect' error injection functionality suffered from bit rot. New device nodes were added without updating vivid_user_gen_s_ctrl(), so that function had to be updated for the new device nodes. Also, vivid didn't check if specific device nodes were actually ever created, so the vivid_is_last_user() would fail on that (it would return true instead of false in that case). Finally, selecting Disconnect, then unbind the vivid driver would fail since the remove() would think that the device nodes were already unregistered. Keep track of whether disconnect was pressed and re-register the device nodes in remove() before doing the real unregister. [hverkuil: unsigned uses -> unsigned int uses] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/test-drivers/vivid/vivid-core.c | 66 +++++++++++++++++--------- drivers/media/test-drivers/vivid/vivid-core.h | 1 + drivers/media/test-drivers/vivid/vivid-ctrls.c | 29 +++++++---- 3 files changed, 66 insertions(+), 30 deletions(-) diff --git a/drivers/media/test-drivers/vivid/vivid-core.c b/drivers/media/test-drivers/vivid/vivid-core.c index aa8d350fd682..0dc65ef3aa14 100644 --- a/drivers/media/test-drivers/vivid/vivid-core.c +++ b/drivers/media/test-drivers/vivid/vivid-core.c @@ -547,11 +547,13 @@ static int vivid_s_fmt_cap_mplane(struct file *file, void *priv, return vidioc_s_fmt_vid_cap_mplane(file, priv, f); } -static bool vivid_is_in_use(struct video_device *vdev) +static bool vivid_is_in_use(bool valid, struct video_device *vdev) { unsigned long flags; bool res; + if (!valid) + return false; spin_lock_irqsave(&vdev->fh_lock, flags); res = !list_empty(&vdev->fh_list); spin_unlock_irqrestore(&vdev->fh_lock, flags); @@ -560,20 +562,46 @@ static bool vivid_is_in_use(struct video_device *vdev) static bool vivid_is_last_user(struct vivid_dev *dev) { - unsigned uses = vivid_is_in_use(&dev->vid_cap_dev) + - vivid_is_in_use(&dev->vid_out_dev) + - vivid_is_in_use(&dev->vbi_cap_dev) + - vivid_is_in_use(&dev->vbi_out_dev) + - vivid_is_in_use(&dev->sdr_cap_dev) + - vivid_is_in_use(&dev->radio_rx_dev) + - vivid_is_in_use(&dev->radio_tx_dev) + - vivid_is_in_use(&dev->meta_cap_dev) + - vivid_is_in_use(&dev->meta_out_dev) + - vivid_is_in_use(&dev->touch_cap_dev); + unsigned int uses = + vivid_is_in_use(dev->has_vid_cap, &dev->vid_cap_dev) + + vivid_is_in_use(dev->has_vid_out, &dev->vid_out_dev) + + vivid_is_in_use(dev->has_vbi_cap, &dev->vbi_cap_dev) + + vivid_is_in_use(dev->has_vbi_out, &dev->vbi_out_dev) + + vivid_is_in_use(dev->has_radio_rx, &dev->radio_rx_dev) + + vivid_is_in_use(dev->has_radio_tx, &dev->radio_tx_dev) + + vivid_is_in_use(dev->has_sdr_cap, &dev->sdr_cap_dev) + + vivid_is_in_use(dev->has_meta_cap, &dev->meta_cap_dev) + + vivid_is_in_use(dev->has_meta_out, &dev->meta_out_dev) + + vivid_is_in_use(dev->has_touch_cap, &dev->touch_cap_dev); return uses == 1; } +static void vivid_reconnect(struct vivid_dev *dev) +{ + if (dev->has_vid_cap) + set_bit(V4L2_FL_REGISTERED, &dev->vid_cap_dev.flags); + if (dev->has_vid_out) + set_bit(V4L2_FL_REGISTERED, &dev->vid_out_dev.flags); + if (dev->has_vbi_cap) + set_bit(V4L2_FL_REGISTERED, &dev->vbi_cap_dev.flags); + if (dev->has_vbi_out) + set_bit(V4L2_FL_REGISTERED, &dev->vbi_out_dev.flags); + if (dev->has_radio_rx) + set_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags); + if (dev->has_radio_tx) + set_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags); + if (dev->has_sdr_cap) + set_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags); + if (dev->has_meta_cap) + set_bit(V4L2_FL_REGISTERED, &dev->meta_cap_dev.flags); + if (dev->has_meta_out) + set_bit(V4L2_FL_REGISTERED, &dev->meta_out_dev.flags); + if (dev->has_touch_cap) + set_bit(V4L2_FL_REGISTERED, &dev->touch_cap_dev.flags); + dev->disconnect_error = false; +} + static int vivid_fop_release(struct file *file) { struct vivid_dev *dev = video_drvdata(file); @@ -581,23 +609,15 @@ static int vivid_fop_release(struct file *file) mutex_lock(&dev->mutex); if (!no_error_inj && v4l2_fh_is_singular_file(file) && - !video_is_registered(vdev) && vivid_is_last_user(dev)) { + dev->disconnect_error && !video_is_registered(vdev) && + vivid_is_last_user(dev)) { /* * I am the last user of this driver, and a disconnect * was forced (since this video_device is unregistered), * so re-register all video_device's again. */ v4l2_info(&dev->v4l2_dev, "reconnect\n"); - set_bit(V4L2_FL_REGISTERED, &dev->vid_cap_dev.flags); - set_bit(V4L2_FL_REGISTERED, &dev->vid_out_dev.flags); - set_bit(V4L2_FL_REGISTERED, &dev->vbi_cap_dev.flags); - set_bit(V4L2_FL_REGISTERED, &dev->vbi_out_dev.flags); - set_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags); - set_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags); - set_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags); - set_bit(V4L2_FL_REGISTERED, &dev->meta_cap_dev.flags); - set_bit(V4L2_FL_REGISTERED, &dev->meta_out_dev.flags); - set_bit(V4L2_FL_REGISTERED, &dev->touch_cap_dev.flags); + vivid_reconnect(dev); } mutex_unlock(&dev->mutex); if (file->private_data == dev->overlay_cap_owner) @@ -1968,6 +1988,8 @@ static int vivid_remove(struct platform_device *pdev) if (!dev) continue; + if (dev->disconnect_error) + vivid_reconnect(dev); #ifdef CONFIG_MEDIA_CONTROLLER media_device_unregister(&dev->mdev); #endif diff --git a/drivers/media/test-drivers/vivid/vivid-core.h b/drivers/media/test-drivers/vivid/vivid-core.h index 99e69b8f770f..9c2d1470b597 100644 --- a/drivers/media/test-drivers/vivid/vivid-core.h +++ b/drivers/media/test-drivers/vivid/vivid-core.h @@ -303,6 +303,7 @@ struct vivid_dev { struct fb_fix_screeninfo fb_fix; /* Error injection */ + bool disconnect_error; bool queue_setup_error; bool buf_prepare_error; bool start_streaming_error; diff --git a/drivers/media/test-drivers/vivid/vivid-ctrls.c b/drivers/media/test-drivers/vivid/vivid-ctrls.c index 334130568dcb..11e3b5617f52 100644 --- a/drivers/media/test-drivers/vivid/vivid-ctrls.c +++ b/drivers/media/test-drivers/vivid/vivid-ctrls.c @@ -107,14 +107,27 @@ static int vivid_user_gen_s_ctrl(struct v4l2_ctrl *ctrl) switch (ctrl->id) { case VIVID_CID_DISCONNECT: v4l2_info(&dev->v4l2_dev, "disconnect\n"); - clear_bit(V4L2_FL_REGISTERED, &dev->vid_cap_dev.flags); - clear_bit(V4L2_FL_REGISTERED, &dev->vid_out_dev.flags); - clear_bit(V4L2_FL_REGISTERED, &dev->vbi_cap_dev.flags); - clear_bit(V4L2_FL_REGISTERED, &dev->vbi_out_dev.flags); - clear_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags); - clear_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags); - clear_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags); - clear_bit(V4L2_FL_REGISTERED, &dev->meta_cap_dev.flags); + dev->disconnect_error = true; + if (dev->has_vid_cap) + clear_bit(V4L2_FL_REGISTERED, &dev->vid_cap_dev.flags); + if (dev->has_vid_out) + clear_bit(V4L2_FL_REGISTERED, &dev->vid_out_dev.flags); + if (dev->has_vbi_cap) + clear_bit(V4L2_FL_REGISTERED, &dev->vbi_cap_dev.flags); + if (dev->has_vbi_out) + clear_bit(V4L2_FL_REGISTERED, &dev->vbi_out_dev.flags); + if (dev->has_radio_rx) + clear_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags); + if (dev->has_radio_tx) + clear_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags); + if (dev->has_sdr_cap) + clear_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags); + if (dev->has_meta_cap) + clear_bit(V4L2_FL_REGISTERED, &dev->meta_cap_dev.flags); + if (dev->has_meta_out) + clear_bit(V4L2_FL_REGISTERED, &dev->meta_out_dev.flags); + if (dev->has_touch_cap) + clear_bit(V4L2_FL_REGISTERED, &dev->touch_cap_dev.flags); break; case VIVID_CID_BUTTON: dev->button_pressed = 30; -- cgit v1.2.3 From 583791191c6d52528ae13a1812ecae43dfa12440 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 12 Nov 2020 23:49:51 +0100 Subject: media: dt-bindings: schema indentation fixes Fix a few new indentation warnings found with yamllint (now integrated into the checks). Cc: Ricardo Ribalda Signed-off-by: Rob Herring Acked-by: Jacopo Mondi Acked-by: Hans Verkuil # For adv7604 Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/i2c/adv7604.yaml | 4 ++-- Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml | 12 ++++++------ Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml | 12 ++++++------ 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Documentation/devicetree/bindings/media/i2c/adv7604.yaml b/Documentation/devicetree/bindings/media/i2c/adv7604.yaml index 3897af540ddd..407baddfaa1d 100644 --- a/Documentation/devicetree/bindings/media/i2c/adv7604.yaml +++ b/Documentation/devicetree/bindings/media/i2c/adv7604.yaml @@ -21,8 +21,8 @@ properties: compatible: items: - enum: - - adi,adv7611 - - adi,adv7612 + - adi,adv7611 + - adi,adv7612 reg: minItems: 1 diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml index 63b3779d7289..6866c2cdac50 100644 --- a/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml @@ -75,18 +75,18 @@ properties: bus-type: const: 6 then: - properties: - hsync-active: false - vsync-active: false + properties: + hsync-active: false + vsync-active: false - if: properties: bus-width: const: 10 then: - properties: - data-shift: - const: 0 + properties: + data-shift: + const: 0 required: - bus-type diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml index 0f5e25fa4e9d..1a3590dd0e98 100644 --- a/Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml @@ -68,13 +68,13 @@ properties: description: See ../video-interfaces.txt anyOf: - items: - - const: 1 - - const: 2 + - const: 1 + - const: 2 - items: - - const: 1 - - const: 2 - - const: 3 - - const: 4 + - const: 1 + - const: 2 + - const: 3 + - const: 4 link-frequencies: $ref: /schemas/types.yaml#/definitions/uint64-array -- cgit v1.2.3 From c3833a228cef7121cb7fc64d5ef71eedcc6f2f01 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 25 Jun 2020 14:13:55 +0200 Subject: media: ccs-pll: Don't use div_u64 to divide a 32-bit number pll->pll_op_clk_freq is a 32-bit number. It does not need div_u64 to divide it. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index 0d57bac1599a..1cfe6cf7e51c 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -445,7 +445,7 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *limits, min_pre_pll_clk_div, max_pre_pll_clk_div); i = gcd(pll->pll_op_clk_freq_hz, pll->ext_clk_freq_hz); - mul = div_u64(pll->pll_op_clk_freq_hz, i); + mul = pll->pll_op_clk_freq_hz / i; div = pll->ext_clk_freq_hz / i; dev_dbg(dev, "mul %u / div %u\n", mul, div); -- cgit v1.2.3 From 415ddd9939783cb79790aba1833ea39fd335caed Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 5 Jun 2020 22:46:54 +0200 Subject: media: ccs-pll: Split limits and PLL configuration into front and back parts The CCS spec supports a lot of variation in the PLL. Split the PLL in front and back parts to better prepare for supporting it. Also use CCS compliant naming for IP and OP PLL frequencies (i.e. include "clk" in the name). Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 282 ++++++++++++++++++++------------------- drivers/media/i2c/ccs-pll.h | 44 +++--- drivers/media/i2c/ccs/ccs-core.c | 71 +++++----- 3 files changed, 209 insertions(+), 188 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index 1cfe6cf7e51c..b2f0fa14ff92 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -53,65 +53,68 @@ static int bounds_check(struct device *dev, uint32_t val, static void print_pll(struct device *dev, struct ccs_pll *pll) { - dev_dbg(dev, "pre_pll_clk_div\t%u\n", pll->pre_pll_clk_div); - dev_dbg(dev, "pll_multiplier \t%u\n", pll->pll_multiplier); + dev_dbg(dev, "pre_pll_clk_div\t%u\n", pll->vt_fr.pre_pll_clk_div); + dev_dbg(dev, "pll_multiplier \t%u\n", pll->vt_fr.pll_multiplier); if (!(pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS)) { - dev_dbg(dev, "op_sys_clk_div \t%u\n", pll->op.sys_clk_div); - dev_dbg(dev, "op_pix_clk_div \t%u\n", pll->op.pix_clk_div); + dev_dbg(dev, "op_sys_clk_div \t%u\n", pll->op_bk.sys_clk_div); + dev_dbg(dev, "op_pix_clk_div \t%u\n", pll->op_bk.pix_clk_div); } - dev_dbg(dev, "vt_sys_clk_div \t%u\n", pll->vt.sys_clk_div); - dev_dbg(dev, "vt_pix_clk_div \t%u\n", pll->vt.pix_clk_div); + dev_dbg(dev, "vt_sys_clk_div \t%u\n", pll->vt_bk.sys_clk_div); + dev_dbg(dev, "vt_pix_clk_div \t%u\n", pll->vt_bk.pix_clk_div); dev_dbg(dev, "ext_clk_freq_hz \t%u\n", pll->ext_clk_freq_hz); - dev_dbg(dev, "pll_ip_clk_freq_hz \t%u\n", pll->pll_ip_clk_freq_hz); - dev_dbg(dev, "pll_op_clk_freq_hz \t%u\n", pll->pll_op_clk_freq_hz); + dev_dbg(dev, "pll_ip_clk_freq_hz \t%u\n", pll->vt_fr.pll_ip_clk_freq_hz); + dev_dbg(dev, "pll_op_clk_freq_hz \t%u\n", pll->vt_fr.pll_op_clk_freq_hz); if (!(pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS)) { dev_dbg(dev, "op_sys_clk_freq_hz \t%u\n", - pll->op.sys_clk_freq_hz); + pll->op_bk.sys_clk_freq_hz); dev_dbg(dev, "op_pix_clk_freq_hz \t%u\n", - pll->op.pix_clk_freq_hz); + pll->op_bk.pix_clk_freq_hz); } - dev_dbg(dev, "vt_sys_clk_freq_hz \t%u\n", pll->vt.sys_clk_freq_hz); - dev_dbg(dev, "vt_pix_clk_freq_hz \t%u\n", pll->vt.pix_clk_freq_hz); + dev_dbg(dev, "vt_sys_clk_freq_hz \t%u\n", pll->vt_bk.sys_clk_freq_hz); + dev_dbg(dev, "vt_pix_clk_freq_hz \t%u\n", pll->vt_bk.pix_clk_freq_hz); } static int check_all_bounds(struct device *dev, - const struct ccs_pll_limits *limits, - const struct ccs_pll_branch_limits *op_limits, - struct ccs_pll *pll, struct ccs_pll_branch *op_pll) + const struct ccs_pll_limits *lim, + const struct ccs_pll_branch_limits_fr *op_lim_fr, + const struct ccs_pll_branch_limits_bk *op_lim_bk, + struct ccs_pll *pll, + struct ccs_pll_branch_fr *op_pll_fr, + struct ccs_pll_branch_bk *op_pll_bk) { int rval; - rval = bounds_check(dev, pll->pll_ip_clk_freq_hz, - limits->min_pll_ip_freq_hz, - limits->max_pll_ip_freq_hz, + rval = bounds_check(dev, op_pll_fr->pll_ip_clk_freq_hz, + op_lim_fr->min_pll_ip_clk_freq_hz, + op_lim_fr->max_pll_ip_clk_freq_hz, "pll_ip_clk_freq_hz"); if (!rval) rval = bounds_check( - dev, pll->pll_multiplier, - limits->min_pll_multiplier, limits->max_pll_multiplier, - "pll_multiplier"); + dev, op_pll_fr->pll_multiplier, + op_lim_fr->min_pll_multiplier, + op_lim_fr->max_pll_multiplier, "pll_multiplier"); if (!rval) rval = bounds_check( - dev, pll->pll_op_clk_freq_hz, - limits->min_pll_op_freq_hz, limits->max_pll_op_freq_hz, - "pll_op_clk_freq_hz"); + dev, op_pll_fr->pll_op_clk_freq_hz, + op_lim_fr->min_pll_op_clk_freq_hz, + op_lim_fr->max_pll_op_clk_freq_hz, "pll_op_clk_freq_hz"); if (!rval) rval = bounds_check( - dev, op_pll->sys_clk_div, - op_limits->min_sys_clk_div, op_limits->max_sys_clk_div, + dev, op_pll_bk->sys_clk_div, + op_lim_bk->min_sys_clk_div, op_lim_bk->max_sys_clk_div, "op_sys_clk_div"); if (!rval) rval = bounds_check( - dev, op_pll->sys_clk_freq_hz, - op_limits->min_sys_clk_freq_hz, - op_limits->max_sys_clk_freq_hz, + dev, op_pll_bk->sys_clk_freq_hz, + op_lim_bk->min_sys_clk_freq_hz, + op_lim_bk->max_sys_clk_freq_hz, "op_sys_clk_freq_hz"); if (!rval) rval = bounds_check( - dev, op_pll->pix_clk_freq_hz, - op_limits->min_pix_clk_freq_hz, - op_limits->max_pix_clk_freq_hz, + dev, op_pll_bk->pix_clk_freq_hz, + op_lim_bk->min_pix_clk_freq_hz, + op_lim_bk->max_pix_clk_freq_hz, "op_pix_clk_freq_hz"); /* @@ -123,15 +126,15 @@ static int check_all_bounds(struct device *dev, if (!rval) rval = bounds_check( - dev, pll->vt.sys_clk_freq_hz, - limits->vt.min_sys_clk_freq_hz, - limits->vt.max_sys_clk_freq_hz, + dev, pll->vt_bk.sys_clk_freq_hz, + lim->vt_bk.min_sys_clk_freq_hz, + lim->vt_bk.max_sys_clk_freq_hz, "vt_sys_clk_freq_hz"); if (!rval) rval = bounds_check( - dev, pll->vt.pix_clk_freq_hz, - limits->vt.min_pix_clk_freq_hz, - limits->vt.max_pix_clk_freq_hz, + dev, pll->vt_bk.pix_clk_freq_hz, + lim->vt_bk.min_pix_clk_freq_hz, + lim->vt_bk.max_pix_clk_freq_hz, "vt_pix_clk_freq_hz"); return rval; @@ -149,10 +152,12 @@ static int check_all_bounds(struct device *dev, * @return Zero on success, error code on error. */ static int -__ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *limits, - const struct ccs_pll_branch_limits *op_limits, - struct ccs_pll *pll, struct ccs_pll_branch *op_pll, - uint32_t mul, uint32_t div, uint32_t lane_op_clock_ratio) +__ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, + const struct ccs_pll_branch_limits_fr *op_lim_fr, + const struct ccs_pll_branch_limits_bk *op_lim_bk, + struct ccs_pll *pll, struct ccs_pll_branch_fr *op_pll_fr, + struct ccs_pll_branch_bk *op_pll_bk, uint32_t mul, + uint32_t div, uint32_t lane_op_clock_ratio) { uint32_t sys_div; uint32_t best_pix_div = INT_MAX >> 1; @@ -173,42 +178,42 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *limits, * Get pre_pll_clk_div so that our pll_op_clk_freq_hz won't be * too high. */ - dev_dbg(dev, "pre_pll_clk_div %u\n", pll->pre_pll_clk_div); + dev_dbg(dev, "op_pre_pll_clk_div %u\n", op_pll_fr->pre_pll_clk_div); /* Don't go above max pll multiplier. */ - more_mul_max = limits->max_pll_multiplier / mul; - dev_dbg(dev, "more_mul_max: max_pll_multiplier check: %u\n", + more_mul_max = op_lim_fr->max_pll_multiplier / mul; + dev_dbg(dev, "more_mul_max: max_op_pll_multiplier check: %u\n", more_mul_max); /* Don't go above max pll op frequency. */ more_mul_max = min_t(uint32_t, more_mul_max, - limits->max_pll_op_freq_hz - / (pll->ext_clk_freq_hz / pll->pre_pll_clk_div * mul)); - dev_dbg(dev, "more_mul_max: max_pll_op_freq_hz check: %u\n", + op_lim_fr->max_pll_op_clk_freq_hz + / (pll->ext_clk_freq_hz / op_pll_fr->pre_pll_clk_div * mul)); + dev_dbg(dev, "more_mul_max: max_pll_op_clk_freq_hz check: %u\n", more_mul_max); /* Don't go above the division capability of op sys clock divider. */ more_mul_max = min(more_mul_max, - op_limits->max_sys_clk_div * pll->pre_pll_clk_div + op_lim_bk->max_sys_clk_div * op_pll_fr->pre_pll_clk_div / div); dev_dbg(dev, "more_mul_max: max_op_sys_clk_div check: %u\n", more_mul_max); /* Ensure we won't go above min_pll_multiplier. */ more_mul_max = min(more_mul_max, - DIV_ROUND_UP(limits->max_pll_multiplier, mul)); + DIV_ROUND_UP(op_lim_fr->max_pll_multiplier, mul)); dev_dbg(dev, "more_mul_max: min_pll_multiplier check: %u\n", more_mul_max); - /* Ensure we won't go below min_pll_op_freq_hz. */ - more_mul_min = DIV_ROUND_UP(limits->min_pll_op_freq_hz, - pll->ext_clk_freq_hz / pll->pre_pll_clk_div - * mul); - dev_dbg(dev, "more_mul_min: min_pll_op_freq_hz check: %u\n", + /* Ensure we won't go below min_pll_op_clk_freq_hz. */ + more_mul_min = DIV_ROUND_UP(op_lim_fr->min_pll_op_clk_freq_hz, + pll->ext_clk_freq_hz / + op_pll_fr->pre_pll_clk_div * mul); + dev_dbg(dev, "more_mul_min: min_op_pll_op_clk_freq_hz check: %u\n", more_mul_min); /* Ensure we won't go below min_pll_multiplier. */ more_mul_min = max(more_mul_min, - DIV_ROUND_UP(limits->min_pll_multiplier, mul)); - dev_dbg(dev, "more_mul_min: min_pll_multiplier check: %u\n", + DIV_ROUND_UP(op_lim_fr->min_pll_multiplier, mul)); + dev_dbg(dev, "more_mul_min: min_op_pll_multiplier check: %u\n", more_mul_min); if (more_mul_min > more_mul_max) { @@ -217,9 +222,9 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *limits, return -EINVAL; } - more_mul_factor = lcm(div, pll->pre_pll_clk_div) / div; + more_mul_factor = lcm(div, op_pll_fr->pre_pll_clk_div) / div; dev_dbg(dev, "more_mul_factor: %u\n", more_mul_factor); - more_mul_factor = lcm(more_mul_factor, op_limits->min_sys_clk_div); + more_mul_factor = lcm(more_mul_factor, op_lim_bk->min_sys_clk_div); dev_dbg(dev, "more_mul_factor: min_op_sys_clk_div: %d\n", more_mul_factor); i = roundup(more_mul_min, more_mul_factor); @@ -232,25 +237,25 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *limits, return -EINVAL; } - pll->pll_multiplier = mul * i; - op_pll->sys_clk_div = div * i / pll->pre_pll_clk_div; - dev_dbg(dev, "op_sys_clk_div: %u\n", op_pll->sys_clk_div); + op_pll_fr->pll_multiplier = mul * i; + op_pll_bk->sys_clk_div = div * i / op_pll_fr->pre_pll_clk_div; + dev_dbg(dev, "op_sys_clk_div: %u\n", op_pll_bk->sys_clk_div); - pll->pll_ip_clk_freq_hz = pll->ext_clk_freq_hz - / pll->pre_pll_clk_div; + op_pll_fr->pll_ip_clk_freq_hz = pll->ext_clk_freq_hz + / op_pll_fr->pre_pll_clk_div; - pll->pll_op_clk_freq_hz = pll->pll_ip_clk_freq_hz - * pll->pll_multiplier; + op_pll_fr->pll_op_clk_freq_hz = op_pll_fr->pll_ip_clk_freq_hz + * op_pll_fr->pll_multiplier; /* Derive pll_op_clk_freq_hz. */ - op_pll->sys_clk_freq_hz = - pll->pll_op_clk_freq_hz / op_pll->sys_clk_div; + op_pll_bk->sys_clk_freq_hz = + op_pll_fr->pll_op_clk_freq_hz / op_pll_bk->sys_clk_div; - op_pll->pix_clk_div = pll->bits_per_pixel; - dev_dbg(dev, "op_pix_clk_div: %u\n", op_pll->pix_clk_div); + op_pll_bk->pix_clk_div = pll->bits_per_pixel; + dev_dbg(dev, "op_pix_clk_div: %u\n", op_pll_bk->pix_clk_div); - op_pll->pix_clk_freq_hz = - op_pll->sys_clk_freq_hz / op_pll->pix_clk_div; + op_pll_bk->pix_clk_freq_hz = + op_pll_bk->sys_clk_freq_hz / op_pll_bk->pix_clk_div; if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS) { /* No OP clocks --- VT clocks are used instead. */ @@ -264,7 +269,7 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *limits, * should run at higher clock rate, so smaller divisor is used * on video timing side. */ - if (limits->min_line_length_pck_bin > limits->min_line_length_pck + if (lim->min_line_length_pck_bin > lim->min_line_length_pck / pll->binning_horizontal) vt_op_binning_div = pll->binning_horizontal; else @@ -283,28 +288,28 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *limits, * Find absolute limits for the factor of vt divider. */ dev_dbg(dev, "scale_m: %u\n", pll->scale_m); - min_vt_div = DIV_ROUND_UP(op_pll->pix_clk_div * op_pll->sys_clk_div - * pll->scale_n, + min_vt_div = DIV_ROUND_UP(op_pll_bk->pix_clk_div + * op_pll_bk->sys_clk_div * pll->scale_n, lane_op_clock_ratio * vt_op_binning_div * pll->scale_m); /* Find smallest and biggest allowed vt divisor. */ dev_dbg(dev, "min_vt_div: %u\n", min_vt_div); min_vt_div = max(min_vt_div, - DIV_ROUND_UP(pll->pll_op_clk_freq_hz, - limits->vt.max_pix_clk_freq_hz)); + DIV_ROUND_UP(op_pll_fr->pll_op_clk_freq_hz, + lim->vt_bk.max_pix_clk_freq_hz)); dev_dbg(dev, "min_vt_div: max_vt_pix_clk_freq_hz: %u\n", min_vt_div); min_vt_div = max_t(uint32_t, min_vt_div, - limits->vt.min_pix_clk_div - * limits->vt.min_sys_clk_div); + lim->vt_bk.min_pix_clk_div + * lim->vt_bk.min_sys_clk_div); dev_dbg(dev, "min_vt_div: min_vt_clk_div: %u\n", min_vt_div); - max_vt_div = limits->vt.max_sys_clk_div * limits->vt.max_pix_clk_div; + max_vt_div = lim->vt_bk.max_sys_clk_div * lim->vt_bk.max_pix_clk_div; dev_dbg(dev, "max_vt_div: %u\n", max_vt_div); max_vt_div = min(max_vt_div, - DIV_ROUND_UP(pll->pll_op_clk_freq_hz, - limits->vt.min_pix_clk_freq_hz)); + DIV_ROUND_UP(op_pll_fr->pll_op_clk_freq_hz, + lim->vt_bk.min_pix_clk_freq_hz)); dev_dbg(dev, "max_vt_div: min_vt_pix_clk_freq_hz: %u\n", max_vt_div); @@ -312,28 +317,28 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *limits, * Find limitsits for sys_clk_div. Not all values are possible * with all values of pix_clk_div. */ - min_sys_div = limits->vt.min_sys_clk_div; + min_sys_div = lim->vt_bk.min_sys_clk_div; dev_dbg(dev, "min_sys_div: %u\n", min_sys_div); min_sys_div = max(min_sys_div, DIV_ROUND_UP(min_vt_div, - limits->vt.max_pix_clk_div)); + lim->vt_bk.max_pix_clk_div)); dev_dbg(dev, "min_sys_div: max_vt_pix_clk_div: %u\n", min_sys_div); min_sys_div = max(min_sys_div, - pll->pll_op_clk_freq_hz - / limits->vt.max_sys_clk_freq_hz); + op_pll_fr->pll_op_clk_freq_hz + / lim->vt_bk.max_sys_clk_freq_hz); dev_dbg(dev, "min_sys_div: max_pll_op_clk_freq_hz: %u\n", min_sys_div); min_sys_div = clk_div_even_up(min_sys_div); dev_dbg(dev, "min_sys_div: one or even: %u\n", min_sys_div); - max_sys_div = limits->vt.max_sys_clk_div; + max_sys_div = lim->vt_bk.max_sys_clk_div; dev_dbg(dev, "max_sys_div: %u\n", max_sys_div); max_sys_div = min(max_sys_div, DIV_ROUND_UP(max_vt_div, - limits->vt.min_pix_clk_div)); + lim->vt_bk.min_pix_clk_div)); dev_dbg(dev, "max_sys_div: min_vt_pix_clk_div: %u\n", max_sys_div); max_sys_div = min(max_sys_div, - DIV_ROUND_UP(pll->pll_op_clk_freq_hz, - limits->vt.min_pix_clk_freq_hz)); + DIV_ROUND_UP(op_pll_fr->pll_op_clk_freq_hz, + lim->vt_bk.min_pix_clk_freq_hz)); dev_dbg(dev, "max_sys_div: min_vt_pix_clk_freq_hz: %u\n", max_sys_div); /* @@ -348,13 +353,13 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *limits, sys_div += 2 - (sys_div & 1)) { uint16_t pix_div = DIV_ROUND_UP(vt_div, sys_div); - if (pix_div < limits->vt.min_pix_clk_div - || pix_div > limits->vt.max_pix_clk_div) { + if (pix_div < lim->vt_bk.min_pix_clk_div + || pix_div > lim->vt_bk.max_pix_clk_div) { dev_dbg(dev, "pix_div %u too small or too big (%u--%u)\n", pix_div, - limits->vt.min_pix_clk_div, - limits->vt.max_pix_clk_div); + lim->vt_bk.min_pix_clk_div, + lim->vt_bk.max_pix_clk_div); continue; } @@ -367,29 +372,32 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *limits, break; } - pll->vt.sys_clk_div = DIV_ROUND_UP(min_vt_div, best_pix_div); - pll->vt.pix_clk_div = best_pix_div; + pll->vt_bk.sys_clk_div = DIV_ROUND_UP(min_vt_div, best_pix_div); + pll->vt_bk.pix_clk_div = best_pix_div; - pll->vt.sys_clk_freq_hz = - pll->pll_op_clk_freq_hz / pll->vt.sys_clk_div; - pll->vt.pix_clk_freq_hz = - pll->vt.sys_clk_freq_hz / pll->vt.pix_clk_div; + pll->vt_bk.sys_clk_freq_hz = + op_pll_fr->pll_op_clk_freq_hz / pll->vt_bk.sys_clk_div; + pll->vt_bk.pix_clk_freq_hz = + pll->vt_bk.sys_clk_freq_hz / pll->vt_bk.pix_clk_div; out_skip_vt_calc: pll->pixel_rate_csi = - op_pll->pix_clk_freq_hz * lane_op_clock_ratio; - pll->pixel_rate_pixel_array = pll->vt.pix_clk_freq_hz; + op_pll_bk->pix_clk_freq_hz * lane_op_clock_ratio; + pll->pixel_rate_pixel_array = pll->vt_bk.pix_clk_freq_hz; - return check_all_bounds(dev, limits, op_limits, pll, op_pll); + return check_all_bounds(dev, lim, op_lim_fr, op_lim_bk, pll, op_pll_fr, + op_pll_bk); } -int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *limits, +int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, struct ccs_pll *pll) { - const struct ccs_pll_branch_limits *op_limits = &limits->op; - struct ccs_pll_branch *op_pll = &pll->op; - uint16_t min_pre_pll_clk_div; - uint16_t max_pre_pll_clk_div; + const struct ccs_pll_branch_limits_fr *op_lim_fr = &lim->vt_fr; + const struct ccs_pll_branch_limits_bk *op_lim_bk = &lim->op_bk; + struct ccs_pll_branch_fr *op_pll_fr = &pll->vt_fr; + struct ccs_pll_branch_bk *op_pll_bk = &pll->op_bk; + uint16_t min_op_pre_pll_clk_div; + uint16_t max_op_pre_pll_clk_div; uint32_t lane_op_clock_ratio; uint32_t mul, div; unsigned int i; @@ -401,8 +409,9 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *limits, * instead. The OP values are ignored for the rest of * the PLL calculation. */ - op_limits = &limits->vt; - op_pll = &pll->vt; + op_lim_fr = &lim->vt_fr; + op_lim_bk = &lim->vt_bk; + op_pll_bk = &pll->vt_bk; } if (pll->flags & CCS_PLL_FLAG_OP_PIX_CLOCK_PER_LANE) @@ -417,11 +426,11 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *limits, switch (pll->bus_type) { case CCS_PLL_BUS_TYPE_CSI2: /* CSI transfers 2 bits per clock per lane; thus times 2 */ - pll->pll_op_clk_freq_hz = pll->link_freq * 2 + op_pll_fr->pll_op_clk_freq_hz = pll->link_freq * 2 * (pll->csi2.lanes / lane_op_clock_ratio); break; case CCS_PLL_BUS_TYPE_PARALLEL: - pll->pll_op_clk_freq_hz = pll->link_freq * pll->bits_per_pixel + op_pll_fr->pll_op_clk_freq_hz = pll->link_freq * pll->bits_per_pixel / DIV_ROUND_UP(pll->bits_per_pixel, pll->parallel.bus_width); break; @@ -429,39 +438,40 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *limits, return -EINVAL; } - /* Figure out limits for pre-pll divider based on extclk */ - dev_dbg(dev, "min / max pre_pll_clk_div: %u / %u\n", - limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div); - max_pre_pll_clk_div = - min_t(uint16_t, limits->max_pre_pll_clk_div, + /* Figure out limits for OP pre-pll divider based on extclk */ + dev_dbg(dev, "min / max op_pre_pll_clk_div: %u / %u\n", + op_lim_fr->min_pre_pll_clk_div, op_lim_fr->max_pre_pll_clk_div); + max_op_pre_pll_clk_div = + min_t(uint16_t, op_lim_fr->max_pre_pll_clk_div, clk_div_even(pll->ext_clk_freq_hz / - limits->min_pll_ip_freq_hz)); - min_pre_pll_clk_div = - max_t(uint16_t, limits->min_pre_pll_clk_div, + op_lim_fr->min_pll_ip_clk_freq_hz)); + min_op_pre_pll_clk_div = + max_t(uint16_t, op_lim_fr->min_pre_pll_clk_div, clk_div_even_up( DIV_ROUND_UP(pll->ext_clk_freq_hz, - limits->max_pll_ip_freq_hz))); - dev_dbg(dev, "pre-pll check: min / max pre_pll_clk_div: %u / %u\n", - min_pre_pll_clk_div, max_pre_pll_clk_div); + op_lim_fr->max_pll_ip_clk_freq_hz))); + dev_dbg(dev, "pre-pll check: min / max op_pre_pll_clk_div: %u / %u\n", + min_op_pre_pll_clk_div, max_op_pre_pll_clk_div); - i = gcd(pll->pll_op_clk_freq_hz, pll->ext_clk_freq_hz); - mul = pll->pll_op_clk_freq_hz / i; + i = gcd(op_pll_fr->pll_op_clk_freq_hz, pll->ext_clk_freq_hz); + mul = op_pll_fr->pll_op_clk_freq_hz / i; div = pll->ext_clk_freq_hz / i; dev_dbg(dev, "mul %u / div %u\n", mul, div); - min_pre_pll_clk_div = - max_t(uint16_t, min_pre_pll_clk_div, + min_op_pre_pll_clk_div = + max_t(uint16_t, min_op_pre_pll_clk_div, clk_div_even_up( DIV_ROUND_UP(mul * pll->ext_clk_freq_hz, - limits->max_pll_op_freq_hz))); - dev_dbg(dev, "pll_op check: min / max pre_pll_clk_div: %u / %u\n", - min_pre_pll_clk_div, max_pre_pll_clk_div); - - for (pll->pre_pll_clk_div = min_pre_pll_clk_div; - pll->pre_pll_clk_div <= max_pre_pll_clk_div; - pll->pre_pll_clk_div += 2 - (pll->pre_pll_clk_div & 1)) { - rval = __ccs_pll_calculate(dev, limits, op_limits, pll, op_pll, - mul, div, lane_op_clock_ratio); + op_lim_fr->max_pll_op_clk_freq_hz))); + dev_dbg(dev, "pll_op check: min / max op_pre_pll_clk_div: %u / %u\n", + min_op_pre_pll_clk_div, max_op_pre_pll_clk_div); + + for (op_pll_fr->pre_pll_clk_div = min_op_pre_pll_clk_div; + op_pll_fr->pre_pll_clk_div <= max_op_pre_pll_clk_div; + op_pll_fr->pre_pll_clk_div += 2 - (op_pll_fr->pre_pll_clk_div & 1)) { + rval = __ccs_pll_calculate(dev, lim, op_lim_fr, op_lim_bk, pll, + op_pll_fr, op_pll_bk, mul, div, + lane_op_clock_ratio); if (rval) continue; diff --git a/drivers/media/i2c/ccs-pll.h b/drivers/media/i2c/ccs-pll.h index 07f7f9e8a1cc..03b1d8d11423 100644 --- a/drivers/media/i2c/ccs-pll.h +++ b/drivers/media/i2c/ccs-pll.h @@ -20,7 +20,14 @@ #define CCS_PLL_FLAG_OP_PIX_CLOCK_PER_LANE (1 << 0) #define CCS_PLL_FLAG_NO_OP_CLOCKS (1 << 1) -struct ccs_pll_branch { +struct ccs_pll_branch_fr { + uint16_t pre_pll_clk_div; + uint16_t pll_multiplier; + uint32_t pll_ip_clk_freq_hz; + uint32_t pll_op_clk_freq_hz; +}; + +struct ccs_pll_branch_bk { uint16_t sys_clk_div; uint16_t pix_clk_div; uint32_t sys_clk_freq_hz; @@ -48,18 +55,26 @@ struct ccs_pll { uint32_t ext_clk_freq_hz; /* output values */ - uint16_t pre_pll_clk_div; - uint16_t pll_multiplier; - uint32_t pll_ip_clk_freq_hz; - uint32_t pll_op_clk_freq_hz; - struct ccs_pll_branch vt; - struct ccs_pll_branch op; + struct ccs_pll_branch_fr vt_fr; + struct ccs_pll_branch_bk vt_bk; + struct ccs_pll_branch_bk op_bk; uint32_t pixel_rate_csi; uint32_t pixel_rate_pixel_array; }; -struct ccs_pll_branch_limits { +struct ccs_pll_branch_limits_fr { + uint16_t min_pre_pll_clk_div; + uint16_t max_pre_pll_clk_div; + uint32_t min_pll_ip_clk_freq_hz; + uint32_t max_pll_ip_clk_freq_hz; + uint16_t min_pll_multiplier; + uint16_t max_pll_multiplier; + uint32_t min_pll_op_clk_freq_hz; + uint32_t max_pll_op_clk_freq_hz; +}; + +struct ccs_pll_branch_limits_bk { uint16_t min_sys_clk_div; uint16_t max_sys_clk_div; uint32_t min_sys_clk_freq_hz; @@ -74,17 +89,10 @@ struct ccs_pll_limits { /* Strict PLL limits */ uint32_t min_ext_clk_freq_hz; uint32_t max_ext_clk_freq_hz; - uint16_t min_pre_pll_clk_div; - uint16_t max_pre_pll_clk_div; - uint32_t min_pll_ip_freq_hz; - uint32_t max_pll_ip_freq_hz; - uint16_t min_pll_multiplier; - uint16_t max_pll_multiplier; - uint32_t min_pll_op_freq_hz; - uint32_t max_pll_op_freq_hz; - struct ccs_pll_branch_limits vt; - struct ccs_pll_branch_limits op; + struct ccs_pll_branch_limits_fr vt_fr; + struct ccs_pll_branch_limits_bk vt_bk; + struct ccs_pll_branch_limits_bk op_bk; /* Other relevant limits */ uint32_t min_line_length_pck_bin; diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 5f69e4c44533..dbb31d2001fb 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -367,67 +367,70 @@ static int ccs_pll_configure(struct ccs_sensor *sensor) struct ccs_pll *pll = &sensor->pll; int rval; - rval = ccs_write(sensor, VT_PIX_CLK_DIV, pll->vt.pix_clk_div); + rval = ccs_write(sensor, VT_PIX_CLK_DIV, pll->vt_bk.pix_clk_div); if (rval < 0) return rval; - rval = ccs_write(sensor, VT_SYS_CLK_DIV, pll->vt.sys_clk_div); + rval = ccs_write(sensor, VT_SYS_CLK_DIV, pll->vt_bk.sys_clk_div); if (rval < 0) return rval; - rval = ccs_write(sensor, PRE_PLL_CLK_DIV, pll->pre_pll_clk_div); + rval = ccs_write(sensor, PRE_PLL_CLK_DIV, pll->vt_fr.pre_pll_clk_div); if (rval < 0) return rval; - rval = ccs_write(sensor, PLL_MULTIPLIER, pll->pll_multiplier); + rval = ccs_write(sensor, PLL_MULTIPLIER, pll->vt_fr.pll_multiplier); if (rval < 0) return rval; /* Lane op clock ratio does not apply here. */ rval = ccs_write(sensor, REQUESTED_LINK_RATE, - DIV_ROUND_UP(pll->op.sys_clk_freq_hz, + DIV_ROUND_UP(pll->op_bk.sys_clk_freq_hz, 1000000 / 256 / 256)); if (rval < 0 || sensor->pll.flags & CCS_PLL_FLAG_NO_OP_CLOCKS) return rval; - rval = ccs_write(sensor, OP_PIX_CLK_DIV, pll->op.pix_clk_div); + rval = ccs_write(sensor, OP_PIX_CLK_DIV, pll->op_bk.pix_clk_div); if (rval < 0) return rval; - return ccs_write(sensor, OP_SYS_CLK_DIV, pll->op.sys_clk_div); + return ccs_write(sensor, OP_SYS_CLK_DIV, pll->op_bk.sys_clk_div); } static int ccs_pll_try(struct ccs_sensor *sensor, struct ccs_pll *pll) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); struct ccs_pll_limits lim = { - .min_pre_pll_clk_div = CCS_LIM(sensor, MIN_PRE_PLL_CLK_DIV), - .max_pre_pll_clk_div = CCS_LIM(sensor, MAX_PRE_PLL_CLK_DIV), - .min_pll_ip_freq_hz = CCS_LIM(sensor, MIN_PLL_IP_CLK_FREQ_MHZ), - .max_pll_ip_freq_hz = CCS_LIM(sensor, MAX_PLL_IP_CLK_FREQ_MHZ), - .min_pll_multiplier = CCS_LIM(sensor, MIN_PLL_MULTIPLIER), - .max_pll_multiplier = CCS_LIM(sensor, MAX_PLL_MULTIPLIER), - .min_pll_op_freq_hz = CCS_LIM(sensor, MIN_PLL_OP_CLK_FREQ_MHZ), - .max_pll_op_freq_hz = CCS_LIM(sensor, MAX_PLL_OP_CLK_FREQ_MHZ), - - .op.min_sys_clk_div = CCS_LIM(sensor, MIN_OP_SYS_CLK_DIV), - .op.max_sys_clk_div = CCS_LIM(sensor, MAX_OP_SYS_CLK_DIV), - .op.min_pix_clk_div = CCS_LIM(sensor, MIN_OP_PIX_CLK_DIV), - .op.max_pix_clk_div = CCS_LIM(sensor, MAX_OP_PIX_CLK_DIV), - .op.min_sys_clk_freq_hz = CCS_LIM(sensor, MIN_OP_SYS_CLK_FREQ_MHZ), - .op.max_sys_clk_freq_hz = CCS_LIM(sensor, MAX_OP_SYS_CLK_FREQ_MHZ), - .op.min_pix_clk_freq_hz = CCS_LIM(sensor, MIN_OP_PIX_CLK_FREQ_MHZ), - .op.max_pix_clk_freq_hz = CCS_LIM(sensor, MAX_OP_PIX_CLK_FREQ_MHZ), - - .vt.min_sys_clk_div = CCS_LIM(sensor, MIN_VT_SYS_CLK_DIV), - .vt.max_sys_clk_div = CCS_LIM(sensor, MAX_VT_SYS_CLK_DIV), - .vt.min_pix_clk_div = CCS_LIM(sensor, MIN_VT_PIX_CLK_DIV), - .vt.max_pix_clk_div = CCS_LIM(sensor, MAX_VT_PIX_CLK_DIV), - .vt.min_sys_clk_freq_hz = CCS_LIM(sensor, MIN_VT_SYS_CLK_FREQ_MHZ), - .vt.max_sys_clk_freq_hz = CCS_LIM(sensor, MAX_VT_SYS_CLK_FREQ_MHZ), - .vt.min_pix_clk_freq_hz = CCS_LIM(sensor, MIN_VT_PIX_CLK_FREQ_MHZ), - .vt.max_pix_clk_freq_hz = CCS_LIM(sensor, MAX_VT_PIX_CLK_FREQ_MHZ), - + .vt_fr = { + .min_pre_pll_clk_div = CCS_LIM(sensor, MIN_PRE_PLL_CLK_DIV), + .max_pre_pll_clk_div = CCS_LIM(sensor, MAX_PRE_PLL_CLK_DIV), + .min_pll_ip_clk_freq_hz = CCS_LIM(sensor, MIN_PLL_IP_CLK_FREQ_MHZ), + .max_pll_ip_clk_freq_hz = CCS_LIM(sensor, MAX_PLL_IP_CLK_FREQ_MHZ), + .min_pll_multiplier = CCS_LIM(sensor, MIN_PLL_MULTIPLIER), + .max_pll_multiplier = CCS_LIM(sensor, MAX_PLL_MULTIPLIER), + .min_pll_op_clk_freq_hz = CCS_LIM(sensor, MIN_PLL_OP_CLK_FREQ_MHZ), + .max_pll_op_clk_freq_hz = CCS_LIM(sensor, MAX_PLL_OP_CLK_FREQ_MHZ), + }, + .op_bk = { + .min_sys_clk_div = CCS_LIM(sensor, MIN_OP_SYS_CLK_DIV), + .max_sys_clk_div = CCS_LIM(sensor, MAX_OP_SYS_CLK_DIV), + .min_pix_clk_div = CCS_LIM(sensor, MIN_OP_PIX_CLK_DIV), + .max_pix_clk_div = CCS_LIM(sensor, MAX_OP_PIX_CLK_DIV), + .min_sys_clk_freq_hz = CCS_LIM(sensor, MIN_OP_SYS_CLK_FREQ_MHZ), + .max_sys_clk_freq_hz = CCS_LIM(sensor, MAX_OP_SYS_CLK_FREQ_MHZ), + .min_pix_clk_freq_hz = CCS_LIM(sensor, MIN_OP_PIX_CLK_FREQ_MHZ), + .max_pix_clk_freq_hz = CCS_LIM(sensor, MAX_OP_PIX_CLK_FREQ_MHZ), + }, + .vt_bk = { + .min_sys_clk_div = CCS_LIM(sensor, MIN_VT_SYS_CLK_DIV), + .max_sys_clk_div = CCS_LIM(sensor, MAX_VT_SYS_CLK_DIV), + .min_pix_clk_div = CCS_LIM(sensor, MIN_VT_PIX_CLK_DIV), + .max_pix_clk_div = CCS_LIM(sensor, MAX_VT_PIX_CLK_DIV), + .min_sys_clk_freq_hz = CCS_LIM(sensor, MIN_VT_SYS_CLK_FREQ_MHZ), + .max_sys_clk_freq_hz = CCS_LIM(sensor, MAX_VT_SYS_CLK_FREQ_MHZ), + .min_pix_clk_freq_hz = CCS_LIM(sensor, MIN_VT_PIX_CLK_FREQ_MHZ), + .max_pix_clk_freq_hz = CCS_LIM(sensor, MAX_VT_PIX_CLK_FREQ_MHZ), + }, .min_line_length_pck_bin = CCS_LIM(sensor, MIN_LINE_LENGTH_PCK_BIN), .min_line_length_pck = CCS_LIM(sensor, MIN_LINE_LENGTH_PCK), }; -- cgit v1.2.3 From 9454432af0c874eba7abb1abb76bbf62950a9087 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 1 Sep 2020 13:08:26 +0200 Subject: media: ccs-pll: Use correct VT divisor for calculating VT SYS divisor Use the correct video timing divisor to calculate the SYS divisor. Instead of the current value, the minimum was used. This could have resulted in a too low SYS divisor. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index b2f0fa14ff92..ea0f84fc8a90 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -365,14 +365,14 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, /* Check if this one is better. */ if (pix_div * sys_div - <= roundup(min_vt_div, best_pix_div)) + <= roundup(vt_div, best_pix_div)) best_pix_div = pix_div; } if (best_pix_div < INT_MAX >> 1) break; } - pll->vt_bk.sys_clk_div = DIV_ROUND_UP(min_vt_div, best_pix_div); + pll->vt_bk.sys_clk_div = DIV_ROUND_UP(vt_div, best_pix_div); pll->vt_bk.pix_clk_div = best_pix_div; pll->vt_bk.sys_clk_freq_hz = -- cgit v1.2.3 From 9c1a0d9e9188e7dc2f8f723ce87885e17636ede8 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 1 Sep 2020 13:11:11 +0200 Subject: media: ccs-pll: End search if there are no better values available The VT divisor search can be ended if we've already found the value that corresponds exactly the total divisor, as there are no better (lower) values available. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index ea0f84fc8a90..22e29127804a 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -352,6 +352,7 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, sys_div <= max_sys_div; sys_div += 2 - (sys_div & 1)) { uint16_t pix_div = DIV_ROUND_UP(vt_div, sys_div); + uint16_t rounded_div; if (pix_div < lim->vt_bk.min_pix_clk_div || pix_div > lim->vt_bk.max_pix_clk_div) { @@ -363,10 +364,15 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, continue; } + rounded_div = roundup(vt_div, best_pix_div); + /* Check if this one is better. */ - if (pix_div * sys_div - <= roundup(vt_div, best_pix_div)) + if (pix_div * sys_div <= rounded_div) best_pix_div = pix_div; + + /* Bail out if we've already found the best value. */ + if (vt_div == rounded_div) + break; } if (best_pix_div < INT_MAX >> 1) break; -- cgit v1.2.3 From 6aadbff9d459d4e4ebaedf19d50b0f057574f756 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 18 Jun 2020 13:23:26 +0200 Subject: media: ccs-pll: Remove parallel bus support The parallel bus PLL calculation has no users. Remove it. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 5 ----- drivers/media/i2c/ccs-pll.h | 14 ++++---------- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index 22e29127804a..da97a2b91717 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -435,11 +435,6 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, op_pll_fr->pll_op_clk_freq_hz = pll->link_freq * 2 * (pll->csi2.lanes / lane_op_clock_ratio); break; - case CCS_PLL_BUS_TYPE_PARALLEL: - op_pll_fr->pll_op_clk_freq_hz = pll->link_freq * pll->bits_per_pixel - / DIV_ROUND_UP(pll->bits_per_pixel, - pll->parallel.bus_width); - break; default: return -EINVAL; } diff --git a/drivers/media/i2c/ccs-pll.h b/drivers/media/i2c/ccs-pll.h index 03b1d8d11423..578c9272688a 100644 --- a/drivers/media/i2c/ccs-pll.h +++ b/drivers/media/i2c/ccs-pll.h @@ -13,8 +13,7 @@ #define CCS_PLL_H /* CSI-2 or CCP-2 */ -#define CCS_PLL_BUS_TYPE_CSI2 0x00 -#define CCS_PLL_BUS_TYPE_PARALLEL 0x01 +#define CCS_PLL_BUS_TYPE_CSI2 0x00 /* op pix clock is for all lanes in total normally */ #define CCS_PLL_FLAG_OP_PIX_CLOCK_PER_LANE (1 << 0) @@ -37,14 +36,9 @@ struct ccs_pll_branch_bk { struct ccs_pll { /* input values */ uint8_t bus_type; - union { - struct { - uint8_t lanes; - } csi2; - struct { - uint8_t bus_width; - } parallel; - }; + struct { + uint8_t lanes; + } csi2; unsigned long flags; uint8_t binning_horizontal; uint8_t binning_vertical; -- cgit v1.2.3 From 47b6eaf36eba143860cf4e772a1108b1ef05520d Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 22 Jun 2020 12:37:45 +0200 Subject: media: ccs-pll: Differentiate between CSI-2 D-PHY and C-PHY Differentiate between CSI-2 D-PHY and C-PHY. This does not yet include support for C-PHY. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 2 +- drivers/media/i2c/ccs-pll.h | 3 ++- drivers/media/i2c/ccs/ccs-core.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index da97a2b91717..c6435ed0597e 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -430,7 +430,7 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, pll->binning_vertical); switch (pll->bus_type) { - case CCS_PLL_BUS_TYPE_CSI2: + case CCS_PLL_BUS_TYPE_CSI2_DPHY: /* CSI transfers 2 bits per clock per lane; thus times 2 */ op_pll_fr->pll_op_clk_freq_hz = pll->link_freq * 2 * (pll->csi2.lanes / lane_op_clock_ratio); diff --git a/drivers/media/i2c/ccs-pll.h b/drivers/media/i2c/ccs-pll.h index 578c9272688a..d06a80c4fc52 100644 --- a/drivers/media/i2c/ccs-pll.h +++ b/drivers/media/i2c/ccs-pll.h @@ -13,7 +13,8 @@ #define CCS_PLL_H /* CSI-2 or CCP-2 */ -#define CCS_PLL_BUS_TYPE_CSI2 0x00 +#define CCS_PLL_BUS_TYPE_CSI2_DPHY 0x00 +#define CCS_PLL_BUS_TYPE_CSI2_CPHY 0x01 /* op pix clock is for all lanes in total normally */ #define CCS_PLL_FLAG_OP_PIX_CLOCK_PER_LANE (1 << 0) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index dbb31d2001fb..a422a523057e 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -3200,7 +3200,7 @@ static int ccs_probe(struct i2c_client *client) sensor->scale_m = CCS_LIM(sensor, SCALER_N_MIN); /* prepare PLL configuration input values */ - sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2; + sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2_DPHY; sensor->pll.csi2.lanes = sensor->hwcfg.lanes; sensor->pll.ext_clk_freq_hz = sensor->hwcfg.ext_clk; sensor->pll.scale_n = CCS_LIM(sensor, SCALER_N_MIN); -- cgit v1.2.3 From d6a88e446c04aaf3ebc4e2221aa51bf367319480 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 23 Jun 2020 15:07:24 +0200 Subject: media: ccs-pll: Move the flags field down, away from 8-bit fields This way the struct will use less memory, with better packing and no waste due to unsigned long. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/ccs-pll.h b/drivers/media/i2c/ccs-pll.h index d06a80c4fc52..1d908b23c934 100644 --- a/drivers/media/i2c/ccs-pll.h +++ b/drivers/media/i2c/ccs-pll.h @@ -40,12 +40,12 @@ struct ccs_pll { struct { uint8_t lanes; } csi2; - unsigned long flags; uint8_t binning_horizontal; uint8_t binning_vertical; uint8_t scale_m; uint8_t scale_n; uint8_t bits_per_pixel; + uint16_t flags; uint32_t link_freq; uint32_t ext_clk_freq_hz; -- cgit v1.2.3 From 925e3e49730346a39ec718f30f0965c3785facbb Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 8 Jun 2020 14:16:29 +0200 Subject: media: ccs-pll: Document the structs in the header as well as the function The CCS pll is used by the CCS driver at the moment, but documenting the interface makes sense. It's non-trivial and the calculator could be used elsewhere. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.h | 89 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/drivers/media/i2c/ccs-pll.h b/drivers/media/i2c/ccs-pll.h index 1d908b23c934..1b8d36068c7d 100644 --- a/drivers/media/i2c/ccs-pll.h +++ b/drivers/media/i2c/ccs-pll.h @@ -20,6 +20,16 @@ #define CCS_PLL_FLAG_OP_PIX_CLOCK_PER_LANE (1 << 0) #define CCS_PLL_FLAG_NO_OP_CLOCKS (1 << 1) +/** + * struct ccs_pll_branch_fr - CCS PLL configuration (front) + * + * A single branch front-end of the CCS PLL tree. + * + * @pre_pll_clk_div: Pre-PLL clock divisor + * @pll_multiplier: PLL multiplier + * @pll_ip_clk_freq_hz: PLL input clock frequency + * @pll_op_clk_freq_hz: PLL output clock frequency + */ struct ccs_pll_branch_fr { uint16_t pre_pll_clk_div; uint16_t pll_multiplier; @@ -27,6 +37,16 @@ struct ccs_pll_branch_fr { uint32_t pll_op_clk_freq_hz; }; +/** + * struct ccs_pll_branch_bk - CCS PLL configuration (back) + * + * A single branch back-end of the CCS PLL tree. + * + * @sys_clk_div: System clock divider + * @pix_clk_div: Pixel clock divider + * @sys_clk_freq_hz: System clock frequency + * @pix_clk_freq_hz: Pixel clock frequency + */ struct ccs_pll_branch_bk { uint16_t sys_clk_div; uint16_t pix_clk_div; @@ -34,6 +54,30 @@ struct ccs_pll_branch_bk { uint32_t pix_clk_freq_hz; }; +/** + * struct ccs_pll - Full CCS PLL configuration + * + * All information required to calculate CCS PLL configuration. + * + * @bus_type: Type of the data bus, CCS_PLL_BUS_TYPE_* (input) + * @csi2: CSI-2 related parameters + * @csi2.lanes: The number of the CSI-2 data lanes (input) + * @binning_vertical: Vertical binning factor (input) + * @binning_horizontal: Horizontal binning factor (input) + * @scale_m: Downscaling factor, M component, [16, max] (input) + * @scale_n: Downscaling factor, N component, typically 16 (input) + * @bits_per_pixel: Bits per pixel on the output data bus (input) + * @flags: CCS_PLL_FLAG_* (input) + * @link_freq: Chosen link frequency (input) + * @ext_clk_freq_hz: External clock frequency, i.e. the sensor's input clock + * (input) + * @vt_fr: Video timing front-end configuration (output) + * @vt_bk: Video timing back-end configuration (output) + * @op_bk: Operational timing back-end configuration (output) + * @pixel_rate_csi: Pixel rate on the output data bus (output) + * @pixel_rate_pixel_array: Nominal pixel rate in the sensor's pixel array + * (output) + */ struct ccs_pll { /* input values */ uint8_t bus_type; @@ -58,6 +102,18 @@ struct ccs_pll { uint32_t pixel_rate_pixel_array; }; +/** + * struct ccs_pll_branch_limits_fr - CCS PLL front-end limits + * + * @min_pre_pll_clk_div: Minimum pre-PLL clock divider + * @max_pre_pll_clk_div: Maximum pre-PLL clock divider + * @min_pll_ip_clk_freq_hz: Minimum PLL input clock frequency + * @max_pll_ip_clk_freq_hz: Maximum PLL input clock frequency + * @min_pll_multiplier: Minimum PLL multiplier + * @max_pll_multiplier: Maximum PLL multiplier + * @min_pll_op_clk_freq_hz: Minimum PLL output clock frequency + * @max_pll_op_clk_freq_hz: Maximum PLL output clock frequency + */ struct ccs_pll_branch_limits_fr { uint16_t min_pre_pll_clk_div; uint16_t max_pre_pll_clk_div; @@ -69,6 +125,18 @@ struct ccs_pll_branch_limits_fr { uint32_t max_pll_op_clk_freq_hz; }; +/** + * struct ccs_pll_branch_limits_bk - CCS PLL back-end limits + * + * @min_sys_clk_div: Minimum system clock divider + * @max_sys_clk_div: Maximum system clock divider + * @min_sys_clk_freq_hz: Minimum system clock frequency + * @max_sys_clk_freq_hz: Maximum system clock frequency + * @min_pix_clk_div: Minimum pixel clock divider + * @max_pix_clk_div: Maximum pixel clock divider + * @min_pix_clk_freq_hz: Minimum pixel clock frequency + * @max_pix_clk_freq_hz: Maximum pixel clock frequency + */ struct ccs_pll_branch_limits_bk { uint16_t min_sys_clk_div; uint16_t max_sys_clk_div; @@ -80,6 +148,17 @@ struct ccs_pll_branch_limits_bk { uint32_t max_pix_clk_freq_hz; }; +/** + * struct ccs_pll_limits - CCS PLL limits + * + * @min_ext_clk_freq_hz: Minimum external clock frequency + * @max_ext_clk_freq_hz: Maximum external clock frequency + * @vt_fr: Video timing front-end limits + * @vt_bk: Video timing back-end limits + * @op_bk: Operational timing back-end limits + * @min_line_length_pck_bin: Minimum line length in pixels, with binning + * @min_line_length_pck: Minimum line length in pixels without binning + */ struct ccs_pll_limits { /* Strict PLL limits */ uint32_t min_ext_clk_freq_hz; @@ -96,6 +175,16 @@ struct ccs_pll_limits { struct device; +/** + * ccs_pll_calculate - Calculate CCS PLL configuration based on input parameters + * + * @dev: Device pointer, used for printing messages + * @limits: Limits specific to the sensor + * @pll: Given PLL configuration + * + * Calculate the CCS PLL configuration based on the limits as well as given + * device specific, system specific or user configured input data. + */ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *limits, struct ccs_pll *pll); -- cgit v1.2.3 From 4f3d9e6eda9d73c43003701ab837868106125d96 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 17 Jun 2020 10:39:34 +0200 Subject: media: ccs-pll: Use the BIT macro Use the BIT macro for setting individual bits. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.h b/drivers/media/i2c/ccs-pll.h index 1b8d36068c7d..3ad4e6524ab6 100644 --- a/drivers/media/i2c/ccs-pll.h +++ b/drivers/media/i2c/ccs-pll.h @@ -12,13 +12,16 @@ #ifndef CCS_PLL_H #define CCS_PLL_H +#include + /* CSI-2 or CCP-2 */ #define CCS_PLL_BUS_TYPE_CSI2_DPHY 0x00 #define CCS_PLL_BUS_TYPE_CSI2_CPHY 0x01 +/* Old SMIA and implementation specific flags */ /* op pix clock is for all lanes in total normally */ -#define CCS_PLL_FLAG_OP_PIX_CLOCK_PER_LANE (1 << 0) -#define CCS_PLL_FLAG_NO_OP_CLOCKS (1 << 1) +#define CCS_PLL_FLAG_OP_PIX_CLOCK_PER_LANE BIT(0) +#define CCS_PLL_FLAG_NO_OP_CLOCKS BIT(1) /** * struct ccs_pll_branch_fr - CCS PLL configuration (front) -- cgit v1.2.3 From cab27256e8b3a6529faab9fc00e40fcf60b16590 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 26 Jun 2020 11:56:47 +0200 Subject: media: ccs-pll: Begin calculation from OP system clock frequency The OP system clock frequency defines the CSI-2 bus clock frequency, not the PLL output clock frequency. Both values were overwritten in the end, but the wrong limit value was used for the OP system clock frequency, possibly leading to too high frequencies being used. Also remove now duplicated calculation of OP system clock frequency later in the PLL calculator. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index c6435ed0597e..584be36f8c66 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -247,10 +247,6 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, op_pll_fr->pll_op_clk_freq_hz = op_pll_fr->pll_ip_clk_freq_hz * op_pll_fr->pll_multiplier; - /* Derive pll_op_clk_freq_hz. */ - op_pll_bk->sys_clk_freq_hz = - op_pll_fr->pll_op_clk_freq_hz / op_pll_bk->sys_clk_div; - op_pll_bk->pix_clk_div = pll->bits_per_pixel; dev_dbg(dev, "op_pix_clk_div: %u\n", op_pll_bk->pix_clk_div); @@ -432,7 +428,7 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, switch (pll->bus_type) { case CCS_PLL_BUS_TYPE_CSI2_DPHY: /* CSI transfers 2 bits per clock per lane; thus times 2 */ - op_pll_fr->pll_op_clk_freq_hz = pll->link_freq * 2 + op_pll_bk->sys_clk_freq_hz = pll->link_freq * 2 * (pll->csi2.lanes / lane_op_clock_ratio); break; default: @@ -454,8 +450,8 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, dev_dbg(dev, "pre-pll check: min / max op_pre_pll_clk_div: %u / %u\n", min_op_pre_pll_clk_div, max_op_pre_pll_clk_div); - i = gcd(op_pll_fr->pll_op_clk_freq_hz, pll->ext_clk_freq_hz); - mul = op_pll_fr->pll_op_clk_freq_hz / i; + i = gcd(op_pll_bk->sys_clk_freq_hz, pll->ext_clk_freq_hz); + mul = op_pll_bk->sys_clk_freq_hz / i; div = pll->ext_clk_freq_hz / i; dev_dbg(dev, "mul %u / div %u\n", mul, div); @@ -463,7 +459,7 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, max_t(uint16_t, min_op_pre_pll_clk_div, clk_div_even_up( DIV_ROUND_UP(mul * pll->ext_clk_freq_hz, - op_lim_fr->max_pll_op_clk_freq_hz))); + op_lim_bk->max_sys_clk_freq_hz))); dev_dbg(dev, "pll_op check: min / max op_pre_pll_clk_div: %u / %u\n", min_op_pre_pll_clk_div, max_op_pre_pll_clk_div); -- cgit v1.2.3 From fe52ece8d2e26bd4d38e2c99a7cd13d944c1ee98 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 7 Jul 2020 10:08:01 +0200 Subject: media: ccs-pll: Fix condition for pre-PLL divider lower bound The lower bound of the pre-PLL divider was calculated based on OP SYS clock frequency which is also affected by the OP SYS clock divider. This is wrong. The right clock frequency is that of the PLL output clock. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index 584be36f8c66..b45e6b30c528 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -459,7 +459,7 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, max_t(uint16_t, min_op_pre_pll_clk_div, clk_div_even_up( DIV_ROUND_UP(mul * pll->ext_clk_freq_hz, - op_lim_bk->max_sys_clk_freq_hz))); + op_lim_fr->max_pll_op_clk_freq_hz))); dev_dbg(dev, "pll_op check: min / max op_pre_pll_clk_div: %u / %u\n", min_op_pre_pll_clk_div, max_op_pre_pll_clk_div); -- cgit v1.2.3 From 482e75e7b3eba6730cbfaa1911916d13887c9606 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 7 Jul 2020 10:31:56 +0200 Subject: media: ccs-pll: Avoid overflow in pre-PLL divisor lower bound search The external clock frequency times the PLL multiplier may exceed the value range of 32-bit unsigned integers. Instead perform the same calculation y using two divisions. The result has some potential to be different, but that's ok: this number is used to limit the range of pre-PLL divisors to find optimal values. So the effect of the rare case of a different result here would mean an invalid pre-PLL divisor is tried. That will be found out a little later in any case. Also guard against dividing by zero if the external clock frequency is higher than the maximum OP PLL output clock --- a rather improbable case. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index b45e6b30c528..78897a7c1448 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -40,6 +40,11 @@ static inline uint32_t is_one_or_even(uint32_t a) return 1; } +static inline uint32_t one_or_more(uint32_t a) +{ + return a ?: 1; +} + static int bounds_check(struct device *dev, uint32_t val, uint32_t min, uint32_t max, char *str) { @@ -458,8 +463,10 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, min_op_pre_pll_clk_div = max_t(uint16_t, min_op_pre_pll_clk_div, clk_div_even_up( - DIV_ROUND_UP(mul * pll->ext_clk_freq_hz, - op_lim_fr->max_pll_op_clk_freq_hz))); + mul / + one_or_more( + DIV_ROUND_UP(op_lim_fr->max_pll_op_clk_freq_hz, + pll->ext_clk_freq_hz)))); dev_dbg(dev, "pll_op check: min / max op_pre_pll_clk_div: %u / %u\n", min_op_pre_pll_clk_div, max_op_pre_pll_clk_div); -- cgit v1.2.3 From c64cf71d10c36513071ca538f59e4c38eb25ae55 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 7 Jul 2020 10:54:14 +0200 Subject: media: ccs-pll: Fix comment on check against maximum PLL multiplier The comment is about minimum PLL multiplier but the related check really deals with the maximum PLL multiplier. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index 78897a7c1448..f4c41d61e332 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -203,7 +203,7 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, / div); dev_dbg(dev, "more_mul_max: max_op_sys_clk_div check: %u\n", more_mul_max); - /* Ensure we won't go above min_pll_multiplier. */ + /* Ensure we won't go above max_pll_multiplier. */ more_mul_max = min(more_mul_max, DIV_ROUND_UP(op_lim_fr->max_pll_multiplier, mul)); dev_dbg(dev, "more_mul_max: min_pll_multiplier check: %u\n", -- cgit v1.2.3 From 82ab97c8c77629c4945de24c722cd4955cf70ef2 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 7 Jul 2020 15:24:09 +0200 Subject: media: ccs-pll: Fix check for PLL multiplier upper bound The additional multiplier (for higher VT timing) of the PLL multiplier was checked against the upper limit but the result was rounded up, possibly producing too high additional multiplier. Round down instead to keep within hardware limits. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index f4c41d61e332..b23e959000a4 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -204,8 +204,7 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, dev_dbg(dev, "more_mul_max: max_op_sys_clk_div check: %u\n", more_mul_max); /* Ensure we won't go above max_pll_multiplier. */ - more_mul_max = min(more_mul_max, - DIV_ROUND_UP(op_lim_fr->max_pll_multiplier, mul)); + more_mul_max = min(more_mul_max, op_lim_fr->max_pll_multiplier / mul); dev_dbg(dev, "more_mul_max: min_pll_multiplier check: %u\n", more_mul_max); -- cgit v1.2.3 From e583e654565fd12e45d8cef64dcdd80e2902ac13 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 25 Aug 2020 22:31:23 +0200 Subject: media: ccs-pll: Use explicit 32-bit unsigned type Use uint32_t instead of unsigned int for a variable that contains explicitly 32-bit numbers. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index b23e959000a4..d33a2575329c 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -177,7 +177,7 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, uint32_t more_mul_factor; uint32_t min_vt_div, max_vt_div, vt_div; uint32_t min_sys_div, max_sys_div; - unsigned int i; + uint32_t i; /* * Get pre_pll_clk_div so that our pll_op_clk_freq_hz won't be @@ -406,7 +406,7 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, uint16_t max_op_pre_pll_clk_div; uint32_t lane_op_clock_ratio; uint32_t mul, div; - unsigned int i; + uint32_t i; int rval = -EINVAL; if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS) { -- cgit v1.2.3 From cac8f5d28e56c405befd1613fc38c962aaf69f30 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 22 Jun 2020 12:16:24 +0200 Subject: media: ccs-pll: Add support for lane speed model CCS PLL includes a capability to calculate the VT clocks on per-lane basis. Add support for this feature. Move calculation of the pixel rate on the CSI-2 bus early in the function as everything needed to calculate it is already available. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 36 +++++++++++++++++++++++++----------- drivers/media/i2c/ccs-pll.h | 6 ++++++ 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index d33a2575329c..9750b49d834a 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -251,11 +251,12 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, op_pll_fr->pll_op_clk_freq_hz = op_pll_fr->pll_ip_clk_freq_hz * op_pll_fr->pll_multiplier; - op_pll_bk->pix_clk_div = pll->bits_per_pixel; - dev_dbg(dev, "op_pix_clk_div: %u\n", op_pll_bk->pix_clk_div); - + op_pll_bk->pix_clk_div = pll->bits_per_pixel + * pll->op_lanes / pll->csi2.lanes; op_pll_bk->pix_clk_freq_hz = op_pll_bk->sys_clk_freq_hz / op_pll_bk->pix_clk_div; + dev_dbg(dev, "op_pix_clk_div: %u\n", op_pll_bk->pix_clk_div); + if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS) { /* No OP clocks --- VT clocks are used instead. */ @@ -283,15 +284,16 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, * divisors. One must make sure that horizontal blanking is * enough to accommodate the CSI-2 sync codes. * - * Take scaling factor into account as well. + * Take scaling factor and number of VT lanes into account as well. * * Find absolute limits for the factor of vt divider. */ dev_dbg(dev, "scale_m: %u\n", pll->scale_m); min_vt_div = DIV_ROUND_UP(op_pll_bk->pix_clk_div - * op_pll_bk->sys_clk_div * pll->scale_n, - lane_op_clock_ratio * vt_op_binning_div - * pll->scale_m); + * op_pll_bk->sys_clk_div * pll->scale_n + * pll->vt_lanes, + pll->op_lanes * vt_op_binning_div + * pll->scale_m * lane_op_clock_ratio); /* Find smallest and biggest allowed vt divisor. */ dev_dbg(dev, "min_vt_div: %u\n", min_vt_div); @@ -387,9 +389,8 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, pll->vt_bk.sys_clk_freq_hz / pll->vt_bk.pix_clk_div; out_skip_vt_calc: - pll->pixel_rate_csi = - op_pll_bk->pix_clk_freq_hz * lane_op_clock_ratio; - pll->pixel_rate_pixel_array = pll->vt_bk.pix_clk_freq_hz; + pll->pixel_rate_pixel_array = + pll->vt_bk.pix_clk_freq_hz * pll->vt_lanes; return check_all_bounds(dev, lim, op_lim_fr, op_lim_bk, pll, op_pll_fr, op_pll_bk); @@ -409,6 +410,13 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, uint32_t i; int rval = -EINVAL; + if (!(pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL)) { + pll->op_lanes = 1; + pll->vt_lanes = 1; + } + dev_dbg(dev, "vt_lanes: %u\n", pll->vt_lanes); + dev_dbg(dev, "op_lanes: %u\n", pll->op_lanes); + if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS) { /* * If there's no OP PLL at all, use the VT values @@ -433,12 +441,18 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, case CCS_PLL_BUS_TYPE_CSI2_DPHY: /* CSI transfers 2 bits per clock per lane; thus times 2 */ op_pll_bk->sys_clk_freq_hz = pll->link_freq * 2 - * (pll->csi2.lanes / lane_op_clock_ratio); + * (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ? + 1 : pll->csi2.lanes) / lane_op_clock_ratio; break; default: return -EINVAL; } + pll->pixel_rate_csi = + op_pll_bk->pix_clk_freq_hz + * (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ? + pll->csi2.lanes : 1) * lane_op_clock_ratio; + /* Figure out limits for OP pre-pll divider based on extclk */ dev_dbg(dev, "min / max op_pre_pll_clk_div: %u / %u\n", op_lim_fr->min_pre_pll_clk_div, op_lim_fr->max_pre_pll_clk_div); diff --git a/drivers/media/i2c/ccs-pll.h b/drivers/media/i2c/ccs-pll.h index 3ad4e6524ab6..fe8eb3d4bcff 100644 --- a/drivers/media/i2c/ccs-pll.h +++ b/drivers/media/i2c/ccs-pll.h @@ -22,6 +22,8 @@ /* op pix clock is for all lanes in total normally */ #define CCS_PLL_FLAG_OP_PIX_CLOCK_PER_LANE BIT(0) #define CCS_PLL_FLAG_NO_OP_CLOCKS BIT(1) +/* CCS PLL flags */ +#define CCS_PLL_FLAG_LANE_SPEED_MODEL BIT(2) /** * struct ccs_pll_branch_fr - CCS PLL configuration (front) @@ -63,6 +65,8 @@ struct ccs_pll_branch_bk { * All information required to calculate CCS PLL configuration. * * @bus_type: Type of the data bus, CCS_PLL_BUS_TYPE_* (input) + * @op_lanes: Number of operational lanes (input) + * @vt_lanes: Number of video timing lanes (input) * @csi2: CSI-2 related parameters * @csi2.lanes: The number of the CSI-2 data lanes (input) * @binning_vertical: Vertical binning factor (input) @@ -84,6 +88,8 @@ struct ccs_pll_branch_bk { struct ccs_pll { /* input values */ uint8_t bus_type; + uint8_t op_lanes; + uint8_t vt_lanes; struct { uint8_t lanes; } csi2; -- cgit v1.2.3 From 585e17c98407e1c2ec7735f37379e96cf0f74e3a Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 23 Sep 2020 12:16:03 +0200 Subject: media: ccs: Add support for lane speed model Convey the relevant PLL flags to the PLL calculator. Also the lane speed model affects how the link rate is calculated on the CSI-2 bus, as the rate is total of all lanes. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index a422a523057e..a0d73e0fa31a 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -386,7 +386,9 @@ static int ccs_pll_configure(struct ccs_sensor *sensor) /* Lane op clock ratio does not apply here. */ rval = ccs_write(sensor, REQUESTED_LINK_RATE, DIV_ROUND_UP(pll->op_bk.sys_clk_freq_hz, - 1000000 / 256 / 256)); + 1000000 / 256 / 256) * + (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ? + sensor->pll.csi2.lanes : 1)); if (rval < 0 || sensor->pll.flags & CCS_PLL_FLAG_NO_OP_CLOCKS) return rval; @@ -3202,6 +3204,13 @@ static int ccs_probe(struct i2c_client *client) /* prepare PLL configuration input values */ sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2_DPHY; sensor->pll.csi2.lanes = sensor->hwcfg.lanes; + if (CCS_LIM(sensor, CLOCK_CALCULATION) & + CCS_CLOCK_CALCULATION_LANE_SPEED) { + sensor->pll.vt_lanes = + CCS_LIM(sensor, NUM_OF_VT_LANES) + 1; + sensor->pll.op_lanes = sensor->pll.vt_lanes; + sensor->pll.flags |= CCS_PLL_FLAG_LANE_SPEED_MODEL; + } sensor->pll.ext_clk_freq_hz = sensor->hwcfg.ext_clk; sensor->pll.scale_n = CCS_LIM(sensor, SCALER_N_MIN); -- cgit v1.2.3 From ae502e08f45e47460406ab5c5fd2167a1011499a Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 18 Jun 2020 12:39:44 +0200 Subject: media: ccs-pll: Add support for decoupled OP domain calculation Add support for decoupled OP domain clock calculation. This means that the number of VT and OP domain clocks are no longer dependent on the number of CSI-2 lanes in the lane speed mode. The support also replaces the existing quirk flag to calculate OP domain clocks per lane. Also support decoupled OP domain calculation in the CCS driver. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 22 +++++++--------------- drivers/media/i2c/ccs-pll.h | 1 + drivers/media/i2c/ccs/ccs-core.c | 14 +++++++++++--- drivers/media/i2c/ccs/ccs-quirk.c | 5 ++++- 4 files changed, 23 insertions(+), 19 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index 9750b49d834a..cb19a36e54df 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -162,7 +162,7 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, const struct ccs_pll_branch_limits_bk *op_lim_bk, struct ccs_pll *pll, struct ccs_pll_branch_fr *op_pll_fr, struct ccs_pll_branch_bk *op_pll_bk, uint32_t mul, - uint32_t div, uint32_t lane_op_clock_ratio) + uint32_t div) { uint32_t sys_div; uint32_t best_pix_div = INT_MAX >> 1; @@ -194,7 +194,8 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, min_t(uint32_t, more_mul_max, op_lim_fr->max_pll_op_clk_freq_hz - / (pll->ext_clk_freq_hz / op_pll_fr->pre_pll_clk_div * mul)); + / (pll->ext_clk_freq_hz / + op_pll_fr->pre_pll_clk_div * mul)); dev_dbg(dev, "more_mul_max: max_pll_op_clk_freq_hz check: %u\n", more_mul_max); /* Don't go above the division capability of op sys clock divider. */ @@ -257,7 +258,6 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, op_pll_bk->sys_clk_freq_hz / op_pll_bk->pix_clk_div; dev_dbg(dev, "op_pix_clk_div: %u\n", op_pll_bk->pix_clk_div); - if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS) { /* No OP clocks --- VT clocks are used instead. */ goto out_skip_vt_calc; @@ -293,7 +293,7 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, * op_pll_bk->sys_clk_div * pll->scale_n * pll->vt_lanes, pll->op_lanes * vt_op_binning_div - * pll->scale_m * lane_op_clock_ratio); + * pll->scale_m); /* Find smallest and biggest allowed vt divisor. */ dev_dbg(dev, "min_vt_div: %u\n", min_vt_div); @@ -405,7 +405,6 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, struct ccs_pll_branch_bk *op_pll_bk = &pll->op_bk; uint16_t min_op_pre_pll_clk_div; uint16_t max_op_pre_pll_clk_div; - uint32_t lane_op_clock_ratio; uint32_t mul, div; uint32_t i; int rval = -EINVAL; @@ -428,12 +427,6 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, op_pll_bk = &pll->vt_bk; } - if (pll->flags & CCS_PLL_FLAG_OP_PIX_CLOCK_PER_LANE) - lane_op_clock_ratio = pll->csi2.lanes; - else - lane_op_clock_ratio = 1; - dev_dbg(dev, "lane_op_clock_ratio: %u\n", lane_op_clock_ratio); - dev_dbg(dev, "binning: %ux%u\n", pll->binning_horizontal, pll->binning_vertical); @@ -442,7 +435,7 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, /* CSI transfers 2 bits per clock per lane; thus times 2 */ op_pll_bk->sys_clk_freq_hz = pll->link_freq * 2 * (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ? - 1 : pll->csi2.lanes) / lane_op_clock_ratio; + 1 : pll->csi2.lanes); break; default: return -EINVAL; @@ -451,7 +444,7 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, pll->pixel_rate_csi = op_pll_bk->pix_clk_freq_hz * (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ? - pll->csi2.lanes : 1) * lane_op_clock_ratio; + pll->csi2.lanes : 1); /* Figure out limits for OP pre-pll divider based on extclk */ dev_dbg(dev, "min / max op_pre_pll_clk_div: %u / %u\n", @@ -487,8 +480,7 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, op_pll_fr->pre_pll_clk_div <= max_op_pre_pll_clk_div; op_pll_fr->pre_pll_clk_div += 2 - (op_pll_fr->pre_pll_clk_div & 1)) { rval = __ccs_pll_calculate(dev, lim, op_lim_fr, op_lim_bk, pll, - op_pll_fr, op_pll_bk, mul, div, - lane_op_clock_ratio); + op_pll_fr, op_pll_bk, mul, div); if (rval) continue; diff --git a/drivers/media/i2c/ccs-pll.h b/drivers/media/i2c/ccs-pll.h index fe8eb3d4bcff..fe20af11a068 100644 --- a/drivers/media/i2c/ccs-pll.h +++ b/drivers/media/i2c/ccs-pll.h @@ -24,6 +24,7 @@ #define CCS_PLL_FLAG_NO_OP_CLOCKS BIT(1) /* CCS PLL flags */ #define CCS_PLL_FLAG_LANE_SPEED_MODEL BIT(2) +#define CCS_PLL_FLAG_LINK_DECOUPLED BIT(3) /** * struct ccs_pll_branch_fr - CCS PLL configuration (front) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index a0d73e0fa31a..855e51675864 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -3206,10 +3206,18 @@ static int ccs_probe(struct i2c_client *client) sensor->pll.csi2.lanes = sensor->hwcfg.lanes; if (CCS_LIM(sensor, CLOCK_CALCULATION) & CCS_CLOCK_CALCULATION_LANE_SPEED) { - sensor->pll.vt_lanes = - CCS_LIM(sensor, NUM_OF_VT_LANES) + 1; - sensor->pll.op_lanes = sensor->pll.vt_lanes; sensor->pll.flags |= CCS_PLL_FLAG_LANE_SPEED_MODEL; + if (CCS_LIM(sensor, CLOCK_CALCULATION) & + CCS_CLOCK_CALCULATION_LINK_DECOUPLED) { + sensor->pll.vt_lanes = + CCS_LIM(sensor, NUM_OF_VT_LANES) + 1; + sensor->pll.op_lanes = + CCS_LIM(sensor, NUM_OF_OP_LANES) + 1; + sensor->pll.flags |= CCS_PLL_FLAG_LINK_DECOUPLED; + } else { + sensor->pll.vt_lanes = sensor->pll.csi2.lanes; + sensor->pll.op_lanes = sensor->pll.csi2.lanes; + } } sensor->pll.ext_clk_freq_hz = sensor->hwcfg.ext_clk; sensor->pll.scale_n = CCS_LIM(sensor, SCALER_N_MIN); diff --git a/drivers/media/i2c/ccs/ccs-quirk.c b/drivers/media/i2c/ccs/ccs-quirk.c index 4fe8c6f70579..e3d4c7a275bc 100644 --- a/drivers/media/i2c/ccs/ccs-quirk.c +++ b/drivers/media/i2c/ccs/ccs-quirk.c @@ -190,7 +190,10 @@ static int jt8ev1_post_streamoff(struct ccs_sensor *sensor) static int jt8ev1_init(struct ccs_sensor *sensor) { - sensor->pll.flags |= CCS_PLL_FLAG_OP_PIX_CLOCK_PER_LANE; + sensor->pll.flags |= CCS_PLL_FLAG_LANE_SPEED_MODEL | + CCS_PLL_FLAG_LINK_DECOUPLED; + sensor->pll.vt_lanes = 1; + sensor->pll.op_lanes = sensor->pll.csi2.lanes; return 0; } -- cgit v1.2.3 From 4e1e8d240dff96bd8dd2c00c5fcd7f04088ace3c Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 23 Jun 2020 13:40:32 +0200 Subject: media: ccs-pll: Add support for extended input PLL clock divider CCS allows odd PLL dividers other than 1, granted that the corresponding capability bit is set. Support this both in the PLL calculator and the CCS driver. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 4 +++- drivers/media/i2c/ccs-pll.h | 1 + drivers/media/i2c/ccs/ccs-core.c | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index cb19a36e54df..62939ca5b8e2 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -478,7 +478,9 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, for (op_pll_fr->pre_pll_clk_div = min_op_pre_pll_clk_div; op_pll_fr->pre_pll_clk_div <= max_op_pre_pll_clk_div; - op_pll_fr->pre_pll_clk_div += 2 - (op_pll_fr->pre_pll_clk_div & 1)) { + op_pll_fr->pre_pll_clk_div += + (pll->flags & CCS_PLL_FLAG_EXT_IP_PLL_DIVIDER) ? 1 : + 2 - (op_pll_fr->pre_pll_clk_div & 1)) { rval = __ccs_pll_calculate(dev, lim, op_lim_fr, op_lim_bk, pll, op_pll_fr, op_pll_bk, mul, div); if (rval) diff --git a/drivers/media/i2c/ccs-pll.h b/drivers/media/i2c/ccs-pll.h index fe20af11a068..807ae7250aa2 100644 --- a/drivers/media/i2c/ccs-pll.h +++ b/drivers/media/i2c/ccs-pll.h @@ -25,6 +25,7 @@ /* CCS PLL flags */ #define CCS_PLL_FLAG_LANE_SPEED_MODEL BIT(2) #define CCS_PLL_FLAG_LINK_DECOUPLED BIT(3) +#define CCS_PLL_FLAG_EXT_IP_PLL_DIVIDER BIT(4) /** * struct ccs_pll_branch_fr - CCS PLL configuration (front) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 855e51675864..6c2b8a4259fd 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -3219,6 +3219,9 @@ static int ccs_probe(struct i2c_client *client) sensor->pll.op_lanes = sensor->pll.csi2.lanes; } } + if (CCS_LIM(sensor, CLOCK_TREE_PLL_CAPABILITY) & + CCS_CLOCK_TREE_PLL_CAPABILITY_EXT_DIVIDER) + sensor->pll.flags |= CCS_PLL_FLAG_EXT_IP_PLL_DIVIDER; sensor->pll.ext_clk_freq_hz = sensor->hwcfg.ext_clk; sensor->pll.scale_n = CCS_LIM(sensor, SCALER_N_MIN); -- cgit v1.2.3 From c4c0b222720d413cc866275a0200019eb3c58f33 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 7 Aug 2020 11:00:59 +0200 Subject: media: ccs-pll: Support two cycles per pixel on OP domain The l parameter defines the number of clock cycles to process a single pixel per OP lane. It is calculated based on a new register op_bits_per_lane. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 19 +++++++++++++------ drivers/media/i2c/ccs-pll.h | 2 ++ drivers/media/i2c/ccs/ccs-core.c | 1 + 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index 62939ca5b8e2..60ab0c043c7a 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -162,7 +162,7 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, const struct ccs_pll_branch_limits_bk *op_lim_bk, struct ccs_pll *pll, struct ccs_pll_branch_fr *op_pll_fr, struct ccs_pll_branch_bk *op_pll_bk, uint32_t mul, - uint32_t div) + uint32_t div, uint32_t l) { uint32_t sys_div; uint32_t best_pix_div = INT_MAX >> 1; @@ -252,10 +252,15 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, op_pll_fr->pll_op_clk_freq_hz = op_pll_fr->pll_ip_clk_freq_hz * op_pll_fr->pll_multiplier; - op_pll_bk->pix_clk_div = pll->bits_per_pixel - * pll->op_lanes / pll->csi2.lanes; + if (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL) + op_pll_bk->pix_clk_div = pll->bits_per_pixel + * pll->op_lanes / pll->csi2.lanes / l; + else + op_pll_bk->pix_clk_div = pll->bits_per_pixel / l; + op_pll_bk->pix_clk_freq_hz = op_pll_bk->sys_clk_freq_hz / op_pll_bk->pix_clk_div; + dev_dbg(dev, "op_pix_clk_div: %u\n", op_pll_bk->pix_clk_div); if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS) { @@ -291,7 +296,7 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, dev_dbg(dev, "scale_m: %u\n", pll->scale_m); min_vt_div = DIV_ROUND_UP(op_pll_bk->pix_clk_div * op_pll_bk->sys_clk_div * pll->scale_n - * pll->vt_lanes, + * pll->vt_lanes * l, pll->op_lanes * vt_op_binning_div * pll->scale_m); @@ -406,6 +411,8 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, uint16_t min_op_pre_pll_clk_div; uint16_t max_op_pre_pll_clk_div; uint32_t mul, div; + uint32_t l = (!pll->op_bits_per_lane || + pll->op_bits_per_lane >= pll->bits_per_pixel) ? 1 : 2; uint32_t i; int rval = -EINVAL; @@ -444,7 +451,7 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, pll->pixel_rate_csi = op_pll_bk->pix_clk_freq_hz * (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ? - pll->csi2.lanes : 1); + pll->csi2.lanes : 1) / l; /* Figure out limits for OP pre-pll divider based on extclk */ dev_dbg(dev, "min / max op_pre_pll_clk_div: %u / %u\n", @@ -482,7 +489,7 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, (pll->flags & CCS_PLL_FLAG_EXT_IP_PLL_DIVIDER) ? 1 : 2 - (op_pll_fr->pre_pll_clk_div & 1)) { rval = __ccs_pll_calculate(dev, lim, op_lim_fr, op_lim_bk, pll, - op_pll_fr, op_pll_bk, mul, div); + op_pll_fr, op_pll_bk, mul, div, l); if (rval) continue; diff --git a/drivers/media/i2c/ccs-pll.h b/drivers/media/i2c/ccs-pll.h index 807ae7250aa2..207822cf2324 100644 --- a/drivers/media/i2c/ccs-pll.h +++ b/drivers/media/i2c/ccs-pll.h @@ -76,6 +76,7 @@ struct ccs_pll_branch_bk { * @scale_m: Downscaling factor, M component, [16, max] (input) * @scale_n: Downscaling factor, N component, typically 16 (input) * @bits_per_pixel: Bits per pixel on the output data bus (input) + * @op_bits_per_lane: Number of bits per OP lane (input) * @flags: CCS_PLL_FLAG_* (input) * @link_freq: Chosen link frequency (input) * @ext_clk_freq_hz: External clock frequency, i.e. the sensor's input clock @@ -100,6 +101,7 @@ struct ccs_pll { uint8_t scale_m; uint8_t scale_n; uint8_t bits_per_pixel; + uint8_t op_bits_per_lane; uint16_t flags; uint32_t link_freq; uint32_t ext_clk_freq_hz; diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 6c2b8a4259fd..d39da0f31d90 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -3222,6 +3222,7 @@ static int ccs_probe(struct i2c_client *client) if (CCS_LIM(sensor, CLOCK_TREE_PLL_CAPABILITY) & CCS_CLOCK_TREE_PLL_CAPABILITY_EXT_DIVIDER) sensor->pll.flags |= CCS_PLL_FLAG_EXT_IP_PLL_DIVIDER; + sensor->pll.op_bits_per_lane = CCS_LIM(sensor, OP_BITS_PER_LANE); sensor->pll.ext_clk_freq_hz = sensor->hwcfg.ext_clk; sensor->pll.scale_n = CCS_LIM(sensor, SCALER_N_MIN); -- cgit v1.2.3 From 9490a2279fab29cf8730120b54c42ef2fc67171c Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 7 Aug 2020 11:07:14 +0200 Subject: media: ccs-pll: Add support flexible OP PLL pixel clock divider Flexible OP PLL pixel clock divider allows a higher OP pixel clock than what the bus can transfer. This generally makes it easier to select pixel clock dividers. This changes how the pixel rate on the bus and minimum VT divisor are calculated, as the pixel rate is no longer directly determined by the OP pixel clock and the number of the lanes. Also add a sanity check for sensors that do not support flexible OP PLL pixel clock divider. This could have caused the PLL calculator to come up with an invalid configuration for those devices. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 26 +++++++++++++++++++------- drivers/media/i2c/ccs-pll.h | 1 + drivers/media/i2c/ccs/ccs-core.c | 4 +++- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index 60ab0c043c7a..e3a6493fd601 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -294,11 +294,11 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, * Find absolute limits for the factor of vt divider. */ dev_dbg(dev, "scale_m: %u\n", pll->scale_m); - min_vt_div = DIV_ROUND_UP(op_pll_bk->pix_clk_div - * op_pll_bk->sys_clk_div * pll->scale_n - * pll->vt_lanes * l, - pll->op_lanes * vt_op_binning_div - * pll->scale_m); + min_vt_div = DIV_ROUND_UP(pll->bits_per_pixel * op_pll_bk->sys_clk_div + * pll->scale_n * pll->vt_lanes, + (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ? + pll->csi2.lanes : 1) + * vt_op_binning_div * pll->scale_m); /* Find smallest and biggest allowed vt divisor. */ dev_dbg(dev, "min_vt_div: %u\n", min_vt_div); @@ -420,6 +420,18 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, pll->op_lanes = 1; pll->vt_lanes = 1; } + + /* + * Make sure op_pix_clk_div will be integer --- unless flexible + * op_pix_clk_div is supported + */ + if (!(pll->flags & CCS_PLL_FLAG_FLEXIBLE_OP_PIX_CLK_DIV) && + (pll->bits_per_pixel * pll->op_lanes) % (pll->csi2.lanes * l)) { + dev_dbg(dev, "op_pix_clk_div not an integer (bpp %u, op lanes %u, lanes %u, l %u)\n", + pll->bits_per_pixel, pll->op_lanes, pll->csi2.lanes, l); + return -EINVAL; + } + dev_dbg(dev, "vt_lanes: %u\n", pll->vt_lanes); dev_dbg(dev, "op_lanes: %u\n", pll->op_lanes); @@ -449,9 +461,9 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, } pll->pixel_rate_csi = - op_pll_bk->pix_clk_freq_hz + op_pll_bk->sys_clk_freq_hz * (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ? - pll->csi2.lanes : 1) / l; + pll->csi2.lanes : 1) / pll->bits_per_pixel / l; /* Figure out limits for OP pre-pll divider based on extclk */ dev_dbg(dev, "min / max op_pre_pll_clk_div: %u / %u\n", diff --git a/drivers/media/i2c/ccs-pll.h b/drivers/media/i2c/ccs-pll.h index 207822cf2324..1b5c20736fe8 100644 --- a/drivers/media/i2c/ccs-pll.h +++ b/drivers/media/i2c/ccs-pll.h @@ -26,6 +26,7 @@ #define CCS_PLL_FLAG_LANE_SPEED_MODEL BIT(2) #define CCS_PLL_FLAG_LINK_DECOUPLED BIT(3) #define CCS_PLL_FLAG_EXT_IP_PLL_DIVIDER BIT(4) +#define CCS_PLL_FLAG_FLEXIBLE_OP_PIX_CLK_DIV BIT(5) /** * struct ccs_pll_branch_fr - CCS PLL configuration (front) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index d39da0f31d90..21158e6d0159 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -30,7 +30,6 @@ #include #include "ccs.h" -#include "ccs-limits.h" #define CCS_ALIGN_DIM(dim, flags) \ ((flags) & V4L2_SEL_FLAG_GE \ @@ -3222,6 +3221,9 @@ static int ccs_probe(struct i2c_client *client) if (CCS_LIM(sensor, CLOCK_TREE_PLL_CAPABILITY) & CCS_CLOCK_TREE_PLL_CAPABILITY_EXT_DIVIDER) sensor->pll.flags |= CCS_PLL_FLAG_EXT_IP_PLL_DIVIDER; + if (CCS_LIM(sensor, CLOCK_TREE_PLL_CAPABILITY) & + CCS_CLOCK_TREE_PLL_CAPABILITY_FLEXIBLE_OP_PIX_CLK_DIV) + sensor->pll.flags |= CCS_PLL_FLAG_FLEXIBLE_OP_PIX_CLK_DIV; sensor->pll.op_bits_per_lane = CCS_LIM(sensor, OP_BITS_PER_LANE); sensor->pll.ext_clk_freq_hz = sensor->hwcfg.ext_clk; sensor->pll.scale_n = CCS_LIM(sensor, SCALER_N_MIN); -- cgit v1.2.3 From d7172c0ebc06b6a363db96fd2fcbd1008f307e4c Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 4 Aug 2020 12:58:30 +0200 Subject: media: ccs-pll: Add sanity checks Add sanity checks for fields that could cause division by zero. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index e3a6493fd601..420d2c4d7b2c 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -421,6 +421,15 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, pll->vt_lanes = 1; } + if (!pll->op_lanes || !pll->vt_lanes || !pll->bits_per_pixel || + !pll->ext_clk_freq_hz || !pll->link_freq || !pll->scale_m || + !op_lim_fr->min_pll_ip_clk_freq_hz || + !op_lim_fr->max_pll_ip_clk_freq_hz || + !op_lim_fr->min_pll_op_clk_freq_hz || + !op_lim_fr->max_pll_op_clk_freq_hz || + !op_lim_bk->max_sys_clk_div || !op_lim_fr->max_pll_multiplier) + return -EINVAL; + /* * Make sure op_pix_clk_div will be integer --- unless flexible * op_pix_clk_div is supported -- cgit v1.2.3 From 8030aa4f9c512ecf8b91b37c88ab6b479e71c8a4 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 3 Jul 2020 09:48:06 +0200 Subject: media: ccs-pll: Add C-PHY support Add C-PHY support for the CCS PLL calculator. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index 420d2c4d7b2c..0fa7c6f67195 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -145,6 +145,10 @@ static int check_all_bounds(struct device *dev, return rval; } +#define CPHY_CONST 7 +#define DPHY_CONST 16 +#define PHY_CONST_DIV 16 + /* * Heuristically guess the PLL tree for a given common multiplier and * divisor. Begin with the operational timing and continue to video @@ -162,7 +166,7 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, const struct ccs_pll_branch_limits_bk *op_lim_bk, struct ccs_pll *pll, struct ccs_pll_branch_fr *op_pll_fr, struct ccs_pll_branch_bk *op_pll_bk, uint32_t mul, - uint32_t div, uint32_t l) + uint32_t div, uint32_t l, bool cphy, uint32_t phy_const) { uint32_t sys_div; uint32_t best_pix_div = INT_MAX >> 1; @@ -254,9 +258,11 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, if (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL) op_pll_bk->pix_clk_div = pll->bits_per_pixel - * pll->op_lanes / pll->csi2.lanes / l; + * pll->op_lanes * phy_const + / PHY_CONST_DIV / pll->csi2.lanes / l; else - op_pll_bk->pix_clk_div = pll->bits_per_pixel / l; + op_pll_bk->pix_clk_div = + pll->bits_per_pixel * phy_const / PHY_CONST_DIV / l; op_pll_bk->pix_clk_freq_hz = op_pll_bk->sys_clk_freq_hz / op_pll_bk->pix_clk_div; @@ -295,10 +301,11 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, */ dev_dbg(dev, "scale_m: %u\n", pll->scale_m); min_vt_div = DIV_ROUND_UP(pll->bits_per_pixel * op_pll_bk->sys_clk_div - * pll->scale_n * pll->vt_lanes, + * pll->scale_n * pll->vt_lanes * phy_const, (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ? pll->csi2.lanes : 1) - * vt_op_binning_div * pll->scale_m); + * vt_op_binning_div * pll->scale_m + * PHY_CONST_DIV); /* Find smallest and biggest allowed vt divisor. */ dev_dbg(dev, "min_vt_div: %u\n", min_vt_div); @@ -408,6 +415,8 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, const struct ccs_pll_branch_limits_bk *op_lim_bk = &lim->op_bk; struct ccs_pll_branch_fr *op_pll_fr = &pll->vt_fr; struct ccs_pll_branch_bk *op_pll_bk = &pll->op_bk; + bool cphy = pll->bus_type == CCS_PLL_BUS_TYPE_CSI2_CPHY; + uint32_t phy_const = cphy ? CPHY_CONST : DPHY_CONST; uint16_t min_op_pre_pll_clk_div; uint16_t max_op_pre_pll_clk_div; uint32_t mul, div; @@ -465,14 +474,21 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, * (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ? 1 : pll->csi2.lanes); break; + case CCS_PLL_BUS_TYPE_CSI2_CPHY: + op_pll_bk->sys_clk_freq_hz = + pll->link_freq + * (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ? + 1 : pll->csi2.lanes); + break; default: return -EINVAL; } pll->pixel_rate_csi = - op_pll_bk->sys_clk_freq_hz - * (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ? - pll->csi2.lanes : 1) / pll->bits_per_pixel / l; + div_u64((uint64_t)op_pll_bk->sys_clk_freq_hz + * (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ? + pll->csi2.lanes : 1) * PHY_CONST_DIV, + phy_const * pll->bits_per_pixel * l); /* Figure out limits for OP pre-pll divider based on extclk */ dev_dbg(dev, "min / max op_pre_pll_clk_div: %u / %u\n", @@ -510,7 +526,8 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, (pll->flags & CCS_PLL_FLAG_EXT_IP_PLL_DIVIDER) ? 1 : 2 - (op_pll_fr->pre_pll_clk_div & 1)) { rval = __ccs_pll_calculate(dev, lim, op_lim_fr, op_lim_bk, pll, - op_pll_fr, op_pll_bk, mul, div, l); + op_pll_fr, op_pll_bk, mul, div, l, + cphy, phy_const); if (rval) continue; -- cgit v1.2.3 From 3e2db036c9b706e68016db7610c333ed926425be Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 25 Aug 2020 22:23:43 +0200 Subject: media: ccs-pll: Split off VT subtree calculation Split off the VT sub clock tree calculation from the rest, into its own function. Also call the op_pll_fr argument pll_fr, since soon these may not be OP tree values. This paves way for additional features in the future such as dual PLL support. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 255 +++++++++++++++++++++++--------------------- 1 file changed, 131 insertions(+), 124 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index 0fa7c6f67195..3d43e737155f 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -149,130 +149,18 @@ static int check_all_bounds(struct device *dev, #define DPHY_CONST 16 #define PHY_CONST_DIV 16 -/* - * Heuristically guess the PLL tree for a given common multiplier and - * divisor. Begin with the operational timing and continue to video - * timing once operational timing has been verified. - * - * @mul is the PLL multiplier and @div is the common divisor - * (pre_pll_clk_div and op_sys_clk_div combined). The final PLL - * multiplier will be a multiple of @mul. - * - * @return Zero on success, error code on error. - */ -static int -__ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, - const struct ccs_pll_branch_limits_fr *op_lim_fr, - const struct ccs_pll_branch_limits_bk *op_lim_bk, - struct ccs_pll *pll, struct ccs_pll_branch_fr *op_pll_fr, - struct ccs_pll_branch_bk *op_pll_bk, uint32_t mul, - uint32_t div, uint32_t l, bool cphy, uint32_t phy_const) +static void +__ccs_pll_calculate_vt(struct device *dev, const struct ccs_pll_limits *lim, + const struct ccs_pll_branch_limits_bk *op_lim_bk, + struct ccs_pll *pll, struct ccs_pll_branch_fr *pll_fr, + struct ccs_pll_branch_bk *op_pll_bk, bool cphy, + uint32_t phy_const) { uint32_t sys_div; uint32_t best_pix_div = INT_MAX >> 1; uint32_t vt_op_binning_div; - /* - * Higher multipliers (and divisors) are often required than - * necessitated by the external clock and the output clocks. - * There are limits for all values in the clock tree. These - * are the minimum and maximum multiplier for mul. - */ - uint32_t more_mul_min, more_mul_max; - uint32_t more_mul_factor; uint32_t min_vt_div, max_vt_div, vt_div; uint32_t min_sys_div, max_sys_div; - uint32_t i; - - /* - * Get pre_pll_clk_div so that our pll_op_clk_freq_hz won't be - * too high. - */ - dev_dbg(dev, "op_pre_pll_clk_div %u\n", op_pll_fr->pre_pll_clk_div); - - /* Don't go above max pll multiplier. */ - more_mul_max = op_lim_fr->max_pll_multiplier / mul; - dev_dbg(dev, "more_mul_max: max_op_pll_multiplier check: %u\n", - more_mul_max); - /* Don't go above max pll op frequency. */ - more_mul_max = - min_t(uint32_t, - more_mul_max, - op_lim_fr->max_pll_op_clk_freq_hz - / (pll->ext_clk_freq_hz / - op_pll_fr->pre_pll_clk_div * mul)); - dev_dbg(dev, "more_mul_max: max_pll_op_clk_freq_hz check: %u\n", - more_mul_max); - /* Don't go above the division capability of op sys clock divider. */ - more_mul_max = min(more_mul_max, - op_lim_bk->max_sys_clk_div * op_pll_fr->pre_pll_clk_div - / div); - dev_dbg(dev, "more_mul_max: max_op_sys_clk_div check: %u\n", - more_mul_max); - /* Ensure we won't go above max_pll_multiplier. */ - more_mul_max = min(more_mul_max, op_lim_fr->max_pll_multiplier / mul); - dev_dbg(dev, "more_mul_max: min_pll_multiplier check: %u\n", - more_mul_max); - - /* Ensure we won't go below min_pll_op_clk_freq_hz. */ - more_mul_min = DIV_ROUND_UP(op_lim_fr->min_pll_op_clk_freq_hz, - pll->ext_clk_freq_hz / - op_pll_fr->pre_pll_clk_div * mul); - dev_dbg(dev, "more_mul_min: min_op_pll_op_clk_freq_hz check: %u\n", - more_mul_min); - /* Ensure we won't go below min_pll_multiplier. */ - more_mul_min = max(more_mul_min, - DIV_ROUND_UP(op_lim_fr->min_pll_multiplier, mul)); - dev_dbg(dev, "more_mul_min: min_op_pll_multiplier check: %u\n", - more_mul_min); - - if (more_mul_min > more_mul_max) { - dev_dbg(dev, - "unable to compute more_mul_min and more_mul_max\n"); - return -EINVAL; - } - - more_mul_factor = lcm(div, op_pll_fr->pre_pll_clk_div) / div; - dev_dbg(dev, "more_mul_factor: %u\n", more_mul_factor); - more_mul_factor = lcm(more_mul_factor, op_lim_bk->min_sys_clk_div); - dev_dbg(dev, "more_mul_factor: min_op_sys_clk_div: %d\n", - more_mul_factor); - i = roundup(more_mul_min, more_mul_factor); - if (!is_one_or_even(i)) - i <<= 1; - - dev_dbg(dev, "final more_mul: %u\n", i); - if (i > more_mul_max) { - dev_dbg(dev, "final more_mul is bad, max %u\n", more_mul_max); - return -EINVAL; - } - - op_pll_fr->pll_multiplier = mul * i; - op_pll_bk->sys_clk_div = div * i / op_pll_fr->pre_pll_clk_div; - dev_dbg(dev, "op_sys_clk_div: %u\n", op_pll_bk->sys_clk_div); - - op_pll_fr->pll_ip_clk_freq_hz = pll->ext_clk_freq_hz - / op_pll_fr->pre_pll_clk_div; - - op_pll_fr->pll_op_clk_freq_hz = op_pll_fr->pll_ip_clk_freq_hz - * op_pll_fr->pll_multiplier; - - if (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL) - op_pll_bk->pix_clk_div = pll->bits_per_pixel - * pll->op_lanes * phy_const - / PHY_CONST_DIV / pll->csi2.lanes / l; - else - op_pll_bk->pix_clk_div = - pll->bits_per_pixel * phy_const / PHY_CONST_DIV / l; - - op_pll_bk->pix_clk_freq_hz = - op_pll_bk->sys_clk_freq_hz / op_pll_bk->pix_clk_div; - - dev_dbg(dev, "op_pix_clk_div: %u\n", op_pll_bk->pix_clk_div); - - if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS) { - /* No OP clocks --- VT clocks are used instead. */ - goto out_skip_vt_calc; - } /* * Some sensors perform analogue binning and some do this @@ -310,7 +198,7 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, /* Find smallest and biggest allowed vt divisor. */ dev_dbg(dev, "min_vt_div: %u\n", min_vt_div); min_vt_div = max(min_vt_div, - DIV_ROUND_UP(op_pll_fr->pll_op_clk_freq_hz, + DIV_ROUND_UP(pll_fr->pll_op_clk_freq_hz, lim->vt_bk.max_pix_clk_freq_hz)); dev_dbg(dev, "min_vt_div: max_vt_pix_clk_freq_hz: %u\n", min_vt_div); @@ -322,7 +210,7 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, max_vt_div = lim->vt_bk.max_sys_clk_div * lim->vt_bk.max_pix_clk_div; dev_dbg(dev, "max_vt_div: %u\n", max_vt_div); max_vt_div = min(max_vt_div, - DIV_ROUND_UP(op_pll_fr->pll_op_clk_freq_hz, + DIV_ROUND_UP(pll_fr->pll_op_clk_freq_hz, lim->vt_bk.min_pix_clk_freq_hz)); dev_dbg(dev, "max_vt_div: min_vt_pix_clk_freq_hz: %u\n", max_vt_div); @@ -338,7 +226,7 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, lim->vt_bk.max_pix_clk_div)); dev_dbg(dev, "min_sys_div: max_vt_pix_clk_div: %u\n", min_sys_div); min_sys_div = max(min_sys_div, - op_pll_fr->pll_op_clk_freq_hz + pll_fr->pll_op_clk_freq_hz / lim->vt_bk.max_sys_clk_freq_hz); dev_dbg(dev, "min_sys_div: max_pll_op_clk_freq_hz: %u\n", min_sys_div); min_sys_div = clk_div_even_up(min_sys_div); @@ -351,7 +239,7 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, lim->vt_bk.min_pix_clk_div)); dev_dbg(dev, "max_sys_div: min_vt_pix_clk_div: %u\n", max_sys_div); max_sys_div = min(max_sys_div, - DIV_ROUND_UP(op_pll_fr->pll_op_clk_freq_hz, + DIV_ROUND_UP(pll_fr->pll_op_clk_freq_hz, lim->vt_bk.min_pix_clk_freq_hz)); dev_dbg(dev, "max_sys_div: min_vt_pix_clk_freq_hz: %u\n", max_sys_div); @@ -396,11 +284,130 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, pll->vt_bk.pix_clk_div = best_pix_div; pll->vt_bk.sys_clk_freq_hz = - op_pll_fr->pll_op_clk_freq_hz / pll->vt_bk.sys_clk_div; + pll_fr->pll_op_clk_freq_hz / pll->vt_bk.sys_clk_div; pll->vt_bk.pix_clk_freq_hz = pll->vt_bk.sys_clk_freq_hz / pll->vt_bk.pix_clk_div; +} + +/* + * Heuristically guess the PLL tree for a given common multiplier and + * divisor. Begin with the operational timing and continue to video + * timing once operational timing has been verified. + * + * @mul is the PLL multiplier and @div is the common divisor + * (pre_pll_clk_div and op_sys_clk_div combined). The final PLL + * multiplier will be a multiple of @mul. + * + * @return Zero on success, error code on error. + */ +static int +__ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, + const struct ccs_pll_branch_limits_fr *op_lim_fr, + const struct ccs_pll_branch_limits_bk *op_lim_bk, + struct ccs_pll *pll, struct ccs_pll_branch_fr *op_pll_fr, + struct ccs_pll_branch_bk *op_pll_bk, uint32_t mul, + uint32_t div, uint32_t l, bool cphy, uint32_t phy_const) +{ + /* + * Higher multipliers (and divisors) are often required than + * necessitated by the external clock and the output clocks. + * There are limits for all values in the clock tree. These + * are the minimum and maximum multiplier for mul. + */ + uint32_t more_mul_min, more_mul_max; + uint32_t more_mul_factor; + uint32_t i; + + /* + * Get pre_pll_clk_div so that our pll_op_clk_freq_hz won't be + * too high. + */ + dev_dbg(dev, "op_pre_pll_clk_div %u\n", op_pll_fr->pre_pll_clk_div); + + /* Don't go above max pll multiplier. */ + more_mul_max = op_lim_fr->max_pll_multiplier / mul; + dev_dbg(dev, "more_mul_max: max_op_pll_multiplier check: %u\n", + more_mul_max); + /* Don't go above max pll op frequency. */ + more_mul_max = + min_t(uint32_t, + more_mul_max, + op_lim_fr->max_pll_op_clk_freq_hz + / (pll->ext_clk_freq_hz / + op_pll_fr->pre_pll_clk_div * mul)); + dev_dbg(dev, "more_mul_max: max_pll_op_clk_freq_hz check: %u\n", + more_mul_max); + /* Don't go above the division capability of op sys clock divider. */ + more_mul_max = min(more_mul_max, + op_lim_bk->max_sys_clk_div * op_pll_fr->pre_pll_clk_div + / div); + dev_dbg(dev, "more_mul_max: max_op_sys_clk_div check: %u\n", + more_mul_max); + /* Ensure we won't go above max_pll_multiplier. */ + more_mul_max = min(more_mul_max, op_lim_fr->max_pll_multiplier / mul); + dev_dbg(dev, "more_mul_max: min_pll_multiplier check: %u\n", + more_mul_max); + + /* Ensure we won't go below min_pll_op_clk_freq_hz. */ + more_mul_min = DIV_ROUND_UP(op_lim_fr->min_pll_op_clk_freq_hz, + pll->ext_clk_freq_hz / + op_pll_fr->pre_pll_clk_div * mul); + dev_dbg(dev, "more_mul_min: min_op_pll_op_clk_freq_hz check: %u\n", + more_mul_min); + /* Ensure we won't go below min_pll_multiplier. */ + more_mul_min = max(more_mul_min, + DIV_ROUND_UP(op_lim_fr->min_pll_multiplier, mul)); + dev_dbg(dev, "more_mul_min: min_op_pll_multiplier check: %u\n", + more_mul_min); + + if (more_mul_min > more_mul_max) { + dev_dbg(dev, + "unable to compute more_mul_min and more_mul_max\n"); + return -EINVAL; + } + + more_mul_factor = lcm(div, op_pll_fr->pre_pll_clk_div) / div; + dev_dbg(dev, "more_mul_factor: %u\n", more_mul_factor); + more_mul_factor = lcm(more_mul_factor, op_lim_bk->min_sys_clk_div); + dev_dbg(dev, "more_mul_factor: min_op_sys_clk_div: %d\n", + more_mul_factor); + i = roundup(more_mul_min, more_mul_factor); + if (!is_one_or_even(i)) + i <<= 1; + + dev_dbg(dev, "final more_mul: %u\n", i); + if (i > more_mul_max) { + dev_dbg(dev, "final more_mul is bad, max %u\n", more_mul_max); + return -EINVAL; + } + + op_pll_fr->pll_multiplier = mul * i; + op_pll_bk->sys_clk_div = div * i / op_pll_fr->pre_pll_clk_div; + dev_dbg(dev, "op_sys_clk_div: %u\n", op_pll_bk->sys_clk_div); + + op_pll_fr->pll_ip_clk_freq_hz = pll->ext_clk_freq_hz + / op_pll_fr->pre_pll_clk_div; + + op_pll_fr->pll_op_clk_freq_hz = op_pll_fr->pll_ip_clk_freq_hz + * op_pll_fr->pll_multiplier; + + if (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL) + op_pll_bk->pix_clk_div = pll->bits_per_pixel + * pll->op_lanes * phy_const + / PHY_CONST_DIV / pll->csi2.lanes / l; + else + op_pll_bk->pix_clk_div = + pll->bits_per_pixel * phy_const / PHY_CONST_DIV / l; + + op_pll_bk->pix_clk_freq_hz = + op_pll_bk->sys_clk_freq_hz / op_pll_bk->pix_clk_div; + + dev_dbg(dev, "op_pix_clk_div: %u\n", op_pll_bk->pix_clk_div); + + if (!(pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS)) + __ccs_pll_calculate_vt(dev, lim, op_lim_bk, pll, op_pll_fr, + op_pll_bk, cphy, phy_const); -out_skip_vt_calc: pll->pixel_rate_pixel_array = pll->vt_bk.pix_clk_freq_hz * pll->vt_lanes; -- cgit v1.2.3 From 38c94eb8d7aa60e32ed6da9e4ecd4b5a1597760e Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 28 Aug 2020 08:24:18 +0200 Subject: media: ccs-pll: Check for derating and overrating, support non-derating sensors Some sensors support derating (VT domain speed faster than OP) or overrating (VT domain speed slower than OP). While this was supported for the driver, the hardware support for the feature was never verified. Do that now, and for those devices without that support, VT and OP speeds have to match. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 84 ++++++++++++++++++++++++++-------------- drivers/media/i2c/ccs-pll.h | 2 + drivers/media/i2c/ccs/ccs-core.c | 7 ++++ 3 files changed, 64 insertions(+), 29 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index 3d43e737155f..96eb71f16c81 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -142,6 +142,18 @@ static int check_all_bounds(struct device *dev, lim->vt_bk.max_pix_clk_freq_hz, "vt_pix_clk_freq_hz"); + if (!(pll->flags & CCS_PLL_FLAG_FIFO_DERATING) && + pll->pixel_rate_pixel_array > pll->pixel_rate_csi) { + dev_dbg(dev, "device does not support derating\n"); + return -EINVAL; + } + + if (!(pll->flags & CCS_PLL_FLAG_FIFO_OVERRATING) && + pll->pixel_rate_pixel_array < pll->pixel_rate_csi) { + dev_dbg(dev, "device does not support overrating\n"); + return -EINVAL; + } + return rval; } @@ -163,37 +175,51 @@ __ccs_pll_calculate_vt(struct device *dev, const struct ccs_pll_limits *lim, uint32_t min_sys_div, max_sys_div; /* - * Some sensors perform analogue binning and some do this - * digitally. The ones doing this digitally can be roughly be - * found out using this formula. The ones doing this digitally - * should run at higher clock rate, so smaller divisor is used - * on video timing side. + * Find out whether a sensor supports derating. If it does not, VT and + * OP domains are required to run at the same pixel rate. */ - if (lim->min_line_length_pck_bin > lim->min_line_length_pck - / pll->binning_horizontal) - vt_op_binning_div = pll->binning_horizontal; - else - vt_op_binning_div = 1; - dev_dbg(dev, "vt_op_binning_div: %u\n", vt_op_binning_div); + if (!(pll->flags & CCS_PLL_FLAG_FIFO_DERATING)) { + min_vt_div = + op_pll_bk->sys_clk_div * op_pll_bk->pix_clk_div + * pll->vt_lanes * phy_const + / pll->op_lanes / PHY_CONST_DIV; + } else { + /* + * Some sensors perform analogue binning and some do this + * digitally. The ones doing this digitally can be roughly be + * found out using this formula. The ones doing this digitally + * should run at higher clock rate, so smaller divisor is used + * on video timing side. + */ + if (lim->min_line_length_pck_bin > lim->min_line_length_pck + / pll->binning_horizontal) + vt_op_binning_div = pll->binning_horizontal; + else + vt_op_binning_div = 1; + dev_dbg(dev, "vt_op_binning_div: %u\n", vt_op_binning_div); - /* - * Profile 2 supports vt_pix_clk_div E [4, 10] - * - * Horizontal binning can be used as a base for difference in - * divisors. One must make sure that horizontal blanking is - * enough to accommodate the CSI-2 sync codes. - * - * Take scaling factor and number of VT lanes into account as well. - * - * Find absolute limits for the factor of vt divider. - */ - dev_dbg(dev, "scale_m: %u\n", pll->scale_m); - min_vt_div = DIV_ROUND_UP(pll->bits_per_pixel * op_pll_bk->sys_clk_div - * pll->scale_n * pll->vt_lanes * phy_const, - (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ? - pll->csi2.lanes : 1) - * vt_op_binning_div * pll->scale_m - * PHY_CONST_DIV); + /* + * Profile 2 supports vt_pix_clk_div E [4, 10] + * + * Horizontal binning can be used as a base for difference in + * divisors. One must make sure that horizontal blanking is + * enough to accommodate the CSI-2 sync codes. + * + * Take scaling factor and number of VT lanes into account as well. + * + * Find absolute limits for the factor of vt divider. + */ + dev_dbg(dev, "scale_m: %u\n", pll->scale_m); + min_vt_div = + DIV_ROUND_UP(pll->bits_per_pixel + * op_pll_bk->sys_clk_div * pll->scale_n + * pll->vt_lanes * phy_const, + (pll->flags & + CCS_PLL_FLAG_LANE_SPEED_MODEL ? + pll->csi2.lanes : 1) + * vt_op_binning_div * pll->scale_m + * PHY_CONST_DIV); + } /* Find smallest and biggest allowed vt divisor. */ dev_dbg(dev, "min_vt_div: %u\n", min_vt_div); diff --git a/drivers/media/i2c/ccs-pll.h b/drivers/media/i2c/ccs-pll.h index 1b5c20736fe8..03c2428c76cd 100644 --- a/drivers/media/i2c/ccs-pll.h +++ b/drivers/media/i2c/ccs-pll.h @@ -27,6 +27,8 @@ #define CCS_PLL_FLAG_LINK_DECOUPLED BIT(3) #define CCS_PLL_FLAG_EXT_IP_PLL_DIVIDER BIT(4) #define CCS_PLL_FLAG_FLEXIBLE_OP_PIX_CLK_DIV BIT(5) +#define CCS_PLL_FLAG_FIFO_DERATING BIT(6) +#define CCS_PLL_FLAG_FIFO_OVERRATING BIT(7) /** * struct ccs_pll_branch_fr - CCS PLL configuration (front) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 21158e6d0159..fa878ecf55a7 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -3224,6 +3224,13 @@ static int ccs_probe(struct i2c_client *client) if (CCS_LIM(sensor, CLOCK_TREE_PLL_CAPABILITY) & CCS_CLOCK_TREE_PLL_CAPABILITY_FLEXIBLE_OP_PIX_CLK_DIV) sensor->pll.flags |= CCS_PLL_FLAG_FLEXIBLE_OP_PIX_CLK_DIV; + if (CCS_LIM(sensor, FIFO_SUPPORT_CAPABILITY) & + CCS_FIFO_SUPPORT_CAPABILITY_DERATING) + sensor->pll.flags |= CCS_PLL_FLAG_FIFO_DERATING; + if (CCS_LIM(sensor, FIFO_SUPPORT_CAPABILITY) & + CCS_FIFO_SUPPORT_CAPABILITY_DERATING_OVERRATING) + sensor->pll.flags |= CCS_PLL_FLAG_FIFO_DERATING | + CCS_PLL_FLAG_FIFO_OVERRATING; sensor->pll.op_bits_per_lane = CCS_LIM(sensor, OP_BITS_PER_LANE); sensor->pll.ext_clk_freq_hz = sensor->hwcfg.ext_clk; sensor->pll.scale_n = CCS_LIM(sensor, SCALER_N_MIN); -- cgit v1.2.3 From a38836b2d026397a56ee9c90ba707c777075b0a1 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 4 Sep 2020 10:52:13 +0200 Subject: media: ccs-pll: Better separate OP and VT sub-tree calculation Better separate OP PLL branch calculation from VT branch calculation. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 54 ++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index 96eb71f16c81..e879c03a3d3b 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -162,11 +162,11 @@ static int check_all_bounds(struct device *dev, #define PHY_CONST_DIV 16 static void -__ccs_pll_calculate_vt(struct device *dev, const struct ccs_pll_limits *lim, - const struct ccs_pll_branch_limits_bk *op_lim_bk, - struct ccs_pll *pll, struct ccs_pll_branch_fr *pll_fr, - struct ccs_pll_branch_bk *op_pll_bk, bool cphy, - uint32_t phy_const) +ccs_pll_calculate_vt(struct device *dev, const struct ccs_pll_limits *lim, + const struct ccs_pll_branch_limits_bk *op_lim_bk, + struct ccs_pll *pll, struct ccs_pll_branch_fr *pll_fr, + struct ccs_pll_branch_bk *op_pll_bk, bool cphy, + uint32_t phy_const) { uint32_t sys_div; uint32_t best_pix_div = INT_MAX >> 1; @@ -174,6 +174,9 @@ __ccs_pll_calculate_vt(struct device *dev, const struct ccs_pll_limits *lim, uint32_t min_vt_div, max_vt_div, vt_div; uint32_t min_sys_div, max_sys_div; + if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS) + goto out_calc_pixel_rate; + /* * Find out whether a sensor supports derating. If it does not, VT and * OP domains are required to run at the same pixel rate. @@ -313,6 +316,10 @@ __ccs_pll_calculate_vt(struct device *dev, const struct ccs_pll_limits *lim, pll_fr->pll_op_clk_freq_hz / pll->vt_bk.sys_clk_div; pll->vt_bk.pix_clk_freq_hz = pll->vt_bk.sys_clk_freq_hz / pll->vt_bk.pix_clk_div; + +out_calc_pixel_rate: + pll->pixel_rate_pixel_array = + pll->vt_bk.pix_clk_freq_hz * pll->vt_lanes; } /* @@ -327,12 +334,12 @@ __ccs_pll_calculate_vt(struct device *dev, const struct ccs_pll_limits *lim, * @return Zero on success, error code on error. */ static int -__ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, - const struct ccs_pll_branch_limits_fr *op_lim_fr, - const struct ccs_pll_branch_limits_bk *op_lim_bk, - struct ccs_pll *pll, struct ccs_pll_branch_fr *op_pll_fr, - struct ccs_pll_branch_bk *op_pll_bk, uint32_t mul, - uint32_t div, uint32_t l, bool cphy, uint32_t phy_const) +ccs_pll_calculate_op(struct device *dev, const struct ccs_pll_limits *lim, + const struct ccs_pll_branch_limits_fr *op_lim_fr, + const struct ccs_pll_branch_limits_bk *op_lim_bk, + struct ccs_pll *pll, struct ccs_pll_branch_fr *op_pll_fr, + struct ccs_pll_branch_bk *op_pll_bk, uint32_t mul, + uint32_t div, uint32_t l, bool cphy, uint32_t phy_const) { /* * Higher multipliers (and divisors) are often required than @@ -430,15 +437,7 @@ __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, dev_dbg(dev, "op_pix_clk_div: %u\n", op_pll_bk->pix_clk_div); - if (!(pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS)) - __ccs_pll_calculate_vt(dev, lim, op_lim_bk, pll, op_pll_fr, - op_pll_bk, cphy, phy_const); - - pll->pixel_rate_pixel_array = - pll->vt_bk.pix_clk_freq_hz * pll->vt_lanes; - - return check_all_bounds(dev, lim, op_lim_fr, op_lim_bk, pll, op_pll_fr, - op_pll_bk); + return 0; } int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, @@ -558,13 +557,22 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, op_pll_fr->pre_pll_clk_div += (pll->flags & CCS_PLL_FLAG_EXT_IP_PLL_DIVIDER) ? 1 : 2 - (op_pll_fr->pre_pll_clk_div & 1)) { - rval = __ccs_pll_calculate(dev, lim, op_lim_fr, op_lim_bk, pll, - op_pll_fr, op_pll_bk, mul, div, l, - cphy, phy_const); + rval = ccs_pll_calculate_op(dev, lim, op_lim_fr, op_lim_bk, pll, + op_pll_fr, op_pll_bk, mul, div, l, + cphy, phy_const); + if (rval) + continue; + + ccs_pll_calculate_vt(dev, lim, op_lim_bk, pll, op_pll_fr, + op_pll_bk, cphy, phy_const); + + rval = check_all_bounds(dev, lim, op_lim_fr, op_lim_bk, pll, + op_pll_fr, op_pll_bk); if (rval) continue; print_pll(dev, pll); + return 0; } -- cgit v1.2.3 From fadfe88441fcf67a15acd0fe47785f89d93782ff Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 9 Sep 2020 14:15:48 +0200 Subject: media: ccs-pll: Print relevant information on PLL tree Print information on PLL tree configuration based on the flags. This also adds support for printing dual PLL trees, and better separates between OP and VT PLL trees. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 85 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 66 insertions(+), 19 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index e879c03a3d3b..43735f6d0bb2 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -56,28 +56,75 @@ static int bounds_check(struct device *dev, uint32_t val, return -EINVAL; } -static void print_pll(struct device *dev, struct ccs_pll *pll) +#define PLL_OP 1 +#define PLL_VT 2 + +static const char *pll_string(unsigned int which) { - dev_dbg(dev, "pre_pll_clk_div\t%u\n", pll->vt_fr.pre_pll_clk_div); - dev_dbg(dev, "pll_multiplier \t%u\n", pll->vt_fr.pll_multiplier); - if (!(pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS)) { - dev_dbg(dev, "op_sys_clk_div \t%u\n", pll->op_bk.sys_clk_div); - dev_dbg(dev, "op_pix_clk_div \t%u\n", pll->op_bk.pix_clk_div); + switch (which) { + case PLL_OP: + return "op"; + case PLL_VT: + return "vt"; } - dev_dbg(dev, "vt_sys_clk_div \t%u\n", pll->vt_bk.sys_clk_div); - dev_dbg(dev, "vt_pix_clk_div \t%u\n", pll->vt_bk.pix_clk_div); - - dev_dbg(dev, "ext_clk_freq_hz \t%u\n", pll->ext_clk_freq_hz); - dev_dbg(dev, "pll_ip_clk_freq_hz \t%u\n", pll->vt_fr.pll_ip_clk_freq_hz); - dev_dbg(dev, "pll_op_clk_freq_hz \t%u\n", pll->vt_fr.pll_op_clk_freq_hz); - if (!(pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS)) { - dev_dbg(dev, "op_sys_clk_freq_hz \t%u\n", - pll->op_bk.sys_clk_freq_hz); - dev_dbg(dev, "op_pix_clk_freq_hz \t%u\n", - pll->op_bk.pix_clk_freq_hz); + + return NULL; +} + +#define PLL_FL(f) CCS_PLL_FLAG_##f + +static void print_pll(struct device *dev, struct ccs_pll *pll) +{ + const struct { + struct ccs_pll_branch_fr *fr; + struct ccs_pll_branch_bk *bk; + unsigned int which; + } branches[] = { + { &pll->vt_fr, &pll->vt_bk, PLL_VT }, + { NULL, &pll->op_bk, PLL_OP } + }, *br; + unsigned int i; + + dev_dbg(dev, "ext_clk_freq_hz\t\t%u\n", pll->ext_clk_freq_hz); + + for (i = 0, br = branches; i < ARRAY_SIZE(branches); i++, br++) { + const char *s = pll_string(br->which); + + if (br->which == PLL_VT) { + dev_dbg(dev, "%s_pre_pll_clk_div\t\t%u\n", s, + br->fr->pre_pll_clk_div); + dev_dbg(dev, "%s_pll_multiplier\t\t%u\n", s, + br->fr->pll_multiplier); + + dev_dbg(dev, "%s_pll_ip_clk_freq_hz\t%u\n", s, + br->fr->pll_ip_clk_freq_hz); + dev_dbg(dev, "%s_pll_op_clk_freq_hz\t%u\n", s, + br->fr->pll_op_clk_freq_hz); + } + + if (!(pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS) || + br->which == PLL_VT) { + dev_dbg(dev, "%s_sys_clk_div\t\t%u\n", s, + br->bk->sys_clk_div); + dev_dbg(dev, "%s_pix_clk_div\t\t%u\n", s, + br->bk->pix_clk_div); + + dev_dbg(dev, "%s_sys_clk_freq_hz\t%u\n", s, + br->bk->sys_clk_freq_hz); + dev_dbg(dev, "%s_pix_clk_freq_hz\t%u\n", s, + br->bk->pix_clk_freq_hz); + } } - dev_dbg(dev, "vt_sys_clk_freq_hz \t%u\n", pll->vt_bk.sys_clk_freq_hz); - dev_dbg(dev, "vt_pix_clk_freq_hz \t%u\n", pll->vt_bk.pix_clk_freq_hz); + + dev_dbg(dev, "flags%s%s%s%s%s%s\n", + pll->flags & PLL_FL(LANE_SPEED_MODEL) ? " lane-speed" : "", + pll->flags & PLL_FL(LINK_DECOUPLED) ? " link-decoupled" : "", + pll->flags & PLL_FL(EXT_IP_PLL_DIVIDER) ? + " ext-ip-pll-divider" : "", + pll->flags & PLL_FL(FLEXIBLE_OP_PIX_CLK_DIV) ? + " flexible-op-pix-div" : "", + pll->flags & PLL_FL(FIFO_DERATING) ? " fifo-derating" : "", + pll->flags & PLL_FL(FIFO_OVERRATING) ? " fifo-overrating" : ""); } static int check_all_bounds(struct device *dev, -- cgit v1.2.3 From f25d3962ac8f23ab4871cef1d79e10a8c34f7908 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 15 Sep 2020 10:37:32 +0200 Subject: media: ccs-pll: Rework bounds checks Refactor bounds checks so that the caller can decide what to check. This allows doing the checks early, when the values are available. This also adds front OP PLL configuration and limits. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 148 +++++++++++++++++++++++++++----------------- drivers/media/i2c/ccs-pll.h | 4 ++ 2 files changed, 95 insertions(+), 57 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index 43735f6d0bb2..a6443589b948 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -46,12 +46,14 @@ static inline uint32_t one_or_more(uint32_t a) } static int bounds_check(struct device *dev, uint32_t val, - uint32_t min, uint32_t max, char *str) + uint32_t min, uint32_t max, const char *prefix, + char *str) { if (val >= min && val <= max) return 0; - dev_dbg(dev, "%s out of bounds: %d (%d--%d)\n", str, val, min, max); + dev_dbg(dev, "%s_%s out of bounds: %d (%d--%d)\n", prefix, + str, val, min, max); return -EINVAL; } @@ -81,7 +83,7 @@ static void print_pll(struct device *dev, struct ccs_pll *pll) unsigned int which; } branches[] = { { &pll->vt_fr, &pll->vt_bk, PLL_VT }, - { NULL, &pll->op_bk, PLL_OP } + { &pll->op_fr, &pll->op_bk, PLL_OP } }, *br; unsigned int i; @@ -127,68 +129,90 @@ static void print_pll(struct device *dev, struct ccs_pll *pll) pll->flags & PLL_FL(FIFO_OVERRATING) ? " fifo-overrating" : ""); } -static int check_all_bounds(struct device *dev, - const struct ccs_pll_limits *lim, - const struct ccs_pll_branch_limits_fr *op_lim_fr, - const struct ccs_pll_branch_limits_bk *op_lim_bk, - struct ccs_pll *pll, - struct ccs_pll_branch_fr *op_pll_fr, - struct ccs_pll_branch_bk *op_pll_bk) +static int check_fr_bounds(struct device *dev, + const struct ccs_pll_limits *lim, + struct ccs_pll *pll, unsigned int which) { + const struct ccs_pll_branch_limits_fr *lim_fr; + struct ccs_pll_branch_fr *pll_fr; + const char *s = pll_string(which); int rval; - rval = bounds_check(dev, op_pll_fr->pll_ip_clk_freq_hz, - op_lim_fr->min_pll_ip_clk_freq_hz, - op_lim_fr->max_pll_ip_clk_freq_hz, - "pll_ip_clk_freq_hz"); - if (!rval) - rval = bounds_check( - dev, op_pll_fr->pll_multiplier, - op_lim_fr->min_pll_multiplier, - op_lim_fr->max_pll_multiplier, "pll_multiplier"); - if (!rval) - rval = bounds_check( - dev, op_pll_fr->pll_op_clk_freq_hz, - op_lim_fr->min_pll_op_clk_freq_hz, - op_lim_fr->max_pll_op_clk_freq_hz, "pll_op_clk_freq_hz"); + if (which == PLL_OP) { + lim_fr = &lim->op_fr; + pll_fr = &pll->op_fr; + } else { + lim_fr = &lim->vt_fr; + pll_fr = &pll->vt_fr; + } + + rval = bounds_check(dev, pll_fr->pre_pll_clk_div, + lim_fr->min_pre_pll_clk_div, + lim_fr->max_pre_pll_clk_div, s, "pre_pll_clk_div"); + if (!rval) - rval = bounds_check( - dev, op_pll_bk->sys_clk_div, - op_lim_bk->min_sys_clk_div, op_lim_bk->max_sys_clk_div, - "op_sys_clk_div"); + rval = bounds_check(dev, pll_fr->pll_ip_clk_freq_hz, + lim_fr->min_pll_ip_clk_freq_hz, + lim_fr->max_pll_ip_clk_freq_hz, + s, "pll_ip_clk_freq_hz"); if (!rval) - rval = bounds_check( - dev, op_pll_bk->sys_clk_freq_hz, - op_lim_bk->min_sys_clk_freq_hz, - op_lim_bk->max_sys_clk_freq_hz, - "op_sys_clk_freq_hz"); + rval = bounds_check(dev, pll_fr->pll_multiplier, + lim_fr->min_pll_multiplier, + lim_fr->max_pll_multiplier, + s, "pll_multiplier"); if (!rval) - rval = bounds_check( - dev, op_pll_bk->pix_clk_freq_hz, - op_lim_bk->min_pix_clk_freq_hz, - op_lim_bk->max_pix_clk_freq_hz, - "op_pix_clk_freq_hz"); + rval = bounds_check(dev, pll_fr->pll_op_clk_freq_hz, + lim_fr->min_pll_op_clk_freq_hz, + lim_fr->max_pll_op_clk_freq_hz, + s, "pll_op_clk_freq_hz"); - /* - * If there are no OP clocks, the VT clocks are contained in - * the OP clock struct. - */ - if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS) - return rval; + return rval; +} + +static int check_bk_bounds(struct device *dev, + const struct ccs_pll_limits *lim, + struct ccs_pll *pll, unsigned int which) +{ + const struct ccs_pll_branch_limits_bk *lim_bk; + struct ccs_pll_branch_bk *pll_bk; + const char *s = pll_string(which); + int rval; + + if (which == PLL_OP) { + if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS) + return 0; + lim_bk = &lim->op_bk; + pll_bk = &pll->op_bk; + } else { + lim_bk = &lim->vt_bk; + pll_bk = &pll->vt_bk; + } + + rval = bounds_check(dev, pll_bk->sys_clk_div, + lim_bk->min_sys_clk_div, + lim_bk->max_sys_clk_div, s, "op_sys_clk_div"); + if (!rval) + rval = bounds_check(dev, pll_bk->sys_clk_freq_hz, + lim_bk->min_sys_clk_freq_hz, + lim_bk->max_sys_clk_freq_hz, + s, "sys_clk_freq_hz"); if (!rval) - rval = bounds_check( - dev, pll->vt_bk.sys_clk_freq_hz, - lim->vt_bk.min_sys_clk_freq_hz, - lim->vt_bk.max_sys_clk_freq_hz, - "vt_sys_clk_freq_hz"); + rval = bounds_check(dev, pll_bk->sys_clk_div, + lim_bk->min_sys_clk_div, + lim_bk->max_sys_clk_div, + s, "sys_clk_div"); if (!rval) - rval = bounds_check( - dev, pll->vt_bk.pix_clk_freq_hz, - lim->vt_bk.min_pix_clk_freq_hz, - lim->vt_bk.max_pix_clk_freq_hz, - "vt_pix_clk_freq_hz"); + rval = bounds_check(dev, pll_bk->pix_clk_freq_hz, + lim_bk->min_pix_clk_freq_hz, + lim_bk->max_pix_clk_freq_hz, + s, "pix_clk_freq_hz"); + + return rval; +} +static int check_ext_bounds(struct device *dev, struct ccs_pll *pll) +{ if (!(pll->flags & CCS_PLL_FLAG_FIFO_DERATING) && pll->pixel_rate_pixel_array > pll->pixel_rate_csi) { dev_dbg(dev, "device does not support derating\n"); @@ -201,7 +225,7 @@ static int check_all_bounds(struct device *dev, return -EINVAL; } - return rval; + return 0; } #define CPHY_CONST 7 @@ -610,11 +634,21 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, if (rval) continue; + rval = check_fr_bounds(dev, lim, pll, PLL_VT); + if (rval) + continue; + + rval = check_bk_bounds(dev, lim, pll, PLL_OP); + if (rval) + continue; + ccs_pll_calculate_vt(dev, lim, op_lim_bk, pll, op_pll_fr, op_pll_bk, cphy, phy_const); - rval = check_all_bounds(dev, lim, op_lim_fr, op_lim_bk, pll, - op_pll_fr, op_pll_bk); + rval = check_bk_bounds(dev, lim, pll, PLL_VT); + if (rval) + continue; + rval = check_ext_bounds(dev, pll); if (rval) continue; diff --git a/drivers/media/i2c/ccs-pll.h b/drivers/media/i2c/ccs-pll.h index 03c2428c76cd..6255803eee38 100644 --- a/drivers/media/i2c/ccs-pll.h +++ b/drivers/media/i2c/ccs-pll.h @@ -86,6 +86,7 @@ struct ccs_pll_branch_bk { * (input) * @vt_fr: Video timing front-end configuration (output) * @vt_bk: Video timing back-end configuration (output) + * @op_fr: Operational timing front-end configuration (output) * @op_bk: Operational timing back-end configuration (output) * @pixel_rate_csi: Pixel rate on the output data bus (output) * @pixel_rate_pixel_array: Nominal pixel rate in the sensor's pixel array @@ -112,6 +113,7 @@ struct ccs_pll { /* output values */ struct ccs_pll_branch_fr vt_fr; struct ccs_pll_branch_bk vt_bk; + struct ccs_pll_branch_fr op_fr; struct ccs_pll_branch_bk op_bk; uint32_t pixel_rate_csi; @@ -171,6 +173,7 @@ struct ccs_pll_branch_limits_bk { * @max_ext_clk_freq_hz: Maximum external clock frequency * @vt_fr: Video timing front-end limits * @vt_bk: Video timing back-end limits + * @op_fr: Operational timing front-end limits * @op_bk: Operational timing back-end limits * @min_line_length_pck_bin: Minimum line length in pixels, with binning * @min_line_length_pck: Minimum line length in pixels without binning @@ -182,6 +185,7 @@ struct ccs_pll_limits { struct ccs_pll_branch_limits_fr vt_fr; struct ccs_pll_branch_limits_bk vt_bk; + struct ccs_pll_branch_limits_fr op_fr; struct ccs_pll_branch_limits_bk op_bk; /* Other relevant limits */ -- cgit v1.2.3 From 594f1e93bb2c48bcc14a020448b46eed15be7ef7 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 15 Sep 2020 14:34:42 +0200 Subject: media: ccs-pll: Make VT divisors 16-bit Make VT divisors 16-bit unsigned numbers. They don't need 32 bits after all. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 51 ++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index a6443589b948..7512f0313010 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -239,11 +239,11 @@ ccs_pll_calculate_vt(struct device *dev, const struct ccs_pll_limits *lim, struct ccs_pll_branch_bk *op_pll_bk, bool cphy, uint32_t phy_const) { - uint32_t sys_div; - uint32_t best_pix_div = INT_MAX >> 1; - uint32_t vt_op_binning_div; - uint32_t min_vt_div, max_vt_div, vt_div; - uint32_t min_sys_div, max_sys_div; + uint16_t sys_div; + uint16_t best_pix_div = SHRT_MAX >> 1; + uint16_t vt_op_binning_div; + uint16_t min_vt_div, max_vt_div, vt_div; + uint16_t min_sys_div, max_sys_div; if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS) goto out_calc_pixel_rate; @@ -297,20 +297,19 @@ ccs_pll_calculate_vt(struct device *dev, const struct ccs_pll_limits *lim, /* Find smallest and biggest allowed vt divisor. */ dev_dbg(dev, "min_vt_div: %u\n", min_vt_div); - min_vt_div = max(min_vt_div, - DIV_ROUND_UP(pll_fr->pll_op_clk_freq_hz, - lim->vt_bk.max_pix_clk_freq_hz)); + min_vt_div = max_t(uint16_t, min_vt_div, + DIV_ROUND_UP(pll_fr->pll_op_clk_freq_hz, + lim->vt_bk.max_pix_clk_freq_hz)); dev_dbg(dev, "min_vt_div: max_vt_pix_clk_freq_hz: %u\n", min_vt_div); - min_vt_div = max_t(uint32_t, min_vt_div, - lim->vt_bk.min_pix_clk_div - * lim->vt_bk.min_sys_clk_div); + min_vt_div = max_t(uint16_t, min_vt_div, lim->vt_bk.min_pix_clk_div + * lim->vt_bk.min_sys_clk_div); dev_dbg(dev, "min_vt_div: min_vt_clk_div: %u\n", min_vt_div); max_vt_div = lim->vt_bk.max_sys_clk_div * lim->vt_bk.max_pix_clk_div; dev_dbg(dev, "max_vt_div: %u\n", max_vt_div); - max_vt_div = min(max_vt_div, - DIV_ROUND_UP(pll_fr->pll_op_clk_freq_hz, + max_vt_div = min_t(uint16_t, max_vt_div, + DIV_ROUND_UP(pll_fr->pll_op_clk_freq_hz, lim->vt_bk.min_pix_clk_freq_hz)); dev_dbg(dev, "max_vt_div: min_vt_pix_clk_freq_hz: %u\n", max_vt_div); @@ -321,26 +320,26 @@ ccs_pll_calculate_vt(struct device *dev, const struct ccs_pll_limits *lim, */ min_sys_div = lim->vt_bk.min_sys_clk_div; dev_dbg(dev, "min_sys_div: %u\n", min_sys_div); - min_sys_div = max(min_sys_div, - DIV_ROUND_UP(min_vt_div, - lim->vt_bk.max_pix_clk_div)); + min_sys_div = max_t(uint16_t, min_sys_div, + DIV_ROUND_UP(min_vt_div, + lim->vt_bk.max_pix_clk_div)); dev_dbg(dev, "min_sys_div: max_vt_pix_clk_div: %u\n", min_sys_div); - min_sys_div = max(min_sys_div, - pll_fr->pll_op_clk_freq_hz - / lim->vt_bk.max_sys_clk_freq_hz); + min_sys_div = max_t(uint16_t, min_sys_div, + pll_fr->pll_op_clk_freq_hz + / lim->vt_bk.max_sys_clk_freq_hz); dev_dbg(dev, "min_sys_div: max_pll_op_clk_freq_hz: %u\n", min_sys_div); min_sys_div = clk_div_even_up(min_sys_div); dev_dbg(dev, "min_sys_div: one or even: %u\n", min_sys_div); max_sys_div = lim->vt_bk.max_sys_clk_div; dev_dbg(dev, "max_sys_div: %u\n", max_sys_div); - max_sys_div = min(max_sys_div, - DIV_ROUND_UP(max_vt_div, - lim->vt_bk.min_pix_clk_div)); + max_sys_div = min_t(uint16_t, max_sys_div, + DIV_ROUND_UP(max_vt_div, + lim->vt_bk.min_pix_clk_div)); dev_dbg(dev, "max_sys_div: min_vt_pix_clk_div: %u\n", max_sys_div); - max_sys_div = min(max_sys_div, - DIV_ROUND_UP(pll_fr->pll_op_clk_freq_hz, - lim->vt_bk.min_pix_clk_freq_hz)); + max_sys_div = min_t(uint16_t, max_sys_div, + DIV_ROUND_UP(pll_fr->pll_op_clk_freq_hz, + lim->vt_bk.min_pix_clk_freq_hz)); dev_dbg(dev, "max_sys_div: min_vt_pix_clk_freq_hz: %u\n", max_sys_div); /* @@ -376,7 +375,7 @@ ccs_pll_calculate_vt(struct device *dev, const struct ccs_pll_limits *lim, if (vt_div == rounded_div) break; } - if (best_pix_div < INT_MAX >> 1) + if (best_pix_div < SHRT_MAX >> 1) break; } -- cgit v1.2.3 From 36154b68b8d9c4a3d771c0d2c58be03927350480 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 15 Sep 2020 21:04:26 +0200 Subject: media: ccs-pll: Fix VT post-PLL divisor calculation The PLL calculator only searched even total divisor values apart from one, but this is wrong: the total divisor is odd in cases where system divisor is one. Fix this by including odd total PLL values where system divisor is one to the search. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index 7512f0313010..4321989b9013 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -347,14 +347,16 @@ ccs_pll_calculate_vt(struct device *dev, const struct ccs_pll_limits *lim, * into a value which is not smaller than div, the desired * divisor. */ - for (vt_div = min_vt_div; vt_div <= max_vt_div; - vt_div += 2 - (vt_div & 1)) { - for (sys_div = min_sys_div; - sys_div <= max_sys_div; + for (vt_div = min_vt_div; vt_div <= max_vt_div; vt_div++) { + uint16_t __max_sys_div = vt_div & 1 ? 1 : max_sys_div; + + for (sys_div = min_sys_div; sys_div <= __max_sys_div; sys_div += 2 - (sys_div & 1)) { - uint16_t pix_div = DIV_ROUND_UP(vt_div, sys_div); + uint16_t pix_div; uint16_t rounded_div; + pix_div = DIV_ROUND_UP(vt_div, sys_div); + if (pix_div < lim->vt_bk.min_pix_clk_div || pix_div > lim->vt_bk.max_pix_clk_div) { dev_dbg(dev, -- cgit v1.2.3 From 9ec6e5b18e6660ccc7b1777a4a4108c6c1723c40 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 15 Sep 2020 18:33:13 +0200 Subject: media: ccs-pll: Separate VT divisor limit calculation from the rest Separate VT divisor limit calculation from the rest of the VT PLL branch calculation. This way it can be used for dual PLL support as well. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 64 ++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index 4321989b9013..8b300e786451 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -228,6 +228,41 @@ static int check_ext_bounds(struct device *dev, struct ccs_pll *pll) return 0; } +static void +ccs_pll_find_vt_sys_div(struct device *dev, const struct ccs_pll_limits *lim, + struct ccs_pll *pll, struct ccs_pll_branch_fr *pll_fr, + uint16_t min_vt_div, uint16_t max_vt_div, + uint16_t *min_sys_div, uint16_t *max_sys_div) +{ + /* + * Find limits for sys_clk_div. Not all values are possible with all + * values of pix_clk_div. + */ + *min_sys_div = lim->vt_bk.min_sys_clk_div; + dev_dbg(dev, "min_sys_div: %u\n", *min_sys_div); + *min_sys_div = max_t(uint16_t, *min_sys_div, + DIV_ROUND_UP(min_vt_div, + lim->vt_bk.max_pix_clk_div)); + dev_dbg(dev, "min_sys_div: max_vt_pix_clk_div: %u\n", *min_sys_div); + *min_sys_div = max_t(uint16_t, *min_sys_div, + pll_fr->pll_op_clk_freq_hz + / lim->vt_bk.max_sys_clk_freq_hz); + dev_dbg(dev, "min_sys_div: max_pll_op_clk_freq_hz: %u\n", *min_sys_div); + *min_sys_div = clk_div_even_up(*min_sys_div); + dev_dbg(dev, "min_sys_div: one or even: %u\n", *min_sys_div); + + *max_sys_div = lim->vt_bk.max_sys_clk_div; + dev_dbg(dev, "max_sys_div: %u\n", *max_sys_div); + *max_sys_div = min_t(uint16_t, *max_sys_div, + DIV_ROUND_UP(max_vt_div, + lim->vt_bk.min_pix_clk_div)); + dev_dbg(dev, "max_sys_div: min_vt_pix_clk_div: %u\n", *max_sys_div); + *max_sys_div = min_t(uint16_t, *max_sys_div, + DIV_ROUND_UP(pll_fr->pll_op_clk_freq_hz, + lim->vt_bk.min_pix_clk_freq_hz)); + dev_dbg(dev, "max_sys_div: min_vt_pix_clk_freq_hz: %u\n", *max_sys_div); +} + #define CPHY_CONST 7 #define DPHY_CONST 16 #define PHY_CONST_DIV 16 @@ -314,33 +349,8 @@ ccs_pll_calculate_vt(struct device *dev, const struct ccs_pll_limits *lim, dev_dbg(dev, "max_vt_div: min_vt_pix_clk_freq_hz: %u\n", max_vt_div); - /* - * Find limitsits for sys_clk_div. Not all values are possible - * with all values of pix_clk_div. - */ - min_sys_div = lim->vt_bk.min_sys_clk_div; - dev_dbg(dev, "min_sys_div: %u\n", min_sys_div); - min_sys_div = max_t(uint16_t, min_sys_div, - DIV_ROUND_UP(min_vt_div, - lim->vt_bk.max_pix_clk_div)); - dev_dbg(dev, "min_sys_div: max_vt_pix_clk_div: %u\n", min_sys_div); - min_sys_div = max_t(uint16_t, min_sys_div, - pll_fr->pll_op_clk_freq_hz - / lim->vt_bk.max_sys_clk_freq_hz); - dev_dbg(dev, "min_sys_div: max_pll_op_clk_freq_hz: %u\n", min_sys_div); - min_sys_div = clk_div_even_up(min_sys_div); - dev_dbg(dev, "min_sys_div: one or even: %u\n", min_sys_div); - - max_sys_div = lim->vt_bk.max_sys_clk_div; - dev_dbg(dev, "max_sys_div: %u\n", max_sys_div); - max_sys_div = min_t(uint16_t, max_sys_div, - DIV_ROUND_UP(max_vt_div, - lim->vt_bk.min_pix_clk_div)); - dev_dbg(dev, "max_sys_div: min_vt_pix_clk_div: %u\n", max_sys_div); - max_sys_div = min_t(uint16_t, max_sys_div, - DIV_ROUND_UP(pll_fr->pll_op_clk_freq_hz, - lim->vt_bk.min_pix_clk_freq_hz)); - dev_dbg(dev, "max_sys_div: min_vt_pix_clk_freq_hz: %u\n", max_sys_div); + ccs_pll_find_vt_sys_div(dev, lim, pll, pll_fr, min_vt_div, + max_vt_div, &min_sys_div, &max_sys_div); /* * Find pix_div such that a legal pix_div * sys_div results -- cgit v1.2.3 From 6c7469e46b603f08462ef586a415a318134392b8 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 15 Sep 2020 20:53:26 +0200 Subject: media: ccs-pll: Add trivial dual PLL support Add support for sensors that have separate VT and OP domain PLLs. This support is trivial in the sense that it aims for the same VT pixel rate than that on the CSI-2 bus. The vast majority of sensors is better supported by higher frequencies in VT domain in binned and possibly scaled configurations. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 217 +++++++++++++++++++++++++++++++++++++++----- drivers/media/i2c/ccs-pll.h | 1 + 2 files changed, 196 insertions(+), 22 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index 8b300e786451..91b578a05a98 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -92,7 +92,8 @@ static void print_pll(struct device *dev, struct ccs_pll *pll) for (i = 0, br = branches; i < ARRAY_SIZE(branches); i++, br++) { const char *s = pll_string(br->which); - if (br->which == PLL_VT) { + if (pll->flags & CCS_PLL_FLAG_DUAL_PLL || + br->which == PLL_VT) { dev_dbg(dev, "%s_pre_pll_clk_div\t\t%u\n", s, br->fr->pre_pll_clk_div); dev_dbg(dev, "%s_pll_multiplier\t\t%u\n", s, @@ -118,7 +119,7 @@ static void print_pll(struct device *dev, struct ccs_pll *pll) } } - dev_dbg(dev, "flags%s%s%s%s%s%s\n", + dev_dbg(dev, "flags%s%s%s%s%s%s%s\n", pll->flags & PLL_FL(LANE_SPEED_MODEL) ? " lane-speed" : "", pll->flags & PLL_FL(LINK_DECOUPLED) ? " link-decoupled" : "", pll->flags & PLL_FL(EXT_IP_PLL_DIVIDER) ? @@ -126,7 +127,8 @@ static void print_pll(struct device *dev, struct ccs_pll *pll) pll->flags & PLL_FL(FLEXIBLE_OP_PIX_CLK_DIV) ? " flexible-op-pix-div" : "", pll->flags & PLL_FL(FIFO_DERATING) ? " fifo-derating" : "", - pll->flags & PLL_FL(FIFO_OVERRATING) ? " fifo-overrating" : ""); + pll->flags & PLL_FL(FIFO_OVERRATING) ? " fifo-overrating" : "", + pll->flags & PLL_FL(DUAL_PLL) ? " dual-pll" : ""); } static int check_fr_bounds(struct device *dev, @@ -267,6 +269,152 @@ ccs_pll_find_vt_sys_div(struct device *dev, const struct ccs_pll_limits *lim, #define DPHY_CONST 16 #define PHY_CONST_DIV 16 +static inline int +__ccs_pll_calculate_vt_tree(struct device *dev, + const struct ccs_pll_limits *lim, + struct ccs_pll *pll, uint32_t mul, uint32_t div) +{ + const struct ccs_pll_branch_limits_fr *lim_fr = &lim->vt_fr; + const struct ccs_pll_branch_limits_bk *lim_bk = &lim->vt_bk; + struct ccs_pll_branch_fr *pll_fr = &pll->vt_fr; + struct ccs_pll_branch_bk *pll_bk = &pll->vt_bk; + uint32_t more_mul; + uint16_t best_pix_div = SHRT_MAX >> 1, best_div; + uint16_t vt_div, min_sys_div, max_sys_div, sys_div; + + pll_fr->pll_ip_clk_freq_hz = + pll->ext_clk_freq_hz / pll_fr->pre_pll_clk_div; + + dev_dbg(dev, "vt_pll_ip_clk_freq_hz %u\n", pll_fr->pll_ip_clk_freq_hz); + + more_mul = one_or_more(DIV_ROUND_UP(lim_fr->min_pll_op_clk_freq_hz, + pll_fr->pll_ip_clk_freq_hz * mul)); + + dev_dbg(dev, "more_mul: %u\n", more_mul); + more_mul *= DIV_ROUND_UP(lim_fr->min_pll_multiplier, mul * more_mul); + dev_dbg(dev, "more_mul2: %u\n", more_mul); + + pll_fr->pll_multiplier = mul * more_mul; + + if (pll_fr->pll_multiplier * pll_fr->pll_ip_clk_freq_hz > + lim_fr->max_pll_op_clk_freq_hz) + return -EINVAL; + + pll_fr->pll_op_clk_freq_hz = + pll_fr->pll_ip_clk_freq_hz * pll_fr->pll_multiplier; + + vt_div = div * more_mul; + + ccs_pll_find_vt_sys_div(dev, lim, pll, pll_fr, vt_div, vt_div, + &min_sys_div, &max_sys_div); + + max_sys_div = (vt_div & 1) ? 1 : max_sys_div; + + dev_dbg(dev, "vt min/max_sys_div: %u,%u\n", min_sys_div, max_sys_div); + + for (sys_div = min_sys_div; sys_div <= max_sys_div; + sys_div += 2 - (sys_div & 1)) { + uint16_t pix_div; + + if (vt_div % sys_div) + continue; + + pix_div = vt_div / sys_div; + + if (pix_div < lim_bk->min_pix_clk_div || + pix_div > lim_bk->max_pix_clk_div) { + dev_dbg(dev, + "pix_div %u too small or too big (%u--%u)\n", + pix_div, + lim_bk->min_pix_clk_div, + lim_bk->max_pix_clk_div); + continue; + } + + if (pix_div * sys_div <= best_div) { + best_pix_div = pix_div; + best_div = pix_div * sys_div; + } + } + if (best_pix_div == SHRT_MAX >> 1) + return -EINVAL; + + pll_bk->sys_clk_div = best_div / best_pix_div; + pll_bk->pix_clk_div = best_pix_div; + + pll_bk->sys_clk_freq_hz = + pll_fr->pll_op_clk_freq_hz / pll_bk->sys_clk_div; + pll_bk->pix_clk_freq_hz = + pll_bk->sys_clk_freq_hz / pll_bk->pix_clk_div; + + pll->pixel_rate_pixel_array = + pll_bk->pix_clk_freq_hz * pll->vt_lanes; + + return 0; +} + +static int ccs_pll_calculate_vt_tree(struct device *dev, + const struct ccs_pll_limits *lim, + struct ccs_pll *pll) +{ + const struct ccs_pll_branch_limits_fr *lim_fr = &lim->vt_fr; + struct ccs_pll_branch_fr *pll_fr = &pll->vt_fr; + uint16_t min_pre_pll_clk_div = lim_fr->min_pre_pll_clk_div; + uint16_t max_pre_pll_clk_div = lim_fr->max_pre_pll_clk_div; + uint32_t pre_mul, pre_div; + + pre_div = gcd(pll->pixel_rate_csi, + pll->ext_clk_freq_hz * pll->vt_lanes); + pre_mul = pll->pixel_rate_csi / pre_div; + pre_div = pll->ext_clk_freq_hz * pll->vt_lanes / pre_div; + + /* Make sure PLL input frequency is within limits */ + max_pre_pll_clk_div = + min_t(uint16_t, max_pre_pll_clk_div, + DIV_ROUND_UP(pll->ext_clk_freq_hz, + lim_fr->min_pll_ip_clk_freq_hz)); + + min_pre_pll_clk_div = max_t(uint16_t, min_pre_pll_clk_div, + pll->ext_clk_freq_hz / + lim_fr->max_pll_ip_clk_freq_hz); + + dev_dbg(dev, "vt min/max_pre_pll_clk_div: %u,%u\n", + min_pre_pll_clk_div, max_pre_pll_clk_div); + + for (pll_fr->pre_pll_clk_div = min_pre_pll_clk_div; + pll_fr->pre_pll_clk_div <= max_pre_pll_clk_div; + pll_fr->pre_pll_clk_div += + (pll->flags & CCS_PLL_FLAG_EXT_IP_PLL_DIVIDER) ? 1 : + 2 - (pll_fr->pre_pll_clk_div & 1)) { + uint32_t mul, div; + int rval; + + div = gcd(pre_mul * pll_fr->pre_pll_clk_div, pre_div); + mul = pre_mul * pll_fr->pre_pll_clk_div / div; + div = pre_div / div; + + dev_dbg(dev, "vt pre-div/mul/div: %u,%u,%u\n", + pll_fr->pre_pll_clk_div, mul, div); + + rval = __ccs_pll_calculate_vt_tree(dev, lim, pll, + mul, div); + if (rval) + continue; + + rval = check_fr_bounds(dev, lim, pll, PLL_VT); + if (rval) + continue; + + rval = check_bk_bounds(dev, lim, pll, PLL_VT); + if (rval) + continue; + + return 0; + } + + return -EINVAL; +} + static void ccs_pll_calculate_vt(struct device *dev, const struct ccs_pll_limits *lim, const struct ccs_pll_branch_limits_bk *op_lim_bk, @@ -525,10 +673,10 @@ ccs_pll_calculate_op(struct device *dev, const struct ccs_pll_limits *lim, int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, struct ccs_pll *pll) { - const struct ccs_pll_branch_limits_fr *op_lim_fr = &lim->vt_fr; - const struct ccs_pll_branch_limits_bk *op_lim_bk = &lim->op_bk; - struct ccs_pll_branch_fr *op_pll_fr = &pll->vt_fr; - struct ccs_pll_branch_bk *op_pll_bk = &pll->op_bk; + const struct ccs_pll_branch_limits_fr *op_lim_fr; + const struct ccs_pll_branch_limits_bk *op_lim_bk; + struct ccs_pll_branch_fr *op_pll_fr; + struct ccs_pll_branch_bk *op_pll_bk; bool cphy = pll->bus_type == CCS_PLL_BUS_TYPE_CSI2_CPHY; uint32_t phy_const = cphy ? CPHY_CONST : DPHY_CONST; uint16_t min_op_pre_pll_clk_div; @@ -544,6 +692,28 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, pll->vt_lanes = 1; } + if (pll->flags & CCS_PLL_FLAG_DUAL_PLL) { + op_lim_fr = &lim->op_fr; + op_lim_bk = &lim->op_bk; + op_pll_fr = &pll->op_fr; + op_pll_bk = &pll->op_bk; + } else if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS) { + /* + * If there's no OP PLL at all, use the VT values + * instead. The OP values are ignored for the rest of + * the PLL calculation. + */ + op_lim_fr = &lim->vt_fr; + op_lim_bk = &lim->vt_bk; + op_pll_fr = &pll->vt_fr; + op_pll_bk = &pll->vt_bk; + } else { + op_lim_fr = &lim->vt_fr; + op_lim_bk = &lim->op_bk; + op_pll_fr = &pll->vt_fr; + op_pll_bk = &pll->op_bk; + } + if (!pll->op_lanes || !pll->vt_lanes || !pll->bits_per_pixel || !pll->ext_clk_freq_hz || !pll->link_freq || !pll->scale_m || !op_lim_fr->min_pll_ip_clk_freq_hz || @@ -567,17 +737,6 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, dev_dbg(dev, "vt_lanes: %u\n", pll->vt_lanes); dev_dbg(dev, "op_lanes: %u\n", pll->op_lanes); - if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS) { - /* - * If there's no OP PLL at all, use the VT values - * instead. The OP values are ignored for the rest of - * the PLL calculation. - */ - op_lim_fr = &lim->vt_fr; - op_lim_bk = &lim->vt_bk; - op_pll_bk = &pll->vt_bk; - } - dev_dbg(dev, "binning: %ux%u\n", pll->binning_horizontal, pll->binning_vertical); @@ -653,6 +812,9 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, if (rval) continue; + if (pll->flags & CCS_PLL_FLAG_DUAL_PLL) + break; + ccs_pll_calculate_vt(dev, lim, op_lim_bk, pll, op_pll_fr, op_pll_bk, cphy, phy_const); @@ -663,14 +825,25 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, if (rval) continue; - print_pll(dev, pll); + break; + } + + if (rval) { + dev_dbg(dev, "unable to compute pre_pll divisor\n"); - return 0; + return rval; } - dev_dbg(dev, "unable to compute pre_pll divisor\n"); + if (pll->flags & CCS_PLL_FLAG_DUAL_PLL) { + rval = ccs_pll_calculate_vt_tree(dev, lim, pll); - return rval; + if (rval) + return rval; + } + + print_pll(dev, pll); + + return 0; } EXPORT_SYMBOL_GPL(ccs_pll_calculate); diff --git a/drivers/media/i2c/ccs-pll.h b/drivers/media/i2c/ccs-pll.h index 6255803eee38..517ee504f44a 100644 --- a/drivers/media/i2c/ccs-pll.h +++ b/drivers/media/i2c/ccs-pll.h @@ -29,6 +29,7 @@ #define CCS_PLL_FLAG_FLEXIBLE_OP_PIX_CLK_DIV BIT(5) #define CCS_PLL_FLAG_FIFO_DERATING BIT(6) #define CCS_PLL_FLAG_FIFO_OVERRATING BIT(7) +#define CCS_PLL_FLAG_DUAL_PLL BIT(8) /** * struct ccs_pll_branch_fr - CCS PLL configuration (front) -- cgit v1.2.3 From b41f270841f85b9b4f8530b9f2020ff3ba1cfec5 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 16 Sep 2020 11:36:32 +0200 Subject: media: ccs: Dual PLL support Add support for sensors that either require dual PLL or support single or dual PLL but use dual PLL as default. Use sensor default configuration for sensors that support both modes. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 9 ++++++-- drivers/media/i2c/ccs/ccs-core.c | 45 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index 91b578a05a98..7df7b96e78e6 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -331,7 +331,10 @@ __ccs_pll_calculate_vt_tree(struct device *dev, continue; } - if (pix_div * sys_div <= best_div) { + dev_dbg(dev, "sys/pix/best_pix: %u,%u,%u\n", sys_div, pix_div, + best_pix_div); + + if (pix_div * sys_div <= best_pix_div) { best_pix_div = pix_div; best_div = pix_div * sys_div; } @@ -804,7 +807,9 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, if (rval) continue; - rval = check_fr_bounds(dev, lim, pll, PLL_VT); + rval = check_fr_bounds(dev, lim, pll, + pll->flags & CCS_PLL_FLAG_DUAL_PLL ? + PLL_OP : PLL_VT); if (rval) continue; diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index fa878ecf55a7..580166b84878 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -395,7 +395,23 @@ static int ccs_pll_configure(struct ccs_sensor *sensor) if (rval < 0) return rval; - return ccs_write(sensor, OP_SYS_CLK_DIV, pll->op_bk.sys_clk_div); + rval = ccs_write(sensor, OP_SYS_CLK_DIV, pll->op_bk.sys_clk_div); + if (rval < 0) + return rval; + + if (!(pll->flags & CCS_PLL_FLAG_DUAL_PLL)) + return 0; + + rval = ccs_write(sensor, PLL_MODE, CCS_PLL_MODE_DUAL); + if (rval < 0) + return rval; + + rval = ccs_write(sensor, OP_PRE_PLL_CLK_DIV, + pll->op_fr.pre_pll_clk_div); + if (rval < 0) + return rval; + + return ccs_write(sensor, OP_PLL_MULTIPLIER, pll->op_fr.pll_multiplier); } static int ccs_pll_try(struct ccs_sensor *sensor, struct ccs_pll *pll) @@ -412,6 +428,16 @@ static int ccs_pll_try(struct ccs_sensor *sensor, struct ccs_pll *pll) .min_pll_op_clk_freq_hz = CCS_LIM(sensor, MIN_PLL_OP_CLK_FREQ_MHZ), .max_pll_op_clk_freq_hz = CCS_LIM(sensor, MAX_PLL_OP_CLK_FREQ_MHZ), }, + .op_fr = { + .min_pre_pll_clk_div = CCS_LIM(sensor, MIN_OP_PRE_PLL_CLK_DIV), + .max_pre_pll_clk_div = CCS_LIM(sensor, MAX_OP_PRE_PLL_CLK_DIV), + .min_pll_ip_clk_freq_hz = CCS_LIM(sensor, MIN_OP_PLL_IP_CLK_FREQ_MHZ), + .max_pll_ip_clk_freq_hz = CCS_LIM(sensor, MAX_OP_PLL_IP_CLK_FREQ_MHZ), + .min_pll_multiplier = CCS_LIM(sensor, MIN_OP_PLL_MULTIPLIER), + .max_pll_multiplier = CCS_LIM(sensor, MAX_OP_PLL_MULTIPLIER), + .min_pll_op_clk_freq_hz = CCS_LIM(sensor, MIN_OP_PLL_OP_CLK_FREQ_MHZ), + .max_pll_op_clk_freq_hz = CCS_LIM(sensor, MAX_OP_PLL_OP_CLK_FREQ_MHZ), + }, .op_bk = { .min_sys_clk_div = CCS_LIM(sensor, MIN_OP_SYS_CLK_DIV), .max_sys_clk_div = CCS_LIM(sensor, MAX_OP_SYS_CLK_DIV), @@ -3231,6 +3257,23 @@ static int ccs_probe(struct i2c_client *client) CCS_FIFO_SUPPORT_CAPABILITY_DERATING_OVERRATING) sensor->pll.flags |= CCS_PLL_FLAG_FIFO_DERATING | CCS_PLL_FLAG_FIFO_OVERRATING; + if (CCS_LIM(sensor, CLOCK_TREE_PLL_CAPABILITY) & + CCS_CLOCK_TREE_PLL_CAPABILITY_DUAL_PLL) { + if (CCS_LIM(sensor, CLOCK_TREE_PLL_CAPABILITY) & + CCS_CLOCK_TREE_PLL_CAPABILITY_SINGLE_PLL) { + u32 v; + + /* Use sensor default in PLL mode selection */ + rval = ccs_read(sensor, PLL_MODE, &v); + if (rval) + goto out_cleanup; + + if (v == CCS_PLL_MODE_DUAL) + sensor->pll.flags |= CCS_PLL_FLAG_DUAL_PLL; + } else { + sensor->pll.flags |= CCS_PLL_FLAG_DUAL_PLL; + } + } sensor->pll.op_bits_per_lane = CCS_LIM(sensor, OP_BITS_PER_LANE); sensor->pll.ext_clk_freq_hz = sensor->hwcfg.ext_clk; sensor->pll.scale_n = CCS_LIM(sensor, SCALER_N_MIN); -- cgit v1.2.3 From 900c33e86e4b53e96e6ea10e9737870e03911a66 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 25 Aug 2020 00:06:26 +0200 Subject: media: ccs-pll: Add support for DDR OP system and pixel clocks Add support for dual data rate operational system and pixel clocks. This is implemented using two PLL flags. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 64 +++++++++++++++++++++++++++++++-------------- drivers/media/i2c/ccs-pll.h | 2 ++ 2 files changed, 46 insertions(+), 20 deletions(-) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index 7df7b96e78e6..5a0162347777 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -119,7 +119,7 @@ static void print_pll(struct device *dev, struct ccs_pll *pll) } } - dev_dbg(dev, "flags%s%s%s%s%s%s%s\n", + dev_dbg(dev, "flags%s%s%s%s%s%s%s%s%s\n", pll->flags & PLL_FL(LANE_SPEED_MODEL) ? " lane-speed" : "", pll->flags & PLL_FL(LINK_DECOUPLED) ? " link-decoupled" : "", pll->flags & PLL_FL(EXT_IP_PLL_DIVIDER) ? @@ -128,7 +128,19 @@ static void print_pll(struct device *dev, struct ccs_pll *pll) " flexible-op-pix-div" : "", pll->flags & PLL_FL(FIFO_DERATING) ? " fifo-derating" : "", pll->flags & PLL_FL(FIFO_OVERRATING) ? " fifo-overrating" : "", - pll->flags & PLL_FL(DUAL_PLL) ? " dual-pll" : ""); + pll->flags & PLL_FL(DUAL_PLL) ? " dual-pll" : "", + pll->flags & PLL_FL(OP_SYS_DDR) ? " op-sys-ddr" : "", + pll->flags & PLL_FL(OP_PIX_DDR) ? " op-pix-ddr" : ""); +} + +static uint32_t op_sys_ddr(uint32_t flags) +{ + return flags & CCS_PLL_FLAG_OP_SYS_DDR ? 1 : 0; +} + +static uint32_t op_pix_ddr(uint32_t flags) +{ + return flags & CCS_PLL_FLAG_OP_PIX_DDR ? 1 : 0; } static int check_fr_bounds(struct device *dev, @@ -441,8 +453,8 @@ ccs_pll_calculate_vt(struct device *dev, const struct ccs_pll_limits *lim, if (!(pll->flags & CCS_PLL_FLAG_FIFO_DERATING)) { min_vt_div = op_pll_bk->sys_clk_div * op_pll_bk->pix_clk_div - * pll->vt_lanes * phy_const - / pll->op_lanes / PHY_CONST_DIV; + * pll->vt_lanes * phy_const / pll->op_lanes + / (PHY_CONST_DIV << op_pix_ddr(pll->flags)); } else { /* * Some sensors perform analogue binning and some do this @@ -478,7 +490,7 @@ ccs_pll_calculate_vt(struct device *dev, const struct ccs_pll_limits *lim, CCS_PLL_FLAG_LANE_SPEED_MODEL ? pll->csi2.lanes : 1) * vt_op_binning_div * pll->scale_m - * PHY_CONST_DIV); + * PHY_CONST_DIV << op_pix_ddr(pll->flags)); } /* Find smallest and biggest allowed vt divisor. */ @@ -572,7 +584,8 @@ ccs_pll_calculate_op(struct device *dev, const struct ccs_pll_limits *lim, const struct ccs_pll_branch_limits_bk *op_lim_bk, struct ccs_pll *pll, struct ccs_pll_branch_fr *op_pll_fr, struct ccs_pll_branch_bk *op_pll_bk, uint32_t mul, - uint32_t div, uint32_t l, bool cphy, uint32_t phy_const) + uint32_t div, uint32_t op_sys_clk_freq_hz_sdr, uint32_t l, + bool cphy, uint32_t phy_const) { /* * Higher multipliers (and divisors) are often required than @@ -658,15 +671,22 @@ ccs_pll_calculate_op(struct device *dev, const struct ccs_pll_limits *lim, * op_pll_fr->pll_multiplier; if (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL) - op_pll_bk->pix_clk_div = pll->bits_per_pixel - * pll->op_lanes * phy_const - / PHY_CONST_DIV / pll->csi2.lanes / l; + op_pll_bk->pix_clk_div = + (pll->bits_per_pixel + * pll->op_lanes * (phy_const << op_sys_ddr(pll->flags)) + / PHY_CONST_DIV / pll->csi2.lanes / l) + >> op_pix_ddr(pll->flags); else op_pll_bk->pix_clk_div = - pll->bits_per_pixel * phy_const / PHY_CONST_DIV / l; + (pll->bits_per_pixel + * (phy_const << op_sys_ddr(pll->flags)) + / PHY_CONST_DIV / l) >> op_pix_ddr(pll->flags); op_pll_bk->pix_clk_freq_hz = - op_pll_bk->sys_clk_freq_hz / op_pll_bk->pix_clk_div; + (op_sys_clk_freq_hz_sdr >> op_pix_ddr(pll->flags)) + / op_pll_bk->pix_clk_div; + op_pll_bk->sys_clk_freq_hz = + op_sys_clk_freq_hz_sdr >> op_sys_ddr(pll->flags); dev_dbg(dev, "op_pix_clk_div: %u\n", op_pll_bk->pix_clk_div); @@ -682,6 +702,7 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, struct ccs_pll_branch_bk *op_pll_bk; bool cphy = pll->bus_type == CCS_PLL_BUS_TYPE_CSI2_CPHY; uint32_t phy_const = cphy ? CPHY_CONST : DPHY_CONST; + uint32_t op_sys_clk_freq_hz_sdr; uint16_t min_op_pre_pll_clk_div; uint16_t max_op_pre_pll_clk_div; uint32_t mul, div; @@ -731,7 +752,8 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, * op_pix_clk_div is supported */ if (!(pll->flags & CCS_PLL_FLAG_FLEXIBLE_OP_PIX_CLK_DIV) && - (pll->bits_per_pixel * pll->op_lanes) % (pll->csi2.lanes * l)) { + (pll->bits_per_pixel * pll->op_lanes) % + (pll->csi2.lanes * l << op_pix_ddr(pll->flags))) { dev_dbg(dev, "op_pix_clk_div not an integer (bpp %u, op lanes %u, lanes %u, l %u)\n", pll->bits_per_pixel, pll->op_lanes, pll->csi2.lanes, l); return -EINVAL; @@ -746,12 +768,12 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, switch (pll->bus_type) { case CCS_PLL_BUS_TYPE_CSI2_DPHY: /* CSI transfers 2 bits per clock per lane; thus times 2 */ - op_pll_bk->sys_clk_freq_hz = pll->link_freq * 2 + op_sys_clk_freq_hz_sdr = pll->link_freq * 2 * (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ? 1 : pll->csi2.lanes); break; case CCS_PLL_BUS_TYPE_CSI2_CPHY: - op_pll_bk->sys_clk_freq_hz = + op_sys_clk_freq_hz_sdr = pll->link_freq * (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ? 1 : pll->csi2.lanes); @@ -761,7 +783,7 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, } pll->pixel_rate_csi = - div_u64((uint64_t)op_pll_bk->sys_clk_freq_hz + div_u64((uint64_t)op_sys_clk_freq_hz_sdr * (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ? pll->csi2.lanes : 1) * PHY_CONST_DIV, phy_const * pll->bits_per_pixel * l); @@ -781,9 +803,10 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, dev_dbg(dev, "pre-pll check: min / max op_pre_pll_clk_div: %u / %u\n", min_op_pre_pll_clk_div, max_op_pre_pll_clk_div); - i = gcd(op_pll_bk->sys_clk_freq_hz, pll->ext_clk_freq_hz); - mul = op_pll_bk->sys_clk_freq_hz / i; - div = pll->ext_clk_freq_hz / i; + i = gcd(op_sys_clk_freq_hz_sdr, + pll->ext_clk_freq_hz << op_pix_ddr(pll->flags)); + mul = op_sys_clk_freq_hz_sdr / i; + div = (pll->ext_clk_freq_hz << op_pix_ddr(pll->flags)) / i; dev_dbg(dev, "mul %u / div %u\n", mul, div); min_op_pre_pll_clk_div = @@ -802,8 +825,9 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim, (pll->flags & CCS_PLL_FLAG_EXT_IP_PLL_DIVIDER) ? 1 : 2 - (op_pll_fr->pre_pll_clk_div & 1)) { rval = ccs_pll_calculate_op(dev, lim, op_lim_fr, op_lim_bk, pll, - op_pll_fr, op_pll_bk, mul, div, l, - cphy, phy_const); + op_pll_fr, op_pll_bk, mul, div, + op_sys_clk_freq_hz_sdr, l, cphy, + phy_const); if (rval) continue; diff --git a/drivers/media/i2c/ccs-pll.h b/drivers/media/i2c/ccs-pll.h index 517ee504f44a..b97d7ff50ea5 100644 --- a/drivers/media/i2c/ccs-pll.h +++ b/drivers/media/i2c/ccs-pll.h @@ -30,6 +30,8 @@ #define CCS_PLL_FLAG_FIFO_DERATING BIT(6) #define CCS_PLL_FLAG_FIFO_OVERRATING BIT(7) #define CCS_PLL_FLAG_DUAL_PLL BIT(8) +#define CCS_PLL_FLAG_OP_SYS_DDR BIT(9) +#define CCS_PLL_FLAG_OP_PIX_DDR BIT(10) /** * struct ccs_pll_branch_fr - CCS PLL configuration (front) -- cgit v1.2.3 From 7c66f58f1c1fb3181074a09c4aac21a0e8a283f0 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 23 Sep 2020 12:22:52 +0200 Subject: media: ccs: Add support for DDR OP SYS and OP PIX clocks Support dual data rate operational system and pixel clocks by conveying the flags to the PLL calculator and updating how the link rate is calculated. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 580166b84878..205d44ca1d6b 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -387,7 +387,8 @@ static int ccs_pll_configure(struct ccs_sensor *sensor) DIV_ROUND_UP(pll->op_bk.sys_clk_freq_hz, 1000000 / 256 / 256) * (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ? - sensor->pll.csi2.lanes : 1)); + sensor->pll.csi2.lanes : 1) << + (pll->flags & CCS_PLL_FLAG_OP_SYS_DDR ? 1 : 0)); if (rval < 0 || sensor->pll.flags & CCS_PLL_FLAG_NO_OP_CLOCKS) return rval; @@ -3273,6 +3274,12 @@ static int ccs_probe(struct i2c_client *client) } else { sensor->pll.flags |= CCS_PLL_FLAG_DUAL_PLL; } + if (CCS_LIM(sensor, CLOCK_CALCULATION) & + CCS_CLOCK_CALCULATION_DUAL_PLL_OP_SYS_DDR) + sensor->pll.flags |= CCS_PLL_FLAG_OP_SYS_DDR; + if (CCS_LIM(sensor, CLOCK_CALCULATION) & + CCS_CLOCK_CALCULATION_DUAL_PLL_OP_PIX_DDR) + sensor->pll.flags |= CCS_PLL_FLAG_OP_PIX_DDR; } sensor->pll.op_bits_per_lane = CCS_LIM(sensor, OP_BITS_PER_LANE); sensor->pll.ext_clk_freq_hz = sensor->hwcfg.ext_clk; -- cgit v1.2.3 From ba9dfeeb4fbe70885ac5372adf463659a9d499da Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 22 Sep 2020 11:08:34 +0200 Subject: media: ccs: Print written register values This helps debugging register writes. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-reg-access.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/i2c/ccs/ccs-reg-access.c b/drivers/media/i2c/ccs/ccs-reg-access.c index 3de863e3bf26..b776af2a3c33 100644 --- a/drivers/media/i2c/ccs/ccs-reg-access.c +++ b/drivers/media/i2c/ccs/ccs-reg-access.c @@ -338,6 +338,10 @@ int ccs_write_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 val) put_unaligned_be16(CCS_REG_ADDR(reg), data); put_unaligned_be32(val << (8 * (sizeof(val) - len)), data + 2); + dev_dbg(&client->dev, "writing reg 0x%4.4x value 0x%*.*x (%u)\n", + CCS_REG_ADDR(reg), ccs_reg_width(reg) << 1, + ccs_reg_width(reg) << 1, val, val); + r = ccs_write_retry(client, &msg); if (r) dev_err(&client->dev, -- cgit v1.2.3 From bd189aac5a91adf88eb5fac062c9d4a0c005c805 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 23 Sep 2020 13:13:34 +0200 Subject: media: ccs-pll: Print pixel rates Print pixel rates on CSI-2 bus as well as in pixel array as the variation allowed in PLL capabilities makes this non-trivial to figure out otherwise. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs-pll.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c index 5a0162347777..eb7b6f01f623 100644 --- a/drivers/media/i2c/ccs-pll.c +++ b/drivers/media/i2c/ccs-pll.c @@ -119,6 +119,11 @@ static void print_pll(struct device *dev, struct ccs_pll *pll) } } + dev_dbg(dev, "pixel rate in pixel array:\t%u\n", + pll->pixel_rate_pixel_array); + dev_dbg(dev, "pixel rate on CSI-2 bus:\t%u\n", + pll->pixel_rate_csi); + dev_dbg(dev, "flags%s%s%s%s%s%s%s%s%s\n", pll->flags & PLL_FL(LANE_SPEED_MODEL) ? " lane-speed" : "", pll->flags & PLL_FL(LINK_DECOUPLED) ? " link-decoupled" : "", -- cgit v1.2.3 From 7ea4d23293300ca2f225595849a4fe444fb80ea4 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 29 Sep 2020 11:34:42 +0200 Subject: media: ccs: Add support for obtaining C-PHY configuration from firmware Try parsing the firmware also as C-PHY. Do this only after D-PHY as older firmware may not explicitly specify bus-type in which case D-PHY is the default. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 205d44ca1d6b..b39ae5f8446b 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -2925,6 +2925,10 @@ static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev) hwcfg->csi_signalling_mode = CCS_CSI_SIGNALING_MODE_CSI_2_DPHY; hwcfg->lanes = bus_cfg.bus.mipi_csi2.num_data_lanes; break; + case V4L2_MBUS_CSI2_CPHY: + hwcfg->csi_signalling_mode = CCS_CSI_SIGNALING_MODE_CSI_2_CPHY; + hwcfg->lanes = bus_cfg.bus.mipi_csi2.num_data_lanes; + break; case V4L2_MBUS_CSI1: case V4L2_MBUS_CCP2: hwcfg->csi_signalling_mode = (bus_cfg.bus.mipi_csi1.strobe) ? -- cgit v1.2.3