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"
28 #define DISP_OD_EN 0x0000
29 #define DISP_OD_INTEN 0x0008
30 #define DISP_OD_INTSTA 0x000c
31 #define DISP_OD_CFG 0x0020
32 #define DISP_OD_SIZE 0x0030
34 #define DISP_REG_UFO_START 0x0000
36 #define DISP_COLOR_CFG_MAIN 0x0400
37 #define DISP_COLOR_START 0x0c00
38 #define DISP_COLOR_WIDTH 0x0c50
39 #define DISP_COLOR_HEIGHT 0x0c54
41 #define DISP_AAL_EN 0x0000
42 #define DISP_AAL_SIZE 0x0030
44 #define OD_RELAY_MODE BIT(0)
46 #define UFO_BYPASS BIT(2)
48 #define COLOR_BYPASS_ALL BIT(7)
49 #define COLOR_SEQ_SEL BIT(13)
53 static void mtk_color_config(struct mtk_ddp_comp
*comp
, unsigned int w
,
54 unsigned int h
, unsigned int vrefresh
)
56 writel(w
, comp
->regs
+ DISP_COLOR_WIDTH
);
57 writel(h
, comp
->regs
+ DISP_COLOR_HEIGHT
);
60 static void mtk_color_start(struct mtk_ddp_comp
*comp
)
62 writel(COLOR_BYPASS_ALL
| COLOR_SEQ_SEL
,
63 comp
->regs
+ DISP_COLOR_CFG_MAIN
);
64 writel(0x1, comp
->regs
+ DISP_COLOR_START
);
67 static void mtk_od_config(struct mtk_ddp_comp
*comp
, unsigned int w
,
68 unsigned int h
, unsigned int vrefresh
)
70 writel(w
<< 16 | h
, comp
->regs
+ DISP_OD_SIZE
);
73 static void mtk_od_start(struct mtk_ddp_comp
*comp
)
75 writel(OD_RELAY_MODE
, comp
->regs
+ DISP_OD_CFG
);
76 writel(1, comp
->regs
+ DISP_OD_EN
);
79 static void mtk_ufoe_start(struct mtk_ddp_comp
*comp
)
81 writel(UFO_BYPASS
, comp
->regs
+ DISP_REG_UFO_START
);
84 static void mtk_aal_config(struct mtk_ddp_comp
*comp
, unsigned int w
,
85 unsigned int h
, unsigned int vrefresh
)
87 writel(h
<< 16 | w
, comp
->regs
+ DISP_AAL_SIZE
);
90 static void mtk_aal_start(struct mtk_ddp_comp
*comp
)
92 writel(AAL_EN
, comp
->regs
+ DISP_AAL_EN
);
95 static void mtk_aal_stop(struct mtk_ddp_comp
*comp
)
97 writel_relaxed(0x0, comp
->regs
+ DISP_AAL_EN
);
100 static const struct mtk_ddp_comp_funcs ddp_aal
= {
101 .config
= mtk_aal_config
,
102 .start
= mtk_aal_start
,
103 .stop
= mtk_aal_stop
,
106 static const struct mtk_ddp_comp_funcs ddp_color
= {
107 .config
= mtk_color_config
,
108 .start
= mtk_color_start
,
111 static const struct mtk_ddp_comp_funcs ddp_od
= {
112 .config
= mtk_od_config
,
113 .start
= mtk_od_start
,
116 static const struct mtk_ddp_comp_funcs ddp_ufoe
= {
117 .start
= mtk_ufoe_start
,
120 static const char * const mtk_ddp_comp_stem
[MTK_DDP_COMP_TYPE_MAX
] = {
121 [MTK_DISP_OVL
] = "ovl",
122 [MTK_DISP_RDMA
] = "rdma",
123 [MTK_DISP_WDMA
] = "wdma",
124 [MTK_DISP_COLOR
] = "color",
125 [MTK_DISP_AAL
] = "aal",
126 [MTK_DISP_GAMMA
] = "gamma",
127 [MTK_DISP_UFOE
] = "ufoe",
130 [MTK_DISP_PWM
] = "pwm",
131 [MTK_DISP_MUTEX
] = "mutex",
132 [MTK_DISP_OD
] = "od",
135 struct mtk_ddp_comp_match
{
136 enum mtk_ddp_comp_type type
;
138 const struct mtk_ddp_comp_funcs
*funcs
;
141 static const struct mtk_ddp_comp_match mtk_ddp_matches
[DDP_COMPONENT_ID_MAX
] = {
142 [DDP_COMPONENT_AAL
] = { MTK_DISP_AAL
, 0, &ddp_aal
},
143 [DDP_COMPONENT_COLOR0
] = { MTK_DISP_COLOR
, 0, &ddp_color
},
144 [DDP_COMPONENT_COLOR1
] = { MTK_DISP_COLOR
, 1, &ddp_color
},
145 [DDP_COMPONENT_DPI0
] = { MTK_DPI
, 0, NULL
},
146 [DDP_COMPONENT_DSI0
] = { MTK_DSI
, 0, NULL
},
147 [DDP_COMPONENT_DSI1
] = { MTK_DSI
, 1, NULL
},
148 [DDP_COMPONENT_GAMMA
] = { MTK_DISP_GAMMA
, 0, NULL
},
149 [DDP_COMPONENT_OD
] = { MTK_DISP_OD
, 0, &ddp_od
},
150 [DDP_COMPONENT_OVL0
] = { MTK_DISP_OVL
, 0, NULL
},
151 [DDP_COMPONENT_OVL1
] = { MTK_DISP_OVL
, 1, NULL
},
152 [DDP_COMPONENT_PWM0
] = { MTK_DISP_PWM
, 0, NULL
},
153 [DDP_COMPONENT_RDMA0
] = { MTK_DISP_RDMA
, 0, NULL
},
154 [DDP_COMPONENT_RDMA1
] = { MTK_DISP_RDMA
, 1, NULL
},
155 [DDP_COMPONENT_RDMA2
] = { MTK_DISP_RDMA
, 2, NULL
},
156 [DDP_COMPONENT_UFOE
] = { MTK_DISP_UFOE
, 0, &ddp_ufoe
},
157 [DDP_COMPONENT_WDMA0
] = { MTK_DISP_WDMA
, 0, NULL
},
158 [DDP_COMPONENT_WDMA1
] = { MTK_DISP_WDMA
, 1, NULL
},
161 int mtk_ddp_comp_get_id(struct device_node
*node
,
162 enum mtk_ddp_comp_type comp_type
)
164 int id
= of_alias_get_id(node
, mtk_ddp_comp_stem
[comp_type
]);
167 for (i
= 0; i
< ARRAY_SIZE(mtk_ddp_matches
); i
++) {
168 if (comp_type
== mtk_ddp_matches
[i
].type
&&
169 (id
< 0 || id
== mtk_ddp_matches
[i
].alias_id
))
176 int mtk_ddp_comp_init(struct device
*dev
, struct device_node
*node
,
177 struct mtk_ddp_comp
*comp
, enum mtk_ddp_comp_id comp_id
,
178 const struct mtk_ddp_comp_funcs
*funcs
)
180 enum mtk_ddp_comp_type type
;
181 struct device_node
*larb_node
;
182 struct platform_device
*larb_pdev
;
184 if (comp_id
< 0 || comp_id
>= DDP_COMPONENT_ID_MAX
)
188 comp
->funcs
= funcs
?: mtk_ddp_matches
[comp_id
].funcs
;
190 if (comp_id
== DDP_COMPONENT_DPI0
||
191 comp_id
== DDP_COMPONENT_DSI0
||
192 comp_id
== DDP_COMPONENT_PWM0
) {
199 comp
->regs
= of_iomap(node
, 0);
200 comp
->irq
= of_irq_get(node
, 0);
201 comp
->clk
= of_clk_get(node
, 0);
202 if (IS_ERR(comp
->clk
))
205 type
= mtk_ddp_matches
[comp_id
].type
;
207 /* Only DMA capable components need the LARB property */
208 comp
->larb_dev
= NULL
;
209 if (type
!= MTK_DISP_OVL
&&
210 type
!= MTK_DISP_RDMA
&&
211 type
!= MTK_DISP_WDMA
)
214 larb_node
= of_parse_phandle(node
, "mediatek,larb", 0);
217 "Missing mediadek,larb phandle in %s node\n",
222 larb_pdev
= of_find_device_by_node(larb_node
);
224 dev_warn(dev
, "Waiting for larb device %s\n",
225 larb_node
->full_name
);
226 of_node_put(larb_node
);
227 return -EPROBE_DEFER
;
229 of_node_put(larb_node
);
231 comp
->larb_dev
= &larb_pdev
->dev
;
236 int mtk_ddp_comp_register(struct drm_device
*drm
, struct mtk_ddp_comp
*comp
)
238 struct mtk_drm_private
*private = drm
->dev_private
;
240 if (private->ddp_comp
[comp
->id
])
243 private->ddp_comp
[comp
->id
] = comp
;
247 void mtk_ddp_comp_unregister(struct drm_device
*drm
, struct mtk_ddp_comp
*comp
)
249 struct mtk_drm_private
*private = drm
->dev_private
;
251 private->ddp_comp
[comp
->id
] = NULL
;