video: rockchip: vehicle: add fast reverse camera driver

Signed-off-by: Jianwei Fan <jianwei.fan@rock-chips.com>
Change-Id: I3c53046462000eaac645b2e5f0ef30b666b3f543
This commit is contained in:
Jianwei Fan
2022-08-02 10:01:36 +00:00
committed by Tao Huang
parent 31b330961a
commit e02a34a7fc
32 changed files with 15030 additions and 0 deletions

View File

@@ -6,3 +6,4 @@ source "drivers/video/rockchip/rve/Kconfig"
source "drivers/video/rockchip/iep/Kconfig"
source "drivers/video/rockchip/mpp/Kconfig"
source "drivers/video/rockchip/dvbm/Kconfig"
source "drivers/video/rockchip/vehicle/Kconfig"

View File

@@ -6,3 +6,4 @@ obj-$(CONFIG_ROCKCHIP_RVE) += rve/
obj-$(CONFIG_IEP) += iep/
obj-$(CONFIG_ROCKCHIP_MPP_SERVICE) += mpp/
obj-$(CONFIG_ROCKCHIP_DVBM) += dvbm/
obj-$(CONFIG_VIDEO_REVERSE_IMAGE) += vehicle/

View File

@@ -0,0 +1,41 @@
# SPDX-License-Identifier: GPL-2.0
config VIDEO_REVERSE_IMAGE
bool "Rockchip Fast Reverse Image driver"
depends on ARCH_ROCKCHIP && ROCKCHIP_DRM_DIRECT_SHOW
depends on VIDEO_ROCKCHIP_CIF && PHY_ROCKCHIP_CSI2_DPHY
help
fast reverse Image module.
if VIDEO_REVERSE_IMAGE
config VIDEO_REVERSE_NVP6324
bool "nvp6324 for reverse sensor"
help
Say y if use nvp6324.
config VIDEO_REVERSE_NVP6188
bool "nvp6188 for reverse sensor"
help
Say y if use nvp6188.
config VIDEO_REVERSE_MAX96714
bool "max96714 for reverse sensor"
help
Say y if use max96714.
config VIDEO_REVERSE_GC2145
bool "gc2145 for reverse sensor"
help
Say y if use gc2145.
config VIDEO_REVERSE_TP2825
bool "tp2825 for reverse sensor"
help
Say y if use tp2825.
config VIDEO_REVERSE_AD7181
bool "ad7181 for reverse sensor"
help
Say y if use ad7181.
endif

View File

@@ -0,0 +1,26 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_VIDEO_REVERSE_IMAGE) += video_rkvehicle.o
video_rkvehicle-objs += vehicle_flinger.o \
vehicle_dev.o \
vehicle_main.o \
vehicle_cif.o \
vehicle_generic_sensor.o \
vehicle_gpio.o \
video_rkvehicle-$(CONFIG_VIDEO_REVERSE_NVP6324) += \
vehicle_ad_nvp6324.o
video_rkvehicle-$(CONFIG_VIDEO_REVERSE_NVP6188) += \
vehicle_ad_nvp6188.o
video_rkvehicle-$(CONFIG_VIDEO_REVERSE_MAX96714) += \
vehicle_ad_max96714.o
video_rkvehicle-$(CONFIG_VIDEO_REVERSE_GC2145) += \
vehicle_ad_gc2145.o
video_rkvehicle-$(CONFIG_VIDEO_REVERSE_TP2825) += \
vehicle_ad_tp2825.o
video_rkvehicle-$(CONFIG_VIDEO_REVERSE_AD7181) += \
vehicle_ad_7181.o

View File

@@ -0,0 +1,362 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Rockchip Vehicle driver
*
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
*/
#ifndef _VEHICLE_CSI2_DPHY_COMMON_H_
#define _VEHICLE_CSI2_DPHY_COMMON_H_
#include <linux/kernel.h>
#include <linux/rk-camera-module.h>
#include <media/v4l2-subdev.h>
#include "vehicle_samsung_dcphy_common.h"
#include "../../../media/platform/rockchip/cif/mipi-csi2.h"
/* GRF REG OFFSET */
#define GRF_VI_CON0 (0x0340)
#define GRF_VI_CON1 (0x0344)
/*RK3588 DPHY GRF REG OFFSET */
#define GRF_DPHY_CON0 (0x0)
#define GRF_SOC_CON2 (0x0308)
/*GRF REG BIT DEFINE */
#define GRF_CSI2PHY_LANE_SEL_SPLIT (0x1)
#define GRF_CSI2PHY_SEL_SPLIT_0_1 (0x0)
#define GRF_CSI2PHY_SEL_SPLIT_2_3 BIT(0)
/*RK3588 DCPHY GRF REG OFFSET */
#define GRF_DCPHY_CON0 (0x0)
/* PHY REG OFFSET */
#define CSI2_DPHY_CTRL_INVALID_OFFSET (0xffff)
#define CSI2_DPHY_CTRL_PWRCTL \
CSI2_DPHY_CTRL_INVALID_OFFSET
#define CSI2_DPHY_CTRL_LANE_ENABLE (0x00)
#define CSI2_DPHY_CLK1_LANE_EN (0x2C)
#define CSI2_DPHY_DUAL_CAL_EN (0x80)
#define CSI2_DPHY_CLK_WR_THS_SETTLE (0x160)
#define CSI2_DPHY_CLK_CALIB_EN (0x168)
#define CSI2_DPHY_LANE0_WR_THS_SETTLE (0x1e0)
#define CSI2_DPHY_LANE0_CALIB_EN (0x1e8)
#define CSI2_DPHY_LANE1_WR_THS_SETTLE (0x260)
#define CSI2_DPHY_LANE1_CALIB_EN (0x268)
#define CSI2_DPHY_LANE2_WR_THS_SETTLE (0x2e0)
#define CSI2_DPHY_LANE2_CALIB_EN (0x2e8)
#define CSI2_DPHY_LANE3_WR_THS_SETTLE (0x360)
#define CSI2_DPHY_LANE3_CALIB_EN (0x368)
#define CSI2_DPHY_CLK1_WR_THS_SETTLE (0x3e0)
#define CSI2_DPHY_CLK1_CALIB_EN (0x3e8)
//DCPHY
#define CSI2_DCPHY_CLK_WR_THS_SETTLE (0x030)
#define CSI2_DCPHY_LANE0_WR_THS_SETTLE (0x130)
#define CSI2_DCPHY_LANE0_WR_ERR_SOT_SYNC (0x134)
#define CSI2_DCPHY_LANE1_WR_THS_SETTLE (0x230)
#define CSI2_DCPHY_LANE1_WR_ERR_SOT_SYNC (0x234)
#define CSI2_DCPHY_LANE2_WR_THS_SETTLE (0x330)
#define CSI2_DCPHY_LANE2_WR_ERR_SOT_SYNC (0x334)
#define CSI2_DCPHY_LANE3_WR_THS_SETTLE (0x430)
#define CSI2_DCPHY_LANE3_WR_ERR_SOT_SYNC (0x434)
#define CSI2_DCPHY_CLK_LANE_ENABLE (0x000)
#define CSI2_DCPHY_DATA_LANE0_ENABLE (0x100)
#define CSI2_DCPHY_DATA_LANE1_ENABLE (0x200)
#define CSI2_DCPHY_DATA_LANE2_ENABLE (0x300)
#define CSI2_DCPHY_DATA_LANE3_ENABLE (0x400)
#define CSI2_DCPHY_S0C_GNR_CON1 (0x004)
#define CSI2_DCPHY_S0C_ANA_CON1 (0x00c)
#define CSI2_DCPHY_S0C_ANA_CON2 (0x010)
#define CSI2_DCPHY_S0C_ANA_CON3 (0x014)
#define CSI2_DCPHY_COMBO_S0D0_GNR_CON1 (0x104)
#define CSI2_DCPHY_COMBO_S0D0_ANA_CON1 (0x10c)
#define CSI2_DCPHY_COMBO_S0D0_ANA_CON2 (0x110)
#define CSI2_DCPHY_COMBO_S0D0_ANA_CON3 (0x114)
#define CSI2_DCPHY_COMBO_S0D0_ANA_CON6 (0x120)
#define CSI2_DCPHY_COMBO_S0D0_ANA_CON7 (0x124)
#define CSI2_DCPHY_COMBO_S0D0_DESKEW_CON0 (0x140)
#define CSI2_DCPHY_COMBO_S0D0_DESKEW_CON2 (0x148)
#define CSI2_DCPHY_COMBO_S0D0_DESKEW_CON4 (0x150)
#define CSI2_DCPHY_COMBO_S0D0_CRC_CON1 (0x164)
#define CSI2_DCPHY_COMBO_S0D0_CRC_CON2 (0x168)
#define CSI2_DCPHY_COMBO_S0D1_GNR_CON1 (0x204)
#define CSI2_DCPHY_COMBO_S0D1_ANA_CON1 (0x20c)
#define CSI2_DCPHY_COMBO_S0D1_ANA_CON2 (0x210)
#define CSI2_DCPHY_COMBO_S0D1_ANA_CON3 (0x214)
#define CSI2_DCPHY_COMBO_S0D1_ANA_CON6 (0x220)
#define CSI2_DCPHY_COMBO_S0D1_ANA_CON7 (0x224)
#define CSI2_DCPHY_COMBO_S0D1_DESKEW_CON0 (0x240)
#define CSI2_DCPHY_COMBO_S0D1_DESKEW_CON2 (0x248)
#define CSI2_DCPHY_COMBO_S0D1_DESKEW_CON4 (0x250)
#define CSI2_DCPHY_COMBO_S0D1_CRC_CON1 (0x264)
#define CSI2_DCPHY_COMBO_S0D1_CRC_CON2 (0x268)
#define CSI2_DCPHY_COMBO_S0D2_GNR_CON1 (0x304)
#define CSI2_DCPHY_COMBO_S0D2_ANA_CON1 (0x30c)
#define CSI2_DCPHY_COMBO_S0D2_ANA_CON2 (0x310)
#define CSI2_DCPHY_COMBO_S0D2_ANA_CON3 (0x314)
#define CSI2_DCPHY_COMBO_S0D2_ANA_CON6 (0x320)
#define CSI2_DCPHY_COMBO_S0D2_ANA_CON7 (0x324)
#define CSI2_DCPHY_COMBO_S0D2_DESKEW_CON0 (0x340)
#define CSI2_DCPHY_COMBO_S0D2_DESKEW_CON2 (0x348)
#define CSI2_DCPHY_COMBO_S0D2_DESKEW_CON4 (0x350)
#define CSI2_DCPHY_COMBO_S0D2_CRC_CON1 (0x364)
#define CSI2_DCPHY_COMBO_S0D2_CRC_CON2 (0x368)
#define CSI2_DCPHY_S0D3_GNR_CON1 (0x404)
#define CSI2_DCPHY_S0D3_ANA_CON1 (0x40c)
#define CSI2_DCPHY_S0D3_ANA_CON2 (0x410)
#define CSI2_DCPHY_S0D3_ANA_CON3 (0x414)
#define CSI2_DCPHY_S0D3_DESKEW_CON0 (0x440)
#define CSI2_DCPHY_S0D3_DESKEW_CON2 (0x448)
#define CSI2_DCPHY_S0D3_DESKEW_CON4 (0x450)
/* PHY REG BIT DEFINE */
#define CSI2_DPHY_LANE_MODE_FULL (0x4)
#define CSI2_DPHY_LANE_MODE_SPLIT (0x2)
#define CSI2_DPHY_LANE_SPLIT_TOP (0x1)
#define CSI2_DPHY_LANE_SPLIT_BOT (0x2)
#define CSI2_DPHY_LANE_SPLIT_LANE0_1 (0x3 << 2)
#define CSI2_DPHY_LANE_SPLIT_LANE2_3 (0x3 << 4)
#define CSI2_DPHY_LANE_DUAL_MODE_EN BIT(6)
#define CSI2_DPHY_LANE_PARA_ARR_NUM (0x2)
#define CSI2_DPHY_CTRL_DATALANE_ENABLE_OFFSET_BIT 2
#define CSI2_DPHY_CTRL_DATALANE_SPLIT_LANE2_3_OFFSET_BIT 4
#define CSI2_DPHY_CTRL_CLKLANE_ENABLE_OFFSET_BIT 6
enum csi2_dphy_index {
DPHY0 = 0x0,
DPHY1,
DPHY2,
};
enum csi2_dphy_lane {
CSI2_DPHY_LANE_CLOCK = 0,
CSI2_DPHY_LANE_CLOCK1,
CSI2_DPHY_LANE_DATA0,
CSI2_DPHY_LANE_DATA1,
CSI2_DPHY_LANE_DATA2,
CSI2_DPHY_LANE_DATA3
};
enum grf_reg_id {
GRF_DPHY_RX0_TURNDISABLE = 0,
GRF_DPHY_RX0_FORCERXMODE,
GRF_DPHY_RX0_FORCETXSTOPMODE,
GRF_DPHY_RX0_ENABLE,
GRF_DPHY_RX0_TESTCLR,
GRF_DPHY_RX0_TESTCLK,
GRF_DPHY_RX0_TESTEN,
GRF_DPHY_RX0_TESTDIN,
GRF_DPHY_RX0_TURNREQUEST,
GRF_DPHY_RX0_TESTDOUT,
GRF_DPHY_TX0_TURNDISABLE,
GRF_DPHY_TX0_FORCERXMODE,
GRF_DPHY_TX0_FORCETXSTOPMODE,
GRF_DPHY_TX0_TURNREQUEST,
GRF_DPHY_TX1RX1_TURNDISABLE,
GRF_DPHY_TX1RX1_FORCERXMODE,
GRF_DPHY_TX1RX1_FORCETXSTOPMODE,
GRF_DPHY_TX1RX1_ENABLE,
GRF_DPHY_TX1RX1_MASTERSLAVEZ,
GRF_DPHY_TX1RX1_BASEDIR,
GRF_DPHY_TX1RX1_ENABLECLK,
GRF_DPHY_TX1RX1_TURNREQUEST,
GRF_DPHY_RX1_SRC_SEL,
/* rk3288 only */
GRF_CON_DISABLE_ISP,
GRF_CON_ISP_DPHY_SEL,
GRF_DSI_CSI_TESTBUS_SEL,
GRF_DVP_V18SEL,
/* rk1808 & rk3326 & rv1126 */
GRF_DPHY_CSI2PHY_FORCERXMODE,
GRF_DPHY_CSI2PHY_CLKLANE_EN,
GRF_DPHY_CSI2PHY_DATALANE_EN,
/* rv1126 only */
GRF_DPHY_CLK_INV_SEL,
GRF_DPHY_SEL,
/* rk3368 only */
GRF_ISP_MIPI_CSI_HOST_SEL,
/* below is for rk3399 only */
GRF_DPHY_RX0_CLK_INV_SEL,
GRF_DPHY_RX1_CLK_INV_SEL,
GRF_DPHY_TX1RX1_SRC_SEL,
/* below is for rk3568 only */
GRF_DPHY_CSI2PHY_CLKLANE1_EN,
GRF_DPHY_CLK1_INV_SEL,
GRF_DPHY_ISP_CSI2PHY_SEL,
GRF_DPHY_CIF_CSI2PHY_SEL,
GRF_DPHY_CSI2PHY_LANE_SEL,
GRF_DPHY_CSI2PHY1_LANE_SEL,
GRF_DPHY_CSI2PHY_DATALANE_EN0,
GRF_DPHY_CSI2PHY_DATALANE_EN1,
GRF_CPHY_MODE,
GRF_DPHY_CSIHOST2_SEL,
GRF_DPHY_CSIHOST3_SEL,
GRF_DPHY_CSIHOST4_SEL,
GRF_DPHY_CSIHOST5_SEL,
};
enum csi2dphy_reg_id {
CSI2PHY_REG_CTRL_LANE_ENABLE = 0,
CSI2PHY_CTRL_PWRCTL,
CSI2PHY_CTRL_DIG_RST,
CSI2PHY_CLK_THS_SETTLE,
CSI2PHY_LANE0_THS_SETTLE,
CSI2PHY_LANE1_THS_SETTLE,
CSI2PHY_LANE2_THS_SETTLE,
CSI2PHY_LANE3_THS_SETTLE,
CSI2PHY_CLK_CALIB_ENABLE,
CSI2PHY_LANE0_CALIB_ENABLE,
CSI2PHY_LANE1_CALIB_ENABLE,
CSI2PHY_LANE2_CALIB_ENABLE,
CSI2PHY_LANE3_CALIB_ENABLE,
//rv1126 only
CSI2PHY_MIPI_LVDS_MODEL,
CSI2PHY_LVDS_MODE,
//rk3568 only
CSI2PHY_DUAL_CLK_EN,
CSI2PHY_CLK1_THS_SETTLE,
CSI2PHY_CLK1_CALIB_ENABLE,
//rk3588
CSI2PHY_CLK_LANE_ENABLE,
CSI2PHY_CLK1_LANE_ENABLE,
CSI2PHY_DATA_LANE0_ENABLE,
CSI2PHY_DATA_LANE1_ENABLE,
CSI2PHY_DATA_LANE2_ENABLE,
CSI2PHY_DATA_LANE3_ENABLE,
CSI2PHY_LANE0_ERR_SOT_SYNC,
CSI2PHY_LANE1_ERR_SOT_SYNC,
CSI2PHY_LANE2_ERR_SOT_SYNC,
CSI2PHY_LANE3_ERR_SOT_SYNC,
CSI2PHY_S0C_GNR_CON1,
CSI2PHY_S0C_ANA_CON1,
CSI2PHY_S0C_ANA_CON2,
CSI2PHY_S0C_ANA_CON3,
CSI2PHY_COMBO_S0D0_GNR_CON1,
CSI2PHY_COMBO_S0D0_ANA_CON1,
CSI2PHY_COMBO_S0D0_ANA_CON2,
CSI2PHY_COMBO_S0D0_ANA_CON3,
CSI2PHY_COMBO_S0D0_ANA_CON6,
CSI2PHY_COMBO_S0D0_ANA_CON7,
CSI2PHY_COMBO_S0D0_DESKEW_CON0,
CSI2PHY_COMBO_S0D0_DESKEW_CON2,
CSI2PHY_COMBO_S0D0_DESKEW_CON4,
CSI2PHY_COMBO_S0D0_CRC_CON1,
CSI2PHY_COMBO_S0D0_CRC_CON2,
CSI2PHY_COMBO_S0D1_GNR_CON1,
CSI2PHY_COMBO_S0D1_ANA_CON1,
CSI2PHY_COMBO_S0D1_ANA_CON2,
CSI2PHY_COMBO_S0D1_ANA_CON3,
CSI2PHY_COMBO_S0D1_ANA_CON6,
CSI2PHY_COMBO_S0D1_ANA_CON7,
CSI2PHY_COMBO_S0D1_DESKEW_CON0,
CSI2PHY_COMBO_S0D1_DESKEW_CON2,
CSI2PHY_COMBO_S0D1_DESKEW_CON4,
CSI2PHY_COMBO_S0D1_CRC_CON1,
CSI2PHY_COMBO_S0D1_CRC_CON2,
CSI2PHY_COMBO_S0D2_GNR_CON1,
CSI2PHY_COMBO_S0D2_ANA_CON1,
CSI2PHY_COMBO_S0D2_ANA_CON2,
CSI2PHY_COMBO_S0D2_ANA_CON3,
CSI2PHY_COMBO_S0D2_ANA_CON6,
CSI2PHY_COMBO_S0D2_ANA_CON7,
CSI2PHY_COMBO_S0D2_DESKEW_CON0,
CSI2PHY_COMBO_S0D2_DESKEW_CON2,
CSI2PHY_COMBO_S0D2_DESKEW_CON4,
CSI2PHY_COMBO_S0D2_CRC_CON1,
CSI2PHY_COMBO_S0D2_CRC_CON2,
CSI2PHY_S0D3_GNR_CON1,
CSI2PHY_S0D3_ANA_CON1,
CSI2PHY_S0D3_ANA_CON2,
CSI2PHY_S0D3_ANA_CON3,
CSI2PHY_S0D3_DESKEW_CON0,
CSI2PHY_S0D3_DESKEW_CON2,
CSI2PHY_S0D3_DESKEW_CON4,
};
#define HIWORD_UPDATE(val, mask, shift) \
((val) << (shift) | (mask) << ((shift) + 16))
#define GRF_REG(_offset, _width, _shift) \
{ .offset = _offset, .mask = BIT(_width) - 1, .shift = _shift, }
#define CSI2PHY_REG(_offset) \
{ .offset = _offset, }
/* add new chip id in tail by time order */
enum csi2_dphy_chip_id {
CHIP_ID_RK3568 = 0x0,
CHIP_ID_RK3588 = 0x1,
CHIP_ID_RK3588_DCPHY = 0x2,
};
enum csi2_dphy_rx_pads {
CSI2_DPHY_RX_PAD_SINK = 0,
CSI2_DPHY_RX_PAD_SOURCE,
CSI2_DPHY_RX_PADS_NUM,
};
enum csi2_dphy_lane_mode {
LANE_MODE_UNDEF = 0x0,
LANE_MODE_FULL,
LANE_MODE_SPLIT,
};
struct grf_reg {
u32 offset;
u32 mask;
u32 shift;
};
struct csi2dphy_reg {
u32 offset;
};
struct hsfreq_range {
u32 range_h;
u16 cfg_bit;
};
#define MAX_DPHY_SENSORS (2)
#define MAX_NUM_CSI2_DPHY (0x2)
#define RKCSI2_MAX_RESET 8
#define RKDPHY_MAX_RESET 8
/* csi2 head */
struct csi2_dphy_hw {
struct clk_bulk_data *dphy_clks;
int num_dphy_clks;
struct clk_bulk_data *csi2_clks;
int num_csi2_clks;
const char * const *csi2_rsts;
struct reset_control *csi2_rst[RKCSI2_MAX_RESET];
int num_csi2_rsts;
const char * const *dphy_rsts;
struct reset_control *dphy_rst[RKDPHY_MAX_RESET];
int num_dphy_rsts;
// struct reset_control *rsts_bulk;
/* spinlock_t lock; */
bool on;
const struct hsfreq_range *hsfreq_ranges;
int num_hsfreq_ranges;
const struct grf_reg *grf_regs;
const struct txrx_reg *txrx_regs;
const struct csi2dphy_reg *csi2dphy_regs;
enum csi2_dphy_chip_id chip_id;
struct device *dev;
struct regmap *regmap_grf;
struct regmap *regmap_sys_grf;
void __iomem *csi2_dphy_base; /*csi2_dphy base addr*/
void __iomem *csi2_base; /*csi2 base addr*/
struct mutex mutex; /* lock for updating protection */
atomic_t stream_cnt;
struct csi2_err_stats err_list[RK_CSI2_ERR_MAX];
u64 data_rate_mbps;
struct rkmodule_csi_dphy_param *dphy_param;
struct samsung_mipi_dcphy *samsung_phy;
};
#endif

