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/module.h>
16 #include <linux/of_device.h>
17 #include <linux/platform_device.h>
18 #include <linux/regmap.h>
20 #include "mtk_drm_ddp.h"
21 #include "mtk_drm_ddp_comp.h"
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
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))
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)
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
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
70 struct mtk_disp_mutex
{
79 struct mtk_disp_mutex mutex
[10];
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
,
100 static unsigned int mtk_ddp_mout_en(enum mtk_ddp_comp_id cur
,
101 enum mtk_ddp_comp_id next
,
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
;
131 static unsigned int mtk_ddp_sel_in(enum mtk_ddp_comp_id cur
,
132 enum mtk_ddp_comp_id next
,
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
;
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
)
157 unsigned int addr
, value
, reg
;
159 value
= mtk_ddp_mout_en(cur
, next
, &addr
);
161 reg
= readl_relaxed(config_regs
+ addr
) | value
;
162 writel_relaxed(reg
, config_regs
+ addr
);
165 value
= mtk_ddp_sel_in(cur
, next
, &addr
);
167 reg
= readl_relaxed(config_regs
+ addr
) | value
;
168 writel_relaxed(reg
, config_regs
+ addr
);
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
)
176 unsigned int addr
, value
, reg
;
178 value
= mtk_ddp_mout_en(cur
, next
, &addr
);
180 reg
= readl_relaxed(config_regs
+ addr
) & ~value
;
181 writel_relaxed(reg
, config_regs
+ addr
);
184 value
= mtk_ddp_sel_in(cur
, next
, &addr
);
186 reg
= readl_relaxed(config_regs
+ addr
) & ~value
;
187 writel_relaxed(reg
, config_regs
+ addr
);
191 struct mtk_disp_mutex
*mtk_disp_mutex_get(struct device
*dev
, unsigned int id
)
193 struct mtk_ddp
*ddp
= dev_get_drvdata(dev
);
196 return ERR_PTR(-EINVAL
);
197 if (ddp
->mutex
[id
].claimed
)
198 return ERR_PTR(-EBUSY
);
200 ddp
->mutex
[id
].claimed
= true;
202 return &ddp
->mutex
[id
];
205 void mtk_disp_mutex_put(struct mtk_disp_mutex
*mutex
)
207 struct mtk_ddp
*ddp
= container_of(mutex
, struct mtk_ddp
,
210 WARN_ON(&ddp
->mutex
[mutex
->id
] != mutex
);
212 mutex
->claimed
= false;
215 int mtk_disp_mutex_prepare(struct mtk_disp_mutex
*mutex
)
217 struct mtk_ddp
*ddp
= container_of(mutex
, struct mtk_ddp
,
219 return clk_prepare_enable(ddp
->clk
);
222 void mtk_disp_mutex_unprepare(struct mtk_disp_mutex
*mutex
)
224 struct mtk_ddp
*ddp
= container_of(mutex
, struct mtk_ddp
,
226 clk_disable_unprepare(ddp
->clk
);
229 void mtk_disp_mutex_add_comp(struct mtk_disp_mutex
*mutex
,
230 enum mtk_ddp_comp_id id
)
232 struct mtk_ddp
*ddp
= container_of(mutex
, struct mtk_ddp
,
236 WARN_ON(&ddp
->mutex
[mutex
->id
] != mutex
);
239 case DDP_COMPONENT_DSI0
:
240 reg
= MUTEX_SOF_DSI0
;
242 case DDP_COMPONENT_DSI1
:
243 reg
= MUTEX_SOF_DSI0
;
245 case DDP_COMPONENT_DPI0
:
246 reg
= MUTEX_SOF_DPI0
;
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
));
255 writel_relaxed(reg
, ddp
->regs
+ DISP_REG_MUTEX_SOF(mutex
->id
));
258 void mtk_disp_mutex_remove_comp(struct mtk_disp_mutex
*mutex
,
259 enum mtk_ddp_comp_id id
)
261 struct mtk_ddp
*ddp
= container_of(mutex
, struct mtk_ddp
,
265 WARN_ON(&ddp
->mutex
[mutex
->id
] != mutex
);
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
));
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
));
282 void mtk_disp_mutex_enable(struct mtk_disp_mutex
*mutex
)
284 struct mtk_ddp
*ddp
= container_of(mutex
, struct mtk_ddp
,
287 WARN_ON(&ddp
->mutex
[mutex
->id
] != mutex
);
289 writel(1, ddp
->regs
+ DISP_REG_MUTEX_EN(mutex
->id
));
292 void mtk_disp_mutex_disable(struct mtk_disp_mutex
*mutex
)
294 struct mtk_ddp
*ddp
= container_of(mutex
, struct mtk_ddp
,
297 WARN_ON(&ddp
->mutex
[mutex
->id
] != mutex
);
299 writel(0, ddp
->regs
+ DISP_REG_MUTEX_EN(mutex
->id
));
302 static int mtk_ddp_probe(struct platform_device
*pdev
)
304 struct device
*dev
= &pdev
->dev
;
306 struct resource
*regs
;
309 ddp
= devm_kzalloc(dev
, sizeof(*ddp
), GFP_KERNEL
);
313 for (i
= 0; i
< 10; i
++)
314 ddp
->mutex
[i
].id
= i
;
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
);
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
);
329 platform_set_drvdata(pdev
, ddp
);
334 static int mtk_ddp_remove(struct platform_device
*pdev
)
339 static const struct of_device_id ddp_driver_dt_match
[] = {
340 { .compatible
= "mediatek,mt8173-disp-mutex" },
343 MODULE_DEVICE_TABLE(of
, ddp_driver_dt_match
);
345 struct platform_driver mtk_ddp_driver
= {
346 .probe
= mtk_ddp_probe
,
347 .remove
= mtk_ddp_remove
,
349 .name
= "mediatek-ddp",
350 .owner
= THIS_MODULE
,
351 .of_match_table
= ddp_driver_dt_match
,