Commit | Line | Data |
---|---|---|
119f5173 CH |
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | }; |