From 40a3e321d4e8f2877de1700db67b8c7f7ea89820 Mon Sep 17 00:00:00 2001 From: Patrick Georgi Date: Mon, 22 Jun 2015 19:41:29 +0200 Subject: nvidia/tegra210: add new SoC This includes Chrome OS downstream up to Change-Id: Ic89ed54c. Change-Id: I81853434600390d643160fe57554495b2bfe60ab Signed-off-by: Patrick Georgi Reviewed-on: http://review.coreboot.org/10633 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer --- src/soc/nvidia/tegra210/mipi_dsi.c | 431 +++++++++++++++++++++++++++++++++++++ 1 file changed, 431 insertions(+) create mode 100644 src/soc/nvidia/tegra210/mipi_dsi.c (limited to 'src/soc/nvidia/tegra210/mipi_dsi.c') diff --git a/src/soc/nvidia/tegra210/mipi_dsi.c b/src/soc/nvidia/tegra210/mipi_dsi.c new file mode 100644 index 0000000000..5e4cf55602 --- /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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; +} -- cgit v1.2.3