View File

@@ -0,0 +1,82 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Rockchip Vehicle driver
*
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
*/
#ifndef __VEHICLE_AD_COMMON_H
#define __VEHICLE_AD_COMMON_H
#include <linux/i2c.h>
#include "vehicle_cfg.h"
#include <linux/rk-camera-module.h>
enum vehicle_ad_fix_format {
AD_FIX_FORMAT_AUTO_DETECT = 0,
AD_FIX_FORMAT_PAL = 1,
AD_FIX_FORMAT_NTSC = 2,
AD_FIX_FORMAT_720P_50FPS = 3,
AD_FIX_FORMAT_720P_30FPS = 4,
AD_FIX_FORMAT_720P_25FPS = 5,
AD_FIX_FORMAT_1080P_30FPS = 6,
AD_FIX_FORMAT_1080P_25FPS = 7,
};
struct vehicle_camera_device_defrect {
unsigned int width;
unsigned int height;
unsigned int crop_x;
unsigned int crop_y;
unsigned int crop_width;
unsigned int crop_height;
const char *interface;
};
struct vehicle_state_check_work {
struct workqueue_struct *state_check_wq;
struct delayed_work work;
};
struct vehicle_ad_dev {
struct device *dev;
struct i2c_adapter *adapter;
const char *ad_name;
int resolution;
int mclk_rate;
int ad_chl;
int i2c_chl;
int i2c_add;
// int i2c_rate;
int powerdown;
int pwdn_active;
int power;
int pwr_active;
int reset;
int rst_active;
int cvstd;
int cvstd_irq_flag;
int irq;
int fix_format;
struct vehicle_camera_device_defrect defrects[4];
struct vehicle_state_check_work state_check_work;
struct vehicle_cfg cfg;
int cif_error_last_line;
u32 channel_reso[PAD_MAX];
u8 detect_status;
u8 last_detect_status;
};
int vehicle_generic_sensor_write(struct vehicle_ad_dev *ad, char reg, char *pval);
int vehicle_sensor_write(struct vehicle_ad_dev *ad, u8 reg, u8 val);
int vehicle_generic_sensor_read(struct vehicle_ad_dev *ad, char reg);
int vehicle_sensor_read(struct vehicle_ad_dev *ad, u8 reg, u8 *val);
int vehicle_parse_sensor(struct vehicle_ad_dev *ad);
void vehicle_ad_channel_set(struct vehicle_ad_dev *ad, int channel);
int vehicle_ad_init(struct vehicle_ad_dev *ad);
int vehicle_ad_deinit(void);
int vehicle_ad_stream(struct vehicle_ad_dev *ad, int val);
struct vehicle_cfg *vehicle_ad_get_vehicle_cfg(void);
void vehicle_ad_check_cif_error(struct vehicle_ad_dev *ad, int last_line);
int vehicle_to_v4l2_drv_init(void);
#endif

View File

