xref: /linux/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c (revision 2c1ed907520c50326b8f604907a8478b27881a2e)
1*9f1e1e14SHeiko Stuebner // SPDX-License-Identifier: GPL-2.0+
2*9f1e1e14SHeiko Stuebner /*
3*9f1e1e14SHeiko Stuebner  * Copyright (C) 2024 Rockchip Electronics Co., Ltd.
4*9f1e1e14SHeiko Stuebner  * Author:
5*9f1e1e14SHeiko Stuebner  *      Guochun Huang <hero.huang@rock-chips.com>
6*9f1e1e14SHeiko Stuebner  *      Heiko Stuebner <heiko.stuebner@cherry.de>
7*9f1e1e14SHeiko Stuebner  */
8*9f1e1e14SHeiko Stuebner 
9*9f1e1e14SHeiko Stuebner #include <linux/bitfield.h>
10*9f1e1e14SHeiko Stuebner #include <linux/clk.h>
11*9f1e1e14SHeiko Stuebner #include <linux/component.h>
12*9f1e1e14SHeiko Stuebner #include <linux/media-bus-format.h>
13*9f1e1e14SHeiko Stuebner #include <linux/mod_devicetable.h>
14*9f1e1e14SHeiko Stuebner #include <linux/module.h>
15*9f1e1e14SHeiko Stuebner #include <linux/of.h>
16*9f1e1e14SHeiko Stuebner #include <linux/pm_runtime.h>
17*9f1e1e14SHeiko Stuebner #include <linux/platform_device.h>
18*9f1e1e14SHeiko Stuebner #include <linux/regmap.h>
19*9f1e1e14SHeiko Stuebner #include <linux/reset.h>
20*9f1e1e14SHeiko Stuebner #include <linux/mfd/syscon.h>
21*9f1e1e14SHeiko Stuebner #include <linux/phy/phy.h>
22*9f1e1e14SHeiko Stuebner 
23*9f1e1e14SHeiko Stuebner #include <drm/bridge/dw_mipi_dsi2.h>
24*9f1e1e14SHeiko Stuebner #include <drm/drm_mipi_dsi.h>
25*9f1e1e14SHeiko Stuebner #include <drm/drm_of.h>
26*9f1e1e14SHeiko Stuebner #include <drm/drm_simple_kms_helper.h>
27*9f1e1e14SHeiko Stuebner 
28*9f1e1e14SHeiko Stuebner #include <uapi/linux/videodev2.h>
29*9f1e1e14SHeiko Stuebner 
30*9f1e1e14SHeiko Stuebner #include "rockchip_drm_drv.h"
31*9f1e1e14SHeiko Stuebner 
32*9f1e1e14SHeiko Stuebner #define PSEC_PER_SEC			1000000000000LL
33*9f1e1e14SHeiko Stuebner 
34*9f1e1e14SHeiko Stuebner struct dsigrf_reg {
35*9f1e1e14SHeiko Stuebner 	u16 offset;
36*9f1e1e14SHeiko Stuebner 	u16 lsb;
37*9f1e1e14SHeiko Stuebner 	u16 msb;
38*9f1e1e14SHeiko Stuebner };
39*9f1e1e14SHeiko Stuebner 
40*9f1e1e14SHeiko Stuebner enum grf_reg_fields {
41*9f1e1e14SHeiko Stuebner 	TXREQCLKHS_EN,
42*9f1e1e14SHeiko Stuebner 	GATING_EN,
43*9f1e1e14SHeiko Stuebner 	IPI_SHUTDN,
44*9f1e1e14SHeiko Stuebner 	IPI_COLORM,
45*9f1e1e14SHeiko Stuebner 	IPI_COLOR_DEPTH,
46*9f1e1e14SHeiko Stuebner 	IPI_FORMAT,
47*9f1e1e14SHeiko Stuebner 	MAX_FIELDS,
48*9f1e1e14SHeiko Stuebner };
49*9f1e1e14SHeiko Stuebner 
50*9f1e1e14SHeiko Stuebner #define IPI_DEPTH_5_6_5_BITS		0x02
51*9f1e1e14SHeiko Stuebner #define IPI_DEPTH_6_BITS		0x03
52*9f1e1e14SHeiko Stuebner #define IPI_DEPTH_8_BITS		0x05
53*9f1e1e14SHeiko Stuebner #define IPI_DEPTH_10_BITS		0x06
54*9f1e1e14SHeiko Stuebner 
55*9f1e1e14SHeiko Stuebner struct rockchip_dw_dsi2_chip_data {
56*9f1e1e14SHeiko Stuebner 	u32 reg;
57*9f1e1e14SHeiko Stuebner 	const struct dsigrf_reg *grf_regs;
58*9f1e1e14SHeiko Stuebner 	unsigned long long max_bit_rate_per_lane;
59*9f1e1e14SHeiko Stuebner };
60*9f1e1e14SHeiko Stuebner 
61*9f1e1e14SHeiko Stuebner struct dw_mipi_dsi2_rockchip {
62*9f1e1e14SHeiko Stuebner 	struct device *dev;
63*9f1e1e14SHeiko Stuebner 	struct rockchip_encoder encoder;
64*9f1e1e14SHeiko Stuebner 	struct regmap *regmap;
65*9f1e1e14SHeiko Stuebner 
66*9f1e1e14SHeiko Stuebner 	unsigned int lane_mbps; /* per lane */
67*9f1e1e14SHeiko Stuebner 	u32 format;
68*9f1e1e14SHeiko Stuebner 
69*9f1e1e14SHeiko Stuebner 	struct regmap *grf_regmap;
70*9f1e1e14SHeiko Stuebner 	struct phy *phy;
71*9f1e1e14SHeiko Stuebner 	union phy_configure_opts phy_opts;
72*9f1e1e14SHeiko Stuebner 
73*9f1e1e14SHeiko Stuebner 	struct dw_mipi_dsi2 *dmd;
74*9f1e1e14SHeiko Stuebner 	struct dw_mipi_dsi2_plat_data pdata;
75*9f1e1e14SHeiko Stuebner 	const struct rockchip_dw_dsi2_chip_data *cdata;
76*9f1e1e14SHeiko Stuebner };
77*9f1e1e14SHeiko Stuebner 
to_dsi2(struct drm_encoder * encoder)78*9f1e1e14SHeiko Stuebner static inline struct dw_mipi_dsi2_rockchip *to_dsi2(struct drm_encoder *encoder)
79*9f1e1e14SHeiko Stuebner {
80*9f1e1e14SHeiko Stuebner 	struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
81*9f1e1e14SHeiko Stuebner 
82*9f1e1e14SHeiko Stuebner 	return container_of(rkencoder, struct dw_mipi_dsi2_rockchip, encoder);
83*9f1e1e14SHeiko Stuebner }
84*9f1e1e14SHeiko Stuebner 
grf_field_write(struct dw_mipi_dsi2_rockchip * dsi2,enum grf_reg_fields index,unsigned int val)85*9f1e1e14SHeiko Stuebner static void grf_field_write(struct dw_mipi_dsi2_rockchip *dsi2, enum grf_reg_fields index,
86*9f1e1e14SHeiko Stuebner 			    unsigned int val)
87*9f1e1e14SHeiko Stuebner {
88*9f1e1e14SHeiko Stuebner 	const struct dsigrf_reg *field = &dsi2->cdata->grf_regs[index];
89*9f1e1e14SHeiko Stuebner 
90*9f1e1e14SHeiko Stuebner 	if (!field)
91*9f1e1e14SHeiko Stuebner 		return;
92*9f1e1e14SHeiko Stuebner 
93*9f1e1e14SHeiko Stuebner 	regmap_write(dsi2->grf_regmap, field->offset,
94*9f1e1e14SHeiko Stuebner 		     (val << field->lsb) | (GENMASK(field->msb, field->lsb) << 16));
95*9f1e1e14SHeiko Stuebner }
96*9f1e1e14SHeiko Stuebner 
dw_mipi_dsi2_phy_init(void * priv_data)97*9f1e1e14SHeiko Stuebner static int dw_mipi_dsi2_phy_init(void *priv_data)
98*9f1e1e14SHeiko Stuebner {
99*9f1e1e14SHeiko Stuebner 	return 0;
100*9f1e1e14SHeiko Stuebner }
101*9f1e1e14SHeiko Stuebner 
dw_mipi_dsi2_phy_power_on(void * priv_data)102*9f1e1e14SHeiko Stuebner static void dw_mipi_dsi2_phy_power_on(void *priv_data)
103*9f1e1e14SHeiko Stuebner {
104*9f1e1e14SHeiko Stuebner 	struct dw_mipi_dsi2_rockchip *dsi2 = priv_data;
105*9f1e1e14SHeiko Stuebner 	int ret;
106*9f1e1e14SHeiko Stuebner 
107*9f1e1e14SHeiko Stuebner 	ret = phy_set_mode(dsi2->phy, PHY_MODE_MIPI_DPHY);
108*9f1e1e14SHeiko Stuebner 	if (ret) {
109*9f1e1e14SHeiko Stuebner 		dev_err(dsi2->dev, "Failed to set phy mode: %d\n", ret);
110*9f1e1e14SHeiko Stuebner 		return;
111*9f1e1e14SHeiko Stuebner 	}
112*9f1e1e14SHeiko Stuebner 
113*9f1e1e14SHeiko Stuebner 	phy_configure(dsi2->phy, &dsi2->phy_opts);
114*9f1e1e14SHeiko Stuebner 	phy_power_on(dsi2->phy);
115*9f1e1e14SHeiko Stuebner }
116*9f1e1e14SHeiko Stuebner 
dw_mipi_dsi2_phy_power_off(void * priv_data)117*9f1e1e14SHeiko Stuebner static void dw_mipi_dsi2_phy_power_off(void *priv_data)
118*9f1e1e14SHeiko Stuebner {
119*9f1e1e14SHeiko Stuebner 	struct dw_mipi_dsi2_rockchip *dsi2 = priv_data;
120*9f1e1e14SHeiko Stuebner 
121*9f1e1e14SHeiko Stuebner 	phy_power_off(dsi2->phy);
122*9f1e1e14SHeiko Stuebner }
123*9f1e1e14SHeiko Stuebner 
124*9f1e1e14SHeiko Stuebner static int
dw_mipi_dsi2_get_lane_mbps(void * priv_data,const struct drm_display_mode * mode,unsigned long mode_flags,u32 lanes,u32 format,unsigned int * lane_mbps)125*9f1e1e14SHeiko Stuebner dw_mipi_dsi2_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
126*9f1e1e14SHeiko Stuebner 			   unsigned long mode_flags, u32 lanes, u32 format,
127*9f1e1e14SHeiko Stuebner 			   unsigned int *lane_mbps)
128*9f1e1e14SHeiko Stuebner {
129*9f1e1e14SHeiko Stuebner 	struct dw_mipi_dsi2_rockchip *dsi2 = priv_data;
130*9f1e1e14SHeiko Stuebner 	u64 max_lane_rate, target_phyclk;
131*9f1e1e14SHeiko Stuebner 	unsigned int lane_rate_kbps;
132*9f1e1e14SHeiko Stuebner 	int bpp;
133*9f1e1e14SHeiko Stuebner 
134*9f1e1e14SHeiko Stuebner 	max_lane_rate = dsi2->cdata->max_bit_rate_per_lane;
135*9f1e1e14SHeiko Stuebner 
136*9f1e1e14SHeiko Stuebner 	dsi2->format = format;
137*9f1e1e14SHeiko Stuebner 	bpp = mipi_dsi_pixel_format_to_bpp(format);
138*9f1e1e14SHeiko Stuebner 	if (bpp < 0) {
139*9f1e1e14SHeiko Stuebner 		dev_err(dsi2->dev, "failed to get bpp for pixel format %d\n", format);
140*9f1e1e14SHeiko Stuebner 		return bpp;
141*9f1e1e14SHeiko Stuebner 	}
142*9f1e1e14SHeiko Stuebner 
143*9f1e1e14SHeiko Stuebner 	lane_rate_kbps = mode->clock * bpp / lanes;
144*9f1e1e14SHeiko Stuebner 
145*9f1e1e14SHeiko Stuebner 	/*
146*9f1e1e14SHeiko Stuebner 	 * Set BW a little larger only in video burst mode in
147*9f1e1e14SHeiko Stuebner 	 * consideration of the protocol overhead and HS mode
148*9f1e1e14SHeiko Stuebner 	 * switching to BLLP mode, take 1 / 0.9, since Mbps must
149*9f1e1e14SHeiko Stuebner 	 * big than bandwidth of RGB
150*9f1e1e14SHeiko Stuebner 	 */
151*9f1e1e14SHeiko Stuebner 	if (mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
152*9f1e1e14SHeiko Stuebner 		lane_rate_kbps = (lane_rate_kbps * 10) / 9;
153*9f1e1e14SHeiko Stuebner 
154*9f1e1e14SHeiko Stuebner 	if (lane_rate_kbps > max_lane_rate) {
155*9f1e1e14SHeiko Stuebner 		dev_err(dsi2->dev, "DPHY clock frequency is out of range\n");
156*9f1e1e14SHeiko Stuebner 		return -ERANGE;
157*9f1e1e14SHeiko Stuebner 	}
158*9f1e1e14SHeiko Stuebner 
159*9f1e1e14SHeiko Stuebner 	dsi2->lane_mbps = lane_rate_kbps / 1000;
160*9f1e1e14SHeiko Stuebner 	*lane_mbps = dsi2->lane_mbps;
161*9f1e1e14SHeiko Stuebner 
162*9f1e1e14SHeiko Stuebner 	if (dsi2->phy) {
163*9f1e1e14SHeiko Stuebner 		target_phyclk = DIV_ROUND_CLOSEST_ULL(lane_rate_kbps * lanes * 1000, bpp);
164*9f1e1e14SHeiko Stuebner 		phy_mipi_dphy_get_default_config(target_phyclk, bpp, lanes,
165*9f1e1e14SHeiko Stuebner 						 &dsi2->phy_opts.mipi_dphy);
166*9f1e1e14SHeiko Stuebner 	}
167*9f1e1e14SHeiko Stuebner 
168*9f1e1e14SHeiko Stuebner 	return 0;
169*9f1e1e14SHeiko Stuebner }
170*9f1e1e14SHeiko Stuebner 
dw_mipi_dsi2_phy_get_iface(void * priv_data,struct dw_mipi_dsi2_phy_iface * iface)171*9f1e1e14SHeiko Stuebner static void dw_mipi_dsi2_phy_get_iface(void *priv_data, struct dw_mipi_dsi2_phy_iface *iface)
172*9f1e1e14SHeiko Stuebner {
173*9f1e1e14SHeiko Stuebner 	/* PPI width is fixed to 16 bits in DCPHY */
174*9f1e1e14SHeiko Stuebner 	iface->ppi_width = 16;
175*9f1e1e14SHeiko Stuebner 	iface->phy_type = DW_MIPI_DSI2_DPHY;
176*9f1e1e14SHeiko Stuebner }
177*9f1e1e14SHeiko Stuebner 
178*9f1e1e14SHeiko Stuebner static int
dw_mipi_dsi2_phy_get_timing(void * priv_data,unsigned int lane_mbps,struct dw_mipi_dsi2_phy_timing * timing)179*9f1e1e14SHeiko Stuebner dw_mipi_dsi2_phy_get_timing(void *priv_data, unsigned int lane_mbps,
180*9f1e1e14SHeiko Stuebner 			    struct dw_mipi_dsi2_phy_timing *timing)
181*9f1e1e14SHeiko Stuebner {
182*9f1e1e14SHeiko Stuebner 	struct dw_mipi_dsi2_rockchip *dsi2 = priv_data;
183*9f1e1e14SHeiko Stuebner 	struct phy_configure_opts_mipi_dphy *cfg = &dsi2->phy_opts.mipi_dphy;
184*9f1e1e14SHeiko Stuebner 	unsigned long long tmp, ui;
185*9f1e1e14SHeiko Stuebner 	unsigned long long hstx_clk;
186*9f1e1e14SHeiko Stuebner 
187*9f1e1e14SHeiko Stuebner 	hstx_clk = DIV_ROUND_CLOSEST_ULL(dsi2->lane_mbps * USEC_PER_SEC, 16);
188*9f1e1e14SHeiko Stuebner 
189*9f1e1e14SHeiko Stuebner 	ui = ALIGN(PSEC_PER_SEC, hstx_clk);
190*9f1e1e14SHeiko Stuebner 	do_div(ui, hstx_clk);
191*9f1e1e14SHeiko Stuebner 
192*9f1e1e14SHeiko Stuebner 	/* PHY_LP2HS_TIME = (TLPX + THS-PREPARE + THS-ZERO) / Tphy_hstx_clk */
193*9f1e1e14SHeiko Stuebner 	tmp = cfg->lpx + cfg->hs_prepare + cfg->hs_zero;
194*9f1e1e14SHeiko Stuebner 	tmp = DIV_ROUND_CLOSEST_ULL(tmp << 16, ui);
195*9f1e1e14SHeiko Stuebner 	timing->data_lp2hs = tmp;
196*9f1e1e14SHeiko Stuebner 
197*9f1e1e14SHeiko Stuebner 	/* PHY_HS2LP_TIME = (THS-TRAIL + THS-EXIT) / Tphy_hstx_clk */
198*9f1e1e14SHeiko Stuebner 	tmp = cfg->hs_trail + cfg->hs_exit;
199*9f1e1e14SHeiko Stuebner 	tmp = DIV_ROUND_CLOSEST_ULL(tmp << 16, ui);
200*9f1e1e14SHeiko Stuebner 	timing->data_hs2lp = tmp;
201*9f1e1e14SHeiko Stuebner 
202*9f1e1e14SHeiko Stuebner 	return 0;
203*9f1e1e14SHeiko Stuebner }
204*9f1e1e14SHeiko Stuebner 
205*9f1e1e14SHeiko Stuebner static const struct dw_mipi_dsi2_phy_ops dw_mipi_dsi2_rockchip_phy_ops = {
206*9f1e1e14SHeiko Stuebner 	.init = dw_mipi_dsi2_phy_init,
207*9f1e1e14SHeiko Stuebner 	.power_on = dw_mipi_dsi2_phy_power_on,
208*9f1e1e14SHeiko Stuebner 	.power_off = dw_mipi_dsi2_phy_power_off,
209*9f1e1e14SHeiko Stuebner 	.get_interface = dw_mipi_dsi2_phy_get_iface,
210*9f1e1e14SHeiko Stuebner 	.get_lane_mbps = dw_mipi_dsi2_get_lane_mbps,
211*9f1e1e14SHeiko Stuebner 	.get_timing = dw_mipi_dsi2_phy_get_timing,
212*9f1e1e14SHeiko Stuebner };
213*9f1e1e14SHeiko Stuebner 
dw_mipi_dsi2_encoder_atomic_enable(struct drm_encoder * encoder,struct drm_atomic_state * state)214*9f1e1e14SHeiko Stuebner static void dw_mipi_dsi2_encoder_atomic_enable(struct drm_encoder *encoder,
215*9f1e1e14SHeiko Stuebner 					       struct drm_atomic_state *state)
216*9f1e1e14SHeiko Stuebner {
217*9f1e1e14SHeiko Stuebner 	struct dw_mipi_dsi2_rockchip *dsi2 = to_dsi2(encoder);
218*9f1e1e14SHeiko Stuebner 	u32 color_depth;
219*9f1e1e14SHeiko Stuebner 
220*9f1e1e14SHeiko Stuebner 	switch (dsi2->format) {
221*9f1e1e14SHeiko Stuebner 	case MIPI_DSI_FMT_RGB666:
222*9f1e1e14SHeiko Stuebner 	case MIPI_DSI_FMT_RGB666_PACKED:
223*9f1e1e14SHeiko Stuebner 		color_depth = IPI_DEPTH_6_BITS;
224*9f1e1e14SHeiko Stuebner 		break;
225*9f1e1e14SHeiko Stuebner 	case MIPI_DSI_FMT_RGB565:
226*9f1e1e14SHeiko Stuebner 		color_depth = IPI_DEPTH_5_6_5_BITS;
227*9f1e1e14SHeiko Stuebner 		break;
228*9f1e1e14SHeiko Stuebner 	case MIPI_DSI_FMT_RGB888:
229*9f1e1e14SHeiko Stuebner 		color_depth = IPI_DEPTH_8_BITS;
230*9f1e1e14SHeiko Stuebner 		break;
231*9f1e1e14SHeiko Stuebner 	default:
232*9f1e1e14SHeiko Stuebner 		/* Should've been caught by atomic_check */
233*9f1e1e14SHeiko Stuebner 		WARN_ON(1);
234*9f1e1e14SHeiko Stuebner 		return;
235*9f1e1e14SHeiko Stuebner 	}
236*9f1e1e14SHeiko Stuebner 
237*9f1e1e14SHeiko Stuebner 	grf_field_write(dsi2, IPI_COLOR_DEPTH, color_depth);
238*9f1e1e14SHeiko Stuebner }
239*9f1e1e14SHeiko Stuebner 
240*9f1e1e14SHeiko Stuebner static int
dw_mipi_dsi2_encoder_atomic_check(struct drm_encoder * encoder,struct drm_crtc_state * crtc_state,struct drm_connector_state * conn_state)241*9f1e1e14SHeiko Stuebner dw_mipi_dsi2_encoder_atomic_check(struct drm_encoder *encoder,
242*9f1e1e14SHeiko Stuebner 				  struct drm_crtc_state *crtc_state,
243*9f1e1e14SHeiko Stuebner 				  struct drm_connector_state *conn_state)
244*9f1e1e14SHeiko Stuebner {
245*9f1e1e14SHeiko Stuebner 	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
246*9f1e1e14SHeiko Stuebner 	struct dw_mipi_dsi2_rockchip *dsi2 = to_dsi2(encoder);
247*9f1e1e14SHeiko Stuebner 	struct drm_connector *connector = conn_state->connector;
248*9f1e1e14SHeiko Stuebner 	struct drm_display_info *info = &connector->display_info;
249*9f1e1e14SHeiko Stuebner 
250*9f1e1e14SHeiko Stuebner 	switch (dsi2->format) {
251*9f1e1e14SHeiko Stuebner 	case MIPI_DSI_FMT_RGB666:
252*9f1e1e14SHeiko Stuebner 	case MIPI_DSI_FMT_RGB666_PACKED:
253*9f1e1e14SHeiko Stuebner 		s->output_mode = ROCKCHIP_OUT_MODE_P666;
254*9f1e1e14SHeiko Stuebner 		break;
255*9f1e1e14SHeiko Stuebner 	case MIPI_DSI_FMT_RGB565:
256*9f1e1e14SHeiko Stuebner 		s->output_mode = ROCKCHIP_OUT_MODE_P565;
257*9f1e1e14SHeiko Stuebner 		break;
258*9f1e1e14SHeiko Stuebner 	case MIPI_DSI_FMT_RGB888:
259*9f1e1e14SHeiko Stuebner 		s->output_mode = ROCKCHIP_OUT_MODE_P888;
260*9f1e1e14SHeiko Stuebner 		break;
261*9f1e1e14SHeiko Stuebner 	default:
262*9f1e1e14SHeiko Stuebner 		WARN_ON(1);
263*9f1e1e14SHeiko Stuebner 		return -EINVAL;
264*9f1e1e14SHeiko Stuebner 	}
265*9f1e1e14SHeiko Stuebner 
266*9f1e1e14SHeiko Stuebner 	if (info->num_bus_formats)
267*9f1e1e14SHeiko Stuebner 		s->bus_format = info->bus_formats[0];
268*9f1e1e14SHeiko Stuebner 	else
269*9f1e1e14SHeiko Stuebner 		s->bus_format = MEDIA_BUS_FMT_RGB888_1X24;
270*9f1e1e14SHeiko Stuebner 
271*9f1e1e14SHeiko Stuebner 	s->output_type = DRM_MODE_CONNECTOR_DSI;
272*9f1e1e14SHeiko Stuebner 	s->bus_flags = info->bus_flags;
273*9f1e1e14SHeiko Stuebner 	s->color_space = V4L2_COLORSPACE_DEFAULT;
274*9f1e1e14SHeiko Stuebner 
275*9f1e1e14SHeiko Stuebner 	return 0;
276*9f1e1e14SHeiko Stuebner }
277*9f1e1e14SHeiko Stuebner 
278*9f1e1e14SHeiko Stuebner static const struct drm_encoder_helper_funcs
279*9f1e1e14SHeiko Stuebner dw_mipi_dsi2_encoder_helper_funcs = {
280*9f1e1e14SHeiko Stuebner 	.atomic_enable = dw_mipi_dsi2_encoder_atomic_enable,
281*9f1e1e14SHeiko Stuebner 	.atomic_check = dw_mipi_dsi2_encoder_atomic_check,
282*9f1e1e14SHeiko Stuebner };
283*9f1e1e14SHeiko Stuebner 
rockchip_dsi2_drm_create_encoder(struct dw_mipi_dsi2_rockchip * dsi2,struct drm_device * drm_dev)284*9f1e1e14SHeiko Stuebner static int rockchip_dsi2_drm_create_encoder(struct dw_mipi_dsi2_rockchip *dsi2,
285*9f1e1e14SHeiko Stuebner 					    struct drm_device *drm_dev)
286*9f1e1e14SHeiko Stuebner {
287*9f1e1e14SHeiko Stuebner 	struct drm_encoder *encoder = &dsi2->encoder.encoder;
288*9f1e1e14SHeiko Stuebner 	int ret;
289*9f1e1e14SHeiko Stuebner 
290*9f1e1e14SHeiko Stuebner 	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
291*9f1e1e14SHeiko Stuebner 							     dsi2->dev->of_node);
292*9f1e1e14SHeiko Stuebner 
293*9f1e1e14SHeiko Stuebner 	ret = drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_DSI);
294*9f1e1e14SHeiko Stuebner 	if (ret) {
295*9f1e1e14SHeiko Stuebner 		dev_err(dsi2->dev, "Failed to initialize encoder with drm\n");
296*9f1e1e14SHeiko Stuebner 		return ret;
297*9f1e1e14SHeiko Stuebner 	}
298*9f1e1e14SHeiko Stuebner 
299*9f1e1e14SHeiko Stuebner 	drm_encoder_helper_add(encoder, &dw_mipi_dsi2_encoder_helper_funcs);
300*9f1e1e14SHeiko Stuebner 
301*9f1e1e14SHeiko Stuebner 	return 0;
302*9f1e1e14SHeiko Stuebner }
303*9f1e1e14SHeiko Stuebner 
dw_mipi_dsi2_rockchip_bind(struct device * dev,struct device * master,void * data)304*9f1e1e14SHeiko Stuebner static int dw_mipi_dsi2_rockchip_bind(struct device *dev, struct device *master,
305*9f1e1e14SHeiko Stuebner 				      void *data)
306*9f1e1e14SHeiko Stuebner {
307*9f1e1e14SHeiko Stuebner 	struct dw_mipi_dsi2_rockchip *dsi2 = dev_get_drvdata(dev);
308*9f1e1e14SHeiko Stuebner 	struct drm_device *drm_dev = data;
309*9f1e1e14SHeiko Stuebner 	int ret;
310*9f1e1e14SHeiko Stuebner 
311*9f1e1e14SHeiko Stuebner 	ret = rockchip_dsi2_drm_create_encoder(dsi2, drm_dev);
312*9f1e1e14SHeiko Stuebner 	if (ret)
313*9f1e1e14SHeiko Stuebner 		return dev_err_probe(dev, ret, "Failed to create drm encoder\n");
314*9f1e1e14SHeiko Stuebner 
315*9f1e1e14SHeiko Stuebner 	rockchip_drm_encoder_set_crtc_endpoint_id(&dsi2->encoder,
316*9f1e1e14SHeiko Stuebner 						  dev->of_node, 0, 0);
317*9f1e1e14SHeiko Stuebner 
318*9f1e1e14SHeiko Stuebner 	ret = dw_mipi_dsi2_bind(dsi2->dmd, &dsi2->encoder.encoder);
319*9f1e1e14SHeiko Stuebner 	if (ret)
320*9f1e1e14SHeiko Stuebner 		return dev_err_probe(dev, ret, "Failed to bind\n");
321*9f1e1e14SHeiko Stuebner 
322*9f1e1e14SHeiko Stuebner 	return 0;
323*9f1e1e14SHeiko Stuebner }
324*9f1e1e14SHeiko Stuebner 
dw_mipi_dsi2_rockchip_unbind(struct device * dev,struct device * master,void * data)325*9f1e1e14SHeiko Stuebner static void dw_mipi_dsi2_rockchip_unbind(struct device *dev, struct device *master,
326*9f1e1e14SHeiko Stuebner 					 void *data)
327*9f1e1e14SHeiko Stuebner {
328*9f1e1e14SHeiko Stuebner 	struct dw_mipi_dsi2_rockchip *dsi2 = dev_get_drvdata(dev);
329*9f1e1e14SHeiko Stuebner 
330*9f1e1e14SHeiko Stuebner 	dw_mipi_dsi2_unbind(dsi2->dmd);
331*9f1e1e14SHeiko Stuebner }
332*9f1e1e14SHeiko Stuebner 
333*9f1e1e14SHeiko Stuebner static const struct component_ops dw_mipi_dsi2_rockchip_ops = {
334*9f1e1e14SHeiko Stuebner 	.bind	= dw_mipi_dsi2_rockchip_bind,
335*9f1e1e14SHeiko Stuebner 	.unbind	= dw_mipi_dsi2_rockchip_unbind,
336*9f1e1e14SHeiko Stuebner };
337*9f1e1e14SHeiko Stuebner 
dw_mipi_dsi2_rockchip_host_attach(void * priv_data,struct mipi_dsi_device * device)338*9f1e1e14SHeiko Stuebner static int dw_mipi_dsi2_rockchip_host_attach(void *priv_data,
339*9f1e1e14SHeiko Stuebner 					     struct mipi_dsi_device *device)
340*9f1e1e14SHeiko Stuebner {
341*9f1e1e14SHeiko Stuebner 	struct dw_mipi_dsi2_rockchip *dsi2 = priv_data;
342*9f1e1e14SHeiko Stuebner 	int ret;
343*9f1e1e14SHeiko Stuebner 
344*9f1e1e14SHeiko Stuebner 	ret = component_add(dsi2->dev, &dw_mipi_dsi2_rockchip_ops);
345*9f1e1e14SHeiko Stuebner 	if (ret)
346*9f1e1e14SHeiko Stuebner 		return dev_err_probe(dsi2->dev, ret, "Failed to register component\n");
347*9f1e1e14SHeiko Stuebner 
348*9f1e1e14SHeiko Stuebner 	return 0;
349*9f1e1e14SHeiko Stuebner }
350*9f1e1e14SHeiko Stuebner 
dw_mipi_dsi2_rockchip_host_detach(void * priv_data,struct mipi_dsi_device * device)351*9f1e1e14SHeiko Stuebner static int dw_mipi_dsi2_rockchip_host_detach(void *priv_data,
352*9f1e1e14SHeiko Stuebner 					     struct mipi_dsi_device *device)
353*9f1e1e14SHeiko Stuebner {
354*9f1e1e14SHeiko Stuebner 	struct dw_mipi_dsi2_rockchip *dsi2 = priv_data;
355*9f1e1e14SHeiko Stuebner 
356*9f1e1e14SHeiko Stuebner 	component_del(dsi2->dev, &dw_mipi_dsi2_rockchip_ops);
357*9f1e1e14SHeiko Stuebner 
358*9f1e1e14SHeiko Stuebner 	return 0;
359*9f1e1e14SHeiko Stuebner }
360*9f1e1e14SHeiko Stuebner 
361*9f1e1e14SHeiko Stuebner static const struct dw_mipi_dsi2_host_ops dw_mipi_dsi2_rockchip_host_ops = {
362*9f1e1e14SHeiko Stuebner 	.attach = dw_mipi_dsi2_rockchip_host_attach,
363*9f1e1e14SHeiko Stuebner 	.detach = dw_mipi_dsi2_rockchip_host_detach,
364*9f1e1e14SHeiko Stuebner };
365*9f1e1e14SHeiko Stuebner 
366*9f1e1e14SHeiko Stuebner static const struct regmap_config dw_mipi_dsi2_rockchip_regmap_config = {
367*9f1e1e14SHeiko Stuebner 	.name = "dsi2-host",
368*9f1e1e14SHeiko Stuebner 	.reg_bits = 32,
369*9f1e1e14SHeiko Stuebner 	.val_bits = 32,
370*9f1e1e14SHeiko Stuebner 	.reg_stride = 4,
371*9f1e1e14SHeiko Stuebner 	.fast_io = true,
372*9f1e1e14SHeiko Stuebner };
373*9f1e1e14SHeiko Stuebner 
dw_mipi_dsi2_rockchip_probe(struct platform_device * pdev)374*9f1e1e14SHeiko Stuebner static int dw_mipi_dsi2_rockchip_probe(struct platform_device *pdev)
375*9f1e1e14SHeiko Stuebner {
376*9f1e1e14SHeiko Stuebner 	struct device *dev = &pdev->dev;
377*9f1e1e14SHeiko Stuebner 	struct device_node *np = dev->of_node;
378*9f1e1e14SHeiko Stuebner 	const struct rockchip_dw_dsi2_chip_data *cdata =
379*9f1e1e14SHeiko Stuebner 						of_device_get_match_data(dev);
380*9f1e1e14SHeiko Stuebner 	struct dw_mipi_dsi2_rockchip *dsi2;
381*9f1e1e14SHeiko Stuebner 	struct resource *res;
382*9f1e1e14SHeiko Stuebner 	void __iomem *base;
383*9f1e1e14SHeiko Stuebner 	int i;
384*9f1e1e14SHeiko Stuebner 
385*9f1e1e14SHeiko Stuebner 	dsi2 = devm_kzalloc(dev, sizeof(*dsi2), GFP_KERNEL);
386*9f1e1e14SHeiko Stuebner 	if (!dsi2)
387*9f1e1e14SHeiko Stuebner 		return -ENOMEM;
388*9f1e1e14SHeiko Stuebner 
389*9f1e1e14SHeiko Stuebner 	base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
390*9f1e1e14SHeiko Stuebner 	if (IS_ERR(base))
391*9f1e1e14SHeiko Stuebner 		return dev_err_probe(dev, PTR_ERR(base), "Unable to get dsi registers\n");
392*9f1e1e14SHeiko Stuebner 
393*9f1e1e14SHeiko Stuebner 	dsi2->regmap = devm_regmap_init_mmio(dev, base, &dw_mipi_dsi2_rockchip_regmap_config);
394*9f1e1e14SHeiko Stuebner 	if (IS_ERR(dsi2->regmap))
395*9f1e1e14SHeiko Stuebner 		return dev_err_probe(dev, PTR_ERR(dsi2->regmap), "failed to init register map\n");
396*9f1e1e14SHeiko Stuebner 
397*9f1e1e14SHeiko Stuebner 	i = 0;
398*9f1e1e14SHeiko Stuebner 	while (cdata[i].reg) {
399*9f1e1e14SHeiko Stuebner 		if (cdata[i].reg == res->start) {
400*9f1e1e14SHeiko Stuebner 			dsi2->cdata = &cdata[i];
401*9f1e1e14SHeiko Stuebner 			break;
402*9f1e1e14SHeiko Stuebner 		}
403*9f1e1e14SHeiko Stuebner 
404*9f1e1e14SHeiko Stuebner 		i++;
405*9f1e1e14SHeiko Stuebner 	}
406*9f1e1e14SHeiko Stuebner 
407*9f1e1e14SHeiko Stuebner 	if (!dsi2->cdata)
408*9f1e1e14SHeiko Stuebner 		return dev_err_probe(dev, -EINVAL, "No dsi-config for %s node\n", np->name);
409*9f1e1e14SHeiko Stuebner 
410*9f1e1e14SHeiko Stuebner 	dsi2->grf_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
411*9f1e1e14SHeiko Stuebner 	if (IS_ERR(dsi2->grf_regmap))
412*9f1e1e14SHeiko Stuebner 		return dev_err_probe(dsi2->dev, PTR_ERR(dsi2->grf_regmap), "Unable to get grf\n");
413*9f1e1e14SHeiko Stuebner 
414*9f1e1e14SHeiko Stuebner 	dsi2->phy = devm_phy_optional_get(dev, "dcphy");
415*9f1e1e14SHeiko Stuebner 	if (IS_ERR(dsi2->phy))
416*9f1e1e14SHeiko Stuebner 		return dev_err_probe(dev, PTR_ERR(dsi2->phy), "failed to get mipi phy\n");
417*9f1e1e14SHeiko Stuebner 
418*9f1e1e14SHeiko Stuebner 	dsi2->dev = dev;
419*9f1e1e14SHeiko Stuebner 	dsi2->pdata.regmap = dsi2->regmap;
420*9f1e1e14SHeiko Stuebner 	dsi2->pdata.max_data_lanes = 4;
421*9f1e1e14SHeiko Stuebner 	dsi2->pdata.phy_ops = &dw_mipi_dsi2_rockchip_phy_ops;
422*9f1e1e14SHeiko Stuebner 	dsi2->pdata.host_ops = &dw_mipi_dsi2_rockchip_host_ops;
423*9f1e1e14SHeiko Stuebner 	dsi2->pdata.priv_data = dsi2;
424*9f1e1e14SHeiko Stuebner 	platform_set_drvdata(pdev, dsi2);
425*9f1e1e14SHeiko Stuebner 
426*9f1e1e14SHeiko Stuebner 	dsi2->dmd = dw_mipi_dsi2_probe(pdev, &dsi2->pdata);
427*9f1e1e14SHeiko Stuebner 	if (IS_ERR(dsi2->dmd))
428*9f1e1e14SHeiko Stuebner 		return dev_err_probe(dev, PTR_ERR(dsi2->dmd), "Failed to probe dw_mipi_dsi2\n");
429*9f1e1e14SHeiko Stuebner 
430*9f1e1e14SHeiko Stuebner 	return 0;
431*9f1e1e14SHeiko Stuebner }
432*9f1e1e14SHeiko Stuebner 
dw_mipi_dsi2_rockchip_remove(struct platform_device * pdev)433*9f1e1e14SHeiko Stuebner static void dw_mipi_dsi2_rockchip_remove(struct platform_device *pdev)
434*9f1e1e14SHeiko Stuebner {
435*9f1e1e14SHeiko Stuebner 	struct dw_mipi_dsi2_rockchip *dsi2 = platform_get_drvdata(pdev);
436*9f1e1e14SHeiko Stuebner 
437*9f1e1e14SHeiko Stuebner 	dw_mipi_dsi2_remove(dsi2->dmd);
438*9f1e1e14SHeiko Stuebner }
439*9f1e1e14SHeiko Stuebner 
440*9f1e1e14SHeiko Stuebner static const struct dsigrf_reg rk3588_dsi0_grf_reg_fields[MAX_FIELDS] = {
441*9f1e1e14SHeiko Stuebner 	[TXREQCLKHS_EN]		= { 0x0000, 11, 11 },
442*9f1e1e14SHeiko Stuebner 	[GATING_EN]		= { 0x0000, 10, 10 },
443*9f1e1e14SHeiko Stuebner 	[IPI_SHUTDN]		= { 0x0000,  9,  9 },
444*9f1e1e14SHeiko Stuebner 	[IPI_COLORM]		= { 0x0000,  8,  8 },
445*9f1e1e14SHeiko Stuebner 	[IPI_COLOR_DEPTH]	= { 0x0000,  4,  7 },
446*9f1e1e14SHeiko Stuebner 	[IPI_FORMAT]		= { 0x0000,  0,  3 },
447*9f1e1e14SHeiko Stuebner };
448*9f1e1e14SHeiko Stuebner 
449*9f1e1e14SHeiko Stuebner static const struct dsigrf_reg rk3588_dsi1_grf_reg_fields[MAX_FIELDS] = {
450*9f1e1e14SHeiko Stuebner 	[TXREQCLKHS_EN]		= { 0x0004, 11, 11 },
451*9f1e1e14SHeiko Stuebner 	[GATING_EN]		= { 0x0004, 10, 10 },
452*9f1e1e14SHeiko Stuebner 	[IPI_SHUTDN]		= { 0x0004,  9,  9 },
453*9f1e1e14SHeiko Stuebner 	[IPI_COLORM]		= { 0x0004,  8,  8 },
454*9f1e1e14SHeiko Stuebner 	[IPI_COLOR_DEPTH]	= { 0x0004,  4,  7 },
455*9f1e1e14SHeiko Stuebner 	[IPI_FORMAT]		= { 0x0004,  0,  3 },
456*9f1e1e14SHeiko Stuebner };
457*9f1e1e14SHeiko Stuebner 
458*9f1e1e14SHeiko Stuebner static const struct rockchip_dw_dsi2_chip_data rk3588_chip_data[] = {
459*9f1e1e14SHeiko Stuebner 	{
460*9f1e1e14SHeiko Stuebner 		.reg = 0xfde20000,
461*9f1e1e14SHeiko Stuebner 		.grf_regs = rk3588_dsi0_grf_reg_fields,
462*9f1e1e14SHeiko Stuebner 		.max_bit_rate_per_lane = 4500000ULL,
463*9f1e1e14SHeiko Stuebner 	},
464*9f1e1e14SHeiko Stuebner 	{
465*9f1e1e14SHeiko Stuebner 		.reg = 0xfde30000,
466*9f1e1e14SHeiko Stuebner 		.grf_regs = rk3588_dsi1_grf_reg_fields,
467*9f1e1e14SHeiko Stuebner 		.max_bit_rate_per_lane = 4500000ULL,
468*9f1e1e14SHeiko Stuebner 	}
469*9f1e1e14SHeiko Stuebner };
470*9f1e1e14SHeiko Stuebner 
471*9f1e1e14SHeiko Stuebner static const struct of_device_id dw_mipi_dsi2_rockchip_dt_ids[] = {
472*9f1e1e14SHeiko Stuebner 	{
473*9f1e1e14SHeiko Stuebner 		.compatible = "rockchip,rk3588-mipi-dsi2",
474*9f1e1e14SHeiko Stuebner 		.data = &rk3588_chip_data,
475*9f1e1e14SHeiko Stuebner 	},
476*9f1e1e14SHeiko Stuebner 	{}
477*9f1e1e14SHeiko Stuebner };
478*9f1e1e14SHeiko Stuebner MODULE_DEVICE_TABLE(of, dw_mipi_dsi2_rockchip_dt_ids);
479*9f1e1e14SHeiko Stuebner 
480*9f1e1e14SHeiko Stuebner struct platform_driver dw_mipi_dsi2_rockchip_driver = {
481*9f1e1e14SHeiko Stuebner 	.probe	= dw_mipi_dsi2_rockchip_probe,
482*9f1e1e14SHeiko Stuebner 	.remove = dw_mipi_dsi2_rockchip_remove,
483*9f1e1e14SHeiko Stuebner 	.driver = {
484*9f1e1e14SHeiko Stuebner 		.of_match_table = dw_mipi_dsi2_rockchip_dt_ids,
485*9f1e1e14SHeiko Stuebner 		.name = "dw-mipi-dsi2",
486*9f1e1e14SHeiko Stuebner 	},
487*9f1e1e14SHeiko Stuebner };
488