summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomasz Gorochowik <tgorochowik@antmicro.com>2016-03-09 16:44:50 +0100
committerMarcel Ziswiler <marcel.ziswiler@toradex.com>2016-11-21 15:05:09 +0100
commit0fc1465eef15c2e0704e38238a82017ca06928f5 (patch)
tree976c4c447d6a2cc67f40f5e4b11f3ab0d766c462
parent51e7588d8bc37af8d977da7a4ee1822692227647 (diff)
media: tc358743: update hdmi to csi-2 driver
A major part of the driver has been rewritten in order to avoid writing binary blobs to the chip. This version also adds support for more video modes. Input video modes supported: - 1920x1080 @ 60 - 1280x1024 @ 75 - 1280x720 @ 60 - 1024x768 @ 75 - 800x600 @ 75 - 640x480 @ 75 Acked-by: Marcel Ziswiler <marcel.ziswiler@toradex.com> Acked-by: Dominik Sliwa <dominik.sliwa@toradex.com>
-rw-r--r--arch/arm/mach-tegra/board-ardbeg-sensors.c2
-rw-r--r--drivers/media/i2c/soc_camera/tc358743.c1320
2 files changed, 701 insertions, 621 deletions
diff --git a/arch/arm/mach-tegra/board-ardbeg-sensors.c b/arch/arm/mach-tegra/board-ardbeg-sensors.c
index 420e5f4cc2f2..da0c4ad5b995 100644
--- a/arch/arm/mach-tegra/board-ardbeg-sensors.c
+++ b/arch/arm/mach-tegra/board-ardbeg-sensors.c
@@ -464,7 +464,7 @@ static struct tegra_camera_platform_data ardbeg_tc358743_camera_platform_data =
.flip_h = 0,
.port = TEGRA_CAMERA_PORT_CSI_A,
.lanes = 2,
- .continuous_clk = 0,
+ .continuous_clk = 1,
};
static struct soc_camera_link tc358743_iclink = {
diff --git a/drivers/media/i2c/soc_camera/tc358743.c b/drivers/media/i2c/soc_camera/tc358743.c
index ba0633b78b55..7a63b1ec019a 100644
--- a/drivers/media/i2c/soc_camera/tc358743.c
+++ b/drivers/media/i2c/soc_camera/tc358743.c
@@ -1,6 +1,8 @@
/*
* based on OV5640 driver and TC358743 driver for i.MX6
*
+ * author: Antmicro Ltd
+ *
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
@@ -22,10 +24,333 @@
#include <media/v4l2-chip-ident.h>
#include <media/soc_camera.h>
+#define PLLCTL0 0x0020
+#define PLLCTL1 0x0022
+
+#define MASK_PLL_PRD 0xf000
+#define SET_PLL_PRD(prd) ((((prd) - 1) << 12) & MASK_PLL_PRD)
+
+#define MASK_PLL_FBD 0x01ff
+#define SET_PLL_FBD(fbd) (((fbd) - 1) & MASK_PLL_FBD)
+
+#define MASK_CKEN 0x0010
+#define MASK_RESETB 0x0002
+#define MASK_PLL_EN 0x0001
+
+#define MASK_NOL_1 0
+#define MASK_NOL_2 2
+#define MASK_NOL_3 4
+#define MASK_NOL_4 6
+
+/* this is true for 27 MHz refclk */
+#define REFCLK_PRE_DIVIDER 9
+#define SET_PLL_FREQ(x) (SET_PLL_PRD(REFCLK_PRE_DIVIDER) | SET_PLL_FBD(DIV_ROUND_UP(x,3)))
+
+#define FRS_BW_25 0x0
+#define FRS_BW_33 0x1
+#define FRS_BW_50 0x2
+#define FRS_BW_MAX 0x3
+
+#define MASK_PLL_FRS 0x0f00
+#define SET_PLL_FRS(frs,bw) (((frs | bw) << 8) & MASK_PLL_FRS)
+#define GET_FRS(x) (x < 125) ? 0xC : (x < 250) ? 0x8 : (x < 500) ? 0x4 : 0x0
+
+#define HCNT_MASK 0x3f
+#define CALC_HDR_CNT(prep, zero) ((zero & HCNT_MASK) << 8) | (prep & HCNT_MASK)
+
+#define SYS_STATUS 0x8520
+#define CSI_STATUS 0x0410
+#define MASK_S_WSYNC 0x0400
+#define VI_STATUS0 0x8521
+#define VI_STATUS1 0x8522
+#define AU_STATUS0 0x8523
+#define VI_STATUS2 0x8525
+#define VI_STATUS3 0x8528
+
+#define EDID_MODE 0x85C7
+#define MASK_EDID_SPEED 0x40
+#define MASK_EDID_MODE 0x03
+#define MASK_EDID_MODE_DISABLE 0x00
+#define MASK_EDID_MODE_DDC2B 0x01
+#define MASK_EDID_MODE_E_DDC 0x02
+#define EDID_LEN1 0x85CA
+#define EDID_LEN2 0x85CB
+
+
+#define SYSCTL 0x0002
+#define CONFCTL 0x0004
+#define MASK_AUTOINDEX 0x0004
+#define FIFOCTL 0x0006
+#define INTSTATUS 0x0014
+#define INTMASK 0x0016
+#define PHY_RST 0x8535
+#define MASK_RESET_CTRL 0x01 /* Reset active low */
+
+#define HPD_CTL 0x8544
+#define MASK_HPD_CTL0 0x10
+#define MASK_HPD_OUT0 0x01
+
+#define BKSV 0x8800
+
+#define CSI_CONFW 0x0500
+#define MASK_MODE_SET 0xa0000000
+#define MASK_ADDRESS_CSI_CONTROL 0x03000000
+#define MASK_CSI_MODE 0x8000
+#define MASK_HTXTOEN 0x0400
+#define MASK_TXHSMD 0x0080
+#define MASK_HSCKMD 0x0020
+#define HSTXVREGEN 0x0234
+#define TXOPTIONCNTRL 0x0238
+#define MASK_CONTCLKMODE 0x00000001
+#define STARTCNTRL 0x0204
+#define MASK_START 0x00000001
+#define CLW_CNTRL 0x0140
+#define MASK_CLW_LANEDISABLE 0x0001
+
+#define D0W_CNTRL 0x0144
+#define MASK_D0W_LANEDISABLE 0x0001
+
+#define D1W_CNTRL 0x0148
+#define MASK_D1W_LANEDISABLE 0x0001
+
+#define D2W_CNTRL 0x014C
+#define MASK_D2W_LANEDISABLE 0x0001
+
+#define D3W_CNTRL 0x0150
+#define MASK_D3W_LANEDISABLE 0x0001
+
+#define LINEINITCNT 0x0210
+#define LPTXTIMECNT 0x0214
+#define TCLK_HEADERCNT 0x0218
+#define TCLK_TRAILCNT 0x021C
+#define THS_HEADERCNT 0x0220
+#define TWAKEUP 0x0224
+#define TCLK_POSTCNT 0x0228
+#define THS_TRAILCNT 0x022C
+
+#define CSI_START 0x0518
+#define MASK_STRT 0x00000001
+
+#define PHY_CTL1 0x8532
+#define PHY_CTL2 0x8533 /* Not in REF_01 */
+#define PHY_BIAS 0x8536 /* Not in REF_01 */
+#define PHY_CSQ 0x853F /* Not in REF_01 */
+#define DDC_CTL 0x8543
+
+#define SYS_FREQ0 0x8540
+#define SYS_FREQ1 0x8541
+
+#define NCO_F0_MOD 0x8670
+#define MASK_NCO_F0_MOD_27MHZ 0x01
+
+
+#define LOCKDET_REF0 0x8630
+#define LOCKDET_REF1 0x8631
+#define LOCKDET_REF2 0x8632
+
+#define SYS_INT 0x8502
+#define MASK_I_DDC 0x01
+#define SYS_INTM 0x8512
+#define PACKET_INTM 0x8514
+#define CBIT_INTM 0x8515
+#define AUDIO_INTM 0x8516
+#define PHY_CTL0 0x8531
+#define MASK_PHY_CTL 0x01
+#define ANA_CTL 0x8545
+#define MASK_APPL_PCSX 0x30
+#define MASK_APPL_PCSX_NORMAL 0x30
+
+#define MASK_ANALOG_ON 0x01
+
+
+#define AVM_CTL 0x8546
+
+
+#define MASK_PHY_AUTO_RST4 0x04
+#define MASK_PHY_AUTO_RST3 0x02
+#define MASK_PHY_AUTO_RST2 0x01
+
+#define VOUT_SET2 0x8573
+#define MASK_VOUT_422FIL_100 0x40
+#define MASK_SEL422 0x80
+#define MASK_VOUTCOLORMODE_AUTO 0x01
+#define MASK_VOUTCOLORMODE_THROUGH 0x00
+#define MASK_VOUTCOLORMODE_MANUAL 0x03
+
+#define VOUT_SET3 0x8574
+#define MASK_VOUT_EXTCNT 0x08
+
+#define PK_INT_MODE 0x8709
+#define NO_PKT_LIMIT 0x870B
+#define NO_PKT_CLR 0x870C
+#define ERR_PK_LIMIT 0x870D
+#define NO_GDB_LIMIT 0x9007
+#define NO_PKT_LIMIT2 0x870E
+
+#define INIT_END 0x854A
+#define MASK_INIT_END 0x01
+
+
+#define HDCP_MODE 0x8560
+#define HDCP_REG1 0x8563
+#define HDCP_REG2 0x8564
+#define HDCP_REG3 0x85D1
+
+#define EDID_LEN2 0x85CB
+#define EDID_MODE 0x85C7
+
+#define FH_MIN0 0x85AA
+#define FH_MIN1 0x85AB
+#define FH_MAX0 0x85AC
+#define FH_MAX1 0x85AD
+
+#define DE_WIDTH_H_LO 0x8582
+#define DE_WIDTH_H_HI 0x8583
+#define DE_WIDTH_V_LO 0x8588
+#define DE_WIDTH_V_HI 0x8589
+#define H_SIZE_LO 0x858A
+#define H_SIZE_HI 0x858B
+#define V_SIZE_LO 0x858C
+#define V_SIZE_HI 0x858D
+#define FV_CNT_LO 0x85A1
+#define FV_CNT_HI 0x85A2
+
+
+#define MASK_IRRST 0x0800
+#define MASK_CECRST 0x0400
+#define MASK_CTXRST 0x0200
+#define MASK_HDMIRST 0x0100
+
+#define MASK_AUDCHNUM_2 0x0c00
+#define MASK_AUTOINDEX 0x0004
+#define MASK_ABUFEN 0x0002
+#define MASK_VBUFEN 0x0001
+#define MASK_AUDOUTSEL_I2S 0x0010
+
+#define MASK_YCBCRFMT 0x00c0
+
+#define MASK_YCBCRFMT_422_12_BIT 0x0040
+#define MASK_YCBCRFMT_COLORBAR 0x0080
+#define MASK_YCBCRFMT_422_8_BIT 0x00c0
+
+#define MASK_YCBCRFMT_444 0x0000
+
+#define MASK_INFRMEN 0x0020
+#define PHY_EN 0x8534
+#define MASK_ENABLE_PHY 0x01
+
+#define MASK_PWRISO 0x8000
+
+#define VI_MODE 0x8570
+#define MASK_RGB_DVI 0x8
+
+#define VI_REP 0x8576
+#define MASK_VOUT_COLOR_SEL 0xe0
+#define MASK_VOUT_COLOR_RGB_FULL 0x00
+#define MASK_VOUT_COLOR_RGB_LIMITED 0x20
+#define MASK_VOUT_COLOR_601_YCBCR_FULL 0x40
+#define MASK_VOUT_COLOR_601_YCBCR_LIMITED 0x60
+#define MASK_VOUT_COLOR_709_YCBCR_FULL 0x80
+#define MASK_VOUT_COLOR_709_YCBCR_LIMITED 0xa0
+#define MASK_VOUT_COLOR_FULL_TO_LIMITED 0xc0
+#define MASK_VOUT_COLOR_LIMITED_TO_FULL 0xe0
+#define MASK_IN_REP_HEN 0x10
+#define MASK_IN_REP 0x0f
+
+/* status regs */
+#define SYS_STATUS 0x8520
+#define MASK_S_SYNC 0x80
+#define MASK_S_AVMUTE 0x40
+#define MASK_S_HDCP 0x20
+#define MASK_S_HDMI 0x10
+#define MASK_S_PHY_SCDT 0x08
+#define MASK_S_PHY_PLL 0x04
+#define MASK_S_TMDS 0x02
+#define MASK_S_DDC5V 0x01
+#define CSI_STATUS 0x0410
+#define MASK_S_WSYNC 0x0400
+#define MASK_S_TXACT 0x0200
+#define MASK_S_RXACT 0x0100
+#define MASK_S_HLT 0x0001
+#define VI_STATUS1 0x8522
+#define MASK_S_V_GBD 0x08
+#define MASK_S_DEEPCOLOR 0x0c
+#define MASK_S_V_422 0x02
+#define MASK_S_V_INTERLACE 0x01
+#define AU_STATUS0 0x8523
+#define MASK_S_A_SAMPLE 0x01
+#define VI_STATUS3 0x8528
+#define MASK_S_V_COLOR 0x1e
+#define MASK_LIMITED 0x01
+
+#define HDMI_DET 0x8552 /* Not in REF_01 */
+#define MASK_HDMI_DET_MOD1 0x80
+#define MASK_HDMI_DET_MOD0 0x40
+#define MASK_HDMI_DET_V 0x30
+#define MASK_HDMI_DET_V_SYNC 0x00
+#define MASK_HDMI_DET_V_ASYNC_25MS 0x10
+#define MASK_HDMI_DET_V_ASYNC_50MS 0x20
+#define MASK_HDMI_DET_V_ASYNC_100MS 0x30
+#define MASK_HDMI_DET_NUM 0x0f
+
+#define HV_RST 0x85AF /* Not in REF_01 */
+#define MASK_H_PI_RST 0x20
+#define MASK_V_PI_RST 0x10
+
+#define MASK_DDC5V_MODE_100MS 2
+
+#define VI_MUTE 0x857F
+#define MASK_AUTO_MUTE 0xc0
+#define MASK_VI_MUTE 0x10
+
+#define FORCE_MUTE 0x8600
+#define MASK_FORCE_AMUTE 0x10
+
+#define BCAPS 0x8840
+#define BSTATUS1 0x8842
+
+#define MASK_MAX_EXCED 0x08
+#define MASK_REPEATER 0x40
+#define MASK_READY 0x20
+
+#define MASK_HDMI_RSVD 0x80
+
+#define VOUT_SET0 0x8571
+#define VOUT_SET1 0x8572
+
+#define CMD_AUD 0x8601
+#define MASK_CMD_BUFINIT 0x04
+#define MASK_CMD_LOCKDET 0x02
+#define MASK_CMD_MUTE 0x01
+
+#define MASK_FORCE_DMUTE 0x01
+
+#define ERR_PK_LIMIT 0x870D
+#define NO_PKT_LIMIT2 0x870E
+#define PK_AVI_0HEAD 0x8710
+#define PK_AVI_1HEAD 0x8711
+#define PK_AVI_2HEAD 0x8712
+#define PK_AVI_0BYTE 0x8713
+#define PK_AVI_1BYTE 0x8714
+#define PK_AVI_2BYTE 0x8715
+#define PK_AVI_3BYTE 0x8716
+#define PK_AVI_4BYTE 0x8717
+#define PK_AVI_5BYTE 0x8718
+#define PK_AVI_6BYTE 0x8719
+#define PK_AVI_7BYTE 0x871A
+#define PK_AVI_8BYTE 0x871B
+#define PK_AVI_9BYTE 0x871C
+#define PK_AVI_10BYTE 0x871D
+#define PK_AVI_11BYTE 0x871E
+#define PK_AVI_12BYTE 0x871F
+#define PK_AVI_13BYTE 0x8720
+#define PK_AVI_14BYTE 0x8721
+#define PK_AVI_15BYTE 0x8722
+#define PK_AVI_16BYTE 0x8723
+
struct reg_value {
u16 addr;
u32 val;
- u8 len;
u32 flags;
};
@@ -52,557 +377,177 @@ tc358743_read_reg_size [] =
{0, 0, 0},
};
-static struct reg_value tc358743_setting_YUV422_2lane_color_bar_640_480_174MHz[] = {
- {0x7080, 0x00000000, 2, 0},
- {0x0002, 0x00000f00, 2, 100},
- {0x0002, 0x00000000, 2, 1000},
- {0x0006, 0x00000000, 2, 0},
- {0x0004, 0x00000084, 2, 0},
- {0x0010, 0x0000001e, 2, 0},
-// Program CSI Tx PLL
- {0x0020, 0x00008073, 2, 0},
- {0x0022, 0x00000213, 2, 0},
-// CSI Tx PHY (32-bit Registers)
- {0x0140, 0x00000000, 4, 0},
- {0x0144, 0x00000000, 4, 0},
- {0x0148, 0x00000000, 4, 0},
-// {0x014c, 0x00000000, 0x00000000, 4, 0},
-// {0x0150, 0x00000000, 0x00000000, 4, 0},
-// CSI Tx PPI (32-bit Registers)
- {0x0210, 0x00001200, 4, 0},
- {0x0214, 0x00000002, 4, 0},
- {0x0218, 0x00000b02, 4, 0},
- {0x021c, 0x00000001, 4, 0},
- {0x0220, 0x00000103, 4, 0},
- {0x0224, 0x00004000, 4, 0},
- {0x0228, 0x00000008, 4, 0},
- {0x022c, 0x00000002, 4, 0},
- {0x0234, 0x0000001f, 4, 0},
- {0x0238, 0x00000000, 4, 0},
- {0x0204, 0x00000001, 4, 0},
- {0x0518, 0x00000001, 4, 0},
- {0x0500, 0xA3008082, 4, 0},
-// 640x480 colorbar
- {0x000a, 0x00000500, 2, 0},
- {0x7080, 0x00000082, 2, 0},
-// 80 pixel black - repeate 80 times
- {0x7000, 0x0000007f, 2, (1<<24)|(80<<16)},
-// 80 pixel blue - repeate 40 times
- {0x7000, 0x000000ff, 2, 0},
- {0x7000, 0x00000000, 2, (2<<24)|(40<<16)},
-// 80 pixel red - repeate 40 times
- {0x7000, 0x00000000, 2, 0},
- {0x7000, 0x000000ff, 2, (2<<24)|(40<<16)},
-// 80 pixel pink - repeate 40 times
- {0x7000, 0x00007fff, 2, 0},
- {0x7000, 0x00007fff, 2, (2<<24)|(40<<16)},
-// 80 pixel green - repeate 40 times
- {0x7000, 0x00007f00, 2, 0},
- {0x7000, 0x00007f00, 2, (2<<24)|(40<<16)},
-// 80 pixel light blue - repeate 40 times
- {0x7000, 0x0000c0ff, 2, 0},
- {0x7000, 0x0000c000, 2, (2<<24)|(40<<16)},
-// 80 pixel yellow - repeate 40 times
- {0x7000, 0x0000ff00, 2, 0},
- {0x7000, 0x0000ffff, 2, (2<<24)|(40<<16)},
-// 80 pixel white - repeate 40 times
- {0x7000, 0x0000ff7f, 2, 0},
- {0x7000, 0x0000ff7f, 2, (2<<24)|(40<<16)},
-// 480 lines
- {0x7090, 0x000001df, 2, 0},
- {0x7092, 0x00000898, 2, 0},
- {0x7094, 0x00000285, 2, 0},
- {0x7080, 0x00000083, 2, 0},
-};
+typedef struct timings_regs {
+ uint32_t frequency;
+ uint32_t line_init_cnt;
+ uint32_t tlpx_time_cnt;
+
+ uint32_t tclk_prepare_cnt;
+ uint32_t tclk_zero_cnt;
+
+ uint32_t tclk_trail_cnt; /* Don't care in continous clk mode */
+
+ uint32_t ths_prepare_cnt;
+ uint32_t ths_zero_cnt;
+
+ uint32_t twakeup_cnt;
+ uint32_t tclk_post_cnt; /* Don't care in continous clk mode */
+
+ uint32_t ths_trail_cnt;
-static struct reg_value tc358743_setting_YUV422_2lane_60fps_640_480_125Mhz[] = {
- {0x7080, 0x00000000, 2, 0},
- {0x0004, 0x00000004, 2, 0},
- {0x0002, 0x00000f00, 2, 100},
- {0x0002, 0x00000000, 2, 1000},
- {0x0006, 0x00000040, 2, 0},
-// {0x000a, 0x000005a0, 0x00000000, 2, 0},
-// {0x0010, 0x0000001e, 0x00000000, 2, 0},
- {0x0014, 0x00000000, 2, 0},
- {0x0016, 0x000005ff, 2, 0},
-// Program CSI Tx PLL
- {0x0020, 0x0000405c, 2, 0},
- {0x0022, 0x00000613, 2, 0},
-// CSI Tx PHY (32-bit Registers)
- {0x0140, 0x00000000, 4, 0},
- {0x0144, 0x00000000, 4, 0},
- {0x0148, 0x00000000, 4, 0},
- {0x014c, 0x00000000, 4, 0},
- {0x0150, 0x00000000, 4, 0},
-// CSI Tx PPI (32-bit Registers)
- {0x0210, 0x00000d00, 4, 0},
- {0x0214, 0x00000001, 4, 0},
- {0x0218, 0x00000701, 4, 0},
- {0x021c, 0x00000000, 4, 0},
- {0x0220, 0x00000001, 4, 0},
- {0x0224, 0x00004000, 4, 0},
- {0x0228, 0x00000005, 4, 0},
- {0x022c, 0x00000000, 4, 0},
- {0x0234, 0x0000001f, 4, 0},
- {0x0238, 0x00000000, 4, 0}, //gated clock
- {0x0204, 0x00000001, 4, 0},
- {0x0518, 0x00000001, 4, 0},
- {0x0500, 0xA30080A2, 4, 0},
-// HDMI Interrupt Mask
- {0x8502, 0x00000001, 1, 0},
- {0x8512, 0x000000fe, 1, 0},
- {0x8514, 0x00000000, 1, 0},
- {0x8515, 0x00000000, 1, 0},
- {0x8516, 0x00000000, 1, 0},
-// HDMI Audio RefClk (26 MHz)
- {0x8531, 0x00000001, 1, 0},
- {0x8540, 0x00000a8c, 1, 0},
- {0x8630, 0x00041eb0, 1, 0},
- {0x8670, 0x00000001, 1, 0},
-// HDMI PHY
- {0x8532, 0x00000080, 1, 0},
- {0x8536, 0x00000040, 1, 0},
- {0x853f, 0x0000000a, 1, 0},
-// HDMI System
- {0x8543, 0x00000032, 1, 0},
- {0x8544, 0x00000000, 1, 100},
-// {0x8544, 0x00000001, 0x00000000, 1, 100},
- {0x8545, 0x00000031, 1, 0},
- {0x8546, 0x0000002d, 1, 0},
-// EDID
- {0x85c7, 0x00000001, 1, 0},
- {0x85cb, 0x00000001, 1, 0},
-// HDCP Setting
- {0x85d1, 0x00000001, 1, 0},
- {0x8560, 0x00000024, 1, 0},
- {0x8563, 0x00000011, 1, 0},
- {0x8564, 0x0000000f, 1, 0},
-// RGB --> YUV Conversion
- {0x8573, 0x00000081, 1, 0},
- {0x8571, 0x00000002, 1, 0},
-// HDMI Audio In Setting
- {0x8600, 0x00000000, 1, 0},
- {0x8602, 0x000000f3, 1, 0},
- {0x8603, 0x00000002, 1, 0},
- {0x8604, 0x0000000c, 1, 0},
- {0x8606, 0x00000005, 1, 0},
- {0x8607, 0x00000000, 1, 0},
- {0x8620, 0x00000022, 1, 0},
- {0x8640, 0x00000001, 1, 0},
- {0x8641, 0x00000065, 1, 0},
- {0x8642, 0x00000007, 1, 0},
- {0x8652, 0x00000002, 1, 0},
- {0x8665, 0x00000010, 1, 0},
-// InfoFrame Extraction
- {0x8709, 0x000000ff, 1, 0},
- {0x870b, 0x0000002c, 1, 0},
- {0x870c, 0x00000053, 1, 0},
- {0x870d, 0x00000001, 1, 0},
- {0x870e, 0x00000030, 1, 0},
- {0x9007, 0x00000010, 1, 0},
- {0x854a, 0x00000001, 1, 0},
-// Output Control
- {0x0004, 0x00000cf7, 2, 0},
- };
-
-static struct reg_value tc358743_setting_YUV422_2lane_color_bar_1280_720_125MHz[] = {
- {0x7080, 0x00000000, 2, 0},
- {0x0002, 0x00000f00, 2, 100},
- {0x0002, 0x00000000, 2, 1000},
- {0x0006, 0x00000000, 2, 0},
- {0x0004, 0x00000084, 2, 0},
- {0x0010, 0x0000001e, 2, 0},
-// Program CSI Tx PLL
- {0x0020, 0x0000405c, 2, 0},
- {0x0022, 0x00000613, 2, 0},
-// CSI Tx PHY (32-bit Registers)
- {0x0140, 0x00000000, 4, 0},
- {0x0144, 0x00000000, 4, 0},
- {0x0148, 0x00000000, 4, 0},
- {0x014c, 0x00000000, 4, 0},
- {0x0150, 0x00000000, 4, 0},
-// CSI Tx PPI (32-bit Registers)
- {0x0210, 0x00000e00, 4, 0},
- {0x0214, 0x00000001, 4, 0},
- {0x0218, 0x00000801, 4, 0},
- {0x021c, 0x00000000, 4, 0},
- {0x0220, 0x00000001, 4, 0},
- {0x0224, 0x00004000, 4, 0},
- {0x0228, 0x00000006, 4, 0},
- {0x022c, 0x00000000, 4, 0},
- {0x0234, 0x00000007, 4, 0},
- {0x0238, 0x00000000, 4, 0},
- {0x0204, 0x00000001, 4, 0},
- {0x0518, 0x00000001, 4, 0},
- {0x0500, 0xa30080a2, 4, 0},
-// 1280x720 colorbar
- {0x000a, 0x00000a00, 2, 0},
- {0x7080, 0x00000082, 2, 0},
-// 128 pixel black - repeat 128 times
- {0x7000, 0x0000007f, 2, (1<<24)|(128<<16)},
-// 128 pixel blue - repeat 64 times
- {0x7000, 0x000000ff, 2, 0},
- {0x7000, 0x00000000, 2, (2<<24)|(64<<16)},
-// 128 pixel red - repeat 64 times
- {0x7000, 0x00000000, 2, 0},
- {0x7000, 0x000000ff, 2, (2<<24)|(64<<16)},
-// 128 pixel pink - repeat 64 times
- {0x7000, 0x00007fff, 2, 0},
- {0x7000, 0x00007fff, 2, (2<<24)|(64<<16)},
-// 128 pixel green - repeat 64 times
- {0x7000, 0x00007f00, 2, 0},
- {0x7000, 0x00007f00, 2, (2<<24)|(64<<16)},
-// 128 pixel light blue - repeat 64 times
- {0x7000, 0x0000c0ff, 2, 0},
- {0x7000, 0x0000c000, 2, (2<<24)|(64<<16)},
-// 128 pixel yellow - repeat 64 times
- {0x7000, 0x0000ff00, 2, 0},
- {0x7000, 0x0000ffff, 2, (2<<24)|(64<<16)},
-// 128 pixel white - repeat 64 times
- {0x7000, 0x0000ff7f, 2, 0},
- {0x7000, 0x0000ff7f, 2, (2<<24)|(64<<16)},
-// 720 lines
- {0x7090, 0x000002cf, 2, 0},
- {0x7092, 0x00000580, 2, 0},
- {0x7094, 0x00000010, 2, 0},
- {0x7080, 0x00000083, 2, 0},
+ uint32_t fifo_delay;
+} timings_regs;
+
+timings_regs timings[] = {
+ /* 640x480 @ 75 */
+ { 500, 3328, 1, 1, 7, 0, 1, 0, 16384, 5, 0, 256},
+ /* 800x600 @ 75 */
+ { 594, 3712, 3, 3, 20, 0, 3, 1, 18562, 8, 2, 180},
+ /* 1024x768 @ 75 */
+ { 600, 7689, 3, 2, 20, 0, 3, 0, 18944, 8, 2, 128},
+ /* 1280x720 @ 60 */
+ { 825, 5160, 5, 4, 29, 0, 5, 5, 18000, 0, 4, 180},
+ /* 1280x1024 @ 75 and 1920x1080 @ 60 */
+ { 1075, 6000, 5, 4, 29, 0, 5, 80, 18000, 0, 4, 256},
+ {},
};
-#if 0
-static struct reg_value tc358743_setting_YUV422_2lane_30fps_720P_1280_720_125MHz[] = {
- {0x7080, 0x00000000, 2, 0},
- {0x0004, 0x00000004, 2, 0},
- {0x0002, 0x00000f00, 2, 100},
- {0x0002, 0x00000000, 2, 1000},
- {0x0006, 0x00000040, 2, 0},
- {0x0014, 0x00000000, 2, 0},
- {0x0016, 0x000005ff, 2, 0},
-// Program CSI Tx PLL
- {0x0020, 0x0000402d, 2, 0},
- {0x0022, 0x00000213, 2, 0},
-// CSI Tx PHY (32-bit Registers)
- {0x0140, 0x00000000, 4, 0},
- {0x0144, 0x00000000, 4, 0},
- {0x0148, 0x00000000, 4, 0},
- {0x014c, 0x00000000, 4, 0},
- {0x0150, 0x00000000, 4, 0},
-// CSI Tx PPI (32-bit Registers)
- {0x0210, 0x00000e00, 4, 0},
- {0x0214, 0x00000001, 4, 0},
- {0x0218, 0x00000801, 4, 0},
- {0x021c, 0x00000001, 4, 0},
- {0x0220, 0x00000001, 4, 0},
- {0x0224, 0x00004800, 4, 0},
- {0x0228, 0x00000005, 4, 0},
- {0x022c, 0x00000000, 4, 0},
- {0x0234, 0x0000001f, 4, 0},
- {0x0238, 0x00000000, 4, 0}, //non-continuous clock
- {0x0204, 0x00000001, 4, 0},
- {0x0518, 0x00000001, 4, 0},
- {0x0500, 0xa300be82, 4, 0},
-// HDMI Interrupt Mask
- {0x8502, 0x00000001, 1, 0},
- {0x8512, 0x000000fe, 1, 0},
- {0x8514, 0x00000000, 1, 0},
- {0x8515, 0x00000000, 1, 0},
- {0x8516, 0x00000000, 1, 0},
-// HDMI Audio RefClk (26 MHz)
- {0x8531, 0x00000001, 1, 0},
- {0x8540, 0x0000008c, 1, 0},
- {0x8541, 0x0000000a, 1, 0},
- {0x8630, 0x000000b0, 1, 0},
- {0x8631, 0x0000001e, 1, 0},
- {0x8632, 0x00000004, 1, 0},
- {0x8670, 0x00000001, 1, 0},
-// HDMI PHY
- {0x8532, 0x00000080, 1, 0},
- {0x8536, 0x00000040, 1, 0},
- {0x853f, 0x0000000a, 1, 0},
-// EDID
- {0x85c7, 0x00000001, 1, 0},
- {0x85cb, 0x00000001, 1, 0},
-// HDMI System
- {0x8543, 0x00000032, 1, 0},
-// {0x8544, 0x00000000, 0x00000000, 1, 1000},
-// {0x8544, 0x00000001, 0x00000000, 1, 100},
- {0x8545, 0x00000031, 1, 0},
- {0x8546, 0x0000002d, 1, 0},
-// HDCP Setting
- {0x85d1, 0x00000001, 1, 0},
- {0x8560, 0x00000024, 1, 0},
- {0x8563, 0x00000011, 1, 0},
- {0x8564, 0x0000000f, 1, 0},
-// Video settings
- {0x8573, 0x00000081, 1, 0},
- {0x8571, 0x00000002, 1, 0},
-// HDMI Audio In Setting
- {0x8600, 0x00000000, 1, 0},
- {0x8602, 0x000000f3, 1, 0},
- {0x8603, 0x00000002, 1, 0},
- {0x8604, 0x0000000c, 1, 0},
- {0x8606, 0x00000005, 1, 0},
- {0x8607, 0x00000000, 1, 0},
- {0x8620, 0x00000022, 1, 0},
- {0x8640, 0x00000001, 1, 0},
- {0x8641, 0x00000065, 1, 0},
- {0x8642, 0x00000007, 1, 0},
-// {0x8651, 0x00000003, 0x00000000, 1, 0}, // Inverted LRCK polarity - (Sony) format
- {0x8652, 0x00000002, 1, 0}, // Left-justified I2S (Phillips) format
-// {0x8652, 0x00000000, 0x00000000, 1, 0}, // Right-justified (Sony) format
- {0x8665, 0x00000010, 1, 0},
-// InfoFrame Extraction
- {0x8709, 0x000000ff, 1, 0},
- {0x870b, 0x0000002c, 1, 0},
- {0x870c, 0x00000053, 1, 0},
- {0x870d, 0x00000001, 1, 0},
- {0x870e, 0x00000030, 1, 0},
- {0x9007, 0x00000010, 1, 0},
- {0x854a, 0x00000001, 1, 0},
-// Output Control
- {0x0004, 0x00000cf7, 2, 0},
- };
-#endif
-
-static struct reg_value tc358743_setting_YUV422_4lane_1080P_60fps_1920_1080_300MHz[] = {
- {0x7080, 0x00000000, 2, 0},
- {0x0004, 0x00000084, 2, 0},
- {0x0002, 0x00000f00, 2, 100},//0},
- {0x0002, 0x00000000, 2, 1000},//0},
- {0x0006, 0x00000000, 2, 0},
- {0x0014, 0x00000000, 2, 0},
- {0x0016, 0x000005ff, 2, 0},
-// Program CSI Tx PLL
- {0x0020, 0x000080c7, 2, 0},
- {0x0022, 0x00000213, 2, 0},
-// CSI Tx PHY (32-bit Registers)
- {0x0140, 0x00000000, 4, 0},
- {0x0144, 0x00000000, 4, 0},
- {0x0148, 0x00000000, 4, 0},
- {0x014c, 0x00000000, 4, 0},
- {0x0150, 0x00000000, 4, 0},
-// CSI Tx PPI (32-bit Registers)
- {0x0210, 0x00001e00, 4, 0},
- {0x0214, 0x00000003, 4, 0},
- {0x0218, 0x00001402, 4, 0},
- {0x021c, 0x00000000, 4, 0},
- {0x0220, 0x00000003, 4, 0},
- {0x0224, 0x00004a00, 4, 0},
- {0x0228, 0x00000008, 4, 0},
- {0x022c, 0x00000002, 4, 0},
- {0x0234, 0x0000001f, 4, 0},
- {0x0238, 0x00000000, 4, 0},
- {0x0204, 0x00000001, 4, 0},
- {0x0518, 0x00000001, 4, 0},
- {0x0500, 0xa30080a6, 4, 0},
-// HDMI Interrupt Mask
- {0x8502, 0x00000001, 1, 0},
- {0x8512, 0x000000fe, 1, 0},
- {0x8514, 0x00000000, 1, 0},
- {0x8515, 0x00000000, 1, 0},
- {0x8516, 0x00000000, 1, 0},
-// HDMI Audio RefClk (27 MHz)
- {0x8531, 0x00000001, 1, 0},
- {0x8540, 0x00000a8c, 1, 0},
- {0x8630, 0x00041eb0, 1, 0},
- {0x8670, 0x00000001, 1, 0},
-// HDMI PHY
- {0x8532, 0x00000080, 1, 0},
- {0x8536, 0x00000040, 1, 0},
- {0x853f, 0x0000000a, 1, 0},
-// HDMI System
- {0x8543, 0x00000032, 1, 0},
- {0x8544, 0x00000010, 1, 100},
- {0x8545, 0x00000031, 1, 0},
- {0x8546, 0x0000002d, 1, 0},
-// EDID
- {0x85c7, 0x00000001, 1, 0},
- {0x85cb, 0x00000001, 1, 0},
-// HDCP Setting
- {0x85d1, 0x00000001, 1, 0},
- {0x8560, 0x00000024, 1, 0},
- {0x8563, 0x00000011, 1, 0},
- {0x8564, 0x0000000f, 1, 0},
-// RGB --> YUV Conversion
- {0x8571, 0x00000002, 1, 0},
- {0x8573, 0x00000081, 1, 0},
- {0x8576, 0x00000060, 1, 0},
-// HDMI Audio In Setting
- {0x8600, 0x00000000, 1, 0},
- {0x8602, 0x000000f3, 1, 0},
- {0x8603, 0x00000002, 1, 0},
- {0x8604, 0x0000000c, 1, 0},
- {0x8606, 0x00000005, 1, 0},
- {0x8607, 0x00000000, 1, 0},
- {0x8620, 0x00000022, 1, 0},
- {0x8640, 0x00000001, 1, 0},
- {0x8641, 0x00000065, 1, 0},
- {0x8642, 0x00000007, 1, 0},
- {0x8652, 0x00000002, 1, 0},
- {0x8665, 0x00000010, 1, 0},
-// InfoFrame Extraction
- {0x8709, 0x000000ff, 1, 0},
- {0x870b, 0x0000002c, 1, 0},
- {0x870c, 0x00000053, 1, 0},
- {0x870d, 0x00000001, 1, 0},
- {0x870e, 0x00000030, 1, 0},
- {0x9007, 0x00000010, 1, 0},
- {0x854a, 0x00000001, 1, 0},
-// Output Control
- {0x0004, 0x00000cf7, 2, 0},
+static struct reg_value tc358743_reset[] = {
+ {CONFCTL, 0, 100},
+
+ {PHY_RST, 0x0, 100},
+ {PHY_RST, 0x1, 100},
+ {PHY_EN, 0, 100},
+ {PHY_EN, 1, 100},
+
+ /* reset */
+ {SYSCTL, MASK_IRRST | MASK_CECRST | MASK_CTXRST | MASK_HDMIRST, 100},
+ {SYSCTL, 0x00000000, 1000},
+
+ /* set ref frequency to 27 MHz */
+ {SYS_FREQ0, (2700) & 0xFF, 0},
+ {SYS_FREQ1, (2700 >> 8) & 0xFF, 0},
+
+ {LOCKDET_REF0, (270000) & 0xFF, 0},
+ {LOCKDET_REF1, (270000 >> 8) & 0xFF, 0},
+ {LOCKDET_REF2, (270000 >> 16) & 0xFF, 0},
+ {FH_MIN0, (270) & 0xFF, 0},
+ {FH_MIN1, (270 >> 8) & 0xFF, 0},
+ {FH_MAX0, (27 * 66) & 0xFF, 0},
+ {FH_MAX1, ((27 * 66) >> 8) & 0xFF, 0},
+ {NCO_F0_MOD, MASK_NCO_F0_MOD_27MHZ, 0},
};
-static struct reg_value tc358743_setting_YUV422_4lane_color_bar_1280_720_125MHz[] = {
- {0x7080, 0x00000000, 2, 0},
- {0x0002, 0x00000f00, 2, 100},
- {0x0002, 0x00000000, 2, 1000},
- {0x0006, 0x00000000, 2, 0},
- {0x0004, 0x00000084, 2, 0},
- {0x0010, 0x0000001e, 2, 0},
-// Program CSI Tx PLL
- {0x0020, 0x0000405c, 2, 0},
- {0x0022, 0x00000613, 2, 0},
-// CSI Tx PHY (32-bit Registers)
- {0x0140, 0x00000000, 4, 0},
- {0x0144, 0x00000000, 4, 0},
- {0x0148, 0x00000000, 4, 0},
- {0x014c, 0x00000000, 4, 0},
- {0x0150, 0x00000000, 4, 0},
-// CSI Tx PPI (32-bit Registers)
- {0x0210, 0x00000e00, 4, 0},
- {0x0214, 0x00000001, 4, 0},
- {0x0218, 0x00000801, 4, 0},
- {0x021c, 0x00000000, 4, 0},
- {0x0220, 0x00000001, 4, 0},
- {0x0224, 0x00004000, 4, 0},
- {0x0228, 0x00000006, 4, 0},
- {0x022c, 0x00000000, 4, 0},
- {0x0234, 0x00000007, 4, 0}, //{0x0234, 0x00000007, 0x00000000, 4, 0},
- {0x0238, 0x00000000, 4, 0}, //non-continuous clock
- {0x0204, 0x00000001, 4, 0},
- {0x0518, 0x00000001, 4, 0},
- {0x0500, 0xa30080a2, 4, 0}, //{0x0500, 0xa30080a2, 0x00000000, 4, 0},
-// 1280x720 colorbar
- {0x000a, 0x00000a00, 2, 0},
- {0x7080, 0x00000082, 2, 0},
-// 128 pixel black - repeat 128 times
- {0x7000, 0x0000007f, 2, (1<<24)|(128<<16)},
-// 128 pixel blue - repeat 64 times
- {0x7000, 0x000000ff, 2, 0},
- {0x7000, 0x00000000, 2, (2<<24)|(64<<16)},
-// 128 pixel red - repeat 64 times
- {0x7000, 0x00000000, 2, 0},
- {0x7000, 0x000000ff, 2, (2<<24)|(64<<16)},
-// 128 pixel pink - repeat 64 times
- {0x7000, 0x00007fff, 2, 0},
- {0x7000, 0x00007fff, 2, (2<<24)|(64<<16)},
-// 128 pixel green - repeat 64 times
- {0x7000, 0x00007f00, 2, 0},
- {0x7000, 0x00007f00, 2, (2<<24)|(64<<16)},
-// 128 pixel light blue - repeat 64 times
- {0x7000, 0x0000c0ff, 2, 0},
- {0x7000, 0x0000c000, 2, (2<<24)|(64<<16)},
-// 128 pixel yellow - repeat 64 times
- {0x7000, 0x0000ff00, 2, 0},
- {0x7000, 0x0000ffff, 2, (2<<24)|(64<<16)},
-// 128 pixel white - repeat 64 times
- {0x7000, 0x0000ff7f, 2, 0},
- {0x7000, 0x0000ff7f, 2, (2<<24)|(64<<16)},
-// 720 lines
- {0x7090, 0x000002cf, 2, 0},
- {0x7092, 0x00000300, 2, 0},
- //{0x7092, 0x00000580, 2, 0},
- {0x7094, 0x00000010, 2, 0},
- {0x7080, 0x00000083, 2, 0},
+static timings_regs tc358743_get_best_timings(uint32_t frequency) {
+ int count = 0;
+ timings_regs best_timings = {};
+ while (1) {
+ if (timings[count].frequency == 0) break;
+ best_timings = timings[count];
+ if (timings[count].frequency >= frequency) break;
+ count++;
+ }
+ return best_timings;
+}
+
+static struct reg_value tc358743_2lanes_start[] = {
+ {CLW_CNTRL, 0x0000, 0},
+
+ /* Make all lanes active */
+ {D0W_CNTRL, 0x0000, 0},
+ {D1W_CNTRL, 0x0000, 0},
+
+ {D2W_CNTRL, 0x0000, 0},
+ {D3W_CNTRL, 0x0000, 0},
+ {HSTXVREGEN, 0x001f, 0},
+
+ /* Continuous clock mode */
+ {TXOPTIONCNTRL, MASK_CONTCLKMODE, 0},
+ {STARTCNTRL, MASK_START, 0},
+ {CSI_START, MASK_STRT, 0},
+
+ /* Use two lanes */
+ {CSI_CONFW, MASK_MODE_SET | MASK_ADDRESS_CSI_CONTROL | MASK_CSI_MODE | MASK_TXHSMD | MASK_HSCKMD | MASK_NOL_2, 0},
+
+ /* Output Control */
+ {CONFCTL, MASK_VBUFEN | MASK_INFRMEN | MASK_YCBCRFMT_422_8_BIT | MASK_AUTOINDEX, 0},
};
-static struct reg_value tc358743_setting_YUV422_4lane_color_bar_1280_720_300MHz[] = {
- {0x7080, 0x00000000, 2, 0},
- {0x0002, 0x00000f00, 2, 100},
- {0x0002, 0x00000000, 2, 1000},
- {0x0006, 0x00000000, 2, 0},
- {0x0004, 0x00000084, 2, 0},
- {0x0010, 0x0000001e, 2, 0},
-// Program CSI Tx PLL
- {0x0020, 0x000080c7, 2, 0},
- {0x0022, 0x00000213, 2, 0},
-// CSI Tx PHY (32-bit Registers)
- {0x0140, 0x00000000, 4, 0},
- {0x0144, 0x00000000, 4, 0},
- {0x0148, 0x00000000, 4, 0},
- {0x014c, 0x00000000, 4, 0},
- {0x0150, 0x00000000, 4, 0},
-// CSI Tx PPI (32-bit Registers)
- {0x0210, 0x00001e00, 4, 0},
- {0x0214, 0x00000003, 4, 0},
- {0x0218, 0x00001402, 4, 0},
- {0x021c, 0x00000000, 4, 0},
- {0x0220, 0x00000003, 4, 0},
- {0x0224, 0x00004a00, 4, 0},
- {0x0228, 0x00000008, 4, 0},
- {0x022c, 0x00000002, 4, 0},
- {0x0234, 0x0000001f, 4, 0},
- {0x0238, 0x00000000, 4, 0},
- {0x0204, 0x00000001, 4, 0},
- {0x0518, 0x00000001, 4, 0},
- {0x0500, 0xa30080a6, 4, 0},
-// 1280x720 colorbar
- {0x000a, 0x00000a00, 2, 0},
- {0x7080, 0x00000082, 2, 0},
-// 128 pixel black - repeat 128 times
- {0x7000, 0x0000007f, 2, (1<<24)|(128<<16)},
-// 128 pixel blue - repeat 64 times
- {0x7000, 0x000000ff, 2, 0},
- {0x7000, 0x00000000, 2, (2<<24)|(64<<16)},
-// 128 pixel red - repeat 64 times
- {0x7000, 0x00000000, 2, 0},
- {0x7000, 0x000000ff, 2, (2<<24)|(64<<16)},
-// 128 pixel pink - repeat 64 times
- {0x7000, 0x00007fff, 2, 0},
- {0x7000, 0x00007fff, 2, (2<<24)|(64<<16)},
-// 128 pixel green - repeat 64 times
- {0x7000, 0x00007f00, 2, 0},
- {0x7000, 0x00007f00, 2, (2<<24)|(64<<16)},
-// 128 pixel light blue - repeat 64 times
- {0x7000, 0x0000c0ff, 2, 0},
- {0x7000, 0x0000c000, 2, (2<<24)|(64<<16)},
-// 128 pixel yellow - repeat 64 times
- {0x7000, 0x0000ff00, 2, 0},
- {0x7000, 0x0000ffff, 2, (2<<24)|(64<<16)},
-// 128 pixel white - repeat 64 times
- {0x7000, 0x0000ff7f, 2, 0},
- {0x7000, 0x0000ff7f, 2, (2<<24)|(64<<16)},
-// 720 lines
- {0x7090, 0x000002cf, 2, 0},
- {0x7092, 0x000006b8, 2, 0},
- {0x7094, 0x00000010, 2, 0},
- {0x7080, 0x00000083, 2, 0},
+static struct reg_value tc358743_setting_hdmi[] = {
+ /* HDMI interrupt mask */
+ {SYS_INT, 0x0000, 100},
+ {SYS_INTM, 0x0000, 0},
+ {PACKET_INTM, 0x0000, 0},
+ {CBIT_INTM, 0x0000, 0},
+ {AUDIO_INTM, 0x0000, 0},
+
+ {PHY_CTL0, MASK_PHY_CTL, 0},
+ /* HDMI PHY */
+ {PHY_CTL1, 0x0080, 0},
+ {PHY_BIAS, 0x0040, 0},
+ {PHY_CSQ, 0x000a, 0},
+
+ {HDMI_DET, MASK_HDMI_DET_V_SYNC | MASK_HDMI_DET_MOD0 | MASK_HDMI_DET_MOD1, 0},
+ {HV_RST, MASK_H_PI_RST | MASK_V_PI_RST, 0},
+ {PHY_CTL2, MASK_PHY_AUTO_RST2 | MASK_PHY_AUTO_RST3 | MASK_PHY_AUTO_RST4, 0},
+
+ /* HDMI system */
+ {DDC_CTL, 0x0030 | MASK_DDC5V_MODE_100MS, 0},
+ {ANA_CTL, MASK_APPL_PCSX_NORMAL | MASK_ANALOG_ON, 0},
+ {AVM_CTL, 0x002d, 0},
+ {VI_MODE, MASK_RGB_DVI, 0},
+ {VI_MUTE, MASK_AUTO_MUTE, 0},
+ {CMD_AUD, MASK_CMD_MUTE, 0},
+
+ /* EDID */
+ {EDID_MODE, 0x0001, 2},
+ {EDID_LEN2, 0x0001, 0},
+
+ {BCAPS, MASK_REPEATER | MASK_READY, 0}, /* Turn off HDMI */
+ {BSTATUS1, MASK_MAX_EXCED, 0},
+
+ /* HDCP Settings */
+ {HDCP_REG3, 0x0001, 0},
+ {HDCP_MODE, 0x0024, 0},
+ {HDCP_REG1, 0x0011, 0},
+ {HDCP_REG2, 0x000f, 0},
+
+ /* RGB to YUV Conversion */
+ {VOUT_SET0, 0x0002,0},
+ {VOUT_SET2, MASK_VOUTCOLORMODE_AUTO | MASK_SEL422 | MASK_VOUT_422FIL_100, 0},
+ {VOUT_SET3, MASK_VOUT_EXTCNT, 0},
+ {VI_REP, MASK_VOUT_COLOR_601_YCBCR_LIMITED, 0},
+
+ /* InfoFrame extraction */
+ {PK_INT_MODE, 0x00ff, 0},
+ {NO_PKT_LIMIT, 0x002c, 0},
+ {NO_PKT_CLR, 0x0053, 0},
+ {ERR_PK_LIMIT, 0x0001, 0},
+ {NO_PKT_LIMIT2, 0x0030, 0},
+ {NO_GDB_LIMIT, 0x0010, 0},
+ {INIT_END, MASK_INIT_END, 0},
};
enum {
TC358743_MODE_640x480,
+ TC358743_MODE_800x600,
+ TC358743_MODE_1024x768,
TC358743_MODE_1280x720,
+ TC358743_MODE_1280x1024,
+ TC358743_MODE_1680x1050,
TC358743_MODE_1920x1080,
TC358743_SIZE_LAST,
};
-static struct reg_value *mode_table[] = {
- [TC358743_MODE_640x480] = tc358743_setting_YUV422_2lane_60fps_640_480_125Mhz,
- //[TC358743_MODE_1280x720] = tc358743_setting_YUV422_2lane_30fps_720P_1280_720_125MHz,
- [TC358743_MODE_1920x1080] = tc358743_setting_YUV422_4lane_1080P_60fps_1920_1080_300MHz,
-};
-
#define to_tc358743(sd) container_of(sd, struct tc358743_priv, subdev)
struct tc358743_priv {
struct v4l2_subdev subdev;
struct v4l2_mbus_framefmt mf;
-
int ident;
u16 chip_id;
u8 revision;
-
int mode;
-
struct i2c_client *client;
};
@@ -612,7 +557,11 @@ static enum v4l2_mbus_pixelcode tc358743_codes[] = {
static const struct v4l2_frmsize_discrete tc358743_frmsizes[TC358743_SIZE_LAST] = {
{640, 480},
+ {800, 600},
+ {1024, 768},
{1280, 720},
+ {1280, 1024},
+ {1680, 1050},
{1920, 1080},
};
@@ -634,24 +583,20 @@ static int tc358743_find_mode(u32 width, u32 height)
for (i = 0; i < TC358743_SIZE_LAST; i++) {
if ((tc358743_frmsizes[i].width >= width) &&
- (tc358743_frmsizes[i].height >= height))
+ (tc358743_frmsizes[i].height >= height))
break;
}
- /* If not found, select biggest */
+ /* If not found, select the biggest */
if (i >= TC358743_SIZE_LAST)
i = TC358743_SIZE_LAST - 1;
return i;
}
-static int tc358743_write_reg(struct i2c_client *client, u16 reg, u32 val, int len)
-{
+static int get_register_size(u16 reg) {
int i = 0;
- u32 data = val;
- u8 au8Buf[6] = {0};
int size = 0;
-
while(0 != tc358743_read_reg_size[i].startaddr ||
0 != tc358743_read_reg_size[i].endaddr ||
0 != tc358743_read_reg_size[i].size)
@@ -663,6 +608,48 @@ static int tc358743_write_reg(struct i2c_client *client, u16 reg, u32 val, int l
}
i++;
}
+ if (size == 0) {
+ printk(KERN_ERR "Unkown register 0x%04x size!!", reg);
+ }
+ return size;
+}
+
+static uint32_t i2c_rd(struct i2c_client *client, u16 reg)
+{
+ int err;
+ uint32_t result = 0;
+ uint8_t *values = (uint8_t*)&result;
+ u8 buf[2] = { reg >> 8, reg & 0xff };
+ int n = get_register_size(reg);
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 2,
+ .buf = buf,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = n,
+ .buf = values,
+ },
+ };
+ err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (err != ARRAY_SIZE(msgs)) {
+ pr_err("%s: reading register 0x%x from 0x%x failed\n", __func__, reg, client->addr);
+ }
+ return result;
+}
+
+static int i2c_wr(struct i2c_client *client, u16 reg, u32 val)
+{
+ int i = 0;
+ u32 data = val;
+ u8 au8Buf[6] = {0};
+ int size = get_register_size(reg);
+ int len = get_register_size(reg);
+
if(!size) {
pr_err("%s:write reg error:reg=%x is not found\n",__func__, reg);
return -1;
@@ -670,12 +657,11 @@ static int tc358743_write_reg(struct i2c_client *client, u16 reg, u32 val, int l
if(size == 3) {
size = 2;
- } else
- if(size != len) {
- pr_err("%s:write reg len error:reg=%x %d instead of %d\n",
- __func__, reg, len, size);
- return 0;
- }
+ } else if(size != len) {
+ pr_err("%s:write reg len error:reg=%x %d instead of %d\n",
+ __func__, reg, len, size);
+ return 0;
+ }
while(len > 0) {
i = 0;
@@ -688,7 +674,7 @@ static int tc358743_write_reg(struct i2c_client *client, u16 reg, u32 val, int l
if (i2c_master_send(client, au8Buf, i) < 0) {
pr_err("%s:write reg error:reg=%x,val=%x\n",
- __func__, reg, val);
+ __func__, reg, val);
return -1;
}
len -= (u8)size;
@@ -698,6 +684,48 @@ static int tc358743_write_reg(struct i2c_client *client, u16 reg, u32 val, int l
return 0;
}
+static int tc358743_set_pll(struct i2c_client *client, uint32_t frequency)
+{
+ int ret = 0;
+
+ timings_regs timings = tc358743_get_best_timings(frequency);
+ if (timings.frequency == 0) return 1;
+
+ printk(KERN_DEBUG "Setting pll to frequency %d (%d) MHz\n",
+ frequency, timings.frequency);
+
+ ret += i2c_wr(client, FIFOCTL, timings.fifo_delay);
+
+ /* Disable all interrupts except the hdmi-rx */
+ ret += i2c_wr(client, INTSTATUS, 0x0);
+ ret += i2c_wr(client, INTMASK, 0x5ff);
+
+ ret += i2c_wr(client, PLLCTL0, SET_PLL_FREQ(frequency));
+
+ ret += i2c_wr(client, PLLCTL1,
+ SET_PLL_FRS(GET_FRS(frequency), FRS_BW_50) | MASK_RESETB | MASK_PLL_EN);
+ mdelay(1);
+ ret += i2c_wr(client, PLLCTL1,
+ SET_PLL_FRS(GET_FRS(frequency), FRS_BW_50) | MASK_RESETB | MASK_PLL_EN | MASK_CKEN);
+
+ ret += i2c_wr(client, LINEINITCNT, timings.line_init_cnt);
+ ret += i2c_wr(client, LPTXTIMECNT, timings.tlpx_time_cnt);
+
+ ret += i2c_wr(client, TCLK_HEADERCNT,
+ CALC_HDR_CNT(timings.tclk_prepare_cnt, timings.tclk_zero_cnt));
+
+ ret += i2c_wr(client, TCLK_TRAILCNT, timings.tclk_trail_cnt);
+
+ ret += i2c_wr(client, THS_HEADERCNT,
+ CALC_HDR_CNT(timings.ths_prepare_cnt, timings.ths_zero_cnt));
+
+ ret += i2c_wr(client, TWAKEUP, timings.twakeup_cnt);
+ ret += i2c_wr(client, TCLK_POSTCNT, timings.tclk_post_cnt);
+ ret += i2c_wr(client, THS_TRAILCNT, timings.ths_trail_cnt);
+
+ return ret;
+}
+
static int tc358743_write_table(struct i2c_client *client, struct reg_value table[], int table_length)
{
u32 lines_to_repeat = 0;
@@ -705,17 +733,15 @@ static int tc358743_write_table(struct i2c_client *client, struct reg_value tabl
u32 delay_ms = 0;
u16 addr = 0;
u32 val = 0;
- u8 len = 0;
int ret = 0;
int i;
for (i = 0; i < table_length; ++i) {
addr = table[i].addr;
val = table[i].val;
- len = table[i].len;
delay_ms = (table[i].flags & 0xffff);
- ret = tc358743_write_reg(client, addr, val, len);
+ ret = i2c_wr(client, addr, val);
if (ret < 0)
break;
@@ -759,33 +785,32 @@ static int tc358743_write_edid(struct i2c_client *client, u8 *edid, int len)
if (i2c_master_send(client, au8Buf, i) < 0) {
pr_err("%s:write reg error:reg=%x,val=%x\n",
- __func__, reg, off);
+ __func__, reg, off);
return -1;
}
len -= (u8)size;
reg += (u16)size;
}
printk(KERN_DEBUG "Activate EDID\n");
- tc358743_write_reg(client, 0x85c7, 0x01, 1);
- tc358743_write_reg(client, 0x85ca, 0x00, 1);
- tc358743_write_reg(client, 0x85cb, 0x01, 1);
+ i2c_wr(client, EDID_MODE, MASK_EDID_MODE_DDC2B);
+ i2c_wr(client, EDID_LEN1, 0x00);
+ i2c_wr(client, EDID_LEN2, 0x01);
return 0;
}
static int tc358743_toggle_hpd(struct i2c_client *client, int active)
{
int ret = 0;
+
if(active)
{
- ret += tc358743_write_reg(client, 0x8544, 0x00, 1);
+ ret += i2c_wr(client, HPD_CTL, 0x00);
mdelay(500);
- ret += tc358743_write_reg(client, 0x8544, 0x10, 1);
- }
- else
- {
- ret += tc358743_write_reg(client, 0x8544, 0x10, 1);
+ ret += i2c_wr(client, HPD_CTL, MASK_HPD_CTL0);
+ } else {
+ ret += i2c_wr(client, HPD_CTL, MASK_HPD_CTL0);
mdelay(500);
- ret += tc358743_write_reg(client, 0x8544, 0x00, 1);
+ ret += i2c_wr(client, HPD_CTL, 0x00);
}
return ret;
}
@@ -794,8 +819,6 @@ static void tc358743_set_default_fmt(struct tc358743_priv *priv)
{
struct v4l2_mbus_framefmt *mf = &priv->mf;
- mf->width = tc358743_frmsizes[TC358743_MODE_640x480].width;
- mf->height = tc358743_frmsizes[TC358743_MODE_640x480].height;
mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
mf->field = V4L2_FIELD_NONE;
mf->colorspace = V4L2_COLORSPACE_SRGB;
@@ -805,26 +828,24 @@ static void tc358743_set_default_fmt(struct tc358743_priv *priv)
static int tc358743_s_stream(struct v4l2_subdev *sd, int enable)
{
struct tc358743_priv *priv = to_tc358743(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret = 0;
if (!enable) {
- tc358743_set_default_fmt(priv);
+ printk(KERN_DEBUG "Disabling stream");
+ i2c_wr(priv->client, CONFCTL, 0);
return 0;
}
- return ret;
+ return 0;
}
static int tc358743_try_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
+ struct v4l2_mbus_framefmt *mf)
{
int mode;
mode = tc358743_find_mode(mf->width, mf->height);
mf->width = tc358743_frmsizes[mode].width;
mf->height = tc358743_frmsizes[mode].height;
-
mf->field = V4L2_FIELD_NONE;
mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
mf->colorspace = V4L2_COLORSPACE_SRGB;
@@ -832,12 +853,44 @@ static int tc358743_try_fmt(struct v4l2_subdev *sd,
return 0;
}
+
+struct aviInfoFrame {
+ u8 f17;
+ u8 y10;
+ u8 a0;
+ u8 b10;
+ u8 s10;
+ u8 c10;
+ u8 m10;
+ u8 r3210;
+ u8 itc;
+ u8 ec210;
+ u8 q10;
+ u8 sc10;
+ u8 f47;
+ u8 vic;
+ u8 yq10;
+ u8 cn10;
+ u8 pr3210;
+ u16 etb;
+ u16 sbb;
+ u16 elb;
+ u16 srb;
+};
+
+static inline bool is_hdmi(struct v4l2_subdev *sd)
+{
+ struct tc358743_priv *priv = to_tc358743(sd);
+ return i2c_rd(priv->client, SYS_STATUS) & MASK_S_HDMI;
+}
+
/* set the format we will capture in */
static int tc358743_s_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
+ struct v4l2_mbus_framefmt *mf)
{
struct tc358743_priv *priv = to_tc358743(sd);
int ret;
+ uint32_t v2, v, width, height, v_size, h_size, fv_cnt, fps;
ret = tc358743_try_fmt(sd, mf);
if (ret < 0)
@@ -847,23 +900,77 @@ static int tc358743_s_fmt(struct v4l2_subdev *sd,
memcpy(&priv->mf, mf, sizeof(struct v4l2_mbus_framefmt));
- return 0;
-}
+ tc358743_write_table(priv->client, tc358743_reset, ARRAY_SIZE(tc358743_reset));
+ tc358743_write_table(priv->client, tc358743_setting_hdmi, ARRAY_SIZE(tc358743_setting_hdmi));
+ msleep(100);
+
+ v = i2c_rd(priv->client, DE_WIDTH_H_LO);
+ v2 = i2c_rd(priv->client, DE_WIDTH_H_HI) & 0x1f;
+ width = (v2 << 8) + v;
+ v = i2c_rd(priv->client, DE_WIDTH_V_LO);
+ v2 = i2c_rd(priv->client, DE_WIDTH_V_HI) & 0x1f;
+ height = (v2 << 8) + v;
+ v = i2c_rd(priv->client, H_SIZE_LO);
+ v2 = i2c_rd(priv->client, H_SIZE_HI) & 0x1f;
+ h_size = (v2 << 8) + v;
+ v = i2c_rd(priv->client, V_SIZE_LO);
+ v2 = i2c_rd(priv->client, V_SIZE_HI) & 0x3f;
+ v_size = ((v2 << 8) + v) / 2;
+ v = i2c_rd(priv->client, FV_CNT_LO);
+ v2 = i2c_rd(priv->client, FV_CNT_HI) & 0x3;
+ fv_cnt = (v2 << 8) + v;
+ fps = fv_cnt > 0 ? DIV_ROUND_CLOSEST(10000, fv_cnt) : 0;
+
+ printk(KERN_DEBUG "Image is %dx%d@%d, ~%d Gbps bandwidth (~%dMHz/lane)",
+ width, height, fps,
+ DIV_ROUND_UP(fps*width*height*16, 1000*1000),
+ DIV_ROUND_UP(fps*width*height*8, 1000*1000));
+
+ if (width * fps == 0) {
+ printk(KERN_ERR "width or fps 0");
+ return 0;
+ }
-static int tc358743_s_power(struct v4l2_subdev *sd, int on)
-{
- struct tc358743_priv *priv = to_tc358743(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct soc_camera_subdev_desc *scsd = soc_camera_i2c_to_desc(client);
+ if ((width != mf->width)) {
+ printk(KERN_ERR "Wrong width (%d vs %d)", width, mf->width);
+ return 0;
+ }
- if (on)
- tc358743_s_fmt(sd, &priv->mf);
+ /* XXX the chip sometimes miscalculates the height of the image,
+ * therefore, we base the output mostly on the width of the image */
+ if (width == 1920) {
+ /* works for 1920x1080 @ 60 */
+ ret = tc358743_set_pll(priv->client, 1075);
+ /* 872 is in the middle between 1024 and 720, should be a safe
+ * value for both 1280x720 and 1280x1024 */
+ } else if (width == 1280 && height >= 872) {
+ /* works on 1280x1024 @ 75 */
+ ret = tc358743_set_pll(priv->client, 1075);
+ } else if (width == 1280 && height < 872) {
+ /* works on 1280x720 @ 60 */
+ ret = tc358743_set_pll(priv->client, 825);
+ } else if (width == 1024) {
+ /* works on 1024x768 @ 75 */
+ ret = tc358743_set_pll(priv->client, 600);
+ } else if (width >= 800) {
+ /* works for 800x600@75 */
+ ret = tc358743_set_pll(priv->client, 594);
+ } else if (width == 640) {
+ /* works on 640x480 @ 75 */
+ ret = tc358743_set_pll(priv->client, 500);
+ } else {
+ return 0;
+ }
- return soc_camera_set_power(&client->dev, scsd, on);
+ tc358743_write_table(priv->client,
+ tc358743_2lanes_start,
+ ARRAY_SIZE(tc358743_2lanes_start));
+
+ return ret;
}
static int tc358743_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
+ enum v4l2_mbus_pixelcode *code)
{
if (index >= ARRAY_SIZE(tc358743_codes))
return -EINVAL;
@@ -873,34 +980,9 @@ static int tc358743_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
return 0;
}
-static int tc358743_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
-{
- a->bounds.left = 0;
- a->bounds.top = 0;
- a->bounds.width = tc358743_frmsizes[TC358743_MODE_640x480].width;
- a->bounds.height = tc358743_frmsizes[TC358743_MODE_640x480].height;
- a->defrect = a->bounds;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- a->pixelaspect.numerator = 1;
- a->pixelaspect.denominator = 1;
-
- return 0;
-}
-
-static int tc358743_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
-{
- a->c.left = 0;
- a->c.top = 0;
- a->c.width = tc358743_frmsizes[TC358743_MODE_640x480].width;
- a->c.height = tc358743_frmsizes[TC358743_MODE_640x480].height;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- return 0;
-}
-
/* Get chip identification */
static int tc358743_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *id)
+ struct v4l2_dbg_chip_ident *id)
{
struct tc358743_priv *priv = to_tc358743(sd);
@@ -910,17 +992,21 @@ static int tc358743_g_chip_ident(struct v4l2_subdev *sd,
return 0;
}
+static int tc358743_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_subdev_desc *scsd = soc_camera_i2c_to_desc(client);
+
+ return soc_camera_set_power(&client->dev, scsd, on);
+}
+
static struct v4l2_subdev_video_ops tc358743_video_ops = {
.s_stream = tc358743_s_stream,
.s_mbus_fmt = tc358743_s_fmt,
.try_mbus_fmt = tc358743_try_fmt,
.enum_mbus_fmt = tc358743_enum_fmt,
- .cropcap = tc358743_cropcap,
- .g_crop = tc358743_g_crop,
- //.querystd = tc358743_querystd,
};
-
static struct v4l2_subdev_core_ops tc358743_core_ops = {
.g_chip_ident = tc358743_g_chip_ident,
.s_power = tc358743_s_power,
@@ -935,21 +1021,21 @@ static struct v4l2_subdev_ops tc358743_subdev_ops = {
* i2c_driver function
*/
static int tc358743_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
+ const struct i2c_device_id *did)
{
struct tc358743_priv *priv;
struct soc_camera_subdev_desc *scsd;
int ret = 0;
/* Checking soc-camera interface */
- scsd = soc_camera_i2c_to_desc(client);
+ scsd = client->dev.platform_data;
if (!scsd) {
dev_err(&client->dev, "Missing soc_camera_link for driver\n");
return -EINVAL;
}
priv = devm_kzalloc(&client->dev, sizeof(struct tc358743_priv),
- GFP_KERNEL);
+ GFP_KERNEL);
if (!priv) {
dev_err(&client->dev, "Failed to allocate private data!\n");
return -ENOMEM;
@@ -958,23 +1044,16 @@ static int tc358743_probe(struct i2c_client *client,
v4l2_i2c_subdev_init(&priv->subdev, client, &tc358743_subdev_ops);
priv->client = client;
+ priv->ident = V4L2_IDENT_OV5640;
/*
* check and show product ID and manufacturer ID
*/
soc_camera_power_on(&client->dev, scsd);
-
tc358743_set_default_fmt(priv);
-
- //tc358743_write_table(client, tc358743_setting_YUV422_2lane_color_bar_1280_720_125MHz,
- // ARRAY_SIZE(tc358743_setting_YUV422_2lane_color_bar_1280_720_125MHz));
-
- tc358743_write_table(client, tc358743_setting_YUV422_2lane_60fps_640_480_125Mhz,
- ARRAY_SIZE(tc358743_setting_YUV422_2lane_60fps_640_480_125Mhz));
-
- //tc358743_write_table(client, tc358743_setting_YUV422_4lane_color_bar_1280_720_300MHz,
- // ARRAY_SIZE(tc358743_setting_YUV422_4lane_color_bar_1280_720_300MHz));
+ tc358743_write_table(client, tc358743_reset, ARRAY_SIZE(tc358743_reset));
+ tc358743_write_table(client, tc358743_setting_hdmi, ARRAY_SIZE(tc358743_setting_hdmi));
if((ret = tc358743_write_edid(client, hdmi_edid, ARRAY_SIZE(hdmi_edid))))
printk(KERN_ERR "%s: Fail to write EDID to tc35874!\n", __FUNCTION__);
@@ -998,8 +1077,9 @@ static const struct i2c_device_id tc358743_id[] = {
MODULE_DEVICE_TABLE(i2c, tc358743_id);
static struct i2c_driver tc358743_i2c_driver = {
- .driver = {
- .name = "tc358743",
+ .driver = {
+ .name = "tc358743",
+ .owner = THIS_MODULE,
},
.probe = tc358743_probe,
.remove = tc358743_remove,