diff options
Diffstat (limited to 'drivers/gpu/drm')
| -rw-r--r-- | drivers/gpu/drm/arm/Kconfig | 16 | ||||
| -rw-r--r-- | drivers/gpu/drm/arm/Makefile | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/arm/malidp_crtc.c | 216 | ||||
| -rw-r--r-- | drivers/gpu/drm/arm/malidp_drv.c | 512 | ||||
| -rw-r--r-- | drivers/gpu/drm/arm/malidp_drv.h | 54 | ||||
| -rw-r--r-- | drivers/gpu/drm/arm/malidp_hw.c | 691 | ||||
| -rw-r--r-- | drivers/gpu/drm/arm/malidp_hw.h | 241 | ||||
| -rw-r--r-- | drivers/gpu/drm/arm/malidp_planes.c | 298 | ||||
| -rw-r--r-- | drivers/gpu/drm/arm/malidp_regs.h | 172 |
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 | |||
| 29 | config 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 @@ | |||
| 1 | hdlcd-y := hdlcd_drv.o hdlcd_crtc.o | 1 | hdlcd-y := hdlcd_drv.o hdlcd_crtc.o |
| 2 | obj-$(CONFIG_DRM_HDLCD) += hdlcd.o | 2 | obj-$(CONFIG_DRM_HDLCD) += hdlcd.o |
| 3 | mali-dp-y := malidp_drv.o malidp_hw.o malidp_planes.o malidp_crtc.o | ||
| 4 | obj-$(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 | |||
| 24 | static 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 | |||
| 56 | static 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 | |||
| 75 | static 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 | |||
| 85 | static 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 | |||
| 163 | static 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 | |||
| 170 | static 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 | |||
| 179 | int 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 | |||
| 212 | crtc_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 | */ | ||
| 39 | static 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 | |||
| 57 | static 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 | |||
| 64 | static 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 | |||
| 88 | static 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 | |||
| 103 | static struct drm_mode_config_helper_funcs malidp_mode_config_helpers = { | ||
| 104 | .atomic_commit_tail = malidp_atomic_commit_tail, | ||
| 105 | }; | ||
| 106 | |||
| 107 | static 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 | |||
| 114 | static 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 | |||
| 124 | static 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 | |||
| 133 | static 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 | |||
| 157 | static 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 | |||
| 187 | static 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 | |||
| 194 | static 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 | |||
| 208 | static 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 | |||
| 237 | static 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 | }; | ||
| 252 | MODULE_DEVICE_TABLE(of, malidp_drm_of_match); | ||
| 253 | |||
| 254 | #define MAX_OUTPUT_CHANNELS 3 | ||
| 255 | |||
| 256 | static 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 | |||
| 397 | fbdev_fail: | ||
| 398 | drm_vblank_cleanup(drm); | ||
| 399 | vblank_fail: | ||
| 400 | malidp_se_irq_fini(drm); | ||
| 401 | malidp_de_irq_fini(drm); | ||
| 402 | irq_init_fail: | ||
| 403 | component_unbind_all(dev, drm); | ||
| 404 | bind_fail: | ||
| 405 | drm_dev_unregister(drm); | ||
| 406 | register_fail: | ||
| 407 | malidp_de_planes_destroy(drm); | ||
| 408 | drm_mode_config_cleanup(drm); | ||
| 409 | init_fail: | ||
| 410 | drm->dev_private = NULL; | ||
| 411 | dev_set_drvdata(dev, NULL); | ||
| 412 | query_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); | ||
| 417 | alloc_fail: | ||
| 418 | of_reserved_mem_device_release(dev); | ||
| 419 | |||
| 420 | return ret; | ||
| 421 | } | ||
| 422 | |||
| 423 | static 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 | |||
| 450 | static const struct component_master_ops malidp_master_ops = { | ||
| 451 | .bind = malidp_bind, | ||
| 452 | .unbind = malidp_unbind, | ||
| 453 | }; | ||
| 454 | |||
| 455 | static 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 | |||
| 462 | static 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 | |||
| 493 | static int malidp_platform_remove(struct platform_device *pdev) | ||
| 494 | { | ||
| 495 | component_master_del(&pdev->dev, &malidp_master_ops); | ||
| 496 | return 0; | ||
| 497 | } | ||
| 498 | |||
| 499 | static 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 | |||
| 508 | module_platform_driver(malidp_platform_driver); | ||
| 509 | |||
| 510 | MODULE_AUTHOR("Liviu Dudau <Liviu.Dudau@arm.com>"); | ||
| 511 | MODULE_DESCRIPTION("ARM Mali DP DRM driver"); | ||
| 512 | MODULE_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 | |||
| 20 | struct 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 | |||
| 31 | struct malidp_plane { | ||
| 32 | struct drm_plane base; | ||
| 33 | struct malidp_hw_device *hwdev; | ||
| 34 | const struct malidp_layer *layer; | ||
| 35 | }; | ||
| 36 | |||
| 37 | struct 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 | |||
| 47 | int malidp_de_planes_init(struct drm_device *drm); | ||
| 48 | void malidp_de_planes_destroy(struct drm_device *drm); | ||
| 49 | int 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 | |||
| 24 | static 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 | |||
| 72 | static const struct malidp_input_format malidp550_de_formats[] = { | ||
| 73 | MALIDP_COMMON_FORMATS, | ||
| 74 | }; | ||
| 75 | |||
| 76 | static 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 | |||
| 82 | static 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 | |||
| 91 | static 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 | |||
| 105 | static 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 | |||
| 124 | static 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 | |||
| 139 | static 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 | |||
| 150 | static void malidp500_set_config_valid(struct malidp_hw_device *hwdev) | ||
| 151 | { | ||
| 152 | malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID); | ||
| 153 | } | ||
| 154 | |||
| 155 | static 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 | |||
| 199 | static 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 | |||
| 218 | static 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 | |||
| 251 | static 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 | |||
| 270 | static 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 | |||
| 285 | static 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 | |||
| 296 | static void malidp550_set_config_valid(struct malidp_hw_device *hwdev) | ||
| 297 | { | ||
| 298 | malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID); | ||
| 299 | } | ||
| 300 | |||
| 301 | static 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 | |||
| 345 | static 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 | |||
| 390 | static 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 | |||
| 418 | const 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 | |||
| 520 | u8 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 | |||
| 534 | static 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 | |||
| 544 | static 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 | |||
| 582 | static 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 | |||
| 592 | int 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 | |||
| 623 | void 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 | |||
| 634 | static 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 | |||
| 655 | static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg) | ||
| 656 | { | ||
| 657 | return IRQ_HANDLED; | ||
| 658 | } | ||
| 659 | |||
| 660 | int 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 | |||
| 684 | void 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 | |||
| 19 | struct videomode; | ||
| 20 | struct clk; | ||
| 21 | |||
| 22 | /* Mali DP IP blocks */ | ||
| 23 | enum { | ||
| 24 | MALIDP_DE_BLOCK = 0, | ||
| 25 | MALIDP_SE_BLOCK, | ||
| 26 | MALIDP_DC_BLOCK | ||
| 27 | }; | ||
| 28 | |||
| 29 | /* Mali DP layer IDs */ | ||
| 30 | enum { | ||
| 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 | |||
| 38 | struct 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 | |||
| 52 | struct 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 | |||
| 57 | struct 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 | |||
| 66 | struct 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 | |||
| 93 | struct 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 */ | ||
| 156 | enum { | ||
| 157 | MALIDP_500 = 0, | ||
| 158 | MALIDP_550, | ||
| 159 | MALIDP_650, | ||
| 160 | /* keep the next entry last */ | ||
| 161 | MALIDP_MAX_DEVICES | ||
| 162 | }; | ||
| 163 | |||
| 164 | extern const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES]; | ||
| 165 | |||
| 166 | static inline u32 malidp_hw_read(struct malidp_hw_device *hwdev, u32 reg) | ||
| 167 | { | ||
| 168 | return readl(hwdev->regs + reg); | ||
| 169 | } | ||
| 170 | |||
| 171 | static inline void malidp_hw_write(struct malidp_hw_device *hwdev, | ||
| 172 | u32 value, u32 reg) | ||
| 173 | { | ||
| 174 | writel(value, hwdev->regs + reg); | ||
| 175 | } | ||
| 176 | |||
| 177 | static 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 | |||
| 186 | static 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 | |||
| 195 | static 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 | |||
| 208 | static 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 | |||
| 216 | static 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 | |||
| 224 | int malidp_de_irq_init(struct drm_device *drm, int irq); | ||
| 225 | void malidp_de_irq_fini(struct drm_device *drm); | ||
| 226 | int malidp_se_irq_init(struct drm_device *drm, int irq); | ||
| 227 | void malidp_se_irq_fini(struct drm_device *drm); | ||
| 228 | |||
| 229 | u8 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 | |||
| 37 | static 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 | |||
| 49 | struct 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 | |||
| 66 | void 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 | |||
| 75 | static 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 | |||
| 84 | static 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 | |||
| 132 | static 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 | |||
| 203 | static 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 | |||
| 212 | static 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 | |||
| 218 | int 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 | |||
| 283 | cleanup: | ||
| 284 | malidp_de_planes_destroy(drm); | ||
| 285 | kfree(formats); | ||
| 286 | |||
| 287 | return ret; | ||
| 288 | } | ||
| 289 | |||
| 290 | void 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__ */ | ||
