History

Merge tag 'exynos-drm-next-for-v4.18' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next

- Add S5PV210 FIMD variant support. - Add IPP v2 framework. . it is a rewritten version of the Exynos mem-to-mem image processing framework which supprts color space conversion, image up/down-scaling and rotation. This new version replaces existing userspace API with new easy-to-use and simple ones so we have already applied the use of these API to real user, Tizen Platform[1], and also makes existing Scaler, FIMC, GScaler and Rotator drivers to use IPP v2 core API. And below are patch lists we have applied to a real user, https://git.tizen.org/cgit/platform/adaptation/samsung_exynos/libtdm-exynos/log/?h=tizen&qt=grep&q=ipp https://git.tizen.org/cgit/platform/adaptation/samsung_exynos/libtdm-exynos/commit/?h=tizen&id=b59be207365d10efd489e6f71c8a045b558c44fe https://git.tizen.org/cgit/platform/kernel/linux-exynos/log/?h=tizen&qt=grep&q=ipp TDM(Tizen Display Manager) is a Display HAL for Tizen platform. Ps. Only real user using IPP API is Tizen. [1] https://www.tizen.org/ - Two cleanups . One is to just remove mode_set callback from MIPI-DSI driver because drm_display_mode data is already available from crtc atomic state. . And other is to just use new return type, vm_fault_t for page fault handler. Signed-off-by: Dave Airlie <airlied@redhat.com> # gpg: Signature made Mon 14 May 2018 14:23:53 AEST # gpg: using RSA key 573834890C4312B8 # gpg: Can't check signature: public key not found Link: https://patchwork.freedesktop.org/patch/msgid/1526276453-29879-1-git-send-email-inki.dae@samsung.com

Dave Airlie committed 8 years ago

Commit 444ac872 parents ba72385 e89299927 files · +3520 −2176Browse files

Unified · Split

27 files
  1. Documentation/devicetree/bindings/gpu/samsung-scaler.txt +27 −0
  2. drivers/gpu/drm/bridge/dumb-vga-dac.c +3 −1
  3. drivers/gpu/drm/exynos/Kconfig +14 −4
  4. drivers/gpu/drm/exynos/Makefile +2 −0
  5. drivers/gpu/drm/exynos/exynos_drm_drv.c +32 −3
  6. drivers/gpu/drm/exynos/exynos_drm_drv.h +10 −0
  7. drivers/gpu/drm/exynos/exynos_drm_dsi.c +10 −30
  8. drivers/gpu/drm/exynos/exynos_drm_fimc.c +349 −731
  9. drivers/gpu/drm/exynos/exynos_drm_fimc.h +0 −23
  10. drivers/gpu/drm/exynos/exynos_drm_fimd.c +8 −0
  11. drivers/gpu/drm/exynos/exynos_drm_gem.c +4 −17
  12. drivers/gpu/drm/exynos/exynos_drm_gem.h +2 −1
  13. drivers/gpu/drm/exynos/exynos_drm_gsc.c +335 −740
  14. drivers/gpu/drm/exynos/exynos_drm_gsc.h +0 −24
  15. drivers/gpu/drm/exynos/exynos_drm_ipp.c +916 −0
  16. drivers/gpu/drm/exynos/exynos_drm_ipp.h +175 −0
  17. drivers/gpu/drm/exynos/exynos_drm_rotator.c +188 −570
  18. drivers/gpu/drm/exynos/exynos_drm_scaler.c +694 −0
  19. drivers/gpu/drm/exynos/exynos_hdmi.c +0 −2
  20. drivers/gpu/drm/exynos/exynos_mixer.c +17 −5
  21. drivers/gpu/drm/exynos/regs-mixer.h +1 −0
  22. drivers/gpu/drm/exynos/regs-scaler.h +426 −0
  23. drivers/gpu/drm/i915/intel_csr.c +1 −0
  24. drivers/gpu/drm/vc4/vc4_crtc.c +45 −1
  25. drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +10 −21
  26. drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +11 −3
  27. include/uapi/drm/exynos_drm.h +240 −0
Documentation/devicetree/bindings/gpu/samsung-scaler.txt+27−0
@@ -0,0 +1,27 @@
1+* Samsung Exynos Image Scaler
2+
3+Required properties:
4+ - compatible : value should be one of the following:
5+ (a) "samsung,exynos5420-scaler" for Scaler IP in Exynos5420
6+ (b) "samsung,exynos5433-scaler" for Scaler IP in Exynos5433
7+
8+ - reg : Physical base address of the IP registers and length of memory
9+ mapped region.
10+
11+ - interrupts : Interrupt specifier for scaler interrupt, according to format
12+ specific to interrupt parent.
13+
14+ - clocks : Clock specifier for scaler clock, according to generic clock
15+ bindings. (See Documentation/devicetree/bindings/clock/exynos*.txt)
16+
17+ - clock-names : Names of clocks. For exynos scaler, it should be "mscl"
18+ on 5420 and "pclk", "aclk" and "aclk_xiu" on 5433.
19+
20+Example:
21+ scaler@12800000 {
22+ compatible = "samsung,exynos5420-scaler";
23+ reg = <0x12800000 0x1294>;
24+ interrupts = <0 220 IRQ_TYPE_LEVEL_HIGH>;
25+ clocks = <&clock CLK_MSCL0>;
26+ clock-names = "mscl";
27+ };
drivers/gpu/drm/bridge/dumb-vga-dac.c+3−1
@@ -56,7 +56,9 @@ static int dumb_vga_get_modes(struct drm_connector *connector) · 55 unmodified lines
5656 }
5757
5858 drm_mode_connector_update_edid_property(connector, edid);
59− return drm_add_edid_modes(connector, edid);
59+ ret = drm_add_edid_modes(connector, edid);
60+ kfree(edid);
61+ return ret;
6062
6163 fallback:
6264 /*
drivers/gpu/drm/exynos/Kconfig+14−4
@@ -1,6 +1,6 @@
11 config DRM_EXYNOS
22 tristate "DRM Support for Samsung SoC EXYNOS Series"
3− depends on OF && DRM && (ARCH_S3C64XX || ARCH_EXYNOS || ARCH_MULTIPLATFORM)
3+ depends on OF && DRM && (ARCH_S3C64XX || ARCH_S5PV210 || ARCH_EXYNOS || ARCH_MULTIPLATFORM)
44 select DRM_KMS_HELPER
55 select VIDEOMODE_HELPERS
66 select SND_SOC_HDMI_CODEC if SND_SOC
@@ -95,21 +95,31 @@ config DRM_EXYNOS_G2D · 88 unmodified lines
9595 help
9696 Choose this option if you want to use Exynos G2D for DRM.
9797
98+config DRM_EXYNOS_IPP
99+ bool
100+
98101 config DRM_EXYNOS_FIMC
99102 bool "FIMC"
100− depends on BROKEN && MFD_SYSCON
103+ select DRM_EXYNOS_IPP
101104 help
102105 Choose this option if you want to use Exynos FIMC for DRM.
103106
104107 config DRM_EXYNOS_ROTATOR
105108 bool "Rotator"
106− depends on BROKEN
109+ select DRM_EXYNOS_IPP
107110 help
108111 Choose this option if you want to use Exynos Rotator for DRM.
109112
113+config DRM_EXYNOS_SCALER
114+ bool "Scaler"
115+ select DRM_EXYNOS_IPP
116+ help
117+ Choose this option if you want to use Exynos Scaler for DRM.
118+
110119 config DRM_EXYNOS_GSC
111120 bool "GScaler"
112− depends on BROKEN && ARCH_EXYNOS5 && VIDEO_SAMSUNG_EXYNOS_GSC=n
121+ depends on VIDEO_SAMSUNG_EXYNOS_GSC=n
122+ select DRM_EXYNOS_IPP
113123 help
114124 Choose this option if you want to use Exynos GSC for DRM.
115125
drivers/gpu/drm/exynos/Makefile+2−0
@@ -18,8 +18,10 @@ exynosdrm-$(CONFIG_DRM_EXYNOS_MIXER) += exynos_mixer.o · 17 unmodified lines
1818 exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o
1919 exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI) += exynos_drm_vidi.o
2020 exynosdrm-$(CONFIG_DRM_EXYNOS_G2D) += exynos_drm_g2d.o
21+exynosdrm-$(CONFIG_DRM_EXYNOS_IPP) += exynos_drm_ipp.o
2122 exynosdrm-$(CONFIG_DRM_EXYNOS_FIMC) += exynos_drm_fimc.o
2223 exynosdrm-$(CONFIG_DRM_EXYNOS_ROTATOR) += exynos_drm_rotator.o
24+exynosdrm-$(CONFIG_DRM_EXYNOS_SCALER) += exynos_drm_scaler.o
2325 exynosdrm-$(CONFIG_DRM_EXYNOS_GSC) += exynos_drm_gsc.o
2426 exynosdrm-$(CONFIG_DRM_EXYNOS_MIC) += exynos_drm_mic.o
2527
drivers/gpu/drm/exynos/exynos_drm_drv.c+32−3
@@ -27,15 +27,23 @@ · 26 unmodified lines
2727 #include "exynos_drm_fb.h"
2828 #include "exynos_drm_gem.h"
2929 #include "exynos_drm_plane.h"
30+#include "exynos_drm_ipp.h"
3031 #include "exynos_drm_vidi.h"
3132 #include "exynos_drm_g2d.h"
3233 #include "exynos_drm_iommu.h"
3334
3435 #define DRIVER_NAME "exynos"
3536 #define DRIVER_DESC "Samsung SoC DRM"
36−#define DRIVER_DATE "20110530"
37+#define DRIVER_DATE "20180330"
38+
39+/*
40+ * Interface history:
41+ *
42+ * 1.0 - Original version
43+ * 1.1 - Upgrade IPP driver to version 2.0
44+ */
3745 #define DRIVER_MAJOR 1
38−#define DRIVER_MINOR 0
46+#define DRIVER_MINOR 1
3947
4048 static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
4149 {
@@ -88,6 +96,16 @@ static const struct drm_ioctl_desc exynos_ioctls[] = { · 46 unmodified lines
8896 DRM_AUTH | DRM_RENDER_ALLOW),
8997 DRM_IOCTL_DEF_DRV(EXYNOS_G2D_EXEC, exynos_g2d_exec_ioctl,
9098 DRM_AUTH | DRM_RENDER_ALLOW),
99+ DRM_IOCTL_DEF_DRV(EXYNOS_IPP_GET_RESOURCES,
100+ exynos_drm_ipp_get_res_ioctl,
101+ DRM_AUTH | DRM_RENDER_ALLOW),
102+ DRM_IOCTL_DEF_DRV(EXYNOS_IPP_GET_CAPS, exynos_drm_ipp_get_caps_ioctl,
103+ DRM_AUTH | DRM_RENDER_ALLOW),
104+ DRM_IOCTL_DEF_DRV(EXYNOS_IPP_GET_LIMITS,
105+ exynos_drm_ipp_get_limits_ioctl,
106+ DRM_AUTH | DRM_RENDER_ALLOW),
107+ DRM_IOCTL_DEF_DRV(EXYNOS_IPP_COMMIT, exynos_drm_ipp_commit_ioctl,
108+ DRM_AUTH | DRM_RENDER_ALLOW),
91109 };
92110
93111 static const struct file_operations exynos_drm_driver_fops = {
@@ -184,6 +202,7 @@ struct exynos_drm_driver_info { · 90 unmodified lines
184202 #define DRM_COMPONENT_DRIVER BIT(0) /* supports component framework */
185203 #define DRM_VIRTUAL_DEVICE BIT(1) /* create virtual platform device */
186204 #define DRM_DMA_DEVICE BIT(2) /* can be used for dma allocations */
205+#define DRM_FIMC_DEVICE BIT(3) /* devices shared with V4L2 subsystem */
187206
188207 #define DRV_PTR(drv, cond) (IS_ENABLED(cond) ? &drv : NULL)
189208
@@ -223,10 +242,16 @@ static struct exynos_drm_driver_info exynos_drm_drivers[] = { · 33 unmodified lines
223242 DRV_PTR(g2d_driver, CONFIG_DRM_EXYNOS_G2D),
224243 }, {
225244 DRV_PTR(fimc_driver, CONFIG_DRM_EXYNOS_FIMC),
245+ DRM_COMPONENT_DRIVER | DRM_FIMC_DEVICE,
226246 }, {
227247 DRV_PTR(rotator_driver, CONFIG_DRM_EXYNOS_ROTATOR),
248+ DRM_COMPONENT_DRIVER
249+ }, {
250+ DRV_PTR(scaler_driver, CONFIG_DRM_EXYNOS_SCALER),
251+ DRM_COMPONENT_DRIVER
228252 }, {
229253 DRV_PTR(gsc_driver, CONFIG_DRM_EXYNOS_GSC),
254+ DRM_COMPONENT_DRIVER
230255 }, {
231256 &exynos_drm_platform_driver,
232257 DRM_VIRTUAL_DEVICE
@@ -254,7 +279,11 @@ static struct component_match *exynos_drm_match_add(struct device *dev) · 21 unmodified lines
254279 &info->driver->driver,
255280 (void *)platform_bus_type.match))) {
256281 put_device(p);
257− component_match_add(dev, &match, compare_dev, d);
282+
283+ if (!(info->flags & DRM_FIMC_DEVICE) ||
284+ exynos_drm_check_fimc_device(d) == 0)
285+ component_match_add(dev, &match,
286+ compare_dev, d);
258287 p = d;
259288 }
260289 put_device(p);
drivers/gpu/drm/exynos/exynos_drm_drv.h+10−0
@@ -273,6 +273,15 @@ static inline int exynos_dpi_bind(struct drm_device *dev, · 272 unmodified lines
273273 }
274274 #endif
275275
276+#ifdef CONFIG_DRM_EXYNOS_FIMC
277+int exynos_drm_check_fimc_device(struct device *dev);
278+#else
279+static inline int exynos_drm_check_fimc_device(struct device *dev)
280+{
281+ return 0;
282+}
283+#endif
284+
276285 int exynos_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state,
277286 bool nonblock);
278287
@@ -288,6 +297,7 @@ extern struct platform_driver vidi_driver; · 9 unmodified lines
288297 extern struct platform_driver g2d_driver;
289298 extern struct platform_driver fimc_driver;
290299 extern struct platform_driver rotator_driver;
300+extern struct platform_driver scaler_driver;
291301 extern struct platform_driver gsc_driver;
292302 extern struct platform_driver mic_driver;
293303 #endif
drivers/gpu/drm/exynos/exynos_drm_dsi.c+10−30
@@ -270,7 +270,6 @@ struct exynos_dsi { · 269 unmodified lines
270270 u32 lanes;
271271 u32 mode_flags;
272272 u32 format;
273− struct videomode vm;
274273
275274 int state;
276275 struct drm_property *brightness;
@@ -881,30 +880,30 @@ static int exynos_dsi_init_link(struct exynos_dsi *dsi) · 604 unmodified lines
881880
882881 static void exynos_dsi_set_display_mode(struct exynos_dsi *dsi)
883882 {
884− struct videomode *vm = &dsi->vm;
883+ struct drm_display_mode *m = &dsi->encoder.crtc->state->adjusted_mode;
885884 unsigned int num_bits_resol = dsi->driver_data->num_bits_resol;
886885 u32 reg;
887886
888887 if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
889888 reg = DSIM_CMD_ALLOW(0xf)
890− | DSIM_STABLE_VFP(vm->vfront_porch)
891− | DSIM_MAIN_VBP(vm->vback_porch);
889+ | DSIM_STABLE_VFP(m->vsync_start - m->vdisplay)
890+ | DSIM_MAIN_VBP(m->vtotal - m->vsync_end);
892891 exynos_dsi_write(dsi, DSIM_MVPORCH_REG, reg);
893892
894− reg = DSIM_MAIN_HFP(vm->hfront_porch)
895− | DSIM_MAIN_HBP(vm->hback_porch);
893+ reg = DSIM_MAIN_HFP(m->hsync_start - m->hdisplay)
894+ | DSIM_MAIN_HBP(m->htotal - m->hsync_end);
896895 exynos_dsi_write(dsi, DSIM_MHPORCH_REG, reg);
897896
898− reg = DSIM_MAIN_VSA(vm->vsync_len)
899− | DSIM_MAIN_HSA(vm->hsync_len);
897+ reg = DSIM_MAIN_VSA(m->vsync_end - m->vsync_start)
898+ | DSIM_MAIN_HSA(m->hsync_end - m->hsync_start);
900899 exynos_dsi_write(dsi, DSIM_MSYNC_REG, reg);
901900 }
902− reg = DSIM_MAIN_HRESOL(vm->hactive, num_bits_resol) |
903− DSIM_MAIN_VRESOL(vm->vactive, num_bits_resol);
901+ reg = DSIM_MAIN_HRESOL(m->hdisplay, num_bits_resol) |
902+ DSIM_MAIN_VRESOL(m->vdisplay, num_bits_resol);
904903
905904 exynos_dsi_write(dsi, DSIM_MDRESOL_REG, reg);
906905
907− dev_dbg(dsi->dev, "LCD size = %dx%d\n", vm->hactive, vm->vactive);
906+ dev_dbg(dsi->dev, "LCD size = %dx%d\n", m->hdisplay, m->vdisplay);
908907 }
909908
910909 static void exynos_dsi_set_display_enable(struct exynos_dsi *dsi, bool enable)
@@ -1485,26 +1484,7 @@ static int exynos_dsi_create_connector(struct drm_encoder *encoder) · 574 unmodified lines
14851484 return 0;
14861485 }
14871486
1488−static void exynos_dsi_mode_set(struct drm_encoder *encoder,
1489− struct drm_display_mode *mode,
1490− struct drm_display_mode *adjusted_mode)
1491−{
1492− struct exynos_dsi *dsi = encoder_to_dsi(encoder);
1493− struct videomode *vm = &dsi->vm;
1494− struct drm_display_mode *m = adjusted_mode;
1495−
1496− vm->hactive = m->hdisplay;
1497− vm->vactive = m->vdisplay;
1498− vm->vfront_porch = m->vsync_start - m->vdisplay;
1499− vm->vback_porch = m->vtotal - m->vsync_end;
1500− vm->vsync_len = m->vsync_end - m->vsync_start;
1501− vm->hfront_porch = m->hsync_start - m->hdisplay;
1502− vm->hback_porch = m->htotal - m->hsync_end;
1503− vm->hsync_len = m->hsync_end - m->hsync_start;
1504−}
1505−
15061487 static const struct drm_encoder_helper_funcs exynos_dsi_encoder_helper_funcs = {
1507− .mode_set = exynos_dsi_mode_set,
15081488 .enable = exynos_dsi_enable,
15091489 .disable = exynos_dsi_disable,
15101490 };
drivers/gpu/drm/exynos/exynos_drm_fimc.c+349−731
@@ -12,6 +12,7 @@ · 11 unmodified lines
1212 *
1313 */
1414 #include <linux/kernel.h>
15+#include <linux/component.h>
1516 #include <linux/platform_device.h>
1617 #include <linux/mfd/syscon.h>
1718 #include <linux/regmap.h>
@@ -24,8 +25,8 @@ · 6 unmodified lines
2425 #include <drm/exynos_drm.h>
2526 #include "regs-fimc.h"
2627 #include "exynos_drm_drv.h"
28+#include "exynos_drm_iommu.h"
2729 #include "exynos_drm_ipp.h"
28−#include "exynos_drm_fimc.h"
2930
3031 /*
3132 * FIMC stands for Fully Interactive Mobile Camera and
@@ -33,23 +34,6 @@ · 1 unmodified line
3334 * input DMA reads image data from the memory.
3435 * output DMA writes image data to memory.
3536 * FIMC supports image rotation and image effect functions.
36− *
37− * M2M operation : supports crop/scale/rotation/csc so on.
38− * Memory ----> FIMC H/W ----> Memory.
39− * Writeback operation : supports cloned screen with FIMD.
40− * FIMD ----> FIMC H/W ----> Memory.
41− * Output operation : supports direct display using local path.
42− * Memory ----> FIMC H/W ----> FIMD.
43− */
44−
45−/*
46− * TODO
47− * 1. check suspend/resume api if needed.
48− * 2. need to check use case platform_device_id.
49− * 3. check src/dst size with, height.
50− * 4. added check_prepare api for right register.
51− * 5. need to add supported list in prop_list.
52− * 6. check prescaler/scaler optimization.
5337 */
5438
5539 #define FIMC_MAX_DEVS 4
@@ -59,29 +43,19 @@ · 3 unmodified lines
5943 #define FIMC_BUF_STOP 1
6044 #define FIMC_BUF_START 2
6145 #define FIMC_WIDTH_ITU_709 1280
62−#define FIMC_REFRESH_MAX 60
63−#define FIMC_REFRESH_MIN 12
64−#define FIMC_CROP_MAX 8192
65−#define FIMC_CROP_MIN 32
66−#define FIMC_SCALE_MAX 4224
67−#define FIMC_SCALE_MIN 32
46+#define FIMC_AUTOSUSPEND_DELAY 2000
47+
48+static unsigned int fimc_mask = 0xc;
49+module_param_named(fimc_devs, fimc_mask, uint, 0644);
50+MODULE_PARM_DESC(fimc_devs, "Alias mask for assigning FIMC devices to Exynos DRM");
6851
6952 #define get_fimc_context(dev) platform_get_drvdata(to_platform_device(dev))
70−#define get_ctx_from_ippdrv(ippdrv) container_of(ippdrv,\
71− struct fimc_context, ippdrv);
72−enum fimc_wb {
73− FIMC_WB_NONE,
74− FIMC_WB_A,
75− FIMC_WB_B,
76−};
7753
7854 enum {
7955 FIMC_CLK_LCLK,
8056 FIMC_CLK_GATE,
8157 FIMC_CLK_WB_A,
8258 FIMC_CLK_WB_B,
83− FIMC_CLK_MUX,
84− FIMC_CLK_PARENT,
8559 FIMC_CLKS_MAX
8660 };
8761
@@ -90,12 +64,8 @@ static const char * const fimc_clock_names[] = { · 2 unmodified lines
9064 [FIMC_CLK_GATE] = "fimc",
9165 [FIMC_CLK_WB_A] = "pxl_async0",
9266 [FIMC_CLK_WB_B] = "pxl_async1",
93− [FIMC_CLK_MUX] = "mux",
94− [FIMC_CLK_PARENT] = "parent",
9567 };
9668
97−#define FIMC_DEFAULT_LCLK_FREQUENCY 133000000UL
98−
9969 /*
10070 * A structure of scaler.
10171 *
@@ -107,7 +77,7 @@ static const char * const fimc_clock_names[] = { · 5 unmodified lines
10777 * @vratio: vertical ratio.
10878 */
10979 struct fimc_scaler {
110− bool range;
80+ bool range;
11181 bool bypass;
11282 bool up_h;
11383 bool up_v;
@@ -115,57 +85,33 @@ struct fimc_scaler { · 1 unmodified line
11585 u32 vratio;
11686 };
11787
118−/*
119− * A structure of scaler capability.
120− *
121− * find user manual table 43-1.
122− * @in_hori: scaler input horizontal size.
123− * @bypass: scaler bypass mode.
124− * @dst_h_wo_rot: target horizontal size without output rotation.
125− * @dst_h_rot: target horizontal size with output rotation.
126− * @rl_w_wo_rot: real width without input rotation.
127− * @rl_h_rot: real height without output rotation.
128− */
129−struct fimc_capability {
130− /* scaler */
131− u32 in_hori;
132− u32 bypass;
133− /* output rotator */
134− u32 dst_h_wo_rot;
135− u32 dst_h_rot;
136− /* input rotator */
137− u32 rl_w_wo_rot;
138− u32 rl_h_rot;
139−};
140−
14188 /*
14289 * A structure of fimc context.
14390 *
144− * @ippdrv: prepare initialization using ippdrv.
14591 * @regs_res: register resources.
14692 * @regs: memory mapped io registers.
14793 * @lock: locking of operations.
14894 * @clocks: fimc clocks.
149− * @clk_frequency: LCLK clock frequency.
150− * @sysreg: handle to SYSREG block regmap.
15195 * @sc: scaler infomations.
15296 * @pol: porarity of writeback.
15397 * @id: fimc id.
15498 * @irq: irq number.
155− * @suspended: qos operations.
15699 */
157100 struct fimc_context {
158− struct exynos_drm_ippdrv ippdrv;
101+ struct exynos_drm_ipp ipp;
102+ struct drm_device *drm_dev;
103+ struct device *dev;
104+ struct exynos_drm_ipp_task *task;
105+ struct exynos_drm_ipp_formats *formats;
106+ unsigned int num_formats;
107+
159108 struct resource *regs_res;
160109 void __iomem *regs;
161110 spinlock_t lock;
162111 struct clk *clocks[FIMC_CLKS_MAX];
163− u32 clk_frequency;
164− struct regmap *sysreg;
165112 struct fimc_scaler sc;
166113 int id;
167114 int irq;
168− bool suspended;
169115 };
170116
171117 static u32 fimc_read(struct fimc_context *ctx, u32 reg)
@@ -217,19 +163,10 @@ static void fimc_sw_reset(struct fimc_context *ctx) · 45 unmodified lines
217163 fimc_write(ctx, 0x0, EXYNOS_CIFCNTSEQ);
218164 }
219165
220−static int fimc_set_camblk_fimd0_wb(struct fimc_context *ctx)
221−{
222− return regmap_update_bits(ctx->sysreg, SYSREG_CAMERA_BLK,
223− SYSREG_FIMD0WB_DEST_MASK,
224− ctx->id << SYSREG_FIMD0WB_DEST_SHIFT);
225−}
226−
227−static void fimc_set_type_ctrl(struct fimc_context *ctx, enum fimc_wb wb)
166+static void fimc_set_type_ctrl(struct fimc_context *ctx)
228167 {
229168 u32 cfg;
230169
231− DRM_DEBUG_KMS("wb[%d]\n", wb);
232−
233170 cfg = fimc_read(ctx, EXYNOS_CIGCTRL);
234171 cfg &= ~(EXYNOS_CIGCTRL_TESTPATTERN_MASK |
235172 EXYNOS_CIGCTRL_SELCAM_ITU_MASK |
@@ -238,23 +175,10 @@ static void fimc_set_type_ctrl(struct fimc_context *ctx, enum fimc_wb wb) · 2 unmodified lines
238175 EXYNOS_CIGCTRL_SELWB_CAMIF_MASK |
239176 EXYNOS_CIGCTRL_SELWRITEBACK_MASK);
240177
241− switch (wb) {
242− case FIMC_WB_A:
243− cfg |= (EXYNOS_CIGCTRL_SELWRITEBACK_A |
244− EXYNOS_CIGCTRL_SELWB_CAMIF_WRITEBACK);
245− break;
246− case FIMC_WB_B:
247− cfg |= (EXYNOS_CIGCTRL_SELWRITEBACK_B |
248− EXYNOS_CIGCTRL_SELWB_CAMIF_WRITEBACK);
249− break;
250− case FIMC_WB_NONE:
251− default:
252− cfg |= (EXYNOS_CIGCTRL_SELCAM_ITU_A |
253− EXYNOS_CIGCTRL_SELWRITEBACK_A |
254− EXYNOS_CIGCTRL_SELCAM_MIPI_A |
255− EXYNOS_CIGCTRL_SELCAM_FIMC_ITU);
256− break;
257− }
178+ cfg |= (EXYNOS_CIGCTRL_SELCAM_ITU_A |
179+ EXYNOS_CIGCTRL_SELWRITEBACK_A |
180+ EXYNOS_CIGCTRL_SELCAM_MIPI_A |
181+ EXYNOS_CIGCTRL_SELCAM_FIMC_ITU);
258182
259183 fimc_write(ctx, cfg, EXYNOS_CIGCTRL);
260184 }
@@ -296,7 +220,6 @@ static void fimc_clear_irq(struct fimc_context *ctx) · 35 unmodified lines
296220
297221 static bool fimc_check_ovf(struct fimc_context *ctx)
298222 {
299− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
300223 u32 status, flag;
301224
302225 status = fimc_read(ctx, EXYNOS_CISTATUS);
@@ -310,7 +233,7 @@ static bool fimc_check_ovf(struct fimc_context *ctx) · 7 unmodified lines
310233 EXYNOS_CIWDOFST_CLROVFIY | EXYNOS_CIWDOFST_CLROVFICB |
311234 EXYNOS_CIWDOFST_CLROVFICR);
312235
313− dev_err(ippdrv->dev, "occurred overflow at %d, status 0x%x.\n",
236+ dev_err(ctx->dev, "occurred overflow at %d, status 0x%x.\n",
314237 ctx->id, status);
315238 return true;
316239 }
@@ -376,10 +299,8 @@ static void fimc_handle_lastend(struct fimc_context *ctx, bool enable) · 59 unmodified lines
376299 fimc_write(ctx, cfg, EXYNOS_CIOCTRL);
377300 }
378301
379−
380−static int fimc_src_set_fmt_order(struct fimc_context *ctx, u32 fmt)
302+static void fimc_src_set_fmt_order(struct fimc_context *ctx, u32 fmt)
381303 {
382− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
383304 u32 cfg;
384305
385306 DRM_DEBUG_KMS("fmt[0x%x]\n", fmt);
@@ -392,12 +313,12 @@ static int fimc_src_set_fmt_order(struct fimc_context *ctx, u32 fmt) · 6 unmodified lines
392313 case DRM_FORMAT_RGB565:
393314 cfg |= EXYNOS_CISCCTRL_INRGB_FMT_RGB565;
394315 fimc_write(ctx, cfg, EXYNOS_CISCCTRL);
395− return 0;
316+ return;
396317 case DRM_FORMAT_RGB888:
397318 case DRM_FORMAT_XRGB8888:
398319 cfg |= EXYNOS_CISCCTRL_INRGB_FMT_RGB888;
399320 fimc_write(ctx, cfg, EXYNOS_CISCCTRL);
400− return 0;
321+ return;
401322 default:
402323 /* bypass */
403324 break;
@@ -438,20 +359,13 @@ static int fimc_src_set_fmt_order(struct fimc_context *ctx, u32 fmt) · 34 unmodified lines
438359 cfg |= (EXYNOS_MSCTRL_ORDER2P_LSB_CBCR |
439360 EXYNOS_MSCTRL_C_INT_IN_2PLANE);
440361 break;
441− default:
442− dev_err(ippdrv->dev, "invalid source yuv order 0x%x.\n", fmt);
443− return -EINVAL;
444362 }
445363
446364 fimc_write(ctx, cfg, EXYNOS_MSCTRL);
447−
448− return 0;
449365 }
450366
451−static int fimc_src_set_fmt(struct device *dev, u32 fmt)
367+static void fimc_src_set_fmt(struct fimc_context *ctx, u32 fmt, bool tiled)
452368 {
453− struct fimc_context *ctx = get_fimc_context(dev);
454− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
455369 u32 cfg;
456370
457371 DRM_DEBUG_KMS("fmt[0x%x]\n", fmt);
@@ -485,9 +399,6 @@ static int fimc_src_set_fmt(struct device *dev, u32 fmt) · 27 unmodified lines
485399 case DRM_FORMAT_NV21:
486400 cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR420;
487401 break;
488− default:
489− dev_err(ippdrv->dev, "invalid source format 0x%x.\n", fmt);
490− return -EINVAL;
491402 }
492403
493404 fimc_write(ctx, cfg, EXYNOS_MSCTRL);
@@ -495,22 +406,22 @@ static int fimc_src_set_fmt(struct device *dev, u32 fmt) · 1 unmodified line
495406 cfg = fimc_read(ctx, EXYNOS_CIDMAPARAM);
496407 cfg &= ~EXYNOS_CIDMAPARAM_R_MODE_MASK;
497408
498− cfg |= EXYNOS_CIDMAPARAM_R_MODE_LINEAR;
409+ if (tiled)
410+ cfg |= EXYNOS_CIDMAPARAM_R_MODE_64X32;
411+ else
412+ cfg |= EXYNOS_CIDMAPARAM_R_MODE_LINEAR;
499413
500414 fimc_write(ctx, cfg, EXYNOS_CIDMAPARAM);
501415
502− return fimc_src_set_fmt_order(ctx, fmt);
416+ fimc_src_set_fmt_order(ctx, fmt);
503417 }
504418
505−static int fimc_src_set_transf(struct device *dev,
506− enum drm_exynos_degree degree,
507− enum drm_exynos_flip flip, bool *swap)
419+static void fimc_src_set_transf(struct fimc_context *ctx, unsigned int rotation)
508420 {
509− struct fimc_context *ctx = get_fimc_context(dev);
510− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
421+ unsigned int degree = rotation & DRM_MODE_ROTATE_MASK;
511422 u32 cfg1, cfg2;
512423
513− DRM_DEBUG_KMS("degree[%d]flip[0x%x]\n", degree, flip);
424+ DRM_DEBUG_KMS("rotation[%x]\n", rotation);
514425
515426 cfg1 = fimc_read(ctx, EXYNOS_MSCTRL);
516427 cfg1 &= ~(EXYNOS_MSCTRL_FLIP_X_MIRROR |
@@ -520,61 +431,56 @@ static int fimc_src_set_transf(struct device *dev, · 3 unmodified lines
520431 cfg2 &= ~EXYNOS_CITRGFMT_INROT90_CLOCKWISE;
521432
522433 switch (degree) {
523− case EXYNOS_DRM_DEGREE_0:
524− if (flip & EXYNOS_DRM_FLIP_VERTICAL)
434+ case DRM_MODE_ROTATE_0:
435+ if (rotation & DRM_MODE_REFLECT_X)
525436 cfg1 |= EXYNOS_MSCTRL_FLIP_X_MIRROR;
526− if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
437+ if (rotation & DRM_MODE_REFLECT_Y)
527438 cfg1 |= EXYNOS_MSCTRL_FLIP_Y_MIRROR;
528439 break;
529− case EXYNOS_DRM_DEGREE_90:
440+ case DRM_MODE_ROTATE_90:
530441 cfg2 |= EXYNOS_CITRGFMT_INROT90_CLOCKWISE;
531− if (flip & EXYNOS_DRM_FLIP_VERTICAL)
442+ if (rotation & DRM_MODE_REFLECT_X)
532443 cfg1 |= EXYNOS_MSCTRL_FLIP_X_MIRROR;
533− if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
444+ if (rotation & DRM_MODE_REFLECT_Y)
534445 cfg1 |= EXYNOS_MSCTRL_FLIP_Y_MIRROR;
535446 break;
536− case EXYNOS_DRM_DEGREE_180:
447+ case DRM_MODE_ROTATE_180:
537448 cfg1 |= (EXYNOS_MSCTRL_FLIP_X_MIRROR |
538449 EXYNOS_MSCTRL_FLIP_Y_MIRROR);
539− if (flip & EXYNOS_DRM_FLIP_VERTICAL)
450+ if (rotation & DRM_MODE_REFLECT_X)
540451 cfg1 &= ~EXYNOS_MSCTRL_FLIP_X_MIRROR;
541− if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
452+ if (rotation & DRM_MODE_REFLECT_Y)
542453 cfg1 &= ~EXYNOS_MSCTRL_FLIP_Y_MIRROR;
543454 break;
544− case EXYNOS_DRM_DEGREE_270:
455+ case DRM_MODE_ROTATE_270:
545456 cfg1 |= (EXYNOS_MSCTRL_FLIP_X_MIRROR |
546457 EXYNOS_MSCTRL_FLIP_Y_MIRROR);
547458 cfg2 |= EXYNOS_CITRGFMT_INROT90_CLOCKWISE;
548− if (flip & EXYNOS_DRM_FLIP_VERTICAL)
459+ if (rotation & DRM_MODE_REFLECT_X)
549460 cfg1 &= ~EXYNOS_MSCTRL_FLIP_X_MIRROR;
550− if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
461+ if (rotation & DRM_MODE_REFLECT_Y)
551462 cfg1 &= ~EXYNOS_MSCTRL_FLIP_Y_MIRROR;
552463 break;
553− default:
554− dev_err(ippdrv->dev, "invalid degree value %d.\n", degree);
555− return -EINVAL;
556464 }
557465
558466 fimc_write(ctx, cfg1, EXYNOS_MSCTRL);
559467 fimc_write(ctx, cfg2, EXYNOS_CITRGFMT);
560− *swap = (cfg2 & EXYNOS_CITRGFMT_INROT90_CLOCKWISE) ? 1 : 0;
561−
562− return 0;
563468 }
564469
565−static int fimc_set_window(struct fimc_context *ctx,
566− struct drm_exynos_pos *pos, struct drm_exynos_sz *sz)
470+static void fimc_set_window(struct fimc_context *ctx,
471+ struct exynos_drm_ipp_buffer *buf)
567472 {
568473 u32 cfg, h1, h2, v1, v2;
569474
570475 /* cropped image */
571− h1 = pos->x;
572− h2 = sz->hsize - pos->w - pos->x;
573− v1 = pos->y;
574− v2 = sz->vsize - pos->h - pos->y;
476+ h1 = buf->rect.x;
477+ h2 = buf->buf.width - buf->rect.w - buf->rect.x;
478+ v1 = buf->rect.y;
479+ v2 = buf->buf.height - buf->rect.h - buf->rect.y;
575480
576481 DRM_DEBUG_KMS("x[%d]y[%d]w[%d]h[%d]hsize[%d]vsize[%d]\n",
577− pos->x, pos->y, pos->w, pos->h, sz->hsize, sz->vsize);
482+ buf->rect.x, buf->rect.y, buf->rect.w, buf->rect.h,
483+ buf->buf.width, buf->buf.height);
578484 DRM_DEBUG_KMS("h1[%d]h2[%d]v1[%d]v2[%d]\n", h1, h2, v1, v2);
579485
580486 /*
@@ -592,42 +498,30 @@ static int fimc_set_window(struct fimc_context *ctx, · 11 unmodified lines
592498 cfg = (EXYNOS_CIWDOFST2_WINHOROFST2(h2) |
593499 EXYNOS_CIWDOFST2_WINVEROFST2(v2));
594500 fimc_write(ctx, cfg, EXYNOS_CIWDOFST2);
595−
596− return 0;
597501 }
598502
599−static int fimc_src_set_size(struct device *dev, int swap,
600− struct drm_exynos_pos *pos, struct drm_exynos_sz *sz)
503+static void fimc_src_set_size(struct fimc_context *ctx,
504+ struct exynos_drm_ipp_buffer *buf)
601505 {
602− struct fimc_context *ctx = get_fimc_context(dev);
603− struct drm_exynos_pos img_pos = *pos;
604− struct drm_exynos_sz img_sz = *sz;
605506 u32 cfg;
606507
607− DRM_DEBUG_KMS("swap[%d]hsize[%d]vsize[%d]\n",
608− swap, sz->hsize, sz->vsize);
508+ DRM_DEBUG_KMS("hsize[%d]vsize[%d]\n", buf->buf.width, buf->buf.height);
609509
610510 /* original size */
611− cfg = (EXYNOS_ORGISIZE_HORIZONTAL(img_sz.hsize) |
612− EXYNOS_ORGISIZE_VERTICAL(img_sz.vsize));
511+ cfg = (EXYNOS_ORGISIZE_HORIZONTAL(buf->buf.width) |
512+ EXYNOS_ORGISIZE_VERTICAL(buf->buf.height));
613513
614514 fimc_write(ctx, cfg, EXYNOS_ORGISIZE);
615515
616− DRM_DEBUG_KMS("x[%d]y[%d]w[%d]h[%d]\n", pos->x, pos->y, pos->w, pos->h);
617−
618− if (swap) {
619− img_pos.w = pos->h;
620− img_pos.h = pos->w;
621− img_sz.hsize = sz->vsize;
622− img_sz.vsize = sz->hsize;
623− }
516+ DRM_DEBUG_KMS("x[%d]y[%d]w[%d]h[%d]\n", buf->rect.x, buf->rect.y,
517+ buf->rect.w, buf->rect.h);
624518
625519 /* set input DMA image size */
626520 cfg = fimc_read(ctx, EXYNOS_CIREAL_ISIZE);
627521 cfg &= ~(EXYNOS_CIREAL_ISIZE_HEIGHT_MASK |
628522 EXYNOS_CIREAL_ISIZE_WIDTH_MASK);
629− cfg |= (EXYNOS_CIREAL_ISIZE_WIDTH(img_pos.w) |
630− EXYNOS_CIREAL_ISIZE_HEIGHT(img_pos.h));
523+ cfg |= (EXYNOS_CIREAL_ISIZE_WIDTH(buf->rect.w) |
524+ EXYNOS_CIREAL_ISIZE_HEIGHT(buf->rect.h));
631525 fimc_write(ctx, cfg, EXYNOS_CIREAL_ISIZE);
632526
633527 /*
@@ -635,91 +529,34 @@ static int fimc_src_set_size(struct device *dev, int swap, · 1 unmodified line
635529 * for now, we support only ITU601 8 bit mode
636530 */
637531 cfg = (EXYNOS_CISRCFMT_ITU601_8BIT |
638− EXYNOS_CISRCFMT_SOURCEHSIZE(img_sz.hsize) |
639− EXYNOS_CISRCFMT_SOURCEVSIZE(img_sz.vsize));
532+ EXYNOS_CISRCFMT_SOURCEHSIZE(buf->buf.width) |
533+ EXYNOS_CISRCFMT_SOURCEVSIZE(buf->buf.height));
640534 fimc_write(ctx, cfg, EXYNOS_CISRCFMT);
641535
642536 /* offset Y(RGB), Cb, Cr */
643− cfg = (EXYNOS_CIIYOFF_HORIZONTAL(img_pos.x) |
644− EXYNOS_CIIYOFF_VERTICAL(img_pos.y));
537+ cfg = (EXYNOS_CIIYOFF_HORIZONTAL(buf->rect.x) |
538+ EXYNOS_CIIYOFF_VERTICAL(buf->rect.y));
645539 fimc_write(ctx, cfg, EXYNOS_CIIYOFF);
646− cfg = (EXYNOS_CIICBOFF_HORIZONTAL(img_pos.x) |
647− EXYNOS_CIICBOFF_VERTICAL(img_pos.y));
540+ cfg = (EXYNOS_CIICBOFF_HORIZONTAL(buf->rect.x) |
541+ EXYNOS_CIICBOFF_VERTICAL(buf->rect.y));
648542 fimc_write(ctx, cfg, EXYNOS_CIICBOFF);
649− cfg = (EXYNOS_CIICROFF_HORIZONTAL(img_pos.x) |
650− EXYNOS_CIICROFF_VERTICAL(img_pos.y));
543+ cfg = (EXYNOS_CIICROFF_HORIZONTAL(buf->rect.x) |
544+ EXYNOS_CIICROFF_VERTICAL(buf->rect.y));
651545 fimc_write(ctx, cfg, EXYNOS_CIICROFF);
652546
653− return fimc_set_window(ctx, &img_pos, &img_sz);
547+ fimc_set_window(ctx, buf);
654548 }
655549
656−static int fimc_src_set_addr(struct device *dev,
657− struct drm_exynos_ipp_buf_info *buf_info, u32 buf_id,
658− enum drm_exynos_ipp_buf_type buf_type)
550+static void fimc_src_set_addr(struct fimc_context *ctx,
551+ struct exynos_drm_ipp_buffer *buf)
659552 {
660− struct fimc_context *ctx = get_fimc_context(dev);
661− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
662− struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;
663− struct drm_exynos_ipp_property *property;
664− struct drm_exynos_ipp_config *config;
665−
666− if (!c_node) {
667− DRM_ERROR("failed to get c_node.\n");
668− return -EINVAL;
669− }
670−
671− property = &c_node->property;
672−
673− DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]buf_type[%d]\n",
674− property->prop_id, buf_id, buf_type);
675−
676− if (buf_id > FIMC_MAX_SRC) {
677− dev_info(ippdrv->dev, "invalid buf_id %d.\n", buf_id);
678− return -ENOMEM;
679− }
680−
681− /* address register set */
682− switch (buf_type) {
683− case IPP_BUF_ENQUEUE:
684− config = &property->config[EXYNOS_DRM_OPS_SRC];
685− fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_Y],
686− EXYNOS_CIIYSA0);
687−
688− if (config->fmt == DRM_FORMAT_YVU420) {
689− fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CR],
690− EXYNOS_CIICBSA0);
691− fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CB],
692− EXYNOS_CIICRSA0);
693− } else {
694− fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CB],
695− EXYNOS_CIICBSA0);
696− fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CR],
697− EXYNOS_CIICRSA0);
698− }
699− break;
700− case IPP_BUF_DEQUEUE:
701− fimc_write(ctx, 0x0, EXYNOS_CIIYSA0);
702− fimc_write(ctx, 0x0, EXYNOS_CIICBSA0);
703− fimc_write(ctx, 0x0, EXYNOS_CIICRSA0);
704− break;
705− default:
706− /* bypass */
707− break;
708− }
709−
710− return 0;
553+ fimc_write(ctx, buf->dma_addr[0], EXYNOS_CIIYSA(0));
554+ fimc_write(ctx, buf->dma_addr[1], EXYNOS_CIICBSA(0));
555+ fimc_write(ctx, buf->dma_addr[2], EXYNOS_CIICRSA(0));
711556 }
712557
713−static struct exynos_drm_ipp_ops fimc_src_ops = {
714− .set_fmt = fimc_src_set_fmt,
715− .set_transf = fimc_src_set_transf,
716− .set_size = fimc_src_set_size,
717− .set_addr = fimc_src_set_addr,
718−};
719−
720−static int fimc_dst_set_fmt_order(struct fimc_context *ctx, u32 fmt)
558+static void fimc_dst_set_fmt_order(struct fimc_context *ctx, u32 fmt)
721559 {
722− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
723560 u32 cfg;
724561
725562 DRM_DEBUG_KMS("fmt[0x%x]\n", fmt);
@@ -732,11 +569,11 @@ static int fimc_dst_set_fmt_order(struct fimc_context *ctx, u32 fmt) · 6 unmodified lines
732569 case DRM_FORMAT_RGB565:
733570 cfg |= EXYNOS_CISCCTRL_OUTRGB_FMT_RGB565;
734571 fimc_write(ctx, cfg, EXYNOS_CISCCTRL);
735− return 0;
572+ return;
736573 case DRM_FORMAT_RGB888:
737574 cfg |= EXYNOS_CISCCTRL_OUTRGB_FMT_RGB888;
738575 fimc_write(ctx, cfg, EXYNOS_CISCCTRL);
739− return 0;
576+ return;
740577 case DRM_FORMAT_XRGB8888:
741578 cfg |= (EXYNOS_CISCCTRL_OUTRGB_FMT_RGB888 |
742579 EXYNOS_CISCCTRL_EXTRGB_EXTENSION);
@@ -784,20 +621,13 @@ static int fimc_dst_set_fmt_order(struct fimc_context *ctx, u32 fmt) · 41 unmodified lines
784621 cfg |= EXYNOS_CIOCTRL_ORDER2P_LSB_CBCR;
785622 cfg |= EXYNOS_CIOCTRL_YCBCR_2PLANE;
786623 break;
787− default:
788− dev_err(ippdrv->dev, "invalid target yuv order 0x%x.\n", fmt);
789− return -EINVAL;
790624 }
791625
792626 fimc_write(ctx, cfg, EXYNOS_CIOCTRL);
793−
794− return 0;
795627 }
796628
797−static int fimc_dst_set_fmt(struct device *dev, u32 fmt)
629+static void fimc_dst_set_fmt(struct fimc_context *ctx, u32 fmt, bool tiled)
798630 {
799− struct fimc_context *ctx = get_fimc_context(dev);
800− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
801631 u32 cfg;
802632
803633 DRM_DEBUG_KMS("fmt[0x%x]\n", fmt);
@@ -837,10 +667,6 @@ static int fimc_dst_set_fmt(struct device *dev, u32 fmt) · 33 unmodified lines
837667 case DRM_FORMAT_NV21:
838668 cfg |= EXYNOS_CITRGFMT_OUTFORMAT_YCBCR420;
839669 break;
840− default:
841− dev_err(ippdrv->dev, "invalid target format 0x%x.\n",
842− fmt);
843− return -EINVAL;
844670 }
845671
846672 fimc_write(ctx, cfg, EXYNOS_CITRGFMT);
@@ -849,73 +675,67 @@ static int fimc_dst_set_fmt(struct device *dev, u32 fmt) · 2 unmodified lines
849675 cfg = fimc_read(ctx, EXYNOS_CIDMAPARAM);
850676 cfg &= ~EXYNOS_CIDMAPARAM_W_MODE_MASK;
851677
852− cfg |= EXYNOS_CIDMAPARAM_W_MODE_LINEAR;
678+ if (tiled)
679+ cfg |= EXYNOS_CIDMAPARAM_W_MODE_64X32;
680+ else
681+ cfg |= EXYNOS_CIDMAPARAM_W_MODE_LINEAR;
853682
854683 fimc_write(ctx, cfg, EXYNOS_CIDMAPARAM);
855684
856− return fimc_dst_set_fmt_order(ctx, fmt);
685+ fimc_dst_set_fmt_order(ctx, fmt);
857686 }
858687
859−static int fimc_dst_set_transf(struct device *dev,
860− enum drm_exynos_degree degree,
861− enum drm_exynos_flip flip, bool *swap)
688+static void fimc_dst_set_transf(struct fimc_context *ctx, unsigned int rotation)
862689 {
863− struct fimc_context *ctx = get_fimc_context(dev);
864− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
690+ unsigned int degree = rotation & DRM_MODE_ROTATE_MASK;
865691 u32 cfg;
866692
867− DRM_DEBUG_KMS("degree[%d]flip[0x%x]\n", degree, flip);
693+ DRM_DEBUG_KMS("rotation[0x%x]\n", rotation);
868694
869695 cfg = fimc_read(ctx, EXYNOS_CITRGFMT);
870696 cfg &= ~EXYNOS_CITRGFMT_FLIP_MASK;
871697 cfg &= ~EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE;
872698
873699 switch (degree) {
874− case EXYNOS_DRM_DEGREE_0:
875− if (flip & EXYNOS_DRM_FLIP_VERTICAL)
700+ case DRM_MODE_ROTATE_0:
701+ if (rotation & DRM_MODE_REFLECT_X)
876702 cfg |= EXYNOS_CITRGFMT_FLIP_X_MIRROR;
877− if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
703+ if (rotation & DRM_MODE_REFLECT_Y)
878704 cfg |= EXYNOS_CITRGFMT_FLIP_Y_MIRROR;
879705 break;
880− case EXYNOS_DRM_DEGREE_90:
706+ case DRM_MODE_ROTATE_90:
881707 cfg |= EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE;
882− if (flip & EXYNOS_DRM_FLIP_VERTICAL)
708+ if (rotation & DRM_MODE_REFLECT_X)
883709 cfg |= EXYNOS_CITRGFMT_FLIP_X_MIRROR;
884− if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
710+ if (rotation & DRM_MODE_REFLECT_Y)
885711 cfg |= EXYNOS_CITRGFMT_FLIP_Y_MIRROR;
886712 break;
887− case EXYNOS_DRM_DEGREE_180:
713+ case DRM_MODE_ROTATE_180:
888714 cfg |= (EXYNOS_CITRGFMT_FLIP_X_MIRROR |
889715 EXYNOS_CITRGFMT_FLIP_Y_MIRROR);
890− if (flip & EXYNOS_DRM_FLIP_VERTICAL)
716+ if (rotation & DRM_MODE_REFLECT_X)
891717 cfg &= ~EXYNOS_CITRGFMT_FLIP_X_MIRROR;
892− if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
718+ if (rotation & DRM_MODE_REFLECT_Y)
893719 cfg &= ~EXYNOS_CITRGFMT_FLIP_Y_MIRROR;
894720 break;
895− case EXYNOS_DRM_DEGREE_270:
721+ case DRM_MODE_ROTATE_270:
896722 cfg |= (EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE |
897723 EXYNOS_CITRGFMT_FLIP_X_MIRROR |
898724 EXYNOS_CITRGFMT_FLIP_Y_MIRROR);
899− if (flip & EXYNOS_DRM_FLIP_VERTICAL)
725+ if (rotation & DRM_MODE_REFLECT_X)
900726 cfg &= ~EXYNOS_CITRGFMT_FLIP_X_MIRROR;
901− if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
727+ if (rotation & DRM_MODE_REFLECT_Y)
902728 cfg &= ~EXYNOS_CITRGFMT_FLIP_Y_MIRROR;
903729 break;
904− default:
905− dev_err(ippdrv->dev, "invalid degree value %d.\n", degree);
906− return -EINVAL;
907730 }
908731
909732 fimc_write(ctx, cfg, EXYNOS_CITRGFMT);
910− *swap = (cfg & EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE) ? 1 : 0;
911−
912− return 0;
913733 }
914734
915735 static int fimc_set_prescaler(struct fimc_context *ctx, struct fimc_scaler *sc,
916− struct drm_exynos_pos *src, struct drm_exynos_pos *dst)
736+ struct drm_exynos_ipp_task_rect *src,
737+ struct drm_exynos_ipp_task_rect *dst)
917738 {
918− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
919739 u32 cfg, cfg_ext, shfactor;
920740 u32 pre_dst_width, pre_dst_height;
921741 u32 hfactor, vfactor;
@@ -942,13 +762,13 @@ static int fimc_set_prescaler(struct fimc_context *ctx, struct fimc_scaler *sc, · 20 unmodified lines
942762 /* fimc_ippdrv_check_property assures that dividers are not null */
943763 hfactor = fls(src_w / dst_w / 2);
944764 if (hfactor > FIMC_SHFACTOR / 2) {
945− dev_err(ippdrv->dev, "failed to get ratio horizontal.\n");
765+ dev_err(ctx->dev, "failed to get ratio horizontal.\n");
946766 return -EINVAL;
947767 }
948768
949769 vfactor = fls(src_h / dst_h / 2);
950770 if (vfactor > FIMC_SHFACTOR / 2) {
951− dev_err(ippdrv->dev, "failed to get ratio vertical.\n");
771+ dev_err(ctx->dev, "failed to get ratio vertical.\n");
952772 return -EINVAL;
953773 }
954774
@@ -1019,83 +839,77 @@ static void fimc_set_scaler(struct fimc_context *ctx, struct fimc_scaler *sc) · 64 unmodified lines
1019839 fimc_write(ctx, cfg_ext, EXYNOS_CIEXTEN);
1020840 }
1021841
1022−static int fimc_dst_set_size(struct device *dev, int swap,
1023− struct drm_exynos_pos *pos, struct drm_exynos_sz *sz)
842+static void fimc_dst_set_size(struct fimc_context *ctx,
843+ struct exynos_drm_ipp_buffer *buf)
1024844 {
1025− struct fimc_context *ctx = get_fimc_context(dev);
1026− struct drm_exynos_pos img_pos = *pos;
1027− struct drm_exynos_sz img_sz = *sz;
1028− u32 cfg;
845+ u32 cfg, cfg_ext;
1029846
1030− DRM_DEBUG_KMS("swap[%d]hsize[%d]vsize[%d]\n",
1031− swap, sz->hsize, sz->vsize);
847+ DRM_DEBUG_KMS("hsize[%d]vsize[%d]\n", buf->buf.width, buf->buf.height);
1032848
1033849 /* original size */
1034− cfg = (EXYNOS_ORGOSIZE_HORIZONTAL(img_sz.hsize) |
1035− EXYNOS_ORGOSIZE_VERTICAL(img_sz.vsize));
850+ cfg = (EXYNOS_ORGOSIZE_HORIZONTAL(buf->buf.width) |
851+ EXYNOS_ORGOSIZE_VERTICAL(buf->buf.height));
1036852
1037853 fimc_write(ctx, cfg, EXYNOS_ORGOSIZE);
1038854
1039− DRM_DEBUG_KMS("x[%d]y[%d]w[%d]h[%d]\n", pos->x, pos->y, pos->w, pos->h);
855+ DRM_DEBUG_KMS("x[%d]y[%d]w[%d]h[%d]\n", buf->rect.x, buf->rect.y,
856+ buf->rect.w, buf->rect.h);
1040857
1041858 /* CSC ITU */
1042859 cfg = fimc_read(ctx, EXYNOS_CIGCTRL);
1043860 cfg &= ~EXYNOS_CIGCTRL_CSC_MASK;
1044861
1045− if (sz->hsize >= FIMC_WIDTH_ITU_709)
862+ if (buf->buf.width >= FIMC_WIDTH_ITU_709)
1046863 cfg |= EXYNOS_CIGCTRL_CSC_ITU709;
1047864 else
1048865 cfg |= EXYNOS_CIGCTRL_CSC_ITU601;
1049866
1050867 fimc_write(ctx, cfg, EXYNOS_CIGCTRL);
1051868
1052− if (swap) {
1053− img_pos.w = pos->h;
1054− img_pos.h = pos->w;
1055− img_sz.hsize = sz->vsize;
1056− img_sz.vsize = sz->hsize;
1057− }
869+ cfg_ext = fimc_read(ctx, EXYNOS_CITRGFMT);
1058870
1059871 /* target image size */
1060872 cfg = fimc_read(ctx, EXYNOS_CITRGFMT);
1061873 cfg &= ~(EXYNOS_CITRGFMT_TARGETH_MASK |
1062874 EXYNOS_CITRGFMT_TARGETV_MASK);
1063− cfg |= (EXYNOS_CITRGFMT_TARGETHSIZE(img_pos.w) |
1064− EXYNOS_CITRGFMT_TARGETVSIZE(img_pos.h));
875+ if (cfg_ext & EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE)
876+ cfg |= (EXYNOS_CITRGFMT_TARGETHSIZE(buf->rect.h) |
877+ EXYNOS_CITRGFMT_TARGETVSIZE(buf->rect.w));
878+ else
879+ cfg |= (EXYNOS_CITRGFMT_TARGETHSIZE(buf->rect.w) |
880+ EXYNOS_CITRGFMT_TARGETVSIZE(buf->rect.h));
1065881 fimc_write(ctx, cfg, EXYNOS_CITRGFMT);
1066882
1067883 /* target area */
1068− cfg = EXYNOS_CITAREA_TARGET_AREA(img_pos.w * img_pos.h);
884+ cfg = EXYNOS_CITAREA_TARGET_AREA(buf->rect.w * buf->rect.h);
1069885 fimc_write(ctx, cfg, EXYNOS_CITAREA);
1070886
1071887 /* offset Y(RGB), Cb, Cr */
1072− cfg = (EXYNOS_CIOYOFF_HORIZONTAL(img_pos.x) |
1073− EXYNOS_CIOYOFF_VERTICAL(img_pos.y));
888+ cfg = (EXYNOS_CIOYOFF_HORIZONTAL(buf->rect.x) |
889+ EXYNOS_CIOYOFF_VERTICAL(buf->rect.y));
1074890 fimc_write(ctx, cfg, EXYNOS_CIOYOFF);
1075− cfg = (EXYNOS_CIOCBOFF_HORIZONTAL(img_pos.x) |
1076− EXYNOS_CIOCBOFF_VERTICAL(img_pos.y));
891+ cfg = (EXYNOS_CIOCBOFF_HORIZONTAL(buf->rect.x) |
892+ EXYNOS_CIOCBOFF_VERTICAL(buf->rect.y));
1077893 fimc_write(ctx, cfg, EXYNOS_CIOCBOFF);
1078− cfg = (EXYNOS_CIOCROFF_HORIZONTAL(img_pos.x) |
1079− EXYNOS_CIOCROFF_VERTICAL(img_pos.y));
894+ cfg = (EXYNOS_CIOCROFF_HORIZONTAL(buf->rect.x) |
895+ EXYNOS_CIOCROFF_VERTICAL(buf->rect.y));
1080896 fimc_write(ctx, cfg, EXYNOS_CIOCROFF);
1081−
1082− return 0;
1083897 }
1084898
1085899 static void fimc_dst_set_buf_seq(struct fimc_context *ctx, u32 buf_id,
1086− enum drm_exynos_ipp_buf_type buf_type)
900+ bool enqueue)
1087901 {
1088902 unsigned long flags;
1089903 u32 buf_num;
1090904 u32 cfg;
1091905
1092− DRM_DEBUG_KMS("buf_id[%d]buf_type[%d]\n", buf_id, buf_type);
906+ DRM_DEBUG_KMS("buf_id[%d]enqueu[%d]\n", buf_id, enqueue);
1093907
1094908 spin_lock_irqsave(&ctx->lock, flags);
1095909
1096910 cfg = fimc_read(ctx, EXYNOS_CIFCNTSEQ);
1097911
1098− if (buf_type == IPP_BUF_ENQUEUE)
912+ if (enqueue)
1099913 cfg |= (1 << buf_id);
1100914 else
1101915 cfg &= ~(1 << buf_id);
@@ -1104,88 +918,29 @@ static void fimc_dst_set_buf_seq(struct fimc_context *ctx, u32 buf_id, · 2 unmodified lines
1104918
1105919 buf_num = hweight32(cfg);
1106920
1107− if (buf_type == IPP_BUF_ENQUEUE && buf_num >= FIMC_BUF_START)
921+ if (enqueue && buf_num >= FIMC_BUF_START)
1108922 fimc_mask_irq(ctx, true);
1109− else if (buf_type == IPP_BUF_DEQUEUE && buf_num <= FIMC_BUF_STOP)
923+ else if (!enqueue && buf_num <= FIMC_BUF_STOP)
1110924 fimc_mask_irq(ctx, false);
1111925
1112926 spin_unlock_irqrestore(&ctx->lock, flags);
1113927 }
1114928
1115−static int fimc_dst_set_addr(struct device *dev,
1116− struct drm_exynos_ipp_buf_info *buf_info, u32 buf_id,
1117− enum drm_exynos_ipp_buf_type buf_type)
929+static void fimc_dst_set_addr(struct fimc_context *ctx,
930+ struct exynos_drm_ipp_buffer *buf)
1118931 {
1119− struct fimc_context *ctx = get_fimc_context(dev);
1120− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
1121− struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;
1122− struct drm_exynos_ipp_property *property;
1123− struct drm_exynos_ipp_config *config;
1124−
1125− if (!c_node) {
1126− DRM_ERROR("failed to get c_node.\n");
1127− return -EINVAL;
1128− }
1129−
1130− property = &c_node->property;
1131−
1132− DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]buf_type[%d]\n",
1133− property->prop_id, buf_id, buf_type);
932+ fimc_write(ctx, buf->dma_addr[0], EXYNOS_CIOYSA(0));
933+ fimc_write(ctx, buf->dma_addr[1], EXYNOS_CIOCBSA(0));
934+ fimc_write(ctx, buf->dma_addr[2], EXYNOS_CIOCRSA(0));
1134935
1135− if (buf_id > FIMC_MAX_DST) {
1136− dev_info(ippdrv->dev, "invalid buf_id %d.\n", buf_id);
1137− return -ENOMEM;
1138− }
1139−
1140− /* address register set */
1141− switch (buf_type) {
1142− case IPP_BUF_ENQUEUE:
1143− config = &property->config[EXYNOS_DRM_OPS_DST];
1144−
1145− fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_Y],
1146− EXYNOS_CIOYSA(buf_id));
1147−
1148− if (config->fmt == DRM_FORMAT_YVU420) {
1149− fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CR],
1150− EXYNOS_CIOCBSA(buf_id));
1151− fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CB],
1152− EXYNOS_CIOCRSA(buf_id));
1153− } else {
1154− fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CB],
1155− EXYNOS_CIOCBSA(buf_id));
1156− fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CR],
1157− EXYNOS_CIOCRSA(buf_id));
1158− }
1159− break;
1160− case IPP_BUF_DEQUEUE:
1161− fimc_write(ctx, 0x0, EXYNOS_CIOYSA(buf_id));
1162− fimc_write(ctx, 0x0, EXYNOS_CIOCBSA(buf_id));
1163− fimc_write(ctx, 0x0, EXYNOS_CIOCRSA(buf_id));
1164− break;
1165− default:
1166− /* bypass */
1167− break;
1168− }
1169−
1170− fimc_dst_set_buf_seq(ctx, buf_id, buf_type);
1171−
1172− return 0;
936+ fimc_dst_set_buf_seq(ctx, 0, true);
1173937 }
1174938
1175−static struct exynos_drm_ipp_ops fimc_dst_ops = {
1176− .set_fmt = fimc_dst_set_fmt,
1177− .set_transf = fimc_dst_set_transf,
1178− .set_size = fimc_dst_set_size,
1179− .set_addr = fimc_dst_set_addr,
1180−};
939+static void fimc_stop(struct fimc_context *ctx);
1181940
1182941 static irqreturn_t fimc_irq_handler(int irq, void *dev_id)
1183942 {
1184943 struct fimc_context *ctx = dev_id;
1185− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
1186− struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;
1187− struct drm_exynos_ipp_event_work *event_work =
1188− c_node->event_work;
1189944 int buf_id;
1190945
1191946 DRM_DEBUG_KMS("fimc id[%d]\n", ctx->id);
@@ -1203,170 +958,19 @@ static irqreturn_t fimc_irq_handler(int irq, void *dev_id) · 11 unmodified lines
1203958
1204959 DRM_DEBUG_KMS("buf_id[%d]\n", buf_id);
1205960
1206− fimc_dst_set_buf_seq(ctx, buf_id, IPP_BUF_DEQUEUE);
1207−
1208− event_work->ippdrv = ippdrv;
1209− event_work->buf_id[EXYNOS_DRM_OPS_DST] = buf_id;
1210− queue_work(ippdrv->event_workq, &event_work->work);
1211−
1212− return IRQ_HANDLED;
1213−}
1214−
1215−static int fimc_init_prop_list(struct exynos_drm_ippdrv *ippdrv)
1216−{
1217− struct drm_exynos_ipp_prop_list *prop_list = &ippdrv->prop_list;
1218−
1219− prop_list->version = 1;
1220− prop_list->writeback = 1;
1221− prop_list->refresh_min = FIMC_REFRESH_MIN;
1222− prop_list->refresh_max = FIMC_REFRESH_MAX;
1223− prop_list->flip = (1 << EXYNOS_DRM_FLIP_NONE) |
1224− (1 << EXYNOS_DRM_FLIP_VERTICAL) |
1225− (1 << EXYNOS_DRM_FLIP_HORIZONTAL);
1226− prop_list->degree = (1 << EXYNOS_DRM_DEGREE_0) |
1227− (1 << EXYNOS_DRM_DEGREE_90) |
1228− (1 << EXYNOS_DRM_DEGREE_180) |
1229− (1 << EXYNOS_DRM_DEGREE_270);
1230− prop_list->csc = 1;
1231− prop_list->crop = 1;
1232− prop_list->crop_max.hsize = FIMC_CROP_MAX;
1233− prop_list->crop_max.vsize = FIMC_CROP_MAX;
1234− prop_list->crop_min.hsize = FIMC_CROP_MIN;
1235− prop_list->crop_min.vsize = FIMC_CROP_MIN;
1236− prop_list->scale = 1;
1237− prop_list->scale_max.hsize = FIMC_SCALE_MAX;
1238− prop_list->scale_max.vsize = FIMC_SCALE_MAX;
1239− prop_list->scale_min.hsize = FIMC_SCALE_MIN;
1240− prop_list->scale_min.vsize = FIMC_SCALE_MIN;
1241−
1242− return 0;
1243−}
1244−
1245−static inline bool fimc_check_drm_flip(enum drm_exynos_flip flip)
1246−{
1247− switch (flip) {
1248− case EXYNOS_DRM_FLIP_NONE:
1249− case EXYNOS_DRM_FLIP_VERTICAL:
1250− case EXYNOS_DRM_FLIP_HORIZONTAL:
1251− case EXYNOS_DRM_FLIP_BOTH:
1252− return true;
1253− default:
1254− DRM_DEBUG_KMS("invalid flip\n");
1255− return false;
1256− }
1257−}
1258−
1259−static int fimc_ippdrv_check_property(struct device *dev,
1260− struct drm_exynos_ipp_property *property)
1261−{
1262− struct fimc_context *ctx = get_fimc_context(dev);
1263− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
1264− struct drm_exynos_ipp_prop_list *pp = &ippdrv->prop_list;
1265− struct drm_exynos_ipp_config *config;
1266− struct drm_exynos_pos *pos;
1267− struct drm_exynos_sz *sz;
1268− bool swap;
1269− int i;
1270−
1271− for_each_ipp_ops(i) {
1272− if ((i == EXYNOS_DRM_OPS_SRC) &&
1273− (property->cmd == IPP_CMD_WB))
1274− continue;
1275−
1276− config = &property->config[i];
1277− pos = &config->pos;
1278− sz = &config->sz;
1279−
1280− /* check for flip */
1281− if (!fimc_check_drm_flip(config->flip)) {
1282− DRM_ERROR("invalid flip.\n");
1283− goto err_property;
1284− }
1285−
1286− /* check for degree */
1287− switch (config->degree) {
1288− case EXYNOS_DRM_DEGREE_90:
1289− case EXYNOS_DRM_DEGREE_270:
1290− swap = true;
1291− break;
1292− case EXYNOS_DRM_DEGREE_0:
1293− case EXYNOS_DRM_DEGREE_180:
1294− swap = false;
1295− break;
1296− default:
1297− DRM_ERROR("invalid degree.\n");
1298− goto err_property;
1299− }
1300−
1301− /* check for buffer bound */
1302− if ((pos->x + pos->w > sz->hsize) ||
1303− (pos->y + pos->h > sz->vsize)) {
1304− DRM_ERROR("out of buf bound.\n");
1305− goto err_property;
1306− }
961+ if (ctx->task) {
962+ struct exynos_drm_ipp_task *task = ctx->task;
1307963
1308− /* check for crop */
1309− if ((i == EXYNOS_DRM_OPS_SRC) && (pp->crop)) {
1310− if (swap) {
1311− if ((pos->h < pp->crop_min.hsize) ||
1312− (sz->vsize > pp->crop_max.hsize) ||
1313− (pos->w < pp->crop_min.vsize) ||
1314− (sz->hsize > pp->crop_max.vsize)) {
1315− DRM_ERROR("out of crop size.\n");
1316− goto err_property;
1317− }
1318− } else {
1319− if ((pos->w < pp->crop_min.hsize) ||
1320− (sz->hsize > pp->crop_max.hsize) ||
1321− (pos->h < pp->crop_min.vsize) ||
1322− (sz->vsize > pp->crop_max.vsize)) {
1323− DRM_ERROR("out of crop size.\n");
1324− goto err_property;
1325− }
1326− }
1327− }
1328−
1329− /* check for scale */
1330− if ((i == EXYNOS_DRM_OPS_DST) && (pp->scale)) {
1331− if (swap) {
1332− if ((pos->h < pp->scale_min.hsize) ||
1333− (sz->vsize > pp->scale_max.hsize) ||
1334− (pos->w < pp->scale_min.vsize) ||
1335− (sz->hsize > pp->scale_max.vsize)) {
1336− DRM_ERROR("out of scale size.\n");
1337− goto err_property;
1338− }
1339− } else {
1340− if ((pos->w < pp->scale_min.hsize) ||
1341− (sz->hsize > pp->scale_max.hsize) ||
1342− (pos->h < pp->scale_min.vsize) ||
1343− (sz->vsize > pp->scale_max.vsize)) {
1344− DRM_ERROR("out of scale size.\n");
1345− goto err_property;
1346− }
1347− }
1348− }
964+ ctx->task = NULL;
965+ pm_runtime_mark_last_busy(ctx->dev);
966+ pm_runtime_put_autosuspend(ctx->dev);
967+ exynos_drm_ipp_task_done(task, 0);
1349968 }
1350969
1351− return 0;
970+ fimc_dst_set_buf_seq(ctx, buf_id, false);
971+ fimc_stop(ctx);
1352972
1353−err_property:
1354− for_each_ipp_ops(i) {
1355− if ((i == EXYNOS_DRM_OPS_SRC) &&
1356− (property->cmd == IPP_CMD_WB))
1357− continue;
1358−
1359− config = &property->config[i];
1360− pos = &config->pos;
1361− sz = &config->sz;
1362−
1363− DRM_ERROR("[%s]f[%d]r[%d]pos[%d %d %d %d]sz[%d %d]\n",
1364− i ? "dst" : "src", config->flip, config->degree,
1365− pos->x, pos->y, pos->w, pos->h,
1366− sz->hsize, sz->vsize);
1367− }
1368−
1369− return -EINVAL;
973+ return IRQ_HANDLED;
1370974 }
1371975
1372976 static void fimc_clear_addr(struct fimc_context *ctx)
@@ -1386,10 +990,8 @@ static void fimc_clear_addr(struct fimc_context *ctx) · 13 unmodified lines
1386990 }
1387991 }
1388992
1389−static int fimc_ippdrv_reset(struct device *dev)
993+static void fimc_reset(struct fimc_context *ctx)
1390994 {
1391− struct fimc_context *ctx = get_fimc_context(dev);
1392−
1393995 /* reset h/w block */
1394996 fimc_sw_reset(ctx);
1395997
@@ -1397,82 +999,26 @@ static int fimc_ippdrv_reset(struct device *dev) · 1 unmodified line
1397999 memset(&ctx->sc, 0x0, sizeof(ctx->sc));
13981000
13991001 fimc_clear_addr(ctx);
1400−
1401− return 0;
14021002 }
14031003
1404−static int fimc_ippdrv_start(struct device *dev, enum drm_exynos_ipp_cmd cmd)
1004+static void fimc_start(struct fimc_context *ctx)
14051005 {
1406− struct fimc_context *ctx = get_fimc_context(dev);
1407− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
1408− struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;
1409− struct drm_exynos_ipp_property *property;
1410− struct drm_exynos_ipp_config *config;
1411− struct drm_exynos_pos img_pos[EXYNOS_DRM_OPS_MAX];
1412− struct drm_exynos_ipp_set_wb set_wb;
1413− int ret, i;
14141006 u32 cfg0, cfg1;
14151007
1416− DRM_DEBUG_KMS("cmd[%d]\n", cmd);
1417−
1418− if (!c_node) {
1419− DRM_ERROR("failed to get c_node.\n");
1420− return -EINVAL;
1421− }
1422−
1423− property = &c_node->property;
1424−
14251008 fimc_mask_irq(ctx, true);
14261009
1427− for_each_ipp_ops(i) {
1428− config = &property->config[i];
1429− img_pos[i] = config->pos;
1430− }
1431−
1432− ret = fimc_set_prescaler(ctx, &ctx->sc,
1433− &img_pos[EXYNOS_DRM_OPS_SRC],
1434− &img_pos[EXYNOS_DRM_OPS_DST]);
1435− if (ret) {
1436− dev_err(dev, "failed to set prescaler.\n");
1437− return ret;
1438− }
1439−
1440− /* If set ture, we can save jpeg about screen */
1010+ /* If set true, we can save jpeg about screen */
14411011 fimc_handle_jpeg(ctx, false);
14421012 fimc_set_scaler(ctx, &ctx->sc);
14431013
1444− switch (cmd) {
1445− case IPP_CMD_M2M:
1446− fimc_set_type_ctrl(ctx, FIMC_WB_NONE);
1447− fimc_handle_lastend(ctx, false);
1448−
1449− /* setup dma */
1450− cfg0 = fimc_read(ctx, EXYNOS_MSCTRL);
1451− cfg0 &= ~EXYNOS_MSCTRL_INPUT_MASK;
1452− cfg0 |= EXYNOS_MSCTRL_INPUT_MEMORY;
1453− fimc_write(ctx, cfg0, EXYNOS_MSCTRL);
1454− break;
1455− case IPP_CMD_WB:
1456− fimc_set_type_ctrl(ctx, FIMC_WB_A);
1457− fimc_handle_lastend(ctx, true);
1458−
1459− /* setup FIMD */
1460− ret = fimc_set_camblk_fimd0_wb(ctx);
1461− if (ret < 0) {
1462− dev_err(dev, "camblk setup failed.\n");
1463− return ret;
1464− }
1014+ fimc_set_type_ctrl(ctx);
1015+ fimc_handle_lastend(ctx, false);
14651016
1466− set_wb.enable = 1;
1467− set_wb.refresh = property->refresh_rate;
1468− exynos_drm_ippnb_send_event(IPP_SET_WRITEBACK, (void *)&set_wb);
1469− break;
1470− case IPP_CMD_OUTPUT:
1471− default:
1472− ret = -EINVAL;
1473− dev_err(dev, "invalid operations.\n");
1474− return ret;
1475− }
1017+ /* setup dma */
1018+ cfg0 = fimc_read(ctx, EXYNOS_MSCTRL);
1019+ cfg0 &= ~EXYNOS_MSCTRL_INPUT_MASK;
1020+ cfg0 |= EXYNOS_MSCTRL_INPUT_MEMORY;
1021+ fimc_write(ctx, cfg0, EXYNOS_MSCTRL);
14761022
14771023 /* Reset status */
14781024 fimc_write(ctx, 0x0, EXYNOS_CISTATUS);
@@ -1498,36 +1044,18 @@ static int fimc_ippdrv_start(struct device *dev, enum drm_exynos_ipp_cmd cmd) · 19 unmodified lines
14981044
14991045 fimc_clear_bits(ctx, EXYNOS_CIOCTRL, EXYNOS_CIOCTRL_WEAVE_MASK);
15001046
1501− if (cmd == IPP_CMD_M2M)
1502− fimc_set_bits(ctx, EXYNOS_MSCTRL, EXYNOS_MSCTRL_ENVID);
1503−
1504− return 0;
1047+ fimc_set_bits(ctx, EXYNOS_MSCTRL, EXYNOS_MSCTRL_ENVID);
15051048 }
15061049
1507−static void fimc_ippdrv_stop(struct device *dev, enum drm_exynos_ipp_cmd cmd)
1050+static void fimc_stop(struct fimc_context *ctx)
15081051 {
1509− struct fimc_context *ctx = get_fimc_context(dev);
1510− struct drm_exynos_ipp_set_wb set_wb = {0, 0};
15111052 u32 cfg;
15121053
1513− DRM_DEBUG_KMS("cmd[%d]\n", cmd);
1514−
1515− switch (cmd) {
1516− case IPP_CMD_M2M:
1517− /* Source clear */
1518− cfg = fimc_read(ctx, EXYNOS_MSCTRL);
1519− cfg &= ~EXYNOS_MSCTRL_INPUT_MASK;
1520− cfg &= ~EXYNOS_MSCTRL_ENVID;
1521− fimc_write(ctx, cfg, EXYNOS_MSCTRL);
1522− break;
1523− case IPP_CMD_WB:
1524− exynos_drm_ippnb_send_event(IPP_SET_WRITEBACK, (void *)&set_wb);
1525− break;
1526− case IPP_CMD_OUTPUT:
1527− default:
1528− dev_err(dev, "invalid operations.\n");
1529− break;
1530− }
1054+ /* Source clear */
1055+ cfg = fimc_read(ctx, EXYNOS_MSCTRL);
1056+ cfg &= ~EXYNOS_MSCTRL_INPUT_MASK;
1057+ cfg &= ~EXYNOS_MSCTRL_ENVID;
1058+ fimc_write(ctx, cfg, EXYNOS_MSCTRL);
15311059
15321060 fimc_mask_irq(ctx, false);
15331061
@@ -1545,6 +1073,87 @@ static void fimc_ippdrv_stop(struct device *dev, enum drm_exynos_ipp_cmd cmd) · 11 unmodified lines
15451073 fimc_set_bits(ctx, EXYNOS_CIGCTRL, EXYNOS_CIGCTRL_IRQ_END_DISABLE);
15461074 }
15471075
1076+static int fimc_commit(struct exynos_drm_ipp *ipp,
1077+ struct exynos_drm_ipp_task *task)
1078+{
1079+ struct fimc_context *ctx =
1080+ container_of(ipp, struct fimc_context, ipp);
1081+
1082+ pm_runtime_get_sync(ctx->dev);
1083+ ctx->task = task;
1084+
1085+ fimc_src_set_fmt(ctx, task->src.buf.fourcc, task->src.buf.modifier);
1086+ fimc_src_set_size(ctx, &task->src);
1087+ fimc_src_set_transf(ctx, DRM_MODE_ROTATE_0);
1088+ fimc_src_set_addr(ctx, &task->src);
1089+ fimc_dst_set_fmt(ctx, task->dst.buf.fourcc, task->dst.buf.modifier);
1090+ fimc_dst_set_transf(ctx, task->transform.rotation);
1091+ fimc_dst_set_size(ctx, &task->dst);
1092+ fimc_dst_set_addr(ctx, &task->dst);
1093+ fimc_set_prescaler(ctx, &ctx->sc, &task->src.rect, &task->dst.rect);
1094+ fimc_start(ctx);
1095+
1096+ return 0;
1097+}
1098+
1099+static void fimc_abort(struct exynos_drm_ipp *ipp,
1100+ struct exynos_drm_ipp_task *task)
1101+{
1102+ struct fimc_context *ctx =
1103+ container_of(ipp, struct fimc_context, ipp);
1104+
1105+ fimc_reset(ctx);
1106+
1107+ if (ctx->task) {
1108+ struct exynos_drm_ipp_task *task = ctx->task;
1109+
1110+ ctx->task = NULL;
1111+ pm_runtime_mark_last_busy(ctx->dev);
1112+ pm_runtime_put_autosuspend(ctx->dev);
1113+ exynos_drm_ipp_task_done(task, -EIO);
1114+ }
1115+}
1116+
1117+static struct exynos_drm_ipp_funcs ipp_funcs = {
1118+ .commit = fimc_commit,
1119+ .abort = fimc_abort,
1120+};
1121+
1122+static int fimc_bind(struct device *dev, struct device *master, void *data)
1123+{
1124+ struct fimc_context *ctx = dev_get_drvdata(dev);
1125+ struct drm_device *drm_dev = data;
1126+ struct exynos_drm_ipp *ipp = &ctx->ipp;
1127+
1128+ ctx->drm_dev = drm_dev;
1129+ drm_iommu_attach_device(drm_dev, dev);
1130+
1131+ exynos_drm_ipp_register(drm_dev, ipp, &ipp_funcs,
1132+ DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE |
1133+ DRM_EXYNOS_IPP_CAP_SCALE | DRM_EXYNOS_IPP_CAP_CONVERT,
1134+ ctx->formats, ctx->num_formats, "fimc");
1135+
1136+ dev_info(dev, "The exynos fimc has been probed successfully\n");
1137+
1138+ return 0;
1139+}
1140+
1141+static void fimc_unbind(struct device *dev, struct device *master,
1142+ void *data)
1143+{
1144+ struct fimc_context *ctx = dev_get_drvdata(dev);
1145+ struct drm_device *drm_dev = data;
1146+ struct exynos_drm_ipp *ipp = &ctx->ipp;
1147+
1148+ exynos_drm_ipp_unregister(drm_dev, ipp);
1149+ drm_iommu_detach_device(drm_dev, dev);
1150+}
1151+
1152+static const struct component_ops fimc_component_ops = {
1153+ .bind = fimc_bind,
1154+ .unbind = fimc_unbind,
1155+};
1156+
15481157 static void fimc_put_clocks(struct fimc_context *ctx)
15491158 {
15501159 int i;
@@ -1559,7 +1168,7 @@ static void fimc_put_clocks(struct fimc_context *ctx) · 8 unmodified lines
15591168
15601169 static int fimc_setup_clocks(struct fimc_context *ctx)
15611170 {
1562− struct device *fimc_dev = ctx->ippdrv.dev;
1171+ struct device *fimc_dev = ctx->dev;
15631172 struct device *dev;
15641173 int ret, i;
15651174
@@ -1574,8 +1183,6 @@ static int fimc_setup_clocks(struct fimc_context *ctx) · 8 unmodified lines
15741183
15751184 ctx->clocks[i] = clk_get(dev, fimc_clock_names[i]);
15761185 if (IS_ERR(ctx->clocks[i])) {
1577− if (i >= FIMC_CLK_MUX)
1578− break;
15791186 ret = PTR_ERR(ctx->clocks[i]);
15801187 dev_err(fimc_dev, "failed to get clock: %s\n",
15811188 fimc_clock_names[i]);
@@ -1583,20 +1190,6 @@ static int fimc_setup_clocks(struct fimc_context *ctx) · 1 unmodified line
15831190 }
15841191 }
15851192
1586− /* Optional FIMC LCLK parent clock setting */
1587− if (!IS_ERR(ctx->clocks[FIMC_CLK_PARENT])) {
1588− ret = clk_set_parent(ctx->clocks[FIMC_CLK_MUX],
1589− ctx->clocks[FIMC_CLK_PARENT]);
1590− if (ret < 0) {
1591− dev_err(fimc_dev, "failed to set parent.\n");
1592− goto e_clk_free;
1593− }
1594− }
1595−
1596− ret = clk_set_rate(ctx->clocks[FIMC_CLK_LCLK], ctx->clk_frequency);
1597− if (ret < 0)
1598− goto e_clk_free;
1599−
16001193 ret = clk_prepare_enable(ctx->clocks[FIMC_CLK_LCLK]);
16011194 if (!ret)
16021195 return ret;
@@ -1605,57 +1198,118 @@ e_clk_free: · 2 unmodified lines
16051198 return ret;
16061199 }
16071200
1608−static int fimc_parse_dt(struct fimc_context *ctx)
1201+int exynos_drm_check_fimc_device(struct device *dev)
16091202 {
1610− struct device_node *node = ctx->ippdrv.dev->of_node;
1203+ unsigned int id = of_alias_get_id(dev->of_node, "fimc");
16111204
1612− /* Handle only devices that support the LCD Writeback data path */
1613− if (!of_property_read_bool(node, "samsung,lcd-wb"))
1614− return -ENODEV;
1205+ if (id >= 0 && (BIT(id) & fimc_mask))
1206+ return 0;
1207+ return -ENODEV;
1208+}
16151209
1616− if (of_property_read_u32(node, "clock-frequency",
1617− &ctx->clk_frequency))
1618− ctx->clk_frequency = FIMC_DEFAULT_LCLK_FREQUENCY;
1210+static const unsigned int fimc_formats[] = {
1211+ DRM_FORMAT_XRGB8888, DRM_FORMAT_RGB565,
1212+ DRM_FORMAT_NV12, DRM_FORMAT_NV16, DRM_FORMAT_NV21, DRM_FORMAT_NV61,
1213+ DRM_FORMAT_UYVY, DRM_FORMAT_VYUY, DRM_FORMAT_YUYV, DRM_FORMAT_YVYU,
1214+ DRM_FORMAT_YUV420, DRM_FORMAT_YVU420, DRM_FORMAT_YUV422,
1215+ DRM_FORMAT_YUV444,
1216+};
16191217
1620− ctx->id = of_alias_get_id(node, "fimc");
1218+static const unsigned int fimc_tiled_formats[] = {
1219+ DRM_FORMAT_NV12, DRM_FORMAT_NV21,
1220+};
16211221
1622− if (ctx->id < 0) {
1623− dev_err(ctx->ippdrv.dev, "failed to get node alias id.\n");
1624− return -EINVAL;
1625− }
1222+static const struct drm_exynos_ipp_limit fimc_4210_limits_v1[] = {
1223+ { IPP_SIZE_LIMIT(BUFFER, .h = { 16, 8192, 8 }, .v = { 16, 8192, 2 }) },
1224+ { IPP_SIZE_LIMIT(AREA, .h = { 16, 4224, 2 }, .v = { 16, 0, 2 }) },
1225+ { IPP_SIZE_LIMIT(ROTATED, .h = { 128, 1920 }, .v = { 128, 0 }) },
1226+ { IPP_SCALE_LIMIT(.h = { (1 << 16) / 64, (1 << 16) * 64 },
1227+ .v = { (1 << 16) / 64, (1 << 16) * 64 }) },
1228+};
16261229
1627− return 0;
1628−}
1230+static const struct drm_exynos_ipp_limit fimc_4210_limits_v2[] = {
1231+ { IPP_SIZE_LIMIT(BUFFER, .h = { 16, 8192, 8 }, .v = { 16, 8192, 2 }) },
1232+ { IPP_SIZE_LIMIT(AREA, .h = { 16, 1920, 2 }, .v = { 16, 0, 2 }) },
1233+ { IPP_SIZE_LIMIT(ROTATED, .h = { 128, 1366 }, .v = { 128, 0 }) },
1234+ { IPP_SCALE_LIMIT(.h = { (1 << 16) / 64, (1 << 16) * 64 },
1235+ .v = { (1 << 16) / 64, (1 << 16) * 64 }) },
1236+};
1237+
1238+static const struct drm_exynos_ipp_limit fimc_4210_limits_tiled_v1[] = {
1239+ { IPP_SIZE_LIMIT(BUFFER, .h = { 128, 1920, 128 }, .v = { 32, 1920, 32 }) },
1240+ { IPP_SIZE_LIMIT(AREA, .h = { 128, 1920, 2 }, .v = { 128, 0, 2 }) },
1241+ { IPP_SCALE_LIMIT(.h = { (1 << 16) / 64, (1 << 16) * 64 },
1242+ .v = { (1 << 16) / 64, (1 << 16) * 64 }) },
1243+};
1244+
1245+static const struct drm_exynos_ipp_limit fimc_4210_limits_tiled_v2[] = {
1246+ { IPP_SIZE_LIMIT(BUFFER, .h = { 128, 1920, 128 }, .v = { 32, 1920, 32 }) },
1247+ { IPP_SIZE_LIMIT(AREA, .h = { 128, 1366, 2 }, .v = { 128, 0, 2 }) },
1248+ { IPP_SCALE_LIMIT(.h = { (1 << 16) / 64, (1 << 16) * 64 },
1249+ .v = { (1 << 16) / 64, (1 << 16) * 64 }) },
1250+};
16291251
16301252 static int fimc_probe(struct platform_device *pdev)
16311253 {
1254+ const struct drm_exynos_ipp_limit *limits;
1255+ struct exynos_drm_ipp_formats *formats;
16321256 struct device *dev = &pdev->dev;
16331257 struct fimc_context *ctx;
16341258 struct resource *res;
1635− struct exynos_drm_ippdrv *ippdrv;
16361259 int ret;
1260+ int i, j, num_limits, num_formats;
16371261
1638− if (!dev->of_node) {
1639− dev_err(dev, "device tree node not found.\n");
1262+ if (exynos_drm_check_fimc_device(dev) != 0)
16401263 return -ENODEV;
1641− }
16421264
16431265 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
16441266 if (!ctx)
16451267 return -ENOMEM;
16461268
1647− ctx->ippdrv.dev = dev;
1269+ ctx->dev = dev;
1270+ ctx->id = of_alias_get_id(dev->of_node, "fimc");
16481271
1649− ret = fimc_parse_dt(ctx);
1650− if (ret < 0)
1651− return ret;
1272+ /* construct formats/limits array */
1273+ num_formats = ARRAY_SIZE(fimc_formats) + ARRAY_SIZE(fimc_tiled_formats);
1274+ formats = devm_kzalloc(dev, sizeof(*formats) * num_formats, GFP_KERNEL);
1275+ if (!formats)
1276+ return -ENOMEM;
1277+
1278+ /* linear formats */
1279+ if (ctx->id < 3) {
1280+ limits = fimc_4210_limits_v1;
1281+ num_limits = ARRAY_SIZE(fimc_4210_limits_v1);
1282+ } else {
1283+ limits = fimc_4210_limits_v2;
1284+ num_limits = ARRAY_SIZE(fimc_4210_limits_v2);
1285+ }
1286+ for (i = 0; i < ARRAY_SIZE(fimc_formats); i++) {
1287+ formats[i].fourcc = fimc_formats[i];
1288+ formats[i].type = DRM_EXYNOS_IPP_FORMAT_SOURCE |
1289+ DRM_EXYNOS_IPP_FORMAT_DESTINATION;
1290+ formats[i].limits = limits;
1291+ formats[i].num_limits = num_limits;
1292+ }
16521293
1653− ctx->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node,
1654− "samsung,sysreg");
1655− if (IS_ERR(ctx->sysreg)) {
1656− dev_err(dev, "syscon regmap lookup failed.\n");
1657− return PTR_ERR(ctx->sysreg);
1294+ /* tiled formats */
1295+ if (ctx->id < 3) {
1296+ limits = fimc_4210_limits_tiled_v1;
1297+ num_limits = ARRAY_SIZE(fimc_4210_limits_tiled_v1);
1298+ } else {
1299+ limits = fimc_4210_limits_tiled_v2;
1300+ num_limits = ARRAY_SIZE(fimc_4210_limits_tiled_v2);
16581301 }
1302+ for (j = i, i = 0; i < ARRAY_SIZE(fimc_tiled_formats); j++, i++) {
1303+ formats[j].fourcc = fimc_tiled_formats[i];
1304+ formats[j].modifier = DRM_FORMAT_MOD_SAMSUNG_64_32_TILE;
1305+ formats[j].type = DRM_EXYNOS_IPP_FORMAT_SOURCE |
1306+ DRM_EXYNOS_IPP_FORMAT_DESTINATION;
1307+ formats[j].limits = limits;
1308+ formats[j].num_limits = num_limits;
1309+ }
1310+
1311+ ctx->formats = formats;
1312+ ctx->num_formats = num_formats;
16591313
16601314 /* resource memory */
16611315 ctx->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1670,9 +1324,8 @@ static int fimc_probe(struct platform_device *pdev) · 8 unmodified lines
16701324 return -ENOENT;
16711325 }
16721326
1673− ctx->irq = res->start;
1674− ret = devm_request_threaded_irq(dev, ctx->irq, NULL, fimc_irq_handler,
1675− IRQF_ONESHOT, "drm_fimc", ctx);
1327+ ret = devm_request_irq(dev, res->start, fimc_irq_handler,
1328+ 0, dev_name(dev), ctx);
16761329 if (ret < 0) {
16771330 dev_err(dev, "failed to request irq.\n");
16781331 return ret;
@@ -1682,39 +1335,24 @@ static int fimc_probe(struct platform_device *pdev) · 3 unmodified lines
16821335 if (ret < 0)
16831336 return ret;
16841337
1685− ippdrv = &ctx->ippdrv;
1686− ippdrv->ops[EXYNOS_DRM_OPS_SRC] = &fimc_src_ops;
1687− ippdrv->ops[EXYNOS_DRM_OPS_DST] = &fimc_dst_ops;
1688− ippdrv->check_property = fimc_ippdrv_check_property;
1689− ippdrv->reset = fimc_ippdrv_reset;
1690− ippdrv->start = fimc_ippdrv_start;
1691− ippdrv->stop = fimc_ippdrv_stop;
1692− ret = fimc_init_prop_list(ippdrv);
1693− if (ret < 0) {
1694− dev_err(dev, "failed to init property list.\n");
1695− goto err_put_clk;
1696− }
1697−
1698− DRM_DEBUG_KMS("id[%d]ippdrv[%pK]\n", ctx->id, ippdrv);
1699−
17001338 spin_lock_init(&ctx->lock);
17011339 platform_set_drvdata(pdev, ctx);
17021340
1341+ pm_runtime_use_autosuspend(dev);
1342+ pm_runtime_set_autosuspend_delay(dev, FIMC_AUTOSUSPEND_DELAY);
17031343 pm_runtime_enable(dev);
17041344
1705− ret = exynos_drm_ippdrv_register(ippdrv);
1706− if (ret < 0) {
1707− dev_err(dev, "failed to register drm fimc device.\n");
1345+ ret = component_add(dev, &fimc_component_ops);
1346+ if (ret)
17081347 goto err_pm_dis;
1709− }
17101348
17111349 dev_info(dev, "drm fimc registered successfully.\n");
17121350
17131351 return 0;
17141352
17151353 err_pm_dis:
1354+ pm_runtime_dont_use_autosuspend(dev);
17161355 pm_runtime_disable(dev);
1717−err_put_clk:
17181356 fimc_put_clocks(ctx);
17191357
17201358 return ret;
@@ -1724,42 +1362,24 @@ static int fimc_remove(struct platform_device *pdev) · 3 unmodified lines
17241362 {
17251363 struct device *dev = &pdev->dev;
17261364 struct fimc_context *ctx = get_fimc_context(dev);
1727− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
17281365
1729− exynos_drm_ippdrv_unregister(ippdrv);
1366+ component_del(dev, &fimc_component_ops);
1367+ pm_runtime_dont_use_autosuspend(dev);
1368+ pm_runtime_disable(dev);
17301369
17311370 fimc_put_clocks(ctx);
1732− pm_runtime_set_suspended(dev);
1733− pm_runtime_disable(dev);
17341371
17351372 return 0;
17361373 }
17371374
17381375 #ifdef CONFIG_PM
1739−static int fimc_clk_ctrl(struct fimc_context *ctx, bool enable)
1740−{
1741− DRM_DEBUG_KMS("enable[%d]\n", enable);
1742−
1743− if (enable) {
1744− clk_prepare_enable(ctx->clocks[FIMC_CLK_GATE]);
1745− clk_prepare_enable(ctx->clocks[FIMC_CLK_WB_A]);
1746− ctx->suspended = false;
1747− } else {
1748− clk_disable_unprepare(ctx->clocks[FIMC_CLK_GATE]);
1749− clk_disable_unprepare(ctx->clocks[FIMC_CLK_WB_A]);
1750− ctx->suspended = true;
1751− }
1752−
1753− return 0;
1754−}
1755−
17561376 static int fimc_runtime_suspend(struct device *dev)
17571377 {
17581378 struct fimc_context *ctx = get_fimc_context(dev);
17591379
17601380 DRM_DEBUG_KMS("id[%d]\n", ctx->id);
1761−
1762− return fimc_clk_ctrl(ctx, false);
1381+ clk_disable_unprepare(ctx->clocks[FIMC_CLK_GATE]);
1382+ return 0;
17631383 }
17641384
17651385 static int fimc_runtime_resume(struct device *dev)
@@ -1767,8 +1387,7 @@ static int fimc_runtime_resume(struct device *dev) · 1 unmodified line
17671387 struct fimc_context *ctx = get_fimc_context(dev);
17681388
17691389 DRM_DEBUG_KMS("id[%d]\n", ctx->id);
1770−
1771− return fimc_clk_ctrl(ctx, true);
1390+ return clk_prepare_enable(ctx->clocks[FIMC_CLK_GATE]);
17721391 }
17731392 #endif
17741393
@@ -1795,4 +1414,3 @@ struct platform_driver fimc_driver = { · 20 unmodified lines
17951414 .pm = &fimc_pm_ops,
17961415 },
17971416 };
1798−
drivers/gpu/drm/exynos/exynos_drm_fimc.h+0−23
@@ -1,23 +0,0 @@
1−/*
2− * Copyright (c) 2012 Samsung Electronics Co., Ltd.
3− *
4− * Authors:
5− * Eunchul Kim <chulspro.kim@samsung.com>
6− * Jinyoung Jeon <jy0.jeon@samsung.com>
7− * Sangmin Lee <lsmin.lee@samsung.com>
8− *
9− * This program is free software; you can redistribute it and/or modify it
10− * under the terms of the GNU General Public License as published by the
11− * Free Software Foundation; either version 2 of the License, or (at your
12− * option) any later version.
13− */
14−
15−#ifndef _EXYNOS_DRM_FIMC_H_
16−#define _EXYNOS_DRM_FIMC_H_
17−
18−/*
19− * TODO
20− * FIMD output interface notifier callback.
21− */
22−
23−#endif /* _EXYNOS_DRM_FIMC_H_ */
drivers/gpu/drm/exynos/exynos_drm_fimd.c+8−0
@@ -121,6 +121,12 @@ static struct fimd_driver_data s3c64xx_fimd_driver_data = { · 120 unmodified lines
121121 .has_limited_fmt = 1,
122122 };
123123
124+static struct fimd_driver_data s5pv210_fimd_driver_data = {
125+ .timing_base = 0x0,
126+ .has_shadowcon = 1,
127+ .has_clksel = 1,
128+};
129+
124130 static struct fimd_driver_data exynos3_fimd_driver_data = {
125131 .timing_base = 0x20000,
126132 .lcdblk_offset = 0x210,
@@ -193,6 +199,8 @@ struct fimd_context { · 66 unmodified lines
193199 static const struct of_device_id fimd_driver_dt_match[] = {
194200 { .compatible = "samsung,s3c6400-fimd",
195201 .data = &s3c64xx_fimd_driver_data },
202+ { .compatible = "samsung,s5pv210-fimd",
203+ .data = &s5pv210_fimd_driver_data },
196204 { .compatible = "samsung,exynos3250-fimd",
197205 .data = &exynos3_fimd_driver_data },
198206 { .compatible = "samsung,exynos4210-fimd",
drivers/gpu/drm/exynos/exynos_drm_gem.c+4−17
@@ -431,37 +431,24 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv, · 430 unmodified lines
431431 return 0;
432432 }
433433
434−int exynos_drm_gem_fault(struct vm_fault *vmf)
434+vm_fault_t exynos_drm_gem_fault(struct vm_fault *vmf)
435435 {
436436 struct vm_area_struct *vma = vmf->vma;
437437 struct drm_gem_object *obj = vma->vm_private_data;
438438 struct exynos_drm_gem *exynos_gem = to_exynos_gem(obj);
439439 unsigned long pfn;
440440 pgoff_t page_offset;
441− int ret;
442441
443442 page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT;
444443
445444 if (page_offset >= (exynos_gem->size >> PAGE_SHIFT)) {
446445 DRM_ERROR("invalid page offset\n");
447− ret = -EINVAL;
448− goto out;
446+ return VM_FAULT_SIGBUS;
449447 }
450448
451449 pfn = page_to_pfn(exynos_gem->pages[page_offset]);
452− ret = vm_insert_mixed(vma, vmf->address, __pfn_to_pfn_t(pfn, PFN_DEV));
453−
454−out:
455− switch (ret) {
456− case 0:
457− case -ERESTARTSYS:
458− case -EINTR:
459− return VM_FAULT_NOPAGE;
460− case -ENOMEM:
461− return VM_FAULT_OOM;
462− default:
463− return VM_FAULT_SIGBUS;
464− }
450+ return vmf_insert_mixed(vma, vmf->address,
451+ __pfn_to_pfn_t(pfn, PFN_DEV));
465452 }
466453
467454 static int exynos_drm_gem_mmap_obj(struct drm_gem_object *obj,
drivers/gpu/drm/exynos/exynos_drm_gem.h+2−1
@@ -13,6 +13,7 @@ · 12 unmodified lines
1313 #define _EXYNOS_DRM_GEM_H_
1414
1515 #include <drm/drm_gem.h>
16+#include <linux/mm_types.h>
1617
1718 #define to_exynos_gem(x) container_of(x, struct exynos_drm_gem, base)
1819
@@ -111,7 +112,7 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv, · 92 unmodified lines
111112 struct drm_mode_create_dumb *args);
112113
113114 /* page fault handler and mmap fault address(virtual) to physical memory. */
114−int exynos_drm_gem_fault(struct vm_fault *vmf);
115+vm_fault_t exynos_drm_gem_fault(struct vm_fault *vmf);
115116
116117 /* set vm_flags and we can change the vm attribute to other one at here. */
117118 int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
drivers/gpu/drm/exynos/exynos_drm_gsc.c+335−740
@@ -12,18 +12,20 @@ · 11 unmodified lines
1212 *
1313 */
1414 #include <linux/kernel.h>
15+#include <linux/component.h>
1516 #include <linux/platform_device.h>
1617 #include <linux/clk.h>
1718 #include <linux/pm_runtime.h>
1819 #include <linux/mfd/syscon.h>
20+#include <linux/of_device.h>
1921 #include <linux/regmap.h>
2022
2123 #include <drm/drmP.h>
2224 #include <drm/exynos_drm.h>
2325 #include "regs-gsc.h"
2426 #include "exynos_drm_drv.h"
27+#include "exynos_drm_iommu.h"
2528 #include "exynos_drm_ipp.h"
26−#include "exynos_drm_gsc.h"
2729
2830 /*
2931 * GSC stands for General SCaler and
@@ -31,26 +33,10 @@ · 1 unmodified line
3133 * input DMA reads image data from the memory.
3234 * output DMA writes image data to memory.
3335 * GSC supports image rotation and image effect functions.
34− *
35− * M2M operation : supports crop/scale/rotation/csc so on.
36− * Memory ----> GSC H/W ----> Memory.
37− * Writeback operation : supports cloned screen with FIMD.
38− * FIMD ----> GSC H/W ----> Memory.
39− * Output operation : supports direct display using local path.
40− * Memory ----> GSC H/W ----> FIMD, Mixer.
4136 */
4237
43−/*
44− * TODO
45− * 1. check suspend/resume api if needed.
46− * 2. need to check use case platform_device_id.
47− * 3. check src/dst size with, height.
48− * 4. added check_prepare api for right register.
49− * 5. need to add supported list in prop_list.
50− * 6. check prescaler/scaler optimization.
51− */
5238
53−#define GSC_MAX_DEVS 4
39+#define GSC_MAX_CLOCKS 8
5440 #define GSC_MAX_SRC 4
5541 #define GSC_MAX_DST 16
5642 #define GSC_RESET_TIMEOUT 50
@@ -65,8 +51,6 @@ · 8 unmodified lines
6551 #define GSC_SC_DOWN_RATIO_4_8 131072
6652 #define GSC_SC_DOWN_RATIO_3_8 174762
6753 #define GSC_SC_DOWN_RATIO_2_8 262144
68−#define GSC_REFRESH_MIN 12
69−#define GSC_REFRESH_MAX 60
7054 #define GSC_CROP_MAX 8192
7155 #define GSC_CROP_MIN 32
7256 #define GSC_SCALE_MAX 4224
@@ -77,10 +61,9 @@ · 4 unmodified lines
7761 #define GSC_COEF_H_8T 8
7862 #define GSC_COEF_V_4T 4
7963 #define GSC_COEF_DEPTH 3
64+#define GSC_AUTOSUSPEND_DELAY 2000
8065
8166 #define get_gsc_context(dev) platform_get_drvdata(to_platform_device(dev))
82−#define get_ctx_from_ippdrv(ippdrv) container_of(ippdrv,\
83− struct gsc_context, ippdrv);
8467 #define gsc_read(offset) readl(ctx->regs + (offset))
8568 #define gsc_write(cfg, offset) writel(cfg, ctx->regs + (offset))
8669
@@ -103,51 +86,48 @@ struct gsc_scaler { · 16 unmodified lines
10386 unsigned long main_vratio;
10487 };
10588
106−/*
107− * A structure of scaler capability.
108− *
109− * find user manual 49.2 features.
110− * @tile_w: tile mode or rotation width.
111− * @tile_h: tile mode or rotation height.
112− * @w: other cases width.
113− * @h: other cases height.
114− */
115−struct gsc_capability {
116− /* tile or rotation */
117− u32 tile_w;
118− u32 tile_h;
119− /* other cases */
120− u32 w;
121− u32 h;
122−};
123−
12489 /*
12590 * A structure of gsc context.
12691 *
127− * @ippdrv: prepare initialization using ippdrv.
12892 * @regs_res: register resources.
12993 * @regs: memory mapped io registers.
130− * @sysreg: handle to SYSREG block regmap.
131− * @lock: locking of operations.
13294 * @gsc_clk: gsc gate clock.
13395 * @sc: scaler infomations.
13496 * @id: gsc id.
13597 * @irq: irq number.
13698 * @rotation: supports rotation of src.
137− * @suspended: qos operations.
13899 */
139100 struct gsc_context {
140− struct exynos_drm_ippdrv ippdrv;
101+ struct exynos_drm_ipp ipp;
102+ struct drm_device *drm_dev;
103+ struct device *dev;
104+ struct exynos_drm_ipp_task *task;
105+ struct exynos_drm_ipp_formats *formats;
106+ unsigned int num_formats;
107+
141108 struct resource *regs_res;
142109 void __iomem *regs;
143− struct regmap *sysreg;
144− struct mutex lock;
145− struct clk *gsc_clk;
110+ const char **clk_names;
111+ struct clk *clocks[GSC_MAX_CLOCKS];
112+ int num_clocks;
146113 struct gsc_scaler sc;
147114 int id;
148115 int irq;
149116 bool rotation;
150− bool suspended;
117+};
118+
119+/**
120+ * struct gsc_driverdata - per device type driver data for init time.
121+ *
122+ * @limits: picture size limits array
123+ * @clk_names: names of clocks needed by this variant
124+ * @num_clocks: the number of clocks needed by this variant
125+ */
126+struct gsc_driverdata {
127+ const struct drm_exynos_ipp_limit *limits;
128+ int num_limits;
129+ const char *clk_names[GSC_MAX_CLOCKS];
130+ int num_clocks;
151131 };
152132
153133 /* 8-tap Filter Coefficient */
@@ -438,25 +418,6 @@ static int gsc_sw_reset(struct gsc_context *ctx) · 284 unmodified lines
438418 return 0;
439419 }
440420
441−static void gsc_set_gscblk_fimd_wb(struct gsc_context *ctx, bool enable)
442−{
443− unsigned int gscblk_cfg;
444−
445− if (!ctx->sysreg)
446− return;
447−
448− regmap_read(ctx->sysreg, SYSREG_GSCBLK_CFG1, &gscblk_cfg);
449−
450− if (enable)
451− gscblk_cfg |= GSC_BLK_DISP1WB_DEST(ctx->id) |
452− GSC_BLK_GSCL_WB_IN_SRC_SEL(ctx->id) |
453− GSC_BLK_SW_RESET_WB_DEST(ctx->id);
454− else
455− gscblk_cfg |= GSC_BLK_PXLASYNC_LO_MASK_WB(ctx->id);
456−
457− regmap_write(ctx->sysreg, SYSREG_GSCBLK_CFG1, gscblk_cfg);
458−}
459−
460421 static void gsc_handle_irq(struct gsc_context *ctx, bool enable,
461422 bool overflow, bool done)
462423 {
@@ -487,10 +448,8 @@ static void gsc_handle_irq(struct gsc_context *ctx, bool enable, · 24 unmodified lines
487448 }
488449
489450
490−static int gsc_src_set_fmt(struct device *dev, u32 fmt)
451+static void gsc_src_set_fmt(struct gsc_context *ctx, u32 fmt)
491452 {
492− struct gsc_context *ctx = get_gsc_context(dev);
493− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
494453 u32 cfg;
495454
496455 DRM_DEBUG_KMS("fmt[0x%x]\n", fmt);
@@ -506,6 +465,7 @@ static int gsc_src_set_fmt(struct device *dev, u32 fmt) · 9 unmodified lines
506465 cfg |= GSC_IN_RGB565;
507466 break;
508467 case DRM_FORMAT_XRGB8888:
468+ case DRM_FORMAT_ARGB8888:
509469 cfg |= GSC_IN_XRGB8888;
510470 break;
511471 case DRM_FORMAT_BGRX8888:
@@ -548,115 +508,84 @@ static int gsc_src_set_fmt(struct device *dev, u32 fmt) · 36 unmodified lines
548508 cfg |= (GSC_IN_CHROMA_ORDER_CBCR |
549509 GSC_IN_YUV420_2P);
550510 break;
551− default:
552− dev_err(ippdrv->dev, "invalid target yuv order 0x%x.\n", fmt);
553− return -EINVAL;
554511 }
555512
556513 gsc_write(cfg, GSC_IN_CON);
557−
558− return 0;
559514 }
560515
561−static int gsc_src_set_transf(struct device *dev,
562− enum drm_exynos_degree degree,
563− enum drm_exynos_flip flip, bool *swap)
516+static void gsc_src_set_transf(struct gsc_context *ctx, unsigned int rotation)
564517 {
565− struct gsc_context *ctx = get_gsc_context(dev);
566− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
518+ unsigned int degree = rotation & DRM_MODE_ROTATE_MASK;
567519 u32 cfg;
568520
569− DRM_DEBUG_KMS("degree[%d]flip[0x%x]\n", degree, flip);
570−
571521 cfg = gsc_read(GSC_IN_CON);
572522 cfg &= ~GSC_IN_ROT_MASK;
573523
574524 switch (degree) {
575− case EXYNOS_DRM_DEGREE_0:
576− if (flip & EXYNOS_DRM_FLIP_VERTICAL)
525+ case DRM_MODE_ROTATE_0:
526+ if (rotation & DRM_MODE_REFLECT_Y)
577527 cfg |= GSC_IN_ROT_XFLIP;
578− if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
528+ if (rotation & DRM_MODE_REFLECT_X)
579529 cfg |= GSC_IN_ROT_YFLIP;
580530 break;
581− case EXYNOS_DRM_DEGREE_90:
582− if (flip & EXYNOS_DRM_FLIP_VERTICAL)
583− cfg |= GSC_IN_ROT_90_XFLIP;
584− else if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
585− cfg |= GSC_IN_ROT_90_YFLIP;
586− else
587− cfg |= GSC_IN_ROT_90;
531+ case DRM_MODE_ROTATE_90:
532+ cfg |= GSC_IN_ROT_90;
533+ if (rotation & DRM_MODE_REFLECT_Y)
534+ cfg |= GSC_IN_ROT_XFLIP;
535+ if (rotation & DRM_MODE_REFLECT_X)
536+ cfg |= GSC_IN_ROT_YFLIP;
588537 break;
589− case EXYNOS_DRM_DEGREE_180:
538+ case DRM_MODE_ROTATE_180:
590539 cfg |= GSC_IN_ROT_180;
591− if (flip & EXYNOS_DRM_FLIP_VERTICAL)
540+ if (rotation & DRM_MODE_REFLECT_Y)
592541 cfg &= ~GSC_IN_ROT_XFLIP;
593− if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
542+ if (rotation & DRM_MODE_REFLECT_X)
594543 cfg &= ~GSC_IN_ROT_YFLIP;
595544 break;
596− case EXYNOS_DRM_DEGREE_270:
545+ case DRM_MODE_ROTATE_270:
597546 cfg |= GSC_IN_ROT_270;
598− if (flip & EXYNOS_DRM_FLIP_VERTICAL)
547+ if (rotation & DRM_MODE_REFLECT_Y)
599548 cfg &= ~GSC_IN_ROT_XFLIP;
600− if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
549+ if (rotation & DRM_MODE_REFLECT_X)
601550 cfg &= ~GSC_IN_ROT_YFLIP;
602551 break;
603− default:
604− dev_err(ippdrv->dev, "invalid degree value %d.\n", degree);
605− return -EINVAL;
606552 }
607553
608554 gsc_write(cfg, GSC_IN_CON);
609555
610556 ctx->rotation = (cfg & GSC_IN_ROT_90) ? 1 : 0;
611− *swap = ctx->rotation;
612−
613− return 0;
614557 }
615558
616−static int gsc_src_set_size(struct device *dev, int swap,
617− struct drm_exynos_pos *pos, struct drm_exynos_sz *sz)
559+static void gsc_src_set_size(struct gsc_context *ctx,
560+ struct exynos_drm_ipp_buffer *buf)
618561 {
619− struct gsc_context *ctx = get_gsc_context(dev);
620− struct drm_exynos_pos img_pos = *pos;
621562 struct gsc_scaler *sc = &ctx->sc;
622563 u32 cfg;
623564
624− DRM_DEBUG_KMS("swap[%d]x[%d]y[%d]w[%d]h[%d]\n",
625− swap, pos->x, pos->y, pos->w, pos->h);
626−
627− if (swap) {
628− img_pos.w = pos->h;
629− img_pos.h = pos->w;
630− }
631−
632565 /* pixel offset */
633− cfg = (GSC_SRCIMG_OFFSET_X(img_pos.x) |
634− GSC_SRCIMG_OFFSET_Y(img_pos.y));
566+ cfg = (GSC_SRCIMG_OFFSET_X(buf->rect.x) |
567+ GSC_SRCIMG_OFFSET_Y(buf->rect.y));
635568 gsc_write(cfg, GSC_SRCIMG_OFFSET);
636569
637570 /* cropped size */
638− cfg = (GSC_CROPPED_WIDTH(img_pos.w) |
639− GSC_CROPPED_HEIGHT(img_pos.h));
571+ cfg = (GSC_CROPPED_WIDTH(buf->rect.w) |
572+ GSC_CROPPED_HEIGHT(buf->rect.h));
640573 gsc_write(cfg, GSC_CROPPED_SIZE);
641574
642− DRM_DEBUG_KMS("hsize[%d]vsize[%d]\n", sz->hsize, sz->vsize);
643−
644575 /* original size */
645576 cfg = gsc_read(GSC_SRCIMG_SIZE);
646577 cfg &= ~(GSC_SRCIMG_HEIGHT_MASK |
647578 GSC_SRCIMG_WIDTH_MASK);
648579
649− cfg |= (GSC_SRCIMG_WIDTH(sz->hsize) |
650− GSC_SRCIMG_HEIGHT(sz->vsize));
580+ cfg |= (GSC_SRCIMG_WIDTH(buf->buf.width) |
581+ GSC_SRCIMG_HEIGHT(buf->buf.height));
651582
652583 gsc_write(cfg, GSC_SRCIMG_SIZE);
653584
654585 cfg = gsc_read(GSC_IN_CON);
655586 cfg &= ~GSC_IN_RGB_TYPE_MASK;
656587
657− DRM_DEBUG_KMS("width[%d]range[%d]\n", pos->w, sc->range);
658−
659− if (pos->w >= GSC_WIDTH_ITU_709)
588+ if (buf->rect.w >= GSC_WIDTH_ITU_709)
660589 if (sc->range)
661590 cfg |= GSC_IN_RGB_HD_WIDE;
662591 else
@@ -668,103 +597,39 @@ static int gsc_src_set_size(struct device *dev, int swap, · 5 unmodified lines
668597 cfg |= GSC_IN_RGB_SD_NARROW;
669598
670599 gsc_write(cfg, GSC_IN_CON);
671−
672− return 0;
673600 }
674601
675−static int gsc_src_set_buf_seq(struct gsc_context *ctx, u32 buf_id,
676− enum drm_exynos_ipp_buf_type buf_type)
602+static void gsc_src_set_buf_seq(struct gsc_context *ctx, u32 buf_id,
603+ bool enqueue)
677604 {
678− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
679− bool masked;
605+ bool masked = !enqueue;
680606 u32 cfg;
681607 u32 mask = 0x00000001 << buf_id;
682608
683− DRM_DEBUG_KMS("buf_id[%d]buf_type[%d]\n", buf_id, buf_type);
684−
685609 /* mask register set */
686610 cfg = gsc_read(GSC_IN_BASE_ADDR_Y_MASK);
687611
688− switch (buf_type) {
689− case IPP_BUF_ENQUEUE:
690− masked = false;
691− break;
692− case IPP_BUF_DEQUEUE:
693− masked = true;
694− break;
695− default:
696− dev_err(ippdrv->dev, "invalid buf ctrl parameter.\n");
697− return -EINVAL;
698− }
699−
700612 /* sequence id */
701613 cfg &= ~mask;
702614 cfg |= masked << buf_id;
703615 gsc_write(cfg, GSC_IN_BASE_ADDR_Y_MASK);
704616 gsc_write(cfg, GSC_IN_BASE_ADDR_CB_MASK);
705617 gsc_write(cfg, GSC_IN_BASE_ADDR_CR_MASK);
706−
707− return 0;
708618 }
709619
710−static int gsc_src_set_addr(struct device *dev,
711− struct drm_exynos_ipp_buf_info *buf_info, u32 buf_id,
712− enum drm_exynos_ipp_buf_type buf_type)
620+static void gsc_src_set_addr(struct gsc_context *ctx, u32 buf_id,
621+ struct exynos_drm_ipp_buffer *buf)
713622 {
714− struct gsc_context *ctx = get_gsc_context(dev);
715− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
716− struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;
717− struct drm_exynos_ipp_property *property;
718−
719− if (!c_node) {
720− DRM_ERROR("failed to get c_node.\n");
721− return -EFAULT;
722− }
723−
724− property = &c_node->property;
725−
726− DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]buf_type[%d]\n",
727− property->prop_id, buf_id, buf_type);
728−
729− if (buf_id > GSC_MAX_SRC) {
730− dev_info(ippdrv->dev, "invalid buf_id %d.\n", buf_id);
731− return -EINVAL;
732− }
733−
734623 /* address register set */
735− switch (buf_type) {
736− case IPP_BUF_ENQUEUE:
737− gsc_write(buf_info->base[EXYNOS_DRM_PLANAR_Y],
738− GSC_IN_BASE_ADDR_Y(buf_id));
739− gsc_write(buf_info->base[EXYNOS_DRM_PLANAR_CB],
740− GSC_IN_BASE_ADDR_CB(buf_id));
741− gsc_write(buf_info->base[EXYNOS_DRM_PLANAR_CR],
742− GSC_IN_BASE_ADDR_CR(buf_id));
743− break;
744− case IPP_BUF_DEQUEUE:
745− gsc_write(0x0, GSC_IN_BASE_ADDR_Y(buf_id));
746− gsc_write(0x0, GSC_IN_BASE_ADDR_CB(buf_id));
747− gsc_write(0x0, GSC_IN_BASE_ADDR_CR(buf_id));
748− break;
749− default:
750− /* bypass */
751− break;
752− }
624+ gsc_write(buf->dma_addr[0], GSC_IN_BASE_ADDR_Y(buf_id));
625+ gsc_write(buf->dma_addr[1], GSC_IN_BASE_ADDR_CB(buf_id));
626+ gsc_write(buf->dma_addr[2], GSC_IN_BASE_ADDR_CR(buf_id));
753627
754− return gsc_src_set_buf_seq(ctx, buf_id, buf_type);
628+ gsc_src_set_buf_seq(ctx, buf_id, true);
755629 }
756630
757−static struct exynos_drm_ipp_ops gsc_src_ops = {
758− .set_fmt = gsc_src_set_fmt,
759− .set_transf = gsc_src_set_transf,
760− .set_size = gsc_src_set_size,
761− .set_addr = gsc_src_set_addr,
762−};
763−
764−static int gsc_dst_set_fmt(struct device *dev, u32 fmt)
631+static void gsc_dst_set_fmt(struct gsc_context *ctx, u32 fmt)
765632 {
766− struct gsc_context *ctx = get_gsc_context(dev);
767− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
768633 u32 cfg;
769634
770635 DRM_DEBUG_KMS("fmt[0x%x]\n", fmt);
@@ -779,8 +644,9 @@ static int gsc_dst_set_fmt(struct device *dev, u32 fmt) · 8 unmodified lines
779644 case DRM_FORMAT_RGB565:
780645 cfg |= GSC_OUT_RGB565;
781646 break;
647+ case DRM_FORMAT_ARGB8888:
782648 case DRM_FORMAT_XRGB8888:
783− cfg |= GSC_OUT_XRGB8888;
649+ cfg |= (GSC_OUT_XRGB8888 | GSC_OUT_GLOBAL_ALPHA(0xff));
784650 break;
785651 case DRM_FORMAT_BGRX8888:
786652 cfg |= (GSC_OUT_XRGB8888 | GSC_OUT_RB_SWAP);
@@ -819,69 +685,9 @@ static int gsc_dst_set_fmt(struct device *dev, u32 fmt) · 32 unmodified lines
819685 cfg |= (GSC_OUT_CHROMA_ORDER_CBCR |
820686 GSC_OUT_YUV420_2P);
821687 break;
822− default:
823− dev_err(ippdrv->dev, "invalid target yuv order 0x%x.\n", fmt);
824− return -EINVAL;
825688 }
826689
827690 gsc_write(cfg, GSC_OUT_CON);
828−
829− return 0;
830−}
831−
832−static int gsc_dst_set_transf(struct device *dev,
833− enum drm_exynos_degree degree,
834− enum drm_exynos_flip flip, bool *swap)
835−{
836− struct gsc_context *ctx = get_gsc_context(dev);
837− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
838− u32 cfg;
839−
840− DRM_DEBUG_KMS("degree[%d]flip[0x%x]\n", degree, flip);
841−
842− cfg = gsc_read(GSC_IN_CON);
843− cfg &= ~GSC_IN_ROT_MASK;
844−
845− switch (degree) {
846− case EXYNOS_DRM_DEGREE_0:
847− if (flip & EXYNOS_DRM_FLIP_VERTICAL)
848− cfg |= GSC_IN_ROT_XFLIP;
849− if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
850− cfg |= GSC_IN_ROT_YFLIP;
851− break;
852− case EXYNOS_DRM_DEGREE_90:
853− if (flip & EXYNOS_DRM_FLIP_VERTICAL)
854− cfg |= GSC_IN_ROT_90_XFLIP;
855− else if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
856− cfg |= GSC_IN_ROT_90_YFLIP;
857− else
858− cfg |= GSC_IN_ROT_90;
859− break;
860− case EXYNOS_DRM_DEGREE_180:
861− cfg |= GSC_IN_ROT_180;
862− if (flip & EXYNOS_DRM_FLIP_VERTICAL)
863− cfg &= ~GSC_IN_ROT_XFLIP;
864− if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
865− cfg &= ~GSC_IN_ROT_YFLIP;
866− break;
867− case EXYNOS_DRM_DEGREE_270:
868− cfg |= GSC_IN_ROT_270;
869− if (flip & EXYNOS_DRM_FLIP_VERTICAL)
870− cfg &= ~GSC_IN_ROT_XFLIP;
871− if (flip & EXYNOS_DRM_FLIP_HORIZONTAL)
872− cfg &= ~GSC_IN_ROT_YFLIP;
873− break;
874− default:
875− dev_err(ippdrv->dev, "invalid degree value %d.\n", degree);
876− return -EINVAL;
877− }
878−
879− gsc_write(cfg, GSC_IN_CON);
880−
881− ctx->rotation = (cfg & GSC_IN_ROT_90) ? 1 : 0;
882− *swap = ctx->rotation;
883−
884− return 0;
885691 }
886692
887693 static int gsc_get_ratio_shift(u32 src, u32 dst, u32 *ratio)
@@ -919,9 +725,9 @@ static void gsc_get_prescaler_shfactor(u32 hratio, u32 vratio, u32 *shfactor) · 31 unmodified lines
919725 }
920726
921727 static int gsc_set_prescaler(struct gsc_context *ctx, struct gsc_scaler *sc,
922− struct drm_exynos_pos *src, struct drm_exynos_pos *dst)
728+ struct drm_exynos_ipp_task_rect *src,
729+ struct drm_exynos_ipp_task_rect *dst)
923730 {
924− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
925731 u32 cfg;
926732 u32 src_w, src_h, dst_w, dst_h;
927733 int ret = 0;
@@ -939,13 +745,13 @@ static int gsc_set_prescaler(struct gsc_context *ctx, struct gsc_scaler *sc, · 11 unmodified lines
939745
940746 ret = gsc_get_ratio_shift(src_w, dst_w, &sc->pre_hratio);
941747 if (ret) {
942− dev_err(ippdrv->dev, "failed to get ratio horizontal.\n");
748+ dev_err(ctx->dev, "failed to get ratio horizontal.\n");
943749 return ret;
944750 }
945751
946752 ret = gsc_get_ratio_shift(src_h, dst_h, &sc->pre_vratio);
947753 if (ret) {
948− dev_err(ippdrv->dev, "failed to get ratio vertical.\n");
754+ dev_err(ctx->dev, "failed to get ratio vertical.\n");
949755 return ret;
950756 }
951757
@@ -1039,47 +845,37 @@ static void gsc_set_scaler(struct gsc_context *ctx, struct gsc_scaler *sc) · 87 unmodified lines
1039845 gsc_write(cfg, GSC_MAIN_V_RATIO);
1040846 }
1041847
1042−static int gsc_dst_set_size(struct device *dev, int swap,
1043− struct drm_exynos_pos *pos, struct drm_exynos_sz *sz)
848+static void gsc_dst_set_size(struct gsc_context *ctx,
849+ struct exynos_drm_ipp_buffer *buf)
1044850 {
1045− struct gsc_context *ctx = get_gsc_context(dev);
1046− struct drm_exynos_pos img_pos = *pos;
1047851 struct gsc_scaler *sc = &ctx->sc;
1048852 u32 cfg;
1049853
1050− DRM_DEBUG_KMS("swap[%d]x[%d]y[%d]w[%d]h[%d]\n",
1051− swap, pos->x, pos->y, pos->w, pos->h);
1052−
1053− if (swap) {
1054− img_pos.w = pos->h;
1055− img_pos.h = pos->w;
1056− }
1057−
1058854 /* pixel offset */
1059− cfg = (GSC_DSTIMG_OFFSET_X(pos->x) |
1060− GSC_DSTIMG_OFFSET_Y(pos->y));
855+ cfg = (GSC_DSTIMG_OFFSET_X(buf->rect.x) |
856+ GSC_DSTIMG_OFFSET_Y(buf->rect.y));
1061857 gsc_write(cfg, GSC_DSTIMG_OFFSET);
1062858
1063859 /* scaled size */
1064− cfg = (GSC_SCALED_WIDTH(img_pos.w) | GSC_SCALED_HEIGHT(img_pos.h));
860+ if (ctx->rotation)
861+ cfg = (GSC_SCALED_WIDTH(buf->rect.h) |
862+ GSC_SCALED_HEIGHT(buf->rect.w));
863+ else
864+ cfg = (GSC_SCALED_WIDTH(buf->rect.w) |
865+ GSC_SCALED_HEIGHT(buf->rect.h));
1065866 gsc_write(cfg, GSC_SCALED_SIZE);
1066867
1067− DRM_DEBUG_KMS("hsize[%d]vsize[%d]\n", sz->hsize, sz->vsize);
1068−
1069868 /* original size */
1070869 cfg = gsc_read(GSC_DSTIMG_SIZE);
1071− cfg &= ~(GSC_DSTIMG_HEIGHT_MASK |
1072− GSC_DSTIMG_WIDTH_MASK);
1073− cfg |= (GSC_DSTIMG_WIDTH(sz->hsize) |
1074− GSC_DSTIMG_HEIGHT(sz->vsize));
870+ cfg &= ~(GSC_DSTIMG_HEIGHT_MASK | GSC_DSTIMG_WIDTH_MASK);
871+ cfg |= GSC_DSTIMG_WIDTH(buf->buf.width) |
872+ GSC_DSTIMG_HEIGHT(buf->buf.height);
1075873 gsc_write(cfg, GSC_DSTIMG_SIZE);
1076874
1077875 cfg = gsc_read(GSC_OUT_CON);
1078876 cfg &= ~GSC_OUT_RGB_TYPE_MASK;
1079877
1080− DRM_DEBUG_KMS("width[%d]range[%d]\n", pos->w, sc->range);
1081−
1082− if (pos->w >= GSC_WIDTH_ITU_709)
878+ if (buf->rect.w >= GSC_WIDTH_ITU_709)
1083879 if (sc->range)
1084880 cfg |= GSC_OUT_RGB_HD_WIDE;
1085881 else
@@ -1091,8 +887,6 @@ static int gsc_dst_set_size(struct device *dev, int swap, · 5 unmodified lines
1091887 cfg |= GSC_OUT_RGB_SD_NARROW;
1092888
1093889 gsc_write(cfg, GSC_OUT_CON);
1094−
1095− return 0;
1096890 }
1097891
1098892 static int gsc_dst_get_buf_seq(struct gsc_context *ctx)
@@ -1111,35 +905,16 @@ static int gsc_dst_get_buf_seq(struct gsc_context *ctx) · 12 unmodified lines
1111905 return buf_num;
1112906 }
1113907
1114−static int gsc_dst_set_buf_seq(struct gsc_context *ctx, u32 buf_id,
1115− enum drm_exynos_ipp_buf_type buf_type)
908+static void gsc_dst_set_buf_seq(struct gsc_context *ctx, u32 buf_id,
909+ bool enqueue)
1116910 {
1117− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
1118− bool masked;
911+ bool masked = !enqueue;
1119912 u32 cfg;
1120913 u32 mask = 0x00000001 << buf_id;
1121− int ret = 0;
1122−
1123− DRM_DEBUG_KMS("buf_id[%d]buf_type[%d]\n", buf_id, buf_type);
1124−
1125− mutex_lock(&ctx->lock);
1126914
1127915 /* mask register set */
1128916 cfg = gsc_read(GSC_OUT_BASE_ADDR_Y_MASK);
1129917
1130− switch (buf_type) {
1131− case IPP_BUF_ENQUEUE:
1132− masked = false;
1133− break;
1134− case IPP_BUF_DEQUEUE:
1135− masked = true;
1136− break;
1137− default:
1138− dev_err(ippdrv->dev, "invalid buf ctrl parameter.\n");
1139− ret = -EINVAL;
1140− goto err_unlock;
1141− }
1142−
1143918 /* sequence id */
1144919 cfg &= ~mask;
1145920 cfg |= masked << buf_id;
@@ -1148,94 +923,29 @@ static int gsc_dst_set_buf_seq(struct gsc_context *ctx, u32 buf_id, · 2 unmodified lines
1148923 gsc_write(cfg, GSC_OUT_BASE_ADDR_CR_MASK);
1149924
1150925 /* interrupt enable */
1151− if (buf_type == IPP_BUF_ENQUEUE &&
1152− gsc_dst_get_buf_seq(ctx) >= GSC_BUF_START)
926+ if (enqueue && gsc_dst_get_buf_seq(ctx) >= GSC_BUF_START)
1153927 gsc_handle_irq(ctx, true, false, true);
1154928
1155929 /* interrupt disable */
1156− if (buf_type == IPP_BUF_DEQUEUE &&
1157− gsc_dst_get_buf_seq(ctx) <= GSC_BUF_STOP)
930+ if (!enqueue && gsc_dst_get_buf_seq(ctx) <= GSC_BUF_STOP)
1158931 gsc_handle_irq(ctx, false, false, true);
1159−
1160−err_unlock:
1161− mutex_unlock(&ctx->lock);
1162− return ret;
1163932 }
1164933
1165−static int gsc_dst_set_addr(struct device *dev,
1166− struct drm_exynos_ipp_buf_info *buf_info, u32 buf_id,
1167− enum drm_exynos_ipp_buf_type buf_type)
934+static void gsc_dst_set_addr(struct gsc_context *ctx,
935+ u32 buf_id, struct exynos_drm_ipp_buffer *buf)
1168936 {
1169− struct gsc_context *ctx = get_gsc_context(dev);
1170− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
1171− struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;
1172− struct drm_exynos_ipp_property *property;
1173−
1174− if (!c_node) {
1175− DRM_ERROR("failed to get c_node.\n");
1176− return -EFAULT;
1177− }
1178−
1179− property = &c_node->property;
1180−
1181− DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]buf_type[%d]\n",
1182− property->prop_id, buf_id, buf_type);
1183−
1184− if (buf_id > GSC_MAX_DST) {
1185− dev_info(ippdrv->dev, "invalid buf_id %d.\n", buf_id);
1186− return -EINVAL;
1187− }
1188−
1189937 /* address register set */
1190− switch (buf_type) {
1191− case IPP_BUF_ENQUEUE:
1192− gsc_write(buf_info->base[EXYNOS_DRM_PLANAR_Y],
1193− GSC_OUT_BASE_ADDR_Y(buf_id));
1194− gsc_write(buf_info->base[EXYNOS_DRM_PLANAR_CB],
1195− GSC_OUT_BASE_ADDR_CB(buf_id));
1196− gsc_write(buf_info->base[EXYNOS_DRM_PLANAR_CR],
1197− GSC_OUT_BASE_ADDR_CR(buf_id));
1198− break;
1199− case IPP_BUF_DEQUEUE:
1200− gsc_write(0x0, GSC_OUT_BASE_ADDR_Y(buf_id));
1201− gsc_write(0x0, GSC_OUT_BASE_ADDR_CB(buf_id));
1202− gsc_write(0x0, GSC_OUT_BASE_ADDR_CR(buf_id));
1203− break;
1204− default:
1205− /* bypass */
1206− break;
1207− }
938+ gsc_write(buf->dma_addr[0], GSC_OUT_BASE_ADDR_Y(buf_id));
939+ gsc_write(buf->dma_addr[1], GSC_OUT_BASE_ADDR_CB(buf_id));
940+ gsc_write(buf->dma_addr[2], GSC_OUT_BASE_ADDR_CR(buf_id));
1208941
1209− return gsc_dst_set_buf_seq(ctx, buf_id, buf_type);
1210−}
1211−
1212−static struct exynos_drm_ipp_ops gsc_dst_ops = {
1213− .set_fmt = gsc_dst_set_fmt,
1214− .set_transf = gsc_dst_set_transf,
1215− .set_size = gsc_dst_set_size,
1216− .set_addr = gsc_dst_set_addr,
1217−};
1218−
1219−static int gsc_clk_ctrl(struct gsc_context *ctx, bool enable)
1220−{
1221− DRM_DEBUG_KMS("enable[%d]\n", enable);
1222−
1223− if (enable) {
1224− clk_prepare_enable(ctx->gsc_clk);
1225− ctx->suspended = false;
1226− } else {
1227− clk_disable_unprepare(ctx->gsc_clk);
1228− ctx->suspended = true;
1229− }
1230−
1231− return 0;
942+ gsc_dst_set_buf_seq(ctx, buf_id, true);
1232943 }
1233944
1234945 static int gsc_get_src_buf_index(struct gsc_context *ctx)
1235946 {
1236947 u32 cfg, curr_index, i;
1237948 u32 buf_id = GSC_MAX_SRC;
1238− int ret;
1239949
1240950 DRM_DEBUG_KMS("gsc id[%d]\n", ctx->id);
1241951
@@ -1249,19 +959,15 @@ static int gsc_get_src_buf_index(struct gsc_context *ctx) · 7 unmodified lines
1249959 }
1250960 }
1251961
962+ DRM_DEBUG_KMS("cfg[0x%x]curr_index[%d]buf_id[%d]\n", cfg,
963+ curr_index, buf_id);
964+
1252965 if (buf_id == GSC_MAX_SRC) {
1253966 DRM_ERROR("failed to get in buffer index.\n");
1254967 return -EINVAL;
1255968 }
1256969
1257− ret = gsc_src_set_buf_seq(ctx, buf_id, IPP_BUF_DEQUEUE);
1258− if (ret < 0) {
1259− DRM_ERROR("failed to dequeue.\n");
1260− return ret;
1261− }
1262−
1263− DRM_DEBUG_KMS("cfg[0x%x]curr_index[%d]buf_id[%d]\n", cfg,
1264− curr_index, buf_id);
970+ gsc_src_set_buf_seq(ctx, buf_id, false);
1265971
1266972 return buf_id;
1267973 }
@@ -1270,7 +976,6 @@ static int gsc_get_dst_buf_index(struct gsc_context *ctx) · 2 unmodified lines
1270976 {
1271977 u32 cfg, curr_index, i;
1272978 u32 buf_id = GSC_MAX_DST;
1273− int ret;
1274979
1275980 DRM_DEBUG_KMS("gsc id[%d]\n", ctx->id);
1276981
@@ -1289,11 +994,7 @@ static int gsc_get_dst_buf_index(struct gsc_context *ctx) · 12 unmodified lines
1289994 return -EINVAL;
1290995 }
1291996
1292− ret = gsc_dst_set_buf_seq(ctx, buf_id, IPP_BUF_DEQUEUE);
1293− if (ret < 0) {
1294− DRM_ERROR("failed to dequeue.\n");
1295− return ret;
1296− }
997+ gsc_dst_set_buf_seq(ctx, buf_id, false);
1297998
1298999 DRM_DEBUG_KMS("cfg[0x%x]curr_index[%d]buf_id[%d]\n", cfg,
12991000 curr_index, buf_id);
@@ -1304,215 +1005,55 @@ static int gsc_get_dst_buf_index(struct gsc_context *ctx) · 4 unmodified lines
13041005 static irqreturn_t gsc_irq_handler(int irq, void *dev_id)
13051006 {
13061007 struct gsc_context *ctx = dev_id;
1307− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
1308− struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;
1309− struct drm_exynos_ipp_event_work *event_work =
1310− c_node->event_work;
13111008 u32 status;
1312− int buf_id[EXYNOS_DRM_OPS_MAX];
1009+ int err = 0;
13131010
13141011 DRM_DEBUG_KMS("gsc id[%d]\n", ctx->id);
13151012
13161013 status = gsc_read(GSC_IRQ);
13171014 if (status & GSC_IRQ_STATUS_OR_IRQ) {
1318− dev_err(ippdrv->dev, "occurred overflow at %d, status 0x%x.\n",
1015+ dev_err(ctx->dev, "occurred overflow at %d, status 0x%x.\n",
13191016 ctx->id, status);
1320− return IRQ_NONE;
1017+ err = -EINVAL;
13211018 }
13221019
13231020 if (status & GSC_IRQ_STATUS_OR_FRM_DONE) {
1324− dev_dbg(ippdrv->dev, "occurred frame done at %d, status 0x%x.\n",
1325− ctx->id, status);
1326−
1327− buf_id[EXYNOS_DRM_OPS_SRC] = gsc_get_src_buf_index(ctx);
1328− if (buf_id[EXYNOS_DRM_OPS_SRC] < 0)
1329− return IRQ_HANDLED;
1330−
1331− buf_id[EXYNOS_DRM_OPS_DST] = gsc_get_dst_buf_index(ctx);
1332− if (buf_id[EXYNOS_DRM_OPS_DST] < 0)
1333− return IRQ_HANDLED;
1334−
1335− DRM_DEBUG_KMS("buf_id_src[%d]buf_id_dst[%d]\n",
1336− buf_id[EXYNOS_DRM_OPS_SRC], buf_id[EXYNOS_DRM_OPS_DST]);
1337−
1338− event_work->ippdrv = ippdrv;
1339− event_work->buf_id[EXYNOS_DRM_OPS_SRC] =
1340− buf_id[EXYNOS_DRM_OPS_SRC];
1341− event_work->buf_id[EXYNOS_DRM_OPS_DST] =
1342− buf_id[EXYNOS_DRM_OPS_DST];
1343− queue_work(ippdrv->event_workq, &event_work->work);
1344− }
1345−
1346− return IRQ_HANDLED;
1347−}
1348−
1349−static int gsc_init_prop_list(struct exynos_drm_ippdrv *ippdrv)
1350−{
1351− struct drm_exynos_ipp_prop_list *prop_list = &ippdrv->prop_list;
1352−
1353− prop_list->version = 1;
1354− prop_list->writeback = 1;
1355− prop_list->refresh_min = GSC_REFRESH_MIN;
1356− prop_list->refresh_max = GSC_REFRESH_MAX;
1357− prop_list->flip = (1 << EXYNOS_DRM_FLIP_VERTICAL) |
1358− (1 << EXYNOS_DRM_FLIP_HORIZONTAL);
1359− prop_list->degree = (1 << EXYNOS_DRM_DEGREE_0) |
1360− (1 << EXYNOS_DRM_DEGREE_90) |
1361− (1 << EXYNOS_DRM_DEGREE_180) |
1362− (1 << EXYNOS_DRM_DEGREE_270);
1363− prop_list->csc = 1;
1364− prop_list->crop = 1;
1365− prop_list->crop_max.hsize = GSC_CROP_MAX;
1366− prop_list->crop_max.vsize = GSC_CROP_MAX;
1367− prop_list->crop_min.hsize = GSC_CROP_MIN;
1368− prop_list->crop_min.vsize = GSC_CROP_MIN;
1369− prop_list->scale = 1;
1370− prop_list->scale_max.hsize = GSC_SCALE_MAX;
1371− prop_list->scale_max.vsize = GSC_SCALE_MAX;
1372− prop_list->scale_min.hsize = GSC_SCALE_MIN;
1373− prop_list->scale_min.vsize = GSC_SCALE_MIN;
1374−
1375− return 0;
1376−}
1377−
1378−static inline bool gsc_check_drm_flip(enum drm_exynos_flip flip)
1379−{
1380− switch (flip) {
1381− case EXYNOS_DRM_FLIP_NONE:
1382− case EXYNOS_DRM_FLIP_VERTICAL:
1383− case EXYNOS_DRM_FLIP_HORIZONTAL:
1384− case EXYNOS_DRM_FLIP_BOTH:
1385− return true;
1386− default:
1387− DRM_DEBUG_KMS("invalid flip\n");
1388− return false;
1389− }
1390−}
1391−
1392−static int gsc_ippdrv_check_property(struct device *dev,
1393− struct drm_exynos_ipp_property *property)
1394−{
1395− struct gsc_context *ctx = get_gsc_context(dev);
1396− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
1397− struct drm_exynos_ipp_prop_list *pp = &ippdrv->prop_list;
1398− struct drm_exynos_ipp_config *config;
1399− struct drm_exynos_pos *pos;
1400− struct drm_exynos_sz *sz;
1401− bool swap;
1402− int i;
1403−
1404− for_each_ipp_ops(i) {
1405− if ((i == EXYNOS_DRM_OPS_SRC) &&
1406− (property->cmd == IPP_CMD_WB))
1407− continue;
1021+ int src_buf_id, dst_buf_id;
14081022
1409− config = &property->config[i];
1410− pos = &config->pos;
1411− sz = &config->sz;
1412−
1413− /* check for flip */
1414− if (!gsc_check_drm_flip(config->flip)) {
1415− DRM_ERROR("invalid flip.\n");
1416− goto err_property;
1417− }
1418−
1419− /* check for degree */
1420− switch (config->degree) {
1421− case EXYNOS_DRM_DEGREE_90:
1422− case EXYNOS_DRM_DEGREE_270:
1423− swap = true;
1424− break;
1425− case EXYNOS_DRM_DEGREE_0:
1426− case EXYNOS_DRM_DEGREE_180:
1427− swap = false;
1428− break;
1429− default:
1430− DRM_ERROR("invalid degree.\n");
1431− goto err_property;
1432− }
1023+ dev_dbg(ctx->dev, "occurred frame done at %d, status 0x%x.\n",
1024+ ctx->id, status);
14331025
1434− /* check for buffer bound */
1435− if ((pos->x + pos->w > sz->hsize) ||
1436− (pos->y + pos->h > sz->vsize)) {
1437− DRM_ERROR("out of buf bound.\n");
1438− goto err_property;
1439− }
1026+ src_buf_id = gsc_get_src_buf_index(ctx);
1027+ dst_buf_id = gsc_get_dst_buf_index(ctx);
14401028
1441− /* check for crop */
1442− if ((i == EXYNOS_DRM_OPS_SRC) && (pp->crop)) {
1443− if (swap) {
1444− if ((pos->h < pp->crop_min.hsize) ||
1445− (sz->vsize > pp->crop_max.hsize) ||
1446− (pos->w < pp->crop_min.vsize) ||
1447− (sz->hsize > pp->crop_max.vsize)) {
1448− DRM_ERROR("out of crop size.\n");
1449− goto err_property;
1450− }
1451− } else {
1452− if ((pos->w < pp->crop_min.hsize) ||
1453− (sz->hsize > pp->crop_max.hsize) ||
1454− (pos->h < pp->crop_min.vsize) ||
1455− (sz->vsize > pp->crop_max.vsize)) {
1456− DRM_ERROR("out of crop size.\n");
1457− goto err_property;
1458− }
1459− }
1460− }
1029+ DRM_DEBUG_KMS("buf_id_src[%d]buf_id_dst[%d]\n", src_buf_id,
1030+ dst_buf_id);
14611031
1462− /* check for scale */
1463− if ((i == EXYNOS_DRM_OPS_DST) && (pp->scale)) {
1464− if (swap) {
1465− if ((pos->h < pp->scale_min.hsize) ||
1466− (sz->vsize > pp->scale_max.hsize) ||
1467− (pos->w < pp->scale_min.vsize) ||
1468− (sz->hsize > pp->scale_max.vsize)) {
1469− DRM_ERROR("out of scale size.\n");
1470− goto err_property;
1471− }
1472− } else {
1473− if ((pos->w < pp->scale_min.hsize) ||
1474− (sz->hsize > pp->scale_max.hsize) ||
1475− (pos->h < pp->scale_min.vsize) ||
1476− (sz->vsize > pp->scale_max.vsize)) {
1477− DRM_ERROR("out of scale size.\n");
1478− goto err_property;
1479− }
1480− }
1481− }
1032+ if (src_buf_id < 0 || dst_buf_id < 0)
1033+ err = -EINVAL;
14821034 }
14831035
1484− return 0;
1485−
1486−err_property:
1487− for_each_ipp_ops(i) {
1488− if ((i == EXYNOS_DRM_OPS_SRC) &&
1489− (property->cmd == IPP_CMD_WB))
1490− continue;
1036+ if (ctx->task) {
1037+ struct exynos_drm_ipp_task *task = ctx->task;
14911038
1492− config = &property->config[i];
1493− pos = &config->pos;
1494− sz = &config->sz;
1495−
1496− DRM_ERROR("[%s]f[%d]r[%d]pos[%d %d %d %d]sz[%d %d]\n",
1497− i ? "dst" : "src", config->flip, config->degree,
1498− pos->x, pos->y, pos->w, pos->h,
1499− sz->hsize, sz->vsize);
1039+ ctx->task = NULL;
1040+ pm_runtime_mark_last_busy(ctx->dev);
1041+ pm_runtime_put_autosuspend(ctx->dev);
1042+ exynos_drm_ipp_task_done(task, err);
15001043 }
15011044
1502− return -EINVAL;
1045+ return IRQ_HANDLED;
15031046 }
15041047
1505−
1506−static int gsc_ippdrv_reset(struct device *dev)
1048+static int gsc_reset(struct gsc_context *ctx)
15071049 {
1508− struct gsc_context *ctx = get_gsc_context(dev);
15091050 struct gsc_scaler *sc = &ctx->sc;
15101051 int ret;
15111052
15121053 /* reset h/w block */
15131054 ret = gsc_sw_reset(ctx);
15141055 if (ret < 0) {
1515− dev_err(dev, "failed to reset hardware.\n");
1056+ dev_err(ctx->dev, "failed to reset hardware.\n");
15161057 return ret;
15171058 }
15181059
@@ -1523,166 +1064,172 @@ static int gsc_ippdrv_reset(struct device *dev) · 4 unmodified lines
15231064 return 0;
15241065 }
15251066
1526−static int gsc_ippdrv_start(struct device *dev, enum drm_exynos_ipp_cmd cmd)
1067+static void gsc_start(struct gsc_context *ctx)
15271068 {
1528− struct gsc_context *ctx = get_gsc_context(dev);
1529− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
1530− struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;
1531− struct drm_exynos_ipp_property *property;
1532− struct drm_exynos_ipp_config *config;
1533− struct drm_exynos_pos img_pos[EXYNOS_DRM_OPS_MAX];
1534− struct drm_exynos_ipp_set_wb set_wb;
15351069 u32 cfg;
1536− int ret, i;
1537−
1538− DRM_DEBUG_KMS("cmd[%d]\n", cmd);
1539−
1540− if (!c_node) {
1541− DRM_ERROR("failed to get c_node.\n");
1542− return -EINVAL;
1543− }
1544−
1545− property = &c_node->property;
15461070
15471071 gsc_handle_irq(ctx, true, false, true);
15481072
1549− for_each_ipp_ops(i) {
1550− config = &property->config[i];
1551− img_pos[i] = config->pos;
1552− }
1073+ /* enable one shot */
1074+ cfg = gsc_read(GSC_ENABLE);
1075+ cfg &= ~(GSC_ENABLE_ON_CLEAR_MASK |
1076+ GSC_ENABLE_CLK_GATE_MODE_MASK);
1077+ cfg |= GSC_ENABLE_ON_CLEAR_ONESHOT;
1078+ gsc_write(cfg, GSC_ENABLE);
15531079
1554− switch (cmd) {
1555− case IPP_CMD_M2M:
1556− /* enable one shot */
1557− cfg = gsc_read(GSC_ENABLE);
1558− cfg &= ~(GSC_ENABLE_ON_CLEAR_MASK |
1559− GSC_ENABLE_CLK_GATE_MODE_MASK);
1560− cfg |= GSC_ENABLE_ON_CLEAR_ONESHOT;
1561− gsc_write(cfg, GSC_ENABLE);
1562−
1563− /* src dma memory */
1564− cfg = gsc_read(GSC_IN_CON);
1565− cfg &= ~(GSC_IN_PATH_MASK | GSC_IN_LOCAL_SEL_MASK);
1566− cfg |= GSC_IN_PATH_MEMORY;
1567− gsc_write(cfg, GSC_IN_CON);
1568−
1569− /* dst dma memory */
1570− cfg = gsc_read(GSC_OUT_CON);
1571− cfg |= GSC_OUT_PATH_MEMORY;
1572− gsc_write(cfg, GSC_OUT_CON);
1573− break;
1574− case IPP_CMD_WB:
1575− set_wb.enable = 1;
1576− set_wb.refresh = property->refresh_rate;
1577− gsc_set_gscblk_fimd_wb(ctx, set_wb.enable);
1578− exynos_drm_ippnb_send_event(IPP_SET_WRITEBACK, (void *)&set_wb);
1579−
1580− /* src local path */
1581− cfg = gsc_read(GSC_IN_CON);
1582− cfg &= ~(GSC_IN_PATH_MASK | GSC_IN_LOCAL_SEL_MASK);
1583− cfg |= (GSC_IN_PATH_LOCAL | GSC_IN_LOCAL_FIMD_WB);
1584− gsc_write(cfg, GSC_IN_CON);
1585−
1586− /* dst dma memory */
1587− cfg = gsc_read(GSC_OUT_CON);
1588− cfg |= GSC_OUT_PATH_MEMORY;
1589− gsc_write(cfg, GSC_OUT_CON);
1590− break;
1591− case IPP_CMD_OUTPUT:
1592− /* src dma memory */
1593− cfg = gsc_read(GSC_IN_CON);
1594− cfg &= ~(GSC_IN_PATH_MASK | GSC_IN_LOCAL_SEL_MASK);
1595− cfg |= GSC_IN_PATH_MEMORY;
1596− gsc_write(cfg, GSC_IN_CON);
1597−
1598− /* dst local path */
1599− cfg = gsc_read(GSC_OUT_CON);
1600− cfg |= GSC_OUT_PATH_MEMORY;
1601− gsc_write(cfg, GSC_OUT_CON);
1602− break;
1603− default:
1604− ret = -EINVAL;
1605− dev_err(dev, "invalid operations.\n");
1606− return ret;
1607− }
1080+ /* src dma memory */
1081+ cfg = gsc_read(GSC_IN_CON);
1082+ cfg &= ~(GSC_IN_PATH_MASK | GSC_IN_LOCAL_SEL_MASK);
1083+ cfg |= GSC_IN_PATH_MEMORY;
1084+ gsc_write(cfg, GSC_IN_CON);
16081085
1609− ret = gsc_set_prescaler(ctx, &ctx->sc,
1610− &img_pos[EXYNOS_DRM_OPS_SRC],
1611− &img_pos[EXYNOS_DRM_OPS_DST]);
1612− if (ret) {
1613− dev_err(dev, "failed to set prescaler.\n");
1614− return ret;
1615− }
1086+ /* dst dma memory */
1087+ cfg = gsc_read(GSC_OUT_CON);
1088+ cfg |= GSC_OUT_PATH_MEMORY;
1089+ gsc_write(cfg, GSC_OUT_CON);
16161090
16171091 gsc_set_scaler(ctx, &ctx->sc);
16181092
16191093 cfg = gsc_read(GSC_ENABLE);
16201094 cfg |= GSC_ENABLE_ON;
16211095 gsc_write(cfg, GSC_ENABLE);
1096+}
1097+
1098+static int gsc_commit(struct exynos_drm_ipp *ipp,
1099+ struct exynos_drm_ipp_task *task)
1100+{
1101+ struct gsc_context *ctx = container_of(ipp, struct gsc_context, ipp);
1102+ int ret;
1103+
1104+ pm_runtime_get_sync(ctx->dev);
1105+ ctx->task = task;
1106+
1107+ ret = gsc_reset(ctx);
1108+ if (ret) {
1109+ pm_runtime_put_autosuspend(ctx->dev);
1110+ ctx->task = NULL;
1111+ return ret;
1112+ }
1113+
1114+ gsc_src_set_fmt(ctx, task->src.buf.fourcc);
1115+ gsc_src_set_transf(ctx, task->transform.rotation);
1116+ gsc_src_set_size(ctx, &task->src);
1117+ gsc_src_set_addr(ctx, 0, &task->src);
1118+ gsc_dst_set_fmt(ctx, task->dst.buf.fourcc);
1119+ gsc_dst_set_size(ctx, &task->dst);
1120+ gsc_dst_set_addr(ctx, 0, &task->dst);
1121+ gsc_set_prescaler(ctx, &ctx->sc, &task->src.rect, &task->dst.rect);
1122+ gsc_start(ctx);
16221123
16231124 return 0;
16241125 }
16251126
1626−static void gsc_ippdrv_stop(struct device *dev, enum drm_exynos_ipp_cmd cmd)
1127+static void gsc_abort(struct exynos_drm_ipp *ipp,
1128+ struct exynos_drm_ipp_task *task)
16271129 {
1628− struct gsc_context *ctx = get_gsc_context(dev);
1629− struct drm_exynos_ipp_set_wb set_wb = {0, 0};
1630− u32 cfg;
1130+ struct gsc_context *ctx =
1131+ container_of(ipp, struct gsc_context, ipp);
16311132
1632− DRM_DEBUG_KMS("cmd[%d]\n", cmd);
1133+ gsc_reset(ctx);
1134+ if (ctx->task) {
1135+ struct exynos_drm_ipp_task *task = ctx->task;
16331136
1634− switch (cmd) {
1635− case IPP_CMD_M2M:
1636− /* bypass */
1637− break;
1638− case IPP_CMD_WB:
1639− gsc_set_gscblk_fimd_wb(ctx, set_wb.enable);
1640− exynos_drm_ippnb_send_event(IPP_SET_WRITEBACK, (void *)&set_wb);
1641− break;
1642− case IPP_CMD_OUTPUT:
1643− default:
1644− dev_err(dev, "invalid operations.\n");
1645− break;
1137+ ctx->task = NULL;
1138+ pm_runtime_mark_last_busy(ctx->dev);
1139+ pm_runtime_put_autosuspend(ctx->dev);
1140+ exynos_drm_ipp_task_done(task, -EIO);
16461141 }
1142+}
16471143
1648− gsc_handle_irq(ctx, false, false, true);
1144+static struct exynos_drm_ipp_funcs ipp_funcs = {
1145+ .commit = gsc_commit,
1146+ .abort = gsc_abort,
1147+};
16491148
1650− /* reset sequence */
1651− gsc_write(0xff, GSC_OUT_BASE_ADDR_Y_MASK);
1652− gsc_write(0xff, GSC_OUT_BASE_ADDR_CB_MASK);
1653− gsc_write(0xff, GSC_OUT_BASE_ADDR_CR_MASK);
1149+static int gsc_bind(struct device *dev, struct device *master, void *data)
1150+{
1151+ struct gsc_context *ctx = dev_get_drvdata(dev);
1152+ struct drm_device *drm_dev = data;
1153+ struct exynos_drm_ipp *ipp = &ctx->ipp;
16541154
1655− cfg = gsc_read(GSC_ENABLE);
1656− cfg &= ~GSC_ENABLE_ON;
1657− gsc_write(cfg, GSC_ENABLE);
1155+ ctx->drm_dev = drm_dev;
1156+ drm_iommu_attach_device(drm_dev, dev);
1157+
1158+ exynos_drm_ipp_register(drm_dev, ipp, &ipp_funcs,
1159+ DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE |
1160+ DRM_EXYNOS_IPP_CAP_SCALE | DRM_EXYNOS_IPP_CAP_CONVERT,
1161+ ctx->formats, ctx->num_formats, "gsc");
1162+
1163+ dev_info(dev, "The exynos gscaler has been probed successfully\n");
1164+
1165+ return 0;
1166+}
1167+
1168+static void gsc_unbind(struct device *dev, struct device *master,
1169+ void *data)
1170+{
1171+ struct gsc_context *ctx = dev_get_drvdata(dev);
1172+ struct drm_device *drm_dev = data;
1173+ struct exynos_drm_ipp *ipp = &ctx->ipp;
1174+
1175+ exynos_drm_ipp_unregister(drm_dev, ipp);
1176+ drm_iommu_detach_device(drm_dev, dev);
16581177 }
16591178
1179+static const struct component_ops gsc_component_ops = {
1180+ .bind = gsc_bind,
1181+ .unbind = gsc_unbind,
1182+};
1183+
1184+static const unsigned int gsc_formats[] = {
1185+ DRM_FORMAT_ARGB8888,
1186+ DRM_FORMAT_XRGB8888, DRM_FORMAT_RGB565, DRM_FORMAT_BGRX8888,
1187+ DRM_FORMAT_NV12, DRM_FORMAT_NV16, DRM_FORMAT_NV21, DRM_FORMAT_NV61,
1188+ DRM_FORMAT_UYVY, DRM_FORMAT_VYUY, DRM_FORMAT_YUYV, DRM_FORMAT_YVYU,
1189+ DRM_FORMAT_YUV420, DRM_FORMAT_YVU420, DRM_FORMAT_YUV422,
1190+};
1191+
16601192 static int gsc_probe(struct platform_device *pdev)
16611193 {
16621194 struct device *dev = &pdev->dev;
1195+ struct gsc_driverdata *driver_data;
1196+ struct exynos_drm_ipp_formats *formats;
16631197 struct gsc_context *ctx;
16641198 struct resource *res;
1665− struct exynos_drm_ippdrv *ippdrv;
1666− int ret;
1199+ int ret, i;
16671200
16681201 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
16691202 if (!ctx)
16701203 return -ENOMEM;
16711204
1672− if (dev->of_node) {
1673− ctx->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node,
1674− "samsung,sysreg");
1675− if (IS_ERR(ctx->sysreg)) {
1676− dev_warn(dev, "failed to get system register.\n");
1677− ctx->sysreg = NULL;
1678− }
1205+ formats = devm_kzalloc(dev, sizeof(*formats) *
1206+ (ARRAY_SIZE(gsc_formats)), GFP_KERNEL);
1207+ if (!formats)
1208+ return -ENOMEM;
1209+
1210+ driver_data = (struct gsc_driverdata *)of_device_get_match_data(dev);
1211+ ctx->dev = dev;
1212+ ctx->num_clocks = driver_data->num_clocks;
1213+ ctx->clk_names = driver_data->clk_names;
1214+
1215+ for (i = 0; i < ARRAY_SIZE(gsc_formats); i++) {
1216+ formats[i].fourcc = gsc_formats[i];
1217+ formats[i].type = DRM_EXYNOS_IPP_FORMAT_SOURCE |
1218+ DRM_EXYNOS_IPP_FORMAT_DESTINATION;
1219+ formats[i].limits = driver_data->limits;
1220+ formats[i].num_limits = driver_data->num_limits;
16791221 }
1222+ ctx->formats = formats;
1223+ ctx->num_formats = ARRAY_SIZE(gsc_formats);
16801224
16811225 /* clock control */
1682− ctx->gsc_clk = devm_clk_get(dev, "gscl");
1683− if (IS_ERR(ctx->gsc_clk)) {
1684− dev_err(dev, "failed to get gsc clock.\n");
1685− return PTR_ERR(ctx->gsc_clk);
1226+ for (i = 0; i < ctx->num_clocks; i++) {
1227+ ctx->clocks[i] = devm_clk_get(dev, ctx->clk_names[i]);
1228+ if (IS_ERR(ctx->clocks[i])) {
1229+ dev_err(dev, "failed to get clock: %s\n",
1230+ ctx->clk_names[i]);
1231+ return PTR_ERR(ctx->clocks[i]);
1232+ }
16861233 }
16871234
16881235 /* resource memory */
@@ -1699,8 +1246,8 @@ static int gsc_probe(struct platform_device *pdev) · 10 unmodified lines
16991246 }
17001247
17011248 ctx->irq = res->start;
1702− ret = devm_request_threaded_irq(dev, ctx->irq, NULL, gsc_irq_handler,
1703− IRQF_ONESHOT, "drm_gsc", ctx);
1249+ ret = devm_request_irq(dev, ctx->irq, gsc_irq_handler, 0,
1250+ dev_name(dev), ctx);
17041251 if (ret < 0) {
17051252 dev_err(dev, "failed to request irq.\n");
17061253 return ret;
@@ -1709,38 +1256,22 @@ static int gsc_probe(struct platform_device *pdev) · 2 unmodified lines
17091256 /* context initailization */
17101257 ctx->id = pdev->id;
17111258
1712− ippdrv = &ctx->ippdrv;
1713− ippdrv->dev = dev;
1714− ippdrv->ops[EXYNOS_DRM_OPS_SRC] = &gsc_src_ops;
1715− ippdrv->ops[EXYNOS_DRM_OPS_DST] = &gsc_dst_ops;
1716− ippdrv->check_property = gsc_ippdrv_check_property;
1717− ippdrv->reset = gsc_ippdrv_reset;
1718− ippdrv->start = gsc_ippdrv_start;
1719− ippdrv->stop = gsc_ippdrv_stop;
1720− ret = gsc_init_prop_list(ippdrv);
1721− if (ret < 0) {
1722− dev_err(dev, "failed to init property list.\n");
1723− return ret;
1724− }
1725−
1726− DRM_DEBUG_KMS("id[%d]ippdrv[%pK]\n", ctx->id, ippdrv);
1727−
1728− mutex_init(&ctx->lock);
17291259 platform_set_drvdata(pdev, ctx);
17301260
1261+ pm_runtime_use_autosuspend(dev);
1262+ pm_runtime_set_autosuspend_delay(dev, GSC_AUTOSUSPEND_DELAY);
17311263 pm_runtime_enable(dev);
17321264
1733− ret = exynos_drm_ippdrv_register(ippdrv);
1734− if (ret < 0) {
1735− dev_err(dev, "failed to register drm gsc device.\n");
1736− goto err_ippdrv_register;
1737− }
1265+ ret = component_add(dev, &gsc_component_ops);
1266+ if (ret)
1267+ goto err_pm_dis;
17381268
17391269 dev_info(dev, "drm gsc registered successfully.\n");
17401270
17411271 return 0;
17421272
1743−err_ippdrv_register:
1273+err_pm_dis:
1274+ pm_runtime_dont_use_autosuspend(dev);
17441275 pm_runtime_disable(dev);
17451276 return ret;
17461277 }
@@ -1748,13 +1279,8 @@ err_ippdrv_register: · 1 unmodified line
17481279 static int gsc_remove(struct platform_device *pdev)
17491280 {
17501281 struct device *dev = &pdev->dev;
1751− struct gsc_context *ctx = get_gsc_context(dev);
1752− struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
17531282
1754− exynos_drm_ippdrv_unregister(ippdrv);
1755− mutex_destroy(&ctx->lock);
1756−
1757− pm_runtime_set_suspended(dev);
1283+ pm_runtime_dont_use_autosuspend(dev);
17581284 pm_runtime_disable(dev);
17591285
17601286 return 0;
@@ -1763,19 +1289,32 @@ static int gsc_remove(struct platform_device *pdev) · 2 unmodified lines
17631289 static int __maybe_unused gsc_runtime_suspend(struct device *dev)
17641290 {
17651291 struct gsc_context *ctx = get_gsc_context(dev);
1292+ int i;
17661293
17671294 DRM_DEBUG_KMS("id[%d]\n", ctx->id);
17681295
1769− return gsc_clk_ctrl(ctx, false);
1296+ for (i = ctx->num_clocks - 1; i >= 0; i--)
1297+ clk_disable_unprepare(ctx->clocks[i]);
1298+
1299+ return 0;
17701300 }
17711301
17721302 static int __maybe_unused gsc_runtime_resume(struct device *dev)
17731303 {
17741304 struct gsc_context *ctx = get_gsc_context(dev);
1305+ int i, ret;
17751306
17761307 DRM_DEBUG_KMS("id[%d]\n", ctx->id);
17771308
1778− return gsc_clk_ctrl(ctx, true);
1309+ for (i = 0; i < ctx->num_clocks; i++) {
1310+ ret = clk_prepare_enable(ctx->clocks[i]);
1311+ if (ret) {
1312+ while (--i > 0)
1313+ clk_disable_unprepare(ctx->clocks[i]);
1314+ return ret;
1315+ }
1316+ }
1317+ return 0;
17791318 }
17801319
17811320 static const struct dev_pm_ops gsc_pm_ops = {
@@ -1784,9 +1323,66 @@ static const struct dev_pm_ops gsc_pm_ops = { · 2 unmodified lines
17841323 SET_RUNTIME_PM_OPS(gsc_runtime_suspend, gsc_runtime_resume, NULL)
17851324 };
17861325
1326+static const struct drm_exynos_ipp_limit gsc_5250_limits[] = {
1327+ { IPP_SIZE_LIMIT(BUFFER, .h = { 32, 4800, 8 }, .v = { 16, 3344, 8 }) },
1328+ { IPP_SIZE_LIMIT(AREA, .h = { 16, 4800, 2 }, .v = { 8, 3344, 2 }) },
1329+ { IPP_SIZE_LIMIT(ROTATED, .h = { 32, 2048 }, .v = { 16, 2048 }) },
1330+ { IPP_SCALE_LIMIT(.h = { (1 << 16) / 16, (1 << 16) * 8 },
1331+ .v = { (1 << 16) / 16, (1 << 16) * 8 }) },
1332+};
1333+
1334+static const struct drm_exynos_ipp_limit gsc_5420_limits[] = {
1335+ { IPP_SIZE_LIMIT(BUFFER, .h = { 32, 4800, 8 }, .v = { 16, 3344, 8 }) },
1336+ { IPP_SIZE_LIMIT(AREA, .h = { 16, 4800, 2 }, .v = { 8, 3344, 2 }) },
1337+ { IPP_SIZE_LIMIT(ROTATED, .h = { 16, 2016 }, .v = { 8, 2016 }) },
1338+ { IPP_SCALE_LIMIT(.h = { (1 << 16) / 16, (1 << 16) * 8 },
1339+ .v = { (1 << 16) / 16, (1 << 16) * 8 }) },
1340+};
1341+
1342+static const struct drm_exynos_ipp_limit gsc_5433_limits[] = {
1343+ { IPP_SIZE_LIMIT(BUFFER, .h = { 32, 8191, 2 }, .v = { 16, 8191, 2 }) },
1344+ { IPP_SIZE_LIMIT(AREA, .h = { 16, 4800, 1 }, .v = { 8, 3344, 1 }) },
1345+ { IPP_SIZE_LIMIT(ROTATED, .h = { 32, 2047 }, .v = { 8, 8191 }) },
1346+ { IPP_SCALE_LIMIT(.h = { (1 << 16) / 16, (1 << 16) * 8 },
1347+ .v = { (1 << 16) / 16, (1 << 16) * 8 }) },
1348+};
1349+
1350+static struct gsc_driverdata gsc_exynos5250_drvdata = {
1351+ .clk_names = {"gscl"},
1352+ .num_clocks = 1,
1353+ .limits = gsc_5250_limits,
1354+ .num_limits = ARRAY_SIZE(gsc_5250_limits),
1355+};
1356+
1357+static struct gsc_driverdata gsc_exynos5420_drvdata = {
1358+ .clk_names = {"gscl"},
1359+ .num_clocks = 1,
1360+ .limits = gsc_5420_limits,
1361+ .num_limits = ARRAY_SIZE(gsc_5420_limits),
1362+};
1363+
1364+static struct gsc_driverdata gsc_exynos5433_drvdata = {
1365+ .clk_names = {"pclk", "aclk", "aclk_xiu", "aclk_gsclbend"},
1366+ .num_clocks = 4,
1367+ .limits = gsc_5433_limits,
1368+ .num_limits = ARRAY_SIZE(gsc_5433_limits),
1369+};
1370+
17871371 static const struct of_device_id exynos_drm_gsc_of_match[] = {
1788− { .compatible = "samsung,exynos5-gsc" },
1789− { },
1372+ {
1373+ .compatible = "samsung,exynos5-gsc",
1374+ .data = &gsc_exynos5250_drvdata,
1375+ }, {
1376+ .compatible = "samsung,exynos5250-gsc",
1377+ .data = &gsc_exynos5250_drvdata,
1378+ }, {
1379+ .compatible = "samsung,exynos5420-gsc",
1380+ .data = &gsc_exynos5420_drvdata,
1381+ }, {
1382+ .compatible = "samsung,exynos5433-gsc",
1383+ .data = &gsc_exynos5433_drvdata,
1384+ }, {
1385+ },
17901386 };
17911387 MODULE_DEVICE_TABLE(of, exynos_drm_gsc_of_match);
17921388
@@ -1800,4 +1396,3 @@ struct platform_driver gsc_driver = { · 7 unmodified lines
18001396 .of_match_table = of_match_ptr(exynos_drm_gsc_of_match),
18011397 },
18021398 };
1803−
drivers/gpu/drm/exynos/exynos_drm_gsc.h+0−24
@@ -1,24 +0,0 @@
1−/*
2− * Copyright (c) 2012 Samsung Electronics Co., Ltd.
3− *
4− * Authors:
5− * Eunchul Kim <chulspro.kim@samsung.com>
6− * Jinyoung Jeon <jy0.jeon@samsung.com>
7− * Sangmin Lee <lsmin.lee@samsung.com>
8− *
9− * This program is free software; you can redistribute it and/or modify it
10− * under the terms of the GNU General Public License as published by the
11− * Free Software Foundation; either version 2 of the License, or (at your
12− * option) any later version.
13− */
14−
15−#ifndef _EXYNOS_DRM_GSC_H_
16−#define _EXYNOS_DRM_GSC_H_
17−
18−/*
19− * TODO
20− * FIMD output interface notifier callback.
21− * Mixer output interface notifier callback.
22− */
23−
24−#endif /* _EXYNOS_DRM_GSC_H_ */
drivers/gpu/drm/exynos/exynos_drm_ipp.c+916−0
@@ -0,0 +1,916 @@
1+/*
2+ * Copyright (C) 2017 Samsung Electronics Co.Ltd
3+ * Authors:
4+ * Marek Szyprowski <m.szyprowski@samsung.com>
5+ *
6+ * Exynos DRM Image Post Processing (IPP) related functions
7+ *
8+ * Permission is hereby granted, free of charge, to any person obtaining a
9+ * copy of this software and associated documentation files (the "Software"),
10+ * to deal in the Software without restriction, including without limitation
11+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12+ * and/or sell copies of the Software, and to permit persons to whom the
13+ * Software is furnished to do so, subject to the following conditions:
14+ *
15+ * The above copyright notice and this permission notice shall be included in
16+ * all copies or substantial portions of the Software.
17+ */
18+
19+
20+#include <drm/drmP.h>
21+#include <drm/drm_mode.h>
22+#include <uapi/drm/exynos_drm.h>
23+
24+#include "exynos_drm_drv.h"
25+#include "exynos_drm_gem.h"
26+#include "exynos_drm_ipp.h"
27+
28+static int num_ipp;
29+static LIST_HEAD(ipp_list);
30+
31+/**
32+ * exynos_drm_ipp_register - Register a new picture processor hardware module
33+ * @dev: DRM device
34+ * @ipp: ipp module to init
35+ * @funcs: callbacks for the new ipp object
36+ * @caps: bitmask of ipp capabilities (%DRM_EXYNOS_IPP_CAP_*)
37+ * @formats: array of supported formats
38+ * @num_formats: size of the supported formats array
39+ * @name: name (for debugging purposes)
40+ *
41+ * Initializes a ipp module.
42+ *
43+ * Returns:
44+ * Zero on success, error code on failure.
45+ */
46+int exynos_drm_ipp_register(struct drm_device *dev, struct exynos_drm_ipp *ipp,
47+ const struct exynos_drm_ipp_funcs *funcs, unsigned int caps,
48+ const struct exynos_drm_ipp_formats *formats,
49+ unsigned int num_formats, const char *name)
50+{
51+ WARN_ON(!ipp);
52+ WARN_ON(!funcs);
53+ WARN_ON(!formats);
54+ WARN_ON(!num_formats);
55+
56+ spin_lock_init(&ipp->lock);
57+ INIT_LIST_HEAD(&ipp->todo_list);
58+ init_waitqueue_head(&ipp->done_wq);
59+ ipp->dev = dev;
60+ ipp->funcs = funcs;
61+ ipp->capabilities = caps;
62+ ipp->name = name;
63+ ipp->formats = formats;
64+ ipp->num_formats = num_formats;
65+
66+ /* ipp_list modification is serialized by component framework */
67+ list_add_tail(&ipp->head, &ipp_list);
68+ ipp->id = num_ipp++;
69+
70+ DRM_DEBUG_DRIVER("Registered ipp %d\n", ipp->id);
71+
72+ return 0;
73+}
74+
75+/**
76+ * exynos_drm_ipp_unregister - Unregister the picture processor module
77+ * @dev: DRM device
78+ * @ipp: ipp module
79+ */
80+void exynos_drm_ipp_unregister(struct drm_device *dev,
81+ struct exynos_drm_ipp *ipp)
82+{
83+ WARN_ON(ipp->task);
84+ WARN_ON(!list_empty(&ipp->todo_list));
85+ list_del(&ipp->head);
86+}
87+
88+/**
89+ * exynos_drm_ipp_ioctl_get_res_ioctl - enumerate all ipp modules
90+ * @dev: DRM device
91+ * @data: ioctl data
92+ * @file_priv: DRM file info
93+ *
94+ * Construct a list of ipp ids.
95+ *
96+ * Called by the user via ioctl.
97+ *
98+ * Returns:
99+ * Zero on success, negative errno on failure.
100+ */
101+int exynos_drm_ipp_get_res_ioctl(struct drm_device *dev, void *data,
102+ struct drm_file *file_priv)
103+{
104+ struct drm_exynos_ioctl_ipp_get_res *resp = data;
105+ struct exynos_drm_ipp *ipp;
106+ uint32_t __user *ipp_ptr = (uint32_t __user *)
107+ (unsigned long)resp->ipp_id_ptr;
108+ unsigned int count = num_ipp, copied = 0;
109+
110+ /*
111+ * This ioctl is called twice, once to determine how much space is
112+ * needed, and the 2nd time to fill it.
113+ */
114+ if (count && resp->count_ipps >= count) {
115+ list_for_each_entry(ipp, &ipp_list, head) {
116+ if (put_user(ipp->id, ipp_ptr + copied))
117+ return -EFAULT;
118+ copied++;
119+ }
120+ }
121+ resp->count_ipps = count;
122+
123+ return 0;
124+}
125+
126+static inline struct exynos_drm_ipp *__ipp_get(uint32_t id)
127+{
128+ struct exynos_drm_ipp *ipp;
129+
130+ list_for_each_entry(ipp, &ipp_list, head)
131+ if (ipp->id == id)
132+ return ipp;
133+ return NULL;
134+}
135+
136+/**
137+ * exynos_drm_ipp_ioctl_get_caps - get ipp module capabilities and formats
138+ * @dev: DRM device
139+ * @data: ioctl data
140+ * @file_priv: DRM file info
141+ *
142+ * Construct a structure describing ipp module capabilities.
143+ *
144+ * Called by the user via ioctl.
145+ *
146+ * Returns:
147+ * Zero on success, negative errno on failure.
148+ */
149+int exynos_drm_ipp_get_caps_ioctl(struct drm_device *dev, void *data,
150+ struct drm_file *file_priv)
151+{
152+ struct drm_exynos_ioctl_ipp_get_caps *resp = data;
153+ void __user *ptr = (void __user *)(unsigned long)resp->formats_ptr;
154+ struct exynos_drm_ipp *ipp;
155+ int i;
156+
157+ ipp = __ipp_get(resp->ipp_id);
158+ if (!ipp)
159+ return -ENOENT;
160+
161+ resp->ipp_id = ipp->id;
162+ resp->capabilities = ipp->capabilities;
163+
164+ /*
165+ * This ioctl is called twice, once to determine how much space is
166+ * needed, and the 2nd time to fill it.
167+ */
168+ if (resp->formats_count >= ipp->num_formats) {
169+ for (i = 0; i < ipp->num_formats; i++) {
170+ struct drm_exynos_ipp_format tmp = {
171+ .fourcc = ipp->formats[i].fourcc,
172+ .type = ipp->formats[i].type,
173+ .modifier = ipp->formats[i].modifier,
174+ };
175+
176+ if (copy_to_user(ptr, &tmp, sizeof(tmp)))
177+ return -EFAULT;
178+ ptr += sizeof(tmp);
179+ }
180+ }
181+ resp->formats_count = ipp->num_formats;
182+
183+ return 0;
184+}
185+
186+static inline const struct exynos_drm_ipp_formats *__ipp_format_get(
187+ struct exynos_drm_ipp *ipp, uint32_t fourcc,
188+ uint64_t mod, unsigned int type)
189+{
190+ int i;
191+
192+ for (i = 0; i < ipp->num_formats; i++) {
193+ if ((ipp->formats[i].type & type) &&
194+ ipp->formats[i].fourcc == fourcc &&
195+ ipp->formats[i].modifier == mod)
196+ return &ipp->formats[i];
197+ }
198+ return NULL;
199+}
200+
201+/**
202+ * exynos_drm_ipp_get_limits_ioctl - get ipp module limits
203+ * @dev: DRM device
204+ * @data: ioctl data
205+ * @file_priv: DRM file info
206+ *
207+ * Construct a structure describing ipp module limitations for provided
208+ * picture format.
209+ *
210+ * Called by the user via ioctl.
211+ *
212+ * Returns:
213+ * Zero on success, negative errno on failure.
214+ */
215+int exynos_drm_ipp_get_limits_ioctl(struct drm_device *dev, void *data,
216+ struct drm_file *file_priv)
217+{
218+ struct drm_exynos_ioctl_ipp_get_limits *resp = data;
219+ void __user *ptr = (void __user *)(unsigned long)resp->limits_ptr;
220+ const struct exynos_drm_ipp_formats *format;
221+ struct exynos_drm_ipp *ipp;
222+
223+ if (resp->type != DRM_EXYNOS_IPP_FORMAT_SOURCE &&
224+ resp->type != DRM_EXYNOS_IPP_FORMAT_DESTINATION)
225+ return -EINVAL;
226+
227+ ipp = __ipp_get(resp->ipp_id);
228+ if (!ipp)
229+ return -ENOENT;
230+
231+ format = __ipp_format_get(ipp, resp->fourcc, resp->modifier,
232+ resp->type);
233+ if (!format)
234+ return -EINVAL;
235+
236+ /*
237+ * This ioctl is called twice, once to determine how much space is
238+ * needed, and the 2nd time to fill it.
239+ */
240+ if (format->num_limits && resp->limits_count >= format->num_limits)
241+ if (copy_to_user((void __user *)ptr, format->limits,
242+ sizeof(*format->limits) * format->num_limits))
243+ return -EFAULT;
244+ resp->limits_count = format->num_limits;
245+
246+ return 0;
247+}
248+
249+struct drm_pending_exynos_ipp_event {
250+ struct drm_pending_event base;
251+ struct drm_exynos_ipp_event event;
252+};
253+
254+static inline struct exynos_drm_ipp_task *
255+ exynos_drm_ipp_task_alloc(struct exynos_drm_ipp *ipp)
256+{
257+ struct exynos_drm_ipp_task *task;
258+
259+ task = kzalloc(sizeof(*task), GFP_KERNEL);
260+ if (!task)
261+ return NULL;
262+
263+ task->dev = ipp->dev;
264+ task->ipp = ipp;
265+
266+ /* some defaults */
267+ task->src.rect.w = task->dst.rect.w = UINT_MAX;
268+ task->src.rect.h = task->dst.rect.h = UINT_MAX;
269+ task->transform.rotation = DRM_MODE_ROTATE_0;
270+
271+ DRM_DEBUG_DRIVER("Allocated task %pK\n", task);
272+
273+ return task;
274+}
275+
276+static const struct exynos_drm_param_map {
277+ unsigned int id;
278+ unsigned int size;
279+ unsigned int offset;
280+} exynos_drm_ipp_params_maps[] = {
281+ {
282+ DRM_EXYNOS_IPP_TASK_BUFFER | DRM_EXYNOS_IPP_TASK_TYPE_SOURCE,
283+ sizeof(struct drm_exynos_ipp_task_buffer),
284+ offsetof(struct exynos_drm_ipp_task, src.buf),
285+ }, {
286+ DRM_EXYNOS_IPP_TASK_BUFFER |
287+ DRM_EXYNOS_IPP_TASK_TYPE_DESTINATION,
288+ sizeof(struct drm_exynos_ipp_task_buffer),
289+ offsetof(struct exynos_drm_ipp_task, dst.buf),
290+ }, {
291+ DRM_EXYNOS_IPP_TASK_RECTANGLE | DRM_EXYNOS_IPP_TASK_TYPE_SOURCE,
292+ sizeof(struct drm_exynos_ipp_task_rect),
293+ offsetof(struct exynos_drm_ipp_task, src.rect),
294+ }, {
295+ DRM_EXYNOS_IPP_TASK_RECTANGLE |
296+ DRM_EXYNOS_IPP_TASK_TYPE_DESTINATION,
297+ sizeof(struct drm_exynos_ipp_task_rect),
298+ offsetof(struct exynos_drm_ipp_task, dst.rect),
299+ }, {
300+ DRM_EXYNOS_IPP_TASK_TRANSFORM,
301+ sizeof(struct drm_exynos_ipp_task_transform),
302+ offsetof(struct exynos_drm_ipp_task, transform),
303+ }, {
304+ DRM_EXYNOS_IPP_TASK_ALPHA,
305+ sizeof(struct drm_exynos_ipp_task_alpha),
306+ offsetof(struct exynos_drm_ipp_task, alpha),
307+ },
308+};
309+
310+static int exynos_drm_ipp_task_set(struct exynos_drm_ipp_task *task,
311+ struct drm_exynos_ioctl_ipp_commit *arg)
312+{
313+ const struct exynos_drm_param_map *map = exynos_drm_ipp_params_maps;
314+ void __user *params = (void __user *)(unsigned long)arg->params_ptr;
315+ unsigned int size = arg->params_size;
316+ uint32_t id;
317+ int i;
318+
319+ while (size) {
320+ if (get_user(id, (uint32_t __user *)params))
321+ return -EFAULT;
322+
323+ for (i = 0; i < ARRAY_SIZE(exynos_drm_ipp_params_maps); i++)
324+ if (map[i].id == id)
325+ break;
326+ if (i == ARRAY_SIZE(exynos_drm_ipp_params_maps) ||
327+ map[i].size > size)
328+ return -EINVAL;
329+
330+ if (copy_from_user((void *)task + map[i].offset, params,
331+ map[i].size))
332+ return -EFAULT;
333+
334+ params += map[i].size;
335+ size -= map[i].size;
336+ }
337+
338+ DRM_DEBUG_DRIVER("Got task %pK configuration from userspace\n", task);
339+ return 0;
340+}
341+
342+static int exynos_drm_ipp_task_setup_buffer(struct exynos_drm_ipp_buffer *buf,
343+ struct drm_file *filp)
344+{
345+ int ret = 0;
346+ int i;
347+
348+ /* basic checks */
349+ if (buf->buf.width == 0 || buf->buf.height == 0)
350+ return -EINVAL;
351+ buf->format = drm_format_info(buf->buf.fourcc);
352+ for (i = 0; i < buf->format->num_planes; i++) {
353+ unsigned int width = (i == 0) ? buf->buf.width :
354+ DIV_ROUND_UP(buf->buf.width, buf->format->hsub);
355+
356+ if (buf->buf.pitch[i] == 0)
357+ buf->buf.pitch[i] = width * buf->format->cpp[i];
358+ if (buf->buf.pitch[i] < width * buf->format->cpp[i])
359+ return -EINVAL;
360+ if (!buf->buf.gem_id[i])
361+ return -ENOENT;
362+ }
363+
364+ /* pitch for additional planes must match */
365+ if (buf->format->num_planes > 2 &&
366+ buf->buf.pitch[1] != buf->buf.pitch[2])
367+ return -EINVAL;
368+
369+ /* get GEM buffers and check their size */
370+ for (i = 0; i < buf->format->num_planes; i++) {
371+ unsigned int height = (i == 0) ? buf->buf.height :
372+ DIV_ROUND_UP(buf->buf.height, buf->format->vsub);
373+ unsigned long size = height * buf->buf.pitch[i];
374+ struct drm_gem_object *obj = drm_gem_object_lookup(filp,
375+ buf->buf.gem_id[i]);
376+ if (!obj) {
377+ ret = -ENOENT;
378+ goto gem_free;
379+ }
380+ buf->exynos_gem[i] = to_exynos_gem(obj);
381+
382+ if (size + buf->buf.offset[i] > buf->exynos_gem[i]->size) {
383+ i++;
384+ ret = -EINVAL;
385+ goto gem_free;
386+ }
387+ buf->dma_addr[i] = buf->exynos_gem[i]->dma_addr +
388+ buf->buf.offset[i];
389+ }
390+
391+ return 0;
392+gem_free:
393+ while (i--) {
394+ drm_gem_object_put_unlocked(&buf->exynos_gem[i]->base);
395+ buf->exynos_gem[i] = NULL;
396+ }
397+ return ret;
398+}
399+
400+static void exynos_drm_ipp_task_release_buf(struct exynos_drm_ipp_buffer *buf)
401+{
402+ int i;
403+
404+ if (!buf->exynos_gem[0])
405+ return;
406+ for (i = 0; i < buf->format->num_planes; i++)
407+ drm_gem_object_put_unlocked(&buf->exynos_gem[i]->base);
408+}
409+
410+static void exynos_drm_ipp_task_free(struct exynos_drm_ipp *ipp,
411+ struct exynos_drm_ipp_task *task)
412+{
413+ DRM_DEBUG_DRIVER("Freeing task %pK\n", task);
414+
415+ exynos_drm_ipp_task_release_buf(&task->src);
416+ exynos_drm_ipp_task_release_buf(&task->dst);
417+ if (task->event)
418+ drm_event_cancel_free(ipp->dev, &task->event->base);
419+ kfree(task);
420+}
421+
422+struct drm_ipp_limit {
423+ struct drm_exynos_ipp_limit_val h;
424+ struct drm_exynos_ipp_limit_val v;
425+};
426+
427+enum drm_ipp_size_id {
428+ IPP_LIMIT_BUFFER, IPP_LIMIT_AREA, IPP_LIMIT_ROTATED, IPP_LIMIT_MAX
429+};
430+
431+static const enum drm_ipp_size_id limit_id_fallback[IPP_LIMIT_MAX][4] = {
432+ [IPP_LIMIT_BUFFER] = { DRM_EXYNOS_IPP_LIMIT_SIZE_BUFFER },
433+ [IPP_LIMIT_AREA] = { DRM_EXYNOS_IPP_LIMIT_SIZE_AREA,
434+ DRM_EXYNOS_IPP_LIMIT_SIZE_BUFFER },
435+ [IPP_LIMIT_ROTATED] = { DRM_EXYNOS_IPP_LIMIT_SIZE_ROTATED,
436+ DRM_EXYNOS_IPP_LIMIT_SIZE_AREA,
437+ DRM_EXYNOS_IPP_LIMIT_SIZE_BUFFER },
438+};
439+
440+static inline void __limit_set_val(unsigned int *ptr, unsigned int val)
441+{
442+ if (!*ptr)
443+ *ptr = val;
444+}
445+
446+static void __get_size_limit(const struct drm_exynos_ipp_limit *limits,
447+ unsigned int num_limits, enum drm_ipp_size_id id,
448+ struct drm_ipp_limit *res)
449+{
450+ const struct drm_exynos_ipp_limit *l = limits;
451+ int i = 0;
452+
453+ memset(res, 0, sizeof(*res));
454+ for (i = 0; limit_id_fallback[id][i]; i++)
455+ for (l = limits; l - limits < num_limits; l++) {
456+ if (((l->type & DRM_EXYNOS_IPP_LIMIT_TYPE_MASK) !=
457+ DRM_EXYNOS_IPP_LIMIT_TYPE_SIZE) ||
458+ ((l->type & DRM_EXYNOS_IPP_LIMIT_SIZE_MASK) !=
459+ limit_id_fallback[id][i]))
460+ continue;
461+ __limit_set_val(&res->h.min, l->h.min);
462+ __limit_set_val(&res->h.max, l->h.max);
463+ __limit_set_val(&res->h.align, l->h.align);
464+ __limit_set_val(&res->v.min, l->v.min);
465+ __limit_set_val(&res->v.max, l->v.max);
466+ __limit_set_val(&res->v.align, l->v.align);
467+ }
468+}
469+
470+static inline bool __align_check(unsigned int val, unsigned int align)
471+{
472+ if (align && (val & (align - 1))) {
473+ DRM_DEBUG_DRIVER("Value %d exceeds HW limits (align %d)\n",
474+ val, align);
475+ return false;
476+ }
477+ return true;
478+}
479+
480+static inline bool __size_limit_check(unsigned int val,
481+ struct drm_exynos_ipp_limit_val *l)
482+{
483+ if ((l->min && val < l->min) || (l->max && val > l->max)) {
484+ DRM_DEBUG_DRIVER("Value %d exceeds HW limits (min %d, max %d)\n",
485+ val, l->min, l->max);
486+ return false;
487+ }
488+ return __align_check(val, l->align);
489+}
490+
491+static int exynos_drm_ipp_check_size_limits(struct exynos_drm_ipp_buffer *buf,
492+ const struct drm_exynos_ipp_limit *limits, unsigned int num_limits,
493+ bool rotate, bool swap)
494+{
495+ enum drm_ipp_size_id id = rotate ? IPP_LIMIT_ROTATED : IPP_LIMIT_AREA;
496+ struct drm_ipp_limit l;
497+ struct drm_exynos_ipp_limit_val *lh = &l.h, *lv = &l.v;
498+
499+ if (!limits)
500+ return 0;
501+
502+ __get_size_limit(limits, num_limits, IPP_LIMIT_BUFFER, &l);
503+ if (!__size_limit_check(buf->buf.width, &l.h) ||
504+ !__size_limit_check(buf->buf.height, &l.v))
505+ return -EINVAL;
506+
507+ if (swap) {
508+ lv = &l.h;
509+ lh = &l.v;
510+ }
511+ __get_size_limit(limits, num_limits, id, &l);
512+ if (!__size_limit_check(buf->rect.w, lh) ||
513+ !__align_check(buf->rect.x, lh->align) ||
514+ !__size_limit_check(buf->rect.h, lv) ||
515+ !__align_check(buf->rect.y, lv->align))
516+ return -EINVAL;
517+
518+ return 0;
519+}
520+
521+static inline bool __scale_limit_check(unsigned int src, unsigned int dst,
522+ unsigned int min, unsigned int max)
523+{
524+ if ((max && (dst << 16) > src * max) ||
525+ (min && (dst << 16) < src * min)) {
526+ DRM_DEBUG_DRIVER("Scale from %d to %d exceeds HW limits (ratio min %d.%05d, max %d.%05d)\n",
527+ src, dst,
528+ min >> 16, 100000 * (min & 0xffff) / (1 << 16),
529+ max >> 16, 100000 * (max & 0xffff) / (1 << 16));
530+ return false;
531+ }
532+ return true;
533+}
534+
535+static int exynos_drm_ipp_check_scale_limits(
536+ struct drm_exynos_ipp_task_rect *src,
537+ struct drm_exynos_ipp_task_rect *dst,
538+ const struct drm_exynos_ipp_limit *limits,
539+ unsigned int num_limits, bool swap)
540+{
541+ const struct drm_exynos_ipp_limit_val *lh, *lv;
542+ int dw, dh;
543+
544+ for (; num_limits; limits++, num_limits--)
545+ if ((limits->type & DRM_EXYNOS_IPP_LIMIT_TYPE_MASK) ==
546+ DRM_EXYNOS_IPP_LIMIT_TYPE_SCALE)
547+ break;
548+ if (!num_limits)
549+ return 0;
550+
551+ lh = (!swap) ? &limits->h : &limits->v;
552+ lv = (!swap) ? &limits->v : &limits->h;
553+ dw = (!swap) ? dst->w : dst->h;
554+ dh = (!swap) ? dst->h : dst->w;
555+
556+ if (!__scale_limit_check(src->w, dw, lh->min, lh->max) ||
557+ !__scale_limit_check(src->h, dh, lv->min, lv->max))
558+ return -EINVAL;
559+
560+ return 0;
561+}
562+
563+static int exynos_drm_ipp_task_check(struct exynos_drm_ipp_task *task)
564+{
565+ struct exynos_drm_ipp *ipp = task->ipp;
566+ const struct exynos_drm_ipp_formats *src_fmt, *dst_fmt;
567+ struct exynos_drm_ipp_buffer *src = &task->src, *dst = &task->dst;
568+ unsigned int rotation = task->transform.rotation;
569+ int ret = 0;
570+ bool swap = drm_rotation_90_or_270(rotation);
571+ bool rotate = (rotation != DRM_MODE_ROTATE_0);
572+ bool scale = false;
573+
574+ DRM_DEBUG_DRIVER("Checking task %pK\n", task);
575+
576+ if (src->rect.w == UINT_MAX)
577+ src->rect.w = src->buf.width;
578+ if (src->rect.h == UINT_MAX)
579+ src->rect.h = src->buf.height;
580+ if (dst->rect.w == UINT_MAX)
581+ dst->rect.w = dst->buf.width;
582+ if (dst->rect.h == UINT_MAX)
583+ dst->rect.h = dst->buf.height;
584+
585+ if (src->rect.x + src->rect.w > (src->buf.width) ||
586+ src->rect.y + src->rect.h > (src->buf.height) ||
587+ dst->rect.x + dst->rect.w > (dst->buf.width) ||
588+ dst->rect.y + dst->rect.h > (dst->buf.height)) {
589+ DRM_DEBUG_DRIVER("Task %pK: defined area is outside provided buffers\n",
590+ task);
591+ return -EINVAL;
592+ }
593+
594+ if ((!swap && (src->rect.w != dst->rect.w ||
595+ src->rect.h != dst->rect.h)) ||
596+ (swap && (src->rect.w != dst->rect.h ||
597+ src->rect.h != dst->rect.w)))
598+ scale = true;
599+
600+ if ((!(ipp->capabilities & DRM_EXYNOS_IPP_CAP_CROP) &&
601+ (src->rect.x || src->rect.y || dst->rect.x || dst->rect.y)) ||
602+ (!(ipp->capabilities & DRM_EXYNOS_IPP_CAP_ROTATE) && rotate) ||
603+ (!(ipp->capabilities & DRM_EXYNOS_IPP_CAP_SCALE) && scale) ||
604+ (!(ipp->capabilities & DRM_EXYNOS_IPP_CAP_CONVERT) &&
605+ src->buf.fourcc != dst->buf.fourcc)) {
606+ DRM_DEBUG_DRIVER("Task %pK: hw capabilities exceeded\n", task);
607+ return -EINVAL;
608+ }
609+
610+ src_fmt = __ipp_format_get(ipp, src->buf.fourcc, src->buf.modifier,
611+ DRM_EXYNOS_IPP_FORMAT_SOURCE);
612+ if (!src_fmt) {
613+ DRM_DEBUG_DRIVER("Task %pK: src format not supported\n", task);
614+ return -EINVAL;
615+ }
616+ ret = exynos_drm_ipp_check_size_limits(src, src_fmt->limits,
617+ src_fmt->num_limits,
618+ rotate, false);
619+ if (ret)
620+ return ret;
621+ ret = exynos_drm_ipp_check_scale_limits(&src->rect, &dst->rect,
622+ src_fmt->limits,
623+ src_fmt->num_limits, swap);
624+ if (ret)
625+ return ret;
626+
627+ dst_fmt = __ipp_format_get(ipp, dst->buf.fourcc, dst->buf.modifier,
628+ DRM_EXYNOS_IPP_FORMAT_DESTINATION);
629+ if (!dst_fmt) {
630+ DRM_DEBUG_DRIVER("Task %pK: dst format not supported\n", task);
631+ return -EINVAL;
632+ }
633+ ret = exynos_drm_ipp_check_size_limits(dst, dst_fmt->limits,
634+ dst_fmt->num_limits,
635+ false, swap);
636+ if (ret)
637+ return ret;
638+ ret = exynos_drm_ipp_check_scale_limits(&src->rect, &dst->rect,
639+ dst_fmt->limits,
640+ dst_fmt->num_limits, swap);
641+ if (ret)
642+ return ret;
643+
644+ DRM_DEBUG_DRIVER("Task %pK: all checks done.\n", task);
645+
646+ return ret;
647+}
648+
649+static int exynos_drm_ipp_task_setup_buffers(struct exynos_drm_ipp_task *task,
650+ struct drm_file *filp)
651+{
652+ struct exynos_drm_ipp_buffer *src = &task->src, *dst = &task->dst;
653+ int ret = 0;
654+
655+ DRM_DEBUG_DRIVER("Setting buffer for task %pK\n", task);
656+
657+ ret = exynos_drm_ipp_task_setup_buffer(src, filp);
658+ if (ret) {
659+ DRM_DEBUG_DRIVER("Task %pK: src buffer setup failed\n", task);
660+ return ret;
661+ }
662+ ret = exynos_drm_ipp_task_setup_buffer(dst, filp);
663+ if (ret) {
664+ DRM_DEBUG_DRIVER("Task %pK: dst buffer setup failed\n", task);
665+ return ret;
666+ }
667+
668+ DRM_DEBUG_DRIVER("Task %pK: buffers prepared.\n", task);
669+
670+ return ret;
671+}
672+
673+
674+static int exynos_drm_ipp_event_create(struct exynos_drm_ipp_task *task,
675+ struct drm_file *file_priv, uint64_t user_data)
676+{
677+ struct drm_pending_exynos_ipp_event *e = NULL;
678+ int ret;
679+
680+ e = kzalloc(sizeof(*e), GFP_KERNEL);
681+ if (!e)
682+ return -ENOMEM;
683+
684+ e->event.base.type = DRM_EXYNOS_IPP_EVENT;
685+ e->event.base.length = sizeof(e->event);
686+ e->event.user_data = user_data;
687+
688+ ret = drm_event_reserve_init(task->dev, file_priv, &e->base,
689+ &e->event.base);
690+ if (ret)
691+ goto free;
692+
693+ task->event = e;
694+ return 0;
695+free:
696+ kfree(e);
697+ return ret;
698+}
699+
700+static void exynos_drm_ipp_event_send(struct exynos_drm_ipp_task *task)
701+{
702+ struct timespec64 now;
703+
704+ ktime_get_ts64(&now);
705+ task->event->event.tv_sec = now.tv_sec;
706+ task->event->event.tv_usec = now.tv_nsec / NSEC_PER_USEC;
707+ task->event->event.sequence = atomic_inc_return(&task->ipp->sequence);
708+
709+ drm_send_event(task->dev, &task->event->base);
710+}
711+
712+static int exynos_drm_ipp_task_cleanup(struct exynos_drm_ipp_task *task)
713+{
714+ int ret = task->ret;
715+
716+ if (ret == 0 && task->event) {
717+ exynos_drm_ipp_event_send(task);
718+ /* ensure event won't be canceled on task free */
719+ task->event = NULL;
720+ }
721+
722+ exynos_drm_ipp_task_free(task->ipp, task);
723+ return ret;
724+}
725+
726+static void exynos_drm_ipp_cleanup_work(struct work_struct *work)
727+{
728+ struct exynos_drm_ipp_task *task = container_of(work,
729+ struct exynos_drm_ipp_task, cleanup_work);
730+
731+ exynos_drm_ipp_task_cleanup(task);
732+}
733+
734+static void exynos_drm_ipp_next_task(struct exynos_drm_ipp *ipp);
735+
736+/**
737+ * exynos_drm_ipp_task_done - finish given task and set return code
738+ * @task: ipp task to finish
739+ * @ret: error code or 0 if operation has been performed successfully
740+ */
741+void exynos_drm_ipp_task_done(struct exynos_drm_ipp_task *task, int ret)
742+{
743+ struct exynos_drm_ipp *ipp = task->ipp;
744+ unsigned long flags;
745+
746+ DRM_DEBUG_DRIVER("ipp: %d, task %pK done: %d\n", ipp->id, task, ret);
747+
748+ spin_lock_irqsave(&ipp->lock, flags);
749+ if (ipp->task == task)
750+ ipp->task = NULL;
751+ task->flags |= DRM_EXYNOS_IPP_TASK_DONE;
752+ task->ret = ret;
753+ spin_unlock_irqrestore(&ipp->lock, flags);
754+
755+ exynos_drm_ipp_next_task(ipp);
756+ wake_up(&ipp->done_wq);
757+
758+ if (task->flags & DRM_EXYNOS_IPP_TASK_ASYNC) {
759+ INIT_WORK(&task->cleanup_work, exynos_drm_ipp_cleanup_work);
760+ schedule_work(&task->cleanup_work);
761+ }
762+}
763+
764+static void exynos_drm_ipp_next_task(struct exynos_drm_ipp *ipp)
765+{
766+ struct exynos_drm_ipp_task *task;
767+ unsigned long flags;
768+ int ret;
769+
770+ DRM_DEBUG_DRIVER("ipp: %d, try to run new task\n", ipp->id);
771+
772+ spin_lock_irqsave(&ipp->lock, flags);
773+
774+ if (ipp->task || list_empty(&ipp->todo_list)) {
775+ spin_unlock_irqrestore(&ipp->lock, flags);
776+ return;
777+ }
778+
779+ task = list_first_entry(&ipp->todo_list, struct exynos_drm_ipp_task,
780+ head);
781+ list_del_init(&task->head);
782+ ipp->task = task;
783+
784+ spin_unlock_irqrestore(&ipp->lock, flags);
785+
786+ DRM_DEBUG_DRIVER("ipp: %d, selected task %pK to run\n", ipp->id, task);
787+
788+ ret = ipp->funcs->commit(ipp, task);
789+ if (ret)
790+ exynos_drm_ipp_task_done(task, ret);
791+}
792+
793+static void exynos_drm_ipp_schedule_task(struct exynos_drm_ipp *ipp,
794+ struct exynos_drm_ipp_task *task)
795+{
796+ unsigned long flags;
797+
798+ spin_lock_irqsave(&ipp->lock, flags);
799+ list_add(&task->head, &ipp->todo_list);
800+ spin_unlock_irqrestore(&ipp->lock, flags);
801+
802+ exynos_drm_ipp_next_task(ipp);
803+}
804+
805+static void exynos_drm_ipp_task_abort(struct exynos_drm_ipp *ipp,
806+ struct exynos_drm_ipp_task *task)
807+{
808+ unsigned long flags;
809+
810+ spin_lock_irqsave(&ipp->lock, flags);
811+ if (task->flags & DRM_EXYNOS_IPP_TASK_DONE) {
812+ /* already completed task */
813+ exynos_drm_ipp_task_cleanup(task);
814+ } else if (ipp->task != task) {
815+ /* task has not been scheduled for execution yet */
816+ list_del_init(&task->head);
817+ exynos_drm_ipp_task_cleanup(task);
818+ } else {
819+ /*
820+ * currently processed task, call abort() and perform
821+ * cleanup with async worker
822+ */
823+ task->flags |= DRM_EXYNOS_IPP_TASK_ASYNC;
824+ spin_unlock_irqrestore(&ipp->lock, flags);
825+ if (ipp->funcs->abort)
826+ ipp->funcs->abort(ipp, task);
827+ return;
828+ }
829+ spin_unlock_irqrestore(&ipp->lock, flags);
830+}
831+
832+/**
833+ * exynos_drm_ipp_commit_ioctl - perform image processing operation
834+ * @dev: DRM device
835+ * @data: ioctl data
836+ * @file_priv: DRM file info
837+ *
838+ * Construct a ipp task from the set of properties provided from the user
839+ * and try to schedule it to framebuffer processor hardware.
840+ *
841+ * Called by the user via ioctl.
842+ *
843+ * Returns:
844+ * Zero on success, negative errno on failure.
845+ */
846+int exynos_drm_ipp_commit_ioctl(struct drm_device *dev, void *data,
847+ struct drm_file *file_priv)
848+{
849+ struct drm_exynos_ioctl_ipp_commit *arg = data;
850+ struct exynos_drm_ipp *ipp;
851+ struct exynos_drm_ipp_task *task;
852+ int ret = 0;
853+
854+ if ((arg->flags & ~DRM_EXYNOS_IPP_FLAGS) || arg->reserved)
855+ return -EINVAL;
856+
857+ /* can't test and expect an event at the same time */
858+ if ((arg->flags & DRM_EXYNOS_IPP_FLAG_TEST_ONLY) &&
859+ (arg->flags & DRM_EXYNOS_IPP_FLAG_EVENT))
860+ return -EINVAL;
861+
862+ ipp = __ipp_get(arg->ipp_id);
863+ if (!ipp)
864+ return -ENOENT;
865+
866+ task = exynos_drm_ipp_task_alloc(ipp);
867+ if (!task)
868+ return -ENOMEM;
869+
870+ ret = exynos_drm_ipp_task_set(task, arg);
871+ if (ret)
872+ goto free;
873+
874+ ret = exynos_drm_ipp_task_check(task);
875+ if (ret)
876+ goto free;
877+
878+ ret = exynos_drm_ipp_task_setup_buffers(task, file_priv);
879+ if (ret || arg->flags & DRM_EXYNOS_IPP_FLAG_TEST_ONLY)
880+ goto free;
881+
882+ if (arg->flags & DRM_EXYNOS_IPP_FLAG_EVENT) {
883+ ret = exynos_drm_ipp_event_create(task, file_priv,
884+ arg->user_data);
885+ if (ret)
886+ goto free;
887+ }
888+
889+ /*
890+ * Queue task for processing on the hardware. task object will be
891+ * then freed after exynos_drm_ipp_task_done()
892+ */
893+ if (arg->flags & DRM_EXYNOS_IPP_FLAG_NONBLOCK) {
894+ DRM_DEBUG_DRIVER("ipp: %d, nonblocking processing task %pK\n",
895+ ipp->id, task);
896+
897+ task->flags |= DRM_EXYNOS_IPP_TASK_ASYNC;
898+ exynos_drm_ipp_schedule_task(task->ipp, task);
899+ ret = 0;
900+ } else {
901+ DRM_DEBUG_DRIVER("ipp: %d, processing task %pK\n", ipp->id,
902+ task);
903+ exynos_drm_ipp_schedule_task(ipp, task);
904+ ret = wait_event_interruptible(ipp->done_wq,
905+ task->flags & DRM_EXYNOS_IPP_TASK_DONE);
906+ if (ret)
907+ exynos_drm_ipp_task_abort(ipp, task);
908+ else
909+ ret = exynos_drm_ipp_task_cleanup(task);
910+ }
911+ return ret;
912+free:
913+ exynos_drm_ipp_task_free(ipp, task);
914+
915+ return ret;
916+}
drivers/gpu/drm/exynos/exynos_drm_ipp.h+175−0
@@ -0,0 +1,175 @@
1+/*
2+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License as published by the
6+ * Free Software Foundation; either version 2 of the License, or (at your
7+ * option) any later version.
8+ */
9+
10+#ifndef _EXYNOS_DRM_IPP_H_
11+#define _EXYNOS_DRM_IPP_H_
12+
13+#include <drm/drmP.h>
14+
15+struct exynos_drm_ipp;
16+struct exynos_drm_ipp_task;
17+
18+/**
19+ * struct exynos_drm_ipp_funcs - exynos_drm_ipp control functions
20+ */
21+struct exynos_drm_ipp_funcs {
22+ /**
23+ * @commit:
24+ *
25+ * This is the main entry point to start framebuffer processing
26+ * in the hardware. The exynos_drm_ipp_task has been already validated.
27+ * This function must not wait until the device finishes processing.
28+ * When the driver finishes processing, it has to call
29+ * exynos_exynos_drm_ipp_task_done() function.
30+ *
31+ * RETURNS:
32+ *
33+ * 0 on success or negative error codes in case of failure.
34+ */
35+ int (*commit)(struct exynos_drm_ipp *ipp,
36+ struct exynos_drm_ipp_task *task);
37+
38+ /**
39+ * @abort:
40+ *
41+ * Informs the driver that it has to abort the currently running
42+ * task as soon as possible (i.e. as soon as it can stop the device
43+ * safely), even if the task would not have been finished by then.
44+ * After the driver performs the necessary steps, it has to call
45+ * exynos_drm_ipp_task_done() (as if the task ended normally).
46+ * This function does not have to (and will usually not) wait
47+ * until the device enters a state when it can be stopped.
48+ */
49+ void (*abort)(struct exynos_drm_ipp *ipp,
50+ struct exynos_drm_ipp_task *task);
51+};
52+
53+/**
54+ * struct exynos_drm_ipp - central picture processor module structure
55+ */
56+struct exynos_drm_ipp {
57+ struct drm_device *dev;
58+ struct list_head head;
59+ unsigned int id;
60+
61+ const char *name;
62+ const struct exynos_drm_ipp_funcs *funcs;
63+ unsigned int capabilities;
64+ const struct exynos_drm_ipp_formats *formats;
65+ unsigned int num_formats;
66+ atomic_t sequence;
67+
68+ spinlock_t lock;
69+ struct exynos_drm_ipp_task *task;
70+ struct list_head todo_list;
71+ wait_queue_head_t done_wq;
72+};
73+
74+struct exynos_drm_ipp_buffer {
75+ struct drm_exynos_ipp_task_buffer buf;
76+ struct drm_exynos_ipp_task_rect rect;
77+
78+ struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER];
79+ const struct drm_format_info *format;
80+ dma_addr_t dma_addr[MAX_FB_BUFFER];
81+};
82+
83+/**
84+ * struct exynos_drm_ipp_task - a structure describing transformation that
85+ * has to be performed by the picture processor hardware module
86+ */
87+struct exynos_drm_ipp_task {
88+ struct drm_device *dev;
89+ struct exynos_drm_ipp *ipp;
90+ struct list_head head;
91+
92+ struct exynos_drm_ipp_buffer src;
93+ struct exynos_drm_ipp_buffer dst;
94+
95+ struct drm_exynos_ipp_task_transform transform;
96+ struct drm_exynos_ipp_task_alpha alpha;
97+
98+ struct work_struct cleanup_work;
99+ unsigned int flags;
100+ int ret;
101+
102+ struct drm_pending_exynos_ipp_event *event;
103+};
104+
105+#define DRM_EXYNOS_IPP_TASK_DONE (1 << 0)
106+#define DRM_EXYNOS_IPP_TASK_ASYNC (1 << 1)
107+
108+struct exynos_drm_ipp_formats {
109+ uint32_t fourcc;
110+ uint32_t type;
111+ uint64_t modifier;
112+ const struct drm_exynos_ipp_limit *limits;
113+ unsigned int num_limits;
114+};
115+
116+/* helper macros to set exynos_drm_ipp_formats structure and limits*/
117+#define IPP_SRCDST_MFORMAT(f, m, l) \
118+ .fourcc = DRM_FORMAT_##f, .modifier = m, .limits = l, \
119+ .num_limits = ARRAY_SIZE(l), \
120+ .type = (DRM_EXYNOS_IPP_FORMAT_SOURCE | \
121+ DRM_EXYNOS_IPP_FORMAT_DESTINATION)
122+
123+#define IPP_SRCDST_FORMAT(f, l) IPP_SRCDST_MFORMAT(f, 0, l)
124+
125+#define IPP_SIZE_LIMIT(l, val...) \
126+ .type = (DRM_EXYNOS_IPP_LIMIT_TYPE_SIZE | \
127+ DRM_EXYNOS_IPP_LIMIT_SIZE_##l), val
128+
129+#define IPP_SCALE_LIMIT(val...) \
130+ .type = (DRM_EXYNOS_IPP_LIMIT_TYPE_SCALE), val
131+
132+int exynos_drm_ipp_register(struct drm_device *dev, struct exynos_drm_ipp *ipp,
133+ const struct exynos_drm_ipp_funcs *funcs, unsigned int caps,
134+ const struct exynos_drm_ipp_formats *formats,
135+ unsigned int num_formats, const char *name);
136+void exynos_drm_ipp_unregister(struct drm_device *dev,
137+ struct exynos_drm_ipp *ipp);
138+
139+void exynos_drm_ipp_task_done(struct exynos_drm_ipp_task *task, int ret);
140+
141+#ifdef CONFIG_DRM_EXYNOS_IPP
142+int exynos_drm_ipp_get_res_ioctl(struct drm_device *dev, void *data,
143+ struct drm_file *file_priv);
144+int exynos_drm_ipp_get_caps_ioctl(struct drm_device *dev, void *data,
145+ struct drm_file *file_priv);
146+int exynos_drm_ipp_get_limits_ioctl(struct drm_device *dev, void *data,
147+ struct drm_file *file_priv);
148+int exynos_drm_ipp_commit_ioctl(struct drm_device *dev,
149+ void *data, struct drm_file *file_priv);
150+#else
151+static inline int exynos_drm_ipp_get_res_ioctl(struct drm_device *dev,
152+ void *data, struct drm_file *file_priv)
153+{
154+ struct drm_exynos_ioctl_ipp_get_res *resp = data;
155+
156+ resp->count_ipps = 0;
157+ return 0;
158+}
159+static inline int exynos_drm_ipp_get_caps_ioctl(struct drm_device *dev,
160+ void *data, struct drm_file *file_priv)
161+{
162+ return -ENODEV;
163+}
164+static inline int exynos_drm_ipp_get_limits_ioctl(struct drm_device *dev,
165+ void *data, struct drm_file *file_priv)
166+{
167+ return -ENODEV;
168+}
169+static inline int exynos_drm_ipp_commit_ioctl(struct drm_device *dev,
170+ void *data, struct drm_file *file_priv)
171+{
172+ return -ENODEV;
173+}
174+#endif
175+#endif
drivers/gpu/drm/exynos/exynos_drm_rotator.c+188−570
@@ -10,6 +10,7 @@ · 9 unmodified lines
1010 */
1111
1212 #include <linux/kernel.h>
13+#include <linux/component.h>
1314 #include <linux/err.h>
1415 #include <linux/interrupt.h>
1516 #include <linux/io.h>
@@ -22,29 +23,18 @@ · 6 unmodified lines
2223 #include <drm/exynos_drm.h>
2324 #include "regs-rotator.h"
2425 #include "exynos_drm_drv.h"
26+#include "exynos_drm_iommu.h"
2527 #include "exynos_drm_ipp.h"
2628
2729 /*
2830 * Rotator supports image crop/rotator and input/output DMA operations.
2931 * input DMA reads image data from the memory.
3032 * output DMA writes image data to memory.
31− *
32− * M2M operation : supports crop/scale/rotation/csc so on.
33− * Memory ----> Rotator H/W ----> Memory.
3433 */
3534
36−/*
37− * TODO
38− * 1. check suspend/resume api if needed.
39− * 2. need to check use case platform_device_id.
40− * 3. check src/dst size with, height.
41− * 4. need to add supported list in prop_list.
42− */
35+#define ROTATOR_AUTOSUSPEND_DELAY 2000
4336
44−#define get_rot_context(dev) platform_get_drvdata(to_platform_device(dev))
45−#define get_ctx_from_ippdrv(ippdrv) container_of(ippdrv,\
46− struct rot_context, ippdrv);
47−#define rot_read(offset) readl(rot->regs + (offset))
37+#define rot_read(offset) readl(rot->regs + (offset))
4838 #define rot_write(cfg, offset) writel(cfg, rot->regs + (offset))
4939
5040 enum rot_irq_status {
@@ -52,54 +42,28 @@ enum rot_irq_status { · 1 unmodified line
5242 ROT_IRQ_STATUS_ILLEGAL = 9,
5343 };
5444
55−/*
56− * A structure of limitation.
57− *
58− * @min_w: minimum width.
59− * @min_h: minimum height.
60− * @max_w: maximum width.
61− * @max_h: maximum height.
62− * @align: align size.
63− */
64−struct rot_limit {
65− u32 min_w;
66− u32 min_h;
67− u32 max_w;
68− u32 max_h;
69− u32 align;
70−};
71−
72−/*
73− * A structure of limitation table.
74− *
75− * @ycbcr420_2p: case of YUV.
76− * @rgb888: case of RGB.
77− */
78−struct rot_limit_table {
79− struct rot_limit ycbcr420_2p;
80− struct rot_limit rgb888;
45+struct rot_variant {
46+ const struct exynos_drm_ipp_formats *formats;
47+ unsigned int num_formats;
8148 };
8249
8350 /*
8451 * A structure of rotator context.
8552 * @ippdrv: prepare initialization using ippdrv.
86− * @regs_res: register resources.
8753 * @regs: memory mapped io registers.
8854 * @clock: rotator gate clock.
8955 * @limit_tbl: limitation of rotator.
9056 * @irq: irq number.
91− * @cur_buf_id: current operation buffer id.
92− * @suspended: suspended state.
9357 */
9458 struct rot_context {
95− struct exynos_drm_ippdrv ippdrv;
96− struct resource *regs_res;
59+ struct exynos_drm_ipp ipp;
60+ struct drm_device *drm_dev;
61+ struct device *dev;
9762 void __iomem *regs;
9863 struct clk *clock;
99− struct rot_limit_table *limit_tbl;
100− int irq;
101− int cur_buf_id[EXYNOS_DRM_OPS_MAX];
102− bool suspended;
64+ const struct exynos_drm_ipp_formats *formats;
65+ unsigned int num_formats;
66+ struct exynos_drm_ipp_task *task;
10367 };
10468
10569 static void rotator_reg_set_irq(struct rot_context *rot, bool enable)
@@ -114,15 +78,6 @@ static void rotator_reg_set_irq(struct rot_context *rot, bool enable) · 8 unmodified lines
11478 rot_write(val, ROT_CONFIG);
11579 }
11680
117−static u32 rotator_reg_get_fmt(struct rot_context *rot)
118−{
119− u32 val = rot_read(ROT_CONTROL);
120−
121− val &= ROT_CONTROL_FMT_MASK;
122−
123− return val;
124−}
125−
12681 static enum rot_irq_status rotator_reg_get_irq_status(struct rot_context *rot)
12782 {
12883 u32 val = rot_read(ROT_STATUS);
@@ -138,9 +93,6 @@ static enum rot_irq_status rotator_reg_get_irq_status(struct rot_context *rot) · 9 unmodified lines
13893 static irqreturn_t rotator_irq_handler(int irq, void *arg)
13994 {
14095 struct rot_context *rot = arg;
141− struct exynos_drm_ippdrv *ippdrv = &rot->ippdrv;
142− struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;
143− struct drm_exynos_ipp_event_work *event_work = c_node->event_work;
14496 enum rot_irq_status irq_status;
14597 u32 val;
14698
@@ -152,56 +104,21 @@ static irqreturn_t rotator_irq_handler(int irq, void *arg) · 5 unmodified lines
152104 val |= ROT_STATUS_IRQ_PENDING((u32)irq_status);
153105 rot_write(val, ROT_STATUS);
154106
155− if (irq_status == ROT_IRQ_STATUS_COMPLETE) {
156− event_work->ippdrv = ippdrv;
157− event_work->buf_id[EXYNOS_DRM_OPS_DST] =
158− rot->cur_buf_id[EXYNOS_DRM_OPS_DST];
159− queue_work(ippdrv->event_workq, &event_work->work);
160− } else {
161− DRM_ERROR("the SFR is set illegally\n");
107+ if (rot->task) {
108+ struct exynos_drm_ipp_task *task = rot->task;
109+
110+ rot->task = NULL;
111+ pm_runtime_mark_last_busy(rot->dev);
112+ pm_runtime_put_autosuspend(rot->dev);
113+ exynos_drm_ipp_task_done(task,
114+ irq_status == ROT_IRQ_STATUS_COMPLETE ? 0 : -EINVAL);
162115 }
163116
164117 return IRQ_HANDLED;
165118 }
166119
167−static void rotator_align_size(struct rot_context *rot, u32 fmt, u32 *hsize,
168− u32 *vsize)
120+static void rotator_src_set_fmt(struct rot_context *rot, u32 fmt)
169121 {
170− struct rot_limit_table *limit_tbl = rot->limit_tbl;
171− struct rot_limit *limit;
172− u32 mask, val;
173−
174− /* Get size limit */
175− if (fmt == ROT_CONTROL_FMT_RGB888)
176− limit = &limit_tbl->rgb888;
177− else
178− limit = &limit_tbl->ycbcr420_2p;
179−
180− /* Get mask for rounding to nearest aligned val */
181− mask = ~((1 << limit->align) - 1);
182−
183− /* Set aligned width */
184− val = ROT_ALIGN(*hsize, limit->align, mask);
185− if (val < limit->min_w)
186− *hsize = ROT_MIN(limit->min_w, mask);
187− else if (val > limit->max_w)
188− *hsize = ROT_MAX(limit->max_w, mask);
189− else
190− *hsize = val;
191−
192− /* Set aligned height */
193− val = ROT_ALIGN(*vsize, limit->align, mask);
194− if (val < limit->min_h)
195− *vsize = ROT_MIN(limit->min_h, mask);
196− else if (val > limit->max_h)
197− *vsize = ROT_MAX(limit->max_h, mask);
198− else
199− *vsize = val;
200−}
201−
202−static int rotator_src_set_fmt(struct device *dev, u32 fmt)
203−{
204− struct rot_context *rot = dev_get_drvdata(dev);
205122 u32 val;
206123
207124 val = rot_read(ROT_CONTROL);
@@ -214,515 +131,176 @@ static int rotator_src_set_fmt(struct device *dev, u32 fmt) · 6 unmodified lines
214131 case DRM_FORMAT_XRGB8888:
215132 val |= ROT_CONTROL_FMT_RGB888;
216133 break;
217− default:
218− DRM_ERROR("invalid image format\n");
219− return -EINVAL;
220134 }
221135
222136 rot_write(val, ROT_CONTROL);
223−
224− return 0;
225137 }
226138
227−static inline bool rotator_check_reg_fmt(u32 fmt)
139+static void rotator_src_set_buf(struct rot_context *rot,
140+ struct exynos_drm_ipp_buffer *buf)
228141 {
229− if ((fmt == ROT_CONTROL_FMT_YCBCR420_2P) ||
230− (fmt == ROT_CONTROL_FMT_RGB888))
231− return true;
232−
233− return false;
234−}
235−
236−static int rotator_src_set_size(struct device *dev, int swap,
237− struct drm_exynos_pos *pos,
238− struct drm_exynos_sz *sz)
239−{
240− struct rot_context *rot = dev_get_drvdata(dev);
241− u32 fmt, hsize, vsize;
242142 u32 val;
243143
244− /* Get format */
245− fmt = rotator_reg_get_fmt(rot);
246− if (!rotator_check_reg_fmt(fmt)) {
247− DRM_ERROR("invalid format.\n");
248− return -EINVAL;
249− }
250−
251− /* Align buffer size */
252− hsize = sz->hsize;
253− vsize = sz->vsize;
254− rotator_align_size(rot, fmt, &hsize, &vsize);
255−
256144 /* Set buffer size configuration */
257− val = ROT_SET_BUF_SIZE_H(vsize) | ROT_SET_BUF_SIZE_W(hsize);
145+ val = ROT_SET_BUF_SIZE_H(buf->buf.height) |
146+ ROT_SET_BUF_SIZE_W(buf->buf.pitch[0] / buf->format->cpp[0]);
258147 rot_write(val, ROT_SRC_BUF_SIZE);
259148
260149 /* Set crop image position configuration */
261− val = ROT_CROP_POS_Y(pos->y) | ROT_CROP_POS_X(pos->x);
150+ val = ROT_CROP_POS_Y(buf->rect.y) | ROT_CROP_POS_X(buf->rect.x);
262151 rot_write(val, ROT_SRC_CROP_POS);
263− val = ROT_SRC_CROP_SIZE_H(pos->h) | ROT_SRC_CROP_SIZE_W(pos->w);
152+ val = ROT_SRC_CROP_SIZE_H(buf->rect.h) |
153+ ROT_SRC_CROP_SIZE_W(buf->rect.w);
264154 rot_write(val, ROT_SRC_CROP_SIZE);
265155
266− return 0;
156+ /* Set buffer DMA address */
157+ rot_write(buf->dma_addr[0], ROT_SRC_BUF_ADDR(0));
158+ rot_write(buf->dma_addr[1], ROT_SRC_BUF_ADDR(1));
267159 }
268160
269−static int rotator_src_set_addr(struct device *dev,
270− struct drm_exynos_ipp_buf_info *buf_info,
271− u32 buf_id, enum drm_exynos_ipp_buf_type buf_type)
161+static void rotator_dst_set_transf(struct rot_context *rot,
162+ unsigned int rotation)
272163 {
273− struct rot_context *rot = dev_get_drvdata(dev);
274− dma_addr_t addr[EXYNOS_DRM_PLANAR_MAX];
275− u32 val, fmt, hsize, vsize;
276− int i;
277−
278− /* Set current buf_id */
279− rot->cur_buf_id[EXYNOS_DRM_OPS_SRC] = buf_id;
280−
281− switch (buf_type) {
282− case IPP_BUF_ENQUEUE:
283− /* Set address configuration */
284− for_each_ipp_planar(i)
285− addr[i] = buf_info->base[i];
286−
287− /* Get format */
288− fmt = rotator_reg_get_fmt(rot);
289− if (!rotator_check_reg_fmt(fmt)) {
290− DRM_ERROR("invalid format.\n");
291− return -EINVAL;
292− }
293−
294− /* Re-set cb planar for NV12 format */
295− if ((fmt == ROT_CONTROL_FMT_YCBCR420_2P) &&
296− !addr[EXYNOS_DRM_PLANAR_CB]) {
297−
298− val = rot_read(ROT_SRC_BUF_SIZE);
299− hsize = ROT_GET_BUF_SIZE_W(val);
300− vsize = ROT_GET_BUF_SIZE_H(val);
301−
302− /* Set cb planar */
303− addr[EXYNOS_DRM_PLANAR_CB] =
304− addr[EXYNOS_DRM_PLANAR_Y] + hsize * vsize;
305− }
306−
307− for_each_ipp_planar(i)
308− rot_write(addr[i], ROT_SRC_BUF_ADDR(i));
309− break;
310− case IPP_BUF_DEQUEUE:
311− for_each_ipp_planar(i)
312− rot_write(0x0, ROT_SRC_BUF_ADDR(i));
313− break;
314− default:
315− /* Nothing to do */
316− break;
317− }
318−
319− return 0;
320−}
321−
322−static int rotator_dst_set_transf(struct device *dev,
323− enum drm_exynos_degree degree,
324− enum drm_exynos_flip flip, bool *swap)
325−{
326− struct rot_context *rot = dev_get_drvdata(dev);
327164 u32 val;
328165
329166 /* Set transform configuration */
330167 val = rot_read(ROT_CONTROL);
331168 val &= ~ROT_CONTROL_FLIP_MASK;
332169
333− switch (flip) {
334− case EXYNOS_DRM_FLIP_VERTICAL:
335− val |= ROT_CONTROL_FLIP_VERTICAL;
336− break;
337− case EXYNOS_DRM_FLIP_HORIZONTAL:
170+ if (rotation & DRM_MODE_REFLECT_X)
338171 val |= ROT_CONTROL_FLIP_HORIZONTAL;
339− break;
340− default:
341− /* Flip None */
342− break;
343− }
172+ if (rotation & DRM_MODE_REFLECT_Y)
173+ val |= ROT_CONTROL_FLIP_VERTICAL;
344174
345175 val &= ~ROT_CONTROL_ROT_MASK;
346176
347− switch (degree) {
348− case EXYNOS_DRM_DEGREE_90:
177+ if (rotation & DRM_MODE_ROTATE_90)
349178 val |= ROT_CONTROL_ROT_90;
350− break;
351− case EXYNOS_DRM_DEGREE_180:
179+ else if (rotation & DRM_MODE_ROTATE_180)
352180 val |= ROT_CONTROL_ROT_180;
353− break;
354− case EXYNOS_DRM_DEGREE_270:
181+ else if (rotation & DRM_MODE_ROTATE_270)
355182 val |= ROT_CONTROL_ROT_270;
356− break;
357− default:
358− /* Rotation 0 Degree */
359− break;
360− }
361183
362184 rot_write(val, ROT_CONTROL);
363−
364− /* Check degree for setting buffer size swap */
365− if ((degree == EXYNOS_DRM_DEGREE_90) ||
366− (degree == EXYNOS_DRM_DEGREE_270))
367− *swap = true;
368− else
369− *swap = false;
370−
371− return 0;
372185 }
373186
374−static int rotator_dst_set_size(struct device *dev, int swap,
375− struct drm_exynos_pos *pos,
376− struct drm_exynos_sz *sz)
187+static void rotator_dst_set_buf(struct rot_context *rot,
188+ struct exynos_drm_ipp_buffer *buf)
377189 {
378− struct rot_context *rot = dev_get_drvdata(dev);
379− u32 val, fmt, hsize, vsize;
380−
381− /* Get format */
382− fmt = rotator_reg_get_fmt(rot);
383− if (!rotator_check_reg_fmt(fmt)) {
384− DRM_ERROR("invalid format.\n");
385− return -EINVAL;
386− }
387−
388− /* Align buffer size */
389− hsize = sz->hsize;
390− vsize = sz->vsize;
391− rotator_align_size(rot, fmt, &hsize, &vsize);
190+ u32 val;
392191
393192 /* Set buffer size configuration */
394− val = ROT_SET_BUF_SIZE_H(vsize) | ROT_SET_BUF_SIZE_W(hsize);
193+ val = ROT_SET_BUF_SIZE_H(buf->buf.height) |
194+ ROT_SET_BUF_SIZE_W(buf->buf.pitch[0] / buf->format->cpp[0]);
395195 rot_write(val, ROT_DST_BUF_SIZE);
396196
397197 /* Set crop image position configuration */
398− val = ROT_CROP_POS_Y(pos->y) | ROT_CROP_POS_X(pos->x);
198+ val = ROT_CROP_POS_Y(buf->rect.y) | ROT_CROP_POS_X(buf->rect.x);
399199 rot_write(val, ROT_DST_CROP_POS);
400200
401− return 0;
201+ /* Set buffer DMA address */
202+ rot_write(buf->dma_addr[0], ROT_DST_BUF_ADDR(0));
203+ rot_write(buf->dma_addr[1], ROT_DST_BUF_ADDR(1));
402204 }
403205
404−static int rotator_dst_set_addr(struct device *dev,
405− struct drm_exynos_ipp_buf_info *buf_info,
406− u32 buf_id, enum drm_exynos_ipp_buf_type buf_type)
206+static void rotator_start(struct rot_context *rot)
407207 {
408− struct rot_context *rot = dev_get_drvdata(dev);
409− dma_addr_t addr[EXYNOS_DRM_PLANAR_MAX];
410− u32 val, fmt, hsize, vsize;
411− int i;
412−
413− /* Set current buf_id */
414− rot->cur_buf_id[EXYNOS_DRM_OPS_DST] = buf_id;
415−
416− switch (buf_type) {
417− case IPP_BUF_ENQUEUE:
418− /* Set address configuration */
419− for_each_ipp_planar(i)
420− addr[i] = buf_info->base[i];
421−
422− /* Get format */
423− fmt = rotator_reg_get_fmt(rot);
424− if (!rotator_check_reg_fmt(fmt)) {
425− DRM_ERROR("invalid format.\n");
426− return -EINVAL;
427− }
428−
429− /* Re-set cb planar for NV12 format */
430− if ((fmt == ROT_CONTROL_FMT_YCBCR420_2P) &&
431− !addr[EXYNOS_DRM_PLANAR_CB]) {
432− /* Get buf size */
433− val = rot_read(ROT_DST_BUF_SIZE);
434−
435− hsize = ROT_GET_BUF_SIZE_W(val);
436− vsize = ROT_GET_BUF_SIZE_H(val);
437−
438− /* Set cb planar */
439− addr[EXYNOS_DRM_PLANAR_CB] =
440− addr[EXYNOS_DRM_PLANAR_Y] + hsize * vsize;
441− }
442−
443− for_each_ipp_planar(i)
444− rot_write(addr[i], ROT_DST_BUF_ADDR(i));
445− break;
446− case IPP_BUF_DEQUEUE:
447− for_each_ipp_planar(i)
448− rot_write(0x0, ROT_DST_BUF_ADDR(i));
449− break;
450− default:
451− /* Nothing to do */
452− break;
453− }
208+ u32 val;
454209
455− return 0;
210+ /* Set interrupt enable */
211+ rotator_reg_set_irq(rot, true);
212+
213+ val = rot_read(ROT_CONTROL);
214+ val |= ROT_CONTROL_START;
215+ rot_write(val, ROT_CONTROL);
456216 }
457217
458−static struct exynos_drm_ipp_ops rot_src_ops = {
459− .set_fmt = rotator_src_set_fmt,
460− .set_size = rotator_src_set_size,
461− .set_addr = rotator_src_set_addr,
462−};
218+static int rotator_commit(struct exynos_drm_ipp *ipp,
219+ struct exynos_drm_ipp_task *task)
220+{
221+ struct rot_context *rot =
222+ container_of(ipp, struct rot_context, ipp);
463223
464−static struct exynos_drm_ipp_ops rot_dst_ops = {
465− .set_transf = rotator_dst_set_transf,
466− .set_size = rotator_dst_set_size,
467− .set_addr = rotator_dst_set_addr,
468−};
224+ pm_runtime_get_sync(rot->dev);
225+ rot->task = task;
469226
470−static int rotator_init_prop_list(struct exynos_drm_ippdrv *ippdrv)
471−{
472− struct drm_exynos_ipp_prop_list *prop_list = &ippdrv->prop_list;
473−
474− prop_list->version = 1;
475− prop_list->flip = (1 << EXYNOS_DRM_FLIP_VERTICAL) |
476− (1 << EXYNOS_DRM_FLIP_HORIZONTAL);
477− prop_list->degree = (1 << EXYNOS_DRM_DEGREE_0) |
478− (1 << EXYNOS_DRM_DEGREE_90) |
479− (1 << EXYNOS_DRM_DEGREE_180) |
480− (1 << EXYNOS_DRM_DEGREE_270);
481− prop_list->csc = 0;
482− prop_list->crop = 0;
483− prop_list->scale = 0;
227+ rotator_src_set_fmt(rot, task->src.buf.fourcc);
228+ rotator_src_set_buf(rot, &task->src);
229+ rotator_dst_set_transf(rot, task->transform.rotation);
230+ rotator_dst_set_buf(rot, &task->dst);
231+ rotator_start(rot);
484232
485233 return 0;
486234 }
487235
488−static inline bool rotator_check_drm_fmt(u32 fmt)
489−{
490− switch (fmt) {
491− case DRM_FORMAT_XRGB8888:
492− case DRM_FORMAT_NV12:
493− return true;
494− default:
495− DRM_DEBUG_KMS("not support format\n");
496− return false;
497− }
498−}
499−
500−static inline bool rotator_check_drm_flip(enum drm_exynos_flip flip)
501−{
502− switch (flip) {
503− case EXYNOS_DRM_FLIP_NONE:
504− case EXYNOS_DRM_FLIP_VERTICAL:
505− case EXYNOS_DRM_FLIP_HORIZONTAL:
506− case EXYNOS_DRM_FLIP_BOTH:
507− return true;
508− default:
509− DRM_DEBUG_KMS("invalid flip\n");
510− return false;
511− }
512−}
236+static const struct exynos_drm_ipp_funcs ipp_funcs = {
237+ .commit = rotator_commit,
238+};
513239
514−static int rotator_ippdrv_check_property(struct device *dev,
515− struct drm_exynos_ipp_property *property)
240+static int rotator_bind(struct device *dev, struct device *master, void *data)
516241 {
517− struct drm_exynos_ipp_config *src_config =
518− &property->config[EXYNOS_DRM_OPS_SRC];
519− struct drm_exynos_ipp_config *dst_config =
520− &property->config[EXYNOS_DRM_OPS_DST];
521− struct drm_exynos_pos *src_pos = &src_config->pos;
522− struct drm_exynos_pos *dst_pos = &dst_config->pos;
523− struct drm_exynos_sz *src_sz = &src_config->sz;
524− struct drm_exynos_sz *dst_sz = &dst_config->sz;
525− bool swap = false;
526−
527− /* Check format configuration */
528− if (src_config->fmt != dst_config->fmt) {
529− DRM_DEBUG_KMS("not support csc feature\n");
530− return -EINVAL;
531− }
532−
533− if (!rotator_check_drm_fmt(dst_config->fmt)) {
534− DRM_DEBUG_KMS("invalid format\n");
535− return -EINVAL;
536− }
537−
538− /* Check transform configuration */
539− if (src_config->degree != EXYNOS_DRM_DEGREE_0) {
540− DRM_DEBUG_KMS("not support source-side rotation\n");
541− return -EINVAL;
542− }
543−
544− switch (dst_config->degree) {
545− case EXYNOS_DRM_DEGREE_90:
546− case EXYNOS_DRM_DEGREE_270:
547− swap = true;
548− case EXYNOS_DRM_DEGREE_0:
549− case EXYNOS_DRM_DEGREE_180:
550− /* No problem */
551− break;
552− default:
553− DRM_DEBUG_KMS("invalid degree\n");
554− return -EINVAL;
555− }
556−
557− if (src_config->flip != EXYNOS_DRM_FLIP_NONE) {
558− DRM_DEBUG_KMS("not support source-side flip\n");
559− return -EINVAL;
560− }
242+ struct rot_context *rot = dev_get_drvdata(dev);
243+ struct drm_device *drm_dev = data;
244+ struct exynos_drm_ipp *ipp = &rot->ipp;
561245
562− if (!rotator_check_drm_flip(dst_config->flip)) {
563− DRM_DEBUG_KMS("invalid flip\n");
564− return -EINVAL;
565− }
246+ rot->drm_dev = drm_dev;
247+ drm_iommu_attach_device(drm_dev, dev);
566248
567− /* Check size configuration */
568− if ((src_pos->x + src_pos->w > src_sz->hsize) ||
569− (src_pos->y + src_pos->h > src_sz->vsize)) {
570− DRM_DEBUG_KMS("out of source buffer bound\n");
571− return -EINVAL;
572− }
249+ exynos_drm_ipp_register(drm_dev, ipp, &ipp_funcs,
250+ DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE,
251+ rot->formats, rot->num_formats, "rotator");
573252
574− if (swap) {
575− if ((dst_pos->x + dst_pos->h > dst_sz->vsize) ||
576− (dst_pos->y + dst_pos->w > dst_sz->hsize)) {
577− DRM_DEBUG_KMS("out of destination buffer bound\n");
578− return -EINVAL;
579− }
580−
581− if ((src_pos->w != dst_pos->h) || (src_pos->h != dst_pos->w)) {
582− DRM_DEBUG_KMS("not support scale feature\n");
583− return -EINVAL;
584− }
585− } else {
586− if ((dst_pos->x + dst_pos->w > dst_sz->hsize) ||
587− (dst_pos->y + dst_pos->h > dst_sz->vsize)) {
588− DRM_DEBUG_KMS("out of destination buffer bound\n");
589− return -EINVAL;
590− }
591−
592− if ((src_pos->w != dst_pos->w) || (src_pos->h != dst_pos->h)) {
593− DRM_DEBUG_KMS("not support scale feature\n");
594− return -EINVAL;
595− }
596− }
253+ dev_info(dev, "The exynos rotator has been probed successfully\n");
597254
598255 return 0;
599256 }
600257
601−static int rotator_ippdrv_start(struct device *dev, enum drm_exynos_ipp_cmd cmd)
258+static void rotator_unbind(struct device *dev, struct device *master,
259+ void *data)
602260 {
603261 struct rot_context *rot = dev_get_drvdata(dev);
604− u32 val;
605−
606− if (rot->suspended) {
607− DRM_ERROR("suspended state\n");
608− return -EPERM;
609− }
610−
611− if (cmd != IPP_CMD_M2M) {
612− DRM_ERROR("not support cmd: %d\n", cmd);
613− return -EINVAL;
614− }
615−
616− /* Set interrupt enable */
617− rotator_reg_set_irq(rot, true);
618−
619− val = rot_read(ROT_CONTROL);
620− val |= ROT_CONTROL_START;
621−
622− rot_write(val, ROT_CONTROL);
262+ struct drm_device *drm_dev = data;
263+ struct exynos_drm_ipp *ipp = &rot->ipp;
623264
624− return 0;
265+ exynos_drm_ipp_unregister(drm_dev, ipp);
266+ drm_iommu_detach_device(rot->drm_dev, rot->dev);
625267 }
626268
627−static struct rot_limit_table rot_limit_tbl_4210 = {
628− .ycbcr420_2p = {
629− .min_w = 32,
630− .min_h = 32,
631− .max_w = SZ_64K,
632− .max_h = SZ_64K,
633− .align = 3,
634− },
635− .rgb888 = {
636− .min_w = 8,
637− .min_h = 8,
638− .max_w = SZ_16K,
639− .max_h = SZ_16K,
640− .align = 2,
641− },
642−};
643−
644−static struct rot_limit_table rot_limit_tbl_4x12 = {
645− .ycbcr420_2p = {
646− .min_w = 32,
647− .min_h = 32,
648− .max_w = SZ_32K,
649− .max_h = SZ_32K,
650− .align = 3,
651− },
652− .rgb888 = {
653− .min_w = 8,
654− .min_h = 8,
655− .max_w = SZ_8K,
656− .max_h = SZ_8K,
657− .align = 2,
658− },
269+static const struct component_ops rotator_component_ops = {
270+ .bind = rotator_bind,
271+ .unbind = rotator_unbind,
659272 };
660273
661−static struct rot_limit_table rot_limit_tbl_5250 = {
662− .ycbcr420_2p = {
663− .min_w = 32,
664− .min_h = 32,
665− .max_w = SZ_32K,
666− .max_h = SZ_32K,
667− .align = 3,
668− },
669− .rgb888 = {
670− .min_w = 8,
671− .min_h = 8,
672− .max_w = SZ_8K,
673− .max_h = SZ_8K,
674− .align = 1,
675− },
676−};
677−
678−static const struct of_device_id exynos_rotator_match[] = {
679− {
680− .compatible = "samsung,exynos4210-rotator",
681− .data = &rot_limit_tbl_4210,
682− },
683− {
684− .compatible = "samsung,exynos4212-rotator",
685− .data = &rot_limit_tbl_4x12,
686− },
687− {
688− .compatible = "samsung,exynos5250-rotator",
689− .data = &rot_limit_tbl_5250,
690− },
691− {},
692−};
693−MODULE_DEVICE_TABLE(of, exynos_rotator_match);
694−
695274 static int rotator_probe(struct platform_device *pdev)
696275 {
697276 struct device *dev = &pdev->dev;
277+ struct resource *regs_res;
698278 struct rot_context *rot;
699− struct exynos_drm_ippdrv *ippdrv;
279+ const struct rot_variant *variant;
280+ int irq;
700281 int ret;
701282
702− if (!dev->of_node) {
703− dev_err(dev, "cannot find of_node.\n");
704− return -ENODEV;
705− }
706−
707283 rot = devm_kzalloc(dev, sizeof(*rot), GFP_KERNEL);
708284 if (!rot)
709285 return -ENOMEM;
710286
711− rot->limit_tbl = (struct rot_limit_table *)
712− of_device_get_match_data(dev);
713− rot->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
714− rot->regs = devm_ioremap_resource(dev, rot->regs_res);
287+ variant = of_device_get_match_data(dev);
288+ rot->formats = variant->formats;
289+ rot->num_formats = variant->num_formats;
290+ rot->dev = dev;
291+ regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
292+ rot->regs = devm_ioremap_resource(dev, regs_res);
715293 if (IS_ERR(rot->regs))
716294 return PTR_ERR(rot->regs);
717295
718− rot->irq = platform_get_irq(pdev, 0);
719− if (rot->irq < 0) {
296+ irq = platform_get_irq(pdev, 0);
297+ if (irq < 0) {
720298 dev_err(dev, "failed to get irq\n");
721− return rot->irq;
299+ return irq;
722300 }
723301
724− ret = devm_request_threaded_irq(dev, rot->irq, NULL,
725− rotator_irq_handler, IRQF_ONESHOT, "drm_rotator", rot);
302+ ret = devm_request_irq(dev, irq, rotator_irq_handler, 0, dev_name(dev),
303+ rot);
726304 if (ret < 0) {
727305 dev_err(dev, "failed to request irq\n");
728306 return ret;
@@ -734,35 +312,19 @@ static int rotator_probe(struct platform_device *pdev) · 5 unmodified lines
734312 return PTR_ERR(rot->clock);
735313 }
736314
315+ pm_runtime_use_autosuspend(dev);
316+ pm_runtime_set_autosuspend_delay(dev, ROTATOR_AUTOSUSPEND_DELAY);
737317 pm_runtime_enable(dev);
738−
739− ippdrv = &rot->ippdrv;
740− ippdrv->dev = dev;
741− ippdrv->ops[EXYNOS_DRM_OPS_SRC] = &rot_src_ops;
742− ippdrv->ops[EXYNOS_DRM_OPS_DST] = &rot_dst_ops;
743− ippdrv->check_property = rotator_ippdrv_check_property;
744− ippdrv->start = rotator_ippdrv_start;
745− ret = rotator_init_prop_list(ippdrv);
746− if (ret < 0) {
747− dev_err(dev, "failed to init property list.\n");
748− goto err_ippdrv_register;
749− }
750−
751− DRM_DEBUG_KMS("ippdrv[%pK]\n", ippdrv);
752−
753318 platform_set_drvdata(pdev, rot);
754319
755− ret = exynos_drm_ippdrv_register(ippdrv);
756− if (ret < 0) {
757− dev_err(dev, "failed to register drm rotator device\n");
758− goto err_ippdrv_register;
759− }
760−
761− dev_info(dev, "The exynos rotator is probed successfully\n");
320+ ret = component_add(dev, &rotator_component_ops);
321+ if (ret)
322+ goto err_component;
762323
763324 return 0;
764325
765−err_ippdrv_register:
326+err_component:
327+ pm_runtime_dont_use_autosuspend(dev);
766328 pm_runtime_disable(dev);
767329 return ret;
768330 }
@@ -770,45 +332,101 @@ err_ippdrv_register: · 1 unmodified line
770332 static int rotator_remove(struct platform_device *pdev)
771333 {
772334 struct device *dev = &pdev->dev;
773− struct rot_context *rot = dev_get_drvdata(dev);
774− struct exynos_drm_ippdrv *ippdrv = &rot->ippdrv;
775−
776− exynos_drm_ippdrv_unregister(ippdrv);
777335
336+ component_del(dev, &rotator_component_ops);
337+ pm_runtime_dont_use_autosuspend(dev);
778338 pm_runtime_disable(dev);
779339
780340 return 0;
781341 }
782342
783343 #ifdef CONFIG_PM
784−static int rotator_clk_crtl(struct rot_context *rot, bool enable)
785−{
786− if (enable) {
787− clk_prepare_enable(rot->clock);
788− rot->suspended = false;
789− } else {
790− clk_disable_unprepare(rot->clock);
791− rot->suspended = true;
792− }
793−
794− return 0;
795−}
796−
797344 static int rotator_runtime_suspend(struct device *dev)
798345 {
799346 struct rot_context *rot = dev_get_drvdata(dev);
800347
801− return rotator_clk_crtl(rot, false);
348+ clk_disable_unprepare(rot->clock);
349+ return 0;
802350 }
803351
804352 static int rotator_runtime_resume(struct device *dev)
805353 {
806354 struct rot_context *rot = dev_get_drvdata(dev);
807355
808− return rotator_clk_crtl(rot, true);
356+ return clk_prepare_enable(rot->clock);
809357 }
810358 #endif
811359
360+static const struct drm_exynos_ipp_limit rotator_4210_rbg888_limits[] = {
361+ { IPP_SIZE_LIMIT(BUFFER, .h = { 8, SZ_16K }, .v = { 8, SZ_16K }) },
362+ { IPP_SIZE_LIMIT(AREA, .h.align = 4, .v.align = 4) },
363+};
364+
365+static const struct drm_exynos_ipp_limit rotator_4412_rbg888_limits[] = {
366+ { IPP_SIZE_LIMIT(BUFFER, .h = { 8, SZ_8K }, .v = { 8, SZ_8K }) },
367+ { IPP_SIZE_LIMIT(AREA, .h.align = 4, .v.align = 4) },
368+};
369+
370+static const struct drm_exynos_ipp_limit rotator_5250_rbg888_limits[] = {
371+ { IPP_SIZE_LIMIT(BUFFER, .h = { 8, SZ_8K }, .v = { 8, SZ_8K }) },
372+ { IPP_SIZE_LIMIT(AREA, .h.align = 2, .v.align = 2) },
373+};
374+
375+static const struct drm_exynos_ipp_limit rotator_4210_yuv_limits[] = {
376+ { IPP_SIZE_LIMIT(BUFFER, .h = { 32, SZ_64K }, .v = { 32, SZ_64K }) },
377+ { IPP_SIZE_LIMIT(AREA, .h.align = 8, .v.align = 8) },
378+};
379+
380+static const struct drm_exynos_ipp_limit rotator_4412_yuv_limits[] = {
381+ { IPP_SIZE_LIMIT(BUFFER, .h = { 32, SZ_32K }, .v = { 32, SZ_32K }) },
382+ { IPP_SIZE_LIMIT(AREA, .h.align = 8, .v.align = 8) },
383+};
384+
385+static const struct exynos_drm_ipp_formats rotator_4210_formats[] = {
386+ { IPP_SRCDST_FORMAT(XRGB8888, rotator_4210_rbg888_limits) },
387+ { IPP_SRCDST_FORMAT(NV12, rotator_4210_yuv_limits) },
388+};
389+
390+static const struct exynos_drm_ipp_formats rotator_4412_formats[] = {
391+ { IPP_SRCDST_FORMAT(XRGB8888, rotator_4412_rbg888_limits) },
392+ { IPP_SRCDST_FORMAT(NV12, rotator_4412_yuv_limits) },
393+};
394+
395+static const struct exynos_drm_ipp_formats rotator_5250_formats[] = {
396+ { IPP_SRCDST_FORMAT(XRGB8888, rotator_5250_rbg888_limits) },
397+ { IPP_SRCDST_FORMAT(NV12, rotator_4412_yuv_limits) },
398+};
399+
400+static const struct rot_variant rotator_4210_data = {
401+ .formats = rotator_4210_formats,
402+ .num_formats = ARRAY_SIZE(rotator_4210_formats),
403+};
404+
405+static const struct rot_variant rotator_4412_data = {
406+ .formats = rotator_4412_formats,
407+ .num_formats = ARRAY_SIZE(rotator_4412_formats),
408+};
409+
410+static const struct rot_variant rotator_5250_data = {
411+ .formats = rotator_5250_formats,
412+ .num_formats = ARRAY_SIZE(rotator_5250_formats),
413+};
414+
415+static const struct of_device_id exynos_rotator_match[] = {
416+ {
417+ .compatible = "samsung,exynos4210-rotator",
418+ .data = &rotator_4210_data,
419+ }, {
420+ .compatible = "samsung,exynos4212-rotator",
421+ .data = &rotator_4412_data,
422+ }, {
423+ .compatible = "samsung,exynos5250-rotator",
424+ .data = &rotator_5250_data,
425+ }, {
426+ },
427+};
428+MODULE_DEVICE_TABLE(of, exynos_rotator_match);
429+
812430 static const struct dev_pm_ops rotator_pm_ops = {
813431 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
814432 pm_runtime_force_resume)
@@ -820,7 +438,7 @@ struct platform_driver rotator_driver = { · 5 unmodified lines
820438 .probe = rotator_probe,
821439 .remove = rotator_remove,
822440 .driver = {
823− .name = "exynos-rot",
441+ .name = "exynos-rotator",
824442 .owner = THIS_MODULE,
825443 .pm = &rotator_pm_ops,
826444 .of_match_table = exynos_rotator_match,
drivers/gpu/drm/exynos/exynos_drm_scaler.c+694−0
@@ -0,0 +1,694 @@
1+/*
2+ * Copyright (C) 2017 Samsung Electronics Co.Ltd
3+ * 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
9+ */
10+
11+#include <linux/kernel.h>
12+#include <linux/component.h>
13+#include <linux/err.h>
14+#include <linux/interrupt.h>
15+#include <linux/io.h>
16+#include <linux/platform_device.h>
17+#include <linux/clk.h>
18+#include <linux/of_device.h>
19+#include <linux/pm_runtime.h>
20+
21+#include <drm/drmP.h>
22+#include <drm/exynos_drm.h>
23+#include "regs-scaler.h"
24+#include "exynos_drm_fb.h"
25+#include "exynos_drm_drv.h"
26+#include "exynos_drm_iommu.h"
27+#include "exynos_drm_ipp.h"
28+
29+#define scaler_read(offset) readl(scaler->regs + (offset))
30+#define scaler_write(cfg, offset) writel(cfg, scaler->regs + (offset))
31+#define SCALER_MAX_CLK 4
32+#define SCALER_AUTOSUSPEND_DELAY 2000
33+
34+struct scaler_data {
35+ const char *clk_name[SCALER_MAX_CLK];
36+ unsigned int num_clk;
37+ const struct exynos_drm_ipp_formats *formats;
38+ unsigned int num_formats;
39+};
40+
41+struct scaler_context {
42+ struct exynos_drm_ipp ipp;
43+ struct drm_device *drm_dev;
44+ struct device *dev;
45+ void __iomem *regs;
46+ struct clk *clock[SCALER_MAX_CLK];
47+ struct exynos_drm_ipp_task *task;
48+ const struct scaler_data *scaler_data;
49+};
50+
51+static u32 scaler_get_format(u32 drm_fmt)
52+{
53+ switch (drm_fmt) {
54+ case DRM_FORMAT_NV21:
55+ return SCALER_YUV420_2P_UV;
56+ case DRM_FORMAT_NV12:
57+ return SCALER_YUV420_2P_VU;
58+ case DRM_FORMAT_YUV420:
59+ return SCALER_YUV420_3P;
60+ case DRM_FORMAT_YUYV:
61+ return SCALER_YUV422_1P_YUYV;
62+ case DRM_FORMAT_UYVY:
63+ return SCALER_YUV422_1P_UYVY;
64+ case DRM_FORMAT_YVYU:
65+ return SCALER_YUV422_1P_YVYU;
66+ case DRM_FORMAT_NV61:
67+ return SCALER_YUV422_2P_UV;
68+ case DRM_FORMAT_NV16:
69+ return SCALER_YUV422_2P_VU;
70+ case DRM_FORMAT_YUV422:
71+ return SCALER_YUV422_3P;
72+ case DRM_FORMAT_NV42:
73+ return SCALER_YUV444_2P_UV;
74+ case DRM_FORMAT_NV24:
75+ return SCALER_YUV444_2P_VU;
76+ case DRM_FORMAT_YUV444:
77+ return SCALER_YUV444_3P;
78+ case DRM_FORMAT_RGB565:
79+ return SCALER_RGB_565;
80+ case DRM_FORMAT_XRGB1555:
81+ return SCALER_ARGB1555;
82+ case DRM_FORMAT_ARGB1555:
83+ return SCALER_ARGB1555;
84+ case DRM_FORMAT_XRGB4444:
85+ return SCALER_ARGB4444;
86+ case DRM_FORMAT_ARGB4444:
87+ return SCALER_ARGB4444;
88+ case DRM_FORMAT_XRGB8888:
89+ return SCALER_ARGB8888;
90+ case DRM_FORMAT_ARGB8888:
91+ return SCALER_ARGB8888;
92+ case DRM_FORMAT_RGBX8888:
93+ return SCALER_RGBA8888;
94+ case DRM_FORMAT_RGBA8888:
95+ return SCALER_RGBA8888;
96+ default:
97+ break;
98+ }
99+
100+ return 0;
101+}
102+
103+static inline void scaler_enable_int(struct scaler_context *scaler)
104+{
105+ u32 val;
106+
107+ val = SCALER_INT_EN_TIMEOUT |
108+ SCALER_INT_EN_ILLEGAL_BLEND |
109+ SCALER_INT_EN_ILLEGAL_RATIO |
110+ SCALER_INT_EN_ILLEGAL_DST_HEIGHT |
111+ SCALER_INT_EN_ILLEGAL_DST_WIDTH |
112+ SCALER_INT_EN_ILLEGAL_DST_V_POS |
113+ SCALER_INT_EN_ILLEGAL_DST_H_POS |
114+ SCALER_INT_EN_ILLEGAL_DST_C_SPAN |
115+ SCALER_INT_EN_ILLEGAL_DST_Y_SPAN |
116+ SCALER_INT_EN_ILLEGAL_DST_CR_BASE |
117+ SCALER_INT_EN_ILLEGAL_DST_CB_BASE |
118+ SCALER_INT_EN_ILLEGAL_DST_Y_BASE |
119+ SCALER_INT_EN_ILLEGAL_DST_COLOR |
120+ SCALER_INT_EN_ILLEGAL_SRC_HEIGHT |
121+ SCALER_INT_EN_ILLEGAL_SRC_WIDTH |
122+ SCALER_INT_EN_ILLEGAL_SRC_CV_POS |
123+ SCALER_INT_EN_ILLEGAL_SRC_CH_POS |
124+ SCALER_INT_EN_ILLEGAL_SRC_YV_POS |
125+ SCALER_INT_EN_ILLEGAL_SRC_YH_POS |
126+ SCALER_INT_EN_ILLEGAL_DST_SPAN |
127+ SCALER_INT_EN_ILLEGAL_SRC_Y_SPAN |
128+ SCALER_INT_EN_ILLEGAL_SRC_CR_BASE |
129+ SCALER_INT_EN_ILLEGAL_SRC_CB_BASE |
130+ SCALER_INT_EN_ILLEGAL_SRC_Y_BASE |
131+ SCALER_INT_EN_ILLEGAL_SRC_COLOR |
132+ SCALER_INT_EN_FRAME_END;
133+ scaler_write(val, SCALER_INT_EN);
134+}
135+
136+static inline void scaler_set_src_fmt(struct scaler_context *scaler,
137+ u32 src_fmt)
138+{
139+ u32 val;
140+
141+ val = SCALER_SRC_CFG_SET_COLOR_FORMAT(src_fmt);
142+ scaler_write(val, SCALER_SRC_CFG);
143+}
144+
145+static inline void scaler_set_src_base(struct scaler_context *scaler,
146+ struct exynos_drm_ipp_buffer *src_buf)
147+{
148+ static unsigned int bases[] = {
149+ SCALER_SRC_Y_BASE,
150+ SCALER_SRC_CB_BASE,
151+ SCALER_SRC_CR_BASE,
152+ };
153+ int i;
154+
155+ for (i = 0; i < src_buf->format->num_planes; ++i)
156+ scaler_write(src_buf->dma_addr[i], bases[i]);
157+}
158+
159+static inline void scaler_set_src_span(struct scaler_context *scaler,
160+ struct exynos_drm_ipp_buffer *src_buf)
161+{
162+ u32 val;
163+
164+ val = SCALER_SRC_SPAN_SET_Y_SPAN(src_buf->buf.pitch[0] /
165+ src_buf->format->cpp[0]);
166+
167+ if (src_buf->format->num_planes > 1)
168+ val |= SCALER_SRC_SPAN_SET_C_SPAN(src_buf->buf.pitch[1]);
169+
170+ scaler_write(val, SCALER_SRC_SPAN);
171+}
172+
173+static inline void scaler_set_src_luma_pos(struct scaler_context *scaler,
174+ struct drm_exynos_ipp_task_rect *src_pos)
175+{
176+ u32 val;
177+
178+ val = SCALER_SRC_Y_POS_SET_YH_POS(src_pos->x << 2);
179+ val |= SCALER_SRC_Y_POS_SET_YV_POS(src_pos->y << 2);
180+ scaler_write(val, SCALER_SRC_Y_POS);
181+ scaler_write(val, SCALER_SRC_C_POS); /* ATTENTION! */
182+}
183+
184+static inline void scaler_set_src_wh(struct scaler_context *scaler,
185+ struct drm_exynos_ipp_task_rect *src_pos)
186+{
187+ u32 val;
188+
189+ val = SCALER_SRC_WH_SET_WIDTH(src_pos->w);
190+ val |= SCALER_SRC_WH_SET_HEIGHT(src_pos->h);
191+ scaler_write(val, SCALER_SRC_WH);
192+}
193+
194+static inline void scaler_set_dst_fmt(struct scaler_context *scaler,
195+ u32 dst_fmt)
196+{
197+ u32 val;
198+
199+ val = SCALER_DST_CFG_SET_COLOR_FORMAT(dst_fmt);
200+ scaler_write(val, SCALER_DST_CFG);
201+}
202+
203+static inline void scaler_set_dst_base(struct scaler_context *scaler,
204+ struct exynos_drm_ipp_buffer *dst_buf)
205+{
206+ static unsigned int bases[] = {
207+ SCALER_DST_Y_BASE,
208+ SCALER_DST_CB_BASE,
209+ SCALER_DST_CR_BASE,
210+ };
211+ int i;
212+
213+ for (i = 0; i < dst_buf->format->num_planes; ++i)
214+ scaler_write(dst_buf->dma_addr[i], bases[i]);
215+}
216+
217+static inline void scaler_set_dst_span(struct scaler_context *scaler,
218+ struct exynos_drm_ipp_buffer *dst_buf)
219+{
220+ u32 val;
221+
222+ val = SCALER_DST_SPAN_SET_Y_SPAN(dst_buf->buf.pitch[0] /
223+ dst_buf->format->cpp[0]);
224+
225+ if (dst_buf->format->num_planes > 1)
226+ val |= SCALER_DST_SPAN_SET_C_SPAN(dst_buf->buf.pitch[1]);
227+
228+ scaler_write(val, SCALER_DST_SPAN);
229+}
230+
231+static inline void scaler_set_dst_luma_pos(struct scaler_context *scaler,
232+ struct drm_exynos_ipp_task_rect *dst_pos)
233+{
234+ u32 val;
235+
236+ val = SCALER_DST_WH_SET_WIDTH(dst_pos->w);
237+ val |= SCALER_DST_WH_SET_HEIGHT(dst_pos->h);
238+ scaler_write(val, SCALER_DST_WH);
239+}
240+
241+static inline void scaler_set_dst_wh(struct scaler_context *scaler,
242+ struct drm_exynos_ipp_task_rect *dst_pos)
243+{
244+ u32 val;
245+
246+ val = SCALER_DST_POS_SET_H_POS(dst_pos->x);
247+ val |= SCALER_DST_POS_SET_V_POS(dst_pos->y);
248+ scaler_write(val, SCALER_DST_POS);
249+}
250+
251+static inline void scaler_set_hv_ratio(struct scaler_context *scaler,
252+ unsigned int rotation,
253+ struct drm_exynos_ipp_task_rect *src_pos,
254+ struct drm_exynos_ipp_task_rect *dst_pos)
255+{
256+ u32 val, h_ratio, v_ratio;
257+
258+ if (drm_rotation_90_or_270(rotation)) {
259+ h_ratio = (src_pos->h << 16) / dst_pos->w;
260+ v_ratio = (src_pos->w << 16) / dst_pos->h;
261+ } else {
262+ h_ratio = (src_pos->w << 16) / dst_pos->w;
263+ v_ratio = (src_pos->h << 16) / dst_pos->h;
264+ }
265+
266+ val = SCALER_H_RATIO_SET(h_ratio);
267+ scaler_write(val, SCALER_H_RATIO);
268+
269+ val = SCALER_V_RATIO_SET(v_ratio);
270+ scaler_write(val, SCALER_V_RATIO);
271+}
272+
273+static inline void scaler_set_rotation(struct scaler_context *scaler,
274+ unsigned int rotation)
275+{
276+ u32 val = 0;
277+
278+ if (rotation & DRM_MODE_ROTATE_90)
279+ val |= SCALER_ROT_CFG_SET_ROTMODE(SCALER_ROT_MODE_90);
280+ else if (rotation & DRM_MODE_ROTATE_180)
281+ val |= SCALER_ROT_CFG_SET_ROTMODE(SCALER_ROT_MODE_180);
282+ else if (rotation & DRM_MODE_ROTATE_270)
283+ val |= SCALER_ROT_CFG_SET_ROTMODE(SCALER_ROT_MODE_270);
284+ if (rotation & DRM_MODE_REFLECT_X)
285+ val |= SCALER_ROT_CFG_FLIP_X_EN;
286+ if (rotation & DRM_MODE_REFLECT_Y)
287+ val |= SCALER_ROT_CFG_FLIP_Y_EN;
288+ scaler_write(val, SCALER_ROT_CFG);
289+}
290+
291+static inline void scaler_set_csc(struct scaler_context *scaler,
292+ const struct drm_format_info *fmt)
293+{
294+ static const u32 csc_mtx[2][3][3] = {
295+ { /* YCbCr to RGB */
296+ {0x254, 0x000, 0x331},
297+ {0x254, 0xf38, 0xe60},
298+ {0x254, 0x409, 0x000},
299+ },
300+ { /* RGB to YCbCr */
301+ {0x084, 0x102, 0x032},
302+ {0xfb4, 0xf6b, 0x0e1},
303+ {0x0e1, 0xf44, 0xfdc},
304+ },
305+ };
306+ int i, j, dir;
307+
308+ switch (fmt->format) {
309+ case DRM_FORMAT_RGB565:
310+ case DRM_FORMAT_XRGB1555:
311+ case DRM_FORMAT_ARGB1555:
312+ case DRM_FORMAT_XRGB4444:
313+ case DRM_FORMAT_ARGB4444:
314+ case DRM_FORMAT_XRGB8888:
315+ case DRM_FORMAT_ARGB8888:
316+ case DRM_FORMAT_RGBX8888:
317+ case DRM_FORMAT_RGBA8888:
318+ dir = 1;
319+ break;
320+ default:
321+ dir = 0;
322+ }
323+
324+ for (i = 0; i < 3; i++)
325+ for (j = 0; j < 3; j++)
326+ scaler_write(csc_mtx[dir][i][j], SCALER_CSC_COEF(j, i));
327+}
328+
329+static inline void scaler_set_timer(struct scaler_context *scaler,
330+ unsigned int timer, unsigned int divider)
331+{
332+ u32 val;
333+
334+ val = SCALER_TIMEOUT_CTRL_TIMER_ENABLE;
335+ val |= SCALER_TIMEOUT_CTRL_SET_TIMER_VALUE(timer);
336+ val |= SCALER_TIMEOUT_CTRL_SET_TIMER_DIV(divider);
337+ scaler_write(val, SCALER_TIMEOUT_CTRL);
338+}
339+
340+static inline void scaler_start_hw(struct scaler_context *scaler)
341+{
342+ scaler_write(SCALER_CFG_START_CMD, SCALER_CFG);
343+}
344+
345+static int scaler_commit(struct exynos_drm_ipp *ipp,
346+ struct exynos_drm_ipp_task *task)
347+{
348+ struct scaler_context *scaler =
349+ container_of(ipp, struct scaler_context, ipp);
350+
351+ u32 src_fmt = scaler_get_format(task->src.buf.fourcc);
352+ struct drm_exynos_ipp_task_rect *src_pos = &task->src.rect;
353+
354+ u32 dst_fmt = scaler_get_format(task->dst.buf.fourcc);
355+ struct drm_exynos_ipp_task_rect *dst_pos = &task->dst.rect;
356+
357+ scaler->task = task;
358+
359+ pm_runtime_get_sync(scaler->dev);
360+
361+ scaler_set_src_fmt(scaler, src_fmt);
362+ scaler_set_src_base(scaler, &task->src);
363+ scaler_set_src_span(scaler, &task->src);
364+ scaler_set_src_luma_pos(scaler, src_pos);
365+ scaler_set_src_wh(scaler, src_pos);
366+
367+ scaler_set_dst_fmt(scaler, dst_fmt);
368+ scaler_set_dst_base(scaler, &task->dst);
369+ scaler_set_dst_span(scaler, &task->dst);
370+ scaler_set_dst_luma_pos(scaler, dst_pos);
371+ scaler_set_dst_wh(scaler, dst_pos);
372+
373+ scaler_set_hv_ratio(scaler, task->transform.rotation, src_pos, dst_pos);
374+ scaler_set_rotation(scaler, task->transform.rotation);
375+
376+ scaler_set_csc(scaler, task->src.format);
377+
378+ scaler_set_timer(scaler, 0xffff, 0xf);
379+
380+ scaler_enable_int(scaler);
381+ scaler_start_hw(scaler);
382+
383+ return 0;
384+}
385+
386+static struct exynos_drm_ipp_funcs ipp_funcs = {
387+ .commit = scaler_commit,
388+};
389+
390+static inline void scaler_disable_int(struct scaler_context *scaler)
391+{
392+ scaler_write(0, SCALER_INT_EN);
393+}
394+
395+static inline u32 scaler_get_int_status(struct scaler_context *scaler)
396+{
397+ return scaler_read(SCALER_INT_STATUS);
398+}
399+
400+static inline bool scaler_task_done(u32 val)
401+{
402+ return val & SCALER_INT_STATUS_FRAME_END ? 0 : -EINVAL;
403+}
404+
405+static irqreturn_t scaler_irq_handler(int irq, void *arg)
406+{
407+ struct scaler_context *scaler = arg;
408+
409+ u32 val = scaler_get_int_status(scaler);
410+
411+ scaler_disable_int(scaler);
412+
413+ if (scaler->task) {
414+ struct exynos_drm_ipp_task *task = scaler->task;
415+
416+ scaler->task = NULL;
417+ pm_runtime_mark_last_busy(scaler->dev);
418+ pm_runtime_put_autosuspend(scaler->dev);
419+ exynos_drm_ipp_task_done(task, scaler_task_done(val));
420+ }
421+
422+ return IRQ_HANDLED;
423+}
424+
425+static int scaler_bind(struct device *dev, struct device *master, void *data)
426+{
427+ struct scaler_context *scaler = dev_get_drvdata(dev);
428+ struct drm_device *drm_dev = data;
429+ struct exynos_drm_ipp *ipp = &scaler->ipp;
430+
431+ scaler->drm_dev = drm_dev;
432+ drm_iommu_attach_device(drm_dev, dev);
433+
434+ exynos_drm_ipp_register(drm_dev, ipp, &ipp_funcs,
435+ DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE |
436+ DRM_EXYNOS_IPP_CAP_SCALE | DRM_EXYNOS_IPP_CAP_CONVERT,
437+ scaler->scaler_data->formats,
438+ scaler->scaler_data->num_formats, "scaler");
439+
440+ dev_info(dev, "The exynos scaler has been probed successfully\n");
441+
442+ return 0;
443+}
444+
445+static void scaler_unbind(struct device *dev, struct device *master,
446+ void *data)
447+{
448+ struct scaler_context *scaler = dev_get_drvdata(dev);
449+ struct drm_device *drm_dev = data;
450+ struct exynos_drm_ipp *ipp = &scaler->ipp;
451+
452+ exynos_drm_ipp_unregister(drm_dev, ipp);
453+ drm_iommu_detach_device(scaler->drm_dev, scaler->dev);
454+}
455+
456+static const struct component_ops scaler_component_ops = {
457+ .bind = scaler_bind,
458+ .unbind = scaler_unbind,
459+};
460+
461+static int scaler_probe(struct platform_device *pdev)
462+{
463+ struct device *dev = &pdev->dev;
464+ struct resource *regs_res;
465+ struct scaler_context *scaler;
466+ int irq;
467+ int ret, i;
468+
469+ scaler = devm_kzalloc(dev, sizeof(*scaler), GFP_KERNEL);
470+ if (!scaler)
471+ return -ENOMEM;
472+
473+ scaler->scaler_data =
474+ (struct scaler_data *)of_device_get_match_data(dev);
475+
476+ scaler->dev = dev;
477+ regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
478+ scaler->regs = devm_ioremap_resource(dev, regs_res);
479+ if (IS_ERR(scaler->regs))
480+ return PTR_ERR(scaler->regs);
481+
482+ irq = platform_get_irq(pdev, 0);
483+ if (irq < 0) {
484+ dev_err(dev, "failed to get irq\n");
485+ return irq;
486+ }
487+
488+ ret = devm_request_threaded_irq(dev, irq, NULL, scaler_irq_handler,
489+ IRQF_ONESHOT, "drm_scaler", scaler);
490+ if (ret < 0) {
491+ dev_err(dev, "failed to request irq\n");
492+ return ret;
493+ }
494+
495+ for (i = 0; i < scaler->scaler_data->num_clk; ++i) {
496+ scaler->clock[i] = devm_clk_get(dev,
497+ scaler->scaler_data->clk_name[i]);
498+ if (IS_ERR(scaler->clock[i])) {
499+ dev_err(dev, "failed to get clock\n");
500+ return PTR_ERR(scaler->clock[i]);
501+ }
502+ }
503+
504+ pm_runtime_use_autosuspend(dev);
505+ pm_runtime_set_autosuspend_delay(dev, SCALER_AUTOSUSPEND_DELAY);
506+ pm_runtime_enable(dev);
507+ platform_set_drvdata(pdev, scaler);
508+
509+ ret = component_add(dev, &scaler_component_ops);
510+ if (ret)
511+ goto err_ippdrv_register;
512+
513+ return 0;
514+
515+err_ippdrv_register:
516+ pm_runtime_dont_use_autosuspend(dev);
517+ pm_runtime_disable(dev);
518+ return ret;
519+}
520+
521+static int scaler_remove(struct platform_device *pdev)
522+{
523+ struct device *dev = &pdev->dev;
524+
525+ component_del(dev, &scaler_component_ops);
526+ pm_runtime_dont_use_autosuspend(dev);
527+ pm_runtime_disable(dev);
528+
529+ return 0;
530+}
531+
532+#ifdef CONFIG_PM
533+
534+static int clk_disable_unprepare_wrapper(struct clk *clk)
535+{
536+ clk_disable_unprepare(clk);
537+
538+ return 0;
539+}
540+
541+static int scaler_clk_ctrl(struct scaler_context *scaler, bool enable)
542+{
543+ int (*clk_fun)(struct clk *clk), i;
544+
545+ clk_fun = enable ? clk_prepare_enable : clk_disable_unprepare_wrapper;
546+
547+ for (i = 0; i < scaler->scaler_data->num_clk; ++i)
548+ clk_fun(scaler->clock[i]);
549+
550+ return 0;
551+}
552+
553+static int scaler_runtime_suspend(struct device *dev)
554+{
555+ struct scaler_context *scaler = dev_get_drvdata(dev);
556+
557+ return scaler_clk_ctrl(scaler, false);
558+}
559+
560+static int scaler_runtime_resume(struct device *dev)
561+{
562+ struct scaler_context *scaler = dev_get_drvdata(dev);
563+
564+ return scaler_clk_ctrl(scaler, true);
565+}
566+#endif
567+
568+static const struct dev_pm_ops scaler_pm_ops = {
569+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
570+ pm_runtime_force_resume)
571+ SET_RUNTIME_PM_OPS(scaler_runtime_suspend, scaler_runtime_resume, NULL)
572+};
573+
574+static const struct drm_exynos_ipp_limit scaler_5420_two_pixel_hv_limits[] = {
575+ { IPP_SIZE_LIMIT(BUFFER, .h = { 16, SZ_8K }, .v = { 16, SZ_8K }) },
576+ { IPP_SIZE_LIMIT(AREA, .h.align = 2, .v.align = 2) },
577+ { IPP_SCALE_LIMIT(.h = { 65536 * 1 / 4, 65536 * 16 },
578+ .v = { 65536 * 1 / 4, 65536 * 16 }) },
579+};
580+
581+static const struct drm_exynos_ipp_limit scaler_5420_two_pixel_h_limits[] = {
582+ { IPP_SIZE_LIMIT(BUFFER, .h = { 16, SZ_8K }, .v = { 16, SZ_8K }) },
583+ { IPP_SIZE_LIMIT(AREA, .h.align = 2, .v.align = 1) },
584+ { IPP_SCALE_LIMIT(.h = { 65536 * 1 / 4, 65536 * 16 },
585+ .v = { 65536 * 1 / 4, 65536 * 16 }) },
586+};
587+
588+static const struct drm_exynos_ipp_limit scaler_5420_one_pixel_limits[] = {
589+ { IPP_SIZE_LIMIT(BUFFER, .h = { 16, SZ_8K }, .v = { 16, SZ_8K }) },
590+ { IPP_SCALE_LIMIT(.h = { 65536 * 1 / 4, 65536 * 16 },
591+ .v = { 65536 * 1 / 4, 65536 * 16 }) },
592+};
593+
594+static const struct exynos_drm_ipp_formats exynos5420_formats[] = {
595+ /* SCALER_YUV420_2P_UV */
596+ { IPP_SRCDST_FORMAT(NV21, scaler_5420_two_pixel_hv_limits) },
597+
598+ /* SCALER_YUV420_2P_VU */
599+ { IPP_SRCDST_FORMAT(NV12, scaler_5420_two_pixel_hv_limits) },
600+
601+ /* SCALER_YUV420_3P */
602+ { IPP_SRCDST_FORMAT(YUV420, scaler_5420_two_pixel_hv_limits) },
603+
604+ /* SCALER_YUV422_1P_YUYV */
605+ { IPP_SRCDST_FORMAT(YUYV, scaler_5420_two_pixel_h_limits) },
606+
607+ /* SCALER_YUV422_1P_UYVY */
608+ { IPP_SRCDST_FORMAT(UYVY, scaler_5420_two_pixel_h_limits) },
609+
610+ /* SCALER_YUV422_1P_YVYU */
611+ { IPP_SRCDST_FORMAT(YVYU, scaler_5420_two_pixel_h_limits) },
612+
613+ /* SCALER_YUV422_2P_UV */
614+ { IPP_SRCDST_FORMAT(NV61, scaler_5420_two_pixel_h_limits) },
615+
616+ /* SCALER_YUV422_2P_VU */
617+ { IPP_SRCDST_FORMAT(NV16, scaler_5420_two_pixel_h_limits) },
618+
619+ /* SCALER_YUV422_3P */
620+ { IPP_SRCDST_FORMAT(YUV422, scaler_5420_two_pixel_h_limits) },
621+
622+ /* SCALER_YUV444_2P_UV */
623+ { IPP_SRCDST_FORMAT(NV42, scaler_5420_one_pixel_limits) },
624+
625+ /* SCALER_YUV444_2P_VU */
626+ { IPP_SRCDST_FORMAT(NV24, scaler_5420_one_pixel_limits) },
627+
628+ /* SCALER_YUV444_3P */
629+ { IPP_SRCDST_FORMAT(YUV444, scaler_5420_one_pixel_limits) },
630+
631+ /* SCALER_RGB_565 */
632+ { IPP_SRCDST_FORMAT(RGB565, scaler_5420_one_pixel_limits) },
633+
634+ /* SCALER_ARGB1555 */
635+ { IPP_SRCDST_FORMAT(XRGB1555, scaler_5420_one_pixel_limits) },
636+
637+ /* SCALER_ARGB1555 */
638+ { IPP_SRCDST_FORMAT(ARGB1555, scaler_5420_one_pixel_limits) },
639+
640+ /* SCALER_ARGB4444 */
641+ { IPP_SRCDST_FORMAT(XRGB4444, scaler_5420_one_pixel_limits) },
642+
643+ /* SCALER_ARGB4444 */
644+ { IPP_SRCDST_FORMAT(ARGB4444, scaler_5420_one_pixel_limits) },
645+
646+ /* SCALER_ARGB8888 */
647+ { IPP_SRCDST_FORMAT(XRGB8888, scaler_5420_one_pixel_limits) },
648+
649+ /* SCALER_ARGB8888 */
650+ { IPP_SRCDST_FORMAT(ARGB8888, scaler_5420_one_pixel_limits) },
651+
652+ /* SCALER_RGBA8888 */
653+ { IPP_SRCDST_FORMAT(RGBX8888, scaler_5420_one_pixel_limits) },
654+
655+ /* SCALER_RGBA8888 */
656+ { IPP_SRCDST_FORMAT(RGBA8888, scaler_5420_one_pixel_limits) },
657+};
658+
659+static const struct scaler_data exynos5420_data = {
660+ .clk_name = {"mscl"},
661+ .num_clk = 1,
662+ .formats = exynos5420_formats,
663+ .num_formats = ARRAY_SIZE(exynos5420_formats),
664+};
665+
666+static const struct scaler_data exynos5433_data = {
667+ .clk_name = {"pclk", "aclk", "aclk_xiu"},
668+ .num_clk = 3,
669+ .formats = exynos5420_formats, /* intentional */
670+ .num_formats = ARRAY_SIZE(exynos5420_formats),
671+};
672+
673+static const struct of_device_id exynos_scaler_match[] = {
674+ {
675+ .compatible = "samsung,exynos5420-scaler",
676+ .data = &exynos5420_data,
677+ }, {
678+ .compatible = "samsung,exynos5433-scaler",
679+ .data = &exynos5433_data,
680+ }, {
681+ },
682+};
683+MODULE_DEVICE_TABLE(of, exynos_scaler_match);
684+
685+struct platform_driver scaler_driver = {
686+ .probe = scaler_probe,
687+ .remove = scaler_remove,
688+ .driver = {
689+ .name = "exynos-scaler",
690+ .owner = THIS_MODULE,
691+ .pm = &scaler_pm_ops,
692+ .of_match_table = exynos_scaler_match,
693+ },
694+};
drivers/gpu/drm/exynos/exynos_hdmi.c+0−2
@@ -954,8 +954,6 @@ static int hdmi_create_connector(struct drm_encoder *encoder) · 953 unmodified lines
954954 drm_mode_connector_attach_encoder(connector, encoder);
955955
956956 if (hdata->bridge) {
957− encoder->bridge = hdata->bridge;
958− hdata->bridge->encoder = encoder;
959957 ret = drm_bridge_attach(encoder, hdata->bridge, NULL);
960958 if (ret)
961959 DRM_ERROR("Failed to attach bridge\n");
drivers/gpu/drm/exynos/exynos_mixer.c+17−5
@@ -473,7 +473,7 @@ static void vp_video_buffer(struct mixer_context *ctx, · 472 unmodified lines
473473 chroma_addr[1] = chroma_addr[0] + 0x40;
474474 } else {
475475 luma_addr[1] = luma_addr[0] + fb->pitches[0];
476− chroma_addr[1] = chroma_addr[0] + fb->pitches[0];
476+ chroma_addr[1] = chroma_addr[0] + fb->pitches[1];
477477 }
478478 } else {
479479 luma_addr[1] = 0;
@@ -482,6 +482,7 @@ static void vp_video_buffer(struct mixer_context *ctx, · 2 unmodified lines
482482
483483 spin_lock_irqsave(&ctx->reg_slock, flags);
484484
485+ vp_reg_write(ctx, VP_SHADOW_UPDATE, 1);
485486 /* interlace or progressive scan mode */
486487 val = (test_bit(MXR_BIT_INTERLACE, &ctx->flags) ? ~0 : 0);
487488 vp_reg_writemask(ctx, VP_MODE, val, VP_MODE_LINE_SKIP);
@@ -495,21 +496,23 @@ static void vp_video_buffer(struct mixer_context *ctx, · 7 unmodified lines
495496 vp_reg_write(ctx, VP_IMG_SIZE_Y, VP_IMG_HSIZE(fb->pitches[0]) |
496497 VP_IMG_VSIZE(fb->height));
497498 /* chroma plane for NV12/NV21 is half the height of the luma plane */
498− vp_reg_write(ctx, VP_IMG_SIZE_C, VP_IMG_HSIZE(fb->pitches[0]) |
499+ vp_reg_write(ctx, VP_IMG_SIZE_C, VP_IMG_HSIZE(fb->pitches[1]) |
499500 VP_IMG_VSIZE(fb->height / 2));
500501
501502 vp_reg_write(ctx, VP_SRC_WIDTH, state->src.w);
502− vp_reg_write(ctx, VP_SRC_HEIGHT, state->src.h);
503503 vp_reg_write(ctx, VP_SRC_H_POSITION,
504504 VP_SRC_H_POSITION_VAL(state->src.x));
505− vp_reg_write(ctx, VP_SRC_V_POSITION, state->src.y);
506−
507505 vp_reg_write(ctx, VP_DST_WIDTH, state->crtc.w);
508506 vp_reg_write(ctx, VP_DST_H_POSITION, state->crtc.x);
507+
509508 if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
509+ vp_reg_write(ctx, VP_SRC_HEIGHT, state->src.h / 2);
510+ vp_reg_write(ctx, VP_SRC_V_POSITION, state->src.y / 2);
510511 vp_reg_write(ctx, VP_DST_HEIGHT, state->crtc.h / 2);
511512 vp_reg_write(ctx, VP_DST_V_POSITION, state->crtc.y / 2);
512513 } else {
514+ vp_reg_write(ctx, VP_SRC_HEIGHT, state->src.h);
515+ vp_reg_write(ctx, VP_SRC_V_POSITION, state->src.y);
513516 vp_reg_write(ctx, VP_DST_HEIGHT, state->crtc.h);
514517 vp_reg_write(ctx, VP_DST_V_POSITION, state->crtc.y);
515518 }
@@ -699,6 +702,15 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg) · 183 unmodified lines
699702
700703 /* interlace scan need to check shadow register */
701704 if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
705+ if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags) &&
706+ vp_reg_read(ctx, VP_SHADOW_UPDATE))
707+ goto out;
708+
709+ base = mixer_reg_read(ctx, MXR_CFG);
710+ shadow = mixer_reg_read(ctx, MXR_CFG_S);
711+ if (base != shadow)
712+ goto out;
713+
702714 base = mixer_reg_read(ctx, MXR_GRAPHIC_BASE(0));
703715 shadow = mixer_reg_read(ctx, MXR_GRAPHIC_BASE_S(0));
704716 if (base != shadow)
drivers/gpu/drm/exynos/regs-mixer.h+1−0
@@ -47,6 +47,7 @@ · 46 unmodified lines
4747 #define MXR_MO 0x0304
4848 #define MXR_RESOLUTION 0x0310
4949
50+#define MXR_CFG_S 0x2004
5051 #define MXR_GRAPHIC0_BASE_S 0x2024
5152 #define MXR_GRAPHIC1_BASE_S 0x2044
5253
drivers/gpu/drm/exynos/regs-scaler.h+426−0
@@ -0,0 +1,426 @@
1+/* drivers/gpu/drm/exynos/regs-scaler.h
2+ *
3+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
4+ * http://www.samsung.com/
5+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
6+ *
7+ * Register definition file for Samsung scaler driver
8+ *
9+ * This program is free software; you can redistribute it and/or modify
10+ * it under the terms of the GNU General Public License version 2 as
11+ * published by the Free Software Foundation.
12+ */
13+
14+#ifndef EXYNOS_REGS_SCALER_H
15+#define EXYNOS_REGS_SCALER_H
16+
17+/* Register part */
18+
19+/* Global setting */
20+#define SCALER_STATUS 0x0 /* no shadow */
21+#define SCALER_CFG 0x4
22+
23+/* Interrupt */
24+#define SCALER_INT_EN 0x8 /* no shadow */
25+#define SCALER_INT_STATUS 0xc /* no shadow */
26+
27+/* SRC */
28+#define SCALER_SRC_CFG 0x10
29+#define SCALER_SRC_Y_BASE 0x14
30+#define SCALER_SRC_CB_BASE 0x18
31+#define SCALER_SRC_CR_BASE 0x294
32+#define SCALER_SRC_SPAN 0x1c
33+#define SCALER_SRC_Y_POS 0x20
34+#define SCALER_SRC_WH 0x24
35+#define SCALER_SRC_C_POS 0x28
36+
37+/* DST */
38+#define SCALER_DST_CFG 0x30
39+#define SCALER_DST_Y_BASE 0x34
40+#define SCALER_DST_CB_BASE 0x38
41+#define SCALER_DST_CR_BASE 0x298
42+#define SCALER_DST_SPAN 0x3c
43+#define SCALER_DST_WH 0x40
44+#define SCALER_DST_POS 0x44
45+
46+/* Ratio */
47+#define SCALER_H_RATIO 0x50
48+#define SCALER_V_RATIO 0x54
49+
50+/* Rotation */
51+#define SCALER_ROT_CFG 0x58
52+
53+/* Coefficient */
54+/*
55+ * YHCOEF_{x}{A|B|C|D} CHCOEF_{x}{A|B|C|D}
56+ *
57+ * A B C D A B C D
58+ * 0 60 64 68 6c 140 144 148 14c
59+ * 1 70 74 78 7c 150 154 158 15c
60+ * 2 80 84 88 8c 160 164 168 16c
61+ * 3 90 94 98 9c 170 174 178 17c
62+ * 4 a0 a4 a8 ac 180 184 188 18c
63+ * 5 b0 b4 b8 bc 190 194 198 19c
64+ * 6 c0 c4 c8 cc 1a0 1a4 1a8 1ac
65+ * 7 d0 d4 d8 dc 1b0 1b4 1b8 1bc
66+ * 8 e0 e4 e8 ec 1c0 1c4 1c8 1cc
67+ *
68+ *
69+ * YVCOEF_{x}{A|B} CVCOEF_{x}{A|B}
70+ *
71+ * A B A B
72+ * 0 f0 f4 1d0 1d4
73+ * 1 f8 fc 1d8 1dc
74+ * 2 100 104 1e0 1e4
75+ * 3 108 10c 1e8 1ec
76+ * 4 110 114 1f0 1f4
77+ * 5 118 11c 1f8 1fc
78+ * 6 120 124 200 204
79+ * 7 128 12c 208 20c
80+ * 8 130 134 210 214
81+ */
82+#define _SCALER_HCOEF_DELTA(r, c) ((r) * 0x10 + (c) * 0x4)
83+#define _SCALER_VCOEF_DELTA(r, c) ((r) * 0x8 + (c) * 0x4)
84+
85+#define SCALER_YHCOEF(r, c) (0x60 + _SCALER_HCOEF_DELTA((r), (c)))
86+#define SCALER_YVCOEF(r, c) (0xf0 + _SCALER_VCOEF_DELTA((r), (c)))
87+#define SCALER_CHCOEF(r, c) (0x140 + _SCALER_HCOEF_DELTA((r), (c)))
88+#define SCALER_CVCOEF(r, c) (0x1d0 + _SCALER_VCOEF_DELTA((r), (c)))
89+
90+
91+/* Color Space Conversion */
92+#define SCALER_CSC_COEF(x, y) (0x220 + (y) * 0xc + (x) * 0x4)
93+
94+/* Dithering */
95+#define SCALER_DITH_CFG 0x250
96+
97+/* Version Number */
98+#define SCALER_VER 0x260 /* no shadow */
99+
100+/* Cycle count and Timeout */
101+#define SCALER_CYCLE_COUNT 0x278 /* no shadow */
102+#define SCALER_TIMEOUT_CTRL 0x2c0 /* no shadow */
103+#define SCALER_TIMEOUT_CNT 0x2c4 /* no shadow */
104+
105+/* Blending */
106+#define SCALER_SRC_BLEND_COLOR 0x280
107+#define SCALER_SRC_BLEND_ALPHA 0x284
108+#define SCALER_DST_BLEND_COLOR 0x288
109+#define SCALER_DST_BLEND_ALPHA 0x28c
110+
111+/* Color Fill */
112+#define SCALER_FILL_COLOR 0x290
113+
114+/* Multiple Command Queue */
115+#define SCALER_ADDR_Q_CONFIG 0x2a0 /* no shadow */
116+#define SCALER_SRC_ADDR_Q_STATUS 0x2a4 /* no shadow */
117+#define SCALER_SRC_ADDR_Q 0x2a8 /* no shadow */
118+
119+/* CRC */
120+#define SCALER_CRC_COLOR00_10 0x2b0 /* no shadow */
121+#define SCALER_CRC_COLOR20_30 0x2b4 /* no shadow */
122+#define SCALER_CRC_COLOR01_11 0x2b8 /* no shadow */
123+#define SCALER_CRC_COLOR21_31 0x2bc /* no shadow */
124+
125+/* Shadow Registers */
126+#define SCALER_SHADOW_OFFSET 0x1000
127+
128+
129+/* Bit definition part */
130+#define SCALER_MASK(hi_b, lo_b) ((1 << ((hi_b) - (lo_b) + 1)) - 1)
131+#define SCALER_GET(reg, hi_b, lo_b) \
132+ (((reg) >> (lo_b)) & SCALER_MASK(hi_b, lo_b))
133+#define SCALER_SET(val, hi_b, lo_b) \
134+ (((val) & SCALER_MASK(hi_b, lo_b)) << lo_b)
135+
136+/* SCALER_STATUS */
137+#define SCALER_STATUS_SCALER_RUNNING (1 << 1)
138+#define SCALER_STATUS_SCALER_READY_CLK_DOWN (1 << 0)
139+
140+/* SCALER_CFG */
141+#define SCALER_CFG_FILL_EN (1 << 24)
142+#define SCALER_CFG_BLEND_COLOR_DIVIDE_ALPHA_EN (1 << 17)
143+#define SCALER_CFG_BLEND_EN (1 << 16)
144+#define SCALER_CFG_CSC_Y_OFFSET_SRC_EN (1 << 10)
145+#define SCALER_CFG_CSC_Y_OFFSET_DST_EN (1 << 9)
146+#define SCALER_CFG_16_BURST_MODE (1 << 8)
147+#define SCALER_CFG_SOFT_RESET (1 << 1)
148+#define SCALER_CFG_START_CMD (1 << 0)
149+
150+/* SCALER_INT_EN */
151+#define SCALER_INT_EN_TIMEOUT (1 << 31)
152+#define SCALER_INT_EN_ILLEGAL_BLEND (1 << 24)
153+#define SCALER_INT_EN_ILLEGAL_RATIO (1 << 23)
154+#define SCALER_INT_EN_ILLEGAL_DST_HEIGHT (1 << 22)
155+#define SCALER_INT_EN_ILLEGAL_DST_WIDTH (1 << 21)
156+#define SCALER_INT_EN_ILLEGAL_DST_V_POS (1 << 20)
157+#define SCALER_INT_EN_ILLEGAL_DST_H_POS (1 << 19)
158+#define SCALER_INT_EN_ILLEGAL_DST_C_SPAN (1 << 18)
159+#define SCALER_INT_EN_ILLEGAL_DST_Y_SPAN (1 << 17)
160+#define SCALER_INT_EN_ILLEGAL_DST_CR_BASE (1 << 16)
161+#define SCALER_INT_EN_ILLEGAL_DST_CB_BASE (1 << 15)
162+#define SCALER_INT_EN_ILLEGAL_DST_Y_BASE (1 << 14)
163+#define SCALER_INT_EN_ILLEGAL_DST_COLOR (1 << 13)
164+#define SCALER_INT_EN_ILLEGAL_SRC_HEIGHT (1 << 12)
165+#define SCALER_INT_EN_ILLEGAL_SRC_WIDTH (1 << 11)
166+#define SCALER_INT_EN_ILLEGAL_SRC_CV_POS (1 << 10)
167+#define SCALER_INT_EN_ILLEGAL_SRC_CH_POS (1 << 9)
168+#define SCALER_INT_EN_ILLEGAL_SRC_YV_POS (1 << 8)
169+#define SCALER_INT_EN_ILLEGAL_SRC_YH_POS (1 << 7)
170+#define SCALER_INT_EN_ILLEGAL_DST_SPAN (1 << 6)
171+#define SCALER_INT_EN_ILLEGAL_SRC_Y_SPAN (1 << 5)
172+#define SCALER_INT_EN_ILLEGAL_SRC_CR_BASE (1 << 4)
173+#define SCALER_INT_EN_ILLEGAL_SRC_CB_BASE (1 << 3)
174+#define SCALER_INT_EN_ILLEGAL_SRC_Y_BASE (1 << 2)
175+#define SCALER_INT_EN_ILLEGAL_SRC_COLOR (1 << 1)
176+#define SCALER_INT_EN_FRAME_END (1 << 0)
177+
178+/* SCALER_INT_STATUS */
179+#define SCALER_INT_STATUS_TIMEOUT (1 << 31)
180+#define SCALER_INT_STATUS_ILLEGAL_BLEND (1 << 24)
181+#define SCALER_INT_STATUS_ILLEGAL_RATIO (1 << 23)
182+#define SCALER_INT_STATUS_ILLEGAL_DST_HEIGHT (1 << 22)
183+#define SCALER_INT_STATUS_ILLEGAL_DST_WIDTH (1 << 21)
184+#define SCALER_INT_STATUS_ILLEGAL_DST_V_POS (1 << 20)
185+#define SCALER_INT_STATUS_ILLEGAL_DST_H_POS (1 << 19)
186+#define SCALER_INT_STATUS_ILLEGAL_DST_C_SPAN (1 << 18)
187+#define SCALER_INT_STATUS_ILLEGAL_DST_Y_SPAN (1 << 17)
188+#define SCALER_INT_STATUS_ILLEGAL_DST_CR_BASE (1 << 16)
189+#define SCALER_INT_STATUS_ILLEGAL_DST_CB_BASE (1 << 15)
190+#define SCALER_INT_STATUS_ILLEGAL_DST_Y_BASE (1 << 14)
191+#define SCALER_INT_STATUS_ILLEGAL_DST_COLOR (1 << 13)
192+#define SCALER_INT_STATUS_ILLEGAL_SRC_HEIGHT (1 << 12)
193+#define SCALER_INT_STATUS_ILLEGAL_SRC_WIDTH (1 << 11)
194+#define SCALER_INT_STATUS_ILLEGAL_SRC_CV_POS (1 << 10)
195+#define SCALER_INT_STATUS_ILLEGAL_SRC_CH_POS (1 << 9)
196+#define SCALER_INT_STATUS_ILLEGAL_SRC_YV_POS (1 << 8)
197+#define SCALER_INT_STATUS_ILLEGAL_SRC_YH_POS (1 << 7)
198+#define SCALER_INT_STATUS_ILLEGAL_DST_SPAN (1 << 6)
199+#define SCALER_INT_STATUS_ILLEGAL_SRC_Y_SPAN (1 << 5)
200+#define SCALER_INT_STATUS_ILLEGAL_SRC_CR_BASE (1 << 4)
201+#define SCALER_INT_STATUS_ILLEGAL_SRC_CB_BASE (1 << 3)
202+#define SCALER_INT_STATUS_ILLEGAL_SRC_Y_BASE (1 << 2)
203+#define SCALER_INT_STATUS_ILLEGAL_SRC_COLOR (1 << 1)
204+#define SCALER_INT_STATUS_FRAME_END (1 << 0)
205+
206+/* SCALER_SRC_CFG */
207+#define SCALER_SRC_CFG_TILE_EN (1 << 10)
208+#define SCALER_SRC_CFG_GET_BYTE_SWAP(r) SCALER_GET(r, 6, 5)
209+#define SCALER_SRC_CFG_SET_BYTE_SWAP(v) SCALER_SET(v, 6, 5)
210+#define SCALER_SRC_CFG_GET_COLOR_FORMAT(r) SCALER_GET(r, 4, 0)
211+#define SCALER_SRC_CFG_SET_COLOR_FORMAT(v) SCALER_SET(v, 4, 0)
212+#define SCALER_YUV420_2P_UV 0
213+#define SCALER_YUV422_2P_UV 2
214+#define SCALER_YUV444_2P_UV 3
215+#define SCALER_RGB_565 4
216+#define SCALER_ARGB1555 5
217+#define SCALER_ARGB8888 6
218+#define SCALER_ARGB8888_PRE 7
219+#define SCALER_YUV422_1P_YVYU 9
220+#define SCALER_YUV422_1P_YUYV 10
221+#define SCALER_YUV422_1P_UYVY 11
222+#define SCALER_ARGB4444 12
223+#define SCALER_L8A8 13
224+#define SCALER_RGBA8888 14
225+#define SCALER_L8 15
226+#define SCALER_YUV420_2P_VU 16
227+#define SCALER_YUV422_2P_VU 18
228+#define SCALER_YUV444_2P_VU 19
229+#define SCALER_YUV420_3P 20
230+#define SCALER_YUV422_3P 22
231+#define SCALER_YUV444_3P 23
232+
233+/* SCALER_SRC_SPAN */
234+#define SCALER_SRC_SPAN_GET_C_SPAN(r) SCALER_GET(r, 29, 16)
235+#define SCALER_SRC_SPAN_SET_C_SPAN(v) SCALER_SET(v, 29, 16)
236+#define SCALER_SRC_SPAN_GET_Y_SPAN(r) SCALER_GET(r, 13, 0)
237+#define SCALER_SRC_SPAN_SET_Y_SPAN(v) SCALER_SET(v, 13, 0)
238+
239+/* SCALER_SRC_Y_POS */
240+#define SCALER_SRC_Y_POS_GET_YH_POS(r) SCALER_GET(r, 31, 16)
241+#define SCALER_SRC_Y_POS_SET_YH_POS(v) SCALER_SET(v, 31, 16)
242+#define SCALER_SRC_Y_POS_GET_YV_POS(r) SCALER_GET(r, 15, 0)
243+#define SCALER_SRC_Y_POS_SET_YV_POS(v) SCALER_SET(v, 15, 0)
244+
245+/* SCALER_SRC_WH */
246+#define SCALER_SRC_WH_GET_WIDTH(r) SCALER_GET(r, 29, 16)
247+#define SCALER_SRC_WH_SET_WIDTH(v) SCALER_SET(v, 29, 16)
248+#define SCALER_SRC_WH_GET_HEIGHT(r) SCALER_GET(r, 13, 0)
249+#define SCALER_SRC_WH_SET_HEIGHT(v) SCALER_SET(v, 13, 0)
250+
251+/* SCALER_SRC_C_POS */
252+#define SCALER_SRC_C_POS_GET_CH_POS(r) SCALER_GET(r, 31, 16)
253+#define SCALER_SRC_C_POS_SET_CH_POS(v) SCALER_SET(v, 31, 16)
254+#define SCALER_SRC_C_POS_GET_CV_POS(r) SCALER_GET(r, 15, 0)
255+#define SCALER_SRC_C_POS_SET_CV_POS(v) SCALER_SET(v, 15, 0)
256+
257+/* SCALER_DST_CFG */
258+#define SCALER_DST_CFG_GET_BYTE_SWAP(r) SCALER_GET(r, 6, 5)
259+#define SCALER_DST_CFG_SET_BYTE_SWAP(v) SCALER_SET(v, 6, 5)
260+#define SCALER_DST_CFG_GET_COLOR_FORMAT(r) SCALER_GET(r, 4, 0)
261+#define SCALER_DST_CFG_SET_COLOR_FORMAT(v) SCALER_SET(v, 4, 0)
262+
263+/* SCALER_DST_SPAN */
264+#define SCALER_DST_SPAN_GET_C_SPAN(r) SCALER_GET(r, 29, 16)
265+#define SCALER_DST_SPAN_SET_C_SPAN(v) SCALER_SET(v, 29, 16)
266+#define SCALER_DST_SPAN_GET_Y_SPAN(r) SCALER_GET(r, 13, 0)
267+#define SCALER_DST_SPAN_SET_Y_SPAN(v) SCALER_SET(v, 13, 0)
268+
269+/* SCALER_DST_WH */
270+#define SCALER_DST_WH_GET_WIDTH(r) SCALER_GET(r, 29, 16)
271+#define SCALER_DST_WH_SET_WIDTH(v) SCALER_SET(v, 29, 16)
272+#define SCALER_DST_WH_GET_HEIGHT(r) SCALER_GET(r, 13, 0)
273+#define SCALER_DST_WH_SET_HEIGHT(v) SCALER_SET(v, 13, 0)
274+
275+/* SCALER_DST_POS */
276+#define SCALER_DST_POS_GET_H_POS(r) SCALER_GET(r, 29, 16)
277+#define SCALER_DST_POS_SET_H_POS(v) SCALER_SET(v, 29, 16)
278+#define SCALER_DST_POS_GET_V_POS(r) SCALER_GET(r, 13, 0)
279+#define SCALER_DST_POS_SET_V_POS(v) SCALER_SET(v, 13, 0)
280+
281+/* SCALER_H_RATIO */
282+#define SCALER_H_RATIO_GET(r) SCALER_GET(r, 18, 0)
283+#define SCALER_H_RATIO_SET(v) SCALER_SET(v, 18, 0)
284+
285+/* SCALER_V_RATIO */
286+#define SCALER_V_RATIO_GET(r) SCALER_GET(r, 18, 0)
287+#define SCALER_V_RATIO_SET(v) SCALER_SET(v, 18, 0)
288+
289+/* SCALER_ROT_CFG */
290+#define SCALER_ROT_CFG_FLIP_X_EN (1 << 3)
291+#define SCALER_ROT_CFG_FLIP_Y_EN (1 << 2)
292+#define SCALER_ROT_CFG_GET_ROTMODE(r) SCALER_GET(r, 1, 0)
293+#define SCALER_ROT_CFG_SET_ROTMODE(v) SCALER_SET(v, 1, 0)
294+#define SCALER_ROT_MODE_90 1
295+#define SCALER_ROT_MODE_180 2
296+#define SCALER_ROT_MODE_270 3
297+
298+/* SCALER_HCOEF, SCALER_VCOEF */
299+#define SCALER_COEF_SHIFT(i) (16 * (1 - (i) % 2))
300+#define SCALER_COEF_GET(r, i) \
301+ (((r) >> SCALER_COEF_SHIFT(i)) & 0x1ff)
302+#define SCALER_COEF_SET(v, i) \
303+ (((v) & 0x1ff) << SCALER_COEF_SHIFT(i))
304+
305+/* SCALER_CSC_COEFxy */
306+#define SCALER_CSC_COEF_GET(r) SCALER_GET(r, 11, 0)
307+#define SCALER_CSC_COEF_SET(v) SCALER_SET(v, 11, 0)
308+
309+/* SCALER_DITH_CFG */
310+#define SCALER_DITH_CFG_GET_R_TYPE(r) SCALER_GET(r, 8, 6)
311+#define SCALER_DITH_CFG_SET_R_TYPE(v) SCALER_SET(v, 8, 6)
312+#define SCALER_DITH_CFG_GET_G_TYPE(r) SCALER_GET(r, 5, 3)
313+#define SCALER_DITH_CFG_SET_G_TYPE(v) SCALER_SET(v, 5, 3)
314+#define SCALER_DITH_CFG_GET_B_TYPE(r) SCALER_GET(r, 2, 0)
315+#define SCALER_DITH_CFG_SET_B_TYPE(v) SCALER_SET(v, 2, 0)
316+
317+/* SCALER_TIMEOUT_CTRL */
318+#define SCALER_TIMEOUT_CTRL_GET_TIMER_VALUE(r) SCALER_GET(r, 31, 16)
319+#define SCALER_TIMEOUT_CTRL_SET_TIMER_VALUE(v) SCALER_SET(v, 31, 16)
320+#define SCALER_TIMEOUT_CTRL_GET_TIMER_DIV(r) SCALER_GET(r, 7, 4)
321+#define SCALER_TIMEOUT_CTRL_SET_TIMER_DIV(v) SCALER_SET(v, 7, 4)
322+#define SCALER_TIMEOUT_CTRL_TIMER_ENABLE (1 << 0)
323+
324+/* SCALER_TIMEOUT_CNT */
325+#define SCALER_TIMEOUT_CTRL_GET_TIMER_COUNT(r) SCALER_GET(r, 31, 16)
326+
327+/* SCALER_SRC_BLEND_COLOR */
328+#define SCALER_SRC_BLEND_COLOR_SEL_INV (1 << 31)
329+#define SCALER_SRC_BLEND_COLOR_GET_SEL(r) SCALER_GET(r, 30, 29)
330+#define SCALER_SRC_BLEND_COLOR_SET_SEL(v) SCALER_SET(v, 30, 29)
331+#define SCALER_SRC_BLEND_COLOR_OP_SEL_INV (1 << 28)
332+#define SCALER_SRC_BLEND_COLOR_GET_OP_SEL(r) SCALER_GET(r, 27, 24)
333+#define SCALER_SRC_BLEND_COLOR_SET_OP_SEL(v) SCALER_SET(v, 27, 24)
334+#define SCALER_SRC_BLEND_COLOR_GET_COLOR0(r) SCALER_GET(r, 23, 16)
335+#define SCALER_SRC_BLEND_COLOR_SET_COLOR0(v) SCALER_SET(v, 23, 16)
336+#define SCALER_SRC_BLEND_COLOR_GET_COLOR1(r) SCALER_GET(r, 15, 8)
337+#define SCALER_SRC_BLEND_COLOR_SET_COLOR1(v) SCALER_SET(v, 15, 8)
338+#define SCALER_SRC_BLEND_COLOR_GET_COLOR2(r) SCALER_GET(r, 7, 0)
339+#define SCALER_SRC_BLEND_COLOR_SET_COLOR2(v) SCALER_SET(v, 7, 0)
340+
341+/* SCALER_SRC_BLEND_ALPHA */
342+#define SCALER_SRC_BLEND_ALPHA_SEL_INV (1 << 31)
343+#define SCALER_SRC_BLEND_ALPHA_GET_SEL(r) SCALER_GET(r, 30, 29)
344+#define SCALER_SRC_BLEND_ALPHA_SET_SEL(v) SCALER_SET(v, 30, 29)
345+#define SCALER_SRC_BLEND_ALPHA_OP_SEL_INV (1 << 28)
346+#define SCALER_SRC_BLEND_ALPHA_GET_OP_SEL(r) SCALER_GET(r, 27, 24)
347+#define SCALER_SRC_BLEND_ALPHA_SET_OP_SEL(v) SCALER_SET(v, 27, 24)
348+#define SCALER_SRC_BLEND_ALPHA_GET_ALPHA(r) SCALER_GET(r, 7, 0)
349+#define SCALER_SRC_BLEND_ALPHA_SET_ALPHA(v) SCALER_SET(v, 7, 0)
350+
351+/* SCALER_DST_BLEND_COLOR */
352+#define SCALER_DST_BLEND_COLOR_SEL_INV (1 << 31)
353+#define SCALER_DST_BLEND_COLOR_GET_SEL(r) SCALER_GET(r, 30, 29)
354+#define SCALER_DST_BLEND_COLOR_SET_SEL(v) SCALER_SET(v, 30, 29)
355+#define SCALER_DST_BLEND_COLOR_OP_SEL_INV (1 << 28)
356+#define SCALER_DST_BLEND_COLOR_GET_OP_SEL(r) SCALER_GET(r, 27, 24)
357+#define SCALER_DST_BLEND_COLOR_SET_OP_SEL(v) SCALER_SET(v, 27, 24)
358+#define SCALER_DST_BLEND_COLOR_GET_COLOR0(r) SCALER_GET(r, 23, 16)
359+#define SCALER_DST_BLEND_COLOR_SET_COLOR0(v) SCALER_SET(v, 23, 16)
360+#define SCALER_DST_BLEND_COLOR_GET_COLOR1(r) SCALER_GET(r, 15, 8)
361+#define SCALER_DST_BLEND_COLOR_SET_COLOR1(v) SCALER_SET(v, 15, 8)
362+#define SCALER_DST_BLEND_COLOR_GET_COLOR2(r) SCALER_GET(r, 7, 0)
363+#define SCALER_DST_BLEND_COLOR_SET_COLOR2(v) SCALER_SET(v, 7, 0)
364+
365+/* SCALER_DST_BLEND_ALPHA */
366+#define SCALER_DST_BLEND_ALPHA_SEL_INV (1 << 31)
367+#define SCALER_DST_BLEND_ALPHA_GET_SEL(r) SCALER_GET(r, 30, 29)
368+#define SCALER_DST_BLEND_ALPHA_SET_SEL(v) SCALER_SET(v, 30, 29)
369+#define SCALER_DST_BLEND_ALPHA_OP_SEL_INV (1 << 28)
370+#define SCALER_DST_BLEND_ALPHA_GET_OP_SEL(r) SCALER_GET(r, 27, 24)
371+#define SCALER_DST_BLEND_ALPHA_SET_OP_SEL(v) SCALER_SET(v, 27, 24)
372+#define SCALER_DST_BLEND_ALPHA_GET_ALPHA(r) SCALER_GET(r, 7, 0)
373+#define SCALER_DST_BLEND_ALPHA_SET_ALPHA(v) SCALER_SET(v, 7, 0)
374+
375+/* SCALER_FILL_COLOR */
376+#define SCALER_FILL_COLOR_GET_ALPHA(r) SCALER_GET(r, 31, 24)
377+#define SCALER_FILL_COLOR_SET_ALPHA(v) SCALER_SET(v, 31, 24)
378+#define SCALER_FILL_COLOR_GET_FILL_COLOR0(r) SCALER_GET(r, 23, 16)
379+#define SCALER_FILL_COLOR_SET_FILL_COLOR0(v) SCALER_SET(v, 23, 16)
380+#define SCALER_FILL_COLOR_GET_FILL_COLOR1(r) SCALER_GET(r, 15, 8)
381+#define SCALER_FILL_COLOR_SET_FILL_COLOR1(v) SCALER_SET(v, 15, 8)
382+#define SCALER_FILL_COLOR_GET_FILL_COLOR2(r) SCALER_GET(r, 7, 0)
383+#define SCALER_FILL_COLOR_SET_FILL_COLOR2(v) SCALER_SET(v, 7, 0)
384+
385+/* SCALER_ADDR_Q_CONFIG */
386+#define SCALER_ADDR_Q_CONFIG_RST (1 << 0)
387+
388+/* SCALER_SRC_ADDR_Q_STATUS */
389+#define SCALER_SRC_ADDR_Q_STATUS_Y_FULL (1 << 23)
390+#define SCALER_SRC_ADDR_Q_STATUS_Y_EMPTY (1 << 22)
391+#define SCALER_SRC_ADDR_Q_STATUS_GET_Y_WR_IDX(r) SCALER_GET(r, 21, 16)
392+#define SCALER_SRC_ADDR_Q_STATUS_CB_FULL (1 << 15)
393+#define SCALER_SRC_ADDR_Q_STATUS_CB_EMPTY (1 << 14)
394+#define SCALER_SRC_ADDR_Q_STATUS_GET_CB_WR_IDX(r) SCALER_GET(r, 13, 8)
395+#define SCALER_SRC_ADDR_Q_STATUS_CR_FULL (1 << 7)
396+#define SCALER_SRC_ADDR_Q_STATUS_CR_EMPTY (1 << 6)
397+#define SCALER_SRC_ADDR_Q_STATUS_GET_CR_WR_IDX(r) SCALER_GET(r, 5, 0)
398+
399+/* SCALER_DST_ADDR_Q_STATUS */
400+#define SCALER_DST_ADDR_Q_STATUS_Y_FULL (1 << 23)
401+#define SCALER_DST_ADDR_Q_STATUS_Y_EMPTY (1 << 22)
402+#define SCALER_DST_ADDR_Q_STATUS_GET_Y_WR_IDX(r) SCALER_GET(r, 21, 16)
403+#define SCALER_DST_ADDR_Q_STATUS_CB_FULL (1 << 15)
404+#define SCALER_DST_ADDR_Q_STATUS_CB_EMPTY (1 << 14)
405+#define SCALER_DST_ADDR_Q_STATUS_GET_CB_WR_IDX(r) SCALER_GET(r, 13, 8)
406+#define SCALER_DST_ADDR_Q_STATUS_CR_FULL (1 << 7)
407+#define SCALER_DST_ADDR_Q_STATUS_CR_EMPTY (1 << 6)
408+#define SCALER_DST_ADDR_Q_STATUS_GET_CR_WR_IDX(r) SCALER_GET(r, 5, 0)
409+
410+/* SCALER_CRC_COLOR00_10 */
411+#define SCALER_CRC_COLOR00_10_GET_00(r) SCALER_GET(r, 31, 16)
412+#define SCALER_CRC_COLOR00_10_GET_10(r) SCALER_GET(r, 15, 0)
413+
414+/* SCALER_CRC_COLOR20_30 */
415+#define SCALER_CRC_COLOR20_30_GET_20(r) SCALER_GET(r, 31, 16)
416+#define SCALER_CRC_COLOR20_30_GET_30(r) SCALER_GET(r, 15, 0)
417+
418+/* SCALER_CRC_COLOR01_11 */
419+#define SCALER_CRC_COLOR01_11_GET_01(r) SCALER_GET(r, 31, 16)
420+#define SCALER_CRC_COLOR01_11_GET_11(r) SCALER_GET(r, 15, 0)
421+
422+/* SCALER_CRC_COLOR21_31 */
423+#define SCALER_CRC_COLOR21_31_GET_21(r) SCALER_GET(r, 31, 16)
424+#define SCALER_CRC_COLOR21_31_GET_31(r) SCALER_GET(r, 15, 0)
425+
426+#endif /* EXYNOS_REGS_SCALER_H */
drivers/gpu/drm/i915/intel_csr.c+1−0
@@ -35,6 +35,7 @@ · 34 unmodified lines
3535 */
3636
3737 #define I915_CSR_GLK "i915/glk_dmc_ver1_04.bin"
38+MODULE_FIRMWARE(I915_CSR_GLK);
3839 #define GLK_CSR_VERSION_REQUIRED CSR_VERSION(1, 4)
3940
4041 #define I915_CSR_CNL "i915/cnl_dmc_ver1_07.bin"
drivers/gpu/drm/vc4/vc4_crtc.c+45−1
@@ -741,6 +741,7 @@ static irqreturn_t vc4_crtc_irq_handler(int irq, void *data) · 740 unmodified lines
741741 struct vc4_async_flip_state {
742742 struct drm_crtc *crtc;
743743 struct drm_framebuffer *fb;
744+ struct drm_framebuffer *old_fb;
744745 struct drm_pending_vblank_event *event;
745746
746747 struct vc4_seqno_cb cb;
@@ -770,6 +771,23 @@ vc4_async_page_flip_complete(struct vc4_seqno_cb *cb) · 23 unmodified lines
770771
771772 drm_crtc_vblank_put(crtc);
772773 drm_framebuffer_put(flip_state->fb);
774+
775+ /* Decrement the BO usecnt in order to keep the inc/dec calls balanced
776+ * when the planes are updated through the async update path.
777+ * FIXME: we should move to generic async-page-flip when it's
778+ * available, so that we can get rid of this hand-made cleanup_fb()
779+ * logic.
780+ */
781+ if (flip_state->old_fb) {
782+ struct drm_gem_cma_object *cma_bo;
783+ struct vc4_bo *bo;
784+
785+ cma_bo = drm_fb_cma_get_gem_obj(flip_state->old_fb, 0);
786+ bo = to_vc4_bo(&cma_bo->base);
787+ vc4_bo_dec_usecnt(bo);
788+ drm_framebuffer_put(flip_state->old_fb);
789+ }
790+
773791 kfree(flip_state);
774792
775793 up(&vc4->async_modeset);
@@ -794,9 +812,22 @@ static int vc4_async_page_flip(struct drm_crtc *crtc, · 18 unmodified lines
794812 struct drm_gem_cma_object *cma_bo = drm_fb_cma_get_gem_obj(fb, 0);
795813 struct vc4_bo *bo = to_vc4_bo(&cma_bo->base);
796814
815+ /* Increment the BO usecnt here, so that we never end up with an
816+ * unbalanced number of vc4_bo_{dec,inc}_usecnt() calls when the
817+ * plane is later updated through the non-async path.
818+ * FIXME: we should move to generic async-page-flip when it's
819+ * available, so that we can get rid of this hand-made prepare_fb()
820+ * logic.
821+ */
822+ ret = vc4_bo_inc_usecnt(bo);
823+ if (ret)
824+ return ret;
825+
797826 flip_state = kzalloc(sizeof(*flip_state), GFP_KERNEL);
798− if (!flip_state)
827+ if (!flip_state) {
828+ vc4_bo_dec_usecnt(bo);
799829 return -ENOMEM;
830+ }
800831
801832 drm_framebuffer_get(fb);
802833 flip_state->fb = fb;
@@ -807,10 +838,23 @@ static int vc4_async_page_flip(struct drm_crtc *crtc, · 4 unmodified lines
807838 ret = down_interruptible(&vc4->async_modeset);
808839 if (ret) {
809840 drm_framebuffer_put(fb);
841+ vc4_bo_dec_usecnt(bo);
810842 kfree(flip_state);
811843 return ret;
812844 }
813845
846+ /* Save the current FB before it's replaced by the new one in
847+ * drm_atomic_set_fb_for_plane(). We'll need the old FB in
848+ * vc4_async_page_flip_complete() to decrement the BO usecnt and keep
849+ * it consistent.
850+ * FIXME: we should move to generic async-page-flip when it's
851+ * available, so that we can get rid of this hand-made cleanup_fb()
852+ * logic.
853+ */
854+ flip_state->old_fb = plane->state->fb;
855+ if (flip_state->old_fb)
856+ drm_framebuffer_get(flip_state->old_fb);
857+
814858 WARN_ON(drm_crtc_vblank_get(crtc) != 0);
815859
816860 /* Immediately update the plane's legacy fb pointer, so that later
drivers/gpu/drm/vmwgfx/vmwgfx_fb.c+10−21
@@ -441,11 +441,11 @@ static int vmwgfx_set_config_internal(struct drm_mode_set *set) · 440 unmodified lines
441441 struct drm_crtc *crtc = set->crtc;
442442 struct drm_framebuffer *fb;
443443 struct drm_crtc *tmp;
444− struct drm_modeset_acquire_ctx *ctx;
445444 struct drm_device *dev = set->crtc->dev;
445+ struct drm_modeset_acquire_ctx ctx;
446446 int ret;
447447
448− ctx = dev->mode_config.acquire_ctx;
448+ drm_modeset_acquire_init(&ctx, 0);
449449
450450 restart:
451451 /*
@@ -458,7 +458,7 @@ restart: · 6 unmodified lines
458458
459459 fb = set->fb;
460460
461− ret = crtc->funcs->set_config(set, ctx);
461+ ret = crtc->funcs->set_config(set, &ctx);
462462 if (ret == 0) {
463463 crtc->primary->crtc = crtc;
464464 crtc->primary->fb = fb;
@@ -473,20 +473,13 @@ restart: · 8 unmodified lines
473473 }
474474
475475 if (ret == -EDEADLK) {
476− dev->mode_config.acquire_ctx = NULL;
477−
478−retry_locking:
479− drm_modeset_backoff(ctx);
480−
481− ret = drm_modeset_lock_all_ctx(dev, ctx);
482− if (ret)
483− goto retry_locking;
484−
485− dev->mode_config.acquire_ctx = ctx;
486−
476+ drm_modeset_backoff(&ctx);
487477 goto restart;
488478 }
489479
480+ drm_modeset_drop_locks(&ctx);
481+ drm_modeset_acquire_fini(&ctx);
482+
490483 return ret;
491484 }
492485
@@ -624,7 +617,6 @@ static int vmw_fb_set_par(struct fb_info *info) · 131 unmodified lines
624617 }
625618
626619 mutex_lock(&par->bo_mutex);
627− drm_modeset_lock_all(vmw_priv->dev);
628620 ret = vmw_fb_kms_framebuffer(info);
629621 if (ret)
630622 goto out_unlock;
@@ -657,7 +649,6 @@ out_unlock: · 26 unmodified lines
657649 drm_mode_destroy(vmw_priv->dev, old_mode);
658650 par->set_mode = mode;
659651
660− drm_modeset_unlock_all(vmw_priv->dev);
661652 mutex_unlock(&par->bo_mutex);
662653
663654 return ret;
@@ -713,18 +704,14 @@ int vmw_fb_init(struct vmw_private *vmw_priv) · 49 unmodified lines
713704 par->max_width = fb_width;
714705 par->max_height = fb_height;
715706
716− drm_modeset_lock_all(vmw_priv->dev);
717707 ret = vmw_kms_fbdev_init_data(vmw_priv, 0, par->max_width,
718708 par->max_height, &par->con,
719709 &par->crtc, &init_mode);
720− if (ret) {
721− drm_modeset_unlock_all(vmw_priv->dev);
710+ if (ret)
722711 goto err_kms;
723− }
724712
725713 info->var.xres = init_mode->hdisplay;
726714 info->var.yres = init_mode->vdisplay;
727− drm_modeset_unlock_all(vmw_priv->dev);
728715
729716 /*
730717 * Create buffers and alloc memory
@@ -832,7 +819,9 @@ int vmw_fb_close(struct vmw_private *vmw_priv) · 101 unmodified lines
832819 cancel_delayed_work_sync(&par->local_work);
833820 unregister_framebuffer(info);
834821
822+ mutex_lock(&par->bo_mutex);
835823 (void) vmw_fb_kms_detach(par, true, true);
824+ mutex_unlock(&par->bo_mutex);
836825
837826 vfree(par->vmalloc);
838827 framebuffer_release(info);
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c+11−3
@@ -2595,6 +2595,7 @@ void vmw_kms_helper_resource_finish(struct vmw_validation_ctx *ctx, · 2594 unmodified lines
25952595 vmw_kms_helper_buffer_finish(res->dev_priv, NULL, ctx->buf,
25962596 out_fence, NULL);
25972597
2598+ vmw_dmabuf_unreference(&ctx->buf);
25982599 vmw_resource_unreserve(res, false, NULL, 0);
25992600 mutex_unlock(&res->dev_priv->cmdbuf_mutex);
26002601 }
@@ -2680,7 +2681,9 @@ int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv, · 79 unmodified lines
26802681 struct vmw_display_unit *du;
26812682 struct drm_display_mode *mode;
26822683 int i = 0;
2684+ int ret = 0;
26832685
2686+ mutex_lock(&dev_priv->dev->mode_config.mutex);
26842687 list_for_each_entry(con, &dev_priv->dev->mode_config.connector_list,
26852688 head) {
26862689 if (i == unit)
@@ -2691,7 +2694,8 @@ int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv, · 4 unmodified lines
26912694
26922695 if (i != unit) {
26932696 DRM_ERROR("Could not find initial display unit.\n");
2694− return -EINVAL;
2697+ ret = -EINVAL;
2698+ goto out_unlock;
26952699 }
26962700
26972701 if (list_empty(&con->modes))
@@ -2699,7 +2703,8 @@ int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv, · 1 unmodified line
26992703
27002704 if (list_empty(&con->modes)) {
27012705 DRM_ERROR("Could not find initial display mode.\n");
2702− return -EINVAL;
2706+ ret = -EINVAL;
2707+ goto out_unlock;
27032708 }
27042709
27052710 du = vmw_connector_to_du(con);
@@ -2720,7 +2725,10 @@ int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv, · 14 unmodified lines
27202725 head);
27212726 }
27222727
2723− return 0;
2728+ out_unlock:
2729+ mutex_unlock(&dev_priv->dev->mode_config.mutex);
2730+
2731+ return ret;
27242732 }
27252733
27262734 /**
include/uapi/drm/exynos_drm.h+240−0
@@ -135,6 +135,219 @@ struct drm_exynos_g2d_exec { · 134 unmodified lines
135135 __u64 async;
136136 };
137137
138+/* Exynos DRM IPP v2 API */
139+
140+/**
141+ * Enumerate available IPP hardware modules.
142+ *
143+ * @count_ipps: size of ipp_id array / number of ipp modules (set by driver)
144+ * @reserved: padding
145+ * @ipp_id_ptr: pointer to ipp_id array or NULL
146+ */
147+struct drm_exynos_ioctl_ipp_get_res {
148+ __u32 count_ipps;
149+ __u32 reserved;
150+ __u64 ipp_id_ptr;
151+};
152+
153+enum drm_exynos_ipp_format_type {
154+ DRM_EXYNOS_IPP_FORMAT_SOURCE = 0x01,
155+ DRM_EXYNOS_IPP_FORMAT_DESTINATION = 0x02,
156+};
157+
158+struct drm_exynos_ipp_format {
159+ __u32 fourcc;
160+ __u32 type;
161+ __u64 modifier;
162+};
163+
164+enum drm_exynos_ipp_capability {
165+ DRM_EXYNOS_IPP_CAP_CROP = 0x01,
166+ DRM_EXYNOS_IPP_CAP_ROTATE = 0x02,
167+ DRM_EXYNOS_IPP_CAP_SCALE = 0x04,
168+ DRM_EXYNOS_IPP_CAP_CONVERT = 0x08,
169+};
170+
171+/**
172+ * Get IPP hardware capabilities and supported image formats.
173+ *
174+ * @ipp_id: id of IPP module to query
175+ * @capabilities: bitmask of drm_exynos_ipp_capability (set by driver)
176+ * @reserved: padding
177+ * @formats_count: size of formats array (in entries) / number of filled
178+ * formats (set by driver)
179+ * @formats_ptr: pointer to formats array or NULL
180+ */
181+struct drm_exynos_ioctl_ipp_get_caps {
182+ __u32 ipp_id;
183+ __u32 capabilities;
184+ __u32 reserved;
185+ __u32 formats_count;
186+ __u64 formats_ptr;
187+};
188+
189+enum drm_exynos_ipp_limit_type {
190+ /* size (horizontal/vertial) limits, in pixels (min, max, alignment) */
191+ DRM_EXYNOS_IPP_LIMIT_TYPE_SIZE = 0x0001,
192+ /* scale ratio (horizonta/vertial), 16.16 fixed point (min, max) */
193+ DRM_EXYNOS_IPP_LIMIT_TYPE_SCALE = 0x0002,
194+
195+ /* image buffer area */
196+ DRM_EXYNOS_IPP_LIMIT_SIZE_BUFFER = 0x0001 << 16,
197+ /* src/dst rectangle area */
198+ DRM_EXYNOS_IPP_LIMIT_SIZE_AREA = 0x0002 << 16,
199+ /* src/dst rectangle area when rotation enabled */
200+ DRM_EXYNOS_IPP_LIMIT_SIZE_ROTATED = 0x0003 << 16,
201+
202+ DRM_EXYNOS_IPP_LIMIT_TYPE_MASK = 0x000f,
203+ DRM_EXYNOS_IPP_LIMIT_SIZE_MASK = 0x000f << 16,
204+};
205+
206+struct drm_exynos_ipp_limit_val {
207+ __u32 min;
208+ __u32 max;
209+ __u32 align;
210+ __u32 reserved;
211+};
212+
213+/**
214+ * IPP module limitation.
215+ *
216+ * @type: limit type (see drm_exynos_ipp_limit_type enum)
217+ * @reserved: padding
218+ * @h: horizontal limits
219+ * @v: vertical limits
220+ */
221+struct drm_exynos_ipp_limit {
222+ __u32 type;
223+ __u32 reserved;
224+ struct drm_exynos_ipp_limit_val h;
225+ struct drm_exynos_ipp_limit_val v;
226+};
227+
228+/**
229+ * Get IPP limits for given image format.
230+ *
231+ * @ipp_id: id of IPP module to query
232+ * @fourcc: image format code (see DRM_FORMAT_* in drm_fourcc.h)
233+ * @modifier: image format modifier (see DRM_FORMAT_MOD_* in drm_fourcc.h)
234+ * @type: source/destination identifier (drm_exynos_ipp_format_flag enum)
235+ * @limits_count: size of limits array (in entries) / number of filled entries
236+ * (set by driver)
237+ * @limits_ptr: pointer to limits array or NULL
238+ */
239+struct drm_exynos_ioctl_ipp_get_limits {
240+ __u32 ipp_id;
241+ __u32 fourcc;
242+ __u64 modifier;
243+ __u32 type;
244+ __u32 limits_count;
245+ __u64 limits_ptr;
246+};
247+
248+enum drm_exynos_ipp_task_id {
249+ /* buffer described by struct drm_exynos_ipp_task_buffer */
250+ DRM_EXYNOS_IPP_TASK_BUFFER = 0x0001,
251+ /* rectangle described by struct drm_exynos_ipp_task_rect */
252+ DRM_EXYNOS_IPP_TASK_RECTANGLE = 0x0002,
253+ /* transformation described by struct drm_exynos_ipp_task_transform */
254+ DRM_EXYNOS_IPP_TASK_TRANSFORM = 0x0003,
255+ /* alpha configuration described by struct drm_exynos_ipp_task_alpha */
256+ DRM_EXYNOS_IPP_TASK_ALPHA = 0x0004,
257+
258+ /* source image data (for buffer and rectangle chunks) */
259+ DRM_EXYNOS_IPP_TASK_TYPE_SOURCE = 0x0001 << 16,
260+ /* destination image data (for buffer and rectangle chunks) */
261+ DRM_EXYNOS_IPP_TASK_TYPE_DESTINATION = 0x0002 << 16,
262+};
263+
264+/**
265+ * Memory buffer with image data.
266+ *
267+ * @id: must be DRM_EXYNOS_IPP_TASK_BUFFER
268+ * other parameters are same as for AddFB2 generic DRM ioctl
269+ */
270+struct drm_exynos_ipp_task_buffer {
271+ __u32 id;
272+ __u32 fourcc;
273+ __u32 width, height;
274+ __u32 gem_id[4];
275+ __u32 offset[4];
276+ __u32 pitch[4];
277+ __u64 modifier;
278+};
279+
280+/**
281+ * Rectangle for processing.
282+ *
283+ * @id: must be DRM_EXYNOS_IPP_TASK_RECTANGLE
284+ * @reserved: padding
285+ * @x,@y: left corner in pixels
286+ * @w,@h: width/height in pixels
287+ */
288+struct drm_exynos_ipp_task_rect {
289+ __u32 id;
290+ __u32 reserved;
291+ __u32 x;
292+ __u32 y;
293+ __u32 w;
294+ __u32 h;
295+};
296+
297+/**
298+ * Image tranformation description.
299+ *
300+ * @id: must be DRM_EXYNOS_IPP_TASK_TRANSFORM
301+ * @rotation: DRM_MODE_ROTATE_* and DRM_MODE_REFLECT_* values
302+ */
303+struct drm_exynos_ipp_task_transform {
304+ __u32 id;
305+ __u32 rotation;
306+};
307+
308+/**
309+ * Image global alpha configuration for formats without alpha values.
310+ *
311+ * @id: must be DRM_EXYNOS_IPP_TASK_ALPHA
312+ * @value: global alpha value (0-255)
313+ */
314+struct drm_exynos_ipp_task_alpha {
315+ __u32 id;
316+ __u32 value;
317+};
318+
319+enum drm_exynos_ipp_flag {
320+ /* generate DRM event after processing */
321+ DRM_EXYNOS_IPP_FLAG_EVENT = 0x01,
322+ /* dry run, only check task parameters */
323+ DRM_EXYNOS_IPP_FLAG_TEST_ONLY = 0x02,
324+ /* non-blocking processing */
325+ DRM_EXYNOS_IPP_FLAG_NONBLOCK = 0x04,
326+};
327+
328+#define DRM_EXYNOS_IPP_FLAGS (DRM_EXYNOS_IPP_FLAG_EVENT |\
329+ DRM_EXYNOS_IPP_FLAG_TEST_ONLY | DRM_EXYNOS_IPP_FLAG_NONBLOCK)
330+
331+/**
332+ * Perform image processing described by array of drm_exynos_ipp_task_*
333+ * structures (parameters array).
334+ *
335+ * @ipp_id: id of IPP module to run the task
336+ * @flags: bitmask of drm_exynos_ipp_flag values
337+ * @reserved: padding
338+ * @params_size: size of parameters array (in bytes)
339+ * @params_ptr: pointer to parameters array or NULL
340+ * @user_data: (optional) data for drm event
341+ */
342+struct drm_exynos_ioctl_ipp_commit {
343+ __u32 ipp_id;
344+ __u32 flags;
345+ __u32 reserved;
346+ __u32 params_size;
347+ __u64 params_ptr;
348+ __u64 user_data;
349+};
350+
138351 #define DRM_EXYNOS_GEM_CREATE 0x00
139352 #define DRM_EXYNOS_GEM_MAP 0x01
140353 /* Reserved 0x03 ~ 0x05 for exynos specific gem ioctl */
@@ -147,6 +360,11 @@ struct drm_exynos_g2d_exec { · 6 unmodified lines
147360 #define DRM_EXYNOS_G2D_EXEC 0x22
148361
149362 /* Reserved 0x30 ~ 0x33 for obsolete Exynos IPP ioctls */
363+/* IPP - Image Post Processing */
364+#define DRM_EXYNOS_IPP_GET_RESOURCES 0x40
365+#define DRM_EXYNOS_IPP_GET_CAPS 0x41
366+#define DRM_EXYNOS_IPP_GET_LIMITS 0x42
367+#define DRM_EXYNOS_IPP_COMMIT 0x43
150368
151369 #define DRM_IOCTL_EXYNOS_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \
152370 DRM_EXYNOS_GEM_CREATE, struct drm_exynos_gem_create)
@@ -165,8 +383,20 @@ struct drm_exynos_g2d_exec { · 12 unmodified lines
165383 #define DRM_IOCTL_EXYNOS_G2D_EXEC DRM_IOWR(DRM_COMMAND_BASE + \
166384 DRM_EXYNOS_G2D_EXEC, struct drm_exynos_g2d_exec)
167385
386+#define DRM_IOCTL_EXYNOS_IPP_GET_RESOURCES DRM_IOWR(DRM_COMMAND_BASE + \
387+ DRM_EXYNOS_IPP_GET_RESOURCES, \
388+ struct drm_exynos_ioctl_ipp_get_res)
389+#define DRM_IOCTL_EXYNOS_IPP_GET_CAPS DRM_IOWR(DRM_COMMAND_BASE + \
390+ DRM_EXYNOS_IPP_GET_CAPS, struct drm_exynos_ioctl_ipp_get_caps)
391+#define DRM_IOCTL_EXYNOS_IPP_GET_LIMITS DRM_IOWR(DRM_COMMAND_BASE + \
392+ DRM_EXYNOS_IPP_GET_LIMITS, \
393+ struct drm_exynos_ioctl_ipp_get_limits)
394+#define DRM_IOCTL_EXYNOS_IPP_COMMIT DRM_IOWR(DRM_COMMAND_BASE + \
395+ DRM_EXYNOS_IPP_COMMIT, struct drm_exynos_ioctl_ipp_commit)
396+
168397 /* EXYNOS specific events */
169398 #define DRM_EXYNOS_G2D_EVENT 0x80000000
399+#define DRM_EXYNOS_IPP_EVENT 0x80000002
170400
171401 struct drm_exynos_g2d_event {
172402 struct drm_event base;
@@ -177,6 +407,16 @@ struct drm_exynos_g2d_event { · 4 unmodified lines
177407 __u32 reserved;
178408 };
179409
410+struct drm_exynos_ipp_event {
411+ struct drm_event base;
412+ __u64 user_data;
413+ __u32 tv_sec;
414+ __u32 tv_usec;
415+ __u32 ipp_id;
416+ __u32 sequence;
417+ __u64 reserved;
418+};
419+
180420 #if defined(__cplusplus)
181421 }
182422 #endif

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t