From 667f793992c1788493bc7b3e97aa643f5fd8676b Mon Sep 17 00:00:00 2001 From: Su Yuefu Date: Thu, 3 Apr 2025 16:58:21 +0800 Subject: [PATCH] media: i2c: sc450ai: add 2lane/4lane hdr config Signed-off-by: Su Yuefu Change-Id: I88228ca481f263e22682beff48bb419847dbc918 --- drivers/media/i2c/sc450ai.c | 945 +++++++++++++++++++++++++++++++++--- 1 file changed, 891 insertions(+), 54 deletions(-) diff --git a/drivers/media/i2c/sc450ai.c b/drivers/media/i2c/sc450ai.c index e5dd37112c5b..b55baa096692 100644 --- a/drivers/media/i2c/sc450ai.c +++ b/drivers/media/i2c/sc450ai.c @@ -6,6 +6,7 @@ * * V0.0X01.0X01 first version * V0.0X01.0X02 Increase vblank in 2688x1520@30fps linear 4lane configuration + * V0.0X01.0X03 Add sc450ai 2lane hdr/linear configuration and 4 lane linear configuration */ //#define DEBUG @@ -26,23 +27,29 @@ #include #include #include +#include +#include #include #include "../platform/rockchip/isp/rkisp_tb_helper.h" #include "cam-tb-setup.h" #include "cam-sleep-wakeup.h" -#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x02) +#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x03) #ifndef V4L2_CID_DIGITAL_GAIN #define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN #endif -#define SC450AI_LANES 4 +#define SC450AI_LANES_2LANE 2 +#define SC450AI_LANES_4LANE 4 #define SC450AI_BITS_PER_SAMPLE 10 +#define SC450AI_LINK_FREQ_180 180000000 #define SC450AI_LINK_FREQ_360 360000000 +#define SC450AI_LINK_FREQ_540 540000000 +#define SC450AI_MAX_LINK_FREQ SC450AI_LINK_FREQ_540 #define PIXEL_RATE_WITH_360M_10BIT (SC450AI_LINK_FREQ_360 / SC450AI_BITS_PER_SAMPLE * 2 * \ - SC450AI_LANES) + SC450AI_LANES_2LANE) #define SC450AI_XVCLK_FREQ 27000000 @@ -56,6 +63,9 @@ #define SC450AI_REG_EXPOSURE_H 0x3e00 #define SC450AI_REG_EXPOSURE_M 0x3e01 #define SC450AI_REG_EXPOSURE_L 0x3e02 +#define SC450AI_REG_EXPOSURE_SHORT_H 0x3e22 +#define SC450AI_REG_EXPOSURE_SHORT_M 0x3e04 +#define SC450AI_REG_EXPOSURE_SHORT_L 0x3e05 #define SC450AI_EXPOSURE_MIN 1 #define SC450AI_EXPOSURE_STEP 1 #define SC450AI_VTS_MAX 0x7fff @@ -64,6 +74,10 @@ #define SC450AI_REG_DIG_FINE_GAIN 0x3e07 #define SC450AI_REG_ANA_GAIN 0x3e08 #define SC450AI_REG_ANA_FINE_GAIN 0x3e09 +#define SC450AI_REG_DIG_GAIN_SHORT 0x3e10 +#define SC450AI_REG_DIG_FINE_GAIN_SHORT 0x3e11 +#define SC450AI_REG_ANA_GAIN_SHORT 0x3e12 +#define SC450AI_REG_ANA_FINE_GAIN_SHORT 0x3e13 #define SC450AI_GAIN_MIN 0x40 //0x0080 #define SC450AI_GAIN_MAX 61975 //60.523*16*64 (99614) //48.64*16*128 #define SC450AI_GAIN_STEP 1 @@ -85,9 +99,6 @@ #define SC450AI_FETCH_EXP_M(VAL) (((VAL) >> 4) & 0xFF) #define SC450AI_FETCH_EXP_L(VAL) (((VAL) & 0xF) << 4) -//#define SC450AI_FETCH_AGAIN_H(VAL) (((VAL) >> 8) & 0x7f)//(((VAL) >> 8) & 0x03) -//#define SC450AI_FETCH_AGAIN_L(VAL) ((VAL) & 0xFF) - #define SC450AI_FETCH_MIRROR(VAL, ENABLE) (ENABLE ? VAL | 0x06 : VAL & 0xf9) #define SC450AI_FETCH_FLIP(VAL, ENABLE) (ENABLE ? VAL | 0x60 : VAL & 0x9f) @@ -100,6 +111,7 @@ #define OF_CAMERA_PINCTRL_STATE_DEFAULT "rockchip,camera_default" #define OF_CAMERA_PINCTRL_STATE_SLEEP "rockchip,camera_sleep" +#define OF_CAMERA_HDR_MODE "rockchip,camera-hdr-mode" #define SC450AI_NAME "sc450ai" static const char * const sc450ai_supply_names[] = { @@ -128,6 +140,7 @@ struct sc450ai_mode { u32 xvclk_freq; u32 link_freq_idx; u32 vc[PAD_MAX]; + u32 lanes; }; struct sc450ai { @@ -167,6 +180,9 @@ struct sc450ai { bool is_first_streamoff; struct preisp_hdrae_exp_s init_hdrae_exp; struct cam_sw_info *cam_sw_inf; + struct v4l2_fwnode_endpoint bus_cfg; + const struct sc450ai_mode *supported_modes; + u32 cfg_num; }; #define to_sc450ai(sd) container_of(sd, struct sc450ai, subdev) @@ -184,7 +200,7 @@ static const struct regval sc450ai_global_regs[] = { * mipi_datarate per lane 720Mbps, 2lane * binning to 1344x760 */ -static const struct regval sc450ai_linear_10_1344x760_120fps_regs[] = { +static const struct regval sc450ai_linear_10_1344x760_120fps_2lane_regs[] = { {0x0103, 0x01}, {0x0100, 0x00}, {0x36e9, 0x80}, @@ -371,12 +387,414 @@ static const struct regval sc450ai_linear_10_1344x760_120fps_regs[] = { {REG_NULL, 0x00}, }; + +/* + * Xclk 27Mhz + * max_framerate 60fps + * mipi_datarate per lane 720Mbps, 2lane + */ +static const struct regval sc450ai_linear_10_2688x1520_30fps_2lane_regs[] = { + {0x0103, 0x01}, + {0x0100, 0x00}, + {0x36e9, 0x80}, + {0x36f9, 0x80}, + {0x3018, 0x3a}, + {0x3019, 0x0c}, + {0x301c, 0x78}, + {0x301f, 0x3c}, + {0x302d, 0xa0}, + {0x302e, 0x00}, + {0x3208, 0x0a}, + {0x3209, 0x80}, + {0x320a, 0x05}, + {0x320b, 0xf0}, + {0x320c, 0x02}, + {0x320d, 0xee}, + {0x320e, 0x06}, + {0x320f, 0x18}, + {0x3214, 0x11}, + {0x3215, 0x11}, + {0x3220, 0x00}, + {0x3223, 0xc0}, + {0x3253, 0x10}, + {0x325f, 0x44}, + {0x3274, 0x09}, + {0x3280, 0x01}, + {0x3301, 0x07}, + {0x3306, 0x20}, + {0x3308, 0x08}, + {0x330b, 0x58}, + {0x330e, 0x18}, + {0x3315, 0x00}, + {0x335d, 0x60}, + {0x3364, 0x56}, + {0x338f, 0x80}, + {0x3390, 0x08}, + {0x3391, 0x18}, + {0x3392, 0x38}, + {0x3393, 0x07}, + {0x3394, 0x10}, + {0x3395, 0x18}, + {0x3396, 0x08}, + {0x3397, 0x18}, + {0x3398, 0x38}, + {0x3399, 0x10}, + {0x339a, 0x13}, + {0x339b, 0x15}, + {0x339c, 0x18}, + {0x33af, 0x18}, + {0x3400, 0x16}, + {0x360f, 0x13}, + {0x3621, 0xec}, + {0x3622, 0x00}, + {0x3625, 0x0b}, + {0x3627, 0x20}, + {0x3630, 0x90}, + {0x3633, 0x56}, + {0x3637, 0x1d}, + {0x3638, 0x12}, + {0x363c, 0x0f}, + {0x363d, 0x0f}, + {0x363e, 0x08}, + {0x3670, 0x4a}, + {0x3671, 0xe0}, + {0x3672, 0xe0}, + {0x3673, 0xe0}, + {0x3674, 0xc0}, + {0x3675, 0x87}, + {0x3676, 0x8c}, + {0x367a, 0x48}, + {0x367b, 0x58}, + {0x367c, 0x48}, + {0x367d, 0x58}, + {0x3690, 0x22}, + {0x3691, 0x33}, + {0x3692, 0x44}, + {0x3699, 0x03}, + {0x369a, 0x0f}, + {0x369b, 0x1f}, + {0x369c, 0x40}, + {0x369d, 0x78}, + {0x36a2, 0x48}, + {0x36a3, 0x78}, + {0x36b0, 0x53}, + {0x36b1, 0x74}, + {0x36b2, 0x34}, + {0x36b3, 0x40}, + {0x36b4, 0x78}, + {0x36b7, 0xa0}, + {0x36b8, 0xa0}, + {0x36b9, 0x20}, + {0x36bd, 0x40}, + {0x36be, 0x48}, + {0x36d0, 0x20}, + {0x36e0, 0x08}, + {0x36e1, 0x08}, + {0x36e2, 0x12}, + {0x36e3, 0x48}, + {0x36e4, 0x78}, + {0x36ec, 0x43}, + {0x36fc, 0x00}, + {0x3907, 0x00}, + {0x3908, 0x41}, + {0x391e, 0xf1}, + {0x391f, 0x11}, + {0x3921, 0x10}, + {0x3933, 0x82}, + {0x3934, 0x30}, + {0x3935, 0x02}, + {0x3936, 0xc7}, + {0x3937, 0x76}, + {0x3938, 0x76}, + {0x3939, 0x00}, + {0x393a, 0x28}, + {0x393b, 0x00}, + {0x393c, 0x23}, + {0x3e01, 0xc2}, + {0x3e02, 0x60}, + {0x3e03, 0x0b}, + {0x3e08, 0x03}, + {0x3e1b, 0x2a}, + {0x440e, 0x02}, + {0x4509, 0x20}, + {0x4837, 0x16}, + {0x5000, 0x0e}, + {0x5001, 0x44}, + {0x5780, 0x76}, + {0x5784, 0x08}, + {0x5785, 0x04}, + {0x5787, 0x0a}, + {0x5788, 0x0a}, + {0x5789, 0x0a}, + {0x578a, 0x0a}, + {0x578b, 0x0a}, + {0x578c, 0x0a}, + {0x578d, 0x40}, + {0x5790, 0x08}, + {0x5791, 0x04}, + {0x5792, 0x04}, + {0x5793, 0x08}, + {0x5794, 0x04}, + {0x5795, 0x04}, + {0x5799, 0x46}, + {0x579a, 0x77}, + {0x57a1, 0x04}, + {0x57a8, 0xd0}, + {0x57aa, 0x28}, + {0x57ab, 0x00}, + {0x57ac, 0x00}, + {0x57ad, 0x00}, + {0x59e0, 0xfe}, + {0x59e1, 0x40}, + {0x59e2, 0x3f}, + {0x59e3, 0x38}, + {0x59e4, 0x30}, + {0x59e5, 0x3f}, + {0x59e6, 0x38}, + {0x59e7, 0x30}, + {0x59e8, 0x3f}, + {0x59e9, 0x3c}, + {0x59ea, 0x38}, + {0x59eb, 0x3f}, + {0x59ec, 0x3c}, + {0x59ed, 0x38}, + {0x59ee, 0xfe}, + {0x59ef, 0x40}, + {0x59f4, 0x3f}, + {0x59f5, 0x38}, + {0x59f6, 0x30}, + {0x59f7, 0x3f}, + {0x59f8, 0x38}, + {0x59f9, 0x30}, + {0x59fa, 0x3f}, + {0x59fb, 0x3c}, + {0x59fc, 0x38}, + {0x59fd, 0x3f}, + {0x59fe, 0x3c}, + {0x59ff, 0x38}, + {0x36e9, 0x44}, + {0x36f9, 0x20}, + {REG_NULL, 0x00}, +}; + +static const struct regval sc450ai_hdr2_10_2688x1520_25fps_2lane_regs[] = { + {0x0103, 0x01}, + {0x0100, 0x00}, + {0x36e9, 0x80}, + {0x36f9, 0x80}, + {0x3018, 0x3a}, + {0x3019, 0x0c}, + {0x301c, 0x78}, + {0x301f, 0x3d}, + {0x302d, 0xa0}, + {0x302e, 0x00}, + {0x3208, 0x0a}, + {0x3209, 0x80}, + {0x320a, 0x05}, + {0x320b, 0xf0}, + {0x320c, 0x03}, + {0x320d, 0x9e}, + {0x320e, 0x0c}, + {0x320f, 0x26}, + {0x3213, 0x14}, + {0x3214, 0x11}, + {0x3215, 0x11}, + {0x3220, 0x00}, + {0x3223, 0xc0}, + {0x3250, 0xff}, + {0x3253, 0x10}, + {0x325f, 0x44}, + {0x3274, 0x09}, + {0x3280, 0x01}, + {0x3281, 0x01}, + {0x3301, 0x08}, + {0x3306, 0x24}, + {0x3309, 0x60}, + {0x330b, 0x64}, + {0x330d, 0x30}, + {0x3314, 0x94}, + {0x3315, 0x00}, + {0x331f, 0x59}, + {0x335d, 0x60}, + {0x3364, 0x56}, + {0x338f, 0x80}, + {0x3390, 0x08}, + {0x3391, 0x18}, + {0x3392, 0x38}, + {0x3393, 0x0a}, + {0x3394, 0x10}, + {0x3395, 0x18}, + {0x3396, 0x08}, + {0x3397, 0x18}, + {0x3398, 0x38}, + {0x3399, 0x0f}, + {0x339a, 0x12}, + {0x339b, 0x14}, + {0x339c, 0x18}, + {0x33af, 0x18}, + {0x3400, 0x16}, + {0x3410, 0x04}, + {0x360f, 0x13}, + {0x3621, 0xec}, + {0x3627, 0xa0}, + {0x3630, 0x90}, + {0x3633, 0x56}, + {0x3637, 0x1d}, + {0x3638, 0x0a}, + {0x363c, 0x0f}, + {0x363d, 0x0f}, + {0x363e, 0x08}, + {0x3670, 0x4a}, + {0x3671, 0xe0}, + {0x3672, 0xe0}, + {0x3673, 0xe0}, + {0x3674, 0xb0}, + {0x3675, 0x88}, + {0x3676, 0x8c}, + {0x367a, 0x48}, + {0x367b, 0x58}, + {0x367c, 0x48}, + {0x367d, 0x58}, + {0x3690, 0x34}, + {0x3691, 0x43}, + {0x3692, 0x44}, + {0x3699, 0x03}, + {0x369a, 0x0f}, + {0x369b, 0x1f}, + {0x369c, 0x40}, + {0x369d, 0x48}, + {0x36a2, 0x48}, + {0x36a3, 0x78}, + {0x36b0, 0x54}, + {0x36b1, 0x55}, + {0x36b2, 0x55}, + {0x36b3, 0x48}, + {0x36b4, 0x78}, + {0x36b7, 0xa0}, + {0x36b8, 0xa0}, + {0x36b9, 0x20}, + {0x36bd, 0x40}, + {0x36be, 0x48}, + {0x36d0, 0x20}, + {0x36e0, 0x08}, + {0x36e1, 0x08}, + {0x36e2, 0x12}, + {0x36e3, 0x48}, + {0x36e4, 0x78}, + {0x36ea, 0x0c}, + {0x36eb, 0x05}, + {0x36ec, 0x43}, + {0x36ed, 0x24}, + {0x36fa, 0x0a}, + {0x36fb, 0xa4}, + {0x36fc, 0x00}, + {0x36fd, 0x14}, + {0x3900, 0x07}, + {0x3902, 0xf0}, + {0x3907, 0x00}, + {0x3908, 0x41}, + {0x391e, 0x01}, + {0x391f, 0x11}, + {0x3921, 0x10}, + {0x3933, 0x82}, + {0x3934, 0x0b}, + {0x3935, 0x02}, + {0x3936, 0x5e}, + {0x3937, 0x76}, + {0x3938, 0x78}, + {0x3939, 0x00}, + {0x393a, 0x28}, + {0x393b, 0x00}, + {0x393c, 0x1d}, + {0x3e00, 0x01}, + {0x3e01, 0x67}, + {0x3e02, 0x00}, + {0x3e03, 0x0b}, + {0x3e04, 0x16}, + {0x3e05, 0x70}, + {0x3e06, 0x00}, + {0x3e07, 0x80}, + {0x3e08, 0x03}, + {0x3e09, 0x40}, + {0x3e10, 0x00}, + {0x3e11, 0x80}, + {0x3e12, 0x03}, + {0x3e13, 0x40}, + {0x3e1b, 0x2a}, + {0x3e22, 0x00}, + {0x3e23, 0x00}, + {0x3e24, 0xba}, + {0x440e, 0x02}, + {0x4503, 0x60}, + {0x4509, 0x20}, + {0x4837, 0x16}, + {0x4853, 0xf8}, + {0x5000, 0x0e}, + {0x5001, 0x44}, + {0x5011, 0x80}, + {0x5780, 0x76}, + {0x5784, 0x08}, + {0x5785, 0x04}, + {0x5787, 0x0a}, + {0x5788, 0x0a}, + {0x5789, 0x0a}, + {0x578a, 0x0a}, + {0x578b, 0x0a}, + {0x578c, 0x0a}, + {0x578d, 0x40}, + {0x5790, 0x08}, + {0x5791, 0x04}, + {0x5792, 0x04}, + {0x5793, 0x08}, + {0x5794, 0x04}, + {0x5795, 0x04}, + {0x5799, 0x46}, + {0x579a, 0x77}, + {0x57a1, 0x04}, + {0x57a8, 0xd0}, + {0x57aa, 0x2a}, + {0x57ab, 0x7f}, + {0x57ac, 0x00}, + {0x57ad, 0x00}, + {0x59e0, 0xfe}, + {0x59e1, 0x40}, + {0x59e2, 0x3f}, + {0x59e3, 0x38}, + {0x59e4, 0x30}, + {0x59e5, 0x3f}, + {0x59e6, 0x38}, + {0x59e7, 0x30}, + {0x59e8, 0x3f}, + {0x59e9, 0x3c}, + {0x59ea, 0x38}, + {0x59eb, 0x3f}, + {0x59ec, 0x3c}, + {0x59ed, 0x38}, + {0x59ee, 0xfe}, + {0x59ef, 0x40}, + {0x59f4, 0x3f}, + {0x59f5, 0x38}, + {0x59f6, 0x30}, + {0x59f7, 0x3f}, + {0x59f8, 0x38}, + {0x59f9, 0x30}, + {0x59fa, 0x3f}, + {0x59fb, 0x3c}, + {0x59fc, 0x38}, + {0x59fd, 0x3f}, + {0x59fe, 0x3c}, + {0x59ff, 0x38}, + {0x36e9, 0x44}, + {0x36f9, 0x44}, + {REG_NULL, 0x00}, +}; + /* * Xclk 27Mhz * max_framerate 30fps * mipi_datarate per lane 720Mbps, 4lane */ -static const struct regval sc450ai_linear_10_2688x1520_30fps_regs[] = { +static const struct regval sc450ai_linear_10_2688x1520_30fps_4lane_regs[] = { {0x0103, 0x01}, {0x0100, 0x00}, {0x36e9, 0x80}, @@ -389,8 +807,10 @@ static const struct regval sc450ai_linear_10_2688x1520_30fps_regs[] = { {0x3209, 0x80}, {0x320a, 0x05}, {0x320b, 0xf0}, - {0x320c, 0x03}, - {0x320d, 0xa8}, + {0x320c, 0x04}, + {0x320d, 0x60}, + //{0x320c, 0x07}, + //{0x320d, 0x50}, {0x320e, 0x0c}, {0x320f, 0x30}, {0x3214, 0x11}, @@ -559,7 +979,215 @@ static const struct regval sc450ai_linear_10_2688x1520_30fps_regs[] = { {REG_NULL, 0x00}, }; -static const struct sc450ai_mode supported_modes[] = { +static const struct regval sc450ai_hdr2_10_2688x1520_30fps_4lane_regs[] = { + {0x0103, 0x01}, + {0x0100, 0x00}, + {0x36e9, 0x80}, + {0x36f9, 0x80}, + {0x301c, 0x78}, + {0x301f, 0x03}, + {0x302d, 0xa0}, + {0x302e, 0x00}, + {0x3208, 0x0a}, + {0x3209, 0x80}, + {0x320a, 0x05}, + {0x320b, 0xf0}, + {0x320c, 0x03}, + {0x320d, 0xa8}, + //{0x320c, 0x07}, + //{0x320d, 0x50}, + {0x320e, 0x0c}, + {0x320f, 0x30}, + {0x3213, 0x14}, + {0x3214, 0x11}, + {0x3215, 0x11}, + {0x3220, 0x00}, + {0x3223, 0xc0}, + {0x3250, 0xff}, + {0x3253, 0x10}, + {0x325f, 0x44}, + {0x3274, 0x09}, + {0x3280, 0x01}, + {0x3281, 0x01}, + {0x3301, 0x08}, + {0x3306, 0x24}, + {0x3309, 0x60}, + {0x330b, 0x64}, + {0x330d, 0x30}, + {0x3314, 0x94}, + {0x3315, 0x00}, + {0x331f, 0x59}, + {0x335d, 0x60}, + {0x3364, 0x56}, + {0x338f, 0x80}, + {0x3390, 0x08}, + {0x3391, 0x18}, + {0x3392, 0x38}, + {0x3393, 0x0a}, + {0x3394, 0x10}, + {0x3395, 0x18}, + {0x3396, 0x08}, + {0x3397, 0x18}, + {0x3398, 0x38}, + {0x3399, 0x0f}, + {0x339a, 0x12}, + {0x339b, 0x14}, + {0x339c, 0x18}, + {0x33af, 0x18}, + {0x3400, 0x16}, + {0x3410, 0x04}, + {0x360f, 0x13}, + {0x3621, 0xec}, + {0x3627, 0xa0}, + {0x3630, 0x90}, + {0x3633, 0x56}, + {0x3637, 0x1d}, + {0x3638, 0x0a}, + {0x363c, 0x0f}, + {0x363d, 0x0f}, + {0x363e, 0x08}, + {0x3670, 0x4a}, + {0x3671, 0xe0}, + {0x3672, 0xe0}, + {0x3673, 0xe0}, + {0x3674, 0xb0}, + {0x3675, 0x88}, + {0x3676, 0x8c}, + {0x367a, 0x48}, + {0x367b, 0x58}, + {0x367c, 0x48}, + {0x367d, 0x58}, + {0x3690, 0x34}, + {0x3691, 0x43}, + {0x3692, 0x44}, + {0x3699, 0x03}, + {0x369a, 0x0f}, + {0x369b, 0x1f}, + {0x369c, 0x40}, + {0x369d, 0x48}, + {0x36a2, 0x48}, + {0x36a3, 0x78}, + {0x36b0, 0x54}, + {0x36b1, 0x55}, + {0x36b2, 0x55}, + {0x36b3, 0x48}, + {0x36b4, 0x78}, + {0x36b7, 0xa0}, + {0x36b8, 0xa0}, + {0x36b9, 0x20}, + {0x36bd, 0x40}, + {0x36be, 0x48}, + {0x36d0, 0x20}, + {0x36e0, 0x08}, + {0x36e1, 0x08}, + {0x36e2, 0x12}, + {0x36e3, 0x48}, + {0x36e4, 0x78}, + {0x36fa, 0x0d}, + {0x36fb, 0xa4}, + {0x36fc, 0x00}, + {0x36fd, 0x24}, + {0x3900, 0x07}, + {0x3902, 0xf0}, + {0x3907, 0x00}, + {0x3908, 0x41}, + {0x391e, 0x01}, + {0x391f, 0x11}, + {0x3921, 0x10}, + {0x3933, 0x82}, + {0x3934, 0x0b}, + {0x3935, 0x02}, + {0x3936, 0x5e}, + {0x3937, 0x76}, + {0x3938, 0x78}, + {0x3939, 0x00}, + {0x393a, 0x28}, + {0x393b, 0x00}, + {0x393c, 0x1d}, + {0x3e00, 0x01}, + {0x3e01, 0x6b}, + {0x3e02, 0x00}, + {0x3e03, 0x0b}, + {0x3e04, 0x16}, + {0x3e05, 0xb0}, + {0x3e06, 0x00}, + {0x3e07, 0x80}, + {0x3e08, 0x03}, + {0x3e09, 0x40}, + {0x3e10, 0x00}, + {0x3e11, 0x80}, + {0x3e12, 0x03}, + {0x3e13, 0x40}, + {0x3e1b, 0x2a}, + {0x3e22, 0x00}, + {0x3e23, 0x00}, + {0x3e24, 0xba}, + {0x440e, 0x02}, + {0x4503, 0x60}, + {0x4509, 0x20}, + {0x4837, 0x16}, + {0x4853, 0xf8}, + {0x5000, 0x0e}, + {0x5001, 0x44}, + {0x5011, 0x80}, + {0x5780, 0x76}, + {0x5784, 0x08}, + {0x5785, 0x04}, + {0x5787, 0x0a}, + {0x5788, 0x0a}, + {0x5789, 0x0a}, + {0x578a, 0x0a}, + {0x578b, 0x0a}, + {0x578c, 0x0a}, + {0x578d, 0x40}, + {0x5790, 0x08}, + {0x5791, 0x04}, + {0x5792, 0x04}, + {0x5793, 0x08}, + {0x5794, 0x04}, + {0x5795, 0x04}, + {0x5799, 0x46}, + {0x579a, 0x77}, + {0x57a1, 0x04}, + {0x57a8, 0xd0}, + {0x57aa, 0x2a}, + {0x57ab, 0x7f}, + {0x57ac, 0x00}, + {0x57ad, 0x00}, + {0x59e0, 0xfe}, + {0x59e1, 0x40}, + {0x59e2, 0x3f}, + {0x59e3, 0x38}, + {0x59e4, 0x30}, + {0x59e5, 0x3f}, + {0x59e6, 0x38}, + {0x59e7, 0x30}, + {0x59e8, 0x3f}, + {0x59e9, 0x3c}, + {0x59ea, 0x38}, + {0x59eb, 0x3f}, + {0x59ec, 0x3c}, + {0x59ed, 0x38}, + {0x59ee, 0xfe}, + {0x59ef, 0x40}, + {0x59f4, 0x3f}, + {0x59f5, 0x38}, + {0x59f6, 0x30}, + {0x59f7, 0x3f}, + {0x59f8, 0x38}, + {0x59f9, 0x30}, + {0x59fa, 0x3f}, + {0x59fb, 0x3c}, + {0x59fc, 0x38}, + {0x59fd, 0x3f}, + {0x59fe, 0x3c}, + {0x59ff, 0x38}, + {0x36e9, 0x44}, + {0x36f9, 0x20}, + {REG_NULL, 0x00}, +}; + +static const struct sc450ai_mode supported_modes_2lane[] = { { .width = 2688, .height = 1520, @@ -569,13 +1197,35 @@ static const struct sc450ai_mode supported_modes[] = { }, .exp_def = 0x0080,//mark .hts_def = 0x2ee * 4, - .vts_def = 0x0c30, + .vts_def = 0x0618, .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, - .reg_list = sc450ai_linear_10_2688x1520_30fps_regs, + .reg_list = sc450ai_linear_10_2688x1520_30fps_2lane_regs, .hdr_mode = NO_HDR, .xvclk_freq = 27000000, - .link_freq_idx = 0, + .link_freq_idx = 1, .vc[PAD0] = 0, + .lanes = 2, + }, + { + .width = 2688, + .height = 1520, + .max_fps = { + .numerator = 10000, + .denominator = 250000, + }, + .exp_def = 0x0080,//mark + .hts_def = 0x39e * 4, + .vts_def = 0x0c26, + .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, + .reg_list = sc450ai_hdr2_10_2688x1520_25fps_2lane_regs, + .hdr_mode = HDR_X2, + .xvclk_freq = 27000000, + .link_freq_idx = 2, + .vc[PAD0] = 1, + .vc[PAD1] = 0,//L->CSI_WR0 + .vc[PAD2] = 1, + .vc[PAD3] = 1,//M->CSI_WR2 + .lanes = 2, }, { .width = 1344, @@ -588,16 +1238,61 @@ static const struct sc450ai_mode supported_modes[] = { .hts_def = 0x03a8, .vts_def = 0x030c, .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, - .reg_list = sc450ai_linear_10_1344x760_120fps_regs, + .reg_list = sc450ai_linear_10_1344x760_120fps_2lane_regs, + .hdr_mode = NO_HDR, + .xvclk_freq = 27000000, + .link_freq_idx = 1, + .vc[PAD0] = 0, + .lanes = 2, + }, +}; + +static const struct sc450ai_mode supported_modes_4lane[] = { + { + .width = 2688, + .height = 1520, + .max_fps = { + .numerator = 10000, + .denominator = 300000, + }, + .exp_def = 0x0080,//mark + .hts_def = 0x2ee * 4, + .vts_def = 0x0c30, + .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, + .reg_list = sc450ai_linear_10_2688x1520_30fps_4lane_regs, .hdr_mode = NO_HDR, .xvclk_freq = 27000000, .link_freq_idx = 0, .vc[PAD0] = 0, + .lanes = 4, + }, + { + .width = 2688, + .height = 1520, + .max_fps = { + .numerator = 10000, + .denominator = 300000, + }, + .exp_def = 0x0080,//mark + .hts_def = 0x3a8 * 4, + .vts_def = 0x0c30, + .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, + .reg_list = sc450ai_hdr2_10_2688x1520_30fps_4lane_regs, + .hdr_mode = HDR_X2, + .xvclk_freq = 27000000, + .link_freq_idx = 1, + .vc[PAD0] = 1, + .vc[PAD1] = 0,//L->CSI_WR0 + .vc[PAD2] = 1, + .vc[PAD3] = 1,//M->CSI_WR2 + .lanes = 4, }, }; static const s64 link_freq_menu_items[] = { + SC450AI_LINK_FREQ_180, SC450AI_LINK_FREQ_360, + SC450AI_LINK_FREQ_540, }; static const char * const sc450ai_test_pattern_menu[] = { @@ -767,6 +1462,26 @@ static int sc450ai_set_gain_reg(struct sc450ai *sc450ai, u32 gain) SC450AI_REG_ANA_FINE_GAIN, SC450AI_REG_VALUE_08BIT, fine_again); + + if (sc450ai->cur_mode->hdr_mode == HDR_X2) { + ret |= sc450ai_write_reg(sc450ai->client, + SC450AI_REG_DIG_GAIN_SHORT, + SC450AI_REG_VALUE_08BIT, + coarse_dgain); + ret |= sc450ai_write_reg(sc450ai->client, + SC450AI_REG_DIG_FINE_GAIN_SHORT, + SC450AI_REG_VALUE_08BIT, + fine_dgain); + ret |= sc450ai_write_reg(sc450ai->client, + SC450AI_REG_ANA_GAIN_SHORT, + SC450AI_REG_VALUE_08BIT, + coarse_again); + ret |= sc450ai_write_reg(sc450ai->client, + SC450AI_REG_ANA_FINE_GAIN_SHORT, + SC450AI_REG_VALUE_08BIT, + fine_again); + } + return ret; } @@ -778,7 +1493,7 @@ static int sc450ai_get_reso_dist(const struct sc450ai_mode *mode, } static const struct sc450ai_mode * -sc450ai_find_best_fit(struct v4l2_subdev_format *fmt) +sc450ai_find_best_fit(struct sc450ai *sc450ai, struct v4l2_subdev_format *fmt) { struct v4l2_mbus_framefmt *framefmt = &fmt->format; int dist; @@ -786,15 +1501,15 @@ sc450ai_find_best_fit(struct v4l2_subdev_format *fmt) int cur_best_fit_dist = -1; unsigned int i; - for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { - dist = sc450ai_get_reso_dist(&supported_modes[i], framefmt); + for (i = 0; i < sc450ai->cfg_num; i++) { + dist = sc450ai_get_reso_dist(&sc450ai->supported_modes[i], framefmt); if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) { cur_best_fit_dist = dist; cur_best_fit = i; } } - return &supported_modes[cur_best_fit]; + return &sc450ai->supported_modes[cur_best_fit]; } static int sc450ai_set_fmt(struct v4l2_subdev *sd, @@ -809,7 +1524,7 @@ static int sc450ai_set_fmt(struct v4l2_subdev *sd, mutex_lock(&sc450ai->mutex); - mode = sc450ai_find_best_fit(fmt); + mode = sc450ai_find_best_fit(sc450ai, fmt); fmt->format.code = mode->bus_fmt; fmt->format.width = mode->width; fmt->format.height = mode->height; @@ -832,7 +1547,7 @@ static int sc450ai_set_fmt(struct v4l2_subdev *sd, 1, vblank_def); dst_link_freq = mode->link_freq_idx; dst_pixel_rate = (u32)link_freq_menu_items[mode->link_freq_idx] / - SC450AI_BITS_PER_SAMPLE * 2 * SC450AI_LANES; + SC450AI_BITS_PER_SAMPLE * 2 * mode->lanes; __v4l2_ctrl_s_ctrl_int64(sc450ai->pixel_rate, dst_pixel_rate); __v4l2_ctrl_s_ctrl(sc450ai->link_freq, @@ -893,16 +1608,18 @@ static int sc450ai_enum_frame_sizes(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { - if (fse->index >= ARRAY_SIZE(supported_modes)) + struct sc450ai *sc450ai = to_sc450ai(sd); + + if (fse->index >= sc450ai->cfg_num) return -EINVAL; - if (fse->code != supported_modes[0].bus_fmt) + if (fse->code != sc450ai->supported_modes[0].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 = sc450ai->supported_modes[fse->index].width; + fse->max_width = sc450ai->supported_modes[fse->index].width; + fse->max_height = sc450ai->supported_modes[fse->index].height; + fse->min_height = sc450ai->supported_modes[fse->index].height; return 0; } @@ -941,8 +1658,10 @@ static int sc450ai_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id, struct v4l2_mbus_config *config) { + struct sc450ai *sc450ai = to_sc450ai(sd); + config->type = V4L2_MBUS_CSI2_DPHY; - config->bus.mipi_csi2.num_data_lanes = SC450AI_LANES; + config->bus.mipi_csi2.num_data_lanes = sc450ai->cur_mode->lanes; return 0; } @@ -957,6 +1676,71 @@ static void sc450ai_get_module_inf(struct sc450ai *sc450ai, strscpy(inf->base.lens, sc450ai->len_name, sizeof(inf->base.lens)); } +static int sc450ai_set_hdrae(struct sc450ai *sc450ai, + struct preisp_hdrae_exp_s *ae) +{ + int ret = 0; + u32 l_exp_time, m_exp_time, s_exp_time; + u32 l_a_gain, m_a_gain, s_a_gain; + + if (!sc450ai->has_init_exp && !sc450ai->streaming) { + sc450ai->init_hdrae_exp = *ae; + sc450ai->has_init_exp = true; + dev_dbg(&sc450ai->client->dev, "sc450ai don't stream, record exp for hdr!\n"); + return ret; + } + l_exp_time = ae->long_exp_reg; + m_exp_time = ae->middle_exp_reg; + s_exp_time = ae->short_exp_reg; + l_a_gain = ae->long_gain_reg; + m_a_gain = ae->middle_gain_reg; + s_a_gain = ae->short_gain_reg; + + dev_dbg(&sc450ai->client->dev, + "rev exp req: L_exp: 0x%x, 0x%x, M_exp: 0x%x, 0x%x S_exp: 0x%x, 0x%x\n", + l_exp_time, m_exp_time, s_exp_time, + l_a_gain, m_a_gain, s_a_gain); + + if (sc450ai->cur_mode->hdr_mode == HDR_X2) { + //2 stagger + l_a_gain = m_a_gain; + l_exp_time = m_exp_time; + } + + //set exposure + l_exp_time = l_exp_time * 2; + s_exp_time = s_exp_time * 2; + if (l_exp_time > 2 * (sc450ai->cur_vts - 0xba) - 13) + l_exp_time = 2 * (sc450ai->cur_vts - 0xba) - 13; + if (s_exp_time > 2 * 0xba - 11) + s_exp_time = 2 * 0xba - 11; + + ret = sc450ai_write_reg(sc450ai->client, + SC450AI_REG_EXPOSURE_H, + SC450AI_REG_VALUE_08BIT, + SC450AI_FETCH_EXP_H(l_exp_time)); + ret |= sc450ai_write_reg(sc450ai->client, + SC450AI_REG_EXPOSURE_M, + SC450AI_REG_VALUE_08BIT, + SC450AI_FETCH_EXP_M(l_exp_time)); + ret |= sc450ai_write_reg(sc450ai->client, + SC450AI_REG_EXPOSURE_L, + SC450AI_REG_VALUE_08BIT, + SC450AI_FETCH_EXP_L(l_exp_time)); + + ret |= sc450ai_write_reg(sc450ai->client, + SC450AI_REG_EXPOSURE_SHORT_M, + SC450AI_REG_VALUE_08BIT, + SC450AI_FETCH_EXP_M(s_exp_time)); + ret |= sc450ai_write_reg(sc450ai->client, + SC450AI_REG_EXPOSURE_SHORT_L, + SC450AI_REG_VALUE_08BIT, + SC450AI_FETCH_EXP_L(s_exp_time)); + + ret |= sc450ai_set_gain_reg(sc450ai, l_a_gain); + return ret; +} + static long sc450ai_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { struct sc450ai *sc450ai = to_sc450ai(sd); @@ -964,6 +1748,10 @@ static long sc450ai_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) u32 i, h, w; long ret = 0; u32 stream = 0; + const struct sc450ai_mode *mode; + u64 dst_link_freq = 0; + u64 dst_pixel_rate = 0; + switch (cmd) { case RKMODULE_GET_MODULE_INFO: @@ -978,29 +1766,38 @@ static long sc450ai_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) hdr = (struct rkmodule_hdr_cfg *)arg; w = sc450ai->cur_mode->width; h = sc450ai->cur_mode->height; - for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { - if (w == supported_modes[i].width && - h == supported_modes[i].height && - supported_modes[i].hdr_mode == hdr->hdr_mode) { - sc450ai->cur_mode = &supported_modes[i]; + for (i = 0; i < sc450ai->cfg_num; i++) { + if (w == sc450ai->supported_modes[i].width && + h == sc450ai->supported_modes[i].height && + sc450ai->supported_modes[i].hdr_mode == hdr->hdr_mode) { + sc450ai->cur_mode = &sc450ai->supported_modes[i]; break; } } - if (i == ARRAY_SIZE(supported_modes)) { + if (i == sc450ai->cfg_num) { dev_err(&sc450ai->client->dev, "not find hdr mode:%d %dx%d config\n", hdr->hdr_mode, w, h); ret = -EINVAL; } else { - w = sc450ai->cur_mode->hts_def - sc450ai->cur_mode->width; - h = sc450ai->cur_mode->vts_def - sc450ai->cur_mode->height; + mode = sc450ai->cur_mode; + w = mode->hts_def - mode->width; + h = mode->vts_def - mode->height; __v4l2_ctrl_modify_range(sc450ai->hblank, w, w, 1, w); __v4l2_ctrl_modify_range(sc450ai->vblank, h, - SC450AI_VTS_MAX - sc450ai->cur_mode->height, 1, h); - sc450ai->cur_fps = sc450ai->cur_mode->max_fps; + SC450AI_VTS_MAX - mode->height, 1, h); + dst_link_freq = mode->link_freq_idx; + dst_pixel_rate = (u32)link_freq_menu_items[mode->link_freq_idx] / + SC450AI_BITS_PER_SAMPLE * 2 * mode->lanes; + __v4l2_ctrl_s_ctrl_int64(sc450ai->pixel_rate, + dst_pixel_rate); + __v4l2_ctrl_s_ctrl(sc450ai->link_freq, + dst_link_freq); + sc450ai->cur_fps = mode->max_fps; } break; case PREISP_CMD_SET_HDRAE_EXP: + ret = sc450ai_set_hdrae(sc450ai, arg); break; case RKMODULE_SET_QUICK_STREAM: @@ -1340,6 +2137,7 @@ static int __maybe_unused sc450ai_resume(struct device *dev) return ret; } } + return 0; } @@ -1387,7 +2185,7 @@ static int sc450ai_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) struct sc450ai *sc450ai = to_sc450ai(sd); struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_get_try_format(sd, fh->state, 0); - const struct sc450ai_mode *def_mode = &supported_modes[0]; + const struct sc450ai_mode *def_mode = &sc450ai->supported_modes[0]; mutex_lock(&sc450ai->mutex); /* Initialize try_fmt */ @@ -1407,14 +2205,17 @@ static int sc450ai_enum_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_interval_enum *fie) { - if (fie->index >= ARRAY_SIZE(supported_modes)) + struct sc450ai *sc450ai = to_sc450ai(sd); + + if (fie->index >= sc450ai->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 = sc450ai->supported_modes[fie->index].bus_fmt; + fie->width = sc450ai->supported_modes[fie->index].width; + fie->height = sc450ai->supported_modes[fie->index].height; + fie->interval = sc450ai->supported_modes[fie->index].max_fps; + fie->reserved[0] = sc450ai->supported_modes[fie->index].hdr_mode; + return 0; } @@ -1571,7 +2372,7 @@ static int sc450ai_initialize_controls(struct sc450ai *sc450ai) u32 h_blank; int ret; u64 dst_link_freq = 0; - u64 dst_pixel_rate = 0; + u64 dst_pixel_rate = 0, max_dst_pixel_rate = 0; handler = &sc450ai->ctrl_handler; mode = sc450ai->cur_mode; @@ -1587,13 +2388,15 @@ static int sc450ai_initialize_controls(struct sc450ai *sc450ai) sc450ai->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; dst_link_freq = mode->link_freq_idx; + max_dst_pixel_rate = SC450AI_MAX_LINK_FREQ / SC450AI_BITS_PER_SAMPLE * 2 * SC450AI_LANES_4LANE; dst_pixel_rate = (u32)link_freq_menu_items[mode->link_freq_idx] / - SC450AI_BITS_PER_SAMPLE * 2 * SC450AI_LANES; + SC450AI_BITS_PER_SAMPLE * 2 * mode->lanes; sc450ai->pixel_rate = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, - 0, PIXEL_RATE_WITH_360M_10BIT, 1, dst_pixel_rate); + 0, max_dst_pixel_rate, 1, dst_pixel_rate); __v4l2_ctrl_s_ctrl(sc450ai->link_freq, dst_link_freq); + h_blank = mode->hts_def - mode->width; sc450ai->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK, h_blank, h_blank, 1, h_blank); @@ -1660,7 +2463,7 @@ static int sc450ai_check_sensor_id(struct sc450ai *sc450ai, return -ENODEV; } - dev_info(dev, "Detected OV%06x sensor\n", CHIP_ID); + dev_info(dev, "Detected %s sensor chip_id %x\n", SC450AI_NAME, CHIP_ID); return 0; } @@ -1687,6 +2490,7 @@ static int sc450ai_probe(struct i2c_client *client, char facing[2]; int ret; int i, hdr_mode = 0; + struct device_node *endpoint; dev_info(dev, "driver version: %02x.%02x.%02x", DRIVER_VERSION >> 16, @@ -1712,16 +2516,49 @@ static int sc450ai_probe(struct i2c_client *client, sc450ai->is_thunderboot = IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP); + ret = of_property_read_u32(node, OF_CAMERA_HDR_MODE, + &hdr_mode); + if (ret) { + 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), + &sc450ai->bus_cfg); + of_node_put(endpoint); + if (ret) { + dev_err(dev, "Failed to get bus config\n"); + return -EINVAL; + } + + if (sc450ai->bus_cfg.bus.mipi_csi2.num_data_lanes == SC450AI_LANES_4LANE) { + sc450ai->supported_modes = supported_modes_4lane; + sc450ai->cfg_num = ARRAY_SIZE(supported_modes_4lane); + } else { + sc450ai->supported_modes = supported_modes_2lane; + sc450ai->cfg_num = ARRAY_SIZE(supported_modes_2lane); + } + sc450ai->client = client; - for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { - if (hdr_mode == supported_modes[i].hdr_mode) { - sc450ai->cur_mode = &supported_modes[i]; + for (i = 0; i < sc450ai->cfg_num; i++) { + if (hdr_mode == sc450ai->supported_modes[i].hdr_mode) { + sc450ai->cur_mode = &sc450ai->supported_modes[i]; break; } } - if (i == ARRAY_SIZE(supported_modes)) - sc450ai->cur_mode = &supported_modes[0]; + if (i == sc450ai->cfg_num) + sc450ai->cur_mode = &sc450ai->supported_modes[0]; + + dev_dbg(dev, "SC450AI Info hdr_mode %d lanes %d vts 0x%04x fps %d\n", + sc450ai->cur_mode->hdr_mode, sc450ai->cur_mode->lanes, sc450ai->cur_mode->vts_def, + sc450ai->cur_mode->max_fps.denominator / sc450ai->cur_mode->max_fps.numerator); sc450ai->xvclk = devm_clk_get(dev, "xvclk"); if (IS_ERR(sc450ai->xvclk)) {