1 /*
2 * Copyright (c) 2023 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7 #include "hpm_panel.h"
8 #include "hpm_pixelmux_drv.h"
9 #include "hpm_mipi_dsi_drv.h"
10 #include "hpm_mipi_dsi_phy_drv.h"
11 #include <stdio.h>
12
13 typedef struct mipi_cmd_list {
14 uint16_t len;
15 uint8_t cmd[4];
16 } mipi_cmd_list_t;
17
18 const static mipi_cmd_list_t mipi_panel_cmd[] = {
19 {4, {0xFF, 0x98, 0x81, 0x03}},
20 {2, {0x01, 0x00}},
21 {2, {0x02, 0x00}},
22 {2, {0x03, 0x55}},
23 {2, {0x04, 0x55}},
24 {2, {0x05, 0x03}},
25 {2, {0x06, 0x06}},
26 {2, {0x07, 0x00}},
27 {2, {0x08, 0x07}},
28 {2, {0x09, 0x00}},
29 {2, {0x0A, 0x00}},
30 {2, {0x0B, 0x00}},
31 {2, {0x0C, 0x00}},
32 {2, {0x0D, 0x00}},
33 {2, {0x0E, 0x00}},
34 {2, {0x0F, 0x00}},
35 {2, {0x10, 0x00}},
36 {2, {0x11, 0x00}},
37 {2, {0x12, 0x00}},
38 {2, {0x13, 0x00}},
39 {2, {0x14, 0x00}},
40 {2, {0x15, 0x00}},
41 {2, {0x16, 0x00}},
42 {2, {0x17, 0x00}},
43 {2, {0x18, 0x00}},
44 {2, {0x19, 0x00}},
45 {2, {0x1A, 0x00}},
46 {2, {0x1B, 0x00}},
47 {2, {0x1C, 0x00}},
48 {2, {0x1D, 0x00}},
49 {2, {0x1E, 0xC0}},
50 {2, {0x1F, 0x80}},
51 {2, {0x20, 0x04}},
52 {2, {0x21, 0x03}},
53 {2, {0x22, 0x00}},
54 {2, {0x23, 0x00}},
55 {2, {0x24, 0x00}},
56 {2, {0x25, 0x00}},
57 {2, {0x26, 0x00}},
58 {2, {0x27, 0x00}},
59 {2, {0x28, 0x33}},
60 {2, {0x29, 0x33}},
61 {2, {0x2A, 0x00}},
62 {2, {0x2B, 0x00}},
63 {2, {0x2C, 0x00}},
64 {2, {0x2D, 0x00}},
65 {2, {0x2E, 0x00}},
66 {2, {0x2F, 0x00}},
67 {2, {0x30, 0x00}},
68 {2, {0x31, 0x00}},
69 {2, {0x32, 0x00}},
70 {2, {0x33, 0x00}},
71 {2, {0x34, 0x04}},
72 {2, {0x35, 0x00}},
73 {2, {0x36, 0x00}},
74 {2, {0x37, 0x00}},
75 {2, {0x38, 0x3C}},
76 {2, {0x39, 0x00}},
77 {2, {0x3A, 0x00}},
78 {2, {0x3B, 0x00}},
79 {2, {0x3C, 0x00}},
80 {2, {0x3D, 0x00}},
81 {2, {0x3E, 0x00}},
82 {2, {0x3F, 0x00}},
83 {2, {0x40, 0x00}},
84 {2, {0x41, 0x00}},
85 {2, {0x42, 0x00}},
86 {2, {0x43, 0x00}},
87 {2, {0x44, 0x00}},
88 {2, {0x50, 0x00}},
89 {2, {0x51, 0x11}},
90 {2, {0x52, 0x44}},
91 {2, {0x53, 0x55}},
92 {2, {0x54, 0x88}},
93 {2, {0x55, 0xAB}},
94 {2, {0x56, 0x00}},
95 {2, {0x57, 0x11}},
96 {2, {0x58, 0x22}},
97 {2, {0x59, 0x33}},
98 {2, {0x5A, 0x44}},
99 {2, {0x5B, 0x55}},
100 {2, {0x5C, 0x66}},
101 {2, {0x5D, 0x77}},
102 {2, {0x5E, 0x00}},
103 {2, {0x5F, 0x02}},
104 {2, {0x60, 0x02}},
105 {2, {0x61, 0x0A}},
106 {2, {0x62, 0x09}},
107 {2, {0x63, 0x08}},
108 {2, {0x64, 0x13}},
109 {2, {0x65, 0x12}},
110 {2, {0x66, 0x11}},
111 {2, {0x67, 0x10}},
112 {2, {0x68, 0x0F}},
113 {2, {0x69, 0x0E}},
114 {2, {0x6A, 0x0D}},
115 {2, {0x6B, 0x0C}},
116 {2, {0x6C, 0x06}},
117 {2, {0x6D, 0x07}},
118 {2, {0x6E, 0x02}},
119 {2, {0x6F, 0x02}},
120 {2, {0x70, 0x02}},
121 {2, {0x71, 0x02}},
122 {2, {0x72, 0x02}},
123 {2, {0x73, 0x02}},
124 {2, {0x74, 0x02}},
125 {2, {0x75, 0x02}},
126 {2, {0x76, 0x02}},
127 {2, {0x77, 0x0A}},
128 {2, {0x78, 0x06}},
129 {2, {0x79, 0x07}},
130 {2, {0x7A, 0x10}},
131 {2, {0x7B, 0x11}},
132 {2, {0x7C, 0x12}},
133 {2, {0x7D, 0x13}},
134 {2, {0x7E, 0x0C}},
135 {2, {0x7F, 0x0D}},
136 {2, {0x80, 0x0E}},
137 {2, {0x81, 0x0F}},
138 {2, {0x82, 0x09}},
139 {2, {0x83, 0x08}},
140 {2, {0x84, 0x02}},
141 {2, {0x85, 0x02}},
142 {2, {0x86, 0x02}},
143 {2, {0x87, 0x02}},
144 {2, {0x88, 0x02}},
145 {2, {0x89, 0x02}},
146 {2, {0x8A, 0x02}},
147 {4, {0xFF, 0x98, 0x81, 0x04}},
148 {2, {0x6E, 0x2A}},
149 {2, {0x6F, 0x37}},
150 {2, {0x3A, 0x24}},
151 {2, {0x8D, 0x19}},
152 {2, {0x87, 0xBA}},
153 {2, {0xB2, 0xD1}},
154 {2, {0x88, 0x0B}},
155 {2, {0x38, 0x01}},
156 {2, {0x39, 0x00}},
157 {2, {0xB5, 0x02}},
158 {2, {0x31, 0x25}},
159 {2, {0x3B, 0x98}},
160 {4, {0xFF, 0x98, 0x81, 0x01}},
161 {2, {0x22, 0x0A}},
162 {2, {0x31, 0x0C}},
163 {2, {0x53, 0x40}},
164 {2, {0x55, 0x45}},
165 {2, {0x50, 0xB7}},
166 {2, {0x51, 0xB2}},
167 {2, {0x60, 0x07}},
168 {2, {0xA0, 0x22}},
169 {2, {0xA1, 0x3F}},
170 {2, {0xA2, 0x4E}},
171 {2, {0xA3, 0x17}},
172 {2, {0xA4, 0x1A}},
173 {2, {0xA5, 0x2D}},
174 {2, {0xA6, 0x21}},
175 {2, {0xA7, 0x22}},
176 {2, {0xA8, 0xC4}},
177 {2, {0xA9, 0x1B}},
178 {2, {0xAA, 0x25}},
179 {2, {0xAB, 0xA7}},
180 {2, {0xAC, 0x1A}},
181 {2, {0xAD, 0x19}},
182 {2, {0xAE, 0x4B}},
183 {2, {0xAF, 0x1F}},
184 {2, {0xB0, 0x2A}},
185 {2, {0xB1, 0x59}},
186 {2, {0xB2, 0x64}},
187 {2, {0xB3, 0x3F}},
188 {2, {0xC0, 0x22}},
189 {2, {0xC1, 0x48}},
190 {2, {0xC2, 0x59}},
191 {2, {0xC3, 0x15}},
192 {2, {0xC4, 0x15}},
193 {2, {0xC5, 0x28}},
194 {2, {0xC6, 0x1C}},
195 {2, {0xC7, 0x1E}},
196 {2, {0xC8, 0xC4}},
197 {2, {0xC9, 0x1C}},
198 {2, {0xCA, 0x2B}},
199 {2, {0xCB, 0xA3}},
200 {2, {0xCC, 0x1F}},
201 {2, {0xCD, 0x1E}},
202 {2, {0xCE, 0x52}},
203 {2, {0xCF, 0x24}},
204 {2, {0xD0, 0x2A}},
205 {2, {0xD1, 0x58}},
206 {2, {0xD2, 0x68}},
207 {2, {0xD3, 0x3F}},
208 {4, {0xFF, 0x98, 0x81, 0x00}},
209 {1, {0x11}},
210 {1, {0x29}},
211 };
212
mipi_panel_init_cmd_send(hpm_panel_t * panel)213 static void mipi_panel_init_cmd_send(hpm_panel_t *panel)
214 {
215 int ret;
216 uint8_t page_cmd[4] = {0xFF, 0x98, 0x81, 0x01};
217 uint8_t panel_id[2] = {0x98, 0x81};
218 uint8_t rdata;
219 MIPI_DSI_Type *mipi_host = panel->hw_if.video.mipi.mipi_host_base;
220
221 mipi_dsi_dcs_write_buffer(mipi_host, 0, page_cmd, 4);
222
223 for (int i = 0; i < 2; i++) {
224 mipi_dsi_set_maximum_return_packet_size(mipi_host, 0, 1);
225 ret = mipi_dsi_dcs_read(mipi_host, 0, i, &rdata, 1);
226 if (ret <= 0 || rdata != panel_id[i]) {
227 printf("read id[%d]: 0x%02X -- failed\n", i, rdata);
228 while (1) {
229 }
230 } else {
231 printf("read id[%d]: 0x%02X -- ok\n", i, rdata);
232 }
233 hpm_panel_delay_ms(10);
234 }
235
236 int mipi_cmd_num = sizeof(mipi_panel_cmd) / sizeof(mipi_panel_cmd[0]);
237 for (int i = 0; i < mipi_cmd_num; i++) {
238 ret = mipi_dsi_dcs_write_buffer(mipi_host, 0, mipi_panel_cmd[i].cmd, mipi_panel_cmd[i].len);
239 if (ret <= 0)
240 printf("mipi_cmd[%d].cmd: 0x%02X -- failed\n", i, mipi_panel_cmd[i].cmd[0]);
241 }
242
243 hpm_panel_delay_ms(10);
244 }
245
mipi_panel_host_init(hpm_panel_t * panel)246 static void mipi_panel_host_init(hpm_panel_t *panel)
247 {
248 MIPI_DSI_Type *mipi_host = panel->hw_if.video.mipi.mipi_host_base;
249 const hpm_panel_timing_t *timing = &panel->timing;
250 mipi_dsi_config_t mipi_cfg;
251 mipi_dsi_get_defconfig_on_video(&mipi_cfg);
252
253 mipi_cfg.channel = 0;
254 mipi_cfg.lanes = 4;
255 mipi_cfg.video_para.pixel_clock_khz = panel->hw_if.lcdc_pixel_clk_khz;
256 mipi_cfg.video_para.hactive = timing->hactive;
257 mipi_cfg.video_para.hsync_len = timing->hsync_len;
258 mipi_cfg.video_para.hback_porch = timing->hback_porch;
259 mipi_cfg.video_para.hfront_porch = timing->hfront_porch;
260 mipi_cfg.video_para.vsync_len = timing->vsync_len;
261 mipi_cfg.video_para.vactive = timing->vactive;
262 mipi_cfg.video_para.vback_porch = timing->vback_porch;
263 mipi_cfg.video_para.vfront_porch = timing->vfront_porch;
264
265 mipi_dsi_init(mipi_host, &mipi_cfg);
266 }
267
mipi_panel_phy_init(hpm_panel_t * panel)268 static void mipi_panel_phy_init(hpm_panel_t *panel)
269 {
270 MIPI_DSI_Type *mipi_host = panel->hw_if.video.mipi.mipi_host_base;
271 MIPI_DSI_PHY_Type *mipi_phy = panel->hw_if.video.mipi.mipi_phy_base;
272
273 mipi_dsi_phy_config_t mipi_phy_cfg = {
274 .lanes = 4,
275 .lane_mbps = 500
276 };
277 mipi_dsi_phy_powerdown(mipi_host);
278 mipi_dsi_phy_init(mipi_phy, &mipi_phy_cfg);
279 mipi_dsi_phy_poweron(mipi_host);
280 }
281
reset(hpm_panel_t * panel)282 static void reset(hpm_panel_t *panel)
283 {
284 if (!panel->hw_if.set_reset_pin_level)
285 return;
286
287 panel->hw_if.set_reset_pin_level(0);
288 hpm_panel_delay_ms(20);
289
290 panel->hw_if.set_reset_pin_level(1);
291 hpm_panel_delay_ms(15);
292 }
293
init(hpm_panel_t * panel)294 static void init(hpm_panel_t *panel)
295 {
296 if (panel->hw_if.set_video_router)
297 panel->hw_if.set_video_router();
298
299 mipi_panel_host_init(panel);
300 mipi_panel_phy_init(panel);
301 mipi_panel_init_cmd_send(panel);
302 }
303
power_on(hpm_panel_t * panel)304 static void power_on(hpm_panel_t *panel)
305 {
306 MIPI_DSI_Type *mipi_host = panel->hw_if.video.mipi.mipi_host_base;
307
308 if (panel->state.power_state != HPM_PANEL_STATE_POWER_ON) {
309 mipi_dsi_video_mode_hs_transfer_enable(mipi_host);
310
311 if (panel->hw_if.set_backlight) {
312 if (panel->state.backlight_percent == 0)
313 panel->state.backlight_percent = 100;
314 panel->hw_if.set_backlight(panel->state.backlight_percent);
315 }
316 panel->state.power_state = HPM_PANEL_STATE_POWER_ON;
317 }
318 }
319
power_off(hpm_panel_t * panel)320 static void power_off(hpm_panel_t *panel)
321 {
322 MIPI_DSI_Type *mipi_host = panel->hw_if.video.mipi.mipi_host_base;
323
324 if (panel->state.power_state != HPM_PANEL_STATE_POWER_OFF) {
325 if (panel->hw_if.set_backlight)
326 panel->hw_if.set_backlight(0);
327 mipi_dsi_video_mode_hs_transfer_disable(mipi_host);
328 panel->state.power_state = HPM_PANEL_STATE_POWER_OFF;
329 }
330 }
331
332 hpm_panel_t panel_mc10128007_31b = {
333 .name = "mc10128007_31b",
334 .if_type = HPM_PANEL_IF_TYPE_MIPI,
335 .timing = {
336 .pixel_clock_khz = 60000,
337 .hactive = 800,
338 .hfront_porch = 52,
339 .hback_porch = 48,
340 .hsync_len = 8,
341
342 .vactive = 1280,
343 .vfront_porch = 15,
344 .vback_porch = 16,
345 .vsync_len = 6,
346 },
347 .funcs = {
348 .reset = reset,
349 .init = init,
350 .power_on = power_on,
351 .power_off = power_off,
352 },
353 };
354
355