diff options
Diffstat (limited to 'drivers/gpu/drm')
| -rw-r--r-- | drivers/gpu/drm/sti/sti_compositor.c | 32 | ||||
| -rw-r--r-- | drivers/gpu/drm/sti/sti_crtc.c | 133 | ||||
| -rw-r--r-- | drivers/gpu/drm/sti/sti_cursor.c | 211 | ||||
| -rw-r--r-- | drivers/gpu/drm/sti/sti_cursor.h | 6 | ||||
| -rw-r--r-- | drivers/gpu/drm/sti/sti_gdp.c | 493 | ||||
| -rw-r--r-- | drivers/gpu/drm/sti/sti_gdp.h | 8 | ||||
| -rw-r--r-- | drivers/gpu/drm/sti/sti_hqvdp.c | 429 | ||||
| -rw-r--r-- | drivers/gpu/drm/sti/sti_mixer.c | 10 | ||||
| -rw-r--r-- | drivers/gpu/drm/sti/sti_mixer.h | 11 | ||||
| -rw-r--r-- | drivers/gpu/drm/sti/sti_plane.c | 253 | ||||
| -rw-r--r-- | drivers/gpu/drm/sti/sti_plane.h | 66 | ||||
| -rw-r--r-- | drivers/gpu/drm/sti/sti_vid.c | 29 | ||||
| -rw-r--r-- | drivers/gpu/drm/sti/sti_vid.h | 5 |
13 files changed, 809 insertions, 877 deletions
diff --git a/drivers/gpu/drm/sti/sti_compositor.c b/drivers/gpu/drm/sti/sti_compositor.c index d62ed7f4cb2c..c652627b1bca 100644 --- a/drivers/gpu/drm/sti/sti_compositor.c +++ b/drivers/gpu/drm/sti/sti_compositor.c | |||
| @@ -61,15 +61,13 @@ static int sti_compositor_bind(struct device *dev, | |||
| 61 | { | 61 | { |
| 62 | struct sti_compositor *compo = dev_get_drvdata(dev); | 62 | struct sti_compositor *compo = dev_get_drvdata(dev); |
| 63 | struct drm_device *drm_dev = data; | 63 | struct drm_device *drm_dev = data; |
| 64 | unsigned int i, mixer_id = 0, vid_id = 0, crtc_id = 0, plane_id = 0; | 64 | unsigned int i, mixer_id = 0, vid_id = 0, crtc_id = 0; |
| 65 | struct sti_private *dev_priv = drm_dev->dev_private; | 65 | struct sti_private *dev_priv = drm_dev->dev_private; |
| 66 | struct drm_plane *cursor = NULL; | 66 | struct drm_plane *cursor = NULL; |
| 67 | struct drm_plane *primary = NULL; | 67 | struct drm_plane *primary = NULL; |
| 68 | struct sti_compositor_subdev_descriptor *desc = compo->data.subdev_desc; | 68 | struct sti_compositor_subdev_descriptor *desc = compo->data.subdev_desc; |
| 69 | unsigned int array_size = compo->data.nb_subdev; | 69 | unsigned int array_size = compo->data.nb_subdev; |
| 70 | 70 | ||
| 71 | struct sti_plane *plane; | ||
| 72 | |||
| 73 | dev_priv->compo = compo; | 71 | dev_priv->compo = compo; |
| 74 | 72 | ||
| 75 | /* Register mixer subdev and video subdev first */ | 73 | /* Register mixer subdev and video subdev first */ |
| @@ -110,27 +108,25 @@ static int sti_compositor_bind(struct device *dev, | |||
| 110 | /* Nothing to do, already done at the first round */ | 108 | /* Nothing to do, already done at the first round */ |
| 111 | break; | 109 | break; |
| 112 | case STI_CURSOR_SUBDEV: | 110 | case STI_CURSOR_SUBDEV: |
| 113 | plane = sti_cursor_create(compo->dev, desc[i].id, | 111 | cursor = sti_cursor_create(drm_dev, compo->dev, |
| 114 | compo->regs + desc[i].offset); | 112 | desc[i].id, |
| 115 | if (!plane) { | 113 | compo->regs + desc[i].offset, |
| 114 | 1); | ||
| 115 | if (!cursor) { | ||
| 116 | DRM_ERROR("Can't create CURSOR plane\n"); | 116 | DRM_ERROR("Can't create CURSOR plane\n"); |
| 117 | break; | 117 | break; |
| 118 | } | 118 | } |
| 119 | cursor = sti_plane_init(drm_dev, plane, 1, | ||
| 120 | DRM_PLANE_TYPE_CURSOR); | ||
| 121 | plane_id++; | ||
| 122 | break; | 119 | break; |
| 123 | case STI_GPD_SUBDEV: | 120 | case STI_GPD_SUBDEV: |
| 124 | plane = sti_gdp_create(compo->dev, desc[i].id, | 121 | primary = sti_gdp_create(drm_dev, compo->dev, |
| 125 | compo->regs + desc[i].offset); | 122 | desc[i].id, |
| 126 | if (!plane) { | 123 | compo->regs + desc[i].offset, |
| 124 | (1 << mixer_id) - 1, | ||
| 125 | plane_type); | ||
| 126 | if (!primary) { | ||
| 127 | DRM_ERROR("Can't create GDP plane\n"); | 127 | DRM_ERROR("Can't create GDP plane\n"); |
| 128 | break; | 128 | break; |
| 129 | } | 129 | } |
| 130 | primary = sti_plane_init(drm_dev, plane, | ||
| 131 | (1 << mixer_id) - 1, | ||
| 132 | plane_type); | ||
| 133 | plane_id++; | ||
| 134 | break; | 130 | break; |
| 135 | default: | 131 | default: |
| 136 | DRM_ERROR("Unknown subdev compoment type\n"); | 132 | DRM_ERROR("Unknown subdev compoment type\n"); |
| @@ -151,10 +147,6 @@ static int sti_compositor_bind(struct device *dev, | |||
| 151 | /* Allow usage of vblank without having to call drm_irq_install */ | 147 | /* Allow usage of vblank without having to call drm_irq_install */ |
| 152 | drm_dev->irq_enabled = 1; | 148 | drm_dev->irq_enabled = 1; |
| 153 | 149 | ||
| 154 | DRM_DEBUG_DRIVER("Initialized %d DRM CRTC(s) and %d DRM plane(s)\n", | ||
| 155 | crtc_id, plane_id); | ||
| 156 | DRM_DEBUG_DRIVER("DRM plane(s) for VID/VDP not created yet\n"); | ||
| 157 | |||
| 158 | return 0; | 150 | return 0; |
| 159 | } | 151 | } |
| 160 | 152 | ||
diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c index 27b3ef207617..23fc2db50d17 100644 --- a/drivers/gpu/drm/sti/sti_crtc.c +++ b/drivers/gpu/drm/sti/sti_crtc.c | |||
| @@ -17,20 +17,18 @@ | |||
| 17 | #include "sti_compositor.h" | 17 | #include "sti_compositor.h" |
| 18 | #include "sti_crtc.h" | 18 | #include "sti_crtc.h" |
| 19 | #include "sti_drv.h" | 19 | #include "sti_drv.h" |
| 20 | #include "sti_vid.h" | ||
| 20 | #include "sti_vtg.h" | 21 | #include "sti_vtg.h" |
| 21 | 22 | ||
| 22 | static void sti_crtc_dpms(struct drm_crtc *crtc, int mode) | 23 | static void sti_crtc_enable(struct drm_crtc *crtc) |
| 23 | { | ||
| 24 | DRM_DEBUG_KMS("\n"); | ||
| 25 | } | ||
| 26 | |||
| 27 | static void sti_crtc_prepare(struct drm_crtc *crtc) | ||
| 28 | { | 24 | { |
| 29 | struct sti_mixer *mixer = to_sti_mixer(crtc); | 25 | struct sti_mixer *mixer = to_sti_mixer(crtc); |
| 30 | struct device *dev = mixer->dev; | 26 | struct device *dev = mixer->dev; |
| 31 | struct sti_compositor *compo = dev_get_drvdata(dev); | 27 | struct sti_compositor *compo = dev_get_drvdata(dev); |
| 32 | 28 | ||
| 33 | mixer->enabled = true; | 29 | DRM_DEBUG_DRIVER("\n"); |
| 30 | |||
| 31 | mixer->status = STI_MIXER_READY; | ||
| 34 | 32 | ||
| 35 | /* Prepare and enable the compo IP clock */ | 33 | /* Prepare and enable the compo IP clock */ |
| 36 | if (mixer->id == STI_MIXER_MAIN) { | 34 | if (mixer->id == STI_MIXER_MAIN) { |
| @@ -41,31 +39,16 @@ static void sti_crtc_prepare(struct drm_crtc *crtc) | |||
| 41 | DRM_INFO("Failed to prepare/enable compo_aux clk\n"); | 39 | DRM_INFO("Failed to prepare/enable compo_aux clk\n"); |
| 42 | } | 40 | } |
| 43 | 41 | ||
| 44 | sti_mixer_clear_all_planes(mixer); | 42 | drm_crtc_vblank_on(crtc); |
| 45 | } | 43 | } |
| 46 | 44 | ||
| 47 | static void sti_crtc_commit(struct drm_crtc *crtc) | 45 | static void sti_crtc_disabling(struct drm_crtc *crtc) |
| 48 | { | 46 | { |
| 49 | struct sti_mixer *mixer = to_sti_mixer(crtc); | 47 | struct sti_mixer *mixer = to_sti_mixer(crtc); |
| 50 | struct device *dev = mixer->dev; | ||
| 51 | struct sti_compositor *compo = dev_get_drvdata(dev); | ||
| 52 | struct sti_plane *plane; | ||
| 53 | |||
| 54 | if ((!mixer || !compo)) { | ||
| 55 | DRM_ERROR("Can't find mixer or compositor)\n"); | ||
| 56 | return; | ||
| 57 | } | ||
| 58 | |||
| 59 | /* get GDP which is reserved to the CRTC FB */ | ||
| 60 | plane = to_sti_plane(crtc->primary); | ||
| 61 | if (!plane) | ||
| 62 | DRM_ERROR("Can't find CRTC dedicated plane (GDP0)\n"); | ||
| 63 | 48 | ||
| 64 | /* Enable plane on mixer */ | 49 | DRM_DEBUG_DRIVER("\n"); |
| 65 | if (sti_mixer_set_plane_status(mixer, plane, true)) | ||
| 66 | DRM_ERROR("Cannot enable plane at mixer\n"); | ||
| 67 | 50 | ||
| 68 | drm_crtc_vblank_on(crtc); | 51 | mixer->status = STI_MIXER_DISABLING; |
| 69 | } | 52 | } |
| 70 | 53 | ||
| 71 | static bool sti_crtc_mode_fixup(struct drm_crtc *crtc, | 54 | static bool sti_crtc_mode_fixup(struct drm_crtc *crtc, |
| @@ -133,9 +116,6 @@ static void sti_crtc_disable(struct drm_crtc *crtc) | |||
| 133 | struct device *dev = mixer->dev; | 116 | struct device *dev = mixer->dev; |
| 134 | struct sti_compositor *compo = dev_get_drvdata(dev); | 117 | struct sti_compositor *compo = dev_get_drvdata(dev); |
| 135 | 118 | ||
| 136 | if (!mixer->enabled) | ||
| 137 | return; | ||
| 138 | |||
| 139 | DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer)); | 119 | DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer)); |
| 140 | 120 | ||
| 141 | /* Disable Background */ | 121 | /* Disable Background */ |
| @@ -152,13 +132,13 @@ static void sti_crtc_disable(struct drm_crtc *crtc) | |||
| 152 | clk_disable_unprepare(compo->clk_compo_aux); | 132 | clk_disable_unprepare(compo->clk_compo_aux); |
| 153 | } | 133 | } |
| 154 | 134 | ||
| 155 | mixer->enabled = false; | 135 | mixer->status = STI_MIXER_DISABLED; |
| 156 | } | 136 | } |
| 157 | 137 | ||
| 158 | static void | 138 | static void |
| 159 | sti_crtc_mode_set_nofb(struct drm_crtc *crtc) | 139 | sti_crtc_mode_set_nofb(struct drm_crtc *crtc) |
| 160 | { | 140 | { |
| 161 | sti_crtc_prepare(crtc); | 141 | sti_crtc_enable(crtc); |
| 162 | sti_crtc_mode_set(crtc, &crtc->state->adjusted_mode); | 142 | sti_crtc_mode_set(crtc, &crtc->state->adjusted_mode); |
| 163 | } | 143 | } |
| 164 | 144 | ||
| @@ -178,17 +158,79 @@ static void sti_crtc_atomic_begin(struct drm_crtc *crtc) | |||
| 178 | 158 | ||
| 179 | static void sti_crtc_atomic_flush(struct drm_crtc *crtc) | 159 | static void sti_crtc_atomic_flush(struct drm_crtc *crtc) |
| 180 | { | 160 | { |
| 161 | struct drm_device *drm_dev = crtc->dev; | ||
| 162 | struct sti_mixer *mixer = to_sti_mixer(crtc); | ||
| 163 | struct sti_compositor *compo = dev_get_drvdata(mixer->dev); | ||
| 164 | struct drm_plane *p; | ||
| 165 | |||
| 166 | DRM_DEBUG_DRIVER("\n"); | ||
| 167 | |||
| 168 | /* perform plane actions */ | ||
| 169 | list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) { | ||
| 170 | struct sti_plane *plane = to_sti_plane(p); | ||
| 171 | |||
| 172 | switch (plane->status) { | ||
| 173 | case STI_PLANE_UPDATED: | ||
| 174 | /* update planes tag as updated */ | ||
| 175 | DRM_DEBUG_DRIVER("update plane %s\n", | ||
| 176 | sti_plane_to_str(plane)); | ||
| 177 | |||
| 178 | if (sti_mixer_set_plane_depth(mixer, plane)) { | ||
| 179 | DRM_ERROR("Cannot set plane %s depth\n", | ||
| 180 | sti_plane_to_str(plane)); | ||
| 181 | break; | ||
| 182 | } | ||
| 183 | |||
| 184 | if (sti_mixer_set_plane_status(mixer, plane, true)) { | ||
| 185 | DRM_ERROR("Cannot enable plane %s at mixer\n", | ||
| 186 | sti_plane_to_str(plane)); | ||
| 187 | break; | ||
| 188 | } | ||
| 189 | |||
| 190 | /* if plane is HQVDP_0 then commit the vid[0] */ | ||
| 191 | if (plane->desc == STI_HQVDP_0) | ||
| 192 | sti_vid_commit(compo->vid[0], p->state); | ||
| 193 | |||
| 194 | plane->status = STI_PLANE_READY; | ||
| 195 | |||
| 196 | break; | ||
| 197 | case STI_PLANE_DISABLING: | ||
| 198 | /* disabling sequence for planes tag as disabling */ | ||
| 199 | DRM_DEBUG_DRIVER("disable plane %s from mixer\n", | ||
| 200 | sti_plane_to_str(plane)); | ||
| 201 | |||
| 202 | if (sti_mixer_set_plane_status(mixer, plane, false)) { | ||
| 203 | DRM_ERROR("Cannot disable plane %s at mixer\n", | ||
| 204 | sti_plane_to_str(plane)); | ||
| 205 | continue; | ||
| 206 | } | ||
| 207 | |||
| 208 | if (plane->desc == STI_CURSOR) | ||
| 209 | /* tag plane status for disabled */ | ||
| 210 | plane->status = STI_PLANE_DISABLED; | ||
| 211 | else | ||
| 212 | /* tag plane status for flushing */ | ||
| 213 | plane->status = STI_PLANE_FLUSHING; | ||
| 214 | |||
| 215 | /* if plane is HQVDP_0 then disable the vid[0] */ | ||
| 216 | if (plane->desc == STI_HQVDP_0) | ||
| 217 | sti_vid_disable(compo->vid[0]); | ||
| 218 | |||
| 219 | break; | ||
| 220 | default: | ||
| 221 | /* Other status case are not handled */ | ||
| 222 | break; | ||
| 223 | } | ||
| 224 | } | ||
| 181 | } | 225 | } |
| 182 | 226 | ||
| 183 | static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = { | 227 | static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = { |
| 184 | .dpms = sti_crtc_dpms, | 228 | .enable = sti_crtc_enable, |
| 185 | .prepare = sti_crtc_prepare, | 229 | .disable = sti_crtc_disabling, |
| 186 | .commit = sti_crtc_commit, | ||
| 187 | .mode_fixup = sti_crtc_mode_fixup, | 230 | .mode_fixup = sti_crtc_mode_fixup, |
| 188 | .mode_set = drm_helper_crtc_mode_set, | 231 | .mode_set = drm_helper_crtc_mode_set, |
| 189 | .mode_set_nofb = sti_crtc_mode_set_nofb, | 232 | .mode_set_nofb = sti_crtc_mode_set_nofb, |
| 190 | .mode_set_base = drm_helper_crtc_mode_set_base, | 233 | .mode_set_base = drm_helper_crtc_mode_set_base, |
| 191 | .disable = sti_crtc_disable, | ||
| 192 | .atomic_begin = sti_crtc_atomic_begin, | 234 | .atomic_begin = sti_crtc_atomic_begin, |
| 193 | .atomic_flush = sti_crtc_atomic_flush, | 235 | .atomic_flush = sti_crtc_atomic_flush, |
| 194 | }; | 236 | }; |
| @@ -237,6 +279,21 @@ int sti_crtc_vblank_cb(struct notifier_block *nb, | |||
| 237 | } | 279 | } |
| 238 | spin_unlock_irqrestore(&drm_dev->event_lock, flags); | 280 | spin_unlock_irqrestore(&drm_dev->event_lock, flags); |
| 239 | 281 | ||
| 282 | if (compo->mixer[*crtc]->status == STI_MIXER_DISABLING) { | ||
| 283 | struct drm_plane *p; | ||
| 284 | |||
| 285 | /* Disable mixer only if all overlay planes (GDP and VDP) | ||
| 286 | * are disabled */ | ||
| 287 | list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) { | ||
| 288 | struct sti_plane *plane = to_sti_plane(p); | ||
| 289 | |||
| 290 | if ((plane->desc & STI_PLANE_TYPE_MASK) <= STI_VDP) | ||
| 291 | if (plane->status != STI_PLANE_DISABLED) | ||
| 292 | return 0; | ||
| 293 | } | ||
| 294 | sti_crtc_disable(&compo->mixer[*crtc]->drm_crtc); | ||
| 295 | } | ||
| 296 | |||
| 240 | return 0; | 297 | return 0; |
| 241 | } | 298 | } |
| 242 | 299 | ||
| @@ -259,9 +316,9 @@ int sti_crtc_enable_vblank(struct drm_device *dev, int crtc) | |||
| 259 | } | 316 | } |
| 260 | EXPORT_SYMBOL(sti_crtc_enable_vblank); | 317 | EXPORT_SYMBOL(sti_crtc_enable_vblank); |
| 261 | 318 | ||
| 262 | void sti_crtc_disable_vblank(struct drm_device *dev, int crtc) | 319 | void sti_crtc_disable_vblank(struct drm_device *drm_dev, int crtc) |
| 263 | { | 320 | { |
| 264 | struct sti_private *priv = dev->dev_private; | 321 | struct sti_private *priv = drm_dev->dev_private; |
| 265 | struct sti_compositor *compo = priv->compo; | 322 | struct sti_compositor *compo = priv->compo; |
| 266 | struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb; | 323 | struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb; |
| 267 | 324 | ||
| @@ -273,7 +330,7 @@ void sti_crtc_disable_vblank(struct drm_device *dev, int crtc) | |||
| 273 | 330 | ||
| 274 | /* free the resources of the pending requests */ | 331 | /* free the resources of the pending requests */ |
| 275 | if (compo->mixer[crtc]->pending_event) { | 332 | if (compo->mixer[crtc]->pending_event) { |
| 276 | drm_vblank_put(dev, crtc); | 333 | drm_vblank_put(drm_dev, crtc); |
| 277 | compo->mixer[crtc]->pending_event = NULL; | 334 | compo->mixer[crtc]->pending_event = NULL; |
| 278 | } | 335 | } |
| 279 | } | 336 | } |
diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c index 2868909aa926..dd1032195051 100644 --- a/drivers/gpu/drm/sti/sti_cursor.c +++ b/drivers/gpu/drm/sti/sti_cursor.c | |||
| @@ -7,6 +7,12 @@ | |||
| 7 | */ | 7 | */ |
| 8 | #include <drm/drmP.h> | 8 | #include <drm/drmP.h> |
| 9 | 9 | ||
| 10 | #include <drm/drm_atomic_helper.h> | ||
| 11 | #include <drm/drm_fb_cma_helper.h> | ||
| 12 | #include <drm/drm_gem_cma_helper.h> | ||
| 13 | #include <drm/drm_plane_helper.h> | ||
| 14 | |||
| 15 | #include "sti_compositor.h" | ||
| 10 | #include "sti_cursor.h" | 16 | #include "sti_cursor.h" |
| 11 | #include "sti_plane.h" | 17 | #include "sti_plane.h" |
| 12 | #include "sti_vtg.h" | 18 | #include "sti_vtg.h" |
| @@ -42,14 +48,14 @@ struct dma_pixmap { | |||
| 42 | /** | 48 | /** |
| 43 | * STI Cursor structure | 49 | * STI Cursor structure |
| 44 | * | 50 | * |
| 45 | * @sti_plane: sti_plane structure | 51 | * @sti_plane: sti_plane structure |
| 46 | * @dev: driver device | 52 | * @dev: driver device |
| 47 | * @regs: cursor registers | 53 | * @regs: cursor registers |
| 48 | * @width: cursor width | 54 | * @width: cursor width |
| 49 | * @height: cursor height | 55 | * @height: cursor height |
| 50 | * @clut: color look up table | 56 | * @clut: color look up table |
| 51 | * @clut_paddr: color look up table physical address | 57 | * @clut_paddr: color look up table physical address |
| 52 | * @pixmap: pixmap dma buffer (clut8-format cursor) | 58 | * @pixmap: pixmap dma buffer (clut8-format cursor) |
| 53 | */ | 59 | */ |
| 54 | struct sti_cursor { | 60 | struct sti_cursor { |
| 55 | struct sti_plane plane; | 61 | struct sti_plane plane; |
| @@ -68,20 +74,8 @@ static const uint32_t cursor_supported_formats[] = { | |||
| 68 | 74 | ||
| 69 | #define to_sti_cursor(x) container_of(x, struct sti_cursor, plane) | 75 | #define to_sti_cursor(x) container_of(x, struct sti_cursor, plane) |
| 70 | 76 | ||
| 71 | static const uint32_t *sti_cursor_get_formats(struct sti_plane *plane) | 77 | static void sti_cursor_argb8888_to_clut8(struct sti_cursor *cursor, u32 *src) |
| 72 | { | ||
| 73 | return cursor_supported_formats; | ||
| 74 | } | ||
| 75 | |||
| 76 | static unsigned int sti_cursor_get_nb_formats(struct sti_plane *plane) | ||
| 77 | { | ||
| 78 | return ARRAY_SIZE(cursor_supported_formats); | ||
| 79 | } | ||
| 80 | |||
| 81 | static void sti_cursor_argb8888_to_clut8(struct sti_plane *plane) | ||
| 82 | { | 78 | { |
| 83 | struct sti_cursor *cursor = to_sti_cursor(plane); | ||
| 84 | u32 *src = plane->vaddr; | ||
| 85 | u8 *dst = cursor->pixmap.base; | 79 | u8 *dst = cursor->pixmap.base; |
| 86 | unsigned int i, j; | 80 | unsigned int i, j; |
| 87 | u32 a, r, g, b; | 81 | u32 a, r, g, b; |
| @@ -100,32 +94,67 @@ static void sti_cursor_argb8888_to_clut8(struct sti_plane *plane) | |||
| 100 | } | 94 | } |
| 101 | } | 95 | } |
| 102 | 96 | ||
| 103 | static int sti_cursor_prepare_plane(struct sti_plane *plane, bool first_prepare) | 97 | static void sti_cursor_init(struct sti_cursor *cursor) |
| 98 | { | ||
| 99 | unsigned short *base = cursor->clut; | ||
| 100 | unsigned int a, r, g, b; | ||
| 101 | |||
| 102 | /* Assign CLUT values, ARGB444 format */ | ||
| 103 | for (a = 0; a < 4; a++) | ||
| 104 | for (r = 0; r < 4; r++) | ||
| 105 | for (g = 0; g < 4; g++) | ||
| 106 | for (b = 0; b < 4; b++) | ||
| 107 | *base++ = (a * 5) << 12 | | ||
| 108 | (r * 5) << 8 | | ||
| 109 | (g * 5) << 4 | | ||
| 110 | (b * 5); | ||
| 111 | } | ||
| 112 | |||
| 113 | static void sti_cursor_atomic_update(struct drm_plane *drm_plane, | ||
| 114 | struct drm_plane_state *oldstate) | ||
| 104 | { | 115 | { |
| 116 | struct drm_plane_state *state = drm_plane->state; | ||
| 117 | struct sti_plane *plane = to_sti_plane(drm_plane); | ||
| 105 | struct sti_cursor *cursor = to_sti_cursor(plane); | 118 | struct sti_cursor *cursor = to_sti_cursor(plane); |
| 106 | struct drm_display_mode *mode = plane->mode; | 119 | struct drm_crtc *crtc = state->crtc; |
| 120 | struct sti_mixer *mixer = to_sti_mixer(crtc); | ||
| 121 | struct drm_framebuffer *fb = state->fb; | ||
| 122 | struct drm_display_mode *mode = &crtc->mode; | ||
| 123 | int dst_x = state->crtc_x; | ||
| 124 | int dst_y = state->crtc_y; | ||
| 125 | int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x); | ||
| 126 | int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y); | ||
| 127 | /* src_x are in 16.16 format */ | ||
| 128 | int src_w = state->src_w >> 16; | ||
| 129 | int src_h = state->src_h >> 16; | ||
| 130 | bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false; | ||
| 131 | struct drm_gem_cma_object *cma_obj; | ||
| 107 | u32 y, x; | 132 | u32 y, x; |
| 108 | u32 val; | 133 | u32 val; |
| 109 | 134 | ||
| 110 | DRM_DEBUG_DRIVER("\n"); | 135 | DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n", |
| 136 | crtc->base.id, sti_mixer_to_str(mixer), | ||
| 137 | drm_plane->base.id, sti_plane_to_str(plane)); | ||
| 138 | DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", dst_w, dst_h, dst_x, dst_y); | ||
| 111 | 139 | ||
| 112 | dev_dbg(cursor->dev, "%s %s\n", __func__, sti_plane_to_str(plane)); | 140 | dev_dbg(cursor->dev, "%s %s\n", __func__, |
| 141 | sti_plane_to_str(plane)); | ||
| 113 | 142 | ||
| 114 | if (plane->src_w < STI_CURS_MIN_SIZE || | 143 | if (src_w < STI_CURS_MIN_SIZE || |
| 115 | plane->src_h < STI_CURS_MIN_SIZE || | 144 | src_h < STI_CURS_MIN_SIZE || |
| 116 | plane->src_w > STI_CURS_MAX_SIZE || | 145 | src_w > STI_CURS_MAX_SIZE || |
| 117 | plane->src_h > STI_CURS_MAX_SIZE) { | 146 | src_h > STI_CURS_MAX_SIZE) { |
| 118 | DRM_ERROR("Invalid cursor size (%dx%d)\n", | 147 | DRM_ERROR("Invalid cursor size (%dx%d)\n", |
| 119 | plane->src_w, plane->src_h); | 148 | src_w, src_h); |
| 120 | return -EINVAL; | 149 | return; |
| 121 | } | 150 | } |
| 122 | 151 | ||
| 123 | /* If the cursor size has changed, re-allocated the pixmap */ | 152 | /* If the cursor size has changed, re-allocated the pixmap */ |
| 124 | if (!cursor->pixmap.base || | 153 | if (!cursor->pixmap.base || |
| 125 | (cursor->width != plane->src_w) || | 154 | (cursor->width != src_w) || |
| 126 | (cursor->height != plane->src_h)) { | 155 | (cursor->height != src_h)) { |
| 127 | cursor->width = plane->src_w; | 156 | cursor->width = src_w; |
| 128 | cursor->height = plane->src_h; | 157 | cursor->height = src_h; |
| 129 | 158 | ||
| 130 | if (cursor->pixmap.base) | 159 | if (cursor->pixmap.base) |
| 131 | dma_free_writecombine(cursor->dev, | 160 | dma_free_writecombine(cursor->dev, |
| @@ -141,12 +170,18 @@ static int sti_cursor_prepare_plane(struct sti_plane *plane, bool first_prepare) | |||
| 141 | GFP_KERNEL | GFP_DMA); | 170 | GFP_KERNEL | GFP_DMA); |
| 142 | if (!cursor->pixmap.base) { | 171 | if (!cursor->pixmap.base) { |
| 143 | DRM_ERROR("Failed to allocate memory for pixmap\n"); | 172 | DRM_ERROR("Failed to allocate memory for pixmap\n"); |
| 144 | return -ENOMEM; | 173 | return; |
| 145 | } | 174 | } |
| 146 | } | 175 | } |
| 147 | 176 | ||
| 177 | cma_obj = drm_fb_cma_get_gem_obj(fb, 0); | ||
| 178 | if (!cma_obj) { | ||
| 179 | DRM_ERROR("Can't get CMA GEM object for fb\n"); | ||
| 180 | return; | ||
| 181 | } | ||
| 182 | |||
| 148 | /* Convert ARGB8888 to CLUT8 */ | 183 | /* Convert ARGB8888 to CLUT8 */ |
| 149 | sti_cursor_argb8888_to_clut8(plane); | 184 | sti_cursor_argb8888_to_clut8(cursor, (u32 *)cma_obj->vaddr); |
| 150 | 185 | ||
| 151 | /* AWS and AWE depend on the mode */ | 186 | /* AWS and AWE depend on the mode */ |
| 152 | y = sti_vtg_get_line_number(*mode, 0); | 187 | y = sti_vtg_get_line_number(*mode, 0); |
| @@ -164,62 +199,50 @@ static int sti_cursor_prepare_plane(struct sti_plane *plane, bool first_prepare) | |||
| 164 | writel(CUR_CTL_CLUT_UPDATE, cursor->regs + CUR_CTL); | 199 | writel(CUR_CTL_CLUT_UPDATE, cursor->regs + CUR_CTL); |
| 165 | } | 200 | } |
| 166 | 201 | ||
| 167 | return 0; | ||
| 168 | } | ||
| 169 | |||
| 170 | static int sti_cursor_commit_plane(struct sti_plane *plane) | ||
| 171 | { | ||
| 172 | struct sti_cursor *cursor = to_sti_cursor(plane); | ||
| 173 | struct drm_display_mode *mode = plane->mode; | ||
| 174 | u32 ydo, xdo; | ||
| 175 | |||
| 176 | dev_dbg(cursor->dev, "%s %s\n", __func__, sti_plane_to_str(plane)); | ||
| 177 | |||
| 178 | /* Set memory location, size, and position */ | 202 | /* Set memory location, size, and position */ |
| 179 | writel(cursor->pixmap.paddr, cursor->regs + CUR_PML); | 203 | writel(cursor->pixmap.paddr, cursor->regs + CUR_PML); |
| 180 | writel(cursor->width, cursor->regs + CUR_PMP); | 204 | writel(cursor->width, cursor->regs + CUR_PMP); |
| 181 | writel(cursor->height << 16 | cursor->width, cursor->regs + CUR_SIZE); | 205 | writel(cursor->height << 16 | cursor->width, cursor->regs + CUR_SIZE); |
| 182 | 206 | ||
| 183 | ydo = sti_vtg_get_line_number(*mode, plane->dst_y); | 207 | y = sti_vtg_get_line_number(*mode, dst_y); |
| 184 | xdo = sti_vtg_get_pixel_number(*mode, plane->dst_y); | 208 | x = sti_vtg_get_pixel_number(*mode, dst_y); |
| 185 | writel((ydo << 16) | xdo, cursor->regs + CUR_VPO); | 209 | writel((y << 16) | x, cursor->regs + CUR_VPO); |
| 186 | 210 | ||
| 187 | return 0; | 211 | plane->status = STI_PLANE_UPDATED; |
| 188 | } | 212 | } |
| 189 | 213 | ||
| 190 | static int sti_cursor_disable_plane(struct sti_plane *plane) | 214 | static void sti_cursor_atomic_disable(struct drm_plane *drm_plane, |
| 215 | struct drm_plane_state *oldstate) | ||
| 191 | { | 216 | { |
| 192 | return 0; | 217 | struct sti_plane *plane = to_sti_plane(drm_plane); |
| 193 | } | 218 | struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc); |
| 194 | 219 | ||
| 195 | static void sti_cursor_init(struct sti_cursor *cursor) | 220 | if (!drm_plane->crtc) { |
| 196 | { | 221 | DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", |
| 197 | unsigned short *base = cursor->clut; | 222 | drm_plane->base.id); |
| 198 | unsigned int a, r, g, b; | 223 | return; |
| 224 | } | ||
| 199 | 225 | ||
| 200 | /* Assign CLUT values, ARGB444 format */ | 226 | DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n", |
| 201 | for (a = 0; a < 4; a++) | 227 | drm_plane->crtc->base.id, sti_mixer_to_str(mixer), |
| 202 | for (r = 0; r < 4; r++) | 228 | drm_plane->base.id, sti_plane_to_str(plane)); |
| 203 | for (g = 0; g < 4; g++) | 229 | |
| 204 | for (b = 0; b < 4; b++) | 230 | plane->status = STI_PLANE_DISABLING; |
| 205 | *base++ = (a * 5) << 12 | | ||
| 206 | (r * 5) << 8 | | ||
| 207 | (g * 5) << 4 | | ||
| 208 | (b * 5); | ||
| 209 | } | 231 | } |
| 210 | 232 | ||
| 211 | static const struct sti_plane_funcs cursor_plane_ops = { | 233 | static const struct drm_plane_helper_funcs sti_cursor_helpers_funcs = { |
| 212 | .get_formats = sti_cursor_get_formats, | 234 | .atomic_update = sti_cursor_atomic_update, |
| 213 | .get_nb_formats = sti_cursor_get_nb_formats, | 235 | .atomic_disable = sti_cursor_atomic_disable, |
| 214 | .prepare = sti_cursor_prepare_plane, | ||
| 215 | .commit = sti_cursor_commit_plane, | ||
| 216 | .disable = sti_cursor_disable_plane, | ||
| 217 | }; | 236 | }; |
| 218 | 237 | ||
| 219 | struct sti_plane *sti_cursor_create(struct device *dev, int desc, | 238 | struct drm_plane *sti_cursor_create(struct drm_device *drm_dev, |
| 220 | void __iomem *baseaddr) | 239 | struct device *dev, int desc, |
| 240 | void __iomem *baseaddr, | ||
| 241 | unsigned int possible_crtcs) | ||
| 221 | { | 242 | { |
| 222 | struct sti_cursor *cursor; | 243 | struct sti_cursor *cursor; |
| 244 | size_t size; | ||
| 245 | int res; | ||
| 223 | 246 | ||
| 224 | cursor = devm_kzalloc(dev, sizeof(*cursor), GFP_KERNEL); | 247 | cursor = devm_kzalloc(dev, sizeof(*cursor), GFP_KERNEL); |
| 225 | if (!cursor) { | 248 | if (!cursor) { |
| @@ -228,23 +251,43 @@ struct sti_plane *sti_cursor_create(struct device *dev, int desc, | |||
| 228 | } | 251 | } |
| 229 | 252 | ||
| 230 | /* Allocate clut buffer */ | 253 | /* Allocate clut buffer */ |
| 231 | cursor->clut = dma_alloc_writecombine(dev, | 254 | size = 0x100 * sizeof(unsigned short); |
| 232 | 0x100 * sizeof(unsigned short), | 255 | cursor->clut = dma_alloc_writecombine(dev, size, &cursor->clut_paddr, |
| 233 | &cursor->clut_paddr, | 256 | GFP_KERNEL | GFP_DMA); |
| 234 | GFP_KERNEL | GFP_DMA); | ||
| 235 | 257 | ||
| 236 | if (!cursor->clut) { | 258 | if (!cursor->clut) { |
| 237 | DRM_ERROR("Failed to allocate memory for cursor clut\n"); | 259 | DRM_ERROR("Failed to allocate memory for cursor clut\n"); |
| 238 | devm_kfree(dev, cursor); | 260 | goto err_clut; |
| 239 | return NULL; | ||
| 240 | } | 261 | } |
| 241 | 262 | ||
| 242 | cursor->dev = dev; | 263 | cursor->dev = dev; |
| 243 | cursor->regs = baseaddr; | 264 | cursor->regs = baseaddr; |
| 244 | cursor->plane.desc = desc; | 265 | cursor->plane.desc = desc; |
| 245 | cursor->plane.ops = &cursor_plane_ops; | 266 | cursor->plane.status = STI_PLANE_DISABLED; |
| 246 | 267 | ||
| 247 | sti_cursor_init(cursor); | 268 | sti_cursor_init(cursor); |
| 248 | 269 | ||
| 249 | return &cursor->plane; | 270 | res = drm_universal_plane_init(drm_dev, &cursor->plane.drm_plane, |
| 271 | possible_crtcs, | ||
| 272 | &sti_plane_helpers_funcs, | ||
| 273 | cursor_supported_formats, | ||
| 274 | ARRAY_SIZE(cursor_supported_formats), | ||
| 275 | DRM_PLANE_TYPE_CURSOR); | ||
| 276 | if (res) { | ||
| 277 | DRM_ERROR("Failed to initialize universal plane\n"); | ||
| 278 | goto err_plane; | ||
| 279 | } | ||
| 280 | |||
| 281 | drm_plane_helper_add(&cursor->plane.drm_plane, | ||
| 282 | &sti_cursor_helpers_funcs); | ||
| 283 | |||
| 284 | sti_plane_init_property(&cursor->plane, DRM_PLANE_TYPE_CURSOR); | ||
| 285 | |||
| 286 | return &cursor->plane.drm_plane; | ||
| 287 | |||
| 288 | err_plane: | ||
| 289 | dma_free_writecombine(dev, size, cursor->clut, cursor->clut_paddr); | ||
| 290 | err_clut: | ||
| 291 | devm_kfree(dev, cursor); | ||
| 292 | return NULL; | ||
| 250 | } | 293 | } |
diff --git a/drivers/gpu/drm/sti/sti_cursor.h b/drivers/gpu/drm/sti/sti_cursor.h index db973b705d92..2ee5c10e8b33 100644 --- a/drivers/gpu/drm/sti/sti_cursor.h +++ b/drivers/gpu/drm/sti/sti_cursor.h | |||
| @@ -7,7 +7,9 @@ | |||
| 7 | #ifndef _STI_CURSOR_H_ | 7 | #ifndef _STI_CURSOR_H_ |
| 8 | #define _STI_CURSOR_H_ | 8 | #define _STI_CURSOR_H_ |
| 9 | 9 | ||
| 10 | struct sti_plane *sti_cursor_create(struct device *dev, int desc, | 10 | struct drm_plane *sti_cursor_create(struct drm_device *drm_dev, |
| 11 | void __iomem *baseaddr); | 11 | struct device *dev, int desc, |
| 12 | void __iomem *baseaddr, | ||
| 13 | unsigned int possible_crtcs); | ||
| 12 | 14 | ||
| 13 | #endif | 15 | #endif |
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c index e323310bfa73..9365670427ad 100644 --- a/drivers/gpu/drm/sti/sti_gdp.c +++ b/drivers/gpu/drm/sti/sti_gdp.c | |||
| @@ -9,6 +9,9 @@ | |||
| 9 | #include <linux/clk.h> | 9 | #include <linux/clk.h> |
| 10 | #include <linux/dma-mapping.h> | 10 | #include <linux/dma-mapping.h> |
| 11 | 11 | ||
| 12 | #include <drm/drm_fb_cma_helper.h> | ||
| 13 | #include <drm/drm_gem_cma_helper.h> | ||
| 14 | |||
| 12 | #include "sti_compositor.h" | 15 | #include "sti_compositor.h" |
| 13 | #include "sti_gdp.h" | 16 | #include "sti_gdp.h" |
| 14 | #include "sti_plane.h" | 17 | #include "sti_plane.h" |
| @@ -26,7 +29,7 @@ | |||
| 26 | #define GDP_XBGR8888 (GDP_RGB888_32 | BIGNOTLITTLE | ALPHASWITCH) | 29 | #define GDP_XBGR8888 (GDP_RGB888_32 | BIGNOTLITTLE | ALPHASWITCH) |
| 27 | #define GDP_ARGB8565 0x04 | 30 | #define GDP_ARGB8565 0x04 |
| 28 | #define GDP_ARGB8888 0x05 | 31 | #define GDP_ARGB8888 0x05 |
| 29 | #define GDP_ABGR8888 (GDP_ARGB8888 | BIGNOTLITTLE | ALPHASWITCH) | 32 | #define GDP_ABGR8888 (GDP_ARGB8888 | BIGNOTLITTLE | ALPHASWITCH) |
| 30 | #define GDP_ARGB1555 0x06 | 33 | #define GDP_ARGB1555 0x06 |
| 31 | #define GDP_ARGB4444 0x07 | 34 | #define GDP_ARGB4444 0x07 |
| 32 | #define GDP_CLUT8 0x0B | 35 | #define GDP_CLUT8 0x0B |
| @@ -53,8 +56,8 @@ | |||
| 53 | #define GAM_GDP_PPT_IGNORE (BIT(1) | BIT(0)) | 56 | #define GAM_GDP_PPT_IGNORE (BIT(1) | BIT(0)) |
| 54 | #define GAM_GDP_SIZE_MAX 0x7FF | 57 | #define GAM_GDP_SIZE_MAX 0x7FF |
| 55 | 58 | ||
| 56 | #define GDP_NODE_NB_BANK 2 | 59 | #define GDP_NODE_NB_BANK 2 |
| 57 | #define GDP_NODE_PER_FIELD 2 | 60 | #define GDP_NODE_PER_FIELD 2 |
| 58 | 61 | ||
| 59 | struct sti_gdp_node { | 62 | struct sti_gdp_node { |
| 60 | u32 gam_gdp_ctl; | 63 | u32 gam_gdp_ctl; |
| @@ -124,16 +127,6 @@ static const uint32_t gdp_supported_formats[] = { | |||
| 124 | DRM_FORMAT_C8, | 127 | DRM_FORMAT_C8, |
| 125 | }; | 128 | }; |
| 126 | 129 | ||
| 127 | static const uint32_t *sti_gdp_get_formats(struct sti_plane *plane) | ||
| 128 | { | ||
| 129 | return gdp_supported_formats; | ||
| 130 | } | ||
| 131 | |||
| 132 | static unsigned int sti_gdp_get_nb_formats(struct sti_plane *plane) | ||
| 133 | { | ||
| 134 | return ARRAY_SIZE(gdp_supported_formats); | ||
| 135 | } | ||
| 136 | |||
| 137 | static int sti_gdp_fourcc2format(int fourcc) | 130 | static int sti_gdp_fourcc2format(int fourcc) |
| 138 | { | 131 | { |
| 139 | switch (fourcc) { | 132 | switch (fourcc) { |
| @@ -179,17 +172,16 @@ static int sti_gdp_get_alpharange(int format) | |||
| 179 | 172 | ||
| 180 | /** | 173 | /** |
| 181 | * sti_gdp_get_free_nodes | 174 | * sti_gdp_get_free_nodes |
| 182 | * @plane: gdp plane | 175 | * @gdp: gdp pointer |
| 183 | * | 176 | * |
| 184 | * Look for a GDP node list that is not currently read by the HW. | 177 | * Look for a GDP node list that is not currently read by the HW. |
| 185 | * | 178 | * |
| 186 | * RETURNS: | 179 | * RETURNS: |
| 187 | * Pointer to the free GDP node list | 180 | * Pointer to the free GDP node list |
| 188 | */ | 181 | */ |
| 189 | static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_plane *plane) | 182 | static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_gdp *gdp) |
| 190 | { | 183 | { |
| 191 | int hw_nvn; | 184 | int hw_nvn; |
| 192 | struct sti_gdp *gdp = to_sti_gdp(plane); | ||
| 193 | unsigned int i; | 185 | unsigned int i; |
| 194 | 186 | ||
| 195 | hw_nvn = readl(gdp->regs + GAM_GDP_NVN_OFFSET); | 187 | hw_nvn = readl(gdp->regs + GAM_GDP_NVN_OFFSET); |
| @@ -203,7 +195,7 @@ static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_plane *plane) | |||
| 203 | 195 | ||
| 204 | /* in hazardious cases restart with the first node */ | 196 | /* in hazardious cases restart with the first node */ |
| 205 | DRM_ERROR("inconsistent NVN for %s: 0x%08X\n", | 197 | DRM_ERROR("inconsistent NVN for %s: 0x%08X\n", |
| 206 | sti_plane_to_str(plane), hw_nvn); | 198 | sti_plane_to_str(&gdp->plane), hw_nvn); |
| 207 | 199 | ||
| 208 | end: | 200 | end: |
| 209 | return &gdp->node_list[0]; | 201 | return &gdp->node_list[0]; |
| @@ -211,7 +203,7 @@ end: | |||
| 211 | 203 | ||
| 212 | /** | 204 | /** |
| 213 | * sti_gdp_get_current_nodes | 205 | * sti_gdp_get_current_nodes |
| 214 | * @plane: GDP plane | 206 | * @gdp: gdp pointer |
| 215 | * | 207 | * |
| 216 | * Look for GDP nodes that are currently read by the HW. | 208 | * Look for GDP nodes that are currently read by the HW. |
| 217 | * | 209 | * |
| @@ -219,10 +211,9 @@ end: | |||
| 219 | * Pointer to the current GDP node list | 211 | * Pointer to the current GDP node list |
| 220 | */ | 212 | */ |
| 221 | static | 213 | static |
| 222 | struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_plane *plane) | 214 | struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_gdp *gdp) |
| 223 | { | 215 | { |
| 224 | int hw_nvn; | 216 | int hw_nvn; |
| 225 | struct sti_gdp *gdp = to_sti_gdp(plane); | ||
| 226 | unsigned int i; | 217 | unsigned int i; |
| 227 | 218 | ||
| 228 | hw_nvn = readl(gdp->regs + GAM_GDP_NVN_OFFSET); | 219 | hw_nvn = readl(gdp->regs + GAM_GDP_NVN_OFFSET); |
| @@ -236,205 +227,25 @@ struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_plane *plane) | |||
| 236 | 227 | ||
| 237 | end: | 228 | end: |
| 238 | DRM_DEBUG_DRIVER("Warning, NVN 0x%08X for %s does not match any node\n", | 229 | DRM_DEBUG_DRIVER("Warning, NVN 0x%08X for %s does not match any node\n", |
| 239 | hw_nvn, sti_plane_to_str(plane)); | 230 | hw_nvn, sti_plane_to_str(&gdp->plane)); |
| 240 | 231 | ||
| 241 | return NULL; | 232 | return NULL; |
| 242 | } | 233 | } |
| 243 | 234 | ||
| 244 | /** | 235 | /** |
| 245 | * sti_gdp_prepare | ||
| 246 | * @plane: gdp plane | ||
| 247 | * @first_prepare: true if it is the first time this function is called | ||
| 248 | * | ||
| 249 | * Update the free GDP node list according to the plane properties. | ||
| 250 | * | ||
| 251 | * RETURNS: | ||
| 252 | * 0 on success. | ||
| 253 | */ | ||
| 254 | static int sti_gdp_prepare(struct sti_plane *plane, bool first_prepare) | ||
| 255 | { | ||
| 256 | struct sti_gdp_node_list *list; | ||
| 257 | struct sti_gdp_node *top_field, *btm_field; | ||
| 258 | struct drm_display_mode *mode = plane->mode; | ||
| 259 | struct sti_gdp *gdp = to_sti_gdp(plane); | ||
| 260 | struct device *dev = gdp->dev; | ||
| 261 | struct sti_compositor *compo = dev_get_drvdata(dev); | ||
| 262 | int format; | ||
| 263 | unsigned int depth, bpp; | ||
| 264 | int rate = mode->clock * 1000; | ||
| 265 | int res; | ||
| 266 | u32 ydo, xdo, yds, xds; | ||
| 267 | |||
| 268 | list = sti_gdp_get_free_nodes(plane); | ||
| 269 | top_field = list->top_field; | ||
| 270 | btm_field = list->btm_field; | ||
| 271 | |||
| 272 | dev_dbg(dev, "%s %s top_node:0x%p btm_node:0x%p\n", __func__, | ||
| 273 | sti_plane_to_str(plane), top_field, btm_field); | ||
| 274 | |||
| 275 | /* Build the top field from plane params */ | ||
| 276 | top_field->gam_gdp_agc = GAM_GDP_AGC_FULL_RANGE; | ||
| 277 | top_field->gam_gdp_ctl = WAIT_NEXT_VSYNC; | ||
| 278 | format = sti_gdp_fourcc2format(plane->format); | ||
| 279 | if (format == -1) { | ||
| 280 | DRM_ERROR("Format not supported by GDP %.4s\n", | ||
| 281 | (char *)&plane->format); | ||
| 282 | return 1; | ||
| 283 | } | ||
| 284 | top_field->gam_gdp_ctl |= format; | ||
| 285 | top_field->gam_gdp_ctl |= sti_gdp_get_alpharange(format); | ||
| 286 | top_field->gam_gdp_ppt &= ~GAM_GDP_PPT_IGNORE; | ||
| 287 | |||
| 288 | /* pixel memory location */ | ||
| 289 | drm_fb_get_bpp_depth(plane->format, &depth, &bpp); | ||
| 290 | top_field->gam_gdp_pml = (u32)plane->paddr + plane->offsets[0]; | ||
| 291 | top_field->gam_gdp_pml += plane->src_x * (bpp >> 3); | ||
| 292 | top_field->gam_gdp_pml += plane->src_y * plane->pitches[0]; | ||
| 293 | |||
| 294 | /* input parameters */ | ||
| 295 | top_field->gam_gdp_pmp = plane->pitches[0]; | ||
| 296 | top_field->gam_gdp_size = | ||
| 297 | clamp_val(plane->src_h, 0, GAM_GDP_SIZE_MAX) << 16 | | ||
| 298 | clamp_val(plane->src_w, 0, GAM_GDP_SIZE_MAX); | ||
| 299 | |||
| 300 | /* output parameters */ | ||
| 301 | ydo = sti_vtg_get_line_number(*mode, plane->dst_y); | ||
| 302 | yds = sti_vtg_get_line_number(*mode, plane->dst_y + plane->dst_h - 1); | ||
| 303 | xdo = sti_vtg_get_pixel_number(*mode, plane->dst_x); | ||
| 304 | xds = sti_vtg_get_pixel_number(*mode, plane->dst_x + plane->dst_w - 1); | ||
| 305 | top_field->gam_gdp_vpo = (ydo << 16) | xdo; | ||
| 306 | top_field->gam_gdp_vps = (yds << 16) | xds; | ||
| 307 | |||
| 308 | /* Same content and chained together */ | ||
| 309 | memcpy(btm_field, top_field, sizeof(*btm_field)); | ||
| 310 | top_field->gam_gdp_nvn = list->btm_field_paddr; | ||
| 311 | btm_field->gam_gdp_nvn = list->top_field_paddr; | ||
| 312 | |||
| 313 | /* Interlaced mode */ | ||
| 314 | if (plane->mode->flags & DRM_MODE_FLAG_INTERLACE) | ||
| 315 | btm_field->gam_gdp_pml = top_field->gam_gdp_pml + | ||
| 316 | plane->pitches[0]; | ||
| 317 | |||
| 318 | if (first_prepare) { | ||
| 319 | /* Register gdp callback */ | ||
| 320 | if (sti_vtg_register_client(plane->mixer_id == STI_MIXER_MAIN ? | ||
| 321 | compo->vtg_main : compo->vtg_aux, | ||
| 322 | &gdp->vtg_field_nb, plane->mixer_id)) { | ||
| 323 | DRM_ERROR("Cannot register VTG notifier\n"); | ||
| 324 | return 1; | ||
| 325 | } | ||
| 326 | |||
| 327 | /* Set and enable gdp clock */ | ||
| 328 | if (gdp->clk_pix) { | ||
| 329 | struct clk *clkp; | ||
| 330 | /* According to the mixer used, the gdp pixel clock | ||
| 331 | * should have a different parent clock. */ | ||
| 332 | if (plane->mixer_id == STI_MIXER_MAIN) | ||
| 333 | clkp = gdp->clk_main_parent; | ||
| 334 | else | ||
| 335 | clkp = gdp->clk_aux_parent; | ||
| 336 | |||
| 337 | if (clkp) | ||
| 338 | clk_set_parent(gdp->clk_pix, clkp); | ||
| 339 | |||
| 340 | res = clk_set_rate(gdp->clk_pix, rate); | ||
| 341 | if (res < 0) { | ||
| 342 | DRM_ERROR("Cannot set rate (%dHz) for gdp\n", | ||
| 343 | rate); | ||
| 344 | return 1; | ||
| 345 | } | ||
| 346 | |||
| 347 | if (clk_prepare_enable(gdp->clk_pix)) { | ||
| 348 | DRM_ERROR("Failed to prepare/enable gdp\n"); | ||
| 349 | return 1; | ||
| 350 | } | ||
| 351 | } | ||
| 352 | } | ||
| 353 | |||
| 354 | return 0; | ||
| 355 | } | ||
| 356 | |||
| 357 | /** | ||
| 358 | * sti_gdp_commit | ||
| 359 | * @plane: gdp plane | ||
| 360 | * | ||
| 361 | * Update the NVN field of the 'right' field of the current GDP node (being | ||
| 362 | * used by the HW) with the address of the updated ('free') top field GDP node. | ||
| 363 | * - In interlaced mode the 'right' field is the bottom field as we update | ||
| 364 | * frames starting from their top field | ||
| 365 | * - In progressive mode, we update both bottom and top fields which are | ||
| 366 | * equal nodes. | ||
| 367 | * At the next VSYNC, the updated node list will be used by the HW. | ||
| 368 | * | ||
| 369 | * RETURNS: | ||
| 370 | * 0 on success. | ||
| 371 | */ | ||
| 372 | static int sti_gdp_commit(struct sti_plane *plane) | ||
| 373 | { | ||
| 374 | struct sti_gdp_node_list *updated_list = sti_gdp_get_free_nodes(plane); | ||
| 375 | struct sti_gdp_node *updated_top_node = updated_list->top_field; | ||
| 376 | struct sti_gdp_node *updated_btm_node = updated_list->btm_field; | ||
| 377 | struct sti_gdp *gdp = to_sti_gdp(plane); | ||
| 378 | u32 dma_updated_top = updated_list->top_field_paddr; | ||
| 379 | u32 dma_updated_btm = updated_list->btm_field_paddr; | ||
| 380 | struct sti_gdp_node_list *curr_list = sti_gdp_get_current_nodes(plane); | ||
| 381 | |||
| 382 | dev_dbg(gdp->dev, "%s %s top/btm_node:0x%p/0x%p\n", __func__, | ||
| 383 | sti_plane_to_str(plane), | ||
| 384 | updated_top_node, updated_btm_node); | ||
| 385 | dev_dbg(gdp->dev, "Current NVN:0x%X\n", | ||
| 386 | readl(gdp->regs + GAM_GDP_NVN_OFFSET)); | ||
| 387 | dev_dbg(gdp->dev, "Posted buff: %lx current buff: %x\n", | ||
| 388 | (unsigned long)plane->paddr, | ||
| 389 | readl(gdp->regs + GAM_GDP_PML_OFFSET)); | ||
| 390 | |||
| 391 | if (curr_list == NULL) { | ||
| 392 | /* First update or invalid node should directly write in the | ||
| 393 | * hw register */ | ||
| 394 | DRM_DEBUG_DRIVER("%s first update (or invalid node)", | ||
| 395 | sti_plane_to_str(plane)); | ||
| 396 | |||
| 397 | writel(gdp->is_curr_top == true ? | ||
| 398 | dma_updated_btm : dma_updated_top, | ||
| 399 | gdp->regs + GAM_GDP_NVN_OFFSET); | ||
| 400 | return 0; | ||
| 401 | } | ||
| 402 | |||
| 403 | if (plane->mode->flags & DRM_MODE_FLAG_INTERLACE) { | ||
| 404 | if (gdp->is_curr_top == true) { | ||
| 405 | /* Do not update in the middle of the frame, but | ||
| 406 | * postpone the update after the bottom field has | ||
| 407 | * been displayed */ | ||
| 408 | curr_list->btm_field->gam_gdp_nvn = dma_updated_top; | ||
| 409 | } else { | ||
| 410 | /* Direct update to avoid one frame delay */ | ||
| 411 | writel(dma_updated_top, | ||
| 412 | gdp->regs + GAM_GDP_NVN_OFFSET); | ||
| 413 | } | ||
| 414 | } else { | ||
| 415 | /* Direct update for progressive to avoid one frame delay */ | ||
| 416 | writel(dma_updated_top, gdp->regs + GAM_GDP_NVN_OFFSET); | ||
| 417 | } | ||
| 418 | |||
| 419 | return 0; | ||
| 420 | } | ||
| 421 | |||
| 422 | /** | ||
| 423 | * sti_gdp_disable | 236 | * sti_gdp_disable |
| 424 | * @plane: gdp plane | 237 | * @gdp: gdp pointer |
| 425 | * | 238 | * |
| 426 | * Disable a GDP. | 239 | * Disable a GDP. |
| 427 | * | ||
| 428 | * RETURNS: | ||
| 429 | * 0 on success. | ||
| 430 | */ | 240 | */ |
| 431 | static int sti_gdp_disable(struct sti_plane *plane) | 241 | static void sti_gdp_disable(struct sti_gdp *gdp) |
| 432 | { | 242 | { |
| 433 | unsigned int i; | 243 | struct drm_plane *drm_plane = &gdp->plane.drm_plane; |
| 434 | struct sti_gdp *gdp = to_sti_gdp(plane); | 244 | struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc); |
| 435 | struct sti_compositor *compo = dev_get_drvdata(gdp->dev); | 245 | struct sti_compositor *compo = dev_get_drvdata(gdp->dev); |
| 246 | unsigned int i; | ||
| 436 | 247 | ||
| 437 | DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(plane)); | 248 | DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(&gdp->plane)); |
| 438 | 249 | ||
| 439 | /* Set the nodes as 'to be ignored on mixer' */ | 250 | /* Set the nodes as 'to be ignored on mixer' */ |
| 440 | for (i = 0; i < GDP_NODE_NB_BANK; i++) { | 251 | for (i = 0; i < GDP_NODE_NB_BANK; i++) { |
| @@ -442,14 +253,14 @@ static int sti_gdp_disable(struct sti_plane *plane) | |||
| 442 | gdp->node_list[i].btm_field->gam_gdp_ppt |= GAM_GDP_PPT_IGNORE; | 253 | gdp->node_list[i].btm_field->gam_gdp_ppt |= GAM_GDP_PPT_IGNORE; |
| 443 | } | 254 | } |
| 444 | 255 | ||
| 445 | if (sti_vtg_unregister_client(plane->mixer_id == STI_MIXER_MAIN ? | 256 | if (sti_vtg_unregister_client(mixer->id == STI_MIXER_MAIN ? |
| 446 | compo->vtg_main : compo->vtg_aux, &gdp->vtg_field_nb)) | 257 | compo->vtg_main : compo->vtg_aux, &gdp->vtg_field_nb)) |
| 447 | DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n"); | 258 | DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n"); |
| 448 | 259 | ||
| 449 | if (gdp->clk_pix) | 260 | if (gdp->clk_pix) |
| 450 | clk_disable_unprepare(gdp->clk_pix); | 261 | clk_disable_unprepare(gdp->clk_pix); |
| 451 | 262 | ||
| 452 | return 0; | 263 | gdp->plane.status = STI_PLANE_DISABLED; |
| 453 | } | 264 | } |
| 454 | 265 | ||
| 455 | /** | 266 | /** |
| @@ -468,6 +279,14 @@ int sti_gdp_field_cb(struct notifier_block *nb, | |||
| 468 | { | 279 | { |
| 469 | struct sti_gdp *gdp = container_of(nb, struct sti_gdp, vtg_field_nb); | 280 | struct sti_gdp *gdp = container_of(nb, struct sti_gdp, vtg_field_nb); |
| 470 | 281 | ||
| 282 | if (gdp->plane.status == STI_PLANE_FLUSHING) { | ||
| 283 | /* disable need to be synchronize on vsync event */ | ||
| 284 | DRM_DEBUG_DRIVER("Vsync event received => disable %s\n", | ||
| 285 | sti_plane_to_str(&gdp->plane)); | ||
| 286 | |||
| 287 | sti_gdp_disable(gdp); | ||
| 288 | } | ||
| 289 | |||
| 471 | switch (event) { | 290 | switch (event) { |
| 472 | case VTG_TOP_FIELD_EVENT: | 291 | case VTG_TOP_FIELD_EVENT: |
| 473 | gdp->is_curr_top = true; | 292 | gdp->is_curr_top = true; |
| @@ -561,18 +380,235 @@ static void sti_gdp_init(struct sti_gdp *gdp) | |||
| 561 | } | 380 | } |
| 562 | } | 381 | } |
| 563 | 382 | ||
| 564 | static const struct sti_plane_funcs gdp_plane_ops = { | 383 | static void sti_gdp_atomic_update(struct drm_plane *drm_plane, |
| 565 | .get_formats = sti_gdp_get_formats, | 384 | struct drm_plane_state *oldstate) |
| 566 | .get_nb_formats = sti_gdp_get_nb_formats, | 385 | { |
| 567 | .prepare = sti_gdp_prepare, | 386 | struct drm_plane_state *state = drm_plane->state; |
| 568 | .commit = sti_gdp_commit, | 387 | struct sti_plane *plane = to_sti_plane(drm_plane); |
| 569 | .disable = sti_gdp_disable, | 388 | struct sti_gdp *gdp = to_sti_gdp(plane); |
| 389 | struct drm_crtc *crtc = state->crtc; | ||
| 390 | struct sti_compositor *compo = dev_get_drvdata(gdp->dev); | ||
| 391 | struct drm_framebuffer *fb = state->fb; | ||
| 392 | bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false; | ||
| 393 | struct sti_mixer *mixer; | ||
| 394 | struct drm_display_mode *mode; | ||
| 395 | int dst_x, dst_y, dst_w, dst_h; | ||
| 396 | int src_x, src_y, src_w, src_h; | ||
| 397 | struct drm_gem_cma_object *cma_obj; | ||
| 398 | struct sti_gdp_node_list *list; | ||
| 399 | struct sti_gdp_node_list *curr_list; | ||
| 400 | struct sti_gdp_node *top_field, *btm_field; | ||
| 401 | u32 dma_updated_top; | ||
| 402 | u32 dma_updated_btm; | ||
| 403 | int format; | ||
| 404 | unsigned int depth, bpp; | ||
| 405 | u32 ydo, xdo, yds, xds; | ||
| 406 | int res; | ||
| 407 | |||
| 408 | /* Manage the case where crtc is null (disabled) */ | ||
| 409 | if (!crtc) | ||
| 410 | return; | ||
| 411 | |||
| 412 | mixer = to_sti_mixer(crtc); | ||
| 413 | mode = &crtc->mode; | ||
| 414 | dst_x = state->crtc_x; | ||
| 415 | dst_y = state->crtc_y; | ||
| 416 | dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x); | ||
| 417 | dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y); | ||
| 418 | /* src_x are in 16.16 format */ | ||
| 419 | src_x = state->src_x >> 16; | ||
| 420 | src_y = state->src_y >> 16; | ||
| 421 | src_w = state->src_w >> 16; | ||
| 422 | src_h = state->src_h >> 16; | ||
| 423 | |||
| 424 | DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n", | ||
| 425 | crtc->base.id, sti_mixer_to_str(mixer), | ||
| 426 | drm_plane->base.id, sti_plane_to_str(plane)); | ||
| 427 | DRM_DEBUG_KMS("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n", | ||
| 428 | sti_plane_to_str(plane), | ||
| 429 | dst_w, dst_h, dst_x, dst_y, | ||
| 430 | src_w, src_h, src_x, src_y); | ||
| 431 | |||
| 432 | list = sti_gdp_get_free_nodes(gdp); | ||
| 433 | top_field = list->top_field; | ||
| 434 | btm_field = list->btm_field; | ||
| 435 | |||
| 436 | dev_dbg(gdp->dev, "%s %s top_node:0x%p btm_node:0x%p\n", __func__, | ||
| 437 | sti_plane_to_str(plane), top_field, btm_field); | ||
| 438 | |||
| 439 | /* build the top field */ | ||
| 440 | top_field->gam_gdp_agc = GAM_GDP_AGC_FULL_RANGE; | ||
| 441 | top_field->gam_gdp_ctl = WAIT_NEXT_VSYNC; | ||
| 442 | format = sti_gdp_fourcc2format(fb->pixel_format); | ||
| 443 | if (format == -1) { | ||
| 444 | DRM_ERROR("Format not supported by GDP %.4s\n", | ||
| 445 | (char *)&fb->pixel_format); | ||
| 446 | return; | ||
| 447 | } | ||
| 448 | top_field->gam_gdp_ctl |= format; | ||
| 449 | top_field->gam_gdp_ctl |= sti_gdp_get_alpharange(format); | ||
| 450 | top_field->gam_gdp_ppt &= ~GAM_GDP_PPT_IGNORE; | ||
| 451 | |||
| 452 | cma_obj = drm_fb_cma_get_gem_obj(fb, 0); | ||
| 453 | if (!cma_obj) { | ||
| 454 | DRM_ERROR("Can't get CMA GEM object for fb\n"); | ||
| 455 | return; | ||
| 456 | } | ||
| 457 | |||
| 458 | DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id, | ||
| 459 | (char *)&fb->pixel_format, | ||
| 460 | (unsigned long)cma_obj->paddr); | ||
| 461 | |||
| 462 | /* pixel memory location */ | ||
| 463 | drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp); | ||
| 464 | top_field->gam_gdp_pml = (u32)cma_obj->paddr + fb->offsets[0]; | ||
| 465 | top_field->gam_gdp_pml += src_x * (bpp >> 3); | ||
| 466 | top_field->gam_gdp_pml += src_y * fb->pitches[0]; | ||
| 467 | |||
| 468 | /* input parameters */ | ||
| 469 | top_field->gam_gdp_pmp = fb->pitches[0]; | ||
| 470 | top_field->gam_gdp_size = clamp_val(src_h, 0, GAM_GDP_SIZE_MAX) << 16 | | ||
| 471 | clamp_val(src_w, 0, GAM_GDP_SIZE_MAX); | ||
| 472 | |||
| 473 | /* output parameters */ | ||
| 474 | ydo = sti_vtg_get_line_number(*mode, dst_y); | ||
| 475 | yds = sti_vtg_get_line_number(*mode, dst_y + dst_h - 1); | ||
| 476 | xdo = sti_vtg_get_pixel_number(*mode, dst_x); | ||
| 477 | xds = sti_vtg_get_pixel_number(*mode, dst_x + dst_w - 1); | ||
| 478 | top_field->gam_gdp_vpo = (ydo << 16) | xdo; | ||
| 479 | top_field->gam_gdp_vps = (yds << 16) | xds; | ||
| 480 | |||
| 481 | /* Same content and chained together */ | ||
| 482 | memcpy(btm_field, top_field, sizeof(*btm_field)); | ||
| 483 | top_field->gam_gdp_nvn = list->btm_field_paddr; | ||
| 484 | btm_field->gam_gdp_nvn = list->top_field_paddr; | ||
| 485 | |||
| 486 | /* Interlaced mode */ | ||
| 487 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) | ||
| 488 | btm_field->gam_gdp_pml = top_field->gam_gdp_pml + | ||
| 489 | fb->pitches[0]; | ||
| 490 | |||
| 491 | if (first_prepare) { | ||
| 492 | /* Register gdp callback */ | ||
| 493 | if (sti_vtg_register_client(mixer->id == STI_MIXER_MAIN ? | ||
| 494 | compo->vtg_main : compo->vtg_aux, | ||
| 495 | &gdp->vtg_field_nb, mixer->id)) { | ||
| 496 | DRM_ERROR("Cannot register VTG notifier\n"); | ||
| 497 | return; | ||
| 498 | } | ||
| 499 | |||
| 500 | /* Set and enable gdp clock */ | ||
| 501 | if (gdp->clk_pix) { | ||
| 502 | struct clk *clkp; | ||
| 503 | int rate = mode->clock * 1000; | ||
| 504 | |||
| 505 | /* According to the mixer used, the gdp pixel clock | ||
| 506 | * should have a different parent clock. */ | ||
| 507 | if (mixer->id == STI_MIXER_MAIN) | ||
| 508 | clkp = gdp->clk_main_parent; | ||
| 509 | else | ||
| 510 | clkp = gdp->clk_aux_parent; | ||
| 511 | |||
| 512 | if (clkp) | ||
| 513 | clk_set_parent(gdp->clk_pix, clkp); | ||
| 514 | |||
| 515 | res = clk_set_rate(gdp->clk_pix, rate); | ||
| 516 | if (res < 0) { | ||
| 517 | DRM_ERROR("Cannot set rate (%dHz) for gdp\n", | ||
| 518 | rate); | ||
| 519 | return; | ||
| 520 | } | ||
| 521 | |||
| 522 | if (clk_prepare_enable(gdp->clk_pix)) { | ||
| 523 | DRM_ERROR("Failed to prepare/enable gdp\n"); | ||
| 524 | return; | ||
| 525 | } | ||
| 526 | } | ||
| 527 | } | ||
| 528 | |||
| 529 | /* Update the NVN field of the 'right' field of the current GDP node | ||
| 530 | * (being used by the HW) with the address of the updated ('free') top | ||
| 531 | * field GDP node. | ||
| 532 | * - In interlaced mode the 'right' field is the bottom field as we | ||
| 533 | * update frames starting from their top field | ||
| 534 | * - In progressive mode, we update both bottom and top fields which | ||
| 535 | * are equal nodes. | ||
| 536 | * At the next VSYNC, the updated node list will be used by the HW. | ||
| 537 | */ | ||
| 538 | curr_list = sti_gdp_get_current_nodes(gdp); | ||
| 539 | dma_updated_top = list->top_field_paddr; | ||
| 540 | dma_updated_btm = list->btm_field_paddr; | ||
| 541 | |||
| 542 | dev_dbg(gdp->dev, "Current NVN:0x%X\n", | ||
| 543 | readl(gdp->regs + GAM_GDP_NVN_OFFSET)); | ||
| 544 | dev_dbg(gdp->dev, "Posted buff: %lx current buff: %x\n", | ||
| 545 | (unsigned long)cma_obj->paddr, | ||
| 546 | readl(gdp->regs + GAM_GDP_PML_OFFSET)); | ||
| 547 | |||
| 548 | if (!curr_list) { | ||
| 549 | /* First update or invalid node should directly write in the | ||
| 550 | * hw register */ | ||
| 551 | DRM_DEBUG_DRIVER("%s first update (or invalid node)", | ||
| 552 | sti_plane_to_str(plane)); | ||
| 553 | |||
| 554 | writel(gdp->is_curr_top ? | ||
| 555 | dma_updated_btm : dma_updated_top, | ||
| 556 | gdp->regs + GAM_GDP_NVN_OFFSET); | ||
| 557 | goto end; | ||
| 558 | } | ||
| 559 | |||
| 560 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) { | ||
| 561 | if (gdp->is_curr_top) { | ||
| 562 | /* Do not update in the middle of the frame, but | ||
| 563 | * postpone the update after the bottom field has | ||
| 564 | * been displayed */ | ||
| 565 | curr_list->btm_field->gam_gdp_nvn = dma_updated_top; | ||
| 566 | } else { | ||
| 567 | /* Direct update to avoid one frame delay */ | ||
| 568 | writel(dma_updated_top, | ||
| 569 | gdp->regs + GAM_GDP_NVN_OFFSET); | ||
| 570 | } | ||
| 571 | } else { | ||
| 572 | /* Direct update for progressive to avoid one frame delay */ | ||
| 573 | writel(dma_updated_top, gdp->regs + GAM_GDP_NVN_OFFSET); | ||
| 574 | } | ||
| 575 | |||
| 576 | end: | ||
| 577 | plane->status = STI_PLANE_UPDATED; | ||
| 578 | } | ||
| 579 | |||
| 580 | static void sti_gdp_atomic_disable(struct drm_plane *drm_plane, | ||
| 581 | struct drm_plane_state *oldstate) | ||
| 582 | { | ||
| 583 | struct sti_plane *plane = to_sti_plane(drm_plane); | ||
| 584 | struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc); | ||
| 585 | |||
| 586 | if (!drm_plane->crtc) { | ||
| 587 | DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", | ||
| 588 | drm_plane->base.id); | ||
| 589 | return; | ||
| 590 | } | ||
| 591 | |||
| 592 | DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n", | ||
| 593 | drm_plane->crtc->base.id, sti_mixer_to_str(mixer), | ||
| 594 | drm_plane->base.id, sti_plane_to_str(plane)); | ||
| 595 | |||
| 596 | plane->status = STI_PLANE_DISABLING; | ||
| 597 | } | ||
| 598 | |||
| 599 | static const struct drm_plane_helper_funcs sti_gdp_helpers_funcs = { | ||
| 600 | .atomic_update = sti_gdp_atomic_update, | ||
| 601 | .atomic_disable = sti_gdp_atomic_disable, | ||
| 570 | }; | 602 | }; |
| 571 | 603 | ||
| 572 | struct sti_plane *sti_gdp_create(struct device *dev, int desc, | 604 | struct drm_plane *sti_gdp_create(struct drm_device *drm_dev, |
| 573 | void __iomem *baseaddr) | 605 | struct device *dev, int desc, |
| 606 | void __iomem *baseaddr, | ||
| 607 | unsigned int possible_crtcs, | ||
| 608 | enum drm_plane_type type) | ||
| 574 | { | 609 | { |
| 575 | struct sti_gdp *gdp; | 610 | struct sti_gdp *gdp; |
| 611 | int res; | ||
| 576 | 612 | ||
| 577 | gdp = devm_kzalloc(dev, sizeof(*gdp), GFP_KERNEL); | 613 | gdp = devm_kzalloc(dev, sizeof(*gdp), GFP_KERNEL); |
| 578 | if (!gdp) { | 614 | if (!gdp) { |
| @@ -583,11 +619,30 @@ struct sti_plane *sti_gdp_create(struct device *dev, int desc, | |||
| 583 | gdp->dev = dev; | 619 | gdp->dev = dev; |
| 584 | gdp->regs = baseaddr; | 620 | gdp->regs = baseaddr; |
| 585 | gdp->plane.desc = desc; | 621 | gdp->plane.desc = desc; |
| 586 | gdp->plane.ops = &gdp_plane_ops; | 622 | gdp->plane.status = STI_PLANE_DISABLED; |
| 587 | 623 | ||
| 588 | gdp->vtg_field_nb.notifier_call = sti_gdp_field_cb; | 624 | gdp->vtg_field_nb.notifier_call = sti_gdp_field_cb; |
| 589 | 625 | ||
| 590 | sti_gdp_init(gdp); | 626 | sti_gdp_init(gdp); |
| 591 | 627 | ||
| 592 | return &gdp->plane; | 628 | res = drm_universal_plane_init(drm_dev, &gdp->plane.drm_plane, |
| 629 | possible_crtcs, | ||
| 630 | &sti_plane_helpers_funcs, | ||
| 631 | gdp_supported_formats, | ||
| 632 | ARRAY_SIZE(gdp_supported_formats), | ||
| 633 | type); | ||
| 634 | if (res) { | ||
| 635 | DRM_ERROR("Failed to initialize universal plane\n"); | ||
| 636 | goto err; | ||
| 637 | } | ||
| 638 | |||
| 639 | drm_plane_helper_add(&gdp->plane.drm_plane, &sti_gdp_helpers_funcs); | ||
| 640 | |||
| 641 | sti_plane_init_property(&gdp->plane, type); | ||
| 642 | |||
| 643 | return &gdp->plane.drm_plane; | ||
| 644 | |||
| 645 | err: | ||
| 646 | devm_kfree(dev, gdp); | ||
| 647 | return NULL; | ||
| 593 | } | 648 | } |
diff --git a/drivers/gpu/drm/sti/sti_gdp.h b/drivers/gpu/drm/sti/sti_gdp.h index 01818ea72125..73947a4a8004 100644 --- a/drivers/gpu/drm/sti/sti_gdp.h +++ b/drivers/gpu/drm/sti/sti_gdp.h | |||
| @@ -11,7 +11,9 @@ | |||
| 11 | 11 | ||
| 12 | #include <linux/types.h> | 12 | #include <linux/types.h> |
| 13 | 13 | ||
| 14 | struct sti_plane *sti_gdp_create(struct device *dev, int desc, | 14 | struct drm_plane *sti_gdp_create(struct drm_device *drm_dev, |
| 15 | void __iomem *baseaddr); | 15 | struct device *dev, int desc, |
| 16 | 16 | void __iomem *baseaddr, | |
| 17 | unsigned int possible_crtcs, | ||
| 18 | enum drm_plane_type type); | ||
| 17 | #endif | 19 | #endif |
diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c index b91a009f0d5d..7c8f9b8bfae1 100644 --- a/drivers/gpu/drm/sti/sti_hqvdp.c +++ b/drivers/gpu/drm/sti/sti_hqvdp.c | |||
| @@ -12,7 +12,10 @@ | |||
| 12 | #include <linux/reset.h> | 12 | #include <linux/reset.h> |
| 13 | 13 | ||
| 14 | #include <drm/drmP.h> | 14 | #include <drm/drmP.h> |
| 15 | #include <drm/drm_fb_cma_helper.h> | ||
| 16 | #include <drm/drm_gem_cma_helper.h> | ||
| 15 | 17 | ||
| 18 | #include "sti_compositor.h" | ||
| 16 | #include "sti_hqvdp_lut.h" | 19 | #include "sti_hqvdp_lut.h" |
| 17 | #include "sti_plane.h" | 20 | #include "sti_plane.h" |
| 18 | #include "sti_vtg.h" | 21 | #include "sti_vtg.h" |
| @@ -357,16 +360,6 @@ static const uint32_t hqvdp_supported_formats[] = { | |||
| 357 | DRM_FORMAT_NV12, | 360 | DRM_FORMAT_NV12, |
| 358 | }; | 361 | }; |
| 359 | 362 | ||
| 360 | static const uint32_t *sti_hqvdp_get_formats(struct sti_plane *plane) | ||
| 361 | { | ||
| 362 | return hqvdp_supported_formats; | ||
| 363 | } | ||
| 364 | |||
| 365 | static unsigned int sti_hqvdp_get_nb_formats(struct sti_plane *plane) | ||
| 366 | { | ||
| 367 | return ARRAY_SIZE(hqvdp_supported_formats); | ||
| 368 | } | ||
| 369 | |||
| 370 | /** | 363 | /** |
| 371 | * sti_hqvdp_get_free_cmd | 364 | * sti_hqvdp_get_free_cmd |
| 372 | * @hqvdp: hqvdp structure | 365 | * @hqvdp: hqvdp structure |
| @@ -482,7 +475,12 @@ static void sti_hqvdp_update_hvsrc(enum sti_hvsrc_orient orient, int scale, | |||
| 482 | 475 | ||
| 483 | /** | 476 | /** |
| 484 | * sti_hqvdp_check_hw_scaling | 477 | * sti_hqvdp_check_hw_scaling |
| 485 | * @plane: hqvdp plane | 478 | * @hqvdp: hqvdp pointer |
| 479 | * @mode: display mode with timing constraints | ||
| 480 | * @src_w: source width | ||
| 481 | * @src_h: source height | ||
| 482 | * @dst_w: destination width | ||
| 483 | * @dst_h: destination height | ||
| 486 | * | 484 | * |
| 487 | * Check if the HW is able to perform the scaling request | 485 | * Check if the HW is able to perform the scaling request |
| 488 | * The firmware scaling limitation is "CEIL(1/Zy) <= FLOOR(LFW)" where: | 486 | * The firmware scaling limitation is "CEIL(1/Zy) <= FLOOR(LFW)" where: |
| @@ -496,194 +494,36 @@ static void sti_hqvdp_update_hvsrc(enum sti_hvsrc_orient orient, int scale, | |||
| 496 | * RETURNS: | 494 | * RETURNS: |
| 497 | * True if the HW can scale. | 495 | * True if the HW can scale. |
| 498 | */ | 496 | */ |
| 499 | static bool sti_hqvdp_check_hw_scaling(struct sti_plane *plane) | 497 | static bool sti_hqvdp_check_hw_scaling(struct sti_hqvdp *hqvdp, |
| 498 | struct drm_display_mode *mode, | ||
| 499 | int src_w, int src_h, | ||
| 500 | int dst_w, int dst_h) | ||
| 500 | { | 501 | { |
| 501 | struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane); | ||
| 502 | unsigned long lfw; | 502 | unsigned long lfw; |
| 503 | unsigned int inv_zy; | 503 | unsigned int inv_zy; |
| 504 | 504 | ||
| 505 | lfw = plane->mode->htotal * (clk_get_rate(hqvdp->clk) / 1000000); | 505 | lfw = mode->htotal * (clk_get_rate(hqvdp->clk) / 1000000); |
| 506 | lfw /= max(plane->src_w, plane->dst_w) * plane->mode->clock / 1000; | 506 | lfw /= max(src_w, dst_w) * mode->clock / 1000; |
| 507 | 507 | ||
| 508 | inv_zy = DIV_ROUND_UP(plane->src_h, plane->dst_h); | 508 | inv_zy = DIV_ROUND_UP(src_h, dst_h); |
| 509 | 509 | ||
| 510 | return (inv_zy <= lfw) ? true : false; | 510 | return (inv_zy <= lfw) ? true : false; |
| 511 | } | 511 | } |
| 512 | 512 | ||
| 513 | /** | 513 | /** |
| 514 | * sti_hqvdp_prepare | ||
| 515 | * @plane: hqvdp plane | ||
| 516 | * @first_prepare: true if it is the first time this function is called | ||
| 517 | * | ||
| 518 | * Prepares a command for the firmware | ||
| 519 | * | ||
| 520 | * RETURNS: | ||
| 521 | * 0 on success. | ||
| 522 | */ | ||
| 523 | static int sti_hqvdp_prepare(struct sti_plane *plane, bool first_prepare) | ||
| 524 | { | ||
| 525 | struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane); | ||
| 526 | struct sti_hqvdp_cmd *cmd; | ||
| 527 | int scale_h, scale_v; | ||
| 528 | int cmd_offset; | ||
| 529 | |||
| 530 | dev_dbg(hqvdp->dev, "%s %s\n", __func__, sti_plane_to_str(plane)); | ||
| 531 | |||
| 532 | cmd_offset = sti_hqvdp_get_free_cmd(hqvdp); | ||
| 533 | if (cmd_offset == -1) { | ||
| 534 | DRM_ERROR("No available hqvdp_cmd now\n"); | ||
| 535 | return -EBUSY; | ||
| 536 | } | ||
| 537 | cmd = hqvdp->hqvdp_cmd + cmd_offset; | ||
| 538 | |||
| 539 | if (!sti_hqvdp_check_hw_scaling(plane)) { | ||
| 540 | DRM_ERROR("Scaling beyond HW capabilities\n"); | ||
| 541 | return -EINVAL; | ||
| 542 | } | ||
| 543 | |||
| 544 | /* Static parameters, defaulting to progressive mode */ | ||
| 545 | cmd->top.config = TOP_CONFIG_PROGRESSIVE; | ||
| 546 | cmd->top.mem_format = TOP_MEM_FORMAT_DFLT; | ||
| 547 | cmd->hvsrc.param_ctrl = HVSRC_PARAM_CTRL_DFLT; | ||
| 548 | cmd->csdi.config = CSDI_CONFIG_PROG; | ||
| 549 | |||
| 550 | /* VC1RE, FMD bypassed : keep everything set to 0 | ||
| 551 | * IQI/P2I bypassed */ | ||
| 552 | cmd->iqi.config = IQI_CONFIG_DFLT; | ||
| 553 | cmd->iqi.con_bri = IQI_CON_BRI_DFLT; | ||
| 554 | cmd->iqi.sat_gain = IQI_SAT_GAIN_DFLT; | ||
| 555 | cmd->iqi.pxf_conf = IQI_PXF_CONF_DFLT; | ||
| 556 | |||
| 557 | /* Buffer planes address */ | ||
| 558 | cmd->top.current_luma = (u32)plane->paddr + plane->offsets[0]; | ||
| 559 | cmd->top.current_chroma = (u32)plane->paddr + plane->offsets[1]; | ||
| 560 | |||
| 561 | /* Pitches */ | ||
| 562 | cmd->top.luma_processed_pitch = cmd->top.luma_src_pitch = | ||
| 563 | plane->pitches[0]; | ||
| 564 | cmd->top.chroma_processed_pitch = cmd->top.chroma_src_pitch = | ||
| 565 | plane->pitches[1]; | ||
| 566 | |||
| 567 | /* Input / output size | ||
| 568 | * Align to upper even value */ | ||
| 569 | plane->dst_w = ALIGN(plane->dst_w, 2); | ||
| 570 | plane->dst_h = ALIGN(plane->dst_h, 2); | ||
| 571 | |||
| 572 | if ((plane->src_w > MAX_WIDTH) || (plane->src_w < MIN_WIDTH) || | ||
| 573 | (plane->src_h > MAX_HEIGHT) || (plane->src_h < MIN_HEIGHT) || | ||
| 574 | (plane->dst_w > MAX_WIDTH) || (plane->dst_w < MIN_WIDTH) || | ||
| 575 | (plane->dst_h > MAX_HEIGHT) || (plane->dst_h < MIN_HEIGHT)) { | ||
| 576 | DRM_ERROR("Invalid in/out size %dx%d -> %dx%d\n", | ||
| 577 | plane->src_w, plane->src_h, | ||
| 578 | plane->dst_w, plane->dst_h); | ||
| 579 | return -EINVAL; | ||
| 580 | } | ||
| 581 | cmd->top.input_viewport_size = cmd->top.input_frame_size = | ||
| 582 | plane->src_h << 16 | plane->src_w; | ||
| 583 | cmd->hvsrc.output_picture_size = plane->dst_h << 16 | plane->dst_w; | ||
| 584 | cmd->top.input_viewport_ori = plane->src_y << 16 | plane->src_x; | ||
| 585 | |||
| 586 | /* Handle interlaced */ | ||
| 587 | if (plane->fb->flags & DRM_MODE_FB_INTERLACED) { | ||
| 588 | /* Top field to display */ | ||
| 589 | cmd->top.config = TOP_CONFIG_INTER_TOP; | ||
| 590 | |||
| 591 | /* Update pitches and vert size */ | ||
| 592 | cmd->top.input_frame_size = (plane->src_h / 2) << 16 | | ||
| 593 | plane->src_w; | ||
| 594 | cmd->top.luma_processed_pitch *= 2; | ||
| 595 | cmd->top.luma_src_pitch *= 2; | ||
| 596 | cmd->top.chroma_processed_pitch *= 2; | ||
| 597 | cmd->top.chroma_src_pitch *= 2; | ||
| 598 | |||
| 599 | /* Enable directional deinterlacing processing */ | ||
| 600 | cmd->csdi.config = CSDI_CONFIG_INTER_DIR; | ||
| 601 | cmd->csdi.config2 = CSDI_CONFIG2_DFLT; | ||
| 602 | cmd->csdi.dcdi_config = CSDI_DCDI_CONFIG_DFLT; | ||
| 603 | } | ||
| 604 | |||
| 605 | /* Update hvsrc lut coef */ | ||
| 606 | scale_h = SCALE_FACTOR * plane->dst_w / plane->src_w; | ||
| 607 | sti_hqvdp_update_hvsrc(HVSRC_HORI, scale_h, &cmd->hvsrc); | ||
| 608 | |||
| 609 | scale_v = SCALE_FACTOR * plane->dst_h / plane->src_h; | ||
| 610 | sti_hqvdp_update_hvsrc(HVSRC_VERT, scale_v, &cmd->hvsrc); | ||
| 611 | |||
| 612 | if (first_prepare) { | ||
| 613 | /* Prevent VTG shutdown */ | ||
| 614 | if (clk_prepare_enable(hqvdp->clk_pix_main)) { | ||
| 615 | DRM_ERROR("Failed to prepare/enable pix main clk\n"); | ||
| 616 | return -ENXIO; | ||
| 617 | } | ||
| 618 | |||
| 619 | /* Register VTG Vsync callback to handle bottom fields */ | ||
| 620 | if ((plane->fb->flags & DRM_MODE_FB_INTERLACED) && | ||
| 621 | sti_vtg_register_client(hqvdp->vtg, &hqvdp->vtg_nb, | ||
| 622 | plane->mixer_id)) { | ||
| 623 | DRM_ERROR("Cannot register VTG notifier\n"); | ||
| 624 | return -ENXIO; | ||
| 625 | } | ||
| 626 | } | ||
| 627 | |||
| 628 | return 0; | ||
| 629 | } | ||
| 630 | |||
| 631 | /** | ||
| 632 | * sti_hqvdp_commit | ||
| 633 | * @plane: hqvdp plane | ||
| 634 | * | ||
| 635 | * Enables the HQVDP plane | ||
| 636 | * | ||
| 637 | * RETURNS: | ||
| 638 | * 0 on success. | ||
| 639 | */ | ||
| 640 | static int sti_hqvdp_commit(struct sti_plane *plane) | ||
| 641 | { | ||
| 642 | struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane); | ||
| 643 | int cmd_offset; | ||
| 644 | |||
| 645 | dev_dbg(hqvdp->dev, "%s %s\n", __func__, sti_plane_to_str(plane)); | ||
| 646 | |||
| 647 | cmd_offset = sti_hqvdp_get_free_cmd(hqvdp); | ||
| 648 | if (cmd_offset == -1) { | ||
| 649 | DRM_ERROR("No available hqvdp_cmd now\n"); | ||
| 650 | return -EBUSY; | ||
| 651 | } | ||
| 652 | |||
| 653 | writel(hqvdp->hqvdp_cmd_paddr + cmd_offset, | ||
| 654 | hqvdp->regs + HQVDP_MBX_NEXT_CMD); | ||
| 655 | |||
| 656 | hqvdp->curr_field_count++; | ||
| 657 | |||
| 658 | /* Interlaced : get ready to display the bottom field at next Vsync */ | ||
| 659 | if (plane->fb->flags & DRM_MODE_FB_INTERLACED) | ||
| 660 | hqvdp->btm_field_pending = true; | ||
| 661 | |||
| 662 | dev_dbg(hqvdp->dev, "%s Posted command:0x%x\n", | ||
| 663 | __func__, hqvdp->hqvdp_cmd_paddr + cmd_offset); | ||
| 664 | |||
| 665 | return 0; | ||
| 666 | } | ||
| 667 | |||
| 668 | /** | ||
| 669 | * sti_hqvdp_disable | 514 | * sti_hqvdp_disable |
| 670 | * @plane: hqvdp plane | 515 | * @hqvdp: hqvdp pointer |
| 671 | * | 516 | * |
| 672 | * Disables the HQVDP plane | 517 | * Disables the HQVDP plane |
| 673 | * | ||
| 674 | * RETURNS: | ||
| 675 | * 0 on success. | ||
| 676 | */ | 518 | */ |
| 677 | static int sti_hqvdp_disable(struct sti_plane *plane) | 519 | static void sti_hqvdp_disable(struct sti_hqvdp *hqvdp) |
| 678 | { | 520 | { |
| 679 | struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane); | ||
| 680 | int i; | 521 | int i; |
| 681 | 522 | ||
| 682 | DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(plane)); | 523 | DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(&hqvdp->plane)); |
| 683 | 524 | ||
| 684 | /* Unregister VTG Vsync callback */ | 525 | /* Unregister VTG Vsync callback */ |
| 685 | if ((plane->fb->flags & DRM_MODE_FB_INTERLACED) && | 526 | if (sti_vtg_unregister_client(hqvdp->vtg, &hqvdp->vtg_nb)) |
| 686 | sti_vtg_unregister_client(hqvdp->vtg, &hqvdp->vtg_nb)) | ||
| 687 | DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n"); | 527 | DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n"); |
| 688 | 528 | ||
| 689 | /* Set next cmd to NULL */ | 529 | /* Set next cmd to NULL */ |
| @@ -699,12 +539,10 @@ static int sti_hqvdp_disable(struct sti_plane *plane) | |||
| 699 | /* VTG can stop now */ | 539 | /* VTG can stop now */ |
| 700 | clk_disable_unprepare(hqvdp->clk_pix_main); | 540 | clk_disable_unprepare(hqvdp->clk_pix_main); |
| 701 | 541 | ||
| 702 | if (i == POLL_MAX_ATTEMPT) { | 542 | if (i == POLL_MAX_ATTEMPT) |
| 703 | DRM_ERROR("XP70 could not revert to idle\n"); | 543 | DRM_ERROR("XP70 could not revert to idle\n"); |
| 704 | return -ENXIO; | ||
| 705 | } | ||
| 706 | 544 | ||
| 707 | return 0; | 545 | hqvdp->plane.status = STI_PLANE_DISABLED; |
| 708 | } | 546 | } |
| 709 | 547 | ||
| 710 | /** | 548 | /** |
| @@ -729,6 +567,14 @@ int sti_hqvdp_vtg_cb(struct notifier_block *nb, unsigned long evt, void *data) | |||
| 729 | return 0; | 567 | return 0; |
| 730 | } | 568 | } |
| 731 | 569 | ||
| 570 | if (hqvdp->plane.status == STI_PLANE_FLUSHING) { | ||
| 571 | /* disable need to be synchronize on vsync event */ | ||
| 572 | DRM_DEBUG_DRIVER("Vsync event received => disable %s\n", | ||
| 573 | sti_plane_to_str(&hqvdp->plane)); | ||
| 574 | |||
| 575 | sti_hqvdp_disable(hqvdp); | ||
| 576 | } | ||
| 577 | |||
| 732 | if (hqvdp->btm_field_pending) { | 578 | if (hqvdp->btm_field_pending) { |
| 733 | /* Create the btm field command from the current one */ | 579 | /* Create the btm field command from the current one */ |
| 734 | btm_cmd_offset = sti_hqvdp_get_free_cmd(hqvdp); | 580 | btm_cmd_offset = sti_hqvdp_get_free_cmd(hqvdp); |
| @@ -782,24 +628,212 @@ static void sti_hqvdp_init(struct sti_hqvdp *hqvdp) | |||
| 782 | memset(hqvdp->hqvdp_cmd, 0, size); | 628 | memset(hqvdp->hqvdp_cmd, 0, size); |
| 783 | } | 629 | } |
| 784 | 630 | ||
| 785 | static const struct sti_plane_funcs hqvdp_plane_ops = { | 631 | static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane, |
| 786 | .get_formats = sti_hqvdp_get_formats, | 632 | struct drm_plane_state *oldstate) |
| 787 | .get_nb_formats = sti_hqvdp_get_nb_formats, | 633 | { |
| 788 | .prepare = sti_hqvdp_prepare, | 634 | struct drm_plane_state *state = drm_plane->state; |
| 789 | .commit = sti_hqvdp_commit, | 635 | struct sti_plane *plane = to_sti_plane(drm_plane); |
| 790 | .disable = sti_hqvdp_disable, | 636 | struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane); |
| 637 | struct drm_crtc *crtc = state->crtc; | ||
| 638 | struct sti_mixer *mixer = to_sti_mixer(crtc); | ||
| 639 | struct drm_framebuffer *fb = state->fb; | ||
| 640 | struct drm_display_mode *mode = &crtc->mode; | ||
| 641 | int dst_x = state->crtc_x; | ||
| 642 | int dst_y = state->crtc_y; | ||
| 643 | int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x); | ||
| 644 | int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y); | ||
| 645 | /* src_x are in 16.16 format */ | ||
| 646 | int src_x = state->src_x >> 16; | ||
| 647 | int src_y = state->src_y >> 16; | ||
| 648 | int src_w = state->src_w >> 16; | ||
| 649 | int src_h = state->src_h >> 16; | ||
| 650 | bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false; | ||
| 651 | struct drm_gem_cma_object *cma_obj; | ||
| 652 | struct sti_hqvdp_cmd *cmd; | ||
| 653 | int scale_h, scale_v; | ||
| 654 | int cmd_offset; | ||
| 655 | |||
| 656 | DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n", | ||
| 657 | crtc->base.id, sti_mixer_to_str(mixer), | ||
| 658 | drm_plane->base.id, sti_plane_to_str(plane)); | ||
| 659 | DRM_DEBUG_KMS("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n", | ||
| 660 | sti_plane_to_str(plane), | ||
| 661 | dst_w, dst_h, dst_x, dst_y, | ||
| 662 | src_w, src_h, src_x, src_y); | ||
| 663 | |||
| 664 | cmd_offset = sti_hqvdp_get_free_cmd(hqvdp); | ||
| 665 | if (cmd_offset == -1) { | ||
| 666 | DRM_ERROR("No available hqvdp_cmd now\n"); | ||
| 667 | return; | ||
| 668 | } | ||
| 669 | cmd = hqvdp->hqvdp_cmd + cmd_offset; | ||
| 670 | |||
| 671 | if (!sti_hqvdp_check_hw_scaling(hqvdp, mode, | ||
| 672 | src_w, src_h, | ||
| 673 | dst_w, dst_h)) { | ||
| 674 | DRM_ERROR("Scaling beyond HW capabilities\n"); | ||
| 675 | return; | ||
| 676 | } | ||
| 677 | |||
| 678 | /* Static parameters, defaulting to progressive mode */ | ||
| 679 | cmd->top.config = TOP_CONFIG_PROGRESSIVE; | ||
| 680 | cmd->top.mem_format = TOP_MEM_FORMAT_DFLT; | ||
| 681 | cmd->hvsrc.param_ctrl = HVSRC_PARAM_CTRL_DFLT; | ||
| 682 | cmd->csdi.config = CSDI_CONFIG_PROG; | ||
| 683 | |||
| 684 | /* VC1RE, FMD bypassed : keep everything set to 0 | ||
| 685 | * IQI/P2I bypassed */ | ||
| 686 | cmd->iqi.config = IQI_CONFIG_DFLT; | ||
| 687 | cmd->iqi.con_bri = IQI_CON_BRI_DFLT; | ||
| 688 | cmd->iqi.sat_gain = IQI_SAT_GAIN_DFLT; | ||
| 689 | cmd->iqi.pxf_conf = IQI_PXF_CONF_DFLT; | ||
| 690 | |||
| 691 | cma_obj = drm_fb_cma_get_gem_obj(fb, 0); | ||
| 692 | if (!cma_obj) { | ||
| 693 | DRM_ERROR("Can't get CMA GEM object for fb\n"); | ||
| 694 | return; | ||
| 695 | } | ||
| 696 | |||
| 697 | DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id, | ||
| 698 | (char *)&fb->pixel_format, | ||
| 699 | (unsigned long)cma_obj->paddr); | ||
| 700 | |||
| 701 | /* Buffer planes address */ | ||
| 702 | cmd->top.current_luma = (u32)cma_obj->paddr + fb->offsets[0]; | ||
| 703 | cmd->top.current_chroma = (u32)cma_obj->paddr + fb->offsets[1]; | ||
| 704 | |||
| 705 | /* Pitches */ | ||
| 706 | cmd->top.luma_processed_pitch = fb->pitches[0]; | ||
| 707 | cmd->top.luma_src_pitch = fb->pitches[0]; | ||
| 708 | cmd->top.chroma_processed_pitch = fb->pitches[1]; | ||
| 709 | cmd->top.chroma_src_pitch = fb->pitches[1]; | ||
| 710 | |||
| 711 | /* Input / output size | ||
| 712 | * Align to upper even value */ | ||
| 713 | dst_w = ALIGN(dst_w, 2); | ||
| 714 | dst_h = ALIGN(dst_h, 2); | ||
| 715 | |||
| 716 | if ((src_w > MAX_WIDTH) || (src_w < MIN_WIDTH) || | ||
| 717 | (src_h > MAX_HEIGHT) || (src_h < MIN_HEIGHT) || | ||
| 718 | (dst_w > MAX_WIDTH) || (dst_w < MIN_WIDTH) || | ||
| 719 | (dst_h > MAX_HEIGHT) || (dst_h < MIN_HEIGHT)) { | ||
| 720 | DRM_ERROR("Invalid in/out size %dx%d -> %dx%d\n", | ||
| 721 | src_w, src_h, | ||
| 722 | dst_w, dst_h); | ||
| 723 | return; | ||
| 724 | } | ||
| 725 | |||
| 726 | cmd->top.input_viewport_size = src_h << 16 | src_w; | ||
| 727 | cmd->top.input_frame_size = src_h << 16 | src_w; | ||
| 728 | cmd->hvsrc.output_picture_size = dst_h << 16 | dst_w; | ||
| 729 | cmd->top.input_viewport_ori = src_y << 16 | src_x; | ||
| 730 | |||
| 731 | /* Handle interlaced */ | ||
| 732 | if (fb->flags & DRM_MODE_FB_INTERLACED) { | ||
| 733 | /* Top field to display */ | ||
| 734 | cmd->top.config = TOP_CONFIG_INTER_TOP; | ||
| 735 | |||
| 736 | /* Update pitches and vert size */ | ||
| 737 | cmd->top.input_frame_size = (src_h / 2) << 16 | src_w; | ||
| 738 | cmd->top.luma_processed_pitch *= 2; | ||
| 739 | cmd->top.luma_src_pitch *= 2; | ||
| 740 | cmd->top.chroma_processed_pitch *= 2; | ||
| 741 | cmd->top.chroma_src_pitch *= 2; | ||
| 742 | |||
| 743 | /* Enable directional deinterlacing processing */ | ||
| 744 | cmd->csdi.config = CSDI_CONFIG_INTER_DIR; | ||
| 745 | cmd->csdi.config2 = CSDI_CONFIG2_DFLT; | ||
| 746 | cmd->csdi.dcdi_config = CSDI_DCDI_CONFIG_DFLT; | ||
| 747 | } | ||
| 748 | |||
| 749 | /* Update hvsrc lut coef */ | ||
| 750 | scale_h = SCALE_FACTOR * dst_w / src_w; | ||
| 751 | sti_hqvdp_update_hvsrc(HVSRC_HORI, scale_h, &cmd->hvsrc); | ||
| 752 | |||
| 753 | scale_v = SCALE_FACTOR * dst_h / src_h; | ||
| 754 | sti_hqvdp_update_hvsrc(HVSRC_VERT, scale_v, &cmd->hvsrc); | ||
| 755 | |||
| 756 | if (first_prepare) { | ||
| 757 | /* Prevent VTG shutdown */ | ||
| 758 | if (clk_prepare_enable(hqvdp->clk_pix_main)) { | ||
| 759 | DRM_ERROR("Failed to prepare/enable pix main clk\n"); | ||
| 760 | return; | ||
| 761 | } | ||
| 762 | |||
| 763 | /* Register VTG Vsync callback to handle bottom fields */ | ||
| 764 | if (sti_vtg_register_client(hqvdp->vtg, | ||
| 765 | &hqvdp->vtg_nb, | ||
| 766 | mixer->id)) { | ||
| 767 | DRM_ERROR("Cannot register VTG notifier\n"); | ||
| 768 | return; | ||
| 769 | } | ||
| 770 | } | ||
| 771 | |||
| 772 | writel(hqvdp->hqvdp_cmd_paddr + cmd_offset, | ||
| 773 | hqvdp->regs + HQVDP_MBX_NEXT_CMD); | ||
| 774 | |||
| 775 | hqvdp->curr_field_count++; | ||
| 776 | |||
| 777 | /* Interlaced : get ready to display the bottom field at next Vsync */ | ||
| 778 | if (fb->flags & DRM_MODE_FB_INTERLACED) | ||
| 779 | hqvdp->btm_field_pending = true; | ||
| 780 | |||
| 781 | dev_dbg(hqvdp->dev, "%s Posted command:0x%x\n", | ||
| 782 | __func__, hqvdp->hqvdp_cmd_paddr + cmd_offset); | ||
| 783 | |||
| 784 | plane->status = STI_PLANE_UPDATED; | ||
| 785 | } | ||
| 786 | |||
| 787 | static void sti_hqvdp_atomic_disable(struct drm_plane *drm_plane, | ||
| 788 | struct drm_plane_state *oldstate) | ||
| 789 | { | ||
| 790 | struct sti_plane *plane = to_sti_plane(drm_plane); | ||
| 791 | struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc); | ||
| 792 | |||
| 793 | if (!drm_plane->crtc) { | ||
| 794 | DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", | ||
| 795 | drm_plane->base.id); | ||
| 796 | return; | ||
| 797 | } | ||
| 798 | |||
| 799 | DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n", | ||
| 800 | drm_plane->crtc->base.id, sti_mixer_to_str(mixer), | ||
| 801 | drm_plane->base.id, sti_plane_to_str(plane)); | ||
| 802 | |||
| 803 | plane->status = STI_PLANE_DISABLING; | ||
| 804 | } | ||
| 805 | |||
| 806 | static const struct drm_plane_helper_funcs sti_hqvdp_helpers_funcs = { | ||
| 807 | .atomic_update = sti_hqvdp_atomic_update, | ||
| 808 | .atomic_disable = sti_hqvdp_atomic_disable, | ||
| 791 | }; | 809 | }; |
| 792 | 810 | ||
| 793 | struct sti_plane *sti_hqvdp_create(struct device *dev, int desc) | 811 | static struct drm_plane *sti_hqvdp_create(struct drm_device *drm_dev, |
| 812 | struct device *dev, int desc) | ||
| 794 | { | 813 | { |
| 795 | struct sti_hqvdp *hqvdp = dev_get_drvdata(dev); | 814 | struct sti_hqvdp *hqvdp = dev_get_drvdata(dev); |
| 815 | int res; | ||
| 796 | 816 | ||
| 797 | hqvdp->plane.desc = desc; | 817 | hqvdp->plane.desc = desc; |
| 798 | hqvdp->plane.ops = &hqvdp_plane_ops; | 818 | hqvdp->plane.status = STI_PLANE_DISABLED; |
| 799 | 819 | ||
| 800 | sti_hqvdp_init(hqvdp); | 820 | sti_hqvdp_init(hqvdp); |
| 801 | 821 | ||
| 802 | return &hqvdp->plane; | 822 | res = drm_universal_plane_init(drm_dev, &hqvdp->plane.drm_plane, 1, |
| 823 | &sti_plane_helpers_funcs, | ||
| 824 | hqvdp_supported_formats, | ||
| 825 | ARRAY_SIZE(hqvdp_supported_formats), | ||
| 826 | DRM_PLANE_TYPE_OVERLAY); | ||
| 827 | if (res) { | ||
| 828 | DRM_ERROR("Failed to initialize universal plane\n"); | ||
| 829 | return NULL; | ||
| 830 | } | ||
| 831 | |||
| 832 | drm_plane_helper_add(&hqvdp->plane.drm_plane, &sti_hqvdp_helpers_funcs); | ||
| 833 | |||
| 834 | sti_plane_init_property(&hqvdp->plane, DRM_PLANE_TYPE_OVERLAY); | ||
| 835 | |||
| 836 | return &hqvdp->plane.drm_plane; | ||
| 803 | } | 837 | } |
| 804 | 838 | ||
| 805 | static void sti_hqvdp_init_plugs(struct sti_hqvdp *hqvdp) | 839 | static void sti_hqvdp_init_plugs(struct sti_hqvdp *hqvdp) |
| @@ -948,7 +982,7 @@ int sti_hqvdp_bind(struct device *dev, struct device *master, void *data) | |||
| 948 | { | 982 | { |
| 949 | struct sti_hqvdp *hqvdp = dev_get_drvdata(dev); | 983 | struct sti_hqvdp *hqvdp = dev_get_drvdata(dev); |
| 950 | struct drm_device *drm_dev = data; | 984 | struct drm_device *drm_dev = data; |
| 951 | struct sti_plane *plane; | 985 | struct drm_plane *plane; |
| 952 | int err; | 986 | int err; |
| 953 | 987 | ||
| 954 | DRM_DEBUG_DRIVER("\n"); | 988 | DRM_DEBUG_DRIVER("\n"); |
| @@ -965,11 +999,8 @@ int sti_hqvdp_bind(struct device *dev, struct device *master, void *data) | |||
| 965 | } | 999 | } |
| 966 | 1000 | ||
| 967 | /* Create HQVDP plane once xp70 is initialized */ | 1001 | /* Create HQVDP plane once xp70 is initialized */ |
| 968 | plane = sti_hqvdp_create(hqvdp->dev, STI_HQVDP_0); | 1002 | plane = sti_hqvdp_create(drm_dev, hqvdp->dev, STI_HQVDP_0); |
| 969 | if (plane) | 1003 | if (!plane) |
| 970 | sti_plane_init(hqvdp->drm_dev, plane, 1, | ||
| 971 | DRM_PLANE_TYPE_OVERLAY); | ||
| 972 | else | ||
| 973 | DRM_ERROR("Can't create HQVDP plane\n"); | 1004 | DRM_ERROR("Can't create HQVDP plane\n"); |
| 974 | 1005 | ||
| 975 | return 0; | 1006 | return 0; |
diff --git a/drivers/gpu/drm/sti/sti_mixer.c b/drivers/gpu/drm/sti/sti_mixer.c index d5a96561c8ce..0182e9365004 100644 --- a/drivers/gpu/drm/sti/sti_mixer.c +++ b/drivers/gpu/drm/sti/sti_mixer.c | |||
| @@ -58,6 +58,7 @@ const char *sti_mixer_to_str(struct sti_mixer *mixer) | |||
| 58 | return "<UNKNOWN MIXER>"; | 58 | return "<UNKNOWN MIXER>"; |
| 59 | } | 59 | } |
| 60 | } | 60 | } |
| 61 | EXPORT_SYMBOL(sti_mixer_to_str); | ||
| 61 | 62 | ||
| 62 | static inline u32 sti_mixer_reg_read(struct sti_mixer *mixer, u32 reg_id) | 63 | static inline u32 sti_mixer_reg_read(struct sti_mixer *mixer, u32 reg_id) |
| 63 | { | 64 | { |
| @@ -225,15 +226,6 @@ int sti_mixer_set_plane_status(struct sti_mixer *mixer, | |||
| 225 | return 0; | 226 | return 0; |
| 226 | } | 227 | } |
| 227 | 228 | ||
| 228 | void sti_mixer_clear_all_planes(struct sti_mixer *mixer) | ||
| 229 | { | ||
| 230 | u32 val; | ||
| 231 | |||
| 232 | DRM_DEBUG_DRIVER("%s clear all planes\n", sti_mixer_to_str(mixer)); | ||
| 233 | val = sti_mixer_reg_read(mixer, GAM_MIXER_CTL) & 0xFFFF0000; | ||
| 234 | sti_mixer_reg_write(mixer, GAM_MIXER_CTL, val); | ||
| 235 | } | ||
| 236 | |||
| 237 | void sti_mixer_set_matrix(struct sti_mixer *mixer) | 229 | void sti_mixer_set_matrix(struct sti_mixer *mixer) |
| 238 | { | 230 | { |
| 239 | unsigned int i; | 231 | unsigned int i; |
diff --git a/drivers/gpu/drm/sti/sti_mixer.h b/drivers/gpu/drm/sti/sti_mixer.h index 2f69b007e7c8..efb1a9a5ba86 100644 --- a/drivers/gpu/drm/sti/sti_mixer.h +++ b/drivers/gpu/drm/sti/sti_mixer.h | |||
| @@ -15,6 +15,12 @@ | |||
| 15 | 15 | ||
| 16 | #define to_sti_mixer(x) container_of(x, struct sti_mixer, drm_crtc) | 16 | #define to_sti_mixer(x) container_of(x, struct sti_mixer, drm_crtc) |
| 17 | 17 | ||
| 18 | enum sti_mixer_status { | ||
| 19 | STI_MIXER_READY, | ||
| 20 | STI_MIXER_DISABLING, | ||
| 21 | STI_MIXER_DISABLED, | ||
| 22 | }; | ||
| 23 | |||
| 18 | /** | 24 | /** |
| 19 | * STI Mixer subdevice structure | 25 | * STI Mixer subdevice structure |
| 20 | * | 26 | * |
| @@ -23,7 +29,7 @@ | |||
| 23 | * @id: id of the mixer | 29 | * @id: id of the mixer |
| 24 | * @drm_crtc: crtc object link to the mixer | 30 | * @drm_crtc: crtc object link to the mixer |
| 25 | * @pending_event: set if a flip event is pending on crtc | 31 | * @pending_event: set if a flip event is pending on crtc |
| 26 | * @enabled: to know if the mixer is active or not | 32 | * @status: to know the status of the mixer |
| 27 | */ | 33 | */ |
| 28 | struct sti_mixer { | 34 | struct sti_mixer { |
| 29 | struct device *dev; | 35 | struct device *dev; |
| @@ -31,7 +37,7 @@ struct sti_mixer { | |||
| 31 | int id; | 37 | int id; |
| 32 | struct drm_crtc drm_crtc; | 38 | struct drm_crtc drm_crtc; |
| 33 | struct drm_pending_vblank_event *pending_event; | 39 | struct drm_pending_vblank_event *pending_event; |
| 34 | bool enabled; | 40 | enum sti_mixer_status status; |
| 35 | }; | 41 | }; |
| 36 | 42 | ||
| 37 | const char *sti_mixer_to_str(struct sti_mixer *mixer); | 43 | const char *sti_mixer_to_str(struct sti_mixer *mixer); |
| @@ -41,7 +47,6 @@ struct sti_mixer *sti_mixer_create(struct device *dev, int id, | |||
| 41 | 47 | ||
| 42 | int sti_mixer_set_plane_status(struct sti_mixer *mixer, | 48 | int sti_mixer_set_plane_status(struct sti_mixer *mixer, |
| 43 | struct sti_plane *plane, bool status); | 49 | struct sti_plane *plane, bool status); |
| 44 | void sti_mixer_clear_all_planes(struct sti_mixer *mixer); | ||
| 45 | int sti_mixer_set_plane_depth(struct sti_mixer *mixer, struct sti_plane *plane); | 50 | int sti_mixer_set_plane_depth(struct sti_mixer *mixer, struct sti_plane *plane); |
| 46 | int sti_mixer_active_video_area(struct sti_mixer *mixer, | 51 | int sti_mixer_active_video_area(struct sti_mixer *mixer, |
| 47 | struct drm_display_mode *mode); | 52 | struct drm_display_mode *mode); |
diff --git a/drivers/gpu/drm/sti/sti_plane.c b/drivers/gpu/drm/sti/sti_plane.c index 6a38521ca9b4..d5c5e91f2956 100644 --- a/drivers/gpu/drm/sti/sti_plane.c +++ b/drivers/gpu/drm/sti/sti_plane.c | |||
| @@ -7,15 +7,12 @@ | |||
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #include <drm/drmP.h> | 9 | #include <drm/drmP.h> |
| 10 | #include <drm/drm_atomic_helper.h> | ||
| 11 | #include <drm/drm_gem_cma_helper.h> | ||
| 12 | #include <drm/drm_fb_cma_helper.h> | 10 | #include <drm/drm_fb_cma_helper.h> |
| 13 | #include <drm/drm_plane_helper.h> | 11 | #include <drm/drm_gem_cma_helper.h> |
| 14 | 12 | ||
| 15 | #include "sti_compositor.h" | 13 | #include "sti_compositor.h" |
| 16 | #include "sti_drv.h" | 14 | #include "sti_drv.h" |
| 17 | #include "sti_plane.h" | 15 | #include "sti_plane.h" |
| 18 | #include "sti_vtg.h" | ||
| 19 | 16 | ||
| 20 | /* (Background) < GDP0 < GDP1 < HQVDP0 < GDP2 < GDP3 < (ForeGround) */ | 17 | /* (Background) < GDP0 < GDP1 < HQVDP0 < GDP2 < GDP3 < (ForeGround) */ |
| 21 | enum sti_plane_desc sti_plane_default_zorder[] = { | 18 | enum sti_plane_desc sti_plane_default_zorder[] = { |
| @@ -47,115 +44,6 @@ const char *sti_plane_to_str(struct sti_plane *plane) | |||
| 47 | } | 44 | } |
| 48 | EXPORT_SYMBOL(sti_plane_to_str); | 45 | EXPORT_SYMBOL(sti_plane_to_str); |
| 49 | 46 | ||
| 50 | static int sti_plane_prepare(struct sti_plane *plane, | ||
| 51 | struct drm_crtc *crtc, | ||
| 52 | struct drm_framebuffer *fb, | ||
| 53 | struct drm_display_mode *mode, int mixer_id, | ||
| 54 | int dest_x, int dest_y, int dest_w, int dest_h, | ||
| 55 | int src_x, int src_y, int src_w, int src_h) | ||
| 56 | { | ||
| 57 | struct drm_gem_cma_object *cma_obj; | ||
| 58 | unsigned int i; | ||
| 59 | int res; | ||
| 60 | |||
| 61 | if (!plane || !fb || !mode) { | ||
| 62 | DRM_ERROR("Null fb, plane or mode\n"); | ||
| 63 | return 1; | ||
| 64 | } | ||
| 65 | |||
| 66 | cma_obj = drm_fb_cma_get_gem_obj(fb, 0); | ||
| 67 | if (!cma_obj) { | ||
| 68 | DRM_ERROR("Can't get CMA GEM object for fb\n"); | ||
| 69 | return 1; | ||
| 70 | } | ||
| 71 | |||
| 72 | plane->fb = fb; | ||
| 73 | plane->mode = mode; | ||
| 74 | plane->mixer_id = mixer_id; | ||
| 75 | plane->dst_x = dest_x; | ||
| 76 | plane->dst_y = dest_y; | ||
| 77 | plane->dst_w = clamp_val(dest_w, 0, mode->crtc_hdisplay - dest_x); | ||
| 78 | plane->dst_h = clamp_val(dest_h, 0, mode->crtc_vdisplay - dest_y); | ||
| 79 | plane->src_x = src_x; | ||
| 80 | plane->src_y = src_y; | ||
| 81 | plane->src_w = src_w; | ||
| 82 | plane->src_h = src_h; | ||
| 83 | plane->format = fb->pixel_format; | ||
| 84 | plane->vaddr = cma_obj->vaddr; | ||
| 85 | plane->paddr = cma_obj->paddr; | ||
| 86 | for (i = 0; i < 4; i++) { | ||
| 87 | plane->pitches[i] = fb->pitches[i]; | ||
| 88 | plane->offsets[i] = fb->offsets[i]; | ||
| 89 | } | ||
| 90 | |||
| 91 | DRM_DEBUG_DRIVER("%s is associated with mixer_id %d\n", | ||
| 92 | sti_plane_to_str(plane), | ||
| 93 | plane->mixer_id); | ||
| 94 | DRM_DEBUG_DRIVER("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n", | ||
| 95 | sti_plane_to_str(plane), | ||
| 96 | plane->dst_w, plane->dst_h, plane->dst_x, plane->dst_y, | ||
| 97 | plane->src_w, plane->src_h, plane->src_x, | ||
| 98 | plane->src_y); | ||
| 99 | |||
| 100 | DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id, | ||
| 101 | (char *)&plane->format, (unsigned long)plane->paddr); | ||
| 102 | |||
| 103 | if (!plane->ops->prepare) { | ||
| 104 | DRM_ERROR("Cannot prepare\n"); | ||
| 105 | return 1; | ||
| 106 | } | ||
| 107 | |||
| 108 | res = plane->ops->prepare(plane, !plane->enabled); | ||
| 109 | if (res) { | ||
| 110 | DRM_ERROR("Plane prepare failed\n"); | ||
| 111 | return res; | ||
| 112 | } | ||
| 113 | |||
| 114 | plane->enabled = true; | ||
| 115 | |||
| 116 | return 0; | ||
| 117 | } | ||
| 118 | |||
| 119 | static int sti_plane_commit(struct sti_plane *plane) | ||
| 120 | { | ||
| 121 | if (!plane) | ||
| 122 | return 1; | ||
| 123 | |||
| 124 | if (!plane->ops->commit) { | ||
| 125 | DRM_ERROR("Cannot commit\n"); | ||
| 126 | return 1; | ||
| 127 | } | ||
| 128 | |||
| 129 | return plane->ops->commit(plane); | ||
| 130 | } | ||
| 131 | |||
| 132 | static int sti_plane_disable(struct sti_plane *plane) | ||
| 133 | { | ||
| 134 | int res; | ||
| 135 | |||
| 136 | DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(plane)); | ||
| 137 | if (!plane) | ||
| 138 | return 1; | ||
| 139 | |||
| 140 | if (!plane->enabled) | ||
| 141 | return 0; | ||
| 142 | |||
| 143 | if (!plane->ops->disable) { | ||
| 144 | DRM_ERROR("Cannot disable\n"); | ||
| 145 | return 1; | ||
| 146 | } | ||
| 147 | |||
| 148 | res = plane->ops->disable(plane); | ||
| 149 | if (res) { | ||
| 150 | DRM_ERROR("Plane disable failed\n"); | ||
| 151 | return res; | ||
| 152 | } | ||
| 153 | |||
| 154 | plane->enabled = false; | ||
| 155 | |||
| 156 | return 0; | ||
| 157 | } | ||
| 158 | |||
| 159 | static void sti_plane_destroy(struct drm_plane *drm_plane) | 47 | static void sti_plane_destroy(struct drm_plane *drm_plane) |
| 160 | { | 48 | { |
| 161 | DRM_DEBUG_DRIVER("\n"); | 49 | DRM_DEBUG_DRIVER("\n"); |
| @@ -182,109 +70,6 @@ static int sti_plane_set_property(struct drm_plane *drm_plane, | |||
| 182 | return -EINVAL; | 70 | return -EINVAL; |
| 183 | } | 71 | } |
| 184 | 72 | ||
| 185 | static struct drm_plane_funcs sti_plane_funcs = { | ||
| 186 | .update_plane = drm_atomic_helper_update_plane, | ||
| 187 | .disable_plane = drm_atomic_helper_disable_plane, | ||
| 188 | .destroy = sti_plane_destroy, | ||
| 189 | .set_property = sti_plane_set_property, | ||
| 190 | .reset = drm_atomic_helper_plane_reset, | ||
| 191 | .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, | ||
| 192 | .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, | ||
| 193 | }; | ||
| 194 | |||
| 195 | static int sti_plane_atomic_check(struct drm_plane *drm_plane, | ||
| 196 | struct drm_plane_state *state) | ||
| 197 | { | ||
| 198 | return 0; | ||
| 199 | } | ||
| 200 | |||
| 201 | static void sti_plane_atomic_update(struct drm_plane *drm_plane, | ||
| 202 | struct drm_plane_state *oldstate) | ||
| 203 | { | ||
| 204 | struct drm_plane_state *state = drm_plane->state; | ||
| 205 | struct sti_plane *plane = to_sti_plane(drm_plane); | ||
| 206 | struct sti_mixer *mixer = to_sti_mixer(state->crtc); | ||
| 207 | int res; | ||
| 208 | |||
| 209 | DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n", | ||
| 210 | state->crtc->base.id, sti_mixer_to_str(mixer), | ||
| 211 | drm_plane->base.id, sti_plane_to_str(plane)); | ||
| 212 | DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", | ||
| 213 | state->crtc_w, state->crtc_h, | ||
| 214 | state->crtc_x, state->crtc_y); | ||
| 215 | |||
| 216 | res = sti_mixer_set_plane_depth(mixer, plane); | ||
| 217 | if (res) { | ||
| 218 | DRM_ERROR("Cannot set plane depth\n"); | ||
| 219 | return; | ||
| 220 | } | ||
| 221 | |||
| 222 | /* src_x are in 16.16 format */ | ||
| 223 | res = sti_plane_prepare(plane, state->crtc, state->fb, | ||
| 224 | &state->crtc->mode, mixer->id, | ||
| 225 | state->crtc_x, state->crtc_y, | ||
| 226 | state->crtc_w, state->crtc_h, | ||
| 227 | state->src_x >> 16, state->src_y >> 16, | ||
| 228 | state->src_w >> 16, state->src_h >> 16); | ||
| 229 | if (res) { | ||
| 230 | DRM_ERROR("Plane prepare failed\n"); | ||
| 231 | return; | ||
| 232 | } | ||
| 233 | |||
| 234 | res = sti_plane_commit(plane); | ||
| 235 | if (res) { | ||
| 236 | DRM_ERROR("Plane commit failed\n"); | ||
| 237 | return; | ||
| 238 | } | ||
| 239 | |||
| 240 | res = sti_mixer_set_plane_status(mixer, plane, true); | ||
| 241 | if (res) { | ||
| 242 | DRM_ERROR("Cannot enable plane at mixer\n"); | ||
| 243 | return; | ||
| 244 | } | ||
| 245 | } | ||
| 246 | |||
| 247 | static void sti_plane_atomic_disable(struct drm_plane *drm_plane, | ||
| 248 | struct drm_plane_state *oldstate) | ||
| 249 | { | ||
| 250 | struct sti_plane *plane = to_sti_plane(drm_plane); | ||
| 251 | struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc); | ||
| 252 | int res; | ||
| 253 | |||
| 254 | if (!drm_plane->crtc) { | ||
| 255 | DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", | ||
| 256 | drm_plane->base.id); | ||
| 257 | return; | ||
| 258 | } | ||
| 259 | |||
| 260 | DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n", | ||
| 261 | drm_plane->crtc->base.id, sti_mixer_to_str(mixer), | ||
| 262 | drm_plane->base.id, sti_plane_to_str(plane)); | ||
| 263 | |||
| 264 | /* Disable plane at mixer level */ | ||
| 265 | res = sti_mixer_set_plane_status(mixer, plane, false); | ||
| 266 | if (res) { | ||
| 267 | DRM_ERROR("Cannot disable plane at mixer\n"); | ||
| 268 | return; | ||
| 269 | } | ||
| 270 | |||
| 271 | /* Wait a while to be sure that a Vsync event is received */ | ||
| 272 | msleep(WAIT_NEXT_VSYNC_MS); | ||
| 273 | |||
| 274 | /* Then disable plane itself */ | ||
| 275 | res = sti_plane_disable(plane); | ||
| 276 | if (res) { | ||
| 277 | DRM_ERROR("Plane disable failed\n"); | ||
| 278 | return; | ||
| 279 | } | ||
| 280 | } | ||
| 281 | |||
| 282 | static const struct drm_plane_helper_funcs sti_plane_helpers_funcs = { | ||
| 283 | .atomic_check = sti_plane_atomic_check, | ||
| 284 | .atomic_update = sti_plane_atomic_update, | ||
| 285 | .atomic_disable = sti_plane_atomic_disable, | ||
| 286 | }; | ||
| 287 | |||
| 288 | static void sti_plane_attach_zorder_property(struct drm_plane *drm_plane) | 73 | static void sti_plane_attach_zorder_property(struct drm_plane *drm_plane) |
| 289 | { | 74 | { |
| 290 | struct drm_device *dev = drm_plane->dev; | 75 | struct drm_device *dev = drm_plane->dev; |
| @@ -305,25 +90,10 @@ static void sti_plane_attach_zorder_property(struct drm_plane *drm_plane) | |||
| 305 | drm_object_attach_property(&drm_plane->base, prop, plane->zorder); | 90 | drm_object_attach_property(&drm_plane->base, prop, plane->zorder); |
| 306 | } | 91 | } |
| 307 | 92 | ||
| 308 | struct drm_plane *sti_plane_init(struct drm_device *dev, | 93 | void sti_plane_init_property(struct sti_plane *plane, |
| 309 | struct sti_plane *plane, | 94 | enum drm_plane_type type) |
| 310 | unsigned int possible_crtcs, | ||
| 311 | enum drm_plane_type type) | ||
| 312 | { | 95 | { |
| 313 | int err, i; | 96 | unsigned int i; |
| 314 | |||
| 315 | err = drm_universal_plane_init(dev, &plane->drm_plane, | ||
| 316 | possible_crtcs, | ||
| 317 | &sti_plane_funcs, | ||
| 318 | plane->ops->get_formats(plane), | ||
| 319 | plane->ops->get_nb_formats(plane), | ||
| 320 | type); | ||
| 321 | if (err) { | ||
| 322 | DRM_ERROR("Failed to initialize universal plane\n"); | ||
| 323 | return NULL; | ||
| 324 | } | ||
| 325 | |||
| 326 | drm_plane_helper_add(&plane->drm_plane, &sti_plane_helpers_funcs); | ||
| 327 | 97 | ||
| 328 | for (i = 0; i < ARRAY_SIZE(sti_plane_default_zorder); i++) | 98 | for (i = 0; i < ARRAY_SIZE(sti_plane_default_zorder); i++) |
| 329 | if (sti_plane_default_zorder[i] == plane->desc) | 99 | if (sti_plane_default_zorder[i] == plane->desc) |
| @@ -337,7 +107,16 @@ struct drm_plane *sti_plane_init(struct drm_device *dev, | |||
| 337 | DRM_DEBUG_DRIVER("drm plane:%d mapped to %s with zorder:%d\n", | 107 | DRM_DEBUG_DRIVER("drm plane:%d mapped to %s with zorder:%d\n", |
| 338 | plane->drm_plane.base.id, | 108 | plane->drm_plane.base.id, |
| 339 | sti_plane_to_str(plane), plane->zorder); | 109 | sti_plane_to_str(plane), plane->zorder); |
| 340 | |||
| 341 | return &plane->drm_plane; | ||
| 342 | } | 110 | } |
| 343 | EXPORT_SYMBOL(sti_plane_init); | 111 | EXPORT_SYMBOL(sti_plane_init_property); |
| 112 | |||
| 113 | struct drm_plane_funcs sti_plane_helpers_funcs = { | ||
| 114 | .update_plane = drm_atomic_helper_update_plane, | ||
| 115 | .disable_plane = drm_atomic_helper_disable_plane, | ||
| 116 | .destroy = sti_plane_destroy, | ||
| 117 | .set_property = sti_plane_set_property, | ||
| 118 | .reset = drm_atomic_helper_plane_reset, | ||
| 119 | .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, | ||
| 120 | .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, | ||
| 121 | }; | ||
| 122 | EXPORT_SYMBOL(sti_plane_helpers_funcs); | ||
diff --git a/drivers/gpu/drm/sti/sti_plane.h b/drivers/gpu/drm/sti/sti_plane.h index bd527543bb1c..86f1e6fc81b9 100644 --- a/drivers/gpu/drm/sti/sti_plane.h +++ b/drivers/gpu/drm/sti/sti_plane.h | |||
| @@ -8,6 +8,10 @@ | |||
| 8 | #define _STI_PLANE_H_ | 8 | #define _STI_PLANE_H_ |
| 9 | 9 | ||
| 10 | #include <drm/drmP.h> | 10 | #include <drm/drmP.h> |
| 11 | #include <drm/drm_atomic_helper.h> | ||
| 12 | #include <drm/drm_plane_helper.h> | ||
| 13 | |||
| 14 | extern struct drm_plane_funcs sti_plane_helpers_funcs; | ||
| 11 | 15 | ||
| 12 | #define to_sti_plane(x) container_of(x, struct sti_plane, drm_plane) | 16 | #define to_sti_plane(x) container_of(x, struct sti_plane, drm_plane) |
| 13 | 17 | ||
| @@ -38,68 +42,30 @@ enum sti_plane_desc { | |||
| 38 | STI_BACK = STI_BCK | 42 | STI_BACK = STI_BCK |
| 39 | }; | 43 | }; |
| 40 | 44 | ||
| 45 | enum sti_plane_status { | ||
| 46 | STI_PLANE_READY, | ||
| 47 | STI_PLANE_UPDATED, | ||
| 48 | STI_PLANE_DISABLING, | ||
| 49 | STI_PLANE_FLUSHING, | ||
| 50 | STI_PLANE_DISABLED, | ||
| 51 | }; | ||
| 52 | |||
| 41 | /** | 53 | /** |
| 42 | * STI plane structure | 54 | * STI plane structure |
| 43 | * | 55 | * |
| 44 | * @plane: drm plane it is bound to (if any) | 56 | * @plane: drm plane it is bound to (if any) |
| 45 | * @fb: drm fb it is bound to | ||
| 46 | * @mode: display mode | ||
| 47 | * @desc: plane type & id | 57 | * @desc: plane type & id |
| 48 | * @ops: plane functions | 58 | * @status: to know the status of the plane |
| 49 | * @zorder: plane z-order | 59 | * @zorder: plane z-order |
| 50 | * @mixer_id: id of the mixer used to display the plane | ||
| 51 | * @enabled: to know if the plane is active or not | ||
| 52 | * @src_x src_y: coordinates of the input (fb) area | ||
| 53 | * @src_w src_h: size of the input (fb) area | ||
| 54 | * @dst_x dst_y: coordinates of the output (crtc) area | ||
| 55 | * @dst_w dst_h: size of the output (crtc) area | ||
| 56 | * @format: format | ||
| 57 | * @pitches: pitch of 'planes' (eg: Y, U, V) | ||
| 58 | * @offsets: offset of 'planes' | ||
| 59 | * @vaddr: virtual address of the input buffer | ||
| 60 | * @paddr: physical address of the input buffer | ||
| 61 | */ | 60 | */ |
| 62 | struct sti_plane { | 61 | struct sti_plane { |
| 63 | struct drm_plane drm_plane; | 62 | struct drm_plane drm_plane; |
| 64 | struct drm_framebuffer *fb; | ||
| 65 | struct drm_display_mode *mode; | ||
| 66 | enum sti_plane_desc desc; | 63 | enum sti_plane_desc desc; |
| 67 | const struct sti_plane_funcs *ops; | 64 | enum sti_plane_status status; |
| 68 | int zorder; | 65 | int zorder; |
| 69 | int mixer_id; | ||
| 70 | bool enabled; | ||
| 71 | int src_x, src_y; | ||
| 72 | int src_w, src_h; | ||
| 73 | int dst_x, dst_y; | ||
| 74 | int dst_w, dst_h; | ||
| 75 | uint32_t format; | ||
| 76 | unsigned int pitches[4]; | ||
| 77 | unsigned int offsets[4]; | ||
| 78 | void *vaddr; | ||
| 79 | dma_addr_t paddr; | ||
| 80 | }; | 66 | }; |
| 81 | 67 | ||
| 82 | /** | ||
| 83 | * STI plane functions structure | ||
| 84 | * | ||
| 85 | * @get_formats: get plane supported formats | ||
| 86 | * @get_nb_formats: get number of format supported | ||
| 87 | * @prepare: prepare plane before rendering | ||
| 88 | * @commit: set plane for rendering | ||
| 89 | * @disable: disable plane | ||
| 90 | */ | ||
| 91 | struct sti_plane_funcs { | ||
| 92 | const uint32_t* (*get_formats)(struct sti_plane *plane); | ||
| 93 | unsigned int (*get_nb_formats)(struct sti_plane *plane); | ||
| 94 | int (*prepare)(struct sti_plane *plane, bool first_prepare); | ||
| 95 | int (*commit)(struct sti_plane *plane); | ||
| 96 | int (*disable)(struct sti_plane *plane); | ||
| 97 | }; | ||
| 98 | |||
| 99 | struct drm_plane *sti_plane_init(struct drm_device *dev, | ||
| 100 | struct sti_plane *sti_plane, | ||
| 101 | unsigned int possible_crtcs, | ||
| 102 | enum drm_plane_type type); | ||
| 103 | const char *sti_plane_to_str(struct sti_plane *plane); | 68 | const char *sti_plane_to_str(struct sti_plane *plane); |
| 104 | 69 | void sti_plane_init_property(struct sti_plane *plane, | |
| 70 | enum drm_plane_type type); | ||
| 105 | #endif | 71 | #endif |
diff --git a/drivers/gpu/drm/sti/sti_vid.c b/drivers/gpu/drm/sti/sti_vid.c index 1e7e1d776adb..a8254cc362a1 100644 --- a/drivers/gpu/drm/sti/sti_vid.c +++ b/drivers/gpu/drm/sti/sti_vid.c | |||
| @@ -43,28 +43,37 @@ | |||
| 43 | #define VID_MPR2_BT709 0x07150545 | 43 | #define VID_MPR2_BT709 0x07150545 |
| 44 | #define VID_MPR3_BT709 0x00000AE8 | 44 | #define VID_MPR3_BT709 0x00000AE8 |
| 45 | 45 | ||
| 46 | int sti_vid_commit(struct sti_vid *vid, struct sti_plane *plane) | 46 | void sti_vid_commit(struct sti_vid *vid, |
| 47 | struct drm_plane_state *state) | ||
| 47 | { | 48 | { |
| 48 | struct drm_display_mode *mode = plane->mode; | 49 | struct drm_crtc *crtc = state->crtc; |
| 50 | struct drm_display_mode *mode = &crtc->mode; | ||
| 51 | int dst_x = state->crtc_x; | ||
| 52 | int dst_y = state->crtc_y; | ||
| 53 | int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x); | ||
| 54 | int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y); | ||
| 49 | u32 val, ydo, xdo, yds, xds; | 55 | u32 val, ydo, xdo, yds, xds; |
| 50 | 56 | ||
| 57 | /* Input / output size | ||
| 58 | * Align to upper even value */ | ||
| 59 | dst_w = ALIGN(dst_w, 2); | ||
| 60 | dst_h = ALIGN(dst_h, 2); | ||
| 61 | |||
| 51 | /* Unmask */ | 62 | /* Unmask */ |
| 52 | val = readl(vid->regs + VID_CTL); | 63 | val = readl(vid->regs + VID_CTL); |
| 53 | val &= ~VID_CTL_IGNORE; | 64 | val &= ~VID_CTL_IGNORE; |
| 54 | writel(val, vid->regs + VID_CTL); | 65 | writel(val, vid->regs + VID_CTL); |
| 55 | 66 | ||
| 56 | ydo = sti_vtg_get_line_number(*mode, plane->dst_y); | 67 | ydo = sti_vtg_get_line_number(*mode, dst_y); |
| 57 | yds = sti_vtg_get_line_number(*mode, plane->dst_y + plane->dst_h - 1); | 68 | yds = sti_vtg_get_line_number(*mode, dst_y + dst_h - 1); |
| 58 | xdo = sti_vtg_get_pixel_number(*mode, plane->dst_x); | 69 | xdo = sti_vtg_get_pixel_number(*mode, dst_x); |
| 59 | xds = sti_vtg_get_pixel_number(*mode, plane->dst_x + plane->dst_w - 1); | 70 | xds = sti_vtg_get_pixel_number(*mode, dst_x + dst_w - 1); |
| 60 | 71 | ||
| 61 | writel((ydo << 16) | xdo, vid->regs + VID_VPO); | 72 | writel((ydo << 16) | xdo, vid->regs + VID_VPO); |
| 62 | writel((yds << 16) | xds, vid->regs + VID_VPS); | 73 | writel((yds << 16) | xds, vid->regs + VID_VPS); |
| 63 | |||
| 64 | return 0; | ||
| 65 | } | 74 | } |
| 66 | 75 | ||
| 67 | int sti_vid_disable(struct sti_vid *vid) | 76 | void sti_vid_disable(struct sti_vid *vid) |
| 68 | { | 77 | { |
| 69 | u32 val; | 78 | u32 val; |
| 70 | 79 | ||
| @@ -72,8 +81,6 @@ int sti_vid_disable(struct sti_vid *vid) | |||
| 72 | val = readl(vid->regs + VID_CTL); | 81 | val = readl(vid->regs + VID_CTL); |
| 73 | val |= VID_CTL_IGNORE; | 82 | val |= VID_CTL_IGNORE; |
| 74 | writel(val, vid->regs + VID_CTL); | 83 | writel(val, vid->regs + VID_CTL); |
| 75 | |||
| 76 | return 0; | ||
| 77 | } | 84 | } |
| 78 | 85 | ||
| 79 | static void sti_vid_init(struct sti_vid *vid) | 86 | static void sti_vid_init(struct sti_vid *vid) |
diff --git a/drivers/gpu/drm/sti/sti_vid.h b/drivers/gpu/drm/sti/sti_vid.h index cc680a23cc5d..5dea4791f1d6 100644 --- a/drivers/gpu/drm/sti/sti_vid.h +++ b/drivers/gpu/drm/sti/sti_vid.h | |||
| @@ -20,8 +20,9 @@ struct sti_vid { | |||
| 20 | int id; | 20 | int id; |
| 21 | }; | 21 | }; |
| 22 | 22 | ||
| 23 | int sti_vid_commit(struct sti_vid *vid, struct sti_plane *plane); | 23 | void sti_vid_commit(struct sti_vid *vid, |
| 24 | int sti_vid_disable(struct sti_vid *vid); | 24 | struct drm_plane_state *state); |
| 25 | void sti_vid_disable(struct sti_vid *vid); | ||
| 25 | struct sti_vid *sti_vid_create(struct device *dev, int id, | 26 | struct sti_vid *sti_vid_create(struct device *dev, int id, |
| 26 | void __iomem *baseaddr); | 27 | void __iomem *baseaddr); |
| 27 | 28 | ||
