Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
/kernel_mod
/sources_*
/.claude/skills/v4l2-test/v4l2-test_results
**__pycache__
135 changes: 67 additions & 68 deletions kernel/realsense/d4xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ enum ds5_mux_pad {
#define DS5_START_POLL_TIME 10
#define DS5_START_MAX_TIME 2000
#define DS5_START_MAX_COUNT (DS5_START_MAX_TIME / DS5_START_POLL_TIME)
#define MAX_DS5_CONFIG_RETRIES 5

/* I2C retry configuration */
#define DS5_I2C_RETRY_COUNT 5
Expand Down Expand Up @@ -1677,9 +1678,9 @@ static int ds5_setup_pipeline(struct ds5 *state, u8 data_type1, u8 data_type2,
int pipe_id, u32 vc_id)
{
int ret = 0;
dev_warn(&state->client->dev,
"set pipe %d, data_type1: 0x%x, data_type2: 0x%x, vc_id: %u\n",
pipe_id, data_type1, data_type2, vc_id);
dev_dbg(&state->client->dev,
"set pipe %d, data_type1: 0x%x, data_type2: 0x%x, vc_id: %u\n",
pipe_id, data_type1, data_type2, vc_id);
ret |= max9295_set_pipe(state->ser_dev, pipe_id,
data_type1, data_type2, vc_id);
ret |= state->dser_ops->set_pipe(state->dser_dev, pipe_id,
Expand Down Expand Up @@ -1760,9 +1761,9 @@ static int ds5_configure(struct ds5 *state)

vc_id = state->g_ctx.dst_vc;
if (PIPE_NOT_CONFIGURED == sensor->pipe_id ||
sensor->pipe_data_type1 != data_type1 ||
sensor->pipe_data_type2 != data_type2 ||
sensor->pipe_vc_id != vc_id) {
sensor->pipe_data_type1 != data_type1 ||
sensor->pipe_data_type2 != data_type2 ||
sensor->pipe_vc_id != vc_id) {
/* Release old pipe only if it changed and was valid */
if (sensor->pipe_id >= 0) {
mutex_lock(&serdes_lock__);
Expand All @@ -1783,8 +1784,7 @@ static int ds5_configure(struct ds5 *state)
mutex_unlock(&serdes_lock__);
if (sensor->pipe_id < 0) {
dev_err(&state->client->dev, "No free pipe in %s\n",state->dser_ops->name);
ret = -(ENOSR);
return ret;
return -ENOSR;
}
ret = ds5_setup_pipeline(state, data_type1, data_type2,
sensor->pipe_id, vc_id);
Expand All @@ -1793,34 +1793,31 @@ static int ds5_configure(struct ds5 *state)
state->dser_ops->reset_oneshot(state->dser_dev);
if (ret < 0)
return ret;
dev_warn(&state->client->dev,
dev_dbg(&state->client->dev,
"pipe %d new (dt1=0x%x dt2=0x%x vc=%u)\n",
sensor->pipe_id, data_type1, data_type2, vc_id);
sensor->pipe_data_type1 = data_type1;
sensor->pipe_data_type2 = data_type2;
sensor->pipe_vc_id = vc_id;
} else {
dev_warn(&state->client->dev,
dev_dbg(&state->client->dev,
"pipe %d already configured (dt1=0x%x dt2=0x%x vc=%u)\n",
sensor->pipe_id, data_type1, data_type2, vc_id);
}
#endif

fmt = sensor->streaming ? sensor->config.format->data_type : 0;

/*
* Set depth stream Z16 data type as 0x31
* Set IR stream Y8I data type as 0x32
/* Determine desired data-type (special cases for depth/IR), then write
* it only when it differs from cached value. This avoids overwriting a
* correct DT with 0 (which caused INVALID_DT on subsequent attempts).
*/
dt_value = fmt;
if (state->is_depth && fmt != 0)
dt_value = 0x31;
else if (state->is_y8 && fmt != 0 &&
sensor->config.format->data_type == GMSL_CSI_DT_YUV422_8)
ret = ds5_write(state, dt_addr, 0x32);
else
ret = ds5_write(state, dt_addr, fmt);
if (ret < 0)
return ret;
dt_value = 0x32;

if (sensor->cached_dt_value != dt_value) {
ret = ds5_write(state, dt_addr, dt_value);
Expand Down Expand Up @@ -4456,14 +4453,14 @@ static int ds5_mux_s_stream(struct v4l2_subdev *sd, int on)
struct ds5 *state = container_of(sd, struct ds5, mux.sd.subdev);
u16 streaming, status;
int ret = 0;
unsigned int i = 0;
unsigned int i = 0, ds5_config_retries = MAX_DS5_CONFIG_RETRIES;
unsigned long timeout, ts;
int restore_val = 0;
u16 stream_cmd;
u16 config_status_base, stream_status_base, stream_id, vc_id;
struct ds5_sensor *sensor = state->mux.last_set;
u16 expected_streaming_state;
bool ds5_config_done = !on;
bool ds5_config_done = !on; /* for stop, skip config */

// spare duplicate calls
if (sensor->streaming == on)
Expand Down Expand Up @@ -4496,13 +4493,23 @@ static int ds5_mux_s_stream(struct v4l2_subdev *sd, int on)
vc_id = state->g_ctx.dst_vc;
#endif
#endif
dev_warn(&state->client->dev, "s_stream for stream %s, vc:%d, SENSOR=%s on = %d\n",
dev_dbg(&state->client->dev, "s_stream for stream %s, vc:%d, SENSOR=%s on = %d\n",
sensor->sd.name, vc_id, ds5_get_sensor_name(state), on);

if (on) {
stream_cmd = (DS5_STREAM_START | stream_id);
expected_streaming_state = DS5_STREAM_STREAMING;
status = 0;
} else {
stream_cmd = (DS5_STREAM_STOP | stream_id);
expected_streaming_state = DS5_STREAM_IDLE;
status = DS5_STATUS_STREAMING;
}

/* Verify stream is in the expected state before issuing command */
ts = jiffies;
for (timeout = ts + msecs_to_jiffies(DS5_START_MAX_TIME);
time_before(jiffies, timeout); msleep_range(i*DS5_START_POLL_TIME))
for (timeout = ts + msecs_to_jiffies(DS5_START_MAX_TIME), i = 0;
time_before(jiffies, timeout); i++, msleep_range(i*DS5_START_POLL_TIME))
{
ret = ds5_read(state, config_status_base, &status);
if ((ret >= 0) && (on == !(status & DS5_STATUS_STREAMING))) {
Expand All @@ -4511,7 +4518,7 @@ static int ds5_mux_s_stream(struct v4l2_subdev *sd, int on)
}
if (on == !(status & DS5_STATUS_STREAMING))
{
dev_warn(&state->client->dev,
dev_dbg(&state->client->dev,
"stream %d in expected state, toggling to %d (status: 0x%04x) %dms\n",
stream_id, on, status, jiffies_to_msecs(jiffies - ts));
} else {
Expand All @@ -4523,27 +4530,20 @@ static int ds5_mux_s_stream(struct v4l2_subdev *sd, int on)

restore_val = sensor->streaming;
sensor->streaming = on;
if (on) {
stream_cmd = (DS5_STREAM_START | stream_id);
expected_streaming_state = DS5_STREAM_STREAMING;
} else {
stream_cmd = (DS5_STREAM_STOP | stream_id);
expected_streaming_state = DS5_STREAM_IDLE;
}
streaming = ~expected_streaming_state; /* force initial toggle */

/*
* Execute command, poll state (retry if necessary) and poll completion.
* For start, also confirm config status is valid and not rejected by FW, otherwise retry.
*/
ts = jiffies;
streaming = ~expected_streaming_state; /* force initial toggle */
for (timeout = ts + msecs_to_jiffies(DS5_START_MAX_TIME), i = 0;
time_before(jiffies, timeout); i++, msleep_range(i*DS5_START_POLL_TIME))
{
if (!ds5_config_done) {
ret = ds5_configure(state);
if (ret < 0) {
dev_err(&state->client->dev, "stream %d config failed on retry %d\n",
dev_warn(&state->client->dev, "stream %d config failed, retry %d\n",
stream_id, i);
continue;
}
Expand All @@ -4553,7 +4553,7 @@ static int ds5_mux_s_stream(struct v4l2_subdev *sd, int on)
if (streaming != expected_streaming_state) {
ret = ds5_write(state, DS5_START_STOP_STREAM, stream_cmd);
if (ret < 0) {
dev_err(&state->client->dev, "stream %d cmd 0x%x write failed on retry %d\n",
dev_warn(&state->client->dev, "stream %d cmd 0x%x write failed, retry %d\n",
stream_id, stream_cmd, i);
continue;
}
Expand All @@ -4576,16 +4576,23 @@ static int ds5_mux_s_stream(struct v4l2_subdev *sd, int on)
DS5_STATUS_INVALID_RES |
DS5_STATUS_INVALID_FPS)))
{
dev_err(&state->client->dev,
dev_warn(&state->client->dev,
"stream %d config rejected, status 0x%04x, retry %u\n", stream_id, status, i);
ds5_config_done = false;
ds5_config_cache_clear(sensor);
if (ds5_config_retries > 0) {
ds5_config_retries--;
ds5_config_done = false;
ds5_config_cache_clear(sensor);
} else {
dev_warn(&state->client->dev,
"stream %d config failed after %d retries, aborting\n", stream_id, i);
break;
}
continue;
}

if (!on == !(status & DS5_STATUS_STREAMING))
{
dev_warn(&state->client->dev,
dev_dbg(&state->client->dev,
"stream %d toggle ok to %d in %dms, retries %d\n",
stream_id, on, jiffies_to_msecs(jiffies - ts), i);
break;
Expand All @@ -4601,44 +4608,36 @@ static int ds5_mux_s_stream(struct v4l2_subdev *sd, int on)
ds5_write(state, DS5_START_STOP_STREAM,
(on ? DS5_STREAM_STOP : DS5_STREAM_START) | stream_id);
}
ret = -EAGAIN;
#ifdef CONFIG_VIDEO_D4XX_SERDES
#ifdef CONFIG_VIDEO_D4XX_SERDES
if (on && sensor->pipe_id >= 0) {
mutex_lock(&serdes_lock__);
if (state->dser_ops->release_pipe(state->dser_dev, sensor->pipe_id) < 0)
dev_warn(&state->client->dev, "release pipe failed\n");
sensor->pipe_id = PIPE_NOT_CONFIGURED;
ret = state->dser_ops->release_pipe(state->dser_dev, sensor->pipe_id);
mutex_unlock(&serdes_lock__);
if (ret < 0) {
dev_warn(&state->client->dev, "release pipe failed\n");
} else {
sensor->pipe_id = PIPE_NOT_CONFIGURED;
}
}
#endif
#endif
sensor->streaming = restore_val;
ret = -EAGAIN;
}
else if (!on)
{
#ifdef CONFIG_VIDEO_D4XX_SERDES
mutex_lock(&serdes_lock__);
// reset data path when Y12I streaming is done
if (state->is_y8 &&
state->ir.sensor.config.format->data_type ==
GMSL_CSI_DT_RGB_888) {
if (state->dser_ops->release_pipe(state->dser_dev, sensor->pipe_id) < 0)
dev_warn(&state->client->dev, "release pipe failed\n");
else
sensor->pipe_id = PIPE_NOT_CONFIGURED;
if (state->is_y8
&& (state->ir.sensor.config.format->data_type == GMSL_CSI_DT_RGB_888))
{
state->dser_ops->reset_oneshot(state->dser_dev);
}
#ifndef CONFIG_TEGRA_CAMERA_PLATFORM
// reset for IPU6
streaming = 0;
for (i = 0; i < ARRAY_SIZE(d4xx_set_sub_stream); i++) {
if (d4xx_set_sub_stream[i]) {
streaming = 1;
break;
}
}
if (!streaming) {
dev_warn(&state->client->dev, "deserializer reset oneshot\n");
state->dser_ops->reset_oneshot(state->dser_dev);
}
#endif
mutex_unlock(&serdes_lock__);
#else
msleep_range(100);
#endif
}
return ret;
Expand Down Expand Up @@ -5413,30 +5412,30 @@ static void ds5_adjust_sync_mode_control(struct i2c_client *client, struct ds5 *
switch (dev_type) {
case DS5_DEVICE_TYPE_D41X:
/* D41X does not support sync mode */
dev_info(&client->dev, "%s(): D41X does not support sync mode\n", __func__);
dev_dbg(&client->dev, "%s(): D41X does not support sync mode\n", __func__);
__v4l2_ctrl_modify_range(state->ctrls.sync_mode, 0, 0, 0, 0);
break;
case DS5_DEVICE_TYPE_D40X:
/* D401 only supports modes 0 (Default) and 2 (Slave) */
__v4l2_ctrl_modify_range(state->ctrls.sync_mode, 0, 2, 0, 0);
state->ctrls.sync_mode->qmenu = sync_mode_menu_d401;
dev_info(&client->dev, "%s(): D401 sync mode: 0 (Default), 2 (Slave)\n", __func__);
dev_dbg(&client->dev, "%s(): D401 sync mode: 0 (Default), 2 (Slave)\n", __func__);
break;
case DS5_DEVICE_TYPE_D43X:
/* D430 GMSL supports all 6 sync modes (0-5) */
__v4l2_ctrl_modify_range(state->ctrls.sync_mode, 0, 5, 0, 0);
state->ctrls.sync_mode->qmenu = sync_mode_menu_full;
dev_info(&client->dev, "%s(): D430 GMSL sync mode: all modes 0-5 supported\n", __func__);
dev_dbg(&client->dev, "%s(): D430 GMSL sync mode: all modes 0-5 supported\n", __func__);
break;
case DS5_DEVICE_TYPE_D45X:
/* D450 supports all 6 sync modes (0-5) */
__v4l2_ctrl_modify_range(state->ctrls.sync_mode, 0, 5, 0, 0);
state->ctrls.sync_mode->qmenu = sync_mode_menu_full;
dev_info(&client->dev, "%s(): D450 sync mode: all modes 0-5 supported\n", __func__);
dev_dbg(&client->dev, "%s(): D450 sync mode: all modes 0-5 supported\n", __func__);
break;
case DS5_DEVICE_TYPE_D46X:
/* D46X does not support sync mode */
dev_info(&client->dev, "%s(): D46X does not support sync mode\n", __func__);
dev_dbg(&client->dev, "%s(): D46X does not support sync mode\n", __func__);
__v4l2_ctrl_modify_range(state->ctrls.sync_mode, 0, 0, 0, 0);
break;
default:
Expand Down
Loading