.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* Hisilicon Hibmc SoC drm driver |
---|
2 | 3 | * |
---|
3 | 4 | * Based on the bochs drm driver. |
---|
.. | .. |
---|
8 | 9 | * Rongrong Zou <zourongrong@huawei.com> |
---|
9 | 10 | * Rongrong Zou <zourongrong@gmail.com> |
---|
10 | 11 | * Jianhua Li <lijianhua@huawei.com> |
---|
11 | | - * |
---|
12 | | - * This program is free software; you can redistribute it and/or modify |
---|
13 | | - * it under the terms of the GNU General Public License as published by |
---|
14 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
15 | | - * (at your option) any later version. |
---|
16 | | - * |
---|
17 | 12 | */ |
---|
| 13 | + |
---|
| 14 | +#include <linux/delay.h> |
---|
18 | 15 | |
---|
19 | 16 | #include <drm/drm_atomic.h> |
---|
20 | 17 | #include <drm/drm_atomic_helper.h> |
---|
21 | | -#include <drm/drm_crtc_helper.h> |
---|
22 | | -#include <drm/drm_plane_helper.h> |
---|
| 18 | +#include <drm/drm_fourcc.h> |
---|
| 19 | +#include <drm/drm_gem_vram_helper.h> |
---|
| 20 | +#include <drm/drm_vblank.h> |
---|
23 | 21 | |
---|
24 | 22 | #include "hibmc_drm_drv.h" |
---|
25 | 23 | #include "hibmc_drm_regs.h" |
---|
.. | .. |
---|
39 | 37 | }; |
---|
40 | 38 | |
---|
41 | 39 | static const struct hibmc_dislay_pll_config hibmc_pll_table[] = { |
---|
| 40 | + {640, 480, CRT_PLL1_HS_25MHZ, CRT_PLL2_HS_25MHZ}, |
---|
42 | 41 | {800, 600, CRT_PLL1_HS_40MHZ, CRT_PLL2_HS_40MHZ}, |
---|
43 | 42 | {1024, 768, CRT_PLL1_HS_65MHZ, CRT_PLL2_HS_65MHZ}, |
---|
44 | 43 | {1152, 864, CRT_PLL1_HS_80MHZ_1152, CRT_PLL2_HS_80MHZ}, |
---|
.. | .. |
---|
46 | 45 | {1280, 720, CRT_PLL1_HS_74MHZ, CRT_PLL2_HS_74MHZ}, |
---|
47 | 46 | {1280, 960, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ}, |
---|
48 | 47 | {1280, 1024, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ}, |
---|
| 48 | + {1440, 900, CRT_PLL1_HS_106MHZ, CRT_PLL2_HS_106MHZ}, |
---|
| 49 | + {1600, 900, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ}, |
---|
49 | 50 | {1600, 1200, CRT_PLL1_HS_162MHZ, CRT_PLL2_HS_162MHZ}, |
---|
50 | 51 | {1920, 1080, CRT_PLL1_HS_148MHZ, CRT_PLL2_HS_148MHZ}, |
---|
51 | 52 | {1920, 1200, CRT_PLL1_HS_193MHZ, CRT_PLL2_HS_193MHZ}, |
---|
.. | .. |
---|
70 | 71 | return PTR_ERR(crtc_state); |
---|
71 | 72 | |
---|
72 | 73 | if (src_w != state->crtc_w || src_h != state->crtc_h) { |
---|
73 | | - DRM_DEBUG_ATOMIC("scale not support\n"); |
---|
| 74 | + drm_dbg_atomic(plane->dev, "scale not support\n"); |
---|
74 | 75 | return -EINVAL; |
---|
75 | 76 | } |
---|
76 | 77 | |
---|
77 | 78 | if (state->crtc_x < 0 || state->crtc_y < 0) { |
---|
78 | | - DRM_DEBUG_ATOMIC("crtc_x/y of drm_plane state is invalid\n"); |
---|
| 79 | + drm_dbg_atomic(plane->dev, "crtc_x/y of drm_plane state is invalid\n"); |
---|
79 | 80 | return -EINVAL; |
---|
80 | 81 | } |
---|
| 82 | + |
---|
| 83 | + if (!crtc_state->enable) |
---|
| 84 | + return 0; |
---|
81 | 85 | |
---|
82 | 86 | if (state->crtc_x + state->crtc_w > |
---|
83 | 87 | crtc_state->adjusted_mode.hdisplay || |
---|
84 | 88 | state->crtc_y + state->crtc_h > |
---|
85 | 89 | crtc_state->adjusted_mode.vdisplay) { |
---|
86 | | - DRM_DEBUG_ATOMIC("visible portion of plane is invalid\n"); |
---|
| 90 | + drm_dbg_atomic(plane->dev, "visible portion of plane is invalid\n"); |
---|
87 | 91 | return -EINVAL; |
---|
88 | 92 | } |
---|
89 | 93 | |
---|
| 94 | + if (state->fb->pitches[0] % 128 != 0) { |
---|
| 95 | + drm_dbg_atomic(plane->dev, "wrong stride with 128-byte aligned\n"); |
---|
| 96 | + return -EINVAL; |
---|
| 97 | + } |
---|
90 | 98 | return 0; |
---|
91 | 99 | } |
---|
92 | 100 | |
---|
.. | .. |
---|
95 | 103 | { |
---|
96 | 104 | struct drm_plane_state *state = plane->state; |
---|
97 | 105 | u32 reg; |
---|
98 | | - int ret; |
---|
99 | | - u64 gpu_addr = 0; |
---|
| 106 | + s64 gpu_addr = 0; |
---|
100 | 107 | unsigned int line_l; |
---|
101 | 108 | struct hibmc_drm_private *priv = plane->dev->dev_private; |
---|
102 | | - struct hibmc_framebuffer *hibmc_fb; |
---|
103 | | - struct hibmc_bo *bo; |
---|
| 109 | + struct drm_gem_vram_object *gbo; |
---|
104 | 110 | |
---|
105 | 111 | if (!state->fb) |
---|
106 | 112 | return; |
---|
107 | 113 | |
---|
108 | | - hibmc_fb = to_hibmc_framebuffer(state->fb); |
---|
109 | | - bo = gem_to_hibmc_bo(hibmc_fb->obj); |
---|
110 | | - ret = ttm_bo_reserve(&bo->bo, true, false, NULL); |
---|
111 | | - if (ret) { |
---|
112 | | - DRM_ERROR("failed to reserve ttm_bo: %d", ret); |
---|
113 | | - return; |
---|
114 | | - } |
---|
| 114 | + gbo = drm_gem_vram_of_gem(state->fb->obj[0]); |
---|
115 | 115 | |
---|
116 | | - ret = hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr); |
---|
117 | | - ttm_bo_unreserve(&bo->bo); |
---|
118 | | - if (ret) { |
---|
119 | | - DRM_ERROR("failed to pin hibmc_bo: %d", ret); |
---|
120 | | - return; |
---|
121 | | - } |
---|
| 116 | + gpu_addr = drm_gem_vram_offset(gbo); |
---|
| 117 | + if (WARN_ON_ONCE(gpu_addr < 0)) |
---|
| 118 | + return; /* Bug: we didn't pin the BO to VRAM in prepare_fb. */ |
---|
122 | 119 | |
---|
123 | 120 | writel(gpu_addr, priv->mmio + HIBMC_CRT_FB_ADDRESS); |
---|
124 | 121 | |
---|
125 | 122 | reg = state->fb->width * (state->fb->format->cpp[0]); |
---|
126 | | - /* now line_pad is 16 */ |
---|
127 | | - reg = PADDING(16, reg); |
---|
128 | 123 | |
---|
129 | | - line_l = state->fb->width * state->fb->format->cpp[0]; |
---|
130 | | - line_l = PADDING(16, line_l); |
---|
| 124 | + line_l = state->fb->pitches[0]; |
---|
131 | 125 | writel(HIBMC_FIELD(HIBMC_CRT_FB_WIDTH_WIDTH, reg) | |
---|
132 | 126 | HIBMC_FIELD(HIBMC_CRT_FB_WIDTH_OFFS, line_l), |
---|
133 | 127 | priv->mmio + HIBMC_CRT_FB_WIDTH); |
---|
.. | .. |
---|
157 | 151 | }; |
---|
158 | 152 | |
---|
159 | 153 | static const struct drm_plane_helper_funcs hibmc_plane_helper_funcs = { |
---|
| 154 | + .prepare_fb = drm_gem_vram_plane_helper_prepare_fb, |
---|
| 155 | + .cleanup_fb = drm_gem_vram_plane_helper_cleanup_fb, |
---|
160 | 156 | .atomic_check = hibmc_plane_atomic_check, |
---|
161 | 157 | .atomic_update = hibmc_plane_atomic_update, |
---|
162 | 158 | }; |
---|
163 | 159 | |
---|
164 | | -static struct drm_plane *hibmc_plane_init(struct hibmc_drm_private *priv) |
---|
| 160 | +static void hibmc_crtc_dpms(struct drm_crtc *crtc, int dpms) |
---|
165 | 161 | { |
---|
166 | | - struct drm_device *dev = priv->dev; |
---|
167 | | - struct drm_plane *plane; |
---|
168 | | - int ret = 0; |
---|
| 162 | + struct hibmc_drm_private *priv = crtc->dev->dev_private; |
---|
| 163 | + unsigned int reg; |
---|
169 | 164 | |
---|
170 | | - plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL); |
---|
171 | | - if (!plane) { |
---|
172 | | - DRM_ERROR("failed to alloc memory when init plane\n"); |
---|
173 | | - return ERR_PTR(-ENOMEM); |
---|
174 | | - } |
---|
175 | | - /* |
---|
176 | | - * plane init |
---|
177 | | - * TODO: Now only support primary plane, overlay planes |
---|
178 | | - * need to do. |
---|
179 | | - */ |
---|
180 | | - ret = drm_universal_plane_init(dev, plane, 1, &hibmc_plane_funcs, |
---|
181 | | - channel_formats1, |
---|
182 | | - ARRAY_SIZE(channel_formats1), |
---|
183 | | - NULL, |
---|
184 | | - DRM_PLANE_TYPE_PRIMARY, |
---|
185 | | - NULL); |
---|
186 | | - if (ret) { |
---|
187 | | - DRM_ERROR("failed to init plane: %d\n", ret); |
---|
188 | | - return ERR_PTR(ret); |
---|
189 | | - } |
---|
190 | | - |
---|
191 | | - drm_plane_helper_add(plane, &hibmc_plane_helper_funcs); |
---|
192 | | - return plane; |
---|
| 165 | + reg = readl(priv->mmio + HIBMC_CRT_DISP_CTL); |
---|
| 166 | + reg &= ~HIBMC_CRT_DISP_CTL_DPMS_MASK; |
---|
| 167 | + reg |= HIBMC_FIELD(HIBMC_CRT_DISP_CTL_DPMS, dpms); |
---|
| 168 | + reg &= ~HIBMC_CRT_DISP_CTL_TIMING_MASK; |
---|
| 169 | + if (dpms == HIBMC_CRT_DPMS_ON) |
---|
| 170 | + reg |= HIBMC_CRT_DISP_CTL_TIMING(1); |
---|
| 171 | + writel(reg, priv->mmio + HIBMC_CRT_DISP_CTL); |
---|
193 | 172 | } |
---|
194 | 173 | |
---|
195 | 174 | static void hibmc_crtc_atomic_enable(struct drm_crtc *crtc, |
---|
.. | .. |
---|
208 | 187 | reg |= HIBMC_CURR_GATE_DISPLAY(1); |
---|
209 | 188 | hibmc_set_current_gate(priv, reg); |
---|
210 | 189 | drm_crtc_vblank_on(crtc); |
---|
| 190 | + hibmc_crtc_dpms(crtc, HIBMC_CRT_DPMS_ON); |
---|
211 | 191 | } |
---|
212 | 192 | |
---|
213 | 193 | static void hibmc_crtc_atomic_disable(struct drm_crtc *crtc, |
---|
.. | .. |
---|
216 | 196 | unsigned int reg; |
---|
217 | 197 | struct hibmc_drm_private *priv = crtc->dev->dev_private; |
---|
218 | 198 | |
---|
| 199 | + hibmc_crtc_dpms(crtc, HIBMC_CRT_DPMS_OFF); |
---|
219 | 200 | drm_crtc_vblank_off(crtc); |
---|
220 | 201 | |
---|
221 | 202 | hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_SLEEP); |
---|
.. | .. |
---|
227 | 208 | reg |= HIBMC_CURR_GATE_LOCALMEM(0); |
---|
228 | 209 | reg |= HIBMC_CURR_GATE_DISPLAY(0); |
---|
229 | 210 | hibmc_set_current_gate(priv, reg); |
---|
| 211 | +} |
---|
| 212 | + |
---|
| 213 | +static enum drm_mode_status |
---|
| 214 | +hibmc_crtc_mode_valid(struct drm_crtc *crtc, |
---|
| 215 | + const struct drm_display_mode *mode) |
---|
| 216 | +{ |
---|
| 217 | + int i = 0; |
---|
| 218 | + int vrefresh = drm_mode_vrefresh(mode); |
---|
| 219 | + |
---|
| 220 | + if (vrefresh < 59 || vrefresh > 61) |
---|
| 221 | + return MODE_NOCLOCK; |
---|
| 222 | + |
---|
| 223 | + for (i = 0; i < ARRAY_SIZE(hibmc_pll_table); i++) { |
---|
| 224 | + if (hibmc_pll_table[i].hdisplay == mode->hdisplay && |
---|
| 225 | + hibmc_pll_table[i].vdisplay == mode->vdisplay) |
---|
| 226 | + return MODE_OK; |
---|
| 227 | + } |
---|
| 228 | + |
---|
| 229 | + return MODE_BAD; |
---|
230 | 230 | } |
---|
231 | 231 | |
---|
232 | 232 | static unsigned int format_pll_reg(void) |
---|
.. | .. |
---|
443 | 443 | priv->mmio + HIBMC_RAW_INTERRUPT_EN); |
---|
444 | 444 | } |
---|
445 | 445 | |
---|
| 446 | +static void hibmc_crtc_load_lut(struct drm_crtc *crtc) |
---|
| 447 | +{ |
---|
| 448 | + struct hibmc_drm_private *priv = crtc->dev->dev_private; |
---|
| 449 | + void __iomem *mmio = priv->mmio; |
---|
| 450 | + u16 *r, *g, *b; |
---|
| 451 | + unsigned int reg; |
---|
| 452 | + int i; |
---|
| 453 | + |
---|
| 454 | + r = crtc->gamma_store; |
---|
| 455 | + g = r + crtc->gamma_size; |
---|
| 456 | + b = g + crtc->gamma_size; |
---|
| 457 | + |
---|
| 458 | + for (i = 0; i < crtc->gamma_size; i++) { |
---|
| 459 | + unsigned int offset = i << 2; |
---|
| 460 | + u8 red = *r++ >> 8; |
---|
| 461 | + u8 green = *g++ >> 8; |
---|
| 462 | + u8 blue = *b++ >> 8; |
---|
| 463 | + u32 rgb = (red << 16) | (green << 8) | blue; |
---|
| 464 | + |
---|
| 465 | + writel(rgb, mmio + HIBMC_CRT_PALETTE + offset); |
---|
| 466 | + } |
---|
| 467 | + |
---|
| 468 | + reg = readl(priv->mmio + HIBMC_CRT_DISP_CTL); |
---|
| 469 | + reg |= HIBMC_FIELD(HIBMC_CTL_DISP_CTL_GAMMA, 1); |
---|
| 470 | + writel(reg, priv->mmio + HIBMC_CRT_DISP_CTL); |
---|
| 471 | +} |
---|
| 472 | + |
---|
| 473 | +static int hibmc_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, |
---|
| 474 | + u16 *blue, uint32_t size, |
---|
| 475 | + struct drm_modeset_acquire_ctx *ctx) |
---|
| 476 | +{ |
---|
| 477 | + hibmc_crtc_load_lut(crtc); |
---|
| 478 | + |
---|
| 479 | + return 0; |
---|
| 480 | +} |
---|
| 481 | + |
---|
446 | 482 | static const struct drm_crtc_funcs hibmc_crtc_funcs = { |
---|
447 | 483 | .page_flip = drm_atomic_helper_page_flip, |
---|
448 | 484 | .set_config = drm_atomic_helper_set_config, |
---|
.. | .. |
---|
452 | 488 | .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, |
---|
453 | 489 | .enable_vblank = hibmc_crtc_enable_vblank, |
---|
454 | 490 | .disable_vblank = hibmc_crtc_disable_vblank, |
---|
| 491 | + .gamma_set = hibmc_crtc_gamma_set, |
---|
455 | 492 | }; |
---|
456 | 493 | |
---|
457 | 494 | static const struct drm_crtc_helper_funcs hibmc_crtc_helper_funcs = { |
---|
.. | .. |
---|
460 | 497 | .atomic_flush = hibmc_crtc_atomic_flush, |
---|
461 | 498 | .atomic_enable = hibmc_crtc_atomic_enable, |
---|
462 | 499 | .atomic_disable = hibmc_crtc_atomic_disable, |
---|
| 500 | + .mode_valid = hibmc_crtc_mode_valid, |
---|
463 | 501 | }; |
---|
464 | 502 | |
---|
465 | 503 | int hibmc_de_init(struct hibmc_drm_private *priv) |
---|
466 | 504 | { |
---|
467 | 505 | struct drm_device *dev = priv->dev; |
---|
468 | | - struct drm_crtc *crtc; |
---|
469 | | - struct drm_plane *plane; |
---|
| 506 | + struct drm_crtc *crtc = &priv->crtc; |
---|
| 507 | + struct drm_plane *plane = &priv->primary_plane; |
---|
470 | 508 | int ret; |
---|
471 | 509 | |
---|
472 | | - plane = hibmc_plane_init(priv); |
---|
473 | | - if (IS_ERR(plane)) { |
---|
474 | | - DRM_ERROR("failed to create plane: %ld\n", PTR_ERR(plane)); |
---|
475 | | - return PTR_ERR(plane); |
---|
| 510 | + ret = drm_universal_plane_init(dev, plane, 1, &hibmc_plane_funcs, |
---|
| 511 | + channel_formats1, |
---|
| 512 | + ARRAY_SIZE(channel_formats1), |
---|
| 513 | + NULL, |
---|
| 514 | + DRM_PLANE_TYPE_PRIMARY, |
---|
| 515 | + NULL); |
---|
| 516 | + |
---|
| 517 | + if (ret) { |
---|
| 518 | + drm_err(dev, "failed to init plane: %d\n", ret); |
---|
| 519 | + return ret; |
---|
476 | 520 | } |
---|
477 | 521 | |
---|
478 | | - crtc = devm_kzalloc(dev->dev, sizeof(*crtc), GFP_KERNEL); |
---|
479 | | - if (!crtc) { |
---|
480 | | - DRM_ERROR("failed to alloc memory when init crtc\n"); |
---|
481 | | - return -ENOMEM; |
---|
482 | | - } |
---|
| 522 | + drm_plane_helper_add(plane, &hibmc_plane_helper_funcs); |
---|
483 | 523 | |
---|
484 | 524 | ret = drm_crtc_init_with_planes(dev, crtc, plane, |
---|
485 | 525 | NULL, &hibmc_crtc_funcs, NULL); |
---|
486 | 526 | if (ret) { |
---|
487 | | - DRM_ERROR("failed to init crtc: %d\n", ret); |
---|
| 527 | + drm_err(dev, "failed to init crtc: %d\n", ret); |
---|
488 | 528 | return ret; |
---|
489 | 529 | } |
---|
490 | 530 | |
---|
491 | 531 | ret = drm_mode_crtc_set_gamma_size(crtc, 256); |
---|
492 | 532 | if (ret) { |
---|
493 | | - DRM_ERROR("failed to set gamma size: %d\n", ret); |
---|
| 533 | + drm_err(dev, "failed to set gamma size: %d\n", ret); |
---|
494 | 534 | return ret; |
---|
495 | 535 | } |
---|
496 | 536 | drm_crtc_helper_add(crtc, &hibmc_crtc_helper_funcs); |
---|