• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2015 MediaTek Inc.
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 as
6  * 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 <linux/clk.h>
15 #include <linux/module.h>
16 #include <linux/of_device.h>
17 #include <linux/platform_device.h>
18 #include <linux/regmap.h>
19 
20 #include "mtk_drm_ddp.h"
21 #include "mtk_drm_ddp_comp.h"
22 
23 #define DISP_REG_CONFIG_DISP_OVL0_MOUT_EN	0x040
24 #define DISP_REG_CONFIG_DISP_OVL1_MOUT_EN	0x044
25 #define DISP_REG_CONFIG_DISP_OD_MOUT_EN		0x048
26 #define DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN	0x04c
27 #define DISP_REG_CONFIG_DISP_UFOE_MOUT_EN	0x050
28 #define DISP_REG_CONFIG_DISP_COLOR0_SEL_IN	0x084
29 #define DISP_REG_CONFIG_DISP_COLOR1_SEL_IN	0x088
30 #define DISP_REG_CONFIG_DPI_SEL_IN		0x0ac
31 #define DISP_REG_CONFIG_DISP_RDMA1_MOUT_EN	0x0c8
32 #define DISP_REG_CONFIG_MMSYS_CG_CON0		0x100
33 
34 #define DISP_REG_MUTEX_EN(n)	(0x20 + 0x20 * (n))
35 #define DISP_REG_MUTEX_RST(n)	(0x28 + 0x20 * (n))
36 #define DISP_REG_MUTEX_MOD(n)	(0x2c + 0x20 * (n))
37 #define DISP_REG_MUTEX_SOF(n)	(0x30 + 0x20 * (n))
38 
39 #define MUTEX_MOD_DISP_OVL0		BIT(11)
40 #define MUTEX_MOD_DISP_OVL1		BIT(12)
41 #define MUTEX_MOD_DISP_RDMA0		BIT(13)
42 #define MUTEX_MOD_DISP_RDMA1		BIT(14)
43 #define MUTEX_MOD_DISP_RDMA2		BIT(15)
44 #define MUTEX_MOD_DISP_WDMA0		BIT(16)
45 #define MUTEX_MOD_DISP_WDMA1		BIT(17)
46 #define MUTEX_MOD_DISP_COLOR0		BIT(18)
47 #define MUTEX_MOD_DISP_COLOR1		BIT(19)
48 #define MUTEX_MOD_DISP_AAL		BIT(20)
49 #define MUTEX_MOD_DISP_GAMMA		BIT(21)
50 #define MUTEX_MOD_DISP_UFOE		BIT(22)
51 #define MUTEX_MOD_DISP_PWM0		BIT(23)
52 #define MUTEX_MOD_DISP_PWM1		BIT(24)
53 #define MUTEX_MOD_DISP_OD		BIT(25)
54 
55 #define MUTEX_SOF_SINGLE_MODE		0
56 #define MUTEX_SOF_DSI0			1
57 #define MUTEX_SOF_DSI1			2
58 #define MUTEX_SOF_DPI0			3
59 
60 #define OVL0_MOUT_EN_COLOR0		0x1
61 #define OD_MOUT_EN_RDMA0		0x1
62 #define UFOE_MOUT_EN_DSI0		0x1
63 #define COLOR0_SEL_IN_OVL0		0x1
64 #define OVL1_MOUT_EN_COLOR1		0x1
65 #define GAMMA_MOUT_EN_RDMA1		0x1
66 #define RDMA1_MOUT_DPI0			0x2
67 #define DPI0_SEL_IN_RDMA1		0x1
68 #define COLOR1_SEL_IN_OVL1		0x1
69 
70 struct mtk_disp_mutex {
71 	int id;
72 	bool claimed;
73 };
74 
75 struct mtk_ddp {
76 	struct device			*dev;
77 	struct clk			*clk;
78 	void __iomem			*regs;
79 	struct mtk_disp_mutex		mutex[10];
80 };
81 
82 static const unsigned int mutex_mod[DDP_COMPONENT_ID_MAX] = {
83 	[DDP_COMPONENT_AAL] = MUTEX_MOD_DISP_AAL,
84 	[DDP_COMPONENT_COLOR0] = MUTEX_MOD_DISP_COLOR0,
85 	[DDP_COMPONENT_COLOR1] = MUTEX_MOD_DISP_COLOR1,
86 	[DDP_COMPONENT_GAMMA] = MUTEX_MOD_DISP_GAMMA,
87 	[DDP_COMPONENT_OD] = MUTEX_MOD_DISP_OD,
88 	[DDP_COMPONENT_OVL0] = MUTEX_MOD_DISP_OVL0,
89 	[DDP_COMPONENT_OVL1] = MUTEX_MOD_DISP_OVL1,
90 	[DDP_COMPONENT_PWM0] = MUTEX_MOD_DISP_PWM0,
91 	[DDP_COMPONENT_PWM1] = MUTEX_MOD_DISP_PWM1,
92 	[DDP_COMPONENT_RDMA0] = MUTEX_MOD_DISP_RDMA0,
93 	[DDP_COMPONENT_RDMA1] = MUTEX_MOD_DISP_RDMA1,
94 	[DDP_COMPONENT_RDMA2] = MUTEX_MOD_DISP_RDMA2,
95 	[DDP_COMPONENT_UFOE] = MUTEX_MOD_DISP_UFOE,
96 	[DDP_COMPONENT_WDMA0] = MUTEX_MOD_DISP_WDMA0,
97 	[DDP_COMPONENT_WDMA1] = MUTEX_MOD_DISP_WDMA1,
98 };
99 
mtk_ddp_mout_en(enum mtk_ddp_comp_id cur,enum mtk_ddp_comp_id next,unsigned int * addr)100 static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur,
101 				    enum mtk_ddp_comp_id next,
102 				    unsigned int *addr)
103 {
104 	unsigned int value;
105 
106 	if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_COLOR0) {
107 		*addr = DISP_REG_CONFIG_DISP_OVL0_MOUT_EN;
108 		value = OVL0_MOUT_EN_COLOR0;
109 	} else if (cur == DDP_COMPONENT_OD && next == DDP_COMPONENT_RDMA0) {
110 		*addr = DISP_REG_CONFIG_DISP_OD_MOUT_EN;
111 		value = OD_MOUT_EN_RDMA0;
112 	} else if (cur == DDP_COMPONENT_UFOE && next == DDP_COMPONENT_DSI0) {
113 		*addr = DISP_REG_CONFIG_DISP_UFOE_MOUT_EN;
114 		value = UFOE_MOUT_EN_DSI0;
115 	} else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) {
116 		*addr = DISP_REG_CONFIG_DISP_OVL1_MOUT_EN;
117 		value = OVL1_MOUT_EN_COLOR1;
118 	} else if (cur == DDP_COMPONENT_GAMMA && next == DDP_COMPONENT_RDMA1) {
119 		*addr = DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN;
120 		value = GAMMA_MOUT_EN_RDMA1;
121 	} else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI0) {
122 		*addr = DISP_REG_CONFIG_DISP_RDMA1_MOUT_EN;
123 		value = RDMA1_MOUT_DPI0;
124 	} else {
125 		value = 0;
126 	}
127 
128 	return value;
129 }
130 
mtk_ddp_sel_in(enum mtk_ddp_comp_id cur,enum mtk_ddp_comp_id next,unsigned int * addr)131 static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur,
132 				   enum mtk_ddp_comp_id next,
133 				   unsigned int *addr)
134 {
135 	unsigned int value;
136 
137 	if (cur == DDP_COMPONENT_OVL0 && next == DDP_COMPONENT_COLOR0) {
138 		*addr = DISP_REG_CONFIG_DISP_COLOR0_SEL_IN;
139 		value = COLOR0_SEL_IN_OVL0;
140 	} else if (cur == DDP_COMPONENT_RDMA1 && next == DDP_COMPONENT_DPI0) {
141 		*addr = DISP_REG_CONFIG_DPI_SEL_IN;
142 		value = DPI0_SEL_IN_RDMA1;
143 	} else if (cur == DDP_COMPONENT_OVL1 && next == DDP_COMPONENT_COLOR1) {
144 		*addr = DISP_REG_CONFIG_DISP_COLOR1_SEL_IN;
145 		value = COLOR1_SEL_IN_OVL1;
146 	} else {
147 		value = 0;
148 	}
149 
150 	return value;
151 }
152 
mtk_ddp_add_comp_to_path(void __iomem * config_regs,enum mtk_ddp_comp_id cur,enum mtk_ddp_comp_id next)153 void mtk_ddp_add_comp_to_path(void __iomem *config_regs,
154 			      enum mtk_ddp_comp_id cur,
155 			      enum mtk_ddp_comp_id next)
156 {
157 	unsigned int addr, value, reg;
158 
159 	value = mtk_ddp_mout_en(cur, next, &addr);
160 	if (value) {
161 		reg = readl_relaxed(config_regs + addr) | value;
162 		writel_relaxed(reg, config_regs + addr);
163 	}
164 
165 	value = mtk_ddp_sel_in(cur, next, &addr);
166 	if (value) {
167 		reg = readl_relaxed(config_regs + addr) | value;
168 		writel_relaxed(reg, config_regs + addr);
169 	}
170 }
171 
mtk_ddp_remove_comp_from_path(void __iomem * config_regs,enum mtk_ddp_comp_id cur,enum mtk_ddp_comp_id next)172 void mtk_ddp_remove_comp_from_path(void __iomem *config_regs,
173 				   enum mtk_ddp_comp_id cur,
174 				   enum mtk_ddp_comp_id next)
175 {
176 	unsigned int addr, value, reg;
177 
178 	value = mtk_ddp_mout_en(cur, next, &addr);
179 	if (value) {
180 		reg = readl_relaxed(config_regs + addr) & ~value;
181 		writel_relaxed(reg, config_regs + addr);
182 	}
183 
184 	value = mtk_ddp_sel_in(cur, next, &addr);
185 	if (value) {
186 		reg = readl_relaxed(config_regs + addr) & ~value;
187 		writel_relaxed(reg, config_regs + addr);
188 	}
189 }
190 
mtk_disp_mutex_get(struct device * dev,unsigned int id)191 struct mtk_disp_mutex *mtk_disp_mutex_get(struct device *dev, unsigned int id)
192 {
193 	struct mtk_ddp *ddp = dev_get_drvdata(dev);
194 
195 	if (id >= 10)
196 		return ERR_PTR(-EINVAL);
197 	if (ddp->mutex[id].claimed)
198 		return ERR_PTR(-EBUSY);
199 
200 	ddp->mutex[id].claimed = true;
201 
202 	return &ddp->mutex[id];
203 }
204 
mtk_disp_mutex_put(struct mtk_disp_mutex * mutex)205 void mtk_disp_mutex_put(struct mtk_disp_mutex *mutex)
206 {
207 	struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
208 					   mutex[mutex->id]);
209 
210 	WARN_ON(&ddp->mutex[mutex->id] != mutex);
211 
212 	mutex->claimed = false;
213 }
214 
mtk_disp_mutex_prepare(struct mtk_disp_mutex * mutex)215 int mtk_disp_mutex_prepare(struct mtk_disp_mutex *mutex)
216 {
217 	struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
218 					   mutex[mutex->id]);
219 	return clk_prepare_enable(ddp->clk);
220 }
221 
mtk_disp_mutex_unprepare(struct mtk_disp_mutex * mutex)222 void mtk_disp_mutex_unprepare(struct mtk_disp_mutex *mutex)
223 {
224 	struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
225 					   mutex[mutex->id]);
226 	clk_disable_unprepare(ddp->clk);
227 }
228 
mtk_disp_mutex_add_comp(struct mtk_disp_mutex * mutex,enum mtk_ddp_comp_id id)229 void mtk_disp_mutex_add_comp(struct mtk_disp_mutex *mutex,
230 			     enum mtk_ddp_comp_id id)
231 {
232 	struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
233 					   mutex[mutex->id]);
234 	unsigned int reg;
235 
236 	WARN_ON(&ddp->mutex[mutex->id] != mutex);
237 
238 	switch (id) {
239 	case DDP_COMPONENT_DSI0:
240 		reg = MUTEX_SOF_DSI0;
241 		break;
242 	case DDP_COMPONENT_DSI1:
243 		reg = MUTEX_SOF_DSI0;
244 		break;
245 	case DDP_COMPONENT_DPI0:
246 		reg = MUTEX_SOF_DPI0;
247 		break;
248 	default:
249 		reg = readl_relaxed(ddp->regs + DISP_REG_MUTEX_MOD(mutex->id));
250 		reg |= mutex_mod[id];
251 		writel_relaxed(reg, ddp->regs + DISP_REG_MUTEX_MOD(mutex->id));
252 		return;
253 	}
254 
255 	writel_relaxed(reg, ddp->regs + DISP_REG_MUTEX_SOF(mutex->id));
256 }
257 
mtk_disp_mutex_remove_comp(struct mtk_disp_mutex * mutex,enum mtk_ddp_comp_id id)258 void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex *mutex,
259 				enum mtk_ddp_comp_id id)
260 {
261 	struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
262 					   mutex[mutex->id]);
263 	unsigned int reg;
264 
265 	WARN_ON(&ddp->mutex[mutex->id] != mutex);
266 
267 	switch (id) {
268 	case DDP_COMPONENT_DSI0:
269 	case DDP_COMPONENT_DSI1:
270 	case DDP_COMPONENT_DPI0:
271 		writel_relaxed(MUTEX_SOF_SINGLE_MODE,
272 			       ddp->regs + DISP_REG_MUTEX_SOF(mutex->id));
273 		break;
274 	default:
275 		reg = readl_relaxed(ddp->regs + DISP_REG_MUTEX_MOD(mutex->id));
276 		reg &= ~mutex_mod[id];
277 		writel_relaxed(reg, ddp->regs + DISP_REG_MUTEX_MOD(mutex->id));
278 		break;
279 	}
280 }
281 
mtk_disp_mutex_enable(struct mtk_disp_mutex * mutex)282 void mtk_disp_mutex_enable(struct mtk_disp_mutex *mutex)
283 {
284 	struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
285 					   mutex[mutex->id]);
286 
287 	WARN_ON(&ddp->mutex[mutex->id] != mutex);
288 
289 	writel(1, ddp->regs + DISP_REG_MUTEX_EN(mutex->id));
290 }
291 
mtk_disp_mutex_disable(struct mtk_disp_mutex * mutex)292 void mtk_disp_mutex_disable(struct mtk_disp_mutex *mutex)
293 {
294 	struct mtk_ddp *ddp = container_of(mutex, struct mtk_ddp,
295 					   mutex[mutex->id]);
296 
297 	WARN_ON(&ddp->mutex[mutex->id] != mutex);
298 
299 	writel(0, ddp->regs + DISP_REG_MUTEX_EN(mutex->id));
300 }
301 
mtk_ddp_probe(struct platform_device * pdev)302 static int mtk_ddp_probe(struct platform_device *pdev)
303 {
304 	struct device *dev = &pdev->dev;
305 	struct mtk_ddp *ddp;
306 	struct resource *regs;
307 	int i;
308 
309 	ddp = devm_kzalloc(dev, sizeof(*ddp), GFP_KERNEL);
310 	if (!ddp)
311 		return -ENOMEM;
312 
313 	for (i = 0; i < 10; i++)
314 		ddp->mutex[i].id = i;
315 
316 	ddp->clk = devm_clk_get(dev, NULL);
317 	if (IS_ERR(ddp->clk)) {
318 		dev_err(dev, "Failed to get clock\n");
319 		return PTR_ERR(ddp->clk);
320 	}
321 
322 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
323 	ddp->regs = devm_ioremap_resource(dev, regs);
324 	if (IS_ERR(ddp->regs)) {
325 		dev_err(dev, "Failed to map mutex registers\n");
326 		return PTR_ERR(ddp->regs);
327 	}
328 
329 	platform_set_drvdata(pdev, ddp);
330 
331 	return 0;
332 }
333 
mtk_ddp_remove(struct platform_device * pdev)334 static int mtk_ddp_remove(struct platform_device *pdev)
335 {
336 	return 0;
337 }
338 
339 static const struct of_device_id ddp_driver_dt_match[] = {
340 	{ .compatible = "mediatek,mt8173-disp-mutex" },
341 	{},
342 };
343 MODULE_DEVICE_TABLE(of, ddp_driver_dt_match);
344 
345 struct platform_driver mtk_ddp_driver = {
346 	.probe		= mtk_ddp_probe,
347 	.remove		= mtk_ddp_remove,
348 	.driver		= {
349 		.name	= "mediatek-ddp",
350 		.owner	= THIS_MODULE,
351 		.of_match_table = ddp_driver_dt_match,
352 	},
353 };
354