1227 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * i.MX8 NWL MIPI DSI host driver4 *5 * Copyright (C) 2017 NXP6 * Copyright (C) 2020 Purism SPC7 */8 9#include <linux/bitfield.h>10#include <linux/bits.h>11#include <linux/clk.h>12#include <linux/irq.h>13#include <linux/math64.h>14#include <linux/mfd/syscon.h>15#include <linux/media-bus-format.h>16#include <linux/module.h>17#include <linux/mux/consumer.h>18#include <linux/of.h>19#include <linux/phy/phy.h>20#include <linux/platform_device.h>21#include <linux/regmap.h>22#include <linux/reset.h>23#include <linux/sys_soc.h>24#include <linux/time64.h>25 26#include <drm/drm_atomic_state_helper.h>27#include <drm/drm_bridge.h>28#include <drm/drm_mipi_dsi.h>29#include <drm/drm_of.h>30#include <drm/drm_print.h>31 32#include <video/mipi_display.h>33 34#include "nwl-dsi.h"35 36#define DRV_NAME "nwl-dsi"37 38/* i.MX8 NWL quirks */39/* i.MX8MQ errata E11418 */40#define E11418_HS_MODE_QUIRK BIT(0)41 42#define NWL_DSI_MIPI_FIFO_TIMEOUT msecs_to_jiffies(500)43 44enum transfer_direction {45 DSI_PACKET_SEND,46 DSI_PACKET_RECEIVE,47};48 49#define NWL_DSI_ENDPOINT_LCDIF 050#define NWL_DSI_ENDPOINT_DCSS 151 52struct nwl_dsi_transfer {53 const struct mipi_dsi_msg *msg;54 struct mipi_dsi_packet packet;55 struct completion completed;56 57 int status; /* status of transmission */58 enum transfer_direction direction;59 bool need_bta;60 u8 cmd;61 u16 rx_word_count;62 size_t tx_len; /* in bytes */63 size_t rx_len; /* in bytes */64};65 66struct nwl_dsi {67 struct drm_bridge bridge;68 struct mipi_dsi_host dsi_host;69 struct device *dev;70 struct phy *phy;71 union phy_configure_opts phy_cfg;72 unsigned int quirks;73 74 struct regmap *regmap;75 int irq;76 /*77 * The DSI host controller needs this reset sequence according to NWL:78 * 1. Deassert pclk reset to get access to DSI regs79 * 2. Configure DSI Host and DPHY and enable DPHY80 * 3. Deassert ESC and BYTE resets to allow host TX operations)81 * 4. Send DSI cmds to configure peripheral (handled by panel drv)82 * 5. Deassert DPI reset so DPI receives pixels and starts sending83 * DSI data84 *85 * TODO: Since panel_bridges do their DSI setup in enable we86 * currently have 4. and 5. swapped.87 */88 struct reset_control *rst_byte;89 struct reset_control *rst_esc;90 struct reset_control *rst_dpi;91 struct reset_control *rst_pclk;92 struct mux_control *mux;93 94 /* DSI clocks */95 struct clk *phy_ref_clk;96 struct clk *rx_esc_clk;97 struct clk *tx_esc_clk;98 struct clk *core_clk;99 /*100 * hardware bug: the i.MX8MQ needs this clock on during reset101 * even when not using LCDIF.102 */103 struct clk *lcdif_clk;104 105 /* dsi lanes */106 u32 lanes;107 enum mipi_dsi_pixel_format format;108 struct drm_display_mode mode;109 unsigned long dsi_mode_flags;110 int error;111 112 struct nwl_dsi_transfer *xfer;113};114 115static const struct regmap_config nwl_dsi_regmap_config = {116 .reg_bits = 16,117 .val_bits = 32,118 .reg_stride = 4,119 .max_register = NWL_DSI_IRQ_MASK2,120 .name = DRV_NAME,121};122 123static inline struct nwl_dsi *bridge_to_dsi(struct drm_bridge *bridge)124{125 return container_of(bridge, struct nwl_dsi, bridge);126}127 128static int nwl_dsi_clear_error(struct nwl_dsi *dsi)129{130 int ret = dsi->error;131 132 dsi->error = 0;133 return ret;134}135 136static void nwl_dsi_write(struct nwl_dsi *dsi, unsigned int reg, u32 val)137{138 int ret;139 140 if (dsi->error)141 return;142 143 ret = regmap_write(dsi->regmap, reg, val);144 if (ret < 0) {145 DRM_DEV_ERROR(dsi->dev,146 "Failed to write NWL DSI reg 0x%x: %d\n", reg,147 ret);148 dsi->error = ret;149 }150}151 152static u32 nwl_dsi_read(struct nwl_dsi *dsi, u32 reg)153{154 unsigned int val;155 int ret;156 157 if (dsi->error)158 return 0;159 160 ret = regmap_read(dsi->regmap, reg, &val);161 if (ret < 0) {162 DRM_DEV_ERROR(dsi->dev, "Failed to read NWL DSI reg 0x%x: %d\n",163 reg, ret);164 dsi->error = ret;165 }166 return val;167}168 169static int nwl_dsi_get_dpi_pixel_format(enum mipi_dsi_pixel_format format)170{171 switch (format) {172 case MIPI_DSI_FMT_RGB565:173 return NWL_DSI_PIXEL_FORMAT_16;174 case MIPI_DSI_FMT_RGB666:175 return NWL_DSI_PIXEL_FORMAT_18L;176 case MIPI_DSI_FMT_RGB666_PACKED:177 return NWL_DSI_PIXEL_FORMAT_18;178 case MIPI_DSI_FMT_RGB888:179 return NWL_DSI_PIXEL_FORMAT_24;180 default:181 return -EINVAL;182 }183}184 185/*186 * ps2bc - Picoseconds to byte clock cycles187 */188static u32 ps2bc(struct nwl_dsi *dsi, unsigned long long ps)189{190 u32 bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);191 192 return DIV64_U64_ROUND_UP(ps * dsi->mode.clock * bpp,193 dsi->lanes * 8ULL * NSEC_PER_SEC);194}195 196/*197 * ui2bc - UI time periods to byte clock cycles198 */199static u32 ui2bc(unsigned int ui)200{201 return DIV_ROUND_UP(ui, BITS_PER_BYTE);202}203 204/*205 * us2bc - micro seconds to lp clock cycles206 */207static u32 us2lp(u32 lp_clk_rate, unsigned long us)208{209 return DIV_ROUND_UP(us * lp_clk_rate, USEC_PER_SEC);210}211 212static int nwl_dsi_config_host(struct nwl_dsi *dsi)213{214 u32 cycles;215 struct phy_configure_opts_mipi_dphy *cfg = &dsi->phy_cfg.mipi_dphy;216 217 if (dsi->lanes < 1 || dsi->lanes > 4)218 return -EINVAL;219 220 DRM_DEV_DEBUG_DRIVER(dsi->dev, "DSI Lanes %d\n", dsi->lanes);221 nwl_dsi_write(dsi, NWL_DSI_CFG_NUM_LANES, dsi->lanes - 1);222 223 if (dsi->dsi_mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) {224 nwl_dsi_write(dsi, NWL_DSI_CFG_NONCONTINUOUS_CLK, 0x01);225 nwl_dsi_write(dsi, NWL_DSI_CFG_AUTOINSERT_EOTP, 0x01);226 } else {227 nwl_dsi_write(dsi, NWL_DSI_CFG_NONCONTINUOUS_CLK, 0x00);228 nwl_dsi_write(dsi, NWL_DSI_CFG_AUTOINSERT_EOTP, 0x00);229 }230 231 /* values in byte clock cycles */232 cycles = ui2bc(cfg->clk_pre);233 DRM_DEV_DEBUG_DRIVER(dsi->dev, "cfg_t_pre: 0x%x\n", cycles);234 nwl_dsi_write(dsi, NWL_DSI_CFG_T_PRE, cycles);235 cycles = ps2bc(dsi, cfg->lpx + cfg->clk_prepare + cfg->clk_zero);236 DRM_DEV_DEBUG_DRIVER(dsi->dev, "cfg_tx_gap (pre): 0x%x\n", cycles);237 cycles += ui2bc(cfg->clk_pre);238 DRM_DEV_DEBUG_DRIVER(dsi->dev, "cfg_t_post: 0x%x\n", cycles);239 nwl_dsi_write(dsi, NWL_DSI_CFG_T_POST, cycles);240 cycles = ps2bc(dsi, cfg->hs_exit);241 DRM_DEV_DEBUG_DRIVER(dsi->dev, "cfg_tx_gap: 0x%x\n", cycles);242 nwl_dsi_write(dsi, NWL_DSI_CFG_TX_GAP, cycles);243 244 nwl_dsi_write(dsi, NWL_DSI_CFG_EXTRA_CMDS_AFTER_EOTP, 0x01);245 nwl_dsi_write(dsi, NWL_DSI_CFG_HTX_TO_COUNT, 0x00);246 nwl_dsi_write(dsi, NWL_DSI_CFG_LRX_H_TO_COUNT, 0x00);247 nwl_dsi_write(dsi, NWL_DSI_CFG_BTA_H_TO_COUNT, 0x00);248 /* In LP clock cycles */249 cycles = us2lp(cfg->lp_clk_rate, cfg->wakeup);250 DRM_DEV_DEBUG_DRIVER(dsi->dev, "cfg_twakeup: 0x%x\n", cycles);251 nwl_dsi_write(dsi, NWL_DSI_CFG_TWAKEUP, cycles);252 253 return nwl_dsi_clear_error(dsi);254}255 256static int nwl_dsi_config_dpi(struct nwl_dsi *dsi)257{258 u32 mode;259 int color_format;260 bool burst_mode;261 int hfront_porch, hback_porch, vfront_porch, vback_porch;262 int hsync_len, vsync_len;263 264 hfront_porch = dsi->mode.hsync_start - dsi->mode.hdisplay;265 hsync_len = dsi->mode.hsync_end - dsi->mode.hsync_start;266 hback_porch = dsi->mode.htotal - dsi->mode.hsync_end;267 268 vfront_porch = dsi->mode.vsync_start - dsi->mode.vdisplay;269 vsync_len = dsi->mode.vsync_end - dsi->mode.vsync_start;270 vback_porch = dsi->mode.vtotal - dsi->mode.vsync_end;271 272 DRM_DEV_DEBUG_DRIVER(dsi->dev, "hfront_porch = %d\n", hfront_porch);273 DRM_DEV_DEBUG_DRIVER(dsi->dev, "hback_porch = %d\n", hback_porch);274 DRM_DEV_DEBUG_DRIVER(dsi->dev, "hsync_len = %d\n", hsync_len);275 DRM_DEV_DEBUG_DRIVER(dsi->dev, "hdisplay = %d\n", dsi->mode.hdisplay);276 DRM_DEV_DEBUG_DRIVER(dsi->dev, "vfront_porch = %d\n", vfront_porch);277 DRM_DEV_DEBUG_DRIVER(dsi->dev, "vback_porch = %d\n", vback_porch);278 DRM_DEV_DEBUG_DRIVER(dsi->dev, "vsync_len = %d\n", vsync_len);279 DRM_DEV_DEBUG_DRIVER(dsi->dev, "vactive = %d\n", dsi->mode.vdisplay);280 DRM_DEV_DEBUG_DRIVER(dsi->dev, "clock = %d kHz\n", dsi->mode.clock);281 282 color_format = nwl_dsi_get_dpi_pixel_format(dsi->format);283 if (color_format < 0) {284 DRM_DEV_ERROR(dsi->dev, "Invalid color format 0x%x\n",285 dsi->format);286 return color_format;287 }288 DRM_DEV_DEBUG_DRIVER(dsi->dev, "pixel fmt = %d\n", dsi->format);289 290 nwl_dsi_write(dsi, NWL_DSI_INTERFACE_COLOR_CODING, NWL_DSI_DPI_24_BIT);291 nwl_dsi_write(dsi, NWL_DSI_PIXEL_FORMAT, color_format);292 nwl_dsi_write(dsi, NWL_DSI_VSYNC_POLARITY,293 dsi->mode.flags & DRM_MODE_FLAG_PVSYNC ?294 NWL_DSI_VSYNC_POLARITY_ACTIVE_HIGH :295 NWL_DSI_VSYNC_POLARITY_ACTIVE_LOW);296 nwl_dsi_write(dsi, NWL_DSI_HSYNC_POLARITY,297 dsi->mode.flags & DRM_MODE_FLAG_PHSYNC ?298 NWL_DSI_HSYNC_POLARITY_ACTIVE_HIGH :299 NWL_DSI_HSYNC_POLARITY_ACTIVE_LOW);300 301 burst_mode = (dsi->dsi_mode_flags & MIPI_DSI_MODE_VIDEO_BURST) &&302 !(dsi->dsi_mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE);303 304 if (burst_mode) {305 nwl_dsi_write(dsi, NWL_DSI_VIDEO_MODE, NWL_DSI_VM_BURST_MODE);306 nwl_dsi_write(dsi, NWL_DSI_PIXEL_FIFO_SEND_LEVEL, 256);307 } else {308 mode = ((dsi->dsi_mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) ?309 NWL_DSI_VM_BURST_MODE_WITH_SYNC_PULSES :310 NWL_DSI_VM_NON_BURST_MODE_WITH_SYNC_EVENTS);311 nwl_dsi_write(dsi, NWL_DSI_VIDEO_MODE, mode);312 nwl_dsi_write(dsi, NWL_DSI_PIXEL_FIFO_SEND_LEVEL,313 dsi->mode.hdisplay);314 }315 316 nwl_dsi_write(dsi, NWL_DSI_HFP, hfront_porch);317 nwl_dsi_write(dsi, NWL_DSI_HBP, hback_porch);318 nwl_dsi_write(dsi, NWL_DSI_HSA, hsync_len);319 320 nwl_dsi_write(dsi, NWL_DSI_ENABLE_MULT_PKTS, 0x0);321 nwl_dsi_write(dsi, NWL_DSI_BLLP_MODE, 0x1);322 nwl_dsi_write(dsi, NWL_DSI_USE_NULL_PKT_BLLP, 0x0);323 nwl_dsi_write(dsi, NWL_DSI_VC, 0x0);324 325 nwl_dsi_write(dsi, NWL_DSI_PIXEL_PAYLOAD_SIZE, dsi->mode.hdisplay);326 nwl_dsi_write(dsi, NWL_DSI_VACTIVE, dsi->mode.vdisplay - 1);327 nwl_dsi_write(dsi, NWL_DSI_VBP, vback_porch);328 nwl_dsi_write(dsi, NWL_DSI_VFP, vfront_porch);329 330 return nwl_dsi_clear_error(dsi);331}332 333static int nwl_dsi_init_interrupts(struct nwl_dsi *dsi)334{335 u32 irq_enable = ~(u32)(NWL_DSI_TX_PKT_DONE_MASK |336 NWL_DSI_RX_PKT_HDR_RCVD_MASK |337 NWL_DSI_TX_FIFO_OVFLW_MASK |338 NWL_DSI_HS_TX_TIMEOUT_MASK);339 340 nwl_dsi_write(dsi, NWL_DSI_IRQ_MASK, irq_enable);341 nwl_dsi_write(dsi, NWL_DSI_IRQ_MASK2, 0x7);342 343 return nwl_dsi_clear_error(dsi);344}345 346static int nwl_dsi_host_attach(struct mipi_dsi_host *dsi_host,347 struct mipi_dsi_device *device)348{349 struct nwl_dsi *dsi = container_of(dsi_host, struct nwl_dsi, dsi_host);350 struct device *dev = dsi->dev;351 352 DRM_DEV_INFO(dev, "lanes=%u, format=0x%x flags=0x%lx\n", device->lanes,353 device->format, device->mode_flags);354 355 if (device->lanes < 1 || device->lanes > 4)356 return -EINVAL;357 358 dsi->lanes = device->lanes;359 dsi->format = device->format;360 dsi->dsi_mode_flags = device->mode_flags;361 362 return 0;363}364 365static bool nwl_dsi_read_packet(struct nwl_dsi *dsi, u32 status)366{367 struct device *dev = dsi->dev;368 struct nwl_dsi_transfer *xfer = dsi->xfer;369 int err;370 u8 *payload = xfer->msg->rx_buf;371 u32 val;372 u16 word_count;373 u8 channel;374 u8 data_type;375 376 xfer->status = 0;377 378 if (xfer->rx_word_count == 0) {379 if (!(status & NWL_DSI_RX_PKT_HDR_RCVD))380 return false;381 /* Get the RX header and parse it */382 val = nwl_dsi_read(dsi, NWL_DSI_RX_PKT_HEADER);383 err = nwl_dsi_clear_error(dsi);384 if (err)385 xfer->status = err;386 word_count = NWL_DSI_WC(val);387 channel = NWL_DSI_RX_VC(val);388 data_type = NWL_DSI_RX_DT(val);389 390 if (channel != xfer->msg->channel) {391 DRM_DEV_ERROR(dev,392 "[%02X] Channel mismatch (%u != %u)\n",393 xfer->cmd, channel, xfer->msg->channel);394 xfer->status = -EINVAL;395 return true;396 }397 398 switch (data_type) {399 case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE:400 case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:401 if (xfer->msg->rx_len > 1) {402 /* read second byte */403 payload[1] = word_count >> 8;404 ++xfer->rx_len;405 }406 fallthrough;407 case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE:408 case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:409 if (xfer->msg->rx_len > 0) {410 /* read first byte */411 payload[0] = word_count & 0xff;412 ++xfer->rx_len;413 }414 xfer->status = xfer->rx_len;415 return true;416 case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:417 word_count &= 0xff;418 DRM_DEV_ERROR(dev, "[%02X] DSI error report: 0x%02x\n",419 xfer->cmd, word_count);420 xfer->status = -EPROTO;421 return true;422 }423 424 if (word_count > xfer->msg->rx_len) {425 DRM_DEV_ERROR(dev,426 "[%02X] Receive buffer too small: %zu (< %u)\n",427 xfer->cmd, xfer->msg->rx_len, word_count);428 xfer->status = -EINVAL;429 return true;430 }431 432 xfer->rx_word_count = word_count;433 } else {434 /* Set word_count from previous header read */435 word_count = xfer->rx_word_count;436 }437 438 /* If RX payload is not yet received, wait for it */439 if (!(status & NWL_DSI_RX_PKT_PAYLOAD_DATA_RCVD))440 return false;441 442 /* Read the RX payload */443 while (word_count >= 4) {444 val = nwl_dsi_read(dsi, NWL_DSI_RX_PAYLOAD);445 payload[0] = (val >> 0) & 0xff;446 payload[1] = (val >> 8) & 0xff;447 payload[2] = (val >> 16) & 0xff;448 payload[3] = (val >> 24) & 0xff;449 payload += 4;450 xfer->rx_len += 4;451 word_count -= 4;452 }453 454 if (word_count > 0) {455 val = nwl_dsi_read(dsi, NWL_DSI_RX_PAYLOAD);456 switch (word_count) {457 case 3:458 payload[2] = (val >> 16) & 0xff;459 ++xfer->rx_len;460 fallthrough;461 case 2:462 payload[1] = (val >> 8) & 0xff;463 ++xfer->rx_len;464 fallthrough;465 case 1:466 payload[0] = (val >> 0) & 0xff;467 ++xfer->rx_len;468 break;469 }470 }471 472 xfer->status = xfer->rx_len;473 err = nwl_dsi_clear_error(dsi);474 if (err)475 xfer->status = err;476 477 return true;478}479 480static void nwl_dsi_finish_transmission(struct nwl_dsi *dsi, u32 status)481{482 struct nwl_dsi_transfer *xfer = dsi->xfer;483 bool end_packet = false;484 485 if (!xfer)486 return;487 488 if (xfer->direction == DSI_PACKET_SEND &&489 status & NWL_DSI_TX_PKT_DONE) {490 xfer->status = xfer->tx_len;491 end_packet = true;492 } else if (status & NWL_DSI_DPHY_DIRECTION &&493 ((status & (NWL_DSI_RX_PKT_HDR_RCVD |494 NWL_DSI_RX_PKT_PAYLOAD_DATA_RCVD)))) {495 end_packet = nwl_dsi_read_packet(dsi, status);496 }497 498 if (end_packet)499 complete(&xfer->completed);500}501 502static void nwl_dsi_begin_transmission(struct nwl_dsi *dsi)503{504 struct nwl_dsi_transfer *xfer = dsi->xfer;505 struct mipi_dsi_packet *pkt = &xfer->packet;506 const u8 *payload;507 size_t length;508 u16 word_count;509 u8 hs_mode;510 u32 val;511 u32 hs_workaround = 0;512 513 /* Send the payload, if any */514 length = pkt->payload_length;515 payload = pkt->payload;516 517 while (length >= 4) {518 val = *(u32 *)payload;519 hs_workaround |= !(val & 0xFFFF00);520 nwl_dsi_write(dsi, NWL_DSI_TX_PAYLOAD, val);521 payload += 4;522 length -= 4;523 }524 /* Send the rest of the payload */525 val = 0;526 switch (length) {527 case 3:528 val |= payload[2] << 16;529 fallthrough;530 case 2:531 val |= payload[1] << 8;532 hs_workaround |= !(val & 0xFFFF00);533 fallthrough;534 case 1:535 val |= payload[0];536 nwl_dsi_write(dsi, NWL_DSI_TX_PAYLOAD, val);537 break;538 }539 xfer->tx_len = pkt->payload_length;540 541 /*542 * Send the header543 * header[0] = Virtual Channel + Data Type544 * header[1] = Word Count LSB (LP) or first param (SP)545 * header[2] = Word Count MSB (LP) or second param (SP)546 */547 word_count = pkt->header[1] | (pkt->header[2] << 8);548 if (hs_workaround && (dsi->quirks & E11418_HS_MODE_QUIRK)) {549 DRM_DEV_DEBUG_DRIVER(dsi->dev,550 "Using hs mode workaround for cmd 0x%x\n",551 xfer->cmd);552 hs_mode = 1;553 } else {554 hs_mode = (xfer->msg->flags & MIPI_DSI_MSG_USE_LPM) ? 0 : 1;555 }556 val = NWL_DSI_WC(word_count) | NWL_DSI_TX_VC(xfer->msg->channel) |557 NWL_DSI_TX_DT(xfer->msg->type) | NWL_DSI_HS_SEL(hs_mode) |558 NWL_DSI_BTA_TX(xfer->need_bta);559 nwl_dsi_write(dsi, NWL_DSI_PKT_CONTROL, val);560 561 /* Send packet command */562 nwl_dsi_write(dsi, NWL_DSI_SEND_PACKET, 0x1);563}564 565static ssize_t nwl_dsi_host_transfer(struct mipi_dsi_host *dsi_host,566 const struct mipi_dsi_msg *msg)567{568 struct nwl_dsi *dsi = container_of(dsi_host, struct nwl_dsi, dsi_host);569 struct nwl_dsi_transfer xfer;570 ssize_t ret = 0;571 572 /* Create packet to be sent */573 dsi->xfer = &xfer;574 ret = mipi_dsi_create_packet(&xfer.packet, msg);575 if (ret < 0) {576 dsi->xfer = NULL;577 return ret;578 }579 580 if ((msg->type & MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM ||581 msg->type & MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM ||582 msg->type & MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM ||583 msg->type & MIPI_DSI_DCS_READ) &&584 msg->rx_len > 0 && msg->rx_buf)585 xfer.direction = DSI_PACKET_RECEIVE;586 else587 xfer.direction = DSI_PACKET_SEND;588 589 xfer.need_bta = (xfer.direction == DSI_PACKET_RECEIVE);590 xfer.need_bta |= (msg->flags & MIPI_DSI_MSG_REQ_ACK) ? 1 : 0;591 xfer.msg = msg;592 xfer.status = -ETIMEDOUT;593 xfer.rx_word_count = 0;594 xfer.rx_len = 0;595 xfer.cmd = 0x00;596 if (msg->tx_len > 0)597 xfer.cmd = ((u8 *)(msg->tx_buf))[0];598 init_completion(&xfer.completed);599 600 ret = clk_prepare_enable(dsi->rx_esc_clk);601 if (ret < 0) {602 DRM_DEV_ERROR(dsi->dev, "Failed to enable rx_esc clk: %zd\n",603 ret);604 return ret;605 }606 DRM_DEV_DEBUG_DRIVER(dsi->dev, "Enabled rx_esc clk @%lu Hz\n",607 clk_get_rate(dsi->rx_esc_clk));608 609 /* Initiate the DSI packet transmision */610 nwl_dsi_begin_transmission(dsi);611 612 if (!wait_for_completion_timeout(&xfer.completed,613 NWL_DSI_MIPI_FIFO_TIMEOUT)) {614 DRM_DEV_ERROR(dsi_host->dev, "[%02X] DSI transfer timed out\n",615 xfer.cmd);616 ret = -ETIMEDOUT;617 } else {618 ret = xfer.status;619 }620 621 clk_disable_unprepare(dsi->rx_esc_clk);622 623 return ret;624}625 626static const struct mipi_dsi_host_ops nwl_dsi_host_ops = {627 .attach = nwl_dsi_host_attach,628 .transfer = nwl_dsi_host_transfer,629};630 631static irqreturn_t nwl_dsi_irq_handler(int irq, void *data)632{633 u32 irq_status;634 struct nwl_dsi *dsi = data;635 636 irq_status = nwl_dsi_read(dsi, NWL_DSI_IRQ_STATUS);637 638 if (irq_status & NWL_DSI_TX_FIFO_OVFLW)639 DRM_DEV_ERROR_RATELIMITED(dsi->dev, "tx fifo overflow\n");640 641 if (irq_status & NWL_DSI_HS_TX_TIMEOUT)642 DRM_DEV_ERROR_RATELIMITED(dsi->dev, "HS tx timeout\n");643 644 if (irq_status & NWL_DSI_TX_PKT_DONE ||645 irq_status & NWL_DSI_RX_PKT_HDR_RCVD ||646 irq_status & NWL_DSI_RX_PKT_PAYLOAD_DATA_RCVD)647 nwl_dsi_finish_transmission(dsi, irq_status);648 649 return IRQ_HANDLED;650}651 652static int nwl_dsi_mode_set(struct nwl_dsi *dsi)653{654 struct device *dev = dsi->dev;655 union phy_configure_opts *phy_cfg = &dsi->phy_cfg;656 int ret;657 658 if (!dsi->lanes) {659 DRM_DEV_ERROR(dev, "Need DSI lanes: %d\n", dsi->lanes);660 return -EINVAL;661 }662 663 ret = phy_init(dsi->phy);664 if (ret < 0) {665 DRM_DEV_ERROR(dev, "Failed to init DSI phy: %d\n", ret);666 return ret;667 }668 669 ret = phy_set_mode(dsi->phy, PHY_MODE_MIPI_DPHY);670 if (ret < 0) {671 DRM_DEV_ERROR(dev, "Failed to set DSI phy mode: %d\n", ret);672 goto uninit_phy;673 }674 675 ret = phy_configure(dsi->phy, phy_cfg);676 if (ret < 0) {677 DRM_DEV_ERROR(dev, "Failed to configure DSI phy: %d\n", ret);678 goto uninit_phy;679 }680 681 ret = clk_prepare_enable(dsi->tx_esc_clk);682 if (ret < 0) {683 DRM_DEV_ERROR(dsi->dev, "Failed to enable tx_esc clk: %d\n",684 ret);685 goto uninit_phy;686 }687 DRM_DEV_DEBUG_DRIVER(dsi->dev, "Enabled tx_esc clk @%lu Hz\n",688 clk_get_rate(dsi->tx_esc_clk));689 690 ret = nwl_dsi_config_host(dsi);691 if (ret < 0) {692 DRM_DEV_ERROR(dev, "Failed to set up DSI: %d", ret);693 goto disable_clock;694 }695 696 ret = nwl_dsi_config_dpi(dsi);697 if (ret < 0) {698 DRM_DEV_ERROR(dev, "Failed to set up DPI: %d", ret);699 goto disable_clock;700 }701 702 ret = phy_power_on(dsi->phy);703 if (ret < 0) {704 DRM_DEV_ERROR(dev, "Failed to power on DPHY (%d)\n", ret);705 goto disable_clock;706 }707 708 ret = nwl_dsi_init_interrupts(dsi);709 if (ret < 0)710 goto power_off_phy;711 712 return ret;713 714power_off_phy:715 phy_power_off(dsi->phy);716disable_clock:717 clk_disable_unprepare(dsi->tx_esc_clk);718uninit_phy:719 phy_exit(dsi->phy);720 721 return ret;722}723 724static int nwl_dsi_disable(struct nwl_dsi *dsi)725{726 struct device *dev = dsi->dev;727 728 DRM_DEV_DEBUG_DRIVER(dev, "Disabling clocks and phy\n");729 730 phy_power_off(dsi->phy);731 phy_exit(dsi->phy);732 733 /* Disabling the clock before the phy breaks enabling dsi again */734 clk_disable_unprepare(dsi->tx_esc_clk);735 736 return 0;737}738 739static void740nwl_dsi_bridge_atomic_disable(struct drm_bridge *bridge,741 struct drm_bridge_state *old_bridge_state)742{743 struct nwl_dsi *dsi = bridge_to_dsi(bridge);744 int ret;745 746 nwl_dsi_disable(dsi);747 748 ret = reset_control_assert(dsi->rst_dpi);749 if (ret < 0) {750 DRM_DEV_ERROR(dsi->dev, "Failed to assert DPI: %d\n", ret);751 return;752 }753 ret = reset_control_assert(dsi->rst_byte);754 if (ret < 0) {755 DRM_DEV_ERROR(dsi->dev, "Failed to assert ESC: %d\n", ret);756 return;757 }758 ret = reset_control_assert(dsi->rst_esc);759 if (ret < 0) {760 DRM_DEV_ERROR(dsi->dev, "Failed to assert BYTE: %d\n", ret);761 return;762 }763 ret = reset_control_assert(dsi->rst_pclk);764 if (ret < 0) {765 DRM_DEV_ERROR(dsi->dev, "Failed to assert PCLK: %d\n", ret);766 return;767 }768 769 clk_disable_unprepare(dsi->core_clk);770 clk_disable_unprepare(dsi->lcdif_clk);771 772 pm_runtime_put(dsi->dev);773}774 775static int nwl_dsi_get_dphy_params(struct nwl_dsi *dsi,776 const struct drm_display_mode *mode,777 union phy_configure_opts *phy_opts)778{779 unsigned long rate;780 int ret;781 782 if (dsi->lanes < 1 || dsi->lanes > 4)783 return -EINVAL;784 785 /*786 * So far the DPHY spec minimal timings work for both mixel787 * dphy and nwl dsi host788 */789 ret = phy_mipi_dphy_get_default_config(mode->clock * 1000,790 mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes,791 &phy_opts->mipi_dphy);792 if (ret < 0)793 return ret;794 795 rate = clk_get_rate(dsi->tx_esc_clk);796 DRM_DEV_DEBUG_DRIVER(dsi->dev, "LP clk is @%lu Hz\n", rate);797 phy_opts->mipi_dphy.lp_clk_rate = rate;798 799 return 0;800}801 802static enum drm_mode_status803nwl_dsi_bridge_mode_valid(struct drm_bridge *bridge,804 const struct drm_display_info *info,805 const struct drm_display_mode *mode)806{807 struct nwl_dsi *dsi = bridge_to_dsi(bridge);808 int bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);809 810 if (mode->clock * bpp > 15000000 * dsi->lanes)811 return MODE_CLOCK_HIGH;812 813 if (mode->clock * bpp < 80000 * dsi->lanes)814 return MODE_CLOCK_LOW;815 816 return MODE_OK;817}818 819static int nwl_dsi_bridge_atomic_check(struct drm_bridge *bridge,820 struct drm_bridge_state *bridge_state,821 struct drm_crtc_state *crtc_state,822 struct drm_connector_state *conn_state)823{824 struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;825 826 /* At least LCDIF + NWL needs active high sync */827 adjusted_mode->flags |= (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);828 adjusted_mode->flags &= ~(DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC);829 830 /*831 * Do a full modeset if crtc_state->active is changed to be true.832 * This ensures our ->mode_set() is called to get the DSI controller833 * and the PHY ready to send DCS commands, when only the connector's834 * DPMS is brought out of "Off" status.835 */836 if (crtc_state->active_changed && crtc_state->active)837 crtc_state->mode_changed = true;838 839 return 0;840}841 842static void843nwl_dsi_bridge_mode_set(struct drm_bridge *bridge,844 const struct drm_display_mode *mode,845 const struct drm_display_mode *adjusted_mode)846{847 struct nwl_dsi *dsi = bridge_to_dsi(bridge);848 struct device *dev = dsi->dev;849 union phy_configure_opts new_cfg;850 unsigned long phy_ref_rate;851 int ret;852 853 ret = nwl_dsi_get_dphy_params(dsi, adjusted_mode, &new_cfg);854 if (ret < 0)855 return;856 857 phy_ref_rate = clk_get_rate(dsi->phy_ref_clk);858 DRM_DEV_DEBUG_DRIVER(dev, "PHY at ref rate: %lu\n", phy_ref_rate);859 /* Save the new desired phy config */860 memcpy(&dsi->phy_cfg, &new_cfg, sizeof(new_cfg));861 862 drm_mode_copy(&dsi->mode, adjusted_mode);863 drm_mode_debug_printmodeline(adjusted_mode);864 865 if (pm_runtime_resume_and_get(dev) < 0)866 return;867 868 if (clk_prepare_enable(dsi->lcdif_clk) < 0)869 goto runtime_put;870 if (clk_prepare_enable(dsi->core_clk) < 0)871 goto runtime_put;872 873 /* Step 1 from DSI reset-out instructions */874 ret = reset_control_deassert(dsi->rst_pclk);875 if (ret < 0) {876 DRM_DEV_ERROR(dev, "Failed to deassert PCLK: %d\n", ret);877 goto runtime_put;878 }879 880 /* Step 2 from DSI reset-out instructions */881 nwl_dsi_mode_set(dsi);882 883 /* Step 3 from DSI reset-out instructions */884 ret = reset_control_deassert(dsi->rst_esc);885 if (ret < 0) {886 DRM_DEV_ERROR(dev, "Failed to deassert ESC: %d\n", ret);887 goto runtime_put;888 }889 ret = reset_control_deassert(dsi->rst_byte);890 if (ret < 0) {891 DRM_DEV_ERROR(dev, "Failed to deassert BYTE: %d\n", ret);892 goto runtime_put;893 }894 895 return;896 897runtime_put:898 pm_runtime_put_sync(dev);899}900 901static void902nwl_dsi_bridge_atomic_enable(struct drm_bridge *bridge,903 struct drm_bridge_state *old_bridge_state)904{905 struct nwl_dsi *dsi = bridge_to_dsi(bridge);906 int ret;907 908 /* Step 5 from DSI reset-out instructions */909 ret = reset_control_deassert(dsi->rst_dpi);910 if (ret < 0)911 DRM_DEV_ERROR(dsi->dev, "Failed to deassert DPI: %d\n", ret);912}913 914static int nwl_dsi_bridge_attach(struct drm_bridge *bridge,915 enum drm_bridge_attach_flags flags)916{917 struct nwl_dsi *dsi = bridge_to_dsi(bridge);918 struct drm_bridge *panel_bridge;919 920 panel_bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node, 1, 0);921 if (IS_ERR(panel_bridge))922 return PTR_ERR(panel_bridge);923 924 return drm_bridge_attach(bridge->encoder, panel_bridge, bridge, flags);925}926 927static u32 *nwl_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,928 struct drm_bridge_state *bridge_state,929 struct drm_crtc_state *crtc_state,930 struct drm_connector_state *conn_state,931 u32 output_fmt,932 unsigned int *num_input_fmts)933{934 u32 *input_fmts, input_fmt;935 936 *num_input_fmts = 0;937 938 switch (output_fmt) {939 /* If MEDIA_BUS_FMT_FIXED is tested, return default bus format */940 case MEDIA_BUS_FMT_FIXED:941 input_fmt = MEDIA_BUS_FMT_RGB888_1X24;942 break;943 case MEDIA_BUS_FMT_RGB888_1X24:944 case MEDIA_BUS_FMT_RGB666_1X18:945 case MEDIA_BUS_FMT_RGB565_1X16:946 input_fmt = output_fmt;947 break;948 default:949 return NULL;950 }951 952 input_fmts = kcalloc(1, sizeof(*input_fmts), GFP_KERNEL);953 if (!input_fmts)954 return NULL;955 input_fmts[0] = input_fmt;956 *num_input_fmts = 1;957 958 return input_fmts;959}960 961static const struct drm_bridge_funcs nwl_dsi_bridge_funcs = {962 .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,963 .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,964 .atomic_reset = drm_atomic_helper_bridge_reset,965 .atomic_check = nwl_dsi_bridge_atomic_check,966 .atomic_enable = nwl_dsi_bridge_atomic_enable,967 .atomic_disable = nwl_dsi_bridge_atomic_disable,968 .atomic_get_input_bus_fmts = nwl_bridge_atomic_get_input_bus_fmts,969 .mode_set = nwl_dsi_bridge_mode_set,970 .mode_valid = nwl_dsi_bridge_mode_valid,971 .attach = nwl_dsi_bridge_attach,972};973 974static int nwl_dsi_parse_dt(struct nwl_dsi *dsi)975{976 struct platform_device *pdev = to_platform_device(dsi->dev);977 struct clk *clk;978 void __iomem *base;979 int ret;980 981 dsi->phy = devm_phy_get(dsi->dev, "dphy");982 if (IS_ERR(dsi->phy)) {983 ret = PTR_ERR(dsi->phy);984 if (ret != -EPROBE_DEFER)985 DRM_DEV_ERROR(dsi->dev, "Could not get PHY: %d\n", ret);986 return ret;987 }988 989 clk = devm_clk_get(dsi->dev, "lcdif");990 if (IS_ERR(clk)) {991 ret = PTR_ERR(clk);992 DRM_DEV_ERROR(dsi->dev, "Failed to get lcdif clock: %d\n",993 ret);994 return ret;995 }996 dsi->lcdif_clk = clk;997 998 clk = devm_clk_get(dsi->dev, "core");999 if (IS_ERR(clk)) {1000 ret = PTR_ERR(clk);1001 DRM_DEV_ERROR(dsi->dev, "Failed to get core clock: %d\n",1002 ret);1003 return ret;1004 }1005 dsi->core_clk = clk;1006 1007 clk = devm_clk_get(dsi->dev, "phy_ref");1008 if (IS_ERR(clk)) {1009 ret = PTR_ERR(clk);1010 DRM_DEV_ERROR(dsi->dev, "Failed to get phy_ref clock: %d\n",1011 ret);1012 return ret;1013 }1014 dsi->phy_ref_clk = clk;1015 1016 clk = devm_clk_get(dsi->dev, "rx_esc");1017 if (IS_ERR(clk)) {1018 ret = PTR_ERR(clk);1019 DRM_DEV_ERROR(dsi->dev, "Failed to get rx_esc clock: %d\n",1020 ret);1021 return ret;1022 }1023 dsi->rx_esc_clk = clk;1024 1025 clk = devm_clk_get(dsi->dev, "tx_esc");1026 if (IS_ERR(clk)) {1027 ret = PTR_ERR(clk);1028 DRM_DEV_ERROR(dsi->dev, "Failed to get tx_esc clock: %d\n",1029 ret);1030 return ret;1031 }1032 dsi->tx_esc_clk = clk;1033 1034 dsi->mux = devm_mux_control_get(dsi->dev, NULL);1035 if (IS_ERR(dsi->mux)) {1036 ret = PTR_ERR(dsi->mux);1037 if (ret != -EPROBE_DEFER)1038 DRM_DEV_ERROR(dsi->dev, "Failed to get mux: %d\n", ret);1039 return ret;1040 }1041 1042 base = devm_platform_ioremap_resource(pdev, 0);1043 if (IS_ERR(base))1044 return PTR_ERR(base);1045 1046 dsi->regmap =1047 devm_regmap_init_mmio(dsi->dev, base, &nwl_dsi_regmap_config);1048 if (IS_ERR(dsi->regmap)) {1049 ret = PTR_ERR(dsi->regmap);1050 DRM_DEV_ERROR(dsi->dev, "Failed to create NWL DSI regmap: %d\n",1051 ret);1052 return ret;1053 }1054 1055 dsi->irq = platform_get_irq(pdev, 0);1056 if (dsi->irq < 0) {1057 DRM_DEV_ERROR(dsi->dev, "Failed to get device IRQ: %d\n",1058 dsi->irq);1059 return dsi->irq;1060 }1061 1062 dsi->rst_pclk = devm_reset_control_get_exclusive(dsi->dev, "pclk");1063 if (IS_ERR(dsi->rst_pclk)) {1064 DRM_DEV_ERROR(dsi->dev, "Failed to get pclk reset: %ld\n",1065 PTR_ERR(dsi->rst_pclk));1066 return PTR_ERR(dsi->rst_pclk);1067 }1068 dsi->rst_byte = devm_reset_control_get_exclusive(dsi->dev, "byte");1069 if (IS_ERR(dsi->rst_byte)) {1070 DRM_DEV_ERROR(dsi->dev, "Failed to get byte reset: %ld\n",1071 PTR_ERR(dsi->rst_byte));1072 return PTR_ERR(dsi->rst_byte);1073 }1074 dsi->rst_esc = devm_reset_control_get_exclusive(dsi->dev, "esc");1075 if (IS_ERR(dsi->rst_esc)) {1076 DRM_DEV_ERROR(dsi->dev, "Failed to get esc reset: %ld\n",1077 PTR_ERR(dsi->rst_esc));1078 return PTR_ERR(dsi->rst_esc);1079 }1080 dsi->rst_dpi = devm_reset_control_get_exclusive(dsi->dev, "dpi");1081 if (IS_ERR(dsi->rst_dpi)) {1082 DRM_DEV_ERROR(dsi->dev, "Failed to get dpi reset: %ld\n",1083 PTR_ERR(dsi->rst_dpi));1084 return PTR_ERR(dsi->rst_dpi);1085 }1086 return 0;1087}1088 1089static int nwl_dsi_select_input(struct nwl_dsi *dsi)1090{1091 struct device_node *remote;1092 u32 use_dcss = 1;1093 int ret;1094 1095 remote = of_graph_get_remote_node(dsi->dev->of_node, 0,1096 NWL_DSI_ENDPOINT_LCDIF);1097 if (remote) {1098 use_dcss = 0;1099 } else {1100 remote = of_graph_get_remote_node(dsi->dev->of_node, 0,1101 NWL_DSI_ENDPOINT_DCSS);1102 if (!remote) {1103 DRM_DEV_ERROR(dsi->dev,1104 "No valid input endpoint found\n");1105 return -EINVAL;1106 }1107 }1108 1109 DRM_DEV_INFO(dsi->dev, "Using %s as input source\n",1110 (use_dcss) ? "DCSS" : "LCDIF");1111 ret = mux_control_try_select(dsi->mux, use_dcss);1112 if (ret < 0)1113 DRM_DEV_ERROR(dsi->dev, "Failed to select input: %d\n", ret);1114 1115 of_node_put(remote);1116 return ret;1117}1118 1119static int nwl_dsi_deselect_input(struct nwl_dsi *dsi)1120{1121 int ret;1122 1123 ret = mux_control_deselect(dsi->mux);1124 if (ret < 0)1125 DRM_DEV_ERROR(dsi->dev, "Failed to deselect input: %d\n", ret);1126 1127 return ret;1128}1129 1130static const struct drm_bridge_timings nwl_dsi_timings = {1131 .input_bus_flags = DRM_BUS_FLAG_DE_LOW,1132};1133 1134static const struct of_device_id nwl_dsi_dt_ids[] = {1135 { .compatible = "fsl,imx8mq-nwl-dsi", },1136 { /* sentinel */ }1137};1138MODULE_DEVICE_TABLE(of, nwl_dsi_dt_ids);1139 1140static const struct soc_device_attribute nwl_dsi_quirks_match[] = {1141 { .soc_id = "i.MX8MQ", .revision = "2.0",1142 .data = (void *)E11418_HS_MODE_QUIRK },1143 { /* sentinel. */ }1144};1145 1146static int nwl_dsi_probe(struct platform_device *pdev)1147{1148 struct device *dev = &pdev->dev;1149 const struct soc_device_attribute *attr;1150 struct nwl_dsi *dsi;1151 int ret;1152 1153 dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);1154 if (!dsi)1155 return -ENOMEM;1156 1157 dsi->dev = dev;1158 1159 ret = nwl_dsi_parse_dt(dsi);1160 if (ret)1161 return ret;1162 1163 ret = devm_request_irq(dev, dsi->irq, nwl_dsi_irq_handler, 0,1164 dev_name(dev), dsi);1165 if (ret < 0) {1166 DRM_DEV_ERROR(dev, "Failed to request IRQ %d: %d\n", dsi->irq,1167 ret);1168 return ret;1169 }1170 1171 dsi->dsi_host.ops = &nwl_dsi_host_ops;1172 dsi->dsi_host.dev = dev;1173 ret = mipi_dsi_host_register(&dsi->dsi_host);1174 if (ret) {1175 DRM_DEV_ERROR(dev, "Failed to register MIPI host: %d\n", ret);1176 return ret;1177 }1178 1179 attr = soc_device_match(nwl_dsi_quirks_match);1180 if (attr)1181 dsi->quirks = (uintptr_t)attr->data;1182 1183 dsi->bridge.driver_private = dsi;1184 dsi->bridge.funcs = &nwl_dsi_bridge_funcs;1185 dsi->bridge.of_node = dev->of_node;1186 dsi->bridge.timings = &nwl_dsi_timings;1187 1188 dev_set_drvdata(dev, dsi);1189 pm_runtime_enable(dev);1190 1191 ret = nwl_dsi_select_input(dsi);1192 if (ret < 0) {1193 pm_runtime_disable(dev);1194 mipi_dsi_host_unregister(&dsi->dsi_host);1195 return ret;1196 }1197 1198 drm_bridge_add(&dsi->bridge);1199 return 0;1200}1201 1202static void nwl_dsi_remove(struct platform_device *pdev)1203{1204 struct nwl_dsi *dsi = platform_get_drvdata(pdev);1205 1206 nwl_dsi_deselect_input(dsi);1207 mipi_dsi_host_unregister(&dsi->dsi_host);1208 drm_bridge_remove(&dsi->bridge);1209 pm_runtime_disable(&pdev->dev);1210}1211 1212static struct platform_driver nwl_dsi_driver = {1213 .probe = nwl_dsi_probe,1214 .remove_new = nwl_dsi_remove,1215 .driver = {1216 .of_match_table = nwl_dsi_dt_ids,1217 .name = DRV_NAME,1218 },1219};1220 1221module_platform_driver(nwl_dsi_driver);1222 1223MODULE_AUTHOR("NXP Semiconductor");1224MODULE_AUTHOR("Purism SPC");1225MODULE_DESCRIPTION("Northwest Logic MIPI-DSI driver");1226MODULE_LICENSE("GPL"); /* GPLv2 or later */1227