Path: blob/master/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi2.c
26516 views
// SPDX-License-Identifier: GPL-2.0+1/*2* Copyright (c) 2024, Fuzhou Rockchip Electronics Co., Ltd3*4* Modified by Heiko Stuebner <[email protected]>5* This generic Synopsys DesignWare MIPI DSI2 host driver is based on the6* Rockchip version from rockchip/dw-mipi-dsi2.c converted to use bridge APIs.7*/89#include <linux/bitfield.h>10#include <linux/clk.h>11#include <linux/export.h>12#include <linux/iopoll.h>13#include <linux/media-bus-format.h>14#include <linux/module.h>15#include <linux/platform_device.h>16#include <linux/pm_runtime.h>17#include <linux/reset.h>1819#include <video/mipi_display.h>2021#include <drm/bridge/dw_mipi_dsi2.h>22#include <drm/drm_atomic_helper.h>23#include <drm/drm_bridge.h>24#include <drm/drm_mipi_dsi.h>25#include <drm/drm_of.h>26#include <drm/drm_print.h>2728#define DSI2_PWR_UP 0x000c29#define RESET 030#define POWER_UP BIT(0)31#define CMD_TX_MODE(x) FIELD_PREP(BIT(24), x)32#define DSI2_SOFT_RESET 0x001033#define SYS_RSTN BIT(2)34#define PHY_RSTN BIT(1)35#define IPI_RSTN BIT(0)36#define INT_ST_MAIN 0x001437#define DSI2_MODE_CTRL 0x001838#define DSI2_MODE_STATUS 0x001c39#define DSI2_CORE_STATUS 0x002040#define PRI_RD_DATA_AVAIL BIT(26)41#define PRI_FIFOS_NOT_EMPTY BIT(25)42#define PRI_BUSY BIT(24)43#define CRI_RD_DATA_AVAIL BIT(18)44#define CRT_FIFOS_NOT_EMPTY BIT(17)45#define CRI_BUSY BIT(16)46#define IPI_FIFOS_NOT_EMPTY BIT(9)47#define IPI_BUSY BIT(8)48#define CORE_FIFOS_NOT_EMPTY BIT(1)49#define CORE_BUSY BIT(0)50#define MANUAL_MODE_CFG 0x002451#define MANUAL_MODE_EN BIT(0)52#define DSI2_TIMEOUT_HSTX_CFG 0x004853#define TO_HSTX(x) FIELD_PREP(GENMASK(15, 0), x)54#define DSI2_TIMEOUT_HSTXRDY_CFG 0x004c55#define TO_HSTXRDY(x) FIELD_PREP(GENMASK(15, 0), x)56#define DSI2_TIMEOUT_LPRX_CFG 0x005057#define TO_LPRXRDY(x) FIELD_PREP(GENMASK(15, 0), x)58#define DSI2_TIMEOUT_LPTXRDY_CFG 0x005459#define TO_LPTXRDY(x) FIELD_PREP(GENMASK(15, 0), x)60#define DSI2_TIMEOUT_LPTXTRIG_CFG 0x005861#define TO_LPTXTRIG(x) FIELD_PREP(GENMASK(15, 0), x)62#define DSI2_TIMEOUT_LPTXULPS_CFG 0x005c63#define TO_LPTXULPS(x) FIELD_PREP(GENMASK(15, 0), x)64#define DSI2_TIMEOUT_BTA_CFG 0x6065#define TO_BTA(x) FIELD_PREP(GENMASK(15, 0), x)6667#define DSI2_PHY_MODE_CFG 0x010068#define PPI_WIDTH(x) FIELD_PREP(GENMASK(9, 8), x)69#define PHY_LANES(x) FIELD_PREP(GENMASK(5, 4), (x) - 1)70#define PHY_TYPE(x) FIELD_PREP(BIT(0), x)71#define DSI2_PHY_CLK_CFG 0X010472#define PHY_LPTX_CLK_DIV(x) FIELD_PREP(GENMASK(12, 8), x)73#define CLK_TYPE_MASK BIT(0)74#define NON_CONTINUOUS_CLK BIT(0)75#define CONTINUOUS_CLK 076#define DSI2_PHY_LP2HS_MAN_CFG 0x010c77#define PHY_LP2HS_TIME(x) FIELD_PREP(GENMASK(28, 0), x)78#define DSI2_PHY_HS2LP_MAN_CFG 0x011479#define PHY_HS2LP_TIME(x) FIELD_PREP(GENMASK(28, 0), x)80#define DSI2_PHY_MAX_RD_T_MAN_CFG 0x011c81#define PHY_MAX_RD_TIME(x) FIELD_PREP(GENMASK(26, 0), x)82#define DSI2_PHY_ESC_CMD_T_MAN_CFG 0x012483#define PHY_ESC_CMD_TIME(x) FIELD_PREP(GENMASK(28, 0), x)84#define DSI2_PHY_ESC_BYTE_T_MAN_CFG 0x012c85#define PHY_ESC_BYTE_TIME(x) FIELD_PREP(GENMASK(28, 0), x)8687#define DSI2_PHY_IPI_RATIO_MAN_CFG 0x013488#define PHY_IPI_RATIO(x) FIELD_PREP(GENMASK(21, 0), x)89#define DSI2_PHY_SYS_RATIO_MAN_CFG 0x013C90#define PHY_SYS_RATIO(x) FIELD_PREP(GENMASK(16, 0), x)9192#define DSI2_DSI_GENERAL_CFG 0x020093#define BTA_EN BIT(1)94#define EOTP_TX_EN BIT(0)95#define DSI2_DSI_VCID_CFG 0x020496#define TX_VCID(x) FIELD_PREP(GENMASK(1, 0), x)97#define DSI2_DSI_SCRAMBLING_CFG 0x020898#define SCRAMBLING_SEED(x) FIELD_PREP(GENMASK(31, 16), x)99#define SCRAMBLING_EN BIT(0)100#define DSI2_DSI_VID_TX_CFG 0x020c101#define LPDT_DISPLAY_CMD_EN BIT(20)102#define BLK_VFP_HS_EN BIT(14)103#define BLK_VBP_HS_EN BIT(13)104#define BLK_VSA_HS_EN BIT(12)105#define BLK_HFP_HS_EN BIT(6)106#define BLK_HBP_HS_EN BIT(5)107#define BLK_HSA_HS_EN BIT(4)108#define VID_MODE_TYPE(x) FIELD_PREP(GENMASK(1, 0), x)109#define DSI2_CRI_TX_HDR 0x02c0110#define CMD_TX_MODE(x) FIELD_PREP(BIT(24), x)111#define DSI2_CRI_TX_PLD 0x02c4112#define DSI2_CRI_RX_HDR 0x02c8113#define DSI2_CRI_RX_PLD 0x02cc114115#define DSI2_IPI_COLOR_MAN_CFG 0x0300116#define IPI_DEPTH(x) FIELD_PREP(GENMASK(7, 4), x)117#define IPI_DEPTH_5_6_5_BITS 0x02118#define IPI_DEPTH_6_BITS 0x03119#define IPI_DEPTH_8_BITS 0x05120#define IPI_DEPTH_10_BITS 0x06121#define IPI_FORMAT(x) FIELD_PREP(GENMASK(3, 0), x)122#define IPI_FORMAT_RGB 0x0123#define IPI_FORMAT_DSC 0x0b124#define DSI2_IPI_VID_HSA_MAN_CFG 0x0304125#define VID_HSA_TIME(x) FIELD_PREP(GENMASK(29, 0), x)126#define DSI2_IPI_VID_HBP_MAN_CFG 0x030c127#define VID_HBP_TIME(x) FIELD_PREP(GENMASK(29, 0), x)128#define DSI2_IPI_VID_HACT_MAN_CFG 0x0314129#define VID_HACT_TIME(x) FIELD_PREP(GENMASK(29, 0), x)130#define DSI2_IPI_VID_HLINE_MAN_CFG 0x031c131#define VID_HLINE_TIME(x) FIELD_PREP(GENMASK(29, 0), x)132#define DSI2_IPI_VID_VSA_MAN_CFG 0x0324133#define VID_VSA_LINES(x) FIELD_PREP(GENMASK(9, 0), x)134#define DSI2_IPI_VID_VBP_MAN_CFG 0X032C135#define VID_VBP_LINES(x) FIELD_PREP(GENMASK(9, 0), x)136#define DSI2_IPI_VID_VACT_MAN_CFG 0X0334137#define VID_VACT_LINES(x) FIELD_PREP(GENMASK(13, 0), x)138#define DSI2_IPI_VID_VFP_MAN_CFG 0X033C139#define VID_VFP_LINES(x) FIELD_PREP(GENMASK(9, 0), x)140#define DSI2_IPI_PIX_PKT_CFG 0x0344141#define MAX_PIX_PKT(x) FIELD_PREP(GENMASK(15, 0), x)142143#define DSI2_INT_ST_PHY 0x0400144#define DSI2_INT_MASK_PHY 0x0404145#define DSI2_INT_ST_TO 0x0410146#define DSI2_INT_MASK_TO 0x0414147#define DSI2_INT_ST_ACK 0x0420148#define DSI2_INT_MASK_ACK 0x0424149#define DSI2_INT_ST_IPI 0x0430150#define DSI2_INT_MASK_IPI 0x0434151#define DSI2_INT_ST_FIFO 0x0440152#define DSI2_INT_MASK_FIFO 0x0444153#define DSI2_INT_ST_PRI 0x0450154#define DSI2_INT_MASK_PRI 0x0454155#define DSI2_INT_ST_CRI 0x0460156#define DSI2_INT_MASK_CRI 0x0464157#define DSI2_INT_FORCE_CRI 0x0468158#define DSI2_MAX_REGISGER DSI2_INT_FORCE_CRI159160#define MODE_STATUS_TIMEOUT_US 10000161#define CMD_PKT_STATUS_TIMEOUT_US 20000162163enum vid_mode_type {164VID_MODE_TYPE_NON_BURST_SYNC_PULSES,165VID_MODE_TYPE_NON_BURST_SYNC_EVENTS,166VID_MODE_TYPE_BURST,167};168169enum mode_ctrl {170IDLE_MODE,171AUTOCALC_MODE,172COMMAND_MODE,173VIDEO_MODE,174DATA_STREAM_MODE,175VIDEO_TEST_MODE,176DATA_STREAM_TEST_MODE,177};178179enum ppi_width {180PPI_WIDTH_8_BITS,181PPI_WIDTH_16_BITS,182PPI_WIDTH_32_BITS,183};184185struct cmd_header {186u8 cmd_type;187u8 delay;188u8 payload_length;189};190191struct dw_mipi_dsi2 {192struct drm_bridge bridge;193struct mipi_dsi_host dsi_host;194struct drm_bridge *panel_bridge;195struct device *dev;196struct regmap *regmap;197struct clk *pclk;198struct clk *sys_clk;199200unsigned int lane_mbps; /* per lane */201u32 channel;202u32 lanes;203u32 format;204unsigned long mode_flags;205206struct drm_display_mode mode;207const struct dw_mipi_dsi2_plat_data *plat_data;208};209210static inline struct dw_mipi_dsi2 *host_to_dsi2(struct mipi_dsi_host *host)211{212return container_of(host, struct dw_mipi_dsi2, dsi_host);213}214215static inline struct dw_mipi_dsi2 *bridge_to_dsi2(struct drm_bridge *bridge)216{217return container_of(bridge, struct dw_mipi_dsi2, bridge);218}219220static int cri_fifos_wait_avail(struct dw_mipi_dsi2 *dsi2)221{222u32 sts, mask;223int ret;224225mask = CRI_BUSY | CRT_FIFOS_NOT_EMPTY;226ret = regmap_read_poll_timeout(dsi2->regmap, DSI2_CORE_STATUS, sts,227!(sts & mask), 0, CMD_PKT_STATUS_TIMEOUT_US);228if (ret < 0) {229dev_err(dsi2->dev, "command interface is busy\n");230return ret;231}232233return 0;234}235236static void dw_mipi_dsi2_set_vid_mode(struct dw_mipi_dsi2 *dsi2)237{238u32 val = 0, mode;239int ret;240241if (dsi2->mode_flags & MIPI_DSI_MODE_VIDEO_NO_HFP)242val |= BLK_HFP_HS_EN;243244if (dsi2->mode_flags & MIPI_DSI_MODE_VIDEO_NO_HBP)245val |= BLK_HBP_HS_EN;246247if (dsi2->mode_flags & MIPI_DSI_MODE_VIDEO_NO_HSA)248val |= BLK_HSA_HS_EN;249250if (dsi2->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)251val |= VID_MODE_TYPE_BURST;252else if (dsi2->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)253val |= VID_MODE_TYPE_NON_BURST_SYNC_PULSES;254else255val |= VID_MODE_TYPE_NON_BURST_SYNC_EVENTS;256257regmap_write(dsi2->regmap, DSI2_DSI_VID_TX_CFG, val);258259regmap_write(dsi2->regmap, DSI2_MODE_CTRL, VIDEO_MODE);260ret = regmap_read_poll_timeout(dsi2->regmap, DSI2_MODE_STATUS,261mode, mode & VIDEO_MODE,2621000, MODE_STATUS_TIMEOUT_US);263if (ret < 0)264dev_err(dsi2->dev, "failed to enter video mode\n");265}266267static void dw_mipi_dsi2_set_data_stream_mode(struct dw_mipi_dsi2 *dsi2)268{269u32 mode;270int ret;271272regmap_write(dsi2->regmap, DSI2_MODE_CTRL, DATA_STREAM_MODE);273ret = regmap_read_poll_timeout(dsi2->regmap, DSI2_MODE_STATUS,274mode, mode & DATA_STREAM_MODE,2751000, MODE_STATUS_TIMEOUT_US);276if (ret < 0)277dev_err(dsi2->dev, "failed to enter data stream mode\n");278}279280static void dw_mipi_dsi2_set_cmd_mode(struct dw_mipi_dsi2 *dsi2)281{282u32 mode;283int ret;284285regmap_write(dsi2->regmap, DSI2_MODE_CTRL, COMMAND_MODE);286ret = regmap_read_poll_timeout(dsi2->regmap, DSI2_MODE_STATUS,287mode, mode & COMMAND_MODE,2881000, MODE_STATUS_TIMEOUT_US);289if (ret < 0)290dev_err(dsi2->dev, "failed to enter data stream mode\n");291}292293static void dw_mipi_dsi2_host_softrst(struct dw_mipi_dsi2 *dsi2)294{295regmap_write(dsi2->regmap, DSI2_SOFT_RESET, 0x0);296usleep_range(50, 100);297regmap_write(dsi2->regmap, DSI2_SOFT_RESET,298SYS_RSTN | PHY_RSTN | IPI_RSTN);299}300301static void dw_mipi_dsi2_phy_clk_mode_cfg(struct dw_mipi_dsi2 *dsi2)302{303u32 sys_clk, esc_clk_div;304u32 val = 0;305306/*307* clk_type should be NON_CONTINUOUS_CLK before308* initial deskew calibration be sent.309*/310val |= NON_CONTINUOUS_CLK;311312/* The maximum value of the escape clock frequency is 20MHz */313sys_clk = clk_get_rate(dsi2->sys_clk) / USEC_PER_SEC;314esc_clk_div = DIV_ROUND_UP(sys_clk, 20 * 2);315val |= PHY_LPTX_CLK_DIV(esc_clk_div);316317regmap_write(dsi2->regmap, DSI2_PHY_CLK_CFG, val);318}319320static void dw_mipi_dsi2_phy_ratio_cfg(struct dw_mipi_dsi2 *dsi2)321{322struct drm_display_mode *mode = &dsi2->mode;323u64 sys_clk = clk_get_rate(dsi2->sys_clk);324u64 pixel_clk, ipi_clk, phy_hsclk;325u64 tmp;326327/*328* in DPHY mode, the phy_hstx_clk is exactly 1/16 the Lane high-speed329* data rate; In CPHY mode, the phy_hstx_clk is exactly 1/7 the trio330* high speed symbol rate.331*/332phy_hsclk = DIV_ROUND_CLOSEST_ULL(dsi2->lane_mbps * USEC_PER_SEC, 16);333334/* IPI_RATIO_MAN_CFG = PHY_HSTX_CLK / IPI_CLK */335pixel_clk = mode->crtc_clock * MSEC_PER_SEC;336ipi_clk = pixel_clk / 4;337338tmp = DIV_ROUND_CLOSEST_ULL(phy_hsclk << 16, ipi_clk);339regmap_write(dsi2->regmap, DSI2_PHY_IPI_RATIO_MAN_CFG,340PHY_IPI_RATIO(tmp));341342/*343* SYS_RATIO_MAN_CFG = MIPI_DCPHY_HSCLK_Freq / MIPI_DCPHY_HSCLK_Freq344*/345tmp = DIV_ROUND_CLOSEST_ULL(phy_hsclk << 16, sys_clk);346regmap_write(dsi2->regmap, DSI2_PHY_SYS_RATIO_MAN_CFG,347PHY_SYS_RATIO(tmp));348}349350static void dw_mipi_dsi2_lp2hs_or_hs2lp_cfg(struct dw_mipi_dsi2 *dsi2)351{352const struct dw_mipi_dsi2_phy_ops *phy_ops = dsi2->plat_data->phy_ops;353struct dw_mipi_dsi2_phy_timing timing;354int ret;355356ret = phy_ops->get_timing(dsi2->plat_data->priv_data,357dsi2->lane_mbps, &timing);358if (ret)359dev_err(dsi2->dev, "Retrieving phy timings failed\n");360361regmap_write(dsi2->regmap, DSI2_PHY_LP2HS_MAN_CFG, PHY_LP2HS_TIME(timing.data_lp2hs));362regmap_write(dsi2->regmap, DSI2_PHY_HS2LP_MAN_CFG, PHY_HS2LP_TIME(timing.data_hs2lp));363}364365static void dw_mipi_dsi2_phy_init(struct dw_mipi_dsi2 *dsi2)366{367const struct dw_mipi_dsi2_phy_ops *phy_ops = dsi2->plat_data->phy_ops;368struct dw_mipi_dsi2_phy_iface iface;369u32 val = 0;370371phy_ops->get_interface(dsi2->plat_data->priv_data, &iface);372373switch (iface.ppi_width) {374case 8:375val |= PPI_WIDTH(PPI_WIDTH_8_BITS);376break;377case 16:378val |= PPI_WIDTH(PPI_WIDTH_16_BITS);379break;380case 32:381val |= PPI_WIDTH(PPI_WIDTH_32_BITS);382break;383default:384/* Caught in probe */385break;386}387388val |= PHY_LANES(dsi2->lanes);389val |= PHY_TYPE(DW_MIPI_DSI2_DPHY);390regmap_write(dsi2->regmap, DSI2_PHY_MODE_CFG, val);391392dw_mipi_dsi2_phy_clk_mode_cfg(dsi2);393dw_mipi_dsi2_phy_ratio_cfg(dsi2);394dw_mipi_dsi2_lp2hs_or_hs2lp_cfg(dsi2);395396/* phy configuration 8 - 10 */397}398399static void dw_mipi_dsi2_tx_option_set(struct dw_mipi_dsi2 *dsi2)400{401u32 val;402403val = BTA_EN | EOTP_TX_EN;404405if (dsi2->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET)406val &= ~EOTP_TX_EN;407408regmap_write(dsi2->regmap, DSI2_DSI_GENERAL_CFG, val);409regmap_write(dsi2->regmap, DSI2_DSI_VCID_CFG, TX_VCID(dsi2->channel));410}411412static void dw_mipi_dsi2_ipi_color_coding_cfg(struct dw_mipi_dsi2 *dsi2)413{414u32 val, color_depth;415416switch (dsi2->format) {417case MIPI_DSI_FMT_RGB666:418case MIPI_DSI_FMT_RGB666_PACKED:419color_depth = IPI_DEPTH_6_BITS;420break;421case MIPI_DSI_FMT_RGB565:422color_depth = IPI_DEPTH_5_6_5_BITS;423break;424case MIPI_DSI_FMT_RGB888:425default:426color_depth = IPI_DEPTH_8_BITS;427break;428}429430val = IPI_DEPTH(color_depth) |431IPI_FORMAT(IPI_FORMAT_RGB);432regmap_write(dsi2->regmap, DSI2_IPI_COLOR_MAN_CFG, val);433}434435static void dw_mipi_dsi2_vertical_timing_config(struct dw_mipi_dsi2 *dsi2,436const struct drm_display_mode *mode)437{438u32 vactive, vsa, vfp, vbp;439440vactive = mode->vdisplay;441vsa = mode->vsync_end - mode->vsync_start;442vfp = mode->vsync_start - mode->vdisplay;443vbp = mode->vtotal - mode->vsync_end;444445regmap_write(dsi2->regmap, DSI2_IPI_VID_VSA_MAN_CFG, VID_VSA_LINES(vsa));446regmap_write(dsi2->regmap, DSI2_IPI_VID_VBP_MAN_CFG, VID_VBP_LINES(vbp));447regmap_write(dsi2->regmap, DSI2_IPI_VID_VACT_MAN_CFG, VID_VACT_LINES(vactive));448regmap_write(dsi2->regmap, DSI2_IPI_VID_VFP_MAN_CFG, VID_VFP_LINES(vfp));449}450451static void dw_mipi_dsi2_ipi_set(struct dw_mipi_dsi2 *dsi2)452{453struct drm_display_mode *mode = &dsi2->mode;454u32 hline, hsa, hbp, hact;455u64 hline_time, hsa_time, hbp_time, hact_time, tmp;456u64 pixel_clk, phy_hs_clk;457u16 val;458459val = mode->hdisplay;460461regmap_write(dsi2->regmap, DSI2_IPI_PIX_PKT_CFG, MAX_PIX_PKT(val));462463dw_mipi_dsi2_ipi_color_coding_cfg(dsi2);464465/*466* if the controller is intended to operate in data stream mode,467* no more steps are required.468*/469if (!(dsi2->mode_flags & MIPI_DSI_MODE_VIDEO))470return;471472hact = mode->hdisplay;473hsa = mode->hsync_end - mode->hsync_start;474hbp = mode->htotal - mode->hsync_end;475hline = mode->htotal;476477pixel_clk = mode->crtc_clock * MSEC_PER_SEC;478479phy_hs_clk = DIV_ROUND_CLOSEST_ULL(dsi2->lane_mbps * USEC_PER_SEC, 16);480481tmp = hsa * phy_hs_clk;482hsa_time = DIV_ROUND_CLOSEST_ULL(tmp << 16, pixel_clk);483regmap_write(dsi2->regmap, DSI2_IPI_VID_HSA_MAN_CFG, VID_HSA_TIME(hsa_time));484485tmp = hbp * phy_hs_clk;486hbp_time = DIV_ROUND_CLOSEST_ULL(tmp << 16, pixel_clk);487regmap_write(dsi2->regmap, DSI2_IPI_VID_HBP_MAN_CFG, VID_HBP_TIME(hbp_time));488489tmp = hact * phy_hs_clk;490hact_time = DIV_ROUND_CLOSEST_ULL(tmp << 16, pixel_clk);491regmap_write(dsi2->regmap, DSI2_IPI_VID_HACT_MAN_CFG, VID_HACT_TIME(hact_time));492493tmp = hline * phy_hs_clk;494hline_time = DIV_ROUND_CLOSEST_ULL(tmp << 16, pixel_clk);495regmap_write(dsi2->regmap, DSI2_IPI_VID_HLINE_MAN_CFG, VID_HLINE_TIME(hline_time));496497dw_mipi_dsi2_vertical_timing_config(dsi2, mode);498}499500static void501dw_mipi_dsi2_work_mode(struct dw_mipi_dsi2 *dsi2, u32 mode)502{503/*504* select controller work in Manual mode505* Manual: MANUAL_MODE_EN506* Automatic: 0507*/508regmap_write(dsi2->regmap, MANUAL_MODE_CFG, mode);509}510511static int dw_mipi_dsi2_host_attach(struct mipi_dsi_host *host,512struct mipi_dsi_device *device)513{514struct dw_mipi_dsi2 *dsi2 = host_to_dsi2(host);515const struct dw_mipi_dsi2_plat_data *pdata = dsi2->plat_data;516struct drm_bridge *bridge;517int ret;518519if (device->lanes > dsi2->plat_data->max_data_lanes) {520dev_err(dsi2->dev, "the number of data lanes(%u) is too many\n",521device->lanes);522return -EINVAL;523}524525dsi2->lanes = device->lanes;526dsi2->channel = device->channel;527dsi2->format = device->format;528dsi2->mode_flags = device->mode_flags;529530bridge = devm_drm_of_get_bridge(dsi2->dev, dsi2->dev->of_node, 1, 0);531if (IS_ERR(bridge))532return PTR_ERR(bridge);533534bridge->pre_enable_prev_first = true;535dsi2->panel_bridge = bridge;536537drm_bridge_add(&dsi2->bridge);538539if (pdata->host_ops && pdata->host_ops->attach) {540ret = pdata->host_ops->attach(pdata->priv_data, device);541if (ret < 0)542return ret;543}544545return 0;546}547548static int dw_mipi_dsi2_host_detach(struct mipi_dsi_host *host,549struct mipi_dsi_device *device)550{551struct dw_mipi_dsi2 *dsi2 = host_to_dsi2(host);552const struct dw_mipi_dsi2_plat_data *pdata = dsi2->plat_data;553int ret;554555if (pdata->host_ops && pdata->host_ops->detach) {556ret = pdata->host_ops->detach(pdata->priv_data, device);557if (ret < 0)558return ret;559}560561drm_bridge_remove(&dsi2->bridge);562563drm_of_panel_bridge_remove(host->dev->of_node, 1, 0);564565return 0;566}567568static int dw_mipi_dsi2_gen_pkt_hdr_write(struct dw_mipi_dsi2 *dsi2,569u32 hdr_val, bool lpm)570{571int ret;572573regmap_write(dsi2->regmap, DSI2_CRI_TX_HDR, hdr_val | CMD_TX_MODE(lpm));574575ret = cri_fifos_wait_avail(dsi2);576if (ret) {577dev_err(dsi2->dev, "failed to write command header\n");578return ret;579}580581return 0;582}583584static int dw_mipi_dsi2_write(struct dw_mipi_dsi2 *dsi2,585const struct mipi_dsi_packet *packet, bool lpm)586{587const u8 *tx_buf = packet->payload;588int len = packet->payload_length, pld_data_bytes = sizeof(u32);589__le32 word;590591/* Send payload */592while (len) {593if (len < pld_data_bytes) {594word = 0;595memcpy(&word, tx_buf, len);596regmap_write(dsi2->regmap, DSI2_CRI_TX_PLD, le32_to_cpu(word));597len = 0;598} else {599memcpy(&word, tx_buf, pld_data_bytes);600regmap_write(dsi2->regmap, DSI2_CRI_TX_PLD, le32_to_cpu(word));601tx_buf += pld_data_bytes;602len -= pld_data_bytes;603}604}605606word = 0;607memcpy(&word, packet->header, sizeof(packet->header));608return dw_mipi_dsi2_gen_pkt_hdr_write(dsi2, le32_to_cpu(word), lpm);609}610611static int dw_mipi_dsi2_read(struct dw_mipi_dsi2 *dsi2,612const struct mipi_dsi_msg *msg)613{614u8 *payload = msg->rx_buf;615int i, j, ret, len = msg->rx_len;616u8 data_type;617u16 wc;618u32 val;619620ret = regmap_read_poll_timeout(dsi2->regmap, DSI2_CORE_STATUS,621val, val & CRI_RD_DATA_AVAIL,622100, CMD_PKT_STATUS_TIMEOUT_US);623if (ret) {624dev_err(dsi2->dev, "CRI has no available read data\n");625return ret;626}627628regmap_read(dsi2->regmap, DSI2_CRI_RX_HDR, &val);629data_type = val & 0x3f;630631if (mipi_dsi_packet_format_is_short(data_type)) {632for (i = 0; i < len && i < 2; i++)633payload[i] = (val >> (8 * (i + 1))) & 0xff;634635return 0;636}637638wc = (val >> 8) & 0xffff;639/* Receive payload */640for (i = 0; i < len && i < wc; i += 4) {641regmap_read(dsi2->regmap, DSI2_CRI_RX_PLD, &val);642for (j = 0; j < 4 && j + i < len && j + i < wc; j++)643payload[i + j] = val >> (8 * j);644}645646return 0;647}648649static ssize_t dw_mipi_dsi2_host_transfer(struct mipi_dsi_host *host,650const struct mipi_dsi_msg *msg)651{652struct dw_mipi_dsi2 *dsi2 = host_to_dsi2(host);653bool lpm = msg->flags & MIPI_DSI_MSG_USE_LPM;654struct mipi_dsi_packet packet;655int ret, nb_bytes;656657regmap_update_bits(dsi2->regmap, DSI2_DSI_VID_TX_CFG,658LPDT_DISPLAY_CMD_EN,659lpm ? LPDT_DISPLAY_CMD_EN : 0);660661/* create a packet to the DSI protocol */662ret = mipi_dsi_create_packet(&packet, msg);663if (ret) {664dev_err(dsi2->dev, "failed to create packet: %d\n", ret);665return ret;666}667668ret = cri_fifos_wait_avail(dsi2);669if (ret)670return ret;671672ret = dw_mipi_dsi2_write(dsi2, &packet, lpm);673if (ret)674return ret;675676if (msg->rx_buf && msg->rx_len) {677ret = dw_mipi_dsi2_read(dsi2, msg);678if (ret < 0)679return ret;680nb_bytes = msg->rx_len;681} else {682nb_bytes = packet.size;683}684685return nb_bytes;686}687688static const struct mipi_dsi_host_ops dw_mipi_dsi2_host_ops = {689.attach = dw_mipi_dsi2_host_attach,690.detach = dw_mipi_dsi2_host_detach,691.transfer = dw_mipi_dsi2_host_transfer,692};693694static u32 *695dw_mipi_dsi2_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,696struct drm_bridge_state *bridge_state,697struct drm_crtc_state *crtc_state,698struct drm_connector_state *conn_state,699u32 output_fmt,700unsigned int *num_input_fmts)701{702struct dw_mipi_dsi2 *dsi2 = bridge_to_dsi2(bridge);703const struct dw_mipi_dsi2_plat_data *pdata = dsi2->plat_data;704u32 *input_fmts;705706if (pdata->get_input_bus_fmts)707return pdata->get_input_bus_fmts(pdata->priv_data,708bridge, bridge_state,709crtc_state, conn_state,710output_fmt, num_input_fmts);711712/* Fall back to MEDIA_BUS_FMT_FIXED as the only input format. */713input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);714if (!input_fmts)715return NULL;716input_fmts[0] = MEDIA_BUS_FMT_FIXED;717*num_input_fmts = 1;718719return input_fmts;720}721722static int dw_mipi_dsi2_bridge_atomic_check(struct drm_bridge *bridge,723struct drm_bridge_state *bridge_state,724struct drm_crtc_state *crtc_state,725struct drm_connector_state *conn_state)726{727struct dw_mipi_dsi2 *dsi2 = bridge_to_dsi2(bridge);728const struct dw_mipi_dsi2_plat_data *pdata = dsi2->plat_data;729bool ret;730731bridge_state->input_bus_cfg.flags =732DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE;733734if (pdata->mode_fixup) {735ret = pdata->mode_fixup(pdata->priv_data, &crtc_state->mode,736&crtc_state->adjusted_mode);737if (!ret) {738DRM_DEBUG_DRIVER("failed to fixup mode " DRM_MODE_FMT "\n",739DRM_MODE_ARG(&crtc_state->mode));740return -EINVAL;741}742}743744return 0;745}746747static void dw_mipi_dsi2_bridge_post_atomic_disable(struct drm_bridge *bridge,748struct drm_atomic_state *state)749{750struct dw_mipi_dsi2 *dsi2 = bridge_to_dsi2(bridge);751const struct dw_mipi_dsi2_phy_ops *phy_ops = dsi2->plat_data->phy_ops;752753regmap_write(dsi2->regmap, DSI2_IPI_PIX_PKT_CFG, 0);754755/*756* Switch to command mode before panel-bridge post_disable &757* panel unprepare.758* Note: panel-bridge disable & panel disable has been called759* before by the drm framework.760*/761dw_mipi_dsi2_set_cmd_mode(dsi2);762763regmap_write(dsi2->regmap, DSI2_PWR_UP, RESET);764765if (phy_ops->power_off)766phy_ops->power_off(dsi2->plat_data->priv_data);767768clk_disable_unprepare(dsi2->sys_clk);769clk_disable_unprepare(dsi2->pclk);770pm_runtime_put(dsi2->dev);771}772773static unsigned int dw_mipi_dsi2_get_lanes(struct dw_mipi_dsi2 *dsi2)774{775/* single-dsi, so no other instance to consider */776return dsi2->lanes;777}778779static void dw_mipi_dsi2_mode_set(struct dw_mipi_dsi2 *dsi2,780const struct drm_display_mode *adjusted_mode)781{782const struct dw_mipi_dsi2_phy_ops *phy_ops = dsi2->plat_data->phy_ops;783void *priv_data = dsi2->plat_data->priv_data;784u32 lanes = dw_mipi_dsi2_get_lanes(dsi2);785int ret;786787clk_prepare_enable(dsi2->pclk);788clk_prepare_enable(dsi2->sys_clk);789790ret = phy_ops->get_lane_mbps(priv_data, adjusted_mode, dsi2->mode_flags,791lanes, dsi2->format, &dsi2->lane_mbps);792if (ret)793DRM_DEBUG_DRIVER("Phy get_lane_mbps() failed\n");794795pm_runtime_get_sync(dsi2->dev);796797dw_mipi_dsi2_host_softrst(dsi2);798regmap_write(dsi2->regmap, DSI2_PWR_UP, RESET);799800dw_mipi_dsi2_work_mode(dsi2, MANUAL_MODE_EN);801dw_mipi_dsi2_phy_init(dsi2);802803if (phy_ops->power_on)804phy_ops->power_on(dsi2->plat_data->priv_data);805806dw_mipi_dsi2_tx_option_set(dsi2);807808/*809* initial deskew calibration is send after phy_power_on,810* then we can configure clk_type.811*/812813regmap_update_bits(dsi2->regmap, DSI2_PHY_CLK_CFG, CLK_TYPE_MASK,814dsi2->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS ? NON_CONTINUOUS_CLK :815CONTINUOUS_CLK);816817regmap_write(dsi2->regmap, DSI2_PWR_UP, POWER_UP);818dw_mipi_dsi2_set_cmd_mode(dsi2);819820dw_mipi_dsi2_ipi_set(dsi2);821}822823static void dw_mipi_dsi2_bridge_atomic_pre_enable(struct drm_bridge *bridge,824struct drm_atomic_state *state)825{826struct dw_mipi_dsi2 *dsi2 = bridge_to_dsi2(bridge);827828/* Power up the dsi ctl into a command mode */829dw_mipi_dsi2_mode_set(dsi2, &dsi2->mode);830}831832static void dw_mipi_dsi2_bridge_mode_set(struct drm_bridge *bridge,833const struct drm_display_mode *mode,834const struct drm_display_mode *adjusted_mode)835{836struct dw_mipi_dsi2 *dsi2 = bridge_to_dsi2(bridge);837838/* Store the display mode for later use in pre_enable callback */839drm_mode_copy(&dsi2->mode, adjusted_mode);840}841842static void dw_mipi_dsi2_bridge_atomic_enable(struct drm_bridge *bridge,843struct drm_atomic_state *state)844{845struct dw_mipi_dsi2 *dsi2 = bridge_to_dsi2(bridge);846847/* Switch to video mode for panel-bridge enable & panel enable */848if (dsi2->mode_flags & MIPI_DSI_MODE_VIDEO)849dw_mipi_dsi2_set_vid_mode(dsi2);850else851dw_mipi_dsi2_set_data_stream_mode(dsi2);852}853854static enum drm_mode_status855dw_mipi_dsi2_bridge_mode_valid(struct drm_bridge *bridge,856const struct drm_display_info *info,857const struct drm_display_mode *mode)858{859struct dw_mipi_dsi2 *dsi2 = bridge_to_dsi2(bridge);860const struct dw_mipi_dsi2_plat_data *pdata = dsi2->plat_data;861enum drm_mode_status mode_status = MODE_OK;862863if (pdata->mode_valid)864mode_status = pdata->mode_valid(pdata->priv_data, mode,865dsi2->mode_flags,866dw_mipi_dsi2_get_lanes(dsi2),867dsi2->format);868869return mode_status;870}871872static int dw_mipi_dsi2_bridge_attach(struct drm_bridge *bridge,873struct drm_encoder *encoder,874enum drm_bridge_attach_flags flags)875{876struct dw_mipi_dsi2 *dsi2 = bridge_to_dsi2(bridge);877878/* Set the encoder type as caller does not know it */879encoder->encoder_type = DRM_MODE_ENCODER_DSI;880881/* Attach the panel-bridge to the dsi bridge */882return drm_bridge_attach(encoder, dsi2->panel_bridge, bridge,883flags);884}885886static const struct drm_bridge_funcs dw_mipi_dsi2_bridge_funcs = {887.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,888.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,889.atomic_get_input_bus_fmts = dw_mipi_dsi2_bridge_atomic_get_input_bus_fmts,890.atomic_check = dw_mipi_dsi2_bridge_atomic_check,891.atomic_reset = drm_atomic_helper_bridge_reset,892.atomic_pre_enable = dw_mipi_dsi2_bridge_atomic_pre_enable,893.atomic_enable = dw_mipi_dsi2_bridge_atomic_enable,894.atomic_post_disable = dw_mipi_dsi2_bridge_post_atomic_disable,895.mode_set = dw_mipi_dsi2_bridge_mode_set,896.mode_valid = dw_mipi_dsi2_bridge_mode_valid,897.attach = dw_mipi_dsi2_bridge_attach,898};899900static const struct regmap_config dw_mipi_dsi2_regmap_config = {901.name = "dsi2-host",902.reg_bits = 32,903.val_bits = 32,904.reg_stride = 4,905.fast_io = true,906};907908static struct dw_mipi_dsi2 *909__dw_mipi_dsi2_probe(struct platform_device *pdev,910const struct dw_mipi_dsi2_plat_data *plat_data)911{912struct device *dev = &pdev->dev;913struct reset_control *apb_rst;914struct dw_mipi_dsi2 *dsi2;915int ret;916917dsi2 = devm_drm_bridge_alloc(dev, struct dw_mipi_dsi2, bridge,918&dw_mipi_dsi2_bridge_funcs);919if (IS_ERR(dsi2))920return ERR_CAST(dsi2);921922dsi2->dev = dev;923dsi2->plat_data = plat_data;924925if (!plat_data->phy_ops->init || !plat_data->phy_ops->get_lane_mbps ||926!plat_data->phy_ops->get_timing)927return dev_err_ptr_probe(dev, -ENODEV, "Phy not properly configured\n");928929if (!plat_data->regmap) {930void __iomem *base = devm_platform_ioremap_resource(pdev, 0);931932if (IS_ERR(base))933return dev_err_cast_probe(dev, base, "failed to registers\n");934935dsi2->regmap = devm_regmap_init_mmio(dev, base,936&dw_mipi_dsi2_regmap_config);937if (IS_ERR(dsi2->regmap))938return dev_err_cast_probe(dev, dsi2->regmap, "failed to init regmap\n");939} else {940dsi2->regmap = plat_data->regmap;941}942943dsi2->pclk = devm_clk_get(dev, "pclk");944if (IS_ERR(dsi2->pclk))945return dev_err_cast_probe(dev, dsi2->pclk, "Unable to get pclk\n");946947dsi2->sys_clk = devm_clk_get(dev, "sys");948if (IS_ERR(dsi2->sys_clk))949return dev_err_cast_probe(dev, dsi2->sys_clk, "Unable to get sys_clk\n");950951/*952* Note that the reset was not defined in the initial device tree, so953* we have to be prepared for it not being found.954*/955apb_rst = devm_reset_control_get_optional_exclusive(dev, "apb");956if (IS_ERR(apb_rst))957return dev_err_cast_probe(dev, apb_rst, "Unable to get reset control\n");958959if (apb_rst) {960ret = clk_prepare_enable(dsi2->pclk);961if (ret) {962dev_err(dev, "%s: Failed to enable pclk\n", __func__);963return ERR_PTR(ret);964}965966reset_control_assert(apb_rst);967usleep_range(10, 20);968reset_control_deassert(apb_rst);969970clk_disable_unprepare(dsi2->pclk);971}972973devm_pm_runtime_enable(dev);974975dsi2->dsi_host.ops = &dw_mipi_dsi2_host_ops;976dsi2->dsi_host.dev = dev;977ret = mipi_dsi_host_register(&dsi2->dsi_host);978if (ret) {979dev_err(dev, "Failed to register MIPI host: %d\n", ret);980pm_runtime_disable(dev);981return ERR_PTR(ret);982}983984dsi2->bridge.driver_private = dsi2;985dsi2->bridge.of_node = pdev->dev.of_node;986987return dsi2;988}989990static void __dw_mipi_dsi2_remove(struct dw_mipi_dsi2 *dsi2)991{992mipi_dsi_host_unregister(&dsi2->dsi_host);993}994995/*996* Probe/remove API, used to create the bridge instance.997*/998struct dw_mipi_dsi2 *999dw_mipi_dsi2_probe(struct platform_device *pdev,1000const struct dw_mipi_dsi2_plat_data *plat_data)1001{1002return __dw_mipi_dsi2_probe(pdev, plat_data);1003}1004EXPORT_SYMBOL_GPL(dw_mipi_dsi2_probe);10051006void dw_mipi_dsi2_remove(struct dw_mipi_dsi2 *dsi2)1007{1008__dw_mipi_dsi2_remove(dsi2);1009}1010EXPORT_SYMBOL_GPL(dw_mipi_dsi2_remove);10111012/*1013* Bind/unbind API, used from platforms based on the component framework1014* to attach the bridge to an encoder.1015*/1016int dw_mipi_dsi2_bind(struct dw_mipi_dsi2 *dsi2, struct drm_encoder *encoder)1017{1018return drm_bridge_attach(encoder, &dsi2->bridge, NULL, 0);1019}1020EXPORT_SYMBOL_GPL(dw_mipi_dsi2_bind);10211022void dw_mipi_dsi2_unbind(struct dw_mipi_dsi2 *dsi2)1023{1024}1025EXPORT_SYMBOL_GPL(dw_mipi_dsi2_unbind);10261027MODULE_AUTHOR("Guochun Huang <[email protected]>");1028MODULE_AUTHOR("Heiko Stuebner <[email protected]>");1029MODULE_DESCRIPTION("DW MIPI DSI2 host controller driver");1030MODULE_LICENSE("GPL");1031MODULE_ALIAS("platform:dw-mipi-dsi2");103210331034