1 /*
2  * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 and
6  * only version 2 as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  */
13 
14 #include "mdp5_kms.h"
15 #include "mdp5_cfg.h"
16 
17 struct mdp5_cfg_handler {
18 	int revision;
19 	struct mdp5_cfg config;
20 };
21 
22 /* mdp5_cfg must be exposed (used in mdp5.xml.h) */
23 const struct mdp5_cfg_hw *mdp5_cfg = NULL;
24 
25 const struct mdp5_cfg_hw msm8x74_config = {
26 	.name = "msm8x74",
27 	.mdp = {
28 		.count = 1,
29 		.base = { 0x00100 },
30 	},
31 	.smp = {
32 		.mmb_count = 22,
33 		.mmb_size = 4096,
34 		.clients = {
35 			[SSPP_VIG0] =  1, [SSPP_VIG1] =  4, [SSPP_VIG2] =  7,
36 			[SSPP_DMA0] = 10, [SSPP_DMA1] = 13,
37 			[SSPP_RGB0] = 16, [SSPP_RGB1] = 17, [SSPP_RGB2] = 18,
38 		},
39 	},
40 	.ctl = {
41 		.count = 5,
42 		.base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 },
43 		.flush_hw_mask = 0x0003ffff,
44 	},
45 	.pipe_vig = {
46 		.count = 3,
47 		.base = { 0x01200, 0x01600, 0x01a00 },
48 	},
49 	.pipe_rgb = {
50 		.count = 3,
51 		.base = { 0x01e00, 0x02200, 0x02600 },
52 	},
53 	.pipe_dma = {
54 		.count = 2,
55 		.base = { 0x02a00, 0x02e00 },
56 	},
57 	.lm = {
58 		.count = 5,
59 		.base = { 0x03200, 0x03600, 0x03a00, 0x03e00, 0x04200 },
60 		.nb_stages = 5,
61 	},
62 	.dspp = {
63 		.count = 3,
64 		.base = { 0x04600, 0x04a00, 0x04e00 },
65 	},
66 	.ad = {
67 		.count = 2,
68 		.base = { 0x13100, 0x13300 }, /* NOTE: no ad in v1.0 */
69 	},
70 	.pp = {
71 		.count = 3,
72 		.base = { 0x12d00, 0x12e00, 0x12f00 },
73 	},
74 	.intf = {
75 		.base = { 0x12500, 0x12700, 0x12900, 0x12b00 },
76 		.connect = {
77 			[0] = INTF_eDP,
78 			[1] = INTF_DSI,
79 			[2] = INTF_DSI,
80 			[3] = INTF_HDMI,
81 		},
82 	},
83 	.max_clk = 200000000,
84 };
85 
86 const struct mdp5_cfg_hw apq8084_config = {
87 	.name = "apq8084",
88 	.mdp = {
89 		.count = 1,
90 		.base = { 0x00100 },
91 	},
92 	.smp = {
93 		.mmb_count = 44,
94 		.mmb_size = 8192,
95 		.clients = {
96 			[SSPP_VIG0] =  1, [SSPP_VIG1] =  4,
97 			[SSPP_VIG2] =  7, [SSPP_VIG3] = 19,
98 			[SSPP_DMA0] = 10, [SSPP_DMA1] = 13,
99 			[SSPP_RGB0] = 16, [SSPP_RGB1] = 17,
100 			[SSPP_RGB2] = 18, [SSPP_RGB3] = 22,
101 		},
102 		.reserved_state[0] = GENMASK(7, 0),	/* first 8 MMBs */
103 		.reserved = {
104 			/* Two SMP blocks are statically tied to RGB pipes: */
105 			[16] = 2, [17] = 2, [18] = 2, [22] = 2,
106 		},
107 	},
108 	.ctl = {
109 		.count = 5,
110 		.base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 },
111 		.flush_hw_mask = 0x003fffff,
112 	},
113 	.pipe_vig = {
114 		.count = 4,
115 		.base = { 0x01200, 0x01600, 0x01a00, 0x01e00 },
116 	},
117 	.pipe_rgb = {
118 		.count = 4,
119 		.base = { 0x02200, 0x02600, 0x02a00, 0x02e00 },
120 	},
121 	.pipe_dma = {
122 		.count = 2,
123 		.base = { 0x03200, 0x03600 },
124 	},
125 	.lm = {
126 		.count = 6,
127 		.base = { 0x03a00, 0x03e00, 0x04200, 0x04600, 0x04a00, 0x04e00 },
128 		.nb_stages = 5,
129 	},
130 	.dspp = {
131 		.count = 4,
132 		.base = { 0x05200, 0x05600, 0x05a00, 0x05e00 },
133 
134 	},
135 	.ad = {
136 		.count = 3,
137 		.base = { 0x13500, 0x13700, 0x13900 },
138 	},
139 	.pp = {
140 		.count = 4,
141 		.base = { 0x12f00, 0x13000, 0x13100, 0x13200 },
142 	},
143 	.intf = {
144 		.base = { 0x12500, 0x12700, 0x12900, 0x12b00, 0x12d00 },
145 		.connect = {
146 			[0] = INTF_eDP,
147 			[1] = INTF_DSI,
148 			[2] = INTF_DSI,
149 			[3] = INTF_HDMI,
150 		},
151 	},
152 	.max_clk = 320000000,
153 };
154 
155 const struct mdp5_cfg_hw msm8x16_config = {
156 	.name = "msm8x16",
157 	.mdp = {
158 		.count = 1,
159 		.base = { 0x01000 },
160 	},
161 	.smp = {
162 		.mmb_count = 8,
163 		.mmb_size = 8192,
164 		.clients = {
165 			[SSPP_VIG0] = 1, [SSPP_DMA0] = 4,
166 			[SSPP_RGB0] = 7, [SSPP_RGB1] = 8,
167 		},
168 	},
169 	.ctl = {
170 		.count = 5,
171 		.base = { 0x02000, 0x02200, 0x02400, 0x02600, 0x02800 },
172 		.flush_hw_mask = 0x4003ffff,
173 	},
174 	.pipe_vig = {
175 		.count = 1,
176 		.base = { 0x05000 },
177 	},
178 	.pipe_rgb = {
179 		.count = 2,
180 		.base = { 0x15000, 0x17000 },
181 	},
182 	.pipe_dma = {
183 		.count = 1,
184 		.base = { 0x25000 },
185 	},
186 	.lm = {
187 		.count = 2, /* LM0 and LM3 */
188 		.base = { 0x45000, 0x48000 },
189 		.nb_stages = 5,
190 	},
191 	.dspp = {
192 		.count = 1,
193 		.base = { 0x55000 },
194 
195 	},
196 	.intf = {
197 		.base = { 0x00000, 0x6b800 },
198 		.connect = {
199 			[0] = INTF_DISABLED,
200 			[1] = INTF_DSI,
201 		},
202 	},
203 	.max_clk = 320000000,
204 };
205 
206 static const struct mdp5_cfg_handler cfg_handlers[] = {
207 	{ .revision = 0, .config = { .hw = &msm8x74_config } },
208 	{ .revision = 2, .config = { .hw = &msm8x74_config } },
209 	{ .revision = 3, .config = { .hw = &apq8084_config } },
210 	{ .revision = 6, .config = { .hw = &msm8x16_config } },
211 };
212 
213 
214 static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev);
215 
mdp5_cfg_get_hw_config(struct mdp5_cfg_handler * cfg_handler)216 const struct mdp5_cfg_hw *mdp5_cfg_get_hw_config(struct mdp5_cfg_handler *cfg_handler)
217 {
218 	return cfg_handler->config.hw;
219 }
220 
mdp5_cfg_get_config(struct mdp5_cfg_handler * cfg_handler)221 struct mdp5_cfg *mdp5_cfg_get_config(struct mdp5_cfg_handler *cfg_handler)
222 {
223 	return &cfg_handler->config;
224 }
225 
mdp5_cfg_get_hw_rev(struct mdp5_cfg_handler * cfg_handler)226 int mdp5_cfg_get_hw_rev(struct mdp5_cfg_handler *cfg_handler)
227 {
228 	return cfg_handler->revision;
229 }
230 
mdp5_cfg_destroy(struct mdp5_cfg_handler * cfg_handler)231 void mdp5_cfg_destroy(struct mdp5_cfg_handler *cfg_handler)
232 {
233 	kfree(cfg_handler);
234 }
235 
mdp5_cfg_init(struct mdp5_kms * mdp5_kms,uint32_t major,uint32_t minor)236 struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms,
237 		uint32_t major, uint32_t minor)
238 {
239 	struct drm_device *dev = mdp5_kms->dev;
240 	struct platform_device *pdev = dev->platformdev;
241 	struct mdp5_cfg_handler *cfg_handler;
242 	struct mdp5_cfg_platform *pconfig;
243 	int i, ret = 0;
244 
245 	cfg_handler = kzalloc(sizeof(*cfg_handler), GFP_KERNEL);
246 	if (unlikely(!cfg_handler)) {
247 		ret = -ENOMEM;
248 		goto fail;
249 	}
250 
251 	if (major != 1) {
252 		dev_err(dev->dev, "unexpected MDP major version: v%d.%d\n",
253 				major, minor);
254 		ret = -ENXIO;
255 		goto fail;
256 	}
257 
258 	/* only after mdp5_cfg global pointer's init can we access the hw */
259 	for (i = 0; i < ARRAY_SIZE(cfg_handlers); i++) {
260 		if (cfg_handlers[i].revision != minor)
261 			continue;
262 		mdp5_cfg = cfg_handlers[i].config.hw;
263 
264 		break;
265 	}
266 	if (unlikely(!mdp5_cfg)) {
267 		dev_err(dev->dev, "unexpected MDP minor revision: v%d.%d\n",
268 				major, minor);
269 		ret = -ENXIO;
270 		goto fail;
271 	}
272 
273 	cfg_handler->revision = minor;
274 	cfg_handler->config.hw = mdp5_cfg;
275 
276 	pconfig = mdp5_get_config(pdev);
277 	memcpy(&cfg_handler->config.platform, pconfig, sizeof(*pconfig));
278 
279 	DBG("MDP5: %s hw config selected", mdp5_cfg->name);
280 
281 	return cfg_handler;
282 
283 fail:
284 	if (cfg_handler)
285 		mdp5_cfg_destroy(cfg_handler);
286 
287 	return NULL;
288 }
289 
mdp5_get_config(struct platform_device * dev)290 static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev)
291 {
292 	static struct mdp5_cfg_platform config = {};
293 #ifdef CONFIG_OF
294 	/* TODO */
295 #endif
296 	config.iommu = iommu_domain_alloc(&platform_bus_type);
297 
298 	return &config;
299 }
300