hc
2024-03-26 e0728245c89800c2038c23308f2d88969d5b41c8
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
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * maxim-max96745.c  --  I2C register interface access for max96745 serdes chip
 *
 * Copyright (c) 2023-2028 Rockchip Electronics Co. Ltd.
 *
 * Author: luowei <lw@rock-chips.com>
 */
#include <serdes-display-core.h>
#include "maxim-max96745.h"
 
static bool max96745_bridge_link_locked(struct serdes *serdes)
{
   int ret;
   unsigned int value;
 
   ret = serdes_reg_read(serdes, 0x002a, &value);
   if (ret < 0)
       return false;
 
   if (!FIELD_GET(LINK_LOCKED, value))
       return false;
 
   return true;
}
 
static bool max96745_bridge_detect(struct serdes *serdes)
{
   return max96745_bridge_link_locked(serdes);
}
 
static int max96745_bridge_enable(struct serdes *serdes)
{
   struct drm_display_mode *mode =
        &serdes->serdes_bridge->bridge->state->conn_state.mode;
   u8 cxtp, tx_rate;
   int ret;
   unsigned int value;
 
   ret = serdes_reg_read(serdes, 0x0011, &value);
   if (ret < 0)
       return ret;
 
   cxtp = FIELD_GET(CXTP_A, value);
 
   ret = serdes_reg_read(serdes, 0x0028, &value);
   if (ret < 0)
       return ret;
 
   tx_rate = FIELD_GET(TX_RATE, value);
 
   if (!cxtp && mode->clock > 95000 && tx_rate == 1) {
       ret = serdes_set_bits(serdes, 0x0028, TX_RATE,
                     FIELD_PREP(TX_RATE, 2));
       if (ret < 0)
           return ret;
 
       ret = serdes_set_bits(serdes, 0x0029, RESET_ONESHOT,
                     FIELD_PREP(RESET_ONESHOT, 1));
       if (ret < 0)
           return ret;
 
       if (readx_poll_timeout(max96745_bridge_link_locked, serdes, ret,
                      ret, 200000))
           printf("%s: GMSL link not locked\n", __func__);
   }
 
   return ret;
}
 
static int max96745_bridge_disable(struct serdes *serdes)
{
   u8 cxtp, tx_rate;
   int ret;
   unsigned int value;
 
   ret = serdes_reg_read(serdes, 0x0011, &value);
   if (ret < 0)
       return ret;
 
   cxtp = FIELD_GET(CXTP_A, value);
 
   ret = serdes_reg_read(serdes, 0x0028, &value);
   if (ret < 0)
       return ret;
 
   tx_rate = FIELD_GET(TX_RATE, value);
 
   if (!cxtp && tx_rate == 2) {
       ret = serdes_set_bits(serdes, 0x0028, TX_RATE,
                     FIELD_PREP(TX_RATE, 1));
       if (ret < 0)
           return ret;
 
       ret = serdes_set_bits(serdes, 0x0029, RESET_ONESHOT,
                     FIELD_PREP(RESET_ONESHOT, 1));
       if (ret < 0)
           return ret;
 
       if (readx_poll_timeout(max96745_bridge_link_locked, serdes, ret,
                      ret, 200000))
           printf("%s: GMSL link not locked\n", __func__);
   }
 
   return ret;
}
 
struct serdes_chip_bridge_ops max96745_bridge_ops = {
   .detect = max96745_bridge_detect,
   .enable = max96745_bridge_enable,
   .disable = max96745_bridge_disable,
};
 
struct serdes_chip_data serdes_max96745_data = {
   .name        = "max96745",
   .serdes_type    = TYPE_SER,
   .serdes_id    = MAXIM_ID_MAX96745,
   .bridge_ops    = &max96745_bridge_ops,
};
EXPORT_SYMBOL_GPL(serdes_max96745_data);