From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933095AbeCMN5g (ORCPT ); Tue, 13 Mar 2018 09:57:36 -0400 Received: from mx07-00178001.pphosted.com ([62.209.51.94]:37405 "EHLO mx07-00178001.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752871AbeCMNuv (ORCPT ); Tue, 13 Mar 2018 09:50:51 -0400 From: yannick fertre To: Vikas Manocha , Tom Rini , Benjamin Gaignard , Yannick Fertre , Philippe Cornu , "Patrice Chotard" , Patrick DELAUNAY , Christophe KERELLO , Archit Taneja , Andrzej Hajda , "Laurent Pinchart" , David Airlie , Brian Norris , Bhumika Goyal , Gustavo Padovan , "Maarten Lankhorst" , Sean Paul , Albert Aribaud , "Simon Glass" , Anatolij Gustschin , Thierry Reding CC: , , Subject: [PATCH v3 05/10] video: add MIPI DSI host controller bridge Date: Tue, 13 Mar 2018 14:50:08 +0100 Message-ID: <1520949014-21468-10-git-send-email-yannick.fertre@st.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1520949014-21468-1-git-send-email-yannick.fertre@st.com> References: <1520949014-21468-1-git-send-email-yannick.fertre@st.com> MIME-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 8bit X-Originating-IP: [10.201.23.68] X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:,, definitions=2018-03-13_07:,, signatures=0 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add a Synopsys Designware MIPI DSI host bridge driver, based on the Rockchip version from rockchip/dw-mipi-dsi.c with phy & bridge APIs. Signed-off-by: yannick fertre --- drivers/video/Kconfig | 9 + drivers/video/Makefile | 1 + drivers/video/dw_mipi_dsi.c | 822 ++++++++++++++++++++++++++++++++++++++++++++ include/dw_mipi_dsi.h | 34 ++ 4 files changed, 866 insertions(+) create mode 100644 drivers/video/dw_mipi_dsi.c create mode 100644 include/dw_mipi_dsi.h diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index b5fc535..0f641d7 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -657,6 +657,15 @@ config VIDEO_DW_HDMI rather requires a SoC-specific glue driver to call it), it can not be enabled from the configuration menu. +config VIDEO_DW_MIPI_DSI + bool + help + Enables the common driver code for the Designware MIPI DSI + block found in SoCs from various vendors. + As this does not provide any functionality by itself (but + rather requires a SoC-specific glue driver to call it), it + can not be enabled from the configuration menu. + config VIDEO_SIMPLE bool "Simple display driver for preconfigured display" help diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 65002af..50be569 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_FORMIKE) += formike.o obj-$(CONFIG_LG4573) += lg4573.o obj-$(CONFIG_AM335X_LCD) += am335x-fb.o obj-$(CONFIG_VIDEO_DW_HDMI) += dw_hdmi.o +obj-$(CONFIG_VIDEO_DW_MIPI_DSI) += dw_mipi_dsi.o obj-${CONFIG_VIDEO_MIPI_DSI} += mipi_display.o obj-$(CONFIG_VIDEO_SIMPLE) += simplefb.o obj-${CONFIG_VIDEO_TEGRA124} += tegra124/ diff --git a/drivers/video/dw_mipi_dsi.c b/drivers/video/dw_mipi_dsi.c new file mode 100644 index 0000000..d7bd92d --- /dev/null +++ b/drivers/video/dw_mipi_dsi.c @@ -0,0 +1,822 @@ +/* + * Copyright (C) 2016, Fuzhou Rockchip Electronics Co., Ltd + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * Author(s): Philippe Cornu for STMicroelectronics. + * Yannick Fertre for STMicroelectronics. + * + * Modified by Yannick Fertre + * This generic Synopsys DesignWare MIPI DSI host driver is based on the + * bridge synopsys from drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c (kernel + * linux). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HWVER_131 0x31333100 /* IP version 1.31 */ + +#define DSI_VERSION 0x00 +#define VERSION GENMASK(31, 8) + +#define DSI_PWR_UP 0x04 +#define RESET 0 +#define POWERUP BIT(0) + +#define DSI_CLKMGR_CFG 0x08 +#define TO_CLK_DIVISION(div) (((div) & 0xff) << 8) +#define TX_ESC_CLK_DIVISION(div) ((div) & 0xff) + +#define DSI_DPI_VCID 0x0c +#define DPI_VCID(vcid) ((vcid) & 0x3) + +#define DSI_DPI_COLOR_CODING 0x10 +#define LOOSELY18_EN BIT(8) +#define DPI_COLOR_CODING_16BIT_1 0x0 +#define DPI_COLOR_CODING_16BIT_2 0x1 +#define DPI_COLOR_CODING_16BIT_3 0x2 +#define DPI_COLOR_CODING_18BIT_1 0x3 +#define DPI_COLOR_CODING_18BIT_2 0x4 +#define DPI_COLOR_CODING_24BIT 0x5 + +#define DSI_DPI_CFG_POL 0x14 +#define COLORM_ACTIVE_LOW BIT(4) +#define SHUTD_ACTIVE_LOW BIT(3) +#define HSYNC_ACTIVE_LOW BIT(2) +#define VSYNC_ACTIVE_LOW BIT(1) +#define DATAEN_ACTIVE_LOW BIT(0) + +#define DSI_DPI_LP_CMD_TIM 0x18 +#define OUTVACT_LPCMD_TIME(p) (((p) & 0xff) << 16) +#define INVACT_LPCMD_TIME(p) ((p) & 0xff) + +#define DSI_DBI_VCID 0x1c +#define DSI_DBI_CFG 0x20 +#define DSI_DBI_PARTITIONING_EN 0x24 +#define DSI_DBI_CMDSIZE 0x28 + +#define DSI_PCKHDL_CFG 0x2c +#define CRC_RX_EN BIT(4) +#define ECC_RX_EN BIT(3) +#define BTA_EN BIT(2) +#define EOTP_RX_EN BIT(1) +#define EOTP_TX_EN BIT(0) + +#define DSI_GEN_VCID 0x30 + +#define DSI_MODE_CFG 0x34 +#define ENABLE_VIDEO_MODE 0 +#define ENABLE_CMD_MODE BIT(0) + +#define DSI_VID_MODE_CFG 0x38 +#define ENABLE_LOW_POWER (0x3f << 8) +#define ENABLE_LOW_POWER_MASK (0x3f << 8) +#define VID_MODE_TYPE_NON_BURST_SYNC_PULSES 0x0 +#define VID_MODE_TYPE_NON_BURST_SYNC_EVENTS 0x1 +#define VID_MODE_TYPE_BURST 0x2 +#define VID_MODE_TYPE_MASK 0x3 + +#define DSI_VID_PKT_SIZE 0x3c +#define VID_PKT_SIZE(p) ((p) & 0x3fff) + +#define DSI_VID_NUM_CHUNKS 0x40 +#define VID_NUM_CHUNKS(c) ((c) & 0x1fff) + +#define DSI_VID_NULL_SIZE 0x44 +#define VID_NULL_SIZE(b) ((b) & 0x1fff) + +#define DSI_VID_HSA_TIME 0x48 +#define DSI_VID_HBP_TIME 0x4c +#define DSI_VID_HLINE_TIME 0x50 +#define DSI_VID_VSA_LINES 0x54 +#define DSI_VID_VBP_LINES 0x58 +#define DSI_VID_VFP_LINES 0x5c +#define DSI_VID_VACTIVE_LINES 0x60 +#define DSI_EDPI_CMD_SIZE 0x64 + +#define DSI_CMD_MODE_CFG 0x68 +#define MAX_RD_PKT_SIZE_LP BIT(24) +#define DCS_LW_TX_LP BIT(19) +#define DCS_SR_0P_TX_LP BIT(18) +#define DCS_SW_1P_TX_LP BIT(17) +#define DCS_SW_0P_TX_LP BIT(16) +#define GEN_LW_TX_LP BIT(14) +#define GEN_SR_2P_TX_LP BIT(13) +#define GEN_SR_1P_TX_LP BIT(12) +#define GEN_SR_0P_TX_LP BIT(11) +#define GEN_SW_2P_TX_LP BIT(10) +#define GEN_SW_1P_TX_LP BIT(9) +#define GEN_SW_0P_TX_LP BIT(8) +#define ACK_RQST_EN BIT(1) +#define TEAR_FX_EN BIT(0) + +#define CMD_MODE_ALL_LP (MAX_RD_PKT_SIZE_LP | \ + DCS_LW_TX_LP | \ + DCS_SR_0P_TX_LP | \ + DCS_SW_1P_TX_LP | \ + DCS_SW_0P_TX_LP | \ + GEN_LW_TX_LP | \ + GEN_SR_2P_TX_LP | \ + GEN_SR_1P_TX_LP | \ + GEN_SR_0P_TX_LP | \ + GEN_SW_2P_TX_LP | \ + GEN_SW_1P_TX_LP | \ + GEN_SW_0P_TX_LP) + +#define DSI_GEN_HDR 0x6c +#define DSI_GEN_PLD_DATA 0x70 + +#define DSI_CMD_PKT_STATUS 0x74 +#define GEN_RD_CMD_BUSY BIT(6) +#define GEN_PLD_R_FULL BIT(5) +#define GEN_PLD_R_EMPTY BIT(4) +#define GEN_PLD_W_FULL BIT(3) +#define GEN_PLD_W_EMPTY BIT(2) +#define GEN_CMD_FULL BIT(1) +#define GEN_CMD_EMPTY BIT(0) + +#define DSI_TO_CNT_CFG 0x78 +#define HSTX_TO_CNT(p) (((p) & 0xffff) << 16) +#define LPRX_TO_CNT(p) ((p) & 0xffff) + +#define DSI_HS_RD_TO_CNT 0x7c +#define DSI_LP_RD_TO_CNT 0x80 +#define DSI_HS_WR_TO_CNT 0x84 +#define DSI_LP_WR_TO_CNT 0x88 +#define DSI_BTA_TO_CNT 0x8c + +#define DSI_LPCLK_CTRL 0x94 +#define AUTO_CLKLANE_CTRL BIT(1) +#define PHY_TXREQUESTCLKHS BIT(0) + +#define DSI_PHY_TMR_LPCLK_CFG 0x98 +#define PHY_CLKHS2LP_TIME(lbcc) (((lbcc) & 0x3ff) << 16) +#define PHY_CLKLP2HS_TIME(lbcc) ((lbcc) & 0x3ff) + +#define DSI_PHY_TMR_CFG 0x9c +#define PHY_HS2LP_TIME(lbcc) (((lbcc) & 0xff) << 24) +#define PHY_LP2HS_TIME(lbcc) (((lbcc) & 0xff) << 16) +#define MAX_RD_TIME(lbcc) ((lbcc) & 0x7fff) +#define PHY_HS2LP_TIME_V131(lbcc) (((lbcc) & 0x3ff) << 16) +#define PHY_LP2HS_TIME_V131(lbcc) ((lbcc) & 0x3ff) + +#define DSI_PHY_RSTZ 0xa0 +#define PHY_DISFORCEPLL 0 +#define PHY_ENFORCEPLL BIT(3) +#define PHY_DISABLECLK 0 +#define PHY_ENABLECLK BIT(2) +#define PHY_RSTZ 0 +#define PHY_UNRSTZ BIT(1) +#define PHY_SHUTDOWNZ 0 +#define PHY_UNSHUTDOWNZ BIT(0) + +#define DSI_PHY_IF_CFG 0xa4 +#define PHY_STOP_WAIT_TIME(cycle) (((cycle) & 0xff) << 8) +#define N_LANES(n) (((n) - 1) & 0x3) + +#define DSI_PHY_ULPS_CTRL 0xa8 +#define DSI_PHY_TX_TRIGGERS 0xac + +#define DSI_PHY_STATUS 0xb0 +#define PHY_STOP_STATE_CLK_LANE BIT(2) +#define PHY_LOCK BIT(0) + +#define DSI_PHY_TST_CTRL0 0xb4 +#define PHY_TESTCLK BIT(1) +#define PHY_UNTESTCLK 0 +#define PHY_TESTCLR BIT(0) +#define PHY_UNTESTCLR 0 + +#define DSI_PHY_TST_CTRL1 0xb8 +#define PHY_TESTEN BIT(16) +#define PHY_UNTESTEN 0 +#define PHY_TESTDOUT(n) (((n) & 0xff) << 8) +#define PHY_TESTDIN(n) ((n) & 0xff) + +#define DSI_INT_ST0 0xbc +#define DSI_INT_ST1 0xc0 +#define DSI_INT_MSK0 0xc4 +#define DSI_INT_MSK1 0xc8 + +#define DSI_PHY_TMR_RD_CFG 0xf4 +#define MAX_RD_TIME_V131(lbcc) ((lbcc) & 0x7fff) + +#define PHY_STATUS_TIMEOUT_US 10000 +#define CMD_PKT_STATUS_TIMEOUT_US 20000 + +#define MSEC_PER_SEC 1000 + +struct dw_mipi_dsi { + struct mipi_dsi_host dsi_host; + struct mipi_dsi_device *device; + void __iomem *base; + unsigned int lane_mbps; /* per lane */ + u32 channel; + u32 lanes; + u32 format; + unsigned long mode_flags; + unsigned int max_data_lanes; + const struct dw_mipi_dsi_phy_ops *phy_ops; +}; + +static int dsi_mode_vrefresh(struct display_timing *timings) +{ + int refresh = 0; + unsigned int calc_val; + u32 htotal = timings->hactive.typ + timings->hfront_porch.typ + + timings->hback_porch.typ + timings->hsync_len.typ; + u32 vtotal = timings->vactive.typ + timings->vfront_porch.typ + + timings->vback_porch.typ + timings->vsync_len.typ; + + if (htotal > 0 && vtotal > 0) { + calc_val = timings->pixelclock.typ; + calc_val /= htotal; + refresh = (calc_val + vtotal / 2) / vtotal; + } + + return refresh; +} + +/* + * The controller should generate 2 frames before + * preparing the peripheral. + */ +static void dw_mipi_dsi_wait_for_two_frames(struct display_timing *timings) +{ + int refresh, two_frames; + + refresh = dsi_mode_vrefresh(timings); + two_frames = DIV_ROUND_UP(MSEC_PER_SEC, refresh) * 2; + mdelay(two_frames); +} + +static inline struct dw_mipi_dsi *host_to_dsi(struct mipi_dsi_host *host) +{ + return container_of(host, struct dw_mipi_dsi, dsi_host); +} + +static inline void dsi_write(struct dw_mipi_dsi *dsi, u32 reg, u32 val) +{ + writel(val, dsi->base + reg); +} + +static inline u32 dsi_read(struct dw_mipi_dsi *dsi, u32 reg) +{ + return readl(dsi->base + reg); +} + +static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, + struct mipi_dsi_device *device) +{ + struct dw_mipi_dsi *dsi = host_to_dsi(host); + + if (device->lanes > dsi->max_data_lanes) { + pr_err("the number of data lanes(%u) is too many\n", + device->lanes); + return -EINVAL; + } + + dsi->lanes = device->lanes; + dsi->channel = device->channel; + dsi->format = device->format; + dsi->mode_flags = device->mode_flags; + + return 0; +} + +static void dw_mipi_message_config(struct dw_mipi_dsi *dsi, + const struct mipi_dsi_msg *msg) +{ + bool lpm = msg->flags & MIPI_DSI_MSG_USE_LPM; + u32 val = 0; + + if (msg->flags & MIPI_DSI_MSG_REQ_ACK) + val |= ACK_RQST_EN; + if (lpm) + val |= CMD_MODE_ALL_LP; + + dsi_write(dsi, DSI_LPCLK_CTRL, lpm ? 0 : PHY_TXREQUESTCLKHS); + dsi_write(dsi, DSI_CMD_MODE_CFG, val); +} + +static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) +{ + int ret; + u32 val, mask; + + ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, + val, !(val & GEN_CMD_FULL), + CMD_PKT_STATUS_TIMEOUT_US); + if (ret < 0) { + pr_err("failed to get available command FIFO\n"); + return ret; + } + + dsi_write(dsi, DSI_GEN_HDR, hdr_val); + + mask = GEN_CMD_EMPTY | GEN_PLD_W_EMPTY; + ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, + val, (val & mask) == mask, + CMD_PKT_STATUS_TIMEOUT_US); + if (ret < 0) { + pr_err("failed to write command FIFO\n"); + return ret; + } + + return 0; +} + +static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi, + const struct mipi_dsi_packet *packet) +{ + const u8 *tx_buf = packet->payload; + int len = packet->payload_length, pld_data_bytes = sizeof(u32), ret; + __le32 word; + u32 val; + + while (len) { + if (len < pld_data_bytes) { + word = 0; + memcpy(&word, tx_buf, len); + dsi_write(dsi, DSI_GEN_PLD_DATA, le32_to_cpu(word)); + len = 0; + } else { + memcpy(&word, tx_buf, pld_data_bytes); + dsi_write(dsi, DSI_GEN_PLD_DATA, le32_to_cpu(word)); + tx_buf += pld_data_bytes; + len -= pld_data_bytes; + } + + ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, + val, !(val & GEN_PLD_W_FULL), + CMD_PKT_STATUS_TIMEOUT_US); + if (ret < 0) { + dev_err(dsi->dev, + "failed to get available write payload FIFO\n"); + return ret; + } + } + + word = 0; + memcpy(&word, packet->header, sizeof(packet->header)); + return dw_mipi_dsi_gen_pkt_hdr_write(dsi, le32_to_cpu(word)); +} + +static int dw_mipi_dsi_read(struct dw_mipi_dsi *dsi, + const struct mipi_dsi_msg *msg) +{ + int i, j, ret, len = msg->rx_len; + u8 *buf = msg->rx_buf; + u32 val; + + /* Wait end of the read operation */ + ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, + val, !(val & GEN_RD_CMD_BUSY), + CMD_PKT_STATUS_TIMEOUT_US); + if (ret) { + dev_err(dsi->dev, "Timeout during read operation\n"); + return ret; + } + + for (i = 0; i < len; i += 4) { + /* Read fifo must not be empty before all bytes are read */ + ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, + val, !(val & GEN_PLD_R_EMPTY), + CMD_PKT_STATUS_TIMEOUT_US); + if (ret) { + dev_err(dsi->dev, "Read payload FIFO is empty\n"); + return ret; + } + + val = dsi_read(dsi, DSI_GEN_PLD_DATA); + for (j = 0; j < 4 && j + i < len; j++) + buf[i + j] = val >> (8 * j); + } + + return ret; +} + +static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, + const struct mipi_dsi_msg *msg) +{ + struct dw_mipi_dsi *dsi = host_to_dsi(host); + struct mipi_dsi_packet packet; + int ret, nb_bytes; + + ret = mipi_dsi_create_packet(&packet, msg); + if (ret) { + dev_err(dsi->dev, "failed to create packet: %d\n", ret); + return ret; + } + + dw_mipi_message_config(dsi, msg); + + ret = dw_mipi_dsi_write(dsi, &packet); + if (ret) + return ret; + + if (msg->rx_buf && msg->rx_len) { + ret = dw_mipi_dsi_read(dsi, msg); + if (ret) + return ret; + nb_bytes = msg->rx_len; + } else { + nb_bytes = packet.size; + } + + return nb_bytes; +} + +static const struct mipi_dsi_host_ops dw_mipi_dsi_host_ops = { + .attach = dw_mipi_dsi_host_attach, + .transfer = dw_mipi_dsi_host_transfer, +}; + +static void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi) +{ + u32 val; + + /* + * TODO dw drv improvements + * enabling low power is panel-dependent, we should use the + * panel configuration here... + */ + val = ENABLE_LOW_POWER; + + if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) + val |= VID_MODE_TYPE_BURST; + else if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) + val |= VID_MODE_TYPE_NON_BURST_SYNC_PULSES; + else + val |= VID_MODE_TYPE_NON_BURST_SYNC_EVENTS; + + dsi_write(dsi, DSI_VID_MODE_CFG, val); +} + +static void dw_mipi_dsi_set_mode(struct dw_mipi_dsi *dsi, + unsigned long mode_flags) +{ + dsi_write(dsi, DSI_PWR_UP, RESET); + + if (mode_flags & MIPI_DSI_MODE_VIDEO) { + dsi_write(dsi, DSI_MODE_CFG, ENABLE_VIDEO_MODE); + dw_mipi_dsi_video_mode_config(dsi); + dsi_write(dsi, DSI_LPCLK_CTRL, PHY_TXREQUESTCLKHS); + } else { + dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE); + } + + dsi_write(dsi, DSI_PWR_UP, POWERUP); +} + +static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi) +{ + /* + * The maximum permitted escape clock is 20MHz and it is derived from + * lanebyteclk, which is running at "lane_mbps / 8". Thus we want: + * + * (lane_mbps >> 3) / esc_clk_division < 20 + * which is: + * (lane_mbps >> 3) / 20 > esc_clk_division + */ + u32 esc_clk_division = (dsi->lane_mbps >> 3) / 20 + 1; + + dsi_write(dsi, DSI_PWR_UP, RESET); + + /* + * TODO dw drv improvements + * timeout clock division should be computed with the + * high speed transmission counter timeout and byte lane... + */ + dsi_write(dsi, DSI_CLKMGR_CFG, TO_CLK_DIVISION(10) | + TX_ESC_CLK_DIVISION(esc_clk_division)); +} + +static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi, + struct display_timing *timings) +{ + u32 val = 0, color = 0; + + switch (dsi->format) { + case MIPI_DSI_FMT_RGB888: + color = DPI_COLOR_CODING_24BIT; + break; + case MIPI_DSI_FMT_RGB666: + color = DPI_COLOR_CODING_18BIT_2 | LOOSELY18_EN; + break; + case MIPI_DSI_FMT_RGB666_PACKED: + color = DPI_COLOR_CODING_18BIT_1; + break; + case MIPI_DSI_FMT_RGB565: + color = DPI_COLOR_CODING_16BIT_1; + break; + } + + if (dsi->mode_flags & DISPLAY_FLAGS_VSYNC_HIGH) + val |= VSYNC_ACTIVE_LOW; + if (dsi->mode_flags & DISPLAY_FLAGS_HSYNC_HIGH) + val |= HSYNC_ACTIVE_LOW; + + dsi_write(dsi, DSI_DPI_VCID, DPI_VCID(dsi->channel)); + dsi_write(dsi, DSI_DPI_COLOR_CODING, color); + dsi_write(dsi, DSI_DPI_CFG_POL, val); + /* + * TODO dw drv improvements + * largest packet sizes during hfp or during vsa/vpb/vfp + * should be computed according to byte lane, lane number and only + * if sending lp cmds in high speed is enable (PHY_TXREQUESTCLKHS) + */ + dsi_write(dsi, DSI_DPI_LP_CMD_TIM, OUTVACT_LPCMD_TIME(4) + | INVACT_LPCMD_TIME(4)); +} + +static void dw_mipi_dsi_packet_handler_config(struct dw_mipi_dsi *dsi) +{ + dsi_write(dsi, DSI_PCKHDL_CFG, CRC_RX_EN | ECC_RX_EN | BTA_EN); +} + +static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi, + struct display_timing *timings) +{ + /* + * TODO dw drv improvements + * only burst mode is supported here. For non-burst video modes, + * we should compute DSI_VID_PKT_SIZE, DSI_VCCR.NUMC & + * DSI_VNPCR.NPSIZE... especially because this driver supports + * non-burst video modes, see dw_mipi_dsi_video_mode_config()... + */ + dsi_write(dsi, DSI_VID_PKT_SIZE, VID_PKT_SIZE(timings->hactive.typ)); +} + +static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi) +{ + /* + * TODO dw drv improvements + * compute high speed transmission counter timeout according + * to the timeout clock division (TO_CLK_DIVISION) and byte lane... + */ + dsi_write(dsi, DSI_TO_CNT_CFG, HSTX_TO_CNT(1000) | LPRX_TO_CNT(1000)); + /* + * TODO dw drv improvements + * the Bus-Turn-Around Timeout Counter should be computed + * according to byte lane... + */ + dsi_write(dsi, DSI_BTA_TO_CNT, 0xd00); + dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE); +} + +/* Get lane byte clock cycles. */ +static u32 dw_mipi_dsi_get_hcomponent_lbcc(struct dw_mipi_dsi *dsi, + struct display_timing *timings, + u32 hcomponent) +{ + u32 frac, lbcc; + + lbcc = hcomponent * dsi->lane_mbps * MSEC_PER_SEC / 8; + + frac = lbcc % (timings->pixelclock.typ / 1000); + lbcc = lbcc / (timings->pixelclock.typ / 1000); + if (frac) + lbcc++; + + return lbcc; +} + +static void dw_mipi_dsi_line_timer_config(struct dw_mipi_dsi *dsi, + struct display_timing *timings) +{ + u32 htotal, hsa, hbp, lbcc; + + htotal = timings->hactive.typ + timings->hfront_porch.typ + + timings->hback_porch.typ + timings->hsync_len.typ; + + hsa = timings->hback_porch.typ; + hbp = timings->hsync_len.typ; + + /* + * TODO dw drv improvements + * computations below may be improved... + */ + lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, timings, htotal); + dsi_write(dsi, DSI_VID_HLINE_TIME, lbcc); + + lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, timings, hsa); + dsi_write(dsi, DSI_VID_HSA_TIME, lbcc); + + lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, timings, hbp); + dsi_write(dsi, DSI_VID_HBP_TIME, lbcc); +} + +static void dw_mipi_dsi_vertical_timing_config(struct dw_mipi_dsi *dsi, + struct display_timing *timings) +{ + u32 vactive, vsa, vfp, vbp; + + vactive = timings->vactive.typ; + vsa = timings->vback_porch.typ; + vfp = timings->vfront_porch.typ; + vbp = timings->vsync_len.typ; + + dsi_write(dsi, DSI_VID_VACTIVE_LINES, vactive); + dsi_write(dsi, DSI_VID_VSA_LINES, vsa); + dsi_write(dsi, DSI_VID_VFP_LINES, vfp); + dsi_write(dsi, DSI_VID_VBP_LINES, vbp); +} + +static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi) +{ + u32 hw_version; + + /* + * TODO dw drv improvements + * data & clock lane timers should be computed according to panel + * blankings and to the automatic clock lane control mode... + * note: DSI_PHY_TMR_CFG.MAX_RD_TIME should be in line with + * DSI_CMD_MODE_CFG.MAX_RD_PKT_SIZE_LP (see CMD_MODE_ALL_LP) + */ + + hw_version = dsi_read(dsi, DSI_VERSION) & VERSION; + + if (hw_version >= HWVER_131) { + dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME_V131(0x40) | + PHY_LP2HS_TIME_V131(0x40)); + dsi_write(dsi, DSI_PHY_TMR_RD_CFG, MAX_RD_TIME_V131(10000)); + } else { + dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME(0x40) | + PHY_LP2HS_TIME(0x40) | MAX_RD_TIME(10000)); + } + + dsi_write(dsi, DSI_PHY_TMR_LPCLK_CFG, PHY_CLKHS2LP_TIME(0x40) + | PHY_CLKLP2HS_TIME(0x40)); +} + +static void dw_mipi_dsi_dphy_interface_config(struct dw_mipi_dsi *dsi) +{ + /* + * TODO dw drv improvements + * stop wait time should be the maximum between host dsi + * and panel stop wait times + */ + dsi_write(dsi, DSI_PHY_IF_CFG, PHY_STOP_WAIT_TIME(0x20) | + N_LANES(dsi->lanes)); +} + +static void dw_mipi_dsi_dphy_init(struct dw_mipi_dsi *dsi) +{ + /* Clear PHY state */ + dsi_write(dsi, DSI_PHY_RSTZ, PHY_DISFORCEPLL | PHY_DISABLECLK + | PHY_RSTZ | PHY_SHUTDOWNZ); + dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLR); + dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLR); + dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLR); +} + +static void dw_mipi_dsi_dphy_enable(struct dw_mipi_dsi *dsi) +{ + u32 val; + int ret; + + dsi_write(dsi, DSI_PHY_RSTZ, PHY_ENFORCEPLL | PHY_ENABLECLK | + PHY_UNRSTZ | PHY_UNSHUTDOWNZ); + + ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS, val, + val & PHY_LOCK, PHY_STATUS_TIMEOUT_US); + if (ret < 0) + pr_err("failed to wait phy lock state\n"); + + ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS, + val, val & PHY_STOP_STATE_CLK_LANE, + PHY_STATUS_TIMEOUT_US); + if (ret < 0) + pr_err("failed to wait phy clk lane stop state\n"); +} + +static void dw_mipi_dsi_clear_err(struct dw_mipi_dsi *dsi) +{ + dsi_read(dsi, DSI_INT_ST0); + dsi_read(dsi, DSI_INT_ST1); + dsi_write(dsi, DSI_INT_MSK0, 0); + dsi_write(dsi, DSI_INT_MSK1, 0); +} + +static void dw_mipi_dsi_bridge_set(struct dw_mipi_dsi *dsi, + struct display_timing *timings) +{ + const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->phy_ops; + int ret; + + ret = phy_ops->get_lane_mbps(dsi->device, timings, dsi->lanes, + dsi->format, &dsi->lane_mbps); + if (ret) + pr_err("Phy get_lane_mbps() failed\n"); + + dw_mipi_dsi_init(dsi); + dw_mipi_dsi_dpi_config(dsi, timings); + dw_mipi_dsi_packet_handler_config(dsi); + dw_mipi_dsi_video_mode_config(dsi); + dw_mipi_dsi_video_packet_config(dsi, timings); + dw_mipi_dsi_command_mode_config(dsi); + dw_mipi_dsi_line_timer_config(dsi, timings); + dw_mipi_dsi_vertical_timing_config(dsi, timings); + + dw_mipi_dsi_dphy_init(dsi); + dw_mipi_dsi_dphy_timing_config(dsi); + dw_mipi_dsi_dphy_interface_config(dsi); + + dw_mipi_dsi_clear_err(dsi); + + ret = phy_ops->init(dsi->device); + if (ret) + pr_err("Phy init() failed\n"); + + dw_mipi_dsi_dphy_enable(dsi); + + dw_mipi_dsi_wait_for_two_frames(timings); + + /* Switch to cmd mode for panel-bridge pre_enable & panel prepare */ + dw_mipi_dsi_set_mode(dsi, 0); +} + +void dw_mipi_dsi_bridge_enable(struct mipi_dsi_device *device) +{ + struct mipi_dsi_host *host = device->host; + struct dw_mipi_dsi *dsi = host_to_dsi(host); + + /* Switch to video mode for panel-bridge enable & panel enable */ + dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO); +} +EXPORT_SYMBOL_GPL(dw_mipi_dsi_bridge_enable); + +int dw_mipi_dsi_init_bridge(struct mipi_dsi_device *device) +{ + struct dw_mipi_dsi_plat_data *platdata = dev_get_platdata(device->dev); + struct display_timing timings; + struct dw_mipi_dsi *dsi; + struct clk clk; + int ret; + + dsi = kzalloc(sizeof(*dsi), GFP_KERNEL); + + dsi->phy_ops = platdata->phy_ops; + dsi->max_data_lanes = platdata->max_data_lanes; + dsi->device = device; + dsi->dsi_host.ops = &dw_mipi_dsi_host_ops; + device->host = &dsi->dsi_host; + + /* TODO Get these settings from panel */ + dsi->lanes = 2; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | + MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM; + + dsi->base = (void *)dev_read_addr(device->dev); + if ((fdt_addr_t)dsi->base == FDT_ADDR_T_NONE) { + pr_err("%s: dsi dt register address error\n", __func__); + return -EINVAL; + } + + ret = fdtdec_decode_display_timing(gd->fdt_blob, + dev_of_offset(platdata->panel), + 0, &timings); + if (ret) { + pr_err("%s: decode display timing error %d\n", __func__, ret); + return ret; + } + + if (!dsi->phy_ops->init || !dsi->phy_ops->get_lane_mbps) { + pr_err("Phy not properly configured\n"); + return -ENODEV; + } + + ret = clk_get_by_name(device->dev, "px_clk", &clk); + if (ret) { + pr_err("%s: peripheral clock get error %d\n", __func__, ret); + return ret; + } + + /* get the pixel clock set by the clock framework */ + timings.pixelclock.typ = clk_get_rate(&clk); + + dw_mipi_dsi_bridge_set(dsi, &timings); + + return 0; +} +EXPORT_SYMBOL_GPL(dw_mipi_dsi_init_bridge); + +MODULE_AUTHOR("Chris Zhong "); +MODULE_AUTHOR("Philippe Cornu "); +MODULE_AUTHOR("Yannick Fertré "); +MODULE_DESCRIPTION("DW MIPI DSI host controller driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:dw-mipi-dsi"); diff --git a/include/dw_mipi_dsi.h b/include/dw_mipi_dsi.h new file mode 100644 index 0000000..266c94b --- /dev/null +++ b/include/dw_mipi_dsi.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2017-2018, STMicroelectronics - All Rights Reserved + * + * Authors: Yannick Fertre + * Philippe Cornu + * + * Modified by Yannick Fertre + * This generic Synopsys DesignWare MIPI DSI host driver is based on the + * bridge synopsys from include/drm/bridge/dw_mipi_dsi.h (kernel linux). + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __DW_MIPI_DSI__ +#define __DW_MIPI_DSI__ + +#include + +struct dw_mipi_dsi_phy_ops { + int (*init)(void *priv_data); + int (*get_lane_mbps)(void *priv_data, struct display_timing *timings, + u32 lanes, u32 format, unsigned int *lane_mbps); +}; + +struct dw_mipi_dsi_plat_data { + unsigned int max_data_lanes; + const struct dw_mipi_dsi_phy_ops *phy_ops; + struct udevice *panel; +}; + +int dw_mipi_dsi_init_bridge(struct mipi_dsi_device *device); +void dw_mipi_dsi_bridge_enable(struct mipi_dsi_device *device); + +#endif /* __DW_MIPI_DSI__ */ -- 1.9.1 From mboxrd@z Thu Jan 1 00:00:00 1970 From: yannick fertre Subject: [PATCH v3 05/10] video: add MIPI DSI host controller bridge Date: Tue, 13 Mar 2018 14:50:08 +0100 Message-ID: <1520949014-21468-10-git-send-email-yannick.fertre@st.com> References: <1520949014-21468-1-git-send-email-yannick.fertre@st.com> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Return-path: Received: from mx07-00178001.pphosted.com (mx07-00178001.pphosted.com [62.209.51.94]) by gabe.freedesktop.org (Postfix) with ESMTPS id 4E4116E50D for ; Tue, 13 Mar 2018 13:50:45 +0000 (UTC) In-Reply-To: <1520949014-21468-1-git-send-email-yannick.fertre@st.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" To: Vikas Manocha , Tom Rini , Benjamin Gaignard , Yannick Fertre , Philippe Cornu , Patrice Chotard , Patrick DELAUNAY , Christophe KERELLO , Archit Taneja , Andrzej Hajda , Laurent Pinchart , David Airlie , Brian Norris , Bhumika Goyal , Gustavo Padovan , Maarten Lankhorst , Sean Paul , Albert Aribaud , Simon Glass , Anatolij Gustschin , Thierry Reding Cc: u-boot@lists.denx.de, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org List-Id: dri-devel@lists.freedesktop.org QWRkIGEgU3lub3BzeXMgRGVzaWdud2FyZSBNSVBJIERTSSBob3N0IGJyaWRnZSBkcml2ZXIsIGJh c2VkIG9uIHRoZQpSb2NrY2hpcCB2ZXJzaW9uIGZyb20gcm9ja2NoaXAvZHctbWlwaS1kc2kuYyB3 aXRoIHBoeSAmIGJyaWRnZSBBUElzLgoKU2lnbmVkLW9mZi1ieTogeWFubmljayBmZXJ0cmUgPHlh bm5pY2suZmVydHJlQHN0LmNvbT4KLS0tCiBkcml2ZXJzL3ZpZGVvL0tjb25maWcgICAgICAgfCAg IDkgKwogZHJpdmVycy92aWRlby9NYWtlZmlsZSAgICAgIHwgICAxICsKIGRyaXZlcnMvdmlkZW8v ZHdfbWlwaV9kc2kuYyB8IDgyMiArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysr KysrKysrKwogaW5jbHVkZS9kd19taXBpX2RzaS5oICAgICAgIHwgIDM0ICsrCiA0IGZpbGVzIGNo YW5nZWQsIDg2NiBpbnNlcnRpb25zKCspCiBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy92aWRl by9kd19taXBpX2RzaS5jCiBjcmVhdGUgbW9kZSAxMDA2NDQgaW5jbHVkZS9kd19taXBpX2RzaS5o CgpkaWZmIC0tZ2l0IGEvZHJpdmVycy92aWRlby9LY29uZmlnIGIvZHJpdmVycy92aWRlby9LY29u ZmlnCmluZGV4IGI1ZmM1MzUuLjBmNjQxZDcgMTAwNjQ0Ci0tLSBhL2RyaXZlcnMvdmlkZW8vS2Nv bmZpZworKysgYi9kcml2ZXJzL3ZpZGVvL0tjb25maWcKQEAgLTY1Nyw2ICs2NTcsMTUgQEAgY29u ZmlnIFZJREVPX0RXX0hETUkKIAkgIHJhdGhlciByZXF1aXJlcyBhIFNvQy1zcGVjaWZpYyBnbHVl IGRyaXZlciB0byBjYWxsIGl0KSwgaXQKIAkgIGNhbiBub3QgYmUgZW5hYmxlZCBmcm9tIHRoZSBj b25maWd1cmF0aW9uIG1lbnUuCiAKK2NvbmZpZyBWSURFT19EV19NSVBJX0RTSQorCWJvb2wKKwlo ZWxwCisJICBFbmFibGVzIHRoZSBjb21tb24gZHJpdmVyIGNvZGUgZm9yIHRoZSBEZXNpZ253YXJl IE1JUEkgRFNJCisJICBibG9jayBmb3VuZCBpbiBTb0NzIGZyb20gdmFyaW91cyB2ZW5kb3JzLgor CSAgQXMgdGhpcyBkb2VzIG5vdCBwcm92aWRlIGFueSBmdW5jdGlvbmFsaXR5IGJ5IGl0c2VsZiAo YnV0CisJICByYXRoZXIgcmVxdWlyZXMgYSBTb0Mtc3BlY2lmaWMgZ2x1ZSBkcml2ZXIgdG8gY2Fs bCBpdCksIGl0CisJICBjYW4gbm90IGJlIGVuYWJsZWQgZnJvbSB0aGUgY29uZmlndXJhdGlvbiBt ZW51LgorCiBjb25maWcgVklERU9fU0lNUExFCiAJYm9vbCAiU2ltcGxlIGRpc3BsYXkgZHJpdmVy IGZvciBwcmVjb25maWd1cmVkIGRpc3BsYXkiCiAJaGVscApkaWZmIC0tZ2l0IGEvZHJpdmVycy92 aWRlby9NYWtlZmlsZSBiL2RyaXZlcnMvdmlkZW8vTWFrZWZpbGUKaW5kZXggNjUwMDJhZi4uNTBi ZTU2OSAxMDA2NDQKLS0tIGEvZHJpdmVycy92aWRlby9NYWtlZmlsZQorKysgYi9kcml2ZXJzL3Zp ZGVvL01ha2VmaWxlCkBAIC01Myw2ICs1Myw3IEBAIG9iai0kKENPTkZJR19GT1JNSUtFKSArPSBm b3JtaWtlLm8KIG9iai0kKENPTkZJR19MRzQ1NzMpICs9IGxnNDU3My5vCiBvYmotJChDT05GSUdf QU0zMzVYX0xDRCkgKz0gYW0zMzV4LWZiLm8KIG9iai0kKENPTkZJR19WSURFT19EV19IRE1JKSAr PSBkd19oZG1pLm8KK29iai0kKENPTkZJR19WSURFT19EV19NSVBJX0RTSSkgKz0gZHdfbWlwaV9k c2kubwogb2JqLSR7Q09ORklHX1ZJREVPX01JUElfRFNJfSArPSBtaXBpX2Rpc3BsYXkubwogb2Jq LSQoQ09ORklHX1ZJREVPX1NJTVBMRSkgKz0gc2ltcGxlZmIubwogb2JqLSR7Q09ORklHX1ZJREVP X1RFR1JBMTI0fSArPSB0ZWdyYTEyNC8KZGlmZiAtLWdpdCBhL2RyaXZlcnMvdmlkZW8vZHdfbWlw aV9kc2kuYyBiL2RyaXZlcnMvdmlkZW8vZHdfbWlwaV9kc2kuYwpuZXcgZmlsZSBtb2RlIDEwMDY0 NAppbmRleCAwMDAwMDAwLi5kN2JkOTJkCi0tLSAvZGV2L251bGwKKysrIGIvZHJpdmVycy92aWRl by9kd19taXBpX2RzaS5jCkBAIC0wLDAgKzEsODIyIEBACisvKgorICogQ29weXJpZ2h0IChDKSAy MDE2LCBGdXpob3UgUm9ja2NoaXAgRWxlY3Ryb25pY3MgQ28uLCBMdGQKKyAqIENvcHlyaWdodCAo QykgMjAxOCwgU1RNaWNyb2VsZWN0cm9uaWNzIC0gQWxsIFJpZ2h0cyBSZXNlcnZlZAorICogQXV0 aG9yKHMpOiBQaGlsaXBwZSBDb3JudSA8cGhpbGlwcGUuY29ybnVAc3QuY29tPiBmb3IgU1RNaWNy b2VsZWN0cm9uaWNzLgorICoJICAgICAgWWFubmljayBGZXJ0cmUgPHlhbm5pY2suZmVydHJlQHN0 LmNvbT4gZm9yIFNUTWljcm9lbGVjdHJvbmljcy4KKyAqCisgKiBNb2RpZmllZCBieSBZYW5uaWNr IEZlcnRyZSA8eWFubmljay5mZXJ0cmVAc3QuY29tPgorICogVGhpcyBnZW5lcmljIFN5bm9wc3lz IERlc2lnbldhcmUgTUlQSSBEU0kgaG9zdCBkcml2ZXIgaXMgYmFzZWQgb24gdGhlCisgKiBicmlk Z2Ugc3lub3BzeXMgZnJvbSBkcml2ZXJzL2dwdS9kcm0vYnJpZGdlL3N5bm9wc3lzL2R3LW1pcGkt ZHNpLmMgKGtlcm5lbAorICogbGludXgpLgorICovCisKKyNpbmNsdWRlIDxjb21tb24uaD4KKyNp bmNsdWRlIDxjbGsuaD4KKyNpbmNsdWRlIDxkbS5oPgorI2luY2x1ZGUgPGVycm5vLmg+CisjaW5j bHVkZSA8bWlwaV9kaXNwbGF5Lmg+CisjaW5jbHVkZSA8cGFuZWwuaD4KKyNpbmNsdWRlIDx2aWRl by5oPgorI2luY2x1ZGUgPGFzbS9pby5oPgorI2luY2x1ZGUgPGFzbS9hcmNoL2dwaW8uaD4KKyNp bmNsdWRlIDxkbS9kZXZpY2UtaW50ZXJuYWwuaD4KKyNpbmNsdWRlIDxkd19taXBpX2RzaS5oPgor I2luY2x1ZGUgPGxpbnV4L2lvcG9sbC5oPgorI2luY2x1ZGUgPHZpZGVvX2JyaWRnZS5oPgorCisj ZGVmaW5lIEhXVkVSXzEzMQkJCTB4MzEzMzMxMDAJLyogSVAgdmVyc2lvbiAxLjMxICovCisKKyNk ZWZpbmUgRFNJX1ZFUlNJT04JCQkweDAwCisjZGVmaW5lIFZFUlNJT04JCQkJR0VOTUFTSygzMSwg OCkKKworI2RlZmluZSBEU0lfUFdSX1VQCQkJMHgwNAorI2RlZmluZSBSRVNFVAkJCQkwCisjZGVm aW5lIFBPV0VSVVAJCQkJQklUKDApCisKKyNkZWZpbmUgRFNJX0NMS01HUl9DRkcJCQkweDA4Cisj ZGVmaW5lIFRPX0NMS19ESVZJU0lPTihkaXYpCQkoKChkaXYpICYgMHhmZikgPDwgOCkKKyNkZWZp bmUgVFhfRVNDX0NMS19ESVZJU0lPTihkaXYpCSgoZGl2KSAmIDB4ZmYpCisKKyNkZWZpbmUgRFNJ X0RQSV9WQ0lECQkJMHgwYworI2RlZmluZSBEUElfVkNJRCh2Y2lkKQkJCSgodmNpZCkgJiAweDMp CisKKyNkZWZpbmUgRFNJX0RQSV9DT0xPUl9DT0RJTkcJCTB4MTAKKyNkZWZpbmUgTE9PU0VMWTE4 X0VOCQkJQklUKDgpCisjZGVmaW5lIERQSV9DT0xPUl9DT0RJTkdfMTZCSVRfMQkweDAKKyNkZWZp bmUgRFBJX0NPTE9SX0NPRElOR18xNkJJVF8yCTB4MQorI2RlZmluZSBEUElfQ09MT1JfQ09ESU5H XzE2QklUXzMJMHgyCisjZGVmaW5lIERQSV9DT0xPUl9DT0RJTkdfMThCSVRfMQkweDMKKyNkZWZp bmUgRFBJX0NPTE9SX0NPRElOR18xOEJJVF8yCTB4NAorI2RlZmluZSBEUElfQ09MT1JfQ09ESU5H XzI0QklUCQkweDUKKworI2RlZmluZSBEU0lfRFBJX0NGR19QT0wJCQkweDE0CisjZGVmaW5lIENP TE9STV9BQ1RJVkVfTE9XCQlCSVQoNCkKKyNkZWZpbmUgU0hVVERfQUNUSVZFX0xPVwkJQklUKDMp CisjZGVmaW5lIEhTWU5DX0FDVElWRV9MT1cJCUJJVCgyKQorI2RlZmluZSBWU1lOQ19BQ1RJVkVf TE9XCQlCSVQoMSkKKyNkZWZpbmUgREFUQUVOX0FDVElWRV9MT1cJCUJJVCgwKQorCisjZGVmaW5l IERTSV9EUElfTFBfQ01EX1RJTQkJMHgxOAorI2RlZmluZSBPVVRWQUNUX0xQQ01EX1RJTUUocCkJ CSgoKHApICYgMHhmZikgPDwgMTYpCisjZGVmaW5lIElOVkFDVF9MUENNRF9USU1FKHApCQkoKHAp ICYgMHhmZikKKworI2RlZmluZSBEU0lfREJJX1ZDSUQJCQkweDFjCisjZGVmaW5lIERTSV9EQklf Q0ZHCQkJMHgyMAorI2RlZmluZSBEU0lfREJJX1BBUlRJVElPTklOR19FTgkJMHgyNAorI2RlZmlu ZSBEU0lfREJJX0NNRFNJWkUJCQkweDI4CisKKyNkZWZpbmUgRFNJX1BDS0hETF9DRkcJCQkweDJj CisjZGVmaW5lIENSQ19SWF9FTgkJCUJJVCg0KQorI2RlZmluZSBFQ0NfUlhfRU4JCQlCSVQoMykK KyNkZWZpbmUgQlRBX0VOCQkJCUJJVCgyKQorI2RlZmluZSBFT1RQX1JYX0VOCQkJQklUKDEpCisj ZGVmaW5lIEVPVFBfVFhfRU4JCQlCSVQoMCkKKworI2RlZmluZSBEU0lfR0VOX1ZDSUQJCQkweDMw CisKKyNkZWZpbmUgRFNJX01PREVfQ0ZHCQkJMHgzNAorI2RlZmluZSBFTkFCTEVfVklERU9fTU9E RQkJMAorI2RlZmluZSBFTkFCTEVfQ01EX01PREUJCQlCSVQoMCkKKworI2RlZmluZSBEU0lfVklE X01PREVfQ0ZHCQkweDM4CisjZGVmaW5lIEVOQUJMRV9MT1dfUE9XRVIJCSgweDNmIDw8IDgpCisj ZGVmaW5lIEVOQUJMRV9MT1dfUE9XRVJfTUFTSwkJKDB4M2YgPDwgOCkKKyNkZWZpbmUgVklEX01P REVfVFlQRV9OT05fQlVSU1RfU1lOQ19QVUxTRVMJMHgwCisjZGVmaW5lIFZJRF9NT0RFX1RZUEVf Tk9OX0JVUlNUX1NZTkNfRVZFTlRTCTB4MQorI2RlZmluZSBWSURfTU9ERV9UWVBFX0JVUlNUCQkJ MHgyCisjZGVmaW5lIFZJRF9NT0RFX1RZUEVfTUFTSwkJCTB4MworCisjZGVmaW5lIERTSV9WSURf UEtUX1NJWkUJCTB4M2MKKyNkZWZpbmUgVklEX1BLVF9TSVpFKHApCQkJKChwKSAmIDB4M2ZmZikK KworI2RlZmluZSBEU0lfVklEX05VTV9DSFVOS1MJCTB4NDAKKyNkZWZpbmUgVklEX05VTV9DSFVO S1MoYykJCSgoYykgJiAweDFmZmYpCisKKyNkZWZpbmUgRFNJX1ZJRF9OVUxMX1NJWkUJCTB4NDQK KyNkZWZpbmUgVklEX05VTExfU0laRShiKQkJKChiKSAmIDB4MWZmZikKKworI2RlZmluZSBEU0lf VklEX0hTQV9USU1FCQkweDQ4CisjZGVmaW5lIERTSV9WSURfSEJQX1RJTUUJCTB4NGMKKyNkZWZp bmUgRFNJX1ZJRF9ITElORV9USU1FCQkweDUwCisjZGVmaW5lIERTSV9WSURfVlNBX0xJTkVTCQkw eDU0CisjZGVmaW5lIERTSV9WSURfVkJQX0xJTkVTCQkweDU4CisjZGVmaW5lIERTSV9WSURfVkZQ X0xJTkVTCQkweDVjCisjZGVmaW5lIERTSV9WSURfVkFDVElWRV9MSU5FUwkJMHg2MAorI2RlZmlu ZSBEU0lfRURQSV9DTURfU0laRQkJMHg2NAorCisjZGVmaW5lIERTSV9DTURfTU9ERV9DRkcJCTB4 NjgKKyNkZWZpbmUgTUFYX1JEX1BLVF9TSVpFX0xQCQlCSVQoMjQpCisjZGVmaW5lIERDU19MV19U WF9MUAkJCUJJVCgxOSkKKyNkZWZpbmUgRENTX1NSXzBQX1RYX0xQCQkJQklUKDE4KQorI2RlZmlu ZSBEQ1NfU1dfMVBfVFhfTFAJCQlCSVQoMTcpCisjZGVmaW5lIERDU19TV18wUF9UWF9MUAkJCUJJ VCgxNikKKyNkZWZpbmUgR0VOX0xXX1RYX0xQCQkJQklUKDE0KQorI2RlZmluZSBHRU5fU1JfMlBf VFhfTFAJCQlCSVQoMTMpCisjZGVmaW5lIEdFTl9TUl8xUF9UWF9MUAkJCUJJVCgxMikKKyNkZWZp bmUgR0VOX1NSXzBQX1RYX0xQCQkJQklUKDExKQorI2RlZmluZSBHRU5fU1dfMlBfVFhfTFAJCQlC SVQoMTApCisjZGVmaW5lIEdFTl9TV18xUF9UWF9MUAkJCUJJVCg5KQorI2RlZmluZSBHRU5fU1df MFBfVFhfTFAJCQlCSVQoOCkKKyNkZWZpbmUgQUNLX1JRU1RfRU4JCQlCSVQoMSkKKyNkZWZpbmUg VEVBUl9GWF9FTgkJCUJJVCgwKQorCisjZGVmaW5lIENNRF9NT0RFX0FMTF9MUAkJCShNQVhfUkRf UEtUX1NJWkVfTFAgfCBcCisJCQkJCSBEQ1NfTFdfVFhfTFAgfCBcCisJCQkJCSBEQ1NfU1JfMFBf VFhfTFAgfCBcCisJCQkJCSBEQ1NfU1dfMVBfVFhfTFAgfCBcCisJCQkJCSBEQ1NfU1dfMFBfVFhf TFAgfCBcCisJCQkJCSBHRU5fTFdfVFhfTFAgfCBcCisJCQkJCSBHRU5fU1JfMlBfVFhfTFAgfCBc CisJCQkJCSBHRU5fU1JfMVBfVFhfTFAgfCBcCisJCQkJCSBHRU5fU1JfMFBfVFhfTFAgfCBcCisJ CQkJCSBHRU5fU1dfMlBfVFhfTFAgfCBcCisJCQkJCSBHRU5fU1dfMVBfVFhfTFAgfCBcCisJCQkJ CSBHRU5fU1dfMFBfVFhfTFApCisKKyNkZWZpbmUgRFNJX0dFTl9IRFIJCQkweDZjCisjZGVmaW5l IERTSV9HRU5fUExEX0RBVEEJCTB4NzAKKworI2RlZmluZSBEU0lfQ01EX1BLVF9TVEFUVVMJCTB4 NzQKKyNkZWZpbmUgR0VOX1JEX0NNRF9CVVNZCQkJQklUKDYpCisjZGVmaW5lIEdFTl9QTERfUl9G VUxMCQkJQklUKDUpCisjZGVmaW5lIEdFTl9QTERfUl9FTVBUWQkJCUJJVCg0KQorI2RlZmluZSBH RU5fUExEX1dfRlVMTAkJCUJJVCgzKQorI2RlZmluZSBHRU5fUExEX1dfRU1QVFkJCQlCSVQoMikK KyNkZWZpbmUgR0VOX0NNRF9GVUxMCQkJQklUKDEpCisjZGVmaW5lIEdFTl9DTURfRU1QVFkJCQlC SVQoMCkKKworI2RlZmluZSBEU0lfVE9fQ05UX0NGRwkJCTB4NzgKKyNkZWZpbmUgSFNUWF9UT19D TlQocCkJCQkoKChwKSAmIDB4ZmZmZikgPDwgMTYpCisjZGVmaW5lIExQUlhfVE9fQ05UKHApCQkJ KChwKSAmIDB4ZmZmZikKKworI2RlZmluZSBEU0lfSFNfUkRfVE9fQ05UCQkweDdjCisjZGVmaW5l IERTSV9MUF9SRF9UT19DTlQJCTB4ODAKKyNkZWZpbmUgRFNJX0hTX1dSX1RPX0NOVAkJMHg4NAor I2RlZmluZSBEU0lfTFBfV1JfVE9fQ05UCQkweDg4CisjZGVmaW5lIERTSV9CVEFfVE9fQ05UCQkJ MHg4YworCisjZGVmaW5lIERTSV9MUENMS19DVFJMCQkJMHg5NAorI2RlZmluZSBBVVRPX0NMS0xB TkVfQ1RSTAkJQklUKDEpCisjZGVmaW5lIFBIWV9UWFJFUVVFU1RDTEtIUwkJQklUKDApCisKKyNk ZWZpbmUgRFNJX1BIWV9UTVJfTFBDTEtfQ0ZHCQkweDk4CisjZGVmaW5lIFBIWV9DTEtIUzJMUF9U SU1FKGxiY2MpCQkoKChsYmNjKSAmIDB4M2ZmKSA8PCAxNikKKyNkZWZpbmUgUEhZX0NMS0xQMkhT X1RJTUUobGJjYykJCSgobGJjYykgJiAweDNmZikKKworI2RlZmluZSBEU0lfUEhZX1RNUl9DRkcJ CQkweDljCisjZGVmaW5lIFBIWV9IUzJMUF9USU1FKGxiY2MpCQkoKChsYmNjKSAmIDB4ZmYpIDw8 IDI0KQorI2RlZmluZSBQSFlfTFAySFNfVElNRShsYmNjKQkJKCgobGJjYykgJiAweGZmKSA8PCAx NikKKyNkZWZpbmUgTUFYX1JEX1RJTUUobGJjYykJCSgobGJjYykgJiAweDdmZmYpCisjZGVmaW5l IFBIWV9IUzJMUF9USU1FX1YxMzEobGJjYykJKCgobGJjYykgJiAweDNmZikgPDwgMTYpCisjZGVm aW5lIFBIWV9MUDJIU19USU1FX1YxMzEobGJjYykJKChsYmNjKSAmIDB4M2ZmKQorCisjZGVmaW5l IERTSV9QSFlfUlNUWgkJCTB4YTAKKyNkZWZpbmUgUEhZX0RJU0ZPUkNFUExMCQkJMAorI2RlZmlu ZSBQSFlfRU5GT1JDRVBMTAkJCUJJVCgzKQorI2RlZmluZSBQSFlfRElTQUJMRUNMSwkJCTAKKyNk ZWZpbmUgUEhZX0VOQUJMRUNMSwkJCUJJVCgyKQorI2RlZmluZSBQSFlfUlNUWgkJCTAKKyNkZWZp bmUgUEhZX1VOUlNUWgkJCUJJVCgxKQorI2RlZmluZSBQSFlfU0hVVERPV05aCQkJMAorI2RlZmlu ZSBQSFlfVU5TSFVURE9XTloJCQlCSVQoMCkKKworI2RlZmluZSBEU0lfUEhZX0lGX0NGRwkJCTB4 YTQKKyNkZWZpbmUgUEhZX1NUT1BfV0FJVF9USU1FKGN5Y2xlKQkoKChjeWNsZSkgJiAweGZmKSA8 PCA4KQorI2RlZmluZSBOX0xBTkVTKG4pCQkJKCgobikgLSAxKSAmIDB4MykKKworI2RlZmluZSBE U0lfUEhZX1VMUFNfQ1RSTAkJMHhhOAorI2RlZmluZSBEU0lfUEhZX1RYX1RSSUdHRVJTCQkweGFj CisKKyNkZWZpbmUgRFNJX1BIWV9TVEFUVVMJCQkweGIwCisjZGVmaW5lIFBIWV9TVE9QX1NUQVRF X0NMS19MQU5FCQlCSVQoMikKKyNkZWZpbmUgUEhZX0xPQ0sJCQlCSVQoMCkKKworI2RlZmluZSBE U0lfUEhZX1RTVF9DVFJMMAkJMHhiNAorI2RlZmluZSBQSFlfVEVTVENMSwkJCUJJVCgxKQorI2Rl ZmluZSBQSFlfVU5URVNUQ0xLCQkJMAorI2RlZmluZSBQSFlfVEVTVENMUgkJCUJJVCgwKQorI2Rl ZmluZSBQSFlfVU5URVNUQ0xSCQkJMAorCisjZGVmaW5lIERTSV9QSFlfVFNUX0NUUkwxCQkweGI4 CisjZGVmaW5lIFBIWV9URVNURU4JCQlCSVQoMTYpCisjZGVmaW5lIFBIWV9VTlRFU1RFTgkJCTAK KyNkZWZpbmUgUEhZX1RFU1RET1VUKG4pCQkJKCgobikgJiAweGZmKSA8PCA4KQorI2RlZmluZSBQ SFlfVEVTVERJTihuKQkJCSgobikgJiAweGZmKQorCisjZGVmaW5lIERTSV9JTlRfU1QwCQkJMHhi YworI2RlZmluZSBEU0lfSU5UX1NUMQkJCTB4YzAKKyNkZWZpbmUgRFNJX0lOVF9NU0swCQkJMHhj NAorI2RlZmluZSBEU0lfSU5UX01TSzEJCQkweGM4CisKKyNkZWZpbmUgRFNJX1BIWV9UTVJfUkRf Q0ZHCQkweGY0CisjZGVmaW5lIE1BWF9SRF9USU1FX1YxMzEobGJjYykJCSgobGJjYykgJiAweDdm ZmYpCisKKyNkZWZpbmUgUEhZX1NUQVRVU19USU1FT1VUX1VTCQkxMDAwMAorI2RlZmluZSBDTURf UEtUX1NUQVRVU19USU1FT1VUX1VTCTIwMDAwCisKKyNkZWZpbmUgTVNFQ19QRVJfU0VDCQkJMTAw MAorCitzdHJ1Y3QgZHdfbWlwaV9kc2kgeworCXN0cnVjdCBtaXBpX2RzaV9ob3N0IGRzaV9ob3N0 OworCXN0cnVjdCBtaXBpX2RzaV9kZXZpY2UgKmRldmljZTsKKwl2b2lkIF9faW9tZW0gKmJhc2U7 CisJdW5zaWduZWQgaW50IGxhbmVfbWJwczsgLyogcGVyIGxhbmUgKi8KKwl1MzIgY2hhbm5lbDsK Kwl1MzIgbGFuZXM7CisJdTMyIGZvcm1hdDsKKwl1bnNpZ25lZCBsb25nIG1vZGVfZmxhZ3M7CisJ dW5zaWduZWQgaW50IG1heF9kYXRhX2xhbmVzOworCWNvbnN0IHN0cnVjdCBkd19taXBpX2RzaV9w aHlfb3BzICpwaHlfb3BzOworfTsKKworc3RhdGljIGludCBkc2lfbW9kZV92cmVmcmVzaChzdHJ1 Y3QgZGlzcGxheV90aW1pbmcgKnRpbWluZ3MpCit7CisJaW50IHJlZnJlc2ggPSAwOworCXVuc2ln bmVkIGludCBjYWxjX3ZhbDsKKwl1MzIgaHRvdGFsID0gdGltaW5ncy0+aGFjdGl2ZS50eXAgKyB0 aW1pbmdzLT5oZnJvbnRfcG9yY2gudHlwICsKKwkJICAgICB0aW1pbmdzLT5oYmFja19wb3JjaC50 eXAgKyB0aW1pbmdzLT5oc3luY19sZW4udHlwOworCXUzMiB2dG90YWwgPSB0aW1pbmdzLT52YWN0 aXZlLnR5cCArIHRpbWluZ3MtPnZmcm9udF9wb3JjaC50eXAgKworCQkgICAgIHRpbWluZ3MtPnZi YWNrX3BvcmNoLnR5cCArIHRpbWluZ3MtPnZzeW5jX2xlbi50eXA7CisKKwlpZiAoaHRvdGFsID4g MCAmJiB2dG90YWwgPiAwKSB7CisJCWNhbGNfdmFsID0gdGltaW5ncy0+cGl4ZWxjbG9jay50eXA7 CisJCWNhbGNfdmFsIC89IGh0b3RhbDsKKwkJcmVmcmVzaCA9IChjYWxjX3ZhbCArIHZ0b3RhbCAv IDIpIC8gdnRvdGFsOworCX0KKworCXJldHVybiByZWZyZXNoOworfQorCisvKgorICogVGhlIGNv bnRyb2xsZXIgc2hvdWxkIGdlbmVyYXRlIDIgZnJhbWVzIGJlZm9yZQorICogcHJlcGFyaW5nIHRo ZSBwZXJpcGhlcmFsLgorICovCitzdGF0aWMgdm9pZCBkd19taXBpX2RzaV93YWl0X2Zvcl90d29f ZnJhbWVzKHN0cnVjdCBkaXNwbGF5X3RpbWluZyAqdGltaW5ncykKK3sKKwlpbnQgcmVmcmVzaCwg dHdvX2ZyYW1lczsKKworCXJlZnJlc2ggPSBkc2lfbW9kZV92cmVmcmVzaCh0aW1pbmdzKTsKKwl0 d29fZnJhbWVzID0gRElWX1JPVU5EX1VQKE1TRUNfUEVSX1NFQywgcmVmcmVzaCkgKiAyOworCW1k ZWxheSh0d29fZnJhbWVzKTsKK30KKworc3RhdGljIGlubGluZSBzdHJ1Y3QgZHdfbWlwaV9kc2kg Kmhvc3RfdG9fZHNpKHN0cnVjdCBtaXBpX2RzaV9ob3N0ICpob3N0KQoreworCXJldHVybiBjb250 YWluZXJfb2YoaG9zdCwgc3RydWN0IGR3X21pcGlfZHNpLCBkc2lfaG9zdCk7Cit9CisKK3N0YXRp YyBpbmxpbmUgdm9pZCBkc2lfd3JpdGUoc3RydWN0IGR3X21pcGlfZHNpICpkc2ksIHUzMiByZWcs IHUzMiB2YWwpCit7CisJd3JpdGVsKHZhbCwgZHNpLT5iYXNlICsgcmVnKTsKK30KKworc3RhdGlj IGlubGluZSB1MzIgZHNpX3JlYWQoc3RydWN0IGR3X21pcGlfZHNpICpkc2ksIHUzMiByZWcpCit7 CisJcmV0dXJuIHJlYWRsKGRzaS0+YmFzZSArIHJlZyk7Cit9CisKK3N0YXRpYyBpbnQgZHdfbWlw aV9kc2lfaG9zdF9hdHRhY2goc3RydWN0IG1pcGlfZHNpX2hvc3QgKmhvc3QsCisJCQkJICAgc3Ry dWN0IG1pcGlfZHNpX2RldmljZSAqZGV2aWNlKQoreworCXN0cnVjdCBkd19taXBpX2RzaSAqZHNp ID0gaG9zdF90b19kc2koaG9zdCk7CisKKwlpZiAoZGV2aWNlLT5sYW5lcyA+IGRzaS0+bWF4X2Rh dGFfbGFuZXMpIHsKKwkJcHJfZXJyKCJ0aGUgbnVtYmVyIG9mIGRhdGEgbGFuZXMoJXUpIGlzIHRv byBtYW55XG4iLAorCQkgICAgICAgZGV2aWNlLT5sYW5lcyk7CisJCXJldHVybiAtRUlOVkFMOwor CX0KKworCWRzaS0+bGFuZXMgPSBkZXZpY2UtPmxhbmVzOworCWRzaS0+Y2hhbm5lbCA9IGRldmlj ZS0+Y2hhbm5lbDsKKwlkc2ktPmZvcm1hdCA9IGRldmljZS0+Zm9ybWF0OworCWRzaS0+bW9kZV9m bGFncyA9IGRldmljZS0+bW9kZV9mbGFnczsKKworCXJldHVybiAwOworfQorCitzdGF0aWMgdm9p ZCBkd19taXBpX21lc3NhZ2VfY29uZmlnKHN0cnVjdCBkd19taXBpX2RzaSAqZHNpLAorCQkJCSAg IGNvbnN0IHN0cnVjdCBtaXBpX2RzaV9tc2cgKm1zZykKK3sKKwlib29sIGxwbSA9IG1zZy0+Zmxh Z3MgJiBNSVBJX0RTSV9NU0dfVVNFX0xQTTsKKwl1MzIgdmFsID0gMDsKKworCWlmIChtc2ctPmZs YWdzICYgTUlQSV9EU0lfTVNHX1JFUV9BQ0spCisJCXZhbCB8PSBBQ0tfUlFTVF9FTjsKKwlpZiAo bHBtKQorCQl2YWwgfD0gQ01EX01PREVfQUxMX0xQOworCisJZHNpX3dyaXRlKGRzaSwgRFNJX0xQ Q0xLX0NUUkwsIGxwbSA/IDAgOiBQSFlfVFhSRVFVRVNUQ0xLSFMpOworCWRzaV93cml0ZShkc2ks IERTSV9DTURfTU9ERV9DRkcsIHZhbCk7Cit9CisKK3N0YXRpYyBpbnQgZHdfbWlwaV9kc2lfZ2Vu X3BrdF9oZHJfd3JpdGUoc3RydWN0IGR3X21pcGlfZHNpICpkc2ksIHUzMiBoZHJfdmFsKQorewor CWludCByZXQ7CisJdTMyIHZhbCwgbWFzazsKKworCXJldCA9IHJlYWRsX3BvbGxfdGltZW91dChk c2ktPmJhc2UgKyBEU0lfQ01EX1BLVF9TVEFUVVMsCisJCQkJIHZhbCwgISh2YWwgJiBHRU5fQ01E X0ZVTEwpLAorCQkJCSBDTURfUEtUX1NUQVRVU19USU1FT1VUX1VTKTsKKwlpZiAocmV0IDwgMCkg eworCQlwcl9lcnIoImZhaWxlZCB0byBnZXQgYXZhaWxhYmxlIGNvbW1hbmQgRklGT1xuIik7CisJ CXJldHVybiByZXQ7CisJfQorCisJZHNpX3dyaXRlKGRzaSwgRFNJX0dFTl9IRFIsIGhkcl92YWwp OworCisJbWFzayA9IEdFTl9DTURfRU1QVFkgfCBHRU5fUExEX1dfRU1QVFk7CisJcmV0ID0gcmVh ZGxfcG9sbF90aW1lb3V0KGRzaS0+YmFzZSArIERTSV9DTURfUEtUX1NUQVRVUywKKwkJCQkgdmFs LCAodmFsICYgbWFzaykgPT0gbWFzaywKKwkJCQkgQ01EX1BLVF9TVEFUVVNfVElNRU9VVF9VUyk7 CisJaWYgKHJldCA8IDApIHsKKwkJcHJfZXJyKCJmYWlsZWQgdG8gd3JpdGUgY29tbWFuZCBGSUZP XG4iKTsKKwkJcmV0dXJuIHJldDsKKwl9CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIGludCBk d19taXBpX2RzaV93cml0ZShzdHJ1Y3QgZHdfbWlwaV9kc2kgKmRzaSwKKwkJCSAgICAgY29uc3Qg c3RydWN0IG1pcGlfZHNpX3BhY2tldCAqcGFja2V0KQoreworCWNvbnN0IHU4ICp0eF9idWYgPSBw YWNrZXQtPnBheWxvYWQ7CisJaW50IGxlbiA9IHBhY2tldC0+cGF5bG9hZF9sZW5ndGgsIHBsZF9k YXRhX2J5dGVzID0gc2l6ZW9mKHUzMiksIHJldDsKKwlfX2xlMzIgd29yZDsKKwl1MzIgdmFsOwor CisJd2hpbGUgKGxlbikgeworCQlpZiAobGVuIDwgcGxkX2RhdGFfYnl0ZXMpIHsKKwkJCXdvcmQg PSAwOworCQkJbWVtY3B5KCZ3b3JkLCB0eF9idWYsIGxlbik7CisJCQlkc2lfd3JpdGUoZHNpLCBE U0lfR0VOX1BMRF9EQVRBLCBsZTMyX3RvX2NwdSh3b3JkKSk7CisJCQlsZW4gPSAwOworCQl9IGVs c2UgeworCQkJbWVtY3B5KCZ3b3JkLCB0eF9idWYsIHBsZF9kYXRhX2J5dGVzKTsKKwkJCWRzaV93 cml0ZShkc2ksIERTSV9HRU5fUExEX0RBVEEsIGxlMzJfdG9fY3B1KHdvcmQpKTsKKwkJCXR4X2J1 ZiArPSBwbGRfZGF0YV9ieXRlczsKKwkJCWxlbiAtPSBwbGRfZGF0YV9ieXRlczsKKwkJfQorCisJ CXJldCA9IHJlYWRsX3BvbGxfdGltZW91dChkc2ktPmJhc2UgKyBEU0lfQ01EX1BLVF9TVEFUVVMs CisJCQkJCSB2YWwsICEodmFsICYgR0VOX1BMRF9XX0ZVTEwpLAorCQkJCQkgQ01EX1BLVF9TVEFU VVNfVElNRU9VVF9VUyk7CisJCWlmIChyZXQgPCAwKSB7CisJCQlkZXZfZXJyKGRzaS0+ZGV2LAor CQkJCSJmYWlsZWQgdG8gZ2V0IGF2YWlsYWJsZSB3cml0ZSBwYXlsb2FkIEZJRk9cbiIpOworCQkJ cmV0dXJuIHJldDsKKwkJfQorCX0KKworCXdvcmQgPSAwOworCW1lbWNweSgmd29yZCwgcGFja2V0 LT5oZWFkZXIsIHNpemVvZihwYWNrZXQtPmhlYWRlcikpOworCXJldHVybiBkd19taXBpX2RzaV9n ZW5fcGt0X2hkcl93cml0ZShkc2ksIGxlMzJfdG9fY3B1KHdvcmQpKTsKK30KKworc3RhdGljIGlu dCBkd19taXBpX2RzaV9yZWFkKHN0cnVjdCBkd19taXBpX2RzaSAqZHNpLAorCQkJICAgIGNvbnN0 IHN0cnVjdCBtaXBpX2RzaV9tc2cgKm1zZykKK3sKKwlpbnQgaSwgaiwgcmV0LCBsZW4gPSBtc2ct PnJ4X2xlbjsKKwl1OCAqYnVmID0gbXNnLT5yeF9idWY7CisJdTMyIHZhbDsKKworCS8qIFdhaXQg ZW5kIG9mIHRoZSByZWFkIG9wZXJhdGlvbiAqLworCXJldCA9IHJlYWRsX3BvbGxfdGltZW91dChk c2ktPmJhc2UgKyBEU0lfQ01EX1BLVF9TVEFUVVMsCisJCQkJIHZhbCwgISh2YWwgJiBHRU5fUkRf Q01EX0JVU1kpLAorCQkJCSBDTURfUEtUX1NUQVRVU19USU1FT1VUX1VTKTsKKwlpZiAocmV0KSB7 CisJCWRldl9lcnIoZHNpLT5kZXYsICJUaW1lb3V0IGR1cmluZyByZWFkIG9wZXJhdGlvblxuIik7 CisJCXJldHVybiByZXQ7CisJfQorCisJZm9yIChpID0gMDsgaSA8IGxlbjsgaSArPSA0KSB7CisJ CS8qIFJlYWQgZmlmbyBtdXN0IG5vdCBiZSBlbXB0eSBiZWZvcmUgYWxsIGJ5dGVzIGFyZSByZWFk ICovCisJCXJldCA9IHJlYWRsX3BvbGxfdGltZW91dChkc2ktPmJhc2UgKyBEU0lfQ01EX1BLVF9T VEFUVVMsCisJCQkJCSB2YWwsICEodmFsICYgR0VOX1BMRF9SX0VNUFRZKSwKKwkJCQkJIENNRF9Q S1RfU1RBVFVTX1RJTUVPVVRfVVMpOworCQlpZiAocmV0KSB7CisJCQlkZXZfZXJyKGRzaS0+ZGV2 LCAiUmVhZCBwYXlsb2FkIEZJRk8gaXMgZW1wdHlcbiIpOworCQkJcmV0dXJuIHJldDsKKwkJfQor CisJCXZhbCA9IGRzaV9yZWFkKGRzaSwgRFNJX0dFTl9QTERfREFUQSk7CisJCWZvciAoaiA9IDA7 IGogPCA0ICYmIGogKyBpIDwgbGVuOyBqKyspCisJCQlidWZbaSArIGpdID0gdmFsID4+ICg4ICog aik7CisJfQorCisJcmV0dXJuIHJldDsKK30KKworc3RhdGljIHNzaXplX3QgZHdfbWlwaV9kc2lf aG9zdF90cmFuc2ZlcihzdHJ1Y3QgbWlwaV9kc2lfaG9zdCAqaG9zdCwKKwkJCQkJIGNvbnN0IHN0 cnVjdCBtaXBpX2RzaV9tc2cgKm1zZykKK3sKKwlzdHJ1Y3QgZHdfbWlwaV9kc2kgKmRzaSA9IGhv c3RfdG9fZHNpKGhvc3QpOworCXN0cnVjdCBtaXBpX2RzaV9wYWNrZXQgcGFja2V0OworCWludCBy ZXQsIG5iX2J5dGVzOworCisJcmV0ID0gbWlwaV9kc2lfY3JlYXRlX3BhY2tldCgmcGFja2V0LCBt c2cpOworCWlmIChyZXQpIHsKKwkJZGV2X2Vycihkc2ktPmRldiwgImZhaWxlZCB0byBjcmVhdGUg cGFja2V0OiAlZFxuIiwgcmV0KTsKKwkJcmV0dXJuIHJldDsKKwl9CisKKwlkd19taXBpX21lc3Nh Z2VfY29uZmlnKGRzaSwgbXNnKTsKKworCXJldCA9IGR3X21pcGlfZHNpX3dyaXRlKGRzaSwgJnBh Y2tldCk7CisJaWYgKHJldCkKKwkJcmV0dXJuIHJldDsKKworCWlmIChtc2ctPnJ4X2J1ZiAmJiBt c2ctPnJ4X2xlbikgeworCQlyZXQgPSBkd19taXBpX2RzaV9yZWFkKGRzaSwgbXNnKTsKKwkJaWYg KHJldCkKKwkJCXJldHVybiByZXQ7CisJCW5iX2J5dGVzID0gbXNnLT5yeF9sZW47CisJfSBlbHNl IHsKKwkJbmJfYnl0ZXMgPSBwYWNrZXQuc2l6ZTsKKwl9CisKKwlyZXR1cm4gbmJfYnl0ZXM7Cit9 CisKK3N0YXRpYyBjb25zdCBzdHJ1Y3QgbWlwaV9kc2lfaG9zdF9vcHMgZHdfbWlwaV9kc2lfaG9z dF9vcHMgPSB7CisJLmF0dGFjaCA9IGR3X21pcGlfZHNpX2hvc3RfYXR0YWNoLAorCS50cmFuc2Zl ciA9IGR3X21pcGlfZHNpX2hvc3RfdHJhbnNmZXIsCit9OworCitzdGF0aWMgdm9pZCBkd19taXBp X2RzaV92aWRlb19tb2RlX2NvbmZpZyhzdHJ1Y3QgZHdfbWlwaV9kc2kgKmRzaSkKK3sKKwl1MzIg dmFsOworCisJLyoKKwkgKiBUT0RPIGR3IGRydiBpbXByb3ZlbWVudHMKKwkgKiBlbmFibGluZyBs b3cgcG93ZXIgaXMgcGFuZWwtZGVwZW5kZW50LCB3ZSBzaG91bGQgdXNlIHRoZQorCSAqIHBhbmVs IGNvbmZpZ3VyYXRpb24gaGVyZS4uLgorCSAqLworCXZhbCA9IEVOQUJMRV9MT1dfUE9XRVI7CisK KwlpZiAoZHNpLT5tb2RlX2ZsYWdzICYgTUlQSV9EU0lfTU9ERV9WSURFT19CVVJTVCkKKwkJdmFs IHw9IFZJRF9NT0RFX1RZUEVfQlVSU1Q7CisJZWxzZSBpZiAoZHNpLT5tb2RlX2ZsYWdzICYgTUlQ SV9EU0lfTU9ERV9WSURFT19TWU5DX1BVTFNFKQorCQl2YWwgfD0gVklEX01PREVfVFlQRV9OT05f QlVSU1RfU1lOQ19QVUxTRVM7CisJZWxzZQorCQl2YWwgfD0gVklEX01PREVfVFlQRV9OT05fQlVS U1RfU1lOQ19FVkVOVFM7CisKKwlkc2lfd3JpdGUoZHNpLCBEU0lfVklEX01PREVfQ0ZHLCB2YWwp OworfQorCitzdGF0aWMgdm9pZCBkd19taXBpX2RzaV9zZXRfbW9kZShzdHJ1Y3QgZHdfbWlwaV9k c2kgKmRzaSwKKwkJCQkgdW5zaWduZWQgbG9uZyBtb2RlX2ZsYWdzKQoreworCWRzaV93cml0ZShk c2ksIERTSV9QV1JfVVAsIFJFU0VUKTsKKworCWlmIChtb2RlX2ZsYWdzICYgTUlQSV9EU0lfTU9E RV9WSURFTykgeworCQlkc2lfd3JpdGUoZHNpLCBEU0lfTU9ERV9DRkcsIEVOQUJMRV9WSURFT19N T0RFKTsKKwkJZHdfbWlwaV9kc2lfdmlkZW9fbW9kZV9jb25maWcoZHNpKTsKKwkJZHNpX3dyaXRl KGRzaSwgRFNJX0xQQ0xLX0NUUkwsIFBIWV9UWFJFUVVFU1RDTEtIUyk7CisJfSBlbHNlIHsKKwkJ ZHNpX3dyaXRlKGRzaSwgRFNJX01PREVfQ0ZHLCBFTkFCTEVfQ01EX01PREUpOworCX0KKworCWRz aV93cml0ZShkc2ksIERTSV9QV1JfVVAsIFBPV0VSVVApOworfQorCitzdGF0aWMgdm9pZCBkd19t aXBpX2RzaV9pbml0KHN0cnVjdCBkd19taXBpX2RzaSAqZHNpKQoreworCS8qCisJICogVGhlIG1h eGltdW0gcGVybWl0dGVkIGVzY2FwZSBjbG9jayBpcyAyME1IeiBhbmQgaXQgaXMgZGVyaXZlZCBm cm9tCisJICogbGFuZWJ5dGVjbGssIHdoaWNoIGlzIHJ1bm5pbmcgYXQgImxhbmVfbWJwcyAvIDgi LiAgVGh1cyB3ZSB3YW50OgorCSAqCisJICogICAgIChsYW5lX21icHMgPj4gMykgLyBlc2NfY2xr X2RpdmlzaW9uIDwgMjAKKwkgKiB3aGljaCBpczoKKwkgKiAgICAgKGxhbmVfbWJwcyA+PiAzKSAv IDIwID4gZXNjX2Nsa19kaXZpc2lvbgorCSAqLworCXUzMiBlc2NfY2xrX2RpdmlzaW9uID0gKGRz aS0+bGFuZV9tYnBzID4+IDMpIC8gMjAgKyAxOworCisJZHNpX3dyaXRlKGRzaSwgRFNJX1BXUl9V UCwgUkVTRVQpOworCisJLyoKKwkgKiBUT0RPIGR3IGRydiBpbXByb3ZlbWVudHMKKwkgKiB0aW1l b3V0IGNsb2NrIGRpdmlzaW9uIHNob3VsZCBiZSBjb21wdXRlZCB3aXRoIHRoZQorCSAqIGhpZ2gg c3BlZWQgdHJhbnNtaXNzaW9uIGNvdW50ZXIgdGltZW91dCBhbmQgYnl0ZSBsYW5lLi4uCisJICov CisJZHNpX3dyaXRlKGRzaSwgRFNJX0NMS01HUl9DRkcsIFRPX0NMS19ESVZJU0lPTigxMCkgfAor CQkgIFRYX0VTQ19DTEtfRElWSVNJT04oZXNjX2Nsa19kaXZpc2lvbikpOworfQorCitzdGF0aWMg dm9pZCBkd19taXBpX2RzaV9kcGlfY29uZmlnKHN0cnVjdCBkd19taXBpX2RzaSAqZHNpLAorCQkJ CSAgIHN0cnVjdCBkaXNwbGF5X3RpbWluZyAqdGltaW5ncykKK3sKKwl1MzIgdmFsID0gMCwgY29s b3IgPSAwOworCisJc3dpdGNoIChkc2ktPmZvcm1hdCkgeworCWNhc2UgTUlQSV9EU0lfRk1UX1JH Qjg4ODoKKwkJY29sb3IgPSBEUElfQ09MT1JfQ09ESU5HXzI0QklUOworCQlicmVhazsKKwljYXNl IE1JUElfRFNJX0ZNVF9SR0I2NjY6CisJCWNvbG9yID0gRFBJX0NPTE9SX0NPRElOR18xOEJJVF8y IHwgTE9PU0VMWTE4X0VOOworCQlicmVhazsKKwljYXNlIE1JUElfRFNJX0ZNVF9SR0I2NjZfUEFD S0VEOgorCQljb2xvciA9IERQSV9DT0xPUl9DT0RJTkdfMThCSVRfMTsKKwkJYnJlYWs7CisJY2Fz ZSBNSVBJX0RTSV9GTVRfUkdCNTY1OgorCQljb2xvciA9IERQSV9DT0xPUl9DT0RJTkdfMTZCSVRf MTsKKwkJYnJlYWs7CisJfQorCisJaWYgKGRzaS0+bW9kZV9mbGFncyAmIERJU1BMQVlfRkxBR1Nf VlNZTkNfSElHSCkKKwkJdmFsIHw9IFZTWU5DX0FDVElWRV9MT1c7CisJaWYgKGRzaS0+bW9kZV9m bGFncyAmIERJU1BMQVlfRkxBR1NfSFNZTkNfSElHSCkKKwkJdmFsIHw9IEhTWU5DX0FDVElWRV9M T1c7CisKKwlkc2lfd3JpdGUoZHNpLCBEU0lfRFBJX1ZDSUQsIERQSV9WQ0lEKGRzaS0+Y2hhbm5l bCkpOworCWRzaV93cml0ZShkc2ksIERTSV9EUElfQ09MT1JfQ09ESU5HLCBjb2xvcik7CisJZHNp X3dyaXRlKGRzaSwgRFNJX0RQSV9DRkdfUE9MLCB2YWwpOworCS8qCisJICogVE9ETyBkdyBkcnYg aW1wcm92ZW1lbnRzCisJICogbGFyZ2VzdCBwYWNrZXQgc2l6ZXMgZHVyaW5nIGhmcCBvciBkdXJp bmcgdnNhL3ZwYi92ZnAKKwkgKiBzaG91bGQgYmUgY29tcHV0ZWQgYWNjb3JkaW5nIHRvIGJ5dGUg bGFuZSwgbGFuZSBudW1iZXIgYW5kIG9ubHkKKwkgKiBpZiBzZW5kaW5nIGxwIGNtZHMgaW4gaGln aCBzcGVlZCBpcyBlbmFibGUgKFBIWV9UWFJFUVVFU1RDTEtIUykKKwkgKi8KKwlkc2lfd3JpdGUo ZHNpLCBEU0lfRFBJX0xQX0NNRF9USU0sIE9VVFZBQ1RfTFBDTURfVElNRSg0KQorCQkgIHwgSU5W QUNUX0xQQ01EX1RJTUUoNCkpOworfQorCitzdGF0aWMgdm9pZCBkd19taXBpX2RzaV9wYWNrZXRf aGFuZGxlcl9jb25maWcoc3RydWN0IGR3X21pcGlfZHNpICpkc2kpCit7CisJZHNpX3dyaXRlKGRz aSwgRFNJX1BDS0hETF9DRkcsIENSQ19SWF9FTiB8IEVDQ19SWF9FTiB8IEJUQV9FTik7Cit9CisK K3N0YXRpYyB2b2lkIGR3X21pcGlfZHNpX3ZpZGVvX3BhY2tldF9jb25maWcoc3RydWN0IGR3X21p cGlfZHNpICpkc2ksCisJCQkJCSAgICBzdHJ1Y3QgZGlzcGxheV90aW1pbmcgKnRpbWluZ3MpCit7 CisJLyoKKwkgKiBUT0RPIGR3IGRydiBpbXByb3ZlbWVudHMKKwkgKiBvbmx5IGJ1cnN0IG1vZGUg aXMgc3VwcG9ydGVkIGhlcmUuIEZvciBub24tYnVyc3QgdmlkZW8gbW9kZXMsCisJICogd2Ugc2hv dWxkIGNvbXB1dGUgRFNJX1ZJRF9QS1RfU0laRSwgRFNJX1ZDQ1IuTlVNQyAmCisJICogRFNJX1ZO UENSLk5QU0laRS4uLiBlc3BlY2lhbGx5IGJlY2F1c2UgdGhpcyBkcml2ZXIgc3VwcG9ydHMKKwkg KiBub24tYnVyc3QgdmlkZW8gbW9kZXMsIHNlZSBkd19taXBpX2RzaV92aWRlb19tb2RlX2NvbmZp ZygpLi4uCisJICovCisJZHNpX3dyaXRlKGRzaSwgRFNJX1ZJRF9QS1RfU0laRSwgVklEX1BLVF9T SVpFKHRpbWluZ3MtPmhhY3RpdmUudHlwKSk7Cit9CisKK3N0YXRpYyB2b2lkIGR3X21pcGlfZHNp X2NvbW1hbmRfbW9kZV9jb25maWcoc3RydWN0IGR3X21pcGlfZHNpICpkc2kpCit7CisJLyoKKwkg KiBUT0RPIGR3IGRydiBpbXByb3ZlbWVudHMKKwkgKiBjb21wdXRlIGhpZ2ggc3BlZWQgdHJhbnNt aXNzaW9uIGNvdW50ZXIgdGltZW91dCBhY2NvcmRpbmcKKwkgKiB0byB0aGUgdGltZW91dCBjbG9j ayBkaXZpc2lvbiAoVE9fQ0xLX0RJVklTSU9OKSBhbmQgYnl0ZSBsYW5lLi4uCisJICovCisJZHNp X3dyaXRlKGRzaSwgRFNJX1RPX0NOVF9DRkcsIEhTVFhfVE9fQ05UKDEwMDApIHwgTFBSWF9UT19D TlQoMTAwMCkpOworCS8qCisJICogVE9ETyBkdyBkcnYgaW1wcm92ZW1lbnRzCisJICogdGhlIEJ1 cy1UdXJuLUFyb3VuZCBUaW1lb3V0IENvdW50ZXIgc2hvdWxkIGJlIGNvbXB1dGVkCisJICogYWNj b3JkaW5nIHRvIGJ5dGUgbGFuZS4uLgorCSAqLworCWRzaV93cml0ZShkc2ksIERTSV9CVEFfVE9f Q05ULCAweGQwMCk7CisJZHNpX3dyaXRlKGRzaSwgRFNJX01PREVfQ0ZHLCBFTkFCTEVfQ01EX01P REUpOworfQorCisvKiBHZXQgbGFuZSBieXRlIGNsb2NrIGN5Y2xlcy4gKi8KK3N0YXRpYyB1MzIg ZHdfbWlwaV9kc2lfZ2V0X2hjb21wb25lbnRfbGJjYyhzdHJ1Y3QgZHdfbWlwaV9kc2kgKmRzaSwK KwkJCQkJICAgc3RydWN0IGRpc3BsYXlfdGltaW5nICp0aW1pbmdzLAorCQkJCQkgICB1MzIgaGNv bXBvbmVudCkKK3sKKwl1MzIgZnJhYywgbGJjYzsKKworCWxiY2MgPSBoY29tcG9uZW50ICogZHNp LT5sYW5lX21icHMgKiBNU0VDX1BFUl9TRUMgLyA4OworCisJZnJhYyA9IGxiY2MgJSAodGltaW5n cy0+cGl4ZWxjbG9jay50eXAgLyAxMDAwKTsKKwlsYmNjID0gbGJjYyAvICh0aW1pbmdzLT5waXhl bGNsb2NrLnR5cCAvIDEwMDApOworCWlmIChmcmFjKQorCQlsYmNjKys7CisKKwlyZXR1cm4gbGJj YzsKK30KKworc3RhdGljIHZvaWQgZHdfbWlwaV9kc2lfbGluZV90aW1lcl9jb25maWcoc3RydWN0 IGR3X21pcGlfZHNpICpkc2ksCisJCQkJCSAgc3RydWN0IGRpc3BsYXlfdGltaW5nICp0aW1pbmdz KQoreworCXUzMiBodG90YWwsIGhzYSwgaGJwLCBsYmNjOworCisJaHRvdGFsID0gdGltaW5ncy0+ aGFjdGl2ZS50eXAgKyB0aW1pbmdzLT5oZnJvbnRfcG9yY2gudHlwICsKKwkJIHRpbWluZ3MtPmhi YWNrX3BvcmNoLnR5cCArIHRpbWluZ3MtPmhzeW5jX2xlbi50eXA7CisKKwloc2EgPSB0aW1pbmdz LT5oYmFja19wb3JjaC50eXA7CisJaGJwID0gdGltaW5ncy0+aHN5bmNfbGVuLnR5cDsKKworCS8q CisJICogVE9ETyBkdyBkcnYgaW1wcm92ZW1lbnRzCisJICogY29tcHV0YXRpb25zIGJlbG93IG1h eSBiZSBpbXByb3ZlZC4uLgorCSAqLworCWxiY2MgPSBkd19taXBpX2RzaV9nZXRfaGNvbXBvbmVu dF9sYmNjKGRzaSwgdGltaW5ncywgaHRvdGFsKTsKKwlkc2lfd3JpdGUoZHNpLCBEU0lfVklEX0hM SU5FX1RJTUUsIGxiY2MpOworCisJbGJjYyA9IGR3X21pcGlfZHNpX2dldF9oY29tcG9uZW50X2xi Y2MoZHNpLCB0aW1pbmdzLCBoc2EpOworCWRzaV93cml0ZShkc2ksIERTSV9WSURfSFNBX1RJTUUs IGxiY2MpOworCisJbGJjYyA9IGR3X21pcGlfZHNpX2dldF9oY29tcG9uZW50X2xiY2MoZHNpLCB0 aW1pbmdzLCBoYnApOworCWRzaV93cml0ZShkc2ksIERTSV9WSURfSEJQX1RJTUUsIGxiY2MpOwor fQorCitzdGF0aWMgdm9pZCBkd19taXBpX2RzaV92ZXJ0aWNhbF90aW1pbmdfY29uZmlnKHN0cnVj dCBkd19taXBpX2RzaSAqZHNpLAorCQkJCQkgICAgICAgc3RydWN0IGRpc3BsYXlfdGltaW5nICp0 aW1pbmdzKQoreworCXUzMiB2YWN0aXZlLCB2c2EsIHZmcCwgdmJwOworCisJdmFjdGl2ZSA9IHRp bWluZ3MtPnZhY3RpdmUudHlwOworCXZzYSA9ICB0aW1pbmdzLT52YmFja19wb3JjaC50eXA7CisJ dmZwID0gIHRpbWluZ3MtPnZmcm9udF9wb3JjaC50eXA7CisJdmJwID0gdGltaW5ncy0+dnN5bmNf bGVuLnR5cDsKKworCWRzaV93cml0ZShkc2ksIERTSV9WSURfVkFDVElWRV9MSU5FUywgdmFjdGl2 ZSk7CisJZHNpX3dyaXRlKGRzaSwgRFNJX1ZJRF9WU0FfTElORVMsIHZzYSk7CisJZHNpX3dyaXRl KGRzaSwgRFNJX1ZJRF9WRlBfTElORVMsIHZmcCk7CisJZHNpX3dyaXRlKGRzaSwgRFNJX1ZJRF9W QlBfTElORVMsIHZicCk7Cit9CisKK3N0YXRpYyB2b2lkIGR3X21pcGlfZHNpX2RwaHlfdGltaW5n X2NvbmZpZyhzdHJ1Y3QgZHdfbWlwaV9kc2kgKmRzaSkKK3sKKwl1MzIgaHdfdmVyc2lvbjsKKwor CS8qCisJICogVE9ETyBkdyBkcnYgaW1wcm92ZW1lbnRzCisJICogZGF0YSAmIGNsb2NrIGxhbmUg dGltZXJzIHNob3VsZCBiZSBjb21wdXRlZCBhY2NvcmRpbmcgdG8gcGFuZWwKKwkgKiBibGFua2lu Z3MgYW5kIHRvIHRoZSBhdXRvbWF0aWMgY2xvY2sgbGFuZSBjb250cm9sIG1vZGUuLi4KKwkgKiBu b3RlOiBEU0lfUEhZX1RNUl9DRkcuTUFYX1JEX1RJTUUgc2hvdWxkIGJlIGluIGxpbmUgd2l0aAor CSAqIERTSV9DTURfTU9ERV9DRkcuTUFYX1JEX1BLVF9TSVpFX0xQIChzZWUgQ01EX01PREVfQUxM X0xQKQorCSAqLworCisJaHdfdmVyc2lvbiA9IGRzaV9yZWFkKGRzaSwgRFNJX1ZFUlNJT04pICYg VkVSU0lPTjsKKworCWlmIChod192ZXJzaW9uID49IEhXVkVSXzEzMSkgeworCQlkc2lfd3JpdGUo ZHNpLCBEU0lfUEhZX1RNUl9DRkcsIFBIWV9IUzJMUF9USU1FX1YxMzEoMHg0MCkgfAorCQkJICBQ SFlfTFAySFNfVElNRV9WMTMxKDB4NDApKTsKKwkJZHNpX3dyaXRlKGRzaSwgRFNJX1BIWV9UTVJf UkRfQ0ZHLCBNQVhfUkRfVElNRV9WMTMxKDEwMDAwKSk7CisJfSBlbHNlIHsKKwkJZHNpX3dyaXRl KGRzaSwgRFNJX1BIWV9UTVJfQ0ZHLCBQSFlfSFMyTFBfVElNRSgweDQwKSB8CisJCQkgIFBIWV9M UDJIU19USU1FKDB4NDApIHwgTUFYX1JEX1RJTUUoMTAwMDApKTsKKwl9CisKKwlkc2lfd3JpdGUo ZHNpLCBEU0lfUEhZX1RNUl9MUENMS19DRkcsIFBIWV9DTEtIUzJMUF9USU1FKDB4NDApCisJCSAg fCBQSFlfQ0xLTFAySFNfVElNRSgweDQwKSk7Cit9CisKK3N0YXRpYyB2b2lkIGR3X21pcGlfZHNp X2RwaHlfaW50ZXJmYWNlX2NvbmZpZyhzdHJ1Y3QgZHdfbWlwaV9kc2kgKmRzaSkKK3sKKwkvKgor CSAqIFRPRE8gZHcgZHJ2IGltcHJvdmVtZW50cworCSAqIHN0b3Agd2FpdCB0aW1lIHNob3VsZCBi ZSB0aGUgbWF4aW11bSBiZXR3ZWVuIGhvc3QgZHNpCisJICogYW5kIHBhbmVsIHN0b3Agd2FpdCB0 aW1lcworCSAqLworCWRzaV93cml0ZShkc2ksIERTSV9QSFlfSUZfQ0ZHLCBQSFlfU1RPUF9XQUlU X1RJTUUoMHgyMCkgfAorCQkgIE5fTEFORVMoZHNpLT5sYW5lcykpOworfQorCitzdGF0aWMgdm9p ZCBkd19taXBpX2RzaV9kcGh5X2luaXQoc3RydWN0IGR3X21pcGlfZHNpICpkc2kpCit7CisJLyog Q2xlYXIgUEhZIHN0YXRlICovCisJZHNpX3dyaXRlKGRzaSwgRFNJX1BIWV9SU1RaLCBQSFlfRElT Rk9SQ0VQTEwgfCBQSFlfRElTQUJMRUNMSworCQkgIHwgUEhZX1JTVFogfCBQSFlfU0hVVERPV05a KTsKKwlkc2lfd3JpdGUoZHNpLCBEU0lfUEhZX1RTVF9DVFJMMCwgUEhZX1VOVEVTVENMUik7CisJ ZHNpX3dyaXRlKGRzaSwgRFNJX1BIWV9UU1RfQ1RSTDAsIFBIWV9URVNUQ0xSKTsKKwlkc2lfd3Jp dGUoZHNpLCBEU0lfUEhZX1RTVF9DVFJMMCwgUEhZX1VOVEVTVENMUik7Cit9CisKK3N0YXRpYyB2 b2lkIGR3X21pcGlfZHNpX2RwaHlfZW5hYmxlKHN0cnVjdCBkd19taXBpX2RzaSAqZHNpKQorewor CXUzMiB2YWw7CisJaW50IHJldDsKKworCWRzaV93cml0ZShkc2ksIERTSV9QSFlfUlNUWiwgUEhZ X0VORk9SQ0VQTEwgfCBQSFlfRU5BQkxFQ0xLIHwKKwkJICBQSFlfVU5SU1RaIHwgUEhZX1VOU0hV VERPV05aKTsKKworCXJldCA9IHJlYWRsX3BvbGxfdGltZW91dChkc2ktPmJhc2UgKyBEU0lfUEhZ X1NUQVRVUywgdmFsLAorCQkJCSB2YWwgJiBQSFlfTE9DSywgUEhZX1NUQVRVU19USU1FT1VUX1VT KTsKKwlpZiAocmV0IDwgMCkKKwkJcHJfZXJyKCJmYWlsZWQgdG8gd2FpdCBwaHkgbG9jayBzdGF0 ZVxuIik7CisKKwlyZXQgPSByZWFkbF9wb2xsX3RpbWVvdXQoZHNpLT5iYXNlICsgRFNJX1BIWV9T VEFUVVMsCisJCQkJIHZhbCwgdmFsICYgUEhZX1NUT1BfU1RBVEVfQ0xLX0xBTkUsCisJCQkJIFBI WV9TVEFUVVNfVElNRU9VVF9VUyk7CisJaWYgKHJldCA8IDApCisJCXByX2VycigiZmFpbGVkIHRv IHdhaXQgcGh5IGNsayBsYW5lIHN0b3Agc3RhdGVcbiIpOworfQorCitzdGF0aWMgdm9pZCBkd19t aXBpX2RzaV9jbGVhcl9lcnIoc3RydWN0IGR3X21pcGlfZHNpICpkc2kpCit7CisJZHNpX3JlYWQo ZHNpLCBEU0lfSU5UX1NUMCk7CisJZHNpX3JlYWQoZHNpLCBEU0lfSU5UX1NUMSk7CisJZHNpX3dy aXRlKGRzaSwgRFNJX0lOVF9NU0swLCAwKTsKKwlkc2lfd3JpdGUoZHNpLCBEU0lfSU5UX01TSzEs IDApOworfQorCitzdGF0aWMgdm9pZCBkd19taXBpX2RzaV9icmlkZ2Vfc2V0KHN0cnVjdCBkd19t aXBpX2RzaSAqZHNpLAorCQkJCSAgIHN0cnVjdCBkaXNwbGF5X3RpbWluZyAqdGltaW5ncykKK3sK Kwljb25zdCBzdHJ1Y3QgZHdfbWlwaV9kc2lfcGh5X29wcyAqcGh5X29wcyA9IGRzaS0+cGh5X29w czsKKwlpbnQgcmV0OworCisJcmV0ID0gcGh5X29wcy0+Z2V0X2xhbmVfbWJwcyhkc2ktPmRldmlj ZSwgdGltaW5ncywgZHNpLT5sYW5lcywKKwkJCQkgICAgIGRzaS0+Zm9ybWF0LCAmZHNpLT5sYW5l X21icHMpOworCWlmIChyZXQpCisJCXByX2VycigiUGh5IGdldF9sYW5lX21icHMoKSBmYWlsZWRc biIpOworCisJZHdfbWlwaV9kc2lfaW5pdChkc2kpOworCWR3X21pcGlfZHNpX2RwaV9jb25maWco ZHNpLCB0aW1pbmdzKTsKKwlkd19taXBpX2RzaV9wYWNrZXRfaGFuZGxlcl9jb25maWcoZHNpKTsK Kwlkd19taXBpX2RzaV92aWRlb19tb2RlX2NvbmZpZyhkc2kpOworCWR3X21pcGlfZHNpX3ZpZGVv X3BhY2tldF9jb25maWcoZHNpLCB0aW1pbmdzKTsKKwlkd19taXBpX2RzaV9jb21tYW5kX21vZGVf Y29uZmlnKGRzaSk7CisJZHdfbWlwaV9kc2lfbGluZV90aW1lcl9jb25maWcoZHNpLCB0aW1pbmdz KTsKKwlkd19taXBpX2RzaV92ZXJ0aWNhbF90aW1pbmdfY29uZmlnKGRzaSwgdGltaW5ncyk7CisK Kwlkd19taXBpX2RzaV9kcGh5X2luaXQoZHNpKTsKKwlkd19taXBpX2RzaV9kcGh5X3RpbWluZ19j b25maWcoZHNpKTsKKwlkd19taXBpX2RzaV9kcGh5X2ludGVyZmFjZV9jb25maWcoZHNpKTsKKwor CWR3X21pcGlfZHNpX2NsZWFyX2Vycihkc2kpOworCisJcmV0ID0gcGh5X29wcy0+aW5pdChkc2kt PmRldmljZSk7CisJaWYgKHJldCkKKwkJcHJfZXJyKCJQaHkgaW5pdCgpIGZhaWxlZFxuIik7CisK Kwlkd19taXBpX2RzaV9kcGh5X2VuYWJsZShkc2kpOworCisJZHdfbWlwaV9kc2lfd2FpdF9mb3Jf dHdvX2ZyYW1lcyh0aW1pbmdzKTsKKworCS8qIFN3aXRjaCB0byBjbWQgbW9kZSBmb3IgcGFuZWwt YnJpZGdlIHByZV9lbmFibGUgJiBwYW5lbCBwcmVwYXJlICovCisJZHdfbWlwaV9kc2lfc2V0X21v ZGUoZHNpLCAwKTsKK30KKwordm9pZCBkd19taXBpX2RzaV9icmlkZ2VfZW5hYmxlKHN0cnVjdCBt aXBpX2RzaV9kZXZpY2UgKmRldmljZSkKK3sKKwlzdHJ1Y3QgbWlwaV9kc2lfaG9zdCAqaG9zdCA9 IGRldmljZS0+aG9zdDsKKwlzdHJ1Y3QgZHdfbWlwaV9kc2kgKmRzaSA9IGhvc3RfdG9fZHNpKGhv c3QpOworCisJLyogU3dpdGNoIHRvIHZpZGVvIG1vZGUgZm9yIHBhbmVsLWJyaWRnZSBlbmFibGUg JiBwYW5lbCBlbmFibGUgKi8KKwlkd19taXBpX2RzaV9zZXRfbW9kZShkc2ksIE1JUElfRFNJX01P REVfVklERU8pOworfQorRVhQT1JUX1NZTUJPTF9HUEwoZHdfbWlwaV9kc2lfYnJpZGdlX2VuYWJs ZSk7CisKK2ludCBkd19taXBpX2RzaV9pbml0X2JyaWRnZShzdHJ1Y3QgbWlwaV9kc2lfZGV2aWNl ICpkZXZpY2UpCit7CisJc3RydWN0IGR3X21pcGlfZHNpX3BsYXRfZGF0YSAqcGxhdGRhdGEgPSBk ZXZfZ2V0X3BsYXRkYXRhKGRldmljZS0+ZGV2KTsKKwlzdHJ1Y3QgZGlzcGxheV90aW1pbmcgdGlt aW5nczsKKwlzdHJ1Y3QgZHdfbWlwaV9kc2kgKmRzaTsKKwlzdHJ1Y3QgY2xrIGNsazsKKwlpbnQg cmV0OworCisJZHNpID0ga3phbGxvYyhzaXplb2YoKmRzaSksIEdGUF9LRVJORUwpOworCisJZHNp LT5waHlfb3BzID0gcGxhdGRhdGEtPnBoeV9vcHM7CisJZHNpLT5tYXhfZGF0YV9sYW5lcyA9IHBs YXRkYXRhLT5tYXhfZGF0YV9sYW5lczsKKwlkc2ktPmRldmljZSA9IGRldmljZTsKKwlkc2ktPmRz aV9ob3N0Lm9wcyA9ICZkd19taXBpX2RzaV9ob3N0X29wczsKKwlkZXZpY2UtPmhvc3QgPSAmZHNp LT5kc2lfaG9zdDsKKworCSAvKiBUT0RPIEdldCB0aGVzZSBzZXR0aW5ncyBmcm9tIHBhbmVsICov CisJZHNpLT5sYW5lcyA9IDI7CisJZHNpLT5mb3JtYXQgPSBNSVBJX0RTSV9GTVRfUkdCODg4Owor CWRzaS0+bW9kZV9mbGFncyA9IE1JUElfRFNJX01PREVfVklERU8gfAorCQkJICBNSVBJX0RTSV9N T0RFX1ZJREVPX0JVUlNUIHwKKwkJCSAgTUlQSV9EU0lfTU9ERV9MUE07CisKKwlkc2ktPmJhc2Ug PSAodm9pZCAqKWRldl9yZWFkX2FkZHIoZGV2aWNlLT5kZXYpOworCWlmICgoZmR0X2FkZHJfdClk c2ktPmJhc2UgPT0gRkRUX0FERFJfVF9OT05FKSB7CisJCXByX2VycigiJXM6IGRzaSBkdCByZWdp c3RlciBhZGRyZXNzIGVycm9yXG4iLCBfX2Z1bmNfXyk7CisJCXJldHVybiAtRUlOVkFMOworCX0K KworCXJldCA9IGZkdGRlY19kZWNvZGVfZGlzcGxheV90aW1pbmcoZ2QtPmZkdF9ibG9iLAorCQkJ CQkgICBkZXZfb2Zfb2Zmc2V0KHBsYXRkYXRhLT5wYW5lbCksCisJCQkJCSAgIDAsICZ0aW1pbmdz KTsKKwlpZiAocmV0KSB7CisJCXByX2VycigiJXM6IGRlY29kZSBkaXNwbGF5IHRpbWluZyBlcnJv ciAlZFxuIiwgX19mdW5jX18sIHJldCk7CisJCXJldHVybiByZXQ7CisJfQorCisJaWYgKCFkc2kt PnBoeV9vcHMtPmluaXQgfHwgIWRzaS0+cGh5X29wcy0+Z2V0X2xhbmVfbWJwcykgeworCQlwcl9l cnIoIlBoeSBub3QgcHJvcGVybHkgY29uZmlndXJlZFxuIik7CisJCXJldHVybiAtRU5PREVWOwor CX0KKworCXJldCA9IGNsa19nZXRfYnlfbmFtZShkZXZpY2UtPmRldiwgInB4X2NsayIsICZjbGsp OworCWlmIChyZXQpIHsKKwkJcHJfZXJyKCIlczogcGVyaXBoZXJhbCBjbG9jayBnZXQgZXJyb3Ig JWRcbiIsIF9fZnVuY19fLCByZXQpOworCQlyZXR1cm4gcmV0OworCX0KKworCS8qICBnZXQgdGhl IHBpeGVsIGNsb2NrIHNldCBieSB0aGUgY2xvY2sgZnJhbWV3b3JrICovCisJdGltaW5ncy5waXhl bGNsb2NrLnR5cCA9IGNsa19nZXRfcmF0ZSgmY2xrKTsKKworCWR3X21pcGlfZHNpX2JyaWRnZV9z ZXQoZHNpLCAmdGltaW5ncyk7CisKKwlyZXR1cm4gMDsKK30KK0VYUE9SVF9TWU1CT0xfR1BMKGR3 X21pcGlfZHNpX2luaXRfYnJpZGdlKTsKKworTU9EVUxFX0FVVEhPUigiQ2hyaXMgWmhvbmcgPHp5 d0Byb2NrLWNoaXBzLmNvbT4iKTsKK01PRFVMRV9BVVRIT1IoIlBoaWxpcHBlIENvcm51IDxwaGls aXBwZS5jb3JudUBzdC5jb20+Iik7CitNT0RVTEVfQVVUSE9SKCJZYW5uaWNrIEZlcnRyw6kgPHlh bm5pY2suZmVydHJlQHN0LmNvbT4iKTsKK01PRFVMRV9ERVNDUklQVElPTigiRFcgTUlQSSBEU0kg aG9zdCBjb250cm9sbGVyIGRyaXZlciIpOworTU9EVUxFX0xJQ0VOU0UoIkdQTCIpOworTU9EVUxF X0FMSUFTKCJwbGF0Zm9ybTpkdy1taXBpLWRzaSIpOwpkaWZmIC0tZ2l0IGEvaW5jbHVkZS9kd19t aXBpX2RzaS5oIGIvaW5jbHVkZS9kd19taXBpX2RzaS5oCm5ldyBmaWxlIG1vZGUgMTAwNjQ0Cmlu ZGV4IDAwMDAwMDAuLjI2NmM5NGIKLS0tIC9kZXYvbnVsbAorKysgYi9pbmNsdWRlL2R3X21pcGlf ZHNpLmgKQEAgLTAsMCArMSwzNCBAQAorLyoKKyAqIENvcHlyaWdodCAoQykgMjAxNy0yMDE4LCBT VE1pY3JvZWxlY3Ryb25pY3MgLSBBbGwgUmlnaHRzIFJlc2VydmVkCisgKgorICogQXV0aG9yczog WWFubmljayBGZXJ0cmUgPHlhbm5pY2suZmVydHJlQHN0LmNvbT4KKyAqICAgICAgICAgIFBoaWxp cHBlIENvcm51IDxwaGlsaXBwZS5jb3JudUBzdC5jb20+CisgKgorICogTW9kaWZpZWQgYnkgWWFu bmljayBGZXJ0cmUgPHlhbm5pY2suZmVydHJlQHN0LmNvbT4KKyAqIFRoaXMgZ2VuZXJpYyBTeW5v cHN5cyBEZXNpZ25XYXJlIE1JUEkgRFNJIGhvc3QgZHJpdmVyIGlzIGJhc2VkIG9uIHRoZQorICog YnJpZGdlIHN5bm9wc3lzIGZyb20gaW5jbHVkZS9kcm0vYnJpZGdlL2R3X21pcGlfZHNpLmggKGtl cm5lbCBsaW51eCkuCisgKgorICogU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEdQTC0yLjAKKyAq LworCisjaWZuZGVmIF9fRFdfTUlQSV9EU0lfXworI2RlZmluZSBfX0RXX01JUElfRFNJX18KKwor I2luY2x1ZGUgPG1pcGlfZGlzcGxheS5oPgorCitzdHJ1Y3QgZHdfbWlwaV9kc2lfcGh5X29wcyB7 CisJaW50ICgqaW5pdCkodm9pZCAqcHJpdl9kYXRhKTsKKwlpbnQgKCpnZXRfbGFuZV9tYnBzKSh2 b2lkICpwcml2X2RhdGEsIHN0cnVjdCBkaXNwbGF5X3RpbWluZyAqdGltaW5ncywKKwkJCSAgICAg dTMyIGxhbmVzLCB1MzIgZm9ybWF0LCB1bnNpZ25lZCBpbnQgKmxhbmVfbWJwcyk7Cit9OworCitz dHJ1Y3QgZHdfbWlwaV9kc2lfcGxhdF9kYXRhIHsKKwl1bnNpZ25lZCBpbnQgbWF4X2RhdGFfbGFu ZXM7CisJY29uc3Qgc3RydWN0IGR3X21pcGlfZHNpX3BoeV9vcHMgKnBoeV9vcHM7CisJc3RydWN0 IHVkZXZpY2UgKnBhbmVsOworfTsKKworaW50IGR3X21pcGlfZHNpX2luaXRfYnJpZGdlKHN0cnVj dCBtaXBpX2RzaV9kZXZpY2UgKmRldmljZSk7Cit2b2lkIGR3X21pcGlfZHNpX2JyaWRnZV9lbmFi bGUoc3RydWN0IG1pcGlfZHNpX2RldmljZSAqZGV2aWNlKTsKKworI2VuZGlmIC8qIF9fRFdfTUlQ SV9EU0lfXyAqLwotLSAKMS45LjEKCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f X19fX19fX19fX19fCmRyaS1kZXZlbCBtYWlsaW5nIGxpc3QKZHJpLWRldmVsQGxpc3RzLmZyZWVk ZXNrdG9wLm9yZwpodHRwczovL2xpc3RzLmZyZWVkZXNrdG9wLm9yZy9tYWlsbWFuL2xpc3RpbmZv L2RyaS1kZXZlbAo= From mboxrd@z Thu Jan 1 00:00:00 1970 From: yannick fertre Date: Tue, 13 Mar 2018 14:50:08 +0100 Subject: [U-Boot] [PATCH v3 05/10] video: add MIPI DSI host controller bridge In-Reply-To: <1520949014-21468-1-git-send-email-yannick.fertre@st.com> References: <1520949014-21468-1-git-send-email-yannick.fertre@st.com> Message-ID: <1520949014-21468-10-git-send-email-yannick.fertre@st.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable To: u-boot@lists.denx.de Add a Synopsys Designware MIPI DSI host bridge driver, based on the Rockchip version from rockchip/dw-mipi-dsi.c with phy & bridge APIs. Signed-off-by: yannick fertre --- drivers/video/Kconfig | 9 + drivers/video/Makefile | 1 + drivers/video/dw_mipi_dsi.c | 822 ++++++++++++++++++++++++++++++++++++++++= ++++ include/dw_mipi_dsi.h | 34 ++ 4 files changed, 866 insertions(+) create mode 100644 drivers/video/dw_mipi_dsi.c create mode 100644 include/dw_mipi_dsi.h diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index b5fc535..0f641d7 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -657,6 +657,15 @@ config VIDEO_DW_HDMI rather requires a SoC-specific glue driver to call it), it can not be enabled from the configuration menu. =20 +config VIDEO_DW_MIPI_DSI + bool + help + Enables the common driver code for the Designware MIPI DSI + block found in SoCs from various vendors. + As this does not provide any functionality by itself (but + rather requires a SoC-specific glue driver to call it), it + can not be enabled from the configuration menu. + config VIDEO_SIMPLE bool "Simple display driver for preconfigured display" help diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 65002af..50be569 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_FORMIKE) +=3D formike.o obj-$(CONFIG_LG4573) +=3D lg4573.o obj-$(CONFIG_AM335X_LCD) +=3D am335x-fb.o obj-$(CONFIG_VIDEO_DW_HDMI) +=3D dw_hdmi.o +obj-$(CONFIG_VIDEO_DW_MIPI_DSI) +=3D dw_mipi_dsi.o obj-${CONFIG_VIDEO_MIPI_DSI} +=3D mipi_display.o obj-$(CONFIG_VIDEO_SIMPLE) +=3D simplefb.o obj-${CONFIG_VIDEO_TEGRA124} +=3D tegra124/ diff --git a/drivers/video/dw_mipi_dsi.c b/drivers/video/dw_mipi_dsi.c new file mode 100644 index 0000000..d7bd92d --- /dev/null +++ b/drivers/video/dw_mipi_dsi.c @@ -0,0 +1,822 @@ +/* + * Copyright (C) 2016, Fuzhou Rockchip Electronics Co., Ltd + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * Author(s): Philippe Cornu for STMicroelectronic= s. + * Yannick Fertre for STMicroelectronics. + * + * Modified by Yannick Fertre + * This generic Synopsys DesignWare MIPI DSI host driver is based on the + * bridge synopsys from drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c (ker= nel + * linux). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HWVER_131 0x31333100 /* IP version 1.31 */ + +#define DSI_VERSION 0x00 +#define VERSION GENMASK(31, 8) + +#define DSI_PWR_UP 0x04 +#define RESET 0 +#define POWERUP BIT(0) + +#define DSI_CLKMGR_CFG 0x08 +#define TO_CLK_DIVISION(div) (((div) & 0xff) << 8) +#define TX_ESC_CLK_DIVISION(div) ((div) & 0xff) + +#define DSI_DPI_VCID 0x0c +#define DPI_VCID(vcid) ((vcid) & 0x3) + +#define DSI_DPI_COLOR_CODING 0x10 +#define LOOSELY18_EN BIT(8) +#define DPI_COLOR_CODING_16BIT_1 0x0 +#define DPI_COLOR_CODING_16BIT_2 0x1 +#define DPI_COLOR_CODING_16BIT_3 0x2 +#define DPI_COLOR_CODING_18BIT_1 0x3 +#define DPI_COLOR_CODING_18BIT_2 0x4 +#define DPI_COLOR_CODING_24BIT 0x5 + +#define DSI_DPI_CFG_POL 0x14 +#define COLORM_ACTIVE_LOW BIT(4) +#define SHUTD_ACTIVE_LOW BIT(3) +#define HSYNC_ACTIVE_LOW BIT(2) +#define VSYNC_ACTIVE_LOW BIT(1) +#define DATAEN_ACTIVE_LOW BIT(0) + +#define DSI_DPI_LP_CMD_TIM 0x18 +#define OUTVACT_LPCMD_TIME(p) (((p) & 0xff) << 16) +#define INVACT_LPCMD_TIME(p) ((p) & 0xff) + +#define DSI_DBI_VCID 0x1c +#define DSI_DBI_CFG 0x20 +#define DSI_DBI_PARTITIONING_EN 0x24 +#define DSI_DBI_CMDSIZE 0x28 + +#define DSI_PCKHDL_CFG 0x2c +#define CRC_RX_EN BIT(4) +#define ECC_RX_EN BIT(3) +#define BTA_EN BIT(2) +#define EOTP_RX_EN BIT(1) +#define EOTP_TX_EN BIT(0) + +#define DSI_GEN_VCID 0x30 + +#define DSI_MODE_CFG 0x34 +#define ENABLE_VIDEO_MODE 0 +#define ENABLE_CMD_MODE BIT(0) + +#define DSI_VID_MODE_CFG 0x38 +#define ENABLE_LOW_POWER (0x3f << 8) +#define ENABLE_LOW_POWER_MASK (0x3f << 8) +#define VID_MODE_TYPE_NON_BURST_SYNC_PULSES 0x0 +#define VID_MODE_TYPE_NON_BURST_SYNC_EVENTS 0x1 +#define VID_MODE_TYPE_BURST 0x2 +#define VID_MODE_TYPE_MASK 0x3 + +#define DSI_VID_PKT_SIZE 0x3c +#define VID_PKT_SIZE(p) ((p) & 0x3fff) + +#define DSI_VID_NUM_CHUNKS 0x40 +#define VID_NUM_CHUNKS(c) ((c) & 0x1fff) + +#define DSI_VID_NULL_SIZE 0x44 +#define VID_NULL_SIZE(b) ((b) & 0x1fff) + +#define DSI_VID_HSA_TIME 0x48 +#define DSI_VID_HBP_TIME 0x4c +#define DSI_VID_HLINE_TIME 0x50 +#define DSI_VID_VSA_LINES 0x54 +#define DSI_VID_VBP_LINES 0x58 +#define DSI_VID_VFP_LINES 0x5c +#define DSI_VID_VACTIVE_LINES 0x60 +#define DSI_EDPI_CMD_SIZE 0x64 + +#define DSI_CMD_MODE_CFG 0x68 +#define MAX_RD_PKT_SIZE_LP BIT(24) +#define DCS_LW_TX_LP BIT(19) +#define DCS_SR_0P_TX_LP BIT(18) +#define DCS_SW_1P_TX_LP BIT(17) +#define DCS_SW_0P_TX_LP BIT(16) +#define GEN_LW_TX_LP BIT(14) +#define GEN_SR_2P_TX_LP BIT(13) +#define GEN_SR_1P_TX_LP BIT(12) +#define GEN_SR_0P_TX_LP BIT(11) +#define GEN_SW_2P_TX_LP BIT(10) +#define GEN_SW_1P_TX_LP BIT(9) +#define GEN_SW_0P_TX_LP BIT(8) +#define ACK_RQST_EN BIT(1) +#define TEAR_FX_EN BIT(0) + +#define CMD_MODE_ALL_LP (MAX_RD_PKT_SIZE_LP | \ + DCS_LW_TX_LP | \ + DCS_SR_0P_TX_LP | \ + DCS_SW_1P_TX_LP | \ + DCS_SW_0P_TX_LP | \ + GEN_LW_TX_LP | \ + GEN_SR_2P_TX_LP | \ + GEN_SR_1P_TX_LP | \ + GEN_SR_0P_TX_LP | \ + GEN_SW_2P_TX_LP | \ + GEN_SW_1P_TX_LP | \ + GEN_SW_0P_TX_LP) + +#define DSI_GEN_HDR 0x6c +#define DSI_GEN_PLD_DATA 0x70 + +#define DSI_CMD_PKT_STATUS 0x74 +#define GEN_RD_CMD_BUSY BIT(6) +#define GEN_PLD_R_FULL BIT(5) +#define GEN_PLD_R_EMPTY BIT(4) +#define GEN_PLD_W_FULL BIT(3) +#define GEN_PLD_W_EMPTY BIT(2) +#define GEN_CMD_FULL BIT(1) +#define GEN_CMD_EMPTY BIT(0) + +#define DSI_TO_CNT_CFG 0x78 +#define HSTX_TO_CNT(p) (((p) & 0xffff) << 16) +#define LPRX_TO_CNT(p) ((p) & 0xffff) + +#define DSI_HS_RD_TO_CNT 0x7c +#define DSI_LP_RD_TO_CNT 0x80 +#define DSI_HS_WR_TO_CNT 0x84 +#define DSI_LP_WR_TO_CNT 0x88 +#define DSI_BTA_TO_CNT 0x8c + +#define DSI_LPCLK_CTRL 0x94 +#define AUTO_CLKLANE_CTRL BIT(1) +#define PHY_TXREQUESTCLKHS BIT(0) + +#define DSI_PHY_TMR_LPCLK_CFG 0x98 +#define PHY_CLKHS2LP_TIME(lbcc) (((lbcc) & 0x3ff) << 16) +#define PHY_CLKLP2HS_TIME(lbcc) ((lbcc) & 0x3ff) + +#define DSI_PHY_TMR_CFG 0x9c +#define PHY_HS2LP_TIME(lbcc) (((lbcc) & 0xff) << 24) +#define PHY_LP2HS_TIME(lbcc) (((lbcc) & 0xff) << 16) +#define MAX_RD_TIME(lbcc) ((lbcc) & 0x7fff) +#define PHY_HS2LP_TIME_V131(lbcc) (((lbcc) & 0x3ff) << 16) +#define PHY_LP2HS_TIME_V131(lbcc) ((lbcc) & 0x3ff) + +#define DSI_PHY_RSTZ 0xa0 +#define PHY_DISFORCEPLL 0 +#define PHY_ENFORCEPLL BIT(3) +#define PHY_DISABLECLK 0 +#define PHY_ENABLECLK BIT(2) +#define PHY_RSTZ 0 +#define PHY_UNRSTZ BIT(1) +#define PHY_SHUTDOWNZ 0 +#define PHY_UNSHUTDOWNZ BIT(0) + +#define DSI_PHY_IF_CFG 0xa4 +#define PHY_STOP_WAIT_TIME(cycle) (((cycle) & 0xff) << 8) +#define N_LANES(n) (((n) - 1) & 0x3) + +#define DSI_PHY_ULPS_CTRL 0xa8 +#define DSI_PHY_TX_TRIGGERS 0xac + +#define DSI_PHY_STATUS 0xb0 +#define PHY_STOP_STATE_CLK_LANE BIT(2) +#define PHY_LOCK BIT(0) + +#define DSI_PHY_TST_CTRL0 0xb4 +#define PHY_TESTCLK BIT(1) +#define PHY_UNTESTCLK 0 +#define PHY_TESTCLR BIT(0) +#define PHY_UNTESTCLR 0 + +#define DSI_PHY_TST_CTRL1 0xb8 +#define PHY_TESTEN BIT(16) +#define PHY_UNTESTEN 0 +#define PHY_TESTDOUT(n) (((n) & 0xff) << 8) +#define PHY_TESTDIN(n) ((n) & 0xff) + +#define DSI_INT_ST0 0xbc +#define DSI_INT_ST1 0xc0 +#define DSI_INT_MSK0 0xc4 +#define DSI_INT_MSK1 0xc8 + +#define DSI_PHY_TMR_RD_CFG 0xf4 +#define MAX_RD_TIME_V131(lbcc) ((lbcc) & 0x7fff) + +#define PHY_STATUS_TIMEOUT_US 10000 +#define CMD_PKT_STATUS_TIMEOUT_US 20000 + +#define MSEC_PER_SEC 1000 + +struct dw_mipi_dsi { + struct mipi_dsi_host dsi_host; + struct mipi_dsi_device *device; + void __iomem *base; + unsigned int lane_mbps; /* per lane */ + u32 channel; + u32 lanes; + u32 format; + unsigned long mode_flags; + unsigned int max_data_lanes; + const struct dw_mipi_dsi_phy_ops *phy_ops; +}; + +static int dsi_mode_vrefresh(struct display_timing *timings) +{ + int refresh =3D 0; + unsigned int calc_val; + u32 htotal =3D timings->hactive.typ + timings->hfront_porch.typ + + timings->hback_porch.typ + timings->hsync_len.typ; + u32 vtotal =3D timings->vactive.typ + timings->vfront_porch.typ + + timings->vback_porch.typ + timings->vsync_len.typ; + + if (htotal > 0 && vtotal > 0) { + calc_val =3D timings->pixelclock.typ; + calc_val /=3D htotal; + refresh =3D (calc_val + vtotal / 2) / vtotal; + } + + return refresh; +} + +/* + * The controller should generate 2 frames before + * preparing the peripheral. + */ +static void dw_mipi_dsi_wait_for_two_frames(struct display_timing *timings) +{ + int refresh, two_frames; + + refresh =3D dsi_mode_vrefresh(timings); + two_frames =3D DIV_ROUND_UP(MSEC_PER_SEC, refresh) * 2; + mdelay(two_frames); +} + +static inline struct dw_mipi_dsi *host_to_dsi(struct mipi_dsi_host *host) +{ + return container_of(host, struct dw_mipi_dsi, dsi_host); +} + +static inline void dsi_write(struct dw_mipi_dsi *dsi, u32 reg, u32 val) +{ + writel(val, dsi->base + reg); +} + +static inline u32 dsi_read(struct dw_mipi_dsi *dsi, u32 reg) +{ + return readl(dsi->base + reg); +} + +static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, + struct mipi_dsi_device *device) +{ + struct dw_mipi_dsi *dsi =3D host_to_dsi(host); + + if (device->lanes > dsi->max_data_lanes) { + pr_err("the number of data lanes(%u) is too many\n", + device->lanes); + return -EINVAL; + } + + dsi->lanes =3D device->lanes; + dsi->channel =3D device->channel; + dsi->format =3D device->format; + dsi->mode_flags =3D device->mode_flags; + + return 0; +} + +static void dw_mipi_message_config(struct dw_mipi_dsi *dsi, + const struct mipi_dsi_msg *msg) +{ + bool lpm =3D msg->flags & MIPI_DSI_MSG_USE_LPM; + u32 val =3D 0; + + if (msg->flags & MIPI_DSI_MSG_REQ_ACK) + val |=3D ACK_RQST_EN; + if (lpm) + val |=3D CMD_MODE_ALL_LP; + + dsi_write(dsi, DSI_LPCLK_CTRL, lpm ? 0 : PHY_TXREQUESTCLKHS); + dsi_write(dsi, DSI_CMD_MODE_CFG, val); +} + +static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_= val) +{ + int ret; + u32 val, mask; + + ret =3D readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, + val, !(val & GEN_CMD_FULL), + CMD_PKT_STATUS_TIMEOUT_US); + if (ret < 0) { + pr_err("failed to get available command FIFO\n"); + return ret; + } + + dsi_write(dsi, DSI_GEN_HDR, hdr_val); + + mask =3D GEN_CMD_EMPTY | GEN_PLD_W_EMPTY; + ret =3D readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, + val, (val & mask) =3D=3D mask, + CMD_PKT_STATUS_TIMEOUT_US); + if (ret < 0) { + pr_err("failed to write command FIFO\n"); + return ret; + } + + return 0; +} + +static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi, + const struct mipi_dsi_packet *packet) +{ + const u8 *tx_buf =3D packet->payload; + int len =3D packet->payload_length, pld_data_bytes =3D sizeof(u32), ret; + __le32 word; + u32 val; + + while (len) { + if (len < pld_data_bytes) { + word =3D 0; + memcpy(&word, tx_buf, len); + dsi_write(dsi, DSI_GEN_PLD_DATA, le32_to_cpu(word)); + len =3D 0; + } else { + memcpy(&word, tx_buf, pld_data_bytes); + dsi_write(dsi, DSI_GEN_PLD_DATA, le32_to_cpu(word)); + tx_buf +=3D pld_data_bytes; + len -=3D pld_data_bytes; + } + + ret =3D readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, + val, !(val & GEN_PLD_W_FULL), + CMD_PKT_STATUS_TIMEOUT_US); + if (ret < 0) { + dev_err(dsi->dev, + "failed to get available write payload FIFO\n"); + return ret; + } + } + + word =3D 0; + memcpy(&word, packet->header, sizeof(packet->header)); + return dw_mipi_dsi_gen_pkt_hdr_write(dsi, le32_to_cpu(word)); +} + +static int dw_mipi_dsi_read(struct dw_mipi_dsi *dsi, + const struct mipi_dsi_msg *msg) +{ + int i, j, ret, len =3D msg->rx_len; + u8 *buf =3D msg->rx_buf; + u32 val; + + /* Wait end of the read operation */ + ret =3D readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, + val, !(val & GEN_RD_CMD_BUSY), + CMD_PKT_STATUS_TIMEOUT_US); + if (ret) { + dev_err(dsi->dev, "Timeout during read operation\n"); + return ret; + } + + for (i =3D 0; i < len; i +=3D 4) { + /* Read fifo must not be empty before all bytes are read */ + ret =3D readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS, + val, !(val & GEN_PLD_R_EMPTY), + CMD_PKT_STATUS_TIMEOUT_US); + if (ret) { + dev_err(dsi->dev, "Read payload FIFO is empty\n"); + return ret; + } + + val =3D dsi_read(dsi, DSI_GEN_PLD_DATA); + for (j =3D 0; j < 4 && j + i < len; j++) + buf[i + j] =3D val >> (8 * j); + } + + return ret; +} + +static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, + const struct mipi_dsi_msg *msg) +{ + struct dw_mipi_dsi *dsi =3D host_to_dsi(host); + struct mipi_dsi_packet packet; + int ret, nb_bytes; + + ret =3D mipi_dsi_create_packet(&packet, msg); + if (ret) { + dev_err(dsi->dev, "failed to create packet: %d\n", ret); + return ret; + } + + dw_mipi_message_config(dsi, msg); + + ret =3D dw_mipi_dsi_write(dsi, &packet); + if (ret) + return ret; + + if (msg->rx_buf && msg->rx_len) { + ret =3D dw_mipi_dsi_read(dsi, msg); + if (ret) + return ret; + nb_bytes =3D msg->rx_len; + } else { + nb_bytes =3D packet.size; + } + + return nb_bytes; +} + +static const struct mipi_dsi_host_ops dw_mipi_dsi_host_ops =3D { + .attach =3D dw_mipi_dsi_host_attach, + .transfer =3D dw_mipi_dsi_host_transfer, +}; + +static void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi) +{ + u32 val; + + /* + * TODO dw drv improvements + * enabling low power is panel-dependent, we should use the + * panel configuration here... + */ + val =3D ENABLE_LOW_POWER; + + if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) + val |=3D VID_MODE_TYPE_BURST; + else if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) + val |=3D VID_MODE_TYPE_NON_BURST_SYNC_PULSES; + else + val |=3D VID_MODE_TYPE_NON_BURST_SYNC_EVENTS; + + dsi_write(dsi, DSI_VID_MODE_CFG, val); +} + +static void dw_mipi_dsi_set_mode(struct dw_mipi_dsi *dsi, + unsigned long mode_flags) +{ + dsi_write(dsi, DSI_PWR_UP, RESET); + + if (mode_flags & MIPI_DSI_MODE_VIDEO) { + dsi_write(dsi, DSI_MODE_CFG, ENABLE_VIDEO_MODE); + dw_mipi_dsi_video_mode_config(dsi); + dsi_write(dsi, DSI_LPCLK_CTRL, PHY_TXREQUESTCLKHS); + } else { + dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE); + } + + dsi_write(dsi, DSI_PWR_UP, POWERUP); +} + +static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi) +{ + /* + * The maximum permitted escape clock is 20MHz and it is derived from + * lanebyteclk, which is running at "lane_mbps / 8". Thus we want: + * + * (lane_mbps >> 3) / esc_clk_division < 20 + * which is: + * (lane_mbps >> 3) / 20 > esc_clk_division + */ + u32 esc_clk_division =3D (dsi->lane_mbps >> 3) / 20 + 1; + + dsi_write(dsi, DSI_PWR_UP, RESET); + + /* + * TODO dw drv improvements + * timeout clock division should be computed with the + * high speed transmission counter timeout and byte lane... + */ + dsi_write(dsi, DSI_CLKMGR_CFG, TO_CLK_DIVISION(10) | + TX_ESC_CLK_DIVISION(esc_clk_division)); +} + +static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi, + struct display_timing *timings) +{ + u32 val =3D 0, color =3D 0; + + switch (dsi->format) { + case MIPI_DSI_FMT_RGB888: + color =3D DPI_COLOR_CODING_24BIT; + break; + case MIPI_DSI_FMT_RGB666: + color =3D DPI_COLOR_CODING_18BIT_2 | LOOSELY18_EN; + break; + case MIPI_DSI_FMT_RGB666_PACKED: + color =3D DPI_COLOR_CODING_18BIT_1; + break; + case MIPI_DSI_FMT_RGB565: + color =3D DPI_COLOR_CODING_16BIT_1; + break; + } + + if (dsi->mode_flags & DISPLAY_FLAGS_VSYNC_HIGH) + val |=3D VSYNC_ACTIVE_LOW; + if (dsi->mode_flags & DISPLAY_FLAGS_HSYNC_HIGH) + val |=3D HSYNC_ACTIVE_LOW; + + dsi_write(dsi, DSI_DPI_VCID, DPI_VCID(dsi->channel)); + dsi_write(dsi, DSI_DPI_COLOR_CODING, color); + dsi_write(dsi, DSI_DPI_CFG_POL, val); + /* + * TODO dw drv improvements + * largest packet sizes during hfp or during vsa/vpb/vfp + * should be computed according to byte lane, lane number and only + * if sending lp cmds in high speed is enable (PHY_TXREQUESTCLKHS) + */ + dsi_write(dsi, DSI_DPI_LP_CMD_TIM, OUTVACT_LPCMD_TIME(4) + | INVACT_LPCMD_TIME(4)); +} + +static void dw_mipi_dsi_packet_handler_config(struct dw_mipi_dsi *dsi) +{ + dsi_write(dsi, DSI_PCKHDL_CFG, CRC_RX_EN | ECC_RX_EN | BTA_EN); +} + +static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi, + struct display_timing *timings) +{ + /* + * TODO dw drv improvements + * only burst mode is supported here. For non-burst video modes, + * we should compute DSI_VID_PKT_SIZE, DSI_VCCR.NUMC & + * DSI_VNPCR.NPSIZE... especially because this driver supports + * non-burst video modes, see dw_mipi_dsi_video_mode_config()... + */ + dsi_write(dsi, DSI_VID_PKT_SIZE, VID_PKT_SIZE(timings->hactive.typ)); +} + +static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi) +{ + /* + * TODO dw drv improvements + * compute high speed transmission counter timeout according + * to the timeout clock division (TO_CLK_DIVISION) and byte lane... + */ + dsi_write(dsi, DSI_TO_CNT_CFG, HSTX_TO_CNT(1000) | LPRX_TO_CNT(1000)); + /* + * TODO dw drv improvements + * the Bus-Turn-Around Timeout Counter should be computed + * according to byte lane... + */ + dsi_write(dsi, DSI_BTA_TO_CNT, 0xd00); + dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE); +} + +/* Get lane byte clock cycles. */ +static u32 dw_mipi_dsi_get_hcomponent_lbcc(struct dw_mipi_dsi *dsi, + struct display_timing *timings, + u32 hcomponent) +{ + u32 frac, lbcc; + + lbcc =3D hcomponent * dsi->lane_mbps * MSEC_PER_SEC / 8; + + frac =3D lbcc % (timings->pixelclock.typ / 1000); + lbcc =3D lbcc / (timings->pixelclock.typ / 1000); + if (frac) + lbcc++; + + return lbcc; +} + +static void dw_mipi_dsi_line_timer_config(struct dw_mipi_dsi *dsi, + struct display_timing *timings) +{ + u32 htotal, hsa, hbp, lbcc; + + htotal =3D timings->hactive.typ + timings->hfront_porch.typ + + timings->hback_porch.typ + timings->hsync_len.typ; + + hsa =3D timings->hback_porch.typ; + hbp =3D timings->hsync_len.typ; + + /* + * TODO dw drv improvements + * computations below may be improved... + */ + lbcc =3D dw_mipi_dsi_get_hcomponent_lbcc(dsi, timings, htotal); + dsi_write(dsi, DSI_VID_HLINE_TIME, lbcc); + + lbcc =3D dw_mipi_dsi_get_hcomponent_lbcc(dsi, timings, hsa); + dsi_write(dsi, DSI_VID_HSA_TIME, lbcc); + + lbcc =3D dw_mipi_dsi_get_hcomponent_lbcc(dsi, timings, hbp); + dsi_write(dsi, DSI_VID_HBP_TIME, lbcc); +} + +static void dw_mipi_dsi_vertical_timing_config(struct dw_mipi_dsi *dsi, + struct display_timing *timings) +{ + u32 vactive, vsa, vfp, vbp; + + vactive =3D timings->vactive.typ; + vsa =3D timings->vback_porch.typ; + vfp =3D timings->vfront_porch.typ; + vbp =3D timings->vsync_len.typ; + + dsi_write(dsi, DSI_VID_VACTIVE_LINES, vactive); + dsi_write(dsi, DSI_VID_VSA_LINES, vsa); + dsi_write(dsi, DSI_VID_VFP_LINES, vfp); + dsi_write(dsi, DSI_VID_VBP_LINES, vbp); +} + +static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi) +{ + u32 hw_version; + + /* + * TODO dw drv improvements + * data & clock lane timers should be computed according to panel + * blankings and to the automatic clock lane control mode... + * note: DSI_PHY_TMR_CFG.MAX_RD_TIME should be in line with + * DSI_CMD_MODE_CFG.MAX_RD_PKT_SIZE_LP (see CMD_MODE_ALL_LP) + */ + + hw_version =3D dsi_read(dsi, DSI_VERSION) & VERSION; + + if (hw_version >=3D HWVER_131) { + dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME_V131(0x40) | + PHY_LP2HS_TIME_V131(0x40)); + dsi_write(dsi, DSI_PHY_TMR_RD_CFG, MAX_RD_TIME_V131(10000)); + } else { + dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME(0x40) | + PHY_LP2HS_TIME(0x40) | MAX_RD_TIME(10000)); + } + + dsi_write(dsi, DSI_PHY_TMR_LPCLK_CFG, PHY_CLKHS2LP_TIME(0x40) + | PHY_CLKLP2HS_TIME(0x40)); +} + +static void dw_mipi_dsi_dphy_interface_config(struct dw_mipi_dsi *dsi) +{ + /* + * TODO dw drv improvements + * stop wait time should be the maximum between host dsi + * and panel stop wait times + */ + dsi_write(dsi, DSI_PHY_IF_CFG, PHY_STOP_WAIT_TIME(0x20) | + N_LANES(dsi->lanes)); +} + +static void dw_mipi_dsi_dphy_init(struct dw_mipi_dsi *dsi) +{ + /* Clear PHY state */ + dsi_write(dsi, DSI_PHY_RSTZ, PHY_DISFORCEPLL | PHY_DISABLECLK + | PHY_RSTZ | PHY_SHUTDOWNZ); + dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLR); + dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLR); + dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLR); +} + +static void dw_mipi_dsi_dphy_enable(struct dw_mipi_dsi *dsi) +{ + u32 val; + int ret; + + dsi_write(dsi, DSI_PHY_RSTZ, PHY_ENFORCEPLL | PHY_ENABLECLK | + PHY_UNRSTZ | PHY_UNSHUTDOWNZ); + + ret =3D readl_poll_timeout(dsi->base + DSI_PHY_STATUS, val, + val & PHY_LOCK, PHY_STATUS_TIMEOUT_US); + if (ret < 0) + pr_err("failed to wait phy lock state\n"); + + ret =3D readl_poll_timeout(dsi->base + DSI_PHY_STATUS, + val, val & PHY_STOP_STATE_CLK_LANE, + PHY_STATUS_TIMEOUT_US); + if (ret < 0) + pr_err("failed to wait phy clk lane stop state\n"); +} + +static void dw_mipi_dsi_clear_err(struct dw_mipi_dsi *dsi) +{ + dsi_read(dsi, DSI_INT_ST0); + dsi_read(dsi, DSI_INT_ST1); + dsi_write(dsi, DSI_INT_MSK0, 0); + dsi_write(dsi, DSI_INT_MSK1, 0); +} + +static void dw_mipi_dsi_bridge_set(struct dw_mipi_dsi *dsi, + struct display_timing *timings) +{ + const struct dw_mipi_dsi_phy_ops *phy_ops =3D dsi->phy_ops; + int ret; + + ret =3D phy_ops->get_lane_mbps(dsi->device, timings, dsi->lanes, + dsi->format, &dsi->lane_mbps); + if (ret) + pr_err("Phy get_lane_mbps() failed\n"); + + dw_mipi_dsi_init(dsi); + dw_mipi_dsi_dpi_config(dsi, timings); + dw_mipi_dsi_packet_handler_config(dsi); + dw_mipi_dsi_video_mode_config(dsi); + dw_mipi_dsi_video_packet_config(dsi, timings); + dw_mipi_dsi_command_mode_config(dsi); + dw_mipi_dsi_line_timer_config(dsi, timings); + dw_mipi_dsi_vertical_timing_config(dsi, timings); + + dw_mipi_dsi_dphy_init(dsi); + dw_mipi_dsi_dphy_timing_config(dsi); + dw_mipi_dsi_dphy_interface_config(dsi); + + dw_mipi_dsi_clear_err(dsi); + + ret =3D phy_ops->init(dsi->device); + if (ret) + pr_err("Phy init() failed\n"); + + dw_mipi_dsi_dphy_enable(dsi); + + dw_mipi_dsi_wait_for_two_frames(timings); + + /* Switch to cmd mode for panel-bridge pre_enable & panel prepare */ + dw_mipi_dsi_set_mode(dsi, 0); +} + +void dw_mipi_dsi_bridge_enable(struct mipi_dsi_device *device) +{ + struct mipi_dsi_host *host =3D device->host; + struct dw_mipi_dsi *dsi =3D host_to_dsi(host); + + /* Switch to video mode for panel-bridge enable & panel enable */ + dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO); +} +EXPORT_SYMBOL_GPL(dw_mipi_dsi_bridge_enable); + +int dw_mipi_dsi_init_bridge(struct mipi_dsi_device *device) +{ + struct dw_mipi_dsi_plat_data *platdata =3D dev_get_platdata(device->dev); + struct display_timing timings; + struct dw_mipi_dsi *dsi; + struct clk clk; + int ret; + + dsi =3D kzalloc(sizeof(*dsi), GFP_KERNEL); + + dsi->phy_ops =3D platdata->phy_ops; + dsi->max_data_lanes =3D platdata->max_data_lanes; + dsi->device =3D device; + dsi->dsi_host.ops =3D &dw_mipi_dsi_host_ops; + device->host =3D &dsi->dsi_host; + + /* TODO Get these settings from panel */ + dsi->lanes =3D 2; + dsi->format =3D MIPI_DSI_FMT_RGB888; + dsi->mode_flags =3D MIPI_DSI_MODE_VIDEO | + MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM; + + dsi->base =3D (void *)dev_read_addr(device->dev); + if ((fdt_addr_t)dsi->base =3D=3D FDT_ADDR_T_NONE) { + pr_err("%s: dsi dt register address error\n", __func__); + return -EINVAL; + } + + ret =3D fdtdec_decode_display_timing(gd->fdt_blob, + dev_of_offset(platdata->panel), + 0, &timings); + if (ret) { + pr_err("%s: decode display timing error %d\n", __func__, ret); + return ret; + } + + if (!dsi->phy_ops->init || !dsi->phy_ops->get_lane_mbps) { + pr_err("Phy not properly configured\n"); + return -ENODEV; + } + + ret =3D clk_get_by_name(device->dev, "px_clk", &clk); + if (ret) { + pr_err("%s: peripheral clock get error %d\n", __func__, ret); + return ret; + } + + /* get the pixel clock set by the clock framework */ + timings.pixelclock.typ =3D clk_get_rate(&clk); + + dw_mipi_dsi_bridge_set(dsi, &timings); + + return 0; +} +EXPORT_SYMBOL_GPL(dw_mipi_dsi_init_bridge); + +MODULE_AUTHOR("Chris Zhong "); +MODULE_AUTHOR("Philippe Cornu "); +MODULE_AUTHOR("Yannick Fertr=C3=A9 "); +MODULE_DESCRIPTION("DW MIPI DSI host controller driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:dw-mipi-dsi"); diff --git a/include/dw_mipi_dsi.h b/include/dw_mipi_dsi.h new file mode 100644 index 0000000..266c94b --- /dev/null +++ b/include/dw_mipi_dsi.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2017-2018, STMicroelectronics - All Rights Reserved + * + * Authors: Yannick Fertre + * Philippe Cornu + * + * Modified by Yannick Fertre + * This generic Synopsys DesignWare MIPI DSI host driver is based on the + * bridge synopsys from include/drm/bridge/dw_mipi_dsi.h (kernel linux). + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __DW_MIPI_DSI__ +#define __DW_MIPI_DSI__ + +#include + +struct dw_mipi_dsi_phy_ops { + int (*init)(void *priv_data); + int (*get_lane_mbps)(void *priv_data, struct display_timing *timings, + u32 lanes, u32 format, unsigned int *lane_mbps); +}; + +struct dw_mipi_dsi_plat_data { + unsigned int max_data_lanes; + const struct dw_mipi_dsi_phy_ops *phy_ops; + struct udevice *panel; +}; + +int dw_mipi_dsi_init_bridge(struct mipi_dsi_device *device); +void dw_mipi_dsi_bridge_enable(struct mipi_dsi_device *device); + +#endif /* __DW_MIPI_DSI__ */ --=20 1.9.1