2 * This file is part of the coreboot project.
4 * Copyright 2014 Google Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
18 * Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd.
19 * Andrzej Hajda <a.hajda@samsung.com>
21 * Permission is hereby granted, free of charge, to any person obtaining a
22 * copy of this software and associated documentation files (the
23 * "Software"), to deal in the Software without restriction, including
24 * without limitation the rights to use, copy, modify, merge, publish,
25 * distribute, sub license, and/or sell copies of the Software, and to
26 * permit persons to whom the Software is furnished to do so, subject to
27 * the following conditions:
29 * The above copyright notice and this permission notice (including the
30 * next paragraph) shall be included in all copies or substantial portions
33 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
36 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
37 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
38 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
39 * USE OR OTHER DEALINGS IN THE SOFTWARE.
41 #include <console/console.h>
48 #include <soc/addressmap.h>
49 #include <soc/clock.h>
50 #include <device/device.h>
51 #include <soc/nvidia/tegra/types.h>
52 #include <soc/display.h>
53 #include <soc/mipi_dsi.h>
54 #include <soc/mipi_display.h>
55 #include <soc/tegra_dsi.h>
57 struct mipi_dsi_device mipi_dsi_device_data
[NUM_DSI
] = {
60 .slave
= &mipi_dsi_device_data
[DSI_B
],
63 .master
= &mipi_dsi_device_data
[DSI_A
],
68 static struct mipi_dsi_device
*
69 mipi_dsi_device_alloc(struct mipi_dsi_host
*host
)
72 struct mipi_dsi_device
*dsi
;
77 dsi
= &mipi_dsi_device_data
[index
++];
82 static struct mipi_dsi_device
*
83 of_mipi_dsi_device_add(struct mipi_dsi_host
*host
)
85 struct mipi_dsi_device
*dsi
;
88 dsi
= mipi_dsi_device_alloc(host
);
89 if (IS_ERR_PTR(dsi
)) {
90 printk(BIOS_ERR
, "failed to allocate DSI device\n");
95 host
->dev
= (void *)dsi
;
100 int mipi_dsi_host_register(struct mipi_dsi_host
*host
)
102 of_mipi_dsi_device_add(host
);
107 * mipi_dsi_attach - attach a DSI device to its DSI host
108 * @dsi: DSI peripheral
110 int mipi_dsi_attach(struct mipi_dsi_device
*dsi
)
112 const struct mipi_dsi_host_ops
*ops
= dsi
->host
->ops
;
114 if (!ops
|| !ops
->attach
)
117 return ops
->attach(dsi
->host
, dsi
);
121 * mipi_dsi_detach - detach a DSI device from its DSI host
122 * @dsi: DSI peripheral
124 int mipi_dsi_detach(struct mipi_dsi_device
*dsi
)
126 const struct mipi_dsi_host_ops
*ops
= dsi
->host
->ops
;
128 if (!ops
|| !ops
->detach
)
131 return ops
->detach(dsi
->host
, dsi
);
135 * mipi_dsi_enslave() - use a MIPI DSI peripheral as slave for dual-channel
137 * @master: master DSI peripheral device
138 * @slave: slave DSI peripheral device
140 * Return: 0 on success or a negative error code on failure.
142 int mipi_dsi_enslave(struct mipi_dsi_device
*master
,
143 struct mipi_dsi_device
*slave
)
147 slave
->master
= master
;
148 master
->slave
= slave
;
150 if (master
->ops
&& master
->ops
->enslave
)
151 err
= master
->ops
->enslave(master
, slave
);
157 * mipi_dsi_liberate() - stop using a MIPI DSI peripheral as slave for dual-
159 * @master: master DSI peripheral device
160 * @slave: slave DSI peripheral device
162 * Return: 0 on success or a negative error code on failure.
164 int mipi_dsi_liberate(struct mipi_dsi_device
*master
,
165 struct mipi_dsi_device
*slave
)
169 if (master
->ops
&& master
->ops
->liberate
)
170 err
= master
->ops
->liberate(master
, slave
);
172 master
->slave
= NULL
;
173 slave
->master
= NULL
;
179 * mipi_dsi_dcs_write() - send DCS write command
180 * @dsi: DSI peripheral device
182 * @data: buffer containing the command payload
183 * @len: command payload length
185 * This function will automatically choose the right data type depending on
186 * the command payload length.
188 * Return: The number of bytes successfully transmitted or a negative error
191 ssize_t
mipi_dsi_dcs_write(struct mipi_dsi_device
*dsi
, u8 cmd
,
192 const void *data
, size_t len
)
194 struct mipi_dsi_msg msg
;
198 u8 buffer
[MAX_DSI_HOST_FIFO_DEPTH
+ 4];
201 if (len
> MAX_DSI_HOST_FIFO_DEPTH
) {
202 printk(BIOS_ERR
, "%s: Error: too large payload length: %zu\n",
209 unsigned int offset
= 0;
212 * DCS long write packets contain the word count in the header
213 * bytes 1 and 2 and have a payload containing the DCS command
214 * byte folowed by word count minus one bytes.
216 * DCS short write packets encode the DCS command and up to
217 * one parameter in header bytes 1 and 2.
224 /* write word count to header for DCS long write packets */
226 tx
[offset
++] = ((1 + len
) >> 0) & 0xff;
227 tx
[offset
++] = ((1 + len
) >> 8) & 0xff;
230 /* write the DCS command byte followed by the payload */
232 memcpy(tx
+ offset
, data
, len
);
238 memset(&msg
, 0, sizeof(msg
));
239 msg
.flags
= MIPI_DSI_MSG_USE_LPM
;
240 msg
.channel
= dsi
->channel
;
246 msg
.type
= MIPI_DSI_DCS_SHORT_WRITE
;
249 msg
.type
= MIPI_DSI_DCS_SHORT_WRITE_PARAM
;
252 msg
.type
= MIPI_DSI_DCS_LONG_WRITE
;
256 err
= dsi
->host
->ops
->transfer(dsi
->host
, &msg
);
262 * mipi_dsi_dcs_exit_sleep_mode() - enable all blocks inside the display
264 * @dsi: DSI peripheral device
266 * Return: 0 on success or a negative error code on failure.
268 int mipi_dsi_dcs_exit_sleep_mode(struct mipi_dsi_device
*dsi
)
272 err
= mipi_dsi_dcs_write(dsi
, MIPI_DCS_EXIT_SLEEP_MODE
, NULL
, 0);
280 * mipi_dsi_dcs_set_display_on() - start displaying the image data on the
282 * @dsi: DSI peripheral device
284 * Return: 0 on success or a negative error code on failure
286 int mipi_dsi_dcs_set_display_on(struct mipi_dsi_device
*dsi
)
290 err
= mipi_dsi_dcs_write(dsi
, MIPI_DCS_SET_DISPLAY_ON
, NULL
, 0);
298 * mipi_dsi_dcs_set_column_address() - define the column extent of the frame
299 * memory accessed by the host processor
300 * @dsi: DSI peripheral device
301 * @start: first column of frame memory
302 * @end: last column of frame memory
304 * Return: 0 on success or a negative error code on failure.
306 int mipi_dsi_dcs_set_column_address(struct mipi_dsi_device
*dsi
, u16 start
,
309 u8 payload
[4] = { start
>> 8, start
& 0xff, end
>> 8, end
& 0xff };
312 err
= mipi_dsi_dcs_write(dsi
, MIPI_DCS_SET_COLUMN_ADDRESS
, payload
,
321 * mipi_dsi_dcs_set_page_address() - define the page extent of the frame
322 * memory accessed by the host processor
323 * @dsi: DSI peripheral device
324 * @start: first page of frame memory
325 * @end: last page of frame memory
327 * Return: 0 on success or a negative error code on failure.
329 int mipi_dsi_dcs_set_page_address(struct mipi_dsi_device
*dsi
, u16 start
,
332 u8 payload
[4] = { start
>> 8, start
& 0xff, end
>> 8, end
& 0xff };
335 err
= mipi_dsi_dcs_write(dsi
, MIPI_DCS_SET_PAGE_ADDRESS
, payload
,
344 * mipi_dsi_dcs_set_tear_on() - turn on the display module's Tearing Effect
345 * output signal on the TE signal line.
346 * @dsi: DSI peripheral device
347 * @mode: the Tearing Effect Output Line mode
349 * Return: 0 on success or a negative error code on failure
351 int mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device
*dsi
,
352 enum mipi_dsi_dcs_tear_mode mode
)
357 err
= mipi_dsi_dcs_write(dsi
, MIPI_DCS_SET_TEAR_ON
, &value
,
366 * mipi_dsi_dcs_set_pixel_format() - sets the pixel format for the RGB image
367 * data used by the interface
368 * @dsi: DSI peripheral device
369 * @format: pixel format
371 * Return: 0 on success or a negative error code on failure.
373 int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device
*dsi
, u8 format
)
377 err
= mipi_dsi_dcs_write(dsi
, MIPI_DCS_SET_PIXEL_FORMAT
, &format
,
386 * mipi_dsi_dcs_set_address_mode() - sets the data order for forward transfers
387 * from the host to the peripheral
388 * @dsi: DSI peripheral device
389 * @reverse_page_address: reverses the page addressing to bottom->top
390 * @reverse_col_address: reverses the column addressing to right->left
391 * @reverse_page_col_address: reverses the page/column addressing order
392 * @refresh_from_bottom: refresh the display bottom to top
393 * @reverse_rgb: send pixel data bgr instead of rgb
394 * @latch_right_to_left: latch the incoming display data right to left
395 * @flip_horizontal: flip the image horizontally, left to right
396 * @flip_vertical: flip the image vertically, top to bottom
398 * Return: 0 on success or a negative error code on failure.
400 int mipi_dsi_dcs_set_address_mode(struct mipi_dsi_device
*dsi
,
401 bool reverse_page_address
,
402 bool reverse_col_address
,
403 bool reverse_page_col_address
,
404 bool refresh_from_bottom
,
406 bool latch_right_to_left
,
407 bool flip_horizontal
,
413 data
= ((flip_vertical
? 1 : 0) << 0) |
414 ((flip_horizontal
? 1 : 0) << 1) |
415 ((latch_right_to_left
? 1 : 0) << 2) |
416 ((reverse_rgb
? 1 : 0) << 3) |
417 ((refresh_from_bottom
? 1 : 0) << 4) |
418 ((reverse_page_col_address
? 1 : 0) << 5) |
419 ((reverse_col_address
? 1 : 0) << 6) |
420 ((reverse_page_address
? 1 : 0) << 7);
422 err
= mipi_dsi_dcs_write(dsi
, MIPI_DCS_SET_ADDRESS_MODE
, &data
, 1);