Blame view

drivers/video/sh_mipi_dsi.c 15.5 KB
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
1
2
3
4
5
6
7
8
9
  /*
   * Renesas SH-mobile MIPI DSI support
   *
   * Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
   *
   * This is free software; you can redistribute it and/or modify
   * it under the terms of version 2 of the GNU General Public License as
   * published by the Free Software Foundation.
   */
26c3d7ac2   Kuninori Morimoto   fbdev: sh_mipi_ds...
10
  #include <linux/bitmap.h>
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
11
12
13
14
15
  #include <linux/clk.h>
  #include <linux/delay.h>
  #include <linux/init.h>
  #include <linux/io.h>
  #include <linux/platform_device.h>
236782a5f   Guennadi Liakhovetski   fbdev: sh-mobile:...
16
  #include <linux/pm_runtime.h>
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
17
18
19
  #include <linux/slab.h>
  #include <linux/string.h>
  #include <linux/types.h>
355b200ba   Paul Gortmaker   video: Add module...
20
  #include <linux/module.h>
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
21
22
23
24
  
  #include <video/mipi_display.h>
  #include <video/sh_mipi_dsi.h>
  #include <video/sh_mobile_lcdc.h>
71b146c81   Magnus Damm   fbdev: sh_mipi_ds...
25
26
27
28
29
30
31
32
33
34
35
36
  #define SYSCTRL		0x0000
  #define SYSCONF		0x0004
  #define TIMSET		0x0008
  #define RESREQSET0	0x0018
  #define RESREQSET1	0x001c
  #define HSTTOVSET	0x0020
  #define LPRTOVSET	0x0024
  #define TATOVSET	0x0028
  #define PRTOVSET	0x002c
  #define DSICTRL		0x0030
  #define DSIINTE		0x0060
  #define PHYCTRL		0x0070
deaba1901   Magnus Damm   fbdev: sh_mipi_ds...
37
38
39
40
41
  /* relative to linkbase */
  #define DTCTR		0x0000
  #define VMCTR1		0x0020
  #define VMCTR2		0x0024
  #define VMLEN1		0x0028
08750617b   Kuninori Morimoto   fbdev: sh_mipi_ds...
42
  #define VMLEN2		0x002c
