1
2
3
4
5
6
7
8
9
10
11
12#include <drm/drm_gem_framebuffer_helper.h>
13#include <drm/tinydrm/mipi-dbi.h>
14#include <drm/tinydrm/tinydrm-helpers.h>
15#include <linux/debugfs.h>
16#include <linux/dma-buf.h>
17#include <linux/gpio/consumer.h>
18#include <linux/module.h>
19#include <linux/regulator/consumer.h>
20#include <linux/spi/spi.h>
21#include <video/mipi_display.h>
22
23#define MIPI_DBI_MAX_SPI_READ_SPEED 2000000
24
25#define DCS_POWER_MODE_DISPLAY BIT(2)
26#define DCS_POWER_MODE_DISPLAY_NORMAL_MODE BIT(3)
27#define DCS_POWER_MODE_SLEEP_MODE BIT(4)
28#define DCS_POWER_MODE_PARTIAL_MODE BIT(5)
29#define DCS_POWER_MODE_IDLE_MODE BIT(6)
30#define DCS_POWER_MODE_RESERVED_MASK (BIT(0) | BIT(1) | BIT(7))
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#define MIPI_DBI_DEBUG_COMMAND(cmd, data, len) \
62({ \
63 if (!len) \
64 DRM_DEBUG_DRIVER("cmd=%02x\n", cmd); \
65 else if (len <= 32) \
66 DRM_DEBUG_DRIVER("cmd=%02x, par=%*ph\n", cmd, (int)len, data);\
67 else \
68 DRM_DEBUG_DRIVER("cmd=%02x, len=%zu\n", cmd, len); \
69})
70
71static const u8 mipi_dbi_dcs_read_commands[] = {
72 MIPI_DCS_GET_DISPLAY_ID,
73 MIPI_DCS_GET_RED_CHANNEL,
74 MIPI_DCS_GET_GREEN_CHANNEL,
75 MIPI_DCS_GET_BLUE_CHANNEL,
76 MIPI_DCS_GET_DISPLAY_STATUS,
77 MIPI_DCS_GET_POWER_MODE,
78 MIPI_DCS_GET_ADDRESS_MODE,
79 MIPI_DCS_GET_PIXEL_FORMAT,
80 MIPI_DCS_GET_DISPLAY_MODE,
81 MIPI_DCS_GET_SIGNAL_MODE,
82 MIPI_DCS_GET_DIAGNOSTIC_RESULT,
83 MIPI_DCS_READ_MEMORY_START,
84 MIPI_DCS_READ_MEMORY_CONTINUE,
85 MIPI_DCS_GET_SCANLINE,
86 MIPI_DCS_GET_DISPLAY_BRIGHTNESS,
87 MIPI_DCS_GET_CONTROL_DISPLAY,
88 MIPI_DCS_GET_POWER_SAVE,
89 MIPI_DCS_GET_CABC_MIN_BRIGHTNESS,
90 MIPI_DCS_READ_DDB_START,
91 MIPI_DCS_READ_DDB_CONTINUE,
92 0,
93};
94
95static bool mipi_dbi_command_is_read(struct mipi_dbi *mipi, u8 cmd)
96{
97 unsigned int i;
98
99 if (!mipi->read_commands)
100 return false;
101
102 for (i = 0; i < 0xff; i++) {
103 if (!mipi->read_commands[i])
104 return false;
105 if (cmd == mipi->read_commands[i])
106 return true;
107 }
108
109 return false;
110}
111
112
113
114
115
116
117
118
119
120
121
122
123int mipi_dbi_command_read(struct mipi_dbi *mipi, u8 cmd, u8 *val)
124{
125 if (!mipi->read_commands)
126 return -EACCES;
127
128 if (!mipi_dbi_command_is_read(mipi, cmd))
129 return -EINVAL;
130
131 return mipi_dbi_command_buf(mipi, cmd, val, 1);
132}
133EXPORT_SYMBOL(mipi_dbi_command_read);
134
135
136
137
138
139
140
141
142
143
144
145int mipi_dbi_command_buf(struct mipi_dbi *mipi, u8 cmd, u8 *data, size_t len)
146{
147 int ret;
148
149 mutex_lock(&mipi->cmdlock);
150 ret = mipi->command(mipi, cmd, data, len);
151 mutex_unlock(&mipi->cmdlock);
152
153 return ret;
154}
155EXPORT_SYMBOL(mipi_dbi_command_buf);
156
157static int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb,
158 struct drm_clip_rect *clip, bool swap)
159{
160 struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
161 struct dma_buf_attachment *import_attach = cma_obj->base.import_attach;
162 struct drm_format_name_buf format_name;
163 void *src = cma_obj->vaddr;
164 int ret = 0;
165
166 if (import_attach) {
167 ret = dma_buf_begin_cpu_access(import_attach->dmabuf,
168 DMA_FROM_DEVICE);
169 if (ret)
170 return ret;
171 }
172
173 switch (fb->format->format) {
174 case DRM_FORMAT_RGB565:
175 if (swap)
176 tinydrm_swab16(dst, src, fb, clip);
177 else
178 tinydrm_memcpy(dst, src, fb, clip);
179 break;
180 case DRM_FORMAT_XRGB8888:
181 tinydrm_xrgb8888_to_rgb565(dst, src, fb, clip, swap);
182 break;
183 default:
184 dev_err_once(fb->dev->dev, "Format is not supported: %s\n",
185 drm_get_format_name(fb->format->format,
186 &format_name));
187 return -EINVAL;
188 }
189
190 if (import_attach)
191 ret = dma_buf_end_cpu_access(import_attach->dmabuf,
192 DMA_FROM_DEVICE);
193 return ret;
194}
195
196static int mipi_dbi_fb_dirty(struct drm_framebuffer *fb,
197 struct drm_file *file_priv,
198 unsigned int flags, unsigned int color,
199 struct drm_clip_rect *clips,
200 unsigned int num_clips)
201{
202 struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
203 struct tinydrm_device *tdev = fb->dev->dev_private;
204 struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
205 bool swap = mipi->swap_bytes;
206 struct drm_clip_rect clip;
207 int ret = 0;
208 bool full;
209 void *tr;
210
211 mutex_lock(&tdev->dirty_lock);
212
213 if (!mipi->enabled)
214 goto out_unlock;
215
216
217 if (tdev->pipe.plane.fb != fb)
218 goto out_unlock;
219
220 full = tinydrm_merge_clips(&clip, clips, num_clips, flags,
221 fb->width, fb->height);
222
223 DRM_DEBUG("Flushing [FB:%d] x1=%u, x2=%u, y1=%u, y2=%u\n", fb->base.id,
224 clip.x1, clip.x2, clip.y1, clip.y2);
225
226 if (!mipi->dc || !full || swap ||
227 fb->format->format == DRM_FORMAT_XRGB8888) {
228 tr = mipi->tx_buf;
229 ret = mipi_dbi_buf_copy(mipi->tx_buf, fb, &clip, swap);
230 if (ret)
231 goto out_unlock;
232 } else {
233 tr = cma_obj->vaddr;
234 }
235
236 mipi_dbi_command(mipi, MIPI_DCS_SET_COLUMN_ADDRESS,
237 (clip.x1 >> 8) & 0xFF, clip.x1 & 0xFF,
238 (clip.x2 >> 8) & 0xFF, (clip.x2 - 1) & 0xFF);
239 mipi_dbi_command(mipi, MIPI_DCS_SET_PAGE_ADDRESS,
240 (clip.y1 >> 8) & 0xFF, clip.y1 & 0xFF,
241 (clip.y2 >> 8) & 0xFF, (clip.y2 - 1) & 0xFF);
242
243 ret = mipi_dbi_command_buf(mipi, MIPI_DCS_WRITE_MEMORY_START, tr,
244 (clip.x2 - clip.x1) * (clip.y2 - clip.y1) * 2);
245
246out_unlock:
247 mutex_unlock(&tdev->dirty_lock);
248
249 if (ret)
250 dev_err_once(fb->dev->dev, "Failed to update display %d\n",
251 ret);
252
253 return ret;
254}
255
256static const struct drm_framebuffer_funcs mipi_dbi_fb_funcs = {
257 .destroy = drm_gem_fb_destroy,
258 .create_handle = drm_gem_fb_create_handle,
259 .dirty = mipi_dbi_fb_dirty,
260};
261
262
263
264
265
266
267
268
269
270void mipi_dbi_pipe_enable(struct drm_simple_display_pipe *pipe,
271 struct drm_crtc_state *crtc_state)
272{
273 struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
274 struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
275 struct drm_framebuffer *fb = pipe->plane.fb;
276
277 DRM_DEBUG_KMS("\n");
278
279 mipi->enabled = true;
280 if (fb)
281 fb->funcs->dirty(fb, NULL, 0, 0, NULL, 0);
282
283 tinydrm_enable_backlight(mipi->backlight);
284}
285EXPORT_SYMBOL(mipi_dbi_pipe_enable);
286
287static void mipi_dbi_blank(struct mipi_dbi *mipi)
288{
289 struct drm_device *drm = mipi->tinydrm.drm;
290 u16 height = drm->mode_config.min_height;
291 u16 width = drm->mode_config.min_width;
292 size_t len = width * height * 2;
293
294 memset(mipi->tx_buf, 0, len);
295
296 mipi_dbi_command(mipi, MIPI_DCS_SET_COLUMN_ADDRESS, 0, 0,
297 (width >> 8) & 0xFF, (width - 1) & 0xFF);
298 mipi_dbi_command(mipi, MIPI_DCS_SET_PAGE_ADDRESS, 0, 0,
299 (height >> 8) & 0xFF, (height - 1) & 0xFF);
300 mipi_dbi_command_buf(mipi, MIPI_DCS_WRITE_MEMORY_START,
301 (u8 *)mipi->tx_buf, len);
302}
303
304
305
306
307
308
309
310
311
312void mipi_dbi_pipe_disable(struct drm_simple_display_pipe *pipe)
313{
314 struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
315 struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
316
317 DRM_DEBUG_KMS("\n");
318
319 mipi->enabled = false;
320
321 if (mipi->backlight)
322 tinydrm_disable_backlight(mipi->backlight);
323 else
324 mipi_dbi_blank(mipi);
325}
326EXPORT_SYMBOL(mipi_dbi_pipe_disable);
327
328static const uint32_t mipi_dbi_formats[] = {
329 DRM_FORMAT_RGB565,
330 DRM_FORMAT_XRGB8888,
331};
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353int mipi_dbi_init(struct device *dev, struct mipi_dbi *mipi,
354 const struct drm_simple_display_pipe_funcs *pipe_funcs,
355 struct drm_driver *driver,
356 const struct drm_display_mode *mode, unsigned int rotation)
357{
358 size_t bufsize = mode->vdisplay * mode->hdisplay * sizeof(u16);
359 struct tinydrm_device *tdev = &mipi->tinydrm;
360 int ret;
361
362 if (!mipi->command)
363 return -EINVAL;
364
365 mutex_init(&mipi->cmdlock);
366
367 mipi->tx_buf = devm_kmalloc(dev, bufsize, GFP_KERNEL);
368 if (!mipi->tx_buf)
369 return -ENOMEM;
370
371 ret = devm_tinydrm_init(dev, tdev, &mipi_dbi_fb_funcs, driver);
372 if (ret)
373 return ret;
374
375
376 ret = tinydrm_display_pipe_init(tdev, pipe_funcs,
377 DRM_MODE_CONNECTOR_VIRTUAL,
378 mipi_dbi_formats,
379 ARRAY_SIZE(mipi_dbi_formats), mode,
380 rotation);
381 if (ret)
382 return ret;
383
384 tdev->drm->mode_config.preferred_depth = 16;
385 mipi->rotation = rotation;
386
387 drm_mode_config_reset(tdev->drm);
388
389 DRM_DEBUG_KMS("preferred_depth=%u, rotation = %u\n",
390 tdev->drm->mode_config.preferred_depth, rotation);
391
392 return 0;
393}
394EXPORT_SYMBOL(mipi_dbi_init);
395
396
397
398
399
400
401
402void mipi_dbi_hw_reset(struct mipi_dbi *mipi)
403{
404 if (!mipi->reset)
405 return;
406
407 gpiod_set_value_cansleep(mipi->reset, 0);
408 msleep(20);
409 gpiod_set_value_cansleep(mipi->reset, 1);
410 msleep(120);
411}
412EXPORT_SYMBOL(mipi_dbi_hw_reset);
413
414
415
416
417
418
419
420
421
422
423
424
425
426bool mipi_dbi_display_is_on(struct mipi_dbi *mipi)
427{
428 u8 val;
429
430 if (mipi_dbi_command_read(mipi, MIPI_DCS_GET_POWER_MODE, &val))
431 return false;
432
433 val &= ~DCS_POWER_MODE_RESERVED_MASK;
434
435 if (val != (DCS_POWER_MODE_DISPLAY |
436 DCS_POWER_MODE_DISPLAY_NORMAL_MODE | DCS_POWER_MODE_SLEEP_MODE))
437 return false;
438
439 DRM_DEBUG_DRIVER("Display is ON\n");
440
441 return true;
442}
443EXPORT_SYMBOL(mipi_dbi_display_is_on);
444
445#if IS_ENABLED(CONFIG_SPI)
446
447
448
449
450
451
452static u32 mipi_dbi_spi_cmd_max_speed(struct spi_device *spi, size_t len)
453{
454 if (len > 64)
455 return 0;
456
457 return min_t(u32, 10000000, spi->max_speed_hz);
458}
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478static int mipi_dbi_spi1e_transfer(struct mipi_dbi *mipi, int dc,
479 const void *buf, size_t len,
480 unsigned int bpw)
481{
482 bool swap_bytes = (bpw == 16 && tinydrm_machine_little_endian());
483 size_t chunk, max_chunk = mipi->tx_buf9_len;
484 struct spi_device *spi = mipi->spi;
485 struct spi_transfer tr = {
486 .tx_buf = mipi->tx_buf9,
487 .bits_per_word = 8,
488 };
489 struct spi_message m;
490 const u8 *src = buf;
491 int i, ret;
492 u8 *dst;
493
494 if (drm_debug & DRM_UT_DRIVER)
495 pr_debug("[drm:%s] dc=%d, max_chunk=%zu, transfers:\n",
496 __func__, dc, max_chunk);
497
498 tr.speed_hz = mipi_dbi_spi_cmd_max_speed(spi, len);
499 spi_message_init_with_transfers(&m, &tr, 1);
500
501 if (!dc) {
502 if (WARN_ON_ONCE(len != 1))
503 return -EINVAL;
504
505
506 dst = mipi->tx_buf9;
507 memset(dst, 0, 9);
508 dst[8] = *src;
509 tr.len = 9;
510
511 tinydrm_dbg_spi_message(spi, &m);
512
513 return spi_sync(spi, &m);
514 }
515
516
517 max_chunk = max_chunk / 9 * 8;
518
519 max_chunk = min(max_chunk, len);
520
521 max_chunk = max_t(size_t, 8, max_chunk & ~0x7);
522
523 while (len) {
524 size_t added = 0;
525
526 chunk = min(len, max_chunk);
527 len -= chunk;
528 dst = mipi->tx_buf9;
529
530 if (chunk < 8) {
531 u8 val, carry = 0;
532
533
534 memset(dst, 0, 9);
535
536 if (swap_bytes) {
537 for (i = 1; i < (chunk + 1); i++) {
538 val = src[1];
539 *dst++ = carry | BIT(8 - i) | (val >> i);
540 carry = val << (8 - i);
541 i++;
542 val = src[0];
543 *dst++ = carry | BIT(8 - i) | (val >> i);
544 carry = val << (8 - i);
545 src += 2;
546 }
547 *dst++ = carry;
548 } else {
549 for (i = 1; i < (chunk + 1); i++) {
550 val = *src++;
551 *dst++ = carry | BIT(8 - i) | (val >> i);
552 carry = val << (8 - i);
553 }
554 *dst++ = carry;
555 }
556
557 chunk = 8;
558 added = 1;
559 } else {
560 for (i = 0; i < chunk; i += 8) {
561 if (swap_bytes) {
562 *dst++ = BIT(7) | (src[1] >> 1);
563 *dst++ = (src[1] << 7) | BIT(6) | (src[0] >> 2);
564 *dst++ = (src[0] << 6) | BIT(5) | (src[3] >> 3);
565 *dst++ = (src[3] << 5) | BIT(4) | (src[2] >> 4);
566 *dst++ = (src[2] << 4) | BIT(3) | (src[5] >> 5);
567 *dst++ = (src[5] << 3) | BIT(2) | (src[4] >> 6);
568 *dst++ = (src[4] << 2) | BIT(1) | (src[7] >> 7);
569 *dst++ = (src[7] << 1) | BIT(0);
570 *dst++ = src[6];
571 } else {
572 *dst++ = BIT(7) | (src[0] >> 1);
573 *dst++ = (src[0] << 7) | BIT(6) | (src[1] >> 2);
574 *dst++ = (src[1] << 6) | BIT(5) | (src[2] >> 3);
575 *dst++ = (src[2] << 5) | BIT(4) | (src[3] >> 4);
576 *dst++ = (src[3] << 4) | BIT(3) | (src[4] >> 5);
577 *dst++ = (src[4] << 3) | BIT(2) | (src[5] >> 6);
578 *dst++ = (src[5] << 2) | BIT(1) | (src[6] >> 7);
579 *dst++ = (src[6] << 1) | BIT(0);
580 *dst++ = src[7];
581 }
582
583 src += 8;
584 added++;
585 }
586 }
587
588 tr.len = chunk + added;
589
590 tinydrm_dbg_spi_message(spi, &m);
591 ret = spi_sync(spi, &m);
592 if (ret)
593 return ret;
594 }
595
596 return 0;
597}
598
599static int mipi_dbi_spi1_transfer(struct mipi_dbi *mipi, int dc,
600 const void *buf, size_t len,
601 unsigned int bpw)
602{
603 struct spi_device *spi = mipi->spi;
604 struct spi_transfer tr = {
605 .bits_per_word = 9,
606 };
607 const u16 *src16 = buf;
608 const u8 *src8 = buf;
609 struct spi_message m;
610 size_t max_chunk;
611 u16 *dst16;
612 int ret;
613
614 if (!tinydrm_spi_bpw_supported(spi, 9))
615 return mipi_dbi_spi1e_transfer(mipi, dc, buf, len, bpw);
616
617 tr.speed_hz = mipi_dbi_spi_cmd_max_speed(spi, len);
618 max_chunk = mipi->tx_buf9_len;
619 dst16 = mipi->tx_buf9;
620
621 if (drm_debug & DRM_UT_DRIVER)
622 pr_debug("[drm:%s] dc=%d, max_chunk=%zu, transfers:\n",
623 __func__, dc, max_chunk);
624
625 max_chunk = min(max_chunk / 2, len);
626
627 spi_message_init_with_transfers(&m, &tr, 1);
628 tr.tx_buf = dst16;
629
630 while (len) {
631 size_t chunk = min(len, max_chunk);
632 unsigned int i;
633
634 if (bpw == 16 && tinydrm_machine_little_endian()) {
635 for (i = 0; i < (chunk * 2); i += 2) {
636 dst16[i] = *src16 >> 8;
637 dst16[i + 1] = *src16++ & 0xFF;
638 if (dc) {
639 dst16[i] |= 0x0100;
640 dst16[i + 1] |= 0x0100;
641 }
642 }
643 } else {
644 for (i = 0; i < chunk; i++) {
645 dst16[i] = *src8++;
646 if (dc)
647 dst16[i] |= 0x0100;
648 }
649 }
650
651 tr.len = chunk;
652 len -= chunk;
653
654 tinydrm_dbg_spi_message(spi, &m);
655 ret = spi_sync(spi, &m);
656 if (ret)
657 return ret;
658 }
659
660 return 0;
661}
662
663static int mipi_dbi_typec1_command(struct mipi_dbi *mipi, u8 cmd,
664 u8 *parameters, size_t num)
665{
666 unsigned int bpw = (cmd == MIPI_DCS_WRITE_MEMORY_START) ? 16 : 8;
667 int ret;
668
669 if (mipi_dbi_command_is_read(mipi, cmd))
670 return -ENOTSUPP;
671
672 MIPI_DBI_DEBUG_COMMAND(cmd, parameters, num);
673
674 ret = mipi_dbi_spi1_transfer(mipi, 0, &cmd, 1, 8);
675 if (ret || !num)
676 return ret;
677
678 return mipi_dbi_spi1_transfer(mipi, 1, parameters, num, bpw);
679}
680
681
682
683static int mipi_dbi_typec3_command_read(struct mipi_dbi *mipi, u8 cmd,
684 u8 *data, size_t len)
685{
686 struct spi_device *spi = mipi->spi;
687 u32 speed_hz = min_t(u32, MIPI_DBI_MAX_SPI_READ_SPEED,
688 spi->max_speed_hz / 2);
689 struct spi_transfer tr[2] = {
690 {
691 .speed_hz = speed_hz,
692 .tx_buf = &cmd,
693 .len = 1,
694 }, {
695 .speed_hz = speed_hz,
696 .len = len,
697 },
698 };
699 struct spi_message m;
700 u8 *buf;
701 int ret;
702
703 if (!len)
704 return -EINVAL;
705
706
707
708
709
710 if (cmd == MIPI_DCS_GET_DISPLAY_ID ||
711 cmd == MIPI_DCS_GET_DISPLAY_STATUS) {
712 if (!(len == 3 || len == 4))
713 return -EINVAL;
714
715 tr[1].len = len + 1;
716 }
717
718 buf = kmalloc(tr[1].len, GFP_KERNEL);
719 if (!buf)
720 return -ENOMEM;
721
722 tr[1].rx_buf = buf;
723 gpiod_set_value_cansleep(mipi->dc, 0);
724
725 spi_message_init_with_transfers(&m, tr, ARRAY_SIZE(tr));
726 ret = spi_sync(spi, &m);
727 if (ret)
728 goto err_free;
729
730 tinydrm_dbg_spi_message(spi, &m);
731
732 if (tr[1].len == len) {
733 memcpy(data, buf, len);
734 } else {
735 unsigned int i;
736
737 for (i = 0; i < len; i++)
738 data[i] = (buf[i] << 1) | !!(buf[i + 1] & BIT(7));
739 }
740
741 MIPI_DBI_DEBUG_COMMAND(cmd, data, len);
742
743err_free:
744 kfree(buf);
745
746 return ret;
747}
748
749static int mipi_dbi_typec3_command(struct mipi_dbi *mipi, u8 cmd,
750 u8 *par, size_t num)
751{
752 struct spi_device *spi = mipi->spi;
753 unsigned int bpw = 8;
754 u32 speed_hz;
755 int ret;
756
757 if (mipi_dbi_command_is_read(mipi, cmd))
758 return mipi_dbi_typec3_command_read(mipi, cmd, par, num);
759
760 MIPI_DBI_DEBUG_COMMAND(cmd, par, num);
761
762 gpiod_set_value_cansleep(mipi->dc, 0);
763 speed_hz = mipi_dbi_spi_cmd_max_speed(spi, 1);
764 ret = tinydrm_spi_transfer(spi, speed_hz, NULL, 8, &cmd, 1);
765 if (ret || !num)
766 return ret;
767
768 if (cmd == MIPI_DCS_WRITE_MEMORY_START && !mipi->swap_bytes)
769 bpw = 16;
770
771 gpiod_set_value_cansleep(mipi->dc, 1);
772 speed_hz = mipi_dbi_spi_cmd_max_speed(spi, num);
773
774 return tinydrm_spi_transfer(spi, speed_hz, NULL, bpw, par, num);
775}
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799int mipi_dbi_spi_init(struct spi_device *spi, struct mipi_dbi *mipi,
800 struct gpio_desc *dc)
801{
802 size_t tx_size = tinydrm_spi_max_transfer_size(spi, 0);
803 struct device *dev = &spi->dev;
804 int ret;
805
806 if (tx_size < 16) {
807 DRM_ERROR("SPI transmit buffer too small: %zu\n", tx_size);
808 return -EINVAL;
809 }
810
811
812
813
814
815
816
817
818
819
820
821 if (!dev->coherent_dma_mask) {
822 ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
823 if (ret) {
824 dev_warn(dev, "Failed to set dma mask %d\n", ret);
825 return ret;
826 }
827 }
828
829 mipi->spi = spi;
830 mipi->read_commands = mipi_dbi_dcs_read_commands;
831
832 if (dc) {
833 mipi->command = mipi_dbi_typec3_command;
834 mipi->dc = dc;
835 if (tinydrm_machine_little_endian() &&
836 !tinydrm_spi_bpw_supported(spi, 16))
837 mipi->swap_bytes = true;
838 } else {
839 mipi->command = mipi_dbi_typec1_command;
840 mipi->tx_buf9_len = tx_size;
841 mipi->tx_buf9 = devm_kmalloc(dev, tx_size, GFP_KERNEL);
842 if (!mipi->tx_buf9)
843 return -ENOMEM;
844 }
845
846 DRM_DEBUG_DRIVER("SPI speed: %uMHz\n", spi->max_speed_hz / 1000000);
847
848 return 0;
849}
850EXPORT_SYMBOL(mipi_dbi_spi_init);
851
852#endif
853
854#ifdef CONFIG_DEBUG_FS
855
856static ssize_t mipi_dbi_debugfs_command_write(struct file *file,
857 const char __user *ubuf,
858 size_t count, loff_t *ppos)
859{
860 struct seq_file *m = file->private_data;
861 struct mipi_dbi *mipi = m->private;
862 u8 val, cmd = 0, parameters[64];
863 char *buf, *pos, *token;
864 unsigned int i;
865 int ret;
866
867 buf = memdup_user_nul(ubuf, count);
868 if (IS_ERR(buf))
869 return PTR_ERR(buf);
870
871
872 for (i = count - 1; i > 0; i--)
873 if (isspace(buf[i]))
874 buf[i] = '\0';
875 else
876 break;
877 i = 0;
878 pos = buf;
879 while (pos) {
880 token = strsep(&pos, " ");
881 if (!token) {
882 ret = -EINVAL;
883 goto err_free;
884 }
885
886 ret = kstrtou8(token, 16, &val);
887 if (ret < 0)
888 goto err_free;
889
890 if (token == buf)
891 cmd = val;
892 else
893 parameters[i++] = val;
894
895 if (i == 64) {
896 ret = -E2BIG;
897 goto err_free;
898 }
899 }
900
901 ret = mipi_dbi_command_buf(mipi, cmd, parameters, i);
902
903err_free:
904 kfree(buf);
905
906 return ret < 0 ? ret : count;
907}
908
909static int mipi_dbi_debugfs_command_show(struct seq_file *m, void *unused)
910{
911 struct mipi_dbi *mipi = m->private;
912 u8 cmd, val[4];
913 size_t len;
914 int ret;
915
916 for (cmd = 0; cmd < 255; cmd++) {
917 if (!mipi_dbi_command_is_read(mipi, cmd))
918 continue;
919
920 switch (cmd) {
921 case MIPI_DCS_READ_MEMORY_START:
922 case MIPI_DCS_READ_MEMORY_CONTINUE:
923 len = 2;
924 break;
925 case MIPI_DCS_GET_DISPLAY_ID:
926 len = 3;
927 break;
928 case MIPI_DCS_GET_DISPLAY_STATUS:
929 len = 4;
930 break;
931 default:
932 len = 1;
933 break;
934 }
935
936 seq_printf(m, "%02x: ", cmd);
937 ret = mipi_dbi_command_buf(mipi, cmd, val, len);
938 if (ret) {
939 seq_puts(m, "XX\n");
940 continue;
941 }
942 seq_printf(m, "%*phN\n", (int)len, val);
943 }
944
945 return 0;
946}
947
948static int mipi_dbi_debugfs_command_open(struct inode *inode,
949 struct file *file)
950{
951 return single_open(file, mipi_dbi_debugfs_command_show,
952 inode->i_private);
953}
954
955static const struct file_operations mipi_dbi_debugfs_command_fops = {
956 .owner = THIS_MODULE,
957 .open = mipi_dbi_debugfs_command_open,
958 .read = seq_read,
959 .llseek = seq_lseek,
960 .release = single_release,
961 .write = mipi_dbi_debugfs_command_write,
962};
963
964static const struct drm_info_list mipi_dbi_debugfs_list[] = {
965 { "fb", drm_fb_cma_debugfs_show, 0 },
966};
967
968
969
970
971
972
973
974
975
976
977
978
979int mipi_dbi_debugfs_init(struct drm_minor *minor)
980{
981 struct tinydrm_device *tdev = minor->dev->dev_private;
982 struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
983 umode_t mode = S_IFREG | S_IWUSR;
984
985 if (mipi->read_commands)
986 mode |= S_IRUGO;
987 debugfs_create_file("command", mode, minor->debugfs_root, mipi,
988 &mipi_dbi_debugfs_command_fops);
989
990 return drm_debugfs_create_files(mipi_dbi_debugfs_list,
991 ARRAY_SIZE(mipi_dbi_debugfs_list),
992 minor->debugfs_root, minor);
993}
994EXPORT_SYMBOL(mipi_dbi_debugfs_init);
995
996#endif
997
998MODULE_LICENSE("GPL");
999