Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.3-rc8 238 lines 7.0 kB view raw
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 23static 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 28static 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 51static 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 60static 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 74static 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 116static 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 127static 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 138static 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 152static 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 160static 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 174static const struct drm_plane_helper_funcs arc_pgu_plane_helper_funcs = { 175 .atomic_update = arc_pgu_plane_atomic_update, 176}; 177 178static void arc_pgu_plane_destroy(struct drm_plane *plane) 179{ 180 drm_plane_cleanup(plane); 181} 182 183static 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 192static 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 219int 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}