hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
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
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) 2022 Rockchip Electronics Co. Ltd.
 *
 * Author: Guochun Huang <hero.huang@rock-chips.com>
 */
 
#include <asm/unaligned.h>
#include <dt-bindings/mfd/rockchip-serdes.h>
#include "rkx110_reg.h"
#include "rkx110_x120.h"
#include "rkx110_dsi_rx.h"
#include "serdes_combphy.h"
 
#define DSI_RX_MIPI_IDX_CTRL0(x)    (0x0100 + x * 8)
#define SW_COMMAND_MODE_EN        BIT(26)
#define SW_DT(x)            UPDATE(x, 15, 10)
#define SW_VC(x)            UPDATE(x, 9, 8)
#define SW_CAP_EN            BIT(0)
#define DSI_RX_MIPI_IDX_CTRL1(x)    (0X0104 + x * 8)
#define SW_HEIGHT(x)            UPDATE(x, 29, 16)
#define SW_WIDTH(x)            UPDATE(x, 13, 0)
#define DSI_RX_MIPI_INTEN        0x0174
#define DSI_RX_MIPI_INTSTAT        0x0178
#define DSI_RX_MIPI_SIZE_NUM(x)        (0x01c0 + x * 4)
 
enum {
   VSYNC_START = 0x01,
   VSYNC_END = 0x11,
   HSYNC_START = 0x21,
   HSYNC_END = 0x31,
};
 
static inline int dsi_rx_write(struct rk_serdes *ser, u32 reg, u32 val)
{
   struct i2c_client *client = ser->chip[DEVICE_LOCAL].client;
 
   return ser->i2c_write_reg(client, reg, val);
}
 
static inline int dsi_rx_read(struct rk_serdes *ser, u32 reg, u32 *val)
{
   struct i2c_client *client = ser->chip[DEVICE_LOCAL].client;
 
   return ser->i2c_read_reg(client, reg, val);
}
 
static inline int dsi_rx_update_bits(struct rk_serdes *ser,
                    u32 reg, u32 mask, u32 val)
{
   struct i2c_client *client = ser->chip[DEVICE_LOCAL].client;
 
   return ser->i2c_update_bits(client, reg, mask, val);
}
 
void rkx110_dsi_rx_enable(struct rk_serdes *ser, struct rk_serdes_route *route, int id)
{
   struct rk_serdes_panel *sd_panel = container_of(route, struct rk_serdes_panel, route);
   struct rkx110_dsi_rx *dsi = &sd_panel->dsi_rx;
   struct rkx110_combrxphy *combrxphy = &sd_panel->combrxphy;
   const struct videomode *vm = &route->vm;
   unsigned long pixelclock;
   u32 hactive, vactive;
   u64 rate;
   u32 val = 0;
   u32 csi_base, dsirx_base;
 
   switch (route->frame_mode) {
   case SERDES_SP_PIXEL_INTERLEAVED:
       fallthrough;
   case SERDES_SP_LEFT_RIGHT_SPLIT:
       pixelclock = vm->pixelclock * 2;
       hactive = vm->hactive * 2;
       vactive = vm->vactive;
       break;
   case SERDES_SP_LINE_INTERLEAVED:
       pixelclock = vm->pixelclock * 2;
       vactive = vm->vactive * 2;
       hactive = vm->hactive;
       break;
   case SERDES_FRAME_NORMAL_MODE:
       fallthrough;
   default:
       pixelclock = vm->pixelclock;
       hactive = vm->hactive;
       vactive = vm->vactive;
       break;
   }
 
   rate = DIV_ROUND_CLOSEST_ULL(pixelclock, dsi->lanes);
 
   rkx110_combrxphy_set_mode(combrxphy, COMBRX_PHY_MODE_VIDEO_MIPI);
   rkx110_combrxphy_set_rate(combrxphy, rate * MSEC_PER_SEC);
   rkx110_combrxphy_set_lanes(combrxphy, dsi->lanes);
   rkx110_combrxphy_power_on(ser, combrxphy, DEVICE_LOCAL, id ? COMBPHY_1 : COMBPHY_0);
 
   csi_base = id ? RKX110_CSI2HOST1_BASE : RKX110_CSI2HOST0_BASE;
   dsirx_base = id ? RKX110_DSI_RX1_BASE : RKX110_DSI_RX0_BASE;
 
 
   dsi_rx_write(ser, csi_base + CSI2HOST_N_LANES, dsi->lanes - 1);
   dsi_rx_write(ser, csi_base + CSI2HOST_RESETN, 0);
 
   val |= SW_DSI_EN | SW_DATETYPE_FE(VSYNC_END) | SW_DATETYPE_FS(VSYNC_START);
   dsi_rx_update_bits(ser, csi_base + CSI2HOST_CONTROL,
              SW_DATETYPE_FE_MASK |
              SW_DATETYPE_FS_MASK |
              SW_DSI_EN, val);
 
   dsi_rx_write(ser, csi_base + CSI2HOST_RESETN, 1);
 
   val = SW_CAP_EN | SW_VC(0);
   /*
    * video mode only support rgb888(0x3e), command mode
    * only support DCS Long Write(0x39)
    */
   val |= (dsi->mode_flags & SERDES_MIPI_DSI_MODE_VIDEO) ?
          (0 | SW_DT(0x3e)) : (SW_COMMAND_MODE_EN | SW_DT(0x39));
   dsi_rx_write(ser, dsirx_base + DSI_RX_MIPI_IDX_CTRL0(0), val);
   dsi_rx_write(ser, dsirx_base + DSI_RX_MIPI_IDX_CTRL1(0),
            SW_HEIGHT(vactive) | SW_WIDTH(hactive));
}
 
void rkx110_dsi_rx_disable(struct rk_serdes *ser, struct rk_serdes_route *route, int id)
{
   struct rk_serdes_panel *sd_panel = container_of(route, struct rk_serdes_panel, route);
   struct rkx110_combrxphy *combrxphy = &sd_panel->combrxphy;
 
   rkx110_combrxphy_power_off(ser, combrxphy, DEVICE_LOCAL, id ? COMBPHY_1 : COMBPHY_0);
}