1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
4  */
5 
6 #include "mdp5_kms.h"
7 #include "mdp5_cfg.h"
8 
9 struct mdp5_cfg_handler {
10 	int revision;
11 	struct mdp5_cfg config;
12 };
13 
14 /* mdp5_cfg must be exposed (used in mdp5.xml.h) */
15 const struct mdp5_cfg_hw *mdp5_cfg = NULL;
16 
17 static const struct mdp5_cfg_hw msm8x74v1_config = {
18 	.name = "msm8x74v1",
19 	.mdp = {
20 		.count = 1,
21 		.caps = MDP_CAP_SMP |
22 			0,
23 	},
24 	.smp = {
25 		.mmb_count = 22,
26 		.mmb_size = 4096,
27 		.clients = {
28 			[SSPP_VIG0] =  1, [SSPP_VIG1] =  4, [SSPP_VIG2] =  7,
29 			[SSPP_DMA0] = 10, [SSPP_DMA1] = 13,
30 			[SSPP_RGB0] = 16, [SSPP_RGB1] = 17, [SSPP_RGB2] = 18,
31 		},
32 	},
33 	.ctl = {
34 		.count = 5,
35 		.base = { 0x00500, 0x00600, 0x00700, 0x00800, 0x00900 },
36 		.flush_hw_mask = 0x0003ffff,
37 	},
38 	.pipe_vig = {
39 		.count = 3,
40 		.base = { 0x01100, 0x01500, 0x01900 },
41 		.caps = MDP_PIPE_CAP_HFLIP |
42 			MDP_PIPE_CAP_VFLIP |
43 			MDP_PIPE_CAP_SCALE |
44 			MDP_PIPE_CAP_CSC   |
45 			0,
46 	},
47 	.pipe_rgb = {
48 		.count = 3,
49 		.base = { 0x01d00, 0x02100, 0x02500 },
50 		.caps = MDP_PIPE_CAP_HFLIP |
51 			MDP_PIPE_CAP_VFLIP |
52 			MDP_PIPE_CAP_SCALE |
53 			0,
54 	},
55 	.pipe_dma = {
56 		.count = 2,
57 		.base = { 0x02900, 0x02d00 },
58 		.caps = MDP_PIPE_CAP_HFLIP |
59 			MDP_PIPE_CAP_VFLIP |
60 			0,
61 	},
62 	.lm = {
63 		.count = 5,
64 		.base = { 0x03100, 0x03500, 0x03900, 0x03d00, 0x04100 },
65 		.instances = {
66 				{ .id = 0, .pp = 0, .dspp = 0,
67 				  .caps = MDP_LM_CAP_DISPLAY, },
68 				{ .id = 1, .pp = 1, .dspp = 1,
69 				  .caps = MDP_LM_CAP_DISPLAY, },
70 				{ .id = 2, .pp = 2, .dspp = 2,
71 				  .caps = MDP_LM_CAP_DISPLAY, },
72 				{ .id = 3, .pp = -1, .dspp = -1,
73 				  .caps = MDP_LM_CAP_WB },
74 				{ .id = 4, .pp = -1, .dspp = -1,
75 				  .caps = MDP_LM_CAP_WB },
76 			     },
77 		.nb_stages = 5,
78 		.max_width = 2048,
79 		.max_height = 0xFFFF,
80 	},
81 	.dspp = {
82 		.count = 3,
83 		.base = { 0x04500, 0x04900, 0x04d00 },
84 	},
85 	.pp = {
86 		.count = 3,
87 		.base = { 0x21a00, 0x21b00, 0x21c00 },
88 	},
89 	.intf = {
90 		.base = { 0x21000, 0x21200, 0x21400, 0x21600 },
91 		.connect = {
92 			[0] = INTF_eDP,
93 			[1] = INTF_DSI,
94 			[2] = INTF_DSI,
95 			[3] = INTF_HDMI,
96 		},
97 	},
98 	.max_clk = 200000000,
99 };
100 
101 static const struct mdp5_cfg_hw msm8x74v2_config = {
102 	.name = "msm8x74",
103 	.mdp = {
104 		.count = 1,
105 		.caps = MDP_CAP_SMP |
106 			0,
107 	},
108 	.smp = {
109 		.mmb_count = 22,
110 		.mmb_size = 4096,
111 		.clients = {
112 			[SSPP_VIG0] =  1, [SSPP_VIG1] =  4, [SSPP_VIG2] =  7,
113 			[SSPP_DMA0] = 10, [SSPP_DMA1] = 13,
114 			[SSPP_RGB0] = 16, [SSPP_RGB1] = 17, [SSPP_RGB2] = 18,
115 		},
116 	},
117 	.ctl = {
118 		.count = 5,
119 		.base = { 0x00500, 0x00600, 0x00700, 0x00800, 0x00900 },
120 		.flush_hw_mask = 0x0003ffff,
121 	},
122 	.pipe_vig = {
123 		.count = 3,
124 		.base = { 0x01100, 0x01500, 0x01900 },
125 		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
126 				MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC |
127 				MDP_PIPE_CAP_DECIMATION,
128 	},
129 	.pipe_rgb = {
130 		.count = 3,
131 		.base = { 0x01d00, 0x02100, 0x02500 },
132 		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
133 				MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION,
134 	},
135 	.pipe_dma = {
136 		.count = 2,
137 		.base = { 0x02900, 0x02d00 },
138 		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP,
139 	},
140 	.lm = {
141 		.count = 5,
142 		.base = { 0x03100, 0x03500, 0x03900, 0x03d00, 0x04100 },
143 		.instances = {
144 				{ .id = 0, .pp = 0, .dspp = 0,
145 				  .caps = MDP_LM_CAP_DISPLAY, },
146 				{ .id = 1, .pp = 1, .dspp = 1,
147 				  .caps = MDP_LM_CAP_DISPLAY, },
148 				{ .id = 2, .pp = 2, .dspp = 2,
149 				  .caps = MDP_LM_CAP_DISPLAY, },
150 				{ .id = 3, .pp = -1, .dspp = -1,
151 				  .caps = MDP_LM_CAP_WB, },
152 				{ .id = 4, .pp = -1, .dspp = -1,
153 				  .caps = MDP_LM_CAP_WB, },
154 			     },
155 		.nb_stages = 5,
156 		.max_width = 2048,
157 		.max_height = 0xFFFF,
158 	},
159 	.dspp = {
160 		.count = 3,
161 		.base = { 0x04500, 0x04900, 0x04d00 },
162 	},
163 	.ad = {
164 		.count = 2,
165 		.base = { 0x13000, 0x13200 },
166 	},
167 	.pp = {
168 		.count = 3,
169 		.base = { 0x12c00, 0x12d00, 0x12e00 },
170 	},
171 	.intf = {
172 		.base = { 0x12400, 0x12600, 0x12800, 0x12a00 },
173 		.connect = {
174 			[0] = INTF_eDP,
175 			[1] = INTF_DSI,
176 			[2] = INTF_DSI,
177 			[3] = INTF_HDMI,
178 		},
179 	},
180 	.max_clk = 320000000,
181 };
182 
183 static const struct mdp5_cfg_hw apq8084_config = {
184 	.name = "apq8084",
185 	.mdp = {
186 		.count = 1,
187 		.caps = MDP_CAP_SMP |
188 			MDP_CAP_SRC_SPLIT |
189 			0,
190 	},
191 	.smp = {
192 		.mmb_count = 44,
193 		.mmb_size = 8192,
194 		.clients = {
195 			[SSPP_VIG0] =  1, [SSPP_VIG1] =  4,
196 			[SSPP_VIG2] =  7, [SSPP_VIG3] = 19,
197 			[SSPP_DMA0] = 10, [SSPP_DMA1] = 13,
198 			[SSPP_RGB0] = 16, [SSPP_RGB1] = 17,
199 			[SSPP_RGB2] = 18, [SSPP_RGB3] = 22,
200 		},
201 		.reserved_state[0] = GENMASK(7, 0),	/* first 8 MMBs */
202 		.reserved = {
203 			/* Two SMP blocks are statically tied to RGB pipes: */
204 			[16] = 2, [17] = 2, [18] = 2, [22] = 2,
205 		},
206 	},
207 	.ctl = {
208 		.count = 5,
209 		.base = { 0x00500, 0x00600, 0x00700, 0x00800, 0x00900 },
210 		.flush_hw_mask = 0x003fffff,
211 	},
212 	.pipe_vig = {
213 		.count = 4,
214 		.base = { 0x01100, 0x01500, 0x01900, 0x01d00 },
215 		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
216 				MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC |
217 				MDP_PIPE_CAP_DECIMATION,
218 	},
219 	.pipe_rgb = {
220 		.count = 4,
221 		.base = { 0x02100, 0x02500, 0x02900, 0x02d00 },
222 		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
223 				MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION,
224 	},
225 	.pipe_dma = {
226 		.count = 2,
227 		.base = { 0x03100, 0x03500 },
228 		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP,
229 	},
230 	.lm = {
231 		.count = 6,
232 		.base = { 0x03900, 0x03d00, 0x04100, 0x04500, 0x04900, 0x04d00 },
233 		.instances = {
234 				{ .id = 0, .pp = 0, .dspp = 0,
235 				  .caps = MDP_LM_CAP_DISPLAY |
236 					  MDP_LM_CAP_PAIR, },
237 				{ .id = 1, .pp = 1, .dspp = 1,
238 				  .caps = MDP_LM_CAP_DISPLAY, },
239 				{ .id = 2, .pp = 2, .dspp = 2,
240 				  .caps = MDP_LM_CAP_DISPLAY |
241 					  MDP_LM_CAP_PAIR, },
242 				{ .id = 3, .pp = -1, .dspp = -1,
243 				  .caps = MDP_LM_CAP_WB, },
244 				{ .id = 4, .pp = -1, .dspp = -1,
245 				  .caps = MDP_LM_CAP_WB, },
246 				{ .id = 5, .pp = 3, .dspp = 3,
247 				  .caps = MDP_LM_CAP_DISPLAY, },
248 			     },
249 		.nb_stages = 5,
250 		.max_width = 2048,
251 		.max_height = 0xFFFF,
252 	},
253 	.dspp = {
254 		.count = 4,
255 		.base = { 0x05100, 0x05500, 0x05900, 0x05d00 },
256 
257 	},
258 	.ad = {
259 		.count = 3,
260 		.base = { 0x13400, 0x13600, 0x13800 },
261 	},
262 	.pp = {
263 		.count = 4,
264 		.base = { 0x12e00, 0x12f00, 0x13000, 0x13100 },
265 	},
266 	.intf = {
267 		.base = { 0x12400, 0x12600, 0x12800, 0x12a00, 0x12c00 },
268 		.connect = {
269 			[0] = INTF_eDP,
270 			[1] = INTF_DSI,
271 			[2] = INTF_DSI,
272 			[3] = INTF_HDMI,
273 		},
274 	},
275 	.max_clk = 320000000,
276 };
277 
278 static const struct mdp5_cfg_hw msm8x16_config = {
279 	.name = "msm8x16",
280 	.mdp = {
281 		.count = 1,
282 		.base = { 0x0 },
283 		.caps = MDP_CAP_SMP |
284 			0,
285 	},
286 	.smp = {
287 		.mmb_count = 8,
288 		.mmb_size = 8192,
289 		.clients = {
290 			[SSPP_VIG0] = 1, [SSPP_DMA0] = 4,
291 			[SSPP_RGB0] = 7, [SSPP_RGB1] = 8,
292 		},
293 	},
294 	.ctl = {
295 		.count = 5,
296 		.base = { 0x01000, 0x01200, 0x01400, 0x01600, 0x01800 },
297 		.flush_hw_mask = 0x4003ffff,
298 	},
299 	.pipe_vig = {
300 		.count = 1,
301 		.base = { 0x04000 },
302 		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
303 				MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC |
304 				MDP_PIPE_CAP_DECIMATION,
305 	},
306 	.pipe_rgb = {
307 		.count = 2,
308 		.base = { 0x14000, 0x16000 },
309 		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
310 				MDP_PIPE_CAP_DECIMATION,
311 	},
312 	.pipe_dma = {
313 		.count = 1,
314 		.base = { 0x24000 },
315 		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP,
316 	},
317 	.lm = {
318 		.count = 2, /* LM0 and LM3 */
319 		.base = { 0x44000, 0x47000 },
320 		.instances = {
321 				{ .id = 0, .pp = 0, .dspp = 0,
322 				  .caps = MDP_LM_CAP_DISPLAY, },
323 				{ .id = 3, .pp = -1, .dspp = -1,
324 				  .caps = MDP_LM_CAP_WB },
325 			     },
326 		.nb_stages = 8,
327 		.max_width = 2048,
328 		.max_height = 0xFFFF,
329 	},
330 	.dspp = {
331 		.count = 1,
332 		.base = { 0x54000 },
333 
334 	},
335 	.intf = {
336 		.base = { 0x00000, 0x6a800 },
337 		.connect = {
338 			[0] = INTF_DISABLED,
339 			[1] = INTF_DSI,
340 		},
341 	},
342 	.max_clk = 320000000,
343 };
344 
345 static const struct mdp5_cfg_hw msm8x36_config = {
346 	.name = "msm8x36",
347 	.mdp = {
348 		.count = 1,
349 		.base = { 0x0 },
350 		.caps = MDP_CAP_SMP |
351 			0,
352 	},
353 	.smp = {
354 		.mmb_count = 8,
355 		.mmb_size = 10240,
356 		.clients = {
357 			[SSPP_VIG0] = 1, [SSPP_DMA0] = 4,
358 			[SSPP_RGB0] = 7, [SSPP_RGB1] = 8,
359 		},
360 	},
361 	.ctl = {
362 		.count = 3,
363 		.base = { 0x01000, 0x01200, 0x01400 },
364 		.flush_hw_mask = 0x4003ffff,
365 	},
366 	.pipe_vig = {
367 		.count = 1,
368 		.base = { 0x04000 },
369 		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
370 				MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC |
371 				MDP_PIPE_CAP_DECIMATION,
372 	},
373 	.pipe_rgb = {
374 		.count = 2,
375 		.base = { 0x14000, 0x16000 },
376 		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
377 				MDP_PIPE_CAP_DECIMATION,
378 	},
379 	.pipe_dma = {
380 		.count = 1,
381 		.base = { 0x24000 },
382 		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP,
383 	},
384 	.lm = {
385 		.count = 2,
386 		.base = { 0x44000, 0x47000 },
387 		.instances = {
388 				{ .id = 0, .pp = 0, .dspp = 0,
389 				  .caps = MDP_LM_CAP_DISPLAY, },
390 				{ .id = 1, .pp = -1, .dspp = -1,
391 				  .caps = MDP_LM_CAP_WB, },
392 				},
393 		.nb_stages = 8,
394 		.max_width = 2560,
395 		.max_height = 0xFFFF,
396 	},
397 	.pp = {
398 		.count = 1,
399 		.base = { 0x70000 },
400 	},
401 	.ad = {
402 		.count = 1,
403 		.base = { 0x78000 },
404 	},
405 	.dspp = {
406 		.count = 1,
407 		.base = { 0x54000 },
408 	},
409 	.intf = {
410 		.base = { 0x00000, 0x6a800, 0x6b000 },
411 		.connect = {
412 			[0] = INTF_DISABLED,
413 			[1] = INTF_DSI,
414 			[2] = INTF_DSI,
415 		},
416 	},
417 	.max_clk = 366670000,
418 };
419 
420 static const struct mdp5_cfg_hw msm8x94_config = {
421 	.name = "msm8x94",
422 	.mdp = {
423 		.count = 1,
424 		.caps = MDP_CAP_SMP |
425 			MDP_CAP_SRC_SPLIT |
426 			0,
427 	},
428 	.smp = {
429 		.mmb_count = 44,
430 		.mmb_size = 8192,
431 		.clients = {
432 			[SSPP_VIG0] =  1, [SSPP_VIG1] =  4,
433 			[SSPP_VIG2] =  7, [SSPP_VIG3] = 19,
434 			[SSPP_DMA0] = 10, [SSPP_DMA1] = 13,
435 			[SSPP_RGB0] = 16, [SSPP_RGB1] = 17,
436 			[SSPP_RGB2] = 18, [SSPP_RGB3] = 22,
437 		},
438 		.reserved_state[0] = GENMASK(23, 0),	/* first 24 MMBs */
439 		.reserved = {
440 			 [1] = 1,  [4] = 1,  [7] = 1, [19] = 1,
441 			[16] = 5, [17] = 5, [18] = 5, [22] = 5,
442 		},
443 	},
444 	.ctl = {
445 		.count = 5,
446 		.base = { 0x01000, 0x01200, 0x01400, 0x01600, 0x01800 },
447 		.flush_hw_mask = 0xf0ffffff,
448 	},
449 	.pipe_vig = {
450 		.count = 4,
451 		.base = { 0x04000, 0x06000, 0x08000, 0x0a000 },
452 		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
453 				MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC |
454 				MDP_PIPE_CAP_DECIMATION,
455 	},
456 	.pipe_rgb = {
457 		.count = 4,
458 		.base = { 0x14000, 0x16000, 0x18000, 0x1a000 },
459 		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP |
460 				MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_DECIMATION,
461 	},
462 	.pipe_dma = {
463 		.count = 2,
464 		.base = { 0x24000, 0x26000 },
465 		.caps = MDP_PIPE_CAP_HFLIP | MDP_PIPE_CAP_VFLIP,
466 	},
467 	.lm = {
468 		.count = 6,
469 		.base = { 0x44000, 0x45000, 0x46000, 0x47000, 0x48000, 0x49000 },
470 		.instances = {
471 				{ .id = 0, .pp = 0, .dspp = 0,
472 				  .caps = MDP_LM_CAP_DISPLAY |
473 					  MDP_LM_CAP_PAIR, },
474 				{ .id = 1, .pp = 1, .dspp = 1,
475 				  .caps = MDP_LM_CAP_DISPLAY, },
476 				{ .id = 2, .pp = 2, .dspp = 2,
477 				  .caps = MDP_LM_CAP_DISPLAY |
478 					  MDP_LM_CAP_PAIR, },
479 				{ .id = 3, .pp = -1, .dspp = -1,
480 				  .caps = MDP_LM_CAP_WB, },
481 				{ .id = 4, .pp = -1, .dspp = -1,
482 				  .caps = MDP_LM_CAP_WB, },
483 				{ .id = 5, .pp = 3, .dspp = 3,
484 				  .caps = MDP_LM_CAP_DISPLAY, },
485 			     },
486 		.nb_stages = 8,
487 		.max_width = 2048,
488 		.max_height = 0xFFFF,
489 	},
490 	.dspp = {
491 		.count = 4,
492 		.base = { 0x54000, 0x56000, 0x58000, 0x5a000 },
493 
494 	},
495 	.ad = {
496 		.count = 3,
497 		.base = { 0x78000, 0x78800, 0x79000 },
498 	},
499 	.pp = {
500 		.count = 4,
501 		.base = { 0x70000, 0x70800, 0x71000, 0x71800 },
502 	},
503 	.intf = {
504 		.base = { 0x6a000, 0x6a800, 0x6b000, 0x6b800, 0x6c000 },
505 		.connect = {
506 			[0] = INTF_DISABLED,
507 			[1] = INTF_DSI,
508 			[2] = INTF_DSI,
509 			[3] = INTF_HDMI,
510 		},
511 	},
512 	.max_clk = 400000000,
513 };
514 
515 static const struct mdp5_cfg_hw msm8x96_config = {
516 	.name = "msm8x96",
517 	.mdp = {
518 		.count = 1,
519 		.caps = MDP_CAP_DSC |
520 			MDP_CAP_CDM |
521 			MDP_CAP_SRC_SPLIT |
522 			0,
523 	},
524 	.ctl = {
525 		.count = 5,
526 		.base = { 0x01000, 0x01200, 0x01400, 0x01600, 0x01800 },
527 		.flush_hw_mask = 0xf4ffffff,
528 	},
529 	.pipe_vig = {
530 		.count = 4,
531 		.base = { 0x04000, 0x06000, 0x08000, 0x0a000 },
532 		.caps = MDP_PIPE_CAP_HFLIP	|
533 			MDP_PIPE_CAP_VFLIP	|
534 			MDP_PIPE_CAP_SCALE	|
535 			MDP_PIPE_CAP_CSC	|
536 			MDP_PIPE_CAP_DECIMATION	|
537 			MDP_PIPE_CAP_SW_PIX_EXT	|
538 			0,
539 	},
540 	.pipe_rgb = {
541 		.count = 4,
542 		.base = { 0x14000, 0x16000, 0x18000, 0x1a000 },
543 		.caps = MDP_PIPE_CAP_HFLIP	|
544 			MDP_PIPE_CAP_VFLIP	|
545 			MDP_PIPE_CAP_SCALE	|
546 			MDP_PIPE_CAP_DECIMATION	|
547 			MDP_PIPE_CAP_SW_PIX_EXT	|
548 			0,
549 	},
550 	.pipe_dma = {
551 		.count = 2,
552 		.base = { 0x24000, 0x26000 },
553 		.caps = MDP_PIPE_CAP_HFLIP	|
554 			MDP_PIPE_CAP_VFLIP	|
555 			MDP_PIPE_CAP_SW_PIX_EXT	|
556 			0,
557 	},
558 	.pipe_cursor = {
559 		.count = 2,
560 		.base = { 0x34000, 0x36000 },
561 		.caps = MDP_PIPE_CAP_HFLIP	|
562 			MDP_PIPE_CAP_VFLIP	|
563 			MDP_PIPE_CAP_SW_PIX_EXT	|
564 			MDP_PIPE_CAP_CURSOR	|
565 			0,
566 	},
567 
568 	.lm = {
569 		.count = 6,
570 		.base = { 0x44000, 0x45000, 0x46000, 0x47000, 0x48000, 0x49000 },
571 		.instances = {
572 				{ .id = 0, .pp = 0, .dspp = 0,
573 				  .caps = MDP_LM_CAP_DISPLAY |
574 					  MDP_LM_CAP_PAIR, },
575 				{ .id = 1, .pp = 1, .dspp = 1,
576 				  .caps = MDP_LM_CAP_DISPLAY, },
577 				{ .id = 2, .pp = 2, .dspp = -1,
578 				  .caps = MDP_LM_CAP_DISPLAY |
579 					  MDP_LM_CAP_PAIR, },
580 				{ .id = 3, .pp = -1, .dspp = -1,
581 				  .caps = MDP_LM_CAP_WB, },
582 				{ .id = 4, .pp = -1, .dspp = -1,
583 				  .caps = MDP_LM_CAP_WB, },
584 				{ .id = 5, .pp = 3, .dspp = -1,
585 				  .caps = MDP_LM_CAP_DISPLAY, },
586 			     },
587 		.nb_stages = 8,
588 		.max_width = 2560,
589 		.max_height = 0xFFFF,
590 	},
591 	.dspp = {
592 		.count = 2,
593 		.base = { 0x54000, 0x56000 },
594 	},
595 	.ad = {
596 		.count = 3,
597 		.base = { 0x78000, 0x78800, 0x79000 },
598 	},
599 	.pp = {
600 		.count = 4,
601 		.base = { 0x70000, 0x70800, 0x71000, 0x71800 },
602 	},
603 	.cdm = {
604 		.count = 1,
605 		.base = { 0x79200 },
606 	},
607 	.dsc = {
608 		.count = 2,
609 		.base = { 0x80000, 0x80400 },
610 	},
611 	.intf = {
612 		.base = { 0x6a000, 0x6a800, 0x6b000, 0x6b800, 0x6c000 },
613 		.connect = {
614 			[0] = INTF_DISABLED,
615 			[1] = INTF_DSI,
616 			[2] = INTF_DSI,
617 			[3] = INTF_HDMI,
618 		},
619 	},
620 	.max_clk = 412500000,
621 };
622 
623 const struct mdp5_cfg_hw msm8x76_config = {
624 	.name = "msm8x76",
625 	.mdp = {
626 		.count = 1,
627 		.caps = MDP_CAP_SMP |
628 			MDP_CAP_DSC |
629 			MDP_CAP_SRC_SPLIT |
630 			0,
631 	},
632 	.ctl = {
633 		.count = 3,
634 		.base = { 0x01000, 0x01200, 0x01400 },
635 		.flush_hw_mask = 0xffffffff,
636 	},
637 	.smp = {
638 		.mmb_count = 10,
639 		.mmb_size = 10240,
640 		.clients = {
641 			[SSPP_VIG0] = 1, [SSPP_VIG1] = 9,
642 			[SSPP_DMA0] = 4,
643 			[SSPP_RGB0] = 7, [SSPP_RGB1] = 8,
644 		},
645 	},
646 	.pipe_vig = {
647 		.count = 2,
648 		.base = { 0x04000, 0x06000 },
649 		.caps = MDP_PIPE_CAP_HFLIP	|
650 			MDP_PIPE_CAP_VFLIP	|
651 			MDP_PIPE_CAP_SCALE	|
652 			MDP_PIPE_CAP_CSC	|
653 			MDP_PIPE_CAP_DECIMATION	|
654 			MDP_PIPE_CAP_SW_PIX_EXT	|
655 			0,
656 	},
657 	.pipe_rgb = {
658 		.count = 2,
659 		.base = { 0x14000, 0x16000 },
660 		.caps = MDP_PIPE_CAP_HFLIP	|
661 			MDP_PIPE_CAP_VFLIP	|
662 			MDP_PIPE_CAP_DECIMATION	|
663 			MDP_PIPE_CAP_SW_PIX_EXT	|
664 			0,
665 	},
666 	.pipe_dma = {
667 		.count = 1,
668 		.base = { 0x24000 },
669 		.caps = MDP_PIPE_CAP_HFLIP	|
670 			MDP_PIPE_CAP_VFLIP	|
671 			MDP_PIPE_CAP_SW_PIX_EXT	|
672 			0,
673 	},
674 	.pipe_cursor = {
675 		.count = 1,
676 		.base = { 0x440DC },
677 		.caps = MDP_PIPE_CAP_HFLIP	|
678 			MDP_PIPE_CAP_VFLIP	|
679 			MDP_PIPE_CAP_SW_PIX_EXT	|
680 			MDP_PIPE_CAP_CURSOR	|
681 			0,
682 	},
683 	.lm = {
684 		.count = 2,
685 		.base = { 0x44000, 0x45000 },
686 		.instances = {
687 				{ .id = 0, .pp = 0, .dspp = 0,
688 				  .caps = MDP_LM_CAP_DISPLAY, },
689 				{ .id = 1, .pp = -1, .dspp = -1,
690 				  .caps = MDP_LM_CAP_WB },
691 			     },
692 		.nb_stages = 8,
693 		.max_width = 2560,
694 		.max_height = 0xFFFF,
695 	},
696 	.dspp = {
697 		.count = 1,
698 		.base = { 0x54000 },
699 
700 	},
701 	.pp = {
702 		.count = 3,
703 		.base = { 0x70000, 0x70800, 0x72000 },
704 	},
705 	.dsc = {
706 		.count = 2,
707 		.base = { 0x80000, 0x80400 },
708 	},
709 	.intf = {
710 		.base = { 0x6a000, 0x6a800, 0x6b000 },
711 		.connect = {
712 			[0] = INTF_DISABLED,
713 			[1] = INTF_DSI,
714 			[2] = INTF_DSI,
715 		},
716 	},
717 	.max_clk = 360000000,
718 };
719 
720 static const struct mdp5_cfg_hw msm8917_config = {
721 	.name = "msm8917",
722 	.mdp = {
723 		.count = 1,
724 		.caps = MDP_CAP_CDM,
725 	},
726 	.ctl = {
727 		.count = 3,
728 		.base = { 0x01000, 0x01200, 0x01400 },
729 		.flush_hw_mask = 0xffffffff,
730 	},
731 	.pipe_vig = {
732 		.count = 1,
733 		.base = { 0x04000 },
734 		.caps = MDP_PIPE_CAP_HFLIP	|
735 			MDP_PIPE_CAP_VFLIP	|
736 			MDP_PIPE_CAP_SCALE	|
737 			MDP_PIPE_CAP_CSC	|
738 			MDP_PIPE_CAP_DECIMATION	|
739 			MDP_PIPE_CAP_SW_PIX_EXT	|
740 			0,
741 	},
742 	.pipe_rgb = {
743 		.count = 2,
744 		.base = { 0x14000, 0x16000 },
745 		.caps = MDP_PIPE_CAP_HFLIP	|
746 			MDP_PIPE_CAP_VFLIP	|
747 			MDP_PIPE_CAP_DECIMATION	|
748 			MDP_PIPE_CAP_SW_PIX_EXT	|
749 			0,
750 	},
751 	.pipe_dma = {
752 		.count = 1,
753 		.base = { 0x24000 },
754 		.caps = MDP_PIPE_CAP_HFLIP	|
755 			MDP_PIPE_CAP_VFLIP	|
756 			MDP_PIPE_CAP_SW_PIX_EXT	|
757 			0,
758 	},
759 	.pipe_cursor = {
760 		.count = 1,
761 		.base = { 0x34000 },
762 		.caps = MDP_PIPE_CAP_HFLIP	|
763 			MDP_PIPE_CAP_VFLIP	|
764 			MDP_PIPE_CAP_SW_PIX_EXT	|
765 			MDP_PIPE_CAP_CURSOR	|
766 			0,
767 	},
768 
769 	.lm = {
770 		.count = 2,
771 		.base = { 0x44000, 0x45000 },
772 		.instances = {
773 				{ .id = 0, .pp = 0, .dspp = 0,
774 				  .caps = MDP_LM_CAP_DISPLAY, },
775 				{ .id = 1, .pp = -1, .dspp = -1,
776 				  .caps = MDP_LM_CAP_WB },
777 			     },
778 		.nb_stages = 8,
779 		.max_width = 2048,
780 		.max_height = 0xFFFF,
781 	},
782 	.dspp = {
783 		.count = 1,
784 		.base = { 0x54000 },
785 
786 	},
787 	.pp = {
788 		.count = 1,
789 		.base = { 0x70000 },
790 	},
791 	.cdm = {
792 		.count = 1,
793 		.base = { 0x79200 },
794 	},
795 	.intf = {
796 		.base = { 0x6a000, 0x6a800 },
797 		.connect = {
798 			[0] = INTF_DISABLED,
799 			[1] = INTF_DSI,
800 		},
801 	},
802 	.max_clk = 320000000,
803 };
804 
805 static const struct mdp5_cfg_hw msm8998_config = {
806 	.name = "msm8998",
807 	.mdp = {
808 		.count = 1,
809 		.caps = MDP_CAP_DSC |
810 			MDP_CAP_CDM |
811 			MDP_CAP_SRC_SPLIT |
812 			0,
813 	},
814 	.ctl = {
815 		.count = 5,
816 		.base = { 0x01000, 0x01200, 0x01400, 0x01600, 0x01800 },
817 		.flush_hw_mask = 0xf7ffffff,
818 	},
819 	.pipe_vig = {
820 		.count = 4,
821 		.base = { 0x04000, 0x06000, 0x08000, 0x0a000 },
822 		.caps = MDP_PIPE_CAP_HFLIP	|
823 			MDP_PIPE_CAP_VFLIP	|
824 			MDP_PIPE_CAP_SCALE	|
825 			MDP_PIPE_CAP_CSC	|
826 			MDP_PIPE_CAP_DECIMATION	|
827 			MDP_PIPE_CAP_SW_PIX_EXT	|
828 			0,
829 	},
830 	.pipe_rgb = {
831 		.count = 4,
832 		.base = { 0x14000, 0x16000, 0x18000, 0x1a000 },
833 		.caps = MDP_PIPE_CAP_HFLIP	|
834 			MDP_PIPE_CAP_VFLIP	|
835 			MDP_PIPE_CAP_SCALE	|
836 			MDP_PIPE_CAP_DECIMATION	|
837 			MDP_PIPE_CAP_SW_PIX_EXT	|
838 			0,
839 	},
840 	.pipe_dma = {
841 		.count = 2, /* driver supports max of 2 currently */
842 		.base = { 0x24000, 0x26000, 0x28000, 0x2a000 },
843 		.caps = MDP_PIPE_CAP_HFLIP	|
844 			MDP_PIPE_CAP_VFLIP	|
845 			MDP_PIPE_CAP_SW_PIX_EXT	|
846 			0,
847 	},
848 	.pipe_cursor = {
849 		.count = 2,
850 		.base = { 0x34000, 0x36000 },
851 		.caps = MDP_PIPE_CAP_HFLIP	|
852 			MDP_PIPE_CAP_VFLIP	|
853 			MDP_PIPE_CAP_SW_PIX_EXT	|
854 			MDP_PIPE_CAP_CURSOR	|
855 			0,
856 	},
857 
858 	.lm = {
859 		.count = 6,
860 		.base = { 0x44000, 0x45000, 0x46000, 0x47000, 0x48000, 0x49000 },
861 		.instances = {
862 				{ .id = 0, .pp = 0, .dspp = 0,
863 				  .caps = MDP_LM_CAP_DISPLAY |
864 					  MDP_LM_CAP_PAIR, },
865 				{ .id = 1, .pp = 1, .dspp = 1,
866 				  .caps = MDP_LM_CAP_DISPLAY, },
867 				{ .id = 2, .pp = 2, .dspp = -1,
868 				  .caps = MDP_LM_CAP_DISPLAY |
869 					  MDP_LM_CAP_PAIR, },
870 				{ .id = 3, .pp = -1, .dspp = -1,
871 				  .caps = MDP_LM_CAP_WB, },
872 				{ .id = 4, .pp = -1, .dspp = -1,
873 				  .caps = MDP_LM_CAP_WB, },
874 				{ .id = 5, .pp = 3, .dspp = -1,
875 				  .caps = MDP_LM_CAP_DISPLAY, },
876 			     },
877 		.nb_stages = 8,
878 		.max_width = 2560,
879 		.max_height = 0xFFFF,
880 	},
881 	.dspp = {
882 		.count = 2,
883 		.base = { 0x54000, 0x56000 },
884 	},
885 	.ad = {
886 		.count = 3,
887 		.base = { 0x78000, 0x78800, 0x79000 },
888 	},
889 	.pp = {
890 		.count = 4,
891 		.base = { 0x70000, 0x70800, 0x71000, 0x71800 },
892 	},
893 	.cdm = {
894 		.count = 1,
895 		.base = { 0x79200 },
896 	},
897 	.dsc = {
898 		.count = 2,
899 		.base = { 0x80000, 0x80400 },
900 	},
901 	.intf = {
902 		.base = { 0x6a000, 0x6a800, 0x6b000, 0x6b800, 0x6c000 },
903 		.connect = {
904 			[0] = INTF_eDP,
905 			[1] = INTF_DSI,
906 			[2] = INTF_DSI,
907 			[3] = INTF_HDMI,
908 		},
909 	},
910 	.max_clk = 412500000,
911 };
912 
913 static const struct mdp5_cfg_hw sdm630_config = {
914 	.name = "sdm630",
915 	.mdp = {
916 		.count = 1,
917 		.caps = MDP_CAP_CDM |
918 			MDP_CAP_SRC_SPLIT |
919 			0,
920 	},
921 	.ctl = {
922 		.count = 5,
923 		.base = { 0x01000, 0x01200, 0x01400, 0x01600, 0x01800 },
924 		.flush_hw_mask = 0xf4ffffff,
925 	},
926 	.pipe_vig = {
927 		.count = 1,
928 		.base = { 0x04000 },
929 		.caps = MDP_PIPE_CAP_HFLIP	|
930 			MDP_PIPE_CAP_VFLIP	|
931 			MDP_PIPE_CAP_SCALE	|
932 			MDP_PIPE_CAP_CSC	|
933 			MDP_PIPE_CAP_DECIMATION	|
934 			MDP_PIPE_CAP_SW_PIX_EXT	|
935 			0,
936 	},
937 	.pipe_rgb = {
938 		.count = 4,
939 		.base = { 0x14000, 0x16000, 0x18000, 0x1a000 },
940 		.caps = MDP_PIPE_CAP_HFLIP	|
941 			MDP_PIPE_CAP_VFLIP	|
942 			MDP_PIPE_CAP_SCALE	|
943 			MDP_PIPE_CAP_DECIMATION	|
944 			MDP_PIPE_CAP_SW_PIX_EXT	|
945 			0,
946 	},
947 	.pipe_dma = {
948 		.count = 2, /* driver supports max of 2 currently */
949 		.base = { 0x24000, 0x26000, 0x28000 },
950 		.caps = MDP_PIPE_CAP_HFLIP	|
951 			MDP_PIPE_CAP_VFLIP	|
952 			MDP_PIPE_CAP_SW_PIX_EXT	|
953 			0,
954 	},
955 	.pipe_cursor = {
956 		.count = 1,
957 		.base = { 0x34000 },
958 		.caps = MDP_PIPE_CAP_HFLIP	|
959 			MDP_PIPE_CAP_VFLIP	|
960 			MDP_PIPE_CAP_SW_PIX_EXT	|
961 			MDP_PIPE_CAP_CURSOR	|
962 			0,
963 	},
964 
965 	.lm = {
966 		.count = 2,
967 		.base = { 0x44000, 0x46000 },
968 		.instances = {
969 				{ .id = 0, .pp = 0, .dspp = 0,
970 				  .caps = MDP_LM_CAP_DISPLAY |
971 					  MDP_LM_CAP_PAIR, },
972 				{ .id = 1, .pp = 1, .dspp = -1,
973 				  .caps = MDP_LM_CAP_WB, },
974 				},
975 		.nb_stages = 8,
976 		.max_width = 2048,
977 		.max_height = 0xFFFF,
978 	},
979 	.dspp = {
980 		.count = 1,
981 		.base = { 0x54000 },
982 	},
983 	.ad = {
984 		.count = 2,
985 		.base = { 0x78000, 0x78800 },
986 	},
987 	.pp = {
988 		.count = 3,
989 		.base = { 0x70000, 0x71000, 0x72000 },
990 	},
991 	.cdm = {
992 		.count = 1,
993 		.base = { 0x79200 },
994 	},
995 	.intf = {
996 		.base = { 0x6a000, 0x6a800 },
997 		.connect = {
998 			[0] = INTF_DISABLED,
999 			[1] = INTF_DSI,
1000 		},
1001 	},
1002 	.max_clk = 412500000,
1003 };
1004 
1005 static const struct mdp5_cfg_hw sdm660_config = {
1006 	.name = "sdm660",
1007 	.mdp = {
1008 		.count = 1,
1009 		.caps = MDP_CAP_DSC |
1010 			MDP_CAP_CDM |
1011 			MDP_CAP_SRC_SPLIT |
1012 			0,
1013 	},
1014 	.ctl = {
1015 		.count = 5,
1016 		.base = { 0x01000, 0x01200, 0x01400, 0x01600, 0x01800 },
1017 		.flush_hw_mask = 0xf4ffffff,
1018 	},
1019 	.pipe_vig = {
1020 		.count = 2,
1021 		.base = { 0x04000, 0x6000 },
1022 		.caps = MDP_PIPE_CAP_HFLIP	|
1023 			MDP_PIPE_CAP_VFLIP	|
1024 			MDP_PIPE_CAP_SCALE	|
1025 			MDP_PIPE_CAP_CSC	|
1026 			MDP_PIPE_CAP_DECIMATION	|
1027 			MDP_PIPE_CAP_SW_PIX_EXT	|
1028 			0,
1029 	},
1030 	.pipe_rgb = {
1031 		.count = 4,
1032 		.base = { 0x14000, 0x16000, 0x18000, 0x1a000 },
1033 		.caps = MDP_PIPE_CAP_HFLIP	|
1034 			MDP_PIPE_CAP_VFLIP	|
1035 			MDP_PIPE_CAP_SCALE	|
1036 			MDP_PIPE_CAP_DECIMATION	|
1037 			MDP_PIPE_CAP_SW_PIX_EXT	|
1038 			0,
1039 	},
1040 	.pipe_dma = {
1041 		.count = 2, /* driver supports max of 2 currently */
1042 		.base = { 0x24000, 0x26000, 0x28000 },
1043 		.caps = MDP_PIPE_CAP_HFLIP	|
1044 			MDP_PIPE_CAP_VFLIP	|
1045 			MDP_PIPE_CAP_SW_PIX_EXT	|
1046 			0,
1047 	},
1048 	.pipe_cursor = {
1049 		.count = 1,
1050 		.base = { 0x34000 },
1051 		.caps = MDP_PIPE_CAP_HFLIP	|
1052 			MDP_PIPE_CAP_VFLIP	|
1053 			MDP_PIPE_CAP_SW_PIX_EXT	|
1054 			MDP_PIPE_CAP_CURSOR	|
1055 			0,
1056 	},
1057 
1058 	.lm = {
1059 		.count = 4,
1060 		.base = { 0x44000, 0x45000, 0x46000, 0x49000 },
1061 		.instances = {
1062 				{ .id = 0, .pp = 0, .dspp = 0,
1063 				  .caps = MDP_LM_CAP_DISPLAY |
1064 					  MDP_LM_CAP_PAIR, },
1065 				{ .id = 1, .pp = 1, .dspp = 1,
1066 				  .caps = MDP_LM_CAP_DISPLAY, },
1067 				{ .id = 2, .pp = 2, .dspp = -1,
1068 				  .caps = MDP_LM_CAP_DISPLAY |
1069 					  MDP_LM_CAP_PAIR, },
1070 				{ .id = 3, .pp = 3, .dspp = -1,
1071 				  .caps = MDP_LM_CAP_WB, },
1072 				},
1073 		.nb_stages = 8,
1074 		.max_width = 2560,
1075 		.max_height = 0xFFFF,
1076 	},
1077 	.dspp = {
1078 		.count = 2,
1079 		.base = { 0x54000, 0x56000 },
1080 	},
1081 	.ad = {
1082 		.count = 2,
1083 		.base = { 0x78000, 0x78800 },
1084 	},
1085 	.pp = {
1086 		.count = 5,
1087 		.base = { 0x70000, 0x70800, 0x71000, 0x71800, 0x72000 },
1088 	},
1089 	.cdm = {
1090 		.count = 1,
1091 		.base = { 0x79200 },
1092 	},
1093 	.dsc = {
1094 		.count = 2,
1095 		.base = { 0x80000, 0x80400 },
1096 	},
1097 	.intf = {
1098 		.base = { 0x6a000, 0x6a800, 0x6b000, 0x6b800 },
1099 		.connect = {
1100 			[0] = INTF_DISABLED,
1101 			[1] = INTF_DSI,
1102 			[2] = INTF_DSI,
1103 			[3] = INTF_HDMI,
1104 		},
1105 	},
1106 	.max_clk = 412500000,
1107 };
1108 
1109 static const struct mdp5_cfg_handler cfg_handlers_v1[] = {
1110 	{ .revision = 0, .config = { .hw = &msm8x74v1_config } },
1111 	{ .revision = 2, .config = { .hw = &msm8x74v2_config } },
1112 	{ .revision = 3, .config = { .hw = &apq8084_config } },
1113 	{ .revision = 6, .config = { .hw = &msm8x16_config } },
1114 	{ .revision = 8, .config = { .hw = &msm8x36_config } },
1115 	{ .revision = 9, .config = { .hw = &msm8x94_config } },
1116 	{ .revision = 7, .config = { .hw = &msm8x96_config } },
1117 	{ .revision = 11, .config = { .hw = &msm8x76_config } },
1118 	{ .revision = 15, .config = { .hw = &msm8917_config } },
1119 };
1120 
1121 static const struct mdp5_cfg_handler cfg_handlers_v3[] = {
1122 	{ .revision = 0, .config = { .hw = &msm8998_config } },
1123 	{ .revision = 2, .config = { .hw = &sdm660_config } },
1124 	{ .revision = 3, .config = { .hw = &sdm630_config } },
1125 };
1126 
1127 static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev);
1128 
1129 const struct mdp5_cfg_hw *mdp5_cfg_get_hw_config(struct mdp5_cfg_handler *cfg_handler)
1130 {
1131 	return cfg_handler->config.hw;
1132 }
1133 
1134 struct mdp5_cfg *mdp5_cfg_get_config(struct mdp5_cfg_handler *cfg_handler)
1135 {
1136 	return &cfg_handler->config;
1137 }
1138 
1139 int mdp5_cfg_get_hw_rev(struct mdp5_cfg_handler *cfg_handler)
1140 {
1141 	return cfg_handler->revision;
1142 }
1143 
1144 void mdp5_cfg_destroy(struct mdp5_cfg_handler *cfg_handler)
1145 {
1146 	kfree(cfg_handler);
1147 }
1148 
1149 struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms,
1150 		uint32_t major, uint32_t minor)
1151 {
1152 	struct drm_device *dev = mdp5_kms->dev;
1153 	struct platform_device *pdev = to_platform_device(dev->dev);
1154 	struct mdp5_cfg_handler *cfg_handler;
1155 	const struct mdp5_cfg_handler *cfg_handlers;
1156 	struct mdp5_cfg_platform *pconfig;
1157 	int i, ret = 0, num_handlers;
1158 
1159 	cfg_handler = kzalloc(sizeof(*cfg_handler), GFP_KERNEL);
1160 	if (unlikely(!cfg_handler)) {
1161 		ret = -ENOMEM;
1162 		goto fail;
1163 	}
1164 
1165 	switch (major) {
1166 	case 1:
1167 		cfg_handlers = cfg_handlers_v1;
1168 		num_handlers = ARRAY_SIZE(cfg_handlers_v1);
1169 		break;
1170 	case 3:
1171 		cfg_handlers = cfg_handlers_v3;
1172 		num_handlers = ARRAY_SIZE(cfg_handlers_v3);
1173 		break;
1174 	default:
1175 		DRM_DEV_ERROR(dev->dev, "unexpected MDP major version: v%d.%d\n",
1176 				major, minor);
1177 		ret = -ENXIO;
1178 		goto fail;
1179 	}
1180 
1181 	/* only after mdp5_cfg global pointer's init can we access the hw */
1182 	for (i = 0; i < num_handlers; i++) {
1183 		if (cfg_handlers[i].revision != minor)
1184 			continue;
1185 		mdp5_cfg = cfg_handlers[i].config.hw;
1186 
1187 		break;
1188 	}
1189 	if (unlikely(!mdp5_cfg)) {
1190 		DRM_DEV_ERROR(dev->dev, "unexpected MDP minor revision: v%d.%d\n",
1191 				major, minor);
1192 		ret = -ENXIO;
1193 		goto fail;
1194 	}
1195 
1196 	cfg_handler->revision = minor;
1197 	cfg_handler->config.hw = mdp5_cfg;
1198 
1199 	pconfig = mdp5_get_config(pdev);
1200 	memcpy(&cfg_handler->config.platform, pconfig, sizeof(*pconfig));
1201 
1202 	DBG("MDP5: %s hw config selected", mdp5_cfg->name);
1203 
1204 	return cfg_handler;
1205 
1206 fail:
1207 	if (cfg_handler)
1208 		mdp5_cfg_destroy(cfg_handler);
1209 
1210 	return ERR_PTR(ret);
1211 }
1212 
1213 static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev)
1214 {
1215 	static struct mdp5_cfg_platform config = {};
1216 
1217 	config.iommu = iommu_domain_alloc(&platform_bus_type);
1218 
1219 	return &config;
1220 }
1221