root/drivers/gpu/drm/arc/arcpgu_crtc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. arc_pgu_set_pxl_fmt
  2. arc_pgu_crtc_mode_valid
  3. arc_pgu_crtc_mode_set_nofb
  4. arc_pgu_crtc_atomic_enable
  5. arc_pgu_crtc_atomic_disable
  6. arc_pgu_crtc_atomic_begin
  7. arc_pgu_plane_atomic_update
  8. arc_pgu_plane_destroy
  9. arc_pgu_plane_init
  10. arc_pgu_setup_crtc

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * ARC PGU DRM driver.
   4  *
   5  * Copyright (C) 2016 Synopsys, Inc. (www.synopsys.com)
   6  */
   7 
   8 #include <drm/drm_atomic_helper.h>
   9 #include <drm/drm_device.h>
  10 #include <drm/drm_fb_cma_helper.h>
  11 #include <drm/drm_gem_cma_helper.h>
  12 #include <drm/drm_vblank.h>
  13 #include <drm/drm_plane_helper.h>
  14 #include <drm/drm_probe_helper.h>
  15 #include <linux/clk.h>
  16 #include <linux/platform_data/simplefb.h>
  17 
  18 #include "arcpgu.h"
  19 #include "arcpgu_regs.h"
  20 
  21 #define ENCODE_PGU_XY(x, y)     ((((x) - 1) << 16) | ((y) - 1))
  22 
  23 static struct simplefb_format supported_formats[] = {
  24         { "r5g6b5", 16, {11, 5}, {5, 6}, {0, 5}, {0, 0}, DRM_FORMAT_RGB565 },
  25         { "r8g8b8", 24, {16, 8}, {8, 8}, {0, 8}, {0, 0}, DRM_FORMAT_RGB888 },
  26 };
  27 
  28 static void arc_pgu_set_pxl_fmt(struct drm_crtc *crtc)
  29 {
  30         struct arcpgu_drm_private *arcpgu = crtc_to_arcpgu_priv(crtc);
  31         const struct drm_framebuffer *fb = crtc->primary->state->fb;
  32         uint32_t pixel_format = fb->format->format;
  33         struct simplefb_format *format = NULL;
  34         int i;
  35 
  36         for (i = 0; i < ARRAY_SIZE(supported_formats); i++) {
  37                 if (supported_formats[i].fourcc == pixel_format)
  38                         format = &supported_formats[i];
  39         }
  40 
  41         if (WARN_ON(!format))
  42                 return;
  43 
  44         if (format->fourcc == DRM_FORMAT_RGB888)
  45                 arc_pgu_write(arcpgu, ARCPGU_REG_CTRL,
  46                               arc_pgu_read(arcpgu, ARCPGU_REG_CTRL) |
  47                                            ARCPGU_MODE_RGB888_MASK);
  48 
  49 }
  50 
  51 static const struct drm_crtc_funcs arc_pgu_crtc_funcs = {
  52         .destroy = drm_crtc_cleanup,
  53         .set_config = drm_atomic_helper_set_config,
  54         .page_flip = drm_atomic_helper_page_flip,
  55         .reset = drm_atomic_helper_crtc_reset,
  56         .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
  57         .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
  58 };
  59 
  60 static enum drm_mode_status arc_pgu_crtc_mode_valid(struct drm_crtc *crtc,
  61                                                     const struct drm_display_mode *mode)
  62 {
  63         struct arcpgu_drm_private *arcpgu = crtc_to_arcpgu_priv(crtc);
  64         long rate, clk_rate = mode->clock * 1000;
  65         long diff = clk_rate / 200; /* +-0.5% allowed by HDMI spec */
  66 
  67         rate = clk_round_rate(arcpgu->clk, clk_rate);
  68         if ((max(rate, clk_rate) - min(rate, clk_rate) < diff) && (rate > 0))
  69                 return MODE_OK;
  70 
  71         return MODE_NOCLOCK;
  72 }
  73 
  74 static void arc_pgu_crtc_mode_set_nofb(struct drm_crtc *crtc)
  75 {
  76         struct arcpgu_drm_private *arcpgu = crtc_to_arcpgu_priv(crtc);
  77         struct drm_display_mode *m = &crtc->state->adjusted_mode;
  78         u32 val;
  79 
  80         arc_pgu_write(arcpgu, ARCPGU_REG_FMT,
  81                       ENCODE_PGU_XY(m->crtc_htotal, m->crtc_vtotal));
  82 
  83         arc_pgu_write(arcpgu, ARCPGU_REG_HSYNC,
  84                       ENCODE_PGU_XY(m->crtc_hsync_start - m->crtc_hdisplay,
  85                                     m->crtc_hsync_end - m->crtc_hdisplay));
  86 
  87         arc_pgu_write(arcpgu, ARCPGU_REG_VSYNC,
  88                       ENCODE_PGU_XY(m->crtc_vsync_start - m->crtc_vdisplay,
  89                                     m->crtc_vsync_end - m->crtc_vdisplay));
  90 
  91         arc_pgu_write(arcpgu, ARCPGU_REG_ACTIVE,
  92                       ENCODE_PGU_XY(m->crtc_hblank_end - m->crtc_hblank_start,
  93                                     m->crtc_vblank_end - m->crtc_vblank_start));
  94 
  95         val = arc_pgu_read(arcpgu, ARCPGU_REG_CTRL);
  96 
  97         if (m->flags & DRM_MODE_FLAG_PVSYNC)
  98                 val |= ARCPGU_CTRL_VS_POL_MASK << ARCPGU_CTRL_VS_POL_OFST;
  99         else
 100                 val &= ~(ARCPGU_CTRL_VS_POL_MASK << ARCPGU_CTRL_VS_POL_OFST);
 101 
 102         if (m->flags & DRM_MODE_FLAG_PHSYNC)
 103                 val |= ARCPGU_CTRL_HS_POL_MASK << ARCPGU_CTRL_HS_POL_OFST;
 104         else
 105                 val &= ~(ARCPGU_CTRL_HS_POL_MASK << ARCPGU_CTRL_HS_POL_OFST);
 106 
 107         arc_pgu_write(arcpgu, ARCPGU_REG_CTRL, val);
 108         arc_pgu_write(arcpgu, ARCPGU_REG_STRIDE, 0);
 109         arc_pgu_write(arcpgu, ARCPGU_REG_START_SET, 1);
 110 
 111         arc_pgu_set_pxl_fmt(crtc);
 112 
 113         clk_set_rate(arcpgu->clk, m->crtc_clock * 1000);
 114 }
 115 
 116 static void arc_pgu_crtc_atomic_enable(struct drm_crtc *crtc,
 117                                        struct drm_crtc_state *old_state)
 118 {
 119         struct arcpgu_drm_private *arcpgu = crtc_to_arcpgu_priv(crtc);
 120 
 121         clk_prepare_enable(arcpgu->clk);
 122         arc_pgu_write(arcpgu, ARCPGU_REG_CTRL,
 123                       arc_pgu_read(arcpgu, ARCPGU_REG_CTRL) |
 124                       ARCPGU_CTRL_ENABLE_MASK);
 125 }
 126 
 127 static void arc_pgu_crtc_atomic_disable(struct drm_crtc *crtc,
 128                                         struct drm_crtc_state *old_state)
 129 {
 130         struct arcpgu_drm_private *arcpgu = crtc_to_arcpgu_priv(crtc);
 131 
 132         clk_disable_unprepare(arcpgu->clk);
 133         arc_pgu_write(arcpgu, ARCPGU_REG_CTRL,
 134                               arc_pgu_read(arcpgu, ARCPGU_REG_CTRL) &
 135                               ~ARCPGU_CTRL_ENABLE_MASK);
 136 }
 137 
 138 static void arc_pgu_crtc_atomic_begin(struct drm_crtc *crtc,
 139                                       struct drm_crtc_state *state)
 140 {
 141         struct drm_pending_vblank_event *event = crtc->state->event;
 142 
 143         if (event) {
 144                 crtc->state->event = NULL;
 145 
 146                 spin_lock_irq(&crtc->dev->event_lock);
 147                 drm_crtc_send_vblank_event(crtc, event);
 148                 spin_unlock_irq(&crtc->dev->event_lock);
 149         }
 150 }
 151 
 152 static const struct drm_crtc_helper_funcs arc_pgu_crtc_helper_funcs = {
 153         .mode_valid     = arc_pgu_crtc_mode_valid,
 154         .mode_set_nofb  = arc_pgu_crtc_mode_set_nofb,
 155         .atomic_begin   = arc_pgu_crtc_atomic_begin,
 156         .atomic_enable  = arc_pgu_crtc_atomic_enable,
 157         .atomic_disable = arc_pgu_crtc_atomic_disable,
 158 };
 159 
 160 static void arc_pgu_plane_atomic_update(struct drm_plane *plane,
 161                                         struct drm_plane_state *state)
 162 {
 163         struct arcpgu_drm_private *arcpgu;
 164         struct drm_gem_cma_object *gem;
 165 
 166         if (!plane->state->crtc || !plane->state->fb)
 167                 return;
 168 
 169         arcpgu = crtc_to_arcpgu_priv(plane->state->crtc);
 170         gem = drm_fb_cma_get_gem_obj(plane->state->fb, 0);
 171         arc_pgu_write(arcpgu, ARCPGU_REG_BUF0_ADDR, gem->paddr);
 172 }
 173 
 174 static const struct drm_plane_helper_funcs arc_pgu_plane_helper_funcs = {
 175         .atomic_update = arc_pgu_plane_atomic_update,
 176 };
 177 
 178 static void arc_pgu_plane_destroy(struct drm_plane *plane)
 179 {
 180         drm_plane_cleanup(plane);
 181 }
 182 
 183 static const struct drm_plane_funcs arc_pgu_plane_funcs = {
 184         .update_plane           = drm_atomic_helper_update_plane,
 185         .disable_plane          = drm_atomic_helper_disable_plane,
 186         .destroy                = arc_pgu_plane_destroy,
 187         .reset                  = drm_atomic_helper_plane_reset,
 188         .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
 189         .atomic_destroy_state   = drm_atomic_helper_plane_destroy_state,
 190 };
 191 
 192 static struct drm_plane *arc_pgu_plane_init(struct drm_device *drm)
 193 {
 194         struct arcpgu_drm_private *arcpgu = drm->dev_private;
 195         struct drm_plane *plane = NULL;
 196         u32 formats[ARRAY_SIZE(supported_formats)], i;
 197         int ret;
 198 
 199         plane = devm_kzalloc(drm->dev, sizeof(*plane), GFP_KERNEL);
 200         if (!plane)
 201                 return ERR_PTR(-ENOMEM);
 202 
 203         for (i = 0; i < ARRAY_SIZE(supported_formats); i++)
 204                 formats[i] = supported_formats[i].fourcc;
 205 
 206         ret = drm_universal_plane_init(drm, plane, 0xff, &arc_pgu_plane_funcs,
 207                                        formats, ARRAY_SIZE(formats),
 208                                        NULL,
 209                                        DRM_PLANE_TYPE_PRIMARY, NULL);
 210         if (ret)
 211                 return ERR_PTR(ret);
 212 
 213         drm_plane_helper_add(plane, &arc_pgu_plane_helper_funcs);
 214         arcpgu->plane = plane;
 215 
 216         return plane;
 217 }
 218 
 219 int arc_pgu_setup_crtc(struct drm_device *drm)
 220 {
 221         struct arcpgu_drm_private *arcpgu = drm->dev_private;
 222         struct drm_plane *primary;
 223         int ret;
 224 
 225         primary = arc_pgu_plane_init(drm);
 226         if (IS_ERR(primary))
 227                 return PTR_ERR(primary);
 228 
 229         ret = drm_crtc_init_with_planes(drm, &arcpgu->crtc, primary, NULL,
 230                                         &arc_pgu_crtc_funcs, NULL);
 231         if (ret) {
 232                 arc_pgu_plane_destroy(primary);
 233                 return ret;
 234         }
 235 
 236         drm_crtc_helper_add(&arcpgu->crtc, &arc_pgu_crtc_helper_funcs);
 237         return 0;
 238 }

/* [<][>][^][v][top][bottom][index][help] */