2 * Copyright (c) 2015 MediaTek Inc.
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.
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.
14 #include <linux/clk.h>
15 #include <linux/iopoll.h>
16 #include <linux/module.h>
17 #include <linux/of_device.h>
18 #include <linux/platform_device.h>
19 #include <linux/regmap.h>
21 #include "mtk_drm_ddp.h"
22 #include "mtk_drm_ddp_comp.h"
24 #define DISP_REG_CONFIG_DISP_OVL0_MOUT_EN 0x040
25 #define DISP_REG_CONFIG_DISP_OVL1_MOUT_EN 0x044
26 #define DISP_REG_CONFIG_DISP_OD_MOUT_EN 0x048
27 #define DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN 0x04c
28 #define DISP_REG_CONFIG_DISP_UFOE_MOUT_EN 0x050
29 #define DISP_REG_CONFIG_DISP_COLOR0_SEL_IN 0x084
30 #define DISP_REG_CONFIG_DISP_COLOR1_SEL_IN 0x088
31 #define DISP_REG_CONFIG_DPI_SEL_IN 0x0ac
32 #define DISP_REG_CONFIG_DISP_RDMA1_MOUT_EN 0x0c8
33 #define DISP_REG_CONFIG_MMSYS_CG_CON0 0x100
35 #define DISP_REG_CONFIG_DISP_OVL_MOUT_EN 0x030
36 #define DISP_REG_CONFIG_OUT_SEL 0x04c
37 #define DISP_REG_CONFIG_DSI_SEL 0x050
39 #define DISP_REG_MUTEX_EN(n) (0x20 + 0x20 * (n))
40 #define DISP_REG_MUTEX(n) (0x24 + 0x20 * (n))
41 #define DISP_REG_MUTEX_RST(n) (0x28 + 0x20 * (n))
42 #define DISP_REG_MUTEX_MOD(n) (0x2c + 0x20 * (n))
43 #define DISP_REG_MUTEX_SOF(n) (0x30 + 0x20 * (n))
45 #define INT_MUTEX BIT(1)
47 #define MT8173_MUTEX_MOD_DISP_OVL0 BIT(11)
48 #define MT8173_MUTEX_MOD_DISP_OVL1 BIT(12)
49 #define MT8173_MUTEX_MOD_DISP_RDMA0 BIT(13)
50 #define MT8173_MUTEX_MOD_DISP_RDMA1 BIT(14)
51 #define MT8173_MUTEX_MOD_DISP_RDMA2 BIT(15)
52 #define MT8173_MUTEX_MOD_DISP_WDMA0 BIT(16)
53 #define MT8173_MUTEX_MOD_DISP_WDMA1 BIT(17)
54 #define MT8173_MUTEX_MOD_DISP_COLOR0 BIT(18)
55 #define MT8173_MUTEX_MOD_DISP_COLOR1 BIT(19)
56 #define MT8173_MUTEX_MOD_DISP_AAL BIT(20)
57 #define MT8173_MUTEX_MOD_DISP_GAMMA BIT(21)
58 #define MT8173_MUTEX_MOD_DISP_UFOE BIT(22)
59 #define MT8173_MUTEX_MOD_DISP_PWM0 BIT(23)
60 #define MT8173_MUTEX_MOD_DISP_PWM1 BIT(24)
61 #define MT8173_MUTEX_MOD_DISP_OD BIT(25)
63 #define MT2701_MUTEX_MOD_DISP_OVL BIT(3)
64 #define MT2701_MUTEX_MOD_DISP_WDMA BIT(6)
65 #define MT2701_MUTEX_MOD_DISP_COLOR BIT(7)
66 #define MT2701_MUTEX_MOD_DISP_BLS BIT(9)
67 #define MT2701_MUTEX_MOD_DISP_RDMA0 BIT(10)
68 #define MT2701_MUTEX_MOD_DISP_RDMA1 BIT(12)
70 #define MUTEX_SOF_SINGLE_MODE 0
71 #define MUTEX_SOF_DSI0 1
72 #define MUTEX_SOF_DSI1 2
73 #define MUTEX_SOF_DPI0 3
75 #define OVL0_MOUT_EN_COLOR0 0x1
76 #define OD_MOUT_EN_RDMA0 0x1
77 #define UFOE_MOUT_EN_DSI0 0x1
78 #define COLOR0_SEL_IN_OVL0 0x1
79 #define OVL1_MOUT_EN_COLOR1 0x1
80 #define GAMMA_MOUT_EN_RDMA1 0x1
81 #define RDMA1_MOUT_DPI0 0x2
82 #define DPI0_SEL_IN_RDMA1 0x1
83 #define COLOR1_SEL_IN_OVL1 0x1
85 #define OVL_MOUT_EN_RDMA 0x1
86 #define BLS_TO_DSI_RDMA1_TO_DPI1 0x8
87 #define DSI_SEL_IN_BLS 0x0
89 struct mtk_disp_mutex
{
98 struct mtk_disp_mutex mutex
[10];
99 const unsigned int *mutex_mod
;
102 static const unsigned int mt2701_mutex_mod
[DDP_COMPONENT_ID_MAX
] = {
103 [DDP_COMPONENT_BLS
] = MT2701_MUTEX_MOD_DISP_BLS
,
104 [DDP_COMPONENT_COLOR0
] = MT2701_MUTEX_MOD_DISP_COLOR
,
105 [DDP_COMPONENT_OVL0
] = MT2701_MUTEX_MOD_DISP_OVL
,
106 [DDP_COMPONENT_RDMA0
] = MT2701_MUTEX_MOD_DISP_RDMA0
,
107 [DDP_COMPONENT_RDMA1
] = MT2701_MUTEX_MOD_DISP_RDMA1
,
108 [DDP_COMPONENT_WDMA0
] = MT2701_MUTEX_MOD_DISP_WDMA
,
111 static const unsigned int mt8173_mutex_mod
[DDP_COMPONENT_ID_MAX
] = {
112 [DDP_COMPONENT_AAL
] = MT8173_MUTEX_MOD_DISP_AAL
,
113 [DDP_COMPONENT_COLOR0
] = MT8173_MUTEX_MOD_DISP_COLOR0
,
114 [DDP_COMPONENT_COLOR1
] = MT8173_MUTEX_MOD_DISP_COLOR1
,
115 [DDP_COMPONENT_GAMMA
] = MT8173_MUTEX_MOD_DISP_GAMMA
,
116 [DDP_COMPONENT_OD
] = MT8173_MUTEX_MOD_DISP_OD
,
117 [DDP_COMPONENT_OVL0
] = MT8173_MUTEX_MOD_DISP_OVL0
,
118 [DDP_COMPONENT_OVL1
] = MT8173_MUTEX_MOD_DISP_OVL1
,
119 [DDP_COMPONENT_PWM0
] = MT8173_MUTEX_MOD_DISP_PWM0
,
120 [DDP_COMPONENT_PWM1
] = MT8173_MUTEX_MOD_DISP_PWM1
,
121 [DDP_COMPONENT_RDMA0
] = MT8173_MUTEX_MOD_DISP_RDMA0
,
122 [DDP_COMPONENT_RDMA1
] = MT8173_MUTEX_MOD_DISP_RDMA1
,
123 [DDP_COMPONENT_RDMA2
] = MT8173_MUTEX_MOD_DISP_RDMA2
,
124 [DDP_COMPONENT_UFOE
] = MT8173_MUTEX_MOD_DISP_UFOE
,
125 [DDP_COMPONENT_WDMA0
] = MT8173_MUTEX_MOD_DISP_WDMA0
,
126 [DDP_COMPONENT_WDMA1
] = MT8173_MUTEX_MOD_DISP_WDMA1
,
129 static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur
,
130 enum mtk_ddp_comp_id next
,
135 if (cur
== DDP_COMPONENT_OVL0
&& next
== DDP_COMPONENT_COLOR0
) {
136 *addr
= DISP_REG_CONFIG_DISP_OVL0_MOUT_EN
;
137 value
= OVL0_MOUT_EN_COLOR0
;
138 } else if (cur
== DDP_COMPONENT_OVL0
&& next
== DDP_COMPONENT_RDMA0
) {
139 *addr
= DISP_REG_CONFIG_DISP_OVL_MOUT_EN
;
140 value
= OVL_MOUT_EN_RDMA
;
141 } else if (cur
== DDP_COMPONENT_OD
&& next
== DDP_COMPONENT_RDMA0
) {
142 *addr
= DISP_REG_CONFIG_DISP_OD_MOUT_EN
;
143 value
= OD_MOUT_EN_RDMA0
;
144 } else if (cur
== DDP_COMPONENT_UFOE
&& next
== DDP_COMPONENT_DSI0
) {
145 *addr
= DISP_REG_CONFIG_DISP_UFOE_MOUT_EN
;
146 value
= UFOE_MOUT_EN_DSI0
;
147 } else if (cur
== DDP_COMPONENT_OVL1
&& next
== DDP_COMPONENT_COLOR1
) {
148 *addr
= DISP_REG_CONFIG_DISP_OVL1_MOUT_EN
;
149 value
= OVL1_MOUT_EN_COLOR1
;
150 } else if (cur
== DDP_COMPONENT_GAMMA
&& next
== DDP_COMPONENT_RDMA1
) {
151 *addr
= DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN
;
152 value
= GAMMA_MOUT_EN_RDMA1
;
153 } else if (cur
== DDP_COMPONENT_RDMA1
&& next
== DDP_COMPONENT_DPI0
) {
154 *addr
= DISP_REG_CONFIG_DISP_RDMA1_MOUT_EN
;
155 value
= RDMA1_MOUT_DPI0
;
163 static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur
,
164 enum mtk_ddp_comp_id next
,
169 if (cur
== DDP_COMPONENT_OVL0
&& next
== DDP_COMPONENT_COLOR0
) {
170 *addr
= DISP_REG_CONFIG_DISP_COLOR0_SEL_IN
;
171 value
= COLOR0_SEL_IN_OVL0
;
172 } else if (cur
== DDP_COMPONENT_RDMA1
&& next
== DDP_COMPONENT_DPI0
) {
173 *addr
= DISP_REG_CONFIG_DPI_SEL_IN
;
174 value
= DPI0_SEL_IN_RDMA1
;
175 } else if (cur
== DDP_COMPONENT_OVL1
&& next
== DDP_COMPONENT_COLOR1
) {
176 *addr
= DISP_REG_CONFIG_DISP_COLOR1_SEL_IN
;
177 value
= COLOR1_SEL_IN_OVL1
;
178 } else if (cur
== DDP_COMPONENT_BLS
&& next
== DDP_COMPONENT_DSI0
) {
179 *addr
= DISP_REG_CONFIG_DSI_SEL
;
180 value
= DSI_SEL_IN_BLS
;
188 static void mtk_ddp_sout_sel(void __iomem
*config_regs
,
189 enum mtk_ddp_comp_id cur
,
190 enum mtk_ddp_comp_id next
)
192 if (cur
== DDP_COMPONENT_BLS
&& next
== DDP_COMPONENT_DSI0
)
193 writel_relaxed(BLS_TO_DSI_RDMA1_TO_DPI1
,
194 config_regs
+ DISP_REG_CONFIG_OUT_SEL
);
197 void mtk_ddp_add_comp_to_path(void __iomem
*config_regs
,
198 enum mtk_ddp_comp_id cur
,
199 enum mtk_ddp_comp_id next
)
201 unsigned int addr
, value
, reg
;
203 value
= mtk_ddp_mout_en(cur
, next
, &addr
);
205 reg
= readl_relaxed(config_regs
+ addr
) | value
;
206 writel_relaxed(reg
, config_regs
+ addr
);
209 mtk_ddp_sout_sel(config_regs
, cur
, next
);
211 value
= mtk_ddp_sel_in(cur
, next
, &addr
);
213 reg
= readl_relaxed(config_regs
+ addr
) | value
;
214 writel_relaxed(reg
, config_regs
+ addr
);
218 void mtk_ddp_remove_comp_from_path(void __iomem
*config_regs
,
219 enum mtk_ddp_comp_id cur
,
220 enum mtk_ddp_comp_id next
)
222 unsigned int addr
, value
, reg
;
224 value
= mtk_ddp_mout_en(cur
, next
, &addr
);
226 reg
= readl_relaxed(config_regs
+ addr
) & ~value
;
227 writel_relaxed(reg
, config_regs
+ addr
);
230 value
= mtk_ddp_sel_in(cur
, next
, &addr
);
232 reg
= readl_relaxed(config_regs
+ addr
) & ~value
;
233 writel_relaxed(reg
, config_regs
+ addr
);
237 struct mtk_disp_mutex
*mtk_disp_mutex_get(struct device
*dev
, unsigned int id
)
239 struct mtk_ddp
*ddp
= dev_get_drvdata(dev
);
242 return ERR_PTR(-EINVAL
);
243 if (ddp
->mutex
[id
].claimed
)
244 return ERR_PTR(-EBUSY
);
246 ddp
->mutex
[id
].claimed
= true;
248 return &ddp
->mutex
[id
];
251 void mtk_disp_mutex_put(struct mtk_disp_mutex
*mutex
)
253 struct mtk_ddp
*ddp
= container_of(mutex
, struct mtk_ddp
,
256 WARN_ON(&ddp
->mutex
[mutex
->id
] != mutex
);
258 mutex
->claimed
= false;
261 int mtk_disp_mutex_prepare(struct mtk_disp_mutex
*mutex
)
263 struct mtk_ddp
*ddp
= container_of(mutex
, struct mtk_ddp
,
265 return clk_prepare_enable(ddp
->clk
);
268 void mtk_disp_mutex_unprepare(struct mtk_disp_mutex
*mutex
)
270 struct mtk_ddp
*ddp
= container_of(mutex
, struct mtk_ddp
,
272 clk_disable_unprepare(ddp
->clk
);
275 void mtk_disp_mutex_add_comp(struct mtk_disp_mutex
*mutex
,
276 enum mtk_ddp_comp_id id
)
278 struct mtk_ddp
*ddp
= container_of(mutex
, struct mtk_ddp
,
282 WARN_ON(&ddp
->mutex
[mutex
->id
] != mutex
);
285 case DDP_COMPONENT_DSI0
:
286 reg
= MUTEX_SOF_DSI0
;
288 case DDP_COMPONENT_DSI1
:
289 reg
= MUTEX_SOF_DSI0
;
291 case DDP_COMPONENT_DPI0
:
292 reg
= MUTEX_SOF_DPI0
;
295 reg
= readl_relaxed(ddp
->regs
+ DISP_REG_MUTEX_MOD(mutex
->id
));
296 reg
|= ddp
->mutex_mod
[id
];
297 writel_relaxed(reg
, ddp
->regs
+ DISP_REG_MUTEX_MOD(mutex
->id
));
301 writel_relaxed(reg
, ddp
->regs
+ DISP_REG_MUTEX_SOF(mutex
->id
));
304 void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex
*mutex
,
305 enum mtk_ddp_comp_id id
)
307 struct mtk_ddp
*ddp
= container_of(mutex
, struct mtk_ddp
,
311 WARN_ON(&ddp
->mutex
[mutex
->id
] != mutex
);
314 case DDP_COMPONENT_DSI0
:
315 case DDP_COMPONENT_DSI1
:
316 case DDP_COMPONENT_DPI0
:
317 writel_relaxed(MUTEX_SOF_SINGLE_MODE
,
318 ddp
->regs
+ DISP_REG_MUTEX_SOF(mutex
->id
));
321 reg
= readl_relaxed(ddp
->regs
+ DISP_REG_MUTEX_MOD(mutex
->id
));
322 reg
&= ~(ddp
->mutex_mod
[id
]);
323 writel_relaxed(reg
, ddp
->regs
+ DISP_REG_MUTEX_MOD(mutex
->id
));
328 void mtk_disp_mutex_enable(struct mtk_disp_mutex
*mutex
)
330 struct mtk_ddp
*ddp
= container_of(mutex
, struct mtk_ddp
,
333 WARN_ON(&ddp
->mutex
[mutex
->id
] != mutex
);
335 writel(1, ddp
->regs
+ DISP_REG_MUTEX_EN(mutex
->id
));
338 void mtk_disp_mutex_disable(struct mtk_disp_mutex
*mutex
)
340 struct mtk_ddp
*ddp
= container_of(mutex
, struct mtk_ddp
,
343 WARN_ON(&ddp
->mutex
[mutex
->id
] != mutex
);
345 writel(0, ddp
->regs
+ DISP_REG_MUTEX_EN(mutex
->id
));
348 void mtk_disp_mutex_acquire(struct mtk_disp_mutex
*mutex
)
350 struct mtk_ddp
*ddp
= container_of(mutex
, struct mtk_ddp
,
354 writel(1, ddp
->regs
+ DISP_REG_MUTEX_EN(mutex
->id
));
355 writel(1, ddp
->regs
+ DISP_REG_MUTEX(mutex
->id
));
356 if (readl_poll_timeout_atomic(ddp
->regs
+ DISP_REG_MUTEX(mutex
->id
),
357 tmp
, tmp
& INT_MUTEX
, 1, 10000))
358 pr_err("could not acquire mutex %d\n", mutex
->id
);
361 void mtk_disp_mutex_release(struct mtk_disp_mutex
*mutex
)
363 struct mtk_ddp
*ddp
= container_of(mutex
, struct mtk_ddp
,
366 writel(0, ddp
->regs
+ DISP_REG_MUTEX(mutex
->id
));
369 static int mtk_ddp_probe(struct platform_device
*pdev
)
371 struct device
*dev
= &pdev
->dev
;
373 struct resource
*regs
;
376 ddp
= devm_kzalloc(dev
, sizeof(*ddp
), GFP_KERNEL
);
380 for (i
= 0; i
< 10; i
++)
381 ddp
->mutex
[i
].id
= i
;
383 ddp
->clk
= devm_clk_get(dev
, NULL
);
384 if (IS_ERR(ddp
->clk
)) {
385 dev_err(dev
, "Failed to get clock\n");
386 return PTR_ERR(ddp
->clk
);
389 regs
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
390 ddp
->regs
= devm_ioremap_resource(dev
, regs
);
391 if (IS_ERR(ddp
->regs
)) {
392 dev_err(dev
, "Failed to map mutex registers\n");
393 return PTR_ERR(ddp
->regs
);
396 ddp
->mutex_mod
= of_device_get_match_data(dev
);
398 platform_set_drvdata(pdev
, ddp
);
403 static int mtk_ddp_remove(struct platform_device
*pdev
)
408 static const struct of_device_id ddp_driver_dt_match
[] = {
409 { .compatible
= "mediatek,mt2701-disp-mutex", .data
= mt2701_mutex_mod
},
410 { .compatible
= "mediatek,mt8173-disp-mutex", .data
= mt8173_mutex_mod
},
413 MODULE_DEVICE_TABLE(of
, ddp_driver_dt_match
);
415 struct platform_driver mtk_ddp_driver
= {
416 .probe
= mtk_ddp_probe
,
417 .remove
= mtk_ddp_remove
,
419 .name
= "mediatek-ddp",
420 .owner
= THIS_MODULE
,
421 .of_match_table
= ddp_driver_dt_match
,