@@ -0,0 +1,608 @@
// SPDX-License-Identifier: GPL-2.0
/*
* vehicle sensor adv7181
*
* Copyright (C) 2022 Rockchip Electronics Co.Ltd
* Authors:
* Zhiqin Wei <wzq@rock-chips.com>
*
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/sysctl.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/proc_fs.h>
#include <linux/suspend.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/uaccess.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/videodev2.h>
#include "vehicle_cfg.h"
#include "vehicle_main.h"
#include "vehicle_ad.h"
#include "vehicle_ad_7181.h"
enum {
FORCE_PAL_WIDTH = 720,
FORCE_PAL_HEIGHT = 576,
FORCE_NTSC_WIDTH = 720,
FORCE_NTSC_HEIGHT = 480,
FORCE_CIF_OUTPUT_FORMAT = CIF_OUTPUT_FORMAT_420,
};
static struct vehicle_ad_dev *ad7181_g_addev;
static v4l2_std_id std_old = V4L2_STD_NTSC;
#define SENSOR_REGISTER_LEN 1 /* sensor register address bytes*/
#define SENSOR_VALUE_LEN 1 /* sensor register value bytes*/
struct rk_sensor_reg {
unsigned int reg;
unsigned int val;
};
#define ADV7181_STATUS1_REG 0x10
#define ADV7181_STATUS1_IN_LOCK 0x01
#define ADV7181_STATUS1_AUTOD_MASK 0x70
#define ADV7181_STATUS1_AUTOD_NTSM_M_J 0x00
#define ADV7181_STATUS1_AUTOD_NTSC_4_43 0x10
#define ADV7181_STATUS1_AUTOD_PAL_M 0x20
#define ADV7181_STATUS1_AUTOD_PAL_60 0x30
#define ADV7181_STATUS1_AUTOD_PAL_B_G 0x40
#define ADV7181_STATUS1_AUTOD_SECAM 0x50
#define ADV7181_STATUS1_AUTOD_PAL_COMB 0x60
#define ADV7181_STATUS1_AUTOD_SECAM_525 0x70
#define ADV7181_INPUT_CONTROL 0x00
#define ADV7181_INPUT_DEFAULT 0x00
#define ADV7181_INPUT_CVBS_AIN2 0x00
#define ADV7181_INPUT_CVBS_AIN3 0x01
#define ADV7181_INPUT_CVBS_AIN5 0x02
#define ADV7181_INPUT_CVBS_AIN6 0x03
#define ADV7181_INPUT_CVBS_AIN8 0x04
#define ADV7181_INPUT_CVBS_AIN10 0x05
#define ADV7181_INPUT_CVBS_AIN1 0x0B
#define ADV7181_INPUT_CVBS_AIN4 0x0D
#define ADV7181_INPUT_CVBS_AIN7 0x0F
#define ADV7181_INPUT_YPRPB_AIN6_8_10 0x00
#define SEQCMD_END 0xFF000000
#define SensorEnd {SEQCMD_END, 0x00}
#define SENSOR_DG VEHICLE_DG
/* Preview resolution setting*/
static struct rk_sensor_reg sensor_preview_data[] = {
/* autodetect cvbs in ntsc/pal/secam 8-bit 422 encode */
{0x00, 0x0B}, /*cvbs in AIN1*/
{0x04, 0x77},
{0x17, 0x41},
{0x1D, 0x47},
{0x31, 0x02},
{0x3A, 0x17},
{0x3B, 0x81},
{0x3D, 0xA2},
{0x3E, 0x6A},
{0x3F, 0xA0},
{0x86, 0x0B},
{0xF3, 0x01},
{0xF9, 0x03},
{0x0E, 0x80},
{0x52, 0x46},
{0x54, 0x80},
{0x7F, 0xFF},
{0x81, 0x30},
{0x90, 0xC9},
{0x91, 0x40},
{0x92, 0x3C},
{0x93, 0xCA},
{0x94, 0xD5},
{0xB1, 0xFF},
{0xB6, 0x08},
{0xC0, 0x9A},
{0xCF, 0x50},
{0xD0, 0x4E},
{0xD1, 0xB9},
{0xD6, 0xDD},
{0xD7, 0xE2},
{0xE5, 0x51},
{0xF6, 0x3B},
{0x0E, 0x00},
{0x03, 0x4C}, //stream off
{0xDF, 0X46},
{0xC9, 0x04},
{0xC5, 0x81},
{0xC4, 0x34},
{0xBf, 0x02},
{0xB5, 0x83},
{0xB6, 0x00},
{0xaf, 0x03},
{0xae, 0x00},
{0xac, 0x00},
{0xAB, 0x00},
{0xa1, 0xFF},
{0xA2, 0x00},
{0xA3, 0x00},
{0xA4, 0x00},
{0xa5, 0x01},
{0xA6, 0x00},
{0xA6, 0x00},
{0xA7, 0x00},
{0xA8, 0x00},
{0xa0, 0x03},
{0x98, 0X00},
{0x97, 0X00},
{0X90, 0X00},
{0X85, 0X02},
{0x7B, 0x1E},
{0x74, 0x04},
{0x75, 0x01},
{0x76, 0x00},
{0x6B, 0xC0},
{0x67, 0x03},
{0x3C, 0x58},
{0x30, 0x4C},
{0x2E, 0X9F},
{0x12, 0XC0},
{0x10, 0X0D},
{0x05, 0X00},
{0x06, 0X02},
{0x60, 0x01},
SensorEnd
};
static struct rk_sensor_reg sensor_preview_data_yprpb_p[] = {
{0x05, 0x01},
{0x06, 0x06},
{0xc3, 0x56},
{0xc4, 0xb4},
{0x1d, 0x47},
{0x3a, 0x11},
{0x3b, 0x81},
{0x3c, 0x3b},
{0x6b, 0x83},
{0xc9, 0x00},
{0x73, 0x10},
{0x74, 0xa3},
{0x75, 0xe8},
{0x76, 0xfa},
{0x7b, 0x1c},
{0x85, 0x19},
{0x86, 0x0b},
{0xbf, 0x06},
{0xc0, 0x40},
{0xc1, 0xf0},
{0xc2, 0x80},
{0xc5, 0x01},
{0xc9, 0x08},
{0x0e, 0x80},
{0x52, 0x46},
{0x54, 0x80},
{0x57, 0x01},
{0xf6, 0x3b},
{0x0e, 0x00},
{0x67, 0x2f},
{0x03, 0x4C}, //disable out put
SensorEnd
};
static v4l2_std_id adv7181_std_to_v4l2(u8 status1)
{
/* in case V4L2_IN_ST_NO_SIGNAL */
if (!(status1 & ADV7181_STATUS1_IN_LOCK))
return V4L2_STD_UNKNOWN;
switch (status1 & ADV7181_STATUS1_AUTOD_MASK) {
case ADV7181_STATUS1_AUTOD_PAL_M:
case ADV7181_STATUS1_AUTOD_NTSM_M_J:
return V4L2_STD_NTSC;
case ADV7181_STATUS1_AUTOD_NTSC_4_43:
return V4L2_STD_NTSC_443;
case ADV7181_STATUS1_AUTOD_PAL_60:
return V4L2_STD_PAL_60;
case ADV7181_STATUS1_AUTOD_PAL_B_G:
return V4L2_STD_PAL;
case ADV7181_STATUS1_AUTOD_SECAM:
return V4L2_STD_SECAM;
case ADV7181_STATUS1_AUTOD_PAL_COMB:
return V4L2_STD_PAL_Nc | V4L2_STD_PAL_N;
case ADV7181_STATUS1_AUTOD_SECAM_525:
return V4L2_STD_SECAM;
default:
return V4L2_STD_UNKNOWN;
}
}
static u32 adv7181_status_to_v4l2(u8 status1)
{
if (!(status1 & ADV7181_STATUS1_IN_LOCK))
return V4L2_IN_ST_NO_SIGNAL;
return 0;
}
static int adv7181_vehicle_status(struct vehicle_ad_dev *ad,
u32 *status,
v4l2_std_id *std)
{
unsigned char status1 = 0;
status1 = vehicle_generic_sensor_read(ad, ADV7181_STATUS1_REG);
if (status1)
return status1;
if (status)
*status = adv7181_status_to_v4l2(status1);
if (std)
*std = adv7181_std_to_v4l2(status1);
return 0;
}
static void adv7181_reinit_parameter(struct vehicle_ad_dev *ad, v4l2_std_id std)
{
int i;
if (ad7181_g_addev->ad_chl == 0) {
ad->cfg.width = 1024;
ad->cfg.height = 500;
ad->cfg.start_x = 56;
ad->cfg.start_y = 0;
ad->cfg.input_format = CIF_INPUT_FORMAT_YUV;
ad->cfg.output_format = FORCE_CIF_OUTPUT_FORMAT;
ad->cfg.field_order = 0;
ad->cfg.yuv_order = 1;
ad->cfg.href = 0;
ad->cfg.vsync = 0;
ad->cfg.frame_rate = 60;
ad->cfg.type = V4L2_MBUS_PARALLEL;
ad->cfg.mbus_flags = V4L2_MBUS_HSYNC_ACTIVE_LOW |
V4L2_MBUS_VSYNC_ACTIVE_LOW |
V4L2_MBUS_PCLK_SAMPLE_RISING;
} else if (std == V4L2_STD_PAL) {
ad->cfg.width = FORCE_PAL_WIDTH;
ad->cfg.height = FORCE_PAL_HEIGHT;
ad->cfg.start_x = 0;
ad->cfg.start_y = 0;
ad->cfg.input_format = CIF_INPUT_FORMAT_PAL;
ad->cfg.output_format = FORCE_CIF_OUTPUT_FORMAT;
ad->cfg.field_order = 0;
ad->cfg.yuv_order = 0;
ad->cfg.href = 0;
ad->cfg.vsync = 0;
ad->cfg.frame_rate = 25;
ad->cfg.type = V4L2_MBUS_PARALLEL;
ad->cfg.mbus_flags = V4L2_MBUS_HSYNC_ACTIVE_LOW |
V4L2_MBUS_VSYNC_ACTIVE_LOW |
V4L2_MBUS_PCLK_SAMPLE_RISING;
} else {
ad->cfg.width = FORCE_NTSC_WIDTH;
ad->cfg.height = FORCE_NTSC_HEIGHT;
ad->cfg.start_x = 0;
ad->cfg.start_y = 0;
ad->cfg.input_format = CIF_INPUT_FORMAT_NTSC;
ad->cfg.output_format = FORCE_CIF_OUTPUT_FORMAT;
ad->cfg.field_order = 0;
ad->cfg.yuv_order = 2;
ad->cfg.href = 0;
ad->cfg.vsync = 0;
ad->cfg.frame_rate = 30;
ad->cfg.type = V4L2_MBUS_PARALLEL;
ad->cfg.mbus_flags = V4L2_MBUS_HSYNC_ACTIVE_LOW |
V4L2_MBUS_VSYNC_ACTIVE_LOW |
V4L2_MBUS_PCLK_SAMPLE_RISING;
}
/* fix crop info from dts config */
for (i = 0; i < 4; i++) {
if ((ad->defrects[i].width == ad->cfg.width) &&
(ad->defrects[i].height == ad->cfg.height)) {
ad->cfg.start_x = ad->defrects[i].crop_x;
ad->cfg.start_y = ad->defrects[i].crop_y;
ad->cfg.width = ad->defrects[i].crop_width;
ad->cfg.height = ad->defrects[i].crop_height;
}
}
SENSOR_DG("size %dx%d, crop(%d,%d)\n",
ad->cfg.width, ad->cfg.height,
ad->cfg.start_x, ad->cfg.start_y);
}
static void adv7181_reg_init(struct vehicle_ad_dev *ad, unsigned char cvstd)
{
struct rk_sensor_reg *sensor;
int i = 0;
unsigned char val[2];
switch (ad->ad_chl) {
case 0:
ad->ad_chl = ADV7181_INPUT_CVBS_AIN1;
break;
case 1:
ad->ad_chl = ADV7181_INPUT_CVBS_AIN6;
break;
case 2:
ad->ad_chl = ADV7181_INPUT_CVBS_AIN8;
break;
case 3:
ad->ad_chl = ADV7181_INPUT_CVBS_AIN10;
break;
case 4:
ad->ad_chl = ADV7181_INPUT_YPRPB_AIN6_8_10;
break;
default:
ad->ad_chl = ADV7181_INPUT_CVBS_AIN1;
}
val[0] = ad->ad_chl;
vehicle_generic_sensor_write(ad, ADV7181_INPUT_CONTROL, val);
if (ad->ad_chl == ADV7181_INPUT_YPRPB_AIN6_8_10) {
SENSOR_DG("%s %d set sensor_preview_data_yprpb_p/p", __func__, __LINE__);
sensor = sensor_preview_data_yprpb_p;
} else {
SENSOR_DG("%s %d set n/p", __func__, __LINE__);
sensor = sensor_preview_data;
}
while ((sensor[i].reg != SEQCMD_END) && (sensor[i].reg != 0xFC000000)) {
if (sensor[i].reg == ADV7181_INPUT_CONTROL) {
SENSOR_DG("%s %d lkg test ad channel = %d\n",
__func__, __LINE__, ad->ad_chl);
} else {
val[0] = sensor[i].val;
vehicle_generic_sensor_write(ad, sensor[i].reg, val);
}
i++;
}
val[0] = ad->ad_chl;
vehicle_generic_sensor_write(ad, ADV7181_INPUT_CONTROL, val);
}
int adv7181_ad_get_cfg(struct vehicle_cfg **cfg)
{
u32 status;
if (!ad7181_g_addev)
return -1;
adv7181_vehicle_status(ad7181_g_addev, &status, NULL);
ad7181_g_addev->cfg.ad_ready = true;
*cfg = &ad7181_g_addev->cfg;
return 0;
}
void adv7181_ad_check_cif_error(struct vehicle_ad_dev *ad, int last_line)
{
SENSOR_DG("%s, last_line %d\n", __func__, last_line);
if (last_line < 1)
return;
ad->cif_error_last_line = last_line;
if (std_old == V4L2_STD_PAL) {
if (last_line == FORCE_NTSC_HEIGHT) {
if (ad->state_check_work.state_check_wq)
queue_delayed_work(
ad->state_check_work.state_check_wq,
&ad->state_check_work.work,
msecs_to_jiffies(0));
}
} else if (std_old == V4L2_STD_NTSC) {
if (last_line == FORCE_PAL_HEIGHT) {
if (ad->state_check_work.state_check_wq)
queue_delayed_work(
ad->state_check_work.state_check_wq,
&ad->state_check_work.work,
msecs_to_jiffies(0));
}
}
}
int adv7181_check_id(struct vehicle_ad_dev *ad)
{
int ret = 0;
int val;
val = vehicle_generic_sensor_read(ad, 0x11);
SENSOR_DG("%s vehicle read 0x11 --> 0x%02x\n", ad->ad_name, val);
if (val != 0x20) {
SENSOR_DG("%s vehicle wrong camera ID, expected 0x20, detected 0x%02x\n",
ad->ad_name, val);
ret = -EINVAL;
}
return ret;
}
static int adv7181_check_std(struct vehicle_ad_dev *ad, v4l2_std_id *std)
{
u32 status = 0;
adv7181_vehicle_status(ad, &status, std);
if (status != 0) { /* No signal */
mdelay(30);
adv7181_vehicle_status(ad, &status, std);
SENSOR_DG("status 0x%x\n", status);
}
return 0;
}
void adv7181_channel_set(struct vehicle_ad_dev *ad, int channel)
{
static int channel_change = 11;
v4l2_std_id std = 0;
ad->ad_chl = channel;
adv7181_reg_init(ad, std);
adv7181_check_std(ad, &std);
adv7181_reinit_parameter(ad, std);
if (channel_change != ad->ad_chl) {
SENSOR_DG("%s %d channel changed now channel = %d old_channel = %d\n",
__func__, __LINE__, ad->ad_chl, channel);
channel_change = ad->ad_chl;
vehicle_ad_stat_change_notify();
}
}
int adv7181_stream(struct vehicle_ad_dev *ad, int value)
{
char val;
if (value)
val = 0x0c; //on
else
val = 0x4c;
SENSOR_DG("stream write 0x%x to reg 0x03\n", val);
vehicle_generic_sensor_write(ad, 0x03, &val);
if (value)
val = 0x47; //on
else
val = 0x87;
SENSOR_DG("stream write 0x%x to reg 0x01d\n", val);
vehicle_generic_sensor_write(ad, 0x1d, &val);
return 0;
}
static void power_on(struct vehicle_ad_dev *ad)
{
/* gpio_direction_output(ad->power, ad->pwr_active); */
if (gpio_is_valid(ad->powerdown)) {
gpio_request(ad->powerdown, "ad_powerdown");
gpio_direction_output(ad->powerdown, !ad->pwdn_active);
/* gpio_set_value(ad->powerdown, !ad->pwdn_active); */
}
if (gpio_is_valid(ad->power)) {
gpio_request(ad->power, "ad_power");
gpio_direction_output(ad->power, ad->pwr_active);
/* gpio_set_value(ad->power, ad->pwr_active); */
}
if (gpio_is_valid(ad->reset)) {
gpio_request(ad->reset, "ad_reset");
gpio_direction_output(ad->reset, 0);
usleep_range(10000, 12000);
gpio_set_value(ad->reset, 1);
usleep_range(10000, 12000);
}
}
static void power_off(struct vehicle_ad_dev *ad)
{
if (gpio_is_valid(ad->powerdown))
gpio_free(ad->powerdown);
if (gpio_is_valid(ad->power))
gpio_free(ad->power);
if (gpio_is_valid(ad->reset))
gpio_free(ad->reset);
}
static void adv7181_check_state_work(struct work_struct *work)
{
struct vehicle_ad_dev *ad;
v4l2_std_id std;
ad = ad7181_g_addev;
if (ad->cif_error_last_line > 0)
ad->cif_error_last_line = 0;
adv7181_check_std(ad, &std);
SENSOR_DG("%s:new std(%llx), std_old(%llx)\n", __func__, std, std_old);
if (std != std_old) {
std_old = std;
adv7181_reinit_parameter(ad, std);
SENSOR_DG("%s:ad signal change notify\n", __func__);
vehicle_ad_stat_change_notify();
}
queue_delayed_work(ad->state_check_work.state_check_wq,
&ad->state_check_work.work, msecs_to_jiffies(3000));
}
int adv7181_ad_deinit(void)
{
struct vehicle_ad_dev *ad;
ad = ad7181_g_addev;
if (!ad)
return -ENODEV;
if (ad->state_check_work.state_check_wq) {
cancel_delayed_work_sync(&ad->state_check_work.work);
flush_delayed_work(&ad->state_check_work.work);
flush_workqueue(ad->state_check_work.state_check_wq);
destroy_workqueue(ad->state_check_work.state_check_wq);
}
if (ad->irq)
free_irq(ad->irq, ad);
power_off(ad);
return 0;
}
int adv7181_ad_init(struct vehicle_ad_dev *ad)
{
v4l2_std_id std = V4L2_STD_NTSC;
if (!ad)
return -1;
ad7181_g_addev = ad;
/* 1. i2c init */
while (ad->adapter == NULL) {
ad->adapter = i2c_get_adapter(ad->i2c_chl);
usleep_range(10000, 12000);
}
if (!i2c_check_functionality(ad->adapter, I2C_FUNC_I2C))
return -EIO;
/* 2. ad power on sequence */
power_on(ad);
/* fix mode */
adv7181_check_std(ad, &std);
std_old = std;
SENSOR_DG("std: %s\n", (std == V4L2_STD_NTSC) ? "ntsc" : "pal");
SENSOR_DG("std_old: %s\n", (std_old == V4L2_STD_NTSC) ? "ntsc" : "pal");
/* 3 .init default format params */
adv7181_reg_init(ad, std);
adv7181_reinit_parameter(ad, std);
vehicle_ad_stat_change_notify();
/* 5. create workqueue to detect signal change */
INIT_DELAYED_WORK(&ad->state_check_work.work, adv7181_check_state_work);
ad->state_check_work.state_check_wq =
create_singlethread_workqueue("vehicle-ad-adv7181");
queue_delayed_work(ad->state_check_work.state_check_wq,
&ad->state_check_work.work, msecs_to_jiffies(100));
return 0;
}

View File

@@ -0,0 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Rockchip Vehicle driver
*
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
*/
#ifndef __VEHICLE_AD_7181_H__
#define __VEHICLE_AD_7181_H__
int adv7181_ad_init(struct vehicle_ad_dev *ad);
int adv7181_ad_deinit(void);
int adv7181_ad_get_cfg(struct vehicle_cfg **cfg);
int adv7181_stream(struct vehicle_ad_dev *ad, int value);
void adv7181_ad_check_cif_error(struct vehicle_ad_dev *ad, int last_line);
int adv7181_check_id(struct vehicle_ad_dev *ad);
void adv7181_channel_set(struct vehicle_ad_dev *ad, int channel);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Rockchip Vehicle driver
*
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
*/
#ifndef __VEHICLE_AD_GC2145_H__
#define __VEHICLE_AD_GC2145_H__
int gc2145_ad_init(struct vehicle_ad_dev *ad);
int gc2145_ad_deinit(void);
int gc2145_ad_get_cfg(struct vehicle_cfg **cfg);
void gc2145_ad_check_cif_error(struct vehicle_ad_dev *ad, int last_line);
int gc2145_check_id(struct vehicle_ad_dev *ad);
int gc2145_stream(struct vehicle_ad_dev *ad, int enable);
void gc2145_channel_set(struct vehicle_ad_dev *ad, int channel);
#endif

View File

