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 OD_RELAY_MODE BIT(0)
43 #define UFO_BYPASS BIT(2)
45 #define COLOR_BYPASS_ALL BIT(7)
46 #define COLOR_SEQ_SEL BIT(13)
48 static void mtk_color_config(struct mtk_ddp_comp
*comp
, unsigned int w
,
49 unsigned int h
, unsigned int vrefresh
)
51 writel(w
, comp
->regs
+ DISP_COLOR_WIDTH
);
52 writel(h
, comp
->regs
+ DISP_COLOR_HEIGHT
);
55 static void mtk_color_start(struct mtk_ddp_comp
*comp
)
57 writel(COLOR_BYPASS_ALL
| COLOR_SEQ_SEL
,
58 comp
->regs
+ DISP_COLOR_CFG_MAIN
);
59 writel(0x1, comp
->regs
+ DISP_COLOR_START
);
62 static void mtk_od_config(struct mtk_ddp_comp
*comp
, unsigned int w
,
63 unsigned int h
, unsigned int vrefresh
)
65 writel(w
<< 16 | h
, comp
->regs
+ DISP_OD_SIZE
);
68 static void mtk_od_start(struct mtk_ddp_comp
*comp
)
70 writel(OD_RELAY_MODE
, comp
->regs
+ DISP_OD_CFG
);
71 writel(1, comp
->regs
+ DISP_OD_EN
);
74 static void mtk_ufoe_start(struct mtk_ddp_comp
*comp
)
76 writel(UFO_BYPASS
, comp
->regs
+ DISP_REG_UFO_START
);
79 static const struct mtk_ddp_comp_funcs ddp_color
= {
80 .config
= mtk_color_config
,
81 .start
= mtk_color_start
,
84 static const struct mtk_ddp_comp_funcs ddp_od
= {
85 .config
= mtk_od_config
,
86 .start
= mtk_od_start
,
89 static const struct mtk_ddp_comp_funcs ddp_ufoe
= {
90 .start
= mtk_ufoe_start
,
93 static const char * const mtk_ddp_comp_stem
[MTK_DDP_COMP_TYPE_MAX
] = {
94 [MTK_DISP_OVL
] = "ovl",
95 [MTK_DISP_RDMA
] = "rdma",
96 [MTK_DISP_WDMA
] = "wdma",
97 [MTK_DISP_COLOR
] = "color",
98 [MTK_DISP_AAL
] = "aal",
99 [MTK_DISP_GAMMA
] = "gamma",
100 [MTK_DISP_UFOE
] = "ufoe",
103 [MTK_DISP_PWM
] = "pwm",
104 [MTK_DISP_MUTEX
] = "mutex",
105 [MTK_DISP_OD
] = "od",
108 struct mtk_ddp_comp_match
{
109 enum mtk_ddp_comp_type type
;
111 const struct mtk_ddp_comp_funcs
*funcs
;
114 static const struct mtk_ddp_comp_match mtk_ddp_matches
[DDP_COMPONENT_ID_MAX
] = {
115 [DDP_COMPONENT_AAL
] = { MTK_DISP_AAL
, 0, NULL
},
116 [DDP_COMPONENT_COLOR0
] = { MTK_DISP_COLOR
, 0, &ddp_color
},
117 [DDP_COMPONENT_COLOR1
] = { MTK_DISP_COLOR
, 1, &ddp_color
},
118 [DDP_COMPONENT_DPI0
] = { MTK_DPI
, 0, NULL
},
119 [DDP_COMPONENT_DSI0
] = { MTK_DSI
, 0, NULL
},
120 [DDP_COMPONENT_DSI1
] = { MTK_DSI
, 1, NULL
},
121 [DDP_COMPONENT_GAMMA
] = { MTK_DISP_GAMMA
, 0, NULL
},
122 [DDP_COMPONENT_OD
] = { MTK_DISP_OD
, 0, &ddp_od
},
123 [DDP_COMPONENT_OVL0
] = { MTK_DISP_OVL
, 0, NULL
},
124 [DDP_COMPONENT_OVL1
] = { MTK_DISP_OVL
, 1, NULL
},
125 [DDP_COMPONENT_PWM0
] = { MTK_DISP_PWM
, 0, NULL
},
126 [DDP_COMPONENT_RDMA0
] = { MTK_DISP_RDMA
, 0, NULL
},
127 [DDP_COMPONENT_RDMA1
] = { MTK_DISP_RDMA
, 1, NULL
},
128 [DDP_COMPONENT_RDMA2
] = { MTK_DISP_RDMA
, 2, NULL
},
129 [DDP_COMPONENT_UFOE
] = { MTK_DISP_UFOE
, 0, &ddp_ufoe
},
130 [DDP_COMPONENT_WDMA0
] = { MTK_DISP_WDMA
, 0, NULL
},
131 [DDP_COMPONENT_WDMA1
] = { MTK_DISP_WDMA
, 1, NULL
},
134 int mtk_ddp_comp_get_id(struct device_node
*node
,
135 enum mtk_ddp_comp_type comp_type
)
137 int id
= of_alias_get_id(node
, mtk_ddp_comp_stem
[comp_type
]);
140 for (i
= 0; i
< ARRAY_SIZE(mtk_ddp_matches
); i
++) {
141 if (comp_type
== mtk_ddp_matches
[i
].type
&&
142 (id
< 0 || id
== mtk_ddp_matches
[i
].alias_id
))
149 int mtk_ddp_comp_init(struct device
*dev
, struct device_node
*node
,
150 struct mtk_ddp_comp
*comp
, enum mtk_ddp_comp_id comp_id
,
151 const struct mtk_ddp_comp_funcs
*funcs
)
153 enum mtk_ddp_comp_type type
;
154 struct device_node
*larb_node
;
155 struct platform_device
*larb_pdev
;
157 if (comp_id
< 0 || comp_id
>= DDP_COMPONENT_ID_MAX
)
161 comp
->funcs
= funcs
?: mtk_ddp_matches
[comp_id
].funcs
;
163 if (comp_id
== DDP_COMPONENT_DPI0
||
164 comp_id
== DDP_COMPONENT_DSI0
||
165 comp_id
== DDP_COMPONENT_PWM0
) {
172 comp
->regs
= of_iomap(node
, 0);
173 comp
->irq
= of_irq_get(node
, 0);
174 comp
->clk
= of_clk_get(node
, 0);
175 if (IS_ERR(comp
->clk
))
178 type
= mtk_ddp_matches
[comp_id
].type
;
180 /* Only DMA capable components need the LARB property */
181 comp
->larb_dev
= NULL
;
182 if (type
!= MTK_DISP_OVL
&&
183 type
!= MTK_DISP_RDMA
&&
184 type
!= MTK_DISP_WDMA
)
187 larb_node
= of_parse_phandle(node
, "mediatek,larb", 0);
190 "Missing mediadek,larb phandle in %s node\n",
195 larb_pdev
= of_find_device_by_node(larb_node
);
197 dev_warn(dev
, "Waiting for larb device %s\n",
198 larb_node
->full_name
);
199 of_node_put(larb_node
);
200 return -EPROBE_DEFER
;
202 of_node_put(larb_node
);
204 comp
->larb_dev
= &larb_pdev
->dev
;
209 int mtk_ddp_comp_register(struct drm_device
*drm
, struct mtk_ddp_comp
*comp
)
211 struct mtk_drm_private
*private = drm
->dev_private
;
213 if (private->ddp_comp
[comp
->id
])
216 private->ddp_comp
[comp
->id
] = comp
;
220 void mtk_ddp_comp_unregister(struct drm_device
*drm
, struct mtk_ddp_comp
*comp
)
222 struct mtk_drm_private
*private = drm
->dev_private
;
224 private->ddp_comp
[comp
->id
] = NULL
;