tree: drop last paragraph of GPL copyright header
[coreboot.git] / src / soc / nvidia / tegra210 / mipi_dsi.c
blobbb313f6a3439ebcf12c6d3970bff1cdce1fd1baf
1 /*
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.
16 * MIPI DSI Bus
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
31 * of the Software.
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>
42 #include <arch/io.h>
43 #include <stdint.h>
44 #include <lib.h>
45 #include <stdlib.h>
46 #include <delay.h>
47 #include <string.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] = {
59 .master = NULL,
60 .slave = &mipi_dsi_device_data[DSI_B],
63 .master = &mipi_dsi_device_data[DSI_A],
64 .slave = NULL,
68 static struct mipi_dsi_device *
69 mipi_dsi_device_alloc(struct mipi_dsi_host *host)
71 static int index = 0;
72 struct mipi_dsi_device *dsi;
74 if (index >= NUM_DSI)
75 return (void *)-EPTR;
77 dsi = &mipi_dsi_device_data[index++];
78 dsi->host = host;
79 return dsi;
82 static struct mipi_dsi_device *
83 of_mipi_dsi_device_add(struct mipi_dsi_host *host)
85 struct mipi_dsi_device *dsi;
86 u32 reg = 0;
88 dsi = mipi_dsi_device_alloc(host);
89 if (IS_ERR_PTR(dsi)) {
90 printk(BIOS_ERR, "failed to allocate DSI device\n");
91 return dsi;
94 dsi->channel = reg;
95 host->dev = (void *)dsi;
97 return dsi;
100 int mipi_dsi_host_register(struct mipi_dsi_host *host)
102 of_mipi_dsi_device_add(host);
103 return 0;
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)
115 return -ENOSYS;
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)
129 return -ENOSYS;
131 return ops->detach(dsi->host, dsi);
135 * mipi_dsi_enslave() - use a MIPI DSI peripheral as slave for dual-channel
136 * operation
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)
145 int err = 0;
147 slave->master = master;
148 master->slave = slave;
150 if (master->ops && master->ops->enslave)
151 err = master->ops->enslave(master, slave);
153 return err;
157 * mipi_dsi_liberate() - stop using a MIPI DSI peripheral as slave for dual-
158 * channel operation
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)
167 int err = 0;
169 if (master->ops && master->ops->liberate)
170 err = master->ops->liberate(master, slave);
172 master->slave = NULL;
173 slave->master = NULL;
175 return err;
179 * mipi_dsi_dcs_write() - send DCS write command
180 * @dsi: DSI peripheral device
181 * @cmd: DCS command
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
189 * code on failure.
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;
195 ssize_t err;
196 size_t size;
198 u8 buffer[MAX_DSI_HOST_FIFO_DEPTH + 4];
199 u8 *tx = buffer;
201 if (len > MAX_DSI_HOST_FIFO_DEPTH) {
202 printk(BIOS_ERR, "%s: Error: too large payload length: %zu\n",
203 __func__, len);
205 return -EINVAL;
208 if (len > 0) {
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.
219 if (len > 1)
220 size = 3 + len;
221 else
222 size = 1 + len;
224 /* write word count to header for DCS long write packets */
225 if (len > 1) {
226 tx[offset++] = ((1 + len) >> 0) & 0xff;
227 tx[offset++] = ((1 + len) >> 8) & 0xff;
230 /* write the DCS command byte followed by the payload */
231 tx[offset++] = cmd;
232 memcpy(tx + offset, data, len);
233 } else {
234 tx = &cmd;
235 size = 1;
238 memset(&msg, 0, sizeof(msg));
239 msg.flags = MIPI_DSI_MSG_USE_LPM;
240 msg.channel = dsi->channel;
241 msg.tx_len = size;
242 msg.tx_buf = tx;
244 switch (len) {
245 case 0:
246 msg.type = MIPI_DSI_DCS_SHORT_WRITE;
247 break;
248 case 1:
249 msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM;
250 break;
251 default:
252 msg.type = MIPI_DSI_DCS_LONG_WRITE;
253 break;
256 err = dsi->host->ops->transfer(dsi->host, &msg);
258 return err;
262 * mipi_dsi_dcs_exit_sleep_mode() - enable all blocks inside the display
263 * module
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)
270 ssize_t err;
272 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0);
273 if (err < 0)
274 return err;
276 return 0;
280 * mipi_dsi_dcs_set_display_on() - start displaying the image data on the
281 * display device
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)
288 ssize_t err;
290 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0);
291 if (err < 0)
292 return err;
294 return 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,
307 u16 end)
309 u8 payload[4] = { start >> 8, start & 0xff, end >> 8, end & 0xff };
310 ssize_t err;
312 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_COLUMN_ADDRESS, payload,
313 sizeof(payload));
314 if (err < 0)
315 return err;
317 return 0;
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,
330 u16 end)
332 u8 payload[4] = { start >> 8, start & 0xff, end >> 8, end & 0xff };
333 ssize_t err;
335 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PAGE_ADDRESS, payload,
336 sizeof(payload));
337 if (err < 0)
338 return err;
340 return 0;
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)
354 u8 value = mode;
355 ssize_t err;
357 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_ON, &value,
358 sizeof(value));
359 if (err < 0)
360 return err;
362 return 0;
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)
375 ssize_t err;
377 err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PIXEL_FORMAT, &format,
378 sizeof(format));
379 if (err < 0)
380 return err;
382 return 0;
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,
405 bool reverse_rgb,
406 bool latch_right_to_left,
407 bool flip_horizontal,
408 bool flip_vertical)
410 ssize_t err;
411 u8 data;
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);
423 if (err < 0)
424 return err;
426 return 0;