summaryrefslogtreecommitdiff
path: root/src/soc/nvidia/tegra132/dsi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/nvidia/tegra132/dsi.c')
-rw-r--r--src/soc/nvidia/tegra132/dsi.c960
1 files changed, 0 insertions, 960 deletions
diff --git a/src/soc/nvidia/tegra132/dsi.c b/src/soc/nvidia/tegra132/dsi.c
deleted file mode 100644
index f2a2b3c83c..0000000000
--- a/src/soc/nvidia/tegra132/dsi.c
+++ /dev/null
@@ -1,960 +0,0 @@
-/*
- * 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.
- */
-#include <console/console.h>
-#include <arch/io.h>
-#include <stdint.h>
-#include <lib.h>
-#include <stdlib.h>
-#include <delay.h>
-#include <timer.h>
-#include <soc/addressmap.h>
-#include <soc/clock.h>
-#include <device/device.h>
-#include <edid.h>
-#include <soc/nvidia/tegra/types.h>
-#include <soc/nvidia/tegra/dc.h>
-#include "chip.h"
-#include <soc/display.h>
-#include <soc/mipi_dsi.h>
-#include <soc/mipi_display.h>
-#include <soc/tegra_dsi.h>
-#include <soc/mipi-phy.h>
-#include "jdi_25x18_display/panel-jdi-lpm102a188a.h"
-
-struct tegra_mipi_device mipi_device_data[NUM_DSI];
-
-struct tegra_dsi dsi_data[NUM_DSI] = {
- {
- .regs = (void *)TEGRA_DSIA_BASE,
- .channel = 0,
- .slave = &dsi_data[DSI_B],
- .master = NULL,
- .video_fifo_depth = MAX_DSI_VIDEO_FIFO_DEPTH,
- .host_fifo_depth = MAX_DSI_HOST_FIFO_DEPTH,
- },
- {
- .regs = (void *)TEGRA_DSIB_BASE,
- .channel = 0,
- .slave = NULL,
- .master = &dsi_data[DSI_A],
- .video_fifo_depth = MAX_DSI_VIDEO_FIFO_DEPTH,
- .host_fifo_depth = MAX_DSI_HOST_FIFO_DEPTH,
- },
-};
-
-static inline struct tegra_dsi *host_to_tegra(struct mipi_dsi_host *host)
-{
- return container_of(host, struct tegra_dsi, host);
-}
-
-/*
- * non-burst mode with sync pulses
- */
-static const u32 pkt_seq_video_non_burst_sync_pulses[NUM_PKT_SEQ] = {
- [ 0] = PKT_ID0(MIPI_DSI_V_SYNC_START) | PKT_LEN0(0) |
- PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
- PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
- PKT_LP,
- [ 1] = 0,
- [ 2] = PKT_ID0(MIPI_DSI_V_SYNC_END) | PKT_LEN0(0) |
- PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
- PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
- PKT_LP,
- [ 3] = 0,
- [ 4] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
- PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
- PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
- PKT_LP,
- [ 5] = 0,
- [ 6] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
- PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
- PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0),
- [ 7] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(2) |
- PKT_ID1(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN1(3) |
- PKT_ID2(MIPI_DSI_BLANKING_PACKET) | PKT_LEN2(4),
- [ 8] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
- PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
- PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
- PKT_LP,
- [ 9] = 0,
- [10] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
- PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
- PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0),
- [11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(2) |
- PKT_ID1(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN1(3) |
- PKT_ID2(MIPI_DSI_BLANKING_PACKET) | PKT_LEN2(4),
-};
-
-/*
- * non-burst mode with sync events
- */
-static const u32 pkt_seq_video_non_burst_sync_events[NUM_PKT_SEQ] = {
- [ 0] = PKT_ID0(MIPI_DSI_V_SYNC_START) | PKT_LEN0(0) |
- PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
- PKT_LP,
- [ 1] = 0,
- [ 2] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
- PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
- PKT_LP,
- [ 3] = 0,
- [ 4] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
- PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
- PKT_LP,
- [ 5] = 0,
-
- [ 6] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
- PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(2) |
- PKT_ID2(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN2(3),
-
- [ 7] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4),
- [ 8] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
- PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
- PKT_LP,
- [ 9] = 0,
-
- [10] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
- PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(2) |
- PKT_ID2(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN2(3),
-
- [11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4),
-};
-
-static const u32 pkt_seq_command_mode[NUM_PKT_SEQ] = {
- [ 0] = 0,
- [ 1] = 0,
- [ 2] = 0,
- [ 3] = 0,
- [ 4] = 0,
- [ 5] = 0,
- [ 6] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(3) | PKT_LP,
- [ 7] = 0,
- [ 8] = 0,
- [ 9] = 0,
- [10] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(5) | PKT_LP,
- [11] = 0,
-};
-
-static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi)
-{
- int err;
-
- err = mipi_dphy_set_timing(dsi);
- if (err < 0) {
- printk(BIOS_ERR, "failed to set D-PHY timing: %d\n", err);
- return err;
- }
-
- if (dsi->slave)
- tegra_dsi_set_phy_timing(dsi->slave);
- return 0;
-}
-
-static int tegra_dsi_get_muldiv(enum mipi_dsi_pixel_format format,
- unsigned int *mulp, unsigned int *divp)
-{
- switch (format) {
- case MIPI_DSI_FMT_RGB666_PACKED:
- case MIPI_DSI_FMT_RGB888:
- *mulp = 3;
- *divp = 1;
- break;
-
- case MIPI_DSI_FMT_RGB565:
- *mulp = 2;
- *divp = 1;
- break;
-
- case MIPI_DSI_FMT_RGB666:
- *mulp = 9;
- *divp = 4;
- break;
-
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int tegra_dsi_get_format(enum mipi_dsi_pixel_format format,
- enum tegra_dsi_format *fmt)
-{
- switch (format) {
- case MIPI_DSI_FMT_RGB888:
- *fmt = TEGRA_DSI_FORMAT_24P;
- break;
-
- case MIPI_DSI_FMT_RGB666:
- *fmt = TEGRA_DSI_FORMAT_18NP;
- break;
-
- case MIPI_DSI_FMT_RGB666_PACKED:
- *fmt = TEGRA_DSI_FORMAT_18P;
- break;
-
- case MIPI_DSI_FMT_RGB565:
- *fmt = TEGRA_DSI_FORMAT_16P;
- break;
-
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static void tegra_dsi_ganged_enable(struct tegra_dsi *dsi, unsigned int start,
- unsigned int size)
-{
- u32 value;
-
- tegra_dsi_writel(dsi, start, DSI_GANGED_MODE_START);
- tegra_dsi_writel(dsi, size << 16 | size, DSI_GANGED_MODE_SIZE);
-
- value = DSI_GANGED_MODE_CONTROL_ENABLE;
- tegra_dsi_writel(dsi, value, DSI_GANGED_MODE_CONTROL);
-}
-
-static void tegra_dsi_enable(struct tegra_dsi *dsi)
-{
- u32 value;
-
- value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
- value |= DSI_POWER_CONTROL_ENABLE;
- tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
-
- if (dsi->slave)
- tegra_dsi_enable(dsi->slave);
-}
-
-static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe,
- const struct soc_nvidia_tegra132_config *mode)
-{
- unsigned int hact, hsw, hbp, hfp, i, mul, div;
- enum tegra_dsi_format format;
- const u32 *pkt_seq;
- u32 value;
- int err;
-
- if (dsi->flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
- printk(BIOS_SPEW, "Non-burst video mode with sync pulses\n");
- pkt_seq = pkt_seq_video_non_burst_sync_pulses;
- } else if (dsi->flags & MIPI_DSI_MODE_VIDEO) {
- printk(BIOS_SPEW, "Non-burst video mode with sync events\n");
- pkt_seq = pkt_seq_video_non_burst_sync_events;
- } else {
- printk(BIOS_SPEW, "Command mode\n");
- pkt_seq = pkt_seq_command_mode;
- }
-
- err = tegra_dsi_get_muldiv(dsi->format, &mul, &div);
- if (err < 0)
- return err;
-
- err = tegra_dsi_get_format(dsi->format, &format);
- if (err < 0)
- return err;
-
- value = DSI_CONTROL_CHANNEL(0) | DSI_CONTROL_FORMAT(format) |
- DSI_CONTROL_LANES(dsi->lanes - 1) |
- DSI_CONTROL_SOURCE(pipe);
- tegra_dsi_writel(dsi, value, DSI_CONTROL);
-
- tegra_dsi_writel(dsi, dsi->video_fifo_depth, DSI_MAX_THRESHOLD);
-
- value = DSI_HOST_CONTROL_HS;
- tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
-
- value = tegra_dsi_readl(dsi, DSI_CONTROL);
-
- if (dsi->flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)
- value |= DSI_CONTROL_HS_CLK_CTRL;
-
- value &= ~DSI_CONTROL_TX_TRIG(3);
-
- /* enable DCS commands for command mode */
- if (dsi->flags & MIPI_DSI_MODE_VIDEO)
- value &= ~DSI_CONTROL_DCS_ENABLE;
- else
- value |= DSI_CONTROL_DCS_ENABLE;
-
- value |= DSI_CONTROL_VIDEO_ENABLE;
- value &= ~DSI_CONTROL_HOST_ENABLE;
- tegra_dsi_writel(dsi, value, DSI_CONTROL);
-
- for (i = 0; i < NUM_PKT_SEQ; i++)
- tegra_dsi_writel(dsi, pkt_seq[i], DSI_PKT_SEQ_0_LO + i);
-
- if (dsi->flags & MIPI_DSI_MODE_VIDEO) {
- /* horizontal active pixels */
- hact = mode->xres * mul / div;
-
- /* horizontal sync width */
- hsw = (hsync_end(mode) - hsync_start(mode)) * mul / div;
- hsw -= 10;
-
- /* horizontal back porch */
- hbp = (htotal(mode) - hsync_end(mode)) * mul / div;
- hbp -= 14;
-
- /* horizontal front porch */
- hfp = (hsync_start(mode) - mode->xres) * mul / div;
- hfp -= 8;
-
- tegra_dsi_writel(dsi, hsw << 16 | 0, DSI_PKT_LEN_0_1);
- tegra_dsi_writel(dsi, hact << 16 | hbp, DSI_PKT_LEN_2_3);
- tegra_dsi_writel(dsi, hfp, DSI_PKT_LEN_4_5);
- tegra_dsi_writel(dsi, 0x0f0f << 16, DSI_PKT_LEN_6_7);
-
- /* set SOL delay (for non-burst mode only) */
- tegra_dsi_writel(dsi, 8 * mul / div, DSI_SOL_DELAY);
-
- /* TODO: implement ganged mode */
- } else {
- u16 bytes;
- if (dsi->ganged_mode) {
- /*
- * For ganged mode, assume symmetric left-right mode.
- */
- bytes = 1 + (mode->xres / 2) * mul / div;
- } else {
- /* 1 byte (DCS command) + pixel data */
- bytes = 1 + mode->xres * mul / div;
- }
-
- tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_0_1);
- tegra_dsi_writel(dsi, bytes << 16, DSI_PKT_LEN_2_3);
- tegra_dsi_writel(dsi, bytes << 16, DSI_PKT_LEN_4_5);
- tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_6_7);
-
- value = MIPI_DCS_WRITE_MEMORY_START << 8 |
- MIPI_DCS_WRITE_MEMORY_CONTINUE;
- tegra_dsi_writel(dsi, value, DSI_DCS_CMDS);
-
- /* set SOL delay */
- if (dsi->ganged_mode) {
- unsigned long delay, bclk, bclk_ganged;
- unsigned int lanes = dsi->ganged_lanes;
-
- /* SOL to valid, valid to FIFO and FIFO write delay */
- delay = 4 + 4 + 2;
- delay = DIV_ROUND_UP(delay * mul, div * lanes);
- /* FIFO read delay */
- delay = delay + 6;
-
- bclk = DIV_ROUND_UP(htotal(mode) * mul, div * lanes);
- bclk_ganged = DIV_ROUND_UP(bclk * lanes / 2, lanes);
- value = bclk - bclk_ganged + delay + 20;
- } else {
- /* TODO: revisit for non-ganged mode */
- value = 8 * mul / div;
- }
-
- tegra_dsi_writel(dsi, value, DSI_SOL_DELAY);
- }
-
- if (dsi->slave) {
- err = tegra_dsi_configure(dsi->slave, pipe, mode);
- if (err < 0)
- return err;
-
- /*
- * enable ganged mode
- */
- if (dsi->ganged_mode) {
- tegra_dsi_ganged_enable(dsi, mode->xres / 2,
- mode->xres / 2);
- tegra_dsi_ganged_enable(dsi->slave, 0, mode->xres / 2);
- }
- }
- return 0;
-}
-
-static int tegra_output_dsi_enable(struct tegra_dsi *dsi,
- const struct soc_nvidia_tegra132_config *config)
-{
- int err;
-
- if (dsi->enabled)
- return 0;
-
- err = tegra_dsi_configure(dsi, 0, config);
- if (err < 0)
- return err;
-
- /* enable DSI controller */
- tegra_dsi_enable(dsi);
-
- dsi->enabled = true;
- return 0;
-}
-
-
-static void tegra_dsi_set_timeout(struct tegra_dsi *dsi, unsigned long bclk,
- unsigned int vrefresh)
-{
- unsigned int timeout;
- u32 value;
-
- /* one frame high-speed transmission timeout */
- timeout = (bclk / vrefresh) / 512;
- value = DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(timeout);
- tegra_dsi_writel(dsi, value, DSI_TIMEOUT_0);
-
- /* 2 ms peripheral timeout for panel */
- timeout = 2 * bclk / 512 * 1000;
- value = DSI_TIMEOUT_PR(timeout) | DSI_TIMEOUT_TA(0x2000);
- tegra_dsi_writel(dsi, value, DSI_TIMEOUT_1);
-
- value = DSI_TALLY_TA(0) | DSI_TALLY_LRX(0) | DSI_TALLY_HTX(0);
- tegra_dsi_writel(dsi, value, DSI_TO_TALLY);
-
- if (dsi->slave)
- tegra_dsi_set_timeout(dsi->slave, bclk, vrefresh);
-}
-
-static int tegra_output_dsi_setup_clock(struct tegra_dsi *dsi,
- const struct soc_nvidia_tegra132_config *config)
-{
- unsigned int mul, div, num_lanes;
- unsigned long bclk;
- unsigned long pclk = config->pixel_clock;
- int plld;
- int err;
- struct display_controller *disp_ctrl =
- (void *)config->display_controller;
- unsigned int shift_clk_div;
-
- err = tegra_dsi_get_muldiv(dsi->format, &mul, &div);
- if (err < 0)
- return err;
-
- /*
- * In ganged mode, account for the total number of lanes across both
- * DSI channels so that the bit clock is properly computed.
- */
- if (dsi->ganged_mode)
- num_lanes = dsi->ganged_lanes;
- else
- num_lanes = dsi->lanes;
-
- /* compute byte clock */
- bclk = (pclk * mul) / (div * num_lanes);
-
- /*
- * Compute bit clock and round up to the next MHz.
- */
- plld = DIV_ROUND_UP(bclk * 8, USECS_PER_SEC) * USECS_PER_SEC;
-
- /*
- * the actual rate on PLLD_OUT0 is 1/2 plld
- */
- dsi->clk_rate = plld / 2;
- if (dsi->slave)
- dsi->slave->clk_rate = dsi->clk_rate;
-
- /* set up plld */
- plld = clock_configure_plld(plld);
- if (plld == 0) {
- printk(BIOS_ERR, "%s: clock init failed\n", __func__);
- return -1;
- }
-
- /*
- * Derive pixel clock from bit clock using the shift clock divider.
- * Note that this is only half of what we would expect, but we need
- * that to make up for the fact that we divided the bit clock by a
- * factor of two above.
- */
- shift_clk_div = ((8 * mul) / (div * num_lanes)) - 2;
- update_display_shift_clock_divider(disp_ctrl, shift_clk_div);
-
- tegra_dsi_set_timeout(dsi, bclk, config->refresh);
- return plld/1000000;
-}
-
-
-
-static int tegra_dsi_pad_enable(struct tegra_dsi *dsi)
-{
- unsigned long value;
-
- value = DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0);
- tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0);
- return 0;
-}
-
-static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi)
-{
- u32 value;
-
- tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0);
- tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1);
- tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2);
- tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3);
- tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4);
-
- /* start calibration */
- tegra_dsi_pad_enable(dsi);
-
- value = DSI_PAD_SLEW_UP(0x7) | DSI_PAD_SLEW_DN(0x7) |
- DSI_PAD_LP_UP(0x1) | DSI_PAD_LP_DN(0x1) |
- DSI_PAD_OUT_CLK(0x0);
- tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2);
-
- return tegra_mipi_calibrate(dsi->mipi);
-}
-
-static const char * const error_report[16] = {
- "SoT Error",
- "SoT Sync Error",
- "EoT Sync Error",
- "Escape Mode Entry Command Error",
- "Low-Power Transmit Sync Error",
- "Peripheral Timeout Error",
- "False Control Error",
- "Contention Detected",
- "ECC Error, single-bit",
- "ECC Error, multi-bit",
- "Checksum Error",
- "DSI Data Type Not Recognized",
- "DSI VC ID Invalid",
- "Invalid Transmission Length",
- "Reserved",
- "DSI Protocol Violation",
-};
-
-static int tegra_dsi_read_response(struct tegra_dsi *dsi,
- const struct mipi_dsi_msg *msg,
- unsigned int count)
-{
- u8 *rx = msg->rx_buf;
- unsigned int i, j, k;
- size_t size = 0;
- u16 errors;
- u32 value;
-
- /* read and parse packet header */
- value = tegra_dsi_readl(dsi, DSI_RD_DATA);
-
- switch (value & 0x3f) {
- case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
- errors = (value >> 8) & 0xffff;
- printk(BIOS_ERR, "Acknowledge and error report: %04x\n",
- errors);
- for (i = 0; i < ARRAY_SIZE(error_report); i++)
- if (errors & BIT(i))
- printk(BIOS_INFO, " %2u: %s\n", i,
- error_report[i]);
- break;
-
- case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
- rx[0] = (value >> 8) & 0xff;
- break;
-
- case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
- rx[0] = (value >> 8) & 0xff;
- rx[1] = (value >> 16) & 0xff;
- break;
-
- case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE:
- size = ((value >> 8) & 0xff00) | ((value >> 8) & 0xff);
- break;
-
- case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE:
- size = ((value >> 8) & 0xff00) | ((value >> 8) & 0xff);
- break;
-
- default:
- printk(BIOS_ERR, "unhandled response type: %02x\n",
- value & 0x3f);
- break;
- }
-
- size = MIN(size, msg->rx_len);
-
- if (msg->rx_buf && size > 0) {
- for (i = 0, j = 0; i < count - 1; i++, j += 4) {
- value = tegra_dsi_readl(dsi, DSI_RD_DATA);
-
- for (k = 0; k < 4 && (j + k) < msg->rx_len; k++)
- rx[j + k] = (value >> (k << 3)) & 0xff;
- }
- }
- return 0;
-}
-
-static int tegra_dsi_transmit(struct tegra_dsi *dsi, unsigned long timeout_ms)
-{
- u32 poll_interval_us = 2000;
- u32 timeout_us = timeout_ms * 1000;
-
- tegra_dsi_writel(dsi, DSI_TRIGGER_HOST, DSI_TRIGGER);
- udelay(poll_interval_us);
-
- do {
- u32 value = tegra_dsi_readl(dsi, DSI_TRIGGER);
- if ((value & DSI_TRIGGER_HOST) == 0)
- return 0;
-
- //usleep_range(1000, 2000);
- if (timeout_us > poll_interval_us)
- timeout_us -= poll_interval_us;
- else
- break;
-
- udelay(poll_interval_us);
- } while (1);
-
- printk(BIOS_ERR, "%s: ERROR: timeout waiting for transmission"
- " to complete\n", __func__);
- return -ETIMEDOUT;
-}
-
-static int tegra_dsi_wait_for_response(struct tegra_dsi *dsi,
- unsigned long timeout_ms)
-{
- u32 poll_interval_us = 2000;
- u32 timeout_us = timeout_ms * 1000;
-
- do {
- u32 value = tegra_dsi_readl(dsi, DSI_STATUS);
- u8 count = value & 0x1f;
-
- if (count > 0)
- return count;
-
- if (timeout_us > poll_interval_us)
- timeout_us -= poll_interval_us;
- else
- break;
-
- udelay(poll_interval_us);
- } while (1);
-
- printk(BIOS_ERR, "%s: ERROR: timeout\n", __func__);
-
- return -ETIMEDOUT;
-}
-
-static ssize_t tegra_dsi_host_transfer(struct mipi_dsi_host *host,
- const struct mipi_dsi_msg *msg)
-{
- struct tegra_dsi *dsi = host_to_tegra(host);
- const u8 *tx = msg->tx_buf;
- unsigned int count, i, j;
- u32 value;
- int err;
-
- if (msg->tx_len > dsi->video_fifo_depth * 4)
- return -ENOSPC;
-
- /* reset underflow/overflow flags */
- value = tegra_dsi_readl(dsi, DSI_STATUS);
- if (value & (DSI_STATUS_UNDERFLOW | DSI_STATUS_OVERFLOW)) {
- value = DSI_HOST_CONTROL_FIFO_RESET;
- tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
- udelay(20); // usleep_range(10, 20);
- }
-
- value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
- value |= DSI_POWER_CONTROL_ENABLE;
- tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
-
- udelay(7000); //usleep_range(5000, 10000);
-
- value = DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST |
- DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC;
-
- if ((msg->flags & MIPI_DSI_MSG_USE_LPM) == 0)
- value |= DSI_HOST_CONTROL_HS;
-
- /*
- * The host FIFO has a maximum of 64 words, so larger transmissions
- * need to use the video FIFO.
- */
- if (msg->tx_len > dsi->host_fifo_depth * 4)
- value |= DSI_HOST_CONTROL_FIFO_SEL;
-
- tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
-
- /*
- * For reads and messages with explicitly requested ACK, generate a
- * BTA sequence after the transmission of the packet.
- */
- if ((msg->flags & MIPI_DSI_MSG_REQ_ACK) ||
- (msg->rx_buf && msg->rx_len > 0)) {
- value = tegra_dsi_readl(dsi, DSI_HOST_CONTROL);
- value |= DSI_HOST_CONTROL_PKT_BTA;
- tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
- }
-
- value = DSI_CONTROL_LANES(0) | DSI_CONTROL_HOST_ENABLE;
- tegra_dsi_writel(dsi, value, DSI_CONTROL);
-
- /* write packet header */
- value = ((msg->channel & 0x3) << 6) | (msg->type & 0x3f);
-
- if (tx && msg->tx_len > 0)
- value |= tx[0] << 8;
-
- if (tx && msg->tx_len > 1)
- value |= tx[1] << 16;
-
- tegra_dsi_writel(dsi, value, DSI_WR_DATA);
-
- /* write payload (if any) */
- if (msg->tx_len > 2) {
- for (j = 2; j < msg->tx_len; j += 4) {
- value = 0;
-
- for (i = 0; i < 4 && j + i < msg->tx_len; i++)
- value |= tx[j + i] << (i << 3);
-
- tegra_dsi_writel(dsi, value, DSI_WR_DATA);
- }
- }
-
- err = tegra_dsi_transmit(dsi, 250);
- if (err < 0)
- return err;
-
- if ((msg->flags & MIPI_DSI_MSG_REQ_ACK) ||
- (msg->rx_buf && msg->rx_len > 0)) {
- err = tegra_dsi_wait_for_response(dsi, 250);
- if (err < 0)
- return err;
-
- count = err;
-
- value = tegra_dsi_readl(dsi, DSI_RD_DATA);
- switch (value) {
- case 0x84:
- /*
- dev_dbg(dsi->dev, "ACK\n");
- */
- break;
-
- case 0x87:
- /*
- dev_dbg(dsi->dev, "ESCAPE\n");
- */
- break;
-
- default:
- printk(BIOS_INFO, "unknown status: %08x\n", value);
- break;
- }
-
- if (count > 1) {
- err = tegra_dsi_read_response(dsi, msg, count);
- if (err < 0)
- printk(BIOS_INFO,
- "failed to parse response: %d\n",
- err);
- }
- }
- return 0;
-}
-
-static int tegra_dsi_ganged_setup(struct tegra_dsi *dsi,
- struct tegra_dsi *slave)
-{
- /*
- * The number of ganged lanes is the sum of lanes of all peripherals
- * in the gang.
- */
- dsi->slave->ganged_lanes = dsi->lanes + dsi->slave->lanes;
- dsi->slave->ganged_mode = 1;
-
- dsi->ganged_lanes = dsi->lanes + dsi->slave->lanes;
- dsi->ganged_mode = 1;
- return 0;
-}
-
-static int tegra_dsi_host_attach(struct mipi_dsi_host *host,
- struct mipi_dsi_device *device)
-{
- struct tegra_dsi *dsi = host_to_tegra(host);
- int err;
-
- dsi->flags = device->mode_flags;
- dsi->format = device->format;
- dsi->lanes = device->lanes;
-
- if (dsi->master) {
- err = tegra_dsi_ganged_setup(dsi->master, dsi);
- if (err < 0) {
- printk(BIOS_ERR, "failed to set up ganged mode: %d\n",
- err);
- return err;
- }
- }
- return 0;
-}
-
-static const struct mipi_dsi_host_ops tegra_dsi_host_ops = {
- .attach = tegra_dsi_host_attach,
- .transfer = tegra_dsi_host_transfer,
-};
-
-static int dsi_probe_if(int dsi_index,
- struct soc_nvidia_tegra132_config *config)
-{
- struct tegra_dsi *dsi = &dsi_data[dsi_index];
- int err;
-
- /*
- * Set default value. Will be taken from attached device once detected
- */
- dsi->flags = 0;
- dsi->format = MIPI_DSI_FMT_RGB888;
- dsi->lanes = 4;
-
- /* get tegra_mipi_device */
- dsi->mipi = tegra_mipi_request(&mipi_device_data[dsi_index], dsi_index);
-
- /* calibrate */
- err = tegra_dsi_pad_calibrate(dsi);
- if (err < 0) {
- printk(BIOS_ERR, "MIPI calibration failed: %d\n", err);
- return err;
- }
-
- dsi->host.ops = &tegra_dsi_host_ops;
- err = mipi_dsi_host_register(&dsi->host);
- if (err < 0) {
- printk(BIOS_ERR, "failed to register DSI host: %d\n", err);
- return err;
- }
-
- /* get panel */
- dsi->panel = panel_jdi_dsi_probe((struct mipi_dsi_device *)dsi->host.dev);
- if (IS_ERR_PTR(dsi->panel)) {
- printk(BIOS_ERR, "failed to get dsi panel\n");
- return -EPTR;
- }
- dsi->panel->mode = config;
- return 0;
-}
-
-static int dsi_probe(struct soc_nvidia_tegra132_config *config)
-{
- dsi_probe_if(DSI_A, config);
- dsi_probe_if(DSI_B, config);
- return 0;
-}
-
-static int dsi_enable(struct soc_nvidia_tegra132_config *config)
-{
- struct tegra_dsi *dsi_a = &dsi_data[DSI_A];
-
- dsi_probe(config);
-
- /* set up clock and TimeOutRegisters */
- tegra_output_dsi_setup_clock(dsi_a, config);
-
- /* configure APB_MISC_GP_MIPI_PAD_CTRL_0 */
- write32((unsigned int *)APB_MISC_GP_MIPI_PAD_CTRL_0, DSIB_MODE_DSI);
-
- /* configure phy interface timing registers */
- tegra_dsi_set_phy_timing(dsi_a);
-
- /* prepare panel */
- panel_jdi_prepare(dsi_a->panel);
-
- /* enable dsi */
- if (tegra_output_dsi_enable(dsi_a, config)) {
- printk(BIOS_ERR,"%s: Error: failed to enable dsi output.\n",
- __func__);
- return -1;
- }
-
- return 0;
-}
-
-void dsi_display_startup(device_t dev)
-{
- struct soc_nvidia_tegra132_config *config = dev->chip_info;
- struct display_controller *disp_ctrl =
- (void *)config->display_controller;
- u32 plld_rate;
-
- u32 framebuffer_size_mb = config->framebuffer_size / MiB;
- u32 framebuffer_base_mb= config->framebuffer_base / MiB;
-
- printk(BIOS_INFO, "%s: entry: disp_ctrl: %p.\n",
- __func__, disp_ctrl);
-
- if (disp_ctrl == NULL) {
- printk(BIOS_ERR, "Error: No dc is assigned by dt.\n");
- return;
- }
-
- if (framebuffer_size_mb == 0){
- framebuffer_size_mb = ALIGN_UP(config->display_xres *
- config->display_yres *
- (config->framebuffer_bits_per_pixel / 8), MiB)/MiB;
- }
-
- config->framebuffer_size = framebuffer_size_mb * MiB;
- config->framebuffer_base = framebuffer_base_mb * MiB;
-
- /*
- * The plld is programmed with the assumption of the SHIFT_CLK_DIVIDER
- * and PIXEL_CLK_DIVIDER are zero (divide by 1). See the
- * update_display_mode() for detail.
- */
- /* set default plld */
- plld_rate = clock_configure_plld(config->pixel_clock * 2);
- if (plld_rate == 0) {
- printk(BIOS_ERR, "dc: clock init failed\n");
- return;
- }
-
- /* set disp1's clock source to PLLD_OUT0 */
- clock_configure_source(disp1, PLLD, (plld_rate/KHz)/2);
-
- /* Init dc */
- if (tegra_dc_init(disp_ctrl)) {
- printk(BIOS_ERR, "dc: init failed\n");
- return;
- }
-
- /* Configure dc mode */
- if (update_display_mode(disp_ctrl, config)) {
- printk(BIOS_ERR, "dc: failed to configure display mode.\n");
- return;
- }
-
- /* Configure and enable dsi controller and panel */
- if (dsi_enable(config)) {
- printk(BIOS_ERR, "%s: failed to enable dsi controllers.\n",
- __func__);
- return;
- }
-
- /* Set up window */
- update_window(config);
- printk(BIOS_INFO, "%s: display init done.\n", __func__);
-
- /* Save panel information to cb tables */
- pass_mode_info_to_payload(config);
-
- /*
- * After this point, it is payload's responsibility to allocate
- * framebuffer and sets the base address to dc's
- * WINBUF_START_ADDR register and enables window by setting dc's
- * DISP_DISP_WIN_OPTIONS register.
- */
-}