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
34 #define DISP_DITHER_5 0x0114
35 #define DISP_DITHER_7 0x011c
36 #define DISP_DITHER_15 0x013c
37 #define DISP_DITHER_16 0x0140
39 #define DISP_REG_UFO_START 0x0000
41 #define DISP_AAL_EN 0x0000
42 #define DISP_AAL_SIZE 0x0030
44 #define DISP_GAMMA_EN 0x0000
45 #define DISP_GAMMA_CFG 0x0020
46 #define DISP_GAMMA_SIZE 0x0030
47 #define DISP_GAMMA_LUT 0x0700
49 #define LUT_10BIT_MASK 0x03ff
51 #define OD_RELAYMODE BIT(0)
53 #define UFO_BYPASS BIT(2)
57 #define GAMMA_EN BIT(0)
58 #define GAMMA_LUT_EN BIT(1)
60 #define DISP_DITHERING BIT(2)
61 #define DITHER_LSB_ERR_SHIFT_R(x) (((x) & 0x7) << 28)
62 #define DITHER_OVFLW_BIT_R(x) (((x) & 0x7) << 24)
63 #define DITHER_ADD_LSHIFT_R(x) (((x) & 0x7) << 20)
64 #define DITHER_ADD_RSHIFT_R(x) (((x) & 0x7) << 16)
65 #define DITHER_NEW_BIT_MODE BIT(0)
66 #define DITHER_LSB_ERR_SHIFT_B(x) (((x) & 0x7) << 28)
67 #define DITHER_OVFLW_BIT_B(x) (((x) & 0x7) << 24)
68 #define DITHER_ADD_LSHIFT_B(x) (((x) & 0x7) << 20)
69 #define DITHER_ADD_RSHIFT_B(x) (((x) & 0x7) << 16)
70 #define DITHER_LSB_ERR_SHIFT_G(x) (((x) & 0x7) << 12)
71 #define DITHER_OVFLW_BIT_G(x) (((x) & 0x7) << 8)
72 #define DITHER_ADD_LSHIFT_G(x) (((x) & 0x7) << 4)
73 #define DITHER_ADD_RSHIFT_G(x) (((x) & 0x7) << 0)
75 void mtk_dither_set(struct mtk_ddp_comp
*comp
, unsigned int bpc
,
78 /* If bpc equal to 0, the dithering function didn't be enabled */
82 if (bpc
>= MTK_MIN_BPC
) {
83 writel(0, comp
->regs
+ DISP_DITHER_5
);
84 writel(0, comp
->regs
+ DISP_DITHER_7
);
85 writel(DITHER_LSB_ERR_SHIFT_R(MTK_MAX_BPC
- bpc
) |
86 DITHER_ADD_LSHIFT_R(MTK_MAX_BPC
- bpc
) |
88 comp
->regs
+ DISP_DITHER_15
);
89 writel(DITHER_LSB_ERR_SHIFT_B(MTK_MAX_BPC
- bpc
) |
90 DITHER_ADD_LSHIFT_B(MTK_MAX_BPC
- bpc
) |
91 DITHER_LSB_ERR_SHIFT_G(MTK_MAX_BPC
- bpc
) |
92 DITHER_ADD_LSHIFT_G(MTK_MAX_BPC
- bpc
),
93 comp
->regs
+ DISP_DITHER_16
);
94 writel(DISP_DITHERING
, comp
->regs
+ CFG
);
98 static void mtk_od_config(struct mtk_ddp_comp
*comp
, unsigned int w
,
99 unsigned int h
, unsigned int vrefresh
,
102 writel(w
<< 16 | h
, comp
->regs
+ DISP_OD_SIZE
);
103 writel(OD_RELAYMODE
, comp
->regs
+ DISP_OD_CFG
);
104 mtk_dither_set(comp
, bpc
, DISP_OD_CFG
);
107 static void mtk_od_start(struct mtk_ddp_comp
*comp
)
109 writel(1, comp
->regs
+ DISP_OD_EN
);
112 static void mtk_ufoe_start(struct mtk_ddp_comp
*comp
)
114 writel(UFO_BYPASS
, comp
->regs
+ DISP_REG_UFO_START
);
117 static void mtk_aal_config(struct mtk_ddp_comp
*comp
, unsigned int w
,
118 unsigned int h
, unsigned int vrefresh
,
121 writel(h
<< 16 | w
, comp
->regs
+ DISP_AAL_SIZE
);
124 static void mtk_aal_start(struct mtk_ddp_comp
*comp
)
126 writel(AAL_EN
, comp
->regs
+ DISP_AAL_EN
);
129 static void mtk_aal_stop(struct mtk_ddp_comp
*comp
)
131 writel_relaxed(0x0, comp
->regs
+ DISP_AAL_EN
);
134 static void mtk_gamma_config(struct mtk_ddp_comp
*comp
, unsigned int w
,
135 unsigned int h
, unsigned int vrefresh
,
138 writel(h
<< 16 | w
, comp
->regs
+ DISP_GAMMA_SIZE
);
139 mtk_dither_set(comp
, bpc
, DISP_GAMMA_CFG
);
142 static void mtk_gamma_start(struct mtk_ddp_comp
*comp
)
144 writel(GAMMA_EN
, comp
->regs
+ DISP_GAMMA_EN
);
147 static void mtk_gamma_stop(struct mtk_ddp_comp
*comp
)
149 writel_relaxed(0x0, comp
->regs
+ DISP_GAMMA_EN
);
152 static void mtk_gamma_set(struct mtk_ddp_comp
*comp
,
153 struct drm_crtc_state
*state
)
156 struct drm_color_lut
*lut
;
157 void __iomem
*lut_base
;
160 if (state
->gamma_lut
) {
161 reg
= readl(comp
->regs
+ DISP_GAMMA_CFG
);
162 reg
= reg
| GAMMA_LUT_EN
;
163 writel(reg
, comp
->regs
+ DISP_GAMMA_CFG
);
164 lut_base
= comp
->regs
+ DISP_GAMMA_LUT
;
165 lut
= (struct drm_color_lut
*)state
->gamma_lut
->data
;
166 for (i
= 0; i
< MTK_LUT_SIZE
; i
++) {
167 word
= (((lut
[i
].red
>> 6) & LUT_10BIT_MASK
) << 20) +
168 (((lut
[i
].green
>> 6) & LUT_10BIT_MASK
) << 10) +
169 ((lut
[i
].blue
>> 6) & LUT_10BIT_MASK
);
170 writel(word
, (lut_base
+ i
* 4));
175 static const struct mtk_ddp_comp_funcs ddp_aal
= {
176 .gamma_set
= mtk_gamma_set
,
177 .config
= mtk_aal_config
,
178 .start
= mtk_aal_start
,
179 .stop
= mtk_aal_stop
,
182 static const struct mtk_ddp_comp_funcs ddp_gamma
= {
183 .gamma_set
= mtk_gamma_set
,
184 .config
= mtk_gamma_config
,
185 .start
= mtk_gamma_start
,
186 .stop
= mtk_gamma_stop
,
189 static const struct mtk_ddp_comp_funcs ddp_od
= {
190 .config
= mtk_od_config
,
191 .start
= mtk_od_start
,
194 static const struct mtk_ddp_comp_funcs ddp_ufoe
= {
195 .start
= mtk_ufoe_start
,
198 static const char * const mtk_ddp_comp_stem
[MTK_DDP_COMP_TYPE_MAX
] = {
199 [MTK_DISP_OVL
] = "ovl",
200 [MTK_DISP_RDMA
] = "rdma",
201 [MTK_DISP_WDMA
] = "wdma",
202 [MTK_DISP_COLOR
] = "color",
203 [MTK_DISP_AAL
] = "aal",
204 [MTK_DISP_GAMMA
] = "gamma",
205 [MTK_DISP_UFOE
] = "ufoe",
208 [MTK_DISP_PWM
] = "pwm",
209 [MTK_DISP_MUTEX
] = "mutex",
210 [MTK_DISP_OD
] = "od",
211 [MTK_DISP_BLS
] = "bls",
214 struct mtk_ddp_comp_match
{
215 enum mtk_ddp_comp_type type
;
217 const struct mtk_ddp_comp_funcs
*funcs
;
220 static const struct mtk_ddp_comp_match mtk_ddp_matches
[DDP_COMPONENT_ID_MAX
] = {
221 [DDP_COMPONENT_AAL0
] = { MTK_DISP_AAL
, 0, &ddp_aal
},
222 [DDP_COMPONENT_AAL1
] = { MTK_DISP_AAL
, 1, &ddp_aal
},
223 [DDP_COMPONENT_BLS
] = { MTK_DISP_BLS
, 0, NULL
},
224 [DDP_COMPONENT_COLOR0
] = { MTK_DISP_COLOR
, 0, NULL
},
225 [DDP_COMPONENT_COLOR1
] = { MTK_DISP_COLOR
, 1, NULL
},
226 [DDP_COMPONENT_DPI0
] = { MTK_DPI
, 0, NULL
},
227 [DDP_COMPONENT_DPI1
] = { MTK_DPI
, 1, NULL
},
228 [DDP_COMPONENT_DSI0
] = { MTK_DSI
, 0, NULL
},
229 [DDP_COMPONENT_DSI1
] = { MTK_DSI
, 1, NULL
},
230 [DDP_COMPONENT_DSI2
] = { MTK_DSI
, 2, NULL
},
231 [DDP_COMPONENT_DSI3
] = { MTK_DSI
, 3, NULL
},
232 [DDP_COMPONENT_GAMMA
] = { MTK_DISP_GAMMA
, 0, &ddp_gamma
},
233 [DDP_COMPONENT_OD0
] = { MTK_DISP_OD
, 0, &ddp_od
},
234 [DDP_COMPONENT_OD1
] = { MTK_DISP_OD
, 1, &ddp_od
},
235 [DDP_COMPONENT_OVL0
] = { MTK_DISP_OVL
, 0, NULL
},
236 [DDP_COMPONENT_OVL1
] = { MTK_DISP_OVL
, 1, NULL
},
237 [DDP_COMPONENT_PWM0
] = { MTK_DISP_PWM
, 0, NULL
},
238 [DDP_COMPONENT_PWM1
] = { MTK_DISP_PWM
, 1, NULL
},
239 [DDP_COMPONENT_PWM2
] = { MTK_DISP_PWM
, 2, NULL
},
240 [DDP_COMPONENT_RDMA0
] = { MTK_DISP_RDMA
, 0, NULL
},
241 [DDP_COMPONENT_RDMA1
] = { MTK_DISP_RDMA
, 1, NULL
},
242 [DDP_COMPONENT_RDMA2
] = { MTK_DISP_RDMA
, 2, NULL
},
243 [DDP_COMPONENT_UFOE
] = { MTK_DISP_UFOE
, 0, &ddp_ufoe
},
244 [DDP_COMPONENT_WDMA0
] = { MTK_DISP_WDMA
, 0, NULL
},
245 [DDP_COMPONENT_WDMA1
] = { MTK_DISP_WDMA
, 1, NULL
},
248 int mtk_ddp_comp_get_id(struct device_node
*node
,
249 enum mtk_ddp_comp_type comp_type
)
251 int id
= of_alias_get_id(node
, mtk_ddp_comp_stem
[comp_type
]);
254 for (i
= 0; i
< ARRAY_SIZE(mtk_ddp_matches
); i
++) {
255 if (comp_type
== mtk_ddp_matches
[i
].type
&&
256 (id
< 0 || id
== mtk_ddp_matches
[i
].alias_id
))
263 int mtk_ddp_comp_init(struct device
*dev
, struct device_node
*node
,
264 struct mtk_ddp_comp
*comp
, enum mtk_ddp_comp_id comp_id
,
265 const struct mtk_ddp_comp_funcs
*funcs
)
267 enum mtk_ddp_comp_type type
;
268 struct device_node
*larb_node
;
269 struct platform_device
*larb_pdev
;
271 if (comp_id
< 0 || comp_id
>= DDP_COMPONENT_ID_MAX
)
274 type
= mtk_ddp_matches
[comp_id
].type
;
277 comp
->funcs
= funcs
?: mtk_ddp_matches
[comp_id
].funcs
;
279 if (comp_id
== DDP_COMPONENT_BLS
||
280 comp_id
== DDP_COMPONENT_DPI0
||
281 comp_id
== DDP_COMPONENT_DPI1
||
282 comp_id
== DDP_COMPONENT_DSI0
||
283 comp_id
== DDP_COMPONENT_DSI1
||
284 comp_id
== DDP_COMPONENT_DSI2
||
285 comp_id
== DDP_COMPONENT_DSI3
||
286 comp_id
== DDP_COMPONENT_PWM0
) {
293 comp
->regs
= of_iomap(node
, 0);
294 comp
->irq
= of_irq_get(node
, 0);
295 comp
->clk
= of_clk_get(node
, 0);
296 if (IS_ERR(comp
->clk
))
297 return PTR_ERR(comp
->clk
);
299 /* Only DMA capable components need the LARB property */
300 comp
->larb_dev
= NULL
;
301 if (type
!= MTK_DISP_OVL
&&
302 type
!= MTK_DISP_RDMA
&&
303 type
!= MTK_DISP_WDMA
)
306 larb_node
= of_parse_phandle(node
, "mediatek,larb", 0);
309 "Missing mediadek,larb phandle in %pOF node\n", node
);
313 larb_pdev
= of_find_device_by_node(larb_node
);
315 dev_warn(dev
, "Waiting for larb device %pOF\n", larb_node
);
316 of_node_put(larb_node
);
317 return -EPROBE_DEFER
;
319 of_node_put(larb_node
);
321 comp
->larb_dev
= &larb_pdev
->dev
;
326 int mtk_ddp_comp_register(struct drm_device
*drm
, struct mtk_ddp_comp
*comp
)
328 struct mtk_drm_private
*private = drm
->dev_private
;
330 if (private->ddp_comp
[comp
->id
])
333 private->ddp_comp
[comp
->id
] = comp
;
337 void mtk_ddp_comp_unregister(struct drm_device
*drm
, struct mtk_ddp_comp
*comp
)
339 struct mtk_drm_private
*private = drm
->dev_private
;
341 private->ddp_comp
[comp
->id
] = NULL
;