deaba1901   Magnus Damm   fbdev: sh_mipi_ds...
43
44
  #define CMTSRTREQ	0x0070
  #define CMTSRTCTR	0x00d0
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
45
46
47
48
49
50
  
  /* E.g., sh7372 has 2 MIPI-DSIs - one for each LCDC */
  #define MAX_SH_MIPI_DSI 2
  
  struct sh_mipi {
  	void __iomem	*base;
deaba1901   Magnus Damm   fbdev: sh_mipi_ds...
51
  	void __iomem	*linkbase;
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
52
  	struct clk	*dsit_clk;
7d9f88b4f   Kuninori Morimoto   fbdev: sh_mipi_ds...
53
  	struct platform_device *pdev;
236782a5f   Guennadi Liakhovetski   fbdev: sh-mobile:...
54
55
56
57
  
  	void	*next_board_data;
  	void	(*next_display_on)(void *board_data, struct fb_info *info);
  	void	(*next_display_off)(void *board_data);
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
  };
  
  static struct sh_mipi *mipi_dsi[MAX_SH_MIPI_DSI];
  
  /* Protect the above array */
  static DEFINE_MUTEX(array_lock);
  
  static struct sh_mipi *sh_mipi_by_handle(int handle)
  {
  	if (handle >= ARRAY_SIZE(mipi_dsi) || handle < 0)
  		return NULL;
  
  	return mipi_dsi[handle];
  }
  
  static int sh_mipi_send_short(struct sh_mipi *mipi, u8 dsi_cmd,
  			      u8 cmd, u8 param)
  {
  	u32 data = (dsi_cmd << 24) | (cmd << 16) | (param << 8);
  	int cnt = 100;
  
  	/* transmit a short packet to LCD panel */
deaba1901   Magnus Damm   fbdev: sh_mipi_ds...
80
81
  	iowrite32(1 | data, mipi->linkbase + CMTSRTCTR);
  	iowrite32(1, mipi->linkbase + CMTSRTREQ);
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
82

deaba1901   Magnus Damm   fbdev: sh_mipi_ds...
83
  	while ((ioread32(mipi->linkbase + CMTSRTREQ) & 1) && --cnt)
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
  		udelay(1);
  
  	return cnt ? 0 : -ETIMEDOUT;
  }
  
  #define LCD_CHAN2MIPI(c) ((c) < LCDC_CHAN_MAINLCD || (c) > LCDC_CHAN_SUBLCD ? \
  				-EINVAL : (c) - 1)
  
  static int sh_mipi_dcs(int handle, u8 cmd)
  {
  	struct sh_mipi *mipi = sh_mipi_by_handle(LCD_CHAN2MIPI(handle));
  	if (!mipi)
  		return -ENODEV;
  	return sh_mipi_send_short(mipi, MIPI_DSI_DCS_SHORT_WRITE, cmd, 0);
  }
  
  static int sh_mipi_dcs_param(int handle, u8 cmd, u8 param)
  {
  	struct sh_mipi *mipi = sh_mipi_by_handle(LCD_CHAN2MIPI(handle));
  	if (!mipi)
  		return -ENODEV;
  	return sh_mipi_send_short(mipi, MIPI_DSI_DCS_SHORT_WRITE_PARAM, cmd,
  				  param);
  }
  
  static void sh_mipi_dsi_enable(struct sh_mipi *mipi, bool enable)
  {
  	/*
  	 * enable LCDC data tx, transition to LPS after completion of each HS
  	 * packet
  	 */
deaba1901   Magnus Damm   fbdev: sh_mipi_ds...
115
  	iowrite32(0x00000002 | enable, mipi->linkbase + DTCTR);
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
116
117
118
119
120
121
122
123
  }
  
  static void sh_mipi_shutdown(struct platform_device *pdev)
  {
  	struct sh_mipi *mipi = platform_get_drvdata(pdev);
  
  	sh_mipi_dsi_enable(mipi, false);
  }
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
124
125
126
127
128
  static int __init sh_mipi_setup(struct sh_mipi *mipi,
  				struct sh_mipi_dsi_info *pdata)
  {
  	void __iomem *base = mipi->base;
  	struct sh_mobile_lcdc_chan_cfg *ch = pdata->lcd_chan;
f832906a5   Kuninori Morimoto   fbdev: sh_mipi_ds...
129
  	u32 pctype, datatype, pixfmt, linelength, vmctr2;
a2e629715   Kuninori Morimoto   fbdev: sh_mipi_ds...
130
  	u32 tmp, top, bottom, delay, div;
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
131
  	bool yuv;
08750617b   Kuninori Morimoto   fbdev: sh_mipi_ds...
132
  	int bpp;
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
133

44432407d   Guennadi Liakhovetski   fbdev: sh_mobile_...
134
135
136
137
138
  	/*
  	 * Select data format. MIPI DSI is not hot-pluggable, so, we just use
  	 * the default videomode. If this ever becomes a problem, We'll have to
  	 * move this to mipi_display_on() above and use info->var.xres
  	 */
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
139
140
141
142
143
  	switch (pdata->data_format) {
  	case MIPI_RGB888:
  		pctype = 0;
  		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24;
  		pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
44432407d   Guennadi Liakhovetski   fbdev: sh_mobile_...
144
  		linelength = ch->lcd_cfg[0].xres * 3;
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
145
146
147
148
149
150
  		yuv = false;
  		break;
  	case MIPI_RGB565:
  		pctype = 1;
  		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16;
  		pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
44432407d   Guennadi Liakhovetski   fbdev: sh_mobile_...
151
  		linelength = ch->lcd_cfg[0].xres * 2;
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
152
153
154
155
156
157
  		yuv = false;
  		break;
  	case MIPI_RGB666_LP:
  		pctype = 2;
  		datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
  		pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
44432407d   Guennadi Liakhovetski   fbdev: sh_mobile_...
158
  		linelength = ch->lcd_cfg[0].xres * 3;
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
159
160
161
162
163
164
  		yuv = false;
  		break;
  	case MIPI_RGB666:
  		pctype = 3;
  		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18;
  		pixfmt = MIPI_DCS_PIXEL_FMT_18BIT;
44432407d   Guennadi Liakhovetski   fbdev: sh_mobile_...
165
  		linelength = (ch->lcd_cfg[0].xres * 18 + 7) / 8;
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
166
167
168
169
170
171
  		yuv = false;
  		break;
  	case MIPI_BGR888:
  		pctype = 8;
  		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24;
  		pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
44432407d   Guennadi Liakhovetski   fbdev: sh_mobile_...
172
  		linelength = ch->lcd_cfg[0].xres * 3;
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
173
174
175
176
177
178
  		yuv = false;
  		break;
  	case MIPI_BGR565:
  		pctype = 9;
  		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16;
  		pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
44432407d   Guennadi Liakhovetski   fbdev: sh_mobile_...
179
  		linelength = ch->lcd_cfg[0].xres * 2;
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
180
181
182
183
184
185
  		yuv = false;
  		break;
  	case MIPI_BGR666_LP:
  		pctype = 0xa;
  		datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
  		pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
44432407d   Guennadi Liakhovetski   fbdev: sh_mobile_...
186
  		linelength = ch->lcd_cfg[0].xres * 3;
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
187
188
189
190
191
192
  		yuv = false;
  		break;
  	case MIPI_BGR666:
  		pctype = 0xb;
  		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18;
  		pixfmt = MIPI_DCS_PIXEL_FMT_18BIT;
44432407d   Guennadi Liakhovetski   fbdev: sh_mobile_...
193
  		linelength = (ch->lcd_cfg[0].xres * 18 + 7) / 8;
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
194
195
196
197
198
199
  		yuv = false;
  		break;
  	case MIPI_YUYV:
  		pctype = 4;
  		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16;
  		pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
44432407d   Guennadi Liakhovetski   fbdev: sh_mobile_...
200
  		linelength = ch->lcd_cfg[0].xres * 2;
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
201
202
203
204
205
206
  		yuv = true;
  		break;
  	case MIPI_UYVY:
  		pctype = 5;
  		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16;
  		pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
44432407d   Guennadi Liakhovetski   fbdev: sh_mobile_...
207
  		linelength = ch->lcd_cfg[0].xres * 2;
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
208
209
210
211
212
213
  		yuv = true;
  		break;
  	case MIPI_YUV420_L:
  		pctype = 6;
  		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12;
  		pixfmt = MIPI_DCS_PIXEL_FMT_12BIT;
44432407d   Guennadi Liakhovetski   fbdev: sh_mobile_...
214
  		linelength = (ch->lcd_cfg[0].xres * 12 + 7) / 8;
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
215
216
217
218
219
220
221
  		yuv = true;
  		break;
  	case MIPI_YUV420:
  		pctype = 7;
  		datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12;
  		pixfmt = MIPI_DCS_PIXEL_FMT_12BIT;
  		/* Length of U/V line */
44432407d   Guennadi Liakhovetski   fbdev: sh_mobile_...
222
  		linelength = (ch->lcd_cfg[0].xres + 1) / 2;
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
223
224
225
226
227
228
229
230
231
  		yuv = true;
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	if ((yuv && ch->interface_type != YUV422) ||
  	    (!yuv && ch->interface_type != RGB24))
  		return -EINVAL;
26c3d7ac2   Kuninori Morimoto   fbdev: sh_mipi_ds...
232
233
  	if (!pdata->lane)
  		return -EINVAL;
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
234
  	/* reset DSI link */
71b146c81   Magnus Damm   fbdev: sh_mipi_ds...
235
  	iowrite32(0x00000001, base + SYSCTRL);
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
236
237
  	/* Hold reset for 100 cycles of the slowest of bus, HS byte and LP clock */
  	udelay(50);
71b146c81   Magnus Damm   fbdev: sh_mipi_ds...
238
  	iowrite32(0x00000000, base + SYSCTRL);
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
239
240
241
242
  
  	/* setup DSI link */
  
  	/*
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
243
244
245
246
247
248
  	 * T_wakeup = 0x7000
  	 * T_hs-trail = 3
  	 * T_hs-prepare = 3
  	 * T_clk-trail = 3
  	 * T_clk-prepare = 2
  	 */
71b146c81   Magnus Damm   fbdev: sh_mipi_ds...
249
  	iowrite32(0x70003332, base + TIMSET);
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
250
  	/* no responses requested */
71b146c81   Magnus Damm   fbdev: sh_mipi_ds...
251
  	iowrite32(0x00000000, base + RESREQSET0);
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
252
  	/* request response to packets of type 0x28 */
71b146c81   Magnus Damm   fbdev: sh_mipi_ds...
253
  	iowrite32(0x00000100, base + RESREQSET1);
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
254
  	/* High-speed transmission timeout, default 0xffffffff */
71b146c81   Magnus Damm   fbdev: sh_mipi_ds...
255
  	iowrite32(0x0fffffff, base + HSTTOVSET);
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
256
  	/* LP reception timeout, default 0xffffffff */
71b146c81   Magnus Damm   fbdev: sh_mipi_ds...
257
  	iowrite32(0x0fffffff, base + LPRTOVSET);
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
258
  	/* Turn-around timeout, default 0xffffffff */
71b146c81   Magnus Damm   fbdev: sh_mipi_ds...
259
  	iowrite32(0x0fffffff, base + TATOVSET);
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
260
  	/* Peripheral reset timeout, default 0xffffffff */
71b146c81   Magnus Damm   fbdev: sh_mipi_ds...
261
  	iowrite32(0x0fffffff, base + PRTOVSET);
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
262
263
264
  	/* Interrupts not used, disable all */
  	iowrite32(0, base + DSIINTE);
  	/* DSI-Tx bias on */
71b146c81   Magnus Damm   fbdev: sh_mipi_ds...
265
  	iowrite32(0x00000001, base + PHYCTRL);
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
266
  	udelay(200);
5e47431aa   Kuninori Morimoto   fbdev: sh_mipi_ds...
267
268
  	/* Deassert resets, power on */
  	iowrite32(0x03070001, base + PHYCTRL);
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
269

a2065a368   Kuninori Morimoto   fbdev: sh_mipi_ds...
270
271
272
273
274
275
276
277
278
279
  	/*
  	 * Default = ULPS enable |
  	 *	Contention detection enabled |
  	 *	EoT packet transmission enable |
  	 *	CRC check enable |
  	 *	ECC check enable
  	 */
  	bitmap_fill((unsigned long *)&tmp, pdata->lane);
  	tmp |= 0x00003700;
  	iowrite32(tmp, base + SYSCONF);
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
280
281
282
283
284
285
  	/* setup l-bridge */
  
  	/*
  	 * Enable transmission of all packets,
  	 * transmit LPS after each HS packet completion
  	 */
deaba1901   Magnus Damm   fbdev: sh_mipi_ds...
286
  	iowrite32(0x00000006, mipi->linkbase + DTCTR);
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
287
  	/* VSYNC width = 2 (<< 17) */
14bbb7c61   Guennadi Liakhovetski   fbdev: sh_mipi_ds...
288
289
  	iowrite32((ch->lcd_cfg[0].vsync_len << pdata->vsynw_offset) |
  		  (pdata->clksrc << 16) | (pctype << 12) | datatype,
deaba1901   Magnus Damm   fbdev: sh_mipi_ds...
290
  		  mipi->linkbase + VMCTR1);
14bbb7c61   Guennadi Liakhovetski   fbdev: sh_mipi_ds...
291

9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
292
293
294
295
  	/*
  	 * Non-burst mode with sync pulses: VSE and HSE are output,
  	 * HSA period allowed, no commands in LP
  	 */
f832906a5   Kuninori Morimoto   fbdev: sh_mipi_ds...
296
297
298
299
300
301
302
  	vmctr2 = 0;
  	if (pdata->flags & SH_MIPI_DSI_VSEE)
  		vmctr2 |= 1 << 23;
  	if (pdata->flags & SH_MIPI_DSI_HSEE)
  		vmctr2 |= 1 << 22;
  	if (pdata->flags & SH_MIPI_DSI_HSAE)
  		vmctr2 |= 1 << 21;
d07a9d2a5   Kuninori Morimoto   fbdev: sh_mipi_ds...
303
304
  	if (pdata->flags & SH_MIPI_DSI_BL2E)
  		vmctr2 |= 1 << 17;
14bbb7c61   Guennadi Liakhovetski   fbdev: sh_mipi_ds...
305
  	if (pdata->flags & SH_MIPI_DSI_HSABM)
3c2a65993   Kuninori Morimoto   fbdev: sh_mipi_ds...
306
  		vmctr2 |= 1 << 5;
32ba95c69   Kuninori Morimoto   fbdev: sh_mipi_ds...
307
  	if (pdata->flags & SH_MIPI_DSI_HBPBM)
3c2a65993   Kuninori Morimoto   fbdev: sh_mipi_ds...
308
  		vmctr2 |= 1 << 4;
f7b0af68b   Kuninori Morimoto   fbdev: sh_mipi_ds...
309
310
  	if (pdata->flags & SH_MIPI_DSI_HFPBM)
  		vmctr2 |= 1 << 3;
14bbb7c61   Guennadi Liakhovetski   fbdev: sh_mipi_ds...
311
  	iowrite32(vmctr2, mipi->linkbase + VMCTR2);
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
312
  	/*
08750617b   Kuninori Morimoto   fbdev: sh_mipi_ds...
313
314
315
316
  	 * VMLEN1 = RGBLEN | HSALEN
  	 *
  	 * see
  	 *  Video mode - Blanking Packet setting
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
317
  	 */
08750617b   Kuninori Morimoto   fbdev: sh_mipi_ds...
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
  	top = linelength << 16; /* RGBLEN */
  	bottom = 0x00000001;
  	if (pdata->flags & SH_MIPI_DSI_HSABM) /* HSALEN */
  		bottom = (pdata->lane * ch->lcd_cfg[0].hsync_len) - 10;
  	iowrite32(top | bottom , mipi->linkbase + VMLEN1);
  
  	/*
  	 * VMLEN2 = HBPLEN | HFPLEN
  	 *
  	 * see
  	 *  Video mode - Blanking Packet setting
  	 */
  	top	= 0x00010000;
  	bottom	= 0x00000001;
  	delay	= 0;
a2e629715   Kuninori Morimoto   fbdev: sh_mipi_ds...
333
334
335
336
337
  	div = 1;	/* HSbyteCLK is calculation base
  			 * HS4divCLK = HSbyteCLK/2
  			 * HS6divCLK is not supported for now */
  	if (pdata->flags & SH_MIPI_DSI_HS4divCLK)
  		div = 2;
08750617b   Kuninori Morimoto   fbdev: sh_mipi_ds...
338
339
  	if (pdata->flags & SH_MIPI_DSI_HFPBM) {	/* HBPLEN */
  		top = ch->lcd_cfg[0].hsync_len + ch->lcd_cfg[0].left_margin;
a2e629715   Kuninori Morimoto   fbdev: sh_mipi_ds...
340
  		top = ((pdata->lane * top / div) - 10) << 16;
08750617b   Kuninori Morimoto   fbdev: sh_mipi_ds...
341
342
343
  	}
  	if (pdata->flags & SH_MIPI_DSI_HBPBM) { /* HFPLEN */
  		bottom = ch->lcd_cfg[0].right_margin;
a2e629715   Kuninori Morimoto   fbdev: sh_mipi_ds...
344
  		bottom = (pdata->lane * bottom / div) - 12;
08750617b   Kuninori Morimoto   fbdev: sh_mipi_ds...
345
346
347
  	}
  
  	bpp = linelength / ch->lcd_cfg[0].xres; /* byte / pixel */
a2e629715   Kuninori Morimoto   fbdev: sh_mipi_ds...
348
  	if ((pdata->lane / div) > bpp) {
08750617b   Kuninori Morimoto   fbdev: sh_mipi_ds...
349
350
351
352
353
354
  		tmp = ch->lcd_cfg[0].xres / bpp; /* output cycle */
  		tmp = ch->lcd_cfg[0].xres - tmp; /* (input - output) cycle */
  		delay = (pdata->lane * tmp);
  	}
  
  	iowrite32(top | (bottom + delay) , mipi->linkbase + VMLEN2);
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
  
  	msleep(5);
  
  	/* setup LCD panel */
  
  	/* cf. drivers/video/omap/lcd_mipid.c */
  	sh_mipi_dcs(ch->chan, MIPI_DCS_EXIT_SLEEP_MODE);
  	msleep(120);
  	/*
  	 * [7] - Page Address Mode
  	 * [6] - Column Address Mode
  	 * [5] - Page / Column Address Mode
  	 * [4] - Display Device Line Refresh Order
  	 * [3] - RGB/BGR Order
  	 * [2] - Display Data Latch Data Order
  	 * [1] - Flip Horizontal
  	 * [0] - Flip Vertical
  	 */
  	sh_mipi_dcs_param(ch->chan, MIPI_DCS_SET_ADDRESS_MODE, 0x00);
  	/* cf. set_data_lines() */
  	sh_mipi_dcs_param(ch->chan, MIPI_DCS_SET_PIXEL_FORMAT,
  			  pixfmt << 4);
  	sh_mipi_dcs(ch->chan, MIPI_DCS_SET_DISPLAY_ON);
97cab4558   Kuninori Morimoto   fbdev: sh_mipi_ds...
378
379
  	/* Enable timeout counters */
  	iowrite32(0x00000f00, base + DSICTRL);
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
380
381
  	return 0;
  }
c2658b70f   Kuninori Morimoto   fbdev: sh_mipi_ds...
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
  static void mipi_display_on(void *arg, struct fb_info *info)
  {
  	struct sh_mipi *mipi = arg;
  	struct sh_mipi_dsi_info *pdata = mipi->pdev->dev.platform_data;
  	int ret;
  
  	pm_runtime_get_sync(&mipi->pdev->dev);
  
  	ret = pdata->set_dot_clock(mipi->pdev, mipi->base, 1);
  	if (ret < 0)
  		goto mipi_display_on_fail1;
  
  	ret = sh_mipi_setup(mipi, pdata);
  	if (ret < 0)
  		goto mipi_display_on_fail2;
  
  	sh_mipi_dsi_enable(mipi, true);
  
  	if (mipi->next_display_on)
  		mipi->next_display_on(mipi->next_board_data, info);
  
  	return;
  
  mipi_display_on_fail1:
  	pm_runtime_put_sync(&mipi->pdev->dev);
  mipi_display_on_fail2:
  	pdata->set_dot_clock(mipi->pdev, mipi->base, 0);
  }
  
  static void mipi_display_off(void *arg)
  {
  	struct sh_mipi *mipi = arg;
  	struct sh_mipi_dsi_info *pdata = mipi->pdev->dev.platform_data;
  
  	if (mipi->next_display_off)
  		mipi->next_display_off(mipi->next_board_data);
  
  	sh_mipi_dsi_enable(mipi, false);
  
  	pdata->set_dot_clock(mipi->pdev, mipi->base, 0);
  
  	pm_runtime_put_sync(&mipi->pdev->dev);
  }
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
425
426
427
428
429
  static int __init sh_mipi_probe(struct platform_device *pdev)
  {
  	struct sh_mipi *mipi;
  	struct sh_mipi_dsi_info *pdata = pdev->dev.platform_data;
  	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
deaba1901   Magnus Damm   fbdev: sh_mipi_ds...
430
  	struct resource *res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
431
432
  	unsigned long rate, f_current;
  	int idx = pdev->id, ret;
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
433

deaba1901   Magnus Damm   fbdev: sh_mipi_ds...
434
  	if (!res || !res2 || idx >= ARRAY_SIZE(mipi_dsi) || !pdata)
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
435
  		return -ENODEV;
5e47431aa   Kuninori Morimoto   fbdev: sh_mipi_ds...
436
437
  	if (!pdata->set_dot_clock)
  		return -EINVAL;
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
  	mutex_lock(&array_lock);
  	if (idx < 0)
  		for (idx = 0; idx < ARRAY_SIZE(mipi_dsi) && mipi_dsi[idx]; idx++)
  			;
  
  	if (idx == ARRAY_SIZE(mipi_dsi)) {
  		ret = -EBUSY;
  		goto efindslot;
  	}
  
  	mipi = kzalloc(sizeof(*mipi), GFP_KERNEL);
  	if (!mipi) {
  		ret = -ENOMEM;
  		goto ealloc;
  	}
  
  	if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
  		dev_err(&pdev->dev, "MIPI register region already claimed
  ");
  		ret = -EBUSY;
  		goto ereqreg;
  	}
  
  	mipi->base = ioremap(res->start, resource_size(res));
  	if (!mipi->base) {
  		ret = -ENOMEM;
  		goto emap;
  	}
deaba1901   Magnus Damm   fbdev: sh_mipi_ds...
466
467
468
469
470
471
472
473
474
475
476
477
  	if (!request_mem_region(res2->start, resource_size(res2), pdev->name)) {
  		dev_err(&pdev->dev, "MIPI register region 2 already claimed
  ");
  		ret = -EBUSY;
  		goto ereqreg2;
  	}
  
  	mipi->linkbase = ioremap(res2->start, resource_size(res2));
  	if (!mipi->linkbase) {
  		ret = -ENOMEM;
  		goto emap2;
  	}
7d9f88b4f   Kuninori Morimoto   fbdev: sh_mipi_ds...
478
  	mipi->pdev = pdev;
236782a5f   Guennadi Liakhovetski   fbdev: sh-mobile:...
479

9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
  	mipi->dsit_clk = clk_get(&pdev->dev, "dsit_clk");
  	if (IS_ERR(mipi->dsit_clk)) {
  		ret = PTR_ERR(mipi->dsit_clk);
  		goto eclktget;
  	}
  
  	f_current = clk_get_rate(mipi->dsit_clk);
  	/* 80MHz required by the datasheet */
  	rate = clk_round_rate(mipi->dsit_clk, 80000000);
  	if (rate > 0 && rate != f_current)
  		ret = clk_set_rate(mipi->dsit_clk, rate);
  	else
  		ret = rate;
  	if (ret < 0)
  		goto esettrate;
  
  	dev_dbg(&pdev->dev, "DSI-T clk %lu -> %lu
  ", f_current, rate);
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
498
499
500
  	ret = clk_enable(mipi->dsit_clk);
  	if (ret < 0)
  		goto eclkton;
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
501
  	mipi_dsi[idx] = mipi;
236782a5f   Guennadi Liakhovetski   fbdev: sh-mobile:...
502
503
  	pm_runtime_enable(&pdev->dev);
  	pm_runtime_resume(&pdev->dev);
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
504
505
  	mutex_unlock(&array_lock);
  	platform_set_drvdata(pdev, mipi);
6722a4016   Magnus Damm   fbdev: sh_mipi_ds...
506
507
508
509
  	/* Save original LCDC callbacks */
  	mipi->next_board_data = pdata->lcd_chan->board_cfg.board_data;
  	mipi->next_display_on = pdata->lcd_chan->board_cfg.display_on;
  	mipi->next_display_off = pdata->lcd_chan->board_cfg.display_off;
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
510
511
512
513
  	/* Set up LCDC callbacks */
  	pdata->lcd_chan->board_cfg.board_data = mipi;
  	pdata->lcd_chan->board_cfg.display_on = mipi_display_on;
  	pdata->lcd_chan->board_cfg.display_off = mipi_display_off;
236782a5f   Guennadi Liakhovetski   fbdev: sh-mobile:...
514
  	pdata->lcd_chan->board_cfg.owner = THIS_MODULE;
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
515
516
  
  	return 0;
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
517
  eclkton:
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
518
519
520
  esettrate:
  	clk_put(mipi->dsit_clk);
  eclktget:
deaba1901   Magnus Damm   fbdev: sh_mipi_ds...
521
522
523
524
  	iounmap(mipi->linkbase);
  emap2:
  	release_mem_region(res2->start, resource_size(res2));
  ereqreg2:
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
  	iounmap(mipi->base);
  emap:
  	release_mem_region(res->start, resource_size(res));
  ereqreg:
  	kfree(mipi);
  ealloc:
  efindslot:
  	mutex_unlock(&array_lock);
  
  	return ret;
  }
  
  static int __exit sh_mipi_remove(struct platform_device *pdev)
  {
  	struct sh_mipi_dsi_info *pdata = pdev->dev.platform_data;
  	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
deaba1901   Magnus Damm   fbdev: sh_mipi_ds...
541
  	struct resource *res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
  	struct sh_mipi *mipi = platform_get_drvdata(pdev);
  	int i, ret;
  
  	mutex_lock(&array_lock);
  
  	for (i = 0; i < ARRAY_SIZE(mipi_dsi) && mipi_dsi[i] != mipi; i++)
  		;
  
  	if (i == ARRAY_SIZE(mipi_dsi)) {
  		ret = -EINVAL;
  	} else {
  		ret = 0;
  		mipi_dsi[i] = NULL;
  	}
  
  	mutex_unlock(&array_lock);
  
  	if (ret < 0)
  		return ret;
236782a5f   Guennadi Liakhovetski   fbdev: sh-mobile:...
561
  	pdata->lcd_chan->board_cfg.owner = NULL;
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
562
563
564
  	pdata->lcd_chan->board_cfg.display_on = NULL;
  	pdata->lcd_chan->board_cfg.display_off = NULL;
  	pdata->lcd_chan->board_cfg.board_data = NULL;
236782a5f   Guennadi Liakhovetski   fbdev: sh-mobile:...
565
  	pm_runtime_disable(&pdev->dev);
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
566
567
  	clk_disable(mipi->dsit_clk);
  	clk_put(mipi->dsit_clk);
5e47431aa   Kuninori Morimoto   fbdev: sh_mipi_ds...
568

deaba1901   Magnus Damm   fbdev: sh_mipi_ds...
569
570
571
  	iounmap(mipi->linkbase);
  	if (res2)
  		release_mem_region(res2->start, resource_size(res2));
9fd04fe34   Guennadi Liakhovetski   sh-mobile: add su...
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
  	iounmap(mipi->base);
  	if (res)
  		release_mem_region(res->start, resource_size(res));
  	platform_set_drvdata(pdev, NULL);
  	kfree(mipi);
  
  	return 0;
  }
  
  static struct platform_driver sh_mipi_driver = {
  	.remove		= __exit_p(sh_mipi_remove),
  	.shutdown	= sh_mipi_shutdown,
  	.driver = {
  		.name	= "sh-mipi-dsi",
  	},
  };
  
  static int __init sh_mipi_init(void)
  {
  	return platform_driver_probe(&sh_mipi_driver, sh_mipi_probe);
  }
  module_init(sh_mipi_init);
  
  static void __exit sh_mipi_exit(void)
  {
  	platform_driver_unregister(&sh_mipi_driver);
  }
  module_exit(sh_mipi_exit);
  
  MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
  MODULE_DESCRIPTION("SuperH / ARM-shmobile MIPI DSI driver");
  MODULE_LICENSE("GPL v2");