From 228586f96e130fc449b84e395152490be68b6eae Mon Sep 17 00:00:00 2001 From: Benjamin Schaaf Date: Mon, 22 Nov 2021 23:38:26 +1100 Subject: [PATCH 047/464] media: ov5640: Improve firmware load time Downloading the firmware can be done in groups to minimize i2c packets. The firmware status is set practically immediately upon successfully loading it, so there's no need for a long timeout or retry. The firmware can also not be loaded when the sensor isn't powered on, so don't bother trying. --- drivers/media/i2c/ov5640.c | 97 ++++++++++++++++++++++++++++---------- 1 file changed, 71 insertions(+), 26 deletions(-) diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index a2edc9c509c4..2a4e37e77048 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -1233,6 +1233,8 @@ static int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val) msg.buf = buf; msg.len = sizeof(buf); + dev_dbg(&client->dev, "[wr %04x] <= %d\n", reg, val); + ret = i2c_transfer(client->adapter, &msg, 1); if (ret < 0) { dev_err(&client->dev, "%s: error: reg=%x, val=%x\n", @@ -1243,6 +1245,42 @@ static int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val) return 0; } +static int ov5640_write_regs(struct ov5640_dev *sensor, u16 reg, + const u8 *data, int data_size) +{ + struct i2c_client *client = sensor->i2c_client; + struct i2c_msg msg; + u8 buf[254 + 2]; + int ret; + + if (data_size > sizeof(buf) - 2) { + v4l2_err(&sensor->sd, "%s: oversized transfer (size=%d)\n", + __func__, data_size); + return -EINVAL; + } + + buf[0] = reg >> 8; + buf[1] = reg & 0xff; + memcpy(buf + 2, data, data_size); + + msg.addr = client->addr; + msg.flags = client->flags; + msg.buf = buf; + msg.len = data_size + 2; + + dev_dbg(&client->dev, "[wr %04x] <= %*ph\n", (u32)reg, data_size, data); + + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret < 0) { + v4l2_err(&sensor->sd, + "%s: error %d: reg=%x, data=%*ph\n", + __func__, ret, (u32)reg, data_size, data); + return ret; + } + + return 0; +} + static int ov5640_read_reg(struct ov5640_dev *sensor, u16 reg, u8 *val) { struct i2c_client *client = sensor->i2c_client; @@ -2546,6 +2584,7 @@ static int ov5640_copy_fw_to_device(struct ov5640_dev *sensor, u8 fw_status; int i; int ret; + int num_groups, group_size = 254; // Putting MCU in reset state ret = ov5640_write_reg(sensor, OV5640_REG_SYS_RESET00, 0x20); @@ -2553,10 +2592,24 @@ static int ov5640_copy_fw_to_device(struct ov5640_dev *sensor, return ret; // Write firmware - for (i = 0; i < fw->size / sizeof(u8); i++) - ov5640_write_reg(sensor, - OV5640_REG_FIRMWARE_BASE + i, - data[i]); + num_groups = fw->size / group_size; + for (i = 0; i < num_groups; i++) { + ret = ov5640_write_regs(sensor, + OV5640_REG_FIRMWARE_BASE + i * group_size, + data + i * group_size, + group_size); + if (ret) + return ret; + } + + if (i * group_size < fw->size) { + ret = ov5640_write_regs(sensor, + OV5640_REG_FIRMWARE_BASE + i * group_size, + data + i * group_size, + fw->size - i * group_size); + if (ret) + return ret; + } // Reset MCU state ov5640_write_reg(sensor, OV5640_REG_FW_CMD_MAIN, 0x00); @@ -2578,31 +2631,17 @@ static int ov5640_copy_fw_to_device(struct ov5640_dev *sensor, // Wait for firmware to be ready for (i = 0; i < 5; i++) { ret = ov5640_read_reg(sensor, OV5640_REG_FW_STATUS, &fw_status); - if (fw_status == OV5640_FW_STATUS_S_IDLE) { - dev_info(&client->dev, "fw started after %d ms\n", i * 50); + if (ret) { return ret; } - msleep(50); - } - dev_err(&client->dev, "uploaded firmware didn't start, got to 0x%x, retrying...\n", fw_status); - // Putting MCU in reset state - ret = ov5640_write_reg(sensor, OV5640_REG_SYS_RESET00, 0x20); - if (ret) - return ret; - // Start AF MCU - ret = ov5640_write_reg(sensor, OV5640_REG_SYS_RESET00, 0x00); - if (ret) - return ret; - // Wait for firmware to be ready - for (i = 0; i < 5; i++) { - ret = ov5640_read_reg(sensor, OV5640_REG_FW_STATUS, &fw_status); if (fw_status == OV5640_FW_STATUS_S_IDLE) { - dev_info(&client->dev, "fw started after %d ms\n", i * 50); - return ret; + dev_info(&client->dev, "fw started after %d ms\n", i * 5); + return 0; } - msleep(50); + msleep(5); } + dev_err(&client->dev, "uploaded firmware didn't start, got to 0x%x\n", fw_status); return -ETIMEDOUT; } @@ -2643,10 +2682,9 @@ static int ov5640_af_init(struct ov5640_dev *sensor) return ret; // Set lens focus driver on - ov5640_write_reg(sensor, OV5640_REG_VCM_CONTROL4, 0x3f); + ret = ov5640_write_reg(sensor, OV5640_REG_VCM_CONTROL4, 0x3f); if (ret) return ret; - return ret; } @@ -3411,9 +3449,16 @@ static int ov5640_set_ctrl_focus(struct ov5640_dev *sensor, int command) struct i2c_client *client = sensor->i2c_client; int ret; + // Don't attempt to do focus if the embedded controller is powered down + if (!sensor->streaming) { + dev_err(&client->dev, "%s: can't set focus when not powered\n", + __func__); + return 0; + } + ret = ov5640_af_init(sensor); if (ret) { - dev_err(&client->dev, "%s: no autofocus firmware loaded\n", + dev_err(&client->dev, "%s: autofocus firmware load failed\n", __func__); return 0; } -- 2.34.1