1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "aml-mipi-phy.h"
6 #include <ddk/debug.h>
7
8 namespace astro_display {
9
10 #define READ32_MIPI_DSI_REG(a) mipi_dsi_mmio_->Read32(a)
11 #define WRITE32_MIPI_DSI_REG(a, v) mipi_dsi_mmio_->Write32(v, a)
12
13 #define READ32_DSI_PHY_REG(a) dsi_phy_mmio_->Read32(a)
14 #define WRITE32_DSI_PHY_REG(a, v) dsi_phy_mmio_->Write32(v, a)
15
16 template<typename T>
NsToLaneByte(T x,uint32_t lanebytetime)17 constexpr inline uint8_t NsToLaneByte(T x, uint32_t lanebytetime) {
18 return (static_cast<uint8_t>((x + lanebytetime - 1) / lanebytetime) & 0xFF);
19 }
20
21 constexpr uint32_t kUnit = (1 * 1000 * 1000 * 100);
22 constexpr uint32_t kPhyDelay = 6;
23
PhyCfgLoad(uint32_t bitrate)24 zx_status_t AmlMipiPhy::PhyCfgLoad(uint32_t bitrate) {
25 ZX_DEBUG_ASSERT(initialized_);
26
27 // According to MIPI -PHY Spec, we need to define Unit Interval (UI).
28 // This UI is defined as the time it takes to send a bit (i.e. bitrate)
29 // The x100 is to ensure the ui is not rounded too much (i.e. 2.56 --> 256)
30 // However, since we have introduced x100, we need to make sure we include x100
31 // to all the PHY timings that are in ns units.
32 const uint32_t ui = kUnit / (bitrate / 1000);
33
34 // Calculate values will be rounded by the lanebyteclk
35 const uint32_t lanebytetime = ui * 8;
36
37 // lp_tesc:TX Excape Clock Division factor (from linebyteclk). Round up to units of ui
38 dsi_phy_cfg_.lp_tesc = NsToLaneByte(DPHY_TIME_LP_TESC, lanebytetime);
39
40 // lp_lpx: Transmit length of any LP state period
41 dsi_phy_cfg_.lp_lpx = NsToLaneByte(DPHY_TIME_LP_LPX, lanebytetime);
42
43 // lp_ta_sure
44 dsi_phy_cfg_.lp_ta_sure = NsToLaneByte(DPHY_TIME_LP_TA_SURE, lanebytetime);
45
46 // lp_ta_go
47 dsi_phy_cfg_.lp_ta_go = NsToLaneByte(DPHY_TIME_LP_TA_GO, lanebytetime);
48
49 // lp_ta_get
50 dsi_phy_cfg_.lp_ta_get = NsToLaneByte(DPHY_TIME_LP_TA_GET, lanebytetime);
51
52 // hs_exit
53 dsi_phy_cfg_.hs_exit = NsToLaneByte(DPHY_TIME_HS_EXIT, lanebytetime);
54
55 // clk-_prepare
56 dsi_phy_cfg_.clk_prepare = NsToLaneByte(DPHY_TIME_CLK_PREPARE, lanebytetime);
57
58 // clk_zero
59 dsi_phy_cfg_.clk_zero = NsToLaneByte(DPHY_TIME_CLK_ZERO(ui), lanebytetime);
60
61 // clk_pre
62 dsi_phy_cfg_.clk_pre = NsToLaneByte(DPHY_TIME_CLK_PRE(ui), lanebytetime);
63
64 // init
65 dsi_phy_cfg_.init = NsToLaneByte(DPHY_TIME_INIT, lanebytetime);
66
67 // wakeup
68 dsi_phy_cfg_.wakeup = NsToLaneByte(DPHY_TIME_WAKEUP, lanebytetime);
69
70 // clk_trail
71 dsi_phy_cfg_.clk_trail = NsToLaneByte(DPHY_TIME_CLK_TRAIL, lanebytetime);
72
73 // clk_post
74 dsi_phy_cfg_.clk_post = NsToLaneByte(DPHY_TIME_CLK_POST(ui), lanebytetime);
75
76 // hs_trail
77 dsi_phy_cfg_.hs_trail = NsToLaneByte(DPHY_TIME_HS_TRAIL(ui), lanebytetime);
78
79 // hs_prepare
80 dsi_phy_cfg_.hs_prepare = NsToLaneByte(DPHY_TIME_HS_PREPARE(ui), lanebytetime);
81
82 // hs_zero
83 dsi_phy_cfg_.hs_zero = NsToLaneByte(DPHY_TIME_HS_ZERO(ui), lanebytetime);
84
85 // Ensure both clk-trail and hs-trail do not exceed Teot (End of Transmission Time)
86 const uint32_t time_req_max = NsToLaneByte(DPHY_TIME_EOT(ui), lanebytetime);
87 if ((dsi_phy_cfg_.clk_trail > time_req_max) ||
88 (dsi_phy_cfg_.hs_trail > time_req_max)) {
89 DISP_ERROR("Invalid clk-trail and/or hs-trail exceed Teot!\n");
90 DISP_ERROR("clk-trail = 0x%02x, hs-trail = 0x%02x, Teot = 0x%02x\n",
91 dsi_phy_cfg_.clk_trail, dsi_phy_cfg_.hs_trail, time_req_max );
92 return ZX_ERR_OUT_OF_RANGE;
93 }
94
95 DISP_SPEW("lp_tesc = 0x%02x\n"
96 "lp_lpx = 0x%02x\n"
97 "lp_ta_sure = 0x%02x\n"
98 "lp_ta_go = 0x%02x\n"
99 "lp_ta_get = 0x%02x\n"
100 "hs_exit = 0x%02x\n"
101 "hs_trail = 0x%02x\n"
102 "hs_zero = 0x%02x\n"
103 "hs_prepare = 0x%02x\n"
104 "clk_trail = 0x%02x\n"
105 "clk_post = 0x%02x\n"
106 "clk_zero = 0x%02x\n"
107 "clk_prepare = 0x%02x\n"
108 "clk_pre = 0x%02x\n"
109 "init = 0x%02x\n"
110 "wakeup = 0x%02x\n\n",
111 dsi_phy_cfg_.lp_tesc,
112 dsi_phy_cfg_.lp_lpx,
113 dsi_phy_cfg_.lp_ta_sure,
114 dsi_phy_cfg_.lp_ta_go,
115 dsi_phy_cfg_.lp_ta_get,
116 dsi_phy_cfg_.hs_exit,
117 dsi_phy_cfg_.hs_trail,
118 dsi_phy_cfg_.hs_zero,
119 dsi_phy_cfg_.hs_prepare,
120 dsi_phy_cfg_.clk_trail,
121 dsi_phy_cfg_.clk_post,
122 dsi_phy_cfg_.clk_zero,
123 dsi_phy_cfg_.clk_prepare,
124 dsi_phy_cfg_.clk_pre,
125 dsi_phy_cfg_.init,
126 dsi_phy_cfg_.wakeup);
127 return ZX_OK;
128 }
129
PhyInit()130 void AmlMipiPhy::PhyInit()
131 {
132 // Enable phy clock.
133 WRITE32_REG(DSI_PHY, MIPI_DSI_PHY_CTRL, PHY_CTRL_TXDDRCLK_EN |
134 PHY_CTRL_DDRCLKPATH_EN | PHY_CTRL_CLK_DIV_COUNTER | PHY_CTRL_CLK_DIV_EN |
135 PHY_CTRL_BYTECLK_EN);
136
137 // Toggle PHY CTRL RST
138 SET_BIT32(DSI_PHY, MIPI_DSI_PHY_CTRL, 1, PHY_CTRL_RST_START, PHY_CTRL_RST_BITS);
139 SET_BIT32(DSI_PHY, MIPI_DSI_PHY_CTRL, 0, PHY_CTRL_RST_START, PHY_CTRL_RST_BITS);
140
141 WRITE32_REG(DSI_PHY, MIPI_DSI_CLK_TIM,
142 (dsi_phy_cfg_.clk_trail | (dsi_phy_cfg_.clk_post << 8) |
143 (dsi_phy_cfg_.clk_zero << 16) |
144 (dsi_phy_cfg_.clk_prepare << 24)));
145
146 WRITE32_REG(DSI_PHY, MIPI_DSI_CLK_TIM1, dsi_phy_cfg_.clk_pre);
147
148 WRITE32_REG(DSI_PHY, MIPI_DSI_HS_TIM,
149 (dsi_phy_cfg_.hs_exit | (dsi_phy_cfg_.hs_trail << 8) |
150 (dsi_phy_cfg_.hs_zero << 16) |
151 (dsi_phy_cfg_.hs_prepare << 24)));
152
153 WRITE32_REG(DSI_PHY, MIPI_DSI_LP_TIM,
154 (dsi_phy_cfg_.lp_lpx | (dsi_phy_cfg_.lp_ta_sure << 8) |
155 (dsi_phy_cfg_.lp_ta_go << 16) | (dsi_phy_cfg_.lp_ta_get << 24)));
156
157 WRITE32_REG(DSI_PHY, MIPI_DSI_ANA_UP_TIM, ANA_UP_TIME);
158 WRITE32_REG(DSI_PHY, MIPI_DSI_INIT_TIM, dsi_phy_cfg_.init);
159 WRITE32_REG(DSI_PHY, MIPI_DSI_WAKEUP_TIM, dsi_phy_cfg_.wakeup);
160 WRITE32_REG(DSI_PHY, MIPI_DSI_LPOK_TIM, LPOK_TIME);
161 WRITE32_REG(DSI_PHY, MIPI_DSI_ULPS_CHECK, ULPS_CHECK_TIME);
162 WRITE32_REG(DSI_PHY, MIPI_DSI_LP_WCHDOG, LP_WCHDOG_TIME);
163 WRITE32_REG(DSI_PHY, MIPI_DSI_TURN_WCHDOG, TURN_WCHDOG_TIME);
164
165 WRITE32_REG(DSI_PHY, MIPI_DSI_CHAN_CTRL, 0);
166 }
167
168
169 // This function checks two things in order to decide whether the PHY is
170 // ready or not. LOCK Bit and StopStateClk bit. According to spec, once these
171 // are set, PHY has completed initialization
WaitforPhyReady()172 zx_status_t AmlMipiPhy::WaitforPhyReady()
173 {
174 int timeout = DPHY_TIMEOUT;
175 while ((GET_BIT32(MIPI_DSI, DW_DSI_PHY_STATUS, PHY_STATUS_PHY_LOCK, 1) == 0) &&
176 timeout--) {
177 zx_nanosleep(zx_deadline_after(ZX_USEC(kPhyDelay)));
178 }
179 if (timeout <= 0) {
180 DISP_ERROR("Timeout! D-PHY did not lock\n");
181 return ZX_ERR_TIMED_OUT;
182 }
183
184 timeout = DPHY_TIMEOUT;
185 while ((GET_BIT32(MIPI_DSI, DW_DSI_PHY_STATUS, PHY_STATUS_PHY_STOPSTATECLKLANE, 1) == 0) &&
186 timeout--) {
187 zx_nanosleep(zx_deadline_after(ZX_USEC(kPhyDelay)));
188 }
189 if (timeout <= 0) {
190 DISP_ERROR("Timeout! D-PHY StopStateClk not set\n");
191 return ZX_ERR_TIMED_OUT;
192 }
193 return ZX_OK;
194 }
195
Shutdown()196 void AmlMipiPhy::Shutdown() {
197 ZX_DEBUG_ASSERT(initialized_);
198
199 if (!phy_enabled_) {
200 return;
201 }
202
203 // Power down DSI
204 WRITE32_REG(MIPI_DSI, DW_DSI_PWR_UP, PWR_UP_RST);
205 WRITE32_REG(DSI_PHY, MIPI_DSI_CHAN_CTRL, 0x1f);
206 SET_BIT32(DSI_PHY, MIPI_DSI_PHY_CTRL, 0, 7, 1);
207 phy_enabled_ = false;
208 }
209
Startup()210 zx_status_t AmlMipiPhy::Startup() {
211 ZX_DEBUG_ASSERT(initialized_);
212
213 if (phy_enabled_) {
214 return ZX_OK;
215 }
216
217 // Power up DSI
218 WRITE32_REG(MIPI_DSI, DW_DSI_PWR_UP, PWR_UP_ON);
219
220 // Setup Parameters of DPHY
221 // Below we are sending test code 0x44 with parameter 0x74. This means
222 // we are setting up the phy to operate in 1050-1099 Mbps mode
223 // TODO(payamm): Find out why 0x74 was selected
224 WRITE32_REG(MIPI_DSI, DW_DSI_PHY_TST_CTRL1, 0x00010044);
225 WRITE32_REG(MIPI_DSI, DW_DSI_PHY_TST_CTRL0, 0x2);
226 WRITE32_REG(MIPI_DSI, DW_DSI_PHY_TST_CTRL0, 0x0);
227 WRITE32_REG(MIPI_DSI, DW_DSI_PHY_TST_CTRL1, 0x00000074);
228 WRITE32_REG(MIPI_DSI, DW_DSI_PHY_TST_CTRL0, 0x2);
229 WRITE32_REG(MIPI_DSI, DW_DSI_PHY_TST_CTRL0, 0x0);
230
231 // Power up D-PHY
232 WRITE32_REG(MIPI_DSI, DW_DSI_PHY_RSTZ, PHY_RSTZ_PWR_UP);
233
234 // Setup PHY Timing parameters
235 PhyInit();
236
237 // Wait for PHY to be read
238 zx_status_t status;
239 if ((status = WaitforPhyReady()) != ZX_OK) {
240 // no need to print additional info.
241 return status;
242 }
243
244 // Trigger a sync active for esc_clk
245 SET_BIT32(DSI_PHY, MIPI_DSI_PHY_CTRL, 1, 1, 1);
246
247 // Startup transfer, default lpclk
248 WRITE32_REG(MIPI_DSI, DW_DSI_LPCLK_CTRL, (0x1 << LPCLK_CTRL_AUTOCLKLANE_CTRL) |
249 (0x1 << LPCLK_CTRL_TXREQUESTCLKHS));
250
251 phy_enabled_ = true;
252 return ZX_OK;
253 }
254
Init(zx_device_t * parent,uint32_t lane_num)255 zx_status_t AmlMipiPhy::Init(zx_device_t* parent, uint32_t lane_num) {
256 if (initialized_) {
257 return ZX_OK;
258 }
259
260 num_of_lanes_ = lane_num;
261
262 zx_status_t status = device_get_protocol(parent, ZX_PROTOCOL_PDEV, &pdev_);
263 if (status != ZX_OK) {
264 DISP_ERROR("AmlMipiPhy: Could not get ZX_PROTOCOL_PDEV protocol\n");
265 return status;
266 }
267
268 // Map Mipi Dsi and Dsi Phy registers
269 mmio_buffer_t mmio;
270 status = pdev_map_mmio_buffer2(&pdev_, MMIO_MPI_DSI, ZX_CACHE_POLICY_UNCACHED_DEVICE,
271 &mmio);
272 if (status != ZX_OK) {
273 DISP_ERROR("AmlMipiPhy: Could not map MIPI DSI mmio\n");
274 return status;
275 }
276 mipi_dsi_mmio_ = ddk::MmioBuffer(mmio);
277
278 status = pdev_map_mmio_buffer2(&pdev_, MMIO_DSI_PHY, ZX_CACHE_POLICY_UNCACHED_DEVICE,
279 &mmio);
280 if (status != ZX_OK) {
281 DISP_ERROR("AmlMipiPhy: Could not map DSI PHY mmio\n");
282 return status;
283 }
284 dsi_phy_mmio_ = ddk::MmioBuffer(mmio);
285
286 initialized_ = true;
287 return ZX_OK;
288 }
289
Dump()290 void AmlMipiPhy::Dump() {
291 ZX_DEBUG_ASSERT(initialized_);
292 DISP_INFO("%s: DUMPING PHY REGS\n", __func__);
293 DISP_INFO("MIPI_DSI_PHY_CTRL = 0x%x\n", READ32_REG(DSI_PHY, MIPI_DSI_PHY_CTRL));
294 DISP_INFO("MIPI_DSI_CHAN_CTRL = 0x%x\n", READ32_REG(DSI_PHY, MIPI_DSI_CHAN_CTRL));
295 DISP_INFO("MIPI_DSI_CHAN_STS = 0x%x\n", READ32_REG(DSI_PHY, MIPI_DSI_CHAN_STS));
296 DISP_INFO("MIPI_DSI_CLK_TIM = 0x%x\n", READ32_REG(DSI_PHY, MIPI_DSI_CLK_TIM));
297 DISP_INFO("MIPI_DSI_HS_TIM = 0x%x\n", READ32_REG(DSI_PHY, MIPI_DSI_HS_TIM));
298 DISP_INFO("MIPI_DSI_LP_TIM = 0x%x\n", READ32_REG(DSI_PHY, MIPI_DSI_LP_TIM));
299 DISP_INFO("MIPI_DSI_ANA_UP_TIM = 0x%x\n", READ32_REG(DSI_PHY, MIPI_DSI_ANA_UP_TIM));
300 DISP_INFO("MIPI_DSI_INIT_TIM = 0x%x\n", READ32_REG(DSI_PHY, MIPI_DSI_INIT_TIM));
301 DISP_INFO("MIPI_DSI_WAKEUP_TIM = 0x%x\n", READ32_REG(DSI_PHY, MIPI_DSI_WAKEUP_TIM));
302 DISP_INFO("MIPI_DSI_LPOK_TIM = 0x%x\n", READ32_REG(DSI_PHY, MIPI_DSI_LPOK_TIM));
303 DISP_INFO("MIPI_DSI_LP_WCHDOG = 0x%x\n", READ32_REG(DSI_PHY, MIPI_DSI_LP_WCHDOG));
304 DISP_INFO("MIPI_DSI_ANA_CTRL = 0x%x\n", READ32_REG(DSI_PHY, MIPI_DSI_ANA_CTRL));
305 DISP_INFO("MIPI_DSI_CLK_TIM1 = 0x%x\n", READ32_REG(DSI_PHY, MIPI_DSI_CLK_TIM1));
306 DISP_INFO("MIPI_DSI_TURN_WCHDOG = 0x%x\n", READ32_REG(DSI_PHY, MIPI_DSI_TURN_WCHDOG));
307 DISP_INFO("MIPI_DSI_ULPS_CHECK = 0x%x\n", READ32_REG(DSI_PHY, MIPI_DSI_ULPS_CHECK));
308 DISP_INFO("MIPI_DSI_TEST_CTRL0 = 0x%x\n", READ32_REG(DSI_PHY, MIPI_DSI_TEST_CTRL0));
309 DISP_INFO("MIPI_DSI_TEST_CTRL1 = 0x%x\n", READ32_REG(DSI_PHY, MIPI_DSI_TEST_CTRL1));
310 DISP_INFO("\n");
311
312 DISP_INFO("#############################\n");
313 DISP_INFO("Dumping dsi_phy_cfg structure:\n");
314 DISP_INFO("#############################\n");
315 DISP_INFO("lp_tesc = 0x%x (%u)\n", dsi_phy_cfg_.lp_tesc,
316 dsi_phy_cfg_.lp_tesc);
317 DISP_INFO("lp_lpx = 0x%x (%u)\n", dsi_phy_cfg_.lp_lpx,
318 dsi_phy_cfg_.lp_lpx);
319 DISP_INFO("lp_ta_sure = 0x%x (%u)\n", dsi_phy_cfg_.lp_ta_sure,
320 dsi_phy_cfg_.lp_ta_sure);
321 DISP_INFO("lp_ta_go = 0x%x (%u)\n", dsi_phy_cfg_.lp_ta_go,
322 dsi_phy_cfg_.lp_ta_go);
323 DISP_INFO("lp_ta_get = 0x%x (%u)\n", dsi_phy_cfg_.lp_ta_get,
324 dsi_phy_cfg_.lp_ta_get);
325 DISP_INFO("hs_exit = 0x%x (%u)\n", dsi_phy_cfg_.hs_exit,
326 dsi_phy_cfg_.hs_exit);
327 DISP_INFO("hs_trail = 0x%x (%u)\n", dsi_phy_cfg_.hs_trail,
328 dsi_phy_cfg_.hs_trail);
329 DISP_INFO("hs_zero = 0x%x (%u)\n", dsi_phy_cfg_.hs_zero,
330 dsi_phy_cfg_.hs_zero);
331 DISP_INFO("hs_prepare = 0x%x (%u)\n", dsi_phy_cfg_.hs_prepare,
332 dsi_phy_cfg_.hs_prepare);
333 DISP_INFO("clk_trail = 0x%x (%u)\n", dsi_phy_cfg_.clk_trail,
334 dsi_phy_cfg_.clk_trail);
335 DISP_INFO("clk_post = 0x%x (%u)\n", dsi_phy_cfg_.clk_post,
336 dsi_phy_cfg_.clk_post);
337 DISP_INFO("clk_zero = 0x%x (%u)\n", dsi_phy_cfg_.clk_zero,
338 dsi_phy_cfg_.clk_zero);
339 DISP_INFO("clk_prepare = 0x%x (%u)\n", dsi_phy_cfg_.clk_prepare,
340 dsi_phy_cfg_.clk_prepare);
341 DISP_INFO("clk_pre = 0x%x (%u)\n", dsi_phy_cfg_.clk_pre,
342 dsi_phy_cfg_.clk_pre);
343 DISP_INFO("init = 0x%x (%u)\n", dsi_phy_cfg_.init,
344 dsi_phy_cfg_.init);
345 DISP_INFO("wakeup = 0x%x (%u)\n", dsi_phy_cfg_.wakeup,
346 dsi_phy_cfg_.wakeup);
347 }
348
349 } // namespace astro_display
350