@@ -0,0 +1,539 @@
// SPDX-License-Identifier: GPL-2.0
/*
* vehicle sensor max96714
*
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
* Authors:
* Jianwei Fan <jianwei.fan@rock-chips.com>
*
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/sysctl.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/proc_fs.h>
#include <linux/suspend.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/uaccess.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include "vehicle_cfg.h"
#include "vehicle_main.h"
#include "vehicle_ad.h"
#include "vehicle_ad_max96714.h"
enum {
CVSTD_720P60 = 0,
CVSTD_720P50,
CVSTD_1080P30,
CVSTD_1080P25,
CVSTD_720P30,
CVSTD_720P25,
CVSTD_SVGAP30,
CVSTD_SD,
CVSTD_NTSC,
CVSTD_PAL
};
enum {
FORCE_PAL_WIDTH = 960,
FORCE_PAL_HEIGHT = 576,
FORCE_NTSC_WIDTH = 960,
FORCE_NTSC_HEIGHT = 480,
FORCE_SVGA_WIDTH = 800,
FORCE_SVGA_HEIGHT = 600,
FORCE_720P_WIDTH = 1280,
FORCE_720P_HEIGHT = 720,
FORCE_1080P_WIDTH = 1920,
FORCE_1080P_HEIGHT = 1080,
FORCE_CIF_OUTPUT_FORMAT = CIF_OUTPUT_FORMAT_420,
};
enum {
VIDEO_UNPLUG,
VIDEO_IN,
VIDEO_LOCKED,
VIDEO_UNLOCK
};
#define FLAG_LOCKED (0x1 << 3)
#define MAX96714_LINK_FREQ_150M 150000000UL
static struct vehicle_ad_dev *max96714_g_addev;
static int cvstd_mode = CVSTD_1080P30;
//static int cvstd_old = CVSTD_720P25;
static int cvstd_old = CVSTD_NTSC;
//static int cvstd_sd = CVSTD_NTSC;
static int cvstd_state = VIDEO_UNPLUG;
static int cvstd_old_state = VIDEO_UNLOCK;
static bool g_max96714_streaming;
#define SENSOR_VALUE_LEN 1 /* sensor register value bytes*/
#define MAX96714_CHIP_ID 0xC9
#define MAX96714_CHIP_ID_REG 0x0D
#define MAX96714_GMSL_STATE 0x0013
#define MAX96714_STREAM_CTL 0x0313
#define MAX96714_MODE_SW_STANDBY 0x0
#define MAX96714_MODE_STREAMING BIT(1)
struct regval {
u16 reg;
u8 val;
};
#define REG_NULL 0xFFFF
/* 1080p Preview resolution setting*/
static struct regval sensor_preview_data_1080p_30hz[] = {
{0x0313, 0x00},
{0x0001, 0x01},
{0x0010, 0x21},
{0x0320, 0x23},
{0x0325, 0x80},
{0x0313, 0x00},
{REG_NULL, 0x00},
};
static struct rkmodule_csi_dphy_param max96714_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 int max96714_read_reg(struct vehicle_ad_dev *ad, 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 = ad->i2c_add;
msgs[0].flags = 0;
msgs[0].len = 2;
msgs[0].buf = (u8 *)&reg_addr_be;
/* Read data from register */
msgs[1].addr = ad->i2c_add;
msgs[1].flags = I2C_M_RD;
msgs[1].len = len;
msgs[1].buf = &data_be_p[4 - len];
ret = i2c_transfer(ad->adapter, msgs, ARRAY_SIZE(msgs));
if (ret != ARRAY_SIZE(msgs))
return -EIO;
*val = be32_to_cpu(data_be);
return 0;
}
static int max96714_write_reg(struct vehicle_ad_dev *ad, u16 reg, u8 val)
{
struct i2c_msg msg;
u8 buf[3];
int ret;
buf[0] = reg >> 8;
buf[1] = reg & 0xff;
buf[2] = val;
msg.addr = ad->i2c_add;
msg.flags = 0;
msg.buf = buf;
msg.len = sizeof(buf);
ret = i2c_transfer(ad->adapter, &msg, 1);
if (ret >= 0)
return 0;
VEHICLE_DGERR(
"max96714 write reg(0x%x val:0x%x) failed !\n", reg, val);
return ret;
}
static int max96714_write_array(struct vehicle_ad_dev *ad,
const struct regval *regs)
{
u32 i = 0;
int ret = 0;
for (i = 0; ret == 0 && regs[i].reg != REG_NULL; i++)
ret = max96714_write_reg(ad, regs[i].reg, regs[i].val);
return ret;
}
static void max96714_reinit_parameter(struct vehicle_ad_dev *ad, unsigned char cvstd)
{
int i = 0;
switch (cvstd) {
case CVSTD_1080P30:
ad->cfg.width = 1920;
ad->cfg.height = 1080;
ad->cfg.start_x = 0;
ad->cfg.start_y = 0;
ad->cfg.input_format = CIF_INPUT_FORMAT_YUV;
ad->cfg.output_format = FORCE_CIF_OUTPUT_FORMAT;
ad->cfg.field_order = 0;
ad->cfg.yuv_order = 0;/*00 - UYVY*/
ad->cfg.href = 0;
ad->cfg.vsync = 0;
ad->cfg.frame_rate = 30;
ad->cfg.mipi_freq = MAX96714_LINK_FREQ_150M;
break;
default:
ad->cfg.width = 1920;
ad->cfg.height = 1080;
ad->cfg.start_x = 0;
ad->cfg.start_y = 0;
ad->cfg.input_format = CIF_INPUT_FORMAT_YUV;
ad->cfg.output_format = FORCE_CIF_OUTPUT_FORMAT;
ad->cfg.field_order = 0;
ad->cfg.yuv_order = 0;/*00 - UYVY*/
ad->cfg.href = 0;
ad->cfg.vsync = 0;
ad->cfg.frame_rate = 30;
ad->cfg.mipi_freq = MAX96714_LINK_FREQ_150M;
break;
}
ad->cfg.type = V4L2_MBUS_CSI2_DPHY;
ad->cfg.mbus_flags = V4L2_MBUS_CSI2_4_LANE | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK |
V4L2_MBUS_CSI2_CHANNEL_0;
ad->cfg.mbus_code = MEDIA_BUS_FMT_UYVY8_2X8;
ad->cfg.dphy_param = &max96714_dcphy_param;
switch (ad->cfg.mbus_flags & V4L2_MBUS_CSI2_LANES) {
case V4L2_MBUS_CSI2_1_LANE:
ad->cfg.lanes = 1;
break;
case V4L2_MBUS_CSI2_2_LANE:
ad->cfg.lanes = 2;
break;
case V4L2_MBUS_CSI2_3_LANE:
ad->cfg.lanes = 3;
break;
case V4L2_MBUS_CSI2_4_LANE:
ad->cfg.lanes = 4;
break;
default:
ad->cfg.lanes = 1;
break;
}
/* fix crop info from dts config */
for (i = 0; i < 4; i++) {
if ((ad->defrects[i].width == ad->cfg.width) &&
(ad->defrects[i].height == ad->cfg.height)) {
ad->cfg.start_x = ad->defrects[i].crop_x;
ad->cfg.start_y = ad->defrects[i].crop_y;
ad->cfg.width = ad->defrects[i].crop_width;
ad->cfg.height = ad->defrects[i].crop_height;
}
}
VEHICLE_DG("crop(%d,%d)", ad->cfg.start_x, ad->cfg.start_y);
}
static void max96714_reg_init(struct vehicle_ad_dev *ad, unsigned char cvstd)
{
struct regval *sensor;
int ret = 0;
switch (cvstd) {
case CVSTD_1080P30:
VEHICLE_INFO("%s, init CVSTD_1080P30 mode", __func__);
sensor = sensor_preview_data_1080p_30hz;
break;
default:
VEHICLE_INFO("%s, init CVSTD_1080P30 mode", __func__);
sensor = sensor_preview_data_1080p_30hz;
break;
}
ret = max96714_write_array(ad, sensor);
if (ret)
VEHICLE_DGERR("%s, init sensor fail", __func__);
}
void max96714_channel_set(struct vehicle_ad_dev *ad, int channel)
{
}
int max96714_ad_get_cfg(struct vehicle_cfg **cfg)
{
if (!max96714_g_addev)
return -1;
switch (cvstd_state) {
case VIDEO_UNPLUG:
max96714_g_addev->cfg.ad_ready = false;
break;
case VIDEO_LOCKED:
max96714_g_addev->cfg.ad_ready = true;
break;
case VIDEO_IN:
max96714_g_addev->cfg.ad_ready = false;
break;
}
max96714_g_addev->cfg.ad_ready = true;
*cfg = &max96714_g_addev->cfg;
return 0;
}
void max96714_ad_check_cif_error(struct vehicle_ad_dev *ad, int last_line)
{
VEHICLE_DG("last_line %d\n", last_line);
if (last_line < 1)
return;
ad->cif_error_last_line = last_line;
if (cvstd_mode == CVSTD_PAL) {
if (last_line == FORCE_NTSC_HEIGHT) {
if (ad->state_check_work.state_check_wq)
queue_delayed_work(
ad->state_check_work.state_check_wq,
&ad->state_check_work.work,
msecs_to_jiffies(0));
}
} else if (cvstd_mode == CVSTD_NTSC) {
if (last_line == FORCE_PAL_HEIGHT) {
if (ad->state_check_work.state_check_wq)
queue_delayed_work(
ad->state_check_work.state_check_wq,
&ad->state_check_work.work,
msecs_to_jiffies(0));
}
} else if (cvstd_mode == CVSTD_1080P30) {
if (last_line == FORCE_1080P_HEIGHT) {
if (ad->state_check_work.state_check_wq)
queue_delayed_work(
ad->state_check_work.state_check_wq,
&ad->state_check_work.work,
msecs_to_jiffies(0));
}
}
}
int max96714_check_id(struct vehicle_ad_dev *ad)
{
int ret = 0;
u32 pid = 0;
ret = max96714_read_reg(ad, MAX96714_CHIP_ID_REG, SENSOR_VALUE_LEN, &pid);
if (pid != MAX96714_CHIP_ID) {
VEHICLE_DGERR("%s: expected 0xC9, detected: 0x%02x !",
ad->ad_name, pid);
ret = -EINVAL;
} else {
VEHICLE_INFO("Found MAX96714 sensor: id(0x%2x) !\n", pid);
}
return ret;
}
static int max96714_check_cvstd(struct vehicle_ad_dev *ad, bool activate_check)
{
static int state = VIDEO_UNPLUG;
int ret = 0;
ret = max96714_read_reg(ad, MAX96714_GMSL_STATE, SENSOR_VALUE_LEN, &state);
if (ret)
VEHICLE_DGERR("read GMSL2 link lock failed!\n");
if (state & FLAG_LOCKED) {
state = VIDEO_LOCKED;
VEHICLE_DG("GMSL2 link locked!\n");
cvstd_mode = CVSTD_1080P30;
} else {
state = VIDEO_UNPLUG;
VEHICLE_DG("GMSL2 link not locked!\n");
cvstd_mode = cvstd_old;
}
return 0;
}
int max96714_stream(struct vehicle_ad_dev *ad, int enable)
{
VEHICLE_INFO("%s on(%d)\n", __func__, enable);
g_max96714_streaming = (enable != 0);
if (g_max96714_streaming) {
max96714_write_reg(ad, MAX96714_STREAM_CTL, MAX96714_MODE_STREAMING);
if (ad->state_check_work.state_check_wq)
queue_delayed_work(ad->state_check_work.state_check_wq,
&ad->state_check_work.work, msecs_to_jiffies(200));
} else {
max96714_write_reg(ad, MAX96714_STREAM_CTL, MAX96714_MODE_SW_STANDBY);
if (ad->state_check_work.state_check_wq)
cancel_delayed_work_sync(&ad->state_check_work.work);
}
return 0;
}
static void max96714_power_on(struct vehicle_ad_dev *ad)
{
/* gpio_direction_output(ad->power, ad->pwr_active); */
if (gpio_is_valid(ad->power)) {
gpio_request(ad->power, "max96714_power");
gpio_direction_output(ad->power, ad->pwr_active);
/* gpio_set_value(ad->power, ad->pwr_active); */
}
if (gpio_is_valid(ad->powerdown)) {
gpio_request(ad->powerdown, "max96714_pwd");
gpio_direction_output(ad->powerdown, 1);
/* gpio_set_value(ad->powerdown, !ad->pwdn_active); */
}
if (gpio_is_valid(ad->reset)) {
gpio_request(ad->reset, "max96714_rst");
gpio_direction_output(ad->reset, 0);
usleep_range(1500, 2000);
gpio_direction_output(ad->reset, 1);
}
}
static void max96714_power_deinit(struct vehicle_ad_dev *ad)
{
if (gpio_is_valid(ad->reset))
gpio_free(ad->reset);
if (gpio_is_valid(ad->power))
gpio_free(ad->power);
if (gpio_is_valid(ad->powerdown))
gpio_free(ad->powerdown);
}
static void max96714_check_state_work(struct work_struct *work)
{
struct vehicle_ad_dev *ad;
ad = max96714_g_addev;
if (ad->cif_error_last_line > 0) {
max96714_check_cvstd(ad, true);
ad->cif_error_last_line = 0;
} else {
max96714_check_cvstd(ad, false);
}
VEHICLE_DG("%s:cvstd_old(%d), cvstd_mode(%d)\n", __func__, cvstd_old, cvstd_mode);
if (cvstd_old != cvstd_mode || cvstd_old_state != cvstd_state) {
VEHICLE_INFO("%s:ad sensor std mode change, cvstd_old(%d), cvstd_mode(%d)\n",
__func__, cvstd_old, cvstd_mode);
cvstd_old = cvstd_mode;
cvstd_old_state = cvstd_state;
max96714_reinit_parameter(ad, cvstd_mode);
max96714_reg_init(ad, cvstd_mode);
vehicle_ad_stat_change_notify();
}
if (g_max96714_streaming) {
queue_delayed_work(ad->state_check_work.state_check_wq,
&ad->state_check_work.work, msecs_to_jiffies(100));
}
}
int max96714_ad_deinit(void)
{
struct vehicle_ad_dev *ad;
ad = max96714_g_addev;
if (!ad)
return -ENODEV;
if (ad->state_check_work.state_check_wq) {
cancel_delayed_work_sync(&ad->state_check_work.work);
flush_delayed_work(&ad->state_check_work.work);
flush_workqueue(ad->state_check_work.state_check_wq);
destroy_workqueue(ad->state_check_work.state_check_wq);
}
if (ad->irq)
free_irq(ad->irq, ad);
max96714_power_deinit(ad);
return 0;
}
static __maybe_unused int get_ad_mode_from_fix_format(int fix_format)
{
int mode = -1;
switch (fix_format) {
case AD_FIX_FORMAT_PAL:
case AD_FIX_FORMAT_NTSC:
case AD_FIX_FORMAT_720P_50FPS:
case AD_FIX_FORMAT_720P_30FPS:
case AD_FIX_FORMAT_720P_25FPS:
mode = CVSTD_720P25;
break;
case AD_FIX_FORMAT_1080P_30FPS:
case AD_FIX_FORMAT_1080P_25FPS:
default:
mode = CVSTD_1080P30;
break;
}
return mode;
}
int max96714_ad_init(struct vehicle_ad_dev *ad)
{
max96714_g_addev = ad;
/* 1. i2c init */
while (ad->adapter == NULL) {
ad->adapter = i2c_get_adapter(ad->i2c_chl);
usleep_range(10000, 12000);
}
if (ad->adapter == NULL)
return -ENODEV;
if (!i2c_check_functionality(ad->adapter, I2C_FUNC_I2C))
return -EIO;
max96714_power_on(ad);
max96714_reg_init(ad, cvstd_mode);
max96714_reinit_parameter(ad, cvstd_mode);
INIT_DELAYED_WORK(&ad->state_check_work.work, max96714_check_state_work);
ad->state_check_work.state_check_wq =
create_singlethread_workqueue("vehicle-ad-max96714");
queue_delayed_work(ad->state_check_work.state_check_wq,
&ad->state_check_work.work, msecs_to_jiffies(100));
return 0;
}

View File

@@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Rockchip Vehicle driver
*
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
*/
#ifndef __VEHICLE_AD_MAX96714_H__
#define __VEHICLE_AD_MAX96714_H__
int max96714_ad_init(struct vehicle_ad_dev *ad);
int max96714_ad_deinit(void);
int max96714_ad_get_cfg(struct vehicle_cfg **cfg);
void max96714_ad_check_cif_error(struct vehicle_ad_dev *ad, int last_line);
int max96714_check_id(struct vehicle_ad_dev *ad);
int max96714_stream(struct vehicle_ad_dev *ad, int enable);
void max96714_channel_set(struct vehicle_ad_dev *ad, int channel);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Rockchip Vehicle driver
*
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
*/
#ifndef __VEHICLE_AD_NVP6188_H__
#define __VEHICLE_AD_NVP6188_H__
int nvp6188_ad_init(struct vehicle_ad_dev *ad);
int nvp6188_ad_deinit(void);
int nvp6188_ad_get_cfg(struct vehicle_cfg **cfg);
void nvp6188_ad_check_cif_error(struct vehicle_ad_dev *ad, int last_line);
int nvp6188_check_id(struct vehicle_ad_dev *ad);
int nvp6188_stream(struct vehicle_ad_dev *ad, int enable);
void nvp6188_channel_set(struct vehicle_ad_dev *ad, int channel);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Rockchip Vehicle driver
*
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
*/
#ifndef __VEHICLE_AD_NVP6324_H__
#define __VEHICLE_AD_NVP6324_H__
int nvp6324_ad_init(struct vehicle_ad_dev *ad);
int nvp6324_ad_deinit(void);
int nvp6324_ad_get_cfg(struct vehicle_cfg **cfg);
void nvp6324_ad_check_cif_error(struct vehicle_ad_dev *ad, int last_line);
int nvp6324_check_id(struct vehicle_ad_dev *ad);
int nvp6324_stream(struct vehicle_ad_dev *ad, int enable);
void nvp6324_channel_set(struct vehicle_ad_dev *ad, int channel);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Rockchip Vehicle driver
*
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
*/
#ifndef __VEHICLE_AD_TP2825_H__
#define __VEHICLE_AD_TP2825_H__
int tp2825_ad_init(struct vehicle_ad_dev *ad);
int tp2825_ad_deinit(void);
int tp2825_ad_get_cfg(struct vehicle_cfg **cfg);
void tp2825_ad_check_cif_error(struct vehicle_ad_dev *ad, int last_line);
int tp2825_check_id(struct vehicle_ad_dev *ad);
int tp2825_stream(struct vehicle_ad_dev *ad, int enable);
void tp2825_channel_set(struct vehicle_ad_dev *ad, int channel);
#endif

View File

