1 #include "bflb_csi.h"
2 #include "hardware/csi_reg.h"
3 #include "hardware/dtsrc_reg.h"
4 
5 #define DTSRC_BASE 0x30012800
6 
bflb_csi_phy_config(struct bflb_device_s * dev,uint32_t tx_clk_escape,uint32_t data_rate)7 static void bflb_csi_phy_config(struct bflb_device_s *dev, uint32_t tx_clk_escape, uint32_t data_rate)
8 {
9     uint32_t reg_base;
10     uint32_t regval;
11 
12     /* Unit: ns */
13     float TD_TERM_EN_MAX = 35 + 4 * (1e3) / data_rate;
14     uint32_t TD_TERM_EN = (TD_TERM_EN_MAX * data_rate / 2 / (1e3)) - 1;
15     float THS_SETTLE_MAX = 145 + 10 * (1e3) / data_rate;
16     /* THS_SETTLE = reg_time_hs_settle + reg_time_hs_term_en */
17     uint32_t THS_SETTLE = ((THS_SETTLE_MAX - TD_TERM_EN * 2 * (1e3) / data_rate) * data_rate / 2 / (1e3)) - 1;
18     uint32_t TCLK_TERM_EN_MAX = 38;
19     uint32_t TCLK_TERM_EN = (tx_clk_escape * TCLK_TERM_EN_MAX) / (1e3);
20     uint32_t TCLK_SETTLE_MAX = 300;
21     /* TCLK_SETTLE = reg_time_ck_settle + reg_time_ck_term_en */
22     uint32_t TCLK_SETTLE = ((TCLK_SETTLE_MAX - TCLK_TERM_EN * (1e3) / tx_clk_escape) * tx_clk_escape / (1e3)) - 1;
23 
24     uint32_t ANA_TERM_EN = 0x8;
25 
26     reg_base = dev->reg_base;
27     regval = TD_TERM_EN  << CSI_REG_TIME_HS_TERM_EN_SHIFT & CSI_REG_TIME_HS_TERM_EN_MASK;
28     regval |= THS_SETTLE << CSI_REG_TIME_HS_SETTLE_SHIFT & CSI_REG_TIME_HS_SETTLE_MASK;
29     regval |= TCLK_TERM_EN << CSI_REG_TIME_CK_TERM_EN_SHIFT & CSI_REG_TIME_CK_TERM_EN_MASK;
30     regval |= TCLK_SETTLE << CSI_REG_TIME_CK_SETTLE_SHIFT & CSI_REG_TIME_CK_SETTLE_MASK;
31     putreg32(regval, reg_base + CSI_DPHY_CONFIG_1_OFFSET);
32 
33     regval = getreg32(DTSRC_BASE + CSI_DPHY_CONFIG_2_OFFSET);
34     regval &= ~CSI_REG_ANA_TERM_EN_MASK;
35     regval |= ANA_TERM_EN << CSI_REG_ANA_TERM_EN_SHIFT & CSI_REG_ANA_TERM_EN_MASK;
36     putreg32(regval, reg_base + CSI_DPHY_CONFIG_2_OFFSET);
37 }
38 
bflb_csi_init(struct bflb_device_s * dev,const struct bflb_csi_config_s * config)39 void bflb_csi_init(struct bflb_device_s *dev, const struct bflb_csi_config_s *config)
40 {
41     uint32_t reg_base;
42     uint32_t regval;
43 
44     reg_base = dev->reg_base;
45     regval = getreg32(DTSRC_BASE + DTSRC_CONFIG_OFFSET);
46     regval |= DTSRC_CR_SNSR_EN;
47     putreg32(regval, DTSRC_BASE + DTSRC_CONFIG_OFFSET);
48 
49     regval = getreg32(reg_base + CSI_DPHY_CONFIG_0_OFFSET);
50     regval &= ~(CSI_DL0_ENABLE | CSI_DL1_ENABLE | CSI_CL_ENABLE | CSI_DL0_FORCERXMODE | CSI_DL1_FORCERXMODE | CSI_RESET_N);
51     putreg32(regval, reg_base + CSI_DPHY_CONFIG_0_OFFSET);
52     regval |= CSI_RESET_N;
53     putreg32(regval, reg_base + CSI_DPHY_CONFIG_0_OFFSET);
54 
55     regval = getreg32(reg_base + CSI_MIPI_CONFIG_OFFSET);
56     if (config->lane_number) {
57         regval |= CSI_CR_LANE_NUM;
58     } else {
59         regval &= ~CSI_CR_LANE_NUM;
60     }
61     regval |= CSI_CR_UNPACK_EN | CSI_CR_SYNC_SP_EN;
62     putreg32(regval, reg_base + CSI_MIPI_CONFIG_OFFSET);
63 
64     bflb_csi_phy_config(dev, config->tx_clk_escape / 1000000, config->data_rate / 1000000);
65 
66     regval = getreg32(reg_base + CSI_DPHY_CONFIG_0_OFFSET);
67     regval |= CSI_DL0_ENABLE | CSI_CL_ENABLE | CSI_DL0_FORCERXMODE;
68     if (config->lane_number) {
69         regval |= CSI_DL1_ENABLE | CSI_DL1_FORCERXMODE;
70     }
71     putreg32(regval, reg_base + CSI_DPHY_CONFIG_0_OFFSET);
72 
73     regval = getreg32(DTSRC_BASE + DTSRC_CONFIG_OFFSET);
74     regval |= DTSRC_CR_ENABLE;
75     putreg32(regval, DTSRC_BASE + DTSRC_CONFIG_OFFSET);
76 }
77 
bflb_csi_start(struct bflb_device_s * dev)78 void bflb_csi_start(struct bflb_device_s *dev)
79 {
80     uint32_t reg_base;
81     uint32_t regval;
82 
83     reg_base = dev->reg_base;
84     regval = getreg32(reg_base + CSI_MIPI_CONFIG_OFFSET);
85     regval |= CSI_CR_CSI_EN;
86     putreg32(regval, reg_base + CSI_MIPI_CONFIG_OFFSET);
87 }
88 
bflb_csi_stop(struct bflb_device_s * dev)89 void bflb_csi_stop(struct bflb_device_s *dev)
90 {
91     uint32_t reg_base;
92     uint32_t regval;
93 
94     reg_base = dev->reg_base;
95     regval = getreg32(reg_base + CSI_MIPI_CONFIG_OFFSET);
96     regval &= ~CSI_CR_CSI_EN;
97     putreg32(regval, reg_base + CSI_MIPI_CONFIG_OFFSET);
98 }
99 
bflb_csi_set_line_threshold(struct bflb_device_s * dev,uint16_t resolution_x,uint32_t pixel_clock,uint32_t dsp_clock)100 void bflb_csi_set_line_threshold(struct bflb_device_s *dev, uint16_t resolution_x, uint32_t pixel_clock, uint32_t dsp_clock)
101 {
102     uint32_t threshold;
103 
104     threshold = (dsp_clock - pixel_clock) / 1000 * resolution_x / (dsp_clock / 1000) + 10;
105     putreg32(threshold, DTSRC_BASE + DTSRC_SNSR2DVP_WAIT_POS_OFFSET);
106 }
107 
bflb_csi_int_mask(struct bflb_device_s * dev,uint32_t int_type,bool mask)108 void bflb_csi_int_mask(struct bflb_device_s *dev, uint32_t int_type, bool mask)
109 {
110     uint32_t reg_base;
111     uint32_t regval;
112 
113     reg_base = dev->reg_base;
114     regval = getreg32(reg_base + CSI_INT_MASK_OFFSET);
115     if (mask) {
116         regval |= int_type;
117     } else {
118         regval &= ~int_type;
119     }
120     putreg32(regval, reg_base + CSI_INT_MASK_OFFSET);
121 }
122 
bflb_csi_int_clear(struct bflb_device_s * dev,uint32_t int_type)123 void bflb_csi_int_clear(struct bflb_device_s *dev, uint32_t int_type)
124 {
125     putreg32(int_type, dev->reg_base + CSI_INT_CLEAR_OFFSET);
126 }
127 
bflb_csi_get_intstatus(struct bflb_device_s * dev)128 uint32_t bflb_csi_get_intstatus(struct bflb_device_s *dev)
129 {
130     return(getreg32(dev->reg_base + CSI_INT_STATUS_OFFSET));
131 }
132 
bflb_csi_feature_control(struct bflb_device_s * dev,int cmd,size_t arg)133 int bflb_csi_feature_control(struct bflb_device_s *dev, int cmd, size_t arg)
134 {
135     int ret = 0;
136 
137     switch (cmd) {
138         default:
139             ret = -EPERM;
140             break;
141     }
142     return ret;
143 }
144