2 * Copyright (c) 2015 MediaTek Inc.
4 * YT Shen <yt.shen@mediatek.com>
5 * CK Hu <ck.hu@mediatek.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
17 #include <linux/clk.h>
19 #include <linux/of_address.h>
20 #include <linux/of_irq.h>
21 #include <linux/of_platform.h>
22 #include <linux/platform_device.h>
24 #include "mtk_drm_drv.h"
25 #include "mtk_drm_plane.h"
26 #include "mtk_drm_ddp_comp.h"
27 #include "mtk_drm_crtc.h"
29 #define DISP_OD_EN 0x0000
30 #define DISP_OD_INTEN 0x0008
31 #define DISP_OD_INTSTA 0x000c
32 #define DISP_OD_CFG 0x0020
33 #define DISP_OD_SIZE 0x0030
35 #define DISP_REG_UFO_START 0x0000
37 #define DISP_COLOR_CFG_MAIN 0x0400
38 #define DISP_COLOR_START 0x0c00
39 #define DISP_COLOR_WIDTH 0x0c50
40 #define DISP_COLOR_HEIGHT 0x0c54
42 #define DISP_AAL_EN 0x0000
43 #define DISP_AAL_SIZE 0x0030
45 #define DISP_GAMMA_EN 0x0000
46 #define DISP_GAMMA_CFG 0x0020
47 #define DISP_GAMMA_SIZE 0x0030
48 #define DISP_GAMMA_LUT 0x0700
50 #define LUT_10BIT_MASK 0x03ff
52 #define OD_RELAY_MODE BIT(0)
54 #define UFO_BYPASS BIT(2)
56 #define COLOR_BYPASS_ALL BIT(7)
57 #define COLOR_SEQ_SEL BIT(13)
61 #define GAMMA_EN BIT(0)
62 #define GAMMA_LUT_EN BIT(1)
64 static void mtk_color_config(struct mtk_ddp_comp
*comp
, unsigned int w
,
65 unsigned int h
, unsigned int vrefresh
)
67 writel(w
, comp
->regs
+ DISP_COLOR_WIDTH
);
68 writel(h
, comp
->regs
+ DISP_COLOR_HEIGHT
);
71 static void mtk_color_start(struct mtk_ddp_comp
*comp
)
73 writel(COLOR_BYPASS_ALL
| COLOR_SEQ_SEL
,
74 comp
->regs
+ DISP_COLOR_CFG_MAIN
);
75 writel(0x1, comp
->regs
+ DISP_COLOR_START
);
78 static void mtk_od_config(struct mtk_ddp_comp
*comp
, unsigned int w
,
79 unsigned int h
, unsigned int vrefresh
)
81 writel(w
<< 16 | h
, comp
->regs
+ DISP_OD_SIZE
);
84 static void mtk_od_start(struct mtk_ddp_comp
*comp
)
86 writel(OD_RELAY_MODE
, comp
->regs
+ DISP_OD_CFG
);
87 writel(1, comp
->regs
+ DISP_OD_EN
);
90 static void mtk_ufoe_start(struct mtk_ddp_comp
*comp
)
92 writel(UFO_BYPASS
, comp
->regs
+ DISP_REG_UFO_START
);
95 static void mtk_aal_config(struct mtk_ddp_comp
*comp
, unsigned int w
,
96 unsigned int h
, unsigned int vrefresh
)
98 writel(h
<< 16 | w
, comp
->regs
+ DISP_AAL_SIZE
);
101 static void mtk_aal_start(struct mtk_ddp_comp
*comp
)
103 writel(AAL_EN
, comp
->regs
+ DISP_AAL_EN
);
106 static void mtk_aal_stop(struct mtk_ddp_comp
*comp
)
108 writel_relaxed(0x0, comp
->regs
+ DISP_AAL_EN
);
111 static void mtk_gamma_config(struct mtk_ddp_comp
*comp
, unsigned int w
,
112 unsigned int h
, unsigned int vrefresh
)
114 writel(h
<< 16 | w
, comp
->regs
+ DISP_GAMMA_SIZE
);
117 static void mtk_gamma_start(struct mtk_ddp_comp
*comp
)
119 writel(GAMMA_EN
, comp
->regs
+ DISP_GAMMA_EN
);
122 static void mtk_gamma_stop(struct mtk_ddp_comp
*comp
)
124 writel_relaxed(0x0, comp
->regs
+ DISP_GAMMA_EN
);
127 static void mtk_gamma_set(struct mtk_ddp_comp
*comp
,
128 struct drm_crtc_state
*state
)
131 struct drm_color_lut
*lut
;
132 void __iomem
*lut_base
;
135 if (state
->gamma_lut
) {
136 reg
= readl(comp
->regs
+ DISP_GAMMA_CFG
);
137 reg
= reg
| GAMMA_LUT_EN
;
138 writel(reg
, comp
->regs
+ DISP_GAMMA_CFG
);
139 lut_base
= comp
->regs
+ DISP_GAMMA_LUT
;
140 lut
= (struct drm_color_lut
*)state
->gamma_lut
->data
;
141 for (i
= 0; i
< MTK_LUT_SIZE
; i
++) {
142 word
= (((lut
[i
].red
>> 6) & LUT_10BIT_MASK
) << 20) +
143 (((lut
[i
].green
>> 6) & LUT_10BIT_MASK
) << 10) +
144 ((lut
[i
].blue
>> 6) & LUT_10BIT_MASK
);
145 writel(word
, (lut_base
+ i
* 4));
150 static const struct mtk_ddp_comp_funcs ddp_aal
= {
151 .gamma_set
= mtk_gamma_set
,
152 .config
= mtk_aal_config
,
153 .start
= mtk_aal_start
,
154 .stop
= mtk_aal_stop
,
157 static const struct mtk_ddp_comp_funcs ddp_gamma
= {
158 .gamma_set
= mtk_gamma_set
,
159 .config
= mtk_gamma_config
,
160 .start
= mtk_gamma_start
,
161 .stop
= mtk_gamma_stop
,
164 static const struct mtk_ddp_comp_funcs ddp_color
= {
165 .config
= mtk_color_config
,
166 .start
= mtk_color_start
,
169 static const struct mtk_ddp_comp_funcs ddp_od
= {
170 .config
= mtk_od_config
,
171 .start
= mtk_od_start
,
174 static const struct mtk_ddp_comp_funcs ddp_ufoe
= {
175 .start
= mtk_ufoe_start
,
178 static const char * const mtk_ddp_comp_stem
[MTK_DDP_COMP_TYPE_MAX
] = {
179 [MTK_DISP_OVL
] = "ovl",
180 [MTK_DISP_RDMA
] = "rdma",
181 [MTK_DISP_WDMA
] = "wdma",
182 [MTK_DISP_COLOR
] = "color",
183 [MTK_DISP_AAL
] = "aal",
184 [MTK_DISP_GAMMA
] = "gamma",
185 [MTK_DISP_UFOE
] = "ufoe",
188 [MTK_DISP_PWM
] = "pwm",
189 [MTK_DISP_MUTEX
] = "mutex",
190 [MTK_DISP_OD
] = "od",
193 struct mtk_ddp_comp_match
{
194 enum mtk_ddp_comp_type type
;
196 const struct mtk_ddp_comp_funcs
*funcs
;
199 static const struct mtk_ddp_comp_match mtk_ddp_matches
[DDP_COMPONENT_ID_MAX
] = {
200 [DDP_COMPONENT_AAL
] = { MTK_DISP_AAL
, 0, &ddp_aal
},
201 [DDP_COMPONENT_COLOR0
] = { MTK_DISP_COLOR
, 0, &ddp_color
},
202 [DDP_COMPONENT_COLOR1
] = { MTK_DISP_COLOR
, 1, &ddp_color
},
203 [DDP_COMPONENT_DPI0
] = { MTK_DPI
, 0, NULL
},
204 [DDP_COMPONENT_DSI0
] = { MTK_DSI
, 0, NULL
},
205 [DDP_COMPONENT_DSI1
] = { MTK_DSI
, 1, NULL
},
206 [DDP_COMPONENT_GAMMA
] = { MTK_DISP_GAMMA
, 0, &ddp_gamma
},
207 [DDP_COMPONENT_OD
] = { MTK_DISP_OD
, 0, &ddp_od
},
208 [DDP_COMPONENT_OVL0
] = { MTK_DISP_OVL
, 0, NULL
},
209 [DDP_COMPONENT_OVL1
] = { MTK_DISP_OVL
, 1, NULL
},
210 [DDP_COMPONENT_PWM0
] = { MTK_DISP_PWM
, 0, NULL
},
211 [DDP_COMPONENT_RDMA0
] = { MTK_DISP_RDMA
, 0, NULL
},
212 [DDP_COMPONENT_RDMA1
] = { MTK_DISP_RDMA
, 1, NULL
},
213 [DDP_COMPONENT_RDMA2
] = { MTK_DISP_RDMA
, 2, NULL
},
214 [DDP_COMPONENT_UFOE
] = { MTK_DISP_UFOE
, 0, &ddp_ufoe
},
215 [DDP_COMPONENT_WDMA0
] = { MTK_DISP_WDMA
, 0, NULL
},
216 [DDP_COMPONENT_WDMA1
] = { MTK_DISP_WDMA
, 1, NULL
},
219 int mtk_ddp_comp_get_id(struct device_node
*node
,
220 enum mtk_ddp_comp_type comp_type
)
222 int id
= of_alias_get_id(node
, mtk_ddp_comp_stem
[comp_type
]);
225 for (i
= 0; i
< ARRAY_SIZE(mtk_ddp_matches
); i
++) {
226 if (comp_type
== mtk_ddp_matches
[i
].type
&&
227 (id
< 0 || id
== mtk_ddp_matches
[i
].alias_id
))
234 int mtk_ddp_comp_init(struct device
*dev
, struct device_node
*node
,
235 struct mtk_ddp_comp
*comp
, enum mtk_ddp_comp_id comp_id
,
236 const struct mtk_ddp_comp_funcs
*funcs
)
238 enum mtk_ddp_comp_type type
;
239 struct device_node
*larb_node
;
240 struct platform_device
*larb_pdev
;
242 if (comp_id
< 0 || comp_id
>= DDP_COMPONENT_ID_MAX
)
246 comp
->funcs
= funcs
?: mtk_ddp_matches
[comp_id
].funcs
;
248 if (comp_id
== DDP_COMPONENT_DPI0
||
249 comp_id
== DDP_COMPONENT_DSI0
||
250 comp_id
== DDP_COMPONENT_PWM0
) {
257 comp
->regs
= of_iomap(node
, 0);
258 comp
->irq
= of_irq_get(node
, 0);
259 comp
->clk
= of_clk_get(node
, 0);
260 if (IS_ERR(comp
->clk
))
263 type
= mtk_ddp_matches
[comp_id
].type
;
265 /* Only DMA capable components need the LARB property */
266 comp
->larb_dev
= NULL
;
267 if (type
!= MTK_DISP_OVL
&&
268 type
!= MTK_DISP_RDMA
&&
269 type
!= MTK_DISP_WDMA
)
272 larb_node
= of_parse_phandle(node
, "mediatek,larb", 0);
275 "Missing mediadek,larb phandle in %s node\n",
280 larb_pdev
= of_find_device_by_node(larb_node
);
282 dev_warn(dev
, "Waiting for larb device %s\n",
283 larb_node
->full_name
);
284 of_node_put(larb_node
);
285 return -EPROBE_DEFER
;
287 of_node_put(larb_node
);
289 comp
->larb_dev
= &larb_pdev
->dev
;
294 int mtk_ddp_comp_register(struct drm_device
*drm
, struct mtk_ddp_comp
*comp
)
296 struct mtk_drm_private
*private = drm
->dev_private
;
298 if (private->ddp_comp
[comp
->id
])
301 private->ddp_comp
[comp
->id
] = comp
;
305 void mtk_ddp_comp_unregister(struct drm_device
*drm
, struct mtk_ddp_comp
*comp
)
307 struct mtk_drm_private
*private = drm
->dev_private
;
309 private->ddp_comp
[comp
->id
] = NULL
;