Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
02dd95fe NT |
2 | /* |
3 | * MIPI Display Bus Interface (DBI) LCD controller support | |
4 | * | |
5 | * Copyright 2016 Noralf Trønnes | |
02dd95fe NT |
6 | */ |
7 | ||
02dd95fe | 8 | #include <linux/debugfs.h> |
84056e9b | 9 | #include <linux/delay.h> |
02dd95fe NT |
10 | #include <linux/dma-buf.h> |
11 | #include <linux/gpio/consumer.h> | |
12 | #include <linux/module.h> | |
13 | #include <linux/regulator/consumer.h> | |
14 | #include <linux/spi/spi.h> | |
3db8d37d | 15 | |
710ae47d | 16 | #include <drm/drm_connector.h> |
af741381 | 17 | #include <drm/drm_damage_helper.h> |
84056e9b | 18 | #include <drm/drm_drv.h> |
3db8d37d | 19 | #include <drm/drm_gem_cma_helper.h> |
7415287e | 20 | #include <drm/drm_format_helper.h> |
84056e9b | 21 | #include <drm/drm_fourcc.h> |
3db8d37d | 22 | #include <drm/drm_gem_framebuffer_helper.h> |
174102f4 | 23 | #include <drm/drm_mipi_dbi.h> |
710ae47d NT |
24 | #include <drm/drm_modes.h> |
25 | #include <drm/drm_probe_helper.h> | |
b051b345 | 26 | #include <drm/drm_rect.h> |
710ae47d | 27 | #include <drm/drm_vblank.h> |
02dd95fe NT |
28 | #include <video/mipi_display.h> |
29 | ||
30 | #define MIPI_DBI_MAX_SPI_READ_SPEED 2000000 /* 2MHz */ | |
31 | ||
32 | #define DCS_POWER_MODE_DISPLAY BIT(2) | |
33 | #define DCS_POWER_MODE_DISPLAY_NORMAL_MODE BIT(3) | |
34 | #define DCS_POWER_MODE_SLEEP_MODE BIT(4) | |
35 | #define DCS_POWER_MODE_PARTIAL_MODE BIT(5) | |
36 | #define DCS_POWER_MODE_IDLE_MODE BIT(6) | |
37 | #define DCS_POWER_MODE_RESERVED_MASK (BIT(0) | BIT(1) | BIT(7)) | |
38 | ||
39 | /** | |
40 | * DOC: overview | |
41 | * | |
42 | * This library provides helpers for MIPI Display Bus Interface (DBI) | |
43 | * compatible display controllers. | |
44 | * | |
45 | * Many controllers for tiny lcd displays are MIPI compliant and can use this | |
46 | * library. If a controller uses registers 0x2A and 0x2B to set the area to | |
47 | * update and uses register 0x2C to write to frame memory, it is most likely | |
48 | * MIPI compliant. | |
49 | * | |
50 | * Only MIPI Type 1 displays are supported since a full frame memory is needed. | |
51 | * | |
52 | * There are 3 MIPI DBI implementation types: | |
53 | * | |
54 | * A. Motorola 6800 type parallel bus | |
55 | * | |
56 | * B. Intel 8080 type parallel bus | |
57 | * | |
58 | * C. SPI type with 3 options: | |
59 | * | |
60 | * 1. 9-bit with the Data/Command signal as the ninth bit | |
61 | * 2. Same as above except it's sent as 16 bits | |
62 | * 3. 8-bit with the Data/Command signal as a separate D/CX pin | |
63 | * | |
64 | * Currently mipi_dbi only supports Type C options 1 and 3 with | |
65 | * mipi_dbi_spi_init(). | |
66 | */ | |
67 | ||
68 | #define MIPI_DBI_DEBUG_COMMAND(cmd, data, len) \ | |
69 | ({ \ | |
70 | if (!len) \ | |
71 | DRM_DEBUG_DRIVER("cmd=%02x\n", cmd); \ | |
72 | else if (len <= 32) \ | |
ce8c0137 | 73 | DRM_DEBUG_DRIVER("cmd=%02x, par=%*ph\n", cmd, (int)len, data);\ |
02dd95fe | 74 | else \ |
ef96152e | 75 | DRM_DEBUG_DRIVER("cmd=%02x, len=%zu\n", cmd, len); \ |
02dd95fe NT |
76 | }) |
77 | ||
78 | static const u8 mipi_dbi_dcs_read_commands[] = { | |
79 | MIPI_DCS_GET_DISPLAY_ID, | |
80 | MIPI_DCS_GET_RED_CHANNEL, | |
81 | MIPI_DCS_GET_GREEN_CHANNEL, | |
82 | MIPI_DCS_GET_BLUE_CHANNEL, | |
83 | MIPI_DCS_GET_DISPLAY_STATUS, | |
84 | MIPI_DCS_GET_POWER_MODE, | |
85 | MIPI_DCS_GET_ADDRESS_MODE, | |
86 | MIPI_DCS_GET_PIXEL_FORMAT, | |
87 | MIPI_DCS_GET_DISPLAY_MODE, | |
88 | MIPI_DCS_GET_SIGNAL_MODE, | |
89 | MIPI_DCS_GET_DIAGNOSTIC_RESULT, | |
90 | MIPI_DCS_READ_MEMORY_START, | |
91 | MIPI_DCS_READ_MEMORY_CONTINUE, | |
92 | MIPI_DCS_GET_SCANLINE, | |
93 | MIPI_DCS_GET_DISPLAY_BRIGHTNESS, | |
94 | MIPI_DCS_GET_CONTROL_DISPLAY, | |
95 | MIPI_DCS_GET_POWER_SAVE, | |
96 | MIPI_DCS_GET_CABC_MIN_BRIGHTNESS, | |
97 | MIPI_DCS_READ_DDB_START, | |
98 | MIPI_DCS_READ_DDB_CONTINUE, | |
99 | 0, /* sentinel */ | |
100 | }; | |
101 | ||
36b50572 | 102 | static bool mipi_dbi_command_is_read(struct mipi_dbi *dbi, u8 cmd) |
02dd95fe NT |
103 | { |
104 | unsigned int i; | |
105 | ||
36b50572 | 106 | if (!dbi->read_commands) |
02dd95fe NT |
107 | return false; |
108 | ||
109 | for (i = 0; i < 0xff; i++) { | |
36b50572 | 110 | if (!dbi->read_commands[i]) |
02dd95fe | 111 | return false; |
36b50572 | 112 | if (cmd == dbi->read_commands[i]) |
02dd95fe NT |
113 | return true; |
114 | } | |
115 | ||
116 | return false; | |
117 | } | |
118 | ||
119 | /** | |
120 | * mipi_dbi_command_read - MIPI DCS read command | |
36b50572 | 121 | * @dbi: MIPI DBI structure |
02dd95fe NT |
122 | * @cmd: Command |
123 | * @val: Value read | |
124 | * | |
125 | * Send MIPI DCS read command to the controller. | |
126 | * | |
127 | * Returns: | |
128 | * Zero on success, negative error code on failure. | |
129 | */ | |
36b50572 | 130 | int mipi_dbi_command_read(struct mipi_dbi *dbi, u8 cmd, u8 *val) |
02dd95fe | 131 | { |
36b50572 | 132 | if (!dbi->read_commands) |
02dd95fe NT |
133 | return -EACCES; |
134 | ||
36b50572 | 135 | if (!mipi_dbi_command_is_read(dbi, cmd)) |
02dd95fe NT |
136 | return -EINVAL; |
137 | ||
36b50572 | 138 | return mipi_dbi_command_buf(dbi, cmd, val, 1); |
02dd95fe NT |
139 | } |
140 | EXPORT_SYMBOL(mipi_dbi_command_read); | |
141 | ||
142 | /** | |
143 | * mipi_dbi_command_buf - MIPI DCS command with parameter(s) in an array | |
36b50572 | 144 | * @dbi: MIPI DBI structure |
02dd95fe NT |
145 | * @cmd: Command |
146 | * @data: Parameter buffer | |
147 | * @len: Buffer length | |
148 | * | |
149 | * Returns: | |
150 | * Zero on success, negative error code on failure. | |
151 | */ | |
36b50572 | 152 | int mipi_dbi_command_buf(struct mipi_dbi *dbi, u8 cmd, u8 *data, size_t len) |
02dd95fe | 153 | { |
a89bfc5d | 154 | u8 *cmdbuf; |
02dd95fe NT |
155 | int ret; |
156 | ||
a89bfc5d NT |
157 | /* SPI requires dma-safe buffers */ |
158 | cmdbuf = kmemdup(&cmd, 1, GFP_KERNEL); | |
159 | if (!cmdbuf) | |
160 | return -ENOMEM; | |
161 | ||
36b50572 NT |
162 | mutex_lock(&dbi->cmdlock); |
163 | ret = dbi->command(dbi, cmdbuf, data, len); | |
164 | mutex_unlock(&dbi->cmdlock); | |
02dd95fe | 165 | |
a89bfc5d NT |
166 | kfree(cmdbuf); |
167 | ||
02dd95fe NT |
168 | return ret; |
169 | } | |
170 | EXPORT_SYMBOL(mipi_dbi_command_buf); | |
171 | ||
a89bfc5d | 172 | /* This should only be used by mipi_dbi_command() */ |
36b50572 | 173 | int mipi_dbi_command_stackbuf(struct mipi_dbi *dbi, u8 cmd, u8 *data, size_t len) |
a89bfc5d NT |
174 | { |
175 | u8 *buf; | |
176 | int ret; | |
177 | ||
178 | buf = kmemdup(data, len, GFP_KERNEL); | |
179 | if (!buf) | |
180 | return -ENOMEM; | |
181 | ||
36b50572 | 182 | ret = mipi_dbi_command_buf(dbi, cmd, buf, len); |
a89bfc5d NT |
183 | |
184 | kfree(buf); | |
185 | ||
186 | return ret; | |
187 | } | |
188 | EXPORT_SYMBOL(mipi_dbi_command_stackbuf); | |
189 | ||
13deee81 DL |
190 | /** |
191 | * mipi_dbi_buf_copy - Copy a framebuffer, transforming it if necessary | |
192 | * @dst: The destination buffer | |
193 | * @fb: The source framebuffer | |
194 | * @clip: Clipping rectangle of the area to be copied | |
195 | * @swap: When true, swap MSB/LSB of 16-bit values | |
196 | * | |
197 | * Returns: | |
198 | * Zero on success, negative error code on failure. | |
199 | */ | |
200 | int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb, | |
b051b345 | 201 | struct drm_rect *clip, bool swap) |
02dd95fe | 202 | { |
7c9f1312 NT |
203 | struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0); |
204 | struct drm_gem_cma_object *cma_obj = to_drm_gem_cma_obj(gem); | |
205 | struct dma_buf_attachment *import_attach = gem->import_attach; | |
02dd95fe NT |
206 | struct drm_format_name_buf format_name; |
207 | void *src = cma_obj->vaddr; | |
208 | int ret = 0; | |
209 | ||
210 | if (import_attach) { | |
211 | ret = dma_buf_begin_cpu_access(import_attach->dmabuf, | |
212 | DMA_FROM_DEVICE); | |
213 | if (ret) | |
214 | return ret; | |
215 | } | |
216 | ||
217 | switch (fb->format->format) { | |
218 | case DRM_FORMAT_RGB565: | |
219 | if (swap) | |
7415287e | 220 | drm_fb_swab16(dst, src, fb, clip); |
02dd95fe | 221 | else |
7415287e | 222 | drm_fb_memcpy(dst, src, fb, clip); |
02dd95fe NT |
223 | break; |
224 | case DRM_FORMAT_XRGB8888: | |
7415287e | 225 | drm_fb_xrgb8888_to_rgb565(dst, src, fb, clip, swap); |
02dd95fe NT |
226 | break; |
227 | default: | |
228 | dev_err_once(fb->dev->dev, "Format is not supported: %s\n", | |
229 | drm_get_format_name(fb->format->format, | |
230 | &format_name)); | |
231 | return -EINVAL; | |
232 | } | |
233 | ||
234 | if (import_attach) | |
235 | ret = dma_buf_end_cpu_access(import_attach->dmabuf, | |
236 | DMA_FROM_DEVICE); | |
237 | return ret; | |
238 | } | |
13deee81 | 239 | EXPORT_SYMBOL(mipi_dbi_buf_copy); |
02dd95fe | 240 | |
af741381 | 241 | static void mipi_dbi_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect) |
02dd95fe | 242 | { |
7c9f1312 NT |
243 | struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0); |
244 | struct drm_gem_cma_object *cma_obj = to_drm_gem_cma_obj(gem); | |
84137b86 | 245 | struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(fb->dev); |
af741381 NT |
246 | unsigned int height = rect->y2 - rect->y1; |
247 | unsigned int width = rect->x2 - rect->x1; | |
84137b86 | 248 | struct mipi_dbi *dbi = &dbidev->dbi; |
36b50572 | 249 | bool swap = dbi->swap_bytes; |
9d5645ad | 250 | int idx, ret = 0; |
02dd95fe NT |
251 | bool full; |
252 | void *tr; | |
253 | ||
440961d2 | 254 | if (!dbidev->enabled) |
af741381 | 255 | return; |
02dd95fe | 256 | |
9d5645ad NT |
257 | if (!drm_dev_enter(fb->dev, &idx)) |
258 | return; | |
259 | ||
af741381 | 260 | full = width == fb->width && height == fb->height; |
02dd95fe | 261 | |
b051b345 | 262 | DRM_DEBUG_KMS("Flushing [FB:%d] " DRM_RECT_FMT "\n", fb->base.id, DRM_RECT_ARG(rect)); |
02dd95fe | 263 | |
36b50572 | 264 | if (!dbi->dc || !full || swap || |
02dd95fe | 265 | fb->format->format == DRM_FORMAT_XRGB8888) { |
440961d2 NT |
266 | tr = dbidev->tx_buf; |
267 | ret = mipi_dbi_buf_copy(dbidev->tx_buf, fb, rect, swap); | |
02dd95fe | 268 | if (ret) |
af741381 | 269 | goto err_msg; |
02dd95fe NT |
270 | } else { |
271 | tr = cma_obj->vaddr; | |
272 | } | |
273 | ||
36b50572 | 274 | mipi_dbi_command(dbi, MIPI_DCS_SET_COLUMN_ADDRESS, |
b051b345 NT |
275 | (rect->x1 >> 8) & 0xff, rect->x1 & 0xff, |
276 | ((rect->x2 - 1) >> 8) & 0xff, (rect->x2 - 1) & 0xff); | |
36b50572 | 277 | mipi_dbi_command(dbi, MIPI_DCS_SET_PAGE_ADDRESS, |
b051b345 NT |
278 | (rect->y1 >> 8) & 0xff, rect->y1 & 0xff, |
279 | ((rect->y2 - 1) >> 8) & 0xff, (rect->y2 - 1) & 0xff); | |
02dd95fe | 280 | |
36b50572 | 281 | ret = mipi_dbi_command_buf(dbi, MIPI_DCS_WRITE_MEMORY_START, tr, |
af741381 NT |
282 | width * height * 2); |
283 | err_msg: | |
284 | if (ret) | |
285 | dev_err_once(fb->dev->dev, "Failed to update display %d\n", ret); | |
9d5645ad NT |
286 | |
287 | drm_dev_exit(idx); | |
02dd95fe NT |
288 | } |
289 | ||
af741381 NT |
290 | /** |
291 | * mipi_dbi_pipe_update - Display pipe update helper | |
292 | * @pipe: Simple display pipe | |
293 | * @old_state: Old plane state | |
294 | * | |
295 | * This function handles framebuffer flushing and vblank events. Drivers can use | |
296 | * this as their &drm_simple_display_pipe_funcs->update callback. | |
297 | */ | |
298 | void mipi_dbi_pipe_update(struct drm_simple_display_pipe *pipe, | |
299 | struct drm_plane_state *old_state) | |
300 | { | |
301 | struct drm_plane_state *state = pipe->plane.state; | |
302 | struct drm_crtc *crtc = &pipe->crtc; | |
303 | struct drm_rect rect; | |
304 | ||
305 | if (drm_atomic_helper_damage_merged(old_state, state, &rect)) | |
306 | mipi_dbi_fb_dirty(state->fb, &rect); | |
307 | ||
308 | if (crtc->state->event) { | |
309 | spin_lock_irq(&crtc->dev->event_lock); | |
310 | drm_crtc_send_vblank_event(crtc, crtc->state->event); | |
311 | spin_unlock_irq(&crtc->dev->event_lock); | |
312 | crtc->state->event = NULL; | |
313 | } | |
314 | } | |
315 | EXPORT_SYMBOL(mipi_dbi_pipe_update); | |
02dd95fe | 316 | |
22edc8d3 NT |
317 | /** |
318 | * mipi_dbi_enable_flush - MIPI DBI enable helper | |
440961d2 | 319 | * @dbidev: MIPI DBI device structure |
5685ca0c NT |
320 | * @crtc_state: CRTC state |
321 | * @plane_state: Plane state | |
22edc8d3 NT |
322 | * |
323 | * This function sets &mipi_dbi->enabled, flushes the whole framebuffer and | |
324 | * enables the backlight. Drivers can use this in their | |
325 | * &drm_simple_display_pipe_funcs->enable callback. | |
af741381 NT |
326 | * |
327 | * Note: Drivers which don't use mipi_dbi_pipe_update() because they have custom | |
328 | * framebuffer flushing, can't use this function since they both use the same | |
329 | * flushing code. | |
22edc8d3 | 330 | */ |
84137b86 | 331 | void mipi_dbi_enable_flush(struct mipi_dbi_dev *dbidev, |
e85d3006 VS |
332 | struct drm_crtc_state *crtc_state, |
333 | struct drm_plane_state *plane_state) | |
22edc8d3 | 334 | { |
e85d3006 | 335 | struct drm_framebuffer *fb = plane_state->fb; |
af741381 NT |
336 | struct drm_rect rect = { |
337 | .x1 = 0, | |
338 | .x2 = fb->width, | |
339 | .y1 = 0, | |
340 | .y2 = fb->height, | |
341 | }; | |
9d5645ad NT |
342 | int idx; |
343 | ||
440961d2 | 344 | if (!drm_dev_enter(&dbidev->drm, &idx)) |
9d5645ad | 345 | return; |
22edc8d3 | 346 | |
440961d2 | 347 | dbidev->enabled = true; |
af741381 | 348 | mipi_dbi_fb_dirty(fb, &rect); |
440961d2 | 349 | backlight_enable(dbidev->backlight); |
9d5645ad NT |
350 | |
351 | drm_dev_exit(idx); | |
22edc8d3 NT |
352 | } |
353 | EXPORT_SYMBOL(mipi_dbi_enable_flush); | |
354 | ||
84137b86 | 355 | static void mipi_dbi_blank(struct mipi_dbi_dev *dbidev) |
02dd95fe | 356 | { |
440961d2 | 357 | struct drm_device *drm = &dbidev->drm; |
02dd95fe NT |
358 | u16 height = drm->mode_config.min_height; |
359 | u16 width = drm->mode_config.min_width; | |
84137b86 | 360 | struct mipi_dbi *dbi = &dbidev->dbi; |
02dd95fe | 361 | size_t len = width * height * 2; |
9d5645ad NT |
362 | int idx; |
363 | ||
364 | if (!drm_dev_enter(drm, &idx)) | |
365 | return; | |
02dd95fe | 366 | |
440961d2 | 367 | memset(dbidev->tx_buf, 0, len); |
02dd95fe | 368 | |
36b50572 | 369 | mipi_dbi_command(dbi, MIPI_DCS_SET_COLUMN_ADDRESS, 0, 0, |
02dd95fe | 370 | (width >> 8) & 0xFF, (width - 1) & 0xFF); |
36b50572 | 371 | mipi_dbi_command(dbi, MIPI_DCS_SET_PAGE_ADDRESS, 0, 0, |
02dd95fe | 372 | (height >> 8) & 0xFF, (height - 1) & 0xFF); |
36b50572 | 373 | mipi_dbi_command_buf(dbi, MIPI_DCS_WRITE_MEMORY_START, |
440961d2 | 374 | (u8 *)dbidev->tx_buf, len); |
9d5645ad NT |
375 | |
376 | drm_dev_exit(idx); | |
02dd95fe NT |
377 | } |
378 | ||
379 | /** | |
380 | * mipi_dbi_pipe_disable - MIPI DBI pipe disable helper | |
381 | * @pipe: Display pipe | |
382 | * | |
f730eceb NT |
383 | * This function disables backlight if present, if not the display memory is |
384 | * blanked. The regulator is disabled if in use. Drivers can use this as their | |
02dd95fe NT |
385 | * &drm_simple_display_pipe_funcs->disable callback. |
386 | */ | |
387 | void mipi_dbi_pipe_disable(struct drm_simple_display_pipe *pipe) | |
388 | { | |
84137b86 | 389 | struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev); |
02dd95fe | 390 | |
440961d2 | 391 | if (!dbidev->enabled) |
9d5645ad NT |
392 | return; |
393 | ||
02dd95fe NT |
394 | DRM_DEBUG_KMS("\n"); |
395 | ||
440961d2 | 396 | dbidev->enabled = false; |
02dd95fe | 397 | |
440961d2 NT |
398 | if (dbidev->backlight) |
399 | backlight_disable(dbidev->backlight); | |
02dd95fe | 400 | else |
440961d2 | 401 | mipi_dbi_blank(dbidev); |
f730eceb | 402 | |
440961d2 NT |
403 | if (dbidev->regulator) |
404 | regulator_disable(dbidev->regulator); | |
02dd95fe NT |
405 | } |
406 | EXPORT_SYMBOL(mipi_dbi_pipe_disable); | |
407 | ||
710ae47d NT |
408 | static int mipi_dbi_connector_get_modes(struct drm_connector *connector) |
409 | { | |
84137b86 | 410 | struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(connector->dev); |
710ae47d NT |
411 | struct drm_display_mode *mode; |
412 | ||
440961d2 | 413 | mode = drm_mode_duplicate(connector->dev, &dbidev->mode); |
710ae47d NT |
414 | if (!mode) { |
415 | DRM_ERROR("Failed to duplicate mode\n"); | |
416 | return 0; | |
417 | } | |
418 | ||
419 | if (mode->name[0] == '\0') | |
420 | drm_mode_set_name(mode); | |
421 | ||
422 | mode->type |= DRM_MODE_TYPE_PREFERRED; | |
423 | drm_mode_probed_add(connector, mode); | |
424 | ||
425 | if (mode->width_mm) { | |
426 | connector->display_info.width_mm = mode->width_mm; | |
427 | connector->display_info.height_mm = mode->height_mm; | |
428 | } | |
429 | ||
430 | return 1; | |
431 | } | |
432 | ||
433 | static const struct drm_connector_helper_funcs mipi_dbi_connector_hfuncs = { | |
434 | .get_modes = mipi_dbi_connector_get_modes, | |
435 | }; | |
436 | ||
437 | static const struct drm_connector_funcs mipi_dbi_connector_funcs = { | |
438 | .reset = drm_atomic_helper_connector_reset, | |
439 | .fill_modes = drm_helper_probe_single_connector_modes, | |
440 | .destroy = drm_connector_cleanup, | |
441 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | |
442 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | |
443 | }; | |
444 | ||
445 | static int mipi_dbi_rotate_mode(struct drm_display_mode *mode, | |
446 | unsigned int rotation) | |
447 | { | |
448 | if (rotation == 0 || rotation == 180) { | |
449 | return 0; | |
450 | } else if (rotation == 90 || rotation == 270) { | |
451 | swap(mode->hdisplay, mode->vdisplay); | |
452 | swap(mode->hsync_start, mode->vsync_start); | |
453 | swap(mode->hsync_end, mode->vsync_end); | |
454 | swap(mode->htotal, mode->vtotal); | |
455 | swap(mode->width_mm, mode->height_mm); | |
456 | return 0; | |
457 | } else { | |
458 | return -EINVAL; | |
459 | } | |
460 | } | |
461 | ||
3eba3922 NT |
462 | static const struct drm_mode_config_funcs mipi_dbi_mode_config_funcs = { |
463 | .fb_create = drm_gem_fb_create_with_dirty, | |
464 | .atomic_check = drm_atomic_helper_check, | |
465 | .atomic_commit = drm_atomic_helper_commit, | |
466 | }; | |
467 | ||
02dd95fe NT |
468 | static const uint32_t mipi_dbi_formats[] = { |
469 | DRM_FORMAT_RGB565, | |
470 | DRM_FORMAT_XRGB8888, | |
471 | }; | |
472 | ||
473 | /** | |
84137b86 | 474 | * mipi_dbi_dev_init_with_formats - MIPI DBI device initialization with custom formats |
440961d2 | 475 | * @dbidev: MIPI DBI device structure to initialize |
3eba3922 | 476 | * @funcs: Display pipe functions |
cc431212 NT |
477 | * @formats: Array of supported formats (DRM_FORMAT\_\*). |
478 | * @format_count: Number of elements in @formats | |
02dd95fe NT |
479 | * @mode: Display mode |
480 | * @rotation: Initial rotation in degrees Counter Clock Wise | |
cc431212 | 481 | * @tx_buf_size: Allocate a transmit buffer of this size. |
02dd95fe | 482 | * |
3eba3922 NT |
483 | * This function sets up a &drm_simple_display_pipe with a &drm_connector that |
484 | * has one fixed &drm_display_mode which is rotated according to @rotation. | |
485 | * This mode is used to set the mode config min/max width/height properties. | |
02dd95fe | 486 | * |
84137b86 | 487 | * Use mipi_dbi_dev_init() if you don't need custom formats. |
cc431212 NT |
488 | * |
489 | * Note: | |
490 | * Some of the helper functions expects RGB565 to be the default format and the | |
491 | * transmit buffer sized to fit that. | |
02dd95fe | 492 | * |
02dd95fe NT |
493 | * Returns: |
494 | * Zero on success, negative error code on failure. | |
495 | */ | |
84137b86 NT |
496 | int mipi_dbi_dev_init_with_formats(struct mipi_dbi_dev *dbidev, |
497 | const struct drm_simple_display_pipe_funcs *funcs, | |
498 | const uint32_t *formats, unsigned int format_count, | |
499 | const struct drm_display_mode *mode, | |
500 | unsigned int rotation, size_t tx_buf_size) | |
02dd95fe | 501 | { |
710ae47d NT |
502 | static const uint64_t modifiers[] = { |
503 | DRM_FORMAT_MOD_LINEAR, | |
504 | DRM_FORMAT_MOD_INVALID | |
505 | }; | |
440961d2 | 506 | struct drm_device *drm = &dbidev->drm; |
02dd95fe NT |
507 | int ret; |
508 | ||
84137b86 | 509 | if (!dbidev->dbi.command) |
02dd95fe NT |
510 | return -EINVAL; |
511 | ||
440961d2 NT |
512 | dbidev->tx_buf = devm_kmalloc(drm->dev, tx_buf_size, GFP_KERNEL); |
513 | if (!dbidev->tx_buf) | |
02dd95fe NT |
514 | return -ENOMEM; |
515 | ||
440961d2 NT |
516 | drm_mode_copy(&dbidev->mode, mode); |
517 | ret = mipi_dbi_rotate_mode(&dbidev->mode, rotation); | |
710ae47d NT |
518 | if (ret) { |
519 | DRM_ERROR("Illegal rotation value %u\n", rotation); | |
520 | return -EINVAL; | |
521 | } | |
522 | ||
440961d2 NT |
523 | drm_connector_helper_add(&dbidev->connector, &mipi_dbi_connector_hfuncs); |
524 | ret = drm_connector_init(drm, &dbidev->connector, &mipi_dbi_connector_funcs, | |
710ae47d NT |
525 | DRM_MODE_CONNECTOR_SPI); |
526 | if (ret) | |
527 | return ret; | |
528 | ||
440961d2 NT |
529 | ret = drm_simple_display_pipe_init(drm, &dbidev->pipe, funcs, formats, format_count, |
530 | modifiers, &dbidev->connector); | |
02dd95fe NT |
531 | if (ret) |
532 | return ret; | |
533 | ||
440961d2 | 534 | drm_plane_enable_fb_damage_clips(&dbidev->pipe.plane); |
af741381 | 535 | |
3eba3922 | 536 | drm->mode_config.funcs = &mipi_dbi_mode_config_funcs; |
440961d2 NT |
537 | drm->mode_config.min_width = dbidev->mode.hdisplay; |
538 | drm->mode_config.max_width = dbidev->mode.hdisplay; | |
539 | drm->mode_config.min_height = dbidev->mode.vdisplay; | |
540 | drm->mode_config.max_height = dbidev->mode.vdisplay; | |
541 | dbidev->rotation = rotation; | |
02dd95fe | 542 | |
cc431212 | 543 | DRM_DEBUG_KMS("rotation = %u\n", rotation); |
02dd95fe NT |
544 | |
545 | return 0; | |
546 | } | |
84137b86 | 547 | EXPORT_SYMBOL(mipi_dbi_dev_init_with_formats); |
cc431212 NT |
548 | |
549 | /** | |
84137b86 | 550 | * mipi_dbi_dev_init - MIPI DBI device initialization |
440961d2 | 551 | * @dbidev: MIPI DBI device structure to initialize |
cc431212 NT |
552 | * @funcs: Display pipe functions |
553 | * @mode: Display mode | |
554 | * @rotation: Initial rotation in degrees Counter Clock Wise | |
555 | * | |
556 | * This function sets up a &drm_simple_display_pipe with a &drm_connector that | |
557 | * has one fixed &drm_display_mode which is rotated according to @rotation. | |
558 | * This mode is used to set the mode config min/max width/height properties. | |
559 | * Additionally &mipi_dbi.tx_buf is allocated. | |
560 | * | |
561 | * Supported formats: Native RGB565 and emulated XRGB8888. | |
562 | * | |
563 | * Returns: | |
564 | * Zero on success, negative error code on failure. | |
565 | */ | |
84137b86 NT |
566 | int mipi_dbi_dev_init(struct mipi_dbi_dev *dbidev, |
567 | const struct drm_simple_display_pipe_funcs *funcs, | |
568 | const struct drm_display_mode *mode, unsigned int rotation) | |
cc431212 NT |
569 | { |
570 | size_t bufsize = mode->vdisplay * mode->hdisplay * sizeof(u16); | |
571 | ||
440961d2 | 572 | dbidev->drm.mode_config.preferred_depth = 16; |
cc431212 | 573 | |
84137b86 NT |
574 | return mipi_dbi_dev_init_with_formats(dbidev, funcs, mipi_dbi_formats, |
575 | ARRAY_SIZE(mipi_dbi_formats), mode, | |
576 | rotation, bufsize); | |
cc431212 | 577 | } |
84137b86 | 578 | EXPORT_SYMBOL(mipi_dbi_dev_init); |
02dd95fe | 579 | |
3eba3922 NT |
580 | /** |
581 | * mipi_dbi_release - DRM driver release helper | |
582 | * @drm: DRM device | |
583 | * | |
584 | * This function finalizes and frees &mipi_dbi. | |
585 | * | |
586 | * Drivers can use this as their &drm_driver->release callback. | |
587 | */ | |
588 | void mipi_dbi_release(struct drm_device *drm) | |
589 | { | |
84137b86 | 590 | struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(drm); |
3eba3922 NT |
591 | |
592 | DRM_DEBUG_DRIVER("\n"); | |
593 | ||
594 | drm_mode_config_cleanup(drm); | |
595 | drm_dev_fini(drm); | |
84137b86 | 596 | kfree(dbidev); |
3eba3922 NT |
597 | } |
598 | EXPORT_SYMBOL(mipi_dbi_release); | |
599 | ||
02dd95fe NT |
600 | /** |
601 | * mipi_dbi_hw_reset - Hardware reset of controller | |
36b50572 | 602 | * @dbi: MIPI DBI structure |
02dd95fe NT |
603 | * |
604 | * Reset controller if the &mipi_dbi->reset gpio is set. | |
605 | */ | |
36b50572 | 606 | void mipi_dbi_hw_reset(struct mipi_dbi *dbi) |
02dd95fe | 607 | { |
36b50572 | 608 | if (!dbi->reset) |
02dd95fe NT |
609 | return; |
610 | ||
36b50572 | 611 | gpiod_set_value_cansleep(dbi->reset, 0); |
10399b22 | 612 | usleep_range(20, 1000); |
36b50572 | 613 | gpiod_set_value_cansleep(dbi->reset, 1); |
02dd95fe NT |
614 | msleep(120); |
615 | } | |
616 | EXPORT_SYMBOL(mipi_dbi_hw_reset); | |
617 | ||
618 | /** | |
619 | * mipi_dbi_display_is_on - Check if display is on | |
36b50572 | 620 | * @dbi: MIPI DBI structure |
02dd95fe NT |
621 | * |
622 | * This function checks the Power Mode register (if readable) to see if | |
623 | * display output is turned on. This can be used to see if the bootloader | |
624 | * has already turned on the display avoiding flicker when the pipeline is | |
625 | * enabled. | |
626 | * | |
627 | * Returns: | |
628 | * true if the display can be verified to be on, false otherwise. | |
629 | */ | |
36b50572 | 630 | bool mipi_dbi_display_is_on(struct mipi_dbi *dbi) |
02dd95fe NT |
631 | { |
632 | u8 val; | |
633 | ||
36b50572 | 634 | if (mipi_dbi_command_read(dbi, MIPI_DCS_GET_POWER_MODE, &val)) |
02dd95fe NT |
635 | return false; |
636 | ||
637 | val &= ~DCS_POWER_MODE_RESERVED_MASK; | |
638 | ||
070ab128 | 639 | /* The poweron/reset value is 08h DCS_POWER_MODE_DISPLAY_NORMAL_MODE */ |
02dd95fe NT |
640 | if (val != (DCS_POWER_MODE_DISPLAY | |
641 | DCS_POWER_MODE_DISPLAY_NORMAL_MODE | DCS_POWER_MODE_SLEEP_MODE)) | |
642 | return false; | |
643 | ||
644 | DRM_DEBUG_DRIVER("Display is ON\n"); | |
645 | ||
646 | return true; | |
647 | } | |
648 | EXPORT_SYMBOL(mipi_dbi_display_is_on); | |
649 | ||
84137b86 | 650 | static int mipi_dbi_poweron_reset_conditional(struct mipi_dbi_dev *dbidev, bool cond) |
070ab128 | 651 | { |
440961d2 | 652 | struct device *dev = dbidev->drm.dev; |
84137b86 | 653 | struct mipi_dbi *dbi = &dbidev->dbi; |
070ab128 NT |
654 | int ret; |
655 | ||
440961d2 NT |
656 | if (dbidev->regulator) { |
657 | ret = regulator_enable(dbidev->regulator); | |
070ab128 NT |
658 | if (ret) { |
659 | DRM_DEV_ERROR(dev, "Failed to enable regulator (%d)\n", ret); | |
660 | return ret; | |
661 | } | |
662 | } | |
663 | ||
36b50572 | 664 | if (cond && mipi_dbi_display_is_on(dbi)) |
070ab128 NT |
665 | return 1; |
666 | ||
36b50572 NT |
667 | mipi_dbi_hw_reset(dbi); |
668 | ret = mipi_dbi_command(dbi, MIPI_DCS_SOFT_RESET); | |
070ab128 NT |
669 | if (ret) { |
670 | DRM_DEV_ERROR(dev, "Failed to send reset command (%d)\n", ret); | |
440961d2 NT |
671 | if (dbidev->regulator) |
672 | regulator_disable(dbidev->regulator); | |
070ab128 NT |
673 | return ret; |
674 | } | |
675 | ||
676 | /* | |
677 | * If we did a hw reset, we know the controller is in Sleep mode and | |
678 | * per MIPI DSC spec should wait 5ms after soft reset. If we didn't, | |
679 | * we assume worst case and wait 120ms. | |
680 | */ | |
36b50572 | 681 | if (dbi->reset) |
070ab128 NT |
682 | usleep_range(5000, 20000); |
683 | else | |
684 | msleep(120); | |
685 | ||
686 | return 0; | |
687 | } | |
688 | ||
689 | /** | |
690 | * mipi_dbi_poweron_reset - MIPI DBI poweron and reset | |
440961d2 | 691 | * @dbidev: MIPI DBI device structure |
070ab128 NT |
692 | * |
693 | * This function enables the regulator if used and does a hardware and software | |
694 | * reset. | |
695 | * | |
696 | * Returns: | |
697 | * Zero on success, or a negative error code. | |
698 | */ | |
84137b86 | 699 | int mipi_dbi_poweron_reset(struct mipi_dbi_dev *dbidev) |
070ab128 | 700 | { |
440961d2 | 701 | return mipi_dbi_poweron_reset_conditional(dbidev, false); |
070ab128 NT |
702 | } |
703 | EXPORT_SYMBOL(mipi_dbi_poweron_reset); | |
704 | ||
705 | /** | |
706 | * mipi_dbi_poweron_conditional_reset - MIPI DBI poweron and conditional reset | |
440961d2 | 707 | * @dbidev: MIPI DBI device structure |
070ab128 NT |
708 | * |
709 | * This function enables the regulator if used and if the display is off, it | |
710 | * does a hardware and software reset. If mipi_dbi_display_is_on() determines | |
711 | * that the display is on, no reset is performed. | |
712 | * | |
713 | * Returns: | |
714 | * Zero if the controller was reset, 1 if the display was already on, or a | |
715 | * negative error code. | |
716 | */ | |
84137b86 | 717 | int mipi_dbi_poweron_conditional_reset(struct mipi_dbi_dev *dbidev) |
070ab128 | 718 | { |
440961d2 | 719 | return mipi_dbi_poweron_reset_conditional(dbidev, true); |
070ab128 NT |
720 | } |
721 | EXPORT_SYMBOL(mipi_dbi_poweron_conditional_reset); | |
722 | ||
02dd95fe NT |
723 | #if IS_ENABLED(CONFIG_SPI) |
724 | ||
13deee81 DL |
725 | /** |
726 | * mipi_dbi_spi_cmd_max_speed - get the maximum SPI bus speed | |
727 | * @spi: SPI device | |
728 | * @len: The transfer buffer length. | |
729 | * | |
02dd95fe NT |
730 | * Many controllers have a max speed of 10MHz, but can be pushed way beyond |
731 | * that. Increase reliability by running pixel data at max speed and the rest | |
732 | * at 10MHz, preventing transfer glitches from messing up the init settings. | |
733 | */ | |
13deee81 | 734 | u32 mipi_dbi_spi_cmd_max_speed(struct spi_device *spi, size_t len) |
02dd95fe NT |
735 | { |
736 | if (len > 64) | |
737 | return 0; /* use default */ | |
738 | ||
739 | return min_t(u32, 10000000, spi->max_speed_hz); | |
740 | } | |
13deee81 | 741 | EXPORT_SYMBOL(mipi_dbi_spi_cmd_max_speed); |
02dd95fe | 742 | |
f729d8d9 NT |
743 | static bool mipi_dbi_machine_little_endian(void) |
744 | { | |
745 | #if defined(__LITTLE_ENDIAN) | |
746 | return true; | |
747 | #else | |
748 | return false; | |
749 | #endif | |
750 | } | |
751 | ||
02dd95fe NT |
752 | /* |
753 | * MIPI DBI Type C Option 1 | |
754 | * | |
755 | * If the SPI controller doesn't have 9 bits per word support, | |
756 | * use blocks of 9 bytes to send 8x 9-bit words using a 8-bit SPI transfer. | |
757 | * Pad partial blocks with MIPI_DCS_NOP (zero). | |
758 | * This is how the D/C bit (x) is added: | |
759 | * x7654321 | |
760 | * 0x765432 | |
761 | * 10x76543 | |
762 | * 210x7654 | |
763 | * 3210x765 | |
764 | * 43210x76 | |
765 | * 543210x7 | |
766 | * 6543210x | |
767 | * 76543210 | |
768 | */ | |
769 | ||
36b50572 | 770 | static int mipi_dbi_spi1e_transfer(struct mipi_dbi *dbi, int dc, |
02dd95fe NT |
771 | const void *buf, size_t len, |
772 | unsigned int bpw) | |
773 | { | |
f729d8d9 | 774 | bool swap_bytes = (bpw == 16 && mipi_dbi_machine_little_endian()); |
36b50572 NT |
775 | size_t chunk, max_chunk = dbi->tx_buf9_len; |
776 | struct spi_device *spi = dbi->spi; | |
02dd95fe | 777 | struct spi_transfer tr = { |
36b50572 | 778 | .tx_buf = dbi->tx_buf9, |
02dd95fe NT |
779 | .bits_per_word = 8, |
780 | }; | |
781 | struct spi_message m; | |
782 | const u8 *src = buf; | |
783 | int i, ret; | |
784 | u8 *dst; | |
785 | ||
786 | if (drm_debug & DRM_UT_DRIVER) | |
787 | pr_debug("[drm:%s] dc=%d, max_chunk=%zu, transfers:\n", | |
788 | __func__, dc, max_chunk); | |
789 | ||
790 | tr.speed_hz = mipi_dbi_spi_cmd_max_speed(spi, len); | |
791 | spi_message_init_with_transfers(&m, &tr, 1); | |
792 | ||
793 | if (!dc) { | |
794 | if (WARN_ON_ONCE(len != 1)) | |
795 | return -EINVAL; | |
796 | ||
797 | /* Command: pad no-op's (zeroes) at beginning of block */ | |
36b50572 | 798 | dst = dbi->tx_buf9; |
02dd95fe NT |
799 | memset(dst, 0, 9); |
800 | dst[8] = *src; | |
801 | tr.len = 9; | |
802 | ||
02dd95fe NT |
803 | return spi_sync(spi, &m); |
804 | } | |
805 | ||
806 | /* max with room for adding one bit per byte */ | |
807 | max_chunk = max_chunk / 9 * 8; | |
808 | /* but no bigger than len */ | |
809 | max_chunk = min(max_chunk, len); | |
810 | /* 8 byte blocks */ | |
811 | max_chunk = max_t(size_t, 8, max_chunk & ~0x7); | |
812 | ||
813 | while (len) { | |
814 | size_t added = 0; | |
815 | ||
816 | chunk = min(len, max_chunk); | |
817 | len -= chunk; | |
36b50572 | 818 | dst = dbi->tx_buf9; |
02dd95fe NT |
819 | |
820 | if (chunk < 8) { | |
821 | u8 val, carry = 0; | |
822 | ||
823 | /* Data: pad no-op's (zeroes) at end of block */ | |
824 | memset(dst, 0, 9); | |
825 | ||
826 | if (swap_bytes) { | |
827 | for (i = 1; i < (chunk + 1); i++) { | |
828 | val = src[1]; | |
829 | *dst++ = carry | BIT(8 - i) | (val >> i); | |
830 | carry = val << (8 - i); | |
831 | i++; | |
832 | val = src[0]; | |
833 | *dst++ = carry | BIT(8 - i) | (val >> i); | |
834 | carry = val << (8 - i); | |
835 | src += 2; | |
836 | } | |
837 | *dst++ = carry; | |
838 | } else { | |
839 | for (i = 1; i < (chunk + 1); i++) { | |
840 | val = *src++; | |
841 | *dst++ = carry | BIT(8 - i) | (val >> i); | |
842 | carry = val << (8 - i); | |
843 | } | |
844 | *dst++ = carry; | |
845 | } | |
846 | ||
847 | chunk = 8; | |
848 | added = 1; | |
849 | } else { | |
850 | for (i = 0; i < chunk; i += 8) { | |
851 | if (swap_bytes) { | |
852 | *dst++ = BIT(7) | (src[1] >> 1); | |
853 | *dst++ = (src[1] << 7) | BIT(6) | (src[0] >> 2); | |
854 | *dst++ = (src[0] << 6) | BIT(5) | (src[3] >> 3); | |
855 | *dst++ = (src[3] << 5) | BIT(4) | (src[2] >> 4); | |
856 | *dst++ = (src[2] << 4) | BIT(3) | (src[5] >> 5); | |
857 | *dst++ = (src[5] << 3) | BIT(2) | (src[4] >> 6); | |
858 | *dst++ = (src[4] << 2) | BIT(1) | (src[7] >> 7); | |
859 | *dst++ = (src[7] << 1) | BIT(0); | |
860 | *dst++ = src[6]; | |
861 | } else { | |
862 | *dst++ = BIT(7) | (src[0] >> 1); | |
863 | *dst++ = (src[0] << 7) | BIT(6) | (src[1] >> 2); | |
864 | *dst++ = (src[1] << 6) | BIT(5) | (src[2] >> 3); | |
865 | *dst++ = (src[2] << 5) | BIT(4) | (src[3] >> 4); | |
866 | *dst++ = (src[3] << 4) | BIT(3) | (src[4] >> 5); | |
867 | *dst++ = (src[4] << 3) | BIT(2) | (src[5] >> 6); | |
868 | *dst++ = (src[5] << 2) | BIT(1) | (src[6] >> 7); | |
869 | *dst++ = (src[6] << 1) | BIT(0); | |
870 | *dst++ = src[7]; | |
871 | } | |
872 | ||
873 | src += 8; | |
874 | added++; | |
875 | } | |
876 | } | |
877 | ||
878 | tr.len = chunk + added; | |
879 | ||
02dd95fe NT |
880 | ret = spi_sync(spi, &m); |
881 | if (ret) | |
882 | return ret; | |
265ffed7 | 883 | } |
02dd95fe NT |
884 | |
885 | return 0; | |
886 | } | |
887 | ||
36b50572 | 888 | static int mipi_dbi_spi1_transfer(struct mipi_dbi *dbi, int dc, |
02dd95fe NT |
889 | const void *buf, size_t len, |
890 | unsigned int bpw) | |
891 | { | |
36b50572 | 892 | struct spi_device *spi = dbi->spi; |
02dd95fe NT |
893 | struct spi_transfer tr = { |
894 | .bits_per_word = 9, | |
895 | }; | |
896 | const u16 *src16 = buf; | |
897 | const u8 *src8 = buf; | |
898 | struct spi_message m; | |
899 | size_t max_chunk; | |
900 | u16 *dst16; | |
901 | int ret; | |
902 | ||
cfcc8fcb | 903 | if (!spi_is_bpw_supported(spi, 9)) |
36b50572 | 904 | return mipi_dbi_spi1e_transfer(dbi, dc, buf, len, bpw); |
02dd95fe NT |
905 | |
906 | tr.speed_hz = mipi_dbi_spi_cmd_max_speed(spi, len); | |
36b50572 NT |
907 | max_chunk = dbi->tx_buf9_len; |
908 | dst16 = dbi->tx_buf9; | |
02dd95fe NT |
909 | |
910 | if (drm_debug & DRM_UT_DRIVER) | |
911 | pr_debug("[drm:%s] dc=%d, max_chunk=%zu, transfers:\n", | |
912 | __func__, dc, max_chunk); | |
913 | ||
914 | max_chunk = min(max_chunk / 2, len); | |
915 | ||
916 | spi_message_init_with_transfers(&m, &tr, 1); | |
917 | tr.tx_buf = dst16; | |
918 | ||
919 | while (len) { | |
920 | size_t chunk = min(len, max_chunk); | |
921 | unsigned int i; | |
922 | ||
f729d8d9 | 923 | if (bpw == 16 && mipi_dbi_machine_little_endian()) { |
02dd95fe NT |
924 | for (i = 0; i < (chunk * 2); i += 2) { |
925 | dst16[i] = *src16 >> 8; | |
926 | dst16[i + 1] = *src16++ & 0xFF; | |
927 | if (dc) { | |
928 | dst16[i] |= 0x0100; | |
929 | dst16[i + 1] |= 0x0100; | |
930 | } | |
931 | } | |
932 | } else { | |
933 | for (i = 0; i < chunk; i++) { | |
934 | dst16[i] = *src8++; | |
935 | if (dc) | |
936 | dst16[i] |= 0x0100; | |
937 | } | |
938 | } | |
939 | ||
940 | tr.len = chunk; | |
941 | len -= chunk; | |
942 | ||
02dd95fe NT |
943 | ret = spi_sync(spi, &m); |
944 | if (ret) | |
945 | return ret; | |
265ffed7 | 946 | } |
02dd95fe NT |
947 | |
948 | return 0; | |
949 | } | |
950 | ||
36b50572 | 951 | static int mipi_dbi_typec1_command(struct mipi_dbi *dbi, u8 *cmd, |
02dd95fe NT |
952 | u8 *parameters, size_t num) |
953 | { | |
a89bfc5d | 954 | unsigned int bpw = (*cmd == MIPI_DCS_WRITE_MEMORY_START) ? 16 : 8; |
02dd95fe NT |
955 | int ret; |
956 | ||
36b50572 | 957 | if (mipi_dbi_command_is_read(dbi, *cmd)) |
c7581a41 | 958 | return -EOPNOTSUPP; |
02dd95fe | 959 | |
a89bfc5d | 960 | MIPI_DBI_DEBUG_COMMAND(*cmd, parameters, num); |
02dd95fe | 961 | |
36b50572 | 962 | ret = mipi_dbi_spi1_transfer(dbi, 0, cmd, 1, 8); |
02dd95fe NT |
963 | if (ret || !num) |
964 | return ret; | |
965 | ||
36b50572 | 966 | return mipi_dbi_spi1_transfer(dbi, 1, parameters, num, bpw); |
02dd95fe NT |
967 | } |
968 | ||
969 | /* MIPI DBI Type C Option 3 */ | |
970 | ||
36b50572 | 971 | static int mipi_dbi_typec3_command_read(struct mipi_dbi *dbi, u8 *cmd, |
02dd95fe NT |
972 | u8 *data, size_t len) |
973 | { | |
36b50572 | 974 | struct spi_device *spi = dbi->spi; |
02dd95fe NT |
975 | u32 speed_hz = min_t(u32, MIPI_DBI_MAX_SPI_READ_SPEED, |
976 | spi->max_speed_hz / 2); | |
977 | struct spi_transfer tr[2] = { | |
978 | { | |
979 | .speed_hz = speed_hz, | |
a89bfc5d | 980 | .tx_buf = cmd, |
02dd95fe NT |
981 | .len = 1, |
982 | }, { | |
983 | .speed_hz = speed_hz, | |
984 | .len = len, | |
985 | }, | |
986 | }; | |
987 | struct spi_message m; | |
988 | u8 *buf; | |
989 | int ret; | |
990 | ||
991 | if (!len) | |
992 | return -EINVAL; | |
993 | ||
994 | /* | |
995 | * Support non-standard 24-bit and 32-bit Nokia read commands which | |
996 | * start with a dummy clock, so we need to read an extra byte. | |
997 | */ | |
a89bfc5d NT |
998 | if (*cmd == MIPI_DCS_GET_DISPLAY_ID || |
999 | *cmd == MIPI_DCS_GET_DISPLAY_STATUS) { | |
02dd95fe NT |
1000 | if (!(len == 3 || len == 4)) |
1001 | return -EINVAL; | |
1002 | ||
1003 | tr[1].len = len + 1; | |
1004 | } | |
1005 | ||
1006 | buf = kmalloc(tr[1].len, GFP_KERNEL); | |
1007 | if (!buf) | |
1008 | return -ENOMEM; | |
1009 | ||
1010 | tr[1].rx_buf = buf; | |
36b50572 | 1011 | gpiod_set_value_cansleep(dbi->dc, 0); |
02dd95fe NT |
1012 | |
1013 | spi_message_init_with_transfers(&m, tr, ARRAY_SIZE(tr)); | |
1014 | ret = spi_sync(spi, &m); | |
1015 | if (ret) | |
1016 | goto err_free; | |
1017 | ||
02dd95fe NT |
1018 | if (tr[1].len == len) { |
1019 | memcpy(data, buf, len); | |
1020 | } else { | |
1021 | unsigned int i; | |
1022 | ||
1023 | for (i = 0; i < len; i++) | |
1024 | data[i] = (buf[i] << 1) | !!(buf[i + 1] & BIT(7)); | |
1025 | } | |
1026 | ||
a89bfc5d | 1027 | MIPI_DBI_DEBUG_COMMAND(*cmd, data, len); |
02dd95fe NT |
1028 | |
1029 | err_free: | |
1030 | kfree(buf); | |
1031 | ||
1032 | return ret; | |
1033 | } | |
1034 | ||
36b50572 | 1035 | static int mipi_dbi_typec3_command(struct mipi_dbi *dbi, u8 *cmd, |
02dd95fe NT |
1036 | u8 *par, size_t num) |
1037 | { | |
36b50572 | 1038 | struct spi_device *spi = dbi->spi; |
02dd95fe NT |
1039 | unsigned int bpw = 8; |
1040 | u32 speed_hz; | |
1041 | int ret; | |
1042 | ||
36b50572 NT |
1043 | if (mipi_dbi_command_is_read(dbi, *cmd)) |
1044 | return mipi_dbi_typec3_command_read(dbi, cmd, par, num); | |
02dd95fe | 1045 | |
a89bfc5d | 1046 | MIPI_DBI_DEBUG_COMMAND(*cmd, par, num); |
02dd95fe | 1047 | |
36b50572 | 1048 | gpiod_set_value_cansleep(dbi->dc, 0); |
02dd95fe | 1049 | speed_hz = mipi_dbi_spi_cmd_max_speed(spi, 1); |
d23d4d4d | 1050 | ret = mipi_dbi_spi_transfer(spi, speed_hz, 8, cmd, 1); |
02dd95fe NT |
1051 | if (ret || !num) |
1052 | return ret; | |
1053 | ||
36b50572 | 1054 | if (*cmd == MIPI_DCS_WRITE_MEMORY_START && !dbi->swap_bytes) |
02dd95fe NT |
1055 | bpw = 16; |
1056 | ||
36b50572 | 1057 | gpiod_set_value_cansleep(dbi->dc, 1); |
02dd95fe NT |
1058 | speed_hz = mipi_dbi_spi_cmd_max_speed(spi, num); |
1059 | ||
d23d4d4d | 1060 | return mipi_dbi_spi_transfer(spi, speed_hz, bpw, par, num); |
02dd95fe NT |
1061 | } |
1062 | ||
1063 | /** | |
36b50572 | 1064 | * mipi_dbi_spi_init - Initialize MIPI DBI SPI interface |
02dd95fe | 1065 | * @spi: SPI device |
36b50572 | 1066 | * @dbi: MIPI DBI structure to initialize |
ace98812 | 1067 | * @dc: D/C gpio (optional) |
02dd95fe | 1068 | * |
36b50572 | 1069 | * This function sets &mipi_dbi->command, enables &mipi_dbi->read_commands for the |
84137b86 | 1070 | * usual read commands. It should be followed by a call to mipi_dbi_dev_init() or |
ace98812 | 1071 | * a driver-specific init. |
02dd95fe NT |
1072 | * |
1073 | * If @dc is set, a Type C Option 3 interface is assumed, if not | |
1074 | * Type C Option 1. | |
1075 | * | |
1076 | * If the SPI master driver doesn't support the necessary bits per word, | |
1077 | * the following transformation is used: | |
1078 | * | |
1079 | * - 9-bit: reorder buffer as 9x 8-bit words, padded with no-op command. | |
1080 | * - 16-bit: if big endian send as 8-bit, if little endian swap bytes | |
1081 | * | |
1082 | * Returns: | |
1083 | * Zero on success, negative error code on failure. | |
1084 | */ | |
36b50572 | 1085 | int mipi_dbi_spi_init(struct spi_device *spi, struct mipi_dbi *dbi, |
ace98812 | 1086 | struct gpio_desc *dc) |
02dd95fe | 1087 | { |
02dd95fe NT |
1088 | struct device *dev = &spi->dev; |
1089 | int ret; | |
1090 | ||
02dd95fe NT |
1091 | /* |
1092 | * Even though it's not the SPI device that does DMA (the master does), | |
1093 | * the dma mask is necessary for the dma_alloc_wc() in | |
1094 | * drm_gem_cma_create(). The dma_addr returned will be a physical | |
eb73e1d5 | 1095 | * address which might be different from the bus address, but this is |
02dd95fe NT |
1096 | * not a problem since the address will not be used. |
1097 | * The virtual address is used in the transfer and the SPI core | |
1098 | * re-maps it on the SPI master device using the DMA streaming API | |
1099 | * (spi_map_buf()). | |
1100 | */ | |
1101 | if (!dev->coherent_dma_mask) { | |
1102 | ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); | |
1103 | if (ret) { | |
1104 | dev_warn(dev, "Failed to set dma mask %d\n", ret); | |
1105 | return ret; | |
1106 | } | |
1107 | } | |
1108 | ||
36b50572 NT |
1109 | dbi->spi = spi; |
1110 | dbi->read_commands = mipi_dbi_dcs_read_commands; | |
02dd95fe NT |
1111 | |
1112 | if (dc) { | |
36b50572 NT |
1113 | dbi->command = mipi_dbi_typec3_command; |
1114 | dbi->dc = dc; | |
f729d8d9 | 1115 | if (mipi_dbi_machine_little_endian() && !spi_is_bpw_supported(spi, 16)) |
36b50572 | 1116 | dbi->swap_bytes = true; |
02dd95fe | 1117 | } else { |
36b50572 NT |
1118 | dbi->command = mipi_dbi_typec1_command; |
1119 | dbi->tx_buf9_len = SZ_16K; | |
1120 | dbi->tx_buf9 = devm_kmalloc(dev, dbi->tx_buf9_len, GFP_KERNEL); | |
1121 | if (!dbi->tx_buf9) | |
02dd95fe NT |
1122 | return -ENOMEM; |
1123 | } | |
1124 | ||
36b50572 | 1125 | mutex_init(&dbi->cmdlock); |
771ea160 | 1126 | |
95a0cfe9 NT |
1127 | DRM_DEBUG_DRIVER("SPI speed: %uMHz\n", spi->max_speed_hz / 1000000); |
1128 | ||
ace98812 | 1129 | return 0; |
02dd95fe NT |
1130 | } |
1131 | EXPORT_SYMBOL(mipi_dbi_spi_init); | |
1132 | ||
d23d4d4d NT |
1133 | /** |
1134 | * mipi_dbi_spi_transfer - SPI transfer helper | |
1135 | * @spi: SPI device | |
1136 | * @speed_hz: Override speed (optional) | |
1137 | * @bpw: Bits per word | |
1138 | * @buf: Buffer to transfer | |
1139 | * @len: Buffer length | |
1140 | * | |
1141 | * This SPI transfer helper breaks up the transfer of @buf into chunks which | |
1142 | * the SPI controller driver can handle. | |
1143 | * | |
1144 | * Returns: | |
1145 | * Zero on success, negative error code on failure. | |
1146 | */ | |
1147 | int mipi_dbi_spi_transfer(struct spi_device *spi, u32 speed_hz, | |
1148 | u8 bpw, const void *buf, size_t len) | |
1149 | { | |
1150 | size_t max_chunk = spi_max_transfer_size(spi); | |
1151 | struct spi_transfer tr = { | |
1152 | .bits_per_word = bpw, | |
1153 | .speed_hz = speed_hz, | |
1154 | }; | |
1155 | struct spi_message m; | |
1156 | size_t chunk; | |
1157 | int ret; | |
1158 | ||
1159 | spi_message_init_with_transfers(&m, &tr, 1); | |
1160 | ||
1161 | while (len) { | |
1162 | chunk = min(len, max_chunk); | |
1163 | ||
1164 | tr.tx_buf = buf; | |
1165 | tr.len = chunk; | |
1166 | buf += chunk; | |
1167 | len -= chunk; | |
1168 | ||
1169 | ret = spi_sync(spi, &m); | |
1170 | if (ret) | |
1171 | return ret; | |
1172 | } | |
1173 | ||
1174 | return 0; | |
1175 | } | |
1176 | EXPORT_SYMBOL(mipi_dbi_spi_transfer); | |
1177 | ||
02dd95fe NT |
1178 | #endif /* CONFIG_SPI */ |
1179 | ||
1180 | #ifdef CONFIG_DEBUG_FS | |
1181 | ||
1182 | static ssize_t mipi_dbi_debugfs_command_write(struct file *file, | |
1183 | const char __user *ubuf, | |
1184 | size_t count, loff_t *ppos) | |
1185 | { | |
1186 | struct seq_file *m = file->private_data; | |
84137b86 | 1187 | struct mipi_dbi_dev *dbidev = m->private; |
b401f343 | 1188 | u8 val, cmd = 0, parameters[64]; |
02dd95fe | 1189 | char *buf, *pos, *token; |
d72cf01f | 1190 | int i, ret, idx; |
9d5645ad | 1191 | |
84137b86 | 1192 | if (!drm_dev_enter(&dbidev->drm, &idx)) |
9d5645ad | 1193 | return -ENODEV; |
02dd95fe NT |
1194 | |
1195 | buf = memdup_user_nul(ubuf, count); | |
9d5645ad NT |
1196 | if (IS_ERR(buf)) { |
1197 | ret = PTR_ERR(buf); | |
1198 | goto err_exit; | |
1199 | } | |
02dd95fe NT |
1200 | |
1201 | /* strip trailing whitespace */ | |
1202 | for (i = count - 1; i > 0; i--) | |
1203 | if (isspace(buf[i])) | |
1204 | buf[i] = '\0'; | |
1205 | else | |
1206 | break; | |
1207 | i = 0; | |
1208 | pos = buf; | |
1209 | while (pos) { | |
1210 | token = strsep(&pos, " "); | |
1211 | if (!token) { | |
1212 | ret = -EINVAL; | |
1213 | goto err_free; | |
1214 | } | |
1215 | ||
1216 | ret = kstrtou8(token, 16, &val); | |
1217 | if (ret < 0) | |
1218 | goto err_free; | |
1219 | ||
1220 | if (token == buf) | |
1221 | cmd = val; | |
1222 | else | |
1223 | parameters[i++] = val; | |
1224 | ||
1225 | if (i == 64) { | |
1226 | ret = -E2BIG; | |
1227 | goto err_free; | |
1228 | } | |
1229 | } | |
1230 | ||
84137b86 | 1231 | ret = mipi_dbi_command_buf(&dbidev->dbi, cmd, parameters, i); |
02dd95fe NT |
1232 | |
1233 | err_free: | |
1234 | kfree(buf); | |
9d5645ad NT |
1235 | err_exit: |
1236 | drm_dev_exit(idx); | |
02dd95fe NT |
1237 | |
1238 | return ret < 0 ? ret : count; | |
1239 | } | |
1240 | ||
1241 | static int mipi_dbi_debugfs_command_show(struct seq_file *m, void *unused) | |
1242 | { | |
84137b86 NT |
1243 | struct mipi_dbi_dev *dbidev = m->private; |
1244 | struct mipi_dbi *dbi = &dbidev->dbi; | |
02dd95fe | 1245 | u8 cmd, val[4]; |
9d5645ad | 1246 | int ret, idx; |
46466b0d | 1247 | size_t len; |
9d5645ad | 1248 | |
84137b86 | 1249 | if (!drm_dev_enter(&dbidev->drm, &idx)) |
9d5645ad | 1250 | return -ENODEV; |
02dd95fe NT |
1251 | |
1252 | for (cmd = 0; cmd < 255; cmd++) { | |
84137b86 | 1253 | if (!mipi_dbi_command_is_read(dbi, cmd)) |
02dd95fe NT |
1254 | continue; |
1255 | ||
1256 | switch (cmd) { | |
1257 | case MIPI_DCS_READ_MEMORY_START: | |
1258 | case MIPI_DCS_READ_MEMORY_CONTINUE: | |
1259 | len = 2; | |
1260 | break; | |
1261 | case MIPI_DCS_GET_DISPLAY_ID: | |
1262 | len = 3; | |
1263 | break; | |
1264 | case MIPI_DCS_GET_DISPLAY_STATUS: | |
1265 | len = 4; | |
1266 | break; | |
1267 | default: | |
1268 | len = 1; | |
1269 | break; | |
1270 | } | |
1271 | ||
1272 | seq_printf(m, "%02x: ", cmd); | |
84137b86 | 1273 | ret = mipi_dbi_command_buf(dbi, cmd, val, len); |
02dd95fe NT |
1274 | if (ret) { |
1275 | seq_puts(m, "XX\n"); | |
1276 | continue; | |
1277 | } | |
46466b0d | 1278 | seq_printf(m, "%*phN\n", (int)len, val); |
02dd95fe NT |
1279 | } |
1280 | ||
9d5645ad NT |
1281 | drm_dev_exit(idx); |
1282 | ||
02dd95fe NT |
1283 | return 0; |
1284 | } | |
1285 | ||
1286 | static int mipi_dbi_debugfs_command_open(struct inode *inode, | |
1287 | struct file *file) | |
1288 | { | |
1289 | return single_open(file, mipi_dbi_debugfs_command_show, | |
1290 | inode->i_private); | |
1291 | } | |
1292 | ||
1293 | static const struct file_operations mipi_dbi_debugfs_command_fops = { | |
1294 | .owner = THIS_MODULE, | |
1295 | .open = mipi_dbi_debugfs_command_open, | |
1296 | .read = seq_read, | |
1297 | .llseek = seq_lseek, | |
1298 | .release = single_release, | |
1299 | .write = mipi_dbi_debugfs_command_write, | |
1300 | }; | |
1301 | ||
02dd95fe NT |
1302 | /** |
1303 | * mipi_dbi_debugfs_init - Create debugfs entries | |
1304 | * @minor: DRM minor | |
1305 | * | |
1306 | * This function creates a 'command' debugfs file for sending commands to the | |
1307 | * controller or getting the read command values. | |
1308 | * Drivers can use this as their &drm_driver->debugfs_init callback. | |
1309 | * | |
1310 | * Returns: | |
1311 | * Zero on success, negative error code on failure. | |
1312 | */ | |
1313 | int mipi_dbi_debugfs_init(struct drm_minor *minor) | |
1314 | { | |
84137b86 | 1315 | struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(minor->dev); |
02dd95fe NT |
1316 | umode_t mode = S_IFREG | S_IWUSR; |
1317 | ||
84137b86 | 1318 | if (dbidev->dbi.read_commands) |
02dd95fe | 1319 | mode |= S_IRUGO; |
84137b86 | 1320 | debugfs_create_file("command", mode, minor->debugfs_root, dbidev, |
02dd95fe NT |
1321 | &mipi_dbi_debugfs_command_fops); |
1322 | ||
beed8313 | 1323 | return 0; |
02dd95fe NT |
1324 | } |
1325 | EXPORT_SYMBOL(mipi_dbi_debugfs_init); | |
1326 | ||
1327 | #endif | |
1328 | ||
1329 | MODULE_LICENSE("GPL"); |