summaryrefslogtreecommitdiff
path: root/drivers/media/i2c/soc_camera/tc358743.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/i2c/soc_camera/tc358743.c')
-rw-r--r--drivers/media/i2c/soc_camera/tc358743.c1320
1 files changed, 700 insertions, 620 deletions
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,