1
2
3
4
5
6
7
8
9
10
11
12#include <linux/clk.h>
13#include <linux/version.h>
14#include <linux/dma-buf.h>
15#include <linux/of_graph.h>
16
17#include <drm/drmP.h>
18#include <drm/drm_panel.h>
19#include <drm/drm_gem_cma_helper.h>
20#include <drm/drm_gem_framebuffer_helper.h>
21#include <drm/drm_fb_cma_helper.h>
22
23#include "tve200_drm.h"
24
25irqreturn_t tve200_irq(int irq, void *data)
26{
27 struct tve200_drm_dev_private *priv = data;
28 u32 stat;
29 u32 val;
30
31 stat = readl(priv->regs + TVE200_INT_STAT);
32
33 if (!stat)
34 return IRQ_NONE;
35
36
37
38
39
40
41
42
43
44
45
46
47 if (stat & TVE200_INT_V_STATUS) {
48 val = readl(priv->regs + TVE200_CTRL);
49
50 if (!(val & TVE200_VSTSTYPE_BITS)) {
51 drm_crtc_handle_vblank(&priv->pipe.crtc);
52
53 val |= TVE200_VSTSTYPE_VAI;
54 } else {
55
56 val &= ~TVE200_VSTSTYPE_BITS;
57 }
58 writel(val, priv->regs + TVE200_CTRL);
59 } else
60 dev_err(priv->drm->dev, "stray IRQ %08x\n", stat);
61
62
63 writel(stat, priv->regs + TVE200_INT_CLR);
64
65 return IRQ_HANDLED;
66}
67
68static int tve200_display_check(struct drm_simple_display_pipe *pipe,
69 struct drm_plane_state *pstate,
70 struct drm_crtc_state *cstate)
71{
72 const struct drm_display_mode *mode = &cstate->mode;
73 struct drm_framebuffer *old_fb = pipe->plane.state->fb;
74 struct drm_framebuffer *fb = pstate->fb;
75
76
77
78
79 if (!(mode->hdisplay == 352 && mode->vdisplay == 240) &&
80 !(mode->hdisplay == 352 && mode->vdisplay == 288) &&
81 !(mode->hdisplay == 640 && mode->vdisplay == 480) &&
82 !(mode->hdisplay == 720 && mode->vdisplay == 480) &&
83 !(mode->hdisplay == 720 && mode->vdisplay == 576)) {
84 DRM_DEBUG_KMS("unsupported display mode (%u x %u)\n",
85 mode->hdisplay, mode->vdisplay);
86 return -EINVAL;
87 }
88
89 if (fb) {
90 u32 offset = drm_fb_cma_get_gem_addr(fb, pstate, 0);
91
92
93 if (offset & 3) {
94 DRM_DEBUG_KMS("FB not 32-bit aligned\n");
95 return -EINVAL;
96 }
97
98
99
100
101
102 if (fb->pitches[0] != mode->hdisplay * fb->format->cpp[0]) {
103 DRM_DEBUG_KMS("can't handle pitches\n");
104 return -EINVAL;
105 }
106
107
108
109
110
111 if (old_fb && old_fb->format != fb->format)
112 cstate->mode_changed = true;
113 }
114
115 return 0;
116}
117
118static void tve200_display_enable(struct drm_simple_display_pipe *pipe,
119 struct drm_crtc_state *cstate,
120 struct drm_plane_state *plane_state)
121{
122 struct drm_crtc *crtc = &pipe->crtc;
123 struct drm_plane *plane = &pipe->plane;
124 struct drm_device *drm = crtc->dev;
125 struct tve200_drm_dev_private *priv = drm->dev_private;
126 const struct drm_display_mode *mode = &cstate->mode;
127 struct drm_framebuffer *fb = plane->state->fb;
128 struct drm_connector *connector = priv->connector;
129 u32 format = fb->format->format;
130 u32 ctrl1 = 0;
131
132 clk_prepare_enable(priv->clk);
133
134
135 ctrl1 |= TVE200_CTRL_CSMODE;
136
137 ctrl1 |= TVE200_CTRL_NONINTERLACE;
138
139 ctrl1 |= TVE200_CTRL_BURST_32_WORDS;
140
141 ctrl1 |= TVE200_CTRL_RETRYCNT_16;
142
143 ctrl1 |= TVE200_CTRL_NTSC;
144
145
146 ctrl1 |= TVE200_VSTSTYPE_VSYNC;
147
148 if (connector->display_info.bus_flags &
149 DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
150 ctrl1 |= TVE200_CTRL_TVCLKP;
151
152 if ((mode->hdisplay == 352 && mode->vdisplay == 240) ||
153 (mode->hdisplay == 352 && mode->vdisplay == 288)) {
154 ctrl1 |= TVE200_CTRL_IPRESOL_CIF;
155 dev_info(drm->dev, "CIF mode\n");
156 } else if (mode->hdisplay == 640 && mode->vdisplay == 480) {
157 ctrl1 |= TVE200_CTRL_IPRESOL_VGA;
158 dev_info(drm->dev, "VGA mode\n");
159 } else if ((mode->hdisplay == 720 && mode->vdisplay == 480) ||
160 (mode->hdisplay == 720 && mode->vdisplay == 576)) {
161 ctrl1 |= TVE200_CTRL_IPRESOL_D1;
162 dev_info(drm->dev, "D1 mode\n");
163 }
164
165 if (format & DRM_FORMAT_BIG_ENDIAN) {
166 ctrl1 |= TVE200_CTRL_BBBP;
167 format &= ~DRM_FORMAT_BIG_ENDIAN;
168 }
169
170 switch (format) {
171 case DRM_FORMAT_XRGB8888:
172 ctrl1 |= TVE200_IPDMOD_RGB888;
173 break;
174 case DRM_FORMAT_RGB565:
175 ctrl1 |= TVE200_IPDMOD_RGB565;
176 break;
177 case DRM_FORMAT_XRGB1555:
178 ctrl1 |= TVE200_IPDMOD_RGB555;
179 break;
180 case DRM_FORMAT_XBGR8888:
181 ctrl1 |= TVE200_IPDMOD_RGB888 | TVE200_BGR;
182 break;
183 case DRM_FORMAT_BGR565:
184 ctrl1 |= TVE200_IPDMOD_RGB565 | TVE200_BGR;
185 break;
186 case DRM_FORMAT_XBGR1555:
187 ctrl1 |= TVE200_IPDMOD_RGB555 | TVE200_BGR;
188 break;
189 case DRM_FORMAT_YUYV:
190 ctrl1 |= TVE200_IPDMOD_YUV422;
191 ctrl1 |= TVE200_CTRL_YCBCRODR_CR0Y1CB0Y0;
192 break;
193 case DRM_FORMAT_YVYU:
194 ctrl1 |= TVE200_IPDMOD_YUV422;
195 ctrl1 |= TVE200_CTRL_YCBCRODR_CB0Y1CR0Y0;
196 break;
197 case DRM_FORMAT_UYVY:
198 ctrl1 |= TVE200_IPDMOD_YUV422;
199 ctrl1 |= TVE200_CTRL_YCBCRODR_Y1CR0Y0CB0;
200 break;
201 case DRM_FORMAT_VYUY:
202 ctrl1 |= TVE200_IPDMOD_YUV422;
203 ctrl1 |= TVE200_CTRL_YCBCRODR_Y1CB0Y0CR0;
204 break;
205 case DRM_FORMAT_YUV420:
206 ctrl1 |= TVE200_CTRL_YUV420;
207 ctrl1 |= TVE200_IPDMOD_YUV420;
208 break;
209 default:
210 dev_err(drm->dev, "Unknown FB format 0x%08x\n",
211 fb->format->format);
212 break;
213 }
214
215 ctrl1 |= TVE200_TVEEN;
216
217
218 writel(ctrl1, priv->regs + TVE200_CTRL);
219
220 drm_crtc_vblank_on(crtc);
221}
222
223static void tve200_display_disable(struct drm_simple_display_pipe *pipe)
224{
225 struct drm_crtc *crtc = &pipe->crtc;
226 struct drm_device *drm = crtc->dev;
227 struct tve200_drm_dev_private *priv = drm->dev_private;
228
229 drm_crtc_vblank_off(crtc);
230
231
232 writel(0, priv->regs + TVE200_CTRL);
233
234 clk_disable_unprepare(priv->clk);
235}
236
237static void tve200_display_update(struct drm_simple_display_pipe *pipe,
238 struct drm_plane_state *old_pstate)
239{
240 struct drm_crtc *crtc = &pipe->crtc;
241 struct drm_device *drm = crtc->dev;
242 struct tve200_drm_dev_private *priv = drm->dev_private;
243 struct drm_pending_vblank_event *event = crtc->state->event;
244 struct drm_plane *plane = &pipe->plane;
245 struct drm_plane_state *pstate = plane->state;
246 struct drm_framebuffer *fb = pstate->fb;
247
248 if (fb) {
249
250 writel(drm_fb_cma_get_gem_addr(fb, pstate, 0),
251 priv->regs + TVE200_Y_FRAME_BASE_ADDR);
252
253
254 if (fb->format->format == DRM_FORMAT_YUV420) {
255 writel(drm_fb_cma_get_gem_addr(fb, pstate, 1),
256 priv->regs + TVE200_U_FRAME_BASE_ADDR);
257 writel(drm_fb_cma_get_gem_addr(fb, pstate, 2),
258 priv->regs + TVE200_V_FRAME_BASE_ADDR);
259 }
260 }
261
262 if (event) {
263 crtc->state->event = NULL;
264
265 spin_lock_irq(&crtc->dev->event_lock);
266 if (crtc->state->active && drm_crtc_vblank_get(crtc) == 0)
267 drm_crtc_arm_vblank_event(crtc, event);
268 else
269 drm_crtc_send_vblank_event(crtc, event);
270 spin_unlock_irq(&crtc->dev->event_lock);
271 }
272}
273
274static int tve200_display_enable_vblank(struct drm_simple_display_pipe *pipe)
275{
276 struct drm_crtc *crtc = &pipe->crtc;
277 struct drm_device *drm = crtc->dev;
278 struct tve200_drm_dev_private *priv = drm->dev_private;
279
280 writel(TVE200_INT_V_STATUS, priv->regs + TVE200_INT_EN);
281 return 0;
282}
283
284static void tve200_display_disable_vblank(struct drm_simple_display_pipe *pipe)
285{
286 struct drm_crtc *crtc = &pipe->crtc;
287 struct drm_device *drm = crtc->dev;
288 struct tve200_drm_dev_private *priv = drm->dev_private;
289
290 writel(0, priv->regs + TVE200_INT_EN);
291}
292
293static const struct drm_simple_display_pipe_funcs tve200_display_funcs = {
294 .check = tve200_display_check,
295 .enable = tve200_display_enable,
296 .disable = tve200_display_disable,
297 .update = tve200_display_update,
298 .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
299 .enable_vblank = tve200_display_enable_vblank,
300 .disable_vblank = tve200_display_disable_vblank,
301};
302
303int tve200_display_init(struct drm_device *drm)
304{
305 struct tve200_drm_dev_private *priv = drm->dev_private;
306 int ret;
307 static const u32 formats[] = {
308 DRM_FORMAT_XRGB8888,
309 DRM_FORMAT_XBGR8888,
310 DRM_FORMAT_RGB565,
311 DRM_FORMAT_BGR565,
312 DRM_FORMAT_XRGB1555,
313 DRM_FORMAT_XBGR1555,
314
315
316
317
318
319 DRM_FORMAT_YUYV,
320 DRM_FORMAT_YVYU,
321 DRM_FORMAT_UYVY,
322 DRM_FORMAT_VYUY,
323
324 DRM_FORMAT_YUV420,
325 };
326
327 ret = drm_simple_display_pipe_init(drm, &priv->pipe,
328 &tve200_display_funcs,
329 formats, ARRAY_SIZE(formats),
330 NULL,
331 priv->connector);
332 if (ret)
333 return ret;
334
335 return 0;
336}
337