aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/arm
diff options
context:
space:
mode:
authorLiviu Dudau <Liviu.Dudau@arm.com>2016-03-07 05:00:53 -0500
committerLiviu Dudau <Liviu.Dudau@arm.com>2016-06-15 12:29:22 -0400
commitad49f8602fe88929b185b21ccf43ff5196bbb7c3 (patch)
tree8b3cd2937deb1421fe6a3c52da138d1599c33869 /drivers/gpu/drm/arm
parentee6ea993dfb27c4a809c3384b19b58eebea65a36 (diff)
drm/arm: Add support for Mali Display Processors
Add support for the new family of Display Processors from ARM Ltd. This commit adds basic support for Mali DP500, DP550 and DP650 parts, with only the display engine being supported at the moment. Cc: David Brown <David.Brown@arm.com> Cc: Brian Starkey <Brian.Starkey@arm.com> Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/arm')
-rw-r--r--drivers/gpu/drm/arm/Kconfig16
-rw-r--r--drivers/gpu/drm/arm/Makefile2
-rw-r--r--drivers/gpu/drm/arm/malidp_crtc.c216
-rw-r--r--drivers/gpu/drm/arm/malidp_drv.c512
-rw-r--r--drivers/gpu/drm/arm/malidp_drv.h54
-rw-r--r--drivers/gpu/drm/arm/malidp_hw.c691
-rw-r--r--drivers/gpu/drm/arm/malidp_hw.h241
-rw-r--r--drivers/gpu/drm/arm/malidp_planes.c298
-rw-r--r--drivers/gpu/drm/arm/malidp_regs.h172
9 files changed, 2202 insertions, 0 deletions
diff --git a/drivers/gpu/drm/arm/Kconfig b/drivers/gpu/drm/arm/Kconfig
index eaed454e043c..1b2906568a48 100644
--- a/drivers/gpu/drm/arm/Kconfig
+++ b/drivers/gpu/drm/arm/Kconfig
@@ -25,3 +25,19 @@ config DRM_HDLCD_SHOW_UNDERRUN
25 Enable this option to show in red colour the pixels that the 25 Enable this option to show in red colour the pixels that the
26 HDLCD device did not fetch from framebuffer due to underrun 26 HDLCD device did not fetch from framebuffer due to underrun
27 conditions. 27 conditions.
28
29config DRM_MALI_DISPLAY
30 tristate "ARM Mali Display Processor"
31 depends on DRM && OF && (ARM || ARM64)
32 depends on COMMON_CLK
33 select DRM_ARM
34 select DRM_KMS_HELPER
35 select DRM_KMS_CMA_HELPER
36 select DRM_GEM_CMA_HELPER
37 select VIDEOMODE_HELPERS
38 help
39 Choose this option if you want to compile the ARM Mali Display
40 Processor driver. It supports the DP500, DP550 and DP650 variants
41 of the hardware.
42
43 If compiled as a module it will be called mali-dp.
diff --git a/drivers/gpu/drm/arm/Makefile b/drivers/gpu/drm/arm/Makefile
index 89dcb7bab93a..bb8b158ff90d 100644
--- a/drivers/gpu/drm/arm/Makefile
+++ b/drivers/gpu/drm/arm/Makefile
@@ -1,2 +1,4 @@
1hdlcd-y := hdlcd_drv.o hdlcd_crtc.o 1hdlcd-y := hdlcd_drv.o hdlcd_crtc.o
2obj-$(CONFIG_DRM_HDLCD) += hdlcd.o 2obj-$(CONFIG_DRM_HDLCD) += hdlcd.o
3mali-dp-y := malidp_drv.o malidp_hw.o malidp_planes.o malidp_crtc.o
4obj-$(CONFIG_DRM_MALI_DISPLAY) += mali-dp.o
diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c
new file mode 100644
index 000000000000..08e6a71f5d05
--- /dev/null
+++ b/drivers/gpu/drm/arm/malidp_crtc.c
@@ -0,0 +1,216 @@
1/*
2 * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
3 * Author: Liviu Dudau <Liviu.Dudau@arm.com>
4 *
5 * This program is free software and is provided to you under the terms of the
6 * GNU General Public License version 2 as published by the Free Software
7 * Foundation, and any use by you of this program is subject to the terms
8 * of such GNU licence.
9 *
10 * ARM Mali DP500/DP550/DP650 driver (crtc operations)
11 */
12
13#include <drm/drmP.h>
14#include <drm/drm_atomic.h>
15#include <drm/drm_atomic_helper.h>
16#include <drm/drm_crtc.h>
17#include <drm/drm_crtc_helper.h>
18#include <linux/clk.h>
19#include <video/videomode.h>
20
21#include "malidp_drv.h"
22#include "malidp_hw.h"
23
24static bool malidp_crtc_mode_fixup(struct drm_crtc *crtc,
25 const struct drm_display_mode *mode,
26 struct drm_display_mode *adjusted_mode)
27{
28 struct malidp_drm *malidp = crtc_to_malidp_device(crtc);
29 struct malidp_hw_device *hwdev = malidp->dev;
30
31 /*
32 * check that the hardware can drive the required clock rate,
33 * but skip the check if the clock is meant to be disabled (req_rate = 0)
34 */
35 long rate, req_rate = mode->crtc_clock * 1000;
36
37 if (req_rate) {
38 rate = clk_round_rate(hwdev->mclk, req_rate);
39 if (rate < req_rate) {
40 DRM_DEBUG_DRIVER("mclk clock unable to reach %d kHz\n",
41 mode->crtc_clock);
42 return false;
43 }
44
45 rate = clk_round_rate(hwdev->pxlclk, req_rate);
46 if (rate != req_rate) {
47 DRM_DEBUG_DRIVER("pxlclk doesn't support %ld Hz\n",
48 req_rate);
49 return false;
50 }
51 }
52
53 return true;
54}
55
56static void malidp_crtc_enable(struct drm_crtc *crtc)
57{
58 struct malidp_drm *malidp = crtc_to_malidp_device(crtc);
59 struct malidp_hw_device *hwdev = malidp->dev;
60 struct videomode vm;
61
62 drm_display_mode_to_videomode(&crtc->state->adjusted_mode, &vm);
63
64 clk_prepare_enable(hwdev->pxlclk);
65
66 /* mclk needs to be set to the same or higher rate than pxlclk */
67 clk_set_rate(hwdev->mclk, crtc->state->adjusted_mode.crtc_clock * 1000);
68 clk_set_rate(hwdev->pxlclk, crtc->state->adjusted_mode.crtc_clock * 1000);
69
70 hwdev->modeset(hwdev, &vm);
71 hwdev->leave_config_mode(hwdev);
72 drm_crtc_vblank_on(crtc);
73}
74
75static void malidp_crtc_disable(struct drm_crtc *crtc)
76{
77 struct malidp_drm *malidp = crtc_to_malidp_device(crtc);
78 struct malidp_hw_device *hwdev = malidp->dev;
79
80 drm_crtc_vblank_off(crtc);
81 hwdev->enter_config_mode(hwdev);
82 clk_disable_unprepare(hwdev->pxlclk);
83}
84
85static int malidp_crtc_atomic_check(struct drm_crtc *crtc,
86 struct drm_crtc_state *state)
87{
88 struct malidp_drm *malidp = crtc_to_malidp_device(crtc);
89 struct malidp_hw_device *hwdev = malidp->dev;
90 struct drm_plane *plane;
91 const struct drm_plane_state *pstate;
92 u32 rot_mem_free, rot_mem_usable;
93 int rotated_planes = 0;
94
95 /*
96 * check if there is enough rotation memory available for planes
97 * that need 90° and 270° rotation. Each plane has set its required
98 * memory size in the ->plane_check() callback, here we only make
99 * sure that the sums are less that the total usable memory.
100 *
101 * The rotation memory allocation algorithm (for each plane):
102 * a. If no more rotated planes exist, all remaining rotate
103 * memory in the bank is available for use by the plane.
104 * b. If other rotated planes exist, and plane's layer ID is
105 * DE_VIDEO1, it can use all the memory from first bank if
106 * secondary rotation memory bank is available, otherwise it can
107 * use up to half the bank's memory.
108 * c. If other rotated planes exist, and plane's layer ID is not
109 * DE_VIDEO1, it can use half of the available memory
110 *
111 * Note: this algorithm assumes that the order in which the planes are
112 * checked always has DE_VIDEO1 plane first in the list if it is
113 * rotated. Because that is how we create the planes in the first
114 * place, under current DRM version things work, but if ever the order
115 * in which drm_atomic_crtc_state_for_each_plane() iterates over planes
116 * changes, we need to pre-sort the planes before validation.
117 */
118
119 /* first count the number of rotated planes */
120 drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) {
121 if (pstate->rotation & MALIDP_ROTATED_MASK)
122 rotated_planes++;
123 }
124
125 rot_mem_free = hwdev->rotation_memory[0];
126 /*
127 * if we have more than 1 plane using rotation memory, use the second
128 * block of rotation memory as well
129 */
130 if (rotated_planes > 1)
131 rot_mem_free += hwdev->rotation_memory[1];
132
133 /* now validate the rotation memory requirements */
134 drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) {
135 struct malidp_plane *mp = to_malidp_plane(plane);
136 struct malidp_plane_state *ms = to_malidp_plane_state(pstate);
137
138 if (pstate->rotation & MALIDP_ROTATED_MASK) {
139 /* process current plane */
140 rotated_planes--;
141
142 if (!rotated_planes) {
143 /* no more rotated planes, we can use what's left */
144 rot_mem_usable = rot_mem_free;
145 } else {
146 if ((mp->layer->id != DE_VIDEO1) ||
147 (hwdev->rotation_memory[1] == 0))
148 rot_mem_usable = rot_mem_free / 2;
149 else
150 rot_mem_usable = hwdev->rotation_memory[0];
151 }
152
153 rot_mem_free -= rot_mem_usable;
154
155 if (ms->rotmem_size > rot_mem_usable)
156 return -EINVAL;
157 }
158 }
159
160 return 0;
161}
162
163static const struct drm_crtc_helper_funcs malidp_crtc_helper_funcs = {
164 .mode_fixup = malidp_crtc_mode_fixup,
165 .enable = malidp_crtc_enable,
166 .disable = malidp_crtc_disable,
167 .atomic_check = malidp_crtc_atomic_check,
168};
169
170static const struct drm_crtc_funcs malidp_crtc_funcs = {
171 .destroy = drm_crtc_cleanup,
172 .set_config = drm_atomic_helper_set_config,
173 .page_flip = drm_atomic_helper_page_flip,
174 .reset = drm_atomic_helper_crtc_reset,
175 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
176 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
177};
178
179int malidp_crtc_init(struct drm_device *drm)
180{
181 struct malidp_drm *malidp = drm->dev_private;
182 struct drm_plane *primary = NULL, *plane;
183 int ret;
184
185 ret = malidp_de_planes_init(drm);
186 if (ret < 0) {
187 DRM_ERROR("Failed to initialise planes\n");
188 return ret;
189 }
190
191 drm_for_each_plane(plane, drm) {
192 if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
193 primary = plane;
194 break;
195 }
196 }
197
198 if (!primary) {
199 DRM_ERROR("no primary plane found\n");
200 ret = -EINVAL;
201 goto crtc_cleanup_planes;
202 }
203
204 ret = drm_crtc_init_with_planes(drm, &malidp->crtc, primary, NULL,
205 &malidp_crtc_funcs, NULL);
206
207 if (!ret) {
208 drm_crtc_helper_add(&malidp->crtc, &malidp_crtc_helper_funcs);
209 return 0;
210 }
211
212crtc_cleanup_planes:
213 malidp_de_planes_destroy(drm);
214
215 return ret;
216}
diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
new file mode 100644
index 000000000000..e5b44e92f8cf
--- /dev/null
+++ b/drivers/gpu/drm/arm/malidp_drv.c
@@ -0,0 +1,512 @@
1/*
2 * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
3 * Author: Liviu Dudau <Liviu.Dudau@arm.com>
4 *
5 * This program is free software and is provided to you under the terms of the
6 * GNU General Public License version 2 as published by the Free Software
7 * Foundation, and any use by you of this program is subject to the terms
8 * of such GNU licence.
9 *
10 * ARM Mali DP500/DP550/DP650 KMS/DRM driver
11 */
12
13#include <linux/module.h>
14#include <linux/clk.h>
15#include <linux/component.h>
16#include <linux/of_device.h>
17#include <linux/of_graph.h>
18#include <linux/of_reserved_mem.h>
19
20#include <drm/drmP.h>
21#include <drm/drm_atomic.h>
22#include <drm/drm_atomic_helper.h>
23#include <drm/drm_crtc.h>
24#include <drm/drm_crtc_helper.h>
25#include <drm/drm_fb_helper.h>
26#include <drm/drm_fb_cma_helper.h>
27#include <drm/drm_gem_cma_helper.h>
28#include <drm/drm_of.h>
29
30#include "malidp_drv.h"
31#include "malidp_regs.h"
32#include "malidp_hw.h"
33
34#define MALIDP_CONF_VALID_TIMEOUT 250
35
36/*
37 * set the "config valid" bit and wait until the hardware acts on it
38 */
39static int malidp_set_and_wait_config_valid(struct drm_device *drm)
40{
41 struct malidp_drm *malidp = drm->dev_private;
42 struct malidp_hw_device *hwdev = malidp->dev;
43 int ret;
44
45 hwdev->set_config_valid(hwdev);
46 /* don't wait for config_valid flag if we are in config mode */
47 if (hwdev->in_config_mode(hwdev))
48 return 0;
49
50 ret = wait_event_interruptible_timeout(malidp->wq,
51 atomic_read(&malidp->config_valid) == 1,
52 msecs_to_jiffies(MALIDP_CONF_VALID_TIMEOUT));
53
54 return (ret > 0) ? 0 : -ETIMEDOUT;
55}
56
57static void malidp_output_poll_changed(struct drm_device *drm)
58{
59 struct malidp_drm *malidp = drm->dev_private;
60
61 drm_fbdev_cma_hotplug_event(malidp->fbdev);
62}
63
64static void malidp_atomic_commit_hw_done(struct drm_atomic_state *state)
65{
66 struct drm_pending_vblank_event *event;
67 struct drm_device *drm = state->dev;
68 struct malidp_drm *malidp = drm->dev_private;
69 int ret = malidp_set_and_wait_config_valid(drm);
70
71 if (ret)
72 DRM_DEBUG_DRIVER("timed out waiting for updated configuration\n");
73
74 event = malidp->crtc.state->event;
75 if (event) {
76 malidp->crtc.state->event = NULL;
77
78 spin_lock_irq(&drm->event_lock);
79 if (drm_crtc_vblank_get(&malidp->crtc) == 0)
80 drm_crtc_arm_vblank_event(&malidp->crtc, event);
81 else
82 drm_crtc_send_vblank_event(&malidp->crtc, event);
83 spin_unlock_irq(&drm->event_lock);
84 }
85 drm_atomic_helper_commit_hw_done(state);
86}
87
88static void malidp_atomic_commit_tail(struct drm_atomic_state *state)
89{
90 struct drm_device *drm = state->dev;
91
92 drm_atomic_helper_commit_modeset_disables(drm, state);
93 drm_atomic_helper_commit_modeset_enables(drm, state);
94 drm_atomic_helper_commit_planes(drm, state, true);
95
96 malidp_atomic_commit_hw_done(state);
97
98 drm_atomic_helper_wait_for_vblanks(drm, state);
99
100 drm_atomic_helper_cleanup_planes(drm, state);
101}
102
103static struct drm_mode_config_helper_funcs malidp_mode_config_helpers = {
104 .atomic_commit_tail = malidp_atomic_commit_tail,
105};
106
107static const struct drm_mode_config_funcs malidp_mode_config_funcs = {
108 .fb_create = drm_fb_cma_create,
109 .output_poll_changed = malidp_output_poll_changed,
110 .atomic_check = drm_atomic_helper_check,
111 .atomic_commit = drm_atomic_helper_commit,
112};
113
114static int malidp_enable_vblank(struct drm_device *drm, unsigned int crtc)
115{
116 struct malidp_drm *malidp = drm->dev_private;
117 struct malidp_hw_device *hwdev = malidp->dev;
118
119 malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK,
120 hwdev->map.de_irq_map.vsync_irq);
121 return 0;
122}
123
124static void malidp_disable_vblank(struct drm_device *drm, unsigned int pipe)
125{
126 struct malidp_drm *malidp = drm->dev_private;
127 struct malidp_hw_device *hwdev = malidp->dev;
128
129 malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK,
130 hwdev->map.de_irq_map.vsync_irq);
131}
132
133static int malidp_init(struct drm_device *drm)
134{
135 int ret;
136 struct malidp_drm *malidp = drm->dev_private;
137 struct malidp_hw_device *hwdev = malidp->dev;
138
139 drm_mode_config_init(drm);
140
141 drm->mode_config.min_width = hwdev->min_line_size;
142 drm->mode_config.min_height = hwdev->min_line_size;
143 drm->mode_config.max_width = hwdev->max_line_size;
144 drm->mode_config.max_height = hwdev->max_line_size;
145 drm->mode_config.funcs = &malidp_mode_config_funcs;
146 drm->mode_config.helper_private = &malidp_mode_config_helpers;
147
148 ret = malidp_crtc_init(drm);
149 if (ret) {
150 drm_mode_config_cleanup(drm);
151 return ret;
152 }
153
154 return 0;
155}
156
157static int malidp_irq_init(struct platform_device *pdev)
158{
159 int irq_de, irq_se, ret = 0;
160 struct drm_device *drm = dev_get_drvdata(&pdev->dev);
161
162 /* fetch the interrupts from DT */
163 irq_de = platform_get_irq_byname(pdev, "DE");
164 if (irq_de < 0) {
165 DRM_ERROR("no 'DE' IRQ specified!\n");
166 return irq_de;
167 }
168 irq_se = platform_get_irq_byname(pdev, "SE");
169 if (irq_se < 0) {
170 DRM_ERROR("no 'SE' IRQ specified!\n");
171 return irq_se;
172 }
173
174 ret = malidp_de_irq_init(drm, irq_de);
175 if (ret)
176 return ret;
177
178 ret = malidp_se_irq_init(drm, irq_se);
179 if (ret) {
180 malidp_de_irq_fini(drm);
181 return ret;
182 }
183
184 return 0;
185}
186
187static void malidp_lastclose(struct drm_device *drm)
188{
189 struct malidp_drm *malidp = drm->dev_private;
190
191 drm_fbdev_cma_restore_mode(malidp->fbdev);
192}
193
194static const struct file_operations fops = {
195 .owner = THIS_MODULE,
196 .open = drm_open,
197 .release = drm_release,
198 .unlocked_ioctl = drm_ioctl,
199#ifdef CONFIG_COMPAT
200 .compat_ioctl = drm_compat_ioctl,
201#endif
202 .poll = drm_poll,
203 .read = drm_read,
204 .llseek = noop_llseek,
205 .mmap = drm_gem_cma_mmap,
206};
207
208static struct drm_driver malidp_driver = {
209 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC |
210 DRIVER_PRIME,
211 .lastclose = malidp_lastclose,
212 .get_vblank_counter = drm_vblank_no_hw_counter,
213 .enable_vblank = malidp_enable_vblank,
214 .disable_vblank = malidp_disable_vblank,
215 .gem_free_object_unlocked = drm_gem_cma_free_object,
216 .gem_vm_ops = &drm_gem_cma_vm_ops,
217 .dumb_create = drm_gem_cma_dumb_create,
218 .dumb_map_offset = drm_gem_cma_dumb_map_offset,
219 .dumb_destroy = drm_gem_dumb_destroy,
220 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
221 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
222 .gem_prime_export = drm_gem_prime_export,
223 .gem_prime_import = drm_gem_prime_import,
224 .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
225 .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
226 .gem_prime_vmap = drm_gem_cma_prime_vmap,
227 .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
228 .gem_prime_mmap = drm_gem_cma_prime_mmap,
229 .fops = &fops,
230 .name = "mali-dp",
231 .desc = "ARM Mali Display Processor driver",
232 .date = "20160106",
233 .major = 1,
234 .minor = 0,
235};
236
237static const struct of_device_id malidp_drm_of_match[] = {
238 {
239 .compatible = "arm,mali-dp500",
240 .data = &malidp_device[MALIDP_500]
241 },
242 {
243 .compatible = "arm,mali-dp550",
244 .data = &malidp_device[MALIDP_550]
245 },
246 {
247 .compatible = "arm,mali-dp650",
248 .data = &malidp_device[MALIDP_650]
249 },
250 {},
251};
252MODULE_DEVICE_TABLE(of, malidp_drm_of_match);
253
254#define MAX_OUTPUT_CHANNELS 3
255
256static int malidp_bind(struct device *dev)
257{
258 struct resource *res;
259 struct drm_device *drm;
260 struct malidp_drm *malidp;
261 struct malidp_hw_device *hwdev;
262 struct platform_device *pdev = to_platform_device(dev);
263 /* number of lines for the R, G and B output */
264 u8 output_width[MAX_OUTPUT_CHANNELS];
265 int ret = 0, i;
266 u32 version, out_depth = 0;
267
268 malidp = devm_kzalloc(dev, sizeof(*malidp), GFP_KERNEL);
269 if (!malidp)
270 return -ENOMEM;
271
272 hwdev = devm_kzalloc(dev, sizeof(*hwdev), GFP_KERNEL);
273 if (!hwdev)
274 return -ENOMEM;
275
276 /*
277 * copy the associated data from malidp_drm_of_match to avoid
278 * having to keep a reference to the OF node after binding
279 */
280 memcpy(hwdev, of_device_get_match_data(dev), sizeof(*hwdev));
281 malidp->dev = hwdev;
282
283 INIT_LIST_HEAD(&malidp->event_list);
284
285 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
286 hwdev->regs = devm_ioremap_resource(dev, res);
287 if (IS_ERR(hwdev->regs)) {
288 DRM_ERROR("Failed to map control registers area\n");
289 return PTR_ERR(hwdev->regs);
290 }
291
292 hwdev->pclk = devm_clk_get(dev, "pclk");
293 if (IS_ERR(hwdev->pclk))
294 return PTR_ERR(hwdev->pclk);
295
296 hwdev->aclk = devm_clk_get(dev, "aclk");
297 if (IS_ERR(hwdev->aclk))
298 return PTR_ERR(hwdev->aclk);
299
300 hwdev->mclk = devm_clk_get(dev, "mclk");
301 if (IS_ERR(hwdev->mclk))
302 return PTR_ERR(hwdev->mclk);
303
304 hwdev->pxlclk = devm_clk_get(dev, "pxlclk");
305 if (IS_ERR(hwdev->pxlclk))
306 return PTR_ERR(hwdev->pxlclk);
307
308 /* Get the optional framebuffer memory resource */
309 ret = of_reserved_mem_device_init(dev);
310 if (ret && ret != -ENODEV)
311 return ret;
312
313 drm = drm_dev_alloc(&malidp_driver, dev);
314 if (!drm) {
315 ret = -ENOMEM;
316 goto alloc_fail;
317 }
318
319 /* Enable APB clock in order to get access to the registers */
320 clk_prepare_enable(hwdev->pclk);
321 /*
322 * Enable AXI clock and main clock so that prefetch can start once
323 * the registers are set
324 */
325 clk_prepare_enable(hwdev->aclk);
326 clk_prepare_enable(hwdev->mclk);
327
328 ret = hwdev->query_hw(hwdev);
329 if (ret) {
330 DRM_ERROR("Invalid HW configuration\n");
331 goto query_hw_fail;
332 }
333
334 version = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_DE_CORE_ID);
335 DRM_INFO("found ARM Mali-DP%3x version r%dp%d\n", version >> 16,
336 (version >> 12) & 0xf, (version >> 8) & 0xf);
337
338 /* set the number of lines used for output of RGB data */
339 ret = of_property_read_u8_array(dev->of_node,
340 "arm,malidp-output-port-lines",
341 output_width, MAX_OUTPUT_CHANNELS);
342 if (ret)
343 goto query_hw_fail;
344
345 for (i = 0; i < MAX_OUTPUT_CHANNELS; i++)
346 out_depth = (out_depth << 8) | (output_width[i] & 0xf);
347 malidp_hw_write(hwdev, out_depth, hwdev->map.out_depth_base);
348
349 drm->dev_private = malidp;
350 dev_set_drvdata(dev, drm);
351 atomic_set(&malidp->config_valid, 0);
352 init_waitqueue_head(&malidp->wq);
353
354 ret = malidp_init(drm);
355 if (ret < 0)
356 goto init_fail;
357
358 ret = drm_dev_register(drm, 0);
359 if (ret)
360 goto register_fail;
361
362 /* Set the CRTC's port so that the encoder component can find it */
363 malidp->crtc.port = of_graph_get_next_endpoint(dev->of_node, NULL);
364
365 ret = component_bind_all(dev, drm);
366 of_node_put(malidp->crtc.port);
367
368 if (ret) {
369 DRM_ERROR("Failed to bind all components\n");
370 goto bind_fail;
371 }
372
373 ret = malidp_irq_init(pdev);
374 if (ret < 0)
375 goto irq_init_fail;
376
377 ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
378 if (ret < 0) {
379 DRM_ERROR("failed to initialise vblank\n");
380 goto vblank_fail;
381 }
382
383 drm_mode_config_reset(drm);
384
385 malidp->fbdev = drm_fbdev_cma_init(drm, 32, drm->mode_config.num_crtc,
386 drm->mode_config.num_connector);
387
388 if (IS_ERR(malidp->fbdev)) {
389 ret = PTR_ERR(malidp->fbdev);
390 malidp->fbdev = NULL;
391 goto fbdev_fail;
392 }
393
394 drm_kms_helper_poll_init(drm);
395 return 0;
396
397fbdev_fail:
398 drm_vblank_cleanup(drm);
399vblank_fail:
400 malidp_se_irq_fini(drm);
401 malidp_de_irq_fini(drm);
402irq_init_fail:
403 component_unbind_all(dev, drm);
404bind_fail:
405 drm_dev_unregister(drm);
406register_fail:
407 malidp_de_planes_destroy(drm);
408 drm_mode_config_cleanup(drm);
409init_fail:
410 drm->dev_private = NULL;
411 dev_set_drvdata(dev, NULL);
412query_hw_fail:
413 clk_disable_unprepare(hwdev->mclk);
414 clk_disable_unprepare(hwdev->aclk);
415 clk_disable_unprepare(hwdev->pclk);
416 drm_dev_unref(drm);
417alloc_fail:
418 of_reserved_mem_device_release(dev);
419
420 return ret;
421}
422
423static void malidp_unbind(struct device *dev)
424{
425 struct drm_device *drm = dev_get_drvdata(dev);
426 struct malidp_drm *malidp = drm->dev_private;
427 struct malidp_hw_device *hwdev = malidp->dev;
428
429 if (malidp->fbdev) {
430 drm_fbdev_cma_fini(malidp->fbdev);
431 malidp->fbdev = NULL;
432 }
433 drm_kms_helper_poll_fini(drm);
434 malidp_se_irq_fini(drm);
435 malidp_de_irq_fini(drm);
436 drm_vblank_cleanup(drm);
437 component_unbind_all(dev, drm);
438 drm_dev_unregister(drm);
439 malidp_de_planes_destroy(drm);
440 drm_mode_config_cleanup(drm);
441 drm->dev_private = NULL;
442 dev_set_drvdata(dev, NULL);
443 clk_disable_unprepare(hwdev->mclk);
444 clk_disable_unprepare(hwdev->aclk);
445 clk_disable_unprepare(hwdev->pclk);
446 drm_dev_unref(drm);
447 of_reserved_mem_device_release(dev);
448}
449
450static const struct component_master_ops malidp_master_ops = {
451 .bind = malidp_bind,
452 .unbind = malidp_unbind,
453};
454
455static int malidp_compare_dev(struct device *dev, void *data)
456{
457 struct device_node *np = data;
458
459 return dev->of_node == np;
460}
461
462static int malidp_platform_probe(struct platform_device *pdev)
463{
464 struct device_node *port, *ep;
465 struct component_match *match = NULL;
466
467 if (!pdev->dev.of_node)
468 return -ENODEV;
469
470 /* there is only one output port inside each device, find it */
471 ep = of_graph_get_next_endpoint(pdev->dev.of_node, NULL);
472 if (!ep)
473 return -ENODEV;
474
475 if (!of_device_is_available(ep)) {
476 of_node_put(ep);
477 return -ENODEV;
478 }
479
480 /* add the remote encoder port as component */
481 port = of_graph_get_remote_port_parent(ep);
482 of_node_put(ep);
483 if (!port || !of_device_is_available(port)) {
484 of_node_put(port);
485 return -EAGAIN;
486 }
487
488 component_match_add(&pdev->dev, &match, malidp_compare_dev, port);
489 return component_master_add_with_match(&pdev->dev, &malidp_master_ops,
490 match);
491}
492
493static int malidp_platform_remove(struct platform_device *pdev)
494{
495 component_master_del(&pdev->dev, &malidp_master_ops);
496 return 0;
497}
498
499static struct platform_driver malidp_platform_driver = {
500 .probe = malidp_platform_probe,
501 .remove = malidp_platform_remove,
502 .driver = {
503 .name = "mali-dp",
504 .of_match_table = malidp_drm_of_match,
505 },
506};
507
508module_platform_driver(malidp_platform_driver);
509
510MODULE_AUTHOR("Liviu Dudau <Liviu.Dudau@arm.com>");
511MODULE_DESCRIPTION("ARM Mali DP DRM driver");
512MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h
new file mode 100644
index 000000000000..95558fde214b
--- /dev/null
+++ b/drivers/gpu/drm/arm/malidp_drv.h
@@ -0,0 +1,54 @@
1/*
2 * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
3 * Author: Liviu Dudau <Liviu.Dudau@arm.com>
4 *
5 * This program is free software and is provided to you under the terms of the
6 * GNU General Public License version 2 as published by the Free Software
7 * Foundation, and any use by you of this program is subject to the terms
8 * of such GNU licence.
9 *
10 * ARM Mali DP500/DP550/DP650 KMS/DRM driver structures
11 */
12
13#ifndef __MALIDP_DRV_H__
14#define __MALIDP_DRV_H__
15
16#include <linux/mutex.h>
17#include <linux/wait.h>
18#include "malidp_hw.h"
19
20struct malidp_drm {
21 struct malidp_hw_device *dev;
22 struct drm_fbdev_cma *fbdev;
23 struct list_head event_list;
24 struct drm_crtc crtc;
25 wait_queue_head_t wq;
26 atomic_t config_valid;
27};
28
29#define crtc_to_malidp_device(x) container_of(x, struct malidp_drm, crtc)
30
31struct malidp_plane {
32 struct drm_plane base;
33 struct malidp_hw_device *hwdev;
34 const struct malidp_layer *layer;
35};
36
37struct malidp_plane_state {
38 struct drm_plane_state base;
39
40 /* size of the required rotation memory if plane is rotated */
41 u32 rotmem_size;
42};
43
44#define to_malidp_plane(x) container_of(x, struct malidp_plane, base)
45#define to_malidp_plane_state(x) container_of(x, struct malidp_plane_state, base)
46
47int malidp_de_planes_init(struct drm_device *drm);
48void malidp_de_planes_destroy(struct drm_device *drm);
49int malidp_crtc_init(struct drm_device *drm);
50
51/* often used combination of rotational bits */
52#define MALIDP_ROTATED_MASK (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))
53
54#endif /* __MALIDP_DRV_H__ */
diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c
new file mode 100644
index 000000000000..a6132f1d58c1
--- /dev/null
+++ b/drivers/gpu/drm/arm/malidp_hw.c
@@ -0,0 +1,691 @@
1/*
2 * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
3 * Author: Liviu Dudau <Liviu.Dudau@arm.com>
4 *
5 * This program is free software and is provided to you under the terms of the
6 * GNU General Public License version 2 as published by the Free Software
7 * Foundation, and any use by you of this program is subject to the terms
8 * of such GNU licence.
9 *
10 * ARM Mali DP500/DP550/DP650 hardware manipulation routines. This is where
11 * the difference between various versions of the hardware is being dealt with
12 * in an attempt to provide to the rest of the driver code a unified view
13 */
14
15#include <linux/types.h>
16#include <linux/io.h>
17#include <drm/drmP.h>
18#include <video/videomode.h>
19#include <video/display_timing.h>
20
21#include "malidp_drv.h"
22#include "malidp_hw.h"
23
24static const struct malidp_input_format malidp500_de_formats[] = {
25 /* fourcc, layers supporting the format, internal id */
26 { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 0 },
27 { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 1 },
28 { DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 2 },
29 { DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 3 },
30 { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 4 },
31 { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 5 },
32 { DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 6 },
33 { DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 7 },
34 { DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 8 },
35 { DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 9 },
36 { DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 10 },
37 { DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 11 },
38 { DRM_FORMAT_UYVY, DE_VIDEO1, 12 },
39 { DRM_FORMAT_YUYV, DE_VIDEO1, 13 },
40 { DRM_FORMAT_NV12, DE_VIDEO1, 14 },
41 { DRM_FORMAT_YUV420, DE_VIDEO1, 15 },
42};
43
44#define MALIDP_ID(__group, __format) \
45 ((((__group) & 0x7) << 3) | ((__format) & 0x7))
46
47#define MALIDP_COMMON_FORMATS \
48 /* fourcc, layers supporting the format, internal id */ \
49 { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 0) }, \
50 { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 1) }, \
51 { DRM_FORMAT_RGBA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 2) }, \
52 { DRM_FORMAT_BGRA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 3) }, \
53 { DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 0) }, \
54 { DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 1) }, \
55 { DRM_FORMAT_RGBA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 2) }, \
56 { DRM_FORMAT_BGRA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 3) }, \
57 { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 0) }, \
58 { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 1) }, \
59 { DRM_FORMAT_RGBX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 2) }, \
60 { DRM_FORMAT_BGRX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 3) }, \
61 { DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(3, 0) }, \
62 { DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(3, 1) }, \
63 { DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 0) }, \
64 { DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 1) }, \
65 { DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 2) }, \
66 { DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 3) }, \
67 { DRM_FORMAT_YUYV, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 2) }, \
68 { DRM_FORMAT_UYVY, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 3) }, \
69 { DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 6) }, \
70 { DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) }
71
72static const struct malidp_input_format malidp550_de_formats[] = {
73 MALIDP_COMMON_FORMATS,
74};
75
76static const struct malidp_layer malidp500_layers[] = {
77 { DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE },
78 { DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE },
79 { DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE },
80};
81
82static const struct malidp_layer malidp550_layers[] = {
83 { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE },
84 { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE },
85 { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE },
86 { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE },
87};
88
89#define MALIDP_DE_DEFAULT_PREFETCH_START 5
90
91static int malidp500_query_hw(struct malidp_hw_device *hwdev)
92{
93 u32 conf = malidp_hw_read(hwdev, MALIDP500_CONFIG_ID);
94 /* bit 4 of the CONFIG_ID register holds the line size multiplier */
95 u8 ln_size_mult = conf & 0x10 ? 2 : 1;
96
97 hwdev->min_line_size = 2;
98 hwdev->max_line_size = SZ_2K * ln_size_mult;
99 hwdev->rotation_memory[0] = SZ_1K * 64 * ln_size_mult;
100 hwdev->rotation_memory[1] = 0; /* no second rotation memory bank */
101
102 return 0;
103}
104
105static void malidp500_enter_config_mode(struct malidp_hw_device *hwdev)
106{
107 u32 status, count = 100;
108
109 malidp_hw_setbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
110 while (count) {
111 status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
112 if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
113 break;
114 /*
115 * entering config mode can take as long as the rendering
116 * of a full frame, hence the long sleep here
117 */
118 usleep_range(1000, 10000);
119 count--;
120 }
121 WARN(count == 0, "timeout while entering config mode");
122}
123
124static void malidp500_leave_config_mode(struct malidp_hw_device *hwdev)
125{
126 u32 status, count = 100;
127
128 malidp_hw_clearbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
129 while (count) {
130 status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
131 if ((status & MALIDP500_DC_CONFIG_REQ) == 0)
132 break;
133 usleep_range(100, 1000);
134 count--;
135 }
136 WARN(count == 0, "timeout while leaving config mode");
137}
138
139static bool malidp500_in_config_mode(struct malidp_hw_device *hwdev)
140{
141 u32 status;
142
143 status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
144 if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
145 return true;
146
147 return false;
148}
149
150static void malidp500_set_config_valid(struct malidp_hw_device *hwdev)
151{
152 malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
153}
154
155static void malidp500_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
156{
157 u32 val = 0;
158
159 malidp_hw_clearbits(hwdev, MALIDP500_DC_CLEAR_MASK, MALIDP500_DC_CONTROL);
160 if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
161 val |= MALIDP500_HSYNCPOL;
162 if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
163 val |= MALIDP500_VSYNCPOL;
164 val |= MALIDP_DE_DEFAULT_PREFETCH_START;
165 malidp_hw_setbits(hwdev, val, MALIDP500_DC_CONTROL);
166
167 /*
168 * Mali-DP500 encodes the background color like this:
169 * - red @ MALIDP500_BGND_COLOR[12:0]
170 * - green @ MALIDP500_BGND_COLOR[27:16]
171 * - blue @ (MALIDP500_BGND_COLOR + 4)[12:0]
172 */
173 val = ((MALIDP_BGND_COLOR_G & 0xfff) << 16) |
174 (MALIDP_BGND_COLOR_R & 0xfff);
175 malidp_hw_write(hwdev, val, MALIDP500_BGND_COLOR);
176 malidp_hw_write(hwdev, MALIDP_BGND_COLOR_B, MALIDP500_BGND_COLOR + 4);
177
178 val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
179 MALIDP_DE_H_BACKPORCH(mode->hback_porch);
180 malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
181
182 val = MALIDP500_DE_V_FRONTPORCH(mode->vfront_porch) |
183 MALIDP_DE_V_BACKPORCH(mode->vback_porch);
184 malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
185
186 val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
187 MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
188 malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
189
190 val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
191 malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
192
193 if (mode->flags & DISPLAY_FLAGS_INTERLACED)
194 malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
195 else
196 malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
197}
198
199static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
200{
201 unsigned int depth;
202 int bpp;
203
204 /* RGB888 or BGR888 can't be rotated */
205 if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888))
206 return -EINVAL;
207
208 /*
209 * Each layer needs enough rotation memory to fit 8 lines
210 * worth of pixel data. Required size is then:
211 * size = rotated_width * (bpp / 8) * 8;
212 */
213 drm_fb_get_bpp_depth(fmt, &depth, &bpp);
214
215 return w * bpp;
216}
217
218static int malidp550_query_hw(struct malidp_hw_device *hwdev)
219{
220 u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
221 u8 ln_size = (conf >> 4) & 0x3, rsize;
222
223 hwdev->min_line_size = 2;
224
225 switch (ln_size) {
226 case 0:
227 hwdev->max_line_size = SZ_2K;
228 /* two banks of 64KB for rotation memory */
229 rsize = 64;
230 break;
231 case 1:
232 hwdev->max_line_size = SZ_4K;
233 /* two banks of 128KB for rotation memory */
234 rsize = 128;
235 break;
236 case 2:
237 hwdev->max_line_size = 1280;
238 /* two banks of 40KB for rotation memory */
239 rsize = 40;
240 break;
241 case 3:
242 /* reserved value */
243 hwdev->max_line_size = 0;
244 return -EINVAL;
245 }
246
247 hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
248 return 0;
249}
250
251static void malidp550_enter_config_mode(struct malidp_hw_device *hwdev)
252{
253 u32 status, count = 100;
254
255 malidp_hw_setbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
256 while (count) {
257 status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
258 if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
259 break;
260 /*
261 * entering config mode can take as long as the rendering
262 * of a full frame, hence the long sleep here
263 */
264 usleep_range(1000, 10000);
265 count--;
266 }
267 WARN(count == 0, "timeout while entering config mode");
268}
269
270static void malidp550_leave_config_mode(struct malidp_hw_device *hwdev)
271{
272 u32 status, count = 100;
273
274 malidp_hw_clearbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
275 while (count) {
276 status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
277 if ((status & MALIDP550_DC_CONFIG_REQ) == 0)
278 break;
279 usleep_range(100, 1000);
280 count--;
281 }
282 WARN(count == 0, "timeout while leaving config mode");
283}
284
285static bool malidp550_in_config_mode(struct malidp_hw_device *hwdev)
286{
287 u32 status;
288
289 status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
290 if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
291 return true;
292
293 return false;
294}
295
296static void malidp550_set_config_valid(struct malidp_hw_device *hwdev)
297{
298 malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
299}
300
301static void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
302{
303 u32 val = MALIDP_DE_DEFAULT_PREFETCH_START;
304
305 malidp_hw_write(hwdev, val, MALIDP550_DE_CONTROL);
306 /*
307 * Mali-DP550 and Mali-DP650 encode the background color like this:
308 * - red @ MALIDP550_DE_BGND_COLOR[23:16]
309 * - green @ MALIDP550_DE_BGND_COLOR[15:8]
310 * - blue @ MALIDP550_DE_BGND_COLOR[7:0]
311 *
312 * We need to truncate the least significant 4 bits from the default
313 * MALIDP_BGND_COLOR_x values
314 */
315 val = (((MALIDP_BGND_COLOR_R >> 4) & 0xff) << 16) |
316 (((MALIDP_BGND_COLOR_G >> 4) & 0xff) << 8) |
317 ((MALIDP_BGND_COLOR_B >> 4) & 0xff);
318 malidp_hw_write(hwdev, val, MALIDP550_DE_BGND_COLOR);
319
320 val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
321 MALIDP_DE_H_BACKPORCH(mode->hback_porch);
322 malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
323
324 val = MALIDP550_DE_V_FRONTPORCH(mode->vfront_porch) |
325 MALIDP_DE_V_BACKPORCH(mode->vback_porch);
326 malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
327
328 val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
329 MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
330 if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
331 val |= MALIDP550_HSYNCPOL;
332 if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
333 val |= MALIDP550_VSYNCPOL;
334 malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
335
336 val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
337 malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
338
339 if (mode->flags & DISPLAY_FLAGS_INTERLACED)
340 malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
341 else
342 malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
343}
344
345static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
346{
347 u32 bytes_per_col;
348
349 /* raw RGB888 or BGR888 can't be rotated */
350 if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888))
351 return -EINVAL;
352
353 switch (fmt) {
354 /* 8 lines at 4 bytes per pixel */
355 case DRM_FORMAT_ARGB2101010:
356 case DRM_FORMAT_ABGR2101010:
357 case DRM_FORMAT_RGBA1010102:
358 case DRM_FORMAT_BGRA1010102:
359 case DRM_FORMAT_ARGB8888:
360 case DRM_FORMAT_ABGR8888:
361 case DRM_FORMAT_RGBA8888:
362 case DRM_FORMAT_BGRA8888:
363 case DRM_FORMAT_XRGB8888:
364 case DRM_FORMAT_XBGR8888:
365 case DRM_FORMAT_RGBX8888:
366 case DRM_FORMAT_BGRX8888:
367 case DRM_FORMAT_RGB888:
368 case DRM_FORMAT_BGR888:
369 /* 16 lines at 2 bytes per pixel */
370 case DRM_FORMAT_RGBA5551:
371 case DRM_FORMAT_ABGR1555:
372 case DRM_FORMAT_RGB565:
373 case DRM_FORMAT_BGR565:
374 case DRM_FORMAT_UYVY:
375 case DRM_FORMAT_YUYV:
376 bytes_per_col = 32;
377 break;
378 /* 16 lines at 1.5 bytes per pixel */
379 case DRM_FORMAT_NV12:
380 case DRM_FORMAT_YUV420:
381 bytes_per_col = 24;
382 break;
383 default:
384 return -EINVAL;
385 }
386
387 return w * bytes_per_col;
388}
389
390static int malidp650_query_hw(struct malidp_hw_device *hwdev)
391{
392 u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
393 u8 ln_size = (conf >> 4) & 0x3, rsize;
394
395 hwdev->min_line_size = 4;
396
397 switch (ln_size) {
398 case 0:
399 case 2:
400 /* reserved values */
401 hwdev->max_line_size = 0;
402 return -EINVAL;
403 case 1:
404 hwdev->max_line_size = SZ_4K;
405 /* two banks of 128KB for rotation memory */
406 rsize = 128;
407 break;
408 case 3:
409 hwdev->max_line_size = 2560;
410 /* two banks of 80KB for rotation memory */
411 rsize = 80;
412 }
413
414 hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
415 return 0;
416}
417
418const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = {
419 [MALIDP_500] = {
420 .map = {
421 .se_base = MALIDP500_SE_BASE,
422 .dc_base = MALIDP500_DC_BASE,
423 .out_depth_base = MALIDP500_OUTPUT_DEPTH,
424 .features = 0, /* no CLEARIRQ register */
425 .n_layers = ARRAY_SIZE(malidp500_layers),
426 .layers = malidp500_layers,
427 .de_irq_map = {
428 .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
429 MALIDP500_DE_IRQ_AXI_ERR |
430 MALIDP500_DE_IRQ_VSYNC |
431 MALIDP500_DE_IRQ_GLOBAL,
432 .vsync_irq = MALIDP500_DE_IRQ_VSYNC,
433 },
434 .se_irq_map = {
435 .irq_mask = MALIDP500_SE_IRQ_CONF_MODE,
436 .vsync_irq = 0,
437 },
438 .dc_irq_map = {
439 .irq_mask = MALIDP500_DE_IRQ_CONF_VALID,
440 .vsync_irq = MALIDP500_DE_IRQ_CONF_VALID,
441 },
442 .input_formats = malidp500_de_formats,
443 .n_input_formats = ARRAY_SIZE(malidp500_de_formats),
444 },
445 .query_hw = malidp500_query_hw,
446 .enter_config_mode = malidp500_enter_config_mode,
447 .leave_config_mode = malidp500_leave_config_mode,
448 .in_config_mode = malidp500_in_config_mode,
449 .set_config_valid = malidp500_set_config_valid,
450 .modeset = malidp500_modeset,
451 .rotmem_required = malidp500_rotmem_required,
452 },
453 [MALIDP_550] = {
454 .map = {
455 .se_base = MALIDP550_SE_BASE,
456 .dc_base = MALIDP550_DC_BASE,
457 .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
458 .features = MALIDP_REGMAP_HAS_CLEARIRQ,
459 .n_layers = ARRAY_SIZE(malidp550_layers),
460 .layers = malidp550_layers,
461 .de_irq_map = {
462 .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
463 MALIDP550_DE_IRQ_VSYNC,
464 .vsync_irq = MALIDP550_DE_IRQ_VSYNC,
465 },
466 .se_irq_map = {
467 .irq_mask = MALIDP550_SE_IRQ_EOW |
468 MALIDP550_SE_IRQ_AXI_ERR,
469 },
470 .dc_irq_map = {
471 .irq_mask = MALIDP550_DC_IRQ_CONF_VALID,
472 .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
473 },
474 .input_formats = malidp550_de_formats,
475 .n_input_formats = ARRAY_SIZE(malidp550_de_formats),
476 },
477 .query_hw = malidp550_query_hw,
478 .enter_config_mode = malidp550_enter_config_mode,
479 .leave_config_mode = malidp550_leave_config_mode,
480 .in_config_mode = malidp550_in_config_mode,
481 .set_config_valid = malidp550_set_config_valid,
482 .modeset = malidp550_modeset,
483 .rotmem_required = malidp550_rotmem_required,
484 },
485 [MALIDP_650] = {
486 .map = {
487 .se_base = MALIDP550_SE_BASE,
488 .dc_base = MALIDP550_DC_BASE,
489 .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
490 .features = MALIDP_REGMAP_HAS_CLEARIRQ,
491 .n_layers = ARRAY_SIZE(malidp550_layers),
492 .layers = malidp550_layers,
493 .de_irq_map = {
494 .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
495 MALIDP650_DE_IRQ_DRIFT |
496 MALIDP550_DE_IRQ_VSYNC,
497 .vsync_irq = MALIDP550_DE_IRQ_VSYNC,
498 },
499 .se_irq_map = {
500 .irq_mask = MALIDP550_SE_IRQ_EOW |
501 MALIDP550_SE_IRQ_AXI_ERR,
502 },
503 .dc_irq_map = {
504 .irq_mask = MALIDP550_DC_IRQ_CONF_VALID,
505 .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
506 },
507 .input_formats = malidp550_de_formats,
508 .n_input_formats = ARRAY_SIZE(malidp550_de_formats),
509 },
510 .query_hw = malidp650_query_hw,
511 .enter_config_mode = malidp550_enter_config_mode,
512 .leave_config_mode = malidp550_leave_config_mode,
513 .in_config_mode = malidp550_in_config_mode,
514 .set_config_valid = malidp550_set_config_valid,
515 .modeset = malidp550_modeset,
516 .rotmem_required = malidp550_rotmem_required,
517 },
518};
519
520u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
521 u8 layer_id, u32 format)
522{
523 unsigned int i;
524
525 for (i = 0; i < map->n_input_formats; i++) {
526 if (((map->input_formats[i].layer & layer_id) == layer_id) &&
527 (map->input_formats[i].format == format))
528 return map->input_formats[i].id;
529 }
530
531 return MALIDP_INVALID_FORMAT_ID;
532}
533
534static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 irq)
535{
536 u32 base = malidp_get_block_base(hwdev, block);
537
538 if (hwdev->map.features & MALIDP_REGMAP_HAS_CLEARIRQ)
539 malidp_hw_write(hwdev, irq, base + MALIDP_REG_CLEARIRQ);
540 else
541 malidp_hw_write(hwdev, irq, base + MALIDP_REG_STATUS);
542}
543
544static irqreturn_t malidp_de_irq(int irq, void *arg)
545{
546 struct drm_device *drm = arg;
547 struct malidp_drm *malidp = drm->dev_private;
548 struct malidp_hw_device *hwdev;
549 const struct malidp_irq_map *de;
550 u32 status, mask, dc_status;
551 irqreturn_t ret = IRQ_NONE;
552
553 if (!drm->dev_private)
554 return IRQ_HANDLED;
555
556 hwdev = malidp->dev;
557 de = &hwdev->map.de_irq_map;
558
559 /* first handle the config valid IRQ */
560 dc_status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
561 if (dc_status & hwdev->map.dc_irq_map.vsync_irq) {
562 /* we have a page flip event */
563 atomic_set(&malidp->config_valid, 1);
564 malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status);
565 ret = IRQ_WAKE_THREAD;
566 }
567
568 status = malidp_hw_read(hwdev, MALIDP_REG_STATUS);
569 if (!(status & de->irq_mask))
570 return ret;
571
572 mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ);
573 status &= mask;
574 if (status & de->vsync_irq)
575 drm_crtc_handle_vblank(&malidp->crtc);
576
577 malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status);
578
579 return (ret == IRQ_NONE) ? IRQ_HANDLED : ret;
580}
581
582static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg)
583{
584 struct drm_device *drm = arg;
585 struct malidp_drm *malidp = drm->dev_private;
586
587 wake_up(&malidp->wq);
588
589 return IRQ_HANDLED;
590}
591
592int malidp_de_irq_init(struct drm_device *drm, int irq)
593{
594 struct malidp_drm *malidp = drm->dev_private;
595 struct malidp_hw_device *hwdev = malidp->dev;
596 int ret;
597
598 /* ensure interrupts are disabled */
599 malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
600 malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
601 malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
602 malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
603
604 ret = devm_request_threaded_irq(drm->dev, irq, malidp_de_irq,
605 malidp_de_irq_thread_handler,
606 IRQF_SHARED, "malidp-de", drm);
607 if (ret < 0) {
608 DRM_ERROR("failed to install DE IRQ handler\n");
609 return ret;
610 }
611
612 /* first enable the DC block IRQs */
613 malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK,
614 hwdev->map.dc_irq_map.irq_mask);
615
616 /* now enable the DE block IRQs */
617 malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK,
618 hwdev->map.de_irq_map.irq_mask);
619
620 return 0;
621}
622
623void malidp_de_irq_fini(struct drm_device *drm)
624{
625 struct malidp_drm *malidp = drm->dev_private;
626 struct malidp_hw_device *hwdev = malidp->dev;
627
628 malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK,
629 hwdev->map.de_irq_map.irq_mask);
630 malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK,
631 hwdev->map.dc_irq_map.irq_mask);
632}
633
634static irqreturn_t malidp_se_irq(int irq, void *arg)
635{
636 struct drm_device *drm = arg;
637 struct malidp_drm *malidp = drm->dev_private;
638 struct malidp_hw_device *hwdev = malidp->dev;
639 u32 status, mask;
640
641 status = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_STATUS);
642 if (!(status & hwdev->map.se_irq_map.irq_mask))
643 return IRQ_NONE;
644
645 mask = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_MASKIRQ);
646 status = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_STATUS);
647 status &= mask;
648 /* ToDo: status decoding and firing up of VSYNC and page flip events */
649
650 malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status);
651
652 return IRQ_HANDLED;
653}
654
655static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg)
656{
657 return IRQ_HANDLED;
658}
659
660int malidp_se_irq_init(struct drm_device *drm, int irq)
661{
662 struct malidp_drm *malidp = drm->dev_private;
663 struct malidp_hw_device *hwdev = malidp->dev;
664 int ret;
665
666 /* ensure interrupts are disabled */
667 malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
668 malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
669
670 ret = devm_request_threaded_irq(drm->dev, irq, malidp_se_irq,
671 malidp_se_irq_thread_handler,
672 IRQF_SHARED, "malidp-se", drm);
673 if (ret < 0) {
674 DRM_ERROR("failed to install SE IRQ handler\n");
675 return ret;
676 }
677
678 malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK,
679 hwdev->map.se_irq_map.irq_mask);
680
681 return 0;
682}
683
684void malidp_se_irq_fini(struct drm_device *drm)
685{
686 struct malidp_drm *malidp = drm->dev_private;
687 struct malidp_hw_device *hwdev = malidp->dev;
688
689 malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK,
690 hwdev->map.se_irq_map.irq_mask);
691}
diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h
new file mode 100644
index 000000000000..141743e9f3a6
--- /dev/null
+++ b/drivers/gpu/drm/arm/malidp_hw.h
@@ -0,0 +1,241 @@
1/*
2 *
3 * (C) COPYRIGHT 2013-2016 ARM Limited. All rights reserved.
4 *
5 * This program is free software and is provided to you under the terms of the
6 * GNU General Public License version 2 as published by the Free Software
7 * Foundation, and any use by you of this program is subject to the terms
8 * of such GNU licence.
9 *
10 * ARM Mali DP hardware manipulation routines.
11 */
12
13#ifndef __MALIDP_HW_H__
14#define __MALIDP_HW_H__
15
16#include <linux/bitops.h>
17#include "malidp_regs.h"
18
19struct videomode;
20struct clk;
21
22/* Mali DP IP blocks */
23enum {
24 MALIDP_DE_BLOCK = 0,
25 MALIDP_SE_BLOCK,
26 MALIDP_DC_BLOCK
27};
28
29/* Mali DP layer IDs */
30enum {
31 DE_VIDEO1 = BIT(0),
32 DE_GRAPHICS1 = BIT(1),
33 DE_GRAPHICS2 = BIT(2), /* used only in DP500 */
34 DE_VIDEO2 = BIT(3),
35 DE_SMART = BIT(4),
36};
37
38struct malidp_input_format {
39 u32 format; /* DRM fourcc */
40 u8 layer; /* bitmask of layers supporting it */
41 u8 id; /* used internally */
42};
43
44#define MALIDP_INVALID_FORMAT_ID 0xff
45
46/*
47 * hide the differences between register maps
48 * by using a common structure to hold the
49 * base register offsets
50 */
51
52struct malidp_irq_map {
53 u32 irq_mask; /* mask of IRQs that can be enabled in the block */
54 u32 vsync_irq; /* IRQ bit used for signaling during VSYNC */
55};
56
57struct malidp_layer {
58 u16 id; /* layer ID */
59 u16 base; /* address offset for the register bank */
60 u16 ptr; /* address offset for the pointer register */
61};
62
63/* regmap features */
64#define MALIDP_REGMAP_HAS_CLEARIRQ (1 << 0)
65
66struct malidp_hw_regmap {
67 /* address offset of the DE register bank */
68 /* is always 0x0000 */
69 /* address offset of the SE registers bank */
70 const u16 se_base;
71 /* address offset of the DC registers bank */
72 const u16 dc_base;
73
74 /* address offset for the output depth register */
75 const u16 out_depth_base;
76
77 /* bitmap with register map features */
78 const u8 features;
79
80 /* list of supported layers */
81 const u8 n_layers;
82 const struct malidp_layer *layers;
83
84 const struct malidp_irq_map de_irq_map;
85 const struct malidp_irq_map se_irq_map;
86 const struct malidp_irq_map dc_irq_map;
87
88 /* list of supported input formats for each layer */
89 const struct malidp_input_format *input_formats;
90 const u8 n_input_formats;
91};
92
93struct malidp_hw_device {
94 const struct malidp_hw_regmap map;
95 void __iomem *regs;
96
97 /* APB clock */
98 struct clk *pclk;
99 /* AXI clock */
100 struct clk *aclk;
101 /* main clock for display core */
102 struct clk *mclk;
103 /* pixel clock for display core */
104 struct clk *pxlclk;
105
106 /*
107 * Validate the driver instance against the hardware bits
108 */
109 int (*query_hw)(struct malidp_hw_device *hwdev);
110
111 /*
112 * Set the hardware into config mode, ready to accept mode changes
113 */
114 void (*enter_config_mode)(struct malidp_hw_device *hwdev);
115
116 /*
117 * Tell hardware to exit configuration mode
118 */
119 void (*leave_config_mode)(struct malidp_hw_device *hwdev);
120
121 /*
122 * Query if hardware is in configuration mode
123 */
124 bool (*in_config_mode)(struct malidp_hw_device *hwdev);
125
126 /*
127 * Set configuration valid flag for hardware parameters that can
128 * be changed outside the configuration mode. Hardware will use
129 * the new settings when config valid is set after the end of the
130 * current buffer scanout
131 */
132 void (*set_config_valid)(struct malidp_hw_device *hwdev);
133
134 /*
135 * Set a new mode in hardware. Requires the hardware to be in
136 * configuration mode before this function is called.
137 */
138 void (*modeset)(struct malidp_hw_device *hwdev, struct videomode *m);
139
140 /*
141 * Calculate the required rotation memory given the active area
142 * and the buffer format.
143 */
144 int (*rotmem_required)(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt);
145
146 u8 features;
147
148 u8 min_line_size;
149 u16 max_line_size;
150
151 /* size of memory used for rotating layers, up to two banks available */
152 u32 rotation_memory[2];
153};
154
155/* Supported variants of the hardware */
156enum {
157 MALIDP_500 = 0,
158 MALIDP_550,
159 MALIDP_650,
160 /* keep the next entry last */
161 MALIDP_MAX_DEVICES
162};
163
164extern const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES];
165
166static inline u32 malidp_hw_read(struct malidp_hw_device *hwdev, u32 reg)
167{
168 return readl(hwdev->regs + reg);
169}
170
171static inline void malidp_hw_write(struct malidp_hw_device *hwdev,
172 u32 value, u32 reg)
173{
174 writel(value, hwdev->regs + reg);
175}
176
177static inline void malidp_hw_setbits(struct malidp_hw_device *hwdev,
178 u32 mask, u32 reg)
179{
180 u32 data = malidp_hw_read(hwdev, reg);
181
182 data |= mask;
183 malidp_hw_write(hwdev, data, reg);
184}
185
186static inline void malidp_hw_clearbits(struct malidp_hw_device *hwdev,
187 u32 mask, u32 reg)
188{
189 u32 data = malidp_hw_read(hwdev, reg);
190
191 data &= ~mask;
192 malidp_hw_write(hwdev, data, reg);
193}
194
195static inline u32 malidp_get_block_base(struct malidp_hw_device *hwdev,
196 u8 block)
197{
198 switch (block) {
199 case MALIDP_SE_BLOCK:
200 return hwdev->map.se_base;
201 case MALIDP_DC_BLOCK:
202 return hwdev->map.dc_base;
203 }
204
205 return 0;
206}
207
208static inline void malidp_hw_disable_irq(struct malidp_hw_device *hwdev,
209 u8 block, u32 irq)
210{
211 u32 base = malidp_get_block_base(hwdev, block);
212
213 malidp_hw_clearbits(hwdev, irq, base + MALIDP_REG_MASKIRQ);
214}
215
216static inline void malidp_hw_enable_irq(struct malidp_hw_device *hwdev,
217 u8 block, u32 irq)
218{
219 u32 base = malidp_get_block_base(hwdev, block);
220
221 malidp_hw_setbits(hwdev, irq, base + MALIDP_REG_MASKIRQ);
222}
223
224int malidp_de_irq_init(struct drm_device *drm, int irq);
225void malidp_de_irq_fini(struct drm_device *drm);
226int malidp_se_irq_init(struct drm_device *drm, int irq);
227void malidp_se_irq_fini(struct drm_device *drm);
228
229u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
230 u8 layer_id, u32 format);
231
232/*
233 * background color components are defined as 12bits values,
234 * they will be shifted right when stored on hardware that
235 * supports only 8bits per channel
236 */
237#define MALIDP_BGND_COLOR_R 0x000
238#define MALIDP_BGND_COLOR_G 0x000
239#define MALIDP_BGND_COLOR_B 0x000
240
241#endif /* __MALIDP_HW_H__ */
diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c
new file mode 100644
index 000000000000..725098d6179a
--- /dev/null
+++ b/drivers/gpu/drm/arm/malidp_planes.c
@@ -0,0 +1,298 @@
1/*
2 * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
3 * Author: Liviu Dudau <Liviu.Dudau@arm.com>
4 *
5 * This program is free software and is provided to you under the terms of the
6 * GNU General Public License version 2 as published by the Free Software
7 * Foundation, and any use by you of this program is subject to the terms
8 * of such GNU licence.
9 *
10 * ARM Mali DP plane manipulation routines.
11 */
12
13#include <drm/drmP.h>
14#include <drm/drm_atomic_helper.h>
15#include <drm/drm_fb_cma_helper.h>
16#include <drm/drm_gem_cma_helper.h>
17#include <drm/drm_plane_helper.h>
18
19#include "malidp_hw.h"
20#include "malidp_drv.h"
21
22/* Layer specific register offsets */
23#define MALIDP_LAYER_FORMAT 0x000
24#define MALIDP_LAYER_CONTROL 0x004
25#define LAYER_ENABLE (1 << 0)
26#define LAYER_ROT_OFFSET 8
27#define LAYER_H_FLIP (1 << 10)
28#define LAYER_V_FLIP (1 << 11)
29#define LAYER_ROT_MASK (0xf << 8)
30#define MALIDP_LAYER_SIZE 0x00c
31#define LAYER_H_VAL(x) (((x) & 0x1fff) << 0)
32#define LAYER_V_VAL(x) (((x) & 0x1fff) << 16)
33#define MALIDP_LAYER_COMP_SIZE 0x010
34#define MALIDP_LAYER_OFFSET 0x014
35#define MALIDP_LAYER_STRIDE 0x018
36
37static void malidp_de_plane_destroy(struct drm_plane *plane)
38{
39 struct malidp_plane *mp = to_malidp_plane(plane);
40
41 if (mp->base.fb)
42 drm_framebuffer_unreference(mp->base.fb);
43
44 drm_plane_helper_disable(plane);
45 drm_plane_cleanup(plane);
46 devm_kfree(plane->dev->dev, mp);
47}
48
49struct drm_plane_state *malidp_duplicate_plane_state(struct drm_plane *plane)
50{
51 struct malidp_plane_state *state, *m_state;
52
53 if (!plane->state)
54 return NULL;
55
56 state = kmalloc(sizeof(*state), GFP_KERNEL);
57 if (state) {
58 m_state = to_malidp_plane_state(plane->state);
59 __drm_atomic_helper_plane_duplicate_state(plane, &state->base);
60 state->rotmem_size = m_state->rotmem_size;
61 }
62
63 return &state->base;
64}
65
66void malidp_destroy_plane_state(struct drm_plane *plane,
67 struct drm_plane_state *state)
68{
69 struct malidp_plane_state *m_state = to_malidp_plane_state(state);
70
71 __drm_atomic_helper_plane_destroy_state(state);
72 kfree(m_state);
73}
74
75static const struct drm_plane_funcs malidp_de_plane_funcs = {
76 .update_plane = drm_atomic_helper_update_plane,
77 .disable_plane = drm_atomic_helper_disable_plane,
78 .destroy = malidp_de_plane_destroy,
79 .reset = drm_atomic_helper_plane_reset,
80 .atomic_duplicate_state = malidp_duplicate_plane_state,
81 .atomic_destroy_state = malidp_destroy_plane_state,
82};
83
84static int malidp_de_plane_check(struct drm_plane *plane,
85 struct drm_plane_state *state)
86{
87 struct malidp_plane *mp = to_malidp_plane(plane);
88 struct malidp_plane_state *ms = to_malidp_plane_state(state);
89 u8 format_id;
90 u32 src_w, src_h;
91
92 if (!state->crtc || !state->fb)
93 return 0;
94
95 format_id = malidp_hw_get_format_id(&mp->hwdev->map, mp->layer->id,
96 state->fb->pixel_format);
97 if (format_id == MALIDP_INVALID_FORMAT_ID)
98 return -EINVAL;
99
100 src_w = state->src_w >> 16;
101 src_h = state->src_h >> 16;
102
103 if ((state->crtc_w > mp->hwdev->max_line_size) ||
104 (state->crtc_h > mp->hwdev->max_line_size) ||
105 (state->crtc_w < mp->hwdev->min_line_size) ||
106 (state->crtc_h < mp->hwdev->min_line_size) ||
107 (state->crtc_w != src_w) || (state->crtc_h != src_h))
108 return -EINVAL;
109
110 /* packed RGB888 / BGR888 can't be rotated or flipped */
111 if (state->rotation != BIT(DRM_ROTATE_0) &&
112 (state->fb->pixel_format == DRM_FORMAT_RGB888 ||
113 state->fb->pixel_format == DRM_FORMAT_BGR888))
114 return -EINVAL;
115
116 ms->rotmem_size = 0;
117 if (state->rotation & MALIDP_ROTATED_MASK) {
118 int val;
119
120 val = mp->hwdev->rotmem_required(mp->hwdev, state->crtc_h,
121 state->crtc_w,
122 state->fb->pixel_format);
123 if (val < 0)
124 return val;
125
126 ms->rotmem_size = val;
127 }
128
129 return 0;
130}
131
132static void malidp_de_plane_update(struct drm_plane *plane,
133 struct drm_plane_state *old_state)
134{
135 struct drm_gem_cma_object *obj;
136 struct malidp_plane *mp;
137 const struct malidp_hw_regmap *map;
138 u8 format_id;
139 u16 ptr;
140 u32 format, src_w, src_h, dest_w, dest_h, val = 0;
141 int num_planes, i;
142
143 mp = to_malidp_plane(plane);
144
145 map = &mp->hwdev->map;
146 format = plane->state->fb->pixel_format;
147 format_id = malidp_hw_get_format_id(map, mp->layer->id, format);
148 num_planes = drm_format_num_planes(format);
149
150 /* convert src values from Q16 fixed point to integer */
151 src_w = plane->state->src_w >> 16;
152 src_h = plane->state->src_h >> 16;
153 if (plane->state->rotation & MALIDP_ROTATED_MASK) {
154 dest_w = plane->state->crtc_h;
155 dest_h = plane->state->crtc_w;
156 } else {
157 dest_w = plane->state->crtc_w;
158 dest_h = plane->state->crtc_h;
159 }
160
161 malidp_hw_write(mp->hwdev, format_id, mp->layer->base);
162
163 for (i = 0; i < num_planes; i++) {
164 /* calculate the offset for the layer's plane registers */
165 ptr = mp->layer->ptr + (i << 4);
166
167 obj = drm_fb_cma_get_gem_obj(plane->state->fb, i);
168 malidp_hw_write(mp->hwdev, lower_32_bits(obj->paddr), ptr);
169 malidp_hw_write(mp->hwdev, upper_32_bits(obj->paddr), ptr + 4);
170 malidp_hw_write(mp->hwdev, plane->state->fb->pitches[i],
171 mp->layer->base + MALIDP_LAYER_STRIDE);
172 }
173
174 malidp_hw_write(mp->hwdev, LAYER_H_VAL(src_w) | LAYER_V_VAL(src_h),
175 mp->layer->base + MALIDP_LAYER_SIZE);
176
177 malidp_hw_write(mp->hwdev, LAYER_H_VAL(dest_w) | LAYER_V_VAL(dest_h),
178 mp->layer->base + MALIDP_LAYER_COMP_SIZE);
179
180 malidp_hw_write(mp->hwdev, LAYER_H_VAL(plane->state->crtc_x) |
181 LAYER_V_VAL(plane->state->crtc_y),
182 mp->layer->base + MALIDP_LAYER_OFFSET);
183
184 /* first clear the rotation bits in the register */
185 malidp_hw_clearbits(mp->hwdev, LAYER_ROT_MASK,
186 mp->layer->base + MALIDP_LAYER_CONTROL);
187
188 /* setup the rotation and axis flip bits */
189 if (plane->state->rotation & DRM_ROTATE_MASK)
190 val = ilog2(plane->state->rotation & DRM_ROTATE_MASK) << LAYER_ROT_OFFSET;
191 if (plane->state->rotation & BIT(DRM_REFLECT_X))
192 val |= LAYER_V_FLIP;
193 if (plane->state->rotation & BIT(DRM_REFLECT_Y))
194 val |= LAYER_H_FLIP;
195
196 /* set the 'enable layer' bit */
197 val |= LAYER_ENABLE;
198
199 malidp_hw_setbits(mp->hwdev, val,
200 mp->layer->base + MALIDP_LAYER_CONTROL);
201}
202
203static void malidp_de_plane_disable(struct drm_plane *plane,
204 struct drm_plane_state *state)
205{
206 struct malidp_plane *mp = to_malidp_plane(plane);
207
208 malidp_hw_clearbits(mp->hwdev, LAYER_ENABLE,
209 mp->layer->base + MALIDP_LAYER_CONTROL);
210}
211
212static const struct drm_plane_helper_funcs malidp_de_plane_helper_funcs = {
213 .atomic_check = malidp_de_plane_check,
214 .atomic_update = malidp_de_plane_update,
215 .atomic_disable = malidp_de_plane_disable,
216};
217
218int malidp_de_planes_init(struct drm_device *drm)
219{
220 struct malidp_drm *malidp = drm->dev_private;
221 const struct malidp_hw_regmap *map = &malidp->dev->map;
222 struct malidp_plane *plane = NULL;
223 enum drm_plane_type plane_type;
224 unsigned long crtcs = 1 << drm->mode_config.num_crtc;
225 u32 *formats;
226 int ret, i, j, n;
227
228 formats = kcalloc(map->n_input_formats, sizeof(*formats), GFP_KERNEL);
229 if (!formats) {
230 ret = -ENOMEM;
231 goto cleanup;
232 }
233
234 for (i = 0; i < map->n_layers; i++) {
235 u8 id = map->layers[i].id;
236
237 plane = kzalloc(sizeof(*plane), GFP_KERNEL);
238 if (!plane) {
239 ret = -ENOMEM;
240 goto cleanup;
241 }
242
243 /* build the list of DRM supported formats based on the map */
244 for (n = 0, j = 0; j < map->n_input_formats; j++) {
245 if ((map->input_formats[j].layer & id) == id)
246 formats[n++] = map->input_formats[j].format;
247 }
248
249 plane_type = (i == 0) ? DRM_PLANE_TYPE_PRIMARY :
250 DRM_PLANE_TYPE_OVERLAY;
251 ret = drm_universal_plane_init(drm, &plane->base, crtcs,
252 &malidp_de_plane_funcs, formats,
253 n, plane_type, NULL);
254 if (ret < 0)
255 goto cleanup;
256
257 if (!drm->mode_config.rotation_property) {
258 unsigned long flags = BIT(DRM_ROTATE_0) |
259 BIT(DRM_ROTATE_90) |
260 BIT(DRM_ROTATE_180) |
261 BIT(DRM_ROTATE_270) |
262 BIT(DRM_REFLECT_X) |
263 BIT(DRM_REFLECT_Y);
264 drm->mode_config.rotation_property =
265 drm_mode_create_rotation_property(drm, flags);
266 }
267 /* SMART layer can't be rotated */
268 if (drm->mode_config.rotation_property && (id != DE_SMART))
269 drm_object_attach_property(&plane->base.base,
270 drm->mode_config.rotation_property,
271 BIT(DRM_ROTATE_0));
272
273 drm_plane_helper_add(&plane->base,
274 &malidp_de_plane_helper_funcs);
275 plane->hwdev = malidp->dev;
276 plane->layer = &map->layers[i];
277 }
278
279 kfree(formats);
280
281 return 0;
282
283cleanup:
284 malidp_de_planes_destroy(drm);
285 kfree(formats);
286
287 return ret;
288}
289
290void malidp_de_planes_destroy(struct drm_device *drm)
291{
292 struct drm_plane *p, *pt;
293
294 list_for_each_entry_safe(p, pt, &drm->mode_config.plane_list, head) {
295 drm_plane_cleanup(p);
296 kfree(p);
297 }
298}
diff --git a/drivers/gpu/drm/arm/malidp_regs.h b/drivers/gpu/drm/arm/malidp_regs.h
new file mode 100644
index 000000000000..73fecb38f955
--- /dev/null
+++ b/drivers/gpu/drm/arm/malidp_regs.h
@@ -0,0 +1,172 @@
1/*
2 * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
3 * Author: Liviu Dudau <Liviu.Dudau@arm.com>
4 *
5 * This program is free software and is provided to you under the terms of the
6 * GNU General Public License version 2 as published by the Free Software
7 * Foundation, and any use by you of this program is subject to the terms
8 * of such GNU licence.
9 *
10 * ARM Mali DP500/DP550/DP650 registers definition.
11 */
12
13#ifndef __MALIDP_REGS_H__
14#define __MALIDP_REGS_H__
15
16/*
17 * abbreviations used:
18 * - DC - display core (general settings)
19 * - DE - display engine
20 * - SE - scaling engine
21 */
22
23/* interrupt bit masks */
24#define MALIDP_DE_IRQ_UNDERRUN (1 << 0)
25
26#define MALIDP500_DE_IRQ_AXI_ERR (1 << 4)
27#define MALIDP500_DE_IRQ_VSYNC (1 << 5)
28#define MALIDP500_DE_IRQ_PROG_LINE (1 << 6)
29#define MALIDP500_DE_IRQ_SATURATION (1 << 7)
30#define MALIDP500_DE_IRQ_CONF_VALID (1 << 8)
31#define MALIDP500_DE_IRQ_CONF_MODE (1 << 11)
32#define MALIDP500_DE_IRQ_CONF_ACTIVE (1 << 17)
33#define MALIDP500_DE_IRQ_PM_ACTIVE (1 << 18)
34#define MALIDP500_DE_IRQ_TESTMODE_ACTIVE (1 << 19)
35#define MALIDP500_DE_IRQ_FORCE_BLNK_ACTIVE (1 << 24)
36#define MALIDP500_DE_IRQ_AXI_BUSY (1 << 28)
37#define MALIDP500_DE_IRQ_GLOBAL (1 << 31)
38#define MALIDP500_SE_IRQ_CONF_MODE (1 << 0)
39#define MALIDP500_SE_IRQ_CONF_VALID (1 << 4)
40#define MALIDP500_SE_IRQ_INIT_BUSY (1 << 5)
41#define MALIDP500_SE_IRQ_AXI_ERROR (1 << 8)
42#define MALIDP500_SE_IRQ_OVERRUN (1 << 9)
43#define MALIDP500_SE_IRQ_PROG_LINE1 (1 << 12)
44#define MALIDP500_SE_IRQ_PROG_LINE2 (1 << 13)
45#define MALIDP500_SE_IRQ_CONF_ACTIVE (1 << 17)
46#define MALIDP500_SE_IRQ_PM_ACTIVE (1 << 18)
47#define MALIDP500_SE_IRQ_AXI_BUSY (1 << 28)
48#define MALIDP500_SE_IRQ_GLOBAL (1 << 31)
49
50#define MALIDP550_DE_IRQ_SATURATION (1 << 8)
51#define MALIDP550_DE_IRQ_VSYNC (1 << 12)
52#define MALIDP550_DE_IRQ_PROG_LINE (1 << 13)
53#define MALIDP550_DE_IRQ_AXI_ERR (1 << 16)
54#define MALIDP550_SE_IRQ_EOW (1 << 0)
55#define MALIDP550_SE_IRQ_AXI_ERR (1 << 16)
56#define MALIDP550_DC_IRQ_CONF_VALID (1 << 0)
57#define MALIDP550_DC_IRQ_CONF_MODE (1 << 4)
58#define MALIDP550_DC_IRQ_CONF_ACTIVE (1 << 16)
59#define MALIDP550_DC_IRQ_DE (1 << 20)
60#define MALIDP550_DC_IRQ_SE (1 << 24)
61
62#define MALIDP650_DE_IRQ_DRIFT (1 << 4)
63
64/* bit masks that are common between products */
65#define MALIDP_CFG_VALID (1 << 0)
66#define MALIDP_DISP_FUNC_ILACED (1 << 8)
67
68/* register offsets for IRQ management */
69#define MALIDP_REG_STATUS 0x00000
70#define MALIDP_REG_SETIRQ 0x00004
71#define MALIDP_REG_MASKIRQ 0x00008
72#define MALIDP_REG_CLEARIRQ 0x0000c
73
74/* register offsets */
75#define MALIDP_DE_CORE_ID 0x00018
76#define MALIDP_DE_DISPLAY_FUNC 0x00020
77
78/* these offsets are relative to MALIDP5x0_TIMINGS_BASE */
79#define MALIDP_DE_H_TIMINGS 0x0
80#define MALIDP_DE_V_TIMINGS 0x4
81#define MALIDP_DE_SYNC_WIDTH 0x8
82#define MALIDP_DE_HV_ACTIVE 0xc
83
84/* macros to set values into registers */
85#define MALIDP_DE_H_FRONTPORCH(x) (((x) & 0xfff) << 0)
86#define MALIDP_DE_H_BACKPORCH(x) (((x) & 0x3ff) << 16)
87#define MALIDP500_DE_V_FRONTPORCH(x) (((x) & 0xff) << 0)
88#define MALIDP550_DE_V_FRONTPORCH(x) (((x) & 0xfff) << 0)
89#define MALIDP_DE_V_BACKPORCH(x) (((x) & 0xff) << 16)
90#define MALIDP_DE_H_SYNCWIDTH(x) (((x) & 0x3ff) << 0)
91#define MALIDP_DE_V_SYNCWIDTH(x) (((x) & 0xff) << 16)
92#define MALIDP_DE_H_ACTIVE(x) (((x) & 0x1fff) << 0)
93#define MALIDP_DE_V_ACTIVE(x) (((x) & 0x1fff) << 16)
94
95/* register offsets and bits specific to DP500 */
96#define MALIDP500_DC_BASE 0x00000
97#define MALIDP500_DC_CONTROL 0x0000c
98#define MALIDP500_DC_CONFIG_REQ (1 << 17)
99#define MALIDP500_HSYNCPOL (1 << 20)
100#define MALIDP500_VSYNCPOL (1 << 21)
101#define MALIDP500_DC_CLEAR_MASK 0x300fff
102#define MALIDP500_DE_LINE_COUNTER 0x00010
103#define MALIDP500_DE_AXI_CONTROL 0x00014
104#define MALIDP500_DE_SECURE_CTRL 0x0001c
105#define MALIDP500_DE_CHROMA_KEY 0x00024
106#define MALIDP500_TIMINGS_BASE 0x00028
107
108#define MALIDP500_CONFIG_3D 0x00038
109#define MALIDP500_BGND_COLOR 0x0003c
110#define MALIDP500_OUTPUT_DEPTH 0x00044
111#define MALIDP500_YUV_RGB_COEF 0x00048
112#define MALIDP500_COLOR_ADJ_COEF 0x00078
113#define MALIDP500_COEF_TABLE_ADDR 0x000a8
114#define MALIDP500_COEF_TABLE_DATA 0x000ac
115#define MALIDP500_DE_LV_BASE 0x00100
116#define MALIDP500_DE_LV_PTR_BASE 0x00124
117#define MALIDP500_DE_LG1_BASE 0x00200
118#define MALIDP500_DE_LG1_PTR_BASE 0x0021c
119#define MALIDP500_DE_LG2_BASE 0x00300
120#define MALIDP500_DE_LG2_PTR_BASE 0x0031c
121#define MALIDP500_SE_BASE 0x00c00
122#define MALIDP500_SE_PTR_BASE 0x00e0c
123#define MALIDP500_DC_IRQ_BASE 0x00f00
124#define MALIDP500_CONFIG_VALID 0x00f00
125#define MALIDP500_CONFIG_ID 0x00fd4
126
127/* register offsets and bits specific to DP550/DP650 */
128#define MALIDP550_DE_CONTROL 0x00010
129#define MALIDP550_DE_LINE_COUNTER 0x00014
130#define MALIDP550_DE_AXI_CONTROL 0x00018
131#define MALIDP550_DE_QOS 0x0001c
132#define MALIDP550_TIMINGS_BASE 0x00030
133#define MALIDP550_HSYNCPOL (1 << 12)
134#define MALIDP550_VSYNCPOL (1 << 28)
135
136#define MALIDP550_DE_DISP_SIDEBAND 0x00040
137#define MALIDP550_DE_BGND_COLOR 0x00044
138#define MALIDP550_DE_OUTPUT_DEPTH 0x0004c
139#define MALIDP550_DE_COLOR_COEF 0x00050
140#define MALIDP550_DE_COEF_TABLE_ADDR 0x00080
141#define MALIDP550_DE_COEF_TABLE_DATA 0x00084
142#define MALIDP550_DE_LV1_BASE 0x00100
143#define MALIDP550_DE_LV1_PTR_BASE 0x00124
144#define MALIDP550_DE_LV2_BASE 0x00200
145#define MALIDP550_DE_LV2_PTR_BASE 0x00224
146#define MALIDP550_DE_LG_BASE 0x00300
147#define MALIDP550_DE_LG_PTR_BASE 0x0031c
148#define MALIDP550_DE_LS_BASE 0x00400
149#define MALIDP550_DE_LS_PTR_BASE 0x0042c
150#define MALIDP550_DE_PERF_BASE 0x00500
151#define MALIDP550_SE_BASE 0x08000
152#define MALIDP550_DC_BASE 0x0c000
153#define MALIDP550_DC_CONTROL 0x0c010
154#define MALIDP550_DC_CONFIG_REQ (1 << 16)
155#define MALIDP550_CONFIG_VALID 0x0c014
156#define MALIDP550_CONFIG_ID 0x0ffd4
157
158/*
159 * Starting with DP550 the register map blocks has been standardised to the
160 * following layout:
161 *
162 * Offset Block registers
163 * 0x00000 Display Engine
164 * 0x08000 Scaling Engine
165 * 0x0c000 Display Core
166 * 0x10000 Secure control
167 *
168 * The old DP500 IP mixes some DC with the DE registers, hence the need
169 * for a mapping structure.
170 */
171
172#endif /* __MALIDP_REGS_H__ */