diff options
Diffstat (limited to 'src/soc/nvidia/tegra132/dsi.c')
-rw-r--r-- | src/soc/nvidia/tegra132/dsi.c | 960 |
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. - */ -} |