brintos

brintos / linux-shallow public Read only

0
0
Text · 33.9 KiB · 4abf4f1 Raw
1258 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Copyright (c) 2016 Allwinnertech Co., Ltd.4 * Copyright (C) 2017-2018 Bootlin5 *6 * Maxime Ripard <maxime.ripard@bootlin.com>7 */8 9#include <linux/clk.h>10#include <linux/component.h>11#include <linux/crc-ccitt.h>12#include <linux/module.h>13#include <linux/of_address.h>14#include <linux/phy/phy-mipi-dphy.h>15#include <linux/phy/phy.h>16#include <linux/platform_device.h>17#include <linux/regmap.h>18#include <linux/regulator/consumer.h>19#include <linux/reset.h>20#include <linux/slab.h>21 22#include <drm/drm_atomic_helper.h>23#include <drm/drm_mipi_dsi.h>24#include <drm/drm_panel.h>25#include <drm/drm_print.h>26#include <drm/drm_probe_helper.h>27#include <drm/drm_simple_kms_helper.h>28 29#include "sun4i_crtc.h"30#include "sun4i_tcon.h"31#include "sun6i_mipi_dsi.h"32 33#include <video/mipi_display.h>34 35#define SUN6I_DSI_CTL_REG		0x00036#define SUN6I_DSI_CTL_EN			BIT(0)37 38#define SUN6I_DSI_BASIC_CTL_REG		0x00c39#define SUN6I_DSI_BASIC_CTL_TRAIL_INV(n)		(((n) & 0xf) << 4)40#define SUN6I_DSI_BASIC_CTL_TRAIL_FILL		BIT(3)41#define SUN6I_DSI_BASIC_CTL_HBP_DIS		BIT(2)42#define SUN6I_DSI_BASIC_CTL_HSA_HSE_DIS		BIT(1)43#define SUN6I_DSI_BASIC_CTL_VIDEO_BURST		BIT(0)44 45#define SUN6I_DSI_BASIC_CTL0_REG	0x01046#define SUN6I_DSI_BASIC_CTL0_HS_EOTP_EN		BIT(18)47#define SUN6I_DSI_BASIC_CTL0_CRC_EN		BIT(17)48#define SUN6I_DSI_BASIC_CTL0_ECC_EN		BIT(16)49#define SUN6I_DSI_BASIC_CTL0_INST_ST		BIT(0)50 51#define SUN6I_DSI_BASIC_CTL1_REG	0x01452#define SUN6I_DSI_BASIC_CTL1_VIDEO_ST_DELAY(n)	(((n) & 0x1fff) << 4)53#define SUN6I_DSI_BASIC_CTL1_VIDEO_FILL		BIT(2)54#define SUN6I_DSI_BASIC_CTL1_VIDEO_PRECISION	BIT(1)55#define SUN6I_DSI_BASIC_CTL1_VIDEO_MODE		BIT(0)56 57#define SUN6I_DSI_BASIC_SIZE0_REG	0x01858#define SUN6I_DSI_BASIC_SIZE0_VBP(n)		(((n) & 0xfff) << 16)59#define SUN6I_DSI_BASIC_SIZE0_VSA(n)		((n) & 0xfff)60 61#define SUN6I_DSI_BASIC_SIZE1_REG	0x01c62#define SUN6I_DSI_BASIC_SIZE1_VT(n)		(((n) & 0xfff) << 16)63#define SUN6I_DSI_BASIC_SIZE1_VACT(n)		((n) & 0xfff)64 65#define SUN6I_DSI_INST_FUNC_REG(n)	(0x020 + (n) * 0x04)66#define SUN6I_DSI_INST_FUNC_INST_MODE(n)	(((n) & 0xf) << 28)67#define SUN6I_DSI_INST_FUNC_ESCAPE_ENTRY(n)	(((n) & 0xf) << 24)68#define SUN6I_DSI_INST_FUNC_TRANS_PACKET(n)	(((n) & 0xf) << 20)69#define SUN6I_DSI_INST_FUNC_LANE_CEN		BIT(4)70#define SUN6I_DSI_INST_FUNC_LANE_DEN(n)		((n) & 0xf)71 72#define SUN6I_DSI_INST_LOOP_SEL_REG	0x04073 74#define SUN6I_DSI_INST_LOOP_NUM_REG(n)	(0x044 + (n) * 0x10)75#define SUN6I_DSI_INST_LOOP_NUM_N1(n)		(((n) & 0xfff) << 16)76#define SUN6I_DSI_INST_LOOP_NUM_N0(n)		((n) & 0xfff)77 78#define SUN6I_DSI_INST_JUMP_SEL_REG	0x04879 80#define SUN6I_DSI_INST_JUMP_CFG_REG(n)	(0x04c + (n) * 0x04)81#define SUN6I_DSI_INST_JUMP_CFG_TO(n)		(((n) & 0xf) << 20)82#define SUN6I_DSI_INST_JUMP_CFG_POINT(n)	(((n) & 0xf) << 16)83#define SUN6I_DSI_INST_JUMP_CFG_NUM(n)		((n) & 0xffff)84 85#define SUN6I_DSI_TRANS_START_REG	0x06086 87#define SUN6I_DSI_TRANS_ZERO_REG	0x07888 89#define SUN6I_DSI_TCON_DRQ_REG		0x07c90#define SUN6I_DSI_TCON_DRQ_ENABLE_MODE		BIT(28)91#define SUN6I_DSI_TCON_DRQ_SET(n)		((n) & 0x3ff)92 93#define SUN6I_DSI_PIXEL_CTL0_REG	0x08094#define SUN6I_DSI_PIXEL_CTL0_PD_PLUG_DISABLE	BIT(16)95#define SUN6I_DSI_PIXEL_CTL0_FORMAT(n)		((n) & 0xf)96 97#define SUN6I_DSI_PIXEL_CTL1_REG	0x08498 99#define SUN6I_DSI_PIXEL_PH_REG		0x090100#define SUN6I_DSI_PIXEL_PH_ECC(n)		(((n) & 0xff) << 24)101#define SUN6I_DSI_PIXEL_PH_WC(n)		(((n) & 0xffff) << 8)102#define SUN6I_DSI_PIXEL_PH_VC(n)		(((n) & 3) << 6)103#define SUN6I_DSI_PIXEL_PH_DT(n)		((n) & 0x3f)104 105#define SUN6I_DSI_PIXEL_PF0_REG		0x098106#define SUN6I_DSI_PIXEL_PF0_CRC_FORCE(n)	((n) & 0xffff)107 108#define SUN6I_DSI_PIXEL_PF1_REG		0x09c109#define SUN6I_DSI_PIXEL_PF1_CRC_INIT_LINEN(n)	(((n) & 0xffff) << 16)110#define SUN6I_DSI_PIXEL_PF1_CRC_INIT_LINE0(n)	((n) & 0xffff)111 112#define SUN6I_DSI_SYNC_HSS_REG		0x0b0113 114#define SUN6I_DSI_SYNC_HSE_REG		0x0b4115 116#define SUN6I_DSI_SYNC_VSS_REG		0x0b8117 118#define SUN6I_DSI_SYNC_VSE_REG		0x0bc119 120#define SUN6I_DSI_BLK_HSA0_REG		0x0c0121 122#define SUN6I_DSI_BLK_HSA1_REG		0x0c4123#define SUN6I_DSI_BLK_PF(n)			(((n) & 0xffff) << 16)124#define SUN6I_DSI_BLK_PD(n)			((n) & 0xff)125 126#define SUN6I_DSI_BLK_HBP0_REG		0x0c8127 128#define SUN6I_DSI_BLK_HBP1_REG		0x0cc129 130#define SUN6I_DSI_BLK_HFP0_REG		0x0d0131 132#define SUN6I_DSI_BLK_HFP1_REG		0x0d4133 134#define SUN6I_DSI_BLK_HBLK0_REG		0x0e0135 136#define SUN6I_DSI_BLK_HBLK1_REG		0x0e4137 138#define SUN6I_DSI_BLK_VBLK0_REG		0x0e8139 140#define SUN6I_DSI_BLK_VBLK1_REG		0x0ec141 142#define SUN6I_DSI_BURST_LINE_REG	0x0f0143#define SUN6I_DSI_BURST_LINE_SYNC_POINT(n)	(((n) & 0xffff) << 16)144#define SUN6I_DSI_BURST_LINE_NUM(n)		((n) & 0xffff)145 146#define SUN6I_DSI_BURST_DRQ_REG		0x0f4147#define SUN6I_DSI_BURST_DRQ_EDGE1(n)		(((n) & 0xffff) << 16)148#define SUN6I_DSI_BURST_DRQ_EDGE0(n)		((n) & 0xffff)149 150#define SUN6I_DSI_CMD_CTL_REG		0x200151#define SUN6I_DSI_CMD_CTL_RX_OVERFLOW		BIT(26)152#define SUN6I_DSI_CMD_CTL_RX_FLAG		BIT(25)153#define SUN6I_DSI_CMD_CTL_TX_FLAG		BIT(9)154 155#define SUN6I_DSI_CMD_RX_REG(n)		(0x240 + (n) * 0x04)156 157#define SUN6I_DSI_DEBUG_DATA_REG	0x2f8158 159#define SUN6I_DSI_CMD_TX_REG(n)		(0x300 + (n) * 0x04)160 161#define SUN6I_DSI_SYNC_POINT		40162 163enum sun6i_dsi_start_inst {164	DSI_START_LPRX,165	DSI_START_LPTX,166	DSI_START_HSC,167	DSI_START_HSD,168};169 170enum sun6i_dsi_inst_id {171	DSI_INST_ID_LP11	= 0,172	DSI_INST_ID_TBA,173	DSI_INST_ID_HSC,174	DSI_INST_ID_HSD,175	DSI_INST_ID_LPDT,176	DSI_INST_ID_HSCEXIT,177	DSI_INST_ID_NOP,178	DSI_INST_ID_DLY,179	DSI_INST_ID_END		= 15,180};181 182enum sun6i_dsi_inst_mode {183	DSI_INST_MODE_STOP	= 0,184	DSI_INST_MODE_TBA,185	DSI_INST_MODE_HS,186	DSI_INST_MODE_ESCAPE,187	DSI_INST_MODE_HSCEXIT,188	DSI_INST_MODE_NOP,189};190 191enum sun6i_dsi_inst_escape {192	DSI_INST_ESCA_LPDT	= 0,193	DSI_INST_ESCA_ULPS,194	DSI_INST_ESCA_UN1,195	DSI_INST_ESCA_UN2,196	DSI_INST_ESCA_RESET,197	DSI_INST_ESCA_UN3,198	DSI_INST_ESCA_UN4,199	DSI_INST_ESCA_UN5,200};201 202enum sun6i_dsi_inst_packet {203	DSI_INST_PACK_PIXEL	= 0,204	DSI_INST_PACK_COMMAND,205};206 207static const u32 sun6i_dsi_ecc_array[] = {208	[0] = (BIT(0) | BIT(1) | BIT(2) | BIT(4) | BIT(5) | BIT(7) | BIT(10) |209	       BIT(11) | BIT(13) | BIT(16) | BIT(20) | BIT(21) | BIT(22) |210	       BIT(23)),211	[1] = (BIT(0) | BIT(1) | BIT(3) | BIT(4) | BIT(6) | BIT(8) | BIT(10) |212	       BIT(12) | BIT(14) | BIT(17) | BIT(20) | BIT(21) | BIT(22) |213	       BIT(23)),214	[2] = (BIT(0) | BIT(2) | BIT(3) | BIT(5) | BIT(6) | BIT(9) | BIT(11) |215	       BIT(12) | BIT(15) | BIT(18) | BIT(20) | BIT(21) | BIT(22)),216	[3] = (BIT(1) | BIT(2) | BIT(3) | BIT(7) | BIT(8) | BIT(9) | BIT(13) |217	       BIT(14) | BIT(15) | BIT(19) | BIT(20) | BIT(21) | BIT(23)),218	[4] = (BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(16) |219	       BIT(17) | BIT(18) | BIT(19) | BIT(20) | BIT(22) | BIT(23)),220	[5] = (BIT(10) | BIT(11) | BIT(12) | BIT(13) | BIT(14) | BIT(15) |221	       BIT(16) | BIT(17) | BIT(18) | BIT(19) | BIT(21) | BIT(22) |222	       BIT(23)),223};224 225static u32 sun6i_dsi_ecc_compute(unsigned int data)226{227	int i;228	u8 ecc = 0;229 230	for (i = 0; i < ARRAY_SIZE(sun6i_dsi_ecc_array); i++) {231		u32 field = sun6i_dsi_ecc_array[i];232		bool init = false;233		u8 val = 0;234		int j;235 236		for (j = 0; j < 24; j++) {237			if (!(BIT(j) & field))238				continue;239 240			if (!init) {241				val = (BIT(j) & data) ? 1 : 0;242				init = true;243			} else {244				val ^= (BIT(j) & data) ? 1 : 0;245			}246		}247 248		ecc |= val << i;249	}250 251	return ecc;252}253 254static u16 sun6i_dsi_crc_compute(u8 const *buffer, size_t len)255{256	return crc_ccitt(0xffff, buffer, len);257}258 259static u16 sun6i_dsi_crc_repeat(u8 pd, u8 *buffer, size_t len)260{261	memset(buffer, pd, len);262 263	return sun6i_dsi_crc_compute(buffer, len);264}265 266static u32 sun6i_dsi_build_sync_pkt(u8 dt, u8 vc, u8 d0, u8 d1)267{268	u32 val = dt & 0x3f;269 270	val |= (vc & 3) << 6;271	val |= (d0 & 0xff) << 8;272	val |= (d1 & 0xff) << 16;273	val |= sun6i_dsi_ecc_compute(val) << 24;274 275	return val;276}277 278static u32 sun6i_dsi_build_blk0_pkt(u8 vc, u16 wc)279{280	return sun6i_dsi_build_sync_pkt(MIPI_DSI_BLANKING_PACKET, vc,281					wc & 0xff, wc >> 8);282}283 284static u32 sun6i_dsi_build_blk1_pkt(u16 pd, u8 *buffer, size_t len)285{286	u32 val = SUN6I_DSI_BLK_PD(pd);287 288	return val | SUN6I_DSI_BLK_PF(sun6i_dsi_crc_repeat(pd, buffer, len));289}290 291static void sun6i_dsi_inst_abort(struct sun6i_dsi *dsi)292{293	regmap_update_bits(dsi->regs, SUN6I_DSI_BASIC_CTL0_REG,294			   SUN6I_DSI_BASIC_CTL0_INST_ST, 0);295}296 297static void sun6i_dsi_inst_commit(struct sun6i_dsi *dsi)298{299	regmap_update_bits(dsi->regs, SUN6I_DSI_BASIC_CTL0_REG,300			   SUN6I_DSI_BASIC_CTL0_INST_ST,301			   SUN6I_DSI_BASIC_CTL0_INST_ST);302}303 304static int sun6i_dsi_inst_wait_for_completion(struct sun6i_dsi *dsi)305{306	u32 val;307 308	return regmap_read_poll_timeout(dsi->regs, SUN6I_DSI_BASIC_CTL0_REG,309					val,310					!(val & SUN6I_DSI_BASIC_CTL0_INST_ST),311					100, 5000);312}313 314static void sun6i_dsi_inst_setup(struct sun6i_dsi *dsi,315				 enum sun6i_dsi_inst_id id,316				 enum sun6i_dsi_inst_mode mode,317				 bool clock, u8 data,318				 enum sun6i_dsi_inst_packet packet,319				 enum sun6i_dsi_inst_escape escape)320{321	regmap_write(dsi->regs, SUN6I_DSI_INST_FUNC_REG(id),322		     SUN6I_DSI_INST_FUNC_INST_MODE(mode) |323		     SUN6I_DSI_INST_FUNC_ESCAPE_ENTRY(escape) |324		     SUN6I_DSI_INST_FUNC_TRANS_PACKET(packet) |325		     (clock ? SUN6I_DSI_INST_FUNC_LANE_CEN : 0) |326		     SUN6I_DSI_INST_FUNC_LANE_DEN(data));327}328 329static void sun6i_dsi_inst_init(struct sun6i_dsi *dsi,330				struct mipi_dsi_device *device)331{332	u8 lanes_mask = GENMASK(device->lanes - 1, 0);333 334	sun6i_dsi_inst_setup(dsi, DSI_INST_ID_LP11, DSI_INST_MODE_STOP,335			     true, lanes_mask, 0, 0);336 337	sun6i_dsi_inst_setup(dsi, DSI_INST_ID_TBA, DSI_INST_MODE_TBA,338			     false, 1, 0, 0);339 340	sun6i_dsi_inst_setup(dsi, DSI_INST_ID_HSC, DSI_INST_MODE_HS,341			     true, 0, DSI_INST_PACK_PIXEL, 0);342 343	sun6i_dsi_inst_setup(dsi, DSI_INST_ID_HSD, DSI_INST_MODE_HS,344			     false, lanes_mask, DSI_INST_PACK_PIXEL, 0);345 346	sun6i_dsi_inst_setup(dsi, DSI_INST_ID_LPDT, DSI_INST_MODE_ESCAPE,347			     false, 1, DSI_INST_PACK_COMMAND,348			     DSI_INST_ESCA_LPDT);349 350	sun6i_dsi_inst_setup(dsi, DSI_INST_ID_HSCEXIT, DSI_INST_MODE_HSCEXIT,351			     true, 0, 0, 0);352 353	sun6i_dsi_inst_setup(dsi, DSI_INST_ID_NOP, DSI_INST_MODE_STOP,354			     false, lanes_mask, 0, 0);355 356	sun6i_dsi_inst_setup(dsi, DSI_INST_ID_DLY, DSI_INST_MODE_NOP,357			     true, lanes_mask, 0, 0);358 359	regmap_write(dsi->regs, SUN6I_DSI_INST_JUMP_CFG_REG(0),360		     SUN6I_DSI_INST_JUMP_CFG_POINT(DSI_INST_ID_NOP) |361		     SUN6I_DSI_INST_JUMP_CFG_TO(DSI_INST_ID_HSCEXIT) |362		     SUN6I_DSI_INST_JUMP_CFG_NUM(1));363};364 365static u16 sun6i_dsi_get_video_start_delay(struct sun6i_dsi *dsi,366					   struct drm_display_mode *mode)367{368	u16 delay = mode->vtotal - (mode->vsync_start - mode->vdisplay) + 1;369 370	if (delay > mode->vtotal)371		delay = delay % mode->vtotal;372 373	return max_t(u16, delay, 1);374}375 376static u16 sun6i_dsi_get_line_num(struct sun6i_dsi *dsi,377				  struct drm_display_mode *mode)378{379	struct mipi_dsi_device *device = dsi->device;380	unsigned int Bpp = mipi_dsi_pixel_format_to_bpp(device->format) / 8;381 382	return mode->htotal * Bpp / device->lanes;383}384 385static u16 sun6i_dsi_get_drq_edge0(struct sun6i_dsi *dsi,386				   struct drm_display_mode *mode,387				   u16 line_num, u16 edge1)388{389	u16 edge0 = edge1;390 391	edge0 += (mode->hdisplay + 40) * SUN6I_DSI_TCON_DIV / 8;392 393	if (edge0 > line_num)394		return edge0 - line_num;395 396	return 1;397}398 399static u16 sun6i_dsi_get_drq_edge1(struct sun6i_dsi *dsi,400				   struct drm_display_mode *mode,401				   u16 line_num)402{403	struct mipi_dsi_device *device = dsi->device;404	unsigned int Bpp = mipi_dsi_pixel_format_to_bpp(device->format) / 8;405	unsigned int hbp = mode->htotal - mode->hsync_end;406	u16 edge1;407 408	edge1 = SUN6I_DSI_SYNC_POINT;409	edge1 += (mode->hdisplay + hbp + 20) * Bpp / device->lanes;410 411	if (edge1 > line_num)412		return line_num;413 414	return edge1;415}416 417static void sun6i_dsi_setup_burst(struct sun6i_dsi *dsi,418				  struct drm_display_mode *mode)419{420	struct mipi_dsi_device *device = dsi->device;421	u32 val = 0;422 423	if (device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) {424		u16 line_num = sun6i_dsi_get_line_num(dsi, mode);425		u16 edge0, edge1;426 427		edge1 = sun6i_dsi_get_drq_edge1(dsi, mode, line_num);428		edge0 = sun6i_dsi_get_drq_edge0(dsi, mode, line_num, edge1);429 430		regmap_write(dsi->regs, SUN6I_DSI_BURST_DRQ_REG,431			     SUN6I_DSI_BURST_DRQ_EDGE0(edge0) |432			     SUN6I_DSI_BURST_DRQ_EDGE1(edge1));433 434		regmap_write(dsi->regs, SUN6I_DSI_BURST_LINE_REG,435			     SUN6I_DSI_BURST_LINE_NUM(line_num) |436			     SUN6I_DSI_BURST_LINE_SYNC_POINT(SUN6I_DSI_SYNC_POINT));437 438		val = SUN6I_DSI_TCON_DRQ_ENABLE_MODE;439	} else if ((mode->hsync_start - mode->hdisplay) > 20) {440		/* Maaaaaagic */441		u16 drq = (mode->hsync_start - mode->hdisplay) - 20;442 443		drq *= mipi_dsi_pixel_format_to_bpp(device->format);444		drq /= 32;445 446		val = (SUN6I_DSI_TCON_DRQ_ENABLE_MODE |447		       SUN6I_DSI_TCON_DRQ_SET(drq));448	}449 450	regmap_write(dsi->regs, SUN6I_DSI_TCON_DRQ_REG, val);451}452 453static void sun6i_dsi_setup_inst_loop(struct sun6i_dsi *dsi,454				      struct drm_display_mode *mode)455{456	struct mipi_dsi_device *device = dsi->device;457	u16 delay = 50 - 1;458 459	if (device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) {460		u32 hsync_porch = (mode->htotal - mode->hdisplay) * 150;461 462		delay = (hsync_porch / ((mode->clock / 1000) * 8));463		delay -= 50;464	}465 466	regmap_write(dsi->regs, SUN6I_DSI_INST_LOOP_SEL_REG,467		     2 << (4 * DSI_INST_ID_LP11) |468		     3 << (4 * DSI_INST_ID_DLY));469 470	regmap_write(dsi->regs, SUN6I_DSI_INST_LOOP_NUM_REG(0),471		     SUN6I_DSI_INST_LOOP_NUM_N0(50 - 1) |472		     SUN6I_DSI_INST_LOOP_NUM_N1(delay));473	regmap_write(dsi->regs, SUN6I_DSI_INST_LOOP_NUM_REG(1),474		     SUN6I_DSI_INST_LOOP_NUM_N0(50 - 1) |475		     SUN6I_DSI_INST_LOOP_NUM_N1(delay));476}477 478static void sun6i_dsi_setup_format(struct sun6i_dsi *dsi,479				   struct drm_display_mode *mode)480{481	struct mipi_dsi_device *device = dsi->device;482	u32 val = SUN6I_DSI_PIXEL_PH_VC(device->channel);483	u8 dt, fmt;484	u16 wc;485 486	/*487	 * TODO: The format defines are only valid in video mode and488	 * change in command mode.489	 */490	switch (device->format) {491	case MIPI_DSI_FMT_RGB888:492		dt = MIPI_DSI_PACKED_PIXEL_STREAM_24;493		fmt = 8;494		break;495	case MIPI_DSI_FMT_RGB666:496		dt = MIPI_DSI_PIXEL_STREAM_3BYTE_18;497		fmt = 9;498		break;499	case MIPI_DSI_FMT_RGB666_PACKED:500		dt = MIPI_DSI_PACKED_PIXEL_STREAM_18;501		fmt = 10;502		break;503	case MIPI_DSI_FMT_RGB565:504		dt = MIPI_DSI_PACKED_PIXEL_STREAM_16;505		fmt = 11;506		break;507	default:508		return;509	}510	val |= SUN6I_DSI_PIXEL_PH_DT(dt);511 512	wc = mode->hdisplay * mipi_dsi_pixel_format_to_bpp(device->format) / 8;513	val |= SUN6I_DSI_PIXEL_PH_WC(wc);514	val |= SUN6I_DSI_PIXEL_PH_ECC(sun6i_dsi_ecc_compute(val));515 516	regmap_write(dsi->regs, SUN6I_DSI_PIXEL_PH_REG, val);517 518	regmap_write(dsi->regs, SUN6I_DSI_PIXEL_PF0_REG,519		     SUN6I_DSI_PIXEL_PF0_CRC_FORCE(0xffff));520 521	regmap_write(dsi->regs, SUN6I_DSI_PIXEL_PF1_REG,522		     SUN6I_DSI_PIXEL_PF1_CRC_INIT_LINE0(0xffff) |523		     SUN6I_DSI_PIXEL_PF1_CRC_INIT_LINEN(0xffff));524 525	regmap_write(dsi->regs, SUN6I_DSI_PIXEL_CTL0_REG,526		     SUN6I_DSI_PIXEL_CTL0_PD_PLUG_DISABLE |527		     SUN6I_DSI_PIXEL_CTL0_FORMAT(fmt));528}529 530static void sun6i_dsi_setup_timings(struct sun6i_dsi *dsi,531				    struct drm_display_mode *mode)532{533	struct mipi_dsi_device *device = dsi->device;534	int Bpp = mipi_dsi_pixel_format_to_bpp(device->format) / 8;535	u16 hbp = 0, hfp = 0, hsa = 0, hblk = 0, vblk = 0;536	u32 basic_ctl = 0;537	size_t bytes;538	u8 *buffer;539 540	/* Do all timing calculations up front to allocate buffer space */541 542	if (device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) {543		hblk = mode->hdisplay * Bpp;544		basic_ctl = SUN6I_DSI_BASIC_CTL_VIDEO_BURST |545			    SUN6I_DSI_BASIC_CTL_HSA_HSE_DIS |546			    SUN6I_DSI_BASIC_CTL_HBP_DIS;547 548		if (device->lanes == 4)549			basic_ctl |= SUN6I_DSI_BASIC_CTL_TRAIL_FILL |550				     SUN6I_DSI_BASIC_CTL_TRAIL_INV(0xc);551	} else {552		/*553		 * A sync period is composed of a blanking packet (4554		 * bytes + payload + 2 bytes) and a sync event packet555		 * (4 bytes). Its minimal size is therefore 10 bytes556		 */557#define HSA_PACKET_OVERHEAD	10558		hsa = max(HSA_PACKET_OVERHEAD,559			  (mode->hsync_end - mode->hsync_start) * Bpp - HSA_PACKET_OVERHEAD);560 561		/*562		 * The backporch is set using a blanking packet (4563		 * bytes + payload + 2 bytes). Its minimal size is564		 * therefore 6 bytes565		 */566#define HBP_PACKET_OVERHEAD	6567		hbp = max(HBP_PACKET_OVERHEAD,568			  (mode->htotal - mode->hsync_end) * Bpp - HBP_PACKET_OVERHEAD);569 570		/*571		 * The frontporch is set using a sync event (4 bytes)572		 * and two blanking packets (each one is 4 bytes +573		 * payload + 2 bytes). Its minimal size is therefore574		 * 16 bytes575		 */576#define HFP_PACKET_OVERHEAD	16577		hfp = max(HFP_PACKET_OVERHEAD,578			  (mode->hsync_start - mode->hdisplay) * Bpp - HFP_PACKET_OVERHEAD);579 580		/*581		 * The blanking is set using a sync event (4 bytes)582		 * and a blanking packet (4 bytes + payload + 2583		 * bytes). Its minimal size is therefore 10 bytes.584		 */585#define HBLK_PACKET_OVERHEAD	10586		hblk = max(HBLK_PACKET_OVERHEAD,587			   (mode->htotal - (mode->hsync_end - mode->hsync_start)) * Bpp -588			   HBLK_PACKET_OVERHEAD);589 590		/*591		 * And I'm not entirely sure what vblk is about. The driver in592		 * Allwinner BSP is using a rather convoluted calculation593		 * there only for 4 lanes. However, using 0 (the !4 lanes594		 * case) even with a 4 lanes screen seems to work...595		 */596		vblk = 0;597	}598 599	/* How many bytes do we need to send all payloads? */600	bytes = max_t(size_t, max(max(hfp, hblk), max(hsa, hbp)), vblk);601	buffer = kmalloc(bytes, GFP_KERNEL);602	if (WARN_ON(!buffer))603		return;604 605	regmap_write(dsi->regs, SUN6I_DSI_BASIC_CTL_REG, basic_ctl);606 607	regmap_write(dsi->regs, SUN6I_DSI_SYNC_HSS_REG,608		     sun6i_dsi_build_sync_pkt(MIPI_DSI_H_SYNC_START,609					      device->channel,610					      0, 0));611 612	regmap_write(dsi->regs, SUN6I_DSI_SYNC_HSE_REG,613		     sun6i_dsi_build_sync_pkt(MIPI_DSI_H_SYNC_END,614					      device->channel,615					      0, 0));616 617	regmap_write(dsi->regs, SUN6I_DSI_SYNC_VSS_REG,618		     sun6i_dsi_build_sync_pkt(MIPI_DSI_V_SYNC_START,619					      device->channel,620					      0, 0));621 622	regmap_write(dsi->regs, SUN6I_DSI_SYNC_VSE_REG,623		     sun6i_dsi_build_sync_pkt(MIPI_DSI_V_SYNC_END,624					      device->channel,625					      0, 0));626 627	regmap_write(dsi->regs, SUN6I_DSI_BASIC_SIZE0_REG,628		     SUN6I_DSI_BASIC_SIZE0_VSA(mode->vsync_end -629					       mode->vsync_start) |630		     SUN6I_DSI_BASIC_SIZE0_VBP(mode->vtotal -631					       mode->vsync_end));632 633	regmap_write(dsi->regs, SUN6I_DSI_BASIC_SIZE1_REG,634		     SUN6I_DSI_BASIC_SIZE1_VACT(mode->vdisplay) |635		     SUN6I_DSI_BASIC_SIZE1_VT(mode->vtotal));636 637	/* sync */638	regmap_write(dsi->regs, SUN6I_DSI_BLK_HSA0_REG,639		     sun6i_dsi_build_blk0_pkt(device->channel, hsa));640	regmap_write(dsi->regs, SUN6I_DSI_BLK_HSA1_REG,641		     sun6i_dsi_build_blk1_pkt(0, buffer, hsa));642 643	/* backporch */644	regmap_write(dsi->regs, SUN6I_DSI_BLK_HBP0_REG,645		     sun6i_dsi_build_blk0_pkt(device->channel, hbp));646	regmap_write(dsi->regs, SUN6I_DSI_BLK_HBP1_REG,647		     sun6i_dsi_build_blk1_pkt(0, buffer, hbp));648 649	/* frontporch */650	regmap_write(dsi->regs, SUN6I_DSI_BLK_HFP0_REG,651		     sun6i_dsi_build_blk0_pkt(device->channel, hfp));652	regmap_write(dsi->regs, SUN6I_DSI_BLK_HFP1_REG,653		     sun6i_dsi_build_blk1_pkt(0, buffer, hfp));654 655	/* hblk */656	regmap_write(dsi->regs, SUN6I_DSI_BLK_HBLK0_REG,657		     sun6i_dsi_build_blk0_pkt(device->channel, hblk));658	regmap_write(dsi->regs, SUN6I_DSI_BLK_HBLK1_REG,659		     sun6i_dsi_build_blk1_pkt(0, buffer, hblk));660 661	/* vblk */662	regmap_write(dsi->regs, SUN6I_DSI_BLK_VBLK0_REG,663		     sun6i_dsi_build_blk0_pkt(device->channel, vblk));664	regmap_write(dsi->regs, SUN6I_DSI_BLK_VBLK1_REG,665		     sun6i_dsi_build_blk1_pkt(0, buffer, vblk));666 667	kfree(buffer);668}669 670static int sun6i_dsi_start(struct sun6i_dsi *dsi,671			   enum sun6i_dsi_start_inst func)672{673	switch (func) {674	case DSI_START_LPTX:675		regmap_write(dsi->regs, SUN6I_DSI_INST_JUMP_SEL_REG,676			     DSI_INST_ID_LPDT << (4 * DSI_INST_ID_LP11) |677			     DSI_INST_ID_END  << (4 * DSI_INST_ID_LPDT));678		break;679	case DSI_START_LPRX:680		regmap_write(dsi->regs, SUN6I_DSI_INST_JUMP_SEL_REG,681			     DSI_INST_ID_LPDT << (4 * DSI_INST_ID_LP11) |682			     DSI_INST_ID_DLY  << (4 * DSI_INST_ID_LPDT) |683			     DSI_INST_ID_TBA  << (4 * DSI_INST_ID_DLY) |684			     DSI_INST_ID_END  << (4 * DSI_INST_ID_TBA));685		break;686	case DSI_START_HSC:687		regmap_write(dsi->regs, SUN6I_DSI_INST_JUMP_SEL_REG,688			     DSI_INST_ID_HSC  << (4 * DSI_INST_ID_LP11) |689			     DSI_INST_ID_END  << (4 * DSI_INST_ID_HSC));690		break;691	case DSI_START_HSD:692		regmap_write(dsi->regs, SUN6I_DSI_INST_JUMP_SEL_REG,693			     DSI_INST_ID_NOP  << (4 * DSI_INST_ID_LP11) |694			     DSI_INST_ID_HSD  << (4 * DSI_INST_ID_NOP) |695			     DSI_INST_ID_DLY  << (4 * DSI_INST_ID_HSD) |696			     DSI_INST_ID_NOP  << (4 * DSI_INST_ID_DLY) |697			     DSI_INST_ID_END  << (4 * DSI_INST_ID_HSCEXIT));698		break;699	default:700		regmap_write(dsi->regs, SUN6I_DSI_INST_JUMP_SEL_REG,701			     DSI_INST_ID_END  << (4 * DSI_INST_ID_LP11));702		break;703	}704 705	sun6i_dsi_inst_abort(dsi);706	sun6i_dsi_inst_commit(dsi);707 708	if (func == DSI_START_HSC)709		regmap_write_bits(dsi->regs,710				  SUN6I_DSI_INST_FUNC_REG(DSI_INST_ID_LP11),711				  SUN6I_DSI_INST_FUNC_LANE_CEN, 0);712 713	return 0;714}715 716static void sun6i_dsi_encoder_enable(struct drm_encoder *encoder)717{718	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;719	struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);720	struct mipi_dsi_device *device = dsi->device;721	union phy_configure_opts opts = { };722	struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;723	u16 delay;724	int err;725 726	DRM_DEBUG_DRIVER("Enabling DSI output\n");727 728	err = regulator_enable(dsi->regulator);729	if (err)730		dev_warn(dsi->dev, "failed to enable VCC-DSI supply: %d\n", err);731 732	reset_control_deassert(dsi->reset);733	clk_prepare_enable(dsi->mod_clk);734 735	/*736	 * Enable the DSI block.737	 */738	regmap_write(dsi->regs, SUN6I_DSI_CTL_REG, SUN6I_DSI_CTL_EN);739 740	regmap_write(dsi->regs, SUN6I_DSI_BASIC_CTL0_REG,741		     SUN6I_DSI_BASIC_CTL0_ECC_EN | SUN6I_DSI_BASIC_CTL0_CRC_EN);742 743	regmap_write(dsi->regs, SUN6I_DSI_TRANS_START_REG, 10);744	regmap_write(dsi->regs, SUN6I_DSI_TRANS_ZERO_REG, 0);745 746	sun6i_dsi_inst_init(dsi, dsi->device);747 748	regmap_write(dsi->regs, SUN6I_DSI_DEBUG_DATA_REG, 0xff);749 750	delay = sun6i_dsi_get_video_start_delay(dsi, mode);751	regmap_write(dsi->regs, SUN6I_DSI_BASIC_CTL1_REG,752		     SUN6I_DSI_BASIC_CTL1_VIDEO_ST_DELAY(delay) |753		     SUN6I_DSI_BASIC_CTL1_VIDEO_FILL |754		     SUN6I_DSI_BASIC_CTL1_VIDEO_PRECISION |755		     SUN6I_DSI_BASIC_CTL1_VIDEO_MODE);756 757	sun6i_dsi_setup_burst(dsi, mode);758	sun6i_dsi_setup_inst_loop(dsi, mode);759	sun6i_dsi_setup_format(dsi, mode);760	sun6i_dsi_setup_timings(dsi, mode);761 762	phy_init(dsi->dphy);763 764	phy_mipi_dphy_get_default_config(mode->clock * 1000,765					 mipi_dsi_pixel_format_to_bpp(device->format),766					 device->lanes, cfg);767 768	phy_set_mode(dsi->dphy, PHY_MODE_MIPI_DPHY);769	phy_configure(dsi->dphy, &opts);770	phy_power_on(dsi->dphy);771 772	if (dsi->panel)773		drm_panel_prepare(dsi->panel);774 775	/*776	 * FIXME: This should be moved after the switch to HS mode.777	 *778	 * Unfortunately, once in HS mode, it seems like we're not779	 * able to send DCS commands anymore, which would prevent any780	 * panel to send any DCS command as part as their enable781	 * method, which is quite common.782	 *783	 * I haven't seen any artifact due to that sub-optimal784	 * ordering on the panels I've tested it with, so I guess this785	 * will do for now, until that IP is better understood.786	 */787	if (dsi->panel)788		drm_panel_enable(dsi->panel);789 790	sun6i_dsi_start(dsi, DSI_START_HSC);791 792	udelay(1000);793 794	sun6i_dsi_start(dsi, DSI_START_HSD);795}796 797static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)798{799	struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);800 801	DRM_DEBUG_DRIVER("Disabling DSI output\n");802 803	if (dsi->panel) {804		drm_panel_disable(dsi->panel);805		drm_panel_unprepare(dsi->panel);806	}807 808	phy_power_off(dsi->dphy);809	phy_exit(dsi->dphy);810 811	clk_disable_unprepare(dsi->mod_clk);812	reset_control_assert(dsi->reset);813	regulator_disable(dsi->regulator);814}815 816static int sun6i_dsi_get_modes(struct drm_connector *connector)817{818	struct sun6i_dsi *dsi = connector_to_sun6i_dsi(connector);819 820	return drm_panel_get_modes(dsi->panel, connector);821}822 823static const struct drm_connector_helper_funcs sun6i_dsi_connector_helper_funcs = {824	.get_modes	= sun6i_dsi_get_modes,825};826 827static enum drm_connector_status828sun6i_dsi_connector_detect(struct drm_connector *connector, bool force)829{830	struct sun6i_dsi *dsi = connector_to_sun6i_dsi(connector);831 832	return dsi->panel ? connector_status_connected :833			    connector_status_disconnected;834}835 836static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {837	.detect			= sun6i_dsi_connector_detect,838	.fill_modes		= drm_helper_probe_single_connector_modes,839	.destroy		= drm_connector_cleanup,840	.reset			= drm_atomic_helper_connector_reset,841	.atomic_duplicate_state	= drm_atomic_helper_connector_duplicate_state,842	.atomic_destroy_state	= drm_atomic_helper_connector_destroy_state,843};844 845static const struct drm_encoder_helper_funcs sun6i_dsi_enc_helper_funcs = {846	.disable	= sun6i_dsi_encoder_disable,847	.enable		= sun6i_dsi_encoder_enable,848};849 850static u32 sun6i_dsi_dcs_build_pkt_hdr(struct sun6i_dsi *dsi,851				       const struct mipi_dsi_msg *msg)852{853	u32 pkt = msg->type;854 855	if (msg->type == MIPI_DSI_DCS_LONG_WRITE) {856		pkt |= ((msg->tx_len) & 0xffff) << 8;857		pkt |= (((msg->tx_len) >> 8) & 0xffff) << 16;858	} else {859		pkt |= (((u8 *)msg->tx_buf)[0] << 8);860		if (msg->tx_len > 1)861			pkt |= (((u8 *)msg->tx_buf)[1] << 16);862	}863 864	pkt |= sun6i_dsi_ecc_compute(pkt) << 24;865 866	return pkt;867}868 869static int sun6i_dsi_dcs_write_short(struct sun6i_dsi *dsi,870				     const struct mipi_dsi_msg *msg)871{872	regmap_write(dsi->regs, SUN6I_DSI_CMD_TX_REG(0),873		     sun6i_dsi_dcs_build_pkt_hdr(dsi, msg));874	regmap_write_bits(dsi->regs, SUN6I_DSI_CMD_CTL_REG,875			  0xff, (4 - 1));876 877	sun6i_dsi_start(dsi, DSI_START_LPTX);878 879	return msg->tx_len;880}881 882static int sun6i_dsi_dcs_write_long(struct sun6i_dsi *dsi,883				    const struct mipi_dsi_msg *msg)884{885	int ret, len = 0;886	u8 *bounce;887	u16 crc;888 889	regmap_write(dsi->regs, SUN6I_DSI_CMD_TX_REG(0),890		     sun6i_dsi_dcs_build_pkt_hdr(dsi, msg));891 892	bounce = kzalloc(ALIGN(msg->tx_len + sizeof(crc), 4), GFP_KERNEL);893	if (!bounce)894		return -ENOMEM;895 896	memcpy(bounce, msg->tx_buf, msg->tx_len);897	len += msg->tx_len;898 899	crc = sun6i_dsi_crc_compute(bounce, msg->tx_len);900	memcpy((u8 *)bounce + msg->tx_len, &crc, sizeof(crc));901	len += sizeof(crc);902 903	regmap_bulk_write(dsi->regs, SUN6I_DSI_CMD_TX_REG(1), bounce, DIV_ROUND_UP(len, 4));904	regmap_write(dsi->regs, SUN6I_DSI_CMD_CTL_REG, len + 4 - 1);905	kfree(bounce);906 907	sun6i_dsi_start(dsi, DSI_START_LPTX);908 909	ret = sun6i_dsi_inst_wait_for_completion(dsi);910	if (ret < 0) {911		sun6i_dsi_inst_abort(dsi);912		return ret;913	}914 915	/*916	 * TODO: There's some bits (reg 0x200, bits 8/9) that917	 * apparently can be used to check whether the data have been918	 * sent, but I couldn't get it to work reliably.919	 */920	return msg->tx_len;921}922 923static int sun6i_dsi_dcs_read(struct sun6i_dsi *dsi,924			      const struct mipi_dsi_msg *msg)925{926	u32 val;927	int ret;928	u8 byte0;929 930	regmap_write(dsi->regs, SUN6I_DSI_CMD_TX_REG(0),931		     sun6i_dsi_dcs_build_pkt_hdr(dsi, msg));932	regmap_write(dsi->regs, SUN6I_DSI_CMD_CTL_REG,933		     (4 - 1));934 935	sun6i_dsi_start(dsi, DSI_START_LPRX);936 937	ret = sun6i_dsi_inst_wait_for_completion(dsi);938	if (ret < 0) {939		sun6i_dsi_inst_abort(dsi);940		return ret;941	}942 943	/*944	 * TODO: There's some bits (reg 0x200, bits 24/25) that945	 * apparently can be used to check whether the data have been946	 * received, but I couldn't get it to work reliably.947	 */948	regmap_read(dsi->regs, SUN6I_DSI_CMD_CTL_REG, &val);949	if (val & SUN6I_DSI_CMD_CTL_RX_OVERFLOW)950		return -EIO;951 952	regmap_read(dsi->regs, SUN6I_DSI_CMD_RX_REG(0), &val);953	byte0 = val & 0xff;954	if (byte0 == MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT)955		return -EIO;956 957	((u8 *)msg->rx_buf)[0] = (val >> 8);958 959	return 1;960}961 962static int sun6i_dsi_attach(struct mipi_dsi_host *host,963			    struct mipi_dsi_device *device)964{965	struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);966	struct drm_panel *panel = of_drm_find_panel(device->dev.of_node);967 968	if (IS_ERR(panel))969		return PTR_ERR(panel);970	if (!dsi->drm || !dsi->drm->registered)971		return -EPROBE_DEFER;972 973	dsi->panel = panel;974	dsi->device = device;975 976	drm_kms_helper_hotplug_event(dsi->drm);977 978	dev_info(host->dev, "Attached device %s\n", device->name);979 980	return 0;981}982 983static int sun6i_dsi_detach(struct mipi_dsi_host *host,984			    struct mipi_dsi_device *device)985{986	struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);987 988	dsi->panel = NULL;989	dsi->device = NULL;990 991	drm_kms_helper_hotplug_event(dsi->drm);992 993	return 0;994}995 996static ssize_t sun6i_dsi_transfer(struct mipi_dsi_host *host,997				  const struct mipi_dsi_msg *msg)998{999	struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);1000	int ret;1001 1002	ret = sun6i_dsi_inst_wait_for_completion(dsi);1003	if (ret < 0)1004		sun6i_dsi_inst_abort(dsi);1005 1006	regmap_write(dsi->regs, SUN6I_DSI_CMD_CTL_REG,1007		     SUN6I_DSI_CMD_CTL_RX_OVERFLOW |1008		     SUN6I_DSI_CMD_CTL_RX_FLAG |1009		     SUN6I_DSI_CMD_CTL_TX_FLAG);1010 1011	switch (msg->type) {1012	case MIPI_DSI_DCS_SHORT_WRITE:1013	case MIPI_DSI_DCS_SHORT_WRITE_PARAM:1014	case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:1015		ret = sun6i_dsi_dcs_write_short(dsi, msg);1016		break;1017 1018	case MIPI_DSI_DCS_LONG_WRITE:1019		ret = sun6i_dsi_dcs_write_long(dsi, msg);1020		break;1021 1022	case MIPI_DSI_DCS_READ:1023		if (msg->rx_len == 1) {1024			ret = sun6i_dsi_dcs_read(dsi, msg);1025			break;1026		}1027		fallthrough;1028 1029	default:1030		ret = -EINVAL;1031	}1032 1033	return ret;1034}1035 1036static const struct mipi_dsi_host_ops sun6i_dsi_host_ops = {1037	.attach		= sun6i_dsi_attach,1038	.detach		= sun6i_dsi_detach,1039	.transfer	= sun6i_dsi_transfer,1040};1041 1042static const struct regmap_config sun6i_dsi_regmap_config = {1043	.reg_bits	= 32,1044	.val_bits	= 32,1045	.reg_stride	= 4,1046	.max_register	= SUN6I_DSI_CMD_TX_REG(255),1047	.name		= "mipi-dsi",1048};1049 1050static int sun6i_dsi_bind(struct device *dev, struct device *master,1051			 void *data)1052{1053	struct drm_device *drm = data;1054	struct sun6i_dsi *dsi = dev_get_drvdata(dev);1055	int ret;1056 1057	drm_encoder_helper_add(&dsi->encoder,1058			       &sun6i_dsi_enc_helper_funcs);1059	ret = drm_simple_encoder_init(drm, &dsi->encoder,1060				      DRM_MODE_ENCODER_DSI);1061	if (ret) {1062		dev_err(dsi->dev, "Couldn't initialise the DSI encoder\n");1063		return ret;1064	}1065	dsi->encoder.possible_crtcs = BIT(0);1066 1067	drm_connector_helper_add(&dsi->connector,1068				 &sun6i_dsi_connector_helper_funcs);1069	ret = drm_connector_init(drm, &dsi->connector,1070				 &sun6i_dsi_connector_funcs,1071				 DRM_MODE_CONNECTOR_DSI);1072	if (ret) {1073		dev_err(dsi->dev,1074			"Couldn't initialise the DSI connector\n");1075		goto err_cleanup_connector;1076	}1077 1078	drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);1079 1080	dsi->drm = drm;1081 1082	return 0;1083 1084err_cleanup_connector:1085	drm_encoder_cleanup(&dsi->encoder);1086	return ret;1087}1088 1089static void sun6i_dsi_unbind(struct device *dev, struct device *master,1090			    void *data)1091{1092	struct sun6i_dsi *dsi = dev_get_drvdata(dev);1093 1094	dsi->drm = NULL;1095}1096 1097static const struct component_ops sun6i_dsi_ops = {1098	.bind	= sun6i_dsi_bind,1099	.unbind	= sun6i_dsi_unbind,1100};1101 1102static int sun6i_dsi_probe(struct platform_device *pdev)1103{1104	const struct sun6i_dsi_variant *variant;1105	struct device *dev = &pdev->dev;1106	struct sun6i_dsi *dsi;1107	void __iomem *base;1108	int ret;1109 1110	variant = device_get_match_data(dev);1111	if (!variant)1112		return -EINVAL;1113 1114	dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);1115	if (!dsi)1116		return -ENOMEM;1117	dev_set_drvdata(dev, dsi);1118	dsi->dev = dev;1119	dsi->host.ops = &sun6i_dsi_host_ops;1120	dsi->host.dev = dev;1121	dsi->variant = variant;1122 1123	base = devm_platform_ioremap_resource(pdev, 0);1124	if (IS_ERR(base)) {1125		dev_err(dev, "Couldn't map the DSI encoder registers\n");1126		return PTR_ERR(base);1127	}1128 1129	dsi->regulator = devm_regulator_get(dev, "vcc-dsi");1130	if (IS_ERR(dsi->regulator))1131		return dev_err_probe(dev, PTR_ERR(dsi->regulator),1132				     "Couldn't get VCC-DSI supply\n");1133 1134	dsi->reset = devm_reset_control_get_shared(dev, NULL);1135	if (IS_ERR(dsi->reset)) {1136		dev_err(dev, "Couldn't get our reset line\n");1137		return PTR_ERR(dsi->reset);1138	}1139 1140	dsi->regs = devm_regmap_init_mmio(dev, base, &sun6i_dsi_regmap_config);1141	if (IS_ERR(dsi->regs)) {1142		dev_err(dev, "Couldn't init regmap\n");1143		return PTR_ERR(dsi->regs);1144	}1145 1146	dsi->bus_clk = devm_clk_get(dev, variant->has_mod_clk ? "bus" : NULL);1147	if (IS_ERR(dsi->bus_clk))1148		return dev_err_probe(dev, PTR_ERR(dsi->bus_clk),1149				     "Couldn't get the DSI bus clock\n");1150 1151	ret = regmap_mmio_attach_clk(dsi->regs, dsi->bus_clk);1152	if (ret)1153		return ret;1154 1155	if (variant->has_mod_clk) {1156		dsi->mod_clk = devm_clk_get(dev, "mod");1157		if (IS_ERR(dsi->mod_clk)) {1158			dev_err(dev, "Couldn't get the DSI mod clock\n");1159			ret = PTR_ERR(dsi->mod_clk);1160			goto err_attach_clk;1161		}1162 1163		/*1164		 * In order to operate properly, the module clock on the1165		 * A31 variant always seems to be set to 297MHz.1166		 */1167		if (variant->set_mod_clk)1168			clk_set_rate_exclusive(dsi->mod_clk, 297000000);1169	}1170 1171	dsi->dphy = devm_phy_get(dev, "dphy");1172	if (IS_ERR(dsi->dphy)) {1173		dev_err(dev, "Couldn't get the MIPI D-PHY\n");1174		ret = PTR_ERR(dsi->dphy);1175		goto err_unprotect_clk;1176	}1177 1178	ret = mipi_dsi_host_register(&dsi->host);1179	if (ret) {1180		dev_err(dev, "Couldn't register MIPI-DSI host\n");1181		goto err_unprotect_clk;1182	}1183 1184	ret = component_add(&pdev->dev, &sun6i_dsi_ops);1185	if (ret) {1186		dev_err(dev, "Couldn't register our component\n");1187		goto err_remove_dsi_host;1188	}1189 1190	return 0;1191 1192err_remove_dsi_host:1193	mipi_dsi_host_unregister(&dsi->host);1194err_unprotect_clk:1195	if (dsi->variant->has_mod_clk && dsi->variant->set_mod_clk)1196		clk_rate_exclusive_put(dsi->mod_clk);1197err_attach_clk:1198	regmap_mmio_detach_clk(dsi->regs);1199 1200	return ret;1201}1202 1203static void sun6i_dsi_remove(struct platform_device *pdev)1204{1205	struct device *dev = &pdev->dev;1206	struct sun6i_dsi *dsi = dev_get_drvdata(dev);1207 1208	component_del(&pdev->dev, &sun6i_dsi_ops);1209	mipi_dsi_host_unregister(&dsi->host);1210	if (dsi->variant->has_mod_clk && dsi->variant->set_mod_clk)1211		clk_rate_exclusive_put(dsi->mod_clk);1212 1213	regmap_mmio_detach_clk(dsi->regs);1214}1215 1216static const struct sun6i_dsi_variant sun6i_a31_mipi_dsi_variant = {1217	.has_mod_clk	= true,1218	.set_mod_clk	= true,1219};1220 1221static const struct sun6i_dsi_variant sun50i_a64_mipi_dsi_variant = {1222};1223 1224static const struct sun6i_dsi_variant sun50i_a100_mipi_dsi_variant = {1225	.has_mod_clk	= true,1226};1227 1228static const struct of_device_id sun6i_dsi_of_table[] = {1229	{1230		.compatible	= "allwinner,sun6i-a31-mipi-dsi",1231		.data		= &sun6i_a31_mipi_dsi_variant,1232	},1233	{1234		.compatible	= "allwinner,sun50i-a64-mipi-dsi",1235		.data		= &sun50i_a64_mipi_dsi_variant,1236	},1237	{1238		.compatible	= "allwinner,sun50i-a100-mipi-dsi",1239		.data		= &sun50i_a100_mipi_dsi_variant,1240	},1241	{ }1242};1243MODULE_DEVICE_TABLE(of, sun6i_dsi_of_table);1244 1245static struct platform_driver sun6i_dsi_platform_driver = {1246	.probe		= sun6i_dsi_probe,1247	.remove_new	= sun6i_dsi_remove,1248	.driver		= {1249		.name		= "sun6i-mipi-dsi",1250		.of_match_table	= sun6i_dsi_of_table,1251	},1252};1253module_platform_driver(sun6i_dsi_platform_driver);1254 1255MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");1256MODULE_DESCRIPTION("Allwinner A31 DSI Driver");1257MODULE_LICENSE("GPL");1258