@@ -0,0 +1,144 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Rockchip Vehicle driver
*
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
*/
#ifndef __VEHICLE_CFG
#define __VEHICLE_CFG
#include <media/v4l2-mediabus.h>
#include <linux/rk-camera-module.h>
/* Driver information */
#define VEHICLE_DRIVER_NAME "Vehicle"
static int vehicle_debug;
#define VEHICLE_DG(format, ...) do { \
if (vehicle_debug) \
pr_info("%s %s(%d): " format, __func__, __LINE__, ## __VA_ARGS__); \
} while (0)
#define VEHICLE_DGERR(format, ...) \
pr_info("%s %s(%d):" format, VEHICLE_DRIVER_NAME, __func__, __LINE__, ## __VA_ARGS__)
#define VEHICLE_INFO(format, ...) \
pr_info("%s %s(%d):" format, VEHICLE_DRIVER_NAME, __func__, __LINE__, ## __VA_ARGS__)
#define MAX_BUF_NUM (6)
#define CVBS_DOUBLE_FPS_MODE /*PAL 50fps; NTSC 60fps*/
enum {
CIF_INPUT_FORMAT_YUV = 0,
CIF_INPUT_FORMAT_PAL = 2,
CIF_INPUT_FORMAT_NTSC = 3,
CIF_INPUT_FORMAT_RAW = 4,
CIF_INPUT_FORMAT_JPEG = 5,
CIF_INPUT_FORMAT_MIPI = 6,
CIF_INPUT_FORMAT_PAL_SW_COMPOSITE = 0xff000000,
CIF_INPUT_FORMAT_NTSC_SW_COMPOSITE = 0xfe000000,
};
enum {
CIF_OUTPUT_FORMAT_422 = 0,
CIF_OUTPUT_FORMAT_420 = 1,
};
struct vehicle_cfg {
/* output */
int width;
int height;
/* sensor output */
int src_width;
int src_height;
/*
* action: source video data input format.
* 000 - YUV
* 010 - PAL
* 011 - NTSC
* 100 - RAW
* 101 - JPEG
* 110 - MIPI
*/
int input_format;
/*
* 0 - output is 422
* 1 - output is 420
*/
int output_format;
/*
* YUV input order
* 00 - UYVY
* 01 - YVYU
* 10 - VYUY
* 11 - YUYV
*/
int yuv_order;
/*
* ccir input order
* 0 : odd field first
* 1 : even field first
*/
int field_order;
/*
* BT.656 not use
* BT.601 hsync polarity
* val:
* 0-low active
* 1-high active
*/
int href;
/*
* BT.656 not use
* BT.601 hsync polarity
* val :
* 0-low active
* 1-high active
*/
int vsync;
/*
* enum v4l2_mbus_type - media bus type
* @V4L2_MBUS_PARALLEL: parallel interface with hsync and vsync
* @V4L2_MBUS_BT656: parallel interface with embedded synchronisation, can
* also be used for BT.1120
* @V4L2_MBUS_CSI1: MIPI CSI-1 serial interface
* @V4L2_MBUS_CCP2: CCP2 (Compact Camera Port 2)
* @V4L2_MBUS_CSI2: MIPI CSI-2 serial interface
*/
enum v4l2_mbus_type type;
/*
* Signal polarity flags
* Note: in BT.656 mode HSYNC, FIELD, and VSYNC are unused
* V4L2_MBUS_[HV]SYNC* flags should be also used for specifying
* configuration of hardware that uses [HV]REF signals
*/
unsigned int mbus_flags;
/*
* Note: in BT.656/601 mode mipi_freq are unused
* only used when v4l2_mbus_type is V4L2_MBUS_CSI2
*/
s64 mipi_freq;
/*
* Note: in BT.656/601 mode mipi_freq are unused
* only used when v4l2_mbus_type is V4L2_MBUS_CSI2
*/
int lanes;
u32 mbus_code;
int start_x;
int start_y;
int frame_rate;
unsigned int buf_phy_addr[MAX_BUF_NUM];
unsigned int buf_num;
int ad_ready;
/*0:no, 1:90; 2:180; 4:270; 0x10:mirror-y; 0x20:mirror-x*/
int rotate_mirror;
struct rkmodule_csi_dphy_param *dphy_param;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,179 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Rockchip Vehicle driver
*
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
*/
#ifndef __VEHICLE_CIF_H
#define __VEHICLE_CIF_H
#include "vehicle_cfg.h"
#include "vehicle_cif_regs.h"
#include "../../../media/platform/rockchip/cif/hw.h"
#include "../../../media/platform/rockchip/cif/dev.h"
#include <linux/dma-mapping.h>
enum vehicle_rkcif_chip_id {
CHIP_RK3568_VEHICLE_CIF = 0x0,
CHIP_RK3588_VEHICLE_CIF,
};
enum rkcif_csi_host_idx {
RKCIF_MIPI0_CSI2 = 0x0,
RKCIF_MIPI1_CSI2,
RKCIF_MIPI2_CSI2,
RKCIF_MIPI3_CSI2,
RKCIF_MIPI4_CSI2,
RKCIF_MIPI5_CSI2,
};
struct vehicle_rkcif_dummy_buffer {
void *vaddr;
dma_addr_t dma_addr;
u32 size;
};
struct rk_cif_clk {
/************clk************/
struct clk *clks[RKCIF_MAX_BUS_CLK];
struct clk *xvclk;
int clks_num;
/************reset************/
struct reset_control *cif_rst[RKCIF_MAX_RESET];
int rsts_num;
/* spinlock_t lock; */
bool on;
};
struct rk_cif_irqinfo {
unsigned int irq;
unsigned long cifirq_idx;
unsigned long cifirq_normal_idx;
unsigned long cifirq_abnormal_idx;
unsigned long dmairq_idx;
/* @csi_overflow_cnt: count of csi overflow irq
* @csi_bwidth_lack_cnt: count of csi bandwidth lack irq
* @dvp_bus_err_cnt: count of dvp bus err irq
* @dvp_overflow_cnt: count dvp overflow irq
* @dvp_line_err_cnt: count dvp line err irq
* @dvp_pix_err_cnt: count dvp pix err irq
* @all_frm_end_cnt: raw frame end count
* @all_err_cnt: all err count
* @
*/
u64 csi_overflow_cnt;
u64 csi_bwidth_lack_cnt;
u64 dvp_bus_err_cnt;
u64 dvp_overflow_cnt;
u64 dvp_line_err_cnt;
u64 dvp_pix_err_cnt;
u64 all_frm_end_cnt;
u64 all_err_cnt;
u64 dvp_size_err_cnt;
u64 dvp_bwidth_lack_cnt;
u64 csi_size_err_cnt;
};
#define RKCIF_MAX_CSI_CHANNEL 4
struct vehicle_csi_channel_info {
unsigned char id;
unsigned char enable; /* capture enable */
unsigned char vc;
unsigned char data_type;
unsigned char crop_en;
unsigned char cmd_mode_en;
unsigned char fmt_val;
unsigned int width;
unsigned int height;
unsigned int virtual_width;
unsigned int crop_st_x;
unsigned int crop_st_y;
};
struct vehicle_cif {
struct device *dev;
struct device_node *phy_node;
struct rk_cif_clk clk;
struct vehicle_cfg cif_cfg;
char *base; /*cif base addr*/
//unsigned long cru_base;
//unsigned long grf_base;
void __iomem *cru_base; /*cru base addr*/
void __iomem *grf_base; /*grf base addr*/
void __iomem *csi2_dphy_base; /*csi2_dphy base addr*/
void __iomem *csi2_base; /*csi2 base addr*/
struct delayed_work work;
bool is_enabled;
u32 frame_buf[MAX_BUF_NUM];
u32 current_buf_index;
u32 last_buf_index;
u32 active[2];
int irq;
int csi2_irq1;
int csi2_irq2;
int drop_frames;
struct rk_cif_irqinfo irqinfo;
const struct vehicle_cif_reg *cif_regs;
struct regmap *regmap_grf;
struct regmap *regmap_dphy_grf;
unsigned int frame_idx;
struct vehicle_rkcif_dummy_buffer dummy_buf;
struct csi2_dphy_hw *dphy_hw;
int num_channels;
int chip_id;
int inf_id;
unsigned int csi_host_idx;
struct vehicle_csi_channel_info channels[RKCIF_MAX_CSI_CHANNEL];
spinlock_t vbq_lock; /* vfd lock */
bool interlaced_enable;
unsigned int interlaced_offset;
unsigned int interlaced_counts;
unsigned long *interlaced_buffer;
atomic_t reset_status;
wait_queue_head_t wq_stopped;
bool stopping;
struct mutex stream_lock;
enum rkcif_state state;
};
int vehicle_cif_init_mclk(struct vehicle_cif *cif);
int vehicle_cif_init(struct vehicle_cif *cif);
int vehicle_cif_deinit(struct vehicle_cif *cif);
int vehicle_cif_reverse_open(struct vehicle_cfg *v_cfg);
int vehicle_cif_reverse_close(void);
int vehicle_wait_cif_reset_done(void);
/* CIF IRQ STAT*/
#define DMA_FRAME_END (0x01 << 0)
#define LINE_END (0x01 << 1)
#define IFIFO_OF (0x01 << 4)
#define DFIFO_OF (0x01 << 5)
#define PRE_INF_FRAME_END (0x01 << 8)
#define PST_INF_FRAME_END (0x01 << 9)
enum rk_camera_signal_polarity {
RK_CAMERA_DEVICE_SIGNAL_HIGH_LEVEL = 1,
RK_CAMERA_DEVICE_SIGNAL_LOW_LEVEL = 0,
};
enum rk_camera_device_type {
RK_CAMERA_DEVICE_BT601_8 = 0x10000011,
RK_CAMERA_DEVICE_BT601_10 = 0x10000012,
RK_CAMERA_DEVICE_BT601_12 = 0x10000014,
RK_CAMERA_DEVICE_BT601_16 = 0x10000018,
RK_CAMERA_DEVICE_BT656_8 = 0x10000021,
RK_CAMERA_DEVICE_BT656_10 = 0x10000022,
RK_CAMERA_DEVICE_BT656_12 = 0x10000024,
RK_CAMERA_DEVICE_BT656_16 = 0x10000028,
RK_CAMERA_DEVICE_CVBS_NTSC = 0x20000001,
RK_CAMERA_DEVICE_CVBS_PAL = 0x20000002
};
#endif

View File

@@ -0,0 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Rockchip Vehicle Driver
*
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
*/
#ifndef _VEHICLE_RKCIF_REGS_H
#define _VEHICLE_RKCIF_REGS_H
#include "../../../media/platform/rockchip/cif/regs.h"
struct vehicle_cif_reg {
u32 offset;
char *name;
};
#define CIF_REG_NAME(_offset, _name) { .offset = (_offset), .name = (_name), }
#endif

View File

@@ -0,0 +1,117 @@
// SPDX-License-Identifier: GPL-2.0
/*
* drivers/video/rockchip/video/vehicle_dev.c
*
* Copyright (C) 2022 Rockchip Electronics Co.Ltd
* Authors:
* Zhiqin Wei <wzq@rock-chips.com>
*
*
*/
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/proc_fs.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/poll.h>
#include <linux/bitops.h>
#include <linux/moduleparam.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include "vehicle_main.h"
#include "vehicle_cfg.h"
static int vechile_open(struct inode *inode, struct file *file)
{
return 0;
}
static int vechile_close(struct inode *inode, struct file *file)
{
return 0;
}
static ssize_t vechile_write(struct file *file, const char __user *buf,
size_t size, loff_t *ppos)
{
int ret = 0;
char data[22] = "";
ret = copy_from_user(data, buf, 18);
if (ret)
return -1;
if (memcmp(data, "88", 2) == 0) {
vehicle_android_is_ready_notify();
VEHICLE_INFO("android already up, set vehicle in bottom\n");
} else {
vehicle_apk_state_change(data);
VEHICLE_INFO("apk_state_change, open dvr\n");
}
return size;
}
static ssize_t
vechile_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
return 1;
}
static const struct file_operations vechile_fops = {
.owner = THIS_MODULE,
/*.compat_ioctl = vechile_ioctl,*/
.open = vechile_open,
.release = vechile_close,
.write = vechile_write,
.read = vechile_read,
};
static struct miscdevice vechile_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "vehicle",
.fops = &vechile_fops,
};
static int __init vechile_module_init(void)
{
int ret = 0;
/* register misc device*/
ret = misc_register(&vechile_dev);
if (ret) {
VEHICLE_DGERR("ERROR: could not register vechile dev\n");
return ret;
}
return 0;
}
static void __exit vechile_module_exit(void)
{
misc_deregister(&vechile_dev);
}
module_init(vechile_module_init);
module_exit(vechile_module_exit);
MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,115 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* drivers/video/rockchip/flinger/flinger.c
*
* Copyright (C) 2022 Rockchip Electronics Co.Ltd
*
*/
#ifndef __VEHICLE_FLINGER_H
#define __VEHICLE_FLINGER_H
#include "vehicle_cfg.h"
#include "../rga3/include/rga.h"
#include <linux/types.h>
#include <linux/dma-mapping.h>
int vehicle_flinger_init(struct device *dev, struct vehicle_cfg *v_cfg);
int vehicle_flinger_deinit(void);
int vehicle_flinger_reverse_open(struct vehicle_cfg *cfg,
bool android_already);
int vehicle_flinger_reverse_close(bool android_already);
unsigned long vehicle_flinger_request_cif_buffer(void);
void vehicle_flinger_commit_cif_buffer(u32 buf_phy_addr);
enum {
RGA_TRANSFORM_ROT_MASK = 0x0000000F,
RGA_TRANSFORM_ROT_0 = 0x00000000,
RGA_TRANSFORM_ROT_90 = 0x00000001,
RGA_TRANSFORM_ROT_180 = 0x00000002,
RGA_TRANSFORM_ROT_270 = 0x00000004,
RGA_TRANSFORM_FLIP_MASK = 0x000000F0,
RGA_TRANSFORM_FLIP_H = 0x00000020,
RGA_TRANSFORM_FLIP_V = 0x00000010,
};
/*
* pixel format definitions,this is copy from android/system/core/include/system/graphics.h
*/
enum {
HAL_PIXEL_FORMAT_RGBA_8888 = 1,
HAL_PIXEL_FORMAT_RGBX_8888 = 2,
HAL_PIXEL_FORMAT_RGB_888 = 3,
HAL_PIXEL_FORMAT_RGB_565 = 4,
HAL_PIXEL_FORMAT_BGRA_8888 = 5,
HAL_PIXEL_FORMAT_RGBA_5551 = 6,
HAL_PIXEL_FORMAT_RGBA_4444 = 7,
/* 0x8 - 0xFF range unavailable */
/*
* 0x100 - 0x1FF
*
* This range is reserved for pixel formats that are specific to the HAL
* implementation. Implementations can use any value in this range to
* communicate video pixel formats between their HAL modules. These formats
* must not have an alpha channel. Additionally, an EGLimage created from a
* gralloc buffer of one of these formats must be supported for use with the
* GL_OES_EGL_image_external OpenGL ES extension.
*/
/*
* Android YUV format:
*
* This format is exposed outside of the HAL to software decoders and
* applications. EGLImageKHR must support it in conjunction with the
* OES_EGL_image_external extension.
*
* YV12 is a 4:2:0 YCrCb planar format comprised of a WxH Y plane followed
* by (W/2) x (H/2) Cr and Cb planes.
*
* This format assumes
* - an even width
* - an even height
* - a horizontal stride multiple of 16 pixels
* - a vertical stride equal to the height
*
* y_size = stride * height
* c_size = ALIGN(stride/2, 16) * height/2
* size = y_size + c_size * 2
* cr_offset = y_size
* cb_offset = y_size + c_size
*
*/
HAL_PIXEL_FORMAT_YV12 = 0x32315659, // YCrCb 4:2:0 Planar
/* Legacy formats (deprecated), used by ImageFormat.java */
/*
*YCbCr format default is BT601.
*/
HAL_PIXEL_FORMAT_YCbCr_422_SP = 0x10, // NV16
HAL_PIXEL_FORMAT_YCrCb_420_SP = 0x11, // NV21
HAL_PIXEL_FORMAT_YCbCr_422_I = 0x14, // YUY2
HAL_PIXEL_FORMAT_YCrCb_NV12 = 0x20, // YUY2
HAL_PIXEL_FORMAT_YCrCb_NV12_VIDEO = 0x21, // YUY2
HAL_PIXEL_FORMAT_YCrCb_NV12_10 = 0x22, // YUV420_1obit
HAL_PIXEL_FORMAT_YCbCr_422_SP_10 = 0x23, // YUV422_1obit
HAL_PIXEL_FORMAT_YCrCb_444_SP_10 = 0x24, //YUV444_1obit
HAL_PIXEL_FORMAT_YCrCb_444 = 0x25, //yuv444
HAL_PIXEL_FORMAT_FBDC_RGB565 = 0x26,
HAL_PIXEL_FORMAT_FBDC_U8U8U8U8 = 0x27, /*ARGB888*/
HAL_PIXEL_FORMAT_FBDC_U8U8U8 = 0x28, /*RGBP888*/
HAL_PIXEL_FORMAT_FBDC_RGBA888 = 0x29, /*ABGR888*/
HAL_PIXEL_FORMAT_BGRX_8888 = 0x30,
HAL_PIXEL_FORMAT_BGR_888 = 0x31,
HAL_PIXEL_FORMAT_BGR_565 = 0x32,
HAL_PIXEL_FORMAT_YUYV422 = 0x33,
HAL_PIXEL_FORMAT_YUYV420 = 0x34,
HAL_PIXEL_FORMAT_UYVY422 = 0x35,
HAL_PIXEL_FORMAT_UYVY420 = 0x36,
};
#endif

View File

@@ -0,0 +1,435 @@
// SPDX-License-Identifier: GPL-2.0
/*
* drivers/video/rockchip/video/vehicle_generic_sensor.c
*
* Copyright (C) 2020 Rockchip Electronics Co.Ltd
* Authors:
* Zhiqin Wei <wzq@rock-chips.com>
*
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/of_gpio.h>
#include "vehicle_ad.h"
#include "vehicle_ad_7181.h"
#include "vehicle_ad_tp2825.h"
#include "vehicle_ad_gc2145.h"
#include "vehicle_ad_nvp6324.h"
#include "vehicle_ad_nvp6188.h"
#include "vehicle_ad_max96714.h"
#include <linux/moduleparam.h>
#include "../../../../drivers/media/i2c/jaguar1_drv/jaguar1_v4l2.h"
#include "../../../../drivers/media/i2c/nvp6188.h"
#include "../../../../drivers/media/i2c/max96714.h"
struct vehicle_sensor_ops {
const char *name;
int (*sensor_init)(struct vehicle_ad_dev *ad);
int (*sensor_deinit)(void);
int (*sensor_stream)(struct vehicle_ad_dev *ad, int value);
int (*sensor_get_cfg)(struct vehicle_cfg **cfg);
void (*sensor_check_cif_error)(struct vehicle_ad_dev *ad, int last_line);
int (*sensor_check_id_cb)(struct vehicle_ad_dev *ad);
void (*sensor_set_channel)(struct vehicle_ad_dev *ad, int channel);
int (*sensor_mod_init)(void);
};
static struct vehicle_sensor_ops *sensor_cb;
static struct vehicle_sensor_ops sensor_cb_series[] = {
{
.name = "adv7181",
#ifdef CONFIG_VIDEO_REVERSE_AD7181
.sensor_init = adv7181_ad_init,
.sensor_deinit = adv7181_ad_deinit,
.sensor_stream = adv7181_stream,
.sensor_get_cfg = adv7181_ad_get_cfg,
.sensor_check_cif_error = adv7181_ad_check_cif_error,
.sensor_check_id_cb = adv7181_check_id,
.sensor_set_channel = adv7181_channel_set
#endif
},
{
.name = "tp2825",
#ifdef CONFIG_VIDEO_REVERSE_TP2825
.sensor_init = tp2825_ad_init,
.sensor_deinit = tp2825_ad_deinit,
.sensor_stream = tp2825_stream,
.sensor_get_cfg = tp2825_ad_get_cfg,
.sensor_check_cif_error = tp2825_ad_check_cif_error,
.sensor_check_id_cb = tp2825_check_id,
.sensor_set_channel = tp2825_channel_set
#endif
},
{
.name = "gc2145",
#ifdef CONFIG_VIDEO_REVERSE_GC2145
.sensor_init = gc2145_ad_init,
.sensor_deinit = gc2145_ad_deinit,
.sensor_stream = gc2145_stream,
.sensor_get_cfg = gc2145_ad_get_cfg,
.sensor_check_cif_error = gc2145_ad_check_cif_error,
.sensor_check_id_cb = gc2145_check_id,
.sensor_set_channel = gc2145_channel_set,
#endif
},
{
.name = "nvp6324",
#ifdef CONFIG_VIDEO_REVERSE_NVP6324
.sensor_init = nvp6324_ad_init,
.sensor_deinit = nvp6324_ad_deinit,
.sensor_stream = nvp6324_stream,
.sensor_get_cfg = nvp6324_ad_get_cfg,
.sensor_check_cif_error = nvp6324_ad_check_cif_error,
.sensor_check_id_cb = nvp6324_check_id,
.sensor_set_channel = nvp6324_channel_set,
#ifdef CONFIG_VIDEO_NVP6324
.sensor_mod_init = nvp6324_sensor_mod_init
#endif
#endif
},
{
.name = "max96714",
#ifdef CONFIG_VIDEO_REVERSE_MAX96714
.sensor_init = max96714_ad_init,
.sensor_deinit = max96714_ad_deinit,
.sensor_stream = max96714_stream,
.sensor_get_cfg = max96714_ad_get_cfg,
.sensor_check_cif_error = max96714_ad_check_cif_error,
.sensor_check_id_cb = max96714_check_id,
.sensor_set_channel = max96714_channel_set,
#ifdef CONFIG_VIDEO_MAX96714
.sensor_mod_init = max96714_sensor_mod_init
#endif
#endif
},
{
.name = "nvp6188",
#ifdef CONFIG_VIDEO_REVERSE_NVP6188
.sensor_init = nvp6188_ad_init,
.sensor_deinit = nvp6188_ad_deinit,
.sensor_stream = nvp6188_stream,
.sensor_get_cfg = nvp6188_ad_get_cfg,
.sensor_check_cif_error = nvp6188_ad_check_cif_error,
.sensor_check_id_cb = nvp6188_check_id,
.sensor_set_channel = nvp6188_channel_set,
#ifdef CONFIG_VIDEO_NVP6188
.sensor_mod_init = nvp6188_sensor_mod_init
#endif
#endif
}
};
int vehicle_generic_sensor_write(struct vehicle_ad_dev *ad, char reg, char *pval)
{
struct i2c_msg msg;
int ret;
char *tx_buf = kmalloc(2, GFP_KERNEL);
if (!tx_buf)
return -ENOMEM;
memcpy(tx_buf, &reg, 1);
memcpy(tx_buf+1, (char *)pval, 1);
msg.addr = ad->i2c_add;
msg.flags = 0;
msg.len = 2;
msg.buf = (char *)tx_buf;
// msg.scl_rate = ad->i2c_rate;
ret = i2c_transfer(ad->adapter, &msg, 1);
kfree(tx_buf);
return (ret == 1) ? 4 : ret;
}
int vehicle_sensor_write(struct vehicle_ad_dev *ad, u8 reg, u8 val)
{
struct i2c_msg msg;
u8 buf[2];
int ret;
//SENSOR_DG("write reg(0x%x val:0x%x)!\n", reg, val);
buf[0] = reg & 0xFF;
buf[1] = val;
msg.addr = ad->i2c_add;
msg.flags = 0;
msg.buf = buf;
msg.len = sizeof(buf);
ret = i2c_transfer(ad->adapter, &msg, 1);
if (ret >= 0)
return 0;
VEHICLE_DGERR("write reg(0x%x val:0x%x) failed !\n", reg, val);
return ret;
}
int vehicle_generic_sensor_read(struct vehicle_ad_dev *ad, char reg)
{
struct i2c_msg msgs[2];
int ret;
char reg_buf[2];
char pval;
memcpy(reg_buf, &reg, 1);
msgs[0].addr = ad->i2c_add;
msgs[0].flags = 0;
msgs[0].len = 1;
msgs[0].buf = reg_buf;
// msgs[0].scl_rate = ad->i2c_rate;
msgs[1].addr = ad->i2c_add;
msgs[1].flags = I2C_M_RD;
msgs[1].len = 1;
msgs[1].buf = &pval;
// msgs[1].scl_rate = ad->i2c_rate;
ret = i2c_transfer(ad->adapter, msgs, 2);
if (ret)
return ret;
return pval;
}
/* sensor register read */
int vehicle_sensor_read(struct vehicle_ad_dev *ad, u8 reg, u8 *val)
{
struct i2c_msg msg[2];
u8 buf[1];
int ret;
buf[0] = reg & 0xFF;
msg[0].addr = ad->i2c_add;
msg[0].flags = 0;
msg[0].buf = buf;
msg[0].len = sizeof(buf);
msg[1].addr = ad->i2c_add;
msg[1].flags = I2C_M_RD;
msg[1].buf = buf;
msg[1].len = 1;
ret = i2c_transfer(ad->adapter, msg, 2);
if (ret >= 0) {
*val = buf[0];
return 0;
}
dev_err(ad->dev,
"read reg:0x%x failed !\n", reg);
return ret;
}
int vehicle_ad_stream(struct vehicle_ad_dev *ad, int val)
{
int ret = 0;
if (sensor_cb && sensor_cb->sensor_stream) {
ret = sensor_cb->sensor_stream(ad, val);
if (ret < 0)
VEHICLE_DGERR("%s sensor_init failed!\n", ad->ad_name);
}
return ret;
}
int vehicle_parse_sensor(struct vehicle_ad_dev *ad)
{
struct device *dev = ad->dev;
struct device_node *node = NULL;
struct device_node *cp = NULL;
enum of_gpio_flags flags;
const char *status = NULL;
int i;
int ret = 0;
if (of_property_read_u32(dev->of_node, "ad,fix-format",
&ad->fix_format))
VEHICLE_DGERR("get fix-format failed!\n");
if (of_property_read_u32(dev->of_node, "vehicle,rotate-mirror",
&ad->cfg.rotate_mirror))
VEHICLE_DGERR("get rotate-mirror failed!\n");
node = of_parse_phandle(dev->of_node, "rockchip,cif-sensor", 0);
if (!node) {
VEHICLE_DGERR("get cif-sensor dts failed\n");
return -ENODEV;
}
for_each_child_of_node(node, cp) {
of_property_read_string(cp, "status", &status);
if (status && !strcmp(status, "disabled"))
continue;
VEHICLE_DG("status: %s\n", status);
// if (of_property_read_u32(cp, "i2c_rata", &ad->i2c_rate))
// SENSOR_DG("Get %s i2c_rata failed!\n", cp->name);
if (of_property_read_u32(cp, "i2c_chl", &ad->i2c_chl))
VEHICLE_DGERR("Get %s i2c_chl failed!", cp->name);
if (of_property_read_u32(cp, "ad_chl", &ad->ad_chl))
VEHICLE_DGERR("Get %s ad_chl failed!", cp->name);
if (ad->ad_chl > 4 || ad->ad_chl < 0) {
VEHICLE_DGERR("error, ad_chl %d !\n", ad->ad_chl);
ad->ad_chl = 0;
}
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, "rst_active", &ad->rst_active))
VEHICLE_DGERR("Get %s rst_active failed!", cp->name);
ad->reset = of_get_named_gpio_flags(cp, "reset-gpios",
0, &flags);
if (of_property_read_u32(cp, "pwr_active", &ad->pwr_active))
VEHICLE_DGERR("Get %s pwr_active failed!\n", cp->name);
if (of_property_read_u32(cp, "pwdn_active", &ad->pwdn_active))
VEHICLE_DGERR("Get %s pwdn_active failed!\n", cp->name);
ad->power = of_get_named_gpio_flags(cp, "power-gpios",
0, &flags);
ad->powerdown = of_get_named_gpio_flags(cp,
"powerdown-gpios",
0, &flags);
ad->reset = of_get_named_gpio_flags(cp, "reset-gpios",
0, &flags);
if (of_property_read_u32(cp, "i2c_add", &ad->i2c_add))
VEHICLE_DGERR("Get %s i2c_add failed!\n", cp->name);
ad->i2c_add = (ad->i2c_add >> 1);
if (of_property_read_u32(cp, "resolution", &ad->resolution))
VEHICLE_DGERR("Get %s resolution failed!\n", cp->name);
of_property_read_u32_array(cp,
"rockchip,camera-module-defrect0",
(unsigned int *)&ad->defrects[0], 6);
of_property_read_u32_array(cp,
"rockchip,camera-module-defrect1",
(unsigned int *)&ad->defrects[1], 6);
of_property_read_u32_array(cp,
"rockchip,camera-module-defrect2",
(unsigned int *)&ad->defrects[2], 6);
of_property_read_u32_array(cp,
"rockchip,camera-module-defrect3",
(unsigned int *)&ad->defrects[3], 6);
of_property_read_string(cp,
"rockchip,camera-module-interface0",
&ad->defrects[0].interface);
of_property_read_string(cp,
"rockchip,camera-module-interface1",
&ad->defrects[1].interface);
of_property_read_string(cp,
"rockchip,camera-module-interface2",
&ad->defrects[2].interface);
of_property_read_string(cp,
"rockchip,camera-module-interface3",
&ad->defrects[3].interface);
ad->ad_name = cp->name;
for (i = 0; i < ARRAY_SIZE(sensor_cb_series); i++) {
if (!strcmp(ad->ad_name, sensor_cb_series[i].name))
sensor_cb = sensor_cb_series + i;
}
VEHICLE_DG("%s: ad_chl=%d,,ad_addr=%x,fix_for=%d\n", ad->ad_name,
ad->ad_chl, ad->i2c_add, ad->fix_format);
VEHICLE_DG("gpio power:%d, active:%d\n", ad->power, ad->pwr_active);
VEHICLE_DG("gpio powerdown:%d, active:%d\n",
ad->powerdown, ad->pwdn_active);
break;
}
if (!ad->ad_name)
ret = -EINVAL;
return ret;
}
void vehicle_ad_channel_set(struct vehicle_ad_dev *ad, int channel)
{
if (sensor_cb->sensor_set_channel)
sensor_cb->sensor_set_channel(ad, channel);
}
int vehicle_ad_init(struct vehicle_ad_dev *ad)
{
int ret = 0;
//WARN_ON(1);
VEHICLE_DGERR("%s(%d) ad_name:%s!", __func__, __LINE__, ad->ad_name);
if (sensor_cb->sensor_init) {
ret = sensor_cb->sensor_init(ad);
if (ret < 0) {
VEHICLE_DGERR("%s sensor_init failed!\n", ad->ad_name);
goto end;
}
} else {
VEHICLE_DGERR("%s sensor_init is NULL!\n", ad->ad_name);
ret = -1;
goto end;
}
if (sensor_cb->sensor_check_id_cb) {
ret = sensor_cb->sensor_check_id_cb(ad);
if (ret < 0)
VEHICLE_DGERR("%s check id failed!\n", ad->ad_name);
}
end:
return ret;
}
int vehicle_ad_deinit(void)
{
int ret = 0;
if (sensor_cb->sensor_deinit)
ret = sensor_cb->sensor_deinit();
else
ret = -EINVAL;
return ret;
}
int vehicle_to_v4l2_drv_init(void)
{
int ret = 0;
VEHICLE_DG("%s(%d) enter!", __func__, __LINE__);
if (sensor_cb && sensor_cb->sensor_mod_init)
ret = sensor_cb->sensor_mod_init();
else
ret = -EINVAL;
return ret;
}
struct vehicle_cfg *vehicle_ad_get_vehicle_cfg(void)
{
struct vehicle_cfg *cfg = NULL;
if (sensor_cb->sensor_get_cfg)
sensor_cb->sensor_get_cfg(&cfg);
return cfg;
}
void vehicle_ad_check_cif_error(struct vehicle_ad_dev *ad, int last_line)
{
if (sensor_cb->sensor_get_cfg)
sensor_cb->sensor_check_cif_error(ad, last_line);
}

