mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 11:50:43 +09:00
Merge commit 'be446793b3a01ed54ae1cbf80bb49555e3d540de'
* commit 'be446793b3a01ed54ae1cbf80bb49555e3d540de': drm/rockchip: vop2: disable acm bypass by default media: rockchip: hdmirx: fix color space err. media: i2c: maxim: driver version v3.06.00 media: i2c: maxim: local: fix the issue of mutex deadlock during hot plug arm64: dts: rockchip: rk3576-vehicle-evb-maxim-max96712-d(/c)phy: dtsi remove vc-array config arm64: dts: rockchip: rk3588-vehicle-evb-maxim-max9671(/2)2-d(/c)phy: dtsi remove vc-array config media: i2c: maxim: local: mode vc initialization when vc-array isn't configured media: i2c: lt6911uxe: add dual mipi support Change-Id: I5d371ae321d5f61a8b0e9d4a8820c6f21935e529
This commit is contained in:
@@ -135,7 +135,6 @@
|
||||
max-fps-denominator = <300000>;
|
||||
bpp = <16>;
|
||||
link-freq-idx = <20>;
|
||||
vc-array = <0x10 0x20 0x40 0x80>; // VC0~3: bit4~7
|
||||
};
|
||||
/* support mode config end */
|
||||
|
||||
|
||||
@@ -135,7 +135,6 @@
|
||||
max-fps-denominator = <300000>;
|
||||
bpp = <16>;
|
||||
link-freq-idx = <24>;
|
||||
vc-array = <0x10 0x20 0x40 0x80>; // VC0~3: bit4~7
|
||||
};
|
||||
/* support mode config end */
|
||||
|
||||
|
||||
@@ -135,7 +135,6 @@
|
||||
max-fps-denominator = <300000>;
|
||||
bpp = <16>;
|
||||
link-freq-idx = <24>;
|
||||
vc-array = <0x10 0x20 0x40 0x80>; // VC0~3: bit4~7
|
||||
};
|
||||
/* support mode config end */
|
||||
|
||||
|
||||
@@ -135,7 +135,6 @@
|
||||
max-fps-denominator = <300000>;
|
||||
bpp = <16>;
|
||||
link-freq-idx = <20>;
|
||||
vc-array = <0x10 0x20 0x40 0x80>; // VC0~3: bit4~7
|
||||
};
|
||||
/* support mode config end */
|
||||
|
||||
|
||||
@@ -135,7 +135,6 @@
|
||||
max-fps-denominator = <300000>;
|
||||
bpp = <16>;
|
||||
link-freq-idx = <20>;
|
||||
vc-array = <0x10 0x20 0x40 0x80>; // VC0~3: bit4~7
|
||||
};
|
||||
/* support mode config end */
|
||||
|
||||
|
||||
@@ -144,7 +144,6 @@
|
||||
vts-def = <0x0cb0>;
|
||||
bpp = <10>;
|
||||
link-freq-idx = <24>;
|
||||
vc-array = <0x10 0x20 0x40 0x80>; // VC0~3: bit4~7
|
||||
};
|
||||
/* support mode config end */
|
||||
|
||||
|
||||
@@ -135,7 +135,6 @@
|
||||
max-fps-denominator = <300000>;
|
||||
bpp = <16>;
|
||||
link-freq-idx = <20>;
|
||||
vc-array = <0x10 0x20 0x40 0x80>; // VC0~3: bit4~7
|
||||
};
|
||||
/* support mode config end */
|
||||
|
||||
|
||||
@@ -135,7 +135,6 @@
|
||||
max-fps-denominator = <300000>;
|
||||
bpp = <16>;
|
||||
link-freq-idx = <24>;
|
||||
vc-array = <0x10 0x20 0x40 0x80>; // VC0~3: bit4~7
|
||||
};
|
||||
/* support mode config end */
|
||||
|
||||
|
||||
@@ -135,7 +135,6 @@
|
||||
max-fps-denominator = <300000>;
|
||||
bpp = <16>;
|
||||
link-freq-idx = <20>;
|
||||
vc-array = <0x10 0x20 0x40 0x80>; // VC0~3: bit4~7
|
||||
};
|
||||
/* support mode config end */
|
||||
|
||||
|
||||
@@ -136,7 +136,6 @@
|
||||
max-fps-denominator = <300000>;
|
||||
bpp = <16>;
|
||||
link-freq-idx = <20>;
|
||||
vc-array = <0x10 0x20 0x40 0x80>; // VC0~3: bit4~7
|
||||
};
|
||||
/* support mode config end */
|
||||
|
||||
|
||||
@@ -135,7 +135,6 @@
|
||||
max-fps-denominator = <300000>;
|
||||
bpp = <16>;
|
||||
link-freq-idx = <20>;
|
||||
vc-array = <0x10 0x20 0x40 0x80>; // VC0~3: bit4~7
|
||||
};
|
||||
/* support mode config end */
|
||||
|
||||
|
||||
@@ -9395,6 +9395,16 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_sta
|
||||
*/
|
||||
if (vop2->version == VOP_VERSION_RK3588)
|
||||
VOP_MODULE_SET(vop2, vp, dsp_background, 0x80000000);
|
||||
|
||||
/*
|
||||
* For RK3576 VP0 enable ACM[bypass = 0] will lead to timing error,
|
||||
* so enable ACM by default.
|
||||
*/
|
||||
if (vop2->version <= VOP_VERSION_RK3576 &&
|
||||
vp_data->feature & VOP_FEATURE_POST_ACM) {
|
||||
writel(0, vop2->acm_regs + RK3528_ACM_CTRL);
|
||||
VOP_MODULE_SET(vop2, vp, acm_bypass_en, 0);
|
||||
}
|
||||
if (is_vop3(vop2))
|
||||
vop3_setup_pipe_dly(vp, NULL);
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
* V0.0X01.0X04
|
||||
* 1.fix some errors.
|
||||
* 2.add dphy timing reg.
|
||||
* V0.0X01.0X05 add dual mipi mode support
|
||||
*
|
||||
*/
|
||||
// #define DEBUG
|
||||
@@ -40,7 +41,7 @@
|
||||
#include <media/v4l2-event.h>
|
||||
#include <media/v4l2-fwnode.h>
|
||||
|
||||
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x04)
|
||||
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x05)
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0644);
|
||||
@@ -185,6 +186,8 @@ struct lt6911uxe {
|
||||
const char *len_name;
|
||||
const struct lt6911uxe_mode *cur_mode;
|
||||
const struct lt6911uxe_mode *support_modes;
|
||||
struct rkmodule_multi_dev_info multi_dev_info;
|
||||
struct rkmodule_csi_dphy_param dphy_param;
|
||||
u32 cfg_num;
|
||||
struct v4l2_fwnode_endpoint bus_cfg;
|
||||
bool nosignal;
|
||||
@@ -196,6 +199,7 @@ struct lt6911uxe {
|
||||
u32 module_index;
|
||||
u32 audio_sampling_rate;
|
||||
int lane_in_use;
|
||||
bool dual_mipi_port;
|
||||
};
|
||||
|
||||
static const struct v4l2_dv_timings_cap lt6911uxe_timings_cap = {
|
||||
@@ -1090,12 +1094,6 @@ static int lt6911uxe_s_dv_timings(struct v4l2_subdev *sd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!v4l2_valid_dv_timings(timings,
|
||||
<6911uxe_timings_cap, NULL, NULL)) {
|
||||
v4l2_dbg(1, debug, sd, "%s: timings out of range\n", __func__);
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
lt6911uxe->timings = *timings;
|
||||
|
||||
enable_stream(sd, false);
|
||||
@@ -1375,6 +1373,7 @@ static long lt6911uxe_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
|
||||
struct lt6911uxe *lt6911uxe = to_lt6911uxe(sd);
|
||||
long ret = 0;
|
||||
struct rkmodule_csi_dphy_param *dphy_param;
|
||||
struct rkmodule_capture_info *capture_info;
|
||||
|
||||
switch (cmd) {
|
||||
case RKMODULE_GET_MODULE_INFO:
|
||||
@@ -1396,6 +1395,17 @@ static long lt6911uxe_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
|
||||
dev_dbg(<6911uxe->i2c_client->dev,
|
||||
"sensor get dphy param\n");
|
||||
break;
|
||||
case RKMODULE_GET_CAPTURE_MODE:
|
||||
capture_info = (struct rkmodule_capture_info *)arg;
|
||||
if (lt6911uxe->dual_mipi_port) {
|
||||
v4l2_dbg(1, debug, sd, "enable dual mipi mode\n");
|
||||
capture_info->mode = RKMODULE_MULTI_DEV_COMBINE_ONE;
|
||||
capture_info->multi_dev = lt6911uxe->multi_dev_info;
|
||||
} else {
|
||||
capture_info->mode = 0;
|
||||
capture_info->multi_dev = lt6911uxe->multi_dev_info;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = -ENOIOCTLCMD;
|
||||
break;
|
||||
@@ -1434,6 +1444,7 @@ static long lt6911uxe_compat_ioctl32(struct v4l2_subdev *sd,
|
||||
long ret;
|
||||
int *seq;
|
||||
struct rkmodule_csi_dphy_param *dphy_param;
|
||||
struct rkmodule_capture_info *capture_info;
|
||||
|
||||
switch (cmd) {
|
||||
case RKMODULE_GET_MODULE_INFO:
|
||||
@@ -1495,6 +1506,21 @@ static long lt6911uxe_compat_ioctl32(struct v4l2_subdev *sd,
|
||||
}
|
||||
kfree(dphy_param);
|
||||
break;
|
||||
case RKMODULE_GET_CAPTURE_MODE:
|
||||
capture_info = kzalloc(sizeof(*capture_info), GFP_KERNEL);
|
||||
if (!capture_info) {
|
||||
ret = -ENOMEM;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = lt6911uxe_ioctl(sd, cmd, capture_info);
|
||||
if (!ret) {
|
||||
ret = copy_to_user(up, capture_info, sizeof(*capture_info));
|
||||
if (ret)
|
||||
ret = -EFAULT;
|
||||
}
|
||||
kfree(capture_info);
|
||||
break;
|
||||
default:
|
||||
ret = -ENOIOCTLCMD;
|
||||
break;
|
||||
@@ -1763,6 +1789,39 @@ static int lt6911uxe_check_chip_id(struct lt6911uxe *lt6911uxe)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lt6911uxe_get_multi_dev_info(struct lt6911uxe *lt6911uxe)
|
||||
{
|
||||
struct device *dev = <6911uxe->i2c_client->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct device_node *multi_info_np;
|
||||
|
||||
lt6911uxe->dual_mipi_port = false;
|
||||
multi_info_np = of_get_child_by_name(node, "multi-dev-info");
|
||||
if (!multi_info_np) {
|
||||
dev_info(dev, "failed to get multi dev info\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
of_property_read_u32(multi_info_np, "dev-idx-l",
|
||||
<6911uxe->multi_dev_info.dev_idx[0]);
|
||||
of_property_read_u32(multi_info_np, "dev-idx-r",
|
||||
<6911uxe->multi_dev_info.dev_idx[1]);
|
||||
of_property_read_u32(multi_info_np, "combine-idx",
|
||||
<6911uxe->multi_dev_info.combine_idx[0]);
|
||||
of_property_read_u32(multi_info_np, "pixel-offset",
|
||||
<6911uxe->multi_dev_info.pixel_offset);
|
||||
of_property_read_u32(multi_info_np, "dev-num",
|
||||
<6911uxe->multi_dev_info.dev_num);
|
||||
|
||||
lt6911uxe->dual_mipi_port = true;
|
||||
dev_info(dev,
|
||||
"multi dev left: mipi%d, multi dev right: mipi%d, combile mipi%d, dev num: %d\n",
|
||||
lt6911uxe->multi_dev_info.dev_idx[0], lt6911uxe->multi_dev_info.dev_idx[1],
|
||||
lt6911uxe->multi_dev_info.combine_idx[0], lt6911uxe->multi_dev_info.dev_num);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lt6911uxe_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
@@ -1795,6 +1854,11 @@ static int lt6911uxe_probe(struct i2c_client *client,
|
||||
|
||||
lt6911uxe->timings = default_timing;
|
||||
lt6911uxe->cur_mode = <6911uxe->support_modes[0];
|
||||
|
||||
err = lt6911uxe_get_multi_dev_info(lt6911uxe);
|
||||
if (err)
|
||||
v4l2_info(sd, "get multi dev info failed, not use dual mipi mode\n");
|
||||
|
||||
err = lt6911uxe_check_chip_id(lt6911uxe);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
@@ -47,6 +47,11 @@
|
||||
* 1. unified use __v4l2_ctrl_handler_setup in the xxx_start_stream
|
||||
* 2. support subscribe hot plug detect v4l2 event
|
||||
*
|
||||
* V3.06.00
|
||||
* 1. support multi-channel information configuration
|
||||
* 2. mode vc initialization when vc-array isn't configured
|
||||
* 3. fix the issue of mutex deadlock during hot plug
|
||||
*
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/i2c.h>
|
||||
@@ -74,7 +79,7 @@
|
||||
|
||||
#include "maxim2c_api.h"
|
||||
|
||||
#define DRIVER_VERSION KERNEL_VERSION(3, 0x05, 0x00)
|
||||
#define DRIVER_VERSION KERNEL_VERSION(3, 0x06, 0x00)
|
||||
|
||||
#define MAXIM2C_NAME "maxim2c"
|
||||
|
||||
@@ -143,24 +148,27 @@ static irqreturn_t maxim2c_hot_plug_detect_irq_handler(int irq, void *dev_id)
|
||||
int lock_gpio_level = 0;
|
||||
|
||||
mutex_lock(&maxim2c->mutex);
|
||||
if (maxim2c->streaming) {
|
||||
lock_gpio_level = gpiod_get_value_cansleep(maxim2c->lock_gpio);
|
||||
if (lock_gpio_level == 0) {
|
||||
dev_info(dev, "serializer hot plug out\n");
|
||||
if (maxim2c->streaming == 0) {
|
||||
mutex_unlock(&maxim2c->mutex);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
maxim2c->hot_plug_state = MAXIM2C_HOT_PLUG_OUT;
|
||||
} else {
|
||||
dev_info(dev, "serializer hot plug in\n");
|
||||
lock_gpio_level = gpiod_get_value_cansleep(maxim2c->lock_gpio);
|
||||
if (lock_gpio_level == 0) {
|
||||
dev_info(dev, "serializer hot plug out\n");
|
||||
|
||||
maxim2c->hot_plug_state = MAXIM2C_HOT_PLUG_IN;
|
||||
}
|
||||
maxim2c->hot_plug_state = MAXIM2C_HOT_PLUG_OUT;
|
||||
} else {
|
||||
dev_info(dev, "serializer hot plug in\n");
|
||||
|
||||
queue_delayed_work(maxim2c->hot_plug_work.state_check_wq,
|
||||
&maxim2c->hot_plug_work.state_d_work,
|
||||
msecs_to_jiffies(100));
|
||||
maxim2c->hot_plug_state = MAXIM2C_HOT_PLUG_IN;
|
||||
}
|
||||
mutex_unlock(&maxim2c->mutex);
|
||||
|
||||
queue_delayed_work(maxim2c->hot_plug_work.state_check_wq,
|
||||
&maxim2c->hot_plug_work.state_d_work,
|
||||
msecs_to_jiffies(100));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@@ -226,6 +234,7 @@ static void maxim2c_hot_plug_state_check_work(struct work_struct *work)
|
||||
maxim2c_hot_plug_event_report(maxim2c, curr_lock_state);
|
||||
maxim2c->link_lock_state = curr_lock_state;
|
||||
}
|
||||
mutex_unlock(&maxim2c->mutex);
|
||||
|
||||
if (link_lock_change & MAXIM2C_LINK_MASK_A) {
|
||||
link_id = MAXIM2C_LINK_ID_A;
|
||||
@@ -287,8 +296,6 @@ static void maxim2c_hot_plug_state_check_work(struct work_struct *work)
|
||||
&maxim2c->hot_plug_work.state_d_work,
|
||||
msecs_to_jiffies(200));
|
||||
}
|
||||
|
||||
mutex_unlock(&maxim2c->mutex);
|
||||
}
|
||||
|
||||
int maxim2c_hot_plug_detect_work_start(maxim2c_t *maxim2c)
|
||||
|
||||
@@ -49,6 +49,21 @@ struct maxim2c_hot_plug_work {
|
||||
u32 hot_plug_state;
|
||||
};
|
||||
|
||||
struct maxim2c_vc_info {
|
||||
u32 enable; // 0: disable, !0: enable
|
||||
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 bus_fmt;
|
||||
|
||||
/*
|
||||
* the following are optional parameters, user-defined data types
|
||||
* default 0: invalid parameter
|
||||
*/
|
||||
u32 data_type;
|
||||
u32 data_bit;
|
||||
};
|
||||
|
||||
struct maxim2c_mode {
|
||||
u32 width;
|
||||
u32 height;
|
||||
@@ -61,6 +76,7 @@ struct maxim2c_mode {
|
||||
u32 bpp;
|
||||
const struct regval *reg_list;
|
||||
u32 vc[PAD_MAX];
|
||||
struct maxim2c_vc_info vc_info[PAD_MAX];
|
||||
struct v4l2_rect crop_rect;
|
||||
};
|
||||
|
||||
|
||||
@@ -103,6 +103,7 @@ static int maxim2c_support_mode_init(maxim2c_t *maxim2c)
|
||||
struct device_node *node = NULL;
|
||||
struct maxim2c_mode *mode = NULL;
|
||||
u32 value = 0, vc_array[PAD_MAX], crop_array[4];
|
||||
struct maxim2c_vc_info vc_info[PAD_MAX];
|
||||
int ret = 0, i = 0, array_size = 0;
|
||||
|
||||
dev_info(dev, "=== maxim2c support mode init ===\n");
|
||||
@@ -213,10 +214,67 @@ static int maxim2c_support_mode_init(maxim2c_t *maxim2c)
|
||||
dev_info(dev, "vc-array[%d] property: 0x%x\n", i, vc_array[i]);
|
||||
mode->vc[i] = vc_array[i];
|
||||
}
|
||||
} else {
|
||||
/* default vc config */
|
||||
#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE
|
||||
for (i = 0; i < PAD_MAX; i++)
|
||||
mode->vc[i] = i;
|
||||
#else
|
||||
switch (PAD_MAX) {
|
||||
case 4:
|
||||
mode->vc[3] = V4L2_MBUS_CSI2_CHANNEL_3;
|
||||
fallthrough;
|
||||
case 3:
|
||||
mode->vc[2] = V4L2_MBUS_CSI2_CHANNEL_2;
|
||||
fallthrough;
|
||||
case 2:
|
||||
mode->vc[1] = V4L2_MBUS_CSI2_CHANNEL_1;
|
||||
fallthrough;
|
||||
case 1:
|
||||
default:
|
||||
mode->vc[0] = V4L2_MBUS_CSI2_CHANNEL_0;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
for (i = 0; i < PAD_MAX; i++)
|
||||
dev_info(dev, "support mode: vc[%d] = 0x%x\n", i, mode->vc[i]);
|
||||
|
||||
/* vc info */
|
||||
array_size = of_property_count_u32_elems(node, "vc-info");
|
||||
if ((array_size > 0) &&
|
||||
(array_size % sizeof(struct maxim2c_vc_info) == 0) &&
|
||||
(array_size <= sizeof(struct maxim2c_vc_info) * PAD_MAX)) {
|
||||
|
||||
memset((char *)vc_info, 0, sizeof(vc_info));
|
||||
|
||||
ret = of_property_read_u32_array(node, "vc-info", (u32 *)vc_info, array_size);
|
||||
if (ret == 0) {
|
||||
/* <enable width height bus_fmt data_type data_bit> */
|
||||
for (i = 0; i < PAD_MAX; i++) {
|
||||
dev_info(dev, "vc-info[%d] property:\n", i);
|
||||
dev_info(dev, " vc-info[%d].enable = %d:\n", i, vc_info[i].enable);
|
||||
|
||||
dev_info(dev, " vc-info[%d].width = %d:\n", i, vc_info[i].width);
|
||||
dev_info(dev, " vc-info[%d].height = %d:\n", i, vc_info[i].height);
|
||||
dev_info(dev, " vc-info[%d].bus_fmt = %d:\n", i, vc_info[i].bus_fmt);
|
||||
|
||||
dev_info(dev, " vc-info[%d].data_type = %d:\n", i, vc_info[i].data_type);
|
||||
dev_info(dev, " vc-info[%d].data_bit = %d:\n", i, vc_info[i].data_bit);
|
||||
|
||||
mode->vc_info[i].enable = vc_info[i].enable;
|
||||
|
||||
mode->vc_info[i].width = vc_info[i].width;
|
||||
mode->vc_info[i].height = vc_info[i].height;
|
||||
mode->vc_info[i].bus_fmt = vc_info[i].bus_fmt;
|
||||
|
||||
mode->vc_info[i].data_type = vc_info[i].data_type;
|
||||
mode->vc_info[i].data_bit = vc_info[i].data_bit;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* crop rect */
|
||||
array_size = of_property_read_variable_u32_array(node,
|
||||
"crop-rect", crop_array, 1, 4);
|
||||
@@ -332,11 +390,52 @@ static void maxim2c_set_vicap_rst_inf(maxim2c_t *maxim2c,
|
||||
maxim2c->is_reset = rst_info.is_reset;
|
||||
}
|
||||
|
||||
static int maxim2c_get_channel_info(maxim2c_t *maxim2c, struct rkmodule_channel_info *ch_info)
|
||||
{
|
||||
const struct maxim2c_mode *mode = maxim2c->cur_mode;
|
||||
struct device *dev = &maxim2c->client->dev;
|
||||
|
||||
if (ch_info->index < PAD0 || ch_info->index >= PAD_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (mode->vc_info[ch_info->index].enable) {
|
||||
ch_info->vc = mode->vc[ch_info->index];
|
||||
|
||||
ch_info->width = mode->vc_info[ch_info->index].width;
|
||||
ch_info->height = mode->vc_info[ch_info->index].height;
|
||||
ch_info->bus_fmt = mode->vc_info[ch_info->index].bus_fmt;
|
||||
|
||||
/* optional parameters, default 0: invalid parameter */
|
||||
ch_info->data_type = mode->vc_info[ch_info->index].data_type;
|
||||
ch_info->data_bit = mode->vc_info[ch_info->index].data_bit;
|
||||
} else {
|
||||
ch_info->vc = mode->vc[ch_info->index];
|
||||
|
||||
ch_info->width = mode->width;
|
||||
ch_info->height = mode->height;
|
||||
ch_info->bus_fmt = mode->bus_fmt;
|
||||
}
|
||||
|
||||
dev_info(dev, "get channel info, ch_info->index = %d\n", ch_info->index);
|
||||
|
||||
dev_info(dev, " ch_info->vc = 0x%x\n", ch_info->vc);
|
||||
|
||||
dev_info(dev, " ch_info->width = %d\n", ch_info->width);
|
||||
dev_info(dev, " ch_info->height = %d\n", ch_info->height);
|
||||
dev_info(dev, " ch_info->bus_fmt = 0x%x\n", ch_info->bus_fmt);
|
||||
|
||||
dev_info(dev, " ch_info->data_type = 0x%x:\n", ch_info->data_type);
|
||||
dev_info(dev, " ch_info->data_bit = %d\n", ch_info->data_bit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long maxim2c_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
|
||||
{
|
||||
maxim2c_t *maxim2c = v4l2_get_subdevdata(sd);
|
||||
struct rkmodule_csi_dphy_param *dphy_param;
|
||||
struct rkmodule_capture_info *capture_info;
|
||||
struct rkmodule_channel_info *ch_info;
|
||||
long ret = 0;
|
||||
|
||||
dev_dbg(&maxim2c->client->dev, "ioctl cmd = 0x%08x\n", cmd);
|
||||
@@ -370,6 +469,10 @@ static long maxim2c_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
|
||||
else
|
||||
capture_info->mode = RKMODULE_CAPTURE_MODE_NONE;
|
||||
break;
|
||||
case RKMODULE_GET_CHANNEL_INFO:
|
||||
ch_info = (struct rkmodule_channel_info *)arg;
|
||||
ret = maxim2c_get_channel_info(maxim2c, ch_info);
|
||||
break;
|
||||
default:
|
||||
ret = -ENOIOCTLCMD;
|
||||
break;
|
||||
@@ -387,6 +490,7 @@ static long maxim2c_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd,
|
||||
struct rkmodule_vicap_reset_info *vicap_rst_inf;
|
||||
struct rkmodule_csi_dphy_param *dphy_param;
|
||||
struct rkmodule_capture_info *capture_info;
|
||||
struct rkmodule_channel_info *ch_info;
|
||||
long ret = 0;
|
||||
|
||||
switch (cmd) {
|
||||
@@ -479,6 +583,21 @@ static long maxim2c_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd,
|
||||
}
|
||||
kfree(capture_info);
|
||||
break;
|
||||
case RKMODULE_GET_CHANNEL_INFO:
|
||||
ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL);
|
||||
if (!ch_info) {
|
||||
ret = -ENOMEM;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = maxim2c_ioctl(sd, cmd, ch_info);
|
||||
if (!ret) {
|
||||
ret = copy_to_user(up, ch_info, sizeof(*ch_info));
|
||||
if (ret)
|
||||
ret = -EFAULT;
|
||||
}
|
||||
kfree(ch_info);
|
||||
break;
|
||||
default:
|
||||
ret = -ENOIOCTLCMD;
|
||||
break;
|
||||
@@ -892,8 +1011,17 @@ static int maxim2c_get_selection(struct v4l2_subdev *sd,
|
||||
#endif
|
||||
{
|
||||
maxim2c_t *maxim2c = v4l2_get_subdevdata(sd);
|
||||
int i = 0;
|
||||
|
||||
if (sel->target == V4L2_SEL_TGT_CROP_BOUNDS) {
|
||||
/* if multiple channel info enable, get_selection isn't support */
|
||||
for (i = 0; i < PAD_MAX; i++) {
|
||||
if (maxim2c->cur_mode->vc_info[i].enable) {
|
||||
v4l2_warn(sd, "Multi-channel enable, get_selection isn't support\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
sel->r.left = maxim2c->cur_mode->crop_rect.left;
|
||||
sel->r.width = maxim2c->cur_mode->crop_rect.width;
|
||||
sel->r.top = maxim2c->cur_mode->crop_rect.top;
|
||||
|
||||
@@ -70,6 +70,11 @@
|
||||
* 1. unified use __v4l2_ctrl_handler_setup in the xxx_start_stream
|
||||
* 2. support subscribe hot plug detect v4l2 event
|
||||
*
|
||||
* V3.06.00
|
||||
* 1. support multi-channel information configuration
|
||||
* 2. mode vc initialization when vc-array isn't configured
|
||||
* 3. fix the issue of mutex deadlock during hot plug
|
||||
*
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/i2c.h>
|
||||
@@ -97,7 +102,7 @@
|
||||
|
||||
#include "maxim4c_api.h"
|
||||
|
||||
#define DRIVER_VERSION KERNEL_VERSION(3, 0x05, 0x00)
|
||||
#define DRIVER_VERSION KERNEL_VERSION(3, 0x06, 0x00)
|
||||
|
||||
#define MAXIM4C_NAME "maxim4c"
|
||||
|
||||
@@ -166,24 +171,27 @@ static irqreturn_t maxim4c_hot_plug_detect_irq_handler(int irq, void *dev_id)
|
||||
int lock_gpio_level = 0;
|
||||
|
||||
mutex_lock(&maxim4c->mutex);
|
||||
if (maxim4c->streaming) {
|
||||
lock_gpio_level = gpiod_get_value_cansleep(maxim4c->lock_gpio);
|
||||
if (lock_gpio_level == 0) {
|
||||
dev_info(dev, "serializer hot plug out\n");
|
||||
if (maxim4c->streaming == 0) {
|
||||
mutex_unlock(&maxim4c->mutex);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
maxim4c->hot_plug_state = MAXIM4C_HOT_PLUG_OUT;
|
||||
} else {
|
||||
dev_info(dev, "serializer hot plug in\n");
|
||||
lock_gpio_level = gpiod_get_value_cansleep(maxim4c->lock_gpio);
|
||||
if (lock_gpio_level == 0) {
|
||||
dev_info(dev, "serializer hot plug out\n");
|
||||
|
||||
maxim4c->hot_plug_state = MAXIM4C_HOT_PLUG_IN;
|
||||
}
|
||||
maxim4c->hot_plug_state = MAXIM4C_HOT_PLUG_OUT;
|
||||
} else {
|
||||
dev_info(dev, "serializer hot plug in\n");
|
||||
|
||||
queue_delayed_work(maxim4c->hot_plug_work.state_check_wq,
|
||||
&maxim4c->hot_plug_work.state_d_work,
|
||||
msecs_to_jiffies(100));
|
||||
maxim4c->hot_plug_state = MAXIM4C_HOT_PLUG_IN;
|
||||
}
|
||||
mutex_unlock(&maxim4c->mutex);
|
||||
|
||||
queue_delayed_work(maxim4c->hot_plug_work.state_check_wq,
|
||||
&maxim4c->hot_plug_work.state_d_work,
|
||||
msecs_to_jiffies(100));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@@ -249,6 +257,7 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work)
|
||||
maxim4c_hot_plug_event_report(maxim4c, curr_lock_state);
|
||||
maxim4c->link_lock_state = curr_lock_state;
|
||||
}
|
||||
mutex_unlock(&maxim4c->mutex);
|
||||
|
||||
if (link_lock_change & MAXIM4C_LINK_MASK_A) {
|
||||
link_id = MAXIM4C_LINK_ID_A;
|
||||
@@ -362,8 +371,6 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work)
|
||||
&maxim4c->hot_plug_work.state_d_work,
|
||||
msecs_to_jiffies(200));
|
||||
}
|
||||
|
||||
mutex_unlock(&maxim4c->mutex);
|
||||
}
|
||||
|
||||
int maxim4c_hot_plug_detect_work_start(maxim4c_t *maxim4c)
|
||||
|
||||
@@ -49,6 +49,21 @@ struct maxim4c_hot_plug_work {
|
||||
u32 hot_plug_state;
|
||||
};
|
||||
|
||||
struct maxim4c_vc_info {
|
||||
u32 enable; // 0: disable, !0: enable
|
||||
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 bus_fmt;
|
||||
|
||||
/*
|
||||
* the following are optional parameters, user-defined data types
|
||||
* default 0: invalid parameter
|
||||
*/
|
||||
u32 data_type;
|
||||
u32 data_bit;
|
||||
};
|
||||
|
||||
struct maxim4c_mode {
|
||||
u32 width;
|
||||
u32 height;
|
||||
@@ -61,6 +76,7 @@ struct maxim4c_mode {
|
||||
u32 bpp;
|
||||
const struct regval *reg_list;
|
||||
u32 vc[PAD_MAX];
|
||||
struct maxim4c_vc_info vc_info[PAD_MAX];
|
||||
struct v4l2_rect crop_rect;
|
||||
};
|
||||
|
||||
|
||||
@@ -103,6 +103,7 @@ static int maxim4c_support_mode_init(maxim4c_t *maxim4c)
|
||||
struct device_node *node = NULL;
|
||||
struct maxim4c_mode *mode = NULL;
|
||||
u32 value = 0, vc_array[PAD_MAX], crop_array[4];
|
||||
struct maxim4c_vc_info vc_info[PAD_MAX];
|
||||
int ret = 0, i = 0, array_size = 0;
|
||||
|
||||
dev_info(dev, "=== maxim4c support mode init ===\n");
|
||||
@@ -213,10 +214,67 @@ static int maxim4c_support_mode_init(maxim4c_t *maxim4c)
|
||||
dev_info(dev, "vc-array[%d] property: 0x%x\n", i, vc_array[i]);
|
||||
mode->vc[i] = vc_array[i];
|
||||
}
|
||||
} else {
|
||||
/* default vc config */
|
||||
#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE
|
||||
for (i = 0; i < PAD_MAX; i++)
|
||||
mode->vc[i] = i;
|
||||
#else
|
||||
switch (PAD_MAX) {
|
||||
case 4:
|
||||
mode->vc[3] = V4L2_MBUS_CSI2_CHANNEL_3;
|
||||
fallthrough;
|
||||
case 3:
|
||||
mode->vc[2] = V4L2_MBUS_CSI2_CHANNEL_2;
|
||||
fallthrough;
|
||||
case 2:
|
||||
mode->vc[1] = V4L2_MBUS_CSI2_CHANNEL_1;
|
||||
fallthrough;
|
||||
case 1:
|
||||
default:
|
||||
mode->vc[0] = V4L2_MBUS_CSI2_CHANNEL_0;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
for (i = 0; i < PAD_MAX; i++)
|
||||
dev_info(dev, "support mode: vc[%d] = 0x%x\n", i, mode->vc[i]);
|
||||
|
||||
/* vc info */
|
||||
array_size = of_property_count_u32_elems(node, "vc-info");
|
||||
if ((array_size > 0) &&
|
||||
(array_size % sizeof(struct maxim4c_vc_info) == 0) &&
|
||||
(array_size <= sizeof(struct maxim4c_vc_info) * PAD_MAX)) {
|
||||
|
||||
memset((char *)vc_info, 0, sizeof(vc_info));
|
||||
|
||||
ret = of_property_read_u32_array(node, "vc-info", (u32 *)vc_info, array_size);
|
||||
if (ret == 0) {
|
||||
/* <enable width height bus_fmt data_type data_bit> */
|
||||
for (i = 0; i < PAD_MAX; i++) {
|
||||
dev_info(dev, "vc-info[%d] property:\n", i);
|
||||
dev_info(dev, " vc-info[%d].enable = %d:\n", i, vc_info[i].enable);
|
||||
|
||||
dev_info(dev, " vc-info[%d].width = %d:\n", i, vc_info[i].width);
|
||||
dev_info(dev, " vc-info[%d].height = %d:\n", i, vc_info[i].height);
|
||||
dev_info(dev, " vc-info[%d].bus_fmt = %d:\n", i, vc_info[i].bus_fmt);
|
||||
|
||||
dev_info(dev, " vc-info[%d].data_type = %d:\n", i, vc_info[i].data_type);
|
||||
dev_info(dev, " vc-info[%d].data_bit = %d:\n", i, vc_info[i].data_bit);
|
||||
|
||||
mode->vc_info[i].enable = vc_info[i].enable;
|
||||
|
||||
mode->vc_info[i].width = vc_info[i].width;
|
||||
mode->vc_info[i].height = vc_info[i].height;
|
||||
mode->vc_info[i].bus_fmt = vc_info[i].bus_fmt;
|
||||
|
||||
mode->vc_info[i].data_type = vc_info[i].data_type;
|
||||
mode->vc_info[i].data_bit = vc_info[i].data_bit;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* crop rect */
|
||||
array_size = of_property_read_variable_u32_array(node,
|
||||
"crop-rect", crop_array, 1, 4);
|
||||
@@ -332,11 +390,52 @@ static void maxim4c_set_vicap_rst_inf(maxim4c_t *maxim4c,
|
||||
maxim4c->is_reset = rst_info.is_reset;
|
||||
}
|
||||
|
||||
static int maxim4c_get_channel_info(maxim4c_t *maxim4c, struct rkmodule_channel_info *ch_info)
|
||||
{
|
||||
const struct maxim4c_mode *mode = maxim4c->cur_mode;
|
||||
struct device *dev = &maxim4c->client->dev;
|
||||
|
||||
if (ch_info->index < PAD0 || ch_info->index >= PAD_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (mode->vc_info[ch_info->index].enable) {
|
||||
ch_info->vc = mode->vc[ch_info->index];
|
||||
|
||||
ch_info->width = mode->vc_info[ch_info->index].width;
|
||||
ch_info->height = mode->vc_info[ch_info->index].height;
|
||||
ch_info->bus_fmt = mode->vc_info[ch_info->index].bus_fmt;
|
||||
|
||||
/* optional parameters, default 0: invalid parameter */
|
||||
ch_info->data_type = mode->vc_info[ch_info->index].data_type;
|
||||
ch_info->data_bit = mode->vc_info[ch_info->index].data_bit;
|
||||
} else {
|
||||
ch_info->vc = mode->vc[ch_info->index];
|
||||
|
||||
ch_info->width = mode->width;
|
||||
ch_info->height = mode->height;
|
||||
ch_info->bus_fmt = mode->bus_fmt;
|
||||
}
|
||||
|
||||
dev_info(dev, "get channel info, ch_info->index = %d\n", ch_info->index);
|
||||
|
||||
dev_info(dev, " ch_info->vc = 0x%x\n", ch_info->vc);
|
||||
|
||||
dev_info(dev, " ch_info->width = %d\n", ch_info->width);
|
||||
dev_info(dev, " ch_info->height = %d\n", ch_info->height);
|
||||
dev_info(dev, " ch_info->bus_fmt = 0x%x\n", ch_info->bus_fmt);
|
||||
|
||||
dev_info(dev, " ch_info->data_type = 0x%x:\n", ch_info->data_type);
|
||||
dev_info(dev, " ch_info->data_bit = %d\n", ch_info->data_bit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long maxim4c_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
|
||||
{
|
||||
maxim4c_t *maxim4c = v4l2_get_subdevdata(sd);
|
||||
struct rkmodule_csi_dphy_param *dphy_param;
|
||||
struct rkmodule_capture_info *capture_info;
|
||||
struct rkmodule_channel_info *ch_info;
|
||||
long ret = 0;
|
||||
|
||||
dev_dbg(&maxim4c->client->dev, "ioctl cmd = 0x%08x\n", cmd);
|
||||
@@ -370,6 +469,10 @@ static long maxim4c_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
|
||||
else
|
||||
capture_info->mode = RKMODULE_CAPTURE_MODE_NONE;
|
||||
break;
|
||||
case RKMODULE_GET_CHANNEL_INFO:
|
||||
ch_info = (struct rkmodule_channel_info *)arg;
|
||||
ret = maxim4c_get_channel_info(maxim4c, ch_info);
|
||||
break;
|
||||
default:
|
||||
ret = -ENOIOCTLCMD;
|
||||
break;
|
||||
@@ -387,6 +490,7 @@ static long maxim4c_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd,
|
||||
struct rkmodule_vicap_reset_info *vicap_rst_inf;
|
||||
struct rkmodule_csi_dphy_param *dphy_param;
|
||||
struct rkmodule_capture_info *capture_info;
|
||||
struct rkmodule_channel_info *ch_info;
|
||||
long ret = 0;
|
||||
|
||||
switch (cmd) {
|
||||
@@ -479,6 +583,21 @@ static long maxim4c_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd,
|
||||
}
|
||||
kfree(capture_info);
|
||||
break;
|
||||
case RKMODULE_GET_CHANNEL_INFO:
|
||||
ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL);
|
||||
if (!ch_info) {
|
||||
ret = -ENOMEM;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = maxim4c_ioctl(sd, cmd, ch_info);
|
||||
if (!ret) {
|
||||
ret = copy_to_user(up, ch_info, sizeof(*ch_info));
|
||||
if (ret)
|
||||
ret = -EFAULT;
|
||||
}
|
||||
kfree(ch_info);
|
||||
break;
|
||||
default:
|
||||
ret = -ENOIOCTLCMD;
|
||||
break;
|
||||
@@ -892,8 +1011,18 @@ static int maxim4c_get_selection(struct v4l2_subdev *sd,
|
||||
#endif
|
||||
{
|
||||
maxim4c_t *maxim4c = v4l2_get_subdevdata(sd);
|
||||
int i = 0;
|
||||
|
||||
if (sel->target == V4L2_SEL_TGT_CROP_BOUNDS) {
|
||||
/* if multiple channel info enable, get_selection isn't support */
|
||||
for (i = 0; i < PAD_MAX; i++) {
|
||||
if (maxim4c->cur_mode->vc_info[i].enable) {
|
||||
v4l2_warn(sd,
|
||||
"Multi-channel enable, get_selection isn't support\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
sel->r.left = maxim4c->cur_mode->crop_rect.left;
|
||||
sel->r.width = maxim4c->cur_mode->crop_rect.width;
|
||||
sel->r.top = maxim4c->cur_mode->crop_rect.top;
|
||||
|
||||
@@ -796,8 +796,8 @@ static void hdmirx_get_color_space(struct rk_hdmirx_dev *hdmirx_dev)
|
||||
*/
|
||||
hdmirx_readl(hdmirx_dev, PKTDEC_AVIIF_PH2_1);
|
||||
val = hdmirx_readl(hdmirx_dev, PKTDEC_AVIIF_PB3_0);
|
||||
EC2_0 = (val & EXTEND_COLORIMETRY) >> 20;
|
||||
C1_C0 = (val & COLORIMETRY_MASK) >> 14;
|
||||
EC2_0 = (val & EXTEND_COLORIMETRY) >> 28;
|
||||
C1_C0 = (val & COLORIMETRY_MASK) >> 22;
|
||||
if (hdmirx_dev->pix_fmt == HDMIRX_RGB888) {
|
||||
if (EC2_0 == HDMIRX_ADOBE_RGB ||
|
||||
EC2_0 == HDMIRX_BT2020_RGB_OR_YCC)
|
||||
@@ -827,14 +827,14 @@ static void hdmirx_get_color_space(struct rk_hdmirx_dev *hdmirx_dev)
|
||||
|
||||
static bool IsColorRangeLimitFormat(uint32_t width, uint32_t height, bool interlace)
|
||||
{
|
||||
if (((width == 720) && (height == 240) && (interlace == false)) \
|
||||
|| ((width == 720) && (height == 1201) && (interlace == false)) \
|
||||
|| ((width == 720) && (height == 480) && (interlace == true)) \
|
||||
|| ((width == 720) && (height == 576) && (interlace == true)) \
|
||||
|| ((width == 1440) && (height == 480) && (interlace == true)) \
|
||||
|| ((width == 1440) && (height == 576) && (interlace == true)) \
|
||||
|| ((width == 1920) && (height == 1080) && (interlace == true)) \
|
||||
|| ((width == 2880) && (height == 480) && (interlace == true)) \
|
||||
if (((width == 720) && (height == 240) && (interlace == false))
|
||||
|| ((width == 720) && (height == 1201) && (interlace == false))
|
||||
|| ((width == 720) && (height == 480) && (interlace == true))
|
||||
|| ((width == 720) && (height == 576) && (interlace == true))
|
||||
|| ((width == 1440) && (height == 480) && (interlace == true))
|
||||
|| ((width == 1440) && (height == 576) && (interlace == true))
|
||||
|| ((width == 1920) && (height == 1080) && (interlace == true))
|
||||
|| ((width == 2880) && (height == 480) && (interlace == true))
|
||||
|| ((width == 3840) && (height == 2160) && (interlace == false))) {
|
||||
return true;
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user