summaryrefslogtreecommitdiffstats
path: root/src/soc/nvidia/tegra210/mipi_dsi.c
diff options
context:
space:
mode:
authorPatrick Georgi <pgeorgi@chromium.org>2015-06-22 19:41:29 +0200
committerPatrick Georgi <pgeorgi@google.com>2015-06-30 21:43:01 +0200
commit40a3e321d4e8f2877de1700db67b8c7f7ea89820 (patch)
treeb8270b2ceb9e290d2e4e9a99868acb9cd335de6f /src/soc/nvidia/tegra210/mipi_dsi.c
parent7f641e68f25c0b79960a97a6b265851c46298aae (diff)
downloadcoreboot-40a3e321d4e8f2877de1700db67b8c7f7ea89820.tar.gz
coreboot-40a3e321d4e8f2877de1700db67b8c7f7ea89820.tar.bz2
coreboot-40a3e321d4e8f2877de1700db67b8c7f7ea89820.zip
nvidia/tegra210: add new SoC
This includes Chrome OS downstream up to Change-Id: Ic89ed54c. Change-Id: I81853434600390d643160fe57554495b2bfe60ab Signed-off-by: Patrick Georgi <pgeorgi@chromium.org> Reviewed-on: http://review.coreboot.org/10633 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Diffstat (limited to 'src/soc/nvidia/tegra210/mipi_dsi.c')
-rw-r--r--src/soc/nvidia/tegra210/mipi_dsi.c431
1 files changed, 431 insertions, 0 deletions
diff --git a/src/soc/nvidia/tegra210/mipi_dsi.c b/src/soc/nvidia/tegra210/mipi_dsi.c
new file mode 100644
index 000000000000..5e4cf55602f7
--- /dev/null
+++ b/src/soc/nvidia/tegra210/mipi_dsi.c
@@ -0,0 +1,431 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+/*
+ * MIPI DSI Bus
+ *
+ * Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd.
+ * Andrzej Hajda <a.hajda@samsung.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <console/console.h>
+#include <arch/io.h>
+#include <stdint.h>
+#include <lib.h>
+#include <stdlib.h>
+#include <delay.h>
+#include <string.h>
+#include <soc/addressmap.h>
+#include <soc/clock.h>
+#include <device/device.h>
+#include <soc/nvidia/tegra/types.h>
+#include <soc/display.h>
+#include <soc/mipi_dsi.h>
+#include <soc/mipi_display.h>
+#include <soc/tegra_dsi.h>
+
+struct mipi_dsi_device mipi_dsi_device_data[NUM_DSI] = {
+ {
+ .master = NULL,
+ .slave = &mipi_dsi_device_data[DSI_B],
+ },
+ {
+ .master = &mipi_dsi_device_data[DSI_A],
+ .slave = NULL,
+ },
+};
+
+static struct mipi_dsi_device *
+mipi_dsi_device_alloc(struct mipi_dsi_host *host)
+{
+ static int index = 0;
+ struct mipi_dsi_device *dsi;
+
+ if (index >= NUM_DSI)
+ return (void *)-EPTR;
+
+ dsi = &mipi_dsi_device_data[index++];
+ dsi->host = host;
+ return dsi;
+}
+
+static struct mipi_dsi_device *
+of_mipi_dsi_device_add(struct mipi_dsi_host *host)
+{
+ struct mipi_dsi_device *dsi;
+ u32 reg = 0;
+
+ dsi = mipi_dsi_device_alloc(host);
+ if (IS_ERR_PTR(dsi)) {
+ printk(BIOS_ERR, "failed to allocate DSI device\n");
+ return dsi;
+ }
+
+ dsi->channel = reg;
+ host->dev = (void *)dsi;
+
+ return dsi;
+}
+
+int mipi_dsi_host_register(struct mipi_dsi_host *host)
+{
+ of_mipi_dsi_device_add(host);
+ return 0;
+}
+
+/**
+ * mipi_dsi_attach - attach a DSI device to its DSI host
+ * @dsi: DSI peripheral
+ */
+int mipi_dsi_attach(struct mipi_dsi_device *dsi)
+{
+ const struct mipi_dsi_host_ops *ops = dsi->host->ops;
+
+ if (!ops || !ops->attach)
+ return -ENOSYS;
+
+ return ops->attach(dsi->host, dsi);
+}
+
+/**
+ * mipi_dsi_detach - detach a DSI device from its DSI host
+ * @dsi: DSI peripheral
+ */
+int mipi_dsi_detach(struct mipi_dsi_device *dsi)
+{
+ const struct mipi_dsi_host_ops *ops = dsi->host->ops;
+
+ if (!ops || !ops->detach)
+ return -ENOSYS;
+
+ return ops->detach(dsi->host, dsi);
+}
+
+/**
+ * mipi_dsi_enslave() - use a MIPI DSI peripheral as slave for dual-channel
+ * operation
+ * @master: master DSI peripheral device
+ * @slave: slave DSI peripheral device
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_enslave(struct mipi_dsi_device *master,
+ struct mipi_dsi_device *slave)
+{
+ int err = 0;
+
+ slave->master = master;
+ master->slave = slave;
+
+ if (master->ops && master->ops->enslave)
+ err = master->ops->enslave(master, slave);
+
+ return err;
+}
+
+/**
+ * mipi_dsi_liberate() - stop using a MIPI DSI peripheral as slave for dual-
+ * channel operation
+ * @master: master DSI peripheral device
+ * @slave: slave DSI peripheral device
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_liberate(struct mipi_dsi_device *master,
+ struct mipi_dsi_device *slave)
+{
+ int err = 0;
+
+ if (master->ops && master->ops->liberate)
+ err = master->ops->liberate(master, slave);
+
+ master->slave = NULL;
+ slave->master = NULL;
+
+ return err;
+}
+
+/**
+ * mipi_dsi_dcs_write() - send DCS write command
+ * @dsi: DSI peripheral device
+ * @cmd: DCS command
+ * @data: buffer containing the command payload
+ * @len: command payload length
+ *
+ * This function will automatically choose the right data type depending on
+ * the command payload length.
+ *
+ * Return: The number of bytes successfully transmitted or a negative error
+ * code on failure.
+ */
+ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd,
+ const void *data, size_t len)
+{
+ struct mipi_dsi_msg msg;
+ ssize_t err;
+ size_t size;
+
+ u8 buffer[MAX_DSI_HOST_FIFO_DEPTH + 4];
+ u8 *tx = buffer;
+
+ if (len > MAX_DSI_HOST_FIFO_DEPTH) {
+ printk(BIOS_ERR, "%s: Error: too large payload length: %zu\n",
+ __func__, len);
+
+ return -EINVAL;
+ }
+
+ if (len > 0) {
+ unsigned int offset = 0;
+
+ /*
+ * DCS long write packets contain the word count in the header
+ * bytes 1 and 2 and have a payload containing the DCS command
+ * byte folowed by word count minus one bytes.
+ *
+ * DCS short write packets encode the DCS command and up to
+ * one parameter in header bytes 1 and 2.
+ */
+ if (len > 1)
+ size = 3 + len;
+ else
+ size = 1 + len;
+
+ /* write word count to header for DCS long write packets */
+ if (len > 1) {
+ tx[offset++] = ((1 + len) >> 0) & 0xff;
+ tx[offset++] = ((1 + len) >> 8) & 0xff;
+ }
+
+ /* write the DCS command byte followed by the payload */
+ tx[offset++] = cmd;
+ memcpy(tx + offset, data, len);
+ } else {
+ tx = &cmd;
+ size = 1;
+ }
+
+ memset(&msg, 0, sizeof(msg));
+ msg.flags = MIPI_DSI_MSG_USE_LPM;
+ msg.channel = dsi->channel;
+ msg.tx_len = size;
+ msg.tx_buf = tx;
+
+ switch (len) {
+ case 0:
+ msg.type = MIPI_DSI_DCS_SHORT_WRITE;
+ break;
+ case 1:
+ msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM;
+ break;
+ default:
+ msg.type = MIPI_DSI_DCS_LONG_WRITE;
+ break;
+ }
+
+ err = dsi->host->ops->transfer(dsi->host, &msg);
+
+ return err;
+}
+
+/**
+ * mipi_dsi_dcs_exit_sleep_mode() - enable all blocks inside the display
+ * module
+ * @dsi: DSI peripheral device
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_exit_sleep_mode(struct mipi_dsi_device *dsi)
+{
+ ssize_t err;
+
+ err = mipi_dsi_dcs_write(dsi, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+/**
+ * mipi_dsi_dcs_set_display_on() - start displaying the image data on the
+ * display device
+ * @dsi: DSI peripheral device
+ *
+ * Return: 0 on success or a negative error code on failure
+ */
+int mipi_dsi_dcs_set_display_on(struct mipi_dsi_device *dsi)
+{
+ ssize_t err;
+
+ err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+/**
+ * mipi_dsi_dcs_set_column_address() - define the column extent of the frame
+ * memory accessed by the host processor
+ * @dsi: DSI peripheral device
+ * @start: first column of frame memory
+ * @end: last column of frame memory
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_set_column_address(struct mipi_dsi_device *dsi, u16 start,
+ u16 end)
+{
+ u8 payload[4] = { start >> 8, start & 0xff, end >> 8, end & 0xff };
+ ssize_t err;
+
+ err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_COLUMN_ADDRESS, payload,
+ sizeof(payload));
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+/**
+ * mipi_dsi_dcs_set_page_address() - define the page extent of the frame
+ * memory accessed by the host processor
+ * @dsi: DSI peripheral device
+ * @start: first page of frame memory
+ * @end: last page of frame memory
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_set_page_address(struct mipi_dsi_device *dsi, u16 start,
+ u16 end)
+{
+ u8 payload[4] = { start >> 8, start & 0xff, end >> 8, end & 0xff };
+ ssize_t err;
+
+ err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PAGE_ADDRESS, payload,
+ sizeof(payload));
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+/**
+ * mipi_dsi_dcs_set_tear_on() - turn on the display module's Tearing Effect
+ * output signal on the TE signal line.
+ * @dsi: DSI peripheral device
+ * @mode: the Tearing Effect Output Line mode
+ *
+ * Return: 0 on success or a negative error code on failure
+ */
+int mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device *dsi,
+ enum mipi_dsi_dcs_tear_mode mode)
+{
+ u8 value = mode;
+ ssize_t err;
+
+ err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_ON, &value,
+ sizeof(value));
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+/**
+ * mipi_dsi_dcs_set_pixel_format() - sets the pixel format for the RGB image
+ * data used by the interface
+ * @dsi: DSI peripheral device
+ * @format: pixel format
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format)
+{
+ ssize_t err;
+
+ err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PIXEL_FORMAT, &format,
+ sizeof(format));
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+/**
+ * mipi_dsi_dcs_set_address_mode() - sets the data order for forward transfers
+ * from the host to the peripheral
+ * @dsi: DSI peripheral device
+ * @reverse_page_address: reverses the page addressing to bottom->top
+ * @reverse_col_address: reverses the column addressing to right->left
+ * @reverse_page_col_address: reverses the page/column addressing order
+ * @refresh_from_bottom: refresh the display bottom to top
+ * @reverse_rgb: send pixel data bgr instead of rgb
+ * @latch_right_to_left: latch the incoming display data right to left
+ * @flip_horizontal: flip the image horizontally, left to right
+ * @flip_vertical: flip the image vertically, top to bottom
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_set_address_mode(struct mipi_dsi_device *dsi,
+ bool reverse_page_address,
+ bool reverse_col_address,
+ bool reverse_page_col_address,
+ bool refresh_from_bottom,
+ bool reverse_rgb,
+ bool latch_right_to_left,
+ bool flip_horizontal,
+ bool flip_vertical)
+{
+ ssize_t err;
+ u8 data;
+
+ data = ((flip_vertical ? 1 : 0) << 0) |
+ ((flip_horizontal ? 1 : 0) << 1) |
+ ((latch_right_to_left ? 1 : 0) << 2) |
+ ((reverse_rgb ? 1 : 0) << 3) |
+ ((refresh_from_bottom ? 1 : 0) << 4) |
+ ((reverse_page_col_address ? 1 : 0) << 5) |
+ ((reverse_col_address ? 1 : 0) << 6) |
+ ((reverse_page_address ? 1 : 0) << 7);
+
+ err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_ADDRESS_MODE, &data, 1);
+ if (err < 0)
+ return err;
+
+ return 0;
+}