View File

@@ -0,0 +1,182 @@
// SPDX-License-Identifier: GPL-2.0
/*
* drivers/video/rockchip/video/vehicle_gpio.c
*
* Copyright (C) 2020 Rockchip Electronics Co.Ltd
* Authors:
* Jianwei Fan <jianwei.fan@rock-chips.com>
*
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/time.h>
#include <linux/platform_device.h>
#include <linux/kthread.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/completion.h>
#include <linux/wakelock.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include "vehicle_gpio.h"
#include "vehicle_main.h"
static void gpio_det_work_func(struct work_struct *work)
{
struct gpio_detect *gpiod = container_of(work, struct gpio_detect,
work.work);
int val = gpio_get_value(gpiod->gpio);
VEHICLE_DG("%s: gpiod->old val(%d), new val(%d)\n",
__func__, gpiod->val, val);
if (gpiod->val != val) {
gpiod->val = val;
vehicle_gpio_stat_change_notify();
}
}
static irqreturn_t gpio_det_interrupt(int irq, void *dev_id)
{
struct gpio_detect *gpiod = dev_id;
int val = gpio_get_value(gpiod->gpio);
unsigned int irqflags = IRQF_ONESHOT;
if (val)
irqflags |= IRQ_TYPE_EDGE_FALLING;
else
irqflags |= IRQ_TYPE_EDGE_RISING;
irq_set_irq_type(gpiod->irq, irqflags);
mod_delayed_work(system_wq, &gpiod->work,
msecs_to_jiffies(gpiod->debounce_ms));
return IRQ_HANDLED;
}
static int vehicle_gpio_init_check(struct gpio_detect *gpiod)
{
gpiod->val = gpio_get_value(gpiod->gpio);
dev_info(gpiod->dev, "%s: gpiod->atv_val(%d), gpiod->val(%d)\n",
__func__, gpiod->atv_val, gpiod->val);
if (gpiod->atv_val == gpiod->val) {
vehicle_gpio_stat_change_notify();
return 1;
} else {
return 0;
}
}
bool vehicle_gpio_reverse_check(struct gpio_detect *gpiod)
{
int val = gpiod->val ^ gpiod->atv_val;
if (gpiod->num == 0)
return true;
else
return (val == 0) ? true : false;
}
static int gpio_parse_dt(struct gpio_detect *gpiod, const char *ad_name)
{
struct device *dev = gpiod->dev;
struct device_node *gpiod_node;
struct device_node *node;
const char *name;
// int num;
int ret = 0;
gpiod_node = of_parse_phandle(dev->of_node, "rockchip,gpio-det", 0);
if (!gpiod_node) {
VEHICLE_DGERR("phase gpio-det from dts failed, maybe no use!\n");
return 0;
}
gpiod->num = of_get_child_count(gpiod_node);
if (gpiod->num == 0) {
VEHICLE_DGERR("gpio-det child count is 0, maybe no use!\n");
return 0;
}
of_property_read_u32(gpiod_node, "rockchip,camcap-mirror",
&gpiod->mirror);
for_each_child_of_node(gpiod_node, node) {
enum of_gpio_flags flags;
name = of_get_property(node, "label", NULL);
if (!strcmp(name, "car-reverse")) {
gpiod->gpio = of_get_named_gpio_flags(node, "car-reverse-gpios", 0, &flags);
if (!gpio_is_valid(gpiod->gpio)) {
dev_err(dev, "failed to get car reverse gpio\n");
ret = -ENOMEM;
}
gpiod->atv_val = !(flags & OF_GPIO_ACTIVE_LOW);
of_property_read_u32(node, "linux,debounce-ms",
&gpiod->debounce_ms);
break;
}
}
VEHICLE_DG("%s:gpio %d, act_val %d, mirror %d, debounce_ms %d\n",
__func__, gpiod->gpio, gpiod->atv_val, gpiod->mirror, gpiod->debounce_ms);
return ret;
}
int vehicle_gpio_init(struct gpio_detect *gpiod, const char *ad_name)
{
int gpio;
int ret;
unsigned long irqflags = IRQF_ONESHOT;
if (gpio_parse_dt(gpiod, ad_name) < 0) {
VEHICLE_DGERR("%s,parse dt failed\n", __func__);
return -EINVAL;
}
gpio = gpiod->gpio;
ret = gpio_request(gpio, "vehicle");
if (ret < 0)
VEHICLE_DGERR("%s:failed to request gpio %d, maybe no use\n", __func__, ret);
dev_info(gpiod->dev, "%s: request irq gpio(%d)\n", __func__, gpio);
gpio_direction_input(gpio);
gpiod->irq = gpio_to_irq(gpio);
if (gpiod->irq < 0)
VEHICLE_DGERR("failed to get irq, GPIO %d, maybe no use\n", gpio);
gpiod->val = gpio_get_value(gpio);
if (gpiod->val)
irqflags |= IRQ_TYPE_EDGE_FALLING;
else
irqflags |= IRQ_TYPE_EDGE_RISING;
ret = devm_request_threaded_irq(gpiod->dev, gpiod->irq,
NULL, gpio_det_interrupt,
irqflags, "vehicle gpio", gpiod);
if (ret < 0)
VEHICLE_DGERR("request irq(%s) failed:%d\n",
"vehicle", ret);
//if not add in create_workqueue only execute once;
INIT_DELAYED_WORK(&gpiod->work, gpio_det_work_func);
vehicle_gpio_init_check(gpiod);
return 0;
}
int vehicle_gpio_deinit(struct gpio_detect *gpiod)
{
free_irq(gpiod->irq, gpiod);
gpio_free(gpiod->gpio);
return 0;
}

View File

@@ -0,0 +1,33 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Rockchip Vehicle driver
*
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
*/
#ifndef __VEHICLE_GPIO_H
#define __VEHICLE_GPIO_H
#include "vehicle_cfg.h"
struct gpio_detect {
int gpio;
int atv_val;
int val;
int irq;
int mirror;
int num;
unsigned int debounce_ms;
struct delayed_work work;
struct device *dev;
};
/*
* true : reverse on
* false : reverse over
*/
bool vehicle_gpio_reverse_check(struct gpio_detect *gpiod);
int vehicle_gpio_init(struct gpio_detect *gpiod, const char *ad_name);
int vehicle_gpio_deinit(struct gpio_detect *gpiod);
#endif

