From 9370bb92b2d16684ee45cf24e879c93c509162da Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Thu, 19 Dec 2024 01:47:39 +0000 Subject: [PATCH] add wifi6 8852be driver --- kernel/drivers/media/i2c/imx415.c | 644 +++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 files changed, 566 insertions(+), 78 deletions(-) diff --git a/kernel/drivers/media/i2c/imx415.c b/kernel/drivers/media/i2c/imx415.c index 5cb5a88..2cf6561 100644 --- a/kernel/drivers/media/i2c/imx415.c +++ b/kernel/drivers/media/i2c/imx415.c @@ -23,6 +23,12 @@ * V0.0X01.0X06 * 1. support DOL3 10bit 20fps 1485Mbps * 2. fixed linkfreq error + * V0.0X01.0X07 + * 1. fix set_fmt & ioctl get mode unmatched issue. + * 2. need to set default vblank when change format. + * 3. enum all supported mode mbus_code, not just cur_mode. + * V0.0X01.0X08 + * 1. add dcphy param for hdrx2 mode. */ #define DEBUG @@ -44,25 +50,30 @@ #include <media/v4l2-subdev.h> #include <linux/pinctrl/consumer.h> #include <linux/rk-preisp.h> +#include <media/v4l2-fwnode.h> +#include <linux/of_graph.h> #include "../platform/rockchip/isp/rkisp_tb_helper.h" -#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x06) +#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x08) #ifndef V4L2_CID_DIGITAL_GAIN #define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN #endif +#define MIPI_FREQ_1188M 1188000000 #define MIPI_FREQ_891M 891000000 #define MIPI_FREQ_446M 446000000 #define MIPI_FREQ_743M 743000000 #define MIPI_FREQ_297M 297000000 #define IMX415_4LANES 4 +#define IMX415_2LANES 2 #define IMX415_MAX_PIXEL_RATE (MIPI_FREQ_891M / 10 * 2 * IMX415_4LANES) #define OF_CAMERA_HDR_MODE "rockchip,camera-hdr-mode" #define IMX415_XVCLK_FREQ_37M 37125000 +#define IMX415_XVCLK_FREQ_27M 27000000 /* TODO: Get the real chip id from reg */ #define CHIP_ID 0xE0 @@ -136,6 +147,7 @@ #define IMX415_FLIP_REG 0x3030 #define REG_NULL 0xFFFF +#define REG_DELAY 0xFFFE #define IMX415_REG_VALUE_08BIT 1 #define IMX415_REG_VALUE_16BIT 2 @@ -158,6 +170,7 @@ #define OF_CAMERA_PINCTRL_STATE_DEFAULT "rockchip,camera_default" #define OF_CAMERA_PINCTRL_STATE_SLEEP "rockchip,camera_sleep" +#define RKMODULE_CAMERA_FASTBOOT_ENABLE "rockchip,camera_fastboot" #define IMX415_NAME "imx415" @@ -168,14 +181,6 @@ }; #define IMX415_NUM_SUPPLIES ARRAY_SIZE(imx415_supply_names) - -enum imx415_max_pad { - PAD0, /* link to isp */ - PAD1, /* link to csi wr0 | hdr x2:L x3:M */ - PAD2, /* link to csi wr1 | hdr x3:L */ - PAD3, /* link to csi wr2 | hdr x2:M x3:S */ - PAD_MAX, -}; struct regval { u16 addr; @@ -196,6 +201,7 @@ const struct regval *reg_list; u32 hdr_mode; u32 vc[PAD_MAX]; + u32 xvclk; }; struct imx415 { @@ -222,9 +228,10 @@ struct mutex mutex; bool streaming; bool power_on; - bool is_thunderboot; + u32 is_thunderboot; bool is_thunderboot_ng; bool is_first_streamoff; + const struct imx415_mode *supported_modes; const struct imx415_mode *cur_mode; u32 module_index; u32 cfg_num; @@ -234,6 +241,18 @@ u32 cur_vts; bool has_init_exp; struct preisp_hdrae_exp_s init_hdrae_exp; + struct v4l2_fwnode_endpoint bus_cfg; +}; + +static struct rkmodule_csi_dphy_param dcphy_param = { + .vendor = PHY_VENDOR_SAMSUNG, + .lp_vol_ref = 6, + .lp_hys_sw = {3, 0, 0, 0}, + .lp_escclk_pol_sel = {1, 1, 1, 1}, + .skew_data_cal_clk = {0, 3, 3, 3}, + .clk_hs_term_sel = 2, + .data_hs_term_sel = {2, 2, 2, 2}, + .reserved = {0}, }; #define to_imx415(sd) container_of(sd, struct imx415, subdev) @@ -737,6 +756,311 @@ }; /* + * Xclk 27Mhz + * 15fps + * CSI-2_2lane + * AD:12bit Output:12bit + * 891Mbps + * Master Mode + * Time 9.988ms Gain:6dB + * All-pixel + */ +static __maybe_unused const struct regval imx415_linear_12bit_3864x2192_891M_regs_2lane[] = { + {0x3008, 0x5D}, + {0x300A, 0x42}, + {0x3028, 0x98}, + {0x3029, 0x08}, + {0x3033, 0x05}, + {0x3050, 0x79}, + {0x3051, 0x07}, + {0x3090, 0x14}, + {0x30C1, 0x00}, + {0x3116, 0x23}, + {0x3118, 0xC6}, + {0x311A, 0xE7}, + {0x311E, 0x23}, + {0x32D4, 0x21}, + {0x32EC, 0xA1}, + {0x344C, 0x2B}, + {0x344D, 0x01}, + {0x344E, 0xED}, + {0x344F, 0x01}, + {0x3450, 0xF6}, + {0x3451, 0x02}, + {0x3452, 0x7F}, + {0x3453, 0x03}, + {0x358A, 0x04}, + {0x35A1, 0x02}, + {0x35EC, 0x27}, + {0x35EE, 0x8D}, + {0x35F0, 0x8D}, + {0x35F2, 0x29}, + {0x36BC, 0x0C}, + {0x36CC, 0x53}, + {0x36CD, 0x00}, + {0x36CE, 0x3C}, + {0x36D0, 0x8C}, + {0x36D1, 0x00}, + {0x36D2, 0x71}, + {0x36D4, 0x3C}, + {0x36D6, 0x53}, + {0x36D7, 0x00}, + {0x36D8, 0x71}, + {0x36DA, 0x8C}, + {0x36DB, 0x00}, + {0x3720, 0x00}, + {0x3724, 0x02}, + {0x3726, 0x02}, + {0x3732, 0x02}, + {0x3734, 0x03}, + {0x3736, 0x03}, + {0x3742, 0x03}, + {0x3862, 0xE0}, + {0x38CC, 0x30}, + {0x38CD, 0x2F}, + {0x395C, 0x0C}, + {0x39A4, 0x07}, + {0x39A8, 0x32}, + {0x39AA, 0x32}, + {0x39AC, 0x32}, + {0x39AE, 0x32}, + {0x39B0, 0x32}, + {0x39B2, 0x2F}, + {0x39B4, 0x2D}, + {0x39B6, 0x28}, + {0x39B8, 0x30}, + {0x39BA, 0x30}, + {0x39BC, 0x30}, + {0x39BE, 0x30}, + {0x39C0, 0x30}, + {0x39C2, 0x2E}, + {0x39C4, 0x2B}, + {0x39C6, 0x25}, + {0x3A42, 0xD1}, + {0x3A4C, 0x77}, + {0x3AE0, 0x02}, + {0x3AEC, 0x0C}, + {0x3B00, 0x2E}, + {0x3B06, 0x29}, + {0x3B98, 0x25}, + {0x3B99, 0x21}, + {0x3B9B, 0x13}, + {0x3B9C, 0x13}, + {0x3B9D, 0x13}, + {0x3B9E, 0x13}, + {0x3BA1, 0x00}, + {0x3BA2, 0x06}, + {0x3BA3, 0x0B}, + {0x3BA4, 0x10}, + {0x3BA5, 0x14}, + {0x3BA6, 0x18}, + {0x3BA7, 0x1A}, + {0x3BA8, 0x1A}, + {0x3BA9, 0x1A}, + {0x3BAC, 0xED}, + {0x3BAD, 0x01}, + {0x3BAE, 0xF6}, + {0x3BAF, 0x02}, + {0x3BB0, 0xA2}, + {0x3BB1, 0x03}, + {0x3BB2, 0xE0}, + {0x3BB3, 0x03}, + {0x3BB4, 0xE0}, + {0x3BB5, 0x03}, + {0x3BB6, 0xE0}, + {0x3BB7, 0x03}, + {0x3BB8, 0xE0}, + {0x3BBA, 0xE0}, + {0x3BBC, 0xDA}, + {0x3BBE, 0x88}, + {0x3BC0, 0x44}, + {0x3BC2, 0x7B}, + {0x3BC4, 0xA2}, + {0x3BC8, 0xBD}, + {0x3BCA, 0xBD}, + {0x4001, 0x01}, + {0x4004, 0xC0}, + {0x4005, 0x06}, + {0x400C, 0x00}, + {0x4018, 0x7F}, + {0x401A, 0x37}, + {0x401C, 0x37}, + {0x401E, 0xF7}, + {0x401F, 0x00}, + {0x4020, 0x3F}, + {0x4022, 0x6F}, + {0x4024, 0x3F}, + {0x4026, 0x5F}, + {0x4028, 0x2F}, + {0x4074, 0x01}, + {0x3002, 0x00}, + //{0x3000, 0x00}, + {REG_DELAY, 0x1E},//wait_ms(30) + {REG_NULL, 0x00}, +}; + +/* + * Xclk 27Mhz + * 90.059fps + * CSI-2_2lane + * AD:10bit Output:12bit + * 2376Mbps + * Master Mode + * Time 9.999ms Gain:6dB + * 2568x1440 2/2-line binning & Window cropping + */ +static __maybe_unused const struct regval imx415_linear_12bit_1284x720_2376M_regs_2lane[] = { + {0x3008, 0x5D}, + {0x300A, 0x42}, + {0x301C, 0x04}, + {0x3020, 0x01}, + {0x3021, 0x01}, + {0x3022, 0x01}, + {0x3024, 0xAB}, + {0x3025, 0x07}, + {0x3028, 0xA4}, + {0x3029, 0x01}, + {0x3031, 0x00}, + {0x3033, 0x00}, + {0x3040, 0x88}, + {0x3041, 0x02}, + {0x3042, 0x08}, + {0x3043, 0x0A}, + {0x3044, 0xF0}, + {0x3045, 0x02}, + {0x3046, 0x40}, + {0x3047, 0x0B}, + {0x3050, 0xC4}, + {0x3090, 0x14}, + {0x30C1, 0x00}, + {0x30D9, 0x02}, + {0x30DA, 0x01}, + {0x3116, 0x23}, + {0x3118, 0x08}, + {0x3119, 0x01}, + {0x311A, 0xE7}, + {0x311E, 0x23}, + {0x32D4, 0x21}, + {0x32EC, 0xA1}, + {0x344C, 0x2B}, + {0x344D, 0x01}, + {0x344E, 0xED}, + {0x344F, 0x01}, + {0x3450, 0xF6}, + {0x3451, 0x02}, + {0x3452, 0x7F}, + {0x3453, 0x03}, + {0x358A, 0x04}, + {0x35A1, 0x02}, + {0x35EC, 0x27}, + {0x35EE, 0x8D}, + {0x35F0, 0x8D}, + {0x35F2, 0x29}, + {0x36BC, 0x0C}, + {0x36CC, 0x53}, + {0x36CD, 0x00}, + {0x36CE, 0x3C}, + {0x36D0, 0x8C}, + {0x36D1, 0x00}, + {0x36D2, 0x71}, + {0x36D4, 0x3C}, + {0x36D6, 0x53}, + {0x36D7, 0x00}, + {0x36D8, 0x71}, + {0x36DA, 0x8C}, + {0x36DB, 0x00}, + {0x3701, 0x00}, + {0x3720, 0x00}, + {0x3724, 0x02}, + {0x3726, 0x02}, + {0x3732, 0x02}, + {0x3734, 0x03}, + {0x3736, 0x03}, + {0x3742, 0x03}, + {0x3862, 0xE0}, + {0x38CC, 0x30}, + {0x38CD, 0x2F}, + {0x395C, 0x0C}, + {0x39A4, 0x07}, + {0x39A8, 0x32}, + {0x39AA, 0x32}, + {0x39AC, 0x32}, + {0x39AE, 0x32}, + {0x39B0, 0x32}, + {0x39B2, 0x2F}, + {0x39B4, 0x2D}, + {0x39B6, 0x28}, + {0x39B8, 0x30}, + {0x39BA, 0x30}, + {0x39BC, 0x30}, + {0x39BE, 0x30}, + {0x39C0, 0x30}, + {0x39C2, 0x2E}, + {0x39C4, 0x2B}, + {0x39C6, 0x25}, + {0x3A42, 0xD1}, + {0x3A4C, 0x77}, + {0x3AE0, 0x02}, + {0x3AEC, 0x0C}, + {0x3B00, 0x2E}, + {0x3B06, 0x29}, + {0x3B98, 0x25}, + {0x3B99, 0x21}, + {0x3B9B, 0x13}, + {0x3B9C, 0x13}, + {0x3B9D, 0x13}, + {0x3B9E, 0x13}, + {0x3BA1, 0x00}, + {0x3BA2, 0x06}, + {0x3BA3, 0x0B}, + {0x3BA4, 0x10}, + {0x3BA5, 0x14}, + {0x3BA6, 0x18}, + {0x3BA7, 0x1A}, + {0x3BA8, 0x1A}, + {0x3BA9, 0x1A}, + {0x3BAC, 0xED}, + {0x3BAD, 0x01}, + {0x3BAE, 0xF6}, + {0x3BAF, 0x02}, + {0x3BB0, 0xA2}, + {0x3BB1, 0x03}, + {0x3BB2, 0xE0}, + {0x3BB3, 0x03}, + {0x3BB4, 0xE0}, + {0x3BB5, 0x03}, + {0x3BB6, 0xE0}, + {0x3BB7, 0x03}, + {0x3BB8, 0xE0}, + {0x3BBA, 0xE0}, + {0x3BBC, 0xDA}, + {0x3BBE, 0x88}, + {0x3BC0, 0x44}, + {0x3BC2, 0x7B}, + {0x3BC4, 0xA2}, + {0x3BC8, 0xBD}, + {0x3BCA, 0xBD}, + {0x4001, 0x01}, + {0x4004, 0xC0}, + {0x4005, 0x06}, + {0x4018, 0xE7}, + {0x401A, 0x8F}, + {0x401C, 0x8F}, + {0x401E, 0x7F}, + {0x401F, 0x02}, + {0x4020, 0x97}, + {0x4022, 0x0F}, + {0x4023, 0x01}, + {0x4024, 0x97}, + {0x4026, 0xF7}, + {0x4028, 0x7F}, + {0x3002, 0x00}, + //{0x3000, 0x00}, + {REG_DELAY, 0x1E},//wait_ms(30) + {REG_NULL, 0x00}, +}; + +/* * The width and height must be configured to be * the same as the current output resolution of the sensor. * The input width of the isp needs to be 16 aligned. @@ -769,6 +1093,8 @@ .hdr_mode = NO_HDR, .mipi_freq_idx = 1, .bpp = 10, + .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, + .xvclk = IMX415_XVCLK_FREQ_37M, }, { .bus_fmt = MEDIA_BUS_FMT_SGBRG10_1X10, @@ -794,6 +1120,7 @@ .vc[PAD1] = V4L2_MBUS_CSI2_CHANNEL_0,//L->csi wr0 .vc[PAD2] = V4L2_MBUS_CSI2_CHANNEL_1, .vc[PAD3] = V4L2_MBUS_CSI2_CHANNEL_1,//M->csi wr2 + .xvclk = IMX415_XVCLK_FREQ_37M, }, { .bus_fmt = MEDIA_BUS_FMT_SGBRG10_1X10, @@ -819,6 +1146,7 @@ .vc[PAD1] = V4L2_MBUS_CSI2_CHANNEL_1,//M->csi wr0 .vc[PAD2] = V4L2_MBUS_CSI2_CHANNEL_0,//L->csi wr0 .vc[PAD3] = V4L2_MBUS_CSI2_CHANNEL_2,//S->csi wr2 + .xvclk = IMX415_XVCLK_FREQ_37M, }, { .bus_fmt = MEDIA_BUS_FMT_SGBRG10_1X10, @@ -844,6 +1172,7 @@ .vc[PAD1] = V4L2_MBUS_CSI2_CHANNEL_1,//M->csi wr0 .vc[PAD2] = V4L2_MBUS_CSI2_CHANNEL_0,//L->csi wr0 .vc[PAD3] = V4L2_MBUS_CSI2_CHANNEL_2,//S->csi wr2 + .xvclk = IMX415_XVCLK_FREQ_37M, }, { /* 1H period = (1100 clock) = (1100 * 1 / 74.25MHz) */ @@ -862,6 +1191,8 @@ .hdr_mode = NO_HDR, .mipi_freq_idx = 1, .bpp = 12, + .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, + .xvclk = IMX415_XVCLK_FREQ_37M, }, { .bus_fmt = MEDIA_BUS_FMT_SGBRG12_1X12, @@ -887,6 +1218,7 @@ .vc[PAD1] = V4L2_MBUS_CSI2_CHANNEL_0,//L->csi wr0 .vc[PAD2] = V4L2_MBUS_CSI2_CHANNEL_1, .vc[PAD3] = V4L2_MBUS_CSI2_CHANNEL_1,//M->csi wr2 + .xvclk = IMX415_XVCLK_FREQ_37M, }, { .bus_fmt = MEDIA_BUS_FMT_SGBRG12_1X12, @@ -912,6 +1244,7 @@ .vc[PAD1] = V4L2_MBUS_CSI2_CHANNEL_1,//M->csi wr0 .vc[PAD2] = V4L2_MBUS_CSI2_CHANNEL_0,//L->csi wr0 .vc[PAD3] = V4L2_MBUS_CSI2_CHANNEL_2,//S->csi wr2 + .xvclk = IMX415_XVCLK_FREQ_37M, }, { .bus_fmt = MEDIA_BUS_FMT_SGBRG12_1X12, @@ -929,6 +1262,8 @@ .hdr_mode = NO_HDR, .mipi_freq_idx = 0, .bpp = 12, + .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, + .xvclk = IMX415_XVCLK_FREQ_37M, }, { .bus_fmt = MEDIA_BUS_FMT_SGBRG12_1X12, @@ -954,6 +1289,50 @@ .vc[PAD1] = V4L2_MBUS_CSI2_CHANNEL_0,//L->csi wr0 .vc[PAD2] = V4L2_MBUS_CSI2_CHANNEL_1, .vc[PAD3] = V4L2_MBUS_CSI2_CHANNEL_1,//M->csi wr2 + .xvclk = IMX415_XVCLK_FREQ_37M, + }, +}; + +static const struct imx415_mode supported_modes_2lane[] = { + { + /* 1H period = (1100 clock) = (1100 * 1 / 74.25MHz) */ + .bus_fmt = MEDIA_BUS_FMT_SGBRG12_1X12, + .width = 3864, + .height = 2192, + .max_fps = { + .numerator = 10000, + .denominator = 150000, + }, + .exp_def = 0x08ca - 0x08, + .hts_def = 0x0898 * IMX415_2LANES * 2, + .vts_def = 0x08ca, + .global_reg_list = NULL, + .reg_list = imx415_linear_12bit_3864x2192_891M_regs_2lane, + .hdr_mode = NO_HDR, + .mipi_freq_idx = 1, + .bpp = 12, + .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, + .xvclk = IMX415_XVCLK_FREQ_27M, + }, + { + /* 1H period = (1100 clock) = (1100 * 1 / 74.25MHz) */ + .bus_fmt = MEDIA_BUS_FMT_SGBRG12_1X12, + .width = 1284, + .height = 720, + .max_fps = { + .numerator = 10000, + .denominator = 900000, + }, + .exp_def = 0x07AB-8, + .hts_def = 0x01A4 * IMX415_2LANES * 2, + .vts_def = 0x07AB, + .global_reg_list = NULL, + .reg_list = imx415_linear_12bit_1284x720_2376M_regs_2lane, + .hdr_mode = NO_HDR, + .mipi_freq_idx = 4, + .bpp = 12, + .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, + .xvclk = IMX415_XVCLK_FREQ_27M, }, }; @@ -962,6 +1341,7 @@ MIPI_FREQ_446M, MIPI_FREQ_743M, MIPI_FREQ_891M, + MIPI_FREQ_1188M, }; /* Write registers up to 4 at a time */ @@ -998,10 +1378,18 @@ { u32 i; int ret = 0; - + if (!regs) { + dev_err(&client->dev, "write reg array error\n"); + return ret; + } for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++) { - ret = imx415_write_reg(client, regs[i].addr, - IMX415_REG_VALUE_08BIT, regs[i].val); + if (regs[i].addr == REG_DELAY) { + usleep_range(regs[i].val * 1000, regs[i].val * 1000 + 500); + dev_info(&client->dev, "write reg array, sleep %dms\n", regs[i].val); + } else { + ret = imx415_write_reg(client, regs[i].addr, + IMX415_REG_VALUE_08BIT, regs[i].val); + } } return ret; } @@ -1058,15 +1446,17 @@ unsigned int i; for (i = 0; i < imx415->cfg_num; i++) { - dist = imx415_get_reso_dist(&supported_modes[i], framefmt); - if ((cur_best_fit_dist == -1 || dist <= cur_best_fit_dist) && - supported_modes[i].bus_fmt == framefmt->code) { + dist = imx415_get_reso_dist(&imx415->supported_modes[i], framefmt); + if ((cur_best_fit_dist == -1 || dist < cur_best_fit_dist) && + imx415->supported_modes[i].bus_fmt == framefmt->code) { cur_best_fit_dist = dist; cur_best_fit = i; } } + dev_info(&imx415->client->dev, "%s: cur_best_fit(%d)", + __func__, cur_best_fit); - return &supported_modes[cur_best_fit]; + return &imx415->supported_modes[cur_best_fit]; } static int __imx415_power_on(struct imx415 *imx415); @@ -1080,8 +1470,8 @@ } imx415->cur_mode = mode; imx415->cur_vts = imx415->cur_mode->vts_def; - dev_dbg(&imx415->client->dev, "set fmt: cur_mode: %dx%d, hdr: %d\n", - mode->width, mode->height, mode->hdr_mode); + dev_info(&imx415->client->dev, "set fmt: cur_mode: %dx%d, hdr: %d, bpp: %d\n", + mode->width, mode->height, mode->hdr_mode, mode->bpp); } static int imx415_set_fmt(struct v4l2_subdev *sd, @@ -1092,6 +1482,7 @@ const struct imx415_mode *mode; s64 h_blank, vblank_def, vblank_min; u64 pixel_rate = 0; + u8 lanes = imx415->bus_cfg.bus.mipi_csi2.num_data_lanes; mutex_lock(&imx415->mutex); @@ -1118,11 +1509,15 @@ __v4l2_ctrl_modify_range(imx415->vblank, vblank_min, IMX415_VTS_MAX - mode->height, 1, vblank_def); + __v4l2_ctrl_s_ctrl(imx415->vblank, vblank_def); __v4l2_ctrl_s_ctrl(imx415->link_freq, mode->mipi_freq_idx); - pixel_rate = (u32)link_freq_items[mode->mipi_freq_idx] / mode->bpp * 2 * IMX415_4LANES; + pixel_rate = (u32)link_freq_items[mode->mipi_freq_idx] / + mode->bpp * 2 * lanes; __v4l2_ctrl_s_ctrl_int64(imx415->pixel_rate, pixel_rate); } + dev_info(&imx415->client->dev, "%s: mode->mipi_freq_idx(%d)", + __func__, mode->mipi_freq_idx); mutex_unlock(&imx415->mutex); @@ -1165,9 +1560,10 @@ { struct imx415 *imx415 = to_imx415(sd); - if (code->index != 0) + if (code->index >= imx415->cfg_num) return -EINVAL; - code->code = imx415->cur_mode->bus_fmt; + + code->code = imx415->supported_modes[code->index].bus_fmt; return 0; } @@ -1181,13 +1577,13 @@ if (fse->index >= imx415->cfg_num) return -EINVAL; - if (fse->code != supported_modes[fse->index].bus_fmt) + if (fse->code != imx415->supported_modes[fse->index].bus_fmt) 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; + fse->min_width = imx415->supported_modes[fse->index].width; + fse->max_width = imx415->supported_modes[fse->index].width; + fse->max_height = imx415->supported_modes[fse->index].height; + fse->min_height = imx415->supported_modes[fse->index].height; return 0; } @@ -1198,28 +1594,27 @@ struct imx415 *imx415 = to_imx415(sd); const struct imx415_mode *mode = imx415->cur_mode; - mutex_lock(&imx415->mutex); fi->interval = mode->max_fps; - mutex_unlock(&imx415->mutex); return 0; } -static int imx415_g_mbus_config(struct v4l2_subdev *sd, +static int imx415_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id, struct v4l2_mbus_config *config) { struct imx415 *imx415 = to_imx415(sd); const struct imx415_mode *mode = imx415->cur_mode; u32 val = 0; + u8 lanes = imx415->bus_cfg.bus.mipi_csi2.num_data_lanes; - val = 1 << (IMX415_4LANES - 1) | + val = 1 << (lanes - 1) | V4L2_MBUS_CSI2_CHANNEL_0 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; if (mode->hdr_mode != NO_HDR) val |= V4L2_MBUS_CSI2_CHANNEL_1; if (mode->hdr_mode == HDR_X3) val |= V4L2_MBUS_CSI2_CHANNEL_2; - config->type = V4L2_MBUS_CSI2; + config->type = V4L2_MBUS_CSI2_DPHY; config->flags = val; return 0; @@ -1650,14 +2045,28 @@ return ret; } +static int imx415_get_channel_info(struct imx415 *imx415, struct rkmodule_channel_info *ch_info) +{ + if (ch_info->index < PAD0 || ch_info->index >= PAD_MAX) + return -EINVAL; + ch_info->vc = imx415->cur_mode->vc[ch_info->index]; + ch_info->width = imx415->cur_mode->width; + ch_info->height = imx415->cur_mode->height; + ch_info->bus_fmt = imx415->cur_mode->bus_fmt; + return 0; +} + static long imx415_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { struct imx415 *imx415 = to_imx415(sd); struct rkmodule_hdr_cfg *hdr; + struct rkmodule_channel_info *ch_info; u32 i, h, w, stream; long ret = 0; const struct imx415_mode *mode; u64 pixel_rate = 0; + struct rkmodule_csi_dphy_param *dphy_param; + u8 lanes = imx415->bus_cfg.bus.mipi_csi2.num_data_lanes; switch (cmd) { case PREISP_CMD_SET_HDRAE_EXP: @@ -1679,10 +2088,11 @@ w = imx415->cur_mode->width; h = imx415->cur_mode->height; for (i = 0; i < imx415->cfg_num; i++) { - if (w == supported_modes[i].width && - h == supported_modes[i].height && - supported_modes[i].hdr_mode == hdr->hdr_mode) { - imx415_change_mode(imx415, &supported_modes[i]); + if (w == imx415->supported_modes[i].width && + h == imx415->supported_modes[i].height && + imx415->supported_modes[i].hdr_mode == hdr->hdr_mode) { + dev_info(&imx415->client->dev, "set hdr cfg, set mode to %d\n", i); + imx415_change_mode(imx415, &imx415->supported_modes[i]); break; } } @@ -1706,14 +2116,17 @@ } w = mode->hts_def - imx415->cur_mode->width; h = mode->vts_def - mode->height; + mutex_lock(&imx415->mutex); __v4l2_ctrl_modify_range(imx415->hblank, w, w, 1, w); __v4l2_ctrl_modify_range(imx415->vblank, h, IMX415_VTS_MAX - mode->height, 1, h); __v4l2_ctrl_s_ctrl(imx415->link_freq, mode->mipi_freq_idx); - pixel_rate = (u32)link_freq_items[mode->mipi_freq_idx] / mode->bpp * 2 * IMX415_4LANES; + pixel_rate = (u32)link_freq_items[mode->mipi_freq_idx] / + mode->bpp * 2 * lanes; __v4l2_ctrl_s_ctrl_int64(imx415->pixel_rate, pixel_rate); + mutex_unlock(&imx415->mutex); } break; case RKMODULE_SET_QUICK_STREAM: @@ -1733,6 +2146,19 @@ else *((u32 *)arg) = BRL_BINNING; break; + case RKMODULE_GET_CHANNEL_INFO: + ch_info = (struct rkmodule_channel_info *)arg; + ret = imx415_get_channel_info(imx415, ch_info); + break; + case RKMODULE_GET_CSI_DPHY_PARAM: + if (imx415->cur_mode->hdr_mode == HDR_X2) { + dphy_param = (struct rkmodule_csi_dphy_param *)arg; + *dphy_param = dcphy_param; + dev_info(&imx415->client->dev, + "get sensor dphy param\n"); + } else + ret = -EINVAL; + break; default: ret = -ENOIOCTLCMD; break; @@ -1750,9 +2176,11 @@ struct rkmodule_awb_cfg *cfg; struct rkmodule_hdr_cfg *hdr; struct preisp_hdrae_exp_s *hdrae; + struct rkmodule_channel_info *ch_info; long ret; u32 stream; u32 brl = 0; + struct rkmodule_csi_dphy_param *dphy_param; switch (cmd) { case RKMODULE_GET_MODULE_INFO: @@ -1841,6 +2269,37 @@ return -EFAULT; } break; + case RKMODULE_GET_CHANNEL_INFO: + ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL); + if (!ch_info) { + ret = -ENOMEM; + return ret; + } + + ret = imx415_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; + case RKMODULE_GET_CSI_DPHY_PARAM: + dphy_param = kzalloc(sizeof(*dphy_param), GFP_KERNEL); + if (!dphy_param) { + ret = -ENOMEM; + return ret; + } + + ret = imx415_ioctl(sd, cmd, dphy_param); + if (!ret) { + ret = copy_to_user(up, dphy_param, sizeof(*dphy_param)); + if (ret) + ret = -EFAULT; + } + kfree(dphy_param); + break; + default: ret = -ENOIOCTLCMD; break; @@ -1896,7 +2355,7 @@ struct i2c_client *client = imx415->client; int ret = 0; - dev_dbg(&imx415->client->dev, "s_stream: %d. %dx%d, hdr: %d, bpp: %d\n", + dev_info(&imx415->client->dev, "s_stream: %d. %dx%d, hdr: %d, bpp: %d\n", on, imx415->cur_mode->width, imx415->cur_mode->height, imx415->cur_mode->hdr_mode, imx415->cur_mode->bpp); @@ -1968,10 +2427,6 @@ { int ret; struct device *dev = &imx415->client->dev; - - if (imx415->is_thunderboot) - return 0; - if (!IS_ERR_OR_NULL(imx415->pins_default)) { ret = pinctrl_select_state(imx415->pinctrl, imx415->pins_default); @@ -1979,26 +2434,28 @@ dev_err(dev, "could not set pins\n"); } - ret = regulator_bulk_enable(IMX415_NUM_SUPPLIES, imx415->supplies); - if (ret < 0) { - dev_err(dev, "Failed to enable regulators\n"); - goto err_pinctrl; - } - if (!IS_ERR(imx415->power_gpio)) - gpiod_direction_output(imx415->power_gpio, 1); - /* At least 500ns between power raising and XCLR */ - /* fix power on timing if insmod this ko */ - usleep_range(10 * 1000, 20 * 1000); - if (!IS_ERR(imx415->reset_gpio)) - gpiod_direction_output(imx415->reset_gpio, 0); + if (!imx415->is_thunderboot) { + ret = regulator_bulk_enable(IMX415_NUM_SUPPLIES, imx415->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators\n"); + goto err_pinctrl; + } + if (!IS_ERR(imx415->power_gpio)) + gpiod_direction_output(imx415->power_gpio, 1); + /* At least 500ns between power raising and XCLR */ + /* fix power on timing if insmod this ko */ + usleep_range(10 * 1000, 20 * 1000); + if (!IS_ERR(imx415->reset_gpio)) + gpiod_direction_output(imx415->reset_gpio, 0); - /* At least 1us between XCLR and clk */ - /* fix power on timing if insmod this ko */ - usleep_range(10 * 1000, 20 * 1000); - ret = clk_set_rate(imx415->xvclk, IMX415_XVCLK_FREQ_37M); + /* At least 1us between XCLR and clk */ + /* fix power on timing if insmod this ko */ + usleep_range(10 * 1000, 20 * 1000); + } + ret = clk_set_rate(imx415->xvclk, imx415->cur_mode->xvclk); if (ret < 0) dev_warn(dev, "Failed to set xvclk rate\n"); - if (clk_get_rate(imx415->xvclk) != IMX415_XVCLK_FREQ_37M) + if (clk_get_rate(imx415->xvclk) != imx415->cur_mode->xvclk) dev_warn(dev, "xvclk mismatched\n"); ret = clk_prepare_enable(imx415->xvclk); if (ret < 0) { @@ -2007,7 +2464,8 @@ } /* At least 20us between XCLR and I2C communication */ - usleep_range(20*1000, 30*1000); + if (!imx415->is_thunderboot) + usleep_range(20*1000, 30*1000); return 0; @@ -2051,7 +2509,7 @@ regulator_bulk_disable(IMX415_NUM_SUPPLIES, imx415->supplies); } -static int imx415_runtime_resume(struct device *dev) +static int __maybe_unused imx415_runtime_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct v4l2_subdev *sd = i2c_get_clientdata(client); @@ -2060,7 +2518,7 @@ return __imx415_power_on(imx415); } -static int imx415_runtime_suspend(struct device *dev) +static int __maybe_unused imx415_runtime_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct v4l2_subdev *sd = i2c_get_clientdata(client); @@ -2077,7 +2535,7 @@ struct imx415 *imx415 = to_imx415(sd); struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_get_try_format(sd, fh->pad, 0); - const struct imx415_mode *def_mode = &supported_modes[0]; + const struct imx415_mode *def_mode = &imx415->supported_modes[0]; mutex_lock(&imx415->mutex); /* Initialize try_fmt */ @@ -2102,11 +2560,11 @@ if (fie->index >= imx415->cfg_num) return -EINVAL; - fie->code = supported_modes[fie->index].bus_fmt; - fie->width = supported_modes[fie->index].width; - fie->height = supported_modes[fie->index].height; - fie->interval = supported_modes[fie->index].max_fps; - fie->reserved[0] = supported_modes[fie->index].hdr_mode; + fie->code = imx415->supported_modes[fie->index].bus_fmt; + fie->width = imx415->supported_modes[fie->index].width; + fie->height = imx415->supported_modes[fie->index].height; + fie->interval = imx415->supported_modes[fie->index].max_fps; + fie->reserved[0] = imx415->supported_modes[fie->index].hdr_mode; return 0; } @@ -2175,7 +2633,6 @@ static const struct v4l2_subdev_video_ops imx415_video_ops = { .s_stream = imx415_s_stream, .g_frame_interval = imx415_g_frame_interval, - .g_mbus_config = imx415_g_mbus_config, }; static const struct v4l2_subdev_pad_ops imx415_pad_ops = { @@ -2185,6 +2642,7 @@ .get_fmt = imx415_get_fmt, .set_fmt = imx415_set_fmt, .get_selection = imx415_get_selection, + .get_mbus_config = imx415_g_mbus_config, }; static const struct v4l2_subdev_ops imx415_subdev_ops = { @@ -2223,7 +2681,7 @@ switch (ctrl->id) { case V4L2_CID_EXPOSURE: if (imx415->cur_mode->hdr_mode != NO_HDR) - return ret; + goto ctrl_end; shr0 = imx415->cur_vts - ctrl->val; ret = imx415_write_reg(imx415->client, IMX415_LF_EXPO_REG_L, IMX415_REG_VALUE_08BIT, @@ -2239,7 +2697,7 @@ break; case V4L2_CID_ANALOGUE_GAIN: if (imx415->cur_mode->hdr_mode != NO_HDR) - return ret; + goto ctrl_end; ret = imx415_write_reg(imx415->client, IMX415_LF_GAIN_REG_H, IMX415_REG_VALUE_08BIT, IMX415_FETCH_GAIN_H(ctrl->val)); @@ -2308,6 +2766,7 @@ break; } +ctrl_end: pm_runtime_put(&client->dev); return ret; @@ -2323,8 +2782,10 @@ struct v4l2_ctrl_handler *handler; s64 exposure_max, vblank_def; u64 pixel_rate; + u64 max_pixel_rate; u32 h_blank; int ret; + u8 lanes = imx415->bus_cfg.bus.mipi_csi2.num_data_lanes; handler = &imx415->ctrl_handler; mode = imx415->cur_mode; @@ -2337,12 +2798,13 @@ V4L2_CID_LINK_FREQ, ARRAY_SIZE(link_freq_items) - 1, 0, link_freq_items); - __v4l2_ctrl_s_ctrl(imx415->link_freq, mode->mipi_freq_idx); + v4l2_ctrl_s_ctrl(imx415->link_freq, mode->mipi_freq_idx); /* pixel rate = link frequency * 2 * lanes / BITS_PER_SAMPLE */ - pixel_rate = (u32)link_freq_items[mode->mipi_freq_idx] / mode->bpp * 2 * IMX415_4LANES; + pixel_rate = (u32)link_freq_items[mode->mipi_freq_idx] / mode->bpp * 2 * lanes; + max_pixel_rate = MIPI_FREQ_1188M / mode->bpp * 2 * lanes; imx415->pixel_rate = v4l2_ctrl_new_std(handler, NULL, - V4L2_CID_PIXEL_RATE, 0, IMX415_MAX_PIXEL_RATE, + V4L2_CID_PIXEL_RATE, 0, max_pixel_rate, 1, pixel_rate); h_blank = mode->hts_def - mode->width; @@ -2433,6 +2895,7 @@ struct device_node *node = dev->of_node; struct imx415 *imx415; struct v4l2_subdev *sd; + struct device_node *endpoint; char facing[2]; int ret; u32 i, hdr_mode = 0; @@ -2464,16 +2927,41 @@ hdr_mode = NO_HDR; dev_warn(dev, " Get hdr mode failed! no hdr default\n"); } + + endpoint = of_graph_get_next_endpoint(dev->of_node, NULL); + if (!endpoint) { + dev_err(dev, "Failed to get endpoint\n"); + return -EINVAL; + } + + ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(endpoint), + &imx415->bus_cfg); + of_node_put(endpoint); + if (ret) { + dev_err(dev, "Failed to get bus config\n"); + return -EINVAL; + } + imx415->client = client; - imx415->cfg_num = ARRAY_SIZE(supported_modes); + if (imx415->bus_cfg.bus.mipi_csi2.num_data_lanes == IMX415_4LANES) { + imx415->supported_modes = supported_modes; + imx415->cfg_num = ARRAY_SIZE(supported_modes); + } else { + imx415->supported_modes = supported_modes_2lane; + imx415->cfg_num = ARRAY_SIZE(supported_modes_2lane); + } + dev_info(dev, "detect imx415 lane %d\n", + imx415->bus_cfg.bus.mipi_csi2.num_data_lanes); + for (i = 0; i < imx415->cfg_num; i++) { - if (hdr_mode == supported_modes[i].hdr_mode) { - imx415->cur_mode = &supported_modes[i]; + if (hdr_mode == imx415->supported_modes[i].hdr_mode) { + imx415->cur_mode = &imx415->supported_modes[i]; break; } } - imx415->is_thunderboot = IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP); + of_property_read_u32(node, RKMODULE_CAMERA_FASTBOOT_ENABLE, + &imx415->is_thunderboot); imx415->xvclk = devm_clk_get(dev, "xvclk"); if (IS_ERR(imx415->xvclk)) { -- Gitblit v1.6.2