diff options
author | Dave Airlie <airlied@redhat.com> | 2015-08-20 00:11:17 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2015-08-20 00:11:17 -0400 |
commit | aaba64487a96df6584a05d8898634307f3c86790 (patch) | |
tree | a6a9690ee1491b7ffd3f8456c9c1575021f8d1a0 /drivers | |
parent | d072f4654464b242e536a03102ebd3d481f6b418 (diff) | |
parent | b55a1b9c55ee9ed5b7d1d2acbabb078a454dbeea (diff) |
Merge branch 'drm-next-fsl-dcu' of https://github.com/Jianwei-Wang/linux-drm-fsl-dcu into drm-next
Merge Freescale DCU FRM driver.
* 'drm-next-fsl-dcu' of https://github.com/Jianwei-Wang/linux-drm-fsl-dcu:
MAINTAINERS: Add Freescale DCU DRM driver maintainer
devicetree: Add NEC to the vendor-prefix list
drm/layerscape: Add Freescale DCU DRM driver
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/Kconfig | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/Kconfig | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/Makefile | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c | 210 | ||||
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.h | 19 | ||||
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c | 404 | ||||
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h | 197 | ||||
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_fbdev.c | 23 | ||||
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c | 43 | ||||
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_output.h | 33 | ||||
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c | 261 | ||||
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.h | 17 | ||||
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 182 |
14 files changed, 1417 insertions, 0 deletions
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index df99b0132134..1a0a8df2eed8 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig | |||
@@ -251,6 +251,8 @@ source "drivers/gpu/drm/virtio/Kconfig" | |||
251 | 251 | ||
252 | source "drivers/gpu/drm/msm/Kconfig" | 252 | source "drivers/gpu/drm/msm/Kconfig" |
253 | 253 | ||
254 | source "drivers/gpu/drm/fsl-dcu/Kconfig" | ||
255 | |||
254 | source "drivers/gpu/drm/tegra/Kconfig" | 256 | source "drivers/gpu/drm/tegra/Kconfig" |
255 | 257 | ||
256 | source "drivers/gpu/drm/panel/Kconfig" | 258 | source "drivers/gpu/drm/panel/Kconfig" |
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 8858510437ea..45e7719846b1 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile | |||
@@ -70,3 +70,4 @@ obj-$(CONFIG_DRM_IMX) += imx/ | |||
70 | obj-y += i2c/ | 70 | obj-y += i2c/ |
71 | obj-y += panel/ | 71 | obj-y += panel/ |
72 | obj-y += bridge/ | 72 | obj-y += bridge/ |
73 | obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/ | ||
diff --git a/drivers/gpu/drm/fsl-dcu/Kconfig b/drivers/gpu/drm/fsl-dcu/Kconfig new file mode 100644 index 000000000000..c78cf3f605d0 --- /dev/null +++ b/drivers/gpu/drm/fsl-dcu/Kconfig | |||
@@ -0,0 +1,18 @@ | |||
1 | config DRM_FSL_DCU | ||
2 | tristate "DRM Support for Freescale DCU" | ||
3 | depends on DRM && OF && ARM | ||
4 | select BACKLIGHT_CLASS_DEVICE | ||
5 | select BACKLIGHT_LCD_SUPPORT | ||
6 | select DRM_KMS_HELPER | ||
7 | select DRM_KMS_CMA_HELPER | ||
8 | select DRM_KMS_FB_HELPER | ||
9 | select DRM_PANEL | ||
10 | select FB_SYS_FILLRECT | ||
11 | select FB_SYS_COPYAREA | ||
12 | select FB_SYS_IMAGEBLIT | ||
13 | select FB_SYS_FOPS | ||
14 | select REGMAP_MMIO | ||
15 | select VIDEOMODE_HELPERS | ||
16 | help | ||
17 | Choose this option if you have an Freescale DCU chipset. | ||
18 | If M is selected the module will be called fsl-dcu-drm. | ||
diff --git a/drivers/gpu/drm/fsl-dcu/Makefile b/drivers/gpu/drm/fsl-dcu/Makefile new file mode 100644 index 000000000000..6ea1523ae6ec --- /dev/null +++ b/drivers/gpu/drm/fsl-dcu/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | fsl-dcu-drm-y := fsl_dcu_drm_drv.o \ | ||
2 | fsl_dcu_drm_kms.o \ | ||
3 | fsl_dcu_drm_rgb.o \ | ||
4 | fsl_dcu_drm_plane.o \ | ||
5 | fsl_dcu_drm_crtc.o \ | ||
6 | fsl_dcu_drm_fbdev.o | ||
7 | obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu-drm.o | ||
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c new file mode 100644 index 000000000000..82a3d311e164 --- /dev/null +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c | |||
@@ -0,0 +1,210 @@ | |||
1 | /* | ||
2 | * Copyright 2015 Freescale Semiconductor, Inc. | ||
3 | * | ||
4 | * Freescale DCU drm device driver | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk.h> | ||
13 | #include <linux/regmap.h> | ||
14 | |||
15 | #include <drm/drmP.h> | ||
16 | #include <drm/drm_atomic.h> | ||
17 | #include <drm/drm_atomic_helper.h> | ||
18 | #include <drm/drm_crtc.h> | ||
19 | #include <drm/drm_crtc_helper.h> | ||
20 | |||
21 | #include "fsl_dcu_drm_crtc.h" | ||
22 | #include "fsl_dcu_drm_drv.h" | ||
23 | #include "fsl_dcu_drm_plane.h" | ||
24 | |||
25 | static void fsl_dcu_drm_crtc_atomic_begin(struct drm_crtc *crtc, | ||
26 | struct drm_crtc_state *old_crtc_state) | ||
27 | { | ||
28 | } | ||
29 | |||
30 | static int fsl_dcu_drm_crtc_atomic_check(struct drm_crtc *crtc, | ||
31 | struct drm_crtc_state *state) | ||
32 | { | ||
33 | return 0; | ||
34 | } | ||
35 | |||
36 | static void fsl_dcu_drm_crtc_atomic_flush(struct drm_crtc *crtc, | ||
37 | struct drm_crtc_state *old_crtc_state) | ||
38 | { | ||
39 | } | ||
40 | |||
41 | static void fsl_dcu_drm_disable_crtc(struct drm_crtc *crtc) | ||
42 | { | ||
43 | struct drm_device *dev = crtc->dev; | ||
44 | struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; | ||
45 | int ret; | ||
46 | |||
47 | ret = regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE, | ||
48 | DCU_MODE_DCU_MODE_MASK, | ||
49 | DCU_MODE_DCU_MODE(DCU_MODE_OFF)); | ||
50 | if (ret) | ||
51 | dev_err(fsl_dev->dev, "Disable CRTC failed\n"); | ||
52 | ret = regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, | ||
53 | DCU_UPDATE_MODE_READREG); | ||
54 | if (ret) | ||
55 | dev_err(fsl_dev->dev, "Enable CRTC failed\n"); | ||
56 | } | ||
57 | |||
58 | static void fsl_dcu_drm_crtc_enable(struct drm_crtc *crtc) | ||
59 | { | ||
60 | struct drm_device *dev = crtc->dev; | ||
61 | struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; | ||
62 | int ret; | ||
63 | |||
64 | ret = regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE, | ||
65 | DCU_MODE_DCU_MODE_MASK, | ||
66 | DCU_MODE_DCU_MODE(DCU_MODE_NORMAL)); | ||
67 | if (ret) | ||
68 | dev_err(fsl_dev->dev, "Enable CRTC failed\n"); | ||
69 | ret = regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, | ||
70 | DCU_UPDATE_MODE_READREG); | ||
71 | if (ret) | ||
72 | dev_err(fsl_dev->dev, "Enable CRTC failed\n"); | ||
73 | } | ||
74 | |||
75 | static bool fsl_dcu_drm_crtc_mode_fixup(struct drm_crtc *crtc, | ||
76 | const struct drm_display_mode *mode, | ||
77 | struct drm_display_mode *adjusted_mode) | ||
78 | { | ||
79 | return true; | ||
80 | } | ||
81 | |||
82 | static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) | ||
83 | { | ||
84 | struct drm_device *dev = crtc->dev; | ||
85 | struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; | ||
86 | struct drm_display_mode *mode = &crtc->state->mode; | ||
87 | unsigned int hbp, hfp, hsw, vbp, vfp, vsw, div, index; | ||
88 | unsigned long dcuclk; | ||
89 | int ret; | ||
90 | |||
91 | index = drm_crtc_index(crtc); | ||
92 | dcuclk = clk_get_rate(fsl_dev->clk); | ||
93 | div = dcuclk / mode->clock / 1000; | ||
94 | |||
95 | /* Configure timings: */ | ||
96 | hbp = mode->htotal - mode->hsync_end; | ||
97 | hfp = mode->hsync_start - mode->hdisplay; | ||
98 | hsw = mode->hsync_end - mode->hsync_start; | ||
99 | vbp = mode->vtotal - mode->vsync_end; | ||
100 | vfp = mode->vsync_start - mode->vdisplay; | ||
101 | vsw = mode->vsync_end - mode->vsync_start; | ||
102 | |||
103 | ret = regmap_write(fsl_dev->regmap, DCU_HSYN_PARA, | ||
104 | DCU_HSYN_PARA_BP(hbp) | | ||
105 | DCU_HSYN_PARA_PW(hsw) | | ||
106 | DCU_HSYN_PARA_FP(hfp)); | ||
107 | if (ret) | ||
108 | goto set_failed; | ||
109 | ret = regmap_write(fsl_dev->regmap, DCU_VSYN_PARA, | ||
110 | DCU_VSYN_PARA_BP(vbp) | | ||
111 | DCU_VSYN_PARA_PW(vsw) | | ||
112 | DCU_VSYN_PARA_FP(vfp)); | ||
113 | if (ret) | ||
114 | goto set_failed; | ||
115 | ret = regmap_write(fsl_dev->regmap, DCU_DISP_SIZE, | ||
116 | DCU_DISP_SIZE_DELTA_Y(mode->vdisplay) | | ||
117 | DCU_DISP_SIZE_DELTA_X(mode->hdisplay)); | ||
118 | if (ret) | ||
119 | goto set_failed; | ||
120 | ret = regmap_write(fsl_dev->regmap, DCU_DIV_RATIO, div); | ||
121 | if (ret) | ||
122 | goto set_failed; | ||
123 | ret = regmap_write(fsl_dev->regmap, DCU_SYN_POL, | ||
124 | DCU_SYN_POL_INV_VS_LOW | DCU_SYN_POL_INV_HS_LOW); | ||
125 | if (ret) | ||
126 | goto set_failed; | ||
127 | ret = regmap_write(fsl_dev->regmap, DCU_BGND, DCU_BGND_R(0) | | ||
128 | DCU_BGND_G(0) | DCU_BGND_B(0)); | ||
129 | if (ret) | ||
130 | goto set_failed; | ||
131 | ret = regmap_write(fsl_dev->regmap, DCU_DCU_MODE, | ||
132 | DCU_MODE_BLEND_ITER(1) | DCU_MODE_RASTER_EN); | ||
133 | if (ret) | ||
134 | goto set_failed; | ||
135 | ret = regmap_write(fsl_dev->regmap, DCU_THRESHOLD, | ||
136 | DCU_THRESHOLD_LS_BF_VS(BF_VS_VAL) | | ||
137 | DCU_THRESHOLD_OUT_BUF_HIGH(BUF_MAX_VAL) | | ||
138 | DCU_THRESHOLD_OUT_BUF_LOW(BUF_MIN_VAL)); | ||
139 | if (ret) | ||
140 | goto set_failed; | ||
141 | ret = regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, | ||
142 | DCU_UPDATE_MODE_READREG); | ||
143 | if (ret) | ||
144 | goto set_failed; | ||
145 | return; | ||
146 | set_failed: | ||
147 | dev_err(dev->dev, "set DCU register failed\n"); | ||
148 | } | ||
149 | |||
150 | static const struct drm_crtc_helper_funcs fsl_dcu_drm_crtc_helper_funcs = { | ||
151 | .atomic_begin = fsl_dcu_drm_crtc_atomic_begin, | ||
152 | .atomic_check = fsl_dcu_drm_crtc_atomic_check, | ||
153 | .atomic_flush = fsl_dcu_drm_crtc_atomic_flush, | ||
154 | .disable = fsl_dcu_drm_disable_crtc, | ||
155 | .enable = fsl_dcu_drm_crtc_enable, | ||
156 | .mode_fixup = fsl_dcu_drm_crtc_mode_fixup, | ||
157 | .mode_set_nofb = fsl_dcu_drm_crtc_mode_set_nofb, | ||
158 | }; | ||
159 | |||
160 | static const struct drm_crtc_funcs fsl_dcu_drm_crtc_funcs = { | ||
161 | .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, | ||
162 | .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, | ||
163 | .destroy = drm_crtc_cleanup, | ||
164 | .page_flip = drm_atomic_helper_page_flip, | ||
165 | .reset = drm_atomic_helper_crtc_reset, | ||
166 | .set_config = drm_atomic_helper_set_config, | ||
167 | }; | ||
168 | |||
169 | int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev) | ||
170 | { | ||
171 | struct drm_plane *primary; | ||
172 | struct drm_crtc *crtc = &fsl_dev->crtc; | ||
173 | unsigned int i, j, reg_num; | ||
174 | int ret; | ||
175 | |||
176 | primary = fsl_dcu_drm_primary_create_plane(fsl_dev->drm); | ||
177 | ret = drm_crtc_init_with_planes(fsl_dev->drm, crtc, primary, NULL, | ||
178 | &fsl_dcu_drm_crtc_funcs); | ||
179 | if (ret < 0) | ||
180 | return ret; | ||
181 | |||
182 | drm_crtc_helper_add(crtc, &fsl_dcu_drm_crtc_helper_funcs); | ||
183 | |||
184 | if (!strcmp(fsl_dev->soc->name, "ls1021a")) | ||
185 | reg_num = LS1021A_LAYER_REG_NUM; | ||
186 | else | ||
187 | reg_num = VF610_LAYER_REG_NUM; | ||
188 | for (i = 0; i <= fsl_dev->soc->total_layer; i++) { | ||
189 | for (j = 0; j < reg_num; j++) { | ||
190 | ret = regmap_write(fsl_dev->regmap, | ||
191 | DCU_CTRLDESCLN(i, j), 0); | ||
192 | if (ret) | ||
193 | goto init_failed; | ||
194 | } | ||
195 | } | ||
196 | ret = regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE, | ||
197 | DCU_MODE_DCU_MODE_MASK, | ||
198 | DCU_MODE_DCU_MODE(DCU_MODE_OFF)); | ||
199 | if (ret) | ||
200 | goto init_failed; | ||
201 | ret = regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, | ||
202 | DCU_UPDATE_MODE_READREG); | ||
203 | if (ret) | ||
204 | goto init_failed; | ||
205 | |||
206 | return 0; | ||
207 | init_failed: | ||
208 | dev_err(fsl_dev->dev, "init DCU register failed\n"); | ||
209 | return ret; | ||
210 | } | ||
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.h b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.h new file mode 100644 index 000000000000..43d4da2c5fe5 --- /dev/null +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.h | |||
@@ -0,0 +1,19 @@ | |||
1 | /* | ||
2 | * Copyright 2015 Freescale Semiconductor, Inc. | ||
3 | * | ||
4 | * Freescale DCU drm device driver | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #ifndef __FSL_DCU_DRM_CRTC_H__ | ||
13 | #define __FSL_DCU_DRM_CRTC_H__ | ||
14 | |||
15 | struct fsl_dcu_drm_device; | ||
16 | |||
17 | int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev); | ||
18 | |||
19 | #endif /* __FSL_DCU_DRM_CRTC_H__ */ | ||
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c new file mode 100644 index 000000000000..9a8e2da47158 --- /dev/null +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c | |||
@@ -0,0 +1,404 @@ | |||
1 | /* | ||
2 | * Copyright 2015 Freescale Semiconductor, Inc. | ||
3 | * | ||
4 | * Freescale DCU drm device driver | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk.h> | ||
13 | #include <linux/clk-provider.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <linux/mfd/syscon.h> | ||
16 | #include <linux/mm.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/of_platform.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/pm.h> | ||
21 | #include <linux/pm_runtime.h> | ||
22 | #include <linux/regmap.h> | ||
23 | |||
24 | #include <drm/drmP.h> | ||
25 | #include <drm/drm_crtc_helper.h> | ||
26 | #include <drm/drm_gem_cma_helper.h> | ||
27 | |||
28 | #include "fsl_dcu_drm_crtc.h" | ||
29 | #include "fsl_dcu_drm_drv.h" | ||
30 | |||
31 | static const struct regmap_config fsl_dcu_regmap_config = { | ||
32 | .reg_bits = 32, | ||
33 | .reg_stride = 4, | ||
34 | .val_bits = 32, | ||
35 | .cache_type = REGCACHE_RBTREE, | ||
36 | }; | ||
37 | |||
38 | static int fsl_dcu_drm_irq_init(struct drm_device *dev) | ||
39 | { | ||
40 | struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; | ||
41 | unsigned int value; | ||
42 | int ret; | ||
43 | |||
44 | ret = drm_irq_install(dev, fsl_dev->irq); | ||
45 | if (ret < 0) | ||
46 | dev_err(dev->dev, "failed to install IRQ handler\n"); | ||
47 | |||
48 | ret = regmap_write(fsl_dev->regmap, DCU_INT_STATUS, 0); | ||
49 | if (ret) | ||
50 | dev_err(dev->dev, "set DCU_INT_STATUS failed\n"); | ||
51 | ret = regmap_read(fsl_dev->regmap, DCU_INT_MASK, &value); | ||
52 | if (ret) | ||
53 | dev_err(dev->dev, "read DCU_INT_MASK failed\n"); | ||
54 | value &= DCU_INT_MASK_VBLANK; | ||
55 | ret = regmap_write(fsl_dev->regmap, DCU_INT_MASK, value); | ||
56 | if (ret) | ||
57 | dev_err(dev->dev, "set DCU_INT_MASK failed\n"); | ||
58 | ret = regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, | ||
59 | DCU_UPDATE_MODE_READREG); | ||
60 | if (ret) | ||
61 | dev_err(dev->dev, "set DCU_UPDATE_MODE failed\n"); | ||
62 | |||
63 | return ret; | ||
64 | } | ||
65 | |||
66 | static int fsl_dcu_load(struct drm_device *drm, unsigned long flags) | ||
67 | { | ||
68 | struct device *dev = drm->dev; | ||
69 | struct fsl_dcu_drm_device *fsl_dev = drm->dev_private; | ||
70 | int ret; | ||
71 | |||
72 | ret = fsl_dcu_drm_modeset_init(fsl_dev); | ||
73 | if (ret < 0) { | ||
74 | dev_err(dev, "failed to initialize mode setting\n"); | ||
75 | return ret; | ||
76 | } | ||
77 | |||
78 | ret = drm_vblank_init(drm, drm->mode_config.num_crtc); | ||
79 | if (ret < 0) { | ||
80 | dev_err(dev, "failed to initialize vblank\n"); | ||
81 | goto done; | ||
82 | } | ||
83 | drm->vblank_disable_allowed = true; | ||
84 | |||
85 | ret = fsl_dcu_drm_irq_init(drm); | ||
86 | if (ret < 0) | ||
87 | goto done; | ||
88 | drm->irq_enabled = true; | ||
89 | |||
90 | fsl_dcu_fbdev_init(drm); | ||
91 | |||
92 | return 0; | ||
93 | done: | ||
94 | if (ret) { | ||
95 | drm_mode_config_cleanup(drm); | ||
96 | drm_vblank_cleanup(drm); | ||
97 | drm_irq_uninstall(drm); | ||
98 | drm->dev_private = NULL; | ||
99 | } | ||
100 | |||
101 | return ret; | ||
102 | } | ||
103 | |||
104 | static int fsl_dcu_unload(struct drm_device *dev) | ||
105 | { | ||
106 | drm_mode_config_cleanup(dev); | ||
107 | drm_vblank_cleanup(dev); | ||
108 | drm_irq_uninstall(dev); | ||
109 | |||
110 | dev->dev_private = NULL; | ||
111 | |||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static void fsl_dcu_drm_preclose(struct drm_device *dev, struct drm_file *file) | ||
116 | { | ||
117 | } | ||
118 | |||
119 | static irqreturn_t fsl_dcu_drm_irq(int irq, void *arg) | ||
120 | { | ||
121 | struct drm_device *dev = arg; | ||
122 | struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; | ||
123 | unsigned int int_status; | ||
124 | int ret; | ||
125 | |||
126 | ret = regmap_read(fsl_dev->regmap, DCU_INT_STATUS, &int_status); | ||
127 | if (ret) | ||
128 | dev_err(dev->dev, "set DCU_INT_STATUS failed\n"); | ||
129 | if (int_status & DCU_INT_STATUS_VBLANK) | ||
130 | drm_handle_vblank(dev, 0); | ||
131 | |||
132 | ret = regmap_write(fsl_dev->regmap, DCU_INT_STATUS, 0xffffffff); | ||
133 | if (ret) | ||
134 | dev_err(dev->dev, "set DCU_INT_STATUS failed\n"); | ||
135 | ret = regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, | ||
136 | DCU_UPDATE_MODE_READREG); | ||
137 | if (ret) | ||
138 | dev_err(dev->dev, "set DCU_UPDATE_MODE failed\n"); | ||
139 | |||
140 | return IRQ_HANDLED; | ||
141 | } | ||
142 | |||
143 | static int fsl_dcu_drm_enable_vblank(struct drm_device *dev, int crtc) | ||
144 | { | ||
145 | struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; | ||
146 | unsigned int value; | ||
147 | int ret; | ||
148 | |||
149 | ret = regmap_read(fsl_dev->regmap, DCU_INT_MASK, &value); | ||
150 | if (ret) | ||
151 | dev_err(dev->dev, "read DCU_INT_MASK failed\n"); | ||
152 | value &= ~DCU_INT_MASK_VBLANK; | ||
153 | ret = regmap_write(fsl_dev->regmap, DCU_INT_MASK, value); | ||
154 | if (ret) | ||
155 | dev_err(dev->dev, "set DCU_INT_MASK failed\n"); | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static void fsl_dcu_drm_disable_vblank(struct drm_device *dev, int crtc) | ||
160 | { | ||
161 | struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; | ||
162 | unsigned int value; | ||
163 | int ret; | ||
164 | |||
165 | ret = regmap_read(fsl_dev->regmap, DCU_INT_MASK, &value); | ||
166 | if (ret) | ||
167 | dev_err(dev->dev, "read DCU_INT_MASK failed\n"); | ||
168 | value |= DCU_INT_MASK_VBLANK; | ||
169 | ret = regmap_write(fsl_dev->regmap, DCU_INT_MASK, value); | ||
170 | if (ret) | ||
171 | dev_err(dev->dev, "set DCU_INT_MASK failed\n"); | ||
172 | } | ||
173 | |||
174 | static const struct file_operations fsl_dcu_drm_fops = { | ||
175 | .owner = THIS_MODULE, | ||
176 | .open = drm_open, | ||
177 | .release = drm_release, | ||
178 | .unlocked_ioctl = drm_ioctl, | ||
179 | #ifdef CONFIG_COMPAT | ||
180 | .compat_ioctl = drm_compat_ioctl, | ||
181 | #endif | ||
182 | .poll = drm_poll, | ||
183 | .read = drm_read, | ||
184 | .llseek = no_llseek, | ||
185 | .mmap = drm_gem_cma_mmap, | ||
186 | }; | ||
187 | |||
188 | static struct drm_driver fsl_dcu_drm_driver = { | ||
189 | .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET | ||
190 | | DRIVER_PRIME | DRIVER_ATOMIC, | ||
191 | .load = fsl_dcu_load, | ||
192 | .unload = fsl_dcu_unload, | ||
193 | .preclose = fsl_dcu_drm_preclose, | ||
194 | .irq_handler = fsl_dcu_drm_irq, | ||
195 | .get_vblank_counter = drm_vblank_count, | ||
196 | .enable_vblank = fsl_dcu_drm_enable_vblank, | ||
197 | .disable_vblank = fsl_dcu_drm_disable_vblank, | ||
198 | .gem_free_object = drm_gem_cma_free_object, | ||
199 | .gem_vm_ops = &drm_gem_cma_vm_ops, | ||
200 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, | ||
201 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, | ||
202 | .gem_prime_import = drm_gem_prime_import, | ||
203 | .gem_prime_export = drm_gem_prime_export, | ||
204 | .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, | ||
205 | .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, | ||
206 | .gem_prime_vmap = drm_gem_cma_prime_vmap, | ||
207 | .gem_prime_vunmap = drm_gem_cma_prime_vunmap, | ||
208 | .gem_prime_mmap = drm_gem_cma_prime_mmap, | ||
209 | .dumb_create = drm_gem_cma_dumb_create, | ||
210 | .dumb_map_offset = drm_gem_cma_dumb_map_offset, | ||
211 | .dumb_destroy = drm_gem_dumb_destroy, | ||
212 | .fops = &fsl_dcu_drm_fops, | ||
213 | .name = "fsl-dcu-drm", | ||
214 | .desc = "Freescale DCU DRM", | ||
215 | .date = "20150213", | ||
216 | .major = 1, | ||
217 | .minor = 0, | ||
218 | }; | ||
219 | |||
220 | #ifdef CONFIG_PM_SLEEP | ||
221 | static int fsl_dcu_drm_pm_suspend(struct device *dev) | ||
222 | { | ||
223 | struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev); | ||
224 | |||
225 | if (!fsl_dev) | ||
226 | return 0; | ||
227 | |||
228 | drm_kms_helper_poll_disable(fsl_dev->drm); | ||
229 | regcache_cache_only(fsl_dev->regmap, true); | ||
230 | regcache_mark_dirty(fsl_dev->regmap); | ||
231 | clk_disable(fsl_dev->clk); | ||
232 | clk_unprepare(fsl_dev->clk); | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static int fsl_dcu_drm_pm_resume(struct device *dev) | ||
238 | { | ||
239 | struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev); | ||
240 | int ret; | ||
241 | |||
242 | if (!fsl_dev) | ||
243 | return 0; | ||
244 | |||
245 | ret = clk_enable(fsl_dev->clk); | ||
246 | if (ret < 0) { | ||
247 | dev_err(dev, "failed to enable dcu clk\n"); | ||
248 | clk_unprepare(fsl_dev->clk); | ||
249 | return ret; | ||
250 | } | ||
251 | ret = clk_prepare(fsl_dev->clk); | ||
252 | if (ret < 0) { | ||
253 | dev_err(dev, "failed to prepare dcu clk\n"); | ||
254 | return ret; | ||
255 | } | ||
256 | |||
257 | drm_kms_helper_poll_enable(fsl_dev->drm); | ||
258 | regcache_cache_only(fsl_dev->regmap, false); | ||
259 | regcache_sync(fsl_dev->regmap); | ||
260 | |||
261 | return 0; | ||
262 | } | ||
263 | #endif | ||
264 | |||
265 | static const struct dev_pm_ops fsl_dcu_drm_pm_ops = { | ||
266 | SET_SYSTEM_SLEEP_PM_OPS(fsl_dcu_drm_pm_suspend, fsl_dcu_drm_pm_resume) | ||
267 | }; | ||
268 | |||
269 | static const struct fsl_dcu_soc_data fsl_dcu_ls1021a_data = { | ||
270 | .name = "ls1021a", | ||
271 | .total_layer = 16, | ||
272 | .max_layer = 4, | ||
273 | }; | ||
274 | |||
275 | static const struct fsl_dcu_soc_data fsl_dcu_vf610_data = { | ||
276 | .name = "vf610", | ||
277 | .total_layer = 64, | ||
278 | .max_layer = 6, | ||
279 | }; | ||
280 | |||
281 | static const struct of_device_id fsl_dcu_of_match[] = { | ||
282 | { | ||
283 | .compatible = "fsl,ls1021a-dcu", | ||
284 | .data = &fsl_dcu_ls1021a_data, | ||
285 | }, { | ||
286 | .compatible = "fsl,vf610-dcu", | ||
287 | .data = &fsl_dcu_vf610_data, | ||
288 | }, { | ||
289 | }, | ||
290 | }; | ||
291 | MODULE_DEVICE_TABLE(of, fsl_dcu_of_match); | ||
292 | |||
293 | static int fsl_dcu_drm_probe(struct platform_device *pdev) | ||
294 | { | ||
295 | struct fsl_dcu_drm_device *fsl_dev; | ||
296 | struct drm_device *drm; | ||
297 | struct device *dev = &pdev->dev; | ||
298 | struct resource *res; | ||
299 | void __iomem *base; | ||
300 | struct drm_driver *driver = &fsl_dcu_drm_driver; | ||
301 | const struct of_device_id *id; | ||
302 | int ret; | ||
303 | |||
304 | fsl_dev = devm_kzalloc(dev, sizeof(*fsl_dev), GFP_KERNEL); | ||
305 | if (!fsl_dev) | ||
306 | return -ENOMEM; | ||
307 | |||
308 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
309 | if (!res) { | ||
310 | dev_err(dev, "could not get memory IO resource\n"); | ||
311 | return -ENODEV; | ||
312 | } | ||
313 | |||
314 | base = devm_ioremap_resource(dev, res); | ||
315 | if (IS_ERR(base)) { | ||
316 | ret = PTR_ERR(base); | ||
317 | return ret; | ||
318 | } | ||
319 | |||
320 | fsl_dev->irq = platform_get_irq(pdev, 0); | ||
321 | if (fsl_dev->irq < 0) { | ||
322 | dev_err(dev, "failed to get irq\n"); | ||
323 | return -ENXIO; | ||
324 | } | ||
325 | |||
326 | fsl_dev->clk = devm_clk_get(dev, "dcu"); | ||
327 | if (IS_ERR(fsl_dev->clk)) { | ||
328 | ret = PTR_ERR(fsl_dev->clk); | ||
329 | dev_err(dev, "failed to get dcu clock\n"); | ||
330 | return ret; | ||
331 | } | ||
332 | ret = clk_prepare(fsl_dev->clk); | ||
333 | if (ret < 0) { | ||
334 | dev_err(dev, "failed to prepare dcu clk\n"); | ||
335 | return ret; | ||
336 | } | ||
337 | ret = clk_enable(fsl_dev->clk); | ||
338 | if (ret < 0) { | ||
339 | dev_err(dev, "failed to enable dcu clk\n"); | ||
340 | clk_unprepare(fsl_dev->clk); | ||
341 | return ret; | ||
342 | } | ||
343 | |||
344 | fsl_dev->regmap = devm_regmap_init_mmio(dev, base, | ||
345 | &fsl_dcu_regmap_config); | ||
346 | if (IS_ERR(fsl_dev->regmap)) { | ||
347 | dev_err(dev, "regmap init failed\n"); | ||
348 | return PTR_ERR(fsl_dev->regmap); | ||
349 | } | ||
350 | |||
351 | id = of_match_node(fsl_dcu_of_match, pdev->dev.of_node); | ||
352 | if (!id) | ||
353 | return -ENODEV; | ||
354 | fsl_dev->soc = id->data; | ||
355 | |||
356 | drm = drm_dev_alloc(driver, dev); | ||
357 | if (!drm) | ||
358 | return -ENOMEM; | ||
359 | |||
360 | fsl_dev->dev = dev; | ||
361 | fsl_dev->drm = drm; | ||
362 | fsl_dev->np = dev->of_node; | ||
363 | drm->dev_private = fsl_dev; | ||
364 | dev_set_drvdata(dev, fsl_dev); | ||
365 | drm_dev_set_unique(drm, dev_name(dev)); | ||
366 | |||
367 | ret = drm_dev_register(drm, 0); | ||
368 | if (ret < 0) | ||
369 | goto unref; | ||
370 | |||
371 | DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", driver->name, | ||
372 | driver->major, driver->minor, driver->patchlevel, | ||
373 | driver->date, drm->primary->index); | ||
374 | |||
375 | return 0; | ||
376 | |||
377 | unref: | ||
378 | drm_dev_unref(drm); | ||
379 | return ret; | ||
380 | } | ||
381 | |||
382 | static int fsl_dcu_drm_remove(struct platform_device *pdev) | ||
383 | { | ||
384 | struct fsl_dcu_drm_device *fsl_dev = platform_get_drvdata(pdev); | ||
385 | |||
386 | drm_put_dev(fsl_dev->drm); | ||
387 | |||
388 | return 0; | ||
389 | } | ||
390 | |||
391 | static struct platform_driver fsl_dcu_drm_platform_driver = { | ||
392 | .probe = fsl_dcu_drm_probe, | ||
393 | .remove = fsl_dcu_drm_remove, | ||
394 | .driver = { | ||
395 | .name = "fsl-dcu", | ||
396 | .pm = &fsl_dcu_drm_pm_ops, | ||
397 | .of_match_table = fsl_dcu_of_match, | ||
398 | }, | ||
399 | }; | ||
400 | |||
401 | module_platform_driver(fsl_dcu_drm_platform_driver); | ||
402 | |||
403 | MODULE_DESCRIPTION("Freescale DCU DRM Driver"); | ||
404 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h new file mode 100644 index 000000000000..579b9e44e764 --- /dev/null +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h | |||
@@ -0,0 +1,197 @@ | |||
1 | /* | ||
2 | * Copyright 2015 Freescale Semiconductor, Inc. | ||
3 | * | ||
4 | * Freescale DCU drm device driver | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #ifndef __FSL_DCU_DRM_DRV_H__ | ||
13 | #define __FSL_DCU_DRM_DRV_H__ | ||
14 | |||
15 | #include "fsl_dcu_drm_crtc.h" | ||
16 | #include "fsl_dcu_drm_output.h" | ||
17 | #include "fsl_dcu_drm_plane.h" | ||
18 | |||
19 | #define DCU_DCU_MODE 0x0010 | ||
20 | #define DCU_MODE_BLEND_ITER(x) ((x) << 20) | ||
21 | #define DCU_MODE_RASTER_EN BIT(14) | ||
22 | #define DCU_MODE_DCU_MODE(x) (x) | ||
23 | #define DCU_MODE_DCU_MODE_MASK 0x03 | ||
24 | #define DCU_MODE_OFF 0 | ||
25 | #define DCU_MODE_NORMAL 1 | ||
26 | #define DCU_MODE_TEST 2 | ||
27 | #define DCU_MODE_COLORBAR 3 | ||
28 | |||
29 | #define DCU_BGND 0x0014 | ||
30 | #define DCU_BGND_R(x) ((x) << 16) | ||
31 | #define DCU_BGND_G(x) ((x) << 8) | ||
32 | #define DCU_BGND_B(x) (x) | ||
33 | |||
34 | #define DCU_DISP_SIZE 0x0018 | ||
35 | #define DCU_DISP_SIZE_DELTA_Y(x) ((x) << 16) | ||
36 | /*Regisiter value 1/16 of horizontal resolution*/ | ||
37 | #define DCU_DISP_SIZE_DELTA_X(x) ((x) >> 4) | ||
38 | |||
39 | #define DCU_HSYN_PARA 0x001c | ||
40 | #define DCU_HSYN_PARA_BP(x) ((x) << 22) | ||
41 | #define DCU_HSYN_PARA_PW(x) ((x) << 11) | ||
42 | #define DCU_HSYN_PARA_FP(x) (x) | ||
43 | |||
44 | #define DCU_VSYN_PARA 0x0020 | ||
45 | #define DCU_VSYN_PARA_BP(x) ((x) << 22) | ||
46 | #define DCU_VSYN_PARA_PW(x) ((x) << 11) | ||
47 | #define DCU_VSYN_PARA_FP(x) (x) | ||
48 | |||
49 | #define DCU_SYN_POL 0x0024 | ||
50 | #define DCU_SYN_POL_INV_PXCK_FALL (0 << 6) | ||
51 | #define DCU_SYN_POL_NEG_REMAIN (0 << 5) | ||
52 | #define DCU_SYN_POL_INV_VS_LOW BIT(1) | ||
53 | #define DCU_SYN_POL_INV_HS_LOW BIT(0) | ||
54 | |||
55 | #define DCU_THRESHOLD 0x0028 | ||
56 | #define DCU_THRESHOLD_LS_BF_VS(x) ((x) << 16) | ||
57 | #define DCU_THRESHOLD_OUT_BUF_HIGH(x) ((x) << 8) | ||
58 | #define DCU_THRESHOLD_OUT_BUF_LOW(x) (x) | ||
59 | #define BF_VS_VAL 0x03 | ||
60 | #define BUF_MAX_VAL 0x78 | ||
61 | #define BUF_MIN_VAL 0x0a | ||
62 | |||
63 | #define DCU_INT_STATUS 0x002C | ||
64 | #define DCU_INT_STATUS_VSYNC BIT(0) | ||
65 | #define DCU_INT_STATUS_UNDRUN BIT(1) | ||
66 | #define DCU_INT_STATUS_LSBFVS BIT(2) | ||
67 | #define DCU_INT_STATUS_VBLANK BIT(3) | ||
68 | #define DCU_INT_STATUS_CRCREADY BIT(4) | ||
69 | #define DCU_INT_STATUS_CRCOVERFLOW BIT(5) | ||
70 | #define DCU_INT_STATUS_P1FIFOLO BIT(6) | ||
71 | #define DCU_INT_STATUS_P1FIFOHI BIT(7) | ||
72 | #define DCU_INT_STATUS_P2FIFOLO BIT(8) | ||
73 | #define DCU_INT_STATUS_P2FIFOHI BIT(9) | ||
74 | #define DCU_INT_STATUS_PROGEND BIT(10) | ||
75 | #define DCU_INT_STATUS_IPMERROR BIT(11) | ||
76 | #define DCU_INT_STATUS_LYRTRANS BIT(12) | ||
77 | #define DCU_INT_STATUS_DMATRANS BIT(14) | ||
78 | #define DCU_INT_STATUS_P3FIFOLO BIT(16) | ||
79 | #define DCU_INT_STATUS_P3FIFOHI BIT(17) | ||
80 | #define DCU_INT_STATUS_P4FIFOLO BIT(18) | ||
81 | #define DCU_INT_STATUS_P4FIFOHI BIT(19) | ||
82 | #define DCU_INT_STATUS_P1EMPTY BIT(26) | ||
83 | #define DCU_INT_STATUS_P2EMPTY BIT(27) | ||
84 | #define DCU_INT_STATUS_P3EMPTY BIT(28) | ||
85 | #define DCU_INT_STATUS_P4EMPTY BIT(29) | ||
86 | |||
87 | #define DCU_INT_MASK 0x0030 | ||
88 | #define DCU_INT_MASK_VSYNC BIT(0) | ||
89 | #define DCU_INT_MASK_UNDRUN BIT(1) | ||
90 | #define DCU_INT_MASK_LSBFVS BIT(2) | ||
91 | #define DCU_INT_MASK_VBLANK BIT(3) | ||
92 | #define DCU_INT_MASK_CRCREADY BIT(4) | ||
93 | #define DCU_INT_MASK_CRCOVERFLOW BIT(5) | ||
94 | #define DCU_INT_MASK_P1FIFOLO BIT(6) | ||
95 | #define DCU_INT_MASK_P1FIFOHI BIT(7) | ||
96 | #define DCU_INT_MASK_P2FIFOLO BIT(8) | ||
97 | #define DCU_INT_MASK_P2FIFOHI BIT(9) | ||
98 | #define DCU_INT_MASK_PROGEND BIT(10) | ||
99 | #define DCU_INT_MASK_IPMERROR BIT(11) | ||
100 | #define DCU_INT_MASK_LYRTRANS BIT(12) | ||
101 | #define DCU_INT_MASK_DMATRANS BIT(14) | ||
102 | #define DCU_INT_MASK_P3FIFOLO BIT(16) | ||
103 | #define DCU_INT_MASK_P3FIFOHI BIT(17) | ||
104 | #define DCU_INT_MASK_P4FIFOLO BIT(18) | ||
105 | #define DCU_INT_MASK_P4FIFOHI BIT(19) | ||
106 | #define DCU_INT_MASK_P1EMPTY BIT(26) | ||
107 | #define DCU_INT_MASK_P2EMPTY BIT(27) | ||
108 | #define DCU_INT_MASK_P3EMPTY BIT(28) | ||
109 | #define DCU_INT_MASK_P4EMPTY BIT(29) | ||
110 | |||
111 | #define DCU_DIV_RATIO 0x0054 | ||
112 | |||
113 | #define DCU_UPDATE_MODE 0x00cc | ||
114 | #define DCU_UPDATE_MODE_MODE BIT(31) | ||
115 | #define DCU_UPDATE_MODE_READREG BIT(30) | ||
116 | |||
117 | #define DCU_DCFB_MAX 0x300 | ||
118 | |||
119 | #define DCU_CTRLDESCLN(layer, reg) (0x200 + (reg - 1) * 4 + (layer) * 0x40) | ||
120 | |||
121 | #define DCU_LAYER_HEIGHT(x) ((x) << 16) | ||
122 | #define DCU_LAYER_WIDTH(x) (x) | ||
123 | |||
124 | #define DCU_LAYER_POSY(x) ((x) << 16) | ||
125 | #define DCU_LAYER_POSX(x) (x) | ||
126 | |||
127 | #define DCU_LAYER_EN BIT(31) | ||
128 | #define DCU_LAYER_TILE_EN BIT(30) | ||
129 | #define DCU_LAYER_DATA_SEL_CLUT BIT(29) | ||
130 | #define DCU_LAYER_SAFETY_EN BIT(28) | ||
131 | #define DCU_LAYER_TRANS(x) ((x) << 20) | ||
132 | #define DCU_LAYER_BPP(x) ((x) << 16) | ||
133 | #define DCU_LAYER_RLE_EN BIT(15) | ||
134 | #define DCU_LAYER_LUOFFS(x) ((x) << 4) | ||
135 | #define DCU_LAYER_BB_ON BIT(2) | ||
136 | #define DCU_LAYER_AB(x) (x) | ||
137 | |||
138 | #define DCU_LAYER_CKMAX_R(x) ((x) << 16) | ||
139 | #define DCU_LAYER_CKMAX_G(x) ((x) << 8) | ||
140 | #define DCU_LAYER_CKMAX_B(x) (x) | ||
141 | |||
142 | #define DCU_LAYER_CKMIN_R(x) ((x) << 16) | ||
143 | #define DCU_LAYER_CKMIN_G(x) ((x) << 8) | ||
144 | #define DCU_LAYER_CKMIN_B(x) (x) | ||
145 | |||
146 | #define DCU_LAYER_TILE_VER(x) ((x) << 16) | ||
147 | #define DCU_LAYER_TILE_HOR(x) (x) | ||
148 | |||
149 | #define DCU_LAYER_FG_FCOLOR(x) (x) | ||
150 | |||
151 | #define DCU_LAYER_BG_BCOLOR(x) (x) | ||
152 | |||
153 | #define DCU_LAYER_POST_SKIP(x) ((x) << 16) | ||
154 | #define DCU_LAYER_PRE_SKIP(x) (x) | ||
155 | |||
156 | #define FSL_DCU_RGB565 4 | ||
157 | #define FSL_DCU_RGB888 5 | ||
158 | #define FSL_DCU_ARGB8888 6 | ||
159 | #define FSL_DCU_ARGB1555 11 | ||
160 | #define FSL_DCU_ARGB4444 12 | ||
161 | #define FSL_DCU_YUV422 14 | ||
162 | |||
163 | #define VF610_LAYER_REG_NUM 9 | ||
164 | #define LS1021A_LAYER_REG_NUM 10 | ||
165 | |||
166 | struct clk; | ||
167 | struct device; | ||
168 | struct drm_device; | ||
169 | |||
170 | struct fsl_dcu_soc_data { | ||
171 | const char *name; | ||
172 | /*total layer number*/ | ||
173 | unsigned int total_layer; | ||
174 | /*max layer number DCU supported*/ | ||
175 | unsigned int max_layer; | ||
176 | }; | ||
177 | |||
178 | struct fsl_dcu_drm_device { | ||
179 | struct device *dev; | ||
180 | struct device_node *np; | ||
181 | struct regmap *regmap; | ||
182 | int irq; | ||
183 | struct clk *clk; | ||
184 | /*protects hardware register*/ | ||
185 | spinlock_t irq_lock; | ||
186 | struct drm_device *drm; | ||
187 | struct drm_fbdev_cma *fbdev; | ||
188 | struct drm_crtc crtc; | ||
189 | struct drm_encoder encoder; | ||
190 | struct fsl_dcu_drm_connector connector; | ||
191 | const struct fsl_dcu_soc_data *soc; | ||
192 | }; | ||
193 | |||
194 | void fsl_dcu_fbdev_init(struct drm_device *dev); | ||
195 | int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev); | ||
196 | |||
197 | #endif /* __FSL_DCU_DRM_DRV_H__ */ | ||
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_fbdev.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_fbdev.c new file mode 100644 index 000000000000..8b8b819ea704 --- /dev/null +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_fbdev.c | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | * Copyright 2015 Freescale Semiconductor, Inc. | ||
3 | * | ||
4 | * Freescale DCU drm device driver | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <drm/drmP.h> | ||
13 | #include <drm/drm_fb_cma_helper.h> | ||
14 | |||
15 | #include "fsl_dcu_drm_drv.h" | ||
16 | |||
17 | /* initialize fbdev helper */ | ||
18 | void fsl_dcu_fbdev_init(struct drm_device *dev) | ||
19 | { | ||
20 | struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev->dev); | ||
21 | |||
22 | fsl_dev->fbdev = drm_fbdev_cma_init(dev, 24, 1, 1); | ||
23 | } | ||
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c new file mode 100644 index 000000000000..0ef5959710e7 --- /dev/null +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c | |||
@@ -0,0 +1,43 @@ | |||
1 | /* | ||
2 | * Copyright 2015 Freescale Semiconductor, Inc. | ||
3 | * | ||
4 | * Freescale DCU drm device driver | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <drm/drmP.h> | ||
13 | #include <drm/drm_atomic_helper.h> | ||
14 | #include <drm/drm_crtc_helper.h> | ||
15 | #include <drm/drm_fb_cma_helper.h> | ||
16 | |||
17 | #include "fsl_dcu_drm_crtc.h" | ||
18 | #include "fsl_dcu_drm_drv.h" | ||
19 | |||
20 | static const struct drm_mode_config_funcs fsl_dcu_drm_mode_config_funcs = { | ||
21 | .atomic_check = drm_atomic_helper_check, | ||
22 | .atomic_commit = drm_atomic_helper_commit, | ||
23 | .fb_create = drm_fb_cma_create, | ||
24 | }; | ||
25 | |||
26 | int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev) | ||
27 | { | ||
28 | drm_mode_config_init(fsl_dev->drm); | ||
29 | |||
30 | fsl_dev->drm->mode_config.min_width = 0; | ||
31 | fsl_dev->drm->mode_config.min_height = 0; | ||
32 | fsl_dev->drm->mode_config.max_width = 2031; | ||
33 | fsl_dev->drm->mode_config.max_height = 2047; | ||
34 | fsl_dev->drm->mode_config.funcs = &fsl_dcu_drm_mode_config_funcs; | ||
35 | |||
36 | drm_kms_helper_poll_init(fsl_dev->drm); | ||
37 | fsl_dcu_drm_crtc_create(fsl_dev); | ||
38 | fsl_dcu_drm_encoder_create(fsl_dev, &fsl_dev->crtc); | ||
39 | fsl_dcu_drm_connector_create(fsl_dev, &fsl_dev->encoder); | ||
40 | drm_mode_config_reset(fsl_dev->drm); | ||
41 | |||
42 | return 0; | ||
43 | } | ||
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_output.h b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_output.h new file mode 100644 index 000000000000..7093109fbc21 --- /dev/null +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_output.h | |||
@@ -0,0 +1,33 @@ | |||
1 | /* | ||
2 | * Copyright 2015 Freescale Semiconductor, Inc. | ||
3 | * | ||
4 | * Freescale DCU drm device driver | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #ifndef __FSL_DCU_DRM_CONNECTOR_H__ | ||
13 | #define __FSL_DCU_DRM_CONNECTOR_H__ | ||
14 | |||
15 | struct fsl_dcu_drm_connector { | ||
16 | struct drm_connector base; | ||
17 | struct drm_encoder *encoder; | ||
18 | struct drm_panel *panel; | ||
19 | }; | ||
20 | |||
21 | static inline struct fsl_dcu_drm_connector * | ||
22 | to_fsl_dcu_connector(struct drm_connector *con) | ||
23 | { | ||
24 | return con ? container_of(con, struct fsl_dcu_drm_connector, base) | ||
25 | : NULL; | ||
26 | } | ||
27 | |||
28 | int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev, | ||
29 | struct drm_encoder *encoder); | ||
30 | int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev, | ||
31 | struct drm_crtc *crtc); | ||
32 | |||
33 | #endif /* __FSL_DCU_DRM_CONNECTOR_H__ */ | ||
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c new file mode 100644 index 000000000000..82be6b86a168 --- /dev/null +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c | |||
@@ -0,0 +1,261 @@ | |||
1 | /* | ||
2 | * Copyright 2015 Freescale Semiconductor, Inc. | ||
3 | * | ||
4 | * Freescale DCU drm device driver | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/regmap.h> | ||
13 | |||
14 | #include <drm/drmP.h> | ||
15 | #include <drm/drm_atomic_helper.h> | ||
16 | #include <drm/drm_crtc.h> | ||
17 | #include <drm/drm_crtc_helper.h> | ||
18 | #include <drm/drm_fb_cma_helper.h> | ||
19 | #include <drm/drm_gem_cma_helper.h> | ||
20 | #include <drm/drm_plane_helper.h> | ||
21 | |||
22 | #include "fsl_dcu_drm_drv.h" | ||
23 | #include "fsl_dcu_drm_plane.h" | ||
24 | |||
25 | static int fsl_dcu_drm_plane_index(struct drm_plane *plane) | ||
26 | { | ||
27 | struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private; | ||
28 | unsigned int total_layer = fsl_dev->soc->total_layer; | ||
29 | unsigned int index; | ||
30 | |||
31 | index = drm_plane_index(plane); | ||
32 | if (index < total_layer) | ||
33 | return total_layer - index - 1; | ||
34 | |||
35 | dev_err(fsl_dev->dev, "No more layer left\n"); | ||
36 | return -EINVAL; | ||
37 | } | ||
38 | |||
39 | static int fsl_dcu_drm_plane_atomic_check(struct drm_plane *plane, | ||
40 | struct drm_plane_state *state) | ||
41 | { | ||
42 | struct drm_framebuffer *fb = state->fb; | ||
43 | |||
44 | switch (fb->pixel_format) { | ||
45 | case DRM_FORMAT_RGB565: | ||
46 | case DRM_FORMAT_RGB888: | ||
47 | case DRM_FORMAT_ARGB8888: | ||
48 | case DRM_FORMAT_BGRA4444: | ||
49 | case DRM_FORMAT_ARGB1555: | ||
50 | case DRM_FORMAT_YUV422: | ||
51 | return 0; | ||
52 | default: | ||
53 | return -EINVAL; | ||
54 | } | ||
55 | } | ||
56 | |||
57 | static void fsl_dcu_drm_plane_atomic_disable(struct drm_plane *plane, | ||
58 | struct drm_plane_state *old_state) | ||
59 | { | ||
60 | struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private; | ||
61 | unsigned int index, value, ret; | ||
62 | |||
63 | index = fsl_dcu_drm_plane_index(plane); | ||
64 | if (index < 0) | ||
65 | return; | ||
66 | |||
67 | ret = regmap_read(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4), &value); | ||
68 | if (ret) | ||
69 | dev_err(fsl_dev->dev, "read DCU_INT_MASK failed\n"); | ||
70 | value &= ~DCU_LAYER_EN; | ||
71 | ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4), value); | ||
72 | if (ret) | ||
73 | dev_err(fsl_dev->dev, "set DCU register failed\n"); | ||
74 | } | ||
75 | |||
76 | static void fsl_dcu_drm_plane_atomic_update(struct drm_plane *plane, | ||
77 | struct drm_plane_state *old_state) | ||
78 | |||
79 | { | ||
80 | struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private; | ||
81 | struct drm_plane_state *state = plane->state; | ||
82 | struct drm_framebuffer *fb = plane->state->fb; | ||
83 | struct drm_gem_cma_object *gem; | ||
84 | unsigned int alpha, bpp; | ||
85 | int index, ret; | ||
86 | |||
87 | if (!fb) | ||
88 | return; | ||
89 | |||
90 | index = fsl_dcu_drm_plane_index(plane); | ||
91 | if (index < 0) | ||
92 | return; | ||
93 | |||
94 | gem = drm_fb_cma_get_gem_obj(fb, 0); | ||
95 | |||
96 | switch (fb->pixel_format) { | ||
97 | case DRM_FORMAT_RGB565: | ||
98 | bpp = FSL_DCU_RGB565; | ||
99 | alpha = 0xff; | ||
100 | break; | ||
101 | case DRM_FORMAT_RGB888: | ||
102 | bpp = FSL_DCU_RGB888; | ||
103 | alpha = 0xff; | ||
104 | break; | ||
105 | case DRM_FORMAT_ARGB8888: | ||
106 | bpp = FSL_DCU_ARGB8888; | ||
107 | alpha = 0xff; | ||
108 | break; | ||
109 | case DRM_FORMAT_BGRA4444: | ||
110 | bpp = FSL_DCU_ARGB4444; | ||
111 | alpha = 0xff; | ||
112 | break; | ||
113 | case DRM_FORMAT_ARGB1555: | ||
114 | bpp = FSL_DCU_ARGB1555; | ||
115 | alpha = 0xff; | ||
116 | break; | ||
117 | case DRM_FORMAT_YUV422: | ||
118 | bpp = FSL_DCU_YUV422; | ||
119 | alpha = 0xff; | ||
120 | break; | ||
121 | default: | ||
122 | return; | ||
123 | } | ||
124 | |||
125 | ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 1), | ||
126 | DCU_LAYER_HEIGHT(state->crtc_h) | | ||
127 | DCU_LAYER_WIDTH(state->crtc_w)); | ||
128 | if (ret) | ||
129 | goto set_failed; | ||
130 | ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 2), | ||
131 | DCU_LAYER_POSY(state->crtc_y) | | ||
132 | DCU_LAYER_POSX(state->crtc_x)); | ||
133 | if (ret) | ||
134 | goto set_failed; | ||
135 | ret = regmap_write(fsl_dev->regmap, | ||
136 | DCU_CTRLDESCLN(index, 3), gem->paddr); | ||
137 | if (ret) | ||
138 | goto set_failed; | ||
139 | ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 4), | ||
140 | DCU_LAYER_EN | | ||
141 | DCU_LAYER_TRANS(alpha) | | ||
142 | DCU_LAYER_BPP(bpp) | | ||
143 | DCU_LAYER_AB(0)); | ||
144 | if (ret) | ||
145 | goto set_failed; | ||
146 | ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 5), | ||
147 | DCU_LAYER_CKMAX_R(0xFF) | | ||
148 | DCU_LAYER_CKMAX_G(0xFF) | | ||
149 | DCU_LAYER_CKMAX_B(0xFF)); | ||
150 | if (ret) | ||
151 | goto set_failed; | ||
152 | ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 6), | ||
153 | DCU_LAYER_CKMIN_R(0) | | ||
154 | DCU_LAYER_CKMIN_G(0) | | ||
155 | DCU_LAYER_CKMIN_B(0)); | ||
156 | if (ret) | ||
157 | goto set_failed; | ||
158 | ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 7), 0); | ||
159 | if (ret) | ||
160 | goto set_failed; | ||
161 | ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 8), | ||
162 | DCU_LAYER_FG_FCOLOR(0)); | ||
163 | if (ret) | ||
164 | goto set_failed; | ||
165 | ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 9), | ||
166 | DCU_LAYER_BG_BCOLOR(0)); | ||
167 | if (ret) | ||
168 | goto set_failed; | ||
169 | if (!strcmp(fsl_dev->soc->name, "ls1021a")) { | ||
170 | ret = regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(index, 10), | ||
171 | DCU_LAYER_POST_SKIP(0) | | ||
172 | DCU_LAYER_PRE_SKIP(0)); | ||
173 | if (ret) | ||
174 | goto set_failed; | ||
175 | } | ||
176 | ret = regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE, | ||
177 | DCU_MODE_DCU_MODE_MASK, | ||
178 | DCU_MODE_DCU_MODE(DCU_MODE_NORMAL)); | ||
179 | if (ret) | ||
180 | goto set_failed; | ||
181 | ret = regmap_write(fsl_dev->regmap, | ||
182 | DCU_UPDATE_MODE, DCU_UPDATE_MODE_READREG); | ||
183 | if (ret) | ||
184 | goto set_failed; | ||
185 | return; | ||
186 | |||
187 | set_failed: | ||
188 | dev_err(fsl_dev->dev, "set DCU register failed\n"); | ||
189 | } | ||
190 | |||
191 | static void | ||
192 | fsl_dcu_drm_plane_cleanup_fb(struct drm_plane *plane, | ||
193 | struct drm_framebuffer *fb, | ||
194 | const struct drm_plane_state *new_state) | ||
195 | { | ||
196 | } | ||
197 | |||
198 | static int | ||
199 | fsl_dcu_drm_plane_prepare_fb(struct drm_plane *plane, | ||
200 | struct drm_framebuffer *fb, | ||
201 | const struct drm_plane_state *new_state) | ||
202 | { | ||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static const struct drm_plane_helper_funcs fsl_dcu_drm_plane_helper_funcs = { | ||
207 | .atomic_check = fsl_dcu_drm_plane_atomic_check, | ||
208 | .atomic_disable = fsl_dcu_drm_plane_atomic_disable, | ||
209 | .atomic_update = fsl_dcu_drm_plane_atomic_update, | ||
210 | .cleanup_fb = fsl_dcu_drm_plane_cleanup_fb, | ||
211 | .prepare_fb = fsl_dcu_drm_plane_prepare_fb, | ||
212 | }; | ||
213 | |||
214 | static void fsl_dcu_drm_plane_destroy(struct drm_plane *plane) | ||
215 | { | ||
216 | drm_plane_cleanup(plane); | ||
217 | } | ||
218 | |||
219 | static const struct drm_plane_funcs fsl_dcu_drm_plane_funcs = { | ||
220 | .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, | ||
221 | .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, | ||
222 | .destroy = fsl_dcu_drm_plane_destroy, | ||
223 | .disable_plane = drm_atomic_helper_disable_plane, | ||
224 | .reset = drm_atomic_helper_plane_reset, | ||
225 | .update_plane = drm_atomic_helper_update_plane, | ||
226 | }; | ||
227 | |||
228 | static const u32 fsl_dcu_drm_plane_formats[] = { | ||
229 | DRM_FORMAT_RGB565, | ||
230 | DRM_FORMAT_RGB888, | ||
231 | DRM_FORMAT_ARGB8888, | ||
232 | DRM_FORMAT_ARGB4444, | ||
233 | DRM_FORMAT_ARGB1555, | ||
234 | DRM_FORMAT_YUV422, | ||
235 | }; | ||
236 | |||
237 | struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device *dev) | ||
238 | { | ||
239 | struct drm_plane *primary; | ||
240 | int ret; | ||
241 | |||
242 | primary = kzalloc(sizeof(*primary), GFP_KERNEL); | ||
243 | if (!primary) { | ||
244 | DRM_DEBUG_KMS("Failed to allocate primary plane\n"); | ||
245 | return NULL; | ||
246 | } | ||
247 | |||
248 | /* possible_crtc's will be filled in later by crtc_init */ | ||
249 | ret = drm_universal_plane_init(dev, primary, 0, | ||
250 | &fsl_dcu_drm_plane_funcs, | ||
251 | fsl_dcu_drm_plane_formats, | ||
252 | ARRAY_SIZE(fsl_dcu_drm_plane_formats), | ||
253 | DRM_PLANE_TYPE_PRIMARY); | ||
254 | if (ret) { | ||
255 | kfree(primary); | ||
256 | primary = NULL; | ||
257 | } | ||
258 | drm_plane_helper_add(primary, &fsl_dcu_drm_plane_helper_funcs); | ||
259 | |||
260 | return primary; | ||
261 | } | ||
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.h b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.h new file mode 100644 index 000000000000..d657f088d859 --- /dev/null +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.h | |||
@@ -0,0 +1,17 @@ | |||
1 | /* | ||
2 | * Copyright 2015 Freescale Semiconductor, Inc. | ||
3 | * | ||
4 | * Freescale DCU drm device driver | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #ifndef __FSL_DCU_DRM_PLANE_H__ | ||
13 | #define __FSL_DCU_DRM_PLANE_H__ | ||
14 | |||
15 | struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device *dev); | ||
16 | |||
17 | #endif /* __FSL_DCU_DRM_PLANE_H__ */ | ||
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c new file mode 100644 index 000000000000..fe8ab5da04fb --- /dev/null +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | |||
@@ -0,0 +1,182 @@ | |||
1 | /* | ||
2 | * Copyright 2015 Freescale Semiconductor, Inc. | ||
3 | * | ||
4 | * Freescale DCU drm device driver | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/backlight.h> | ||
13 | |||
14 | #include <drm/drmP.h> | ||
15 | #include <drm/drm_atomic_helper.h> | ||
16 | #include <drm/drm_crtc_helper.h> | ||
17 | #include <drm/drm_panel.h> | ||
18 | |||
19 | #include "fsl_dcu_drm_drv.h" | ||
20 | |||
21 | static int | ||
22 | fsl_dcu_drm_encoder_atomic_check(struct drm_encoder *encoder, | ||
23 | struct drm_crtc_state *crtc_state, | ||
24 | struct drm_connector_state *conn_state) | ||
25 | { | ||
26 | return 0; | ||
27 | } | ||
28 | |||
29 | static void fsl_dcu_drm_encoder_disable(struct drm_encoder *encoder) | ||
30 | { | ||
31 | } | ||
32 | |||
33 | static void fsl_dcu_drm_encoder_enable(struct drm_encoder *encoder) | ||
34 | { | ||
35 | } | ||
36 | |||
37 | static const struct drm_encoder_helper_funcs encoder_helper_funcs = { | ||
38 | .atomic_check = fsl_dcu_drm_encoder_atomic_check, | ||
39 | .disable = fsl_dcu_drm_encoder_disable, | ||
40 | .enable = fsl_dcu_drm_encoder_enable, | ||
41 | }; | ||
42 | |||
43 | static void fsl_dcu_drm_encoder_destroy(struct drm_encoder *encoder) | ||
44 | { | ||
45 | drm_encoder_cleanup(encoder); | ||
46 | } | ||
47 | |||
48 | static const struct drm_encoder_funcs encoder_funcs = { | ||
49 | .destroy = fsl_dcu_drm_encoder_destroy, | ||
50 | }; | ||
51 | |||
52 | int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev, | ||
53 | struct drm_crtc *crtc) | ||
54 | { | ||
55 | struct drm_encoder *encoder = &fsl_dev->encoder; | ||
56 | int ret; | ||
57 | |||
58 | encoder->possible_crtcs = 1; | ||
59 | ret = drm_encoder_init(fsl_dev->drm, encoder, &encoder_funcs, | ||
60 | DRM_MODE_ENCODER_LVDS); | ||
61 | if (ret < 0) | ||
62 | return ret; | ||
63 | |||
64 | drm_encoder_helper_add(encoder, &encoder_helper_funcs); | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static void fsl_dcu_drm_connector_destroy(struct drm_connector *connector) | ||
70 | { | ||
71 | drm_connector_unregister(connector); | ||
72 | drm_connector_cleanup(connector); | ||
73 | } | ||
74 | |||
75 | static enum drm_connector_status | ||
76 | fsl_dcu_drm_connector_detect(struct drm_connector *connector, bool force) | ||
77 | { | ||
78 | return connector_status_connected; | ||
79 | } | ||
80 | |||
81 | static const struct drm_connector_funcs fsl_dcu_drm_connector_funcs = { | ||
82 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | ||
83 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | ||
84 | .destroy = fsl_dcu_drm_connector_destroy, | ||
85 | .detect = fsl_dcu_drm_connector_detect, | ||
86 | .dpms = drm_atomic_helper_connector_dpms, | ||
87 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
88 | .reset = drm_atomic_helper_connector_reset, | ||
89 | }; | ||
90 | |||
91 | static struct drm_encoder * | ||
92 | fsl_dcu_drm_connector_best_encoder(struct drm_connector *connector) | ||
93 | { | ||
94 | struct fsl_dcu_drm_connector *fsl_con = to_fsl_dcu_connector(connector); | ||
95 | |||
96 | return fsl_con->encoder; | ||
97 | } | ||
98 | |||
99 | static int fsl_dcu_drm_connector_get_modes(struct drm_connector *connector) | ||
100 | { | ||
101 | struct fsl_dcu_drm_connector *fsl_connector; | ||
102 | int (*get_modes)(struct drm_panel *panel); | ||
103 | int num_modes = 0; | ||
104 | |||
105 | fsl_connector = to_fsl_dcu_connector(connector); | ||
106 | if (fsl_connector->panel && fsl_connector->panel->funcs && | ||
107 | fsl_connector->panel->funcs->get_modes) { | ||
108 | get_modes = fsl_connector->panel->funcs->get_modes; | ||
109 | num_modes = get_modes(fsl_connector->panel); | ||
110 | } | ||
111 | |||
112 | return num_modes; | ||
113 | } | ||
114 | |||
115 | static int fsl_dcu_drm_connector_mode_valid(struct drm_connector *connector, | ||
116 | struct drm_display_mode *mode) | ||
117 | { | ||
118 | if (mode->hdisplay & 0xf) | ||
119 | return MODE_ERROR; | ||
120 | |||
121 | return MODE_OK; | ||
122 | } | ||
123 | |||
124 | static const struct drm_connector_helper_funcs connector_helper_funcs = { | ||
125 | .best_encoder = fsl_dcu_drm_connector_best_encoder, | ||
126 | .get_modes = fsl_dcu_drm_connector_get_modes, | ||
127 | .mode_valid = fsl_dcu_drm_connector_mode_valid, | ||
128 | }; | ||
129 | |||
130 | int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev, | ||
131 | struct drm_encoder *encoder) | ||
132 | { | ||
133 | struct drm_connector *connector = &fsl_dev->connector.base; | ||
134 | struct drm_mode_config mode_config = fsl_dev->drm->mode_config; | ||
135 | struct device_node *panel_node; | ||
136 | int ret; | ||
137 | |||
138 | fsl_dev->connector.encoder = encoder; | ||
139 | |||
140 | ret = drm_connector_init(fsl_dev->drm, connector, | ||
141 | &fsl_dcu_drm_connector_funcs, | ||
142 | DRM_MODE_CONNECTOR_LVDS); | ||
143 | if (ret < 0) | ||
144 | return ret; | ||
145 | |||
146 | drm_connector_helper_add(connector, &connector_helper_funcs); | ||
147 | ret = drm_connector_register(connector); | ||
148 | if (ret < 0) | ||
149 | goto err_cleanup; | ||
150 | |||
151 | ret = drm_mode_connector_attach_encoder(connector, encoder); | ||
152 | if (ret < 0) | ||
153 | goto err_sysfs; | ||
154 | |||
155 | drm_object_property_set_value(&connector->base, | ||
156 | mode_config.dpms_property, | ||
157 | DRM_MODE_DPMS_OFF); | ||
158 | |||
159 | panel_node = of_parse_phandle(fsl_dev->np, "fsl,panel", 0); | ||
160 | if (panel_node) { | ||
161 | fsl_dev->connector.panel = of_drm_find_panel(panel_node); | ||
162 | if (!fsl_dev->connector.panel) { | ||
163 | ret = -EPROBE_DEFER; | ||
164 | goto err_sysfs; | ||
165 | } | ||
166 | of_node_put(panel_node); | ||
167 | } | ||
168 | |||
169 | ret = drm_panel_attach(fsl_dev->connector.panel, connector); | ||
170 | if (ret) { | ||
171 | dev_err(fsl_dev->dev, "failed to attach panel\n"); | ||
172 | goto err_sysfs; | ||
173 | } | ||
174 | |||
175 | return 0; | ||
176 | |||
177 | err_sysfs: | ||
178 | drm_connector_unregister(connector); | ||
179 | err_cleanup: | ||
180 | drm_connector_cleanup(connector); | ||
181 | return ret; | ||
182 | } | ||