From 16b27eed7c3980eb9ed04a39c050bce7a5e24b15 Mon Sep 17 00:00:00 2001 From: Sandy Huang Date: Mon, 3 Apr 2023 16:41:25 +0800 Subject: [PATCH 001/133] drm/rockchip: vop2: recover win state when exit psr Change-Id: I0d30042473ae84f49b4d326b31732180995b8b52 Signed-off-by: Sandy Huang --- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 67 +++++++++++++++++--- 1 file changed, 58 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 5ca4fcade790..c70cd445146a 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -642,6 +642,11 @@ struct vop2_video_port { * @win_mask: Bitmask of wins attached to the video port; */ uint32_t win_mask; + /** + * @enabled_win_mask: Bitmask of enabled wins attached to the video port; + */ + uint32_t enabled_win_mask; + /** * @nr_layers: active layers attached to the video port; */ @@ -4269,13 +4274,24 @@ static int vop2_clk_set_parent_extend(struct vop2_video_port *vp, return 0; } -static void vop2_crtc_atomic_disable_for_psr(struct drm_crtc *crtc, - struct drm_crtc_state *old_state) +static void vop2_crtc_atomic_enter_psr(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { struct vop2_video_port *vp = to_vop2_video_port(crtc); struct vop2 *vop2 = vp->vop2; + struct vop2_win *win; + unsigned long win_mask = vp->enabled_win_mask; + int phys_id; - vop2_disable_all_planes_for_crtc(crtc); + for_each_set_bit(phys_id, &win_mask, ROCKCHIP_MAX_LAYER) { + win = vop2_find_win_by_phys_id(vop2, phys_id); + VOP_WIN_SET(vop2, win, enable, 0); + + if (win->feature & WIN_FEATURE_CLUSTER_MAIN) + VOP_CLUSTER_SET(vop2, win, enable, 0); + } + + vop2_cfg_done(crtc); + vop2_wait_for_fs_by_done_bit_status(vp); drm_crtc_vblank_off(crtc); if (hweight8(vop2->active_vp_mask) == 1) { u32 adjust_aclk_rate = 0; @@ -4298,6 +4314,30 @@ static void vop2_crtc_atomic_disable_for_psr(struct drm_crtc *crtc, } } +static void vop2_crtc_atomic_exit_psr(struct drm_crtc *crtc, struct drm_crtc_state *old_state) +{ + struct vop2_video_port *vp = to_vop2_video_port(crtc); + struct vop2 *vop2 = vp->vop2; + u32 phys_id; + struct vop2_win *win; + unsigned long enabled_win_mask = vp->enabled_win_mask; + + drm_crtc_vblank_on(crtc); + if (vop2->aclk_rate_reset) + clk_set_rate(vop2->aclk, vop2->aclk_rate); + vop2->aclk_rate_reset = false; + + for_each_set_bit(phys_id, &enabled_win_mask, ROCKCHIP_MAX_LAYER) { + win = vop2_find_win_by_phys_id(vop2, phys_id); + VOP_WIN_SET(vop2, win, enable, 1); + if (win->feature & WIN_FEATURE_CLUSTER_MAIN) + VOP_CLUSTER_SET(vop2, win, enable, 1); + } + + vop2_cfg_done(crtc); + vop2_wait_for_fs_by_done_bit_status(vp); +} + static void vop2_crtc_atomic_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { @@ -4312,7 +4352,7 @@ static void vop2_crtc_atomic_disable(struct drm_crtc *crtc, WARN_ON(vp->event); if (crtc->state->self_refresh_active) { - vop2_crtc_atomic_disable_for_psr(crtc, old_state); + vop2_crtc_atomic_enter_psr(crtc, old_state); goto out; } @@ -4777,6 +4817,9 @@ static void vop2_plane_atomic_disable(struct drm_plane *plane, struct drm_plane_ { struct vop2_win *win = to_vop2_win(plane); struct vop2 *vop2 = win->vop2; + struct drm_crtc *crtc; + struct vop2_video_port *vp; + #if defined(CONFIG_ROCKCHIP_DRM_DEBUG) struct vop2_plane_state *vpstate = to_vop2_plane_state(plane->state); #endif @@ -4789,9 +4832,15 @@ static void vop2_plane_atomic_disable(struct drm_plane *plane, struct drm_plane_ spin_lock(&vop2->reg_lock); + crtc = old_state->crtc; + vp = to_vop2_video_port(crtc); + vop2_win_disable(win, false); - if (win->splice_win) + vp->enabled_win_mask &= ~BIT(win->phys_id); + if (win->splice_win) { vop2_win_disable(win->splice_win, false); + vp->enabled_win_mask &= ~BIT(win->splice_win->phys_id); + } #if defined(CONFIG_ROCKCHIP_DRM_DEBUG) kfree(vpstate->planlist); @@ -5203,6 +5252,7 @@ static void vop2_win_atomic_update(struct vop2_win *win, struct drm_rect *src, s VOP_WIN_SET(vop2, win, dither_up, dither_up); VOP_WIN_SET(vop2, win, enable, 1); + vp->enabled_win_mask |= BIT(win->phys_id); if (vop2_cluster_window(win)) { lb_mode = vop2_get_cluster_lb_mode(win, vpstate); VOP_CLUSTER_SET(vop2, win, lb_mode, lb_mode); @@ -5972,6 +6022,7 @@ static int vop2_crtc_loader_protect(struct drm_crtc *crtc, bool on, void *data) win->pd->vp_mask |= BIT(vp->id); } + vp->enabled_win_mask |= BIT(win->phys_id); crtc_state = drm_atomic_get_crtc_state(crtc->state->state, crtc); mode = &crtc_state->adjusted_mode; if (mode->hdisplay > VOP2_MAX_VP_OUTPUT_WIDTH) { @@ -5984,6 +6035,7 @@ static int vop2_crtc_loader_protect(struct drm_crtc *crtc, bool on, void *data) splice_vp->win_mask |= BIT(splice_win->phys_id); splice_win->vp_mask = BIT(splice_vp->id); vop2->active_vp_mask |= BIT(splice_vp->id); + vp->enabled_win_mask |= BIT(splice_win->phys_id); if (splice_win->pd && VOP_WIN_GET(vop2, splice_win, enable)) { @@ -7559,10 +7611,7 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state int ret; if (old_state && old_state->self_refresh_active) { - drm_crtc_vblank_on(crtc); - if (vop2->aclk_rate_reset) - clk_set_rate(vop2->aclk, vop2->aclk_rate); - vop2->aclk_rate_reset = false; + vop2_crtc_atomic_exit_psr(crtc, old_state); return; } From 76d1ca6150e7ad9a7604c92411dcbc57ba2329f8 Mon Sep 17 00:00:00 2001 From: Lin Jinhan Date: Wed, 12 Jul 2023 17:56:28 +0800 Subject: [PATCH 002/133] media: i2c: add sc5336 driver Signed-off-by: Lin Jinhan Change-Id: I683d49cfd323afba4bb5322bd811eeaf67b0edfd --- drivers/media/i2c/Kconfig | 10 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/sc5336.c | 1588 ++++++++++++++++++++++++++++++++++++ 3 files changed, 1599 insertions(+) create mode 100644 drivers/media/i2c/sc5336.c diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 77b48f60ce01..509a85003103 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -2122,6 +2122,16 @@ config VIDEO_SC530AI This is a Video4Linux2 sensor driver for the SmartSens SC530AI camera. +config VIDEO_SC5336 + tristate "SmartSens SC5336 sensor support" + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + select V4L2_FWNODE + help + This is a Video4Linux2 sensor driver for the SmartSens + SC5336 camera. + config VIDEO_SC850SL tristate "SmartSens SC850SL sensor support" depends on I2C && VIDEO_V4L2 diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index fa2f8362c6ee..95612d4a43f3 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -144,6 +144,7 @@ obj-$(CONFIG_VIDEO_SC4336) += sc4336.o obj-$(CONFIG_VIDEO_SC500AI) += sc500ai.o obj-$(CONFIG_VIDEO_SC501AI) += sc501ai.o obj-$(CONFIG_VIDEO_SC530AI) += sc530ai.o +obj-$(CONFIG_VIDEO_SC5336) += sc5336.o obj-$(CONFIG_VIDEO_SC850SL) += sc850sl.o obj-$(CONFIG_VIDEO_SENSOR_ADAPTER) += sensor_adapter.o obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o diff --git a/drivers/media/i2c/sc5336.c b/drivers/media/i2c/sc5336.c new file mode 100644 index 000000000000..eb0b925cd7d2 --- /dev/null +++ b/drivers/media/i2c/sc5336.c @@ -0,0 +1,1588 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * sc5336 driver + * + * Copyright (C) 2023 Rockchip Electronics Co., Ltd. + * + */ + +//#define DEBUG +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../platform/rockchip/isp/rkisp_tb_helper.h" + +#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x01) + +#ifndef V4L2_CID_DIGITAL_GAIN +#define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN +#endif + +#define SC5336_LANES 2 +#define SC5336_BITS_PER_SAMPLE 10 +#define SC5336_LINK_FREQ 432000000 + +#define PIXEL_RATE_WITH_315M_10BIT (SC5336_LINK_FREQ * 2 * \ + SC5336_LANES / SC5336_BITS_PER_SAMPLE) +#define SC5336_XVCLK_FREQ 24000000 + +#define CHIP_ID 0xce50 +#define SC5336_REG_CHIP_ID 0x3107 + +#define SC5336_REG_CTRL_MODE 0x0100 +#define SC5336_MODE_SW_STANDBY 0x0 +#define SC5336_MODE_STREAMING BIT(0) + +#define SC5336_REG_EXPOSURE_H 0x3e00 +#define SC5336_REG_EXPOSURE_M 0x3e01 +#define SC5336_REG_EXPOSURE_L 0x3e02 +#define SC5336_EXPOSURE_MIN 1 +#define SC5336_EXPOSURE_STEP 1 +#define SC5336_VTS_MAX 0x7fff + +#define SC5336_REG_DIG_GAIN 0x3e06 +#define SC5336_REG_DIG_FINE_GAIN 0x3e07 +#define SC5336_REG_ANA_GAIN 0x3e09 +#define SC5336_GAIN_MIN 0x0020 +#define SC5336_GAIN_MAX (32 * 15 * 32) //32*15*32 +#define SC5336_GAIN_STEP 1 +#define SC5336_GAIN_DEFAULT 0x120 + + +#define SC5336_REG_GROUP_HOLD 0x3812 +#define SC5336_GROUP_HOLD_START 0x00 +#define SC5336_GROUP_HOLD_END 0x30 + +#define SC5336_REG_TEST_PATTERN 0x4501 + +#define SC5336_REG_VTS_H 0x320e +#define SC5336_REG_VTS_L 0x320f + +#define SC5336_FLIP_MIRROR_REG 0x3221 + +#define SC5336_FETCH_EXP_H(VAL) (((VAL) >> 12) & 0xF) +#define SC5336_FETCH_EXP_M(VAL) (((VAL) >> 4) & 0xFF) +#define SC5336_FETCH_EXP_L(VAL) (((VAL) & 0xF) << 4) + +#define SC5336_FETCH_AGAIN_H(VAL) (((VAL) >> 8) & 0x03) +#define SC5336_FETCH_AGAIN_L(VAL) ((VAL) & 0xFF) + +#define SC5336_FETCH_MIRROR(VAL, ENABLE) (ENABLE ? VAL | 0x06 : VAL & 0xf9) +#define SC5336_FETCH_FLIP(VAL, ENABLE) (ENABLE ? VAL | 0x60 : VAL & 0x9f) + +#define REG_DELAY 0xFFFE +#define REG_NULL 0xFFFF + +#define SC5336_REG_VALUE_08BIT 1 +#define SC5336_REG_VALUE_16BIT 2 +#define SC5336_REG_VALUE_24BIT 3 + +#define OF_CAMERA_PINCTRL_STATE_DEFAULT "rockchip,camera_default" +#define OF_CAMERA_PINCTRL_STATE_SLEEP "rockchip,camera_sleep" +#define SC5336_NAME "sc5336" + +static const char * const sc5336_supply_names[] = { + "avdd", /* Analog power */ + "dovdd", /* Digital I/O power */ + "dvdd", /* Digital core power */ +}; + +#define SC5336_NUM_SUPPLIES ARRAY_SIZE(sc5336_supply_names) + +struct regval { + u16 addr; + u8 val; +}; + +struct sc5336_mode { + u32 bus_fmt; + u32 width; + u32 height; + struct v4l2_fract max_fps; + u32 hts_def; + u32 vts_def; + u32 exp_def; + const struct regval *reg_list; + u32 hdr_mode; + u32 vc[PAD_MAX]; +}; + +struct sc5336 { + struct i2c_client *client; + struct clk *xvclk; + struct gpio_desc *reset_gpio; + struct gpio_desc *pwdn_gpio; + struct regulator_bulk_data supplies[SC5336_NUM_SUPPLIES]; + + struct pinctrl *pinctrl; + struct pinctrl_state *pins_default; + struct pinctrl_state *pins_sleep; + + struct v4l2_subdev subdev; + struct media_pad pad; + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *anal_gain; + struct v4l2_ctrl *digi_gain; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *test_pattern; + struct mutex mutex; + bool streaming; + bool power_on; + const struct sc5336_mode *cur_mode; + struct v4l2_fract cur_fps; + u32 module_index; + const char *module_facing; + const char *module_name; + const char *len_name; + u32 cur_vts; + bool is_thunderboot; + bool is_first_streamoff; +}; + +#define to_sc5336(sd) container_of(sd, struct sc5336, subdev) + +/* + * Xclk 24Mhz + */ +static const struct regval sc5336_global_regs[] = { + {REG_NULL, 0x00}, +}; + +/* + * Xclk 24Mhz + * max_framerate 30fps + * mipi_datarate per lane 864Mbps, 2lane + */ +static const struct regval sc5336_linear_10_2880x1620_regs[] = { + {0x0103, 0x01}, + {0x36e9, 0x80}, + {0x37f9, 0x80}, + {0x301f, 0x1a}, + {0x320e, 0x07}, + {0x320f, 0x08}, + {0x3213, 0x04}, + {0x3241, 0x00}, + {0x3243, 0x01}, + {0x3248, 0x02}, + {0x3249, 0x0b}, + {0x3253, 0x10}, + {0x3258, 0x0c}, + {0x3301, 0x0a}, + {0x3305, 0x00}, + {0x3306, 0x58}, + {0x3308, 0x08}, + {0x3309, 0xb0}, + {0x330a, 0x00}, + {0x330b, 0xc8}, + {0x3314, 0x14}, + {0x331f, 0xa1}, + {0x3321, 0x10}, + {0x3327, 0x14}, + {0x3328, 0x0b}, + {0x3329, 0x0e}, + {0x3333, 0x10}, + {0x3334, 0x40}, + {0x3356, 0x10}, + {0x3364, 0x5e}, + {0x338f, 0x80}, + {0x3390, 0x09}, + {0x3391, 0x0b}, + {0x3392, 0x0f}, + {0x3393, 0x10}, + {0x3394, 0x16}, + {0x3395, 0x98}, + {0x3396, 0x08}, + {0x3397, 0x09}, + {0x3398, 0x0f}, + {0x3399, 0x0a}, + {0x339a, 0x18}, + {0x339b, 0x60}, + {0x339c, 0xff}, + {0x33ad, 0x0c}, + {0x33ae, 0x5c}, + {0x33af, 0x52}, + {0x33b1, 0xa0}, + {0x33b2, 0x38}, + {0x33b3, 0x18}, + {0x33f8, 0x00}, + {0x33f9, 0x60}, + {0x33fa, 0x00}, + {0x33fb, 0x80}, + {0x33fc, 0x0b}, + {0x33fd, 0x1f}, + {0x349f, 0x03}, + {0x34a6, 0x0b}, + {0x34a7, 0x1f}, + {0x34a8, 0x08}, + {0x34a9, 0x08}, + {0x34aa, 0x00}, + {0x34ab, 0xd0}, + {0x34ac, 0x00}, + {0x34ad, 0xf0}, + {0x34f8, 0x3f}, + {0x34f9, 0x08}, + {0x3630, 0xc0}, + {0x3631, 0x83}, + {0x3632, 0x54}, + {0x3633, 0x33}, + {0x3638, 0xcf}, + {0x363f, 0xc0}, + {0x3641, 0x20}, + {0x3670, 0x56}, + {0x3674, 0xc0}, + {0x3675, 0xa0}, + {0x3676, 0xa0}, + {0x3677, 0x83}, + {0x3678, 0x86}, + {0x3679, 0x8a}, + {0x367c, 0x08}, + {0x367d, 0x0f}, + {0x367e, 0x08}, + {0x367f, 0x0f}, + {0x3696, 0x23}, + {0x3697, 0x33}, + {0x3698, 0x34}, + {0x36a0, 0x09}, + {0x36a1, 0x0f}, + {0x36b0, 0x85}, + {0x36b1, 0x8a}, + {0x36b2, 0x95}, + {0x36b3, 0xa6}, + {0x36b4, 0x09}, + {0x36b5, 0x0b}, + {0x36b6, 0x0f}, + {0x36ea, 0x0c}, + {0x36eb, 0x0c}, + {0x36ec, 0x0c}, + {0x36ed, 0xb6}, + {0x370f, 0x01}, + {0x3721, 0x6c}, + {0x3722, 0x89}, + {0x3724, 0x21}, + {0x3725, 0xb4}, + {0x3727, 0x14}, + {0x3771, 0x89}, + {0x3772, 0x89}, + {0x3773, 0xc5}, + {0x377a, 0x0b}, + {0x377b, 0x1f}, + {0x37fa, 0x0c}, + {0x37fb, 0x24}, + {0x37fc, 0x01}, + {0x37fd, 0x36}, + {0x3901, 0x00}, + {0x3904, 0x04}, + {0x3905, 0x8c}, + {0x391d, 0x04}, + {0x391f, 0x49}, + {0x3926, 0x21}, + {0x3933, 0x80}, + {0x3934, 0x0a}, + {0x3935, 0x00}, + {0x3936, 0xff}, + {0x3937, 0x75}, + {0x3938, 0x74}, + {0x393c, 0x1e}, + {0x39dc, 0x02}, + {0x3e00, 0x00}, + {0x3e01, 0x70}, + {0x3e02, 0x00}, + {0x3e09, 0x00}, + {0x440d, 0x10}, + {0x440e, 0x02}, + {0x450d, 0x18}, + {0x4819, 0x0b}, + {0x481b, 0x06}, + {0x481d, 0x17}, + {0x481f, 0x05}, + {0x4821, 0x0b}, + {0x4823, 0x06}, + {0x4825, 0x05}, + {0x4827, 0x05}, + {0x4829, 0x09}, + {0x5780, 0x66}, + {0x5787, 0x08}, + {0x5788, 0x03}, + {0x5789, 0x00}, + {0x578a, 0x08}, + {0x578b, 0x03}, + {0x578c, 0x00}, + {0x578d, 0x40}, + {0x5790, 0x08}, + {0x5791, 0x04}, + {0x5792, 0x01}, + {0x5793, 0x08}, + {0x5794, 0x04}, + {0x5795, 0x01}, + {0x5799, 0x46}, + {0x57aa, 0x2a}, + {0x5ae0, 0xfe}, + {0x5ae1, 0x40}, + {0x5ae2, 0x38}, + {0x5ae3, 0x30}, + {0x5ae4, 0x0c}, + {0x5ae5, 0x38}, + {0x5ae6, 0x30}, + {0x5ae7, 0x28}, + {0x5ae8, 0x3f}, + {0x5ae9, 0x34}, + {0x5aea, 0x2c}, + {0x5aeb, 0x3f}, + {0x5aec, 0x34}, + {0x5aed, 0x2c}, + {0x36e9, 0x20}, + {0x37f9, 0x20}, + {REG_NULL, 0x00}, +}; + +static const struct sc5336_mode supported_modes[] = { + { + .width = 2880, + .height = 1620, + .max_fps = { + .numerator = 10000, + .denominator = 300000, + }, + .exp_def = 0x0080 * 4, + .hts_def = 0x0654 * 2, + .vts_def = 0x0708, + .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, + .reg_list = sc5336_linear_10_2880x1620_regs, + .hdr_mode = NO_HDR, + .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, + } +}; + +static const s64 link_freq_menu_items[] = { + SC5336_LINK_FREQ +}; + +static const char * const sc5336_test_pattern_menu[] = { + "Disabled", + "Vertical Gray Bar Type 1", +}; + +/* Write registers up to 4 at a time */ +static int sc5336_write_reg(struct i2c_client *client, u16 reg, + u32 len, u32 val) +{ + u32 buf_i, val_i; + u8 buf[6]; + u8 *val_p; + __be32 val_be; + + if (len > 4) + return -EINVAL; + + buf[0] = reg >> 8; + buf[1] = reg & 0xff; + + val_be = cpu_to_be32(val); + val_p = (u8 *)&val_be; + buf_i = 2; + val_i = 4 - len; + + while (val_i < 4) + buf[buf_i++] = val_p[val_i++]; + + if (i2c_master_send(client, buf, len + 2) != len + 2) + return -EIO; + return 0; +} + +static int sc5336_write_array(struct i2c_client *client, + const struct regval *regs) +{ + u32 i; + int ret = 0; + + for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++) + ret = sc5336_write_reg(client, regs[i].addr, + SC5336_REG_VALUE_08BIT, regs[i].val); + + return ret; +} + +/* Read registers up to 4 at a time */ +static int sc5336_read_reg(struct i2c_client *client, u16 reg, unsigned int len, + u32 *val) +{ + struct i2c_msg msgs[2]; + u8 *data_be_p; + __be32 data_be = 0; + __be16 reg_addr_be = cpu_to_be16(reg); + int ret; + + if (len > 4 || !len) + return -EINVAL; + + data_be_p = (u8 *)&data_be; + /* Write register address */ + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = 2; + msgs[0].buf = (u8 *)®_addr_be; + + /* Read data from register */ + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = &data_be_p[4 - len]; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) + return -EIO; + + *val = be32_to_cpu(data_be); + + return 0; +} + +static int sc5336_set_gain_reg(struct sc5336 *sc5336, u32 gain) +{ + u32 coarse_again = 0, coarse_dgian = 0, fine_dgian = 0; + u32 gain_factor; + int ret = 0; + + if (gain < 32) + gain = 32; + else if (gain > SC5336_GAIN_MAX) + gain = SC5336_GAIN_MAX; + + gain_factor = gain * 1000 / 32; + if (gain_factor < 2000) { + coarse_again = 0x00; + coarse_dgian = 0x00; + fine_dgian = gain_factor * 128 / 1000; + } else if (gain_factor < 4000) { + coarse_again = 0x08; + coarse_dgian = 0x00; + fine_dgian = gain_factor * 128 / 2000; + } else if (gain_factor < 8000) { + coarse_again = 0x09; + coarse_dgian = 0x00; + fine_dgian = gain_factor * 128 / 4000; + } else if (gain_factor < 16000) { + coarse_again = 0x0b; + coarse_dgian = 0x00; + fine_dgian = gain_factor * 128 / 8000; + } else if (gain_factor < 32000) { + coarse_again = 0x0f; + coarse_dgian = 0x00; + fine_dgian = gain_factor * 128 / 16000; + } else if (gain_factor < 32000 * 2) { + coarse_again = 0x1f; + coarse_dgian = 0x00; + fine_dgian = gain_factor * 128 / 32000; + } else if (gain_factor < 32000 * 4) { + //open dgain begin max digital gain 4X + coarse_again = 0x1f; + coarse_dgian = 0x01; + fine_dgian = gain_factor * 128 / 32000 / 2; + } else if (gain_factor < 32000 * 8) { + coarse_again = 0x1f; + coarse_dgian = 0x03; + fine_dgian = gain_factor * 128 / 32000 / 4; + } else if (gain_factor < 32000 * 15) { + coarse_again = 0x1f; + coarse_dgian = 0x07; + fine_dgian = gain_factor * 128 / 32000 / 8; + } else { + coarse_again = 0x1f; + coarse_dgian = 0x07; + fine_dgian = 0xf0; + } + + ret = sc5336_write_reg(sc5336->client, + SC5336_REG_DIG_GAIN, + SC5336_REG_VALUE_08BIT, + coarse_dgian); + ret |= sc5336_write_reg(sc5336->client, + SC5336_REG_DIG_FINE_GAIN, + SC5336_REG_VALUE_08BIT, + fine_dgian); + ret |= sc5336_write_reg(sc5336->client, + SC5336_REG_ANA_GAIN, + SC5336_REG_VALUE_08BIT, + coarse_again); + + return ret; +} + +static int sc5336_get_reso_dist(const struct sc5336_mode *mode, + struct v4l2_mbus_framefmt *framefmt) +{ + return abs(mode->width - framefmt->width) + + abs(mode->height - framefmt->height); +} + +static const struct sc5336_mode * +sc5336_find_best_fit(struct v4l2_subdev_format *fmt) +{ + struct v4l2_mbus_framefmt *framefmt = &fmt->format; + int dist; + int cur_best_fit = 0; + int cur_best_fit_dist = -1; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { + dist = sc5336_get_reso_dist(&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]; +} + +static int sc5336_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct sc5336 *sc5336 = to_sc5336(sd); + const struct sc5336_mode *mode; + s64 h_blank, vblank_def; + + mutex_lock(&sc5336->mutex); + + mode = sc5336_find_best_fit(fmt); + fmt->format.code = mode->bus_fmt; + fmt->format.width = mode->width; + fmt->format.height = mode->height; + fmt->format.field = V4L2_FIELD_NONE; + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format; +#else + mutex_unlock(&sc5336->mutex); + return -ENOTTY; +#endif + } else { + sc5336->cur_mode = mode; + h_blank = mode->hts_def - mode->width; + __v4l2_ctrl_modify_range(sc5336->hblank, h_blank, + h_blank, 1, h_blank); + vblank_def = mode->vts_def - mode->height; + __v4l2_ctrl_modify_range(sc5336->vblank, vblank_def, + SC5336_VTS_MAX - mode->height, + 1, vblank_def); + sc5336->cur_fps = mode->max_fps; + } + + mutex_unlock(&sc5336->mutex); + + return 0; +} + +static int sc5336_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct sc5336 *sc5336 = to_sc5336(sd); + const struct sc5336_mode *mode = sc5336->cur_mode; + + mutex_lock(&sc5336->mutex); + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad); +#else + mutex_unlock(&sc5336->mutex); + return -ENOTTY; +#endif + } else { + fmt->format.width = mode->width; + fmt->format.height = mode->height; + fmt->format.code = mode->bus_fmt; + fmt->format.field = V4L2_FIELD_NONE; + /* format info: width/height/data type/virctual channel */ + if (fmt->pad < PAD_MAX && mode->hdr_mode != NO_HDR) + fmt->reserved[0] = mode->vc[fmt->pad]; + else + fmt->reserved[0] = mode->vc[PAD0]; + } + mutex_unlock(&sc5336->mutex); + + return 0; +} + +static int sc5336_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct sc5336 *sc5336 = to_sc5336(sd); + + if (code->index != 0) + return -EINVAL; + code->code = sc5336->cur_mode->bus_fmt; + + return 0; +} + +static int sc5336_enum_frame_sizes(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + + if (fse->code != 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; + + return 0; +} + +static int sc5336_enable_test_pattern(struct sc5336 *sc5336, u32 pattern) +{ + int ret = 0; + + if (pattern) { + ret |= sc5336_write_reg(sc5336->client, 0x4501, SC5336_REG_VALUE_08BIT, 0xac); + ret |= sc5336_write_reg(sc5336->client, 0x3902, SC5336_REG_VALUE_08BIT, 0x80); + ret |= sc5336_write_reg(sc5336->client, 0x3e07, SC5336_REG_VALUE_08BIT, 0x40); + } else { + ret |= sc5336_write_reg(sc5336->client, 0x4501, SC5336_REG_VALUE_08BIT, 0xa4); + ret |= sc5336_write_reg(sc5336->client, 0x3902, SC5336_REG_VALUE_08BIT, 0xc0); + ret |= sc5336_write_reg(sc5336->client, 0x3e07, SC5336_REG_VALUE_08BIT, 0x80); + } + + return ret; +} + +static int sc5336_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + struct sc5336 *sc5336 = to_sc5336(sd); + const struct sc5336_mode *mode = sc5336->cur_mode; + + if (sc5336->streaming) + fi->interval = sc5336->cur_fps; + else + fi->interval = mode->max_fps; + + return 0; +} + +static int sc5336_g_mbus_config(struct v4l2_subdev *sd, + unsigned int pad_id, + struct v4l2_mbus_config *config) +{ + struct sc5336 *sc5336 = to_sc5336(sd); + const struct sc5336_mode *mode = sc5336->cur_mode; + u32 val = 1 << (SC5336_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_DPHY; + config->flags = val; + + return 0; +} + +static void sc5336_get_module_inf(struct sc5336 *sc5336, + struct rkmodule_inf *inf) +{ + memset(inf, 0, sizeof(*inf)); + strscpy(inf->base.sensor, SC5336_NAME, sizeof(inf->base.sensor)); + strscpy(inf->base.module, sc5336->module_name, + sizeof(inf->base.module)); + strscpy(inf->base.lens, sc5336->len_name, sizeof(inf->base.lens)); +} + +static long sc5336_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct sc5336 *sc5336 = to_sc5336(sd); + struct rkmodule_hdr_cfg *hdr; + u32 i, h, w; + long ret = 0; + u32 stream = 0; + + switch (cmd) { + case RKMODULE_GET_MODULE_INFO: + sc5336_get_module_inf(sc5336, (struct rkmodule_inf *)arg); + break; + case RKMODULE_GET_HDR_CFG: + hdr = (struct rkmodule_hdr_cfg *)arg; + hdr->esp.mode = HDR_NORMAL_VC; + hdr->hdr_mode = sc5336->cur_mode->hdr_mode; + break; + case RKMODULE_SET_HDR_CFG: + hdr = (struct rkmodule_hdr_cfg *)arg; + w = sc5336->cur_mode->width; + h = sc5336->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) { + sc5336->cur_mode = &supported_modes[i]; + break; + } + } + if (i == ARRAY_SIZE(supported_modes)) { + dev_err(&sc5336->client->dev, + "not find hdr mode:%d %dx%d config\n", + hdr->hdr_mode, w, h); + ret = -EINVAL; + } else { + w = sc5336->cur_mode->hts_def - sc5336->cur_mode->width; + h = sc5336->cur_mode->vts_def - sc5336->cur_mode->height; + __v4l2_ctrl_modify_range(sc5336->hblank, w, w, 1, w); + __v4l2_ctrl_modify_range(sc5336->vblank, h, + SC5336_VTS_MAX - sc5336->cur_mode->height, 1, h); + } + break; + case PREISP_CMD_SET_HDRAE_EXP: + break; + case RKMODULE_SET_QUICK_STREAM: + + stream = *((u32 *)arg); + + if (stream) + ret = sc5336_write_reg(sc5336->client, SC5336_REG_CTRL_MODE, + SC5336_REG_VALUE_08BIT, SC5336_MODE_STREAMING); + else + ret = sc5336_write_reg(sc5336->client, SC5336_REG_CTRL_MODE, + SC5336_REG_VALUE_08BIT, SC5336_MODE_SW_STANDBY); + break; + default: + ret = -ENOIOCTLCMD; + break; + } + + return ret; +} + +#ifdef CONFIG_COMPAT +static long sc5336_compat_ioctl32(struct v4l2_subdev *sd, + unsigned int cmd, unsigned long arg) +{ + void __user *up = compat_ptr(arg); + struct rkmodule_inf *inf; + struct rkmodule_hdr_cfg *hdr; + struct preisp_hdrae_exp_s *hdrae; + long ret; + u32 stream = 0; + + switch (cmd) { + case RKMODULE_GET_MODULE_INFO: + inf = kzalloc(sizeof(*inf), GFP_KERNEL); + if (!inf) { + ret = -ENOMEM; + return ret; + } + + ret = sc5336_ioctl(sd, cmd, inf); + if (!ret) { + if (copy_to_user(up, inf, sizeof(*inf))) + ret = -EFAULT; + } + kfree(inf); + break; + case RKMODULE_GET_HDR_CFG: + hdr = kzalloc(sizeof(*hdr), GFP_KERNEL); + if (!hdr) { + ret = -ENOMEM; + return ret; + } + + ret = sc5336_ioctl(sd, cmd, hdr); + if (!ret) { + if (copy_to_user(up, hdr, sizeof(*hdr))) + ret = -EFAULT; + } + kfree(hdr); + break; + case RKMODULE_SET_HDR_CFG: + hdr = kzalloc(sizeof(*hdr), GFP_KERNEL); + if (!hdr) { + ret = -ENOMEM; + return ret; + } + + ret = copy_from_user(hdr, up, sizeof(*hdr)); + if (!ret) + ret = sc5336_ioctl(sd, cmd, hdr); + else + ret = -EFAULT; + kfree(hdr); + break; + case PREISP_CMD_SET_HDRAE_EXP: + hdrae = kzalloc(sizeof(*hdrae), GFP_KERNEL); + if (!hdrae) { + ret = -ENOMEM; + return ret; + } + + ret = copy_from_user(hdrae, up, sizeof(*hdrae)); + if (!ret) + ret = sc5336_ioctl(sd, cmd, hdrae); + else + ret = -EFAULT; + kfree(hdrae); + break; + case RKMODULE_SET_QUICK_STREAM: + ret = copy_from_user(&stream, up, sizeof(u32)); + if (!ret) + ret = sc5336_ioctl(sd, cmd, &stream); + else + ret = -EFAULT; + break; + default: + ret = -ENOIOCTLCMD; + break; + } + + return ret; +} +#endif + +static int __sc5336_start_stream(struct sc5336 *sc5336) +{ + int ret; + + if (!sc5336->is_thunderboot) { + ret = sc5336_write_array(sc5336->client, sc5336->cur_mode->reg_list); + if (ret) + return ret; + + /* In case these controls are set before streaming */ + ret = __v4l2_ctrl_handler_setup(&sc5336->ctrl_handler); + if (ret) + return ret; + } + + return sc5336_write_reg(sc5336->client, SC5336_REG_CTRL_MODE, + SC5336_REG_VALUE_08BIT, SC5336_MODE_STREAMING); +} + +static int __sc5336_stop_stream(struct sc5336 *sc5336) +{ + if (sc5336->is_thunderboot) { + sc5336->is_first_streamoff = true; + pm_runtime_put(&sc5336->client->dev); + } + return sc5336_write_reg(sc5336->client, SC5336_REG_CTRL_MODE, + SC5336_REG_VALUE_08BIT, SC5336_MODE_SW_STANDBY); +} + +static int __sc5336_power_on(struct sc5336 *sc5336); +static int sc5336_s_stream(struct v4l2_subdev *sd, int on) +{ + struct sc5336 *sc5336 = to_sc5336(sd); + struct i2c_client *client = sc5336->client; + int ret = 0; + + mutex_lock(&sc5336->mutex); + on = !!on; + if (on == sc5336->streaming) + goto unlock_and_return; + + if (on) { + if (sc5336->is_thunderboot && rkisp_tb_get_state() == RKISP_TB_NG) { + sc5336->is_thunderboot = false; + __sc5336_power_on(sc5336); + } + + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) { + pm_runtime_put_noidle(&client->dev); + goto unlock_and_return; + } + + ret = __sc5336_start_stream(sc5336); + if (ret) { + v4l2_err(sd, "start stream failed while write regs\n"); + pm_runtime_put(&client->dev); + goto unlock_and_return; + } + } else { + __sc5336_stop_stream(sc5336); + pm_runtime_put(&client->dev); + } + + sc5336->streaming = on; + +unlock_and_return: + mutex_unlock(&sc5336->mutex); + + return ret; +} + +static int sc5336_s_power(struct v4l2_subdev *sd, int on) +{ + struct sc5336 *sc5336 = to_sc5336(sd); + struct i2c_client *client = sc5336->client; + int ret = 0; + + mutex_lock(&sc5336->mutex); + + /* If the power state is not modified - no work to do. */ + if (sc5336->power_on == !!on) + goto unlock_and_return; + + if (on) { + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) { + pm_runtime_put_noidle(&client->dev); + goto unlock_and_return; + } + + if (!sc5336->is_thunderboot) { + ret = sc5336_write_array(sc5336->client, sc5336_global_regs); + if (ret) { + v4l2_err(sd, "could not set init registers\n"); + pm_runtime_put_noidle(&client->dev); + goto unlock_and_return; + } + } + + sc5336->power_on = true; + } else { + pm_runtime_put(&client->dev); + sc5336->power_on = false; + } + +unlock_and_return: + mutex_unlock(&sc5336->mutex); + + return ret; +} + +/* Calculate the delay in us by clock rate and clock cycles */ +static inline u32 sc5336_cal_delay(u32 cycles) +{ + return DIV_ROUND_UP(cycles, SC5336_XVCLK_FREQ / 1000 / 1000); +} + +static int __sc5336_power_on(struct sc5336 *sc5336) +{ + int ret; + u32 delay_us; + struct device *dev = &sc5336->client->dev; + + if (!IS_ERR_OR_NULL(sc5336->pins_default)) { + ret = pinctrl_select_state(sc5336->pinctrl, + sc5336->pins_default); + if (ret < 0) + dev_err(dev, "could not set pins\n"); + } + ret = clk_set_rate(sc5336->xvclk, SC5336_XVCLK_FREQ); + if (ret < 0) + dev_warn(dev, "Failed to set xvclk rate (24MHz)\n"); + if (clk_get_rate(sc5336->xvclk) != SC5336_XVCLK_FREQ) + dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n"); + ret = clk_prepare_enable(sc5336->xvclk); + if (ret < 0) { + dev_err(dev, "Failed to enable xvclk\n"); + return ret; + } + if (sc5336->is_thunderboot) + return 0; + + if (!IS_ERR(sc5336->reset_gpio)) + gpiod_set_value_cansleep(sc5336->reset_gpio, 0); + + ret = regulator_bulk_enable(SC5336_NUM_SUPPLIES, sc5336->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators\n"); + goto disable_clk; + } + + if (!IS_ERR(sc5336->reset_gpio)) + gpiod_set_value_cansleep(sc5336->reset_gpio, 1); + + usleep_range(500, 1000); + if (!IS_ERR(sc5336->pwdn_gpio)) + gpiod_set_value_cansleep(sc5336->pwdn_gpio, 1); + + if (!IS_ERR(sc5336->reset_gpio)) + usleep_range(6000, 8000); + else + usleep_range(12000, 16000); + + /* 8192 cycles prior to first SCCB transaction */ + delay_us = sc5336_cal_delay(8192); + usleep_range(delay_us, delay_us * 2); + + return 0; + +disable_clk: + clk_disable_unprepare(sc5336->xvclk); + + return ret; +} + +static void __sc5336_power_off(struct sc5336 *sc5336) +{ + int ret; + struct device *dev = &sc5336->client->dev; + + clk_disable_unprepare(sc5336->xvclk); + if (sc5336->is_thunderboot) { + if (sc5336->is_first_streamoff) { + sc5336->is_thunderboot = false; + sc5336->is_first_streamoff = false; + } else { + return; + } + } + + if (!IS_ERR(sc5336->pwdn_gpio)) + gpiod_set_value_cansleep(sc5336->pwdn_gpio, 0); + if (!IS_ERR(sc5336->reset_gpio)) + gpiod_set_value_cansleep(sc5336->reset_gpio, 0); + if (!IS_ERR_OR_NULL(sc5336->pins_sleep)) { + ret = pinctrl_select_state(sc5336->pinctrl, + sc5336->pins_sleep); + if (ret < 0) + dev_dbg(dev, "could not set pins\n"); + } + regulator_bulk_disable(SC5336_NUM_SUPPLIES, sc5336->supplies); +} + +static int sc5336_runtime_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct sc5336 *sc5336 = to_sc5336(sd); + + return __sc5336_power_on(sc5336); +} + +static int sc5336_runtime_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct sc5336 *sc5336 = to_sc5336(sd); + + __sc5336_power_off(sc5336); + + return 0; +} + +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API +static int sc5336_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct sc5336 *sc5336 = to_sc5336(sd); + struct v4l2_mbus_framefmt *try_fmt = + v4l2_subdev_get_try_format(sd, fh->pad, 0); + const struct sc5336_mode *def_mode = &supported_modes[0]; + + mutex_lock(&sc5336->mutex); + /* Initialize try_fmt */ + try_fmt->width = def_mode->width; + try_fmt->height = def_mode->height; + try_fmt->code = def_mode->bus_fmt; + try_fmt->field = V4L2_FIELD_NONE; + + mutex_unlock(&sc5336->mutex); + /* No crop or compose */ + + return 0; +} +#endif + +static int sc5336_enum_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_interval_enum *fie) +{ + if (fie->index >= ARRAY_SIZE(supported_modes)) + 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; + return 0; +} + +static const struct dev_pm_ops sc5336_pm_ops = { + SET_RUNTIME_PM_OPS(sc5336_runtime_suspend, + sc5336_runtime_resume, NULL) +}; + +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API +static const struct v4l2_subdev_internal_ops sc5336_internal_ops = { + .open = sc5336_open, +}; +#endif + +static const struct v4l2_subdev_core_ops sc5336_core_ops = { + .s_power = sc5336_s_power, + .ioctl = sc5336_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = sc5336_compat_ioctl32, +#endif +}; + +static const struct v4l2_subdev_video_ops sc5336_video_ops = { + .s_stream = sc5336_s_stream, + .g_frame_interval = sc5336_g_frame_interval, +}; + +static const struct v4l2_subdev_pad_ops sc5336_pad_ops = { + .enum_mbus_code = sc5336_enum_mbus_code, + .enum_frame_size = sc5336_enum_frame_sizes, + .enum_frame_interval = sc5336_enum_frame_interval, + .get_fmt = sc5336_get_fmt, + .set_fmt = sc5336_set_fmt, + .get_mbus_config = sc5336_g_mbus_config, +}; + +static const struct v4l2_subdev_ops sc5336_subdev_ops = { + .core = &sc5336_core_ops, + .video = &sc5336_video_ops, + .pad = &sc5336_pad_ops, +}; + +static void sc5336_modify_fps_info(struct sc5336 *sc5336) +{ + const struct sc5336_mode *mode = sc5336->cur_mode; + + sc5336->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / + sc5336->cur_vts; +} + +static int sc5336_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct sc5336 *sc5336 = container_of(ctrl->handler, + struct sc5336, ctrl_handler); + struct i2c_client *client = sc5336->client; + s64 max; + int ret = 0; + u32 val = 0; + + /* Propagate change of current control to all related controls */ + switch (ctrl->id) { + case V4L2_CID_VBLANK: + /* Update max exposure while meeting expected vblanking */ + max = sc5336->cur_mode->height + ctrl->val - 8; + __v4l2_ctrl_modify_range(sc5336->exposure, + sc5336->exposure->minimum, max, + sc5336->exposure->step, + sc5336->exposure->default_value); + break; + } + + if (!pm_runtime_get_if_in_use(&client->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + dev_dbg(&client->dev, "set exposure 0x%x\n", ctrl->val); + if (sc5336->cur_mode->hdr_mode == NO_HDR) { + val = ctrl->val; + /* 4 least significant bits of expsoure are fractional part */ + ret = sc5336_write_reg(sc5336->client, + SC5336_REG_EXPOSURE_H, + SC5336_REG_VALUE_08BIT, + SC5336_FETCH_EXP_H(val)); + ret |= sc5336_write_reg(sc5336->client, + SC5336_REG_EXPOSURE_M, + SC5336_REG_VALUE_08BIT, + SC5336_FETCH_EXP_M(val)); + ret |= sc5336_write_reg(sc5336->client, + SC5336_REG_EXPOSURE_L, + SC5336_REG_VALUE_08BIT, + SC5336_FETCH_EXP_L(val)); + } + break; + case V4L2_CID_ANALOGUE_GAIN: + dev_dbg(&client->dev, "set gain 0x%x\n", ctrl->val); + if (sc5336->cur_mode->hdr_mode == NO_HDR) + ret = sc5336_set_gain_reg(sc5336, ctrl->val); + break; + case V4L2_CID_VBLANK: + dev_dbg(&client->dev, "set vblank 0x%x\n", ctrl->val); + ret = sc5336_write_reg(sc5336->client, + SC5336_REG_VTS_H, + SC5336_REG_VALUE_08BIT, + (ctrl->val + sc5336->cur_mode->height) + >> 8); + ret |= sc5336_write_reg(sc5336->client, + SC5336_REG_VTS_L, + SC5336_REG_VALUE_08BIT, + (ctrl->val + sc5336->cur_mode->height) + & 0xff); + sc5336->cur_vts = ctrl->val + sc5336->cur_mode->height; + if (sc5336->cur_vts != sc5336->cur_mode->vts_def) + sc5336_modify_fps_info(sc5336); + break; + case V4L2_CID_TEST_PATTERN: + ret = sc5336_enable_test_pattern(sc5336, ctrl->val); + break; + case V4L2_CID_HFLIP: + ret = sc5336_read_reg(sc5336->client, SC5336_FLIP_MIRROR_REG, + SC5336_REG_VALUE_08BIT, &val); + ret |= sc5336_write_reg(sc5336->client, SC5336_FLIP_MIRROR_REG, + SC5336_REG_VALUE_08BIT, + SC5336_FETCH_MIRROR(val, ctrl->val)); + break; + case V4L2_CID_VFLIP: + ret = sc5336_read_reg(sc5336->client, SC5336_FLIP_MIRROR_REG, + SC5336_REG_VALUE_08BIT, &val); + ret |= sc5336_write_reg(sc5336->client, SC5336_FLIP_MIRROR_REG, + SC5336_REG_VALUE_08BIT, + SC5336_FETCH_FLIP(val, ctrl->val)); + break; + default: + dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n", + __func__, ctrl->id, ctrl->val); + break; + } + + pm_runtime_put(&client->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops sc5336_ctrl_ops = { + .s_ctrl = sc5336_set_ctrl, +}; + +static int sc5336_initialize_controls(struct sc5336 *sc5336) +{ + const struct sc5336_mode *mode; + struct v4l2_ctrl_handler *handler; + struct v4l2_ctrl *ctrl; + s64 exposure_max, vblank_def; + u32 h_blank; + int ret; + + handler = &sc5336->ctrl_handler; + mode = sc5336->cur_mode; + ret = v4l2_ctrl_handler_init(handler, 9); + if (ret) + return ret; + handler->lock = &sc5336->mutex; + + ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ, + 0, 0, link_freq_menu_items); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, + 0, PIXEL_RATE_WITH_315M_10BIT, 1, PIXEL_RATE_WITH_315M_10BIT); + + h_blank = mode->hts_def - mode->width; + sc5336->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK, + h_blank, h_blank, 1, h_blank); + if (sc5336->hblank) + sc5336->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + vblank_def = mode->vts_def - mode->height; + sc5336->vblank = v4l2_ctrl_new_std(handler, &sc5336_ctrl_ops, + V4L2_CID_VBLANK, vblank_def, + SC5336_VTS_MAX - mode->height, + 1, vblank_def); + sc5336->cur_fps = mode->max_fps; + exposure_max = mode->vts_def - 8; + sc5336->exposure = v4l2_ctrl_new_std(handler, &sc5336_ctrl_ops, + V4L2_CID_EXPOSURE, SC5336_EXPOSURE_MIN, + exposure_max, SC5336_EXPOSURE_STEP, + mode->exp_def); + sc5336->anal_gain = v4l2_ctrl_new_std(handler, &sc5336_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, SC5336_GAIN_MIN, + SC5336_GAIN_MAX, SC5336_GAIN_STEP, + SC5336_GAIN_DEFAULT); + sc5336->test_pattern = v4l2_ctrl_new_std_menu_items(handler, + &sc5336_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(sc5336_test_pattern_menu) - 1, + 0, 0, sc5336_test_pattern_menu); + v4l2_ctrl_new_std(handler, &sc5336_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(handler, &sc5336_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + if (handler->error) { + ret = handler->error; + dev_err(&sc5336->client->dev, + "Failed to init controls(%d)\n", ret); + goto err_free_handler; + } + + sc5336->subdev.ctrl_handler = handler; + + return 0; + +err_free_handler: + v4l2_ctrl_handler_free(handler); + + return ret; +} + +static int sc5336_check_sensor_id(struct sc5336 *sc5336, + struct i2c_client *client) +{ + struct device *dev = &sc5336->client->dev; + u32 id = 0; + int ret; + + if (sc5336->is_thunderboot) { + dev_info(dev, "Enable thunderboot mode, skip sensor id check\n"); + return 0; + } + + ret = sc5336_read_reg(client, SC5336_REG_CHIP_ID, + SC5336_REG_VALUE_16BIT, &id); + if (id != CHIP_ID) { + dev_err(dev, "Unexpected sensor id(%06x), ret(%d)\n", id, ret); + return -ENODEV; + } + + dev_info(dev, "Detected OV%06x sensor\n", CHIP_ID); + + return 0; +} + +static int sc5336_configure_regulators(struct sc5336 *sc5336) +{ + unsigned int i; + + for (i = 0; i < SC5336_NUM_SUPPLIES; i++) + sc5336->supplies[i].supply = sc5336_supply_names[i]; + + return devm_regulator_bulk_get(&sc5336->client->dev, + SC5336_NUM_SUPPLIES, + sc5336->supplies); +} + +static int sc5336_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct device_node *node = dev->of_node; + struct sc5336 *sc5336; + struct v4l2_subdev *sd; + char facing[2]; + int ret; + + dev_info(dev, "driver version: %02x.%02x.%02x", + DRIVER_VERSION >> 16, + (DRIVER_VERSION & 0xff00) >> 8, + DRIVER_VERSION & 0x00ff); + + sc5336 = devm_kzalloc(dev, sizeof(*sc5336), GFP_KERNEL); + if (!sc5336) + return -ENOMEM; + + ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX, + &sc5336->module_index); + ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING, + &sc5336->module_facing); + ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME, + &sc5336->module_name); + ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME, + &sc5336->len_name); + if (ret) { + dev_err(dev, "could not get module information!\n"); + return -EINVAL; + } + + sc5336->is_thunderboot = IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP); + sc5336->client = client; + sc5336->cur_mode = &supported_modes[0]; + + sc5336->xvclk = devm_clk_get(dev, "xvclk"); + if (IS_ERR(sc5336->xvclk)) { + dev_err(dev, "Failed to get xvclk\n"); + return -EINVAL; + } + + if (sc5336->is_thunderboot) { + sc5336->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS); + if (IS_ERR(sc5336->reset_gpio)) + dev_warn(dev, "Failed to get reset-gpios\n"); + + sc5336->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_ASIS); + if (IS_ERR(sc5336->pwdn_gpio)) + dev_warn(dev, "Failed to get pwdn-gpios\n"); + } else { + sc5336->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(sc5336->reset_gpio)) + dev_warn(dev, "Failed to get reset-gpios\n"); + + sc5336->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW); + if (IS_ERR(sc5336->pwdn_gpio)) + dev_warn(dev, "Failed to get pwdn-gpios\n"); + } + sc5336->pinctrl = devm_pinctrl_get(dev); + if (!IS_ERR(sc5336->pinctrl)) { + sc5336->pins_default = + pinctrl_lookup_state(sc5336->pinctrl, + OF_CAMERA_PINCTRL_STATE_DEFAULT); + if (IS_ERR(sc5336->pins_default)) + dev_err(dev, "could not get default pinstate\n"); + + sc5336->pins_sleep = + pinctrl_lookup_state(sc5336->pinctrl, + OF_CAMERA_PINCTRL_STATE_SLEEP); + if (IS_ERR(sc5336->pins_sleep)) + dev_err(dev, "could not get sleep pinstate\n"); + } else { + dev_err(dev, "no pinctrl\n"); + } + + ret = sc5336_configure_regulators(sc5336); + if (ret) { + dev_err(dev, "Failed to get power regulators\n"); + return ret; + } + + mutex_init(&sc5336->mutex); + + sd = &sc5336->subdev; + v4l2_i2c_subdev_init(sd, client, &sc5336_subdev_ops); + ret = sc5336_initialize_controls(sc5336); + if (ret) + goto err_destroy_mutex; + + ret = __sc5336_power_on(sc5336); + if (ret) + goto err_free_handler; + + ret = sc5336_check_sensor_id(sc5336, client); + if (ret) + goto err_power_off; + +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + sd->internal_ops = &sc5336_internal_ops; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | + V4L2_SUBDEV_FL_HAS_EVENTS; +#endif +#if defined(CONFIG_MEDIA_CONTROLLER) + sc5336->pad.flags = MEDIA_PAD_FL_SOURCE; + sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&sd->entity, 1, &sc5336->pad); + if (ret < 0) + goto err_power_off; +#endif + + memset(facing, 0, sizeof(facing)); + if (strcmp(sc5336->module_facing, "back") == 0) + facing[0] = 'b'; + else + facing[0] = 'f'; + + snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s", + sc5336->module_index, facing, + SC5336_NAME, dev_name(sd->dev)); + ret = v4l2_async_register_subdev_sensor_common(sd); + if (ret) { + dev_err(dev, "v4l2 async register subdev failed\n"); + goto err_clean_entity; + } + + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + if (sc5336->is_thunderboot) + pm_runtime_get_sync(dev); + else + pm_runtime_idle(dev); + + return 0; + +err_clean_entity: +#if defined(CONFIG_MEDIA_CONTROLLER) + media_entity_cleanup(&sd->entity); +#endif +err_power_off: + __sc5336_power_off(sc5336); +err_free_handler: + v4l2_ctrl_handler_free(&sc5336->ctrl_handler); +err_destroy_mutex: + mutex_destroy(&sc5336->mutex); + + return ret; +} + +static int sc5336_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct sc5336 *sc5336 = to_sc5336(sd); + + v4l2_async_unregister_subdev(sd); +#if defined(CONFIG_MEDIA_CONTROLLER) + media_entity_cleanup(&sd->entity); +#endif + v4l2_ctrl_handler_free(&sc5336->ctrl_handler); + mutex_destroy(&sc5336->mutex); + + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + __sc5336_power_off(sc5336); + pm_runtime_set_suspended(&client->dev); + + return 0; +} + +#if IS_ENABLED(CONFIG_OF) +static const struct of_device_id sc5336_of_match[] = { + { .compatible = "smartsens,sc5336" }, + {}, +}; +MODULE_DEVICE_TABLE(of, sc5336_of_match); +#endif + +static const struct i2c_device_id sc5336_match_id[] = { + { "smartsens,sc5336", 0 }, + { }, +}; + +static struct i2c_driver sc5336_i2c_driver = { + .driver = { + .name = SC5336_NAME, + .pm = &sc5336_pm_ops, + .of_match_table = of_match_ptr(sc5336_of_match), + }, + .probe = &sc5336_probe, + .remove = &sc5336_remove, + .id_table = sc5336_match_id, +}; + +static int __init sensor_mod_init(void) +{ + return i2c_add_driver(&sc5336_i2c_driver); +} + +static void __exit sensor_mod_exit(void) +{ + i2c_del_driver(&sc5336_i2c_driver); +} + +#if defined(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP) && !defined(CONFIG_INITCALL_ASYNC) +subsys_initcall(sensor_mod_init); +#else +device_initcall_sync(sensor_mod_init); +#endif +module_exit(sensor_mod_exit); + +MODULE_DESCRIPTION("smartsens sc5336 sensor driver"); +MODULE_LICENSE("GPL"); From 5d2e8c3cf9ee22d491b7a01e1d7fa14826f2c608 Mon Sep 17 00:00:00 2001 From: Wang Panzhenzhuan Date: Thu, 29 Jun 2023 09:24:17 +0800 Subject: [PATCH 003/133] video: rockchip: vehicle: cif use workqueue to print mipi err if too many mipi err print in irq, it cause system stuck, so use workqueue to print mipi err to fix it. Signed-off-by: Wang Panzhenzhuan Change-Id: I8bf29f3dc17c1e1b722fad6b2b3841db71e17dca --- drivers/video/rockchip/vehicle/vehicle_cif.c | 143 +++++++++++++++---- drivers/video/rockchip/vehicle/vehicle_cif.h | 10 ++ 2 files changed, 122 insertions(+), 31 deletions(-) diff --git a/drivers/video/rockchip/vehicle/vehicle_cif.c b/drivers/video/rockchip/vehicle/vehicle_cif.c index 904cd206116b..8a4142070a5b 100644 --- a/drivers/video/rockchip/vehicle/vehicle_cif.c +++ b/drivers/video/rockchip/vehicle/vehicle_cif.c @@ -4488,6 +4488,37 @@ IRQ_EXIT: return IRQ_HANDLED; } +#define vehicle_csi2_err_strncat(dst_str, src_str) {\ + if (strlen(dst_str) + strlen(src_str) < CSI_ERRSTR_LEN)\ + strncat(dst_str, src_str, strlen(src_str)); } + +static void vehicle_csi2_find_err_vc(int val, char *vc_info) +{ + int i; + char cur_str[CSI_VCINFO_LEN] = {0}; + + memset(vc_info, 0, sizeof(*vc_info)); + for (i = 0; i < 4; i++) { + if ((val >> i) & 0x1) { + snprintf(cur_str, CSI_VCINFO_LEN, " %d", i); + if (strlen(vc_info) + strlen(cur_str) < CSI_VCINFO_LEN) + strncat(vc_info, cur_str, strlen(cur_str)); + } + } +} + +static void vehicle_csi2_err_print_work(struct work_struct *work) +{ + struct vehicle_csi2_err_state_work *err_state = container_of(work, + struct vehicle_csi2_err_state_work, + work); + + pr_err("mipi_csi2: ERR%d:0x%x %s\n", err_state->err_num, + err_state->err_val, err_state->err_str); + if (err_state->err_num == 1) + pr_info("mipi_csi2: err_stat:0x%x\n", err_state->err_stat); +} + static irqreturn_t vehicle_csirx_irq1(int irq, void *data) { struct vehicle_cif *cif = (struct vehicle_cif *)data; @@ -4495,6 +4526,9 @@ static irqreturn_t vehicle_csirx_irq1(int irq, void *data) struct csi2_err_stats *err_list = NULL; unsigned long err_stat = 0; u32 val; + char err_str[CSI_ERRSTR_LEN] = {0}; + char cur_str[CSI_ERRSTR_LEN] = {0}; + char vc_info[CSI_VCINFO_LEN] = {0}; val = read_reg(hw->csi2_base, CSIHOST_ERR1); if (val) { @@ -4504,53 +4538,69 @@ static irqreturn_t vehicle_csirx_irq1(int irq, void *data) if (val & CSIHOST_ERR1_PHYERR_SPTSYNCHS) { err_list = &hw->err_list[RK_CSI2_ERR_SOTSYN]; err_list->cnt++; - VEHICLE_DGERR( - "ERR1: start of transmission error, reg: 0x%x,cnt:%d\n", - val, err_list->cnt); + + vehicle_csi2_find_err_vc(val & 0xf, vc_info); + snprintf(cur_str, CSI_ERRSTR_LEN, "(sot sync,lane:%s) ", vc_info); + vehicle_csi2_err_strncat(err_str, cur_str); } if (val & CSIHOST_ERR1_ERR_BNDRY_MATCH) { err_list = &hw->err_list[RK_CSI2_ERR_FS_FE_MIS]; err_list->cnt++; - VEHICLE_DGERR( - "ERR1: error matching frame start with frame end, reg: 0x%x,cnt:%d\n", - val, err_list->cnt); + vehicle_csi2_find_err_vc((val >> 4) & 0xf, vc_info); + snprintf(cur_str, CSI_ERRSTR_LEN, "(fs/fe miss,vc:%s) ", vc_info); + vehicle_csi2_err_strncat(err_str, cur_str); + } if (val & CSIHOST_ERR1_ERR_SEQ) { err_list = &hw->err_list[RK_CSI2_ERR_FRM_SEQ_ERR]; err_list->cnt++; - VEHICLE_DGERR("ERR1: incorrect frame sequence detected, reg: 0x%x,cnt:%d\n", - val, err_list->cnt); + vehicle_csi2_find_err_vc((val >> 8) & 0xf, vc_info); + snprintf(cur_str, CSI_ERRSTR_LEN, "(f_seq,vc:%s) ", vc_info); + vehicle_csi2_err_strncat(err_str, cur_str); + } if (val & CSIHOST_ERR1_ERR_FRM_DATA) { err_list = &hw->err_list[RK_CSI2_ERR_CRC_ONCE]; err_list->cnt++; - VEHICLE_DGERR("ERR1: at least one crc error, reg: 0x%x\n,cnt:%d", - val, err_list->cnt); + vehicle_csi2_find_err_vc((val >> 12) & 0xf, vc_info); + snprintf(cur_str, CSI_ERRSTR_LEN, "(err_data,vc:%s) ", vc_info); + vehicle_csi2_err_strncat(err_str, cur_str); + } if (val & CSIHOST_ERR1_ERR_CRC) { err_list = &hw->err_list[RK_CSI2_ERR_CRC]; err_list->cnt++; - VEHICLE_DGERR("ERR1: crc errors, reg: 0x%x, cnt:%d\n", - val, err_list->cnt); + vehicle_csi2_find_err_vc((val >> 24) & 0xf, vc_info); + snprintf(cur_str, CSI_ERRSTR_LEN, "(crc,vc:%s) ", vc_info); + vehicle_csi2_err_strncat(err_str, cur_str); + } if (val & CSIHOST_ERR1_ERR_ECC2) { err_list = &hw->err_list[RK_CSI2_ERR_CRC]; err_list->cnt++; - VEHICLE_DGERR("ERR1: ecc errors, reg: 0x%x, cnt:%d\n", - val, err_list->cnt); - } - if (val & CSIHOST_ERR1_ERR_CTRL) - VEHICLE_DGERR("ERR1: ctrl errors, reg: 0x%x\n", val); + snprintf(cur_str, CSI_ERRSTR_LEN, "(ecc2) "); + vehicle_csi2_err_strncat(err_str, cur_str); + } + if (val & CSIHOST_ERR1_ERR_CTRL) { + vehicle_csi2_find_err_vc((val >> 16) & 0xf, vc_info); + snprintf(cur_str, CSI_ERRSTR_LEN, "(ctrl,vc:%s) ", vc_info); + vehicle_csi2_err_strncat(err_str, cur_str); + } hw->err_list[RK_CSI2_ERR_ALL].cnt++; err_stat = ((hw->err_list[RK_CSI2_ERR_FS_FE_MIS].cnt & 0xff) << 8) | ((hw->err_list[RK_CSI2_ERR_ALL].cnt) & 0xff); - VEHICLE_INFO("%s: err_stat: %x\n", err_stat); + + cif->err_state.err_val = val; + cif->err_state.err_num = 1; + cif->err_state.err_stat = err_stat; + strscpy(cif->err_state.err_str, err_str, CSI_ERRSTR_LEN); + queue_work(cif->err_state.err_print_wq, &cif->err_state.work); } @@ -4562,22 +4612,41 @@ static irqreturn_t vehicle_csirx_irq2(int irq, void *data) struct vehicle_cif *cif = (struct vehicle_cif *)data; struct csi2_dphy_hw *hw = cif->dphy_hw; u32 val; + char cur_str[CSI_ERRSTR_LEN] = {0}; + char err_str[CSI_ERRSTR_LEN] = {0}; + char vc_info[CSI_VCINFO_LEN] = {0}; val = read_reg(hw->csi2_base, CSIHOST_ERR2); if (val) { - if (val & CSIHOST_ERR2_PHYERR_ESC) - VEHICLE_DGERR("ERR2: escape entry error(ULPM), reg: 0x%x\n", val); - if (val & CSIHOST_ERR2_PHYERR_SOTHS) - VEHICLE_DGERR( - "ERR2: start of transmission error, reg: 0x%x\n", val); - if (val & CSIHOST_ERR2_ECC_CORRECTED) - VEHICLE_DGERR( - "ERR2: header error detected and corrected, reg: 0x%x\n", val); - if (val & CSIHOST_ERR2_ERR_ID) - VEHICLE_DGERR( - "ERR2: unrecognized data type detected, reg: 0x%x\n", val); - if (val & CSIHOST_ERR2_PHYERR_CODEHS) - VEHICLE_DGERR("ERR2: receive error code, reg: 0x%x\n", val); + if (val & CSIHOST_ERR2_PHYERR_ESC) { + vehicle_csi2_find_err_vc(val & 0xf, vc_info); + snprintf(cur_str, CSI_ERRSTR_LEN, "(ULPM,lane:%s) ", vc_info); + vehicle_csi2_err_strncat(err_str, cur_str); + } + if (val & CSIHOST_ERR2_PHYERR_SOTHS) { + vehicle_csi2_find_err_vc((val >> 4) & 0xf, vc_info); + snprintf(cur_str, CSI_ERRSTR_LEN, "(sot,lane:%s) ", vc_info); + vehicle_csi2_err_strncat(err_str, cur_str); + } + if (val & CSIHOST_ERR2_ECC_CORRECTED) { + vehicle_csi2_find_err_vc((val >> 8) & 0xf, vc_info); + snprintf(cur_str, CSI_ERRSTR_LEN, "(ecc,vc:%s) ", vc_info); + vehicle_csi2_err_strncat(err_str, cur_str); + } + if (val & CSIHOST_ERR2_ERR_ID) { + vehicle_csi2_find_err_vc((val >> 12) & 0xf, vc_info); + snprintf(cur_str, CSI_ERRSTR_LEN, "(err id,vc:%s) ", vc_info); + vehicle_csi2_err_strncat(err_str, cur_str); + } + if (val & CSIHOST_ERR2_PHYERR_CODEHS) { + snprintf(cur_str, CSI_ERRSTR_LEN, "(err code) "); + vehicle_csi2_err_strncat(err_str, cur_str); + } + cif->err_state.err_val = val; + cif->err_state.err_num = 2; + strscpy(cif->err_state.err_str, err_str, CSI_ERRSTR_LEN); + queue_work(cif->err_state.err_print_wq, &cif->err_state.work); + } return IRQ_HANDLED; @@ -4696,6 +4765,7 @@ int vehicle_cif_reverse_close(void) cif->stopping = true; cancel_delayed_work_sync(&(cif->work)); flush_delayed_work(&(cif->work)); + cancel_work_sync(&cif->err_state.work); ret = wait_event_timeout(cif->wq_stopped, cif->state != RKCIF_STATE_STREAMING, @@ -5176,6 +5246,13 @@ int vehicle_cif_init(struct vehicle_cif *cif) spin_lock_init(&cif->vbq_lock); + INIT_WORK(&cif->err_state.work, vehicle_csi2_err_print_work); + cif->err_state.err_print_wq = create_workqueue("cis2_err_print_queue"); + if (cif->err_state.err_print_wq == NULL) { + dev_err(dev, "%s: %s create failed.\n", __func__, + "csi2_err_print_wq"); + } + return 0; } @@ -5246,6 +5323,10 @@ int vehicle_cif_deinit(struct vehicle_cif *cif) free_irq(cif->csi2_irq1, cif); free_irq(cif->csi2_irq2, cif); } + if (cif->err_state.err_print_wq) { + flush_workqueue(cif->err_state.err_print_wq); + destroy_workqueue(cif->err_state.err_print_wq); + } return 0; } diff --git a/drivers/video/rockchip/vehicle/vehicle_cif.h b/drivers/video/rockchip/vehicle/vehicle_cif.h index e5ab1916241d..3c75694acd89 100644 --- a/drivers/video/rockchip/vehicle/vehicle_cif.h +++ b/drivers/video/rockchip/vehicle/vehicle_cif.h @@ -92,6 +92,15 @@ struct vehicle_csi_channel_info { unsigned int crop_st_y; }; +struct vehicle_csi2_err_state_work { + struct workqueue_struct *err_print_wq; + struct work_struct work; + char err_str[CSI_ERRSTR_LEN]; + u32 err_val; + u32 err_num; + unsigned long err_stat; +}; + struct vehicle_cif { struct device *dev; struct device_node *phy_node; @@ -137,6 +146,7 @@ struct vehicle_cif { bool stopping; struct mutex stream_lock; enum rkcif_state state; + struct vehicle_csi2_err_state_work err_state; }; int vehicle_cif_init_mclk(struct vehicle_cif *cif); From a365675d53eada3af6334f08e6a15a352d09f18c Mon Sep 17 00:00:00 2001 From: Wang Panzhenzhuan Date: Wed, 12 Jul 2023 08:19:26 +0000 Subject: [PATCH 004/133] video: rockchip: vehicle support drop vop show frames sample usage: cif_sensor: cif_sensor { nvp6324 { ... drop_frames = <4>; //frames to drop ... }; }; Signed-off-by: Wang Panzhenzhuan Change-Id: I7c7ad473471e2b90ab32600a3d7a31511870307d --- drivers/video/rockchip/vehicle/vehicle_ad.h | 1 + drivers/video/rockchip/vehicle/vehicle_ad_nvp6324.c | 1 + drivers/video/rockchip/vehicle/vehicle_cfg.h | 1 + drivers/video/rockchip/vehicle/vehicle_flinger.c | 8 ++++++++ drivers/video/rockchip/vehicle/vehicle_generic_sensor.c | 6 ++++++ 5 files changed, 17 insertions(+) diff --git a/drivers/video/rockchip/vehicle/vehicle_ad.h b/drivers/video/rockchip/vehicle/vehicle_ad.h index 66d156f9e778..a83233b791e0 100644 --- a/drivers/video/rockchip/vehicle/vehicle_ad.h +++ b/drivers/video/rockchip/vehicle/vehicle_ad.h @@ -63,6 +63,7 @@ struct vehicle_ad_dev { u32 channel_reso[PAD_MAX]; u8 detect_status; u8 last_detect_status; + int drop_frames; }; int vehicle_generic_sensor_write(struct vehicle_ad_dev *ad, char reg, char *pval); diff --git a/drivers/video/rockchip/vehicle/vehicle_ad_nvp6324.c b/drivers/video/rockchip/vehicle/vehicle_ad_nvp6324.c index 3f5115fd097c..af9274dd35e7 100644 --- a/drivers/video/rockchip/vehicle/vehicle_ad_nvp6324.c +++ b/drivers/video/rockchip/vehicle/vehicle_ad_nvp6324.c @@ -1950,6 +1950,7 @@ int nvp6324_ad_get_cfg(struct vehicle_cfg **cfg) } nvp6324_g_addev->cfg.ad_ready = true; + nvp6324_g_addev->cfg.drop_frames = nvp6324_g_addev->drop_frames; *cfg = &nvp6324_g_addev->cfg; diff --git a/drivers/video/rockchip/vehicle/vehicle_cfg.h b/drivers/video/rockchip/vehicle/vehicle_cfg.h index b03b6a80b9a3..96241b7b5128 100644 --- a/drivers/video/rockchip/vehicle/vehicle_cfg.h +++ b/drivers/video/rockchip/vehicle/vehicle_cfg.h @@ -139,6 +139,7 @@ struct vehicle_cfg { /*0:no, 1:90; 2:180; 4:270; 0x10:mirror-y; 0x20:mirror-x*/ int rotate_mirror; struct rkmodule_csi_dphy_param *dphy_param; + int drop_frames; }; #endif diff --git a/drivers/video/rockchip/vehicle/vehicle_flinger.c b/drivers/video/rockchip/vehicle/vehicle_flinger.c index ef5c605c4c4d..3aed9a87a7a6 100644 --- a/drivers/video/rockchip/vehicle/vehicle_flinger.c +++ b/drivers/video/rockchip/vehicle/vehicle_flinger.c @@ -1076,6 +1076,7 @@ static void rk_drm_vehicle_commit(struct flinger *flinger, struct graphic_buffer rockchip_drm_direct_show_commit(flinger->drm_dev, &commit_info); } +static int drop_frames_number; static int rk_flinger_vop_show(struct flinger *flinger, struct graphic_buffer *buffer) { @@ -1084,6 +1085,12 @@ static int rk_flinger_vop_show(struct flinger *flinger, VEHICLE_DG("flinger vop show buffer wxh(%zux%zu)\n", buffer->src.w, buffer->src.h); + if (drop_frames_number > 0) { + VEHICLE_INFO("%s discard the frame num(%d)!\n", __func__, drop_frames_number); + drop_frames_number--; + return 0; + } + if (!flinger->running) return 0; @@ -1444,6 +1451,7 @@ int vehicle_flinger_reverse_open(struct vehicle_cfg *v_cfg, flg->cvbs_field_count = 0; memcpy(&flg->v_cfg, v_cfg, sizeof(struct vehicle_cfg)); flg->running = true; + drop_frames_number = v_cfg->drop_frames; return 0; } diff --git a/drivers/video/rockchip/vehicle/vehicle_generic_sensor.c b/drivers/video/rockchip/vehicle/vehicle_generic_sensor.c index bafe0c8fd13b..ccb45fd01051 100644 --- a/drivers/video/rockchip/vehicle/vehicle_generic_sensor.c +++ b/drivers/video/rockchip/vehicle/vehicle_generic_sensor.c @@ -285,6 +285,12 @@ int vehicle_parse_sensor(struct vehicle_ad_dev *ad) if (of_property_read_u32(cp, "mclk_rate", &ad->mclk_rate)) VEHICLE_DGERR("Get %s mclk_rate failed!\n", cp->name); + if (of_property_read_u32(cp, "drop_frames", + &ad->drop_frames)) { + VEHICLE_DGERR("%s:Get sensor, drop-frames failed!\n", __func__); + ad->drop_frames = 0; //default drop frames; + } + if (of_property_read_u32(cp, "rst_active", &ad->rst_active)) VEHICLE_DGERR("Get %s rst_active failed!", cp->name); From ced3b6d069cce0fa2bd4e2706dc51570118a02c8 Mon Sep 17 00:00:00 2001 From: Wang Panzhenzhuan Date: Wed, 12 Jul 2023 09:04:46 +0000 Subject: [PATCH 005/133] video: rockchip: vehicle: flinger fix 720P & 1080P rotate blurred issue Original vop show required 64 pixel aligned for width, but now all resolution are scale to 1920x1080 or 1088x1920 for 90/270 degree rotation is 64 aligned; so rga blit is no needed to do 64 aligned limit, fix it. Signed-off-by: Wang Panzhenzhuan Change-Id: I42433009182d1f29372a0ebe4f7482f9b82a64f6 --- drivers/video/rockchip/vehicle/vehicle_flinger.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/video/rockchip/vehicle/vehicle_flinger.c b/drivers/video/rockchip/vehicle/vehicle_flinger.c index 3aed9a87a7a6..a2f48103dc8e 100644 --- a/drivers/video/rockchip/vehicle/vehicle_flinger.c +++ b/drivers/video/rockchip/vehicle/vehicle_flinger.c @@ -836,7 +836,7 @@ static int rk_flinger_rga_blit(struct flinger *flinger, rga_request.rotate_mode = 0; rga_request.sina = 0; rga_request.cosa = 0; - rga_request.dst.vir_w = ALIGN(ds, 64); + rga_request.dst.vir_w = ds; rga_request.dst.vir_h = dh; rga_request.dst.act_w = dw; rga_request.dst.act_h = dh; @@ -845,7 +845,7 @@ static int rk_flinger_rga_blit(struct flinger *flinger, break; case RGA_TRANSFORM_FLIP_H:/*x mirror*/ rga_request.rotate_mode = 2; - rga_request.dst.vir_w = ALIGN(ds, 64); + rga_request.dst.vir_w = ds; rga_request.dst.vir_h = dh; rga_request.dst.act_w = dw; rga_request.dst.act_h = dh; @@ -854,7 +854,7 @@ static int rk_flinger_rga_blit(struct flinger *flinger, break; case RGA_TRANSFORM_FLIP_V:/*y mirror*/ rga_request.rotate_mode = 3; - rga_request.dst.vir_w = ALIGN(ds, 64); + rga_request.dst.vir_w = ds; rga_request.dst.vir_h = dh; rga_request.dst.act_w = dw; rga_request.dst.act_h = dh; @@ -865,7 +865,7 @@ static int rk_flinger_rga_blit(struct flinger *flinger, rga_request.rotate_mode = 1; rga_request.sina = 65536; rga_request.cosa = 0; - rga_request.dst.vir_w = ALIGN(ds, 64); + rga_request.dst.vir_w = ds; rga_request.dst.vir_h = dh; rga_request.dst.act_w = dh; rga_request.dst.act_h = dw; @@ -876,7 +876,7 @@ static int rk_flinger_rga_blit(struct flinger *flinger, rga_request.rotate_mode = 1; rga_request.sina = 0; rga_request.cosa = -65536; - rga_request.dst.vir_w = ALIGN(ds, 64); + rga_request.dst.vir_w = ds; rga_request.dst.vir_h = dh; rga_request.dst.act_w = dw; rga_request.dst.act_h = dh; @@ -887,7 +887,7 @@ static int rk_flinger_rga_blit(struct flinger *flinger, rga_request.rotate_mode = 1; rga_request.sina = -65536; rga_request.cosa = 0; - rga_request.dst.vir_w = ALIGN(ds, 64); + rga_request.dst.vir_w = ds; rga_request.dst.vir_h = dh; rga_request.dst.act_w = dh; rga_request.dst.act_h = dw; @@ -898,7 +898,7 @@ static int rk_flinger_rga_blit(struct flinger *flinger, rga_request.rotate_mode = 0; rga_request.sina = 0; rga_request.cosa = 0; - rga_request.dst.vir_w = ALIGN(ds, 64); + rga_request.dst.vir_w = ds; rga_request.dst.vir_h = dh; rga_request.dst.act_w = dw; rga_request.dst.act_h = dh; From 4004a8990ce9078ccbae3ffd903ad02728eba461 Mon Sep 17 00:00:00 2001 From: Wang Panzhenzhuan Date: Wed, 12 Jul 2023 10:01:37 +0000 Subject: [PATCH 006/133] video: rockchip: vehicle: fix unexpected change when open set android ready when vehicle in open state, set android ready will close/open stream; cause preview stuck a moment, so fix it. Signed-off-by: Wang Panzhenzhuan Change-Id: I1734edb8de1f52434fa8e6a3a890453fbd51945e --- drivers/video/rockchip/vehicle/vehicle_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/video/rockchip/vehicle/vehicle_main.c b/drivers/video/rockchip/vehicle/vehicle_main.c index 46f947e8496e..8c98dd7aa4d6 100644 --- a/drivers/video/rockchip/vehicle/vehicle_main.c +++ b/drivers/video/rockchip/vehicle/vehicle_main.c @@ -171,7 +171,7 @@ static int vehicle_state_change(struct vehicle *v) gpio_reverse_on = vehicle_gpio_reverse_check(gpiod); gpio_reverse_on = TEST_GPIO & gpio_reverse_on; - VEHICLE_DG( + VEHICLE_INFO( "%s, gpio = reverse %s, width = %d, sensor_ready = %d, state=%d dvr_apk_need_start = %d\n", __func__, gpio_reverse_on ? "on" : "over", v_cfg->width, v_cfg->ad_ready, v->state, dvr_apk_need_start); @@ -201,7 +201,7 @@ static int vehicle_state_change(struct vehicle *v) vehicle_close(); vehicle_ad_stream(&v->ad, 0); v->state = STATE_CLOSE; - } else if (gpio_reverse_on) { // reverse on & video format change + } else if (gpio_reverse_on && !v->android_is_ready) { //video fmt change vehicle_open_close(); vehicle_open(v_cfg); msleep(100); @@ -244,7 +244,7 @@ static int vehicle_state_change(struct vehicle *v) vehicle_close(); vehicle_ad_stream(&v->ad, 0); v->state = STATE_CLOSE; - } else if (gpio_reverse_on) { // reverse on & video format change + } else if (gpio_reverse_on && !v->android_is_ready) { //video fmt change vehicle_open_close(); vehicle_ad_stream(&v->ad, 0); vehicle_ad_channel_set(&g_vehicle->ad, 0); @@ -287,7 +287,7 @@ static int vehicle_state_change(struct vehicle *v) vehicle_close(); vehicle_ad_stream(&v->ad, 0); v->state = STATE_CLOSE; - } else if (gpio_reverse_on) { // reverse on & video format change + } else if (gpio_reverse_on && !v->android_is_ready) { //video fmt change vehicle_open_close(); vehicle_ad_stream(&v->ad, 0); vehicle_ad_channel_set(&g_vehicle->ad, 0); From 89b5efc0915ac23b8d19669faf4a5e1e368ac111 Mon Sep 17 00:00:00 2001 From: Wang Panzhenzhuan Date: Thu, 13 Jul 2023 02:13:33 +0000 Subject: [PATCH 007/133] video: rockchip: vehicle: flinger fix rotate-mirror config be changed rk_flinger_first_done & vehicle_flinger_reverse_open may run at the same time, cause buffer rotate-mirror value changed; so fix it. Signed-off-by: Wang Panzhenzhuan Change-Id: Ie278d89d53386a91700961137f2a60a6a442c0e9 --- drivers/video/rockchip/vehicle/vehicle_flinger.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/video/rockchip/vehicle/vehicle_flinger.c b/drivers/video/rockchip/vehicle/vehicle_flinger.c index a2f48103dc8e..a40c33b53dd9 100644 --- a/drivers/video/rockchip/vehicle/vehicle_flinger.c +++ b/drivers/video/rockchip/vehicle/vehicle_flinger.c @@ -1169,9 +1169,11 @@ static void rk_flinger_first_done(struct work_struct *work) FORCE_XOFFSET, FORCE_YOFFSET, v_cfg->width, v_cfg->height, v_cfg->width, FORCE_FORMAT); - rk_flinger_set_buffer_rotation(buffer, FORCE_ROTATION); + rk_flinger_set_buffer_rotation(buffer, v_cfg->rotate_mirror); rk_flinger_cacultae_dst_rect_by_rotation(buffer); buffer->dst.f = buffer->src.f; + VEHICLE_INFO("buffer[%d]->rotation(%d).\n", + i, buffer->rotation); } } } From a22026c960eb2f2c0348c78420adbb1edc7f8deb Mon Sep 17 00:00:00 2001 From: Johnson Ding Date: Thu, 13 Jul 2023 18:33:08 +0800 Subject: [PATCH 008/133] video: rockchip: mpp: fix rk3328 h265d timeout issue Power save optimization may cause rkvdec timeout when decoding some HEVC bitstream. Signed-off-by: Johnson Ding Change-Id: I60c9e578e53a37dbe610b03912fc0007a782f960 --- drivers/video/rockchip/mpp/mpp_rkvdec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/rockchip/mpp/mpp_rkvdec.c b/drivers/video/rockchip/mpp/mpp_rkvdec.c index cad51ddc562b..1fcdbdc52902 100644 --- a/drivers/video/rockchip/mpp/mpp_rkvdec.c +++ b/drivers/video/rockchip/mpp/mpp_rkvdec.c @@ -953,11 +953,11 @@ static int rkvdec_3328_run(struct mpp_dev *mpp, task = to_rkvdec_task(mpp_task); /* - * HW defeat workaround: VP9 power save optimization cause decoding + * HW defeat workaround: VP9 and H.265 power save optimization cause decoding * corruption, disable optimization here. */ fmt = RKVDEC_GET_FORMAT(task->reg[RKVDEC_REG_SYS_CTRL_INDEX]); - if (fmt == RKVDEC_FMT_VP9D) { + if (fmt == RKVDEC_FMT_VP9D || fmt == RKVDEC_FMT_H265D) { cfg = task->reg[RKVDEC_POWER_CTL_INDEX] | 0xFFFF; task->reg[RKVDEC_POWER_CTL_INDEX] = cfg & (~(1 << 12)); mpp_write_relaxed(mpp, RKVDEC_POWER_CTL_BASE, From 5bde57f34fae289a887174d08391a605787feef9 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Thu, 13 Jul 2023 08:30:38 +0800 Subject: [PATCH 009/133] mmc: dw_mmc-rockchip: Disable PM runtime for SDIO devices Some SDIO devices need stable clock provided even after finishing data transfer. Signed-off-by: Shawn Lin Change-Id: I5f048e15b3cafb2d24b93dbd41892f2fb77f8df8 --- drivers/mmc/host/dw_mmc-rockchip.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index d87ceb85c3ac..69970381d0e7 100644 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -448,8 +448,10 @@ static int dw_mci_rockchip_probe(struct platform_device *pdev) if (!pdev->dev.of_node) return -ENODEV; - if (!device_property_read_bool(&pdev->dev, "non-removable") && - !device_property_read_bool(&pdev->dev, "cd-gpios")) + if ((!device_property_read_bool(&pdev->dev, "non-removable") && + !device_property_read_bool(&pdev->dev, "cd-gpios")) || + (device_property_read_bool(&pdev->dev, "no-sd") && + device_property_read_bool(&pdev->dev, "no-mmc"))) use_rpm = false; match = of_match_node(dw_mci_rockchip_match, pdev->dev.of_node); From cf933b81f8eda0374f4dc9b4f4934b5a973b61c5 Mon Sep 17 00:00:00 2001 From: Cai YiWei Date: Fri, 7 Jul 2023 19:01:18 +0800 Subject: [PATCH 010/133] media: rockchip: isp: distinguish buf done or subscribed event for param poll Change-Id: I9b366a9f47ce24783651c93512125dca7c49917f Signed-off-by: Cai YiWei --- drivers/media/platform/rockchip/isp/isp_params.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/rockchip/isp/isp_params.c b/drivers/media/platform/rockchip/isp/isp_params.c index 020ff5a4dd58..65f8525e536b 100644 --- a/drivers/media/platform/rockchip/isp/isp_params.c +++ b/drivers/media/platform/rockchip/isp/isp_params.c @@ -284,10 +284,21 @@ static int rkisp_params_fop_release(struct file *file) return ret; } +static __poll_t rkisp_params_fop_poll(struct file *file, poll_table *wait) +{ + struct video_device *vdev = video_devdata(file); + + /* buf done or subscribe event */ + if (vdev->queue->owner == file->private_data) + return vb2_fop_poll(file, wait); + else + return v4l2_ctrl_poll(file, wait); +} + struct v4l2_file_operations rkisp_params_fops = { .mmap = vb2_fop_mmap, .unlocked_ioctl = video_ioctl2, - .poll = vb2_fop_poll, + .poll = rkisp_params_fop_poll, .open = rkisp_params_fh_open, .release = rkisp_params_fop_release }; From efd29cb1487fe5b189f1a69e050690905ff6cbfe Mon Sep 17 00:00:00 2001 From: LongChang Ma Date: Mon, 26 Jun 2023 09:37:12 +0800 Subject: [PATCH 011/133] media: i2c: optimize gc2053 sync issue Signed-off-by: LongChang Ma Change-Id: Ibedcc39845d7a1e02fe4f5bcf6794b32a882e793 --- drivers/media/i2c/gc2053.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/gc2053.c b/drivers/media/i2c/gc2053.c index 7a93d864f217..8475b675c243 100644 --- a/drivers/media/i2c/gc2053.c +++ b/drivers/media/i2c/gc2053.c @@ -574,11 +574,13 @@ static int gc2053_set_ctrl(struct v4l2_ctrl *ctrl) break; case V4L2_CID_VBLANK: vts = ctrl->val + gc2053->cur_mode->height; - ret = gc2053_write_reg(gc2053->client, GC2053_REG_VTS_H, (vts >> 8) & 0x3f); - ret |= gc2053_write_reg(gc2053->client, GC2053_REG_VTS_L, vts & 0xff); /* Note: In master-slave mode, Galaxycore request slave sensor frame rate bigger than master. */ if (gc2053->sync_mode == INTERNAL_MASTER_MODE) - gc2053_write_reg(gc2053->client, GC2053_REG_VTS_L, (vts & 0xff) + 10); + vts += 10; + ret = gc2053_write_reg(gc2053->client, GC2053_REG_VTS_H, (vts >> 8) & 0x3f); + ret |= gc2053_write_reg(gc2053->client, GC2053_REG_VTS_L, vts & 0xff); + /* TBD: master and slave not sync to streaming, but except sleep 20ms below */ + usleep_range(20000, 50000); break; case V4L2_CID_HFLIP: if (ctrl->val) From b1773149c4e1ebf559f08bf0a590750b575042e9 Mon Sep 17 00:00:00 2001 From: Binyuan Lan Date: Tue, 11 Jul 2023 03:25:50 +0000 Subject: [PATCH 012/133] ASoC: rockchip: rk817-codec: Solve pop problems cause by re-configure APLL SMIC TudorAG and previous versions: During playback, a POP sound occurs when the recording is opened. This patch is intended to fix this issue. Change-Id: I86f79cd531738113092723e1ef198b093ae472b9 Signed-off-by: Binyuan Lan --- sound/soc/codecs/rk817_codec.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/rk817_codec.c b/sound/soc/codecs/rk817_codec.c index a334f763224a..c178da3e52a2 100644 --- a/sound/soc/codecs/rk817_codec.c +++ b/sound/soc/codecs/rk817_codec.c @@ -286,10 +286,10 @@ static struct rk817_reg_val_typ playback_power_up_list[] = { {RK817_CODEC_AREF_RTCFG1, 0x40}, {RK817_CODEC_DDAC_POPD_DACST, 0x02}, /* APLL */ - {RK817_CODEC_APLL_CFG0, 0x04}, + /* {RK817_CODEC_APLL_CFG0, 0x04}, */ {RK817_CODEC_APLL_CFG1, 0x58}, {RK817_CODEC_APLL_CFG2, 0x2d}, - {RK817_CODEC_APLL_CFG4, 0xa5}, + /* {RK817_CODEC_APLL_CFG4, 0xa5}, */ {RK817_CODEC_APLL_CFG5, 0x00}, {RK817_CODEC_DI2S_RXCMD_TSD, 0x00}, @@ -324,10 +324,10 @@ static struct rk817_reg_val_typ capture_power_up_list[] = { {RK817_CODEC_AREF_RTCFG1, 0x40}, {RK817_CODEC_DADC_SR_ACL0, 0x02}, /* {RK817_CODEC_DTOP_DIGEN_CLKE, 0xff}, */ - {RK817_CODEC_APLL_CFG0, 0x04}, + /* {RK817_CODEC_APLL_CFG0, 0x04}, */ {RK817_CODEC_APLL_CFG1, 0x58}, {RK817_CODEC_APLL_CFG2, 0x2d}, - {RK817_CODEC_APLL_CFG4, 0xa5}, + /* {RK817_CODEC_APLL_CFG4, 0xa5}, */ {RK817_CODEC_APLL_CFG5, 0x00}, /*{RK817_CODEC_DI2S_RXCMD_TSD, 0x00},*/ @@ -378,12 +378,16 @@ static int rk817_codec_power_up(struct snd_soc_component *component, int type) playback_power_up_list[i].value); } - /* Re-configure APLL CFG0/4 if (chip_ver <= 0x4) */ + /* configure APLL CFG0/4 */ if (rk817->chip_ver <= 0x4) { DBG("%s (%d): SMIC TudorAG and previous versions\n", __func__, __LINE__); snd_soc_component_write(component, RK817_CODEC_APLL_CFG0, 0x0c); snd_soc_component_write(component, RK817_CODEC_APLL_CFG4, 0x95); + } else { + DBG("%s: SMIC TudorAG version later\n", __func__); + snd_soc_component_write(component, RK817_CODEC_APLL_CFG0, 0x04); + snd_soc_component_write(component, RK817_CODEC_APLL_CFG4, 0xa5); } snd_soc_component_update_bits(component, RK817_CODEC_DTOP_DIGEN_CLKE, @@ -405,12 +409,16 @@ static int rk817_codec_power_up(struct snd_soc_component *component, int type) capture_power_up_list[i].value); } - /* Re-configure APLL CFG0/4 if (chip_ver <= 0x4) */ + /* configure APLL CFG0/4 */ if (rk817->chip_ver <= 0x4) { DBG("%s (%d): SMIC TudorAG and previous versions\n", __func__, __LINE__); snd_soc_component_write(component, RK817_CODEC_APLL_CFG0, 0x0c); snd_soc_component_write(component, RK817_CODEC_APLL_CFG4, 0x95); + } else { + DBG("%s: SMIC TudorAG version later\n", __func__); + snd_soc_component_write(component, RK817_CODEC_APLL_CFG0, 0x04); + snd_soc_component_write(component, RK817_CODEC_APLL_CFG4, 0xa5); } snd_soc_component_update_bits(component, RK817_CODEC_DTOP_DIGEN_CLKE, From aa029efb520b70066c34de891d194fe01f6b17c7 Mon Sep 17 00:00:00 2001 From: Luo Wei Date: Sat, 8 Jul 2023 13:26:18 +0800 Subject: [PATCH 013/133] arm64: dts: rockchip: rk3588-vehicle: init s66 project dts files Support two AVM cameras powered by max96712 and max96722. Support i2s1 works with ADSP-21562 in tdm8 format, and i2s3 to bluetooth. Signed-off-by: Cai Wenzhong Signed-off-by: Jianqun Xu Signed-off-by: Luo Wei Change-Id: Ic766cc17298ef2a03cc362a62e780e24f2ca1060 --- arch/arm64/boot/dts/rockchip/Makefile | 1 + .../rk3588-vehicle-adsp-audio-s66.dtsi | 99 +++ .../rk3588-vehicle-maxim-cameras-s66.dtsi | 319 ++++++++++ ...3588-vehicle-maxim-serdes-display-s66.dtsi | 564 ++++++++++++++++++ .../dts/rockchip/rk3588-vehicle-s66-v10.dts | 89 +++ .../dts/rockchip/rk3588-vehicle-s66-v10.dtsi | 199 ++++++ .../boot/dts/rockchip/rk3588-vehicle-s66.dtsi | 434 ++++++++++++++ 7 files changed, 1705 insertions(+) create mode 100644 arch/arm64/boot/dts/rockchip/rk3588-vehicle-adsp-audio-s66.dtsi create mode 100644 arch/arm64/boot/dts/rockchip/rk3588-vehicle-maxim-cameras-s66.dtsi create mode 100644 arch/arm64/boot/dts/rockchip/rk3588-vehicle-maxim-serdes-display-s66.dtsi create mode 100644 arch/arm64/boot/dts/rockchip/rk3588-vehicle-s66-v10.dts create mode 100644 arch/arm64/boot/dts/rockchip/rk3588-vehicle-s66-v10.dtsi create mode 100644 arch/arm64/boot/dts/rockchip/rk3588-vehicle-s66.dtsi diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile index bf95b466266a..ee0205d0e292 100644 --- a/arch/arm64/boot/dts/rockchip/Makefile +++ b/arch/arm64/boot/dts/rockchip/Makefile @@ -192,6 +192,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-toybrick-x0-linux.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-vehicle-evb-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-vehicle-evb-v20.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-vehicle-evb-v21.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-vehicle-s66-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-evb1-lp4x-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-evb1-lp4x-v10-linux.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-evb2-lp5-v10.dtb diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-adsp-audio-s66.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-adsp-audio-s66.dtsi new file mode 100644 index 000000000000..4fd049fd55a4 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-adsp-audio-s66.dtsi @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. + * + */ + +/ { + dummy_codec: dummy-codec { + compatible = "rockchip,dummy-codec"; + #sound-dai-cells = <0>; + status = "okay"; + }; + + sound0 { + compatible = "simple-audio-card"; + simple-audio-card,name = "rockchip,tdm"; + simple-audio-card,format = "i2s"; + simple-audio-card,mclk-fs = <256>; + simple-audio-card,bitclock-master = <&codec_master>; + simple-audio-card,frame-master = <&codec_master>; + status = "okay"; + + simple-audio-card,cpu { + sound-dai = <&i2s1_8ch>; + }; + codec_master: simple-audio-card,codec { + sound-dai = <&dummy_codec>; + }; + }; + + bt_codec: bt-codec { + compatible = "delta,dfbmcs320"; + #sound-dai-cells = <1>; + status = "okay"; + }; + + sound1 { + compatible = "simple-audio-card"; + simple-audio-card,name = "rockchip,bt"; + simple-audio-card,format = "dsp_a"; + simple-audio-card,bitclock-inversion = <1>; + simple-audio-card,mclk-fs = <256>; + simple-audio-card,cpu { + sound-dai = <&i2s3_2ch>; + }; + simple-audio-card,codec { + sound-dai = <&bt_codec 1>; + }; + }; +}; + +&i2s1_8ch { + pinctrl-0 = <&i2s1m0_lrck + &i2s1m0_sclk + &i2s1m0_sdi0 + &i2s1m0_sdi1 + &i2s1m0_sdo0 + &i2s1m0_sdo1 + &i2s1m0_sdo2>; + i2s-lrck-gpio = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>; + tdm-fsync-gpio = <&gpio4 RK_PA0 GPIO_ACTIVE_HIGH>; + rockchip,tdm-multi-lanes; + rockchip,tx-lanes = <3>; + rockchip,rx-lanes = <2>; + rockchip,clk-trcm = <1>; + status = "okay"; +}; + +&i2s3_2ch { + assigned-clocks = <&cru CLK_I2S3_2CH>; + assigned-clock-parents = <&mclkin_i2s3>; + pinctrl-0 = <&i2s3_sdi + &i2s3_sdo + &i2s3_mclk>; + status = "okay"; +}; + +&mclkin_i2s3 { + clock-frequency = <12288000>; +}; + +&spi3 { + status = "okay"; + assigned-clocks = <&cru CLK_SPI3>; + assigned-clock-rates = <200000000>; + num-cs = <2>; + pinctrl-0 = <&spi3m2_cs0 + &spi3m2_cs1 + &spi3m2_pins>; + + flash: is25lp032@1 { + compatible = "issi,is25lp032", "jedec,spi-nor"; + reg = <1>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <5000000>; + m25p,fast-read; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-maxim-cameras-s66.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-maxim-cameras-s66.dtsi new file mode 100644 index 000000000000..566c9d00095b --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-maxim-cameras-s66.dtsi @@ -0,0 +1,319 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. + * + */ + +/ { + max96712_osc: max96712-oscillator { + compatible = "fixed-clock"; + #clock-cells = <1>; + clock-frequency = <25000000>; + clock-output-names = "max96712-osc"; + }; + + max96722_osc: max96722-oscillator { + compatible = "fixed-clock"; + #clock-cells = <1>; + clock-frequency = <25000000>; + clock-output-names = "max96722-osc"; + }; +}; + +/** + * ============================================================================ + * Inno DPHY0: full mode + * ============================================================================ + */ +&csi2_dphy0_hw { + status = "okay"; +}; + +&csi2_dphy0 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + mipi_dphy0_in_max96712: endpoint@1 { + reg = <1>; + remote-endpoint = <&max96712_out>; + data-lanes = <1 2 3 4>; + }; + }; + port@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + csidphy0_out: endpoint@0 { + reg = <0>; + remote-endpoint = <&mipi2_csi2_input>; + }; + }; + }; +}; + +&mipi2_csi2 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + mipi2_csi2_input: endpoint@1 { + reg = <1>; + remote-endpoint = <&csidphy0_out>; + }; + }; + + port@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + mipi2_csi2_output: endpoint@0 { + reg = <0>; + remote-endpoint = <&cif_mipi2_in>; + }; + }; + }; +}; + +&rkcif_mipi_lvds2 { + status = "okay"; + /* parameters for do cif reset detecting: + * index0: monitor mode, + 0 for idle, + 1 for continue, + 2 for trigger, + 3 for hotplug (for nextchip) + * index1: the frame id to start timer, + min is 2 + * index2: frame num of monitoring cycle + * index3: err time for keep monitoring + after finding out err (ms) + * index4: csi2 err reference val for resetting + */ + rockchip,cif-monitor = <3 2 1 1000 5>; + + port { + cif_mipi2_in: endpoint { + remote-endpoint = <&mipi2_csi2_output>; + }; + }; +}; + +/** + * ============================================================================ + * Inno DPHY1: full mode + * ============================================================================ + */ +&csi2_dphy1_hw { + status = "okay"; +}; + +&csi2_dphy3 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + mipi_dphy3_in_max96722: endpoint@1 { + reg = <1>; + remote-endpoint = <&max96722_out>; + data-lanes = <1 2 3 4>; + }; + }; + port@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + csidphy3_out: endpoint@0 { + reg = <0>; + remote-endpoint = <&mipi4_csi2_input>; + }; + }; + }; +}; + +&mipi4_csi2 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + mipi4_csi2_input: endpoint@1 { + reg = <1>; + remote-endpoint = <&csidphy3_out>; + }; + }; + + port@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + mipi4_csi2_output: endpoint@0 { + reg = <0>; + remote-endpoint = <&cif_mipi4_in>; + }; + }; + }; +}; + +&rkcif_mipi_lvds4 { + status = "okay"; + /* parameters for do cif reset detecting: + * index0: monitor mode, + 0 for idle, + 1 for continue, + 2 for trigger, + 3 for hotplug (for nextchip) + * index1: the frame id to start timer, + min is 2 + * index2: frame num of monitoring cycle + * index3: err time for keep monitoring + after finding out err (ms) + * index4: csi2 err reference val for resetting + */ + rockchip,cif-monitor = <3 2 1 1000 5>; + + port { + cif_mipi4_in: endpoint { + remote-endpoint = <&mipi4_csi2_output>; + }; + }; +}; + +/** + * ============================================================================= + * Common + * ============================================================================= + */ +&rkcif { + status = "okay"; + rockchip,android-usb-camerahal-enable; +}; + +&rkcif_mmu { + status = "okay"; +}; + +&i2c2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c2m4_xfer>; + clock-frequency = <400000>; + + // AVM Camera x4 + max96712: max96712@29 { + compatible = "maxim,max96712"; + status = "okay"; + reg = <0x29>; + clock-names = "xvclk"; + clocks = <&max96712_osc 0>; + pinctrl-names = "default"; + pinctrl-0 = <&max96712_power>, <&max96712_errb>, <&max96712_lock>; + power-domains = <&power RK3588_PD_VI>; + rockchip,grf = <&sys_grf>; + power-gpios = <&gpio1 RK_PC4 GPIO_ACTIVE_HIGH>; + lock-gpios = <&gpio1 RK_PC6 GPIO_ACTIVE_HIGH>; + link-mask = <0x0F>; + auto-init-deskew-mask = <0x3>; + frame-sync-period = <0>; + link-rx-rate = <0>; + rockchip,camera-module-index = <0>; + rockchip,camera-module-facing = "back"; + rockchip,camera-module-name = "max96712"; + rockchip,camera-module-lens-name = "max96712"; + + port { + max96712_out: endpoint { + remote-endpoint = <&mipi_dphy0_in_max96712>; + data-lanes = <1 2 3 4>; + }; + }; + }; + + // DMS Camera x1 + OMS Camera x3 + max96722: max96722@6b { + compatible = "maxim,max96722"; + status = "okay"; + reg = <0x6b>; + clock-names = "xvclk"; + clocks = <&max96722_osc 0>; + pinctrl-names = "default"; + pinctrl-0 = <&max96722_power>, <&max96722_errb>, <&max96722_lock>; + power-domains = <&power RK3588_PD_VI>; + rockchip,grf = <&sys_grf>; + power-gpios = <&gpio1 RK_PC7 GPIO_ACTIVE_HIGH>; + lock-gpios = <&gpio1 RK_PD5 GPIO_ACTIVE_HIGH>; + link-mask = <0x33>; + auto-init-deskew-mask = <0x3>; + frame-sync-period = <0>; + rockchip,camera-module-index = <0>; + rockchip,camera-module-facing = "back"; + rockchip,camera-module-name = "max96722"; + rockchip,camera-module-lens-name = "max96722"; + + port { + max96722_out: endpoint { + remote-endpoint = <&mipi_dphy3_in_max96722>; + data-lanes = <1 2 3 4>; + }; + }; + }; +}; + +&pinctrl { + maxim-cameras { + max96712_power: max96712-power { + rockchip,pins = <1 RK_PC4 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + max96712_errb: max96712-errb { + rockchip,pins = <1 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + max96712_lock: max96712-lock { + rockchip,pins = <1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + max96722_power: max96722-power { + rockchip,pins = <1 RK_PC7 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + max96722_errb: max96722-errb { + rockchip,pins = <1 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + max96722_lock: max96722-lock { + rockchip,pins = <1 RK_PD5 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-maxim-serdes-display-s66.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-maxim-serdes-display-s66.dtsi new file mode 100644 index 000000000000..588e5695bf11 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-maxim-serdes-display-s66.dtsi @@ -0,0 +1,564 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2022 Rockchip Electronics Co., Ltd. + */ + +#include + +/ { + aliases { + pinctrl0 = &pinctrl; + }; + + backlight { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + i2c8_max96755f_backlight: backlight@0 { + compatible = "pwm-backlight"; + reg = <0>; + pwms = <&pwm0 0 1000000 0>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; + }; + + i2c8_max96745_1_backlight: backlight@1 { + compatible = "pwm-backlight"; + reg = <0>; + pwms = <&pwm1 0 1000000 0>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; + }; + + i2c8_max96745_2_backlight: backlight@2 { + compatible = "pwm-backlight"; + reg = <0>; + pwms = <&pwm7 0 1000000 0>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; + }; + }; +}; + +&dp0 { + //split-mode; + force-hpd; + status = "disabled"; +}; + +&dp0_in_vp0 { + status = "okay"; +}; + +&usbdp_phy0 { + rockchip,dp-lane-mux = <0 1 2 3>; + status = "okay"; +}; + +&usbdp_phy0_dp { + status = "okay"; +}; + +&route_dp0 { + connect = <&vp0_out_dp0>; + status = "disabled"; +}; + +&dp1 { + force-hpd; + status = "disabled"; +}; + +&usbdp_phy1 { + //rockchip,dp-lane-mux = <0 1 2 3>; + status = "disabled"; +}; + +&usbdp_phy1_dp { + status = "disabled"; +}; + +&dsi0 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + + dsi0_out: endpoint { + remote-endpoint = <&i2c8_max96755f_in>; + }; + }; + }; +}; + +&mipi_dcphy0 { + status = "okay"; +}; + +&dsi0_in_vp2 { + status = "okay"; +}; + +&route_dsi0 { + connect = <&vp2_out_dsi0>; + status = "disabled"; +}; + +&dsi1 { + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + + dsi1_out: endpoint { + //remote-endpoint = <&i2c6_max96755f_in>; + }; + }; + }; +}; + +&mipi_dcphy1 { + status = "okay"; +}; + +&dsi1_in_vp3 { + status = "okay"; +}; + +&route_dsi1 { + connect = <&vp3_out_dsi1>; + status = "disabled"; +}; + +&edp0 { + split-mode; + force-hpd; + status = "disabled"; +}; + +&edp0_out { + link-frequencies = /bits/ 64 <2700000000>; + remote-endpoint = <&i2c8_max96745_1_in>; +}; + +&hdptxphy0 { + status = "okay"; +}; + +&edp0_in_vp1 { + status = "okay"; +}; + +&route_edp0 { + connect = <&vp1_out_edp0>; + status = "disabled"; +}; + +&edp1 { + force-hpd; + status = "disabled"; +}; + +&edp1_out { + link-frequencies = /bits/ 64 <2700000000>; + remote-endpoint = <&i2c8_max96745_2_in>; +}; + +&hdptxphy1 { + status = "okay"; +}; + +&hdmi0 { + status = "disabled"; +}; + +&hdmi1 { + status = "disabled"; +}; + +&hdptxphy_hdmi0 { + status = "disabled"; +}; + +&hdptxphy_hdmi1 { + status = "disabled"; +}; + +&i2c8 { + pinctrl-0 = <&i2c8m4_xfer>; + clock-frequency = <400000>; + status = "okay"; + + max96755f@62 { + compatible = "maxim,max96755f"; + reg = <0x62>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c8_ser1_lock_pins>, <&i2c8_ser1_pwdnb_pins>; + #address-cells = <1>; + #size-cells = <0>; + + pinctrl { + compatible = "maxim,max96755f-pinctrl"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c8_max96755f_pinctrl_hog>; + + i2c8_max96755f_pinctrl_hog: hog { + i2c { + groups = "I2C"; + function = "I2C"; + }; + }; + + i2c8_max96755f_panel_pins: panel-pins { + bl-pwm { + pins = "MFP7"; + function = "GPIO_TX_0"; + }; + + tp-int { + pins = "MFP8"; + function = "GPIO_RX_2"; + }; + }; + }; + + bridge { + compatible = "maxim,max96755f-bridge"; + lock-gpios = <&gpio1 RK_PA4 GPIO_ACTIVE_HIGH>; + bridge_dual_link; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + i2c8_max96755f_in: endpoint { + remote-endpoint = <&dsi0_out>; + }; + }; + + port@1 { + reg = <1>; + + i2c8_max96755f_out: endpoint { + remote-endpoint = <&i2c8_max96755f_panel_in>; + }; + }; + }; + }; + + gmsl@0 { + reg = <0>; + clock-frequency = <400000>; + #address-cells = <1>; + #size-cells = <0>; + + ts@30 { + compatible = "gac,gac_ts"; + reg = <0x30>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend"; + pinctrl-0 = <&touch_pin>; + pinctrl-1 = <&touch_pin>; + interrupt-parent = <&gpio1>; + interrupts = ; + gac,max_x = <2560>; + gac,max_y = <1440>; + }; + + panel@48 { + compatible = "boe,ae146m1t-l10"; + reg = <0x48>; + backlight = <&i2c8_max96755f_backlight>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c8_max96755f_panel_pins>; + panel_dual_link; + + panel-timing { + clock-frequency = <303000000>; + hactive = <2560>; + vactive = <1440>; + hfront-porch = <122>; + hsync-len = <60>; + hback-porch = <60>; + vfront-porch = <340>; + vsync-len = <2>; + vback-porch = <20>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <0>; + pixelclk-active = <0>; + }; + + port { + i2c8_max96755f_panel_in: endpoint { + remote-endpoint = <&i2c8_max96755f_out>; + }; + }; + }; + }; + }; +}; + +&i2c8 { + status = "okay"; + + max96745@42 { + compatible = "maxim,max96745"; + reg = <0x42>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c8_ser2_lock_pins>; + #address-cells = <1>; + #size-cells = <0>; + + pinctrl { + compatible = "maxim,max96745-pinctrl"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c8_max96745_1_pinctrl_hog>; + + i2c8_max96745_1_pinctrl_hog: hog { + i2c { + groups = "I2C"; + function = "I2C"; + }; + }; + + i2c8_max96745_1_panel_pins: panel-pins { + bl-pwm { + pins = "MFP11"; + function = "GPIO_TX_A_0"; + }; + }; + }; + + bridge { + compatible = "maxim,max96745-bridge"; + lock-gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_HIGH>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + i2c8_max96745_1_in: endpoint { + remote-endpoint = <&edp0_out>; + }; + }; + + port@1 { + reg = <1>; + + i2c8_max96745_1_out: endpoint { + remote-endpoint = <&i2c8_max96745_1_panel_in>; + }; + }; + }; + }; + + gmsl@0 { + reg = <0>; + clock-frequency = <400000>; + #address-cells = <1>; + #size-cells = <0>; + + panel@48 { + compatible = "boe,av156fht-l83"; + reg = <0x48>; + backlight = <&i2c8_max96745_1_backlight>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c8_max96745_1_panel_pins>; + + panel-timing { + clock-frequency = <148500000>; + hactive = <1920>; + vactive = <1080>; + hfront-porch = <20>; + hsync-len = <20>; + hback-porch = <20>; + vfront-porch = <250>; + vsync-len = <2>; + vback-porch = <8>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <0>; + pixelclk-active = <0>; + }; + + port { + i2c8_max96745_1_panel_in: endpoint { + remote-endpoint = <&i2c8_max96745_1_out>; + }; + }; + }; + }; + }; +}; + +&i2c8 { + status = "okay"; + + max96745@60 { + compatible = "maxim,max96745"; + reg = <0x60>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c8_ser3_lock_pins>; + #address-cells = <1>; + #size-cells = <0>; + + pinctrl { + compatible = "maxim,max96745-pinctrl"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c8_max96745_2_pinctrl_hog>; + + i2c8_max96745_2_pinctrl_hog: hog { + i2c { + groups = "I2C"; + function = "I2C"; + }; + }; + + i2c8_max96745_2_panel_pins: panel-pins { + bl-pwm { + pins = "MFP11"; + function = "GPIO_TX_A_0"; + }; + }; + }; + + bridge { + compatible = "maxim,max96745-bridge"; + lock-gpios = <&gpio4 RK_PC4 GPIO_ACTIVE_HIGH>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + i2c8_max96745_2_in: endpoint { + remote-endpoint = <&edp1_out>; + }; + }; + + port@1 { + reg = <1>; + + i2c8_max96745_2_out: endpoint { + remote-endpoint = <&i2c8_max96745_2_panel_in>; + }; + }; + }; + }; + + gmsl@0 { + reg = <0>; + clock-frequency = <400000>; + #address-cells = <1>; + #size-cells = <0>; + + panel@48 { + compatible = "boe,av156fht-l83"; + reg = <0x48>; + backlight = <&i2c8_max96745_2_backlight>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c8_max96745_2_panel_pins>; + + panel-timing { + clock-frequency = <148500000>; + hactive = <1920>; + vactive = <1080>; + hfront-porch = <20>; + hsync-len = <20>; + hback-porch = <20>; + vfront-porch = <250>; + vsync-len = <2>; + vback-porch = <8>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <0>; + pixelclk-active = <0>; + }; + + port { + i2c8_max96745_2_panel_in: endpoint { + remote-endpoint = <&i2c8_max96745_2_out>; + }; + }; + }; + }; + }; +}; + +&pinctrl { + serdes { + i2c8_ser1_lock_pins: i2c8-ser1-lock-pins { + rockchip,pins = + <1 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + i2c8_ser2_lock_pins: i2c8-ser2-lock-pins { + rockchip,pins = + <3 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + i2c8_ser3_lock_pins: i2c8-ser3-lock-pins { + rockchip,pins = + <4 RK_PC4 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + i2c8_ser1_errb_pins: i2c8-ser1-errb-pins { + rockchip,pins = + <1 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + i2c8_ser2_errb_pins: i2c8-ser2-errb-pins { + rockchip,pins = + <3 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + i2c8_ser3_errb_pins: i2c8-ser3-errb-pins { + rockchip,pins = + <4 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + i2c8_ser1_pwdnb_pins: i2c8-ser1-pwdnb-pins { + rockchip,pins = + <1 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + touch { + touch_pin: touch-pin { + rockchip,pins = + <1 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; +}; + +&pwm0 { + pinctrl-0 = <&pwm0m2_pins>; + status = "okay"; +}; + +&pwm1 { + pinctrl-0 = <&pwm1m1_pins>; + status = "okay"; +}; + +&pwm7 { + pinctrl-0 = <&pwm7m3_pins>; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-s66-v10.dts b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-s66-v10.dts new file mode 100644 index 000000000000..e27ee5107455 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-s66-v10.dts @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. + * + */ + +/dts-v1/; + +#include "rk3588-vehicle-s66-v10.dtsi" +#include "rk3588-vehicle-adsp-audio-s66.dtsi" +#include "rk3588-vehicle-maxim-serdes-display-s66.dtsi" +#include "rk3588-vehicle-maxim-cameras-s66.dtsi" +#include "rk3588-android.dtsi" + +/ { + model = "Rockchip RK3588 VEHICLE S66 Board V10"; + compatible = "rockchip,rk3588-vehicle-s66-v10", "rockchip,rk3588"; +}; + +&rockchip_suspend { + rockchip,sleep-mode-config = < + (0 + | RKPM_SLP_ARMOFF_DDRPD + | RKPM_SLP_PMU_PMUALIVE_32K + | RKPM_SLP_PMU_DIS_OSC + | RKPM_SLP_32K_EXT + ) + >; + rockchip,wakeup-config = < + (0 + | RKPM_GPIO_WKUP_EN + ) + >; + status = "okay"; +}; + +&vdd_log_s0 { + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <800000>; + }; +}; + +&vcc_3v3_s0 { + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; +}; + +&vcc_1v8_s0 { + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; +}; + +&vccio_sd_s0 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; +}; + +&vdd_0v75_hdmi_edp_s0 { + regulator-min-microvolt = <837500>; + regulator-max-microvolt = <837500>; +}; + +&vdd_cpu_big1_mem_s0 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; +}; + +&vdd_cpu_big0_mem_s0 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; +}; + +&vdd_cpu_lit_mem_s0 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; +}; + +&vdd_gpu_mem_s0 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-state-mem { + regulator-on-in-suspend; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-s66-v10.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-s66-v10.dtsi new file mode 100644 index 000000000000..0346f3c9f9ba --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-s66-v10.dtsi @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. + * + */ + +#include "rk3588m.dtsi" +#include "rk3588-vehicle-s66.dtsi" +#include "rk3588-rk806-dual.dtsi" +/ { + pcie20_avdd0v85: pcie20-avdd0v85 { + compatible = "regulator-fixed"; + regulator-name = "pcie20_avdd0v85"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + vin-supply = <&vdd_0v85_s0>; + }; + + pcie20_avdd1v8: pcie20-avdd1v8 { + compatible = "regulator-fixed"; + regulator-name = "pcie20_avdd1v8"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&avcc_1v8_s0>; + }; + + pcie30_avdd0v75: pcie30-avdd0v75 { + compatible = "regulator-fixed"; + regulator-name = "pcie30_avdd0v75"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + vin-supply = <&avdd_0v75_s0>; + }; + + pcie30_avdd1v8: pcie30-avdd1v8 { + compatible = "regulator-fixed"; + regulator-name = "pcie30_avdd1v8"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&avcc_1v8_s0>; + }; + + vcc5v0_host: vcc5v0-host { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_host"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + enable-active-high; + //gpio = <&gpio4 RK_PA3 GPIO_ACTIVE_HIGH>; + vin-supply = <&vcc5v0_usb>; + //pinctrl-names = "default"; + //pinctrl-0 = <&vcc5v0_host_en>; + //TODO: should powered by MCU + }; +}; + +&combphy0_ps { + status = "okay"; +}; + +&combphy1_ps { + status = "okay"; +}; + +&combphy2_psu { + status = "okay"; +}; + +&gmac0 { + /* Use rgmii-rxid mode to disable rx delay inside Soc */ + phy-mode = "rgmii-rxid"; + clock_in_out = "output"; + snps,reset-gpio = <&gpio2 RK_PC5 GPIO_ACTIVE_LOW>; + snps,reset-active-low; + /* Reset time is 20ms, 100ms for rtl8211f */ + snps,reset-delays-us = <0 20000 100000>; + pinctrl-0 = <&gmac0_miim + &gmac0_tx_bus2 + &gmac0_rx_bus2 + &gmac0_rgmii_clk + &gmac0_rgmii_bus>; + tx_delay = <0x43>; + //rx_delay = <0x3f>; + phy-handle = <&rgmii_phy>; + status = "okay"; +}; + +&i2c3 { + status = "okay"; + //todo, add gyro IAM20680 + //todo, add mfi +}; + +&i2c4 { + status = "okay"; + pinctrl-0 = <&i2c4m0_xfer>; + //todo, add LT9211 +}; + +&mdio0 { + rgmii_phy: phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x1>; + }; +}; + +&pcie2x1l0 { + status = "disabled"; +}; + +&pcie2x1l1 { + status = "disabled"; +}; + +&pcie2x1l2 { + rockchip,skip-scan-in-resume; + status = "okay"; +}; + +&pcie30phy { + rockchip,pcie30-phymode = ; + status = "disabled"; +}; + +&pcie3x4 { + num-lanes = <1>; + status = "disabled"; +}; + +&sata0 { + status = "disabled"; +}; + +&sdmmc { + status = "disabled"; +}; + +&u2phy1_otg { + phy-supply = <&vcc5v0_host>; +}; + +&u2phy2_host { + phy-supply = <&vcc5v0_host>; +}; + +&u2phy3_host { + phy-supply = <&vcc5v0_host>; +}; + +&usbdp_phy0 { + rockchip,dp-lane-mux = <2 3>; + status = "okay"; +}; + +&usbdp_phy0_dp { + status = "okay"; +}; + +&usbdp_phy0_u3 { + status = "okay"; +}; + +&usbdp_phy1 { + rockchip,dp-lane-mux = <3 2 1 0>; + status = "disabled"; +}; + +&usbdp_phy1_dp { + status = "disabled"; +}; + +&usbdp_phy1_u3 { + maximum-speed = "high-speed"; + status = "okay"; +}; + +&usbdrd_dwc3_0 { + dr_mode = "peripheral"; + maximum-speed = "high-speed"; + extcon = <&u2phy0>; + status = "okay"; +}; + +&usbdrd_dwc3_1 { + dr_mode = "host"; + maximum-speed = "high-speed"; + snps,dis_u2_susphy_quirk; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-s66.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-s66.dtsi new file mode 100644 index 000000000000..33e9186ca2e0 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-s66.dtsi @@ -0,0 +1,434 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. + * + */ + +#include +#include +#include +#include +#include +#include +/ { + backlight: backlight { + compatible = "pwm-backlight"; + brightness-levels = < + 0 20 20 21 21 22 22 23 + 23 24 24 25 25 26 26 27 + 27 28 28 29 29 30 30 31 + 31 32 32 33 33 34 34 35 + 35 36 36 37 37 38 38 39 + 40 41 42 43 44 45 46 47 + 48 49 50 51 52 53 54 55 + 56 57 58 59 60 61 62 63 + 64 65 66 67 68 69 70 71 + 72 73 74 75 76 77 78 79 + 80 81 82 83 84 85 86 87 + 88 89 90 91 92 93 94 95 + 96 97 98 99 100 101 102 103 + 104 105 106 107 108 109 110 111 + 112 113 114 115 116 117 118 119 + 120 121 122 123 124 125 126 127 + 128 129 130 131 132 133 134 135 + 136 137 138 139 140 141 142 143 + 144 145 146 147 148 149 150 151 + 152 153 154 155 156 157 158 159 + 160 161 162 163 164 165 166 167 + 168 169 170 171 172 173 174 175 + 176 177 178 179 180 181 182 183 + 184 185 186 187 188 189 190 191 + 192 193 194 195 196 197 198 199 + 200 201 202 203 204 205 206 207 + 208 209 210 211 212 213 214 215 + 216 217 218 219 220 221 222 223 + 224 225 226 227 228 229 230 231 + 232 233 234 235 236 237 238 239 + 240 241 242 243 244 245 246 247 + 248 249 250 251 252 253 254 255 + >; + default-brightness-level = <200>; + }; + + test-power { + status = "okay"; + }; + + vcc12v_dcin: vcc12v-dcin { + compatible = "regulator-fixed"; + regulator-name = "vcc12v_dcin"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + }; + + vcc5v0_sys: vcc5v0-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc12v_dcin>; + }; + + vcc5v0_usbdcin: vcc5v0-usbdcin { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_usbdcin"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc12v_dcin>; + }; + + vcc5v0_usb: vcc5v0-usb { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_usb"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc5v0_usbdcin>; + }; +}; + +&av1d_mmu { + status = "okay"; +}; + +&cpu_l0 { + cpu-supply = <&vdd_cpu_lit_s0>; + mem-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_b0 { + cpu-supply = <&vdd_cpu_big0_s0>; + mem-supply = <&vdd_cpu_big0_s0>; +}; + +&cpu_b2 { + cpu-supply = <&vdd_cpu_big1_s0>; + mem-supply = <&vdd_cpu_big1_s0>; +}; + +&gpu { + mali-supply = <&vdd_gpu_s0>; + mem-supply = <&vdd_gpu_s0>; + status = "okay"; +}; + +&i2s0_8ch { + status = "disabled"; +}; + +&iep { + status = "okay"; +}; + +&iep_mmu { + status = "okay"; +}; + +&jpegd { + status = "okay"; +}; + +&jpegd_mmu { + status = "okay"; +}; + +&jpege_ccu { + status = "okay"; +}; + +&jpege0 { + status = "okay"; +}; + +&jpege0_mmu { + status = "okay"; +}; + +&jpege1 { + status = "okay"; +}; + +&jpege1_mmu { + status = "okay"; +}; + +&jpege2 { + status = "okay"; +}; + +&jpege2_mmu { + status = "okay"; +}; + +&jpege3 { + status = "okay"; +}; + +&jpege3_mmu { + status = "okay"; +}; + +&mpp_srv { + status = "okay"; +}; + +&rga3_core0 { + status = "okay"; +}; + +&rga3_0_mmu { + status = "okay"; +}; + +&rga3_core1 { + status = "okay"; +}; + +&rga3_1_mmu { + status = "okay"; +}; + +&rga2 { + status = "okay"; +}; + +&rknpu { + rknpu-supply = <&vdd_npu_s0>; + mem-supply = <&vdd_npu_s0>; + status = "okay"; +}; + +&rknpu_mmu { + status = "okay"; +}; + +&rkvdec_ccu { + status = "okay"; +}; + +&rkvdec0 { + status = "okay"; +}; + +&rkvdec0_mmu { + status = "okay"; +}; + +&rkvdec1 { + status = "okay"; +}; + +&rkvdec1_mmu { + status = "okay"; +}; + +&rkvenc_ccu { + status = "okay"; +}; + +&rkvenc0 { + status = "okay"; +}; + +&rkvenc0_mmu { + status = "okay"; +}; + +&rkvenc1 { + status = "okay"; +}; + +&rkvenc1_mmu { + status = "okay"; +}; + +&rockchip_suspend { + status = "okay"; + rockchip,sleep-debug-en = <1>; +}; + +&saradc { + status = "okay"; + vref-supply = <&vcc_1v8_s0>; +}; + +&sdhci { + bus-width = <8>; + no-sdio; + no-sd; + non-removable; + max-frequency = <200000000>; + mmc-hs400-1_8v; + mmc-hs400-enhanced-strobe; + status = "okay"; +}; + +&sdmmc { + max-frequency = <150000000>; + no-sdio; + no-mmc; + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + disable-wp; + sd-uhs-sdr104; + vqmmc-supply = <&vccio_sd_s0>; + status = "disabled"; +}; + +&tsadc { + status = "okay"; +}; + +&u2phy0 { + status = "okay"; +}; + +&u2phy1 { + status = "okay"; +}; + +&u2phy2 { + status = "okay"; +}; + +&u2phy3 { + status = "okay"; +}; + +&u2phy0_otg { + status = "okay"; +}; + +&u2phy1_otg { + rockchip,sel-pipe-phystatus; + status = "okay"; +}; + +&u2phy2_host { + status = "okay"; +}; + +&u2phy3_host { + status = "okay"; +}; + +&usb_host0_ehci { + status = "okay"; +}; + +&usb_host0_ohci { + status = "okay"; +}; + +&usb_host1_ehci { + status = "okay"; +}; + +&usb_host1_ohci { + status = "okay"; +}; + +&usbdp_phy0 { + rockchip,dp-lane-mux = <2 3>; + status = "okay"; +}; + +&usbdp_phy0_dp { + status = "disabled"; +}; + +&usbdp_phy0_u3 { + status = "okay"; +}; + +&usbdp_phy1 { + status = "okay"; +}; + +&usbdp_phy1_dp { + status = "okay"; +}; + +&usbdp_phy1_u3 { + status = "okay"; +}; + +&usbdrd3_0 { + status = "okay"; +}; + +&usbdrd_dwc3_0 { + dr_mode = "otg"; + extcon=<&u2phy0>; + status = "okay"; +}; + +&usbhost3_0 { + status = "okay"; +}; + +&usbhost_dwc3_0 { + status = "okay"; +}; + +&usbdrd3_1 { + status = "okay"; +}; + +&usbdrd_dwc3_1 { + dr_mode = "host"; + maximum-speed = "high-speed"; + phys = <&u2phy1_otg>; + phy-names = "usb2-phy"; + snps,dis_u2_susphy_quirk; + status = "okay"; +}; + +&vdpu { + status = "okay"; +}; + +&vdpu_mmu { + status = "okay"; +}; + +&vepu { + status = "okay"; +}; + +&vop { + status = "okay"; +}; + +&vop_mmu { + status = "okay"; +}; + +/* vp0 & vp1 splice for 8K output */ +&vp0 { + rockchip,plane-mask = <(1 << ROCKCHIP_VOP2_CLUSTER0 | 1 << ROCKCHIP_VOP2_ESMART0)>; + rockchip,primary-plane = ; +}; + +&vp1 { + rockchip,plane-mask = <(1 << ROCKCHIP_VOP2_CLUSTER1 | 1 << ROCKCHIP_VOP2_ESMART1)>; + rockchip,primary-plane = ; +}; + +&vp2 { + rockchip,plane-mask = <(1 << ROCKCHIP_VOP2_CLUSTER2 | 1 << ROCKCHIP_VOP2_ESMART2)>; + rockchip,primary-plane = ; +}; + +&vp3 { + rockchip,plane-mask = <(1 << ROCKCHIP_VOP2_CLUSTER3 | 1 << ROCKCHIP_VOP2_ESMART3)>; + rockchip,primary-plane = ; +}; From 709dbbec5e7183dbd5249c62f458563c365a4d73 Mon Sep 17 00:00:00 2001 From: Jon Lin Date: Fri, 14 Jul 2023 19:49:29 +0800 Subject: [PATCH 014/133] PCIe: dw: rockchip: Setting rk_pcie_hot_rst_wq before interrupt unmask Change-Id: I04d628dc2ac390bb5affe276e8c673daa8e14931 Signed-off-by: Jon Lin --- drivers/pci/controller/dwc/pcie-dw-rockchip.c | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index 2689d9df913d..760171b70bd4 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -2093,6 +2093,14 @@ retry_regulator: if (device_property_read_bool(dev, "rockchip,skip-scan-in-resume")) rk_pcie->skip_scan_in_resume = true; + rk_pcie->hot_rst_wq = create_singlethread_workqueue("rk_pcie_hot_rst_wq"); + if (!rk_pcie->hot_rst_wq) { + dev_err(dev, "failed to create hot_rst workqueue\n"); + ret = -ENOMEM; + goto remove_irq_domain; + } + INIT_WORK(&rk_pcie->hot_rst_work, rk_pcie_hot_rst_work); + switch (rk_pcie->mode) { case RK_PCIE_RC_TYPE: ret = rk_add_pcie_port(rk_pcie, pdev); @@ -2106,12 +2114,12 @@ retry_regulator: return 0; if (ret) - goto remove_irq_domain; + goto remove_rst_wq; ret = rk_pcie_init_dma_trx(rk_pcie); if (ret) { dev_err(dev, "failed to add dma extension\n"); - goto remove_irq_domain; + goto remove_rst_wq; } if (rk_pcie->dma_obj) { @@ -2123,19 +2131,11 @@ retry_regulator: /* hold link reset grant after link-up */ ret = rk_pcie_reset_grant_ctrl(rk_pcie, false); if (ret) - goto remove_irq_domain; + goto remove_rst_wq; } dw_pcie_dbi_ro_wr_dis(pci); - rk_pcie->hot_rst_wq = create_singlethread_workqueue("rk_pcie_hot_rst_wq"); - if (!rk_pcie->hot_rst_wq) { - dev_err(dev, "failed to create hot_rst workqueue\n"); - ret = -ENOMEM; - goto remove_irq_domain; - } - INIT_WORK(&rk_pcie->hot_rst_work, rk_pcie_hot_rst_work); - device_init_wakeup(dev, true); /* Enable async system PM for multiports SoC */ @@ -2159,6 +2159,8 @@ retry_regulator: return 0; +remove_rst_wq: + destroy_workqueue(rk_pcie->hot_rst_wq); remove_irq_domain: if (rk_pcie->irq_domain) irq_domain_remove(rk_pcie->irq_domain); From 6ee64dc3c149c2fe549f7a0677123684bd614d9c Mon Sep 17 00:00:00 2001 From: Damon Ding Date: Mon, 17 Jul 2023 18:00:49 +0800 Subject: [PATCH 015/133] ARM: dts: rockchip: fix frame rate of mcu panel to 60Hz for rv1103/rv1106 evb Signed-off-by: Damon Ding Change-Id: I32dab30576fca3df53138beb468090340c8cb1e1 --- .../boot/dts/rv1103g-evb-mcu-display-v11.dts | 36 +++++++++++++------ arch/arm/boot/dts/rv1106-evb-ext-mcu-v10.dtsi | 36 +++++++++++++------ 2 files changed, 52 insertions(+), 20 deletions(-) diff --git a/arch/arm/boot/dts/rv1103g-evb-mcu-display-v11.dts b/arch/arm/boot/dts/rv1103g-evb-mcu-display-v11.dts index 5d1c51bb86a1..5368752334bb 100644 --- a/arch/arm/boot/dts/rv1103g-evb-mcu-display-v11.dts +++ b/arch/arm/boot/dts/rv1103g-evb-mcu-display-v11.dts @@ -161,20 +161,23 @@ 00 00 01 36 01 00 01 48 - 00 00 01 3a //interface mode control - 01 00 01 77 //spi rgb:66(r1 r4 r5) mcu parallel: 55(r2 r3 r6) - // mcu serial: 77(r1 r3 r6) + 00 00 01 3a //interface pixel format + 01 00 01 77 // bpp cfg + // 3 11 + // 16 55 + // 18 66 + // 24 77 00 00 01 b0 //interface mode control 01 00 01 00 - 00 00 01 b1 //frame rate 70hz - 01 00 01 b0 + 00 00 01 b1 //frame rate 60hz + 01 00 01 a0 01 00 01 11 00 00 01 b4 01 00 01 02 - 00 00 01 B6 //RGB/MCU Interface Control - 01 00 01 02 //02 mcu, 32 rgb + 00 00 01 B6 + 01 00 01 02 01 00 01 02 00 00 01 b7 @@ -208,7 +211,7 @@ native-mode = <&kd050fwfba002_timing>; kd050fwfba002_timing: timing0 { - clock-frequency = <20000000>; + clock-frequency = <73174500>; hactive = <320>; vactive = <480>; hback-porch = <10>; @@ -267,10 +270,23 @@ &vop { status = "okay"; + /* + * Default config is as follows: + * + * mcu-pix-total = <9>; + * mcu-cs-pst = <1>; + * mcu-cs-pend = <8>; + * mcu-rw-pst = <2>; + * mcu-rw-pend = <5>; + * mcu-hold-mode = <0>; // default set to 0 + * + * Ruduce all parameters because the max vop dclk + * is 74.25M in rv1106. + */ mcu-timing { - mcu-pix-total = <9>; + mcu-pix-total = <7>; mcu-cs-pst = <1>; - mcu-cs-pend = <8>; + mcu-cs-pend = <6>; mcu-rw-pst = <2>; mcu-rw-pend = <5>; diff --git a/arch/arm/boot/dts/rv1106-evb-ext-mcu-v10.dtsi b/arch/arm/boot/dts/rv1106-evb-ext-mcu-v10.dtsi index cbc2e6ac6a16..d862112e99dd 100644 --- a/arch/arm/boot/dts/rv1106-evb-ext-mcu-v10.dtsi +++ b/arch/arm/boot/dts/rv1106-evb-ext-mcu-v10.dtsi @@ -155,20 +155,23 @@ 00 00 01 36 01 00 01 48 - 00 00 01 3a //interface mode control - 01 00 01 55 //spi rgb:66(r1 r4 r5) mcu parallel: 55(r2 r3 r6) - // mcu serial: 77(r1 r3 r6) + 00 00 01 3a //interface pixel format + 01 00 01 55 // bpp cfg + // 3 11 + // 16 55 + // 18 66 + // 24 77 00 00 01 b0 //interface mode control 01 00 01 00 - 00 00 01 b1 //frame rate 70hz - 01 00 01 b0 + 00 00 01 b1 //frame rate 60hz + 01 00 01 a0 01 00 01 11 00 00 01 b4 01 00 01 02 - 00 00 01 B6 //RGB/MCU Interface Control - 01 00 01 02 //02 mcu, 32 rgb + 00 00 01 B6 + 01 00 01 02 01 00 01 02 00 00 01 b7 @@ -202,7 +205,7 @@ native-mode = <&kd050fwfba002_timing>; kd050fwfba002_timing: timing0 { - clock-frequency = <20000000>; + clock-frequency = <73174500>; hactive = <320>; vactive = <480>; hback-porch = <10>; @@ -261,10 +264,23 @@ &vop { status = "okay"; + /* + * Default config is as follows: + * + * mcu-pix-total = <9>; + * mcu-cs-pst = <1>; + * mcu-cs-pend = <8>; + * mcu-rw-pst = <2>; + * mcu-rw-pend = <5>; + * mcu-hold-mode = <0>; // default set to 0 + * + * Ruduce all parameters because the max vop dclk + * is 74.25M in rv1106. + */ mcu-timing { - mcu-pix-total = <9>; + mcu-pix-total = <7>; mcu-cs-pst = <1>; - mcu-cs-pend = <8>; + mcu-cs-pend = <6>; mcu-rw-pst = <2>; mcu-rw-pend = <5>; From b181d44259ff171ea9815133c4cef321fef0cdd1 Mon Sep 17 00:00:00 2001 From: Damon Ding Date: Mon, 17 Jul 2023 18:40:47 +0800 Subject: [PATCH 016/133] arm64: dts: rockchip: fix frame rate of mcu panel to 60Hz for rk3308/rk3562 evb Signed-off-by: Damon Ding Change-Id: I85e7fc920360b44c70c409f160916ae449e84c68 --- .../boot/dts/rockchip/rk3308-evb-ext-v10.dtsi | 28 ++++++++++++++----- .../rockchip/rk3308bs-evb-ext-mcu-v10.dtsi | 18 +++++++----- .../rk3562-evb1-lp4x-v10-mcu-k350c4516t.dts | 19 +++++++------ .../rk3562-evb1-lp4x-v10-rgb-k350c4516t.dts | 18 +++++++----- 4 files changed, 54 insertions(+), 29 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3308-evb-ext-v10.dtsi b/arch/arm64/boot/dts/rockchip/rk3308-evb-ext-v10.dtsi index 1c0e66384c16..73089bf04e09 100644 --- a/arch/arm64/boot/dts/rockchip/rk3308-evb-ext-v10.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3308-evb-ext-v10.dtsi @@ -118,19 +118,23 @@ 00 00 01 36 01 00 01 48 - 00 00 01 3a /* interface mode control */ - 01 00 01 66 + 00 00 01 3a //interface pixel format + 01 00 01 66 // bpp cfg + // 3 11 + // 16 55 + // 18 66 + // 24 77 00 00 01 b0 /* interface mode control */ 01 00 01 00 - 00 00 01 b1 /* frame rate 70hz */ - 01 00 01 b0 + 00 00 01 b1 /* frame rate 60hz */ + 01 00 01 a0 01 00 01 11 00 00 01 b4 01 00 01 02 - 00 00 01 B6 /* RGB/MCU Interface Control */ - 01 00 01 32 /* 02 mcu, 32 rgb */ + 00 00 01 B6 + 01 00 01 32 01 00 01 02 00 00 01 b7 @@ -163,7 +167,7 @@ native-mode = <&kd050fwfba002_timing>; kd050fwfba002_timing: timing0 { - clock-frequency = <12000000>; + clock-frequency = <94081500>; hactive = <320>; vactive = <480>; hback-porch = <10>; @@ -232,4 +236,14 @@ &vop { status = "okay"; + + mcu-timing { + mcu-pix-total = <9>; + mcu-cs-pst = <1>; + mcu-cs-pend = <8>; + mcu-rw-pst = <2>; + mcu-rw-pend = <5>; + + mcu-hold-mode = <0>; // default set to 0 + }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3308bs-evb-ext-mcu-v10.dtsi b/arch/arm64/boot/dts/rockchip/rk3308bs-evb-ext-mcu-v10.dtsi index 990d00a570a2..095d2e197951 100644 --- a/arch/arm64/boot/dts/rockchip/rk3308bs-evb-ext-mcu-v10.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3308bs-evb-ext-mcu-v10.dtsi @@ -113,19 +113,23 @@ 00 00 01 36 01 00 01 48 - 00 00 01 3a //interface mode control - 01 00 01 55 //spi rgb:66(r1 r4 r5), mcu: 55(r2, r3 r6) + 00 00 01 3a //interface pixel format + 01 00 01 55 // bpp cfg + // 3 11 + // 16 55 + // 18 66 + // 24 77 00 00 01 b0 //interface mode control 01 00 01 00 - 00 00 01 b1 //frame rate 70hz - 01 00 01 b0 + 00 00 01 b1 //frame rate 60hz + 01 00 01 a0 01 00 01 11 00 00 01 b4 01 00 01 02 - 00 00 01 B6 //RGB/MCU Interface Control - 01 00 01 02 //02 mcu, 32 rgb + 00 00 01 B6 + 01 00 01 02 01 00 01 02 00 00 01 b7 @@ -159,7 +163,7 @@ native-mode = <&kd050fwfba002_timing>; kd050fwfba002_timing: timing0 { - clock-frequency = <20000000>; + clock-frequency = <94081500>; hactive = <320>; vactive = <480>; hback-porch = <10>; diff --git a/arch/arm64/boot/dts/rockchip/rk3562-evb1-lp4x-v10-mcu-k350c4516t.dts b/arch/arm64/boot/dts/rockchip/rk3562-evb1-lp4x-v10-mcu-k350c4516t.dts index d34221e26613..a462ed70f3b3 100644 --- a/arch/arm64/boot/dts/rockchip/rk3562-evb1-lp4x-v10-mcu-k350c4516t.dts +++ b/arch/arm64/boot/dts/rockchip/rk3562-evb1-lp4x-v10-mcu-k350c4516t.dts @@ -124,20 +124,23 @@ 00 00 01 36 01 00 01 48 - 00 00 01 3a //interface mode control - 01 00 01 55 //spi rgb:66(r1 r4 r5) mcu parallel: 55(r2 r3 r6) - // mcu serial: 77(r1 r3 r6) + 00 00 01 3a //interface pixel format + 01 00 01 55 // bpp cfg + // 3 11 + // 16 55 + // 18 66 + // 24 77 00 00 01 b0 //interface mode control 01 00 01 00 - 00 00 01 b1 //frame rate 70hz - 01 00 01 b0 + 00 00 01 b1 //frame rate 60hz + 01 00 01 a0 01 00 01 11 00 00 01 b4 01 00 01 02 - 00 00 01 B6 //RGB/MCU Interface Control - 01 00 01 02 //02 mcu, 32 rgb + 00 00 01 B6 + 01 00 01 02 01 00 01 02 00 00 01 b7 @@ -171,7 +174,7 @@ native-mode = <&kd050fwfba002_timing>; kd050fwfba002_timing: timing0 { - clock-frequency = <80000000>; + clock-frequency = <94081500>; hactive = <320>; vactive = <480>; hback-porch = <10>; diff --git a/arch/arm64/boot/dts/rockchip/rk3562-evb1-lp4x-v10-rgb-k350c4516t.dts b/arch/arm64/boot/dts/rockchip/rk3562-evb1-lp4x-v10-rgb-k350c4516t.dts index faaf453266f4..57c317a3bf2d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3562-evb1-lp4x-v10-rgb-k350c4516t.dts +++ b/arch/arm64/boot/dts/rockchip/rk3562-evb1-lp4x-v10-rgb-k350c4516t.dts @@ -99,19 +99,23 @@ 00 00 01 36 01 00 01 48 - 00 00 01 3a /* interface mode control */ - 01 00 01 66 + 00 00 01 3a //interface pixel format + 01 00 01 66 // bpp cfg + // 3 11 + // 16 55 + // 18 66 + // 24 77 00 00 01 b0 /* interface mode control */ 01 00 01 00 - 00 00 01 b1 /* frame rate 70hz */ - 01 00 01 b0 + 00 00 01 b1 /* frame rate 60hz */ + 01 00 01 a0 01 00 01 11 00 00 01 b4 01 00 01 02 - 00 00 01 B6 /* RGB/MCU Interface Control */ - 01 00 01 32 /* 02 mcu, 32 rgb */ + 00 00 01 B6 + 01 00 01 32 01 00 01 02 00 00 01 b7 @@ -144,7 +148,7 @@ native-mode = <&kd050fwfba002_timing>; kd050fwfba002_timing: timing0 { - clock-frequency = <12000000>; + clock-frequency = <10453500>; hactive = <320>; vactive = <480>; hback-porch = <10>; From 48a7374baa9887bab4ea87c878a40e2a692ff4fd Mon Sep 17 00:00:00 2001 From: Frank Wang Date: Mon, 10 Jul 2023 15:52:00 +0800 Subject: [PATCH 017/133] usb: typec: tcpm: fix dp altmode negotiation failure Do DR_SWAP (UFP/Sink swap to DFP/Sink) when received VDM DiscIdentity NAK or terminated in VDM DiscModes to fix altmode negotiation failure. This can fix a few odd DP monitor (DFP/Source) can not start DR_SWAP to UFP/Source role at DP altmode negotiation stage. Signed-off-by: Frank Wang Signed-off-by: Zhang Yubing Change-Id: Ieae9489c068064a20e04151f322ac82a71a72aa4 --- drivers/usb/typec/tcpm/tcpm.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index a088c6e91e37..141a14305335 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -1724,6 +1724,14 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev, rlen = 1; } else if (port->data_role == TYPEC_HOST) { tcpm_register_partner_altmodes(port); + } else { + /* Do dr_swap for ufp if the port supports drd */ + if (port->typec_caps.data == TYPEC_PORT_DRD && + !IS_ERR_OR_NULL(port->port_altmode[0])) { + port->vdm_sm_running = false; + port->upcoming_state = DR_SWAP_SEND; + tcpm_ams_start(port, DATA_ROLE_SWAP); + } } break; case CMD_ENTER_MODE: @@ -1755,6 +1763,16 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev, tcpm_ams_finish(port); switch (cmd) { case CMD_DISCOVER_IDENT: + /* Do dr_swap for ufp if the port supports drd */ + if (port->typec_caps.data == TYPEC_PORT_DRD && + port->data_role == TYPEC_DEVICE && + !IS_ERR_OR_NULL(port->port_altmode[0])) { + port->vdm_sm_running = false; + port->upcoming_state = DR_SWAP_SEND; + tcpm_ams_start(port, DATA_ROLE_SWAP); + break; + } + fallthrough; case CMD_DISCOVER_SVID: case CMD_DISCOVER_MODES: case VDO_CMD_VENDOR(0) ... VDO_CMD_VENDOR(15): From cedb72825d1bcd296ba097d9f7b3ed930b138b86 Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Tue, 27 Jun 2023 09:53:45 +0800 Subject: [PATCH 018/133] media: rockchip: vicap support tool video capture raw with rdbk by isp used in the case of thunderboot Signed-off-by: Zefa Chen Change-Id: I94e21fe6c130dd52f08cf695a5f1e46d555d7399 --- drivers/media/platform/rockchip/cif/capture.c | 89 ++++++++++++----- .../media/platform/rockchip/cif/cif-tools.c | 98 ++++++++++++++++++- drivers/media/platform/rockchip/cif/dev.h | 3 +- drivers/media/platform/rockchip/cif/procfs.c | 5 + .../media/platform/rockchip/cif/subdev-itf.c | 4 +- 5 files changed, 168 insertions(+), 31 deletions(-) diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index 94a2347feb78..ee29771164ca 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -1670,6 +1670,20 @@ static void rkcif_disable_skip_frame(struct rkcif_stream *stream) stream->skip_info.skip_en = false; } +static void rkcif_rdbk_with_tools(struct rkcif_stream *stream, + struct rkcif_rx_buffer *active_buf) +{ + unsigned long flags; + + spin_lock_irqsave(&stream->tools_vdev->vbq_lock, flags); + if (stream->tools_vdev->state == RKCIF_STATE_STREAMING) { + list_add_tail(&active_buf->list, &stream->tools_vdev->buf_done_head); + if (!work_busy(&stream->tools_vdev->work)) + schedule_work(&stream->tools_vdev->work); + } + spin_unlock_irqrestore(&stream->tools_vdev->vbq_lock, flags); +} + static void rkcif_rdbk_frame_end_toisp(struct rkcif_stream *stream, struct rkcif_rx_buffer *buffer) { @@ -1734,6 +1748,12 @@ static void rkcif_rdbk_frame_end_toisp(struct rkcif_stream *stream, rkcif_s_rx_buffer(dev, &dev->rdbk_rx_buf[RDBK_L]->dbufs); rkcif_s_rx_buffer(dev, &dev->rdbk_rx_buf[RDBK_M]->dbufs); rkcif_s_rx_buffer(dev, &dev->rdbk_rx_buf[RDBK_S]->dbufs); + rkcif_rdbk_with_tools(&dev->stream[RDBK_L], dev->rdbk_rx_buf[RDBK_L]); + rkcif_rdbk_with_tools(&dev->stream[RDBK_M], dev->rdbk_rx_buf[RDBK_M]); + rkcif_rdbk_with_tools(&dev->stream[RDBK_S], dev->rdbk_rx_buf[RDBK_S]); + atomic_dec(&dev->stream[RDBK_L].buf_cnt); + atomic_dec(&dev->stream[RDBK_M].buf_cnt); + atomic_dec(&dev->stream[RDBK_S].buf_cnt); dev->rdbk_rx_buf[RDBK_L] = NULL; dev->rdbk_rx_buf[RDBK_M] = NULL; dev->rdbk_rx_buf[RDBK_S] = NULL; @@ -1772,6 +1792,10 @@ static void rkcif_rdbk_frame_end_toisp(struct rkcif_stream *stream, dev->rdbk_rx_buf[RDBK_M]->dbufs.sequence = dev->rdbk_rx_buf[RDBK_L]->dbufs.sequence; rkcif_s_rx_buffer(dev, &dev->rdbk_rx_buf[RDBK_L]->dbufs); rkcif_s_rx_buffer(dev, &dev->rdbk_rx_buf[RDBK_M]->dbufs); + rkcif_rdbk_with_tools(&dev->stream[RDBK_L], dev->rdbk_rx_buf[RDBK_L]); + rkcif_rdbk_with_tools(&dev->stream[RDBK_M], dev->rdbk_rx_buf[RDBK_M]); + atomic_dec(&dev->stream[RDBK_L].buf_cnt); + atomic_dec(&dev->stream[RDBK_M].buf_cnt); dev->rdbk_rx_buf[RDBK_L] = NULL; dev->rdbk_rx_buf[RDBK_M] = NULL; } @@ -1889,14 +1913,18 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, active_buf->dbufs.timestamp = stream->readout.fs_timestamp; active_buf->fe_timestamp = ktime_get_ns(); stream->last_frame_idx = stream->frame_idx; - if (dev->hdr.hdr_mode == NO_HDR) + if (dev->hdr.hdr_mode == NO_HDR) { rkcif_s_rx_buffer(dev, &active_buf->dbufs); - else + if (dev->is_support_tools && stream->tools_vdev) + rkcif_rdbk_with_tools(stream, active_buf); + atomic_dec(&stream->buf_cnt); + } else { rkcif_rdbk_frame_end_toisp(stream, active_buf); - stream->buf_num_toisp--; + } } else { - rkcif_s_rx_buffer(dev, &stream->next_buf_toisp->dbufs); - stream->buf_num_toisp--; + rkcif_s_rx_buffer(dev, &active_buf->dbufs); + if (dev->is_support_tools && stream->tools_vdev) + rkcif_rdbk_with_tools(stream, active_buf); } } else if (stream->frame_phase == CIF_CSI_FRAME1_READY) { if (stream->curr_buf_toisp == stream->next_buf_toisp) @@ -1918,14 +1946,18 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, active_buf->dbufs.timestamp = stream->readout.fs_timestamp; active_buf->fe_timestamp = ktime_get_ns(); stream->last_frame_idx = stream->frame_idx; - if (dev->hdr.hdr_mode == NO_HDR) + if (dev->hdr.hdr_mode == NO_HDR) { rkcif_s_rx_buffer(dev, &active_buf->dbufs); - else + if (dev->is_support_tools && stream->tools_vdev) + rkcif_rdbk_with_tools(stream, active_buf); + atomic_dec(&stream->buf_cnt); + } else { rkcif_rdbk_frame_end_toisp(stream, active_buf); - stream->buf_num_toisp--; + } } else { - rkcif_s_rx_buffer(dev, &stream->curr_buf_toisp->dbufs); - stream->buf_num_toisp--; + rkcif_s_rx_buffer(dev, &active_buf->dbufs); + if (dev->is_support_tools && stream->tools_vdev) + rkcif_rdbk_with_tools(stream, active_buf); } } if (stream->lack_buf_cnt) @@ -1967,10 +1999,14 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, active_buf->dbufs.timestamp = stream->readout.fs_timestamp; active_buf->fe_timestamp = ktime_get_ns(); stream->last_frame_idx = stream->frame_idx; - if (dev->hdr.hdr_mode == NO_HDR) + if (dev->hdr.hdr_mode == NO_HDR) { rkcif_s_rx_buffer(dev, &active_buf->dbufs); - else + if (dev->is_support_tools && stream->tools_vdev) + rkcif_rdbk_with_tools(stream, active_buf); + atomic_dec(&stream->buf_cnt); + } else { rkcif_rdbk_frame_end_toisp(stream, active_buf); + } } else { if (stream->cifdev->rdbk_debug && dev->hw_dev->dummy_buf.vaddr) v4l2_info(&stream->cifdev->v4l2_dev, @@ -1978,6 +2014,8 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, stream->id, stream->frame_idx - 1); } + if (dev->is_support_tools && stream->tools_vdev && stream->curr_buf_toisp) + rkcif_rdbk_with_tools(stream, stream->curr_buf_toisp); } out_get_buf: @@ -2091,7 +2129,6 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) stream->id, stream->frame_idx - 1, frm_addr_y, (u32)stream->curr_buf_toisp->dummy.dma_addr); - stream->buf_num_toisp--; } } else if (frame_phase == CIF_CSI_FRAME1_READY) { active_buf = stream->next_buf_toisp; @@ -2109,7 +2146,6 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) stream->id, stream->frame_idx - 1, frm_addr_y, (u32)stream->next_buf_toisp->dummy.dma_addr); - stream->buf_num_toisp--; } } if (stream->lack_buf_cnt) @@ -2439,7 +2475,6 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, } if (dbufs) rkcif_s_rx_buffer(dev, dbufs); - stream->buf_num_toisp--; } } else { if (stream->dma_en & RKCIF_DMAEN_BY_ISP) { @@ -2460,7 +2495,6 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, dbufs = &stream->curr_buf_toisp->dbufs; } rkcif_s_rx_buffer(dev, dbufs); - stream->buf_num_toisp--; if (stream->curr_buf && stream->frame_phase == CIF_CSI_FRAME0_READY) { stream->curr_buf = NULL; if (stream->buf_replace_cnt) @@ -2507,7 +2541,6 @@ stop_dma: } if (dbufs) rkcif_s_rx_buffer(dev, dbufs); - stream->buf_num_toisp--; if (stream->frame_phase == CIF_CSI_FRAME0_READY && stream->curr_buf) { @@ -3955,7 +3988,7 @@ static int rkcif_queue_setup(struct vb2_queue *queue, plane_fmt = &pixm->plane_fmt[i]; sizes[i] = plane_fmt->sizeimage / height * h; } - + stream->total_buf_num = *num_buffers; v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, "%s count %d, size %d, extended(%d, %d)\n", v4l2_type_names[queue->type], *num_buffers, sizes[0], is_extended, extend_line->is_extended); @@ -4230,6 +4263,8 @@ void rkcif_free_rx_buf(struct rkcif_stream *stream, int buf_num) rkcif_free_buffer(dev, &buf->dummy); else list_add_tail(&buf->list_free, &priv->buf_free_list); + atomic_dec(&stream->buf_cnt); + stream->total_buf_num--; } if (dev->is_thunderboot) { @@ -4323,7 +4358,6 @@ int rkcif_init_rx_buf(struct rkcif_stream *stream, int buf_num) if (priv && priv->mode.rdbk_mode == RKISP_VICAP_ONLINE && i == 0) { buf->dbufs.is_first = true; rkcif_s_rx_buffer(dev, &buf->dbufs); - stream->buf_num_toisp--; } i++; if (!dev->is_thunderboot && i >= buf_num) { @@ -4339,7 +4373,8 @@ int rkcif_init_rx_buf(struct rkcif_stream *stream, int buf_num) (u64)dummy->dma_addr, pixm->plane_fmt[0].sizeimage); } if (priv->buf_num) { - stream->buf_num_toisp = priv->buf_num; + stream->total_buf_num = priv->buf_num; + atomic_set(&stream->buf_cnt, priv->buf_num); return 0; } else { return -EINVAL; @@ -4665,7 +4700,7 @@ void rkcif_do_stop_stream(struct rkcif_stream *stream, vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); } } - + stream->total_buf_num = 0; atomic_set(&stream->buf_cnt, 0); stream->lack_buf_cnt = 0; stream->dma_en &= ~RKCIF_DMAEN_BY_VICAP; @@ -8313,8 +8348,10 @@ static void rkcif_release_unnecessary_buf_for_online(struct rkcif_stream *stream spin_lock_irqsave(&priv->cif_dev->buffree_lock, flags); for (i = 0; i < priv->buf_num; i++) { rx_buf = &stream->rx_buf[i]; - if (rx_buf && (!rx_buf->dummy.is_free) && rx_buf != buf) + if (rx_buf && (!rx_buf->dummy.is_free) && rx_buf != buf) { list_add_tail(&rx_buf->list_free, &priv->buf_free_list); + stream->total_buf_num--; + } } spin_unlock_irqrestore(&priv->cif_dev->buffree_lock, flags); schedule_work(&priv->buffree_work.work); @@ -8384,11 +8421,13 @@ static void rkcif_line_wake_up_rdbk(struct rkcif_stream *stream, int mipi_id) active_buf->dbufs.timestamp = stream->readout.fs_timestamp; active_buf->fe_timestamp = ktime_get_ns(); stream->last_frame_idx = stream->frame_idx; - if (stream->cifdev->hdr.hdr_mode == NO_HDR) + if (stream->cifdev->hdr.hdr_mode == NO_HDR) { rkcif_s_rx_buffer(stream->cifdev, &active_buf->dbufs); - else + if (stream->cifdev->is_support_tools && stream->tools_vdev) + rkcif_rdbk_with_tools(stream, active_buf); + } else { rkcif_rdbk_frame_end_toisp(stream, active_buf); - stream->buf_num_toisp--; + } } } } diff --git a/drivers/media/platform/rockchip/cif/cif-tools.c b/drivers/media/platform/rockchip/cif/cif-tools.c index 5c9f2b812623..e3a676c04b4b 100644 --- a/drivers/media/platform/rockchip/cif/cif-tools.c +++ b/drivers/media/platform/rockchip/cif/cif-tools.c @@ -589,11 +589,8 @@ static int rkcif_tools_init_vb2_queue(struct vb2_queue *q, return vb2_queue_init(q); } -static void rkcif_tools_work(struct work_struct *work) +static void rkcif_tools_buf_done(struct rkcif_tools_vdev *tools_vdev) { - struct rkcif_tools_vdev *tools_vdev = container_of(work, - struct rkcif_tools_vdev, - work); struct rkcif_stream *stream = tools_vdev->stream; struct rkcif_tools_buffer *tools_buf; const struct cif_output_fmt *fmt = tools_vdev->tools_out_fmt; @@ -700,6 +697,99 @@ retry_done_buf: spin_unlock_irqrestore(&tools_vdev->vbq_lock, flags); } +static void rkcif_tools_buf_done_rdbk(struct rkcif_tools_vdev *tools_vdev) +{ + struct rkcif_stream *stream = tools_vdev->stream; + struct rkcif_device *dev = stream->cifdev; + const struct cif_output_fmt *fmt = tools_vdev->tools_out_fmt; + struct rkcif_rx_buffer *buf = NULL; + int i = 0; + unsigned long flags; + +retry_done_rdbk_buf: + spin_lock_irqsave(&tools_vdev->vbq_lock, flags); + if (!list_empty(&tools_vdev->buf_done_head)) { + buf = list_first_entry(&tools_vdev->buf_done_head, + struct rkcif_rx_buffer, list); + if (buf) + list_del(&buf->list); + } + spin_unlock_irqrestore(&tools_vdev->vbq_lock, flags); + if (!buf) { + v4l2_err(&dev->v4l2_dev, "stream[%d] tools fail to get buf form list\n", + stream->id); + return; + } + + if (tools_vdev->stopping) { + rkcif_tools_stop(tools_vdev); + tools_vdev->stopping = false; + spin_lock_irqsave(&tools_vdev->vbq_lock, flags); + while (!list_empty(&tools_vdev->buf_done_head)) { + buf = list_first_entry(&tools_vdev->buf_done_head, + struct rkcif_rx_buffer, list); + if (buf) + list_del(&buf->list); + } + spin_unlock_irqrestore(&tools_vdev->vbq_lock, flags); + wake_up(&tools_vdev->wq_stopped); + return; + } + + if (!list_empty(&tools_vdev->buf_head)) { + tools_vdev->curr_buf = list_first_entry(&tools_vdev->buf_head, + struct rkcif_buffer, queue); + if (!tools_vdev->curr_buf || tools_vdev->state != RKCIF_STATE_STREAMING) { + spin_lock_irqsave(&tools_vdev->vbq_lock, flags); + if (!list_empty(&tools_vdev->buf_done_head)) { + spin_unlock_irqrestore(&stream->tools_vdev->vbq_lock, flags); + goto retry_done_rdbk_buf; + } + spin_unlock_irqrestore(&tools_vdev->vbq_lock, flags); + return; + } + list_del(&tools_vdev->curr_buf->queue); + /* Dequeue a filled buffer */ + for (i = 0; i < fmt->mplanes; i++) { + u32 payload_size = tools_vdev->pixm.plane_fmt[i].sizeimage; + void *src = buf->dummy.vaddr; + void *dst = vb2_plane_vaddr(&tools_vdev->curr_buf->vb.vb2_buf, i); + + if (!src || !dst) + break; + dma_sync_single_for_device(dev->dev, + buf->dummy.dma_addr, + buf->dummy.size, + DMA_FROM_DEVICE); + vb2_set_plane_payload(&tools_vdev->curr_buf->vb.vb2_buf, i, + payload_size); + memcpy(dst, src, payload_size); + } + tools_vdev->curr_buf->vb.sequence = buf->dbufs.sequence; + tools_vdev->curr_buf->vb.vb2_buf.timestamp = buf->dbufs.timestamp; + vb2_buffer_done(&tools_vdev->curr_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + tools_vdev->curr_buf = NULL; + } + + spin_lock_irqsave(&tools_vdev->vbq_lock, flags); + if (!list_empty(&tools_vdev->buf_done_head)) { + spin_unlock_irqrestore(&stream->tools_vdev->vbq_lock, flags); + goto retry_done_rdbk_buf; + } + spin_unlock_irqrestore(&tools_vdev->vbq_lock, flags); +} + +static void rkcif_tools_work(struct work_struct *work) +{ + struct rkcif_tools_vdev *tools_vdev = container_of(work, + struct rkcif_tools_vdev, + work); + if (tools_vdev->stream->dma_en & RKCIF_DMAEN_BY_VICAP) + rkcif_tools_buf_done(tools_vdev); + else if (tools_vdev->stream->dma_en & RKCIF_DMAEN_BY_ISP) + rkcif_tools_buf_done_rdbk(tools_vdev); +} + void rkcif_init_tools_vdev(struct rkcif_device *cif_dev, u32 ch) { struct rkcif_tools_vdev *tools_vdev = &cif_dev->tools_vdev[ch]; diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index 503c5562f75d..8cdfab14fd27 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -193,6 +193,7 @@ struct rkcif_buffer { struct rkcif_tools_buffer { struct vb2_v4l2_buffer *vb; + struct rkisp_rx_buf *dbufs; struct list_head list; u32 frame_idx; u64 timestamp; @@ -526,7 +527,7 @@ struct rkcif_stream { unsigned int cur_stream_mode; struct rkcif_rx_buffer rx_buf[RKISP_VICAP_BUF_CNT_MAX]; struct list_head rx_buf_head; - int buf_num_toisp; + int total_buf_num; u64 line_int_cnt; int lack_buf_cnt; unsigned int buf_wake_up_cnt; diff --git a/drivers/media/platform/rockchip/cif/procfs.c b/drivers/media/platform/rockchip/cif/procfs.c index 9686faacf036..d9f063f63f13 100644 --- a/drivers/media/platform/rockchip/cif/procfs.c +++ b/drivers/media/platform/rockchip/cif/procfs.c @@ -376,6 +376,11 @@ static void rkcif_show_format(struct rkcif_device *dev, struct seq_file *f) atomic_read(&dev->stream[1].buf_cnt), atomic_read(&dev->stream[2].buf_cnt), atomic_read(&dev->stream[3].buf_cnt)); + seq_printf(f, "total buf_cnt: %d %d %d %d\n", + dev->stream[0].total_buf_num, + dev->stream[1].total_buf_num, + dev->stream[2].total_buf_num, + dev->stream[3].total_buf_num); } } diff --git a/drivers/media/platform/rockchip/cif/subdev-itf.c b/drivers/media/platform/rockchip/cif/subdev-itf.c index 7f850cc75e47..27f83002ca37 100644 --- a/drivers/media/platform/rockchip/cif/subdev-itf.c +++ b/drivers/media/platform/rockchip/cif/subdev-itf.c @@ -781,8 +781,8 @@ static int sditf_s_rx_buffer(struct v4l2_subdev *sd, rx_buf = to_cif_rx_buf(dbufs); spin_lock_irqsave(&stream->vbq_lock, flags); - stream->buf_num_toisp++; stream->last_rx_buf_idx = dbufs->sequence + 1; + atomic_inc(&stream->buf_cnt); if (!list_empty(&stream->rx_buf_head) && cif_dev->is_thunderboot && @@ -791,6 +791,8 @@ static int sditf_s_rx_buffer(struct v4l2_subdev *sd, spin_lock_irqsave(&cif_dev->buffree_lock, buffree_flags); list_add_tail(&rx_buf->list_free, &priv->buf_free_list); spin_unlock_irqrestore(&cif_dev->buffree_lock, buffree_flags); + atomic_dec(&stream->buf_cnt); + stream->total_buf_num--; schedule_work(&priv->buffree_work.work); is_free = true; } From 903953ddebfbd3ca01e494ac27f85af7db3fa580 Mon Sep 17 00:00:00 2001 From: Sandy Huang Date: Mon, 17 Jul 2023 20:12:35 +0800 Subject: [PATCH 019/133] drm/rockchip: vop2: update pre_dither_down config 1. config vp1 pre_dither_down at split mode; 2. disable pre_dither_down at YUV 10/8 bit output and RGB 10 bit output; 3. enable pre_dither_down at RGB 8/6 bit output; Signed-off-by: Sandy Huang Change-Id: I304fc66324c97e3e4f50e03b8c8c2c1835871b1a --- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 22 +++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index c70cd445146a..edd0edde70d9 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -6736,37 +6736,37 @@ static bool vop2_crtc_mode_fixup(struct drm_crtc *crtc, return true; } -static void vop2_dither_setup(struct drm_crtc *crtc) +static void vop2_dither_setup(struct rockchip_crtc_state *vcstate, struct drm_crtc *crtc) { - struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); struct vop2_video_port *vp = to_vop2_video_port(crtc); struct vop2 *vop2 = vp->vop2; + bool pre_dither_down_en = false; switch (vcstate->bus_format) { case MEDIA_BUS_FMT_RGB565_1X16: VOP_MODULE_SET(vop2, vp, dither_down_en, 1); VOP_MODULE_SET(vop2, vp, dither_down_mode, RGB888_TO_RGB565); - VOP_MODULE_SET(vop2, vp, pre_dither_down_en, 1); + pre_dither_down_en = true; break; case MEDIA_BUS_FMT_RGB666_1X18: case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: VOP_MODULE_SET(vop2, vp, dither_down_en, 1); VOP_MODULE_SET(vop2, vp, dither_down_mode, RGB888_TO_RGB666); - VOP_MODULE_SET(vop2, vp, pre_dither_down_en, 1); + pre_dither_down_en = true; break; case MEDIA_BUS_FMT_YUYV8_1X16: case MEDIA_BUS_FMT_YUV8_1X24: case MEDIA_BUS_FMT_UYYVYY8_0_5X24: VOP_MODULE_SET(vop2, vp, dither_down_en, 0); - VOP_MODULE_SET(vop2, vp, pre_dither_down_en, 1); + pre_dither_down_en = true; break; case MEDIA_BUS_FMT_YUYV10_1X20: case MEDIA_BUS_FMT_YUV10_1X30: case MEDIA_BUS_FMT_UYYVYY10_0_5X30: case MEDIA_BUS_FMT_RGB101010_1X30: VOP_MODULE_SET(vop2, vp, dither_down_en, 0); - VOP_MODULE_SET(vop2, vp, pre_dither_down_en, 0); + pre_dither_down_en = false; break; case MEDIA_BUS_FMT_RGB888_3X8: case MEDIA_BUS_FMT_RGB888_DUMMY_4X8: @@ -6775,10 +6775,14 @@ static void vop2_dither_setup(struct drm_crtc *crtc) case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: default: VOP_MODULE_SET(vop2, vp, dither_down_en, 0); - VOP_MODULE_SET(vop2, vp, pre_dither_down_en, 1); + pre_dither_down_en = true; break; } + if (is_yuv_output(vcstate->bus_format)) + pre_dither_down_en = false; + + VOP_MODULE_SET(vop2, vp, pre_dither_down_en, pre_dither_down_en); VOP_MODULE_SET(vop2, vp, dither_down_sel, DITHER_DOWN_ALLEGRO); } @@ -9742,7 +9746,9 @@ static void vop2_cfg_update(struct drm_crtc *crtc, vop2_post_color_swap(crtc); - vop2_dither_setup(crtc); + vop2_dither_setup(vcstate, crtc); + if (vcstate->splice_mode) + vop2_dither_setup(vcstate, &splice_vp->rockchip_crtc.crtc); VOP_MODULE_SET(vop2, vp, overlay_mode, vcstate->yuv_overlay); From 4056d4ef2caab5fddec02c7ef08e71929b5c2dec Mon Sep 17 00:00:00 2001 From: Sandy Huang Date: Tue, 18 Apr 2023 15:54:10 +0800 Subject: [PATCH 020/133] drm/rockchip: vop2: only legacy gamma set need extra config done The legacy api drmModeCrtcSetGammalegacy can be called independently, so it need extra config done; and the atomic api have config done at the vop2_crtc_atomic_flush(); Signed-off-by: Sandy Huang Change-Id: Idca4c42f1d298ec312dc839ee526e4132d9d8b73 --- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 45 +++++++++++--------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index edd0edde70d9..4c12c3ee4a6d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -3391,7 +3391,6 @@ static void rk3568_crtc_load_lut(struct drm_crtc *crtc) VOP_MODULE_SET(vop2, vp, dsp_lut_en, 1); vop2_write_reg_uncached(vop2, &vp->regs->gamma_update_en, 1); - vop2_cfg_done(crtc); vp->gamma_lut_active = true; spin_unlock(&vop2->reg_lock); @@ -3438,26 +3437,7 @@ static void vop2_crtc_load_lut(struct drm_crtc *crtc) rk3588_crtc_load_lut(&vp->rockchip_crtc.crtc, vp->lut); if (vcstate->splice_mode) rk3588_crtc_load_lut(&splice_vp->rockchip_crtc.crtc, vp->lut); - vop2_cfg_done(crtc); } - /* - * maybe appear the following case: - * -> set gamma - * -> config done - * -> atomic commit - * --> update win format - * --> update win address - * ---> here maybe meet vop hardware frame start, and triggle some config take affect. - * ---> as only some config take affect, this maybe lead to iommu pagefault. - * --> update win size - * --> update win other parameters - * -> config done - * - * so we add vop2_wait_for_fs_by_done_bit_status() to make sure the first config done take - * effect and then to do next frame config. - */ - if (VOP_MODULE_GET(vop2, vp, standby) == 0) - vop2_wait_for_fs_by_done_bit_status(vp); } static void rockchip_vop2_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, @@ -3499,6 +3479,7 @@ static int vop2_crtc_legacy_gamma_set(struct drm_crtc *crtc, u16 *red, struct drm_modeset_acquire_ctx *ctx) { struct vop2_video_port *vp = to_vop2_video_port(crtc); + struct vop2 *vop2 = vp->vop2; int i; if (!vp->lut) @@ -3513,6 +3494,25 @@ static int vop2_crtc_legacy_gamma_set(struct drm_crtc *crtc, u16 *red, rockchip_vop2_crtc_fb_gamma_set(crtc, red[i], green[i], blue[i], i); vop2_crtc_load_lut(crtc); + vop2_cfg_done(crtc); + /* + * maybe appear the following case: + * -> set gamma + * -> config done + * -> atomic commit + * --> update win format + * --> update win address + * ---> here maybe meet vop hardware frame start, and triggle some config take affect. + * ---> as only some config take affect, this maybe lead to iommu pagefault. + * --> update win size + * --> update win other parameters + * -> config done + * + * so we add vop2_wait_for_fs_by_done_bit_status() to make sure the first config done take + * effect and then to do next frame config. + */ + if (VOP_MODULE_GET(vop2, vp, standby) == 0) + vop2_wait_for_fs_by_done_bit_status(vp); return 0; } @@ -8040,8 +8040,11 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state /* * restore the lut table. */ - if (vp->gamma_lut_active) + if (vp->gamma_lut_active) { vop2_crtc_load_lut(crtc); + vop2_cfg_done(crtc); + vop2_wait_for_fs_by_done_bit_status(vp); + } out: vop2_unlock(vop2); } From 01947f7dfd274abb910be04c4be7e1a35052727e Mon Sep 17 00:00:00 2001 From: Luo Wei Date: Mon, 17 Jul 2023 16:42:35 +0800 Subject: [PATCH 021/133] arm64: dts: rockchip: rk3588-vehicle: fix lt7911 compatible name error Signed-off-by: Luo Wei Change-Id: I0bff3c570e8b5a4d374e4c895f5868a3049c7f88 --- .../dts/rockchip/rk3588-vehicle-serdes-display-v21.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-display-v21.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-display-v21.dtsi index eb927ddb0ddf..425cfeeacb69 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-display-v21.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-vehicle-serdes-display-v21.dtsi @@ -1060,7 +1060,7 @@ }; lt7911d@2b { - compatible = "lontium,lt7911d"; + compatible = "lontium,lt7911d-fb-notifier"; reg = <0x2b>; reset-gpios = <&gpio3 RK_PD4 GPIO_ACTIVE_LOW>; status = "okay"; @@ -1268,7 +1268,7 @@ }; lt7911d@2b { - compatible = "lontium,lt7911d"; + compatible = "lontium,lt7911d-fb-notifier"; reg = <0x2b>; reset-gpios = <&gpio0 RK_PD2 GPIO_ACTIVE_LOW>; status = "okay"; @@ -1686,7 +1686,7 @@ }; lt7911d@2b { - compatible = "lontium,lt7911d"; + compatible = "lontium,lt7911d-fb-notifier"; reg = <0x2b>; reset-gpios = <&gpio4 RK_PA7 GPIO_ACTIVE_LOW>; status = "okay"; @@ -1895,7 +1895,7 @@ }; lt7911d@2b { - compatible = "lontium,lt7911d"; + compatible = "lontium,lt7911d-fb-notifier"; reg = <0x2b>; reset-gpios = <&gpio3 RK_PD2 GPIO_ACTIVE_LOW>; status = "okay"; From bea83cc7bcebff1207cd659e7532d6fb8c2efb78 Mon Sep 17 00:00:00 2001 From: William Wu Date: Mon, 10 Jul 2023 11:16:06 +0800 Subject: [PATCH 022/133] phy: rockchip: inno-usb2: enable bvalid detect irq upon resume The voltage domain of the usb2 phy grf interrupt mask register usually belongs to the VD_LOGIC in most of Rockchip SoCs. So if the VD_LOGIC is power off after system suspend, the configuration of the usb2 phy grf interrupt mask may lost when resume. Test on RK3588 platform with micro usb2.0 interface, if this case happened, the usb device failed to connect to host, because the usb device depends on the bvalid irq to start the enumeration. This patch enable the bvalid detect irq upon resume for otg port, and schedule the otg sm delayed work if the bvalid is high which means that usb device has connected to Host. Change-Id: I29245ec4fc812e45eb3f52cc5c2c270b659a0cc6 Signed-off-by: William Wu --- drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index fe928d98f9f0..fdf1ebaf3ec6 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -3123,6 +3123,26 @@ static int rockchip_usb2phy_pm_resume(struct device *dev) } } + /* Enable bvalid detect irq */ + if (rport->port_id == USB2PHY_PORT_OTG && + (rport->mode == USB_DR_MODE_PERIPHERAL || + rport->mode == USB_DR_MODE_OTG) && + (rport->bvalid_irq > 0 || rport->otg_mux_irq > 0 || rphy->irq > 0) && + !rport->vbus_always_on) { + ret = rockchip_usb2phy_enable_vbus_irq(rphy, rport, + true); + if (ret) { + dev_err(rphy->dev, + "failed to enable bvalid irq\n"); + return ret; + } + + if (property_enabled(rphy->grf, &rport->port_cfg->utmi_bvalid)) + schedule_delayed_work(&rport->otg_sm_work, + OTG_SCHEDULE_DELAY); + + } + if (rport->port_id == USB2PHY_PORT_OTG && wakeup_enable && rport->bvalid_irq > 0) disable_irq_wake(rport->bvalid_irq); From 01edaa491afb2ae7283be0a6bb949497bc14a417 Mon Sep 17 00:00:00 2001 From: Wang Panzhenzhuan Date: Thu, 13 Jul 2023 02:27:49 +0000 Subject: [PATCH 023/133] video: rockchip: vehicle: support config rotate & mirror simultaneously usage: dts config /*0:no, 1:90; 2:180; 4:270; 0x10:mirror-y; 0x20:mirror-x*/ vehicle,rotate-mirror = <0x11>; means do mirror-y and rotate 90 degree together Signed-off-by: Wang Panzhenzhuan Change-Id: Iadda38968ae1950a81d244e37954aeb84d66d75e --- .../video/rockchip/vehicle/vehicle_flinger.c | 59 +++++++++++++++---- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/drivers/video/rockchip/vehicle/vehicle_flinger.c b/drivers/video/rockchip/vehicle/vehicle_flinger.c index a40c33b53dd9..e2c0e676ba85 100644 --- a/drivers/video/rockchip/vehicle/vehicle_flinger.c +++ b/drivers/video/rockchip/vehicle/vehicle_flinger.c @@ -325,8 +325,11 @@ int vehicle_flinger_init(struct device *dev, struct vehicle_cfg *v_cfg) if (inited) return 0; + VEHICLE_INFO("%s: v_cfg->rotate_mirror(0x%x)\n", __func__, v_cfg->rotate_mirror); + // if (FORCE_ROTATION == RGA_TRANSFORM_ROT_270 || FORCE_ROTATION == RGA_TRANSFORM_ROT_90) { - if (v_cfg->rotate_mirror == 0x01 || v_cfg->rotate_mirror == 0x04) { + if ((v_cfg->rotate_mirror & RGA_TRANSFORM_ROT_MASK) == 0x01 || + (v_cfg->rotate_mirror & RGA_TRANSFORM_ROT_MASK) == 0x04) { w = FORCE_WIDTH; h = ALIGN(FORCE_HEIGHT, 64); s = ALIGN(FORCE_HEIGHT, 64); @@ -386,7 +389,8 @@ int vehicle_flinger_init(struct device *dev, struct vehicle_cfg *v_cfg) // f = HAL_PIXEL_FORMAT_RGBX_8888; // if (FORCE_ROTATION == RGA_TRANSFORM_ROT_270 || // FORCE_ROTATION == RGA_TRANSFORM_ROT_90) - if (v_cfg->rotate_mirror == 0x01 || v_cfg->rotate_mirror == 0x04) + if ((v_cfg->rotate_mirror & RGA_TRANSFORM_ROT_MASK) == 0x01 || + (v_cfg->rotate_mirror & RGA_TRANSFORM_ROT_MASK) == 0x04) ret = rk_flinger_alloc_buffer(flg, buffer, h, w, s, f); else ret = rk_flinger_alloc_buffer(flg, buffer, w, h, s, f); @@ -527,7 +531,7 @@ rk_flinger_cacultae_dst_rect_by_rotation(struct graphic_buffer *buffer) src_rect = &buffer->src; dst_rect = &buffer->dst; - switch (buffer->rotation) { + switch (buffer->rotation & RGA_TRANSFORM_ROT_MASK) { case RGA_TRANSFORM_ROT_90: case RGA_TRANSFORM_ROT_270: dst_rect->x = src_rect->x; @@ -954,19 +958,41 @@ static int rk_flinger_rga_blit(struct flinger *flinger, static int rk_flinger_rga_render(struct flinger *flinger, struct graphic_buffer *src_buffer, - struct graphic_buffer *dst_buffer) + struct graphic_buffer *dst_buffer, + struct graphic_buffer *tmp_buffer) { + int rotation; + if (!flinger || !src_buffer || !dst_buffer) return -EINVAL; if (dst_buffer && dst_buffer->rel_fence) dst_buffer->rel_fence = NULL; - rk_flinger_rga_blit(flinger, src_buffer, dst_buffer); - rk_flinger_fill_buffer_rects(dst_buffer, &src_buffer->dst, - &src_buffer->dst); - dst_buffer->src.f = src_buffer->dst.f; + if ((src_buffer->rotation & RGA_TRANSFORM_ROT_MASK) && + (src_buffer->rotation & RGA_TRANSFORM_FLIP_MASK)) { + rotation = flinger->v_cfg.rotate_mirror; + /* 1. rotate */ + src_buffer->rotation = rotation & RGA_TRANSFORM_ROT_MASK; + rk_flinger_rga_blit(flinger, src_buffer, tmp_buffer); + rk_flinger_fill_buffer_rects(tmp_buffer, &src_buffer->dst, + &src_buffer->dst); + tmp_buffer->src.f = src_buffer->dst.f; + tmp_buffer->rotation = rotation & RGA_TRANSFORM_FLIP_MASK; + /* 2. mirror */ + rk_flinger_rga_blit(flinger, tmp_buffer, dst_buffer); + rk_flinger_fill_buffer_rects(dst_buffer, &tmp_buffer->dst, + &tmp_buffer->dst); + dst_buffer->src.f = src_buffer->dst.f; + + src_buffer->rotation = rotation; + } else { + rk_flinger_rga_blit(flinger, src_buffer, dst_buffer); + rk_flinger_fill_buffer_rects(dst_buffer, &src_buffer->dst, + &src_buffer->dst); + dst_buffer->src.f = src_buffer->dst.f; + } /* save rga out buffer */ if (vehicle_dump_rga) { struct file *filep = NULL; @@ -1306,7 +1332,7 @@ try_again: iep_buffer = &(flg->target_buffer[NUM_TARGET_BUFFERS - 1]); iep_buffer->state = ACQUIRE; //scaler by rga to force widthxheight display - rk_flinger_rga_render(flg, src_buffer, iep_buffer); + rk_flinger_rga_render(flg, src_buffer, iep_buffer, dst_buffer); src_buffer->state = FREE; rk_flinger_rga_scaler(flg, iep_buffer, dst_buffer); iep_buffer->state = FREE; @@ -1321,7 +1347,7 @@ try_again: } else { // cvbs VEHICLE_DG("it is a cvbs signal\n"); - rk_flinger_rga_render(flg, src_buffer, dst_buffer); + rk_flinger_rga_render(flg, src_buffer, dst_buffer, iep_buffer); src_buffer->state = FREE; rk_flinger_iep_deinterlace(flg, dst_buffer, iep_buffer); dst_buffer->state = FREE; @@ -1387,18 +1413,27 @@ rk_flinger_lookup_buffer_by_phy_addr(unsigned long phy_addr) static bool vehicle_rotation_param_check(struct vehicle_cfg *v_cfg) { - switch (v_cfg->rotate_mirror) { + switch (v_cfg->rotate_mirror & RGA_TRANSFORM_ROT_MASK) { case RGA_TRANSFORM_ROT_90: case RGA_TRANSFORM_ROT_270: case RGA_TRANSFORM_ROT_0: case RGA_TRANSFORM_ROT_180: + return true; + default: + VEHICLE_INFO("invalid rotate-mirror param %d\n", + v_cfg->rotate_mirror); + v_cfg->rotate_mirror = v_cfg->rotate_mirror & RGA_TRANSFORM_FLIP_MASK; + return false; + } + + switch (v_cfg->rotate_mirror & RGA_TRANSFORM_FLIP_MASK) { case RGA_TRANSFORM_FLIP_H: case RGA_TRANSFORM_FLIP_V: return true; default: VEHICLE_INFO("invalid rotate-mirror param %d\n", v_cfg->rotate_mirror); - v_cfg->rotate_mirror = 0; + v_cfg->rotate_mirror = v_cfg->rotate_mirror & RGA_TRANSFORM_ROT_MASK; return false; } } From ec50666d2117669813e7d006179074b922029f94 Mon Sep 17 00:00:00 2001 From: Guochun Huang Date: Wed, 19 Jul 2023 01:41:08 +0000 Subject: [PATCH 024/133] phy: rockchip: mipi-dcphy: fix HSTX_CLK_SEL config set HSTX_CLK_SEL 1`b1 when cphy lane rate under 500Msps, while set HSTX_CLK_SEL 1`b1 when dphy lane rate under 1500Mbps Change-Id: Ic42ce385c1952febe0327594231f6bffb2543c5e Signed-off-by: Guochun Huang --- drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c b/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c index 8e9e71923791..48b570d5a4a7 100644 --- a/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c +++ b/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c @@ -1466,9 +1466,9 @@ static void samsung_mipi_cphy_timing_init(struct samsung_mipi_dcphy *samsung) /* * Divide-by-2 Clock from Serial Clock. Use this when data rate is under - * 1500Mbps, otherwise divide-by-16 Clock from Serial Clock + * 500Msps, otherwise divide-by-16 Clock from Serial Clock */ - if (lane_hs_rate < 1500) + if (lane_hs_rate < 500) val = HSTX_CLK_SEL; val |= T_LPX(timing->lpx); From 82da1a9d3cc9847b258529c057389f4e94d9f6fb Mon Sep 17 00:00:00 2001 From: Yifeng Zhao Date: Fri, 28 Apr 2023 08:38:02 +0800 Subject: [PATCH 025/133] mms: rk_sdmmc_ops: support multi-blocks ops Signed-off-by: Yifeng Zhao Change-Id: I39c6fd9756124c120b64fd1caa478c93750e2ea5 --- drivers/mmc/host/rk_sdmmc_ops.c | 6 +++--- drivers/mmc/host/rk_sdmmc_ops.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/rk_sdmmc_ops.c b/drivers/mmc/host/rk_sdmmc_ops.c index 96f20d2dcfc7..47967a40915a 100644 --- a/drivers/mmc/host/rk_sdmmc_ops.c +++ b/drivers/mmc/host/rk_sdmmc_ops.c @@ -131,7 +131,7 @@ static int rk_emmc_wait_busy(void) /* * Transfer a single sector of kernel addressable data */ -int rk_emmc_transfer(u8 *buffer, unsigned addr, unsigned blksz, int write) +int rk_emmc_transfer(u8 *buffer, unsigned int addr, unsigned int datasz, int write) { int ret = 0; enum emmc_area_type areatype; @@ -150,9 +150,9 @@ int rk_emmc_transfer(u8 *buffer, unsigned addr, unsigned blksz, int write) mrq.data = &data; mrq.stop = &stop; - sg_init_one(&sg, buffer, blksz); + sg_init_one(&sg, buffer, datasz); - rk_emmc_prepare_mrq(&mrq, &sg, 1, addr, 1, blksz, write); + rk_emmc_prepare_mrq(&mrq, &sg, 1, addr, datasz / BLKSZ, BLKSZ, write); mmc_claim_host(this_card->host); diff --git a/drivers/mmc/host/rk_sdmmc_ops.h b/drivers/mmc/host/rk_sdmmc_ops.h index 8261d69f561d..81890ab6a94e 100644 --- a/drivers/mmc/host/rk_sdmmc_ops.h +++ b/drivers/mmc/host/rk_sdmmc_ops.h @@ -6,6 +6,6 @@ #ifndef _RK_SDMMC_OPS_H_ #define _RK_SDMMC_OPS_H_ -int rk_emmc_transfer(u8 *buffer, unsigned int addr, unsigned int blksz, int write); +int rk_emmc_transfer(u8 *buffer, unsigned int addr, unsigned int datasz, int write); #endif From e0bf8700b9c6151f999655b41a06420c662c795b Mon Sep 17 00:00:00 2001 From: Yifeng Zhao Date: Fri, 28 Apr 2023 08:59:13 +0800 Subject: [PATCH 026/133] soc: rockchip: sdmmc_vendor_storage: Using multiple blocks of read/write data Signed-off-by: Yifeng Zhao Change-Id: If642f464ca22df4e27574fc020fce0312a062b36 --- drivers/soc/rockchip/sdmmc_vendor_storage.c | 29 ++++----------------- 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/drivers/soc/rockchip/sdmmc_vendor_storage.c b/drivers/soc/rockchip/sdmmc_vendor_storage.c index d8681b920742..ea1d9410b8eb 100644 --- a/drivers/soc/rockchip/sdmmc_vendor_storage.c +++ b/drivers/soc/rockchip/sdmmc_vendor_storage.c @@ -49,12 +49,7 @@ static DEFINE_MUTEX(vendor_ops_mutex); static int emmc_vendor_ops(u8 *buffer, u32 addr, u32 n_sec, int write) { - u32 i, ret = 0; - - for (i = 0; i < n_sec; i++) - ret = rk_emmc_transfer(buffer + i * 512, addr + i, 512, write); - - return ret; + return rk_emmc_transfer(buffer, addr, n_sec << 9, write); } static int emmc_vendor_storage_init(void) @@ -210,34 +205,20 @@ static int emmc_vendor_write(u32 id, void *pbuf, u32 size) #ifdef CONFIG_ROCKCHIP_VENDOR_STORAGE_UPDATE_LOADER static int id_blk_read_data(u32 index, u32 n_sec, u8 *buf) { - u32 i; - u32 ret = 0; - if (index + n_sec >= 1024 * 5) return 0; index = index + EMMC_IDB_PART_OFFSET; - for (i = 0; i < n_sec; i++) { - ret = rk_emmc_transfer(buf + i * 512, index + i, 512, 0); - if (ret) - return ret; - } - return ret; + + return rk_emmc_transfer(buf, index, n_sec << 9, 0); } static int id_blk_write_data(u32 index, u32 n_sec, u8 *buf) { - u32 i; - u32 ret = 0; - if (index + n_sec >= 1024 * 5) return 0; index = index + EMMC_IDB_PART_OFFSET; - for (i = 0; i < n_sec; i++) { - ret = rk_emmc_transfer(buf + i * 512, index + i, 512, 1); - if (ret) - return ret; - } - return ret; + + return rk_emmc_transfer(buf, index, n_sec << 9, 1); } static int emmc_write_idblock(u32 size, u8 *buf, u32 *id_blk_tbl) From 5d45ac929fb1189c2eb3706482eaa0d68e824ae9 Mon Sep 17 00:00:00 2001 From: Yifeng Zhao Date: Thu, 25 May 2023 10:25:09 +0800 Subject: [PATCH 027/133] mms: rk_sdmmc_ops: disabled command queue while execute Signed-off-by: Yifeng Zhao Change-Id: I1cdca1d01012de8749b0033367ae050c87f19193 --- drivers/mmc/host/rk_sdmmc_ops.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/mmc/host/rk_sdmmc_ops.c b/drivers/mmc/host/rk_sdmmc_ops.c index 47967a40915a..b731d7dae085 100644 --- a/drivers/mmc/host/rk_sdmmc_ops.c +++ b/drivers/mmc/host/rk_sdmmc_ops.c @@ -156,6 +156,12 @@ int rk_emmc_transfer(u8 *buffer, unsigned int addr, unsigned int datasz, int wri mmc_claim_host(this_card->host); + if (this_card->ext_csd.cmdq_en) { + ret = mmc_cmdq_disable(this_card); + if (ret) + goto exit; + } + areatype = (enum emmc_area_type)this_card->ext_csd.part_config & EXT_CSD_PART_CONFIG_ACC_MASK; if (areatype != MMC_DATA_AREA_MAIN) { @@ -186,6 +192,9 @@ int rk_emmc_transfer(u8 *buffer, unsigned int addr, unsigned int datasz, int wri } exit: + if (this_card->reenable_cmdq && !this_card->ext_csd.cmdq_en) + mmc_cmdq_enable(this_card); + mmc_release_host(this_card->host); return ret; } From 5ff437c20084df9226bf49d03d630d0ebbfd28ce Mon Sep 17 00:00:00 2001 From: Yifeng Zhao Date: Tue, 18 Jul 2023 16:12:34 +0800 Subject: [PATCH 028/133] mms: rk_sdmmc_ops: support resume and suspend Signed-off-by: Yifeng Zhao Change-Id: Idb3168b4b33cf1251390b783c1aa798db39782da --- drivers/mmc/host/rk_sdmmc_ops.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/mmc/host/rk_sdmmc_ops.c b/drivers/mmc/host/rk_sdmmc_ops.c index b731d7dae085..d0ef613ae60e 100644 --- a/drivers/mmc/host/rk_sdmmc_ops.c +++ b/drivers/mmc/host/rk_sdmmc_ops.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include "../core/block.h" #include "../core/card.h" #include "../core/core.h" @@ -154,6 +156,7 @@ int rk_emmc_transfer(u8 *buffer, unsigned int addr, unsigned int datasz, int wri rk_emmc_prepare_mrq(&mrq, &sg, 1, addr, datasz / BLKSZ, BLKSZ, write); + pm_runtime_get_sync(&this_card->dev); mmc_claim_host(this_card->host); if (this_card->ext_csd.cmdq_en) { @@ -196,6 +199,8 @@ exit: mmc_cmdq_enable(this_card); mmc_release_host(this_card->host); + pm_runtime_put(&this_card->dev); + return ret; } EXPORT_SYMBOL(rk_emmc_transfer); From bcc5f7e0258ec1ad15eda7de6484d607c7153b4e Mon Sep 17 00:00:00 2001 From: Finley Xiao Date: Mon, 17 Jul 2023 11:13:00 +0800 Subject: [PATCH 029/133] arm64: dts: rockchip: rk3588s: Add package serial number for otp Signed-off-by: Finley Xiao Change-Id: Icbae70352ba127bb327d5c86580da30259d36742 --- arch/arm64/boot/dts/rockchip/rk3588s.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi index 6c0bce60eedf..76561f5b8f5e 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi @@ -6372,6 +6372,14 @@ cpu_code: cpu-code@2 { reg = <0x02 0x2>; }; + package_serial_number_high: package-serial-number-high@5 { + reg = <0x05 0x1>; + bits = <0 1>; + }; + package_serial_number_low: package-serial-number-low@6 { + reg = <0x06 0x1>; + bits = <5 3>; + }; specification_serial_number: specification-serial-number@6 { reg = <0x06 0x1>; bits = <0 5>; From 9adfbb364a4b3148fcda177fcb780d7a393bfcc5 Mon Sep 17 00:00:00 2001 From: Finley Xiao Date: Mon, 17 Jul 2023 11:13:30 +0800 Subject: [PATCH 030/133] arm64: dts: rockchip: rk3588s: Add nvmem-cells for rkcif Signed-off-by: Finley Xiao Change-Id: I6e98ce0ce435637f0522c3a67e86117bcd4dc103 --- arch/arm64/boot/dts/rockchip/rk3588s.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi index 76561f5b8f5e..8c30ebf334ad 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi @@ -4355,6 +4355,12 @@ power-domains = <&power RK3588_PD_VI>; rockchip,grf = <&sys_grf>; iommus = <&rkcif_mmu>; + nvmem-cells = <&specification_serial_number>, + <&package_serial_number_low>, + <&package_serial_number_high>; + nvmem-cell-names = "specification", + "package_low", + "package_high"; status = "disabled"; }; From 69c3088116adb36c5b0263007cb46a212fd7fa47 Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Wed, 7 Sep 2022 15:20:54 +0800 Subject: [PATCH 031/133] arm64: dts: rockchip: rk3588 mipi dphy config modify 1. all logic node of mipi phy can get all hw of mipi phy 2. the links between logic and hw is determined by upper level equipmen Signed-off-by: Zefa Chen Change-Id: Icc0cb88c3294a119431ac24b0043e44e34b1b292 --- arch/arm64/boot/dts/rockchip/rk3588.dtsi | 36 --------- arch/arm64/boot/dts/rockchip/rk3588s.dtsi | 92 +++++++++++++++++------ 2 files changed, 70 insertions(+), 58 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3588.dtsi b/arch/arm64/boot/dts/rockchip/rk3588.dtsi index ad414c61fd38..9d5ead9396d7 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588.dtsi @@ -9,9 +9,6 @@ / { aliases { - csi2dphy3 = &csi2_dphy3; - csi2dphy4 = &csi2_dphy4; - csi2dphy5 = &csi2_dphy5; dp0 = &dp0; dp1 = &dp1; edp0 = &edp0; @@ -30,27 +27,6 @@ usbdp1 = &usbdp_phy1; }; - /* dphy1 full mode */ - csi2_dphy3: csi2-dphy3 { - compatible = "rockchip,rk3568-csi2-dphy"; - rockchip,hw = <&csi2_dphy1_hw>; - status = "disabled"; - }; - - /* dphy1 split mode 01 */ - csi2_dphy4: csi2-dphy4 { - compatible = "rockchip,rk3568-csi2-dphy"; - rockchip,hw = <&csi2_dphy1_hw>; - status = "disabled"; - }; - - /* dphy1 split mode 23 */ - csi2_dphy5: csi2-dphy5 { - compatible = "rockchip,rk3568-csi2-dphy"; - rockchip,hw = <&csi2_dphy1_hw>; - status = "disabled"; - }; - rkcif_mipi_lvds4: rkcif-mipi-lvds4 { compatible = "rockchip,rkcif-mipi-lvds"; rockchip,hw = <&rkcif>; @@ -868,18 +844,6 @@ }; }; - csi2_dphy1_hw: csi2-dphy1-hw@fedc8000 { - compatible = "rockchip,rk3588-csi2-dphy-hw"; - reg = <0x0 0xfedc8000 0x0 0x8000>; - clocks = <&cru PCLK_CSIPHY1>; - clock-names = "pclk"; - resets = <&cru SRST_CSIPHY1>, <&cru SRST_P_CSIPHY1>; - reset-names = "srst_csiphy1", "srst_p_csiphy1"; - rockchip,grf = <&mipidphy1_grf>; - rockchip,sys_grf = <&sys_grf>; - status = "disabled"; - }; - combphy1_ps: phy@fee10000 { compatible = "rockchip,rk3588-naneng-combphy"; reg = <0x0 0xfee10000 0x0 0x100>; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi index 8c30ebf334ad..48b777886bd8 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi @@ -26,6 +26,9 @@ csi2dphy0 = &csi2_dphy0; csi2dphy1 = &csi2_dphy1; csi2dphy2 = &csi2_dphy2; + csi2dphy3 = &csi2_dphy3; + csi2dphy4 = &csi2_dphy4; + csi2dphy5 = &csi2_dphy5; dsi0 = &dsi0; dsi1 = &dsi1; ethernet1 = &gmac1; @@ -1586,37 +1589,66 @@ }; csi2_dcphy0: csi2-dcphy0 { - compatible = "rockchip,rk3588-csi2-dcphy"; - phys = <&mipi_dcphy0>; - phy-names = "dcphy"; + compatible = "rockchip,rk3588-csi2-dphy"; + rockchip,hw = <&csi2_dphy0_hw>, <&csi2_dphy1_hw>; + phys = <&mipidcphy0>, <&mipidcphy1>; + phy-names = "dcphy0", "dcphy1"; status = "disabled"; }; csi2_dcphy1: csi2-dcphy1 { - compatible = "rockchip,rk3588-csi2-dcphy"; - phys = <&mipi_dcphy1>; - phy-names = "dcphy"; + compatible = "rockchip,rk3588-csi2-dphy"; + rockchip,hw = <&csi2_dphy0_hw>, <&csi2_dphy1_hw>; + phys = <&mipidcphy0>, <&mipidcphy1>; + phy-names = "dcphy0", "dcphy1"; status = "disabled"; }; - /* dphy0 full mode */ csi2_dphy0: csi2-dphy0 { - compatible = "rockchip,rk3568-csi2-dphy"; - rockchip,hw = <&csi2_dphy0_hw>; + compatible = "rockchip,rk3588-csi2-dphy"; + rockchip,hw = <&csi2_dphy0_hw>, <&csi2_dphy1_hw>; + phys = <&mipidcphy0>, <&mipidcphy1>; + phy-names = "dcphy0", "dcphy1"; status = "disabled"; }; - /* dphy0 split mode 01 */ csi2_dphy1: csi2-dphy1 { - compatible = "rockchip,rk3568-csi2-dphy"; - rockchip,hw = <&csi2_dphy0_hw>; + compatible = "rockchip,rk3588-csi2-dphy"; + rockchip,hw = <&csi2_dphy0_hw>, <&csi2_dphy1_hw>; + phys = <&mipidcphy0>, <&mipidcphy1>; + phy-names = "dcphy0", "dcphy1"; status = "disabled"; }; - /* dphy0 split mode 23 */ csi2_dphy2: csi2-dphy2 { - compatible = "rockchip,rk3568-csi2-dphy"; - rockchip,hw = <&csi2_dphy0_hw>; + compatible = "rockchip,rk3588-csi2-dphy"; + rockchip,hw = <&csi2_dphy0_hw>, <&csi2_dphy1_hw>; + phys = <&mipidcphy0>, <&mipidcphy1>; + phy-names = "dcphy0", "dcphy1"; + status = "disabled"; + }; + + csi2_dphy3: csi2-dphy3 { + compatible = "rockchip,rk3588-csi2-dphy"; + rockchip,hw = <&csi2_dphy0_hw>, <&csi2_dphy1_hw>; + phys = <&mipidcphy0>, <&mipidcphy1>; + phy-names = "dcphy0", "dcphy1"; + status = "disabled"; + }; + + csi2_dphy4: csi2-dphy4 { + compatible = "rockchip,rk3588-csi2-dphy"; + rockchip,hw = <&csi2_dphy0_hw>, <&csi2_dphy1_hw>; + phys = <&mipidcphy0>, <&mipidcphy1>; + phy-names = "dcphy0", "dcphy1"; + status = "disabled"; + }; + + csi2_dphy5: csi2-dphy5 { + compatible = "rockchip,rk3588-csi2-dphy"; + rockchip,hw = <&csi2_dphy0_hw>, <&csi2_dphy1_hw>; + phys = <&mipidcphy0>, <&mipidcphy1>; + phy-names = "dcphy0", "dcphy1"; status = "disabled"; }; @@ -1860,6 +1892,10 @@ status = "disabled"; }; + /omit-if-no-ref/ + mipi_dcphy1: mipi_dcphy0: mipi-dcphy-dummy { + }; + mpp_srv: mpp-srv { compatible = "rockchip,mpp-service"; rockchip,taskqueue-count = <12>; @@ -4710,7 +4746,7 @@ resets = <&cru SRST_P_DSIHOST0>; reset-names = "apb"; power-domains = <&power RK3588_PD_VOP>; - phys = <&mipi_dcphy0>; + phys = <&mipidcphy0>; phy-names = "dcphy"; rockchip,grf = <&vop_grf>; #address-cells = <1>; @@ -4750,7 +4786,7 @@ resets = <&cru SRST_P_DSIHOST1>; reset-names = "apb"; power-domains = <&power RK3588_PD_VOP>; - phys = <&mipi_dcphy1>; + phys = <&mipidcphy1>; phy-names = "dcphy"; rockchip,grf = <&vop_grf>; #address-cells = <1>; @@ -6534,7 +6570,7 @@ }; }; - mipi_dcphy0: phy@feda0000 { + mipidcphy0: phy@feda0000 { compatible = "rockchip,rk3588-mipi-dcphy"; reg = <0x0 0xfeda0000 0x0 0x10000>; rockchip,grf = <&mipidcphy0_grf>; @@ -6547,10 +6583,10 @@ <&cru SRST_S_MIPI_DCPHY0>; reset-names = "m_phy", "apb", "grf", "s_phy"; #phy-cells = <0>; - status = "disabled"; + status = "okay"; }; - mipi_dcphy1: phy@fedb0000 { + mipidcphy1: phy@fedb0000 { compatible = "rockchip,rk3588-mipi-dcphy"; reg = <0x0 0xfedb0000 0x0 0x10000>; rockchip,grf = <&mipidcphy1_grf>; @@ -6563,7 +6599,7 @@ <&cru SRST_S_MIPI_DCPHY1>; reset-names = "m_phy", "apb", "grf", "s_phy"; #phy-cells = <0>; - status = "disabled"; + status = "okay"; }; csi2_dphy0_hw: csi2-dphy0-hw@fedc0000 { @@ -6575,7 +6611,19 @@ reset-names = "srst_csiphy0", "srst_p_csiphy0"; rockchip,grf = <&mipidphy0_grf>; rockchip,sys_grf = <&sys_grf>; - status = "disabled"; + status = "okay"; + }; + + csi2_dphy1_hw: csi2-dphy1-hw@fedc8000 { + compatible = "rockchip,rk3588-csi2-dphy-hw"; + reg = <0x0 0xfedc8000 0x0 0x8000>; + clocks = <&cru PCLK_CSIPHY1>; + clock-names = "pclk"; + resets = <&cru SRST_CSIPHY1>, <&cru SRST_P_CSIPHY1>; + reset-names = "srst_csiphy1", "srst_p_csiphy1"; + rockchip,grf = <&mipidphy1_grf>; + rockchip,sys_grf = <&sys_grf>; + status = "okay"; }; combphy0_ps: phy@fee00000 { From 4efcdeacf3a7846f4c14a2a1bf5bd79a81bc39da Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Wed, 7 Sep 2022 15:07:21 +0800 Subject: [PATCH 032/133] arm64: dts: rockchip: rk3588 separate the node of csi2 logic and hw logical and physical nodes are separated, one logic node can connect multi hw node Signed-off-by: Zefa Chen Change-Id: Ibb75cc466452aedff8f50d29331b191d2fbd922a --- arch/arm64/boot/dts/rockchip/rk3588.dtsi | 28 ------ arch/arm64/boot/dts/rockchip/rk3588s.dtsi | 102 +++++++++++++++++++--- 2 files changed, 89 insertions(+), 41 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3588.dtsi b/arch/arm64/boot/dts/rockchip/rk3588.dtsi index 9d5ead9396d7..0f78f6e6a20e 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588.dtsi @@ -168,34 +168,6 @@ reg = <0x0 0xfd5e4000 0x0 0x100>; }; - mipi4_csi2: mipi4-csi2@fdd50000 { - compatible = "rockchip,rk3588-mipi-csi2"; - reg = <0x0 0xfdd50000 0x0 0x10000>; - reg-names = "csihost_regs"; - interrupts = , - ; - interrupt-names = "csi-intr1", "csi-intr2"; - clocks = <&cru PCLK_CSI_HOST_4>; - clock-names = "pclk_csi2host"; - resets = <&cru SRST_P_CSI_HOST_4>; - reset-names = "srst_csihost_p"; - status = "disabled"; - }; - - mipi5_csi2: mipi5-csi2@fdd60000 { - compatible = "rockchip,rk3588-mipi-csi2"; - reg = <0x0 0xfdd60000 0x0 0x10000>; - reg-names = "csihost_regs"; - interrupts = , - ; - interrupt-names = "csi-intr1", "csi-intr2"; - clocks = <&cru PCLK_CSI_HOST_5>; - clock-names = "pclk_csi2host"; - resets = <&cru SRST_P_CSI_HOST_5>; - reset-names = "srst_csihost_p"; - status = "disabled"; - }; - spdif_tx5: spdif-tx@fddb8000 { compatible = "rockchip,rk3588-spdif", "rockchip,rk3568-spdif"; reg = <0x0 0xfddb8000 0x0 0x1000>; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi index 48b777886bd8..dcd429389151 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi @@ -1896,6 +1896,54 @@ mipi_dcphy1: mipi_dcphy0: mipi-dcphy-dummy { }; + mipi0_csi2: mipi0-csi2 { + compatible = "rockchip,rk3588-mipi-csi2"; + rockchip,hw = <&mipi0_csi2_hw>, <&mipi1_csi2_hw>, + <&mipi2_csi2_hw>, <&mipi3_csi2_hw>, + <&mipi4_csi2_hw>, <&mipi5_csi2_hw>; + status = "disabled"; + }; + + mipi1_csi2: mipi1-csi2 { + compatible = "rockchip,rk3588-mipi-csi2"; + rockchip,hw = <&mipi0_csi2_hw>, <&mipi1_csi2_hw>, + <&mipi2_csi2_hw>, <&mipi3_csi2_hw>, + <&mipi4_csi2_hw>, <&mipi5_csi2_hw>; + status = "disabled"; + }; + + mipi2_csi2: mipi2-csi2 { + compatible = "rockchip,rk3588-mipi-csi2"; + rockchip,hw = <&mipi0_csi2_hw>, <&mipi1_csi2_hw>, + <&mipi2_csi2_hw>, <&mipi3_csi2_hw>, + <&mipi4_csi2_hw>, <&mipi5_csi2_hw>; + status = "disabled"; + }; + + mipi3_csi2: mipi3-csi2 { + compatible = "rockchip,rk3588-mipi-csi2"; + rockchip,hw = <&mipi0_csi2_hw>, <&mipi1_csi2_hw>, + <&mipi2_csi2_hw>, <&mipi3_csi2_hw>, + <&mipi4_csi2_hw>, <&mipi5_csi2_hw>; + status = "disabled"; + }; + + mipi4_csi2: mipi4-csi2 { + compatible = "rockchip,rk3588-mipi-csi2"; + rockchip,hw = <&mipi0_csi2_hw>, <&mipi1_csi2_hw>, + <&mipi2_csi2_hw>, <&mipi3_csi2_hw>, + <&mipi4_csi2_hw>, <&mipi5_csi2_hw>; + status = "disabled"; + }; + + mipi5_csi2: mipi5-csi2 { + compatible = "rockchip,rk3588-mipi-csi2"; + rockchip,hw = <&mipi0_csi2_hw>, <&mipi1_csi2_hw>, + <&mipi2_csi2_hw>, <&mipi3_csi2_hw>, + <&mipi4_csi2_hw>, <&mipi5_csi2_hw>; + status = "disabled"; + }; + mpp_srv: mpp-srv { compatible = "rockchip,mpp-service"; rockchip,taskqueue-count = <12>; @@ -4414,8 +4462,8 @@ status = "disabled"; }; - mipi0_csi2: mipi0-csi2@fdd10000 { - compatible = "rockchip,rk3588-mipi-csi2"; + mipi0_csi2_hw: mipi0-csi2-hw@fdd10000 { + compatible = "rockchip,rk3588-mipi-csi2-hw"; reg = <0x0 0xfdd10000 0x0 0x10000>; reg-names = "csihost_regs"; interrupts = , @@ -4425,11 +4473,11 @@ clock-names = "pclk_csi2host"; resets = <&cru SRST_P_CSI_HOST_0>; reset-names = "srst_csihost_p"; - status = "disabled"; + status = "okay"; }; - mipi1_csi2: mipi1-csi2@fdd20000 { - compatible = "rockchip,rk3588-mipi-csi2"; + mipi1_csi2_hw: mipi1-csi2-hw@fdd20000 { + compatible = "rockchip,rk3588-mipi-csi2-hw"; reg = <0x0 0xfdd20000 0x0 0x10000>; reg-names = "csihost_regs"; interrupts = , @@ -4438,12 +4486,12 @@ clocks = <&cru PCLK_CSI_HOST_1>; clock-names = "pclk_csi2host"; resets = <&cru SRST_P_CSI_HOST_1>; - reset-names = "srst_csihost_p", "srst_csihost_vicap"; - status = "disabled"; + reset-names = "srst_csihost_p"; + status = "okay"; }; - mipi2_csi2: mipi2-csi2@fdd30000 { - compatible = "rockchip,rk3588-mipi-csi2"; + mipi2_csi2_hw: mipi2-csi2-hw@fdd30000 { + compatible = "rockchip,rk3588-mipi-csi2-hw"; reg = <0x0 0xfdd30000 0x0 0x10000>; reg-names = "csihost_regs"; interrupts = , @@ -4453,11 +4501,11 @@ clock-names = "pclk_csi2host"; resets = <&cru SRST_P_CSI_HOST_2>; reset-names = "srst_csihost_p"; - status = "disabled"; + status = "okay"; }; - mipi3_csi2: mipi3-csi2@fdd40000 { - compatible = "rockchip,rk3588-mipi-csi2"; + mipi3_csi2_hw: mipi3-csi2-hw@fdd40000 { + compatible = "rockchip,rk3588-mipi-csi2-hw"; reg = <0x0 0xfdd40000 0x0 0x10000>; reg-names = "csihost_regs"; interrupts = , @@ -4467,7 +4515,35 @@ clock-names = "pclk_csi2host"; resets = <&cru SRST_P_CSI_HOST_3>; reset-names = "srst_csihost_p"; - status = "disabled"; + status = "okay"; + }; + + mipi4_csi2_hw: mipi4-csi2-hw@fdd50000 { + compatible = "rockchip,rk3588-mipi-csi2-hw"; + reg = <0x0 0xfdd50000 0x0 0x10000>; + reg-names = "csihost_regs"; + interrupts = , + ; + interrupt-names = "csi-intr1", "csi-intr2"; + clocks = <&cru PCLK_CSI_HOST_4>; + clock-names = "pclk_csi2host"; + resets = <&cru SRST_P_CSI_HOST_4>; + reset-names = "srst_csihost_p"; + status = "okay"; + }; + + mipi5_csi2_hw: mipi5-csi2-hw@fdd60000 { + compatible = "rockchip,rk3588-mipi-csi2-hw"; + reg = <0x0 0xfdd60000 0x0 0x10000>; + reg-names = "csihost_regs"; + interrupts = , + ; + interrupt-names = "csi-intr1", "csi-intr2"; + clocks = <&cru PCLK_CSI_HOST_5>; + clock-names = "pclk_csi2host"; + resets = <&cru SRST_P_CSI_HOST_5>; + reset-names = "srst_csihost_p"; + status = "okay"; }; vop: vop@fdd90000 { From 841fa2175dceb692130b15ced678ba71342048c7 Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Mon, 3 Oct 2022 21:38:56 +0800 Subject: [PATCH 033/133] arm64: dts: rockchip: rk3568 separate the node of csi2 and hw Signed-off-by: Zefa Chen Change-Id: Ia3694d29ee53a1ccd46e2e375eed94ce45dcf1fc --- arch/arm64/boot/dts/rockchip/rk3568.dtsi | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3568.dtsi b/arch/arm64/boot/dts/rockchip/rk3568.dtsi index c28278bc5642..cd7b5fdfd298 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3568.dtsi @@ -309,6 +309,12 @@ }; }; + mipi_csi2: mipi-csi2 { + compatible = "rockchip,rk3568-mipi-csi2"; + rockchip,hw = <&mipi_csi2_hw>; + status = "disabled"; + }; + mpp_srv: mpp-srv { compatible = "rockchip,mpp-service"; rockchip,taskqueue-count = <6>; @@ -1640,8 +1646,8 @@ status = "disabled"; }; - mipi_csi2: mipi-csi2@fdfb0000 { - compatible = "rockchip,rk3568-mipi-csi2"; + mipi_csi2_hw: mipi-csi2-hw@fdfb0000 { + compatible = "rockchip,rk3568-mipi-csi2-hw"; reg = <0x0 0xfdfb0000 0x0 0x10000>; reg-names = "csihost_regs"; interrupts = , From a2af16b03a37b72aa7c96c28083f418ff4aeb2ea Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Fri, 14 Jul 2023 14:23:46 +0800 Subject: [PATCH 034/133] arm64: dts: rockchip: rk3562 separate hw node of mipi csi2 and mipi dphy Signed-off-by: Zefa Chen Change-Id: I9e23e9b94cb851f31c6701deb5d57b1e8297a7b5 --- arch/arm64/boot/dts/rockchip/rk3562.dtsi | 68 +++++++++++++++++------- 1 file changed, 48 insertions(+), 20 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3562.dtsi b/arch/arm64/boot/dts/rockchip/rk3562.dtsi index 57cefcbcba8e..4ec5f3c5cbc7 100644 --- a/arch/arm64/boot/dts/rockchip/rk3562.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3562.dtsi @@ -384,42 +384,42 @@ /* dphy0 full mode */ csi2_dphy0: csi2-dphy0 { compatible = "rockchip,rk3562-csi2-dphy"; - rockchip,hw = <&csi2_dphy0_hw>; + rockchip,hw = <&csi2_dphy0_hw>, <&csi2_dphy1_hw>; status = "disabled"; }; /* dphy0 split mode 01 */ csi2_dphy1: csi2-dphy1 { compatible = "rockchip,rk3562-csi2-dphy"; - rockchip,hw = <&csi2_dphy0_hw>; + rockchip,hw = <&csi2_dphy0_hw>, <&csi2_dphy1_hw>; status = "disabled"; }; /* dphy0 split mode 23 */ csi2_dphy2: csi2-dphy2 { compatible = "rockchip,rk3562-csi2-dphy"; - rockchip,hw = <&csi2_dphy0_hw>; + rockchip,hw = <&csi2_dphy0_hw>, <&csi2_dphy1_hw>; status = "disabled"; }; /* dphy1 full mode */ csi2_dphy3: csi2-dphy3 { compatible = "rockchip,rk3562-csi2-dphy"; - rockchip,hw = <&csi2_dphy1_hw>; + rockchip,hw = <&csi2_dphy0_hw>, <&csi2_dphy1_hw>; status = "disabled"; }; /* dphy1 split mode 01 */ csi2_dphy4: csi2-dphy4 { compatible = "rockchip,rk3562-csi2-dphy"; - rockchip,hw = <&csi2_dphy1_hw>; + rockchip,hw = <&csi2_dphy0_hw>, <&csi2_dphy1_hw>; status = "disabled"; }; /* dphy1 split mode 23 */ csi2_dphy5: csi2-dphy5 { compatible = "rockchip,rk3562-csi2-dphy"; - rockchip,hw = <&csi2_dphy1_hw>; + rockchip,hw = <&csi2_dphy0_hw>, <&csi2_dphy1_hw>; status = "disabled"; }; @@ -536,6 +536,34 @@ status = "disabled"; }; + mipi0_csi2: mipi0-csi2 { + compatible = "rockchip,rk3562-mipi-csi2"; + rockchip,hw = <&mipi0_csi2_hw>, <&mipi1_csi2_hw>, + <&mipi2_csi2_hw>, <&mipi3_csi2_hw>; + status = "disabled"; + }; + + mipi1_csi2: mipi1-csi2 { + compatible = "rockchip,rk3562-mipi-csi2"; + rockchip,hw = <&mipi0_csi2_hw>, <&mipi1_csi2_hw>, + <&mipi2_csi2_hw>, <&mipi3_csi2_hw>; + status = "disabled"; + }; + + mipi2_csi2: mipi2-csi2 { + compatible = "rockchip,rk3562-mipi-csi2"; + rockchip,hw = <&mipi0_csi2_hw>, <&mipi1_csi2_hw>, + <&mipi2_csi2_hw>, <&mipi3_csi2_hw>; + status = "disabled"; + }; + + mipi3_csi2: mipi3-csi2 { + compatible = "rockchip,rk3562-mipi-csi2"; + rockchip,hw = <&mipi0_csi2_hw>, <&mipi1_csi2_hw>, + <&mipi2_csi2_hw>, <&mipi3_csi2_hw>; + status = "disabled"; + }; + psci { compatible = "arm,psci-1.0"; method = "smc"; @@ -1554,8 +1582,8 @@ status = "disabled"; }; - mipi0_csi2: mipi0-csi2@ff380000 { - compatible = "rockchip,rk3562-mipi-csi2"; + mipi0_csi2_hw: mipi0-csi2-hw@ff380000 { + compatible = "rockchip,rk3562-mipi-csi2-hw"; reg = <0x0 0xff380000 0x0 0x10000>; reg-names = "csihost_regs"; interrupts = , @@ -1565,11 +1593,11 @@ clock-names = "pclk_csi2host"; resets = <&cru SRST_P_CSIHOST0>; reset-names = "srst_csihost_p"; - status = "disabled"; + status = "okay"; }; - mipi1_csi2: mipi1-csi2@ff390000 { - compatible = "rockchip,rk3562-mipi-csi2"; + mipi1_csi2_hw: mipi1-csi2-hw@ff390000 { + compatible = "rockchip,rk3562-mipi-csi2-hw"; reg = <0x0 0xff390000 0x0 0x10000>; reg-names = "csihost_regs"; interrupts = , @@ -1579,11 +1607,11 @@ clock-names = "pclk_csi2host"; resets = <&cru SRST_P_CSIHOST1>; reset-names = "srst_csihost_p"; - status = "disabled"; + status = "okay"; }; - mipi2_csi2: mipi2-csi2@ff3a0000 { - compatible = "rockchip,rk3562-mipi-csi2"; + mipi2_csi2_hw: mipi2-csi2-hw@ff3a0000 { + compatible = "rockchip,rk3562-mipi-csi2-hw"; reg = <0x0 0xff3a0000 0x0 0x10000>; reg-names = "csihost_regs"; interrupts = , @@ -1593,11 +1621,11 @@ clock-names = "pclk_csi2host"; resets = <&cru SRST_P_CSIHOST2>; reset-names = "srst_csihost_p"; - status = "disabled"; + status = "okay"; }; - mipi3_csi2: mipi3-csi2@ff3b0000 { - compatible = "rockchip,rk3562-mipi-csi2"; + mipi3_csi2_hw: mipi3-csi2-hw@ff3b0000 { + compatible = "rockchip,rk3562-mipi-csi2-hw"; reg = <0x0 0xff3b0000 0x0 0x10000>; reg-names = "csihost_regs"; interrupts = , @@ -1607,7 +1635,7 @@ clock-names = "pclk_csi2host"; resets = <&cru SRST_P_CSIHOST3>; reset-names = "srst_csihost_p"; - status = "disabled"; + status = "okay"; }; csi2_dphy0_hw: csi2-dphy0-hw@ff3c0000 { @@ -1618,7 +1646,7 @@ resets = <&cru SRST_P_CSIPHY0>; reset-names = "srst_p_csiphy0"; rockchip,grf = <&sys_grf>; - status = "disabled"; + status = "okay"; }; csi2_dphy1_hw: csi2-dphy1-hw@ff3d0000 { @@ -1629,7 +1657,7 @@ resets = <&cru SRST_P_CSIPHY1>; reset-names = "srst_p_csiphy1"; rockchip,grf = <&sys_grf>; - status = "disabled"; + status = "okay"; }; rkcif: rkcif@ff3e0000 { From d4c693bd95ca8c9d439d3d6840e93f84fd6dce4a Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Mon, 3 Oct 2022 21:46:37 +0800 Subject: [PATCH 035/133] arm64: dts: rockchip: rk1808 separate the node of csi2 and hw Signed-off-by: Zefa Chen Change-Id: I4fdacd6bcac96094ea7746828fbab3e05b31fbab --- arch/arm64/boot/dts/rockchip/rk1808.dtsi | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk1808.dtsi b/arch/arm64/boot/dts/rockchip/rk1808.dtsi index 297b41269efb..3401beb0837b 100644 --- a/arch/arm64/boot/dts/rockchip/rk1808.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk1808.dtsi @@ -247,6 +247,12 @@ #clock-cells = <0>; }; + mipi_csi2: mipi-csi2 { + compatible = "rockchip,rk1808-mipi-csi2"; + rockchip,hw = <&mipi_csi2_hw>; + status = "disabled"; + }; + psci { compatible = "arm,psci-1.0"; method = "smc"; @@ -1525,8 +1531,8 @@ status = "disabled"; }; - mipi_csi2: mipi-csi2@ffb10000 { - compatible = "rockchip,rk1808-mipi-csi2"; + mipi_csi2_hw: mipi-csi2-hw@ffb10000 { + compatible = "rockchip,rk1808-mipi-csi2-hw"; reg = <0x0 0xffb10000 0x0 0x100>; reg-names = "csihost_regs"; interrupts = , From f442c757df9f57f1f61fd361223925a3410a6dab Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Mon, 3 Oct 2022 21:33:01 +0800 Subject: [PATCH 036/133] ARM: dts: rockchip: rv1126 separate the node of csi2 and hw Signed-off-by: Zefa Chen Change-Id: Iae8f9d8bd721e549d89a27fdb61a9e63da76a6f1 --- arch/arm/boot/dts/rv1126.dtsi | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/rv1126.dtsi b/arch/arm/boot/dts/rv1126.dtsi index 1c64f55d9929..2900694f1d2c 100644 --- a/arch/arm/boot/dts/rv1126.dtsi +++ b/arch/arm/boot/dts/rv1126.dtsi @@ -353,6 +353,12 @@ }; }; + mipi_csi2: mipi-csi2 { + compatible = "rockchip,rv1126-mipi-csi2"; + rockchip,hw = <&mipi_csi2_hw>; + status = "disabled"; + }; + mpp_srv: mpp-srv { compatible = "rockchip,mpp-service"; rockchip,taskqueue-count = <4>; @@ -1861,8 +1867,8 @@ status = "disabled"; }; - mipi_csi2: mipi-csi2@ffb10000 { - compatible = "rockchip,rv1126-mipi-csi2"; + mipi_csi2_hw: mipi-csi2-hw@ffb10000 { + compatible = "rockchip,rv1126-mipi-csi2-hw"; reg = <0xffb10000 0x10000>; reg-names = "csihost_regs"; interrupts = , From d174390f316ef1d16003162a555b890ff80454b8 Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Mon, 3 Oct 2022 21:51:21 +0800 Subject: [PATCH 037/133] ARM: dts: rockchip: rv1106 separate the node of csi2 and hw Signed-off-by: Zefa Chen Change-Id: Ifd8eef8e03d9d9edc0a93115b62e2fac41a828dd --- arch/arm/boot/dts/rv1106.dtsi | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/arch/arm/boot/dts/rv1106.dtsi b/arch/arm/boot/dts/rv1106.dtsi index 4bb093b80aa3..1cf580756db0 100644 --- a/arch/arm/boot/dts/rv1106.dtsi +++ b/arch/arm/boot/dts/rv1106.dtsi @@ -239,6 +239,18 @@ }; }; + mipi0_csi2: mipi0-csi2 { + compatible = "rockchip,rv1106-mipi-csi2"; + rockchip,hw = <&mipi0_csi2_hw>, <&mipi1_csi2_hw>; + status = "disabled"; + }; + + mipi1_csi2: mipi1-csi2 { + compatible = "rockchip,rv1106-mipi-csi2"; + rockchip,hw = <&mipi0_csi2_hw>, <&mipi1_csi2_hw>; + status = "disabled"; + }; + mpp_srv: mpp-srv { compatible = "rockchip,mpp-service"; rockchip,taskqueue-count = <2>; @@ -1175,8 +1187,8 @@ status = "disabled"; }; - mipi0_csi2: mipi-csi2@ffa20000 { - compatible = "rockchip,rk3588-mipi-csi2"; + mipi0_csi2_hw: mipi-csi2-hw@ffa20000 { + compatible = "rockchip,rv1106-mipi-csi2-hw"; reg = <0xffa20000 0x10000>; reg-names = "csihost_regs"; interrupts = , @@ -1186,11 +1198,11 @@ clock-names = "pclk_csi2host", "clk_rxbyte_hs"; resets = <&cru SRST_P_CSIHOST0>; reset-names = "srst_csihost_p"; - status = "disabled"; + status = "okay"; }; - mipi1_csi2: mipi-csi2@ffa30000 { - compatible = "rockchip,rk3588-mipi-csi2"; + mipi1_csi2_hw: mipi-csi2-hw@ffa30000 { + compatible = "rockchip,rv1106-mipi-csi2-hw"; reg = <0xffa30000 0x10000>; reg-names = "csihost_regs"; interrupts = , @@ -1200,7 +1212,7 @@ clock-names = "pclk_csi2host", "clk_rxbyte_hs"; resets = <&cru SRST_P_CSIHOST1>; reset-names = "srst_csihost_p"; - status = "disabled"; + status = "okay"; }; rkvenc: rkvenc@ffa50000 { From f23f29d33485e0781aee19924f0bdc1c613ef0db Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Wed, 14 Sep 2022 15:19:02 +0800 Subject: [PATCH 038/133] include: rkcif-config: support set multi csi info Signed-off-by: Zefa Chen Change-Id: I8509ed952b9554659c0238024a383e547620825b --- include/uapi/linux/rkcif-config.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/rkcif-config.h b/include/uapi/linux/rkcif-config.h index eed947319dcc..a65b5b16d242 100644 --- a/include/uapi/linux/rkcif-config.h +++ b/include/uapi/linux/rkcif-config.h @@ -9,7 +9,9 @@ #include #include -#define RKCIF_API_VERSION KERNEL_VERSION(0, 1, 0xa) +#define RKCIF_MAX_CSI_NUM 4 + +#define RKCIF_API_VERSION KERNEL_VERSION(0, 2, 0) #define V4L2_EVENT_RESET_DEV 0X1001 @@ -32,7 +34,7 @@ _IOW('V', BASE_VIDIOC_PRIVATE + 6, int) #define RKCIF_CMD_SET_CSI_IDX \ - _IOW('V', BASE_VIDIOC_PRIVATE + 7, unsigned int) + _IOW('V', BASE_VIDIOC_PRIVATE + 7, struct rkcif_csi_info) /* cif memory mode * 0: raw12/raw10/raw8 8bit memory compact @@ -71,4 +73,10 @@ struct rkcif_fps { int fps; }; +struct rkcif_csi_info { + int csi_num; + int csi_idx[RKCIF_MAX_CSI_NUM]; + int dphy_vendor[RKCIF_MAX_CSI_NUM]; +}; + #endif From c929ccacbb38fb047ca64ffee41ca4ab43f324eb Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Wed, 14 Sep 2022 15:19:46 +0800 Subject: [PATCH 039/133] include: rk-camera-module: support get/set capture info Signed-off-by: Zefa Chen Change-Id: Ic1f117afcb53b035086f6835deb0ccf2733ee972 --- include/uapi/linux/rk-camera-module.h | 42 +++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/include/uapi/linux/rk-camera-module.h b/include/uapi/linux/rk-camera-module.h index fd0416141011..b1204b09cdca 100644 --- a/include/uapi/linux/rk-camera-module.h +++ b/include/uapi/linux/rk-camera-module.h @@ -58,6 +58,7 @@ RKMODULE_CAMERA_BT656_CHANNEL_3) #define DPHY_MAX_LANE 4 +#define RKMODULE_MULTI_DEV_NUM 4 #define RKMODULE_GET_MODULE_INFO \ _IOR('V', BASE_VIDIOC_PRIVATE + 0, struct rkmodule_inf) @@ -176,6 +177,12 @@ #define RKMODULE_SET_GROUP_ID \ _IOW('V', BASE_VIDIOC_PRIVATE + 38, __u32) +#define RKMODULE_GET_CAPTURE_MODE \ + _IOR('V', BASE_VIDIOC_PRIVATE + 39, struct rkmodule_capture_info) + +#define RKMODULE_SET_CAPTURE_MODE \ + _IOW('V', BASE_VIDIOC_PRIVATE + 40, struct rkmodule_capture_info) + struct rkmodule_i2cdev_info { __u8 slave_addr; } __attribute__ ((packed)); @@ -766,4 +773,39 @@ struct rkmodule_sensor_infos { struct rkmodule_sensor_fmt sensor_fmt[RKMODULE_MAX_SENSOR_NUM]; }; +enum rkmodule_capture_mode { + RKMODULE_CAPTURE_MODE_NONE = 0, + RKMODULE_MULTI_DEV_COMBINE_ONE, + RKMODULE_ONE_CH_TO_MULTI_ISP, + RKMODULE_MULTI_CH_TO_MULTI_ISP, + RKMODULE_MULTI_CH_COMBINE_SQUARE, +}; + +struct rkmodule_multi_dev_info { + __u32 dev_idx[RKMODULE_MULTI_DEV_NUM]; + __u32 combine_idx[RKMODULE_MULTI_DEV_NUM]; + __u32 pixel_offset; + __u32 dev_num; + __u32 reserved[8]; +}; + +struct rkmodule_one_to_multi_info { + __u32 isp_num; + __u32 frame_pattern[RKMODULE_MULTI_DEV_NUM]; +}; + +struct rkmodule_multi_combine_info { + __u32 combine_num; + __u32 combine_index[RKMODULE_MULTI_DEV_NUM]; +}; + +struct rkmodule_capture_info { + __u32 mode; + union { + struct rkmodule_multi_dev_info multi_dev; + struct rkmodule_one_to_multi_info one_to_multi; + struct rkmodule_multi_combine_info multi_combine_info; + }; +}; + #endif /* _UAPI_RKMODULE_CAMERA_H */ From 08330d500d8c691e34f5a2a1582030f1bcb924a4 Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Wed, 7 Sep 2022 15:38:48 +0800 Subject: [PATCH 040/133] phy: rockchip: csi2-dphy: logic node of mipi phy can control all hw of mipi phy Signed-off-by: Zefa Chen Change-Id: I30cc62cc1d28c4219e9e5c5ccd77fa9f589e63af --- .../rockchip/phy-rockchip-csi2-dphy-common.h | 15 +- drivers/phy/rockchip/phy-rockchip-csi2-dphy.c | 810 ++++++++++++------ .../phy/rockchip/phy-rockchip-samsung-dcphy.c | 10 +- 3 files changed, 548 insertions(+), 287 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-csi2-dphy-common.h b/drivers/phy/rockchip/phy-rockchip-csi2-dphy-common.h index 0ec812bcb014..3811d6fe6283 100644 --- a/drivers/phy/rockchip/phy-rockchip-csi2-dphy-common.h +++ b/drivers/phy/rockchip/phy-rockchip-csi2-dphy-common.h @@ -9,10 +9,15 @@ #define _PHY_ROCKCHIP_CSI2_DPHY_COMMON_H_ #include +#include #define PHY_MAX 16 #define MAX_DEV_NAME_LEN 32 +#define MAX_SAMSUNG_PHY_NUM 2 + +#define MAX_INNO_PHY_NUM 2 + /* add new chip id in tail by time order */ enum csi2_dphy_chip_id { CHIP_ID_RK3568 = 0x0, @@ -59,14 +64,18 @@ struct samsung_mipi_dcphy; struct dphy_drv_data { const char dev_name[MAX_DEV_NAME_LEN]; - enum csi2_dphy_vendor vendor; + enum csi2_dphy_chip_id chip_id; + char num_inno_phy; + char num_samsung_phy; }; struct csi2_dphy { struct device *dev; struct list_head list; struct csi2_dphy_hw *dphy_hw; + struct csi2_dphy_hw *dphy_hw_group[MAX_INNO_PHY_NUM]; struct samsung_mipi_dcphy *samsung_phy; + struct samsung_mipi_dcphy *samsung_phy_group[MAX_SAMSUNG_PHY_NUM]; struct v4l2_async_notifier notifier; struct v4l2_subdev sd; struct mutex mutex; /* lock for updating protection */ @@ -75,8 +84,10 @@ struct csi2_dphy { u64 data_rate_mbps; int num_sensors; int phy_index; + struct rkcif_csi_info csi_info; + void *phy_hw[RKMODULE_MULTI_DEV_NUM]; bool is_streaming; - enum csi2_dphy_lane_mode lane_mode; + int lane_mode; const struct dphy_drv_data *drv_data; struct rkmodule_csi_dphy_param dphy_param; }; diff --git a/drivers/phy/rockchip/phy-rockchip-csi2-dphy.c b/drivers/phy/rockchip/phy-rockchip-csi2-dphy.c index 81827de21d9c..1fff30da8651 100644 --- a/drivers/phy/rockchip/phy-rockchip-csi2-dphy.c +++ b/drivers/phy/rockchip/phy-rockchip-csi2-dphy.c @@ -25,6 +25,17 @@ #include "phy-rockchip-csi2-dphy-common.h" #include "phy-rockchip-samsung-dcphy.h" +static struct rkmodule_csi_dphy_param rk3588_dcphy_param = { + .vendor = PHY_VENDOR_SAMSUNG, + .lp_vol_ref = 3, + .lp_hys_sw = {3, 0, 0, 0}, + .lp_escclk_pol_sel = {1, 0, 0, 0}, + .skew_data_cal_clk = {0, 3, 3, 3}, + .clk_hs_term_sel = 2, + .data_hs_term_sel = {2, 2, 2, 2}, + .reserved = {0}, +}; + struct sensor_async_subdev { struct v4l2_async_subdev asd; struct v4l2_mbus_config mbus; @@ -42,7 +53,10 @@ static struct v4l2_subdev *get_remote_sensor(struct v4l2_subdev *sd) { struct media_pad *local, *remote; struct media_entity *sensor_me; + struct csi2_dphy *dphy = to_csi2_dphy(sd); + if (dphy->num_sensors == 0) + return NULL; local = &sd->entity.pads[CSI2_DPHY_RX_PAD_SINK]; remote = media_entity_remote_pad(local); if (!remote) { @@ -72,7 +86,7 @@ static int csi2_dphy_get_sensor_data_rate(struct v4l2_subdev *sd) struct v4l2_subdev *sensor_sd = get_remote_sensor(sd); struct v4l2_ctrl *link_freq; struct v4l2_querymenu qm = { .id = V4L2_CID_LINK_FREQ, }; - int ret; + int ret = 0; if (!sensor_sd) return -ENODEV; @@ -101,14 +115,213 @@ static int csi2_dphy_get_sensor_data_rate(struct v4l2_subdev *sd) return 0; } +static int rockchip_csi2_dphy_attach_hw(struct csi2_dphy *dphy, int csi_idx, int index) +{ + struct csi2_dphy_hw *dphy_hw; + struct samsung_mipi_dcphy *dcphy_hw; + struct v4l2_subdev *sensor_sd = get_remote_sensor(&dphy->sd); + struct csi2_sensor *sensor = NULL; + int lanes = 2; + + if (sensor_sd) { + sensor = sd_to_sensor(dphy, sensor_sd); + lanes = sensor->lanes; + } + + if (dphy->drv_data->chip_id == CHIP_ID_RK3568 || + dphy->drv_data->chip_id == CHIP_ID_RV1106) { + dphy_hw = dphy->dphy_hw_group[0]; + mutex_lock(&dphy_hw->mutex); + dphy_hw->dphy_dev[dphy_hw->dphy_dev_num] = dphy; + dphy_hw->dphy_dev_num++; + switch (dphy->phy_index) { + case 0: + dphy->lane_mode = PHY_FULL_MODE; + dphy_hw->lane_mode = LANE_MODE_FULL; + break; + case 1: + dphy->lane_mode = PHY_SPLIT_01; + dphy_hw->lane_mode = LANE_MODE_SPLIT; + break; + case 2: + dphy->lane_mode = PHY_SPLIT_23; + dphy_hw->lane_mode = LANE_MODE_SPLIT; + break; + default: + dphy->lane_mode = PHY_FULL_MODE; + dphy_hw->lane_mode = LANE_MODE_FULL; + break; + } + dphy->dphy_hw = dphy_hw; + dphy->phy_hw[index] = (void *)dphy_hw; + dphy->csi_info.dphy_vendor[index] = PHY_VENDOR_INNO; + mutex_unlock(&dphy_hw->mutex); + } else if (dphy->drv_data->chip_id == CHIP_ID_RK3588) { + if (csi_idx < 2) { + dcphy_hw = dphy->samsung_phy_group[csi_idx]; + mutex_lock(&dcphy_hw->mutex); + dcphy_hw->dphy_dev_num++; + mutex_unlock(&dcphy_hw->mutex); + dphy->samsung_phy = dcphy_hw; + dphy->phy_hw[index] = (void *)dcphy_hw; + dphy->dphy_param = rk3588_dcphy_param; + dphy->csi_info.dphy_vendor[index] = PHY_VENDOR_SAMSUNG; + } else { + dphy_hw = dphy->dphy_hw_group[(csi_idx - 2) / 2]; + mutex_lock(&dphy_hw->mutex); + if (csi_idx == 2 || csi_idx == 4) { + if (lanes == 4) { + dphy->lane_mode = PHY_FULL_MODE; + dphy_hw->lane_mode = LANE_MODE_FULL; + if (csi_idx == 2) + dphy->phy_index = 0; + else + dphy->phy_index = 3; + } else { + dphy->lane_mode = PHY_SPLIT_01; + dphy_hw->lane_mode = LANE_MODE_SPLIT; + if (csi_idx == 2) + dphy->phy_index = 1; + else + dphy->phy_index = 4; + } + } else if (csi_idx == 3 || csi_idx == 5) { + if (lanes == 4) { + dev_info(dphy->dev, "%s csi host%d only support PHY_SPLIT_23\n", + __func__, csi_idx); + mutex_unlock(&dphy_hw->mutex); + return -EINVAL; + } + dphy->lane_mode = PHY_SPLIT_23; + dphy_hw->lane_mode = LANE_MODE_SPLIT; + if (csi_idx == 3) + dphy->phy_index = 2; + else + dphy->phy_index = 5; + } + dphy_hw->dphy_dev_num++; + dphy->dphy_hw = dphy_hw; + dphy->phy_hw[index] = (void *)dphy_hw; + dphy->csi_info.dphy_vendor[index] = PHY_VENDOR_INNO; + mutex_unlock(&dphy_hw->mutex); + } + } else { + dphy_hw = dphy->dphy_hw_group[csi_idx / 2]; + mutex_lock(&dphy_hw->mutex); + if (csi_idx == 0 || csi_idx == 2) { + if (lanes == 4) { + dphy->lane_mode = PHY_FULL_MODE; + dphy_hw->lane_mode = LANE_MODE_FULL; + if (csi_idx == 0) + dphy->phy_index = 0; + else + dphy->phy_index = 3; + } else { + dphy->lane_mode = PHY_SPLIT_01; + dphy_hw->lane_mode = LANE_MODE_SPLIT; + if (csi_idx == 0) + dphy->phy_index = 1; + else + dphy->phy_index = 4; + } + } else if (csi_idx == 1 || csi_idx == 3) { + if (lanes == 4) { + dev_info(dphy->dev, "%s csi host%d only support PHY_SPLIT_23\n", + __func__, csi_idx); + mutex_unlock(&dphy_hw->mutex); + return -EINVAL; + } + dphy->lane_mode = PHY_SPLIT_23; + dphy_hw->lane_mode = LANE_MODE_SPLIT; + if (csi_idx == 1) + dphy->phy_index = 2; + else + dphy->phy_index = 5; + } else { + dev_info(dphy->dev, "%s error csi host%d\n", + __func__, csi_idx); + mutex_unlock(&dphy_hw->mutex); + return -EINVAL; + } + dphy_hw->dphy_dev[dphy_hw->dphy_dev_num] = dphy; + dphy->phy_hw[index] = (void *)dphy_hw; + dphy->csi_info.dphy_vendor[index] = PHY_VENDOR_INNO; + mutex_unlock(&dphy_hw->mutex); + } + + return 0; +} + +static int rockchip_csi2_dphy_detach_hw(struct csi2_dphy *dphy, int csi_idx, int index) +{ + struct csi2_dphy_hw *dphy_hw = NULL; + struct samsung_mipi_dcphy *dcphy_hw = NULL; + struct csi2_dphy *csi2_dphy = NULL; + int i = 0; + + if (dphy->drv_data->chip_id == CHIP_ID_RK3568 || + dphy->drv_data->chip_id == CHIP_ID_RV1106) { + dphy_hw = (struct csi2_dphy_hw *)dphy->phy_hw[index]; + if (!dphy_hw) { + dev_err(dphy->dev, "%s csi_idx %d detach hw failed\n", + __func__, csi_idx); + return -EINVAL; + } + mutex_lock(&dphy_hw->mutex); + for (i = 0; i < dphy_hw->dphy_dev_num; i++) { + csi2_dphy = dphy_hw->dphy_dev[i]; + if (csi2_dphy && + csi2_dphy->phy_index == dphy->phy_index) { + dphy_hw->dphy_dev[i] = NULL; + dphy_hw->dphy_dev_num--; + break; + } + } + mutex_unlock(&dphy_hw->mutex); + } else if (dphy->drv_data->chip_id == CHIP_ID_RK3588) { + if (csi_idx < 2) { + dcphy_hw = (struct samsung_mipi_dcphy *)dphy->phy_hw[index]; + if (!dcphy_hw) { + dev_err(dphy->dev, "%s csi_idx %d detach hw failed\n", + __func__, csi_idx); + return -EINVAL; + } + mutex_lock(&dcphy_hw->mutex); + dcphy_hw->dphy_dev_num--; + mutex_unlock(&dcphy_hw->mutex); + } else { + dphy_hw = (struct csi2_dphy_hw *)dphy->phy_hw[index]; + if (!dphy_hw) { + dev_err(dphy->dev, "%s csi_idx %d detach hw failed\n", + __func__, csi_idx); + return -EINVAL; + } + mutex_lock(&dphy_hw->mutex); + dphy_hw->dphy_dev_num--; + mutex_unlock(&dphy_hw->mutex); + } + } else { + dphy_hw = (struct csi2_dphy_hw *)dphy->phy_hw[index]; + if (!dphy_hw) { + dev_err(dphy->dev, "%s csi_idx %d detach hw failed\n", + __func__, csi_idx); + return -EINVAL; + } + mutex_lock(&dphy_hw->mutex); + dphy_hw->dphy_dev_num--; + mutex_unlock(&dphy_hw->mutex); + } + + return 0; +} + static int csi2_dphy_update_sensor_mbus(struct v4l2_subdev *sd) { struct csi2_dphy *dphy = to_csi2_dphy(sd); struct v4l2_subdev *sensor_sd = get_remote_sensor(sd); struct csi2_sensor *sensor; struct v4l2_mbus_config mbus; - struct rkmodule_bus_config bus_config; - int ret; + int ret = 0; if (!sensor_sd) return -ENODEV; @@ -137,86 +350,83 @@ static int csi2_dphy_update_sensor_mbus(struct v4l2_subdev *sd) default: return -EINVAL; } - if (dphy->drv_data->vendor == PHY_VENDOR_INNO) { - ret = v4l2_subdev_call(sensor_sd, core, ioctl, - RKMODULE_GET_BUS_CONFIG, &bus_config); - if (!ret) { - dev_info(dphy->dev, "phy_mode %d,lane %d\n", - bus_config.bus.phy_mode, bus_config.bus.lanes); - if (bus_config.bus.phy_mode == PHY_FULL_MODE) { - if (dphy->dphy_hw->drv_data->chip_id == CHIP_ID_RK3588 && - dphy->phy_index % 3 == 2) { - dev_err(dphy->dev, "%s dphy%d only use for PHY_SPLIT_23\n", - __func__, dphy->phy_index); - ret = -EINVAL; - } - dphy->lane_mode = LANE_MODE_FULL; - } else if (bus_config.bus.phy_mode == PHY_SPLIT_01) { - if (dphy->dphy_hw->drv_data->chip_id == CHIP_ID_RK3588_DCPHY) { - dev_err(dphy->dev, "%s The chip not support split mode\n", - __func__); - ret = -EINVAL; - } else if (dphy->phy_index % 3 == 2) { - dev_err(dphy->dev, "%s dphy%d only use for PHY_SPLIT_23\n", - __func__, dphy->phy_index); - ret = -EINVAL; - } else { - dphy->lane_mode = LANE_MODE_SPLIT; - } - } else if (bus_config.bus.phy_mode == PHY_SPLIT_23) { - if (dphy->dphy_hw->drv_data->chip_id == CHIP_ID_RK3588_DCPHY) { - dev_err(dphy->dev, "%s The chip not support split mode\n", - __func__); - ret = -EINVAL; - } else if (dphy->phy_index % 3 != 2) { - dev_err(dphy->dev, "%s dphy%d not support PHY_SPLIT_23\n", - __func__, dphy->phy_index); - ret = -EINVAL; - } else { - dphy->lane_mode = LANE_MODE_SPLIT; + + return 0; +} + +static int csi2_dphy_update_config(struct v4l2_subdev *sd) +{ + struct csi2_dphy *dphy = to_csi2_dphy(sd); + struct v4l2_subdev *sensor_sd = get_remote_sensor(sd); + struct rkmodule_csi_dphy_param dphy_param; + struct rkmodule_bus_config bus_config; + int csi_idx = 0; + int ret = 0; + int i = 0; + + for (i = 0; i < dphy->csi_info.csi_num; i++) { + if (dphy->drv_data->chip_id != CHIP_ID_RK3568 && + dphy->drv_data->chip_id != CHIP_ID_RV1106) { + csi_idx = dphy->csi_info.csi_idx[i]; + rockchip_csi2_dphy_attach_hw(dphy, csi_idx, i); + } + if (dphy->csi_info.dphy_vendor[i] == PHY_VENDOR_INNO) { + ret = v4l2_subdev_call(sensor_sd, core, ioctl, + RKMODULE_GET_BUS_CONFIG, &bus_config); + if (!ret) { + dev_info(dphy->dev, "phy_mode %d,lane %d\n", + bus_config.bus.phy_mode, bus_config.bus.lanes); + if (bus_config.bus.phy_mode == PHY_FULL_MODE) { + if (dphy->phy_index % 3 == 2) { + dev_err(dphy->dev, "%s dphy%d only use for PHY_SPLIT_23\n", + __func__, dphy->phy_index); + return -EINVAL; + } + dphy->lane_mode = PHY_FULL_MODE; + dphy->dphy_hw->lane_mode = LANE_MODE_FULL; + } else if (bus_config.bus.phy_mode == PHY_SPLIT_01) { + if (dphy->phy_index % 3 == 2) { + dev_err(dphy->dev, "%s dphy%d only use for PHY_SPLIT_23\n", + __func__, dphy->phy_index); + return -EINVAL; + } + dphy->lane_mode = PHY_SPLIT_01; + dphy->dphy_hw->lane_mode = LANE_MODE_SPLIT; + } else if (bus_config.bus.phy_mode == PHY_SPLIT_23) { + if (dphy->phy_index % 3 != 2) { + dev_err(dphy->dev, "%s dphy%d not support PHY_SPLIT_23\n", + __func__, dphy->phy_index); + return -EINVAL; + } + dphy->lane_mode = PHY_SPLIT_23; + dphy->dphy_hw->lane_mode = LANE_MODE_SPLIT; } } - if (!ret) - dphy->dphy_hw->lane_mode = dphy->lane_mode; - } else { - ret = 0; } } - if (dphy->drv_data->vendor == PHY_VENDOR_SAMSUNG) { - ret = v4l2_subdev_call(sensor_sd, core, ioctl, - RKMODULE_GET_CSI_DPHY_PARAM, - &dphy->dphy_param); - if (ret) { - dev_dbg(dphy->dev, "%s fail to get dphy param, used default value\n", - __func__); - ret = 0; - } - } - return ret; + ret = v4l2_subdev_call(sensor_sd, core, ioctl, + RKMODULE_GET_CSI_DPHY_PARAM, + &dphy_param); + if (!ret) + dphy->dphy_param = dphy_param; + return 0; } static int csi2_dphy_s_stream_start(struct v4l2_subdev *sd) { struct csi2_dphy *dphy = to_csi2_dphy(sd); - struct csi2_dphy_hw *hw = dphy->dphy_hw; - struct samsung_mipi_dcphy *samsung_phy = dphy->samsung_phy; - int ret = 0; + int i = 0; - if (dphy->is_streaming) - return 0; - - ret = csi2_dphy_get_sensor_data_rate(sd); - if (ret < 0) - return ret; - - csi2_dphy_update_sensor_mbus(sd); - - if (dphy->drv_data->vendor == PHY_VENDOR_SAMSUNG) { - if (samsung_phy && samsung_phy->stream_on) - samsung_phy->stream_on(dphy, sd); - } else { - if (hw->stream_on) - hw->stream_on(dphy, sd); + for (i = 0; i < dphy->csi_info.csi_num; i++) { + if (dphy->csi_info.dphy_vendor[i] == PHY_VENDOR_SAMSUNG) { + dphy->samsung_phy = (struct samsung_mipi_dcphy *)dphy->phy_hw[i]; + if (dphy->samsung_phy && dphy->samsung_phy->stream_on) + dphy->samsung_phy->stream_on(dphy, sd); + } else { + dphy->dphy_hw = (struct csi2_dphy_hw *)dphy->phy_hw[i]; + if (dphy->dphy_hw && dphy->dphy_hw->stream_on) + dphy->dphy_hw->stream_on(dphy, sd); + } } dphy->is_streaming = true; @@ -227,18 +437,21 @@ static int csi2_dphy_s_stream_start(struct v4l2_subdev *sd) static int csi2_dphy_s_stream_stop(struct v4l2_subdev *sd) { struct csi2_dphy *dphy = to_csi2_dphy(sd); - struct csi2_dphy_hw *hw = dphy->dphy_hw; - struct samsung_mipi_dcphy *samsung_phy = dphy->samsung_phy; + int i = 0; - if (!dphy->is_streaming) - return 0; - - if (dphy->drv_data->vendor == PHY_VENDOR_SAMSUNG) { - if (samsung_phy && samsung_phy->stream_off) - samsung_phy->stream_off(dphy, sd); - } else { - if (hw->stream_off) - hw->stream_off(dphy, sd); + for (i = 0; i < dphy->csi_info.csi_num; i++) { + if (dphy->csi_info.dphy_vendor[i] == PHY_VENDOR_SAMSUNG) { + dphy->samsung_phy = (struct samsung_mipi_dcphy *)dphy->phy_hw[i]; + if (dphy->samsung_phy && dphy->samsung_phy->stream_off) + dphy->samsung_phy->stream_off(dphy, sd); + } else { + dphy->dphy_hw = (struct csi2_dphy_hw *)dphy->phy_hw[i]; + if (dphy->dphy_hw && dphy->dphy_hw->stream_off) + dphy->dphy_hw->stream_off(dphy, sd); + } + if (dphy->drv_data->chip_id != CHIP_ID_RK3568 && + dphy->drv_data->chip_id != CHIP_ID_RV1106) + rockchip_csi2_dphy_detach_hw(dphy, dphy->csi_info.csi_idx[i], i); } dphy->is_streaming = false; @@ -249,20 +462,94 @@ static int csi2_dphy_s_stream_stop(struct v4l2_subdev *sd) return 0; } +static int csi2_dphy_enable_clk(struct csi2_dphy *dphy) +{ + struct csi2_dphy_hw *hw = NULL; + struct samsung_mipi_dcphy *samsung_phy = NULL; + int ret; + int i = 0; + + for (i = 0; i < dphy->csi_info.csi_num; i++) { + if (dphy->csi_info.dphy_vendor[i] == PHY_VENDOR_SAMSUNG) { + samsung_phy = (struct samsung_mipi_dcphy *)dphy->phy_hw[i]; + if (samsung_phy) + clk_prepare_enable(samsung_phy->pclk); + } else { + hw = (struct csi2_dphy_hw *)dphy->phy_hw[i]; + if (hw) { + ret = clk_bulk_prepare_enable(hw->num_clks, hw->clks_bulk); + if (ret) { + dev_err(hw->dev, "failed to enable clks\n"); + return ret; + } + } + } + } + return 0; +} + +static void csi2_dphy_disable_clk(struct csi2_dphy *dphy) +{ + struct csi2_dphy_hw *hw = NULL; + struct samsung_mipi_dcphy *samsung_phy = NULL; + int i = 0; + + for (i = 0; i < dphy->csi_info.csi_num; i++) { + if (dphy->csi_info.dphy_vendor[i] == PHY_VENDOR_SAMSUNG) { + samsung_phy = (struct samsung_mipi_dcphy *)dphy->phy_hw[i]; + if (samsung_phy) + clk_disable_unprepare(samsung_phy->pclk); + } else { + hw = (struct csi2_dphy_hw *)dphy->phy_hw[i]; + if (hw) + clk_bulk_disable_unprepare(hw->num_clks, hw->clks_bulk); + } + } +} + static int csi2_dphy_s_stream(struct v4l2_subdev *sd, int on) { struct csi2_dphy *dphy = to_csi2_dphy(sd); int ret = 0; mutex_lock(&dphy->mutex); - if (on) + if (on) { + if (dphy->is_streaming) { + mutex_unlock(&dphy->mutex); + return 0; + } + + ret = csi2_dphy_get_sensor_data_rate(sd); + if (ret < 0) { + mutex_unlock(&dphy->mutex); + return ret; + } + + csi2_dphy_update_sensor_mbus(sd); + ret = csi2_dphy_update_config(sd); + if (ret < 0) { + mutex_unlock(&dphy->mutex); + return ret; + } + + ret = csi2_dphy_enable_clk(dphy); + if (ret) { + mutex_unlock(&dphy->mutex); + return ret; + } ret = csi2_dphy_s_stream_start(sd); - else + } else { + if (!dphy->is_streaming) { + mutex_unlock(&dphy->mutex); + return 0; + } ret = csi2_dphy_s_stream_stop(sd); + csi2_dphy_disable_clk(dphy); + } mutex_unlock(&dphy->mutex); - dev_info(dphy->dev, "%s stream on:%d, dphy%d\n", - __func__, on, dphy->phy_index); + dev_info(dphy->dev, "%s stream on:%d, dphy%d, ret %d\n", + __func__, on, dphy->phy_index, ret); return ret; } @@ -312,15 +599,10 @@ static __maybe_unused int csi2_dphy_runtime_suspend(struct device *dev) struct media_entity *me = dev_get_drvdata(dev); struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(me); struct csi2_dphy *dphy = to_csi2_dphy(sd); - struct csi2_dphy_hw *hw = dphy->dphy_hw; - struct samsung_mipi_dcphy *samsung_phy = dphy->samsung_phy; - if (dphy->drv_data->vendor == PHY_VENDOR_SAMSUNG) { - if (samsung_phy) - clk_disable_unprepare(samsung_phy->pclk); - } else { - if (hw) - clk_bulk_disable_unprepare(hw->num_clks, hw->clks_bulk); + if (dphy->is_streaming) { + csi2_dphy_s_stream(sd, 0); + dphy->is_streaming = false; } return 0; @@ -328,26 +610,6 @@ static __maybe_unused int csi2_dphy_runtime_suspend(struct device *dev) static __maybe_unused int csi2_dphy_runtime_resume(struct device *dev) { - struct media_entity *me = dev_get_drvdata(dev); - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(me); - struct csi2_dphy *dphy = to_csi2_dphy(sd); - struct csi2_dphy_hw *hw = dphy->dphy_hw; - struct samsung_mipi_dcphy *samsung_phy = dphy->samsung_phy; - int ret; - - if (dphy->drv_data->vendor == PHY_VENDOR_SAMSUNG) { - if (samsung_phy) - clk_prepare_enable(samsung_phy->pclk); - } else { - if (hw) { - ret = clk_bulk_prepare_enable(hw->num_clks, hw->clks_bulk); - if (ret) { - dev_err(hw->dev, "failed to enable clks\n"); - return ret; - } - } - } - return 0; } @@ -384,8 +646,55 @@ static int csi2_dphy_get_selection(struct v4l2_subdev *sd, return v4l2_subdev_call(sensor, pad, get_selection, NULL, sel); } +static long rkcif_csi2_dphy_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct csi2_dphy *dphy = to_csi2_dphy(sd); + long ret = 0; + + switch (cmd) { + case RKCIF_CMD_SET_CSI_IDX: + if (dphy->drv_data->chip_id != CHIP_ID_RK3568 && + dphy->drv_data->chip_id != CHIP_ID_RV1106) + dphy->csi_info = *((struct rkcif_csi_info *)arg); + break; + default: + ret = -ENOIOCTLCMD; + break; + } + + return ret; +} + +#ifdef CONFIG_COMPAT +static long rkcif_csi2_dphy_compat_ioctl32(struct v4l2_subdev *sd, + unsigned int cmd, unsigned long arg) +{ + void __user *up = compat_ptr(arg); + struct rkcif_csi_info csi_info = {0}; + long ret; + + switch (cmd) { + case RKCIF_CMD_SET_CSI_IDX: + if (copy_from_user(&csi_info, up, sizeof(struct rkcif_csi_info))) + return -EFAULT; + + ret = rkcif_csi2_dphy_ioctl(sd, cmd, &csi_info); + break; + default: + ret = -ENOIOCTLCMD; + break; + } + + return ret; +} +#endif + static const struct v4l2_subdev_core_ops csi2_dphy_core_ops = { .s_power = csi2_dphy_s_power, + .ioctl = rkcif_csi2_dphy_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = rkcif_csi2_dphy_compat_ioctl32, +#endif }; static const struct v4l2_subdev_video_ops csi2_dphy_video_ops = { @@ -559,162 +868,32 @@ static int rockchip_csi2dphy_media_init(struct csi2_dphy *dphy) return v4l2_async_register_subdev(&dphy->sd); } -static int rockchip_csi2_dphy_attach_samsung_phy(struct csi2_dphy *dphy) -{ - struct device *dev = dphy->dev; - struct phy *dcphy; - struct samsung_mipi_dcphy *dphy_hw; - int ret = 0; - - dcphy = devm_phy_optional_get(dev, "dcphy"); - if (IS_ERR(dcphy)) { - ret = PTR_ERR(dcphy); - dev_err(dphy->dev, "failed to get mipi dcphy: %d\n", ret); - return ret; - } - - dphy_hw = phy_get_drvdata(dcphy); - dphy_hw->dphy_dev[dphy_hw->dphy_dev_num] = dphy; - dphy_hw->dphy_dev_num++; - dphy->samsung_phy = dphy_hw; - - return 0; -} - -static int rockchip_csi2_dphy_detach_samsung_phy(struct csi2_dphy *dphy) -{ - struct samsung_mipi_dcphy *dphy_hw = dphy->samsung_phy; - struct csi2_dphy *csi2_dphy = NULL; - int i; - - for (i = 0; i < dphy_hw->dphy_dev_num; i++) { - csi2_dphy = dphy_hw->dphy_dev[i]; - if (csi2_dphy && - csi2_dphy->phy_index == dphy->phy_index) { - dphy_hw->dphy_dev[i] = NULL; - dphy_hw->dphy_dev_num--; - break; - } - } - - return 0; -} - -static int rockchip_csi2_dphy_attach_hw(struct csi2_dphy *dphy) -{ - struct platform_device *plat_dev; - struct device *dev = dphy->dev; - struct csi2_dphy_hw *dphy_hw; - struct device_node *np; - enum csi2_dphy_lane_mode target_mode; - int i; - - if (dphy->phy_index % 3 == 0) - target_mode = LANE_MODE_FULL; - else - target_mode = LANE_MODE_SPLIT; - - np = of_parse_phandle(dev->of_node, "rockchip,hw", 0); - if (!np || !of_device_is_available(np)) { - dev_err(dphy->dev, - "failed to get dphy%d hw node\n", dphy->phy_index); - return -ENODEV; - } - - plat_dev = of_find_device_by_node(np); - of_node_put(np); - if (!plat_dev) { - dev_err(dphy->dev, - "failed to get dphy%d hw from node\n", - dphy->phy_index); - return -ENODEV; - } - - dphy_hw = platform_get_drvdata(plat_dev); - if (!dphy_hw) { - dev_err(dphy->dev, - "failed attach dphy%d hw\n", - dphy->phy_index); - return -EINVAL; - } - - if (dphy_hw->lane_mode == LANE_MODE_UNDEF) { - dphy_hw->lane_mode = target_mode; - } else { - struct csi2_dphy *phy = dphy_hw->dphy_dev[0]; - - for (i = 0; i < dphy_hw->dphy_dev_num; i++) { - if (dphy_hw->dphy_dev[i]->lane_mode == dphy_hw->lane_mode) { - phy = dphy_hw->dphy_dev[i]; - break; - } - } - - if (target_mode != dphy_hw->lane_mode) { - dev_err(dphy->dev, - "Err:csi2 dphy hw has been set as %s mode by phy%d, target mode is:%s\n", - dphy_hw->lane_mode == LANE_MODE_FULL ? "full" : "split", - phy->phy_index, - target_mode == LANE_MODE_FULL ? "full" : "split"); - return -ENODEV; - } - } - - dphy_hw->dphy_dev[dphy_hw->dphy_dev_num] = dphy; - dphy_hw->dphy_dev_num++; - dphy->dphy_hw = dphy_hw; - - return 0; -} - -static int rockchip_csi2_dphy_detach_hw(struct csi2_dphy *dphy) -{ - struct csi2_dphy_hw *dphy_hw = dphy->dphy_hw; - struct csi2_dphy *csi2_dphy = NULL; - int i; - - for (i = 0; i < dphy_hw->dphy_dev_num; i++) { - csi2_dphy = dphy_hw->dphy_dev[i]; - if (csi2_dphy && - csi2_dphy->phy_index == dphy->phy_index) { - dphy_hw->dphy_dev[i] = NULL; - dphy_hw->dphy_dev_num--; - break; - } - } - - return 0; -} - static struct dphy_drv_data rk3568_dphy_drv_data = { .dev_name = "csi2dphy", - .vendor = PHY_VENDOR_INNO, + .chip_id = CHIP_ID_RK3568, + .num_inno_phy = 1, + .num_samsung_phy = 0, }; -static struct dphy_drv_data rk3588_dcphy_drv_data = { - .dev_name = "csi2dcphy", - .vendor = PHY_VENDOR_SAMSUNG, -}; - -static struct rkmodule_csi_dphy_param rk3588_dcphy_param = { - .vendor = PHY_VENDOR_SAMSUNG, - .lp_vol_ref = 3, - .lp_hys_sw = {3, 0, 0, 0}, - .lp_escclk_pol_sel = {1, 0, 0, 0}, - .skew_data_cal_clk = {0, 3, 3, 3}, - .clk_hs_term_sel = 2, - .data_hs_term_sel = {2, 2, 2, 2}, - .reserved = {0}, +static struct dphy_drv_data rk3588_dphy_drv_data = { + .dev_name = "csi2dphy", + .chip_id = CHIP_ID_RK3588, + .num_inno_phy = 2, + .num_samsung_phy = 2, }; static struct dphy_drv_data rv1106_dphy_drv_data = { .dev_name = "csi2dphy", - .vendor = PHY_VENDOR_INNO, + .chip_id = CHIP_ID_RV1106, + .num_inno_phy = 1, + .num_samsung_phy = 0, }; static struct dphy_drv_data rk3562_dphy_drv_data = { .dev_name = "csi2dphy", - .vendor = PHY_VENDOR_INNO, + .chip_id = CHIP_ID_RK3562, + .num_inno_phy = 2, + .num_samsung_phy = 0, }; static const struct of_device_id rockchip_csi2_dphy_match_id[] = { @@ -723,8 +902,8 @@ static const struct of_device_id rockchip_csi2_dphy_match_id[] = { .data = &rk3568_dphy_drv_data, }, { - .compatible = "rockchip,rk3588-csi2-dcphy", - .data = &rk3588_dcphy_drv_data, + .compatible = "rockchip,rk3588-csi2-dphy", + .data = &rk3588_dphy_drv_data, }, { .compatible = "rockchip,rv1106-csi2-dphy", @@ -738,6 +917,79 @@ static const struct of_device_id rockchip_csi2_dphy_match_id[] = { }; MODULE_DEVICE_TABLE(of, rockchip_csi2_dphy_match_id); +static int rockchip_csi2_dphy_get_samsung_phy_hw(struct csi2_dphy *dphy) +{ + struct phy *dcphy; + struct device *dev = dphy->dev; + struct samsung_mipi_dcphy *dcphy_hw; + char phy_name[32]; + int i = 0; + int ret = 0; + + for (i = 0; i < dphy->drv_data->num_samsung_phy; i++) { + sprintf(phy_name, "dcphy%d", i); + dcphy = devm_phy_optional_get(dev, phy_name); + if (IS_ERR(dcphy)) { + ret = PTR_ERR(dcphy); + dev_err(dphy->dev, "failed to get mipi dcphy: %d\n", ret); + return ret; + } + dcphy_hw = phy_get_drvdata(dcphy); + dphy->samsung_phy_group[i] = dcphy_hw; + } + return 0; +} + +static int rockchip_csi2_dphy_get_inno_phy_hw(struct csi2_dphy *dphy) +{ + struct platform_device *plat_dev; + struct device *dev = dphy->dev; + struct csi2_dphy_hw *dphy_hw; + struct device_node *np; + int i = 0; + + for (i = 0; i < dphy->drv_data->num_inno_phy; i++) { + np = of_parse_phandle(dev->of_node, "rockchip,hw", i); + if (!np || !of_device_is_available(np)) { + dev_err(dphy->dev, + "failed to get dphy%d hw node\n", dphy->phy_index); + return -ENODEV; + } + plat_dev = of_find_device_by_node(np); + of_node_put(np); + if (!plat_dev) { + dev_err(dphy->dev, + "failed to get dphy%d hw from node\n", + dphy->phy_index); + return -ENODEV; + } + dphy_hw = platform_get_drvdata(plat_dev); + if (!dphy_hw) { + dev_err(dphy->dev, + "failed attach dphy%d hw\n", + dphy->phy_index); + return -EINVAL; + } + dphy->dphy_hw_group[i] = dphy_hw; + } + return 0; +} + +static int rockchip_csi2_dphy_get_hw(struct csi2_dphy *dphy) +{ + int ret = 0; + + if (dphy->drv_data->chip_id == CHIP_ID_RK3588) { + ret = rockchip_csi2_dphy_get_samsung_phy_hw(dphy); + if (ret) + return ret; + ret = rockchip_csi2_dphy_get_inno_phy_hw(dphy); + } else { + ret = rockchip_csi2_dphy_get_inno_phy_hw(dphy); + } + return ret; +} + static int rockchip_csi2_dphy_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -757,22 +1009,22 @@ static int rockchip_csi2_dphy_probe(struct platform_device *pdev) return -EINVAL; drv_data = of_id->data; csi2dphy->drv_data = drv_data; + csi2dphy->phy_index = of_alias_get_id(dev->of_node, drv_data->dev_name); if (csi2dphy->phy_index < 0 || csi2dphy->phy_index >= PHY_MAX) csi2dphy->phy_index = 0; - if (csi2dphy->drv_data->vendor == PHY_VENDOR_SAMSUNG) { - ret = rockchip_csi2_dphy_attach_samsung_phy(csi2dphy); - csi2dphy->dphy_param = rk3588_dcphy_param; - } else { - ret = rockchip_csi2_dphy_attach_hw(csi2dphy); - } - if (ret) { - dev_err(dev, - "csi2 dphy hw can't be attached, register dphy%d failed!\n", - csi2dphy->phy_index); - return -ENODEV; - } + ret = rockchip_csi2_dphy_get_hw(csi2dphy); + if (ret) + return -EINVAL; + if (csi2dphy->drv_data->chip_id == CHIP_ID_RK3568 || + csi2dphy->drv_data->chip_id == CHIP_ID_RV1106) { + csi2dphy->csi_info.csi_num = 1; + csi2dphy->csi_info.dphy_vendor[0] = PHY_VENDOR_INNO; + rockchip_csi2_dphy_attach_hw(csi2dphy, 0, 0); + } else { + csi2dphy->csi_info.csi_num = 0; + } sd = &csi2dphy->sd; mutex_init(&csi2dphy->mutex); v4l2_subdev_init(sd, &csi2_dphy_subdev_ops); @@ -795,12 +1047,7 @@ static int rockchip_csi2_dphy_probe(struct platform_device *pdev) detach_hw: mutex_destroy(&csi2dphy->mutex); - if (csi2dphy->drv_data->vendor == PHY_VENDOR_SAMSUNG) - rockchip_csi2_dphy_detach_samsung_phy(csi2dphy); - else - rockchip_csi2_dphy_detach_hw(csi2dphy); - - return 0; + return -EINVAL; } static int rockchip_csi2_dphy_remove(struct platform_device *pdev) @@ -808,7 +1055,10 @@ static int rockchip_csi2_dphy_remove(struct platform_device *pdev) struct media_entity *me = platform_get_drvdata(pdev); struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(me); struct csi2_dphy *dphy = to_csi2_dphy(sd); + int i = 0; + for (i = 0; i < dphy->csi_info.csi_num; i++) + rockchip_csi2_dphy_detach_hw(dphy, dphy->csi_info.csi_idx[i], i); media_entity_cleanup(&sd->entity); pm_runtime_disable(&pdev->dev); diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c b/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c index 48b570d5a4a7..125e58d83dba 100644 --- a/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c +++ b/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c @@ -1269,9 +1269,9 @@ static const struct hsfreq_range samsung_cphy_rx_hsfreq_ranges[] = { { 500, 0x102}, { 990, 0x002}, { 2500, 0x001}, }; -static void samsung_mipi_dcphy_bias_block_enable(struct samsung_mipi_dcphy *samsung) +static void samsung_mipi_dcphy_bias_block_enable(struct samsung_mipi_dcphy *samsung, + struct csi2_dphy *csi_dphy) { - struct csi2_dphy *csi_dphy = samsung->dphy_dev[0]; u32 bias_con2 = 0x3223; if (csi_dphy && @@ -1701,7 +1701,7 @@ static void samsung_mipi_dphy_power_on(struct samsung_mipi_dcphy *samsung) { reset_control_assert(samsung->m_phy_rst); - samsung_mipi_dcphy_bias_block_enable(samsung); + samsung_mipi_dcphy_bias_block_enable(samsung, NULL); samsung_mipi_dcphy_pll_configure(samsung); samsung_mipi_dphy_clk_lane_timing_init(samsung); samsung_mipi_dphy_data_lane_timing_init(samsung); @@ -1721,7 +1721,7 @@ static void samsung_mipi_cphy_power_on(struct samsung_mipi_dcphy *samsung) regmap_write(samsung->grf_regmap, MIPI_DCPHY_GRF_CON0, M_CPHY_MODE); reset_control_assert(samsung->m_phy_rst); - samsung_mipi_dcphy_bias_block_enable(samsung); + samsung_mipi_dcphy_bias_block_enable(samsung, NULL); samsung_mipi_dcphy_hs_vreg_amp_configure(samsung); samsung_mipi_dcphy_pll_configure(samsung); samsung_mipi_cphy_timing_init(samsung); @@ -2207,7 +2207,7 @@ static int samsung_dcphy_rx_stream_on(struct csi2_dphy *dphy, if (samsung->s_phy_rst) reset_control_assert(samsung->s_phy_rst); - samsung_mipi_dcphy_bias_block_enable(samsung); + samsung_mipi_dcphy_bias_block_enable(samsung, dphy); ret = samsung_dcphy_rx_config_common(dphy, sensor); if (ret) goto out_streamon; From a8c5673b5b77c0639d6a4cefca6f7e9aeff815cc Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Wed, 14 Sep 2022 15:15:03 +0800 Subject: [PATCH 041/133] media: rockchip: vicap support combine two mipi to one dev Signed-off-by: Zefa Chen Change-Id: Iba3e83d0bc1433458d56c2542c3224ffee127b90 --- drivers/media/platform/rockchip/cif/capture.c | 679 +++++++++++++----- drivers/media/platform/rockchip/cif/dev.c | 11 +- drivers/media/platform/rockchip/cif/dev.h | 2 + drivers/media/platform/rockchip/cif/hw.c | 2 + .../media/platform/rockchip/cif/mipi-csi2.c | 403 ++++++++--- .../media/platform/rockchip/cif/mipi-csi2.h | 35 +- .../media/platform/rockchip/cif/subdev-itf.c | 27 +- drivers/media/platform/rockchip/cif/version.h | 2 + 8 files changed, 882 insertions(+), 279 deletions(-) diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index ee29771164ca..2b76a5f17c0e 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -852,6 +852,7 @@ cif_input_fmt *get_input_fmt(struct v4l2_subdev *sd, struct v4l2_rect *rect, { struct v4l2_subdev_format fmt; struct rkmodule_channel_info ch_info = {0}; + struct rkmodule_capture_info capture_info; int ret; u32 i; @@ -909,7 +910,12 @@ cif_input_fmt *get_input_fmt(struct v4l2_subdev *sd, struct v4l2_rect *rect, rect->top = 0; rect->width = fmt.format.width; rect->height = fmt.format.height; - + ret = v4l2_subdev_call(sd, + core, ioctl, + RKMODULE_GET_CAPTURE_MODE, + &capture_info); + if (!ret) + csi_info->capture_info = capture_info; for (i = 0; i < ARRAY_SIZE(in_fmts); i++) if (fmt.format.code == in_fmts[i].mbus_code && fmt.format.field == in_fmts[i].field) @@ -1807,14 +1813,51 @@ RDBK_TOISP_UNMATCH: spin_unlock_irqrestore(&dev->hdr_lock, flags); } +static void rkcif_write_buff_addr_multi_dev_combine(struct rkcif_stream *stream, + u32 frm_addr_y, u32 frm_addr_uv, + u32 buff_addr_y, u32 buff_addr_cbcr, + bool is_dummy_buf) +{ + struct rkcif_device *dev = stream->cifdev; + struct rkmodule_capture_info *capture_info = &dev->channels[stream->id].capture_info; + u32 addr_y, addr_cbcr; + int addr_offset = 0; + int i = 0; + int tmp_host_index = dev->csi_host_idx; + + for (i = 0; i < capture_info->multi_dev.dev_num; i++) { + if (is_dummy_buf) { + addr_y = buff_addr_y; + } else { + addr_offset = dev->channels[stream->id].left_virtual_width; + addr_y = buff_addr_y + addr_offset * i; + } + dev->csi_host_idx = capture_info->multi_dev.dev_idx[i]; + rkcif_write_register(dev, frm_addr_y, addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW && + frm_addr_uv && buff_addr_cbcr) { + if (is_dummy_buf) { + addr_cbcr = buff_addr_cbcr; + } else { + addr_offset = dev->channels[stream->id].left_virtual_width; + addr_cbcr = buff_addr_cbcr + addr_offset * i; + } + rkcif_write_register(dev, frm_addr_uv, addr_cbcr); + } + } + dev->csi_host_idx = tmp_host_index; +} + static void rkcif_assign_new_buffer_init_toisp(struct rkcif_stream *stream, int channel_id) { struct rkcif_device *dev = stream->cifdev; struct rkcif_rx_buffer *rx_buf; struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; + struct rkmodule_capture_info *capture_info = &dev->channels[channel_id].capture_info; u32 frm0_addr_y; u32 frm1_addr_y; + u32 buff_addr_y; unsigned long flags; if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || @@ -1841,9 +1884,15 @@ static void rkcif_assign_new_buffer_init_toisp(struct rkcif_stream *stream, } } - if (stream->curr_buf_toisp) - rkcif_write_register(dev, frm0_addr_y, - stream->curr_buf_toisp->dummy.dma_addr); + if (stream->curr_buf_toisp) { + buff_addr_y = stream->curr_buf_toisp->dummy.dma_addr; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, frm0_addr_y, 0, + buff_addr_y, 0, false); + } else { + rkcif_write_register(dev, frm0_addr_y, buff_addr_y); + } + } if (!stream->next_buf_toisp) { if (!list_empty(&stream->rx_buf_head)) { @@ -1860,9 +1909,15 @@ static void rkcif_assign_new_buffer_init_toisp(struct rkcif_stream *stream, } } - if (stream->next_buf_toisp) - rkcif_write_register(dev, frm1_addr_y, - stream->next_buf_toisp->dummy.dma_addr); + if (stream->next_buf_toisp) { + buff_addr_y = stream->next_buf_toisp->dummy.dma_addr; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, frm1_addr_y, 0, + buff_addr_y, 0, false); + } else { + rkcif_write_register(dev, frm1_addr_y, buff_addr_y); + } + } spin_unlock_irqrestore(&stream->vbq_lock, flags); stream->buf_owner = RKCIF_DMAEN_BY_ISP; @@ -1873,10 +1928,11 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, { struct rkcif_device *dev = stream->cifdev; struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; + struct rkmodule_capture_info *capture_info = &dev->channels[channel_id].capture_info; struct rkcif_rx_buffer *buffer = NULL; struct rkcif_rx_buffer *active_buf = NULL; struct sditf_priv *priv = dev->sditf[0]; - u32 frm_addr_y; + u32 frm_addr_y, buff_addr_y; unsigned long flags; if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || @@ -2021,8 +2077,13 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, out_get_buf: stream->frame_phase_cache = stream->frame_phase; if (buffer) { - rkcif_write_register(dev, frm_addr_y, - buffer->dummy.dma_addr); + buff_addr_y = buffer->dummy.dma_addr; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, frm_addr_y, 0, + buff_addr_y, 0, false); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + } if (dev->rdbk_debug > 1 && stream->frame_idx < 15) v4l2_info(&dev->v4l2_dev, @@ -2032,8 +2093,13 @@ out_get_buf: frm_addr_y, (u32)buffer->dummy.dma_addr); } else if (dev->hw_dev->dummy_buf.vaddr && priv && priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO) { - rkcif_write_register(dev, frm_addr_y, - dev->hw_dev->dummy_buf.dma_addr); + buff_addr_y = dev->hw_dev->dummy_buf.dma_addr; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, frm_addr_y, 0, + buff_addr_y, 0, true); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + } } spin_unlock_irqrestore(&stream->vbq_lock, flags); return 0; @@ -2056,8 +2122,9 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) struct rkcif_device *dev = stream->cifdev; struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; struct rkcif_rx_buffer *buffer = NULL; + struct rkmodule_capture_info *capture_info = &dev->channels[stream->id].capture_info; struct rkcif_rx_buffer *active_buf = NULL; - u32 frm_addr_y; + u32 frm_addr_y, buff_addr_y; u32 vblank = 0; u32 vblank_ns = 0; u64 cur_time = 0; @@ -2120,8 +2187,15 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) if (buffer) { list_del(&buffer->list); stream->curr_buf_toisp = buffer; - rkcif_write_register(dev, frm_addr_y, - stream->curr_buf_toisp->dummy.dma_addr); + buff_addr_y = stream->curr_buf_toisp->dummy.dma_addr; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, 0, + buff_addr_y, 0, + false); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + } if (dev->rdbk_debug > 1 && stream->frame_idx < 15) v4l2_info(&dev->v4l2_dev, @@ -2137,8 +2211,15 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) if (buffer) { list_del(&buffer->list); stream->next_buf_toisp = buffer; - rkcif_write_register(dev, frm_addr_y, - stream->next_buf_toisp->dummy.dma_addr); + buff_addr_y = stream->next_buf_toisp->dummy.dma_addr; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, 0, + buff_addr_y, 0, + false); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + } if (dev->rdbk_debug > 1 && stream->frame_idx < 15) v4l2_info(&dev->v4l2_dev, @@ -2186,8 +2267,13 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) stream->next_buf_toisp = stream->curr_buf_toisp; else stream->curr_buf_toisp = stream->next_buf_toisp; - rkcif_write_register(dev, frm_addr_y, - stream->curr_buf_toisp->dummy.dma_addr); + buff_addr_y = stream->curr_buf_toisp->dummy.dma_addr; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, frm_addr_y, 0, + buff_addr_y, 0, false); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + } } } @@ -2198,6 +2284,7 @@ static void rkcif_assign_new_buffer_init(struct rkcif_stream *stream, struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; u32 frm0_addr_y, frm0_addr_uv; u32 frm1_addr_y, frm1_addr_uv; + u32 buff_addr_y, buff_addr_cbcr; unsigned long flags; struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf; struct csi_channel_info *channel = &dev->channels[channel_id]; @@ -2228,16 +2315,38 @@ static void rkcif_assign_new_buffer_init(struct rkcif_stream *stream, } if (stream->curr_buf) { - rkcif_write_register(dev, frm0_addr_y, - stream->curr_buf->buff_addr[RKCIF_PLANE_Y]); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm0_addr_uv, - stream->curr_buf->buff_addr[RKCIF_PLANE_CBCR]); + buff_addr_y = stream->curr_buf->buff_addr[RKCIF_PLANE_Y]; + buff_addr_cbcr = stream->curr_buf->buff_addr[RKCIF_PLANE_CBCR]; + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm0_addr_y, + frm0_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); + } else { + rkcif_write_register(dev, frm0_addr_y, + stream->curr_buf->buff_addr[RKCIF_PLANE_Y]); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm0_addr_uv, + stream->curr_buf->buff_addr[RKCIF_PLANE_CBCR]); + } } else { if (dummy_buf->vaddr) { - rkcif_write_register(dev, frm0_addr_y, dummy_buf->dma_addr); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm0_addr_uv, dummy_buf->dma_addr); + buff_addr_y = dummy_buf->dma_addr; + buff_addr_cbcr = dummy_buf->dma_addr; + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm0_addr_y, + frm0_addr_uv, + buff_addr_y, + buff_addr_cbcr, + true); + } else { + rkcif_write_register(dev, frm0_addr_y, buff_addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm0_addr_uv, buff_addr_cbcr); + } } else { if (stream->lack_buf_cnt < 2) stream->lack_buf_cnt++; @@ -2247,11 +2356,22 @@ static void rkcif_assign_new_buffer_init(struct rkcif_stream *stream, if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) { stream->next_buf = stream->curr_buf; if (stream->next_buf) { - rkcif_write_register(dev, frm1_addr_y, - stream->next_buf->buff_addr[RKCIF_PLANE_Y] + (channel->virtual_width / 2)); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm1_addr_uv, - stream->next_buf->buff_addr[RKCIF_PLANE_CBCR] + (channel->virtual_width / 2)); + buff_addr_y = stream->next_buf->buff_addr[RKCIF_PLANE_Y]; + buff_addr_cbcr = stream->next_buf->buff_addr[RKCIF_PLANE_CBCR]; + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm1_addr_y, + frm1_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); + } else { + rkcif_write_register(dev, frm1_addr_y, + buff_addr_y + (channel->virtual_width / 2)); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm1_addr_uv, + buff_addr_cbcr + (channel->virtual_width / 2)); + } } } else { if (!stream->next_buf) { @@ -2262,28 +2382,41 @@ static void rkcif_assign_new_buffer_init(struct rkcif_stream *stream, } } - if (stream->next_buf) { - rkcif_write_register(dev, frm1_addr_y, - stream->next_buf->buff_addr[RKCIF_PLANE_Y]); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm1_addr_uv, - stream->next_buf->buff_addr[RKCIF_PLANE_CBCR]); - } else { - if (dummy_buf->vaddr) { + if (!stream->next_buf && dummy_buf->vaddr) { + buff_addr_y = dummy_buf->dma_addr; + buff_addr_cbcr = dummy_buf->dma_addr; + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm1_addr_y, + frm1_addr_uv, + buff_addr_y, + buff_addr_cbcr, + true); + } else { rkcif_write_register(dev, frm1_addr_y, dummy_buf->dma_addr); if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) rkcif_write_register(dev, frm1_addr_uv, dummy_buf->dma_addr); + } + + } else if (!stream->next_buf && stream->curr_buf) { + stream->next_buf = stream->curr_buf; + if (stream->lack_buf_cnt < 2) + stream->lack_buf_cnt++; + } + if (stream->next_buf) { + buff_addr_y = stream->next_buf->buff_addr[RKCIF_PLANE_Y]; + buff_addr_cbcr = stream->next_buf->buff_addr[RKCIF_PLANE_CBCR]; + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm1_addr_y, + frm1_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); } else { - if (stream->curr_buf) { - stream->next_buf = stream->curr_buf; - rkcif_write_register(dev, frm1_addr_y, - stream->next_buf->buff_addr[RKCIF_PLANE_Y]); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm1_addr_uv, - stream->next_buf->buff_addr[RKCIF_PLANE_CBCR]); - } - if (stream->lack_buf_cnt < 2) - stream->lack_buf_cnt++; + rkcif_write_register(dev, frm1_addr_y, buff_addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm1_addr_uv, buff_addr_cbcr); } } } @@ -2331,6 +2464,7 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, struct rkisp_rx_buf *dbufs = NULL; struct dma_buf *dbuf = NULL; int ret = 0; + u32 buff_addr_y, buff_addr_cbcr; unsigned long flags; if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || @@ -2443,19 +2577,37 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, stream->frame_phase_cache = stream->frame_phase; if (buffer) { + buff_addr_y = buffer->buff_addr[RKCIF_PLANE_Y]; + buff_addr_cbcr = buffer->buff_addr[RKCIF_PLANE_CBCR]; if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED && stream->frame_phase == CIF_CSI_FRAME1_READY) { - rkcif_write_register(dev, frm_addr_y, - buffer->buff_addr[RKCIF_PLANE_Y] + (channel->virtual_width / 2)); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm_addr_uv, - buffer->buff_addr[RKCIF_PLANE_CBCR] + (channel->virtual_width / 2)); + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, + frm_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); + } else { + rkcif_write_register(dev, frm_addr_y, + buff_addr_y + (channel->virtual_width / 2)); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm_addr_uv, + buff_addr_cbcr + (channel->virtual_width / 2)); + } } else { - rkcif_write_register(dev, frm_addr_y, - buffer->buff_addr[RKCIF_PLANE_Y]); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm_addr_uv, - buffer->buff_addr[RKCIF_PLANE_CBCR]); + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, + frm_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm_addr_uv, buff_addr_cbcr); + } } if (stream->dma_en & RKCIF_DMAEN_BY_ISP) { if (stream->buf_replace_cnt < 2) @@ -2478,8 +2630,13 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, } } else { if (stream->dma_en & RKCIF_DMAEN_BY_ISP) { - rkcif_write_register(dev, frm_addr_y, - stream->curr_buf_toisp->dummy.dma_addr); + buff_addr_y = stream->curr_buf_toisp->dummy.dma_addr; + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, 0, + buff_addr_y, 0, false); + else + rkcif_write_register(dev, frm_addr_y, buff_addr_y); if (stream->frame_phase == CIF_CSI_FRAME0_READY && stream->next_buf) dbuf = stream->next_buf->dbuf; @@ -2505,11 +2662,24 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, stream->buf_replace_cnt--; } } else if (dummy_buf->vaddr) { - rkcif_write_register(dev, frm_addr_y, dummy_buf->dma_addr); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm_addr_uv, dummy_buf->dma_addr); + + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + buff_addr_y = dummy_buf->dma_addr; + buff_addr_cbcr = dummy_buf->dma_addr; + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, + frm_addr_uv, + buff_addr_y, + buff_addr_cbcr, + true); + } else { + rkcif_write_register(dev, frm_addr_y, dummy_buf->dma_addr); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm_addr_uv, dummy_buf->dma_addr); + } dev->err_state |= (RKCIF_ERR_ID0_NOT_BUF << stream->id); dev->irq_stats.not_active_buf_cnt[stream->id]++; + } else { ret = -EINVAL; stream->curr_buf = NULL; @@ -2523,8 +2693,13 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, stop_dma: if (stream->buf_replace_cnt) { spin_lock_irqsave(&stream->vbq_lock, flags); - rkcif_write_register(dev, frm_addr_y, - stream->curr_buf_toisp->dummy.dma_addr); + buff_addr_y = stream->curr_buf_toisp->dummy.dma_addr; + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, 0, + buff_addr_y, 0, false); + else + rkcif_write_register(dev, frm_addr_y, buff_addr_y); if (stream->frame_phase == CIF_CSI_FRAME0_READY && stream->next_buf) dbuf = stream->next_buf->dbuf; @@ -2620,8 +2795,10 @@ static int rkcif_update_new_buffer_wake_up_mode(struct rkcif_stream *stream) struct rkcif_device *dev = stream->cifdev; struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf; struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; + struct rkmodule_capture_info *capture_info = &dev->channels[stream->id].capture_info; struct rkcif_buffer *buffer = NULL; u32 frm_addr_y, frm_addr_uv; + u32 buff_addr_y, buff_addr_cbcr; int channel_id = stream->id; int ret = 0; unsigned long flags; @@ -2652,16 +2829,35 @@ static int rkcif_update_new_buffer_wake_up_mode(struct rkcif_stream *stream) } spin_unlock_irqrestore(&stream->vbq_lock, flags); if (buffer) { - rkcif_write_register(dev, frm_addr_y, - buffer->buff_addr[RKCIF_PLANE_Y]); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm_addr_uv, - buffer->buff_addr[RKCIF_PLANE_CBCR]); + buff_addr_y = buffer->buff_addr[RKCIF_PLANE_Y]; + buff_addr_cbcr = buffer->buff_addr[RKCIF_PLANE_CBCR]; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, frm_addr_y, + frm_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm_addr_uv, buff_addr_cbcr); + } } else { if (dummy_buf->vaddr) { - rkcif_write_register(dev, frm_addr_y, dummy_buf->dma_addr); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm_addr_uv, dummy_buf->dma_addr); + buff_addr_y = dummy_buf->dma_addr; + buff_addr_cbcr = dummy_buf->dma_addr; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, + frm_addr_uv, + buff_addr_y, + buff_addr_cbcr, + true); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm_addr_uv, buff_addr_cbcr); + } } else { if (dev->chip_id < CHIP_RK3588_CIF) ret = -EINVAL; @@ -3196,6 +3392,7 @@ static int rkcif_csi_channel_init(struct rkcif_stream *stream, struct csi_channel_info *channel) { struct rkcif_device *dev = stream->cifdev; + struct sditf_priv *priv = dev->sditf[0]; const struct cif_output_fmt *fmt; u32 fourcc; int vc = dev->channels[stream->id].vc; @@ -3220,7 +3417,7 @@ static int rkcif_csi_channel_init(struct rkcif_stream *stream, channel->crop_st_x = stream->crop[CROP_SRC_ACT].left; channel->crop_st_y = stream->crop[CROP_SRC_ACT].top; - if (dev->sditf_cnt > 1 && dev->sditf_cnt <= RKCIF_MAX_SDITF) + if (priv && priv->is_combine_mode && dev->sditf_cnt <= RKCIF_MAX_SDITF) channel->crop_st_y *= dev->sditf_cnt; channel->width = stream->crop[CROP_SRC_ACT].width; channel->height = stream->crop[CROP_SRC_ACT].height; @@ -3230,7 +3427,7 @@ static int rkcif_csi_channel_init(struct rkcif_stream *stream, channel->crop_en = 0; } - if (dev->sditf_cnt > 1 && dev->sditf_cnt <= RKCIF_MAX_SDITF) + if (priv && priv->is_combine_mode && dev->sditf_cnt <= RKCIF_MAX_SDITF) channel->height *= dev->sditf_cnt; fmt = rkcif_find_output_fmt(stream, stream->pixm.pixelformat); @@ -3240,6 +3437,8 @@ static int rkcif_csi_channel_init(struct rkcif_stream *stream, return -EINVAL; } + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) + channel->width /= channel->capture_info.multi_dev.dev_num; /* * for mipi or lvds, when enable compact, the virtual width of raw10/raw12 * needs aligned with :ALIGN(bits_per_pixel * width / 8, 8), if enable 16bit mode @@ -3249,9 +3448,19 @@ static int rkcif_csi_channel_init(struct rkcif_stream *stream, if (fmt->fmt_type == CIF_FMT_TYPE_RAW && stream->is_compact && fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB888 && fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB565) { - channel->virtual_width = ALIGN(channel->width * fmt->raw_bpp / 8, 256); + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + channel->virtual_width = ALIGN(channel->width * 2 * fmt->raw_bpp / 8, 256); + channel->left_virtual_width = channel->width * fmt->raw_bpp / 8; + } else { + channel->virtual_width = ALIGN(channel->width * fmt->raw_bpp / 8, 256); + } } else { - channel->virtual_width = ALIGN(channel->width * fmt->bpp[0] / 8, 8); + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + channel->virtual_width = ALIGN(channel->width * 2 * fmt->bpp[0] / 8, 8); + channel->left_virtual_width = ALIGN(channel->width * fmt->bpp[0] / 8, 8); + } else { + channel->virtual_width = ALIGN(channel->width * fmt->bpp[0] / 8, 8); + } } if (channel->fmt_val == CSI_WRDDR_TYPE_RGB888 || channel->fmt_val == CSI_WRDDR_TYPE_RGB565) @@ -3270,6 +3479,8 @@ static int rkcif_csi_channel_init(struct rkcif_stream *stream, channel->width *= 2; } channel->virtual_width *= 2; + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) + channel->left_virtual_width *= 2; } if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) { channel->virtual_width *= 2; @@ -3618,15 +3829,18 @@ static void rkcif_modify_frame_skip_config(struct rkcif_stream *stream) /*config reg for rk3588*/ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, - struct csi_channel_info *channel, - enum v4l2_mbus_type mbus_type, unsigned int mode) + struct csi_channel_info *channel, + enum v4l2_mbus_type mbus_type, unsigned int mode, + int index) { unsigned int val = 0x0; struct rkcif_device *dev = stream->cifdev; struct rkcif_stream *detect_stream = &dev->stream[0]; struct sditf_priv *priv = dev->sditf[0]; + struct rkmodule_capture_info *capture_info = &channel->capture_info; unsigned int wait_line = 0x3fff; unsigned int dma_en = 0; + int offset = 0; if (channel->id >= 4) return -EINVAL; @@ -3642,21 +3856,28 @@ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, CSI_DMA_END_INTSTAT(channel->id) | CSI_LINE_INTSTAT_V1(channel->id))); - rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, - CSI_START_INTEN(channel->id)); + if (!(capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE && + index < capture_info->multi_dev.dev_num - 1)) { - if (priv && priv->mode.rdbk_mode && detect_stream->is_line_wake_up) { rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, - CSI_LINE_INTEN_RK3588(channel->id)); - wait_line = dev->wait_line; - } - rkcif_write_register(dev, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1, - wait_line << 16 | wait_line); - rkcif_write_register(dev, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3, - wait_line << 16 | wait_line); + CSI_START_INTEN(channel->id)); - rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, - CSI_DMA_END_INTEN(channel->id)); + if (priv && priv->mode.rdbk_mode && detect_stream->is_line_wake_up) { + rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, + CSI_LINE_INTEN_RK3588(channel->id)); + wait_line = dev->wait_line; + } + rkcif_write_register(dev, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1, + wait_line << 16 | wait_line); + rkcif_write_register(dev, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3, + wait_line << 16 | wait_line); + + rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, + CSI_DMA_END_INTEN(channel->id)); + + rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, + CSI_ALL_ERROR_INTEN_V1); + } if (stream->cifdev->id_use_cnt == 0) { val = CIF_MIPI_LVDS_SW_PRESS_VALUE_RK3588(0x3) | CIF_MIPI_LVDS_SW_PRESS_ENABLE | @@ -3670,25 +3891,26 @@ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, else val |= CIF_MIPI_LVDS_SW_SEL_LVDS_RV1106; rkcif_write_register(dev, CIF_REG_MIPI_LVDS_CTRL, val); - - rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, - CSI_ALL_ERROR_INTEN_V1); } #if IS_ENABLED(CONFIG_CPU_RV1106) if (channel->id == 1) rv1106_sdmmc_get_lock(); #endif + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE && + priv && priv->mode.rdbk_mode == RKISP_VICAP_ONLINE && + (dev->hdr.hdr_mode == NO_HDR || + (dev->hdr.hdr_mode == HDR_X2 && stream->id == 1) || + (dev->hdr.hdr_mode == HDR_X3 && stream->id == 2))) + offset = channel->capture_info.multi_dev.pixel_offset; + rkcif_write_register(dev, get_reg_index_of_id_ctrl1(channel->id), - channel->width | (channel->height << 16)); + (channel->width + offset) | (channel->height << 16)); #if IS_ENABLED(CONFIG_CPU_RV1106) if (channel->id == 1) rv1106_sdmmc_put_lock(); #endif - rkcif_write_register(dev, get_reg_index_of_frm0_y_vlw(channel->id), - channel->virtual_width); - if (channel->crop_en) rkcif_write_register(dev, get_reg_index_of_id_crop_start(channel->id), channel->crop_st_y << 16 | channel->crop_st_x); @@ -3706,6 +3928,17 @@ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, rkcif_assign_new_buffer_pingpong_rockit(stream, RKCIF_YUV_ADDR_STATE_INIT, channel->id); + + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE && + index == (capture_info->multi_dev.dev_num - 1) && + priv && priv->mode.rdbk_mode != RKISP_VICAP_ONLINE) + rkcif_write_register(dev, get_reg_index_of_id_crop_start(channel->id), + channel->crop_st_y << 16 | + (channel->crop_st_x + capture_info->multi_dev.pixel_offset)); + + rkcif_write_register(dev, get_reg_index_of_frm0_y_vlw(channel->id), + channel->virtual_width); + if (stream->lack_buf_cnt == 2) stream->dma_en = 0; @@ -3768,7 +4001,24 @@ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, } if (dev->chip_id >= CHIP_RV1106_CIF) rkcif_modify_frame_skip_config(stream); - stream->cifdev->id_use_cnt++; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + if (index == (capture_info->multi_dev.dev_num - 1)) + stream->cifdev->id_use_cnt++; + } else { + stream->cifdev->id_use_cnt++; + } + if (!(capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE && + index < capture_info->multi_dev.dev_num - 1)) { + if (mode == RKCIF_STREAM_MODE_CAPTURE) + rkcif_assign_new_buffer_pingpong(stream, + RKCIF_YUV_ADDR_STATE_INIT, + channel->id); + else if (mode == RKCIF_STREAM_MODE_TOISP || + mode == RKCIF_STREAM_MODE_TOISP_RDBK) + rkcif_assign_new_buffer_pingpong_toisp(stream, + RKCIF_YUV_ADDR_STATE_INIT, + channel->id); + } return 0; } @@ -3780,6 +4030,7 @@ static int rkcif_csi_stream_start(struct rkcif_stream *stream, unsigned int mode enum v4l2_mbus_type mbus_type = active_sensor->mbus.type; struct csi_channel_info *channel; u32 ret = 0; + int i; if (stream->state < RKCIF_STATE_STREAMING) { stream->frame_idx = 0; @@ -3818,10 +4069,18 @@ static int rkcif_csi_stream_start(struct rkcif_stream *stream, unsigned int mode } else if (mode == RKCIF_STREAM_MODE_ROCKIT) { stream->dma_en |= RKCIF_DMAEN_BY_ROCKIT; } - if (stream->cifdev->chip_id < CHIP_RK3588_CIF) + if (stream->cifdev->chip_id < CHIP_RK3588_CIF) { rkcif_csi_channel_set(stream, channel, mbus_type); - else - rkcif_csi_channel_set_v1(stream, channel, mbus_type, mode); + } else { + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + for (i = 0; i < channel->capture_info.multi_dev.dev_num; i++) { + dev->csi_host_idx = channel->capture_info.multi_dev.dev_idx[i]; + rkcif_csi_channel_set_v1(stream, channel, mbus_type, mode, i); + } + } else { + rkcif_csi_channel_set_v1(stream, channel, mbus_type, mode, 0); + } + } } else { if (stream->cifdev->chip_id >= CHIP_RK3588_CIF) { if (mode == RKCIF_STREAM_MODE_CAPTURE) { @@ -3861,7 +4120,9 @@ static void rkcif_stream_stop(struct rkcif_stream *stream) struct v4l2_mbus_config *mbus_cfg = &cif_dev->active_sensor->mbus; u32 val; int id; + int i = 0; + stream->cifdev->id_use_cnt--; if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || mbus_cfg->type == V4L2_MBUS_CCP2) { @@ -3873,7 +4134,14 @@ static void rkcif_stream_stop(struct rkcif_stream *stream) else val &= ~LVDS_ENABLE_CAPTURE; - rkcif_write_register(cif_dev, get_reg_index_of_id_ctrl0(id), val); + if (cif_dev->channels[id].capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + for (i = 0; i < cif_dev->channels[id].capture_info.multi_dev.dev_num; i++) { + cif_dev->csi_host_idx = cif_dev->channels[id].capture_info.multi_dev.dev_idx[i]; + rkcif_write_register(cif_dev, get_reg_index_of_id_ctrl0(id), val); + } + } else { + rkcif_write_register(cif_dev, get_reg_index_of_id_ctrl0(id), val); + } rkcif_write_register_or(cif_dev, CIF_REG_MIPI_LVDS_INTSTAT, CSI_START_INTSTAT(id) | @@ -3892,8 +4160,16 @@ static void rkcif_stream_stop(struct rkcif_stream *stream) if (stream->cifdev->id_use_cnt == 0) { rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_INTEN, ~CSI_ALL_ERROR_INTEN_V1); - rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_CTRL, - ~CSI_ENABLE_CAPTURE); + if (cif_dev->channels[id].capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + for (i = 0; i < cif_dev->channels[id].capture_info.multi_dev.dev_num; i++) { + cif_dev->csi_host_idx = cif_dev->channels[id].capture_info.multi_dev.dev_idx[i]; + rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_CTRL, + ~CSI_ENABLE_CAPTURE); + } + } else { + rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_CTRL, + ~CSI_ENABLE_CAPTURE); + } } } @@ -3909,7 +4185,6 @@ static void rkcif_stream_stop(struct rkcif_stream *stream) rkcif_config_dvp_pin(cif_dev, false); } } - stream->cifdev->id_use_cnt--; stream->state = RKCIF_STATE_READY; stream->dma_en = 0; } @@ -4006,6 +4281,8 @@ static void rkcif_check_buffer_update_pingpong(struct rkcif_stream *stream, u32 frm_addr_y = 0, frm_addr_uv = 0; u32 frm0_addr_y = 0, frm0_addr_uv = 0; u32 frm1_addr_y = 0, frm1_addr_uv = 0; + u32 buff_addr_y = 0, buff_addr_cbcr = 0; + struct rkmodule_capture_info *capture_info = &dev->channels[channel_id].capture_info; unsigned long flags; int frame_phase = 0; bool is_dual_update_buf = false; @@ -4072,22 +4349,51 @@ static void rkcif_check_buffer_update_pingpong(struct rkcif_stream *stream, } if (buffer) { if (is_dual_update_buf) { - rkcif_write_register(dev, frm0_addr_y, - buffer->buff_addr[RKCIF_PLANE_Y]); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm0_addr_uv, - buffer->buff_addr[RKCIF_PLANE_CBCR]); - rkcif_write_register(dev, frm1_addr_y, - buffer->buff_addr[RKCIF_PLANE_Y]); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm1_addr_uv, - buffer->buff_addr[RKCIF_PLANE_CBCR]); + buff_addr_y = buffer->buff_addr[RKCIF_PLANE_Y]; + buff_addr_cbcr = buffer->buff_addr[RKCIF_PLANE_CBCR]; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm0_addr_y, + frm0_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); + rkcif_write_buff_addr_multi_dev_combine(stream, + frm1_addr_y, + frm1_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); + } else { + rkcif_write_register(dev, frm0_addr_y, buff_addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, + frm0_addr_uv, + buff_addr_cbcr); + rkcif_write_register(dev, frm1_addr_y, buff_addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, + frm1_addr_uv, + buff_addr_cbcr); + } } else { - rkcif_write_register(dev, frm_addr_y, - buffer->buff_addr[RKCIF_PLANE_Y]); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm_addr_uv, - buffer->buff_addr[RKCIF_PLANE_CBCR]); + + buff_addr_y = buffer->buff_addr[RKCIF_PLANE_Y]; + buff_addr_cbcr = buffer->buff_addr[RKCIF_PLANE_CBCR]; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, + frm_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, + frm_addr_uv, + buff_addr_cbcr); + } } } } else { @@ -5600,6 +5906,7 @@ static void rkcif_attach_sync_mode(struct rkcif_device *cifdev) { struct rkcif_hw *hw = cifdev->hw_dev; struct rkcif_device *dev; + struct sditf_priv *priv; int i = 0, j = 0; int ret = 0; int count = 0; @@ -5677,26 +5984,31 @@ static void rkcif_attach_sync_mode(struct rkcif_device *cifdev) else sync_cfg.group = 0; } else { - for (j = 0; j < dev->sditf_cnt; j++) { - ret |= v4l2_subdev_call(dev->sditf[j]->sensor_sd, - core, ioctl, - RKMODULE_GET_SYNC_MODE, - &sync_type); - if (!ret && sync_type) - break; + priv = dev->sditf[0]; + if (priv && priv->is_combine_mode && dev->sditf_cnt <= RKCIF_MAX_SDITF) { + for (j = 0; j < dev->sditf_cnt; j++) { + ret |= v4l2_subdev_call(dev->sditf[j]->sensor_sd, + core, ioctl, + RKMODULE_GET_SYNC_MODE, + &sync_type); + if (!ret && sync_type) { + priv = dev->sditf[j]; + break; + } + } + if (!ret) + sync_cfg.type = sync_type; + else + sync_cfg.type = NO_SYNC_MODE; + ret = v4l2_subdev_call(priv->sensor_sd, + core, ioctl, + RKMODULE_GET_GROUP_ID, + &sync_group); + if (!ret && sync_group < RKCIF_MAX_GROUP) + sync_cfg.group = sync_group; + else + sync_cfg.group = 0; } - if (!ret) - sync_cfg.type = sync_type; - else - sync_cfg.type = NO_SYNC_MODE; - ret = v4l2_subdev_call(dev->sditf[j]->sensor_sd, - core, ioctl, - RKMODULE_GET_GROUP_ID, - &sync_group); - if (!ret && sync_group < RKCIF_MAX_GROUP) - sync_cfg.group = sync_group; - else - sync_cfg.group = 0; } if (sync_cfg.group == cifdev->sync_cfg.group) { if (sync_cfg.type == EXTERNAL_MASTER_MODE) { @@ -5719,6 +6031,11 @@ static void rkcif_attach_sync_mode(struct rkcif_device *cifdev) sync_config->sync_mask |= BIT(dev->csi_host_idx); } dev->sync_cfg = sync_cfg; + } else { + ret = v4l2_subdev_call(dev->terminal_sensor.sd, + core, ioctl, + RKMODULE_GET_SYNC_MODE, + &sync_type); } } if (sync_config->int_master.count == 1) { @@ -5752,15 +6069,18 @@ int rkcif_do_start_stream(struct rkcif_stream *stream, unsigned int mode) struct rkcif_hw *hw_dev = dev->hw_dev; struct v4l2_device *v4l2_dev = &dev->v4l2_dev; struct rkcif_sensor_info *sensor_info = dev->active_sensor; - struct rkcif_sensor_info *terminal_sensor = &dev->terminal_sensor; + struct rkcif_sensor_info *terminal_sensor = NULL; struct rkmodule_hdr_cfg hdr_cfg; + struct rkcif_csi_info csi_info = {0}; int rkmodule_stream_seq = RKMODULE_START_STREAM_DEFAULT; int ret; + int i = 0; v4l2_info(&dev->v4l2_dev, "stream[%d] start streaming\n", stream->id); rkcif_attach_sync_mode(dev); mutex_lock(&dev->stream_lock); + if ((stream->cur_stream_mode & RKCIF_STREAM_MODE_CAPTURE) == mode) { ret = -EBUSY; v4l2_err(v4l2_dev, "stream in busy state\n"); @@ -5773,7 +6093,7 @@ int rkcif_do_start_stream(struct rkcif_stream *stream, unsigned int mode) else stream->is_line_inten = false; - if (dev->active_sensor) { + if (!dev->active_sensor) { ret = rkcif_update_sensor_info(stream); if (ret < 0) { v4l2_err(v4l2_dev, @@ -5782,7 +6102,7 @@ int rkcif_do_start_stream(struct rkcif_stream *stream, unsigned int mode) goto out; } } - + terminal_sensor = &dev->terminal_sensor; if (terminal_sensor->sd) { ret = v4l2_subdev_call(terminal_sensor->sd, core, ioctl, @@ -5813,6 +6133,34 @@ int rkcif_do_start_stream(struct rkcif_stream *stream, unsigned int mode) goto destroy_buf; mutex_lock(&hw_dev->dev_lock); + if (atomic_read(&dev->pipe.stream_cnt) == 0 && + dev->active_sensor && + (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_DPHY || + dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_CPHY || + dev->active_sensor->mbus.type == V4L2_MBUS_CCP2)) { + if (dev->channels[0].capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + csi_info.csi_num = dev->channels[0].capture_info.multi_dev.dev_num; + if (csi_info.csi_num > RKCIF_MAX_CSI_NUM) { + v4l2_err(v4l2_dev, + "csi num %d, max %d\n", + csi_info.csi_num, RKCIF_MAX_CSI_NUM); + goto out; + } + for (i = 0; i < csi_info.csi_num; i++) + csi_info.csi_idx[i] = dev->channels[0].capture_info.multi_dev.dev_idx[i]; + } else { + csi_info.csi_num = 1; + csi_info.csi_idx[0] = dev->csi_host_idx; + } + ret = v4l2_subdev_call(dev->active_sensor->sd, + core, ioctl, + RKCIF_CMD_SET_CSI_IDX, + &csi_info); + if (ret) + v4l2_err(&dev->v4l2_dev, "set csi idx %d fail\n", dev->csi_host_idx); + + } + if (((dev->active_sensor && dev->active_sensor->mbus.type == V4L2_MBUS_BT656) || dev->is_use_dummybuf) && (!dev->hw_dev->dummy_buf.vaddr) && @@ -5980,6 +6328,7 @@ int rkcif_set_fmt(struct rkcif_stream *stream, bool try) { struct rkcif_device *dev = stream->cifdev; + struct sditf_priv *priv = dev->sditf[0]; const struct cif_output_fmt *fmt; const struct cif_input_fmt *cif_fmt_in = NULL; struct v4l2_rect input_rect; @@ -5987,6 +6336,7 @@ int rkcif_set_fmt(struct rkcif_stream *stream, u32 xsubs = 1, ysubs = 1, i; struct rkmodule_hdr_cfg hdr_cfg; struct rkcif_extend_info *extend_line = &stream->extend_line; + struct csi_channel_info *channel_info = &dev->channels[stream->id]; int ret; for (i = 0; i < RKCIF_MAX_PLANE; i++) @@ -6002,7 +6352,7 @@ int rkcif_set_fmt(struct rkcif_stream *stream, if (dev->terminal_sensor.sd) { cif_fmt_in = get_input_fmt(dev->terminal_sensor.sd, &input_rect, stream->id, - &dev->channels[stream->id]); + channel_info); stream->cif_fmt_in = cif_fmt_in; } else { v4l2_err(&stream->cifdev->v4l2_dev, @@ -6044,8 +6394,9 @@ int rkcif_set_fmt(struct rkcif_stream *stream, planes = fmt->cplanes ? fmt->cplanes : fmt->mplanes; - if (cif_fmt_in && (cif_fmt_in->mbus_code == MEDIA_BUS_FMT_SPD_2X8 || - cif_fmt_in->mbus_code == MEDIA_BUS_FMT_EBD_1X8)) + if (cif_fmt_in && + (cif_fmt_in->mbus_code == MEDIA_BUS_FMT_SPD_2X8 || + cif_fmt_in->mbus_code == MEDIA_BUS_FMT_EBD_1X8)) stream->crop_enable = false; for (i = 0; i < planes; i++) { @@ -6070,7 +6421,7 @@ int rkcif_set_fmt(struct rkcif_stream *stream, } } - if (dev->sditf_cnt > 1 && dev->sditf_cnt <= RKCIF_MAX_SDITF) + if (priv && priv->is_combine_mode && dev->sditf_cnt <= RKCIF_MAX_SDITF) height *= dev->sditf_cnt; extend_line->pixm.height = height + RKMODULE_EXTEND_LINE; @@ -6080,8 +6431,9 @@ int rkcif_set_fmt(struct rkcif_stream *stream, * to optimize reading and writing of ddr, aliged with 256. */ if (fmt->fmt_type == CIF_FMT_TYPE_RAW && - (stream->cif_fmt_in->mbus_code == MEDIA_BUS_FMT_EBD_1X8 || - stream->cif_fmt_in->mbus_code == MEDIA_BUS_FMT_SPD_2X8)) { + cif_fmt_in && + (cif_fmt_in->mbus_code == MEDIA_BUS_FMT_EBD_1X8 || + cif_fmt_in->mbus_code == MEDIA_BUS_FMT_SPD_2X8)) { stream->is_compact = false; } @@ -8499,8 +8851,8 @@ static void rkcif_update_stream(struct rkcif_device *cif_dev, if (!stream->is_line_wake_up) { ret = rkcif_assign_new_buffer_pingpong(stream, - RKCIF_YUV_ADDR_STATE_UPDATE, - mipi_id); + RKCIF_YUV_ADDR_STATE_UPDATE, + mipi_id); if (ret && cif_dev->chip_id < CHIP_RK3588_CIF) return; } else { @@ -8634,6 +8986,7 @@ static int rkcif_do_reset_work(struct rkcif_device *cif_dev, struct rkcif_sensor_info *terminal_sensor = &cif_dev->terminal_sensor; struct rkcif_resume_info *resume_info = &cif_dev->reset_work.resume_info; struct rkcif_timer *timer = &cif_dev->reset_watchdog_timer; + struct sditf_priv *priv = cif_dev->sditf[0]; int i, j, ret = 0; u32 on, sof_cnt; int capture_mode = 0; @@ -8702,10 +9055,12 @@ static int rkcif_do_reset_work(struct rkcif_device *cif_dev, __func__, on ? "on" : "off", p->subdevs[i]->name); } - for (i = 0; i < cif_dev->sditf_cnt; i++) { - if (cif_dev->sditf[i] && cif_dev->sditf[i]->sensor_sd) - ret = v4l2_subdev_call(cif_dev->sditf[i]->sensor_sd, core, ioctl, - RKMODULE_SET_QUICK_STREAM, &on); + if (priv && priv->is_combine_mode && cif_dev->sditf_cnt <= RKCIF_MAX_SDITF) { + for (i = 0; i < cif_dev->sditf_cnt; i++) { + if (cif_dev->sditf[i] && cif_dev->sditf[i]->sensor_sd) + ret = v4l2_subdev_call(cif_dev->sditf[i]->sensor_sd, core, ioctl, + RKMODULE_SET_QUICK_STREAM, &on); + } } rockchip_clear_system_status(SYS_STATUS_CIF0); @@ -8800,10 +9155,12 @@ static int rkcif_do_reset_work(struct rkcif_device *cif_dev, p->subdevs[i]->name); } - for (i = 0; i < cif_dev->sditf_cnt; i++) { - if (cif_dev->sditf[i] && cif_dev->sditf[i]->sensor_sd) - v4l2_subdev_call(cif_dev->sditf[i]->sensor_sd, core, ioctl, - RKMODULE_SET_QUICK_STREAM, &on); + if (priv && priv->is_combine_mode && cif_dev->sditf_cnt <= RKCIF_MAX_SDITF) { + for (i = 0; i < cif_dev->sditf_cnt; i++) { + if (cif_dev->sditf[i] && cif_dev->sditf[i]->sensor_sd) + v4l2_subdev_call(cif_dev->sditf[i]->sensor_sd, core, ioctl, + RKMODULE_SET_QUICK_STREAM, &on); + } } if (cif_dev->chip_id < CHIP_RK3588_CIF) diff --git a/drivers/media/platform/rockchip/cif/dev.c b/drivers/media/platform/rockchip/cif/dev.c index f9081634bcd6..e931dc61389d 100644 --- a/drivers/media/platform/rockchip/cif/dev.c +++ b/drivers/media/platform/rockchip/cif/dev.c @@ -1571,16 +1571,6 @@ static int subdev_notifier_complete(struct v4l2_async_notifier *notifier) if (!completion_done(&dev->cmpl_ntf)) complete(&dev->cmpl_ntf); - if (dev->active_sensor && - (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_DPHY || - dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_CPHY)) { - ret = v4l2_subdev_call(dev->active_sensor->sd, - core, ioctl, - RKCIF_CMD_SET_CSI_IDX, - &dev->csi_host_idx); - if (ret) - v4l2_err(&dev->v4l2_dev, "set csi idx %d fail\n", dev->csi_host_idx); - } v4l2_info(&dev->v4l2_dev, "Async subdev notifier completed\n"); return ret; @@ -1950,6 +1940,7 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int cif_dev->early_line = 0; cif_dev->is_thunderboot = false; cif_dev->rdbk_debug = 0; + memset(&cif_dev->channels[0].capture_info, 0, sizeof(cif_dev->channels[0].capture_info)); if (cif_dev->chip_id == CHIP_RV1126_CIF_LITE) cif_dev->isr_hdl = rkcif_irq_lite_handler; diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index 8cdfab14fd27..c0974a8c7719 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -280,10 +280,12 @@ struct csi_channel_info { unsigned int width; unsigned int height; unsigned int virtual_width; + unsigned int left_virtual_width; unsigned int crop_st_x; unsigned int crop_st_y; unsigned int dsi_input; struct rkmodule_lvds_cfg lvds_cfg; + struct rkmodule_capture_info capture_info; }; struct rkcif_vdev_node { diff --git a/drivers/media/platform/rockchip/cif/hw.c b/drivers/media/platform/rockchip/cif/hw.c index 55179f795866..af0f0633e7bb 100644 --- a/drivers/media/platform/rockchip/cif/hw.c +++ b/drivers/media/platform/rockchip/cif/hw.c @@ -1506,6 +1506,7 @@ int rk_cif_plat_drv_init(void) ret = platform_driver_register(&rkcif_hw_plat_drv); if (ret) return ret; + rkcif_csi2_hw_plat_drv_init(); return rkcif_csi2_plat_drv_init(); } @@ -1513,6 +1514,7 @@ static void __exit rk_cif_plat_drv_exit(void) { platform_driver_unregister(&rkcif_hw_plat_drv); rkcif_csi2_plat_drv_exit(); + rkcif_csi2_hw_plat_drv_exit(); } #if defined(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP) && !defined(CONFIG_INITCALL_ASYNC) diff --git a/drivers/media/platform/rockchip/cif/mipi-csi2.c b/drivers/media/platform/rockchip/cif/mipi-csi2.c index c0e5999d325b..f526b4392221 100644 --- a/drivers/media/platform/rockchip/cif/mipi-csi2.c +++ b/drivers/media/platform/rockchip/cif/mipi-csi2.c @@ -13,12 +13,12 @@ #include #include #include +#include #include #include #include #include #include "mipi-csi2.h" -#include #include static int csi2_debug; @@ -147,47 +147,55 @@ static void csi2_update_sensor_info(struct csi2_dev *csi2) } -static void csi2_hw_do_reset(struct csi2_dev *csi2) +static void csi2_hw_do_reset(struct csi2_hw *csi2_hw) { - reset_control_assert(csi2->rsts_bulk); + + if (!csi2_hw->rsts_bulk) + return; + + reset_control_assert(csi2_hw->rsts_bulk); udelay(5); - reset_control_deassert(csi2->rsts_bulk); + reset_control_deassert(csi2_hw->rsts_bulk); } -static int csi2_enable_clks(struct csi2_dev *csi2) +static int csi2_enable_clks(struct csi2_hw *csi2_hw) { int ret = 0; - ret = clk_bulk_prepare_enable(csi2->clks_num, csi2->clks_bulk); + if (!csi2_hw->clks_bulk) + return -EINVAL; + + ret = clk_bulk_prepare_enable(csi2_hw->clks_num, csi2_hw->clks_bulk); if (ret) - dev_err(csi2->dev, "failed to enable clks\n"); + dev_err(csi2_hw->dev, "failed to enable clks\n"); return ret; } -static void csi2_disable_clks(struct csi2_dev *csi2) +static void csi2_disable_clks(struct csi2_hw *csi2_hw) { - clk_bulk_disable_unprepare(csi2->clks_num, csi2->clks_bulk); + if (!csi2_hw->clks_bulk) + return; + clk_bulk_disable_unprepare(csi2_hw->clks_num, csi2_hw->clks_bulk); } -static void csi2_disable(struct csi2_dev *csi2) +static void csi2_disable(struct csi2_hw *csi2_hw) { - void __iomem *base = csi2->base; - - write_csihost_reg(base, CSIHOST_RESETN, 0); - write_csihost_reg(base, CSIHOST_MSK1, 0xffffffff); - write_csihost_reg(base, CSIHOST_MSK2, 0xffffffff); + write_csihost_reg(csi2_hw->base, CSIHOST_RESETN, 0); + write_csihost_reg(csi2_hw->base, CSIHOST_MSK1, 0xffffffff); + write_csihost_reg(csi2_hw->base, CSIHOST_MSK2, 0xffffffff); } static int csi2_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id, struct v4l2_mbus_config *mbus); -static void csi2_enable(struct csi2_dev *csi2, +static void csi2_enable(struct csi2_hw *csi2_hw, enum host_type_t host_type) { - void __iomem *base = csi2->base; + void __iomem *base = csi2_hw->base; + struct csi2_dev *csi2 = csi2_hw->csi2; int lanes = csi2->bus.num_data_lanes; struct v4l2_mbus_config mbus; u32 val = 0; @@ -225,16 +233,10 @@ static int csi2_start(struct csi2_dev *csi2) { enum host_type_t host_type; int ret, i; + int csi_idx = 0; atomic_set(&csi2->frm_sync_seq, 0); - csi2_hw_do_reset(csi2); - ret = csi2_enable_clks(csi2); - if (ret) { - v4l2_err(&csi2->sd, "%s: enable clks failed\n", __func__); - return ret; - } - csi2_update_sensor_info(csi2); if (csi2->dsi_input_en == RKMODULE_DSI_INPUT) @@ -242,7 +244,16 @@ static int csi2_start(struct csi2_dev *csi2) else host_type = RK_CSI_RXHOST; - csi2_enable(csi2, host_type); + for (i = 0; i < csi2->csi_info.csi_num; i++) { + csi_idx = csi2->csi_info.csi_idx[i]; + csi2_hw_do_reset(csi2->csi2_hw[csi_idx]); + ret = csi2_enable_clks(csi2->csi2_hw[csi_idx]); + if (ret) { + v4l2_err(&csi2->sd, "%s: enable clks failed\n", __func__); + return ret; + } + csi2_enable(csi2->csi2_hw[csi_idx], host_type); + } pr_debug("stream sd: %s\n", csi2->src_sd->name); ret = v4l2_subdev_call(csi2->src_sd, video, s_stream, 1); @@ -256,20 +267,29 @@ static int csi2_start(struct csi2_dev *csi2) return 0; err_assert_reset: - csi2_disable(csi2); - csi2_disable_clks(csi2); + for (i = 0; i < csi2->csi_info.csi_num; i++) { + csi_idx = csi2->csi_info.csi_idx[i]; + csi2_disable(csi2->csi2_hw[csi_idx]); + csi2_disable_clks(csi2->csi2_hw[csi_idx]); + } return ret; } static void csi2_stop(struct csi2_dev *csi2) { + int i = 0; + int csi_idx = 0; + /* stop upstream */ v4l2_subdev_call(csi2->src_sd, video, s_stream, 0); - csi2_disable(csi2); - csi2_hw_do_reset(csi2); - csi2_disable_clks(csi2); + for (i = 0; i < csi2->csi_info.csi_num; i++) { + csi_idx = csi2->csi_info.csi_idx[i]; + csi2_disable(csi2->csi2_hw[csi_idx]); + csi2_hw_do_reset(csi2->csi2_hw[csi_idx]); + csi2_disable_clks(csi2->csi2_hw[csi_idx]); + } } /* @@ -379,7 +399,6 @@ static int csi2_media_init(struct v4l2_subdev *sd) csi2->crop.left = 0; csi2->crop.width = RKCIF_DEFAULT_WIDTH; csi2->crop.height = RKCIF_DEFAULT_HEIGHT; - csi2->csi_idx = 0; return media_entity_pads_init(&sd->entity, num_pads, csi2->pad); } @@ -567,11 +586,19 @@ static int rkcif_csi2_s_power(struct v4l2_subdev *sd, int on) static long rkcif_csi2_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { struct csi2_dev *csi2 = sd_to_dev(sd); + struct v4l2_subdev *sensor = get_remote_sensor(sd); long ret = 0; + int i = 0; switch (cmd) { case RKCIF_CMD_SET_CSI_IDX: - csi2->csi_idx = *((u32 *)arg); + csi2->csi_info = *((struct rkcif_csi_info *)arg); + for (i = 0; i < csi2->csi_info.csi_num; i++) + csi2->csi2_hw[csi2->csi_info.csi_idx[i]]->csi2 = csi2; + if (csi2->match_data->chip_id > CHIP_RV1126_CSI2) + ret = v4l2_subdev_call(sensor, core, ioctl, + RKCIF_CMD_SET_CSI_IDX, + arg); break; default: ret = -ENOIOCTLCMD; @@ -586,15 +613,15 @@ static long rkcif_csi2_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd, unsigned long arg) { void __user *up = compat_ptr(arg); - u32 csi_idx = 0; + struct rkcif_csi_info csi_info; long ret; switch (cmd) { case RKCIF_CMD_SET_CSI_IDX: - if (copy_from_user(&csi_idx, up, sizeof(u32))) + if (copy_from_user(&csi_info, up, sizeof(struct rkcif_csi_info))) return -EFAULT; - ret = rkcif_csi2_ioctl(sd, cmd, &csi_idx); + ret = rkcif_csi2_ioctl(sd, cmd, &csi_info); break; default: ret = -ENOIOCTLCMD; @@ -749,7 +776,8 @@ static void csi2_find_err_vc(int val, char *vc_info) static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx) { struct device *dev = ctx; - struct csi2_dev *csi2 = sd_to_dev(dev_get_drvdata(dev)); + struct csi2_hw *csi2_hw = dev_get_drvdata(dev); + struct csi2_dev *csi2 = csi2_hw->csi2; struct csi2_err_stats *err_list = NULL; unsigned long err_stat = 0; u32 val; @@ -758,7 +786,7 @@ static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx) char vc_info[CSI_VCINFO_LEN] = {0}; bool is_add_cnt = false; - val = read_csihost_reg(csi2->base, CSIHOST_ERR1); + val = read_csihost_reg(csi2_hw->base, CSIHOST_ERR1); if (val) { if (val & CSIHOST_ERR1_PHYERR_SPTSYNCHS) { err_list = &csi2->err_list[RK_CSI2_ERR_SOTSYN]; @@ -767,7 +795,7 @@ static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx) if (err_list->cnt > 3 && csi2->err_list[RK_CSI2_ERR_ALL].cnt <= err_list->cnt) { csi2->is_check_sot_sync = false; - write_csihost_reg(csi2->base, CSIHOST_MSK1, 0xf); + write_csihost_reg(csi2_hw->base, CSIHOST_MSK1, 0xf); } if (csi2->is_check_sot_sync) { csi2_find_err_vc(val & 0xf, vc_info); @@ -832,7 +860,7 @@ static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx) csi2_err_strncat(err_str, cur_str); } - pr_err("%s ERR1:0x%x %s\n", csi2->dev_name, val, err_str); + pr_err("%s ERR1:0x%x %s\n", csi2_hw->dev_name, val, err_str); if (is_add_cnt) { csi2->err_list[RK_CSI2_ERR_ALL].cnt++; @@ -841,7 +869,7 @@ static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx) atomic_notifier_call_chain(&g_csi_host_chain, err_stat, - &csi2->csi_idx); + &csi2->csi_info.csi_idx[csi2->csi_info.csi_num - 1]); } } @@ -852,13 +880,13 @@ static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx) static irqreturn_t rk_csirx_irq2_handler(int irq, void *ctx) { struct device *dev = ctx; - struct csi2_dev *csi2 = sd_to_dev(dev_get_drvdata(dev)); + struct csi2_hw *csi2_hw = dev_get_drvdata(dev); u32 val; char cur_str[CSI_ERRSTR_LEN] = {0}; char err_str[CSI_ERRSTR_LEN] = {0}; char vc_info[CSI_VCINFO_LEN] = {0}; - val = read_csihost_reg(csi2->base, CSIHOST_ERR2); + val = read_csihost_reg(csi2_hw->base, CSIHOST_ERR2); if (val) { if (val & CSIHOST_ERR2_PHYERR_ESC) { csi2_find_err_vc(val & 0xf, vc_info); @@ -885,7 +913,7 @@ static irqreturn_t rk_csirx_irq2_handler(int irq, void *ctx) csi2_err_strncat(err_str, cur_str); } - pr_err("%s ERR2:0x%x %s\n", csi2->dev_name, val, err_str); + pr_err("%s ERR2:0x%x %s\n", csi2_hw->dev_name, val, err_str); } return IRQ_HANDLED; @@ -924,31 +952,43 @@ static int csi2_notifier(struct csi2_dev *csi2) static const struct csi2_match_data rk1808_csi2_match_data = { .chip_id = CHIP_RK1808_CSI2, .num_pads = CSI2_NUM_PADS, + .num_hw = 1, }; static const struct csi2_match_data rk3288_csi2_match_data = { .chip_id = CHIP_RK3288_CSI2, .num_pads = CSI2_NUM_PADS_SINGLE_LINK, + .num_hw = 1, }; static const struct csi2_match_data rv1126_csi2_match_data = { .chip_id = CHIP_RV1126_CSI2, .num_pads = CSI2_NUM_PADS, + .num_hw = 1, }; static const struct csi2_match_data rk3568_csi2_match_data = { .chip_id = CHIP_RK3568_CSI2, .num_pads = CSI2_NUM_PADS, + .num_hw = 1, }; static const struct csi2_match_data rk3588_csi2_match_data = { .chip_id = CHIP_RK3588_CSI2, .num_pads = CSI2_NUM_PADS_MAX, + .num_hw = 6, +}; + +static const struct csi2_match_data rv1106_csi2_match_data = { + .chip_id = CHIP_RV1106_CSI2, + .num_pads = CSI2_NUM_PADS_MAX, + .num_hw = 2, }; static const struct csi2_match_data rk3562_csi2_match_data = { .chip_id = CHIP_RK3562_CSI2, .num_pads = CSI2_NUM_PADS_MAX, + .num_hw = 4, }; static const struct of_device_id csi2_dt_ids[] = { @@ -972,6 +1012,10 @@ static const struct of_device_id csi2_dt_ids[] = { .compatible = "rockchip,rk3588-mipi-csi2", .data = &rk3588_csi2_match_data, }, + { + .compatible = "rockchip,rv1106-mipi-csi2", + .data = &rv1106_csi2_match_data, + }, { .compatible = "rockchip,rk3562-mipi-csi2", .data = &rk3562_csi2_match_data, @@ -980,15 +1024,48 @@ static const struct of_device_id csi2_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, csi2_dt_ids); +static int csi2_attach_hw(struct csi2_dev *csi2) +{ + struct device_node *np; + struct platform_device *pdev; + struct csi2_hw *hw; + int i = 0; + + for (i = 0; i < csi2->match_data->num_hw; i++) { + np = of_parse_phandle(csi2->dev->of_node, "rockchip,hw", i); + if (!np || !of_device_is_available(np)) { + dev_err(csi2->dev, "failed to get csi2 hw node\n"); + return -ENODEV; + } + + pdev = of_find_device_by_node(np); + of_node_put(np); + if (!pdev) { + dev_err(csi2->dev, "failed to get csi2 hw from node\n"); + return -ENODEV; + } + + hw = platform_get_drvdata(pdev); + if (!hw) { + dev_err(csi2->dev, "failed attach csi2 hw\n"); + return -EINVAL; + } + + hw->csi2 = csi2; + csi2->csi2_hw[i] = hw; + } + dev_info(csi2->dev, "attach to csi2 hw node\n"); + + return 0; +} + static int csi2_probe(struct platform_device *pdev) { const struct of_device_id *match; - struct device *dev = &pdev->dev; struct device_node *node = pdev->dev.of_node; struct csi2_dev *csi2 = NULL; - struct resource *res; const struct csi2_match_data *data; - int ret, irq; + int ret; match = of_match_node(csi2_dt_ids, node); if (IS_ERR(match)) @@ -1014,63 +1091,11 @@ static int csi2_probe(struct platform_device *pdev) v4l2_err(&csi2->sd, "failed to copy name\n"); platform_set_drvdata(pdev, &csi2->sd); - csi2->clks_num = devm_clk_bulk_get_all(dev, &csi2->clks_bulk); - if (csi2->clks_num < 0) { - csi2->clks_num = 0; - dev_err(dev, "failed to get csi2 clks\n"); + ret = csi2_attach_hw(csi2); + if (ret) { + v4l2_err(&csi2->sd, "must enable all mipi csi2 hw node\n"); + return -EINVAL; } - - csi2->rsts_bulk = devm_reset_control_array_get_optional_exclusive(dev); - if (IS_ERR(csi2->rsts_bulk)) { - if (PTR_ERR(csi2->rsts_bulk) != -EPROBE_DEFER) - dev_err(dev, "failed to get csi2 reset\n"); - csi2->rsts_bulk = NULL; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - csi2->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(csi2->base)) { - resource_size_t offset = res->start; - resource_size_t size = resource_size(res); - - dev_warn(&pdev->dev, "avoid secondary mipi resource check!\n"); - - csi2->base = devm_ioremap(&pdev->dev, offset, size); - if (IS_ERR(csi2->base)) { - dev_err(&pdev->dev, "Failed to ioremap resource\n"); - - return PTR_ERR(csi2->base); - } - } - - irq = platform_get_irq_byname(pdev, "csi-intr1"); - if (irq > 0) { - ret = devm_request_irq(&pdev->dev, irq, - rk_csirx_irq1_handler, 0, - dev_driver_string(&pdev->dev), - &pdev->dev); - if (ret < 0) - v4l2_err(&csi2->sd, "request csi-intr1 irq failed: %d\n", - ret); - csi2->irq1 = irq; - } else { - v4l2_err(&csi2->sd, "No found irq csi-intr1\n"); - } - - irq = platform_get_irq_byname(pdev, "csi-intr2"); - if (irq > 0) { - ret = devm_request_irq(&pdev->dev, irq, - rk_csirx_irq2_handler, 0, - dev_driver_string(&pdev->dev), - &pdev->dev); - if (ret < 0) - v4l2_err(&csi2->sd, "request csi-intr2 failed: %d\n", - ret); - csi2->irq2 = irq; - } else { - v4l2_err(&csi2->sd, "No found irq csi-intr2\n"); - } - mutex_init(&csi2->lock); ret = csi2_media_init(&csi2->sd); @@ -1115,11 +1140,183 @@ int rkcif_csi2_plat_drv_init(void) return platform_driver_register(&csi2_driver); } -void __exit rkcif_csi2_plat_drv_exit(void) +void rkcif_csi2_plat_drv_exit(void) { platform_driver_unregister(&csi2_driver); } +static const struct csi2_hw_match_data rk1808_csi2_hw_match_data = { + .chip_id = CHIP_RK1808_CSI2, +}; + +static const struct csi2_hw_match_data rk3288_csi2_hw_match_data = { + .chip_id = CHIP_RK3288_CSI2, +}; + +static const struct csi2_hw_match_data rv1126_csi2_hw_match_data = { + .chip_id = CHIP_RV1126_CSI2, +}; + +static const struct csi2_hw_match_data rk3568_csi2_hw_match_data = { + .chip_id = CHIP_RK3568_CSI2, +}; + +static const struct csi2_hw_match_data rk3588_csi2_hw_match_data = { + .chip_id = CHIP_RK3588_CSI2, +}; + +static const struct csi2_hw_match_data rv1106_csi2_hw_match_data = { + .chip_id = CHIP_RV1106_CSI2, +}; + +static const struct csi2_hw_match_data rk3562_csi2_hw_match_data = { + .chip_id = CHIP_RK3562_CSI2, +}; + +static const struct of_device_id csi2_hw_ids[] = { + { + .compatible = "rockchip,rk1808-mipi-csi2-hw", + .data = &rk1808_csi2_hw_match_data, + }, + { + .compatible = "rockchip,rk3288-mipi-csi2-hw", + .data = &rk3288_csi2_hw_match_data, + }, + { + .compatible = "rockchip,rk3568-mipi-csi2-hw", + .data = &rk3568_csi2_hw_match_data, + }, + { + .compatible = "rockchip,rv1126-mipi-csi2-hw", + .data = &rv1126_csi2_hw_match_data, + }, + { + .compatible = "rockchip,rk3588-mipi-csi2-hw", + .data = &rk3588_csi2_hw_match_data, + }, + { + .compatible = "rockchip,rv1106-mipi-csi2-hw", + .data = &rv1106_csi2_hw_match_data, + }, + { + .compatible = "rockchip,rk3562-mipi-csi2-hw", + .data = &rk3588_csi2_hw_match_data, + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, csi2_hw_ids); + +static int csi2_hw_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + struct device *dev = &pdev->dev; + struct device_node *node = pdev->dev.of_node; + struct csi2_hw *csi2_hw = NULL; + struct resource *res; + const struct csi2_hw_match_data *data; + int ret, irq; + + dev_info(&pdev->dev, "enter mipi csi2 hw probe!\n"); + match = of_match_node(csi2_hw_ids, node); + if (IS_ERR(match)) + return PTR_ERR(match); + data = match->data; + + csi2_hw = devm_kzalloc(&pdev->dev, sizeof(*csi2_hw), GFP_KERNEL); + if (!csi2_hw) + return -ENOMEM; + + csi2_hw->dev = &pdev->dev; + csi2_hw->match_data = data; + + csi2_hw->dev_name = node->name; + + csi2_hw->clks_num = devm_clk_bulk_get_all(dev, &csi2_hw->clks_bulk); + if (csi2_hw->clks_num < 0) { + csi2_hw->clks_num = 0; + dev_err(dev, "failed to get csi2 clks\n"); + } + + csi2_hw->rsts_bulk = devm_reset_control_array_get_optional_exclusive(dev); + if (IS_ERR(csi2_hw->rsts_bulk)) { + if (PTR_ERR(csi2_hw->rsts_bulk) != -EPROBE_DEFER) + dev_err(dev, "failed to get csi2 reset\n"); + csi2_hw->rsts_bulk = NULL; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + csi2_hw->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(csi2_hw->base)) { + resource_size_t offset = res->start; + resource_size_t size = resource_size(res); + + dev_warn(&pdev->dev, "avoid secondary mipi resource check!\n"); + + csi2_hw->base = devm_ioremap(&pdev->dev, offset, size); + if (IS_ERR(csi2_hw->base)) { + dev_err(&pdev->dev, "Failed to ioremap resource\n"); + + return PTR_ERR(csi2_hw->base); + } + } + + irq = platform_get_irq_byname(pdev, "csi-intr1"); + if (irq > 0) { + ret = devm_request_irq(&pdev->dev, irq, + rk_csirx_irq1_handler, 0, + dev_driver_string(&pdev->dev), + &pdev->dev); + if (ret < 0) + dev_err(&pdev->dev, "request csi-intr1 irq failed: %d\n", + ret); + csi2_hw->irq1 = irq; + } else { + dev_err(&pdev->dev, "No found irq csi-intr1\n"); + } + + irq = platform_get_irq_byname(pdev, "csi-intr2"); + if (irq > 0) { + ret = devm_request_irq(&pdev->dev, irq, + rk_csirx_irq2_handler, 0, + dev_driver_string(&pdev->dev), + &pdev->dev); + if (ret < 0) + dev_err(&pdev->dev, "request csi-intr2 failed: %d\n", + ret); + csi2_hw->irq2 = irq; + } else { + dev_err(&pdev->dev, "No found irq csi-intr2\n"); + } + platform_set_drvdata(pdev, csi2_hw); + dev_info(&pdev->dev, "probe success, v4l2_dev:%s!\n", csi2_hw->dev_name); + + return 0; +} + +static int csi2_hw_remove(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver csi2_hw_driver = { + .driver = { + .name = DEVICE_NAME_HW, + .of_match_table = csi2_hw_ids, + }, + .probe = csi2_hw_probe, + .remove = csi2_hw_remove, +}; + +int rkcif_csi2_hw_plat_drv_init(void) +{ + return platform_driver_register(&csi2_hw_driver); +} + +void rkcif_csi2_hw_plat_drv_exit(void) +{ + platform_driver_unregister(&csi2_hw_driver); +} + MODULE_DESCRIPTION("Rockchip MIPI CSI2 driver"); MODULE_AUTHOR("Macrofly.xu "); MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/rockchip/cif/mipi-csi2.h b/drivers/media/platform/rockchip/cif/mipi-csi2.h index 28bc7c8c6fa4..fc21782fbc32 100644 --- a/drivers/media/platform/rockchip/cif/mipi-csi2.h +++ b/drivers/media/platform/rockchip/cif/mipi-csi2.h @@ -8,6 +8,7 @@ #include #include #include +#include #define CSI2_ERR_FSFE_MASK (0xff << 8) #define CSI2_ERR_COUNT_ALL_MASK (0xff) @@ -42,6 +43,7 @@ #define CSIHOST_MAX_ERRINT_COUNT 10 #define DEVICE_NAME "rockchip-mipi-csi2" +#define DEVICE_NAME_HW "rockchip-mipi-csi2-hw" /* CSI Host Registers Define */ #define CSIHOST_N_LANES 0x04 @@ -76,6 +78,8 @@ #define SW_DATATYPE_LS(x) ((x) << 20) #define SW_DATATYPE_LE(x) ((x) << 26) +#define RK_MAX_CSI_HW (6) + /* * add new chip id in tail in time order * by increasing to distinguish csi2 host version @@ -88,6 +92,7 @@ enum rkcsi2_chip_id { CHIP_RV1126_CSI2, CHIP_RK3568_CSI2, CHIP_RK3588_CSI2, + CHIP_RV1106_CSI2, CHIP_RK3562_CSI2, }; @@ -117,6 +122,11 @@ enum host_type_t { struct csi2_match_data { int chip_id; int num_pads; + int num_hw; +}; + +struct csi2_hw_match_data { + int chip_id; }; struct csi2_sensor_info { @@ -155,10 +165,29 @@ struct csi2_dev { int num_sensors; atomic_t frm_sync_seq; struct csi2_err_stats err_list[RK_CSI2_ERR_MAX]; + struct csi2_hw *csi2_hw[RK_MAX_CSI_HW]; int irq1; int irq2; int dsi_input_en; - u32 csi_idx; + struct rkcif_csi_info csi_info; + const char *dev_name; +}; + +struct csi2_hw { + struct device *dev; + struct clk_bulk_data *clks_bulk; + int clks_num; + struct reset_control *rsts_bulk; + struct csi2_dev *csi2; + const struct csi2_hw_match_data *match_data; + + void __iomem *base; + + /* lock to protect all members below */ + struct mutex lock; + + int irq1; + int irq2; const char *dev_name; }; @@ -166,7 +195,9 @@ u32 rkcif_csi2_get_sof(struct csi2_dev *csi2_dev); void rkcif_csi2_set_sof(struct csi2_dev *csi2_dev, u32 seq); void rkcif_csi2_event_inc_sof(struct csi2_dev *csi2_dev); int rkcif_csi2_plat_drv_init(void); -void __exit rkcif_csi2_plat_drv_exit(void); +void rkcif_csi2_plat_drv_exit(void); +int rkcif_csi2_hw_plat_drv_init(void); +void rkcif_csi2_hw_plat_drv_exit(void); int rkcif_csi2_register_notifier(struct notifier_block *nb); int rkcif_csi2_unregister_notifier(struct notifier_block *nb); void rkcif_csi2_event_reset_pipe(struct csi2_dev *csi2_dev, int reset_src); diff --git a/drivers/media/platform/rockchip/cif/subdev-itf.c b/drivers/media/platform/rockchip/cif/subdev-itf.c index 27f83002ca37..9020fff82c63 100644 --- a/drivers/media/platform/rockchip/cif/subdev-itf.c +++ b/drivers/media/platform/rockchip/cif/subdev-itf.c @@ -342,7 +342,10 @@ static long sditf_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) mode = (struct rkisp_vicap_mode *)arg; memcpy(&priv->mode, mode, sizeof(*mode)); sditf_reinit_mode(priv, &priv->mode); - mode->input.merge_num = cif_dev->sditf_cnt; + if (priv->is_combine_mode) + mode->input.merge_num = cif_dev->sditf_cnt; + else + mode->input.merge_num = 1; mode->input.index = priv->combine_index; return 0; case RKISP_VICAP_CMD_INIT_BUF: @@ -430,6 +433,7 @@ static long sditf_compat_ioctl32(struct v4l2_subdev *sd, static int sditf_channel_enable(struct sditf_priv *priv, int user) { struct rkcif_device *cif_dev = priv->cif_dev; + struct rkmodule_capture_info *capture_info = &cif_dev->channels[0].capture_info; unsigned int ch0 = 0, ch1 = 0, ch2 = 0; unsigned int ctrl_val = 0; unsigned int int_en = 0; @@ -437,11 +441,25 @@ static int sditf_channel_enable(struct sditf_priv *priv, int user) unsigned int offset_y = 0; unsigned int width = priv->cap_info.width; unsigned int height = priv->cap_info.height; + int csi_idx = cif_dev->csi_host_idx; + + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE && + priv->toisp_inf.link_mode == TOISP_UNITE) { + if (capture_info->multi_dev.dev_num != 2 || + capture_info->multi_dev.pixel_offset != RKMOUDLE_UNITE_EXTEND_PIXEL) { + v4l2_err(&cif_dev->v4l2_dev, + "param error of online mode, combine dev num %d, offset %d\n", + capture_info->multi_dev.dev_num, + capture_info->multi_dev.pixel_offset); + return -EINVAL; + } + csi_idx = capture_info->multi_dev.dev_idx[user]; + } if (priv->hdr_cfg.hdr_mode == NO_HDR || priv->hdr_cfg.hdr_mode == HDR_COMPR) { if (cif_dev->inf_id == RKCIF_MIPI_LVDS) - ch0 = cif_dev->csi_host_idx * 4; + ch0 = csi_idx * 4; else ch0 = 24;//dvp ctrl_val = (ch0 << 3) | 0x1; @@ -496,7 +514,10 @@ static int sditf_channel_enable(struct sditf_priv *priv, int user) } } else { if (priv->toisp_inf.link_mode == TOISP_UNITE) { - offset_x = priv->cap_info.width / 2 - RKMOUDLE_UNITE_EXTEND_PIXEL; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) + offset_x = 0; + else + offset_x = priv->cap_info.width / 2 - RKMOUDLE_UNITE_EXTEND_PIXEL; width = priv->cap_info.width / 2 + RKMOUDLE_UNITE_EXTEND_PIXEL; } rkcif_write_register(cif_dev, CIF_REG_TOISP1_CTRL, ctrl_val); diff --git a/drivers/media/platform/rockchip/cif/version.h b/drivers/media/platform/rockchip/cif/version.h index 627b4a3a11e5..dbebed0ca0ef 100644 --- a/drivers/media/platform/rockchip/cif/version.h +++ b/drivers/media/platform/rockchip/cif/version.h @@ -67,6 +67,8 @@ *7. add keepint time to csi2 err for resetting *8. mipi supports pdaf/embedded data *9. mipi supports interlaced capture + *v0.2.0 + *1. vicap support combine multi mipi dev to one dev, this function is mainly used for rk3588 */ #define RKCIF_DRIVER_VERSION RKCIF_API_VERSION From a9ed7b93e657b49420dc7c02c3ce9ce810e9b7d3 Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Wed, 21 Dec 2022 10:19:50 +0800 Subject: [PATCH 042/133] media: rockchip: vicap compatible with rk3588s2 Signed-off-by: Zefa Chen Change-Id: Idd8312275b97b690de378094116d558e85b4cb00 --- drivers/media/platform/rockchip/cif/capture.c | 50 +++++++++++------ .../media/platform/rockchip/cif/cif-scale.c | 4 +- .../media/platform/rockchip/cif/cif-tools.c | 4 +- drivers/media/platform/rockchip/cif/dev.c | 15 +++++- drivers/media/platform/rockchip/cif/dev.h | 3 +- drivers/media/platform/rockchip/cif/hw.c | 54 +++++++++++++++++++ drivers/media/platform/rockchip/cif/hw.h | 1 + 7 files changed, 110 insertions(+), 21 deletions(-) diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index 2b76a5f17c0e..3d5a1d55123c 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -847,10 +847,11 @@ static int get_csi_crop_align(const struct cif_input_fmt *fmt_in) } const struct -cif_input_fmt *get_input_fmt(struct v4l2_subdev *sd, struct v4l2_rect *rect, +cif_input_fmt *rkcif_get_input_fmt(struct rkcif_device *dev, struct v4l2_rect *rect, u32 pad_id, struct csi_channel_info *csi_info) { struct v4l2_subdev_format fmt; + struct v4l2_subdev *sd = dev->terminal_sensor.sd; struct rkmodule_channel_info ch_info = {0}; struct rkmodule_capture_info capture_info; int ret; @@ -914,8 +915,22 @@ cif_input_fmt *get_input_fmt(struct v4l2_subdev *sd, struct v4l2_rect *rect, core, ioctl, RKMODULE_GET_CAPTURE_MODE, &capture_info); - if (!ret) + if (!ret) { + if (capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE && + dev->hw_dev->is_rk3588s2) { + for (i = 0; i < capture_info.multi_dev.dev_num; i++) { + if (capture_info.multi_dev.dev_idx[i] == 0) + capture_info.multi_dev.dev_idx[i] = 2; + else if (capture_info.multi_dev.dev_idx[i] == 2) + capture_info.multi_dev.dev_idx[i] = 4; + else if (capture_info.multi_dev.dev_idx[i] == 3) + capture_info.multi_dev.dev_idx[i] = 5; + } + } csi_info->capture_info = capture_info; + } else { + csi_info->capture_info.mode = RKMODULE_CAPTURE_MODE_NONE; + } for (i = 0; i < ARRAY_SIZE(in_fmts); i++) if (fmt.format.code == in_fmts[i].mbus_code && fmt.format.field == in_fmts[i].field) @@ -5362,9 +5377,9 @@ static int rkcif_sanity_check_fmt(struct rkcif_stream *stream, struct v4l2_rect input, *crop; if (dev->terminal_sensor.sd) { - stream->cif_fmt_in = get_input_fmt(dev->terminal_sensor.sd, - &input, stream->id, - &dev->channels[stream->id]); + stream->cif_fmt_in = rkcif_get_input_fmt(dev, + &input, stream->id, + &dev->channels[stream->id]); if (!stream->cif_fmt_in) { v4l2_err(v4l2_dev, "Input fmt is invalid\n"); return -EINVAL; @@ -6146,10 +6161,15 @@ int rkcif_do_start_stream(struct rkcif_stream *stream, unsigned int mode) csi_info.csi_num, RKCIF_MAX_CSI_NUM); goto out; } - for (i = 0; i < csi_info.csi_num; i++) + for (i = 0; i < csi_info.csi_num; i++) { csi_info.csi_idx[i] = dev->channels[0].capture_info.multi_dev.dev_idx[i]; + if (dev->hw_dev->is_rk3588s2) + v4l2_info(v4l2_dev, "rk3588s2 combine mode attach to mipi%d\n", + csi_info.csi_idx[i]); + } } else { csi_info.csi_num = 1; + dev->csi_host_idx = dev->csi_host_idx_def; csi_info.csi_idx[0] = dev->csi_host_idx; } ret = v4l2_subdev_call(dev->active_sensor->sd, @@ -6350,9 +6370,9 @@ int rkcif_set_fmt(struct rkcif_stream *stream, input_rect.height = RKCIF_DEFAULT_HEIGHT; if (dev->terminal_sensor.sd) { - cif_fmt_in = get_input_fmt(dev->terminal_sensor.sd, - &input_rect, stream->id, - channel_info); + cif_fmt_in = rkcif_get_input_fmt(dev, + &input_rect, stream->id, + channel_info); stream->cif_fmt_in = cif_fmt_in; } else { v4l2_err(&stream->cifdev->v4l2_dev, @@ -6720,9 +6740,9 @@ static int rkcif_enum_framesizes(struct file *file, void *prov, input_rect.height = RKCIF_DEFAULT_HEIGHT; if (dev->terminal_sensor.sd) - get_input_fmt(dev->terminal_sensor.sd, - &input_rect, stream->id, - &csi_info); + rkcif_get_input_fmt(dev, + &input_rect, stream->id, + &csi_info); if (dev->hw_dev->adapt_to_usbcamerahal) { fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; @@ -6801,7 +6821,7 @@ static int rkcif_enum_fmt_vid_cap_mplane(struct file *file, void *priv, return -EINVAL; if (dev->terminal_sensor.sd) { - cif_fmt_in = get_input_fmt(dev->terminal_sensor.sd, + cif_fmt_in = rkcif_get_input_fmt(dev, &input_rect, stream->id, &dev->channels[stream->id]); stream->cif_fmt_in = cif_fmt_in; @@ -7187,8 +7207,8 @@ static long rkcif_ioctl_default(struct file *file, void *fh, break; case RKCIF_CMD_SET_CSI_MEMORY_MODE: if (dev->terminal_sensor.sd) { - in_fmt = get_input_fmt(dev->terminal_sensor.sd, - &rect, 0, &csi_info); + in_fmt = rkcif_get_input_fmt(dev, + &rect, 0, &csi_info); if (in_fmt == NULL) { v4l2_err(&dev->v4l2_dev, "can't get sensor input format\n"); return -EINVAL; diff --git a/drivers/media/platform/rockchip/cif/cif-scale.c b/drivers/media/platform/rockchip/cif/cif-scale.c index 7ea3404258f0..3beede6ee93f 100644 --- a/drivers/media/platform/rockchip/cif/cif-scale.c +++ b/drivers/media/platform/rockchip/cif/cif-scale.c @@ -364,8 +364,8 @@ static int rkcif_scale_enum_framesizes(struct file *file, void *prov, input_rect.height = RKCIF_DEFAULT_HEIGHT; if (terminal_sensor && terminal_sensor->sd) - get_input_fmt(terminal_sensor->sd, - &input_rect, 0, &csi_info); + rkcif_get_input_fmt(dev, + &input_rect, 0, &csi_info); switch (fsize->index) { case SCALE_8TIMES: diff --git a/drivers/media/platform/rockchip/cif/cif-tools.c b/drivers/media/platform/rockchip/cif/cif-tools.c index e3a676c04b4b..60103bf71402 100644 --- a/drivers/media/platform/rockchip/cif/cif-tools.c +++ b/drivers/media/platform/rockchip/cif/cif-tools.c @@ -300,8 +300,8 @@ static int rkcif_tools_enum_framesizes(struct file *file, void *prov, input_rect.height = RKCIF_DEFAULT_HEIGHT; if (terminal_sensor && terminal_sensor->sd) - get_input_fmt(terminal_sensor->sd, - &input_rect, 0, &csi_info); + rkcif_get_input_fmt(dev, + &input_rect, 0, &csi_info); fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; s->width = input_rect.width; diff --git a/drivers/media/platform/rockchip/cif/dev.c b/drivers/media/platform/rockchip/cif/dev.c index e931dc61389d..6f41ab36a23a 100644 --- a/drivers/media/platform/rockchip/cif/dev.c +++ b/drivers/media/platform/rockchip/cif/dev.c @@ -1998,6 +1998,17 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int cif_dev->csi_host_idx = of_alias_get_id(node, "rkcif_mipi_lvds"); if (cif_dev->csi_host_idx < 0 || cif_dev->csi_host_idx > 5) cif_dev->csi_host_idx = 0; + if (cif_dev->hw_dev->is_rk3588s2) { + if (cif_dev->csi_host_idx == 0) + cif_dev->csi_host_idx = 2; + else if (cif_dev->csi_host_idx == 2) + cif_dev->csi_host_idx = 4; + else if (cif_dev->csi_host_idx == 3) + cif_dev->csi_host_idx = 5; + v4l2_info(&cif_dev->v4l2_dev, "rk3588s2 attach to mipi%d\n", + cif_dev->csi_host_idx); + } + cif_dev->csi_host_idx_def = cif_dev->csi_host_idx; cif_dev->media_dev.dev = dev; v4l2_dev = &cif_dev->v4l2_dev; v4l2_dev->mdev = &cif_dev->media_dev; @@ -2160,7 +2171,9 @@ static int rkcif_plat_probe(struct platform_device *pdev) if (sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp)) return -ENODEV; - rkcif_attach_hw(cif_dev); + ret = rkcif_attach_hw(cif_dev); + if (ret) + return ret; rkcif_parse_dts(cif_dev); diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index c0974a8c7719..b5d4c0315e8c 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -845,6 +845,7 @@ struct rkcif_device { struct rkcif_work_struct reset_work; int id_use_cnt; unsigned int csi_host_idx; + unsigned int csi_host_idx_def; unsigned int dvp_sof_in_oneframe; unsigned int wait_line; unsigned int wait_line_bak; @@ -887,7 +888,7 @@ void rkcif_vb_done_tasklet(struct rkcif_stream *stream, struct rkcif_buffer *buf int rkcif_scale_start(struct rkcif_scale_vdev *scale_vdev); const struct -cif_input_fmt *get_input_fmt(struct v4l2_subdev *sd, +cif_input_fmt *rkcif_get_input_fmt(struct rkcif_device *dev, struct v4l2_rect *rect, u32 pad_id, struct csi_channel_info *csi_info); diff --git a/drivers/media/platform/rockchip/cif/hw.c b/drivers/media/platform/rockchip/cif/hw.c index af0f0633e7bb..bf5653961509 100644 --- a/drivers/media/platform/rockchip/cif/hw.c +++ b/drivers/media/platform/rockchip/cif/hw.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -1252,6 +1253,51 @@ void rkcif_hw_soft_reset(struct rkcif_hw *cif_hw, bool is_rst_iommu) rkcif_iommu_enable(cif_hw); } +static int rkcif_get_efuse_value(struct device_node *np, char *porp_name, + u8 *value) +{ + struct nvmem_cell *cell; + unsigned char *buf; + size_t len; + + cell = of_nvmem_cell_get(np, porp_name); + if (IS_ERR(cell)) + return PTR_ERR(cell); + + buf = (unsigned char *)nvmem_cell_read(cell, &len); + + nvmem_cell_put(cell); + + if (IS_ERR(buf)) + return PTR_ERR(buf); + + *value = buf[0]; + + kfree(buf); + + return 0; +} + +static int rkcif_get_speciand_package_number(struct device_node *np) +{ + u8 spec = 0, package = 0, low = 0, high = 0; + + if (rkcif_get_efuse_value(np, "specification", &spec)) + return -EINVAL; + if (rkcif_get_efuse_value(np, "package_low", &low)) + return -EINVAL; + if (rkcif_get_efuse_value(np, "package_high", &high)) + return -EINVAL; + + package = ((high & 0x1) << 3) | low; + + /* RK3588S */ + if (spec == 0x13) + return package; + + return -EINVAL; +} + static int rkcif_plat_hw_probe(struct platform_device *pdev) { const struct of_device_id *match; @@ -1265,6 +1311,7 @@ static int rkcif_plat_hw_probe(struct platform_device *pdev) int i, ret, irq; bool is_mem_reserved = false; struct notifier_block *notifier; + int package = 0; match = of_match_node(rkcif_plat_of_match, node); if (IS_ERR(match)) @@ -1278,6 +1325,13 @@ static int rkcif_plat_hw_probe(struct platform_device *pdev) dev_set_drvdata(dev, cif_hw); cif_hw->dev = dev; + package = rkcif_get_speciand_package_number(node); + if (package == 0x2) { + cif_hw->is_rk3588s2 = true; + dev_info(dev, "attach rk3588s2\n"); + } else { + cif_hw->is_rk3588s2 = false; + } irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; diff --git a/drivers/media/platform/rockchip/cif/hw.h b/drivers/media/platform/rockchip/cif/hw.h index 56bc785cdd82..4faa9c46e085 100644 --- a/drivers/media/platform/rockchip/cif/hw.h +++ b/drivers/media/platform/rockchip/cif/hw.h @@ -150,6 +150,7 @@ struct rkcif_hw { bool is_dma_contig; bool adapt_to_usbcamerahal; u64 irq_time; + bool is_rk3588s2; }; void rkcif_hw_soft_reset(struct rkcif_hw *cif_hw, bool is_rst_iommu); From 458d4574259e8963a96c46244690281222cde349 Mon Sep 17 00:00:00 2001 From: Jianwei Fan Date: Sat, 8 Jul 2023 03:03:13 +0000 Subject: [PATCH 043/133] media: i2c: lt6911uxe: modify rk3588_dcphy params Change-Id: I5455c5e18e0074aa08a9bd97d20fa51bf2790a8a Signed-off-by: Jianwei Fan --- drivers/media/i2c/lt6911uxe.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/lt6911uxe.c b/drivers/media/i2c/lt6911uxe.c index 50cf2920eed0..fb15093c13d5 100644 --- a/drivers/media/i2c/lt6911uxe.c +++ b/drivers/media/i2c/lt6911uxe.c @@ -223,9 +223,9 @@ struct lt6911uxe_mode { static struct rkmodule_csi_dphy_param rk3588_dcphy_param = { .vendor = PHY_VENDOR_SAMSUNG, .lp_vol_ref = 3, - .lp_hys_sw = {3, 0, 0, 0}, - .lp_escclk_pol_sel = {1, 0, 0, 0}, - .skew_data_cal_clk = {0, 3, 3, 3}, + .lp_hys_sw = {3, 0, 3, 0}, + .lp_escclk_pol_sel = {1, 1, 0, 0}, + .skew_data_cal_clk = {0, 13, 0, 13}, .clk_hs_term_sel = 2, .data_hs_term_sel = {2, 2, 2, 2}, .reserved = {0}, From e57d4ee1aeb89e0af2e16b98c2abae3d59743504 Mon Sep 17 00:00:00 2001 From: Jianwei Fan Date: Tue, 4 Jul 2023 11:52:44 +0000 Subject: [PATCH 044/133] media: i2c: it6616: modify set ctrl when video stable Change-Id: I84b583f0a8c17a84a4c22f5a9d62dbde42904132 Signed-off-by: Jianwei Fan --- drivers/media/i2c/it6616.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/it6616.c b/drivers/media/i2c/it6616.c index 6928a11ac47c..fc930d2938c7 100644 --- a/drivers/media/i2c/it6616.c +++ b/drivers/media/i2c/it6616.c @@ -3519,6 +3519,16 @@ static int it6616_isr(struct v4l2_subdev *sd, u32 status, bool *handled) return 0; } +static void it6616_detect_hot_plug(struct v4l2_subdev *sd) +{ + struct it6616 *it6616 = to_it6616(sd); + + if (it6616->mipi_tx_video_stable && it6616_hdmi_is_5v_on(it6616)) + v4l2_ctrl_s_ctrl(it6616->detect_tx_5v_ctrl, 1); + else + v4l2_ctrl_s_ctrl(it6616->detect_tx_5v_ctrl, 0); +} + static void it6616_work_i2c_poll(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); @@ -3526,8 +3536,8 @@ static void it6616_work_i2c_poll(struct work_struct *work) struct it6616, work_i2c_poll); bool handled; - it6616_s_ctrl_detect_tx_5v(&it6616->sd); it6616_isr(&it6616->sd, 0, &handled); + it6616_detect_hot_plug(&it6616->sd); schedule_delayed_work(&it6616->work_i2c_poll, msecs_to_jiffies(POLL_INTERVAL_MS)); } From 78e9c25543b5c1721b17452887e5ee7ff34706a4 Mon Sep 17 00:00:00 2001 From: Wyon Bi Date: Mon, 19 Jun 2023 16:10:53 +0800 Subject: [PATCH 045/133] drm/panel: Add panel driver for Maxim MAX96772 based LCDs Signed-off-by: Wyon Bi Change-Id: Ie1981f600dd1422052f57c329ceed0702bb97ca4 --- drivers/gpu/drm/panel/Kconfig | 8 + drivers/gpu/drm/panel/Makefile | 1 + drivers/gpu/drm/panel/panel-maxim-max96772.c | 543 +++++++++++++++++++ 3 files changed, 552 insertions(+) create mode 100644 drivers/gpu/drm/panel/panel-maxim-max96772.c diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 2794dd34726f..c04e091233f1 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -236,6 +236,14 @@ config DRM_PANEL_MAXIM_MAX96752F Say Y if you want to enable support for panels based on the Maxim MAX96752F. +config DRM_PANEL_MAXIM_MAX96772 + tristate "Maxim MAX96772-based panels" + depends on OF + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y if you want to enable support for panels based on the + Maxim MAX96772. + config DRM_PANEL_OLIMEX_LCD_OLINUXINO tristate "Olimex LCD-OLinuXino panel" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index d99b1eaf92c2..f28d98218387 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35510) += panel-novatek-nt35510.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT39016) += panel-novatek-nt39016.o obj-$(CONFIG_DRM_PANEL_MANTIX_MLAF057WE51) += panel-mantix-mlaf057we51.o obj-$(CONFIG_DRM_PANEL_MAXIM_MAX96752F) += panel-maxim-max96752f.o +obj-$(CONFIG_DRM_PANEL_MAXIM_MAX96772) += panel-maxim-max96772.o obj-$(CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO) += panel-olimex-lcd-olinuxino.o obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o obj-$(CONFIG_DRM_PANEL_OSD_OSD101T2587_53TS) += panel-osd-osd101t2587-53ts.o diff --git a/drivers/gpu/drm/panel/panel-maxim-max96772.c b/drivers/gpu/drm/panel/panel-maxim-max96772.c new file mode 100644 index 000000000000..2e16d0337887 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-maxim-max96772.c @@ -0,0 +1,543 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2022 Rockchip Electronics Co. Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include