forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-05-13 9d77db3c730780c8ef5ccd4b66403ff5675cfe4e
kernel/drivers/gpu/drm/mxsfb/mxsfb_drv.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Copyright (C) 2016 Marek Vasut <marex@denx.de>
34 *
....@@ -5,40 +6,29 @@
56 * Copyright (C) 2010 Juergen Beisert, Pengutronix
67 * Copyright (C) 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
78 * Copyright (C) 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8
- *
9
- * This program is free software; you can redistribute it and/or
10
- * modify it under the terms of the GNU General Public License
11
- * as published by the Free Software Foundation; either version 2
12
- * of the License, or (at your option) any later version.
13
- * This program is distributed in the hope that it will be useful,
14
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
- * GNU General Public License for more details.
179 */
1810
19
-#include <linux/module.h>
20
-#include <linux/spinlock.h>
2111 #include <linux/clk.h>
22
-#include <linux/component.h>
23
-#include <linux/list.h>
12
+#include <linux/dma-mapping.h>
13
+#include <linux/io.h>
14
+#include <linux/module.h>
2415 #include <linux/of_device.h>
25
-#include <linux/of_graph.h>
26
-#include <linux/of_reserved_mem.h>
16
+#include <linux/platform_device.h>
2717 #include <linux/pm_runtime.h>
28
-#include <linux/reservation.h>
2918
30
-#include <drm/drmP.h>
31
-#include <drm/drm_atomic.h>
3219 #include <drm/drm_atomic_helper.h>
33
-#include <drm/drm_crtc.h>
34
-#include <drm/drm_crtc_helper.h>
20
+#include <drm/drm_bridge.h>
21
+#include <drm/drm_connector.h>
22
+#include <drm/drm_drv.h>
3523 #include <drm/drm_fb_helper.h>
36
-#include <drm/drm_fb_cma_helper.h>
24
+#include <drm/drm_fourcc.h>
3725 #include <drm/drm_gem_cma_helper.h>
3826 #include <drm/drm_gem_framebuffer_helper.h>
27
+#include <drm/drm_irq.h>
28
+#include <drm/drm_mode_config.h>
3929 #include <drm/drm_of.h>
40
-#include <drm/drm_panel.h>
41
-#include <drm/drm_simple_kms_helper.h>
30
+#include <drm/drm_probe_helper.h>
31
+#include <drm/drm_vblank.h>
4232
4333 #include "mxsfb_drv.h"
4434 #include "mxsfb_regs.h"
....@@ -46,6 +36,11 @@
4636 enum mxsfb_devtype {
4737 MXSFB_V3,
4838 MXSFB_V4,
39
+ /*
40
+ * Starting at i.MX6 the hardware version register is gone, use the
41
+ * i.MX family number as the version.
42
+ */
43
+ MXSFB_V6,
4944 };
5045
5146 static const struct mxsfb_devdata mxsfb_devdata[] = {
....@@ -53,32 +48,30 @@
5348 .transfer_count = LCDC_V3_TRANSFER_COUNT,
5449 .cur_buf = LCDC_V3_CUR_BUF,
5550 .next_buf = LCDC_V3_NEXT_BUF,
56
- .debug0 = LCDC_V3_DEBUG0,
5751 .hs_wdth_mask = 0xff,
5852 .hs_wdth_shift = 24,
59
- .ipversion = 3,
53
+ .has_overlay = false,
54
+ .has_ctrl2 = false,
6055 },
6156 [MXSFB_V4] = {
6257 .transfer_count = LCDC_V4_TRANSFER_COUNT,
6358 .cur_buf = LCDC_V4_CUR_BUF,
6459 .next_buf = LCDC_V4_NEXT_BUF,
65
- .debug0 = LCDC_V4_DEBUG0,
6660 .hs_wdth_mask = 0x3fff,
6761 .hs_wdth_shift = 18,
68
- .ipversion = 4,
62
+ .has_overlay = false,
63
+ .has_ctrl2 = true,
64
+ },
65
+ [MXSFB_V6] = {
66
+ .transfer_count = LCDC_V4_TRANSFER_COUNT,
67
+ .cur_buf = LCDC_V4_CUR_BUF,
68
+ .next_buf = LCDC_V4_NEXT_BUF,
69
+ .hs_wdth_mask = 0x3fff,
70
+ .hs_wdth_shift = 18,
71
+ .has_overlay = true,
72
+ .has_ctrl2 = true,
6973 },
7074 };
71
-
72
-static const uint32_t mxsfb_formats[] = {
73
- DRM_FORMAT_XRGB8888,
74
- DRM_FORMAT_RGB565
75
-};
76
-
77
-static struct mxsfb_drm_private *
78
-drm_pipe_to_mxsfb_drm_private(struct drm_simple_display_pipe *pipe)
79
-{
80
- return container_of(pipe, struct mxsfb_drm_private, pipe);
81
-}
8275
8376 void mxsfb_enable_axi_clk(struct mxsfb_drm_private *mxsfb)
8477 {
....@@ -92,74 +85,76 @@
9285 clk_disable_unprepare(mxsfb->clk_axi);
9386 }
9487
88
+static struct drm_framebuffer *
89
+mxsfb_fb_create(struct drm_device *dev, struct drm_file *file_priv,
90
+ const struct drm_mode_fb_cmd2 *mode_cmd)
91
+{
92
+ const struct drm_format_info *info;
93
+
94
+ info = drm_get_format_info(dev, mode_cmd);
95
+ if (!info)
96
+ return ERR_PTR(-EINVAL);
97
+
98
+ if (mode_cmd->width * info->cpp[0] != mode_cmd->pitches[0]) {
99
+ dev_dbg(dev->dev, "Invalid pitch: fb width must match pitch\n");
100
+ return ERR_PTR(-EINVAL);
101
+ }
102
+
103
+ return drm_gem_fb_create(dev, file_priv, mode_cmd);
104
+}
105
+
95106 static const struct drm_mode_config_funcs mxsfb_mode_config_funcs = {
96
- .fb_create = drm_gem_fb_create,
107
+ .fb_create = mxsfb_fb_create,
97108 .atomic_check = drm_atomic_helper_check,
98109 .atomic_commit = drm_atomic_helper_commit,
99110 };
100111
101
-static void mxsfb_pipe_enable(struct drm_simple_display_pipe *pipe,
102
- struct drm_crtc_state *crtc_state,
103
- struct drm_plane_state *plane_state)
112
+static const struct drm_mode_config_helper_funcs mxsfb_mode_config_helpers = {
113
+ .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
114
+};
115
+
116
+static int mxsfb_attach_bridge(struct mxsfb_drm_private *mxsfb)
104117 {
105
- struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
118
+ struct drm_device *drm = mxsfb->drm;
119
+ struct drm_connector_list_iter iter;
120
+ struct drm_panel *panel;
121
+ struct drm_bridge *bridge;
122
+ int ret;
106123
107
- drm_panel_prepare(mxsfb->panel);
108
- mxsfb_crtc_enable(mxsfb);
109
- drm_panel_enable(mxsfb->panel);
110
-}
124
+ ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 0, 0, &panel,
125
+ &bridge);
126
+ if (ret)
127
+ return ret;
111128
112
-static void mxsfb_pipe_disable(struct drm_simple_display_pipe *pipe)
113
-{
114
- struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
129
+ if (panel) {
130
+ bridge = devm_drm_panel_bridge_add_typed(drm->dev, panel,
131
+ DRM_MODE_CONNECTOR_DPI);
132
+ if (IS_ERR(bridge))
133
+ return PTR_ERR(bridge);
134
+ }
115135
116
- drm_panel_disable(mxsfb->panel);
117
- mxsfb_crtc_disable(mxsfb);
118
- drm_panel_unprepare(mxsfb->panel);
119
-}
136
+ if (!bridge)
137
+ return -ENODEV;
120138
121
-static void mxsfb_pipe_update(struct drm_simple_display_pipe *pipe,
122
- struct drm_plane_state *plane_state)
123
-{
124
- struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
139
+ ret = drm_bridge_attach(&mxsfb->encoder, bridge, NULL, 0);
140
+ if (ret)
141
+ return dev_err_probe(drm->dev, ret, "Failed to attach bridge\n");
125142
126
- mxsfb_plane_atomic_update(mxsfb, plane_state);
127
-}
143
+ mxsfb->bridge = bridge;
128144
129
-static int mxsfb_pipe_enable_vblank(struct drm_simple_display_pipe *pipe)
130
-{
131
- struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
132
-
133
- /* Clear and enable VBLANK IRQ */
134
- mxsfb_enable_axi_clk(mxsfb);
135
- writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
136
- writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_SET);
137
- mxsfb_disable_axi_clk(mxsfb);
145
+ /*
146
+ * Get hold of the connector. This is a bit of a hack, until the bridge
147
+ * API gives us bus flags and formats.
148
+ */
149
+ drm_connector_list_iter_begin(drm, &iter);
150
+ mxsfb->connector = drm_connector_list_iter_next(&iter);
151
+ drm_connector_list_iter_end(&iter);
138152
139153 return 0;
140154 }
141155
142
-static void mxsfb_pipe_disable_vblank(struct drm_simple_display_pipe *pipe)
143
-{
144
- struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
145
-
146
- /* Disable and clear VBLANK IRQ */
147
- mxsfb_enable_axi_clk(mxsfb);
148
- writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_CLR);
149
- writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
150
- mxsfb_disable_axi_clk(mxsfb);
151
-}
152
-
153
-static struct drm_simple_display_pipe_funcs mxsfb_funcs = {
154
- .enable = mxsfb_pipe_enable,
155
- .disable = mxsfb_pipe_disable,
156
- .update = mxsfb_pipe_update,
157
- .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
158
- .enable_vblank = mxsfb_pipe_enable_vblank,
159
- .disable_vblank = mxsfb_pipe_disable_vblank,
160
-};
161
-
162
-static int mxsfb_load(struct drm_device *drm, unsigned long flags)
156
+static int mxsfb_load(struct drm_device *drm,
157
+ const struct mxsfb_devdata *devdata)
163158 {
164159 struct platform_device *pdev = to_platform_device(drm->dev);
165160 struct mxsfb_drm_private *mxsfb;
....@@ -170,8 +165,9 @@
170165 if (!mxsfb)
171166 return -ENOMEM;
172167
168
+ mxsfb->drm = drm;
173169 drm->dev_private = mxsfb;
174
- mxsfb->devdata = &mxsfb_devdata[pdev->id_entry->driver_data];
170
+ mxsfb->devdata = devdata;
175171
176172 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
177173 mxsfb->base = devm_ioremap_resource(drm->dev, res);
....@@ -196,32 +192,28 @@
196192
197193 pm_runtime_enable(drm->dev);
198194
195
+ /* Modeset init */
196
+ drm_mode_config_init(drm);
197
+
198
+ ret = mxsfb_kms_init(mxsfb);
199
+ if (ret < 0) {
200
+ dev_err(drm->dev, "Failed to initialize KMS pipeline\n");
201
+ goto err_vblank;
202
+ }
203
+
199204 ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
200205 if (ret < 0) {
201206 dev_err(drm->dev, "Failed to initialise vblank\n");
202207 goto err_vblank;
203208 }
204209
205
- /* Modeset init */
206
- drm_mode_config_init(drm);
210
+ /* Start with vertical blanking interrupt reporting disabled. */
211
+ drm_crtc_vblank_off(&mxsfb->crtc);
207212
208
- ret = mxsfb_create_output(drm);
209
- if (ret < 0) {
210
- dev_err(drm->dev, "Failed to create outputs\n");
211
- goto err_vblank;
212
- }
213
-
214
- ret = drm_simple_display_pipe_init(drm, &mxsfb->pipe, &mxsfb_funcs,
215
- mxsfb_formats, ARRAY_SIZE(mxsfb_formats), NULL,
216
- &mxsfb->connector);
217
- if (ret < 0) {
218
- dev_err(drm->dev, "Cannot setup simple display pipe\n");
219
- goto err_vblank;
220
- }
221
-
222
- ret = drm_panel_attach(mxsfb->panel, &mxsfb->connector);
213
+ ret = mxsfb_attach_bridge(mxsfb);
223214 if (ret) {
224
- dev_err(drm->dev, "Cannot connect panel\n");
215
+ if (ret != -EPROBE_DEFER)
216
+ dev_err(drm->dev, "Cannot connect bridge: %d\n", ret);
225217 goto err_vblank;
226218 }
227219
....@@ -230,6 +222,7 @@
230222 drm->mode_config.max_width = MXSFB_MAX_XRES;
231223 drm->mode_config.max_height = MXSFB_MAX_YRES;
232224 drm->mode_config.funcs = &mxsfb_mode_config_funcs;
225
+ drm->mode_config.helper_private = &mxsfb_mode_config_helpers;
233226
234227 drm_mode_config_reset(drm);
235228
....@@ -239,19 +232,10 @@
239232
240233 if (ret < 0) {
241234 dev_err(drm->dev, "Failed to install IRQ handler\n");
242
- goto err_irq;
235
+ goto err_vblank;
243236 }
244237
245238 drm_kms_helper_poll_init(drm);
246
-
247
- mxsfb->fbdev = drm_fbdev_cma_init(drm, 32,
248
- drm->mode_config.num_connector);
249
- if (IS_ERR(mxsfb->fbdev)) {
250
- ret = PTR_ERR(mxsfb->fbdev);
251
- mxsfb->fbdev = NULL;
252
- dev_err(drm->dev, "Failed to init FB CMA area\n");
253
- goto err_cma;
254
- }
255239
256240 platform_set_drvdata(pdev, drm);
257241
....@@ -259,10 +243,6 @@
259243
260244 return 0;
261245
262
-err_cma:
263
- drm_irq_uninstall(drm);
264
-err_irq:
265
- drm_panel_detach(mxsfb->panel);
266246 err_vblank:
267247 pm_runtime_disable(drm->dev);
268248
....@@ -271,11 +251,6 @@
271251
272252 static void mxsfb_unload(struct drm_device *drm)
273253 {
274
- struct mxsfb_drm_private *mxsfb = drm->dev_private;
275
-
276
- if (mxsfb->fbdev)
277
- drm_fbdev_cma_fini(mxsfb->fbdev);
278
-
279254 drm_kms_helper_poll_fini(drm);
280255 drm_mode_config_cleanup(drm);
281256
....@@ -288,18 +263,17 @@
288263 pm_runtime_disable(drm->dev);
289264 }
290265
291
-static void mxsfb_lastclose(struct drm_device *drm)
266
+static void mxsfb_irq_disable(struct drm_device *drm)
292267 {
293268 struct mxsfb_drm_private *mxsfb = drm->dev_private;
294269
295
- drm_fbdev_cma_restore_mode(mxsfb->fbdev);
296
-}
270
+ mxsfb_enable_axi_clk(mxsfb);
297271
298
-static void mxsfb_irq_preinstall(struct drm_device *drm)
299
-{
300
- struct mxsfb_drm_private *mxsfb = drm->dev_private;
272
+ /* Disable and clear VBLANK IRQ */
273
+ writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_CLR);
274
+ writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
301275
302
- mxsfb_pipe_disable_vblank(&mxsfb->pipe);
276
+ mxsfb_disable_axi_clk(mxsfb);
303277 }
304278
305279 static irqreturn_t mxsfb_irq_handler(int irq, void *data)
....@@ -308,16 +282,12 @@
308282 struct mxsfb_drm_private *mxsfb = drm->dev_private;
309283 u32 reg;
310284
311
- mxsfb_enable_axi_clk(mxsfb);
312
-
313285 reg = readl(mxsfb->base + LCDC_CTRL1);
314286
315287 if (reg & CTRL1_CUR_FRAME_DONE_IRQ)
316
- drm_crtc_handle_vblank(&mxsfb->pipe.crtc);
288
+ drm_crtc_handle_vblank(&mxsfb->crtc);
317289
318290 writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
319
-
320
- mxsfb_disable_axi_clk(mxsfb);
321291
322292 return IRQ_HANDLED;
323293 }
....@@ -325,25 +295,11 @@
325295 DEFINE_DRM_GEM_CMA_FOPS(fops);
326296
327297 static struct drm_driver mxsfb_driver = {
328
- .driver_features = DRIVER_GEM | DRIVER_MODESET |
329
- DRIVER_PRIME | DRIVER_ATOMIC |
330
- DRIVER_HAVE_IRQ,
331
- .lastclose = mxsfb_lastclose,
298
+ .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
332299 .irq_handler = mxsfb_irq_handler,
333
- .irq_preinstall = mxsfb_irq_preinstall,
334
- .irq_uninstall = mxsfb_irq_preinstall,
335
- .gem_free_object_unlocked = drm_gem_cma_free_object,
336
- .gem_vm_ops = &drm_gem_cma_vm_ops,
337
- .dumb_create = drm_gem_cma_dumb_create,
338
- .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
339
- .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
340
- .gem_prime_export = drm_gem_prime_export,
341
- .gem_prime_import = drm_gem_prime_import,
342
- .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
343
- .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
344
- .gem_prime_vmap = drm_gem_cma_prime_vmap,
345
- .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
346
- .gem_prime_mmap = drm_gem_cma_prime_mmap,
300
+ .irq_preinstall = mxsfb_irq_disable,
301
+ .irq_uninstall = mxsfb_irq_disable,
302
+ DRM_GEM_CMA_DRIVER_OPS,
347303 .fops = &fops,
348304 .name = "mxsfb-drm",
349305 .desc = "MXSFB Controller DRM",
....@@ -352,18 +308,10 @@
352308 .minor = 0,
353309 };
354310
355
-static const struct platform_device_id mxsfb_devtype[] = {
356
- { .name = "imx23-fb", .driver_data = MXSFB_V3, },
357
- { .name = "imx28-fb", .driver_data = MXSFB_V4, },
358
- { .name = "imx6sx-fb", .driver_data = MXSFB_V4, },
359
- { /* sentinel */ }
360
-};
361
-MODULE_DEVICE_TABLE(platform, mxsfb_devtype);
362
-
363311 static const struct of_device_id mxsfb_dt_ids[] = {
364
- { .compatible = "fsl,imx23-lcdif", .data = &mxsfb_devtype[0], },
365
- { .compatible = "fsl,imx28-lcdif", .data = &mxsfb_devtype[1], },
366
- { .compatible = "fsl,imx6sx-lcdif", .data = &mxsfb_devtype[2], },
312
+ { .compatible = "fsl,imx23-lcdif", .data = &mxsfb_devdata[MXSFB_V3], },
313
+ { .compatible = "fsl,imx28-lcdif", .data = &mxsfb_devdata[MXSFB_V4], },
314
+ { .compatible = "fsl,imx6sx-lcdif", .data = &mxsfb_devdata[MXSFB_V6], },
367315 { /* sentinel */ }
368316 };
369317 MODULE_DEVICE_TABLE(of, mxsfb_dt_ids);
....@@ -378,14 +326,11 @@
378326 if (!pdev->dev.of_node)
379327 return -ENODEV;
380328
381
- if (of_id)
382
- pdev->id_entry = of_id->data;
383
-
384329 drm = drm_dev_alloc(&mxsfb_driver, &pdev->dev);
385330 if (IS_ERR(drm))
386331 return PTR_ERR(drm);
387332
388
- ret = mxsfb_load(drm, 0);
333
+ ret = mxsfb_load(drm, of_id->data);
389334 if (ret)
390335 goto err_free;
391336
....@@ -393,12 +338,14 @@
393338 if (ret)
394339 goto err_unload;
395340
341
+ drm_fbdev_generic_setup(drm, 32);
342
+
396343 return 0;
397344
398345 err_unload:
399346 mxsfb_unload(drm);
400347 err_free:
401
- drm_dev_unref(drm);
348
+ drm_dev_put(drm);
402349
403350 return ret;
404351 }
....@@ -409,18 +356,38 @@
409356
410357 drm_dev_unregister(drm);
411358 mxsfb_unload(drm);
412
- drm_dev_unref(drm);
359
+ drm_dev_put(drm);
413360
414361 return 0;
415362 }
416363
364
+#ifdef CONFIG_PM_SLEEP
365
+static int mxsfb_suspend(struct device *dev)
366
+{
367
+ struct drm_device *drm = dev_get_drvdata(dev);
368
+
369
+ return drm_mode_config_helper_suspend(drm);
370
+}
371
+
372
+static int mxsfb_resume(struct device *dev)
373
+{
374
+ struct drm_device *drm = dev_get_drvdata(dev);
375
+
376
+ return drm_mode_config_helper_resume(drm);
377
+}
378
+#endif
379
+
380
+static const struct dev_pm_ops mxsfb_pm_ops = {
381
+ SET_SYSTEM_SLEEP_PM_OPS(mxsfb_suspend, mxsfb_resume)
382
+};
383
+
417384 static struct platform_driver mxsfb_platform_driver = {
418385 .probe = mxsfb_probe,
419386 .remove = mxsfb_remove,
420
- .id_table = mxsfb_devtype,
421387 .driver = {
422388 .name = "mxsfb",
423389 .of_match_table = mxsfb_dt_ids,
390
+ .pm = &mxsfb_pm_ops,
424391 },
425392 };
426393