View File

@@ -0,0 +1,504 @@
// SPDX-License-Identifier: GPL-2.0
/*
* drivers/video/rockchip/video/vehicle_main.c
*
* Copyright (C) 2022 Rockchip Electronics Co.Ltd
* Authors:
* Zhiqin Wei <wzq@rock-chips.com>
* <randy.wang@rock-chips.com>
* Jianwei Fan <jianwei.fan@rock-chips.com>
*
*/
#define CAMMODULE_NAME "vehicle_main"
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/time.h>
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/kthread.h>
#include <linux/fb.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/completion.h>
#include <linux/wakelock.h>
#include <linux/of_gpio.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/pm_runtime.h>
#include <linux/interrupt.h>
#include "vehicle_flinger.h"
#include "vehicle_cfg.h"
#include "vehicle_ad.h"
#include "vehicle_main.h"
#include "vehicle_cif.h"
#include "vehicle_gpio.h"
#include <linux/version.h>
#include "../../../media/platform/rockchip/cif/hw.h"
#include "../../../media/platform/rockchip/cif/dev.h"
// #include "../../../media/platform/rockchip/cif/mipi-csi2.h"
#include "../../../phy/rockchip/phy-rockchip-csi2-dphy-common.h"
#define DRIVER_VERSION KERNEL_VERSION(0, 0x03, 0x00)
static bool flinger_inited;
static bool TEST_GPIO = true;
static bool dvr_apk_need_start;
enum {
STATE_CLOSE = 0,
STATE_OPEN,
};
struct vehicle {
struct device *dev;
struct pinctrl *pinctrl;
struct pinctrl_state *pins_default;
struct wake_lock wake_lock;
struct gpio_detect gpio_data;
struct vehicle_cif cif;
struct vehicle_ad_dev ad;
int mirror;
wait_queue_head_t vehicle_wait;
atomic_t vehicle_atomic;
int state;
bool android_is_ready;
bool gpio_over;
};
static struct vehicle *g_vehicle;
static int vehicle_parse_dt(struct vehicle *vehicle_info)
{
struct device *dev = vehicle_info->dev;
/* 1. pinctrl */
vehicle_info->pinctrl = devm_pinctrl_get(dev);
if (IS_ERR(vehicle_info->pinctrl)) {
dev_err(dev, "pinctrl get failed\n");
return PTR_ERR(vehicle_info->pinctrl);
}
vehicle_info->pins_default = pinctrl_lookup_state(vehicle_info->pinctrl,
"default");
if (IS_ERR(vehicle_info->pins_default))
dev_err(dev, "get default pinstate failed\n");
return 0;
}
void vehicle_ad_stat_change_notify(void)
{
if (g_vehicle) {
VEHICLE_INFO("ad state change! set atpmic to 1!\n");
atomic_set(&g_vehicle->vehicle_atomic, 1);
}
}
void vehicle_cif_stat_change_notify(void)
{
if (g_vehicle) {
VEHICLE_INFO("cif state change! set atpmic to 1!\n");
atomic_set(&g_vehicle->vehicle_atomic, 1);
}
}
void vehicle_gpio_stat_change_notify(void)
{
if (g_vehicle && !g_vehicle->gpio_over) {
VEHICLE_INFO("reverse gpio state change! set atpmic to 1!\n");
atomic_set(&g_vehicle->vehicle_atomic, 1);
}
}
void vehicle_cif_error_notify(int last_line)
{
if (g_vehicle) {
VEHICLE_INFO("cif error notify\n");
vehicle_ad_check_cif_error(&g_vehicle->ad, last_line);
}
}
static void vehicle_open(struct vehicle_cfg *v_cfg)
{
VEHICLE_INFO("%s enter: android_is_ready ?= %d",
__func__, g_vehicle->android_is_ready);
vehicle_flinger_reverse_open(v_cfg, g_vehicle->android_is_ready);
vehicle_cif_reverse_open(v_cfg);
}
static void vehicle_close(void)
{
vehicle_cif_reverse_close();
vehicle_flinger_reverse_close(g_vehicle->android_is_ready);
}
static void vehicle_open_close(void)
{
vehicle_cif_reverse_close();
}
static int vehicle_state_change(struct vehicle *v)
{
struct vehicle_cfg *v_cfg;
struct gpio_detect *gpiod = &v->gpio_data;
bool gpio_reverse_on;
int ret = 0;
/* 1. get ad sensor cfg */
v_cfg = vehicle_ad_get_vehicle_cfg();
if (!v_cfg) {
VEHICLE_DGERR("v_cfg is NULL, if for test continue.\n");
return -ENODEV;
}
if (!flinger_inited) {
do {
/* 2. flinger */
VEHICLE_DG("%s: flinger init start\r\n", __func__);
ret = vehicle_flinger_init(v->dev, v_cfg);
if (ret < 0) {
VEHICLE_DG("rk_vehicle_system_main: flinger init failed\r\n");
msleep(20);
}
} while (ret);
}
VEHICLE_DG("%s: flinger init success\r\n", __func__);
flinger_inited = true;
gpio_reverse_on = vehicle_gpio_reverse_check(gpiod);
gpio_reverse_on = TEST_GPIO & gpio_reverse_on;
VEHICLE_DG(
"%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);
if (v_cfg->mbus_flags & V4L2_MBUS_CSI2_CONTINUOUS_CLOCK) {
switch (v->state) {
case STATE_CLOSE:
if (dvr_apk_need_start) {
vehicle_open(v_cfg);
msleep(20);
vehicle_ad_stream(&v->ad, 0);
vehicle_ad_channel_set(&g_vehicle->ad, 0);
vehicle_ad_stream(&v->ad, 1);
v->state = STATE_OPEN;
}
if (gpio_reverse_on) {
vehicle_open(v_cfg);
msleep(20);
vehicle_ad_stream(&v->ad, 0);
vehicle_ad_channel_set(&g_vehicle->ad, 0);
vehicle_ad_stream(&v->ad, 1);
v->state = STATE_OPEN;
}
break;
case STATE_OPEN:
/* reverse exit || video loss */
if (!dvr_apk_need_start && (!gpio_reverse_on || !v_cfg->ad_ready)) {
vehicle_close();
vehicle_ad_stream(&v->ad, 0);
v->state = STATE_CLOSE;
} else if (gpio_reverse_on) { // reverse on & video format change
vehicle_open_close();
vehicle_open(v_cfg);
msleep(100);
vehicle_ad_stream(&v->ad, 0);
vehicle_ad_channel_set(&g_vehicle->ad, 0);
vehicle_ad_stream(&v->ad, 1);
} else if (!gpio_reverse_on && dvr_apk_need_start) {
vehicle_close();
vehicle_open(v_cfg);
msleep(20);
vehicle_ad_stream(&v->ad, 0);
vehicle_ad_channel_set(&g_vehicle->ad, 0);
vehicle_ad_stream(&v->ad, 1);
}
break;
}
} else if (v_cfg->mbus_flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK) {
switch (v->state) {
case STATE_CLOSE:
if (dvr_apk_need_start) {
vehicle_ad_stream(&v->ad, 0);
vehicle_ad_channel_set(&g_vehicle->ad, 0);
vehicle_ad_stream(&v->ad, 1);
msleep(20);
vehicle_open(v_cfg);
v->state = STATE_OPEN;
}
if (gpio_reverse_on) {
vehicle_ad_stream(&v->ad, 0);
vehicle_ad_channel_set(&g_vehicle->ad, 0);
vehicle_ad_stream(&v->ad, 1);
msleep(20);
vehicle_open(v_cfg);
v->state = STATE_OPEN;
}
break;
case STATE_OPEN:
/* reverse exit || video loss */
if (!dvr_apk_need_start && (!gpio_reverse_on || !v_cfg->ad_ready)) {
vehicle_close();
vehicle_ad_stream(&v->ad, 0);
v->state = STATE_CLOSE;
} else if (gpio_reverse_on) { // reverse on & video format change
vehicle_open_close();
vehicle_ad_stream(&v->ad, 0);
vehicle_ad_channel_set(&g_vehicle->ad, 0);
vehicle_ad_stream(&v->ad, 1);
msleep(100);
vehicle_open(v_cfg);
} else if (!gpio_reverse_on && dvr_apk_need_start) {
vehicle_close();
vehicle_ad_stream(&v->ad, 0);
vehicle_ad_channel_set(&g_vehicle->ad, 0);
vehicle_ad_stream(&v->ad, 1);
msleep(20);
vehicle_open(v_cfg);
}
break;
}
} else {
switch (v->state) {
case STATE_CLOSE:
if (dvr_apk_need_start) {
vehicle_ad_stream(&v->ad, 0);
vehicle_ad_channel_set(&g_vehicle->ad, 0);
vehicle_ad_stream(&v->ad, 1);
msleep(20);
vehicle_open(v_cfg);
v->state = STATE_OPEN;
}
if (gpio_reverse_on) {
vehicle_ad_stream(&v->ad, 0);
vehicle_ad_channel_set(&g_vehicle->ad, 0);
vehicle_ad_stream(&v->ad, 1);
msleep(20);
vehicle_open(v_cfg);
v->state = STATE_OPEN;
}
break;
case STATE_OPEN:
/* reverse exit || video loss */
if (!dvr_apk_need_start && (!gpio_reverse_on || !v_cfg->ad_ready)) {
vehicle_close();
vehicle_ad_stream(&v->ad, 0);
v->state = STATE_CLOSE;
} else if (gpio_reverse_on) { // reverse on & video format change
vehicle_open_close();
vehicle_ad_stream(&v->ad, 0);
vehicle_ad_channel_set(&g_vehicle->ad, 0);
vehicle_ad_stream(&v->ad, 1);
msleep(100);
vehicle_open(v_cfg);
} else if (!gpio_reverse_on && dvr_apk_need_start) {
vehicle_close();
vehicle_ad_stream(&v->ad, 0);
vehicle_ad_channel_set(&g_vehicle->ad, 0);
vehicle_ad_stream(&v->ad, 1);
msleep(20);
vehicle_open(v_cfg);
}
break;
}
}
return 0;
}
static int vehicle_probe(struct platform_device *pdev)
{
struct vehicle *vehicle_info;
dev_info(&pdev->dev, "driver version: %02x.%02x.%02x",
DRIVER_VERSION >> 16,
(DRIVER_VERSION & 0xff00) >> 8,
DRIVER_VERSION & 0x00ff);
vehicle_info = devm_kzalloc(&pdev->dev,
sizeof(struct vehicle), GFP_KERNEL);
if (!vehicle_info)
return -ENOMEM;
vehicle_info->dev = &pdev->dev;
vehicle_info->gpio_data.dev = &pdev->dev;
vehicle_info->cif.dev = &pdev->dev;
vehicle_info->ad.dev = &pdev->dev;
dev_set_name(vehicle_info->dev, "vehicle_main");
if (!pdev->dev.of_node)
return -EINVAL;
vehicle_parse_dt(vehicle_info);
if (vehicle_parse_sensor(&vehicle_info->ad) < 0) {
VEHICLE_DGERR("parse sensor failed!\n");
return -EINVAL;
}
wake_lock_init(&vehicle_info->wake_lock, WAKE_LOCK_SUSPEND, "vehicle");
dev_info(vehicle_info->dev, "vehicle driver probe success\n");
init_waitqueue_head(&vehicle_info->vehicle_wait);
atomic_set(&vehicle_info->vehicle_atomic, 0);
vehicle_info->state = STATE_CLOSE;
vehicle_info->android_is_ready = false;
vehicle_info->gpio_over = false;
g_vehicle = vehicle_info;
return 0;
}
#if defined(CONFIG_OF)
static const struct of_device_id vehicle_of_match[] = {
{ .compatible = "rockchip,vehicle", },
{},
};
#endif
static struct platform_driver vehicle_driver = {
.driver = {
.name = "vehicle",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(vehicle_of_match),
},
.probe = vehicle_probe,
};
void vehicle_android_is_ready_notify(void)
{
if (g_vehicle)
g_vehicle->android_is_ready = true;
TEST_GPIO = !TEST_GPIO;
atomic_set(&g_vehicle->vehicle_atomic, 1);
}
void vehicle_apk_state_change(char data[22])
{
if (memcmp(data, "11", 2) == 0)
dvr_apk_need_start = true;
else if (memcmp(data, "10", 2) == 0)
dvr_apk_need_start = false;
if (g_vehicle)
atomic_set(&g_vehicle->vehicle_atomic, 1);
}
static void vehicle_exit_complete_notify(struct vehicle *v)
{
char *status = NULL;
char *envp[2];
if (!v)
return;
status = kasprintf(GFP_KERNEL, "vehicle_exit=done");
envp[0] = status;
envp[1] = NULL;
wake_lock_timeout(&v->wake_lock, 5 * HZ);
kobject_uevent_env(&v->dev->kobj, KOBJ_CHANGE, envp);
kfree(status);
}
static int rk_vehicle_system_main(void *arg)
{
int ret = -1;
struct vehicle *v = g_vehicle;
int loop_times = 0;
if (!g_vehicle) {
VEHICLE_DGERR("vehicle probe failed, g_vehicle is NULL.\n");
goto VEHICLE_EXIT;
}
/* 0. gpio init and check state */
ret = vehicle_gpio_init(&v->gpio_data, v->ad.ad_name);
if (ret < 0) {
VEHICLE_DGERR("%s: gpio init failed\r\n", __func__);
goto VEHICLE_GPIO_DEINIT;
}
VEHICLE_DG("vehicle_gpio_init ok!\n");
/* 1.ad */
VEHICLE_DG("%s: vehicle_ad_init start\r\n", __func__);
/* config mclk first */
ret = vehicle_cif_init_mclk(&v->cif);
ret |= vehicle_ad_init(&v->ad);
if (ret < 0) {
VEHICLE_DGERR("%s: ad init failed\r\n", __func__);
goto VEHICLE_AD_DEINIT;
}
VEHICLE_DG("vehicle_ad_init ok!\r\n");
/* 3. cif init */
ret = vehicle_cif_init(&v->cif);
if (ret < 0) {
VEHICLE_DGERR("%s: cif init failed\r\n", __func__);
goto VEHICLE_CIF_DEINIT;
}
VEHICLE_DG("%s: vehicle_cif_init ok!\r\n", __func__);
pm_runtime_enable(v->dev);
pm_runtime_get_sync(v->dev);
//while (STATE_OPEN == v->state || !v->vehicle_need_exit) {
while (v->state == STATE_OPEN || !v->android_is_ready) {
if (v->android_is_ready && !v->state)
v->gpio_over = true;
wait_event_timeout(v->vehicle_wait,
atomic_read(&v->vehicle_atomic),
msecs_to_jiffies(100));
if (atomic_read(&v->vehicle_atomic)) {
atomic_set(&v->vehicle_atomic, 0);
vehicle_state_change(v);
}
VEHICLE_DG("loop time(%d) \r\n", loop_times);
loop_times++;
}
VEHICLE_CIF_DEINIT:
vehicle_cif_deinit(&v->cif);
VEHICLE_AD_DEINIT:
vehicle_ad_deinit();
VEHICLE_GPIO_DEINIT:
vehicle_gpio_deinit(&v->gpio_data);
/*Init normal drivers*/
VEHICLE_EXIT:
if (flinger_inited)
vehicle_flinger_deinit();
// if (v && v->pinctrl)
// pinctrl_put(v->pinctrl);
vehicle_to_v4l2_drv_init();
msleep(500);
rockchip_csi2_dphy_hw_init();
rockchip_csi2_dphy_init();
rk_cif_plat_drv_init();
// rkcif_csi2_plat_drv_init();
rkcif_clr_unready_dev();
#ifdef CONFIG_GPIO_DET
//gpio_det_init();
#endif
// msleep(1000);
vehicle_exit_complete_notify(v);
return 0;
}
static int __init vehicle_system_start(void)
{
platform_driver_register(&vehicle_driver);
kthread_run(rk_vehicle_system_main, NULL, "vehicle main");
return 0;
}
subsys_initcall_sync(vehicle_system_start);

View File

@@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Rockchip Vehicle driver
*
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
*/
#ifndef __VEHICLE_MAIN_H
#define __VEHICLE_MAIN_H
/* impl by vehicle_main, call by ad detect */
void vehicle_ad_stat_change_notify(void);
void vehicle_cif_stat_change_notify(void);
void vehicle_gpio_stat_change_notify(void);
void vehicle_cif_error_notify(int last_line);
void vehicle_android_is_ready_notify(void);
void vehicle_apk_state_change(char crtc[22]);
#endif

View File

@@ -0,0 +1,246 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Rockchip Vehicle driver
*
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
*
*/
#ifndef _VEHICLE_SAMSUNG_DCPHY_COMMON_H_
#define _VEHICLE_SAMSUNG_DCPHY_COMMON_H_
#define MAX_NUM_CSI2_DPHY (0x2)
/*redefine samsung_mipi_dcphy info*/
struct samsung_mipi_dcphy {
struct device *dev;
struct clk *ref_clk;
struct clk *pclk;
struct regmap *regmap;
struct regmap *grf_regmap;
struct reset_control *m_phy_rst;
struct reset_control *s_phy_rst;
struct reset_control *apb_rst;
struct reset_control *grf_apb_rst;
struct mutex mutex;
struct csi2_dphy *dphy_dev[MAX_NUM_CSI2_DPHY];
atomic_t stream_cnt;
int dphy_dev_num;
bool c_option;
unsigned int lanes;
struct {
unsigned long long rate;
u8 prediv;
u16 fbdiv;
long dsm;
u8 scaler;
bool ssc_en;
u8 mfr;
u8 mrr;
} pll;
int (*stream_on)(struct csi2_dphy *dphy, struct v4l2_subdev *sd);
int (*stream_off)(struct csi2_dphy *dphy, struct v4l2_subdev *sd);
/*for vehicle*/
struct csi2_dphy_hw *dphy_vehicle[MAX_NUM_CSI2_DPHY];
int dphy_vehicle_num;
};
#define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l)))
/*samsung mipi dcphy register*/
#define BIAS_CON0 0x0000
#define BIAS_CON1 0x0004
#define BIAS_CON2 0x0008
#define BIAS_CON4 0x0010
#define I_MUX_SEL_MASK GENMASK(6, 5)
#define I_MUX_SEL(x) UPDATE(x, 6, 5)
#define PLL_CON0 0x0100
#define PLL_EN BIT(12)
#define S_MASK GENMASK(10, 8)
#define S(x) UPDATE(x, 10, 8)
#define P_MASK GENMASK(5, 0)
#define P(x) UPDATE(x, 5, 0)
#define PLL_CON1 0x0104
#define PLL_CON2 0x0108
#define M_MASK GENMASK(9, 0)
#define M(x) UPDATE(x, 9, 0)
#define PLL_CON3 0x010c
#define MRR_MASK GENMASK(13, 8)
#define MRR(x) UPDATE(x, 13, 8)
#define MFR_MASK GENMASK(7, 0)
#define MFR(x) UPDATE(x, 7, 0)
#define PLL_CON4 0x0110
#define SSCG_EN BIT(11)
#define PLL_CON5 0x0114
#define RESET_N_SEL BIT(10)
#define PLL_ENABLE_SEL BIT(8)
#define PLL_CON6 0x0118
#define PLL_CON7 0x011c
#define PLL_LOCK_CNT(x) UPDATE(x, 15, 0)
#define PLL_CON8 0x0120
#define PLL_STB_CNT(x) UPDATE(x, 15, 0)
#define PLL_STAT0 0x0140
#define PLL_LOCK BIT(0)
#define DPHY_MC_GNR_CON0 0x0300
#define PHY_READY BIT(1)
#define PHY_ENABLE BIT(0)
#define DPHY_MC_GNR_CON1 0x0304
#define T_PHY_READY(x) UPDATE(x, 15, 0)
#define DPHY_MC_ANA_CON0 0x0308
#define DPHY_MC_ANA_CON1 0x030c
#define DPHY_MC_ANA_CON2 0x0310
#define HS_VREG_AMP_ICON(x) UPDATE(x, 1, 0)
#define DPHY_MC_TIME_CON0 0x0330
#define HSTX_CLK_SEL BIT(12)
#define T_LPX(x) UPDATE(x, 11, 4)
#define DPHY_MC_TIME_CON1 0x0334
#define T_CLK_ZERO(x) UPDATE(x, 15, 8)
#define T_CLK_PREPARE(x) UPDATE(x, 7, 0)
#define DPHY_MC_TIME_CON2 0x0338
#define T_HS_EXIT(x) UPDATE(x, 15, 8)
#define T_CLK_TRAIL(x) UPDATE(x, 7, 0)
#define DPHY_MC_TIME_CON3 0x033c
#define T_CLK_POST(x) UPDATE(x, 7, 0)
#define DPHY_MC_TIME_CON4 0x0340
#define T_ULPS_EXIT(x) UPDATE(x, 9, 0)
#define DPHY_MC_DESKEW_CON0 0x0350
#define SKEW_CAL_RUN_TIME(x) UPDATE(x, 15, 12)
#define SKEW_CAL_INIT_RUN_TIME(x) UPDATE(x, 11, 8)
#define SKEW_CAL_INIT_WAIT_TIME(x) UPDATE(x, 7, 4)
#define SKEW_CAL_EN BIT(0)
#define COMBO_MD0_GNR_CON0 0x0400
#define COMBO_MD0_GNR_CON1 0x0404
#define COMBO_MD0_ANA_CON0 0x0408
#define COMBO_MD0_ANA_CON1 0x040C
#define COMBO_MD0_ANA_CON2 0x0410
#define COMBO_MD0_TIME_CON0 0x0430
#define COMBO_MD0_TIME_CON1 0x0434
#define COMBO_MD0_TIME_CON2 0x0438
#define COMBO_MD0_TIME_CON3 0x043C
#define COMBO_MD0_TIME_CON4 0x0440
#define COMBO_MD0_DATA_CON0 0x0444
#define COMBO_MD1_GNR_CON0 0x0500
#define COMBO_MD1_GNR_CON1 0x0504
#define COMBO_MD1_ANA_CON0 0x0508
#define COMBO_MD1_ANA_CON1 0x050c
#define COMBO_MD1_ANA_CON2 0x0510
#define COMBO_MD1_TIME_CON0 0x0530
#define COMBO_MD1_TIME_CON1 0x0534
#define COMBO_MD1_TIME_CON2 0x0538
#define COMBO_MD1_TIME_CON3 0x053C
#define COMBO_MD1_TIME_CON4 0x0540
#define COMBO_MD1_DATA_CON0 0x0544
#define COMBO_MD2_GNR_CON0 0x0600
#define COMBO_MD2_GNR_CON1 0x0604
#define COMBO_MD2_ANA_CON0 0X0608
#define COMBO_MD2_ANA_CON1 0X060C
#define COMBO_MD2_ANA_CON2 0X0610
#define COMBO_MD2_TIME_CON0 0x0630
#define COMBO_MD2_TIME_CON1 0x0634
#define COMBO_MD2_TIME_CON2 0x0638
#define COMBO_MD2_TIME_CON3 0x063C
#define COMBO_MD2_TIME_CON4 0x0640
#define COMBO_MD2_DATA_CON0 0x0644
#define DPHY_MD3_GNR_CON0 0x0700
#define DPHY_MD3_GNR_CON1 0x0704
#define DPHY_MD3_ANA_CON0 0X0708
#define DPHY_MD3_ANA_CON1 0X070C
#define DPHY_MD3_ANA_CON2 0X0710
#define DPHY_MD3_TIME_CON0 0x0730
#define DPHY_MD3_TIME_CON1 0x0734
#define DPHY_MD3_TIME_CON2 0x0738
#define DPHY_MD3_TIME_CON3 0x073C
#define DPHY_MD3_TIME_CON4 0x0740
#define DPHY_MD3_DATA_CON0 0x0744
#define T_LP_EXIT_SKEW(x) UPDATE(x, 3, 2)
#define T_LP_ENTRY_SKEW(x) UPDATE(x, 1, 0)
#define T_HS_ZERO(x) UPDATE(x, 15, 8)
#define T_HS_PREPARE(x) UPDATE(x, 7, 0)
#define T_HS_EXIT(x) UPDATE(x, 15, 8)
#define T_HS_TRAIL(x) UPDATE(x, 7, 0)
#define T_TA_GET(x) UPDATE(x, 7, 4)
#define T_TA_GO(x) UPDATE(x, 3, 0)
/* MIPI_CDPHY_GRF registers */
#define MIPI_DCPHY_GRF_CON0 0x0000
#define S_CPHY_MODE HIWORD_UPDATE(1, 3, 3)
#define M_CPHY_MODE HIWORD_UPDATE(1, 0, 0)
#define MAX_DPHY_BW 4500000L
#define MAX_CPHY_BW 2000000L
#define RX_CLK_THS_SETTLE (0xb30)
#define RX_LANE0_THS_SETTLE (0xC30)
#define RX_LANE0_ERR_SOT_SYNC (0xC34)
#define RX_LANE1_THS_SETTLE (0xD30)
#define RX_LANE1_ERR_SOT_SYNC (0xD34)
#define RX_LANE2_THS_SETTLE (0xE30)
#define RX_LANE2_ERR_SOT_SYNC (0xE34)
#define RX_LANE3_THS_SETTLE (0xF30)
#define RX_LANE3_ERR_SOT_SYNC (0xF34)
#define RX_CLK_LANE_ENABLE (0xB00)
#define RX_DATA_LANE0_ENABLE (0xC00)
#define RX_DATA_LANE1_ENABLE (0xD00)
#define RX_DATA_LANE2_ENABLE (0xE00)
#define RX_DATA_LANE3_ENABLE (0xF00)
#define RX_S0C_GNR_CON1 (0xB04)
#define RX_S0C_ANA_CON1 (0xB0c)
#define RX_S0C_ANA_CON2 (0xB10)
#define RX_S0C_ANA_CON3 (0xB14)
#define RX_COMBO_S0D0_GNR_CON1 (0xC04)
#define RX_COMBO_S0D0_ANA_CON1 (0xC0c)
#define RX_COMBO_S0D0_ANA_CON2 (0xC10)
#define RX_COMBO_S0D0_ANA_CON3 (0xC14)
#define RX_COMBO_S0D0_ANA_CON6 (0xC20)
#define RX_COMBO_S0D0_ANA_CON7 (0xC24)
#define RX_COMBO_S0D0_DESKEW_CON0 (0xC40)
#define RX_COMBO_S0D0_DESKEW_CON2 (0xC48)
#define RX_COMBO_S0D0_DESKEW_CON4 (0xC50)
#define RX_COMBO_S0D0_CRC_CON1 (0xC64)
#define RX_COMBO_S0D0_CRC_CON2 (0xC68)
#define RX_COMBO_S0D1_GNR_CON1 (0xD04)
#define RX_COMBO_S0D1_ANA_CON1 (0xD0c)
#define RX_COMBO_S0D1_ANA_CON2 (0xD10)
#define RX_COMBO_S0D1_ANA_CON3 (0xD14)
#define RX_COMBO_S0D1_ANA_CON6 (0xD20)
#define RX_COMBO_S0D1_ANA_CON7 (0xD24)
#define RX_COMBO_S0D1_DESKEW_CON0 (0xD40)
#define RX_COMBO_S0D1_DESKEW_CON2 (0xD48)
#define RX_COMBO_S0D1_DESKEW_CON4 (0xD50)
#define RX_COMBO_S0D1_CRC_CON1 (0xD64)
#define RX_COMBO_S0D1_CRC_CON2 (0xD68)
#define RX_COMBO_S0D2_GNR_CON1 (0xE04)
#define RX_COMBO_S0D2_ANA_CON1 (0xE0c)
#define RX_COMBO_S0D2_ANA_CON2 (0xE10)
#define RX_COMBO_S0D2_ANA_CON3 (0xE14)
#define RX_COMBO_S0D2_ANA_CON6 (0xE20)
#define RX_COMBO_S0D2_ANA_CON7 (0xE24)
#define RX_COMBO_S0D2_DESKEW_CON0 (0xE40)
#define RX_COMBO_S0D2_DESKEW_CON2 (0xE48)
#define RX_COMBO_S0D2_DESKEW_CON4 (0xE50)
#define RX_COMBO_S0D2_CRC_CON1 (0xE64)
#define RX_COMBO_S0D2_CRC_CON2 (0xE68)
#define RX_S0D3_GNR_CON1 (0xF04)
#define RX_S0D3_ANA_CON1 (0xF0c)
#define RX_S0D3_ANA_CON2 (0xF10)
#define RX_S0D3_ANA_CON3 (0xF14)
#define RX_S0D3_DESKEW_CON0 (0xF40)
#define RX_S0D3_DESKEW_CON2 (0xF48)
#define RX_S0D3_DESKEW_CON4 (0xF50)
#endif

View File

@@ -0,0 +1,73 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Rockchip Vehicle driver
*
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
*/
#ifndef _RKVEHICLE_VERSION_H
#define _RKVEHICLE_VERSION_H
#include <linux/version.h>
/*
*RKVEHICLE DRIVER VERSION NOTE
*
* V0.0X01.0X00 first version.
* 1. add support rk356x dvp/mipi fast vehicle reverse
* 2. add sample dvp interface sensor gc2145 for test
* 3. add sample mipi interface sensor nvp6314 one channel for test
* 4. fixup rga old/new format transform issue
* V0.0X01.0X01 fixup rga yuvtorgb transform issue
* V0.0X01.0X02 modify debug log issue
* V0.0X01.0X03 fix vehicle reverse close crash issue
* V0.0X01.0X04 fix vehicle reverse reopen not ok issue
* V0.0X01.0X05 fix after add hwc reserved plane patch, but not use reverse display issue.
* V0.0X01.0X06 fix reverse open/close probably stay in reverse preview issue.
* V0.0X01.0X07 rename function & remove deprecated code.
* V0.0X01.0X08 use Esmart0-win0 plane for vehicle, for Esmart1 depend on Esmart0 open first
* V0.0X01.0X09
* 1. fix vehicle plane zpos not update issue
* 2. use vop_drm_zpos 0x7 & not use drm_direct_disable_kernel_logo to fix kernel logo issue
* V0.0X01.0Xa
* 1. add cif output nv16 format to display support
* 2. use parameter vehicle_dump_data to control dump data
* V0.0X01.0Xb add cvbs in PAL/NTSC I format to mipi csi support
* V0.0X01.0Xc fix format switch split issue:
* such as: PAL/NTSC I format switch to 720P, cause split problem;
* V0.0X01.0Xd fix rk356x vehicle 1080P alloc_buffer_failed issue
* nvp6324 default use 1080p for test.
* V0.0X01.0Xe use dummy buffer when request buffer failed case
* fix flicker issue
* V0.0X01.0Xf set ddr scene to fix reverse sys stuck issue
* V0.0X02.0X0
* 1. add mipi csi2 hw soft reset
* 2. add ahd hot plug support, sample driver: vehicle_ad_nvp6324.c
* V0.0X02.0X1
* 1. support quit vehicle, switch to normal v4l2 driver
* 2. sample: vehicle_ad_nvp6324.c, vehicle_ad_gc2145.c
* 3. switch cmd: echo 88 > /dev/vehicle
* V0.0x02.0x2 support rk3588 csi2_dphy in kernel-5.10
* V0.0x02.0x3 support rk3588 csi2_dcphy
* V0.0x02.0x4 fix some rga3 ioctl and drm interface in kernel-5.10 for rk3588
* V0.0X02.0X5 support rk3588 dvp interface sensor
* V0.0X02.0X6 add dts phy_node to adapt different csi2_dphy or dvp sensor
* V0.0X02.0X7 adapt flinger driver to drm direct show interface
* V0.0X02.0X8 remove rockchip_ion falloc buf
* V0.0X02.0X9 fix RGA rotation error
* V0.0X02.0Xa add support MIPI CONTINUOUS CLOCK
* V0.0X02.0Xb add support config crtc and plane from dts
* 1.default crtc video_port3
* 2.default plane Esmart0-win0
* V0.0X02.0Xc remove some gpio unnecessary code
* V0.0X02.0Xd support samsung mipi_dcphy combo one driver
* V0.0X02.0Xe add GMSL to MIPI max96714 driver support
* V0.0X02.0Xf add nvp6188 driver support
* V0.0X03.0X00 update driver
* 1.fix some code errors
* 2.default palne Esmart3-win0
* 3.fix rotation parameters config from dts
* 4.add vehicle_version.h
*/
#endif