summaryrefslogtreecommitdiff
path: root/bsp/bouffalo_lab/libraries/bl_mcu_sdk/drivers/lhal/src/bflb_csi.c
blob: 7237e2c3d5add569fd6a8d7dafeef18cce96fa95 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include "bflb_csi.h"
#include "hardware/csi_reg.h"
#include "hardware/dtsrc_reg.h"

#define DTSRC_BASE 0x30012800

static void bflb_csi_phy_config(struct bflb_device_s *dev, uint32_t tx_clk_escape, uint32_t data_rate)
{
    uint32_t reg_base;
    uint32_t regval;
    
    /* Unit: ns */
    float TD_TERM_EN_MAX = 35 + 4 * (1e3) / data_rate; 
    uint32_t TD_TERM_EN = (TD_TERM_EN_MAX * data_rate / 2 / (1e3)) - 1;
    float THS_SETTLE_MAX = 145 + 10 * (1e3) / data_rate;
    /* THS_SETTLE = reg_time_hs_settle + reg_time_hs_term_en */
    uint32_t THS_SETTLE = ((THS_SETTLE_MAX - TD_TERM_EN * 2 * (1e3) / data_rate) * data_rate / 2 / (1e3)) - 1;
    uint32_t TCLK_TERM_EN_MAX = 38;
    uint32_t TCLK_TERM_EN = (tx_clk_escape * TCLK_TERM_EN_MAX) / (1e3);
    uint32_t TCLK_SETTLE_MAX = 300;
    /* TCLK_SETTLE = reg_time_ck_settle + reg_time_ck_term_en */
    uint32_t TCLK_SETTLE = ((TCLK_SETTLE_MAX - TCLK_TERM_EN * (1e3) / tx_clk_escape) * tx_clk_escape / (1e3)) - 1;

    uint32_t ANA_TERM_EN = 0x8;
    
    reg_base = dev->reg_base;
    regval = TD_TERM_EN  << CSI_REG_TIME_HS_TERM_EN_SHIFT & CSI_REG_TIME_HS_TERM_EN_MASK;
    regval |= THS_SETTLE << CSI_REG_TIME_HS_SETTLE_SHIFT & CSI_REG_TIME_HS_SETTLE_MASK;
    regval |= TCLK_TERM_EN << CSI_REG_TIME_CK_TERM_EN_SHIFT & CSI_REG_TIME_CK_TERM_EN_MASK;
    regval |= TCLK_SETTLE << CSI_REG_TIME_CK_SETTLE_SHIFT & CSI_REG_TIME_CK_SETTLE_MASK;
    putreg32(regval, reg_base + CSI_DPHY_CONFIG_1_OFFSET);
    
    regval = getreg32(DTSRC_BASE + CSI_DPHY_CONFIG_2_OFFSET);
    regval &= ~CSI_REG_ANA_TERM_EN_MASK;
    regval |= ANA_TERM_EN << CSI_REG_ANA_TERM_EN_SHIFT & CSI_REG_ANA_TERM_EN_MASK;
    putreg32(regval, reg_base + CSI_DPHY_CONFIG_2_OFFSET);
}

void bflb_csi_init(struct bflb_device_s *dev, const struct bflb_csi_config_s *config)
{
    uint32_t reg_base;
    uint32_t regval;

    reg_base = dev->reg_base;
    regval = getreg32(DTSRC_BASE + DTSRC_CONFIG_OFFSET);
    regval |= DTSRC_CR_SNSR_EN;
    putreg32(regval, DTSRC_BASE + DTSRC_CONFIG_OFFSET);
    
    regval = getreg32(reg_base + CSI_DPHY_CONFIG_0_OFFSET);
    regval &= ~(CSI_DL0_ENABLE | CSI_DL1_ENABLE | CSI_CL_ENABLE | CSI_DL0_FORCERXMODE | CSI_DL1_FORCERXMODE | CSI_RESET_N);
    putreg32(regval, reg_base + CSI_DPHY_CONFIG_0_OFFSET);
    regval |= CSI_RESET_N;
    putreg32(regval, reg_base + CSI_DPHY_CONFIG_0_OFFSET);
    
    regval = getreg32(reg_base + CSI_MIPI_CONFIG_OFFSET);
    if (config->lane_number) {
        regval |= CSI_CR_LANE_NUM;
    } else {
        regval &= ~CSI_CR_LANE_NUM;
    }
    regval |= CSI_CR_UNPACK_EN | CSI_CR_SYNC_SP_EN;
    putreg32(regval, reg_base + CSI_MIPI_CONFIG_OFFSET);
    
    bflb_csi_phy_config(dev, config->tx_clk_escape / 1000000, config->data_rate / 1000000);
    
    regval = getreg32(reg_base + CSI_DPHY_CONFIG_0_OFFSET);
    regval |= CSI_DL0_ENABLE | CSI_CL_ENABLE | CSI_DL0_FORCERXMODE;
    if (config->lane_number) {
        regval |= CSI_DL1_ENABLE | CSI_DL1_FORCERXMODE;
    }
    putreg32(regval, reg_base + CSI_DPHY_CONFIG_0_OFFSET);
    
    regval = getreg32(DTSRC_BASE + DTSRC_CONFIG_OFFSET);
    regval |= DTSRC_CR_ENABLE;
    putreg32(regval, DTSRC_BASE + DTSRC_CONFIG_OFFSET);
}

void bflb_csi_start(struct bflb_device_s *dev)
{
    uint32_t reg_base;
    uint32_t regval;

    reg_base = dev->reg_base;
    regval = getreg32(reg_base + CSI_MIPI_CONFIG_OFFSET);
    regval |= CSI_CR_CSI_EN;
    putreg32(regval, reg_base + CSI_MIPI_CONFIG_OFFSET);
}

void bflb_csi_stop(struct bflb_device_s *dev)
{
    uint32_t reg_base;
    uint32_t regval;

    reg_base = dev->reg_base;
    regval = getreg32(reg_base + CSI_MIPI_CONFIG_OFFSET);
    regval &= ~CSI_CR_CSI_EN;
    putreg32(regval, reg_base + CSI_MIPI_CONFIG_OFFSET);
}

void bflb_csi_set_line_threshold(struct bflb_device_s *dev, uint16_t resolution_x, uint32_t pixel_clock, uint32_t dsp_clock)
{
    uint32_t threshold;
    
    threshold = (dsp_clock - pixel_clock) / 1000 * resolution_x / (dsp_clock / 1000) + 10;
    putreg32(threshold, DTSRC_BASE + DTSRC_SNSR2DVP_WAIT_POS_OFFSET);
}

void bflb_csi_int_mask(struct bflb_device_s *dev, uint32_t int_type, bool mask)
{
    uint32_t reg_base;
    uint32_t regval;

    reg_base = dev->reg_base;
    regval = getreg32(reg_base + CSI_INT_MASK_OFFSET);
    if (mask) {
        regval |= int_type;
    } else {
        regval &= ~int_type;
    }
    putreg32(regval, reg_base + CSI_INT_MASK_OFFSET);
}

void bflb_csi_int_clear(struct bflb_device_s *dev, uint32_t int_type)
{
    putreg32(int_type, dev->reg_base + CSI_INT_CLEAR_OFFSET);
}

uint32_t bflb_csi_get_intstatus(struct bflb_device_s *dev)
{
    return(getreg32(dev->reg_base + CSI_INT_STATUS_OFFSET));
}

int bflb_csi_feature_control(struct bflb_device_s *dev, int cmd, size_t arg)
{
    int ret = 0;

    switch (cmd) {
        default:
            ret = -EPERM;
            break;
    }
    return ret;
}