.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2017 Samsung Electronics Co.Ltd |
---|
3 | 4 | * Author: |
---|
4 | | - * Andrzej Pietrasiewicz <andrzej.p@samsung.com> |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify |
---|
7 | | - * it under the terms of the GNU General Public License version 2 as |
---|
8 | | - * published by the Free Software Foundationr |
---|
| 5 | + * Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> |
---|
9 | 6 | */ |
---|
10 | 7 | |
---|
11 | | -#include <linux/kernel.h> |
---|
| 8 | +#include <linux/clk.h> |
---|
12 | 9 | #include <linux/component.h> |
---|
13 | 10 | #include <linux/err.h> |
---|
14 | 11 | #include <linux/interrupt.h> |
---|
15 | 12 | #include <linux/io.h> |
---|
16 | | -#include <linux/platform_device.h> |
---|
17 | | -#include <linux/clk.h> |
---|
| 13 | +#include <linux/kernel.h> |
---|
18 | 14 | #include <linux/of_device.h> |
---|
| 15 | +#include <linux/platform_device.h> |
---|
19 | 16 | #include <linux/pm_runtime.h> |
---|
20 | 17 | |
---|
21 | | -#include <drm/drmP.h> |
---|
| 18 | +#include <drm/drm_fourcc.h> |
---|
22 | 19 | #include <drm/exynos_drm.h> |
---|
23 | | -#include "regs-scaler.h" |
---|
24 | | -#include "exynos_drm_fb.h" |
---|
| 20 | + |
---|
25 | 21 | #include "exynos_drm_drv.h" |
---|
26 | | -#include "exynos_drm_iommu.h" |
---|
| 22 | +#include "exynos_drm_fb.h" |
---|
27 | 23 | #include "exynos_drm_ipp.h" |
---|
| 24 | +#include "regs-scaler.h" |
---|
28 | 25 | |
---|
29 | 26 | #define scaler_read(offset) readl(scaler->regs + (offset)) |
---|
30 | 27 | #define scaler_write(cfg, offset) writel(cfg, scaler->regs + (offset)) |
---|
.. | .. |
---|
42 | 39 | struct scaler_context { |
---|
43 | 40 | struct exynos_drm_ipp ipp; |
---|
44 | 41 | struct drm_device *drm_dev; |
---|
| 42 | + void *dma_priv; |
---|
45 | 43 | struct device *dev; |
---|
46 | 44 | void __iomem *regs; |
---|
47 | 45 | struct clk *clock[SCALER_MAX_CLK]; |
---|
.. | .. |
---|
49 | 47 | const struct scaler_data *scaler_data; |
---|
50 | 48 | }; |
---|
51 | 49 | |
---|
52 | | -static u32 scaler_get_format(u32 drm_fmt) |
---|
53 | | -{ |
---|
54 | | - switch (drm_fmt) { |
---|
55 | | - case DRM_FORMAT_NV12: |
---|
56 | | - return SCALER_YUV420_2P_UV; |
---|
57 | | - case DRM_FORMAT_NV21: |
---|
58 | | - return SCALER_YUV420_2P_VU; |
---|
59 | | - case DRM_FORMAT_YUV420: |
---|
60 | | - return SCALER_YUV420_3P; |
---|
61 | | - case DRM_FORMAT_YUYV: |
---|
62 | | - return SCALER_YUV422_1P_YUYV; |
---|
63 | | - case DRM_FORMAT_UYVY: |
---|
64 | | - return SCALER_YUV422_1P_UYVY; |
---|
65 | | - case DRM_FORMAT_YVYU: |
---|
66 | | - return SCALER_YUV422_1P_YVYU; |
---|
67 | | - case DRM_FORMAT_NV16: |
---|
68 | | - return SCALER_YUV422_2P_UV; |
---|
69 | | - case DRM_FORMAT_NV61: |
---|
70 | | - return SCALER_YUV422_2P_VU; |
---|
71 | | - case DRM_FORMAT_YUV422: |
---|
72 | | - return SCALER_YUV422_3P; |
---|
73 | | - case DRM_FORMAT_NV24: |
---|
74 | | - return SCALER_YUV444_2P_UV; |
---|
75 | | - case DRM_FORMAT_NV42: |
---|
76 | | - return SCALER_YUV444_2P_VU; |
---|
77 | | - case DRM_FORMAT_YUV444: |
---|
78 | | - return SCALER_YUV444_3P; |
---|
79 | | - case DRM_FORMAT_RGB565: |
---|
80 | | - return SCALER_RGB_565; |
---|
81 | | - case DRM_FORMAT_XRGB1555: |
---|
82 | | - return SCALER_ARGB1555; |
---|
83 | | - case DRM_FORMAT_ARGB1555: |
---|
84 | | - return SCALER_ARGB1555; |
---|
85 | | - case DRM_FORMAT_XRGB4444: |
---|
86 | | - return SCALER_ARGB4444; |
---|
87 | | - case DRM_FORMAT_ARGB4444: |
---|
88 | | - return SCALER_ARGB4444; |
---|
89 | | - case DRM_FORMAT_XRGB8888: |
---|
90 | | - return SCALER_ARGB8888; |
---|
91 | | - case DRM_FORMAT_ARGB8888: |
---|
92 | | - return SCALER_ARGB8888; |
---|
93 | | - case DRM_FORMAT_RGBX8888: |
---|
94 | | - return SCALER_RGBA8888; |
---|
95 | | - case DRM_FORMAT_RGBA8888: |
---|
96 | | - return SCALER_RGBA8888; |
---|
97 | | - default: |
---|
98 | | - break; |
---|
99 | | - } |
---|
| 50 | +struct scaler_format { |
---|
| 51 | + u32 drm_fmt; |
---|
| 52 | + u32 internal_fmt; |
---|
| 53 | + u32 chroma_tile_w; |
---|
| 54 | + u32 chroma_tile_h; |
---|
| 55 | +}; |
---|
100 | 56 | |
---|
101 | | - return 0; |
---|
| 57 | +static const struct scaler_format scaler_formats[] = { |
---|
| 58 | + { DRM_FORMAT_NV12, SCALER_YUV420_2P_UV, 8, 8 }, |
---|
| 59 | + { DRM_FORMAT_NV21, SCALER_YUV420_2P_VU, 8, 8 }, |
---|
| 60 | + { DRM_FORMAT_YUV420, SCALER_YUV420_3P, 8, 8 }, |
---|
| 61 | + { DRM_FORMAT_YUYV, SCALER_YUV422_1P_YUYV, 16, 16 }, |
---|
| 62 | + { DRM_FORMAT_UYVY, SCALER_YUV422_1P_UYVY, 16, 16 }, |
---|
| 63 | + { DRM_FORMAT_YVYU, SCALER_YUV422_1P_YVYU, 16, 16 }, |
---|
| 64 | + { DRM_FORMAT_NV16, SCALER_YUV422_2P_UV, 8, 16 }, |
---|
| 65 | + { DRM_FORMAT_NV61, SCALER_YUV422_2P_VU, 8, 16 }, |
---|
| 66 | + { DRM_FORMAT_YUV422, SCALER_YUV422_3P, 8, 16 }, |
---|
| 67 | + { DRM_FORMAT_NV24, SCALER_YUV444_2P_UV, 16, 16 }, |
---|
| 68 | + { DRM_FORMAT_NV42, SCALER_YUV444_2P_VU, 16, 16 }, |
---|
| 69 | + { DRM_FORMAT_YUV444, SCALER_YUV444_3P, 16, 16 }, |
---|
| 70 | + { DRM_FORMAT_RGB565, SCALER_RGB_565, 0, 0 }, |
---|
| 71 | + { DRM_FORMAT_XRGB1555, SCALER_ARGB1555, 0, 0 }, |
---|
| 72 | + { DRM_FORMAT_ARGB1555, SCALER_ARGB1555, 0, 0 }, |
---|
| 73 | + { DRM_FORMAT_XRGB4444, SCALER_ARGB4444, 0, 0 }, |
---|
| 74 | + { DRM_FORMAT_ARGB4444, SCALER_ARGB4444, 0, 0 }, |
---|
| 75 | + { DRM_FORMAT_XRGB8888, SCALER_ARGB8888, 0, 0 }, |
---|
| 76 | + { DRM_FORMAT_ARGB8888, SCALER_ARGB8888, 0, 0 }, |
---|
| 77 | + { DRM_FORMAT_RGBX8888, SCALER_RGBA8888, 0, 0 }, |
---|
| 78 | + { DRM_FORMAT_RGBA8888, SCALER_RGBA8888, 0, 0 }, |
---|
| 79 | +}; |
---|
| 80 | + |
---|
| 81 | +static const struct scaler_format *scaler_get_format(u32 drm_fmt) |
---|
| 82 | +{ |
---|
| 83 | + int i; |
---|
| 84 | + |
---|
| 85 | + for (i = 0; i < ARRAY_SIZE(scaler_formats); i++) |
---|
| 86 | + if (scaler_formats[i].drm_fmt == drm_fmt) |
---|
| 87 | + return &scaler_formats[i]; |
---|
| 88 | + |
---|
| 89 | + return NULL; |
---|
102 | 90 | } |
---|
103 | 91 | |
---|
104 | 92 | static inline int scaler_reset(struct scaler_context *scaler) |
---|
.. | .. |
---|
152 | 140 | } |
---|
153 | 141 | |
---|
154 | 142 | static inline void scaler_set_src_fmt(struct scaler_context *scaler, |
---|
155 | | - u32 src_fmt) |
---|
| 143 | + u32 src_fmt, u32 tile) |
---|
156 | 144 | { |
---|
157 | 145 | u32 val; |
---|
158 | 146 | |
---|
159 | | - val = SCALER_SRC_CFG_SET_COLOR_FORMAT(src_fmt); |
---|
| 147 | + val = SCALER_SRC_CFG_SET_COLOR_FORMAT(src_fmt) | (tile << 10); |
---|
160 | 148 | scaler_write(val, SCALER_SRC_CFG); |
---|
161 | 149 | } |
---|
162 | 150 | |
---|
.. | .. |
---|
188 | 176 | scaler_write(val, SCALER_SRC_SPAN); |
---|
189 | 177 | } |
---|
190 | 178 | |
---|
191 | | -static inline void scaler_set_src_luma_pos(struct scaler_context *scaler, |
---|
192 | | - struct drm_exynos_ipp_task_rect *src_pos) |
---|
| 179 | +static inline void scaler_set_src_luma_chroma_pos(struct scaler_context *scaler, |
---|
| 180 | + struct drm_exynos_ipp_task_rect *src_pos, |
---|
| 181 | + const struct scaler_format *fmt) |
---|
193 | 182 | { |
---|
194 | 183 | u32 val; |
---|
195 | 184 | |
---|
196 | 185 | val = SCALER_SRC_Y_POS_SET_YH_POS(src_pos->x << 2); |
---|
197 | 186 | val |= SCALER_SRC_Y_POS_SET_YV_POS(src_pos->y << 2); |
---|
198 | 187 | scaler_write(val, SCALER_SRC_Y_POS); |
---|
199 | | - scaler_write(val, SCALER_SRC_C_POS); /* ATTENTION! */ |
---|
| 188 | + val = SCALER_SRC_C_POS_SET_CH_POS( |
---|
| 189 | + (src_pos->x * fmt->chroma_tile_w / 16) << 2); |
---|
| 190 | + val |= SCALER_SRC_C_POS_SET_CV_POS( |
---|
| 191 | + (src_pos->y * fmt->chroma_tile_h / 16) << 2); |
---|
| 192 | + scaler_write(val, SCALER_SRC_C_POS); |
---|
200 | 193 | } |
---|
201 | 194 | |
---|
202 | 195 | static inline void scaler_set_src_wh(struct scaler_context *scaler, |
---|
.. | .. |
---|
366 | 359 | struct scaler_context *scaler = |
---|
367 | 360 | container_of(ipp, struct scaler_context, ipp); |
---|
368 | 361 | |
---|
369 | | - u32 src_fmt = scaler_get_format(task->src.buf.fourcc); |
---|
370 | 362 | struct drm_exynos_ipp_task_rect *src_pos = &task->src.rect; |
---|
371 | | - |
---|
372 | | - u32 dst_fmt = scaler_get_format(task->dst.buf.fourcc); |
---|
373 | 363 | struct drm_exynos_ipp_task_rect *dst_pos = &task->dst.rect; |
---|
| 364 | + const struct scaler_format *src_fmt, *dst_fmt; |
---|
| 365 | + |
---|
| 366 | + src_fmt = scaler_get_format(task->src.buf.fourcc); |
---|
| 367 | + dst_fmt = scaler_get_format(task->dst.buf.fourcc); |
---|
374 | 368 | |
---|
375 | 369 | pm_runtime_get_sync(scaler->dev); |
---|
376 | 370 | if (scaler_reset(scaler)) { |
---|
.. | .. |
---|
380 | 374 | |
---|
381 | 375 | scaler->task = task; |
---|
382 | 376 | |
---|
383 | | - scaler_set_src_fmt(scaler, src_fmt); |
---|
| 377 | + scaler_set_src_fmt( |
---|
| 378 | + scaler, src_fmt->internal_fmt, task->src.buf.modifier != 0); |
---|
384 | 379 | scaler_set_src_base(scaler, &task->src); |
---|
385 | 380 | scaler_set_src_span(scaler, &task->src); |
---|
386 | | - scaler_set_src_luma_pos(scaler, src_pos); |
---|
| 381 | + scaler_set_src_luma_chroma_pos(scaler, src_pos, src_fmt); |
---|
387 | 382 | scaler_set_src_wh(scaler, src_pos); |
---|
388 | 383 | |
---|
389 | | - scaler_set_dst_fmt(scaler, dst_fmt); |
---|
| 384 | + scaler_set_dst_fmt(scaler, dst_fmt->internal_fmt); |
---|
390 | 385 | scaler_set_dst_base(scaler, &task->dst); |
---|
391 | 386 | scaler_set_dst_span(scaler, &task->dst); |
---|
392 | 387 | scaler_set_dst_luma_pos(scaler, dst_pos); |
---|
.. | .. |
---|
455 | 450 | struct exynos_drm_ipp *ipp = &scaler->ipp; |
---|
456 | 451 | |
---|
457 | 452 | scaler->drm_dev = drm_dev; |
---|
458 | | - drm_iommu_attach_device(drm_dev, dev); |
---|
| 453 | + ipp->drm_dev = drm_dev; |
---|
| 454 | + exynos_drm_register_dma(drm_dev, dev, &scaler->dma_priv); |
---|
459 | 455 | |
---|
460 | | - exynos_drm_ipp_register(drm_dev, ipp, &ipp_funcs, |
---|
| 456 | + exynos_drm_ipp_register(dev, ipp, &ipp_funcs, |
---|
461 | 457 | DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE | |
---|
462 | 458 | DRM_EXYNOS_IPP_CAP_SCALE | DRM_EXYNOS_IPP_CAP_CONVERT, |
---|
463 | 459 | scaler->scaler_data->formats, |
---|
.. | .. |
---|
472 | 468 | void *data) |
---|
473 | 469 | { |
---|
474 | 470 | struct scaler_context *scaler = dev_get_drvdata(dev); |
---|
475 | | - struct drm_device *drm_dev = data; |
---|
476 | 471 | struct exynos_drm_ipp *ipp = &scaler->ipp; |
---|
477 | 472 | |
---|
478 | | - exynos_drm_ipp_unregister(drm_dev, ipp); |
---|
479 | | - drm_iommu_detach_device(scaler->drm_dev, scaler->dev); |
---|
| 473 | + exynos_drm_ipp_unregister(dev, ipp); |
---|
| 474 | + exynos_drm_unregister_dma(scaler->drm_dev, scaler->dev, |
---|
| 475 | + &scaler->dma_priv); |
---|
480 | 476 | } |
---|
481 | 477 | |
---|
482 | 478 | static const struct component_ops scaler_component_ops = { |
---|
.. | .. |
---|
506 | 502 | return PTR_ERR(scaler->regs); |
---|
507 | 503 | |
---|
508 | 504 | irq = platform_get_irq(pdev, 0); |
---|
509 | | - if (irq < 0) { |
---|
510 | | - dev_err(dev, "failed to get irq\n"); |
---|
| 505 | + if (irq < 0) |
---|
511 | 506 | return irq; |
---|
512 | | - } |
---|
513 | 507 | |
---|
514 | 508 | ret = devm_request_threaded_irq(dev, irq, NULL, scaler_irq_handler, |
---|
515 | 509 | IRQF_ONESHOT, "drm_scaler", scaler); |
---|
.. | .. |
---|
617 | 611 | .v = { 65536 * 1 / 4, 65536 * 16 }) }, |
---|
618 | 612 | }; |
---|
619 | 613 | |
---|
| 614 | +static const struct drm_exynos_ipp_limit scaler_5420_tile_limits[] = { |
---|
| 615 | + { IPP_SIZE_LIMIT(BUFFER, .h = { 16, SZ_8K }, .v = { 16, SZ_8K })}, |
---|
| 616 | + { IPP_SIZE_LIMIT(AREA, .h.align = 16, .v.align = 16) }, |
---|
| 617 | + { IPP_SCALE_LIMIT(.h = {1, 1}, .v = {1, 1})}, |
---|
| 618 | + { } |
---|
| 619 | +}; |
---|
| 620 | + |
---|
| 621 | +#define IPP_SRCDST_TILE_FORMAT(f, l) \ |
---|
| 622 | + IPP_SRCDST_MFORMAT(f, DRM_FORMAT_MOD_SAMSUNG_16_16_TILE, (l)) |
---|
| 623 | + |
---|
620 | 624 | static const struct exynos_drm_ipp_formats exynos5420_formats[] = { |
---|
621 | 625 | /* SCALER_YUV420_2P_UV */ |
---|
622 | 626 | { IPP_SRCDST_FORMAT(NV21, scaler_5420_two_pixel_hv_limits) }, |
---|
.. | .. |
---|
680 | 684 | |
---|
681 | 685 | /* SCALER_RGBA8888 */ |
---|
682 | 686 | { IPP_SRCDST_FORMAT(RGBA8888, scaler_5420_one_pixel_limits) }, |
---|
| 687 | + |
---|
| 688 | + /* SCALER_YUV420_2P_UV TILE */ |
---|
| 689 | + { IPP_SRCDST_TILE_FORMAT(NV21, scaler_5420_tile_limits) }, |
---|
| 690 | + |
---|
| 691 | + /* SCALER_YUV420_2P_VU TILE */ |
---|
| 692 | + { IPP_SRCDST_TILE_FORMAT(NV12, scaler_5420_tile_limits) }, |
---|
| 693 | + |
---|
| 694 | + /* SCALER_YUV420_3P TILE */ |
---|
| 695 | + { IPP_SRCDST_TILE_FORMAT(YUV420, scaler_5420_tile_limits) }, |
---|
| 696 | + |
---|
| 697 | + /* SCALER_YUV422_1P_YUYV TILE */ |
---|
| 698 | + { IPP_SRCDST_TILE_FORMAT(YUYV, scaler_5420_tile_limits) }, |
---|
683 | 699 | }; |
---|
684 | 700 | |
---|
685 | 701 | static const struct scaler_data exynos5420_data = { |
---|