// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) Rockchip Electronics Co., Ltd. * Author: * Guochun Huang */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "phy-rockchip-csi2-dphy-common.h" #include "phy-rockchip-samsung-dcphy.h" #define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l))) #define HIWORD_UPDATE(v, h, l) (((v) << (l)) | (GENMASK((h), (l)) << 16)) #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 EDGE_CON(x) UPDATE(x, 14, 12) #define EDGE_CON_DIR(x) UPDATE(x, 9, 9) #define EDGE_CON_EN BIT(8) #define RES_UP(x) UPDATE(x, 7, 4) #define RES_DN(x) UPDATE(x, 3, 0) #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 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) #define RX_S0D3_ADI_STAT0 (0XFEC) #define MIPI_DCPHY_MAX_REGISGER RX_S0D3_ADI_STAT0 struct samsung_mipi_dphy_timing { unsigned int max_lane_mbps; u8 clk_prepare; u8 clk_zero; u8 clk_post; u8 clk_trail_eot; u8 hs_prepare; u8 hs_zero; u8 hs_trail_eot; u8 lpx; u8 hs_exit; u8 hs_settle; }; struct samsung_mipi_cphy_timing { unsigned int max_lane_msps; u8 prepare_3; u8 prebegin_3; u8 post_3; u8 lpx; u8 hs_exit; u8 settle_3; }; static const struct samsung_mipi_dphy_timing samsung_mipi_dphy_timing_table[] = { {6500, 32, 117, 31, 28, 30, 56, 27, 24, 44, 37}, {6490, 32, 116, 31, 28, 30, 56, 27, 24, 44, 37}, {6480, 32, 116, 31, 28, 30, 56, 27, 24, 44, 37}, {6470, 32, 116, 31, 28, 30, 56, 27, 24, 44, 37}, {6460, 32, 116, 31, 28, 30, 56, 27, 24, 44, 37}, {6450, 32, 115, 31, 28, 30, 56, 27, 24, 44, 37}, {6440, 32, 115, 31, 28, 30, 56, 27, 24, 44, 37}, {6430, 31, 116, 31, 28, 30, 55, 27, 24, 44, 37}, {6420, 31, 116, 31, 28, 30, 55, 27, 24, 44, 37}, {6410, 31, 116, 31, 27, 30, 55, 27, 24, 44, 37}, {6400, 31, 115, 30, 27, 30, 55, 27, 23, 43, 36}, {6390, 31, 115, 30, 27, 30, 55, 27, 23, 43, 36}, {6380, 31, 115, 30, 27, 30, 55, 27, 23, 43, 36}, {6370, 31, 115, 30, 27, 30, 55, 26, 23, 43, 36}, {6360, 31, 114, 30, 27, 30, 54, 26, 23, 43, 36}, {6350, 31, 114, 30, 27, 30, 54, 26, 23, 43, 36}, {6340, 31, 114, 30, 27, 30, 54, 26, 23, 43, 36}, {6330, 31, 114, 30, 27, 30, 54, 26, 23, 43, 36}, {6320, 31, 113, 30, 27, 30, 54, 26, 23, 43, 36}, {6310, 31, 113, 30, 27, 30, 54, 26, 23, 43, 36}, {6300, 31, 113, 30, 27, 30, 54, 26, 23, 43, 36}, {6290, 31, 113, 30, 27, 29, 54, 26, 23, 43, 36}, {6280, 31, 112, 30, 27, 29, 54, 26, 23, 43, 36}, {6270, 31, 112, 30, 27, 29, 54, 26, 23, 43, 36}, {6260, 31, 112, 30, 27, 29, 54, 26, 23, 43, 36}, {6250, 31, 112, 30, 27, 29, 54, 26, 23, 42, 36}, {6240, 30, 113, 30, 27, 29, 54, 26, 23, 42, 36}, {6230, 30, 112, 30, 27, 29, 54, 26, 23, 42, 35}, {6220, 30, 112, 30, 27, 29, 53, 26, 23, 42, 35}, {6210, 30, 112, 30, 27, 29, 53, 26, 23, 42, 35}, {6200, 30, 112, 29, 27, 29, 53, 26, 23, 42, 35}, {6190, 30, 111, 29, 27, 29, 53, 26, 23, 42, 35}, {6180, 30, 111, 29, 27, 29, 53, 26, 23, 42, 35}, {6170, 30, 111, 29, 26, 29, 53, 26, 23, 42, 35}, {6160, 30, 111, 29, 26, 29, 53, 26, 23, 42, 35}, {6150, 30, 110, 29, 26, 29, 53, 26, 23, 42, 35}, {6140, 30, 110, 29, 26, 29, 52, 26, 23, 42, 35}, {6130, 30, 110, 29, 26, 29, 52, 25, 22, 42, 35}, {6120, 30, 110, 29, 26, 29, 52, 25, 22, 42, 35}, {6110, 30, 110, 29, 26, 29, 52, 25, 22, 42, 35}, {6100, 30, 109, 29, 26, 29, 52, 25, 22, 41, 35}, {6090, 30, 109, 29, 26, 29, 52, 25, 22, 41, 35}, {6080, 30, 109, 29, 26, 28, 53, 25, 22, 41, 35}, {6070, 30, 109, 29, 26, 28, 52, 25, 22, 41, 34}, {6060, 30, 108, 29, 26, 28, 52, 25, 22, 41, 34}, {6050, 30, 108, 29, 26, 28, 52, 25, 22, 41, 34}, {6040, 29, 109, 29, 26, 28, 52, 25, 22, 41, 34}, {6030, 29, 109, 29, 26, 28, 52, 25, 22, 41, 34}, {6020, 29, 108, 29, 26, 28, 52, 25, 22, 41, 34}, {6010, 29, 108, 29, 26, 28, 52, 25, 22, 41, 34}, {6000, 29, 108, 28, 26, 28, 51, 25, 22, 41, 34}, {5990, 29, 108, 28, 26, 28, 51, 25, 22, 41, 34}, {5980, 29, 107, 28, 26, 28, 51, 25, 22, 41, 34}, {5970, 29, 107, 28, 26, 28, 51, 25, 22, 41, 34}, {5960, 29, 107, 28, 26, 28, 51, 25, 22, 40, 34}, {5950, 29, 107, 28, 26, 28, 51, 25, 22, 40, 34}, {5940, 29, 107, 28, 25, 28, 51, 25, 22, 40, 34}, {5930, 29, 106, 28, 25, 28, 50, 25, 22, 40, 34}, {5920, 29, 106, 28, 25, 28, 50, 25, 22, 40, 34}, {5910, 29, 106, 28, 25, 28, 50, 25, 22, 40, 34}, {5900, 29, 106, 28, 25, 28, 50, 24, 22, 40, 33}, {5890, 29, 105, 28, 25, 28, 50, 24, 22, 40, 33}, {5880, 29, 105, 28, 25, 28, 50, 24, 22, 40, 33}, {5870, 29, 105, 28, 25, 27, 51, 24, 22, 40, 33}, {5860, 29, 105, 28, 25, 27, 51, 24, 21, 40, 33}, {5850, 29, 104, 28, 25, 27, 50, 24, 21, 40, 33}, {5840, 28, 105, 28, 25, 27, 50, 24, 21, 40, 33}, {5830, 28, 105, 28, 25, 27, 50, 24, 21, 40, 33}, {5820, 28, 105, 28, 25, 27, 50, 24, 21, 40, 33}, {5810, 28, 104, 28, 25, 27, 50, 24, 21, 39, 33}, {5800, 28, 104, 27, 25, 27, 50, 24, 21, 39, 33}, {5790, 28, 104, 27, 25, 27, 50, 24, 21, 39, 33}, {5780, 28, 104, 27, 25, 27, 49, 24, 21, 39, 33}, {5770, 28, 104, 27, 25, 27, 49, 24, 21, 39, 33}, {5760, 28, 103, 27, 25, 27, 49, 24, 21, 39, 33}, {5750, 28, 103, 27, 25, 27, 49, 24, 21, 39, 33}, {5740, 28, 103, 27, 25, 27, 49, 24, 21, 39, 33}, {5730, 28, 103, 27, 25, 27, 49, 24, 21, 39, 32}, {5720, 28, 102, 27, 25, 27, 49, 24, 21, 39, 32}, {5710, 28, 102, 27, 25, 27, 48, 24, 21, 39, 32}, {5700, 28, 102, 27, 24, 27, 48, 24, 21, 39, 32}, {5690, 28, 102, 27, 24, 27, 48, 24, 21, 39, 32}, {5680, 28, 101, 27, 24, 27, 48, 24, 21, 39, 32}, {5670, 28, 101, 27, 24, 27, 48, 23, 21, 38, 32}, {5660, 28, 101, 27, 24, 26, 49, 23, 21, 38, 32}, {5650, 28, 101, 27, 24, 26, 49, 23, 21, 38, 32}, {5640, 27, 101, 27, 24, 26, 48, 23, 21, 38, 32}, {5630, 27, 101, 27, 24, 26, 48, 23, 21, 38, 32}, {5620, 27, 101, 27, 24, 26, 48, 23, 21, 38, 32}, {5610, 27, 101, 27, 24, 26, 48, 23, 21, 38, 32}, {5600, 27, 101, 26, 24, 26, 48, 23, 20, 38, 32}, {5590, 27, 100, 26, 24, 26, 48, 23, 20, 38, 32}, {5580, 27, 100, 26, 24, 26, 48, 23, 20, 38, 32}, {5570, 27, 100, 26, 24, 26, 48, 23, 20, 38, 31}, {5560, 27, 100, 26, 24, 26, 47, 23, 20, 38, 31}, {5550, 27, 99, 26, 24, 26, 47, 23, 20, 38, 31}, {5540, 27, 99, 26, 24, 26, 47, 23, 20, 38, 31}, {5530, 27, 99, 26, 24, 26, 47, 23, 20, 38, 31}, {5520, 27, 99, 26, 24, 26, 47, 23, 20, 37, 31}, {5510, 27, 98, 26, 24, 26, 47, 23, 20, 37, 31}, {5500, 27, 98, 26, 24, 26, 47, 23, 20, 37, 31}, {5490, 27, 98, 26, 24, 26, 46, 23, 20, 37, 31}, {5480, 27, 98, 26, 24, 26, 46, 23, 20, 37, 31}, {5470, 27, 97, 26, 23, 26, 46, 23, 20, 37, 31}, {5460, 27, 97, 26, 23, 26, 46, 23, 20, 37, 31}, {5450, 27, 97, 26, 23, 25, 47, 23, 20, 37, 31}, {5440, 26, 98, 26, 23, 25, 47, 23, 20, 37, 31}, {5430, 26, 98, 26, 23, 25, 47, 22, 20, 37, 31}, {5420, 26, 97, 26, 23, 25, 46, 22, 20, 37, 31}, {5410, 26, 97, 26, 23, 25, 46, 22, 20, 37, 31}, {5400, 26, 97, 25, 23, 25, 46, 22, 20, 37, 30}, {5390, 26, 97, 25, 23, 25, 46, 22, 20, 37, 30}, {5380, 26, 96, 25, 23, 25, 46, 22, 20, 36, 30}, {5370, 26, 96, 25, 23, 25, 46, 22, 20, 36, 30}, {5360, 26, 96, 25, 23, 25, 46, 22, 20, 36, 30}, {5350, 26, 96, 25, 23, 25, 46, 22, 20, 36, 30}, {5340, 26, 95, 25, 23, 25, 45, 22, 20, 36, 30}, {5330, 26, 95, 25, 23, 25, 45, 22, 19, 36, 30}, {5320, 26, 95, 25, 23, 25, 45, 22, 19, 36, 30}, {5310, 26, 95, 25, 23, 25, 45, 22, 19, 36, 30}, {5300, 26, 95, 25, 23, 25, 45, 22, 19, 36, 30}, {5290, 26, 94, 25, 23, 25, 45, 22, 19, 36, 30}, {5280, 26, 94, 25, 23, 25, 45, 22, 19, 36, 30}, {5270, 26, 94, 25, 23, 25, 44, 22, 19, 36, 30}, {5260, 26, 94, 25, 23, 25, 44, 22, 19, 36, 30}, {5250, 25, 94, 25, 23, 24, 45, 22, 19, 36, 30}, {5240, 25, 94, 25, 23, 24, 45, 22, 19, 36, 29}, {5230, 25, 94, 25, 22, 24, 45, 22, 19, 35, 29}, {5220, 25, 94, 25, 22, 24, 45, 22, 19, 35, 29}, {5210, 25, 93, 25, 22, 24, 45, 22, 19, 35, 29}, {5200, 25, 93, 24, 22, 24, 44, 21, 19, 35, 29}, {5190, 25, 93, 24, 22, 24, 44, 21, 19, 35, 29}, {5180, 25, 93, 24, 22, 24, 44, 21, 19, 35, 29}, {5170, 25, 92, 24, 22, 24, 44, 21, 19, 35, 29}, {5160, 25, 92, 24, 22, 24, 44, 21, 19, 35, 29}, {5150, 25, 92, 24, 22, 24, 44, 21, 19, 35, 29}, {5140, 25, 92, 24, 22, 24, 44, 21, 19, 35, 29}, {5130, 25, 92, 24, 22, 24, 43, 21, 19, 35, 29}, {5120, 25, 91, 24, 22, 24, 43, 21, 19, 35, 29}, {5110, 25, 91, 24, 22, 24, 43, 21, 19, 35, 29}, {5100, 25, 91, 24, 22, 24, 43, 21, 19, 35, 29}, {5090, 25, 91, 24, 22, 24, 43, 21, 19, 34, 29}, {5080, 25, 90, 24, 22, 24, 43, 21, 19, 34, 29}, {5070, 25, 90, 24, 22, 24, 43, 21, 19, 34, 28}, {5060, 25, 90, 24, 22, 24, 43, 21, 18, 34, 28}, {5050, 24, 91, 24, 22, 24, 42, 21, 18, 34, 28}, {5040, 24, 90, 24, 22, 23, 43, 21, 18, 34, 28}, {5030, 24, 90, 24, 22, 23, 43, 21, 18, 34, 28}, {5020, 24, 90, 24, 22, 23, 43, 21, 18, 34, 28}, {5010, 24, 90, 24, 22, 23, 43, 21, 18, 34, 28}, {5000, 24, 89, 23, 21, 23, 43, 21, 18, 34, 28}, {4990, 24, 89, 23, 21, 23, 43, 21, 18, 34, 28}, {4980, 24, 89, 23, 21, 23, 42, 21, 18, 34, 28}, {4970, 24, 89, 23, 21, 23, 42, 21, 18, 34, 28}, {4960, 24, 89, 23, 21, 23, 42, 20, 18, 34, 28}, {4950, 24, 88, 23, 21, 23, 42, 20, 18, 34, 28}, {4940, 24, 88, 23, 21, 23, 42, 20, 18, 33, 28}, {4930, 24, 88, 23, 21, 23, 42, 20, 18, 33, 28}, {4920, 24, 88, 23, 21, 23, 42, 20, 18, 33, 28}, {4910, 24, 87, 23, 21, 23, 41, 20, 18, 33, 28}, {4900, 24, 87, 23, 21, 23, 41, 20, 18, 33, 27}, {4890, 24, 87, 23, 21, 23, 41, 20, 18, 33, 27}, {4880, 24, 87, 23, 21, 23, 41, 20, 18, 33, 27}, {4870, 24, 86, 23, 21, 23, 41, 20, 18, 33, 27}, {4860, 24, 86, 23, 21, 23, 41, 20, 18, 33, 27}, {4850, 23, 87, 23, 21, 23, 41, 20, 18, 33, 27}, {4840, 23, 87, 23, 21, 23, 40, 20, 18, 33, 27}, {4830, 23, 86, 23, 21, 22, 41, 20, 18, 33, 27}, {4820, 23, 86, 23, 21, 22, 41, 20, 18, 33, 27}, {4810, 23, 86, 23, 21, 22, 41, 20, 18, 33, 27}, {4800, 23, 86, 22, 21, 22, 41, 20, 17, 32, 27}, {4790, 23, 86, 22, 21, 22, 41, 20, 17, 32, 27}, {4780, 23, 85, 22, 21, 22, 41, 20, 17, 32, 27}, {4770, 23, 85, 22, 21, 22, 41, 20, 17, 32, 27}, {4760, 23, 85, 22, 20, 22, 40, 20, 17, 32, 27}, {4750, 23, 85, 22, 20, 22, 40, 20, 17, 32, 27}, {4740, 23, 84, 22, 20, 22, 40, 20, 17, 32, 26}, {4730, 23, 84, 22, 20, 22, 40, 19, 17, 32, 26}, {4720, 23, 84, 22, 20, 22, 40, 19, 17, 32, 26}, {4710, 23, 84, 22, 20, 22, 40, 19, 17, 32, 26}, {4700, 23, 83, 22, 20, 22, 40, 19, 17, 32, 26}, {4690, 23, 83, 22, 20, 22, 39, 19, 17, 32, 26}, {4680, 23, 83, 22, 20, 22, 39, 19, 17, 32, 26}, {4670, 23, 83, 22, 20, 22, 39, 19, 17, 32, 26}, {4660, 23, 82, 22, 20, 22, 39, 19, 17, 32, 26}, {4650, 22, 83, 22, 20, 22, 39, 19, 17, 31, 26}, {4640, 22, 83, 22, 20, 22, 39, 19, 17, 31, 26}, {4630, 22, 83, 22, 20, 22, 39, 19, 17, 31, 26}, {4620, 22, 83, 22, 20, 21, 39, 19, 17, 31, 26}, {4610, 22, 82, 22, 20, 21, 39, 19, 17, 31, 26}, {4600, 22, 82, 21, 20, 21, 39, 19, 17, 31, 26}, {4590, 22, 82, 21, 20, 21, 39, 19, 17, 31, 26}, {4580, 22, 82, 21, 20, 21, 39, 19, 17, 31, 26}, {4570, 22, 81, 21, 20, 21, 39, 19, 17, 31, 25}, {4560, 22, 81, 21, 20, 21, 39, 19, 17, 31, 25}, {4550, 22, 81, 21, 20, 21, 38, 19, 17, 31, 25}, {4540, 22, 81, 21, 20, 21, 38, 19, 17, 31, 25}, {4530, 22, 80, 21, 19, 21, 38, 19, 16, 31, 25}, {4520, 22, 80, 21, 19, 21, 38, 19, 16, 31, 25}, {4510, 22, 80, 21, 19, 21, 38, 19, 16, 31, 25}, {4500, 22, 80, 21, 19, 21, 38, 19, 16, 30, 25}, {4490, 22, 80, 21, 19, 21, 38, 18, 16, 30, 25}, {4480, 22, 79, 21, 19, 21, 38, 18, 16, 30, 25}, {4470, 22, 79, 21, 19, 21, 37, 18, 16, 30, 25}, {4460, 22, 79, 21, 19, 21, 37, 18, 16, 30, 25}, {4450, 21, 80, 21, 19, 21, 37, 18, 16, 30, 25}, {4440, 21, 79, 21, 19, 21, 37, 18, 16, 30, 25}, {4430, 21, 79, 21, 19, 21, 37, 18, 16, 30, 25}, {4420, 21, 79, 21, 19, 21, 37, 18, 16, 30, 25}, {4410, 21, 79, 21, 19, 20, 38, 18, 16, 30, 25}, {4400, 21, 78, 20, 19, 20, 37, 18, 16, 30, 24}, {4390, 21, 78, 20, 19, 20, 37, 18, 16, 30, 24}, {4380, 21, 78, 20, 19, 20, 37, 18, 16, 30, 24}, {4370, 21, 78, 20, 19, 20, 37, 18, 16, 30, 24}, {4360, 21, 77, 20, 19, 20, 37, 18, 16, 29, 24}, {4350, 21, 77, 20, 19, 20, 37, 18, 16, 29, 24}, {4340, 21, 77, 20, 19, 20, 37, 18, 16, 29, 24}, {4330, 21, 77, 20, 19, 20, 36, 18, 16, 29, 24}, {4320, 21, 77, 20, 19, 20, 36, 18, 16, 29, 24}, {4310, 21, 76, 20, 19, 20, 36, 18, 16, 29, 24}, {4300, 21, 76, 20, 18, 20, 36, 18, 16, 29, 24}, {4290, 21, 76, 20, 18, 20, 36, 18, 16, 29, 24}, {4280, 21, 76, 20, 18, 20, 36, 18, 16, 29, 24}, {4270, 21, 75, 20, 18, 20, 36, 18, 16, 29, 24}, {4260, 21, 75, 20, 18, 20, 35, 17, 15, 29, 24}, {4250, 20, 76, 20, 18, 20, 35, 17, 15, 29, 24}, {4240, 20, 76, 20, 18, 20, 35, 17, 15, 29, 23}, {4230, 20, 75, 20, 18, 20, 35, 17, 15, 29, 23}, {4220, 20, 75, 20, 18, 20, 35, 17, 15, 29, 23}, {4210, 20, 75, 20, 18, 20, 35, 17, 15, 28, 23}, {4200, 20, 75, 19, 18, 19, 36, 17, 15, 28, 23}, {4190, 20, 74, 19, 18, 19, 36, 17, 15, 28, 23}, {4180, 20, 74, 19, 18, 19, 35, 17, 15, 28, 23}, {4170, 20, 74, 19, 18, 19, 35, 17, 15, 28, 23}, {4160, 20, 74, 19, 18, 19, 35, 17, 15, 28, 23}, {4150, 20, 74, 19, 18, 19, 35, 17, 15, 28, 23}, {4140, 20, 73, 19, 18, 19, 35, 17, 15, 28, 23}, {4130, 20, 73, 19, 18, 19, 35, 17, 15, 28, 23}, {4120, 20, 73, 19, 18, 19, 35, 17, 15, 28, 23}, {4110, 20, 73, 19, 18, 19, 34, 17, 15, 28, 23}, {4100, 20, 72, 19, 18, 19, 34, 17, 15, 28, 23}, {4090, 20, 72, 19, 18, 19, 34, 17, 15, 28, 23}, {4080, 20, 72, 19, 18, 19, 34, 17, 15, 28, 23}, {4070, 20, 72, 19, 18, 19, 34, 17, 15, 27, 22}, {4060, 19, 72, 19, 17, 19, 34, 17, 15, 27, 22}, {4050, 19, 72, 19, 17, 19, 34, 17, 15, 27, 22}, {4040, 19, 72, 19, 17, 19, 33, 17, 15, 27, 22}, {4030, 19, 72, 19, 17, 19, 33, 17, 15, 27, 22}, {4020, 19, 71, 19, 17, 19, 33, 16, 15, 27, 22}, {4010, 19, 71, 19, 17, 19, 33, 16, 15, 27, 22}, {4000, 19, 71, 18, 17, 19, 33, 16, 14, 27, 22}, {3990, 19, 71, 18, 17, 18, 34, 16, 14, 27, 22}, {3980, 19, 71, 18, 17, 18, 34, 16, 14, 27, 22}, {3970, 19, 70, 18, 17, 18, 33, 16, 14, 27, 22}, {3960, 19, 70, 18, 17, 18, 33, 16, 14, 27, 22}, {3950, 19, 70, 18, 17, 18, 33, 16, 14, 27, 22}, {3940, 19, 70, 18, 17, 18, 33, 16, 14, 27, 22}, {3930, 19, 69, 18, 17, 18, 33, 16, 14, 27, 22}, {3920, 19, 69, 18, 17, 18, 33, 16, 14, 26, 22}, {3910, 19, 69, 18, 17, 18, 33, 16, 14, 26, 22}, {3900, 19, 69, 18, 17, 18, 33, 16, 14, 26, 21}, {3890, 19, 68, 18, 17, 18, 32, 16, 14, 26, 21}, {3880, 19, 68, 18, 17, 18, 32, 16, 14, 26, 21}, {3870, 19, 68, 18, 17, 18, 32, 16, 14, 26, 21}, {3860, 18, 69, 18, 17, 18, 32, 16, 14, 26, 21}, {3850, 18, 68, 18, 17, 18, 32, 16, 14, 26, 21}, {3840, 18, 68, 18, 17, 18, 32, 16, 14, 26, 21}, {3830, 18, 68, 18, 16, 18, 32, 16, 14, 26, 21}, {3820, 18, 68, 18, 16, 18, 31, 16, 14, 26, 21}, {3810, 18, 68, 18, 16, 18, 31, 16, 14, 26, 21}, {3800, 18, 67, 17, 16, 18, 31, 16, 14, 26, 21}, {3790, 18, 67, 17, 16, 17, 32, 15, 14, 26, 21}, {3780, 18, 67, 17, 16, 17, 32, 15, 14, 25, 21}, {3770, 18, 67, 17, 16, 17, 32, 15, 14, 25, 21}, {3760, 18, 66, 17, 16, 17, 32, 15, 14, 25, 21}, {3750, 18, 66, 17, 16, 17, 31, 15, 14, 25, 21}, {3740, 18, 66, 17, 16, 17, 31, 15, 14, 25, 20}, {3730, 18, 66, 17, 16, 17, 31, 15, 13, 25, 20}, {3720, 18, 65, 17, 16, 17, 31, 15, 13, 25, 20}, {3710, 18, 65, 17, 16, 17, 31, 15, 13, 25, 20}, {3700, 18, 65, 17, 16, 17, 31, 15, 13, 25, 20}, {3690, 18, 65, 17, 16, 17, 31, 15, 13, 25, 20}, {3680, 18, 64, 17, 16, 17, 31, 15, 13, 25, 20}, {3670, 18, 64, 17, 16, 17, 30, 15, 13, 25, 20}, {3660, 17, 65, 17, 16, 17, 30, 15, 13, 25, 20}, {3650, 17, 65, 17, 16, 17, 30, 15, 13, 25, 20}, {3640, 17, 65, 17, 16, 17, 30, 15, 13, 25, 20}, {3630, 17, 64, 17, 16, 17, 30, 15, 13, 24, 20}, {3620, 17, 64, 17, 16, 17, 30, 15, 13, 24, 20}, {3610, 17, 64, 17, 16, 17, 30, 15, 13, 24, 20}, {3600, 17, 64, 16, 16, 17, 29, 15, 13, 24, 20}, {3590, 17, 63, 16, 15, 17, 29, 15, 13, 24, 20}, {3580, 17, 63, 16, 15, 16, 30, 15, 13, 24, 20}, {3570, 17, 63, 16, 15, 16, 30, 15, 13, 24, 19}, {3560, 17, 63, 16, 15, 16, 30, 14, 13, 24, 19}, {3550, 17, 62, 16, 15, 16, 30, 14, 13, 24, 19}, {3540, 17, 62, 16, 15, 16, 30, 14, 13, 24, 19}, {3530, 17, 62, 16, 15, 16, 29, 14, 13, 24, 19}, {3520, 17, 62, 16, 15, 16, 29, 14, 13, 24, 19}, {3510, 17, 62, 16, 15, 16, 29, 14, 13, 24, 19}, {3500, 17, 61, 16, 15, 16, 29, 14, 13, 24, 19}, {3490, 17, 61, 16, 15, 16, 29, 14, 13, 23, 19}, {3480, 17, 61, 16, 15, 16, 29, 14, 13, 23, 19}, {3470, 17, 61, 16, 15, 16, 29, 14, 13, 23, 19}, {3460, 16, 61, 16, 15, 16, 28, 14, 12, 23, 19}, {3450, 16, 61, 16, 15, 16, 28, 14, 12, 23, 19}, {3440, 16, 61, 16, 15, 16, 28, 14, 12, 23, 19}, {3430, 16, 61, 16, 15, 16, 28, 14, 12, 23, 19}, {3420, 16, 60, 16, 15, 16, 28, 14, 12, 23, 19}, {3410, 16, 60, 16, 15, 16, 28, 14, 12, 23, 18}, {3400, 16, 60, 15, 15, 16, 28, 14, 12, 23, 18}, {3390, 16, 60, 15, 15, 16, 28, 14, 12, 23, 18}, {3380, 16, 59, 15, 15, 16, 27, 14, 12, 23, 18}, {3370, 16, 59, 15, 15, 15, 28, 14, 12, 23, 18}, {3360, 16, 59, 15, 14, 15, 28, 14, 12, 23, 18}, {3350, 16, 59, 15, 14, 15, 28, 14, 12, 23, 18}, {3340, 16, 59, 15, 14, 15, 28, 14, 12, 22, 18}, {3330, 16, 58, 15, 14, 15, 28, 14, 12, 22, 18}, {3320, 16, 58, 15, 14, 15, 28, 13, 12, 22, 18}, {3310, 16, 58, 15, 14, 15, 27, 13, 12, 22, 18}, {3300, 16, 58, 15, 14, 15, 27, 13, 12, 22, 18}, {3290, 16, 57, 15, 14, 15, 27, 13, 12, 22, 18}, {3280, 16, 57, 15, 14, 15, 27, 13, 12, 22, 18}, {3270, 16, 57, 15, 14, 15, 27, 13, 12, 22, 18}, {3260, 15, 58, 15, 14, 15, 27, 13, 12, 22, 18}, {3250, 15, 57, 15, 14, 15, 27, 13, 12, 22, 18}, {3240, 15, 57, 15, 14, 15, 26, 13, 12, 22, 17}, {3230, 15, 57, 15, 14, 15, 26, 13, 12, 22, 17}, {3220, 15, 57, 15, 14, 15, 26, 13, 12, 22, 17}, {3210, 15, 56, 15, 14, 15, 26, 13, 12, 22, 17}, {3200, 15, 56, 14, 14, 15, 26, 13, 11, 21, 17}, {3190, 15, 56, 14, 14, 15, 26, 13, 11, 21, 17}, {3180, 15, 56, 14, 14, 15, 26, 13, 11, 21, 17}, {3170, 15, 56, 14, 14, 15, 25, 13, 11, 21, 17}, {3160, 15, 55, 14, 14, 14, 26, 13, 11, 21, 17}, {3150, 15, 55, 14, 14, 14, 26, 13, 11, 21, 17}, {3140, 15, 55, 14, 14, 14, 26, 13, 11, 21, 17}, {3130, 15, 55, 14, 14, 14, 26, 13, 11, 21, 17}, {3120, 15, 54, 14, 13, 14, 26, 13, 11, 21, 17}, {3110, 15, 54, 14, 13, 14, 26, 13, 11, 21, 17}, {3100, 15, 54, 14, 13, 14, 26, 13, 11, 21, 17}, {3090, 15, 54, 14, 13, 14, 25, 12, 11, 21, 17}, {3080, 15, 53, 14, 13, 14, 25, 12, 11, 21, 17}, {3070, 14, 54, 14, 13, 14, 25, 12, 11, 21, 16}, {3060, 14, 54, 14, 13, 14, 25, 12, 11, 21, 16}, {3050, 14, 54, 14, 13, 14, 25, 12, 11, 20, 16}, {3040, 14, 53, 14, 13, 14, 25, 12, 11, 20, 16}, {3030, 14, 53, 14, 13, 14, 25, 12, 11, 20, 16}, {3020, 14, 53, 14, 13, 14, 24, 12, 11, 20, 16}, {3010, 14, 53, 14, 13, 14, 24, 12, 11, 20, 16}, {3000, 14, 53, 13, 13, 14, 24, 12, 11, 20, 16}, {2990, 14, 52, 13, 13, 14, 24, 12, 11, 20, 16}, {2980, 14, 52, 13, 13, 14, 24, 12, 11, 20, 16}, {2970, 14, 52, 13, 13, 14, 24, 12, 11, 20, 16}, {2960, 14, 52, 13, 13, 14, 24, 12, 11, 20, 16}, {2950, 14, 51, 13, 13, 13, 24, 12, 11, 20, 16}, {2940, 14, 51, 13, 13, 13, 24, 12, 11, 20, 16}, {2930, 14, 51, 13, 13, 13, 24, 12, 10, 20, 16}, {2920, 14, 51, 13, 13, 13, 24, 12, 10, 20, 16}, {2910, 14, 50, 13, 13, 13, 24, 12, 10, 20, 15}, {2900, 14, 50, 13, 13, 13, 24, 12, 10, 19, 15}, {2890, 14, 50, 13, 12, 13, 24, 12, 10, 19, 15}, {2880, 14, 50, 13, 12, 13, 23, 12, 10, 19, 15}, {2870, 13, 50, 13, 12, 13, 23, 12, 10, 19, 15}, {2860, 13, 50, 13, 12, 13, 23, 12, 10, 19, 15}, {2850, 13, 50, 13, 12, 13, 23, 11, 10, 19, 15}, {2840, 13, 50, 13, 12, 13, 23, 11, 10, 19, 15}, {2830, 13, 50, 13, 12, 13, 23, 11, 10, 19, 15}, {2820, 13, 49, 13, 12, 13, 23, 11, 10, 19, 15}, {2810, 13, 49, 13, 12, 13, 23, 11, 10, 19, 15}, {2800, 13, 49, 12, 12, 13, 22, 11, 10, 19, 15}, {2790, 13, 49, 12, 12, 13, 22, 11, 10, 19, 15}, {2780, 13, 48, 12, 12, 13, 22, 11, 10, 19, 15}, {2770, 13, 48, 12, 12, 13, 22, 11, 10, 19, 15}, {2760, 13, 48, 12, 12, 13, 22, 11, 10, 18, 15}, {2750, 13, 48, 12, 12, 13, 22, 11, 10, 18, 15}, {2740, 13, 47, 12, 12, 12, 23, 11, 10, 18, 14}, {2730, 13, 47, 12, 12, 12, 22, 11, 10, 18, 14}, {2720, 13, 47, 12, 12, 12, 22, 11, 10, 18, 14}, {2710, 13, 47, 12, 12, 12, 22, 11, 10, 18, 14}, {2700, 13, 47, 12, 12, 12, 22, 11, 10, 18, 14}, {2690, 13, 46, 12, 12, 12, 22, 11, 10, 18, 14}, {2680, 13, 46, 12, 12, 12, 22, 11, 10, 18, 14}, {2670, 12, 47, 12, 12, 12, 22, 11, 10, 18, 14}, {2660, 12, 47, 12, 12, 12, 21, 11, 9, 18, 14}, {2650, 12, 46, 12, 11, 12, 21, 11, 9, 18, 14}, {2640, 12, 46, 12, 11, 12, 21, 11, 9, 18, 14}, {2630, 12, 46, 12, 11, 12, 21, 11, 9, 18, 14}, {2620, 12, 46, 12, 11, 12, 21, 10, 9, 18, 14}, {2610, 12, 45, 12, 11, 12, 21, 10, 9, 17, 14}, {2600, 12, 45, 11, 11, 12, 21, 10, 9, 17, 14}, {2590, 12, 45, 11, 11, 12, 20, 10, 9, 17, 14}, {2580, 12, 45, 11, 11, 12, 20, 10, 9, 17, 14}, {2570, 12, 44, 11, 11, 12, 20, 10, 9, 17, 13}, {2560, 12, 44, 11, 11, 12, 20, 10, 9, 17, 13}, {2550, 12, 44, 11, 11, 12, 20, 10, 9, 17, 13}, {2540, 12, 44, 11, 11, 11, 21, 10, 9, 17, 13}, {2530, 12, 44, 11, 11, 11, 21, 10, 9, 17, 13}, {2520, 12, 43, 11, 11, 11, 21, 10, 9, 17, 13}, {2510, 12, 43, 11, 11, 11, 20, 10, 9, 17, 13}, {2500, 12, 43, 11, 11, 11, 20, 10, 9, 17, 13}, {2490, 12, 43, 11, 11, 11, 20, 10, 9, 17, 13}, {2480, 12, 42, 11, 11, 11, 20, 10, 9, 17, 13}, {2470, 11, 43, 11, 11, 11, 20, 10, 9, 16, 13}, {2460, 11, 43, 11, 11, 11, 20, 10, 9, 16, 13}, {2450, 11, 43, 11, 11, 11, 20, 10, 9, 16, 13}, {2440, 11, 42, 11, 11, 11, 19, 10, 9, 16, 13}, {2430, 11, 42, 11, 11, 11, 19, 10, 9, 16, 13}, {2420, 11, 42, 11, 10, 11, 19, 10, 9, 16, 13}, {2410, 11, 42, 11, 10, 11, 19, 10, 9, 16, 12}, {2400, 11, 41, 10, 10, 11, 19, 10, 8, 16, 12}, {2390, 11, 41, 10, 10, 11, 19, 10, 8, 16, 12}, {2380, 11, 41, 10, 10, 11, 19, 9, 8, 16, 12}, {2370, 11, 41, 10, 10, 11, 18, 9, 8, 16, 12}, {2360, 11, 41, 10, 10, 11, 18, 9, 8, 16, 12}, {2350, 11, 40, 10, 10, 11, 18, 9, 8, 16, 12}, {2340, 11, 40, 10, 10, 11, 18, 9, 8, 16, 12}, {2330, 11, 40, 10, 10, 10, 19, 9, 8, 16, 12}, {2320, 11, 40, 10, 10, 10, 19, 9, 8, 15, 12}, {2310, 11, 39, 10, 10, 10, 19, 9, 8, 15, 12}, {2300, 11, 39, 10, 10, 10, 18, 9, 8, 15, 12}, {2290, 11, 39, 10, 10, 10, 18, 9, 8, 15, 12}, {2280, 11, 39, 10, 10, 10, 18, 9, 8, 15, 12}, {2270, 10, 39, 10, 10, 10, 18, 9, 8, 15, 12}, {2260, 10, 39, 10, 10, 10, 18, 9, 8, 15, 12}, {2250, 10, 39, 10, 10, 10, 18, 9, 8, 15, 12}, {2240, 10, 39, 10, 10, 10, 18, 9, 8, 15, 11}, {2230, 10, 38, 10, 10, 10, 18, 9, 8, 15, 11}, {2220, 10, 38, 10, 10, 10, 17, 9, 8, 15, 11}, {2210, 10, 38, 10, 10, 10, 17, 9, 8, 15, 11}, {2200, 10, 38, 9, 10, 10, 17, 9, 8, 15, 11}, {2190, 10, 38, 9, 9, 10, 17, 9, 8, 15, 11}, {2180, 10, 37, 9, 9, 10, 17, 9, 8, 14, 11}, {2170, 10, 37, 9, 9, 10, 17, 9, 8, 14, 11}, {2160, 10, 37, 9, 9, 10, 17, 9, 8, 14, 11}, {2150, 10, 37, 9, 9, 10, 16, 8, 8, 14, 11}, {2140, 10, 36, 9, 9, 10, 16, 8, 8, 14, 11}, {2130, 10, 36, 9, 9, 10, 16, 8, 7, 14, 11}, {2120, 10, 36, 9, 9, 9, 17, 8, 7, 14, 11}, {2110, 10, 36, 9, 9, 9, 17, 8, 7, 14, 11}, {2100, 10, 35, 9, 9, 9, 17, 8, 7, 14, 11}, {2090, 10, 35, 9, 9, 9, 17, 8, 7, 14, 11}, {2080, 9, 36, 9, 9, 9, 16, 8, 7, 14, 11}, {2070, 9, 36, 9, 9, 9, 16, 8, 7, 14, 10}, {2060, 9, 35, 9, 9, 9, 16, 8, 7, 14, 10}, {2050, 9, 35, 9, 9, 9, 16, 8, 7, 14, 10}, {2040, 9, 35, 9, 9, 9, 16, 8, 7, 14, 10}, {2030, 9, 35, 9, 9, 9, 16, 8, 7, 13, 10}, {2020, 9, 35, 9, 9, 9, 16, 8, 7, 13, 10}, {2010, 9, 34, 9, 9, 9, 15, 8, 7, 13, 10}, {2000, 9, 34, 8, 9, 9, 15, 8, 7, 13, 10}, {1990, 9, 34, 8, 9, 9, 15, 8, 7, 13, 10}, {1980, 9, 34, 8, 9, 9, 15, 8, 7, 13, 10}, {1970, 9, 33, 8, 9, 9, 15, 8, 7, 13, 10}, {1960, 9, 33, 8, 9, 9, 15, 8, 7, 13, 10}, {1950, 9, 33, 8, 8, 9, 15, 8, 7, 13, 10}, {1940, 9, 33, 8, 8, 9, 15, 8, 7, 13, 10}, {1930, 9, 32, 8, 8, 9, 14, 8, 7, 13, 10}, {1920, 9, 32, 8, 8, 9, 14, 8, 7, 13, 10}, {1910, 9, 32, 8, 8, 8, 15, 7, 7, 13, 9}, {1900, 9, 32, 8, 8, 8, 15, 7, 7, 13, 9}, {1890, 9, 31, 8, 8, 8, 15, 7, 7, 12, 9}, {1880, 8, 32, 8, 8, 8, 15, 7, 7, 12, 9}, {1870, 8, 32, 8, 8, 8, 15, 7, 7, 12, 9}, {1860, 8, 32, 8, 8, 8, 14, 7, 6, 12, 9}, {1850, 8, 32, 8, 8, 8, 14, 7, 6, 12, 9}, {1840, 8, 31, 8, 8, 8, 14, 7, 6, 12, 9}, {1830, 8, 31, 8, 8, 8, 14, 7, 6, 12, 9}, {1820, 8, 31, 8, 8, 8, 14, 7, 6, 12, 9}, {1810, 8, 31, 8, 8, 8, 14, 7, 6, 12, 9}, {1800, 8, 30, 7, 8, 8, 14, 7, 6, 12, 9}, {1790, 8, 30, 7, 8, 8, 13, 7, 6, 12, 9}, {1780, 8, 30, 7, 8, 8, 13, 7, 6, 12, 9}, {1770, 8, 30, 7, 8, 8, 13, 7, 6, 12, 9}, {1760, 8, 29, 7, 8, 8, 13, 7, 6, 12, 9}, {1750, 8, 29, 7, 8, 8, 13, 7, 6, 12, 9}, {1740, 8, 29, 7, 8, 8, 13, 7, 6, 11, 8}, {1730, 8, 29, 7, 8, 8, 13, 7, 6, 11, 8}, {1720, 8, 29, 7, 7, 8, 13, 7, 6, 11, 8}, {1710, 8, 28, 7, 7, 8, 12, 7, 6, 11, 8}, {1700, 8, 28, 7, 7, 7, 13, 7, 6, 11, 8}, {1690, 8, 28, 7, 7, 7, 13, 7, 6, 11, 8}, {1680, 7, 29, 7, 7, 7, 13, 6, 6, 11, 8}, {1670, 7, 28, 7, 7, 7, 13, 6, 6, 11, 8}, {1660, 7, 28, 7, 7, 7, 13, 6, 6, 11, 8}, {1650, 7, 28, 7, 7, 7, 13, 6, 6, 11, 8}, {1640, 7, 28, 7, 7, 7, 12, 6, 6, 11, 8}, {1630, 7, 27, 7, 7, 7, 12, 6, 6, 11, 8}, {1620, 7, 27, 7, 7, 7, 12, 6, 6, 11, 8}, {1610, 7, 27, 7, 7, 7, 12, 6, 6, 11, 8}, {1600, 7, 27, 6, 7, 7, 12, 6, 5, 10, 8}, {1590, 7, 26, 6, 7, 7, 12, 6, 5, 10, 8}, {1580, 7, 26, 6, 7, 7, 12, 6, 5, 10, 7}, {1570, 7, 26, 6, 7, 7, 11, 6, 5, 10, 7}, {1560, 7, 26, 6, 7, 7, 11, 6, 5, 10, 7}, {1550, 7, 26, 6, 7, 7, 11, 6, 5, 10, 7}, {1540, 7, 25, 6, 7, 7, 11, 6, 5, 10, 7}, {1530, 7, 25, 6, 7, 7, 11, 6, 5, 10, 7}, {1520, 7, 25, 6, 7, 7, 11, 6, 5, 10, 7}, {1510, 7, 25, 6, 7, 7, 11, 6, 5, 10, 7}, {1500, 7, 24, 6, 7, 7, 10, 6, 5, 10, 7}, {1490, 59, 25, 6, 77, 59, 10, 70, 44, 9, 73}, {1480, 59, 24, 6, 76, 58, 10, 70, 44, 9, 73}, {1470, 58, 24, 6, 76, 58, 10, 69, 44, 9, 72}, {1460, 58, 24, 6, 76, 58, 10, 69, 43, 9, 72}, {1450, 58, 24, 6, 75, 57, 10, 68, 43, 9, 71}, {1440, 57, 24, 6, 75, 57, 10, 68, 43, 9, 71}, {1430, 57, 23, 6, 75, 57, 10, 68, 43, 8, 70}, {1420, 56, 23, 6, 74, 57, 9, 67, 43, 8, 70}, {1410, 56, 23, 6, 74, 57, 9, 67, 43, 8, 69}, {1400, 56, 23, 5, 74, 55, 9, 67, 41, 8, 69}, {1390, 55, 23, 5, 73, 55, 9, 66, 41, 8, 68}, {1380, 55, 23, 5, 73, 54, 9, 66, 41, 8, 68}, {1370, 54, 22, 5, 72, 54, 9, 66, 41, 8, 67}, {1360, 54, 22, 5, 72, 54, 9, 65, 40, 8, 67}, {1350, 54, 22, 5, 72, 53, 9, 65, 40, 8, 66}, {1340, 53, 22, 5, 71, 53, 9, 65, 40, 8, 66}, {1330, 53, 22, 5, 71, 53, 9, 64, 39, 8, 65}, {1320, 52, 22, 5, 71, 53, 8, 64, 40, 8, 65}, {1310, 52, 21, 5, 70, 53, 8, 64, 40, 8, 64}, {1300, 51, 21, 5, 70, 51, 8, 63, 38, 8, 64}, {1290, 51, 21, 5, 70, 51, 8, 63, 38, 7, 64}, {1280, 51, 21, 5, 69, 51, 8, 63, 38, 7, 63}, {1270, 50, 21, 5, 69, 50, 8, 62, 38, 7, 63}, {1260, 50, 20, 5, 69, 50, 8, 62, 37, 7, 62}, {1250, 49, 20, 5, 68, 49, 8, 62, 37, 7, 62}, {1240, 49, 20, 5, 68, 49, 8, 61, 37, 7, 61}, {1230, 49, 20, 5, 68, 49, 8, 61, 36, 7, 61}, {1220, 48, 20, 5, 67, 48, 8, 61, 36, 7, 60}, {1210, 48, 19, 5, 67, 48, 7, 60, 36, 7, 60}, {1200, 49, 19, 4, 67, 49, 7, 60, 36, 7, 59}, {1190, 48, 19, 4, 66, 48, 7, 60, 36, 7, 59}, {1180, 48, 19, 4, 66, 48, 7, 59, 36, 7, 58}, {1170, 46, 19, 4, 66, 46, 7, 59, 35, 7, 58}, {1160, 46, 18, 4, 65, 46, 7, 59, 34, 7, 57}, {1150, 45, 18, 4, 65, 46, 7, 58, 34, 7, 57}, {1140, 45, 18, 4, 65, 45, 7, 58, 34, 6, 56}, {1130, 45, 18, 4, 64, 45, 7, 58, 33, 6, 56}, {1120, 44, 18, 4, 64, 44, 7, 57, 33, 6, 55}, {1110, 44, 18, 4, 64, 44, 7, 57, 33, 6, 55}, {1100, 43, 17, 4, 63, 44, 6, 57, 32, 6, 54}, {1090, 43, 17, 4, 63, 44, 6, 56, 33, 6, 54}, {1080, 43, 17, 4, 63, 44, 6, 56, 33, 6, 53}, {1070, 42, 17, 4, 62, 44, 6, 56, 33, 6, 53}, {1060, 42, 17, 4, 62, 42, 6, 55, 31, 6, 52}, {1050, 41, 17, 4, 62, 42, 6, 55, 31, 6, 52}, {1040, 41, 16, 4, 61, 41, 6, 54, 31, 6, 52}, {1030, 41, 16, 4, 61, 41, 6, 54, 30, 6, 51}, {1020, 40, 16, 4, 61, 41, 6, 54, 30, 6, 51}, {1010, 40, 16, 4, 60, 40, 6, 53, 30, 6, 50}, {1000, 39, 16, 3, 60, 40, 6, 53, 29, 5, 50}, { 990, 39, 15, 3, 60, 39, 6, 53, 29, 5, 49}, { 980, 39, 15, 3, 59, 39, 5, 52, 29, 5, 49}, { 970, 38, 15, 3, 59, 39, 5, 52, 29, 5, 48}, { 960, 38, 15, 3, 59, 39, 5, 52, 29, 5, 48}, { 950, 37, 15, 3, 58, 39, 5, 51, 29, 5, 47}, { 940, 37, 14, 3, 58, 39, 5, 51, 29, 5, 47}, { 930, 37, 14, 3, 57, 37, 5, 51, 27, 5, 46}, { 920, 36, 14, 3, 57, 37, 5, 50, 27, 5, 46}, { 910, 36, 14, 3, 57, 36, 5, 50, 27, 5, 45}, { 900, 35, 14, 3, 56, 36, 5, 50, 26, 5, 45}, { 890, 35, 14, 3, 56, 36, 5, 49, 26, 5, 44}, { 880, 35, 13, 3, 56, 35, 5, 49, 26, 5, 44}, { 870, 34, 13, 3, 55, 35, 4, 49, 26, 5, 43}, { 860, 34, 13, 3, 55, 35, 4, 48, 25, 5, 43}, { 850, 33, 13, 3, 55, 35, 4, 48, 26, 4, 42}, { 840, 33, 13, 3, 54, 35, 4, 48, 26, 4, 42}, { 830, 33, 12, 3, 54, 33, 4, 47, 24, 4, 41}, { 820, 32, 12, 3, 54, 33, 4, 47, 24, 4, 41}, { 810, 32, 12, 3, 53, 33, 4, 47, 24, 4, 40}, { 800, 31, 12, 2, 53, 32, 4, 46, 23, 4, 40}, { 790, 31, 12, 2, 53, 32, 4, 46, 23, 4, 39}, { 780, 30, 12, 2, 52, 31, 4, 46, 23, 4, 39}, { 770, 30, 11, 2, 52, 31, 4, 45, 23, 4, 39}, { 760, 30, 11, 2, 52, 31, 3, 45, 22, 4, 38}, { 750, 29, 11, 2, 51, 30, 3, 45, 22, 4, 38}, { 740, 29, 11, 2, 51, 30, 3, 44, 22, 4, 37}, { 730, 28, 11, 2, 51, 31, 3, 44, 22, 4, 37}, { 720, 28, 10, 2, 50, 30, 3, 44, 22, 4, 36}, { 710, 28, 10, 2, 50, 30, 3, 43, 22, 4, 36}, { 700, 27, 10, 2, 50, 28, 3, 43, 20, 3, 35}, { 690, 27, 10, 2, 49, 28, 3, 43, 20, 3, 35}, { 680, 26, 10, 2, 49, 28, 3, 42, 20, 3, 34}, { 670, 26, 10, 2, 49, 27, 3, 42, 20, 3, 34}, { 660, 26, 9, 2, 48, 27, 3, 42, 19, 3, 33}, { 650, 25, 9, 2, 48, 26, 3, 41, 19, 3, 33}, { 640, 25, 9, 2, 48, 26, 2, 41, 19, 3, 32}, { 630, 24, 9, 2, 47, 26, 2, 40, 18, 3, 32}, { 620, 24, 9, 2, 47, 26, 2, 40, 19, 3, 31}, { 610, 24, 8, 2, 47, 26, 2, 40, 19, 3, 31}, { 600, 23, 8, 1, 46, 26, 2, 39, 18, 3, 30}, { 590, 23, 8, 1, 46, 24, 2, 39, 17, 3, 30}, { 580, 22, 8, 1, 46, 24, 2, 39, 17, 3, 29}, { 570, 22, 8, 1, 45, 23, 2, 38, 17, 3, 29}, { 560, 22, 7, 1, 45, 23, 2, 38, 16, 2, 28}, { 550, 21, 7, 1, 45, 23, 2, 38, 16, 2, 28}, { 540, 21, 7, 1, 44, 22, 2, 37, 16, 2, 27}, { 530, 20, 7, 1, 44, 22, 1, 37, 15, 2, 27}, { 520, 20, 7, 1, 43, 21, 1, 37, 15, 2, 27}, { 510, 20, 6, 1, 43, 21, 1, 36, 15, 2, 26}, { 500, 19, 6, 1, 43, 22, 1, 36, 15, 2, 26}, { 490, 19, 6, 1, 42, 21, 1, 36, 15, 2, 25}, { 480, 18, 6, 1, 42, 21, 1, 35, 15, 2, 25}, { 470, 18, 6, 1, 42, 21, 1, 35, 15, 2, 24}, { 460, 18, 6, 1, 41, 19, 1, 35, 13, 2, 24}, { 450, 17, 5, 1, 41, 19, 1, 34, 13, 2, 23}, { 440, 17, 5, 1, 41, 18, 1, 34, 13, 2, 23}, { 430, 16, 5, 1, 40, 18, 0, 34, 12, 2, 22}, { 420, 16, 5, 1, 40, 18, 0, 33, 12, 2, 22}, { 410, 16, 5, 1, 40, 17, 0, 33, 12, 1, 21}, { 400, 15, 5, 0, 39, 17, 0, 33, 11, 1, 21}, { 390, 15, 4, 0, 39, 17, 0, 32, 12, 1, 20}, { 380, 14, 4, 0, 39, 17, 0, 32, 12, 1, 20}, { 370, 14, 4, 0, 38, 17, 0, 32, 12, 1, 19}, { 360, 14, 4, 0, 38, 15, 0, 31, 10, 1, 19}, { 350, 13, 4, 0, 38, 15, 0, 31, 10, 1, 18}, { 340, 13, 3, 0, 37, 15, 0, 31, 10, 1, 18}, { 330, 12, 3, 0, 37, 14, 0, 30, 9, 1, 17}, { 320, 12, 3, 0, 37, 14, 0, 30, 9, 1, 17}, { 310, 12, 3, 0, 36, 13, 0, 30, 9, 1, 16}, { 300, 11, 3, 0, 36, 13, 0, 29, 8, 1, 16}, { 290, 11, 2, 0, 36, 13, 0, 29, 8, 1, 15}, { 280, 10, 2, 0, 35, 12, 0, 29, 8, 1, 15}, { 270, 10, 2, 0, 35, 12, 0, 28, 8, 0, 14}, { 260, 9, 2, 0, 35, 12, 0, 28, 8, 0, 14}, { 250, 9, 2, 0, 34, 12, 0, 28, 8, 0, 14}, { 240, 9, 2, 0, 34, 12, 0, 27, 8, 0, 13}, { 230, 8, 1, 0, 34, 10, 0, 27, 6, 0, 13}, { 220, 8, 1, 0, 33, 10, 0, 27, 6, 0, 12}, { 210, 7, 1, 0, 33, 10, 0, 26, 6, 0, 12}, { 200, 7, 1, 0, 33, 9, 0, 26, 5, 0, 11}, { 190, 7, 1, 0, 32, 9, 0, 25, 5, 0, 11}, { 180, 6, 1, 0, 32, 8, 0, 25, 5, 0, 10}, { 170, 6, 0, 0, 32, 8, 0, 25, 5, 0, 10}, { 160, 5, 0, 0, 31, 8, 0, 24, 4, 0, 9}, { 150, 5, 0, 0, 31, 8, 0, 24, 5, 0, 9}, { 140, 5, 0, 0, 31, 8, 0, 24, 5, 0, 8}, { 130, 4, 0, 0, 30, 6, 0, 23, 3, 0, 8}, { 120, 4, 0, 0, 30, 6, 0, 23, 3, 0, 7}, { 110, 3, 0, 0, 30, 6, 0, 23, 3, 0, 7}, { 100, 3, 0, 0, 29, 5, 0, 22, 2, 0, 6}, { 90, 3, 0, 0, 29, 5, 0, 22, 2, 0, 6}, { 80, 2, 0, 0, 28, 5, 0, 22, 2, 0, 5}, }; static const struct samsung_mipi_cphy_timing samsung_mipi_cphy_timing_table[] = { { 3500, 39, 50, 25, 29, 54, 1 }, { 3490, 39, 50, 25, 29, 54, 1 }, { 3480, 39, 50, 25, 29, 54, 1 }, { 3470, 39, 50, 25, 29, 54, 1 }, { 3460, 39, 50, 25, 29, 54, 1 }, { 3450, 39, 50, 25, 29, 54, 1 }, { 3440, 38, 50, 25, 29, 54, 1 }, { 3430, 38, 50, 25, 29, 53, 1 }, { 3420, 38, 50, 25, 29, 53, 1 }, { 3410, 38, 50, 25, 29, 53, 1 }, { 3400, 38, 50, 25, 29, 53, 1 }, { 3390, 38, 50, 25, 29, 53, 1 }, { 3380, 38, 50, 25, 28, 53, 1 }, { 3370, 38, 50, 25, 28, 52, 1 }, { 3360, 37, 50, 25, 28, 52, 1 }, { 3350, 37, 50, 25, 28, 52, 1 }, { 3340, 37, 50, 25, 28, 52, 1 }, { 3330, 37, 50, 25, 28, 52, 1 }, { 3320, 37, 50, 25, 28, 52, 1 }, { 3310, 37, 50, 25, 28, 52, 1 }, { 3300, 37, 50, 25, 28, 51, 1 }, { 3290, 37, 50, 25, 28, 51, 1 }, { 3280, 37, 50, 25, 28, 51, 1 }, { 3270, 36, 50, 25, 28, 51, 1 }, { 3260, 36, 50, 25, 27, 51, 1 }, { 3250, 36, 50, 25, 27, 51, 1 }, { 3240, 36, 50, 25, 27, 50, 1 }, { 3230, 36, 50, 25, 27, 50, 1 }, { 3220, 36, 50, 25, 27, 50, 1 }, { 3210, 36, 50, 25, 27, 50, 1 }, { 3200, 36, 50, 25, 27, 50, 1 }, { 3190, 36, 50, 25, 27, 50, 1 }, { 3180, 35, 50, 25, 27, 49, 1 }, { 3170, 35, 50, 25, 27, 49, 1 }, { 3160, 35, 50, 25, 27, 49, 1 }, { 3150, 35, 50, 25, 26, 49, 1 }, { 3140, 35, 50, 25, 26, 49, 1 }, { 3130, 35, 50, 25, 26, 49, 1 }, { 3120, 35, 50, 25, 26, 49, 1 }, { 3110, 35, 50, 25, 26, 48, 1 }, { 3100, 34, 50, 25, 26, 48, 1 }, { 3090, 34, 50, 25, 26, 48, 1 }, { 3080, 34, 50, 25, 26, 48, 1 }, { 3070, 34, 50, 25, 26, 48, 1 }, { 3060, 34, 50, 25, 26, 48, 1 }, { 3050, 34, 50, 25, 26, 47, 1 }, { 3040, 34, 50, 25, 26, 47, 1 }, { 3030, 34, 50, 25, 25, 47, 1 }, { 3020, 34, 50, 25, 25, 47, 1 }, { 3010, 33, 50, 25, 25, 47, 1 }, { 3000, 33, 50, 25, 25, 47, 1 }, { 2990, 33, 50, 25, 25, 46, 1 }, { 2980, 33, 50, 25, 25, 46, 1 }, { 2970, 33, 50, 25, 25, 46, 1 }, { 2960, 33, 50, 25, 25, 46, 1 }, { 2950, 33, 50, 25, 25, 46, 1 }, { 2940, 33, 50, 25, 25, 46, 1 }, { 2930, 33, 50, 25, 25, 46, 1 }, { 2920, 32, 50, 25, 25, 45, 1 }, { 2910, 32, 50, 25, 24, 45, 1 }, { 2900, 32, 50, 25, 24, 45, 1 }, { 2890, 32, 50, 25, 24, 45, 1 }, { 2880, 32, 50, 25, 24, 45, 1 }, { 2870, 32, 50, 25, 24, 45, 1 }, { 2860, 32, 50, 25, 24, 44, 1 }, { 2850, 32, 50, 25, 24, 44, 1 }, { 2840, 31, 50, 25, 24, 44, 1 }, { 2830, 31, 50, 25, 24, 44, 1 }, { 2820, 31, 50, 25, 24, 44, 1 }, { 2810, 31, 50, 25, 24, 44, 1 }, { 2800, 31, 50, 25, 23, 43, 1 }, { 2790, 31, 50, 25, 23, 43, 1 }, { 2780, 31, 50, 25, 23, 43, 1 }, { 2770, 31, 50, 25, 23, 43, 1 }, { 2760, 31, 50, 25, 23, 43, 1 }, { 2750, 30, 50, 25, 23, 43, 1 }, { 2740, 30, 50, 25, 23, 43, 1 }, { 2730, 30, 50, 25, 23, 42, 1 }, { 2720, 30, 50, 25, 23, 42, 1 }, { 2710, 30, 50, 25, 23, 42, 1 }, { 2700, 30, 50, 25, 23, 42, 1 }, { 2690, 30, 50, 25, 23, 42, 1 }, { 2680, 30, 50, 25, 22, 42, 1 }, { 2670, 30, 50, 25, 22, 41, 1 }, { 2660, 29, 50, 25, 22, 41, 1 }, { 2650, 29, 50, 25, 22, 41, 1 }, { 2640, 29, 50, 25, 22, 41, 1 }, { 2630, 29, 50, 25, 22, 41, 1 }, { 2620, 29, 50, 25, 22, 41, 1 }, { 2610, 29, 50, 25, 22, 41, 1 }, { 2600, 29, 50, 25, 22, 40, 1 }, { 2590, 29, 50, 25, 22, 40, 1 }, { 2580, 28, 50, 25, 22, 40, 1 }, { 2570, 28, 50, 25, 22, 40, 1 }, { 2560, 28, 50, 25, 21, 40, 1 }, { 2550, 28, 50, 25, 21, 40, 1 }, { 2540, 28, 50, 25, 21, 39, 1 }, { 2530, 28, 50, 25, 21, 39, 1 }, { 2520, 28, 50, 25, 21, 39, 1 }, { 2510, 28, 50, 25, 21, 39, 1 }, { 2500, 28, 50, 25, 21, 39, 1 }, { 2490, 27, 50, 25, 21, 39, 1 }, { 2480, 27, 50, 25, 21, 38, 1 }, { 2470, 27, 50, 25, 21, 38, 1 }, { 2460, 27, 50, 25, 21, 38, 1 }, { 2450, 27, 50, 25, 20, 38, 1 }, { 2440, 27, 50, 25, 20, 38, 1 }, { 2430, 27, 50, 25, 20, 38, 1 }, { 2420, 27, 50, 25, 20, 38, 1 }, { 2410, 27, 50, 25, 20, 37, 1 }, { 2400, 26, 50, 25, 20, 37, 1 }, { 2390, 26, 50, 25, 20, 37, 1 }, { 2380, 26, 50, 25, 20, 37, 1 }, { 2370, 26, 50, 25, 20, 37, 1 }, { 2360, 26, 50, 25, 20, 37, 1 }, { 2350, 26, 50, 25, 20, 36, 1 }, { 2340, 26, 50, 25, 20, 36, 1 }, { 2330, 26, 50, 25, 19, 36, 1 }, { 2320, 25, 50, 25, 19, 36, 1 }, { 2310, 25, 50, 25, 19, 36, 1 }, { 2300, 25, 50, 25, 19, 36, 1 }, { 2290, 25, 50, 25, 19, 35, 1 }, { 2280, 25, 50, 25, 19, 35, 1 }, { 2270, 25, 50, 25, 19, 35, 1 }, { 2260, 25, 50, 25, 19, 35, 1 }, { 2250, 25, 50, 25, 19, 35, 1 }, { 2240, 25, 50, 25, 19, 35, 1 }, { 2230, 24, 50, 25, 19, 35, 1 }, { 2220, 24, 50, 25, 19, 34, 1 }, { 2210, 24, 50, 25, 18, 34, 1 }, { 2200, 24, 50, 25, 18, 34, 1 }, { 2190, 24, 50, 25, 18, 34, 1 }, { 2180, 24, 50, 25, 18, 34, 1 }, { 2170, 24, 50, 25, 18, 34, 1 }, { 2160, 24, 50, 25, 18, 33, 1 }, { 2150, 24, 50, 25, 18, 33, 1 }, { 2140, 23, 50, 25, 18, 33, 1 }, { 2130, 23, 50, 25, 18, 33, 1 }, { 2120, 23, 50, 25, 18, 33, 1 }, { 2110, 23, 50, 25, 18, 33, 1 }, { 2100, 23, 50, 25, 17, 32, 1 }, { 2090, 23, 50, 25, 17, 32, 1 }, { 2080, 23, 50, 25, 17, 32, 1 }, { 2070, 23, 50, 25, 17, 32, 1 }, { 2060, 22, 50, 25, 17, 32, 1 }, { 2050, 22, 50, 25, 17, 32, 1 }, { 2040, 22, 50, 25, 17, 32, 1 }, { 2030, 22, 50, 25, 17, 31, 1 }, { 2020, 22, 50, 25, 17, 31, 1 }, { 2010, 22, 50, 25, 17, 31, 1 }, { 2000, 22, 50, 25, 17, 31, 1 }, { 1990, 22, 50, 25, 17, 31, 1 }, { 1980, 22, 50, 25, 16, 31, 1 }, { 1970, 21, 50, 25, 16, 30, 1 }, { 1960, 21, 50, 25, 16, 30, 1 }, { 1950, 21, 50, 25, 16, 30, 1 }, { 1940, 21, 50, 25, 16, 30, 1 }, { 1930, 21, 50, 25, 16, 30, 1 }, { 1920, 21, 50, 25, 16, 30, 1 }, { 1910, 21, 50, 25, 16, 30, 1 }, { 1900, 21, 50, 25, 16, 29, 1 }, { 1890, 21, 50, 25, 16, 29, 1 }, { 1880, 20, 50, 25, 16, 29, 1 }, { 1870, 20, 50, 25, 16, 29, 1 }, { 1860, 20, 50, 25, 15, 29, 1 }, { 1850, 20, 50, 25, 15, 29, 1 }, { 1840, 20, 50, 25, 15, 28, 1 }, { 1830, 20, 50, 25, 15, 28, 1 }, { 1820, 20, 50, 25, 15, 28, 1 }, { 1810, 20, 50, 25, 15, 28, 1 }, { 1800, 19, 50, 25, 15, 28, 1 }, { 1790, 19, 50, 25, 15, 28, 1 }, { 1780, 19, 50, 25, 15, 27, 1 }, { 1770, 19, 50, 25, 15, 27, 1 }, { 1760, 19, 50, 25, 15, 27, 1 }, { 1750, 19, 50, 25, 14, 27, 1 }, { 1740, 19, 50, 25, 14, 27, 1 }, { 1730, 19, 50, 25, 14, 27, 1 }, { 1720, 19, 50, 25, 14, 27, 1 }, { 1710, 18, 50, 25, 14, 26, 1 }, { 1700, 18, 50, 25, 14, 26, 1 }, { 1690, 18, 50, 25, 14, 26, 1 }, { 1680, 18, 50, 25, 14, 26, 1 }, { 1670, 18, 50, 25, 14, 26, 1 }, { 1660, 18, 50, 25, 14, 26, 1 }, { 1650, 18, 50, 25, 14, 25, 1 }, { 1640, 18, 50, 25, 14, 25, 1 }, { 1630, 18, 50, 25, 13, 25, 1 }, { 1620, 17, 50, 25, 13, 25, 1 }, { 1610, 17, 50, 25, 13, 25, 1 }, { 1600, 17, 50, 25, 13, 25, 1 }, { 1590, 17, 50, 25, 13, 24, 1 }, { 1580, 17, 50, 25, 13, 24, 1 }, { 1570, 17, 50, 25, 13, 24, 1 }, { 1560, 17, 50, 25, 13, 24, 1 }, { 1550, 17, 50, 25, 13, 24, 1 }, { 1540, 16, 50, 25, 13, 24, 1 }, { 1530, 16, 50, 25, 13, 24, 1 }, { 1520, 16, 50, 25, 13, 23, 1 }, { 1510, 16, 50, 25, 12, 23, 1 }, { 1500, 16, 50, 25, 12, 23, 1 }, { 1490, 16, 50, 25, 12, 23, 1 }, { 1480, 16, 50, 25, 12, 23, 1 }, { 1470, 16, 50, 25, 12, 23, 1 }, { 1460, 16, 50, 25, 12, 22, 1 }, { 1450, 15, 50, 25, 12, 22, 1 }, { 1440, 15, 50, 25, 12, 22, 1 }, { 1430, 15, 50, 25, 12, 22, 1 }, { 1420, 15, 50, 25, 12, 22, 1 }, { 1410, 15, 50, 25, 12, 22, 1 }, { 1400, 15, 50, 25, 11, 21, 1 }, { 1390, 15, 50, 25, 11, 21, 1 }, { 1380, 15, 50, 25, 11, 21, 1 }, { 1370, 15, 50, 25, 11, 21, 1 }, { 1360, 14, 50, 25, 11, 21, 1 }, { 1350, 14, 50, 25, 11, 21, 1 }, { 1340, 14, 50, 25, 11, 21, 1 }, { 1330, 14, 50, 25, 11, 20, 1 }, { 1320, 14, 50, 25, 11, 20, 1 }, { 1310, 14, 50, 25, 11, 20, 1 }, { 1300, 14, 50, 25, 11, 20, 1 }, { 1290, 14, 50, 25, 11, 20, 1 }, { 1280, 13, 50, 25, 10, 20, 1 }, { 1270, 13, 50, 25, 10, 19, 1 }, { 1260, 13, 50, 25, 10, 19, 1 }, { 1250, 13, 50, 25, 10, 19, 1 }, { 1240, 13, 50, 25, 10, 19, 1 }, { 1230, 13, 50, 25, 10, 19, 1 }, { 1220, 13, 50, 25, 10, 19, 1 }, { 1210, 13, 50, 25, 10, 19, 1 }, { 1200, 13, 50, 25, 10, 18, 1 }, { 1190, 12, 50, 25, 10, 18, 1 }, { 1180, 12, 50, 25, 10, 18, 1 }, { 1170, 12, 50, 25, 10, 18, 1 }, { 1160, 12, 50, 25, 9, 18, 1 }, { 1150, 12, 50, 25, 9, 18, 1 }, { 1140, 12, 50, 25, 9, 17, 1 }, { 1130, 12, 50, 25, 9, 17, 1 }, { 1120, 12, 50, 25, 9, 17, 1 }, { 1110, 12, 50, 25, 9, 17, 1 }, { 1100, 11, 50, 25, 9, 17, 1 }, { 1090, 11, 50, 25, 9, 17, 1 }, { 1080, 11, 50, 25, 9, 16, 1 }, { 1070, 11, 50, 25, 9, 16, 1 }, { 1060, 11, 50, 25, 9, 16, 1 }, { 1050, 11, 50, 25, 8, 16, 1 }, { 1040, 11, 50, 25, 8, 16, 1 }, { 1030, 11, 50, 25, 8, 16, 1 }, { 1020, 10, 50, 25, 8, 16, 1 }, { 1010, 10, 50, 25, 8, 15, 1 }, { 1000, 10, 50, 25, 8, 15, 1 }, { 990, 10, 50, 25, 8, 15, 2 }, { 980, 10, 50, 25, 8, 15, 2 }, { 970, 10, 50, 25, 8, 15, 2 }, { 960, 10, 50, 25, 8, 15, 2 }, { 950, 10, 50, 25, 8, 14, 2 }, { 940, 10, 50, 25, 8, 14, 2 }, { 930, 9, 50, 25, 7, 14, 2 }, { 920, 9, 50, 25, 7, 14, 2 }, { 910, 9, 50, 25, 7, 14, 2 }, { 900, 9, 50, 25, 7, 14, 2 }, { 890, 9, 50, 25, 7, 13, 2 }, { 880, 9, 50, 25, 7, 13, 2 }, { 870, 9, 50, 25, 7, 13, 2 }, { 860, 9, 50, 25, 7, 13, 2 }, { 850, 9, 50, 25, 7, 13, 2 }, { 840, 8, 50, 25, 7, 13, 2 }, { 830, 8, 50, 25, 7, 13, 2 }, { 820, 8, 50, 25, 7, 12, 2 }, { 810, 8, 50, 25, 6, 12, 2 }, { 800, 8, 50, 25, 6, 12, 2 }, { 790, 8, 50, 25, 6, 12, 2 }, { 780, 8, 50, 25, 6, 12, 2 }, { 770, 8, 50, 25, 6, 12, 2 }, { 760, 7, 50, 25, 6, 11, 2 }, { 750, 7, 50, 25, 6, 11, 2 }, { 740, 7, 50, 25, 6, 11, 2 }, { 730, 7, 50, 25, 6, 11, 2 }, { 720, 7, 50, 25, 6, 11, 2 }, { 710, 7, 50, 25, 6, 11, 2 }, { 700, 7, 50, 25, 5, 10, 2 }, { 690, 7, 50, 25, 5, 10, 2 }, { 680, 7, 50, 25, 5, 10, 2 }, { 670, 6, 50, 25, 5, 10, 2 }, { 660, 6, 50, 25, 5, 10, 2 }, { 650, 6, 50, 25, 5, 10, 2 }, { 640, 6, 50, 25, 5, 10, 2 }, { 630, 6, 50, 25, 5, 9, 2 }, { 620, 6, 50, 25, 5, 9, 2 }, { 610, 6, 50, 25, 5, 9, 2 }, { 600, 6, 50, 25, 5, 9, 2 }, { 590, 6, 50, 25, 5, 9, 2 }, { 580, 5, 50, 25, 4, 9, 2 }, { 570, 5, 50, 25, 4, 8, 2 }, { 560, 5, 50, 25, 4, 8, 2 }, { 550, 5, 50, 25, 4, 8, 2 }, { 540, 5, 50, 25, 4, 8, 2 }, { 530, 5, 50, 25, 4, 8, 2 }, { 520, 5, 50, 25, 4, 8, 2 }, { 510, 5, 50, 25, 4, 8, 2 }, { 500, 4, 50, 25, 4, 7, 2 }, { 490, 18, 50, 25, 14, 6, 2 }, { 480, 17, 50, 25, 14, 6, 2 }, { 470, 17, 50, 25, 14, 6, 2 }, { 460, 17, 50, 25, 13, 6, 2 }, { 450, 16, 50, 25, 13, 6, 2 }, { 440, 16, 50, 25, 13, 6, 2 }, { 430, 15, 50, 25, 12, 6, 2 }, { 420, 15, 50, 25, 12, 5, 2 }, { 410, 15, 50, 25, 12, 5, 2 }, { 400, 14, 50, 25, 11, 5, 2 }, { 390, 14, 50, 25, 11, 5, 2 }, { 380, 13, 50, 25, 11, 5, 2 }, { 370, 13, 50, 25, 11, 5, 2 }, { 360, 13, 50, 25, 10, 4, 2 }, { 350, 12, 50, 25, 10, 4, 2 }, { 340, 12, 50, 25, 10, 4, 2 }, { 330, 11, 50, 25, 9, 4, 2 }, { 320, 11, 50, 25, 9, 4, 2 }, { 310, 11, 50, 25, 9, 4, 2 }, { 300, 10, 50, 25, 8, 3, 2 }, { 290, 10, 50, 25, 8, 3, 2 }, { 280, 9, 50, 25, 8, 3, 2 }, { 270, 9, 50, 25, 8, 3, 2 }, { 260, 8, 50, 25, 7, 3, 2 }, { 250, 8, 50, 25, 7, 3, 2 }, { 240, 8, 50, 25, 7, 3, 2 }, { 230, 7, 50, 25, 6, 2, 2 }, { 220, 7, 50, 25, 6, 2, 2 }, { 210, 6, 50, 25, 6, 2, 2 }, { 200, 6, 50, 25, 5, 2, 2 }, { 190, 6, 50, 25, 5, 2, 2 }, { 180, 5, 50, 25, 5, 2, 2 }, { 170, 5, 50, 25, 5, 1, 2 }, { 160, 4, 50, 25, 4, 1, 2 }, { 150, 4, 50, 25, 4, 1, 2 }, { 140, 4, 50, 25, 4, 1, 2 }, { 130, 3, 50, 25, 3, 1, 2 }, { 120, 3, 50, 25, 3, 1, 2 }, { 110, 2, 50, 25, 3, 1, 2 }, { 100, 2, 50, 25, 2, 0, 2 }, { 90, 2, 50, 25, 2, 0, 2 }, { 80, 1, 50, 25, 2, 0, 2 }, }; struct hsfreq_range { u32 range_h; u16 cfg_bit; }; /* These tables must be sorted by .range_h ascending. */ static const struct hsfreq_range samsung_dphy_rx_hsfreq_ranges[] = { { 80, 0x105}, { 100, 0x106}, { 120, 0x107}, { 140, 0x108}, { 160, 0x109}, { 180, 0x10a}, { 200, 0x10b}, { 220, 0x10c}, { 240, 0x10d}, { 270, 0x10e}, { 290, 0x10f}, { 310, 0x110}, { 330, 0x111}, { 350, 0x112}, { 370, 0x113}, { 390, 0x114}, { 410, 0x115}, { 430, 0x116}, { 450, 0x117}, { 470, 0x118}, { 490, 0x119}, { 510, 0x11a}, { 540, 0x11b}, { 560, 0x11c}, { 580, 0x11d}, { 600, 0x11e}, { 620, 0x11f}, { 640, 0x120}, { 660, 0x121}, { 680, 0x122}, { 700, 0x123}, { 720, 0x124}, { 740, 0x125}, { 760, 0x126}, { 790, 0x127}, { 810, 0x128}, { 830, 0x129}, { 850, 0x12a}, { 870, 0x12b}, { 890, 0x12c}, { 910, 0x12d}, { 930, 0x12e}, { 950, 0x12f}, { 970, 0x130}, { 990, 0x131}, {1010, 0x132}, {1030, 0x133}, {1060, 0x134}, {1080, 0x135}, {1100, 0x136}, {1120, 0x137}, {1140, 0x138}, {1160, 0x139}, {1180, 0x13a}, {1200, 0x13b}, {1220, 0x13c}, {1240, 0x13d}, {1260, 0x13e}, {1280, 0x13f}, {1310, 0x140}, {1330, 0x141}, {1350, 0x142}, {1370, 0x143}, {1390, 0x144}, {1410, 0x145}, {1430, 0x146}, {1450, 0x147}, {1470, 0x148}, {1490, 0x149}, {1580, 0x007}, {1740, 0x008}, {1910, 0x009}, {2070, 0x00a}, {2240, 0x00b}, {2410, 0x00c}, {2570, 0x00d}, {2740, 0x00e}, {2910, 0x00f}, {3070, 0x010}, {3240, 0x011}, {3410, 0x012}, {3570, 0x013}, {3740, 0x014}, {3890, 0x015}, {4070, 0x016}, {4240, 0x017}, {4400, 0x018}, {4500, 0x019}, }; /* These tables must be sorted by .range_h ascending. */ static const struct hsfreq_range samsung_cphy_rx_hsfreq_ranges[] = { { 500, 0x102}, { 990, 0x002}, { 2500, 0x001}, }; static void samsung_mipi_dcphy_bias_block_enable(struct samsung_mipi_dcphy *samsung, struct csi2_dphy *csi_dphy) { u32 bias_con2 = 0x3223; if (csi_dphy && csi_dphy->dphy_param.lp_vol_ref != 3 && csi_dphy->dphy_param.lp_vol_ref < 0x7) { bias_con2 &= 0xfffffff8; bias_con2 |= csi_dphy->dphy_param.lp_vol_ref; dev_info(samsung->dev, "rx change lp_vol_ref to %d, it may cause tx exception\n", csi_dphy->dphy_param.lp_vol_ref); } regmap_write(samsung->regmap, BIAS_CON0, 0x0010); regmap_write(samsung->regmap, BIAS_CON1, 0x0110); regmap_write(samsung->regmap, BIAS_CON2, bias_con2); /* default output voltage select: * dphy: 400mv * cphy: 530mv */ if (samsung->c_option) regmap_update_bits(samsung->regmap, BIAS_CON4, I_MUX_SEL_MASK, I_MUX_SEL(2)); } static void samsung_mipi_dcphy_bias_block_disable(struct samsung_mipi_dcphy *samsung) { } static void samsung_mipi_dphy_lane_enable(struct samsung_mipi_dcphy *samsung) { regmap_write(samsung->regmap, DPHY_MC_GNR_CON1, T_PHY_READY(0x2000)); regmap_update_bits(samsung->regmap, DPHY_MC_GNR_CON0, PHY_ENABLE, PHY_ENABLE); switch (samsung->lanes) { case 4: regmap_write(samsung->regmap, DPHY_MD3_GNR_CON1, T_PHY_READY(0x2000)); regmap_update_bits(samsung->regmap, DPHY_MD3_GNR_CON0, PHY_ENABLE, PHY_ENABLE); fallthrough; case 3: regmap_write(samsung->regmap, COMBO_MD2_GNR_CON1, T_PHY_READY(0x2000)); regmap_update_bits(samsung->regmap, COMBO_MD2_GNR_CON0, PHY_ENABLE, PHY_ENABLE); fallthrough; case 2: regmap_write(samsung->regmap, COMBO_MD1_GNR_CON1, T_PHY_READY(0x2000)); regmap_update_bits(samsung->regmap, COMBO_MD1_GNR_CON0, PHY_ENABLE, PHY_ENABLE); fallthrough; case 1: default: regmap_write(samsung->regmap, COMBO_MD0_GNR_CON1, T_PHY_READY(0x2000)); regmap_update_bits(samsung->regmap, COMBO_MD0_GNR_CON0, PHY_ENABLE, PHY_ENABLE); break; } } static void samsung_mipi_cphy_lane_enable(struct samsung_mipi_dcphy *samsung) { regmap_write(samsung->regmap, COMBO_MD0_GNR_CON1, T_PHY_READY(0x2000)); regmap_write(samsung->regmap, COMBO_MD1_GNR_CON1, T_PHY_READY(0x2000)); regmap_write(samsung->regmap, COMBO_MD2_GNR_CON1, T_PHY_READY(0x2000)); regmap_update_bits(samsung->regmap, COMBO_MD0_GNR_CON0, PHY_ENABLE, PHY_ENABLE); regmap_update_bits(samsung->regmap, COMBO_MD1_GNR_CON0, PHY_ENABLE, PHY_ENABLE); regmap_update_bits(samsung->regmap, COMBO_MD2_GNR_CON0, PHY_ENABLE, PHY_ENABLE); } static void samsung_mipi_dphy_lane_disable(struct samsung_mipi_dcphy *samsung) { regmap_update_bits(samsung->regmap, DPHY_MC_GNR_CON0, PHY_ENABLE, 0); regmap_update_bits(samsung->regmap, COMBO_MD0_GNR_CON0, PHY_ENABLE, 0); regmap_update_bits(samsung->regmap, COMBO_MD1_GNR_CON0, PHY_ENABLE, 0); regmap_update_bits(samsung->regmap, COMBO_MD2_GNR_CON0, PHY_ENABLE, 0); regmap_update_bits(samsung->regmap, DPHY_MD3_GNR_CON0, PHY_ENABLE, 0); } static void samsung_mipi_cphy_lane_disable(struct samsung_mipi_dcphy *samsung) { regmap_update_bits(samsung->regmap, COMBO_MD0_GNR_CON0, PHY_ENABLE, 0); regmap_update_bits(samsung->regmap, COMBO_MD1_GNR_CON0, PHY_ENABLE, 0); regmap_update_bits(samsung->regmap, COMBO_MD2_GNR_CON0, PHY_ENABLE, 0); } static void samsung_mipi_dcphy_pll_configure(struct samsung_mipi_dcphy *samsung) { regmap_update_bits(samsung->regmap, PLL_CON0, S_MASK | P_MASK, S(samsung->pll.scaler) | P(samsung->pll.prediv)); regmap_write(samsung->regmap, PLL_CON1, samsung->pll.dsm); regmap_update_bits(samsung->regmap, PLL_CON2, M_MASK, M(samsung->pll.fbdiv)); if (samsung->pll.ssc_en) { regmap_write(samsung->regmap, PLL_CON3, MRR(samsung->pll.mrr) | MFR(samsung->pll.mfr)); regmap_update_bits(samsung->regmap, PLL_CON4, SSCG_EN, SSCG_EN); } regmap_write(samsung->regmap, PLL_CON5, RESET_N_SEL | PLL_ENABLE_SEL); regmap_write(samsung->regmap, PLL_CON7, PLL_LOCK_CNT(0xf000)); regmap_write(samsung->regmap, PLL_CON8, PLL_STB_CNT(0xf000)); } static void samsung_mipi_dcphy_pll_enable(struct samsung_mipi_dcphy *samsung) { u32 sts; int ret; regmap_update_bits(samsung->regmap, PLL_CON0, PLL_EN, PLL_EN); ret = regmap_read_poll_timeout(samsung->regmap, PLL_STAT0, sts, (sts & PLL_LOCK), 1000, 20000); if (ret < 0) dev_err(samsung->dev, "DC-PHY pll is not locked\n"); } static void samsung_mipi_dcphy_pll_disable(struct samsung_mipi_dcphy *samsung) { regmap_update_bits(samsung->regmap, PLL_CON0, PLL_EN, 0); } static const struct samsung_mipi_dphy_timing * samsung_mipi_dphy_get_timing(struct samsung_mipi_dcphy *samsung) { const struct samsung_mipi_dphy_timing *timings; unsigned int num_timings; unsigned int lane_mbps = div64_ul(samsung->pll.rate, USEC_PER_SEC); unsigned int i; timings = samsung_mipi_dphy_timing_table; num_timings = ARRAY_SIZE(samsung_mipi_dphy_timing_table); for (i = num_timings; i > 0; i--) if (lane_mbps <= timings[i - 1].max_lane_mbps) break; if (i == 0) ++i; return &timings[i - 1]; } static const struct samsung_mipi_cphy_timing * samsung_mipi_cphy_get_timing(struct samsung_mipi_dcphy *samsung) { const struct samsung_mipi_cphy_timing *timings; unsigned int num_timings; unsigned int lane_msps = div64_ul(samsung->pll.rate, USEC_PER_SEC); unsigned int i; timings = samsung_mipi_cphy_timing_table; num_timings = ARRAY_SIZE(samsung_mipi_cphy_timing_table); for (i = num_timings; i > 0; i--) if (lane_msps <= timings[i - 1].max_lane_msps) break; if (i == 0) ++i; return &timings[i - 1]; } static void samsung_mipi_cphy_timing_init(struct samsung_mipi_dcphy *samsung) { const struct samsung_mipi_cphy_timing *timing; unsigned int lane_hs_rate = div64_ul(samsung->pll.rate, USEC_PER_SEC); u32 val = 0; timing = samsung_mipi_cphy_get_timing(samsung); /* * Divide-by-2 Clock from Serial Clock. Use this when data rate is under * 500Msps, otherwise divide-by-16 Clock from Serial Clock */ if (lane_hs_rate < 500) val = HSTX_CLK_SEL; val |= T_LPX(timing->lpx); /* T_LP_EXIT_SKEW/T_LP_ENTRY_SKEW unconfig */ regmap_write(samsung->regmap, COMBO_MD0_TIME_CON0, val); regmap_write(samsung->regmap, COMBO_MD1_TIME_CON0, val); regmap_write(samsung->regmap, COMBO_MD2_TIME_CON0, val); val = T_HS_ZERO(timing->prebegin_3) | T_HS_PREPARE(timing->prepare_3); regmap_write(samsung->regmap, COMBO_MD0_TIME_CON1, val); regmap_write(samsung->regmap, COMBO_MD1_TIME_CON1, val); regmap_write(samsung->regmap, COMBO_MD2_TIME_CON1, val); val = T_HS_EXIT(timing->hs_exit) | T_HS_TRAIL(timing->post_3); regmap_write(samsung->regmap, COMBO_MD0_TIME_CON2, val); regmap_write(samsung->regmap, COMBO_MD1_TIME_CON2, val); regmap_write(samsung->regmap, COMBO_MD2_TIME_CON2, val); /* TTA-GET/TTA-GO Timing Counter register use default value */ val = T_TA_GET(0x3) | T_TA_GO(0x0); regmap_write(samsung->regmap, COMBO_MD0_TIME_CON3, val); regmap_write(samsung->regmap, COMBO_MD1_TIME_CON3, val); regmap_write(samsung->regmap, COMBO_MD2_TIME_CON3, val); /* Escape Clock is 20.00MHz */ regmap_write(samsung->regmap, COMBO_MD0_TIME_CON4, 0x1f4); regmap_write(samsung->regmap, COMBO_MD1_TIME_CON4, 0x1f4); regmap_write(samsung->regmap, COMBO_MD2_TIME_CON4, 0x1f4); /* set T_ERR_SOT_SYNC default value */ } static int samsung_mipi_dcphy_pll_ssc_modulation_calc(struct samsung_mipi_dcphy *samsung, u16 prediv, u16 fbdiv, u8 *mfr, u8 *mrr); static unsigned long samsung_mipi_dcphy_pll_round_rate(struct samsung_mipi_dcphy *samsung, unsigned long prate, unsigned long rate, u8 *prediv, u16 *fbdiv, u16 *dsm, u8 *scaler, u8 *mfr, u8 *mrr) { u32 max_fout = samsung->c_option ? samsung->pdata->cphy_tx_max_ksps_per_lane : samsung->pdata->dphy_tx_max_kbps_per_lane; u64 _freq, best_freq = 0; u64 fin, fvco, fout; u8 min_prediv, max_prediv; u8 _mfr = 0, best_mfr = 0; u8 _mrr = 0, best_mrr = 0; u8 _prediv, best_prediv = 1; u16 _fbdiv, best_fbdiv = 1; u8 _scaler, best_scaler = 0; u32 min_delta = UINT_MAX; long long _dsm, best_dsm = 0; int ret = 0; if (!prate) { dev_err(samsung->dev, "prate of pll can not be set zero\n"); return 0; } dev_dbg(samsung->dev, "%s: fin=%lu, req_rate=%lu\n", __func__, prate, rate); /* * The PLL output frequency can be calculated using a simple formula: * Fvco = ((m+k/65536) x 2 x Fin) / p * Fout = ((m+k/65536) x 2 x Fin) / (p x 2^s) */ fin = div64_ul(prate, MSEC_PER_SEC); while (!best_freq) { fout = div64_ul(rate, MSEC_PER_SEC); if (fout > max_fout) fout = max_fout; /* 0 ≤ S[2:0] ≤ 6 */ for (_scaler = 0; _scaler < 7; _scaler++) { fvco = fout << _scaler; /* * 2600MHz ≤ FVCO ≤ 6600MHz */ if (fvco < 2600 * MSEC_PER_SEC || fvco > 6600 * MSEC_PER_SEC) continue; /* 6MHz ≤ Fref(Fin / p) ≤ 30MHz */ min_prediv = DIV_ROUND_UP_ULL(fin, 30 * MSEC_PER_SEC); max_prediv = DIV_ROUND_CLOSEST_ULL(fin, 6 * MSEC_PER_SEC); for (_prediv = min_prediv; _prediv <= max_prediv; _prediv++) { u64 delta, tmp; _fbdiv = DIV_ROUND_CLOSEST_ULL(fvco * _prediv, 2 * fin); /* 64 ≤ M[9:0] ≤ 1023 */ if ((_fbdiv < 64) || (_fbdiv > 1023)) continue; /* -32768 ≤ K[15:0] ≤ 32767 */ _dsm = _prediv * fvco - 2 * _fbdiv * fin; _dsm = _dsm / abs(_dsm) * DIV_ROUND_UP_ULL(abs(_dsm) << 15, fin); if (_dsm < -32768 || _dsm > 32767) continue; tmp = DIV_ROUND_CLOSEST_ULL(_fbdiv * fin * 2 * 1000, _prediv); tmp += (_dsm / abs(_dsm) * DIV_ROUND_CLOSEST_ULL(abs(_dsm) * fin * 1000, _prediv << 15)); _freq = (DIV_ROUND_CLOSEST_ULL(tmp, 1000) * MSEC_PER_SEC); /* * All DPHY 2.0 compliant Transmitters shall support SSC * operating above 2.5 Gbps */ if ((_freq >> _scaler) > 2500000000LL) ret = samsung_mipi_dcphy_pll_ssc_modulation_calc(samsung, _prediv, _fbdiv, &_mfr, &_mrr); delta = abs(fvco * MSEC_PER_SEC - tmp); if (!ret && delta <= min_delta) { best_prediv = _prediv; best_fbdiv = _fbdiv; best_dsm = _dsm; best_mfr = _mfr; best_mrr = _mrr; best_scaler = _scaler; min_delta = delta; best_freq = _freq; } } } rate += 100 * MSEC_PER_SEC; } *prediv = best_prediv; *fbdiv = best_fbdiv; *dsm = (int)best_dsm & 0xffff; *scaler = best_scaler; *mfr = best_mfr; *mrr = best_mrr; dev_dbg(samsung->dev, "%s: fout=%llu, prediv=%u, fbdiv=%u, dsm=%lld, scaler=%u\n", __func__, best_freq >> best_scaler, best_prediv, best_fbdiv, best_dsm, best_scaler); return best_freq >> best_scaler; } static void samsung_mipi_dphy_clk_lane_timing_init(struct samsung_mipi_dcphy *samsung) { const struct samsung_mipi_dphy_timing *timing; unsigned int lane_hs_rate = div64_ul(samsung->pll.rate, USEC_PER_SEC); u32 val, res_up, res_down; timing = samsung_mipi_dphy_get_timing(samsung); regmap_write(samsung->regmap, DPHY_MC_GNR_CON0, 0xf000); /* * The Drive-Strength / Voltage-Amplitude is adjusted by adjusting the * Driver-Up Resistor and Driver-Down Resistor. */ res_up = samsung->pdata->dphy_hs_drv_res_cfg->clk_hs_drv_up_ohm; res_down = samsung->pdata->dphy_hs_drv_res_cfg->clk_hs_drv_down_ohm; val = EDGE_CON(7) | EDGE_CON_DIR(0) | EDGE_CON_EN | RES_UP(res_up) | RES_DN(res_down); regmap_write(samsung->regmap, DPHY_MC_ANA_CON0, val); if (lane_hs_rate >= 4500) regmap_write(samsung->regmap, DPHY_MC_ANA_CON1, 0x0001); val = 0; /* * Divide-by-2 Clock from Serial Clock. Use this when data rate is under * 1500Mbps, otherwise divide-by-16 Clock from Serial Clock */ if (lane_hs_rate < 1500) val = HSTX_CLK_SEL; val |= T_LPX(timing->lpx); /* T_LP_EXIT_SKEW/T_LP_ENTRY_SKEW unconfig */ regmap_write(samsung->regmap, DPHY_MC_TIME_CON0, val); val = T_CLK_ZERO(timing->clk_zero) | T_CLK_PREPARE(timing->clk_prepare); regmap_write(samsung->regmap, DPHY_MC_TIME_CON1, val); val = T_HS_EXIT(timing->hs_exit) | T_CLK_TRAIL(timing->clk_trail_eot); regmap_write(samsung->regmap, DPHY_MC_TIME_CON2, val); val = T_CLK_POST(timing->clk_post); regmap_write(samsung->regmap, DPHY_MC_TIME_CON3, val); /* Escape Clock is 20.00MHz */ regmap_write(samsung->regmap, DPHY_MC_TIME_CON4, 0x1f4); /* * skew calibration should be off, if the operation data rate is * under 1.5Gbps or equal to 1.5Gbps. */ if (lane_hs_rate > 1500) regmap_write(samsung->regmap, DPHY_MC_DESKEW_CON0, 0x9cb1); } static void samsung_mipi_dphy_data_lane_timing_init(struct samsung_mipi_dcphy *samsung) { const struct samsung_mipi_dphy_timing *timing; unsigned int lane_hs_rate = div64_ul(samsung->pll.rate, USEC_PER_SEC); u32 val, res_up, res_down; timing = samsung_mipi_dphy_get_timing(samsung); /* * The Drive-Strength / Voltage-Amplitude is adjusted by adjusting the * Driver-Up Resistor and Driver-Down Resistor. */ res_up = samsung->pdata->dphy_hs_drv_res_cfg->data_hs_drv_up_ohm; res_down = samsung->pdata->dphy_hs_drv_res_cfg->data_hs_drv_down_ohm; val = EDGE_CON(7) | EDGE_CON_DIR(0) | EDGE_CON_EN | RES_UP(res_up) | RES_DN(res_down); regmap_write(samsung->regmap, COMBO_MD0_ANA_CON0, val); regmap_write(samsung->regmap, COMBO_MD1_ANA_CON0, val); regmap_write(samsung->regmap, COMBO_MD2_ANA_CON0, val); regmap_write(samsung->regmap, DPHY_MD3_ANA_CON0, val); if (lane_hs_rate >= 4500) { regmap_write(samsung->regmap, COMBO_MD0_ANA_CON1, 0x0001); regmap_write(samsung->regmap, COMBO_MD1_ANA_CON1, 0x0001); regmap_write(samsung->regmap, COMBO_MD2_ANA_CON1, 0x0001); regmap_write(samsung->regmap, DPHY_MD3_ANA_CON1, 0x0001); } val = 0; /* * Divide-by-2 Clock from Serial Clock. Use this when data rate is under * 1500Mbps, otherwise divide-by-16 Clock from Serial Clock */ if (lane_hs_rate < 1500) val = HSTX_CLK_SEL; val |= T_LPX(timing->lpx); /* T_LP_EXIT_SKEW/T_LP_ENTRY_SKEW unconfig */ regmap_write(samsung->regmap, COMBO_MD0_TIME_CON0, val); regmap_write(samsung->regmap, COMBO_MD1_TIME_CON0, val); regmap_write(samsung->regmap, COMBO_MD2_TIME_CON0, val); regmap_write(samsung->regmap, DPHY_MD3_TIME_CON0, val); val = T_HS_ZERO(timing->hs_zero) | T_HS_PREPARE(timing->hs_prepare); regmap_write(samsung->regmap, COMBO_MD0_TIME_CON1, val); regmap_write(samsung->regmap, COMBO_MD1_TIME_CON1, val); regmap_write(samsung->regmap, COMBO_MD2_TIME_CON1, val); regmap_write(samsung->regmap, DPHY_MD3_TIME_CON1, val); val = T_HS_EXIT(timing->hs_exit) | T_HS_TRAIL(timing->hs_trail_eot); regmap_write(samsung->regmap, COMBO_MD0_TIME_CON2, val); regmap_write(samsung->regmap, COMBO_MD1_TIME_CON2, val); regmap_write(samsung->regmap, COMBO_MD2_TIME_CON2, val); regmap_write(samsung->regmap, DPHY_MD3_TIME_CON2, val); /* TTA-GET/TTA-GO Timing Counter register use default value */ val = T_TA_GET(0x3) | T_TA_GO(0x0); regmap_write(samsung->regmap, COMBO_MD0_TIME_CON3, val); regmap_write(samsung->regmap, COMBO_MD1_TIME_CON3, val); regmap_write(samsung->regmap, COMBO_MD2_TIME_CON3, val); regmap_write(samsung->regmap, DPHY_MD3_TIME_CON3, val); /* Escape Clock is 20.00MHz */ regmap_write(samsung->regmap, COMBO_MD0_TIME_CON4, 0x1f4); regmap_write(samsung->regmap, COMBO_MD1_TIME_CON4, 0x1f4); regmap_write(samsung->regmap, COMBO_MD2_TIME_CON4, 0x1f4); regmap_write(samsung->regmap, DPHY_MD3_TIME_CON4, 0x1f4); } static void samsung_mipi_dcphy_hs_vreg_amp_configure(struct samsung_mipi_dcphy *samsung) { regmap_write(samsung->regmap, DPHY_MC_ANA_CON2, HS_VREG_AMP_ICON(2)); } static void samsung_mipi_dphy_power_on(struct samsung_mipi_dcphy *samsung) { reset_control_assert(samsung->m_phy_rst); samsung_mipi_dcphy_bias_block_enable(samsung, NULL); samsung_mipi_dcphy_pll_configure(samsung); samsung_mipi_dphy_clk_lane_timing_init(samsung); samsung_mipi_dphy_data_lane_timing_init(samsung); samsung_mipi_dcphy_pll_enable(samsung); samsung_mipi_dphy_lane_enable(samsung); reset_control_deassert(samsung->m_phy_rst); /* The TSKEWCAL maximum is 100 µsec * at initial calibration. */ usleep_range(100, 110); } static void samsung_mipi_cphy_power_on(struct samsung_mipi_dcphy *samsung) { regmap_write(samsung->grf_regmap, MIPI_DCPHY_GRF_CON0, M_CPHY_MODE); reset_control_assert(samsung->m_phy_rst); samsung_mipi_dcphy_bias_block_enable(samsung, NULL); samsung_mipi_dcphy_hs_vreg_amp_configure(samsung); samsung_mipi_dcphy_pll_configure(samsung); samsung_mipi_cphy_timing_init(samsung); samsung_mipi_dcphy_pll_enable(samsung); samsung_mipi_cphy_lane_enable(samsung); reset_control_deassert(samsung->m_phy_rst); } static struct v4l2_subdev *get_remote_sensor(struct v4l2_subdev *sd); static int samsung_mipi_dcphy_power_on(struct phy *phy) { struct samsung_mipi_dcphy *samsung = phy_get_drvdata(phy); enum phy_mode mode = phy_get_mode(phy); int on = 0; struct v4l2_subdev *sensor_sd = NULL; pm_runtime_get_sync(samsung->dev); reset_control_assert(samsung->apb_rst); udelay(1); reset_control_deassert(samsung->apb_rst); if (atomic_read(&samsung->stream_cnt) && samsung->dphy_dev[0]) { sensor_sd = get_remote_sensor(&samsung->dphy_dev[0]->sd); samsung->stream_off(samsung->dphy_dev[0], &samsung->dphy_dev[0]->sd); if (sensor_sd) v4l2_subdev_call(sensor_sd, core, ioctl, RKMODULE_SET_QUICK_STREAM, &on); samsung->stream_on(samsung->dphy_dev[0], &samsung->dphy_dev[0]->sd); on = 1; if (sensor_sd) v4l2_subdev_call(sensor_sd, core, ioctl, RKMODULE_SET_QUICK_STREAM, &on); } switch (mode) { case PHY_MODE_MIPI_DPHY: samsung_mipi_dphy_power_on(samsung); break; default: samsung_mipi_cphy_power_on(samsung); } return 0; } static int samsung_mipi_dcphy_power_off(struct phy *phy) { struct samsung_mipi_dcphy *samsung = phy_get_drvdata(phy); enum phy_mode mode = phy_get_mode(phy); switch (mode) { case PHY_MODE_MIPI_DPHY: samsung_mipi_dphy_lane_disable(samsung); break; default: samsung_mipi_cphy_lane_disable(samsung); } samsung_mipi_dcphy_pll_disable(samsung); samsung_mipi_dcphy_bias_block_disable(samsung); pm_runtime_put(samsung->dev); return 0; } static int samsung_mipi_dcphy_set_mode(struct phy *phy, enum phy_mode mode, int submode) { return 0; } static int samsung_mipi_dcphy_pll_ssc_modulation_calc(struct samsung_mipi_dcphy *samsung, u16 prediv, u16 fbdiv, u8 *mfr, u8 *mrr) { unsigned long fin = div64_ul(clk_get_rate(samsung->ref_clk), MSEC_PER_SEC); u16 min_mfr, max_mfr, mid_mfr, mfr_end; u16 _mfr, best_mfr = 0; u16 _mrr, best_mrr = 0; /* MF(MHz) = Fref / p / mfr / 32 */ /* 30MHz ≤ MF ≤ 33MHz, default 31 */ max_mfr = DIV_ROUND_UP(fin, (30 * prediv) << 5); min_mfr = div64_ul(fin, ((33 * prediv) << 5)); mid_mfr = div64_ul(fin, (31 * prediv) << 5); /* 0 ≤ mfr ≤ 255 */ if (max_mfr > 256) max_mfr = 256; mfr_end = max_mfr; for (_mfr = mid_mfr; _mfr < mfr_end; _mfr++) { /* MR(%) = mfr * mrr * 100 / m / 64 */ /* 0 ≤ MR ≤ 5000ppm(0.5%), default is reduced from 0.25%. */ _mrr = (25 * fbdiv << 6) / (_mfr * 100 * 100); for (; _mrr > 0; _mrr--) { /* 0 ≤ mrr * mfr ≤ 512 */ if (_mfr * _mrr <= 512) { best_mfr = _mfr; best_mrr = _mrr; break; } } if (best_mrr) break; if (_mfr == mfr_end - 1 && _mfr > mid_mfr) { _mfr = min_mfr - 1; mfr_end = mid_mfr; } } if (best_mrr) { *mfr = best_mfr & 0xff; *mrr = best_mrr & 0x3f; dev_dbg(samsung->dev, "mfr=%d, mrr=%d, MF=%llukHz, MR=%lluppm\n", *mfr, *mrr, div64_ul(fin, (prediv * *mfr) << 5), div64_ul(*mfr * *mrr * 1000000, fbdiv << 6)); return 0; } dev_err(samsung->dev, "%s: failed to calc ssc parameter mfr and mrr\n", __func__); return -EINVAL; } static void samsung_mipi_dcphy_pll_calc_rate(struct samsung_mipi_dcphy *samsung, unsigned long long rate) { unsigned long prate = clk_get_rate(samsung->ref_clk); unsigned long fout; u8 scaler = 0, mfr = 0, mrr = 0; u16 fbdiv = 0; u8 prediv = 1; u16 dsm = 0; fout = samsung_mipi_dcphy_pll_round_rate(samsung, prate, rate, &prediv, &fbdiv, &dsm, &scaler, &mfr, &mrr); if (fout != 0) { samsung->pll.prediv = prediv; samsung->pll.fbdiv = fbdiv; samsung->pll.dsm = dsm; samsung->pll.scaler = scaler; samsung->pll.rate = fout; if (fout > 2500000000LL) { samsung->pll.ssc_en = true; samsung->pll.mfr = mfr; samsung->pll.mrr = mrr; } } } static int samsung_mipi_dcphy_configure(struct phy *phy, union phy_configure_opts *opts) { struct samsung_mipi_dcphy *samsung = phy_get_drvdata(phy); unsigned long long target_rate = opts->mipi_dphy.hs_clk_rate; enum phy_mode mode = phy_get_mode(phy); samsung->c_option = (mode == PHY_MODE_MIPI_DPHY) ? false : true; samsung->lanes = opts->mipi_dphy.lanes > 4 ? 4 : opts->mipi_dphy.lanes; samsung_mipi_dcphy_pll_calc_rate(samsung, target_rate); opts->mipi_dphy.hs_clk_rate = samsung->pll.rate; return 0; } static struct v4l2_subdev *get_remote_sensor(struct v4l2_subdev *sd) { struct media_pad *local, *remote; struct media_entity *sensor_me; local = &sd->entity.pads[CSI2_DPHY_RX_PAD_SINK]; remote = media_pad_remote_pad_first(local); if (!remote) { v4l2_warn(sd, "No link between dphy and sensor\n"); return NULL; } sensor_me = media_pad_remote_pad_first(local)->entity; return media_entity_to_v4l2_subdev(sensor_me); } static struct csi2_sensor *sd_to_sensor(struct csi2_dphy *dphy, struct v4l2_subdev *sd) { int i; for (i = 0; i < dphy->num_sensors; ++i) if (dphy->sensors[i].sd == sd) return &dphy->sensors[i]; return NULL; } static void samsung_dcphy_rx_config_settle(struct csi2_dphy *dphy, struct csi2_sensor *sensor) { struct samsung_mipi_dcphy *samsung = dphy->samsung_phy; const struct hsfreq_range *hsfreq_ranges = NULL; int num_hsfreq_ranges = 0; int i, hsfreq = 0; u32 sot_sync = 0; if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) { hsfreq_ranges = samsung_dphy_rx_hsfreq_ranges; num_hsfreq_ranges = ARRAY_SIZE(samsung_dphy_rx_hsfreq_ranges); sot_sync = 0x03; } else if (sensor->mbus.type == V4L2_MBUS_CSI2_CPHY) { hsfreq_ranges = samsung_cphy_rx_hsfreq_ranges; num_hsfreq_ranges = ARRAY_SIZE(samsung_cphy_rx_hsfreq_ranges); sot_sync = 0x32; } else { dev_err(dphy->dev, "mbus type %d is not support", sensor->mbus.type); return; } /* set data lane */ for (i = 0; i < num_hsfreq_ranges; i++) { if (hsfreq_ranges[i].range_h >= dphy->data_rate_mbps) { hsfreq = hsfreq_ranges[i].cfg_bit; break; } } if (i == num_hsfreq_ranges) { i = num_hsfreq_ranges - 1; dev_warn(dphy->dev, "data rate: %lld mbps, max support %d mbps", dphy->data_rate_mbps, hsfreq_ranges[i].range_h + 1); hsfreq = hsfreq_ranges[i].cfg_bit; } /*clk settle fix to 0x301*/ if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) regmap_write(samsung->regmap, RX_CLK_THS_SETTLE, 0x301); if (sensor->lanes > 0x00) { regmap_update_bits(samsung->regmap, RX_LANE0_THS_SETTLE, 0x1ff, hsfreq); regmap_update_bits(samsung->regmap, RX_LANE0_ERR_SOT_SYNC, 0xff, sot_sync); } if (sensor->lanes > 0x01) { regmap_update_bits(samsung->regmap, RX_LANE1_THS_SETTLE, 0x1ff, hsfreq); regmap_update_bits(samsung->regmap, RX_LANE1_ERR_SOT_SYNC, 0xff, sot_sync); } if (sensor->lanes > 0x02) { regmap_update_bits(samsung->regmap, RX_LANE2_THS_SETTLE, 0x1ff, hsfreq); regmap_update_bits(samsung->regmap, RX_LANE2_ERR_SOT_SYNC, 0xff, sot_sync); } if (sensor->lanes > 0x03) { regmap_update_bits(samsung->regmap, RX_LANE3_THS_SETTLE, 0x1ff, hsfreq); regmap_update_bits(samsung->regmap, RX_LANE3_ERR_SOT_SYNC, 0xff, sot_sync); } } static int samsung_dcphy_rx_config_common(struct csi2_dphy *dphy, struct csi2_sensor *sensor) { struct samsung_mipi_dcphy *samsung = dphy->samsung_phy; u32 dlysel = 0; int i = 0; if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) { if (dphy->data_rate_mbps < 1500) dlysel = 0; else if (dphy->data_rate_mbps < 2000) dlysel = 3 << 8; else if (dphy->data_rate_mbps < 3000) dlysel = 2 << 8; else if (dphy->data_rate_mbps < 4000) dlysel = 1 << 8; else if (dphy->data_rate_mbps < 6500) dlysel = 0; if (dphy->dphy_param.clk_hs_term_sel > 0x7) { dev_err(dphy->dev, "clk_hs_term_sel error param %d\n", dphy->dphy_param.clk_hs_term_sel); return -EINVAL; } for (i = 0; i < sensor->lanes; i++) { if (dphy->dphy_param.data_hs_term_sel[i] > 0x7) { dev_err(dphy->dev, "data_hs_term_sel[%d] error param %d\n", i, dphy->dphy_param.data_hs_term_sel[i]); return -EINVAL; } if (dphy->dphy_param.lp_hys_sw[i] > 0x3) { dev_err(dphy->dev, "lp_hys_sw[%d] error param %d\n", i, dphy->dphy_param.lp_hys_sw[i]); return -EINVAL; } if (dphy->dphy_param.lp_escclk_pol_sel[i] > 0x1) { dev_err(dphy->dev, "lp_escclk_pol_sel[%d] error param %d\n", i, dphy->dphy_param.lp_escclk_pol_sel[i]); return -EINVAL; } if (dphy->dphy_param.skew_data_cal_clk[i] > 0x1f) { dev_err(dphy->dev, "skew_data_cal_clk[%d] error param %d\n", i, dphy->dphy_param.skew_data_cal_clk[i]); return -EINVAL; } } regmap_write(samsung->regmap, RX_S0C_GNR_CON1, 0x1450); regmap_write(samsung->regmap, RX_S0C_ANA_CON1, 0x8000); regmap_write(samsung->regmap, RX_S0C_ANA_CON2, dphy->dphy_param.clk_hs_term_sel); regmap_write(samsung->regmap, RX_S0C_ANA_CON3, 0x0600); if (sensor->lanes > 0x00) { regmap_write(samsung->regmap, RX_COMBO_S0D0_GNR_CON1, 0x1450); regmap_write(samsung->regmap, RX_COMBO_S0D0_ANA_CON1, 0x8000); regmap_write(samsung->regmap, RX_COMBO_S0D0_ANA_CON2, dlysel | dphy->dphy_param.data_hs_term_sel[0]); regmap_write(samsung->regmap, RX_COMBO_S0D0_ANA_CON3, 0x0600 | (dphy->dphy_param.lp_hys_sw[0] << 4) | (dphy->dphy_param.lp_escclk_pol_sel[0] << 11)); regmap_write(samsung->regmap, RX_COMBO_S0D0_ANA_CON7, 0x40); regmap_write(samsung->regmap, RX_COMBO_S0D0_DESKEW_CON2, dphy->dphy_param.skew_data_cal_clk[0]); if (dphy->data_rate_mbps >= 1500 && dphy->drv_data->chip_id >= CHIP_ID_RK3576) { regmap_write(samsung->regmap, RX_COMBO_S0D0_DESKEW_CON0, BIT(0)); regmap_write(samsung->regmap, RX_COMBO_S0D0_DESKEW_CON4, 0x81A); } } if (sensor->lanes > 0x01) { regmap_write(samsung->regmap, RX_COMBO_S0D1_GNR_CON1, 0x1450); regmap_write(samsung->regmap, RX_COMBO_S0D1_ANA_CON1, 0x8000); regmap_write(samsung->regmap, RX_COMBO_S0D1_ANA_CON2, dlysel | dphy->dphy_param.data_hs_term_sel[1]); regmap_write(samsung->regmap, RX_COMBO_S0D1_ANA_CON3, 0x0600 | (dphy->dphy_param.lp_hys_sw[1] << 4) | (dphy->dphy_param.lp_escclk_pol_sel[1] << 11)); regmap_write(samsung->regmap, RX_COMBO_S0D1_ANA_CON7, 0x40); regmap_write(samsung->regmap, RX_COMBO_S0D1_DESKEW_CON2, dphy->dphy_param.skew_data_cal_clk[1]); if (dphy->data_rate_mbps >= 1500 && dphy->drv_data->chip_id >= CHIP_ID_RK3576) { regmap_write(samsung->regmap, RX_COMBO_S0D1_DESKEW_CON0, BIT(0)); regmap_write(samsung->regmap, RX_COMBO_S0D1_DESKEW_CON4, 0x81A); } } if (sensor->lanes > 0x02) { regmap_write(samsung->regmap, RX_COMBO_S0D2_GNR_CON1, 0x1450); regmap_write(samsung->regmap, RX_COMBO_S0D2_ANA_CON1, 0x8000); regmap_write(samsung->regmap, RX_COMBO_S0D2_ANA_CON2, dlysel | dphy->dphy_param.data_hs_term_sel[2]); regmap_write(samsung->regmap, RX_COMBO_S0D2_ANA_CON3, 0x0600 | (dphy->dphy_param.lp_hys_sw[2] << 4) | (dphy->dphy_param.lp_escclk_pol_sel[2] << 11)); regmap_write(samsung->regmap, RX_COMBO_S0D2_ANA_CON7, 0x40); regmap_write(samsung->regmap, RX_COMBO_S0D2_DESKEW_CON2, dphy->dphy_param.skew_data_cal_clk[2]); if (dphy->data_rate_mbps >= 1500 && dphy->drv_data->chip_id >= CHIP_ID_RK3576) { regmap_write(samsung->regmap, RX_COMBO_S0D2_DESKEW_CON0, BIT(0)); regmap_write(samsung->regmap, RX_COMBO_S0D2_DESKEW_CON4, 0x81A); } } if (sensor->lanes > 0x03) { regmap_write(samsung->regmap, RX_S0D3_GNR_CON1, 0x1450); regmap_write(samsung->regmap, RX_S0D3_ANA_CON1, 0x8000); regmap_write(samsung->regmap, RX_S0D3_ANA_CON2, dlysel | dphy->dphy_param.data_hs_term_sel[3]); regmap_write(samsung->regmap, RX_S0D3_ANA_CON3, 0x0600 | (dphy->dphy_param.lp_hys_sw[3] << 4) | (dphy->dphy_param.lp_escclk_pol_sel[3] << 11)); regmap_write(samsung->regmap, RX_S0D3_DESKEW_CON2, dphy->dphy_param.skew_data_cal_clk[3]); if (dphy->data_rate_mbps >= 1500 && dphy->drv_data->chip_id >= CHIP_ID_RK3576) { regmap_write(samsung->regmap, RX_S0D3_DESKEW_CON0, BIT(0)); regmap_write(samsung->regmap, RX_S0D3_DESKEW_CON4, 0x81A); } } } else { if (sensor->lanes > 0x00) { regmap_write(samsung->regmap, RX_COMBO_S0D0_GNR_CON1, 0x1450); regmap_write(samsung->regmap, RX_COMBO_S0D0_ANA_CON1, 0x8000); regmap_write(samsung->regmap, RX_COMBO_S0D0_ANA_CON2, 0x5); regmap_write(samsung->regmap, RX_COMBO_S0D0_ANA_CON3, 0x600); regmap_write(samsung->regmap, RX_COMBO_S0D0_ANA_CON6, 0x608); regmap_write(samsung->regmap, RX_COMBO_S0D0_ANA_CON7, 0x40); regmap_write(samsung->regmap, RX_COMBO_S0D0_CRC_CON1, 0x1500); regmap_write(samsung->regmap, RX_COMBO_S0D0_CRC_CON2, 0x30); if (dphy->data_rate_mbps >= 3000 && dphy->drv_data->chip_id >= CHIP_ID_RK3576) regmap_write(samsung->regmap, RX_COMBO_S0D0_DESKEW_CON0, BIT(0)); } if (sensor->lanes > 0x01) { regmap_write(samsung->regmap, RX_COMBO_S0D1_GNR_CON1, 0x1450); regmap_write(samsung->regmap, RX_COMBO_S0D1_ANA_CON1, 0x8000); regmap_write(samsung->regmap, RX_COMBO_S0D1_ANA_CON2, 0x5); regmap_write(samsung->regmap, RX_COMBO_S0D1_ANA_CON3, 0x600); regmap_write(samsung->regmap, RX_COMBO_S0D1_ANA_CON6, 0x608); regmap_write(samsung->regmap, RX_COMBO_S0D1_ANA_CON7, 0x40); regmap_write(samsung->regmap, RX_COMBO_S0D1_CRC_CON1, 0x1500); regmap_write(samsung->regmap, RX_COMBO_S0D1_CRC_CON2, 0x30); if (dphy->data_rate_mbps >= 3000 && dphy->drv_data->chip_id >= CHIP_ID_RK3576) regmap_write(samsung->regmap, RX_COMBO_S0D1_DESKEW_CON0, BIT(0)); } if (sensor->lanes > 0x02) { regmap_write(samsung->regmap, RX_COMBO_S0D2_GNR_CON1, 0x1450); regmap_write(samsung->regmap, RX_COMBO_S0D2_ANA_CON1, 0x8000); regmap_write(samsung->regmap, RX_COMBO_S0D2_ANA_CON2, 0x5); regmap_write(samsung->regmap, RX_COMBO_S0D2_ANA_CON3, 0x600); regmap_write(samsung->regmap, RX_COMBO_S0D2_ANA_CON6, 0x608); regmap_write(samsung->regmap, RX_COMBO_S0D2_ANA_CON7, 0x40); regmap_write(samsung->regmap, RX_COMBO_S0D2_CRC_CON1, 0x1500); regmap_write(samsung->regmap, RX_COMBO_S0D2_CRC_CON2, 0x30); if (dphy->data_rate_mbps >= 3000 && dphy->drv_data->chip_id >= CHIP_ID_RK3576) regmap_write(samsung->regmap, RX_COMBO_S0D2_DESKEW_CON0, BIT(0)); } } return 0; } static int samsung_dcphy_rx_lane_enable(struct csi2_dphy *dphy, struct csi2_sensor *sensor) { struct samsung_mipi_dcphy *samsung = dphy->samsung_phy; u32 sts; int ret = 0; if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) regmap_update_bits(samsung->regmap, RX_CLK_LANE_ENABLE, PHY_ENABLE, PHY_ENABLE); if (sensor->lanes > 0x00) regmap_update_bits(samsung->regmap, RX_DATA_LANE0_ENABLE, PHY_ENABLE, PHY_ENABLE); if (sensor->lanes > 0x01) regmap_update_bits(samsung->regmap, RX_DATA_LANE1_ENABLE, PHY_ENABLE, PHY_ENABLE); if (sensor->lanes > 0x02) regmap_update_bits(samsung->regmap, RX_DATA_LANE2_ENABLE, PHY_ENABLE, PHY_ENABLE); if (sensor->lanes > 0x03) regmap_update_bits(samsung->regmap, RX_DATA_LANE3_ENABLE, PHY_ENABLE, PHY_ENABLE); /*wait for clk lane ready*/ if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) { ret = regmap_read_poll_timeout(samsung->regmap, RX_CLK_LANE_ENABLE, sts, (sts & PHY_READY), 200, 4000); if (ret < 0) { dev_err(samsung->dev, "phy rx clk lane is not locked\n"); return -EINVAL; } } /*wait for data lane ready*/ if (sensor->lanes > 0x00) { ret = regmap_read_poll_timeout(samsung->regmap, RX_DATA_LANE0_ENABLE, sts, (sts & PHY_READY), 200, 2000); if (ret < 0) { dev_err(samsung->dev, "phy rx data lane 0 is not locked\n"); return -EINVAL; } } if (sensor->lanes > 0x01) { ret = regmap_read_poll_timeout(samsung->regmap, RX_DATA_LANE1_ENABLE, sts, (sts & PHY_READY), 200, 2000); if (ret < 0) { dev_err(samsung->dev, "phy rx data lane 1 is not locked\n"); return -EINVAL; } } if (sensor->lanes > 0x02) { ret = regmap_read_poll_timeout(samsung->regmap, RX_DATA_LANE2_ENABLE, sts, (sts & PHY_READY), 200, 2000); if (ret < 0) { dev_err(samsung->dev, "phy rx data lane 2 is not locked\n"); return -EINVAL; } } if (sensor->lanes > 0x03) { ret = regmap_read_poll_timeout(samsung->regmap, RX_DATA_LANE3_ENABLE, sts, (sts & PHY_READY), 200, 2000); if (ret < 0) { dev_err(samsung->dev, "phy rx data lane 3 is not locked\n"); return -EINVAL; } } return 0; } static int samsung_dcphy_rx_stream_on(struct csi2_dphy *dphy, struct v4l2_subdev *sd) { struct v4l2_subdev *sensor_sd = get_remote_sensor(sd); struct csi2_sensor *sensor; struct samsung_mipi_dcphy *samsung = dphy->samsung_phy; int ret = 0; if (!sensor_sd) return -ENODEV; sensor = sd_to_sensor(dphy, sensor_sd); if (!sensor) return -ENODEV; mutex_lock(&samsung->mutex); if (sensor->mbus.type == V4L2_MBUS_CSI2_CPHY) regmap_write(samsung->grf_regmap, MIPI_DCPHY_GRF_CON0, S_CPHY_MODE); if (samsung->s_phy_rst) reset_control_assert(samsung->s_phy_rst); samsung_mipi_dcphy_bias_block_enable(samsung, dphy); ret = samsung_dcphy_rx_config_common(dphy, sensor); if (ret) goto out_streamon; samsung_dcphy_rx_config_settle(dphy, sensor); ret = samsung_dcphy_rx_lane_enable(dphy, sensor); if (ret) goto out_streamon; if (samsung->s_phy_rst) reset_control_deassert(samsung->s_phy_rst); atomic_inc(&samsung->stream_cnt); mutex_unlock(&samsung->mutex); return 0; out_streamon: if (samsung->s_phy_rst) reset_control_deassert(samsung->s_phy_rst); mutex_unlock(&samsung->mutex); dev_err(dphy->dev, "stream on error\n"); return -EINVAL; } static int samsung_dcphy_rx_stream_off(struct csi2_dphy *dphy, struct v4l2_subdev *sd) { struct samsung_mipi_dcphy *samsung = dphy->samsung_phy; struct v4l2_subdev *sensor_sd = get_remote_sensor(sd); struct csi2_sensor *sensor; if (!sensor_sd) return -ENODEV; sensor = sd_to_sensor(dphy, sensor_sd); if (!sensor) return -ENODEV; if (atomic_dec_return(&samsung->stream_cnt)) return 0; mutex_lock(&samsung->mutex); if (samsung->s_phy_rst) reset_control_assert(samsung->s_phy_rst); if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) regmap_update_bits(samsung->regmap, RX_CLK_LANE_ENABLE, PHY_ENABLE, 0); if (sensor->lanes > 0x00) regmap_update_bits(samsung->regmap, RX_DATA_LANE0_ENABLE, PHY_ENABLE, 0); if (sensor->lanes > 0x01) regmap_update_bits(samsung->regmap, RX_DATA_LANE1_ENABLE, PHY_ENABLE, 0); if (sensor->lanes > 0x02) regmap_update_bits(samsung->regmap, RX_DATA_LANE2_ENABLE, PHY_ENABLE, 0); if (sensor->lanes > 0x03) regmap_update_bits(samsung->regmap, RX_DATA_LANE3_ENABLE, PHY_ENABLE, 0); if (samsung->s_phy_rst) reset_control_deassert(samsung->s_phy_rst); usleep_range(500, 1000); mutex_unlock(&samsung->mutex); return 0; } static int samsung_mipi_dcphy_init(struct phy *phy) { struct samsung_mipi_dcphy *samsung = phy_get_drvdata(phy); pm_runtime_get_sync(samsung->dev); return 0; } static int samsung_mipi_dcphy_exit(struct phy *phy) { struct samsung_mipi_dcphy *samsung = phy_get_drvdata(phy); pm_runtime_put(samsung->dev); return 0; } static const struct phy_ops samsung_mipi_dcphy_ops = { .configure = samsung_mipi_dcphy_configure, .set_mode = samsung_mipi_dcphy_set_mode, .power_on = samsung_mipi_dcphy_power_on, .power_off = samsung_mipi_dcphy_power_off, .init = samsung_mipi_dcphy_init, .exit = samsung_mipi_dcphy_exit, .owner = THIS_MODULE, }; static const struct regmap_config samsung_mipi_dcphy_regmap_config = { .name = "dcphy", .reg_bits = 32, .val_bits = 32, .reg_stride = 4, .max_register = MIPI_DCPHY_MAX_REGISGER, }; static int samsung_mipi_dcphy_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct samsung_mipi_dcphy *samsung; struct phy_provider *phy_provider; struct phy *phy; struct resource *res; void __iomem *regs; int ret; samsung = devm_kzalloc(dev, sizeof(*samsung), GFP_KERNEL); if (!samsung) return -ENOMEM; samsung->dev = dev; samsung->pdata = device_get_match_data(dev); platform_set_drvdata(pdev, samsung); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); samsung->res = res; regs = devm_ioremap_resource(dev, res); if (IS_ERR(regs)) return PTR_ERR(regs); samsung->regmap = devm_regmap_init_mmio(dev, regs, &samsung_mipi_dcphy_regmap_config); if (IS_ERR(samsung->regmap)) { ret = PTR_ERR(samsung->regmap); dev_err(dev, "failed to init regmap: %d\n", ret); return ret; } samsung->grf_regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); if (IS_ERR(samsung->grf_regmap)) { dev_err(dev, "Unable to get rockchip,grf\n"); return PTR_ERR(samsung->grf_regmap); } samsung->ref_clk = devm_clk_get(dev, "ref"); if (IS_ERR(samsung->ref_clk)) { dev_err(dev, "failed to get reference clock\n"); return PTR_ERR(samsung->ref_clk); } samsung->pclk = devm_clk_get(dev, "pclk"); if (IS_ERR(samsung->pclk)) { dev_err(dev, "failed to get pclk\n"); return PTR_ERR(samsung->pclk); } samsung->m_phy_rst = devm_reset_control_get(dev, "m_phy"); if (IS_ERR(samsung->m_phy_rst)) { dev_err(dev, "failed to get system m_phy_rst control\n"); return PTR_ERR(samsung->m_phy_rst); } samsung->s_phy_rst = devm_reset_control_get(dev, "s_phy"); if (IS_ERR(samsung->s_phy_rst)) { dev_err(dev, "failed to get system s_phy_rst control\n"); return PTR_ERR(samsung->s_phy_rst); } samsung->apb_rst = devm_reset_control_get(dev, "apb"); if (IS_ERR(samsung->apb_rst)) { dev_err(dev, "failed to get system apb_rst control\n"); return PTR_ERR(samsung->apb_rst); } samsung->grf_apb_rst = devm_reset_control_get(dev, "grf"); if (IS_ERR(samsung->grf_apb_rst)) { dev_err(dev, "failed to get system grf_apb_rst control\n"); return PTR_ERR(samsung->grf_apb_rst); } phy = devm_phy_create(dev, NULL, &samsung_mipi_dcphy_ops); if (IS_ERR(phy)) { dev_err(dev, "failed to create MIPI Dc-PHY\n"); return PTR_ERR(phy); } phy_set_drvdata(phy, samsung); phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); if (IS_ERR(phy_provider)) { dev_err(dev, "failed to register phy provider\n"); return PTR_ERR(phy_provider); } samsung->stream_on = samsung_dcphy_rx_stream_on; samsung->stream_off = samsung_dcphy_rx_stream_off; mutex_init(&samsung->mutex); pm_runtime_enable(dev); return 0; } static int samsung_mipi_dcphy_remove(struct platform_device *pdev) { struct samsung_mipi_dcphy *samsung = platform_get_drvdata(pdev); pm_runtime_disable(samsung->dev); mutex_destroy(&samsung->mutex); return 0; } static __maybe_unused int samsung_mipi_dcphy_runtime_suspend(struct device *dev) { struct samsung_mipi_dcphy *samsung = dev_get_drvdata(dev); clk_disable_unprepare(samsung->pclk); clk_disable_unprepare(samsung->ref_clk); return 0; } static __maybe_unused int samsung_mipi_dcphy_runtime_resume(struct device *dev) { struct samsung_mipi_dcphy *samsung = dev_get_drvdata(dev); clk_prepare_enable(samsung->pclk); clk_prepare_enable(samsung->ref_clk); return 0; } static const struct dev_pm_ops samsung_mipi_dcphy_pm_ops = { SET_RUNTIME_PM_OPS(samsung_mipi_dcphy_runtime_suspend, samsung_mipi_dcphy_runtime_resume, NULL) }; static const struct hs_drv_res_cfg rk3576_dphy_hs_drv_res_cfg = { .clk_hs_drv_up_ohm = _52_OHM, .clk_hs_drv_down_ohm = _52_OHM, .data_hs_drv_up_ohm = _39_OHM, .data_hs_drv_down_ohm = _39_OHM, }; static const struct hs_drv_res_cfg rk3588_dphy_hs_drv_res_cfg = { .clk_hs_drv_up_ohm = _34_OHM, .clk_hs_drv_down_ohm = _34_OHM, .data_hs_drv_up_ohm = _43_OHM, .data_hs_drv_down_ohm = _43_OHM, }; static const struct samsung_mipi_dcphy_plat_data rk3576_samsung_mipi_dcphy_plat_data = { .dphy_hs_drv_res_cfg = &rk3576_dphy_hs_drv_res_cfg, .dphy_tx_max_kbps_per_lane = 2500000L, .cphy_tx_max_ksps_per_lane = 1700000L, }; static const struct samsung_mipi_dcphy_plat_data rk3588_samsung_mipi_dcphy_plat_data = { .dphy_hs_drv_res_cfg = &rk3588_dphy_hs_drv_res_cfg, .dphy_tx_max_kbps_per_lane = 4500000L, .cphy_tx_max_ksps_per_lane = 2000000L, }; static const struct of_device_id samsung_mipi_dcphy_of_match[] = { { .compatible = "rockchip,rk3576-mipi-dcphy", .data = &rk3576_samsung_mipi_dcphy_plat_data, }, { .compatible = "rockchip,rk3588-mipi-dcphy", .data = &rk3588_samsung_mipi_dcphy_plat_data, }, {} }; MODULE_DEVICE_TABLE(of, samsung_mipi_dcphy_of_match); static struct platform_driver samsung_mipi_dcphy_driver = { .driver = { .name = "samsung-mipi-dcphy", .of_match_table = of_match_ptr(samsung_mipi_dcphy_of_match), .pm = &samsung_mipi_dcphy_pm_ops, }, .probe = samsung_mipi_dcphy_probe, .remove = samsung_mipi_dcphy_remove, }; module_platform_driver(samsung_mipi_dcphy_driver); MODULE_AUTHOR("Guochun Huang"); MODULE_DESCRIPTION("Samsung MIPI DCPHY Driver"); MODULE_LICENSE("GPL v2");