diff options
38 files changed, 2028 insertions, 1753 deletions
diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt index bf4a18047309..3a50a7862cf3 100644 --- a/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt +++ b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt | |||
| @@ -37,6 +37,7 @@ Required properties: | |||
| 37 | - GXL (S905X, S905D) : "amlogic,meson-gxl-dw-hdmi" | 37 | - GXL (S905X, S905D) : "amlogic,meson-gxl-dw-hdmi" |
| 38 | - GXM (S912) : "amlogic,meson-gxm-dw-hdmi" | 38 | - GXM (S912) : "amlogic,meson-gxm-dw-hdmi" |
| 39 | followed by the common "amlogic,meson-gx-dw-hdmi" | 39 | followed by the common "amlogic,meson-gx-dw-hdmi" |
| 40 | - G12A (S905X2, S905Y2, S905D2) : "amlogic,meson-g12a-dw-hdmi" | ||
| 40 | - reg: Physical base address and length of the controller's registers. | 41 | - reg: Physical base address and length of the controller's registers. |
| 41 | - interrupts: The HDMI interrupt number | 42 | - interrupts: The HDMI interrupt number |
| 42 | - clocks, clock-names : must have the phandles to the HDMI iahb and isfr clocks, | 43 | - clocks, clock-names : must have the phandles to the HDMI iahb and isfr clocks, |
| @@ -66,6 +67,9 @@ corresponding to each HDMI output and input. | |||
| 66 | S905X (GXL) VENC Input TMDS Output | 67 | S905X (GXL) VENC Input TMDS Output |
| 67 | S905D (GXL) VENC Input TMDS Output | 68 | S905D (GXL) VENC Input TMDS Output |
| 68 | S912 (GXM) VENC Input TMDS Output | 69 | S912 (GXM) VENC Input TMDS Output |
| 70 | S905X2 (G12A) VENC Input TMDS Output | ||
| 71 | S905Y2 (G12A) VENC Input TMDS Output | ||
| 72 | S905D2 (G12A) VENC Input TMDS Output | ||
| 69 | 73 | ||
| 70 | Example: | 74 | Example: |
| 71 | 75 | ||
diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt index 419444e2b4d3..be40a780501c 100644 --- a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt +++ b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt | |||
| @@ -57,6 +57,7 @@ Required properties: | |||
| 57 | - GXL (S905X, S905D) : "amlogic,meson-gxl-vpu" | 57 | - GXL (S905X, S905D) : "amlogic,meson-gxl-vpu" |
| 58 | - GXM (S912) : "amlogic,meson-gxm-vpu" | 58 | - GXM (S912) : "amlogic,meson-gxm-vpu" |
| 59 | followed by the common "amlogic,meson-gx-vpu" | 59 | followed by the common "amlogic,meson-gx-vpu" |
| 60 | - G12A (S905X2, S905Y2, S905D2) : "amlogic,meson-g12a-vpu" | ||
| 60 | - reg: base address and size of he following memory-mapped regions : | 61 | - reg: base address and size of he following memory-mapped regions : |
| 61 | - vpu | 62 | - vpu |
| 62 | - hhi | 63 | - hhi |
| @@ -83,6 +84,9 @@ corresponding to each VPU output. | |||
| 83 | S905X (GXL) CVBS VDAC HDMI-TX | 84 | S905X (GXL) CVBS VDAC HDMI-TX |
| 84 | S905D (GXL) CVBS VDAC HDMI-TX | 85 | S905D (GXL) CVBS VDAC HDMI-TX |
| 85 | S912 (GXM) CVBS VDAC HDMI-TX | 86 | S912 (GXM) CVBS VDAC HDMI-TX |
| 87 | S905X2 (G12A) CVBS VDAC HDMI-TX | ||
| 88 | S905Y2 (G12A) CVBS VDAC HDMI-TX | ||
| 89 | S905D2 (G12A) CVBS VDAC HDMI-TX | ||
| 86 | 90 | ||
| 87 | Example: | 91 | Example: |
| 88 | 92 | ||
diff --git a/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.txt b/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.txt new file mode 100644 index 000000000000..b8be9dbc68b4 --- /dev/null +++ b/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.txt | |||
| @@ -0,0 +1,92 @@ | |||
| 1 | ARM Mali Bifrost GPU | ||
| 2 | ==================== | ||
| 3 | |||
| 4 | Required properties: | ||
| 5 | |||
| 6 | - compatible : | ||
| 7 | * Since Mali Bifrost GPU model/revision is fully discoverable by reading | ||
| 8 | some determined registers, must contain the following: | ||
| 9 | + "arm,mali-bifrost" | ||
| 10 | * which must be preceded by one of the following vendor specifics: | ||
| 11 | + "amlogic,meson-g12a-mali" | ||
| 12 | |||
| 13 | - reg : Physical base address of the device and length of the register area. | ||
| 14 | |||
| 15 | - interrupts : Contains the three IRQ lines required by Mali Bifrost devices, | ||
| 16 | in the following defined order. | ||
| 17 | |||
| 18 | - interrupt-names : Contains the names of IRQ resources in this exact defined | ||
| 19 | order: "job", "mmu", "gpu". | ||
| 20 | |||
| 21 | Optional properties: | ||
| 22 | |||
| 23 | - clocks : Phandle to clock for the Mali Bifrost device. | ||
| 24 | |||
| 25 | - mali-supply : Phandle to regulator for the Mali device. Refer to | ||
| 26 | Documentation/devicetree/bindings/regulator/regulator.txt for details. | ||
| 27 | |||
| 28 | - operating-points-v2 : Refer to Documentation/devicetree/bindings/opp/opp.txt | ||
| 29 | for details. | ||
| 30 | |||
| 31 | - resets : Phandle of the GPU reset line. | ||
| 32 | |||
| 33 | Vendor-specific bindings | ||
| 34 | ------------------------ | ||
| 35 | |||
| 36 | The Mali GPU is integrated very differently from one SoC to | ||
| 37 | another. In order to accommodate those differences, you have the option | ||
| 38 | to specify one more vendor-specific compatible, among: | ||
| 39 | |||
| 40 | - "amlogic,meson-g12a-mali" | ||
| 41 | Required properties: | ||
| 42 | - resets : Should contain phandles of : | ||
| 43 | + GPU reset line | ||
| 44 | + GPU APB glue reset line | ||
| 45 | |||
| 46 | Example for a Mali-G31: | ||
| 47 | |||
| 48 | gpu@ffa30000 { | ||
| 49 | compatible = "amlogic,meson-g12a-mali", "arm,mali-bifrost"; | ||
| 50 | reg = <0xffe40000 0x10000>; | ||
| 51 | interrupts = <GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>, | ||
| 52 | <GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>, | ||
| 53 | <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>; | ||
| 54 | interrupt-names = "job", "mmu", "gpu"; | ||
| 55 | clocks = <&clk CLKID_MALI>; | ||
| 56 | mali-supply = <&vdd_gpu>; | ||
| 57 | operating-points-v2 = <&gpu_opp_table>; | ||
| 58 | resets = <&reset RESET_DVALIN_CAPB3>, <&reset RESET_DVALIN>; | ||
| 59 | }; | ||
| 60 | |||
| 61 | gpu_opp_table: opp_table0 { | ||
| 62 | compatible = "operating-points-v2"; | ||
| 63 | |||
| 64 | opp@533000000 { | ||
| 65 | opp-hz = /bits/ 64 <533000000>; | ||
| 66 | opp-microvolt = <1250000>; | ||
| 67 | }; | ||
| 68 | opp@450000000 { | ||
| 69 | opp-hz = /bits/ 64 <450000000>; | ||
| 70 | opp-microvolt = <1150000>; | ||
| 71 | }; | ||
| 72 | opp@400000000 { | ||
| 73 | opp-hz = /bits/ 64 <400000000>; | ||
| 74 | opp-microvolt = <1125000>; | ||
| 75 | }; | ||
| 76 | opp@350000000 { | ||
| 77 | opp-hz = /bits/ 64 <350000000>; | ||
| 78 | opp-microvolt = <1075000>; | ||
| 79 | }; | ||
| 80 | opp@266000000 { | ||
| 81 | opp-hz = /bits/ 64 <266000000>; | ||
| 82 | opp-microvolt = <1025000>; | ||
| 83 | }; | ||
| 84 | opp@160000000 { | ||
| 85 | opp-hz = /bits/ 64 <160000000>; | ||
| 86 | opp-microvolt = <925000>; | ||
| 87 | }; | ||
| 88 | opp@100000000 { | ||
| 89 | opp-hz = /bits/ 64 <100000000>; | ||
| 90 | opp-microvolt = <912500>; | ||
| 91 | }; | ||
| 92 | }; | ||
diff --git a/Documentation/gpu/meson.rst b/Documentation/gpu/meson.rst index 479f6f51a13b..b9e2f9aa3bd8 100644 --- a/Documentation/gpu/meson.rst +++ b/Documentation/gpu/meson.rst | |||
| @@ -42,12 +42,6 @@ Video Encoder | |||
| 42 | .. kernel-doc:: drivers/gpu/drm/meson/meson_venc.c | 42 | .. kernel-doc:: drivers/gpu/drm/meson/meson_venc.c |
| 43 | :doc: Video Encoder | 43 | :doc: Video Encoder |
| 44 | 44 | ||
| 45 | Video Canvas Management | ||
| 46 | ======================= | ||
| 47 | |||
| 48 | .. kernel-doc:: drivers/gpu/drm/meson/meson_canvas.c | ||
| 49 | :doc: Canvas | ||
| 50 | |||
| 51 | Video Clocks | 45 | Video Clocks |
| 52 | ============ | 46 | ============ |
| 53 | 47 | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 4b69b6b48b3b..8825dffebb4c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -5209,7 +5209,7 @@ F: Documentation/devicetree/bindings/display/hisilicon/ | |||
| 5209 | DRM DRIVERS FOR LIMA | 5209 | DRM DRIVERS FOR LIMA |
| 5210 | M: Qiang Yu <yuq825@gmail.com> | 5210 | M: Qiang Yu <yuq825@gmail.com> |
| 5211 | L: dri-devel@lists.freedesktop.org | 5211 | L: dri-devel@lists.freedesktop.org |
| 5212 | L: lima@lists.freedesktop.org | 5212 | L: lima@lists.freedesktop.org (moderated for non-subscribers) |
| 5213 | S: Maintained | 5213 | S: Maintained |
| 5214 | F: drivers/gpu/drm/lima/ | 5214 | F: drivers/gpu/drm/lima/ |
| 5215 | F: include/uapi/drm/lima_drm.h | 5215 | F: include/uapi/drm/lima_drm.h |
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index d97c0a3a8cfc..7ebae3d45505 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile | |||
| @@ -38,7 +38,8 @@ drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper | |||
| 38 | drm_kms_helper_common.o drm_dp_dual_mode_helper.o \ | 38 | drm_kms_helper_common.o drm_dp_dual_mode_helper.o \ |
| 39 | drm_simple_kms_helper.o drm_modeset_helper.o \ | 39 | drm_simple_kms_helper.o drm_modeset_helper.o \ |
| 40 | drm_scdc_helper.o drm_gem_framebuffer_helper.o \ | 40 | drm_scdc_helper.o drm_gem_framebuffer_helper.o \ |
| 41 | drm_atomic_state_helper.o drm_damage_helper.o | 41 | drm_atomic_state_helper.o drm_damage_helper.o \ |
| 42 | drm_format_helper.o | ||
| 42 | 43 | ||
| 43 | drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o | 44 | drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o |
| 44 | drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o | 45 | drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o |
diff --git a/drivers/gpu/drm/cirrus/Kconfig b/drivers/gpu/drm/cirrus/Kconfig index fc78c90ee931..dd4f52a0bc1c 100644 --- a/drivers/gpu/drm/cirrus/Kconfig +++ b/drivers/gpu/drm/cirrus/Kconfig | |||
| @@ -2,7 +2,7 @@ config DRM_CIRRUS_QEMU | |||
| 2 | tristate "Cirrus driver for QEMU emulated device" | 2 | tristate "Cirrus driver for QEMU emulated device" |
| 3 | depends on DRM && PCI && MMU | 3 | depends on DRM && PCI && MMU |
| 4 | select DRM_KMS_HELPER | 4 | select DRM_KMS_HELPER |
| 5 | select DRM_TTM | 5 | select DRM_GEM_SHMEM_HELPER |
| 6 | help | 6 | help |
| 7 | This is a KMS driver for emulated cirrus device in qemu. | 7 | This is a KMS driver for emulated cirrus device in qemu. |
| 8 | It is *NOT* intended for real cirrus devices. This requires | 8 | It is *NOT* intended for real cirrus devices. This requires |
diff --git a/drivers/gpu/drm/cirrus/Makefile b/drivers/gpu/drm/cirrus/Makefile index 919c0a336c97..acf8971d37a1 100644 --- a/drivers/gpu/drm/cirrus/Makefile +++ b/drivers/gpu/drm/cirrus/Makefile | |||
| @@ -1,4 +1 @@ | |||
| 1 | cirrus-y := cirrus_main.o cirrus_mode.o \ | ||
| 2 | cirrus_drv.o cirrus_fbdev.o cirrus_ttm.o | ||
| 3 | |||
| 4 | obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus.o | obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus.o | |
diff --git a/drivers/gpu/drm/cirrus/cirrus.c b/drivers/gpu/drm/cirrus/cirrus.c new file mode 100644 index 000000000000..5095b8ce52c2 --- /dev/null +++ b/drivers/gpu/drm/cirrus/cirrus.c | |||
| @@ -0,0 +1,657 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | /* | ||
| 3 | * Copyright 2012-2019 Red Hat | ||
| 4 | * | ||
| 5 | * This file is subject to the terms and conditions of the GNU General | ||
| 6 | * Public License version 2. See the file COPYING in the main | ||
| 7 | * directory of this archive for more details. | ||
| 8 | * | ||
| 9 | * Authors: Matthew Garrett | ||
| 10 | * Dave Airlie | ||
| 11 | * Gerd Hoffmann | ||
| 12 | * | ||
| 13 | * Portions of this code derived from cirrusfb.c: | ||
| 14 | * drivers/video/cirrusfb.c - driver for Cirrus Logic chipsets | ||
| 15 | * | ||
| 16 | * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com> | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/console.h> | ||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/pci.h> | ||
| 22 | |||
| 23 | #include <video/cirrus.h> | ||
| 24 | #include <video/vga.h> | ||
| 25 | |||
| 26 | #include <drm/drm_atomic_helper.h> | ||
| 27 | #include <drm/drm_atomic_state_helper.h> | ||
| 28 | #include <drm/drm_connector.h> | ||
| 29 | #include <drm/drm_damage_helper.h> | ||
| 30 | #include <drm/drm_drv.h> | ||
| 31 | #include <drm/drm_fb_helper.h> | ||
| 32 | #include <drm/drm_file.h> | ||
| 33 | #include <drm/drm_format_helper.h> | ||
| 34 | #include <drm/drm_fourcc.h> | ||
| 35 | #include <drm/drm_gem_shmem_helper.h> | ||
| 36 | #include <drm/drm_gem_framebuffer_helper.h> | ||
| 37 | #include <drm/drm_ioctl.h> | ||
| 38 | #include <drm/drm_modeset_helper_vtables.h> | ||
| 39 | #include <drm/drm_probe_helper.h> | ||
| 40 | #include <drm/drm_simple_kms_helper.h> | ||
| 41 | #include <drm/drm_vblank.h> | ||
| 42 | |||
| 43 | #define DRIVER_NAME "cirrus" | ||
| 44 | #define DRIVER_DESC "qemu cirrus vga" | ||
| 45 | #define DRIVER_DATE "2019" | ||
| 46 | #define DRIVER_MAJOR 2 | ||
| 47 | #define DRIVER_MINOR 0 | ||
| 48 | |||
| 49 | #define CIRRUS_MAX_PITCH (0x1FF << 3) /* (4096 - 1) & ~111b bytes */ | ||
| 50 | #define CIRRUS_VRAM_SIZE (4 * 1024 * 1024) /* 4 MB */ | ||
| 51 | |||
| 52 | struct cirrus_device { | ||
| 53 | struct drm_device dev; | ||
| 54 | struct drm_simple_display_pipe pipe; | ||
| 55 | struct drm_connector conn; | ||
| 56 | unsigned int cpp; | ||
| 57 | unsigned int pitch; | ||
| 58 | void __iomem *vram; | ||
| 59 | void __iomem *mmio; | ||
| 60 | }; | ||
| 61 | |||
| 62 | /* ------------------------------------------------------------------ */ | ||
| 63 | /* | ||
| 64 | * The meat of this driver. The core passes us a mode and we have to program | ||
| 65 | * it. The modesetting here is the bare minimum required to satisfy the qemu | ||
| 66 | * emulation of this hardware, and running this against a real device is | ||
| 67 | * likely to result in an inadequately programmed mode. We've already had | ||
| 68 | * the opportunity to modify the mode, so whatever we receive here should | ||
| 69 | * be something that can be correctly programmed and displayed | ||
| 70 | */ | ||
| 71 | |||
| 72 | #define SEQ_INDEX 4 | ||
| 73 | #define SEQ_DATA 5 | ||
| 74 | |||
| 75 | static u8 rreg_seq(struct cirrus_device *cirrus, u8 reg) | ||
| 76 | { | ||
| 77 | iowrite8(reg, cirrus->mmio + SEQ_INDEX); | ||
| 78 | return ioread8(cirrus->mmio + SEQ_DATA); | ||
| 79 | } | ||
| 80 | |||
| 81 | static void wreg_seq(struct cirrus_device *cirrus, u8 reg, u8 val) | ||
| 82 | { | ||
| 83 | iowrite8(reg, cirrus->mmio + SEQ_INDEX); | ||
| 84 | iowrite8(val, cirrus->mmio + SEQ_DATA); | ||
| 85 | } | ||
| 86 | |||
| 87 | #define CRT_INDEX 0x14 | ||
| 88 | #define CRT_DATA 0x15 | ||
| 89 | |||
| 90 | static u8 rreg_crt(struct cirrus_device *cirrus, u8 reg) | ||
| 91 | { | ||
| 92 | iowrite8(reg, cirrus->mmio + CRT_INDEX); | ||
| 93 | return ioread8(cirrus->mmio + CRT_DATA); | ||
| 94 | } | ||
| 95 | |||
| 96 | static void wreg_crt(struct cirrus_device *cirrus, u8 reg, u8 val) | ||
| 97 | { | ||
| 98 | iowrite8(reg, cirrus->mmio + CRT_INDEX); | ||
| 99 | iowrite8(val, cirrus->mmio + CRT_DATA); | ||
| 100 | } | ||
| 101 | |||
| 102 | #define GFX_INDEX 0xe | ||
| 103 | #define GFX_DATA 0xf | ||
| 104 | |||
| 105 | static void wreg_gfx(struct cirrus_device *cirrus, u8 reg, u8 val) | ||
| 106 | { | ||
| 107 | iowrite8(reg, cirrus->mmio + GFX_INDEX); | ||
| 108 | iowrite8(val, cirrus->mmio + GFX_DATA); | ||
| 109 | } | ||
| 110 | |||
| 111 | #define VGA_DAC_MASK 0x06 | ||
| 112 | |||
| 113 | static void wreg_hdr(struct cirrus_device *cirrus, u8 val) | ||
| 114 | { | ||
| 115 | ioread8(cirrus->mmio + VGA_DAC_MASK); | ||
| 116 | ioread8(cirrus->mmio + VGA_DAC_MASK); | ||
| 117 | ioread8(cirrus->mmio + VGA_DAC_MASK); | ||
| 118 | ioread8(cirrus->mmio + VGA_DAC_MASK); | ||
| 119 | iowrite8(val, cirrus->mmio + VGA_DAC_MASK); | ||
| 120 | } | ||
| 121 | |||
| 122 | static int cirrus_convert_to(struct drm_framebuffer *fb) | ||
| 123 | { | ||
| 124 | if (fb->format->cpp[0] == 4 && fb->pitches[0] > CIRRUS_MAX_PITCH) { | ||
| 125 | if (fb->width * 3 <= CIRRUS_MAX_PITCH) | ||
| 126 | /* convert from XR24 to RG24 */ | ||
| 127 | return 3; | ||
| 128 | else | ||
| 129 | /* convert from XR24 to RG16 */ | ||
| 130 | return 2; | ||
| 131 | } | ||
| 132 | return 0; | ||
| 133 | } | ||
| 134 | |||
| 135 | static int cirrus_cpp(struct drm_framebuffer *fb) | ||
| 136 | { | ||
| 137 | int convert_cpp = cirrus_convert_to(fb); | ||
| 138 | |||
| 139 | if (convert_cpp) | ||
| 140 | return convert_cpp; | ||
| 141 | return fb->format->cpp[0]; | ||
| 142 | } | ||
| 143 | |||
| 144 | static int cirrus_pitch(struct drm_framebuffer *fb) | ||
| 145 | { | ||
| 146 | int convert_cpp = cirrus_convert_to(fb); | ||
| 147 | |||
| 148 | if (convert_cpp) | ||
| 149 | return convert_cpp * fb->width; | ||
| 150 | return fb->pitches[0]; | ||
| 151 | } | ||
| 152 | |||
| 153 | static void cirrus_set_start_address(struct cirrus_device *cirrus, u32 offset) | ||
| 154 | { | ||
| 155 | u32 addr; | ||
| 156 | u8 tmp; | ||
| 157 | |||
| 158 | addr = offset >> 2; | ||
| 159 | wreg_crt(cirrus, 0x0c, (u8)((addr >> 8) & 0xff)); | ||
| 160 | wreg_crt(cirrus, 0x0d, (u8)(addr & 0xff)); | ||
| 161 | |||
| 162 | tmp = rreg_crt(cirrus, 0x1b); | ||
| 163 | tmp &= 0xf2; | ||
| 164 | tmp |= (addr >> 16) & 0x01; | ||
| 165 | tmp |= (addr >> 15) & 0x0c; | ||
| 166 | wreg_crt(cirrus, 0x1b, tmp); | ||
| 167 | |||
| 168 | tmp = rreg_crt(cirrus, 0x1d); | ||
| 169 | tmp &= 0x7f; | ||
| 170 | tmp |= (addr >> 12) & 0x80; | ||
| 171 | wreg_crt(cirrus, 0x1d, tmp); | ||
| 172 | } | ||
| 173 | |||
| 174 | static int cirrus_mode_set(struct cirrus_device *cirrus, | ||
| 175 | struct drm_display_mode *mode, | ||
| 176 | struct drm_framebuffer *fb) | ||
| 177 | { | ||
| 178 | int hsyncstart, hsyncend, htotal, hdispend; | ||
| 179 | int vtotal, vdispend; | ||
| 180 | int tmp; | ||
| 181 | int sr07 = 0, hdr = 0; | ||
| 182 | |||
| 183 | htotal = mode->htotal / 8; | ||
| 184 | hsyncend = mode->hsync_end / 8; | ||
| 185 | hsyncstart = mode->hsync_start / 8; | ||
| 186 | hdispend = mode->hdisplay / 8; | ||
| 187 | |||
| 188 | vtotal = mode->vtotal; | ||
| 189 | vdispend = mode->vdisplay; | ||
| 190 | |||
| 191 | vdispend -= 1; | ||
| 192 | vtotal -= 2; | ||
| 193 | |||
| 194 | htotal -= 5; | ||
| 195 | hdispend -= 1; | ||
| 196 | hsyncstart += 1; | ||
| 197 | hsyncend += 1; | ||
| 198 | |||
| 199 | wreg_crt(cirrus, VGA_CRTC_V_SYNC_END, 0x20); | ||
| 200 | wreg_crt(cirrus, VGA_CRTC_H_TOTAL, htotal); | ||
| 201 | wreg_crt(cirrus, VGA_CRTC_H_DISP, hdispend); | ||
| 202 | wreg_crt(cirrus, VGA_CRTC_H_SYNC_START, hsyncstart); | ||
| 203 | wreg_crt(cirrus, VGA_CRTC_H_SYNC_END, hsyncend); | ||
| 204 | wreg_crt(cirrus, VGA_CRTC_V_TOTAL, vtotal & 0xff); | ||
| 205 | wreg_crt(cirrus, VGA_CRTC_V_DISP_END, vdispend & 0xff); | ||
| 206 | |||
| 207 | tmp = 0x40; | ||
| 208 | if ((vdispend + 1) & 512) | ||
| 209 | tmp |= 0x20; | ||
| 210 | wreg_crt(cirrus, VGA_CRTC_MAX_SCAN, tmp); | ||
| 211 | |||
| 212 | /* | ||
| 213 | * Overflow bits for values that don't fit in the standard registers | ||
| 214 | */ | ||
| 215 | tmp = 0x10; | ||
| 216 | if (vtotal & 0x100) | ||
| 217 | tmp |= 0x01; | ||
| 218 | if (vdispend & 0x100) | ||
| 219 | tmp |= 0x02; | ||
| 220 | if ((vdispend + 1) & 0x100) | ||
| 221 | tmp |= 0x08; | ||
| 222 | if (vtotal & 0x200) | ||
| 223 | tmp |= 0x20; | ||
| 224 | if (vdispend & 0x200) | ||
| 225 | tmp |= 0x40; | ||
| 226 | wreg_crt(cirrus, VGA_CRTC_OVERFLOW, tmp); | ||
| 227 | |||
| 228 | tmp = 0; | ||
| 229 | |||
| 230 | /* More overflow bits */ | ||
| 231 | |||
| 232 | if ((htotal + 5) & 0x40) | ||
| 233 | tmp |= 0x10; | ||
| 234 | if ((htotal + 5) & 0x80) | ||
| 235 | tmp |= 0x20; | ||
| 236 | if (vtotal & 0x100) | ||
| 237 | tmp |= 0x40; | ||
| 238 | if (vtotal & 0x200) | ||
| 239 | tmp |= 0x80; | ||
| 240 | |||
| 241 | wreg_crt(cirrus, CL_CRT1A, tmp); | ||
| 242 | |||
| 243 | /* Disable Hercules/CGA compatibility */ | ||
| 244 | wreg_crt(cirrus, VGA_CRTC_MODE, 0x03); | ||
| 245 | |||
| 246 | sr07 = rreg_seq(cirrus, 0x07); | ||
| 247 | sr07 &= 0xe0; | ||
| 248 | hdr = 0; | ||
| 249 | |||
| 250 | cirrus->cpp = cirrus_cpp(fb); | ||
| 251 | switch (cirrus->cpp * 8) { | ||
| 252 | case 8: | ||
| 253 | sr07 |= 0x11; | ||
| 254 | break; | ||
| 255 | case 16: | ||
| 256 | sr07 |= 0x17; | ||
| 257 | hdr = 0xc1; | ||
| 258 | break; | ||
| 259 | case 24: | ||
| 260 | sr07 |= 0x15; | ||
| 261 | hdr = 0xc5; | ||
| 262 | break; | ||
| 263 | case 32: | ||
| 264 | sr07 |= 0x19; | ||
| 265 | hdr = 0xc5; | ||
| 266 | break; | ||
| 267 | default: | ||
| 268 | return -1; | ||
| 269 | } | ||
| 270 | |||
| 271 | wreg_seq(cirrus, 0x7, sr07); | ||
| 272 | |||
| 273 | /* Program the pitch */ | ||
| 274 | cirrus->pitch = cirrus_pitch(fb); | ||
| 275 | tmp = cirrus->pitch / 8; | ||
| 276 | wreg_crt(cirrus, VGA_CRTC_OFFSET, tmp); | ||
| 277 | |||
| 278 | /* Enable extended blanking and pitch bits, and enable full memory */ | ||
| 279 | tmp = 0x22; | ||
| 280 | tmp |= (cirrus->pitch >> 7) & 0x10; | ||
| 281 | tmp |= (cirrus->pitch >> 6) & 0x40; | ||
| 282 | wreg_crt(cirrus, 0x1b, tmp); | ||
| 283 | |||
| 284 | /* Enable high-colour modes */ | ||
| 285 | wreg_gfx(cirrus, VGA_GFX_MODE, 0x40); | ||
| 286 | |||
| 287 | /* And set graphics mode */ | ||
| 288 | wreg_gfx(cirrus, VGA_GFX_MISC, 0x01); | ||
| 289 | |||
| 290 | wreg_hdr(cirrus, hdr); | ||
| 291 | |||
| 292 | cirrus_set_start_address(cirrus, 0); | ||
| 293 | |||
| 294 | /* Unblank (needed on S3 resume, vgabios doesn't do it then) */ | ||
| 295 | outb(0x20, 0x3c0); | ||
| 296 | return 0; | ||
| 297 | } | ||
| 298 | |||
| 299 | static int cirrus_fb_blit_rect(struct drm_framebuffer *fb, | ||
| 300 | struct drm_rect *rect) | ||
| 301 | { | ||
| 302 | struct cirrus_device *cirrus = fb->dev->dev_private; | ||
| 303 | void *vmap; | ||
| 304 | |||
| 305 | vmap = drm_gem_shmem_vmap(fb->obj[0]); | ||
| 306 | if (!vmap) | ||
| 307 | return -ENOMEM; | ||
| 308 | |||
| 309 | if (cirrus->cpp == fb->format->cpp[0]) | ||
| 310 | drm_fb_memcpy_dstclip(__io_virt(cirrus->vram), | ||
| 311 | vmap, fb, rect); | ||
| 312 | |||
| 313 | else if (fb->format->cpp[0] == 4 && cirrus->cpp == 2) | ||
| 314 | drm_fb_xrgb8888_to_rgb565_dstclip(__io_virt(cirrus->vram), | ||
| 315 | cirrus->pitch, | ||
| 316 | vmap, fb, rect, false); | ||
| 317 | |||
| 318 | else if (fb->format->cpp[0] == 4 && cirrus->cpp == 3) | ||
| 319 | drm_fb_xrgb8888_to_rgb888_dstclip(__io_virt(cirrus->vram), | ||
| 320 | cirrus->pitch, | ||
| 321 | vmap, fb, rect); | ||
| 322 | |||
| 323 | else | ||
| 324 | WARN_ON_ONCE("cpp mismatch"); | ||
| 325 | |||
| 326 | drm_gem_shmem_vunmap(fb->obj[0], vmap); | ||
| 327 | return 0; | ||
| 328 | } | ||
| 329 | |||
| 330 | static int cirrus_fb_blit_fullscreen(struct drm_framebuffer *fb) | ||
| 331 | { | ||
| 332 | struct drm_rect fullscreen = { | ||
| 333 | .x1 = 0, | ||
| 334 | .x2 = fb->width, | ||
| 335 | .y1 = 0, | ||
| 336 | .y2 = fb->height, | ||
| 337 | }; | ||
| 338 | return cirrus_fb_blit_rect(fb, &fullscreen); | ||
| 339 | } | ||
| 340 | |||
| 341 | static int cirrus_check_size(int width, int height, | ||
| 342 | struct drm_framebuffer *fb) | ||
| 343 | { | ||
| 344 | int pitch = width * 2; | ||
| 345 | |||
| 346 | if (fb) | ||
| 347 | pitch = cirrus_pitch(fb); | ||
| 348 | |||
| 349 | if (pitch > CIRRUS_MAX_PITCH) | ||
| 350 | return -EINVAL; | ||
| 351 | if (pitch * height > CIRRUS_VRAM_SIZE) | ||
| 352 | return -EINVAL; | ||
| 353 | return 0; | ||
| 354 | } | ||
| 355 | |||
| 356 | /* ------------------------------------------------------------------ */ | ||
| 357 | /* cirrus connector */ | ||
| 358 | |||
| 359 | static int cirrus_conn_get_modes(struct drm_connector *conn) | ||
| 360 | { | ||
| 361 | int count; | ||
| 362 | |||
| 363 | count = drm_add_modes_noedid(conn, | ||
| 364 | conn->dev->mode_config.max_width, | ||
| 365 | conn->dev->mode_config.max_height); | ||
| 366 | drm_set_preferred_mode(conn, 1024, 768); | ||
| 367 | return count; | ||
| 368 | } | ||
| 369 | |||
| 370 | static const struct drm_connector_helper_funcs cirrus_conn_helper_funcs = { | ||
| 371 | .get_modes = cirrus_conn_get_modes, | ||
| 372 | }; | ||
| 373 | |||
| 374 | static const struct drm_connector_funcs cirrus_conn_funcs = { | ||
| 375 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
| 376 | .destroy = drm_connector_cleanup, | ||
| 377 | .reset = drm_atomic_helper_connector_reset, | ||
| 378 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | ||
| 379 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | ||
| 380 | }; | ||
| 381 | |||
| 382 | static int cirrus_conn_init(struct cirrus_device *cirrus) | ||
| 383 | { | ||
| 384 | drm_connector_helper_add(&cirrus->conn, &cirrus_conn_helper_funcs); | ||
| 385 | return drm_connector_init(&cirrus->dev, &cirrus->conn, | ||
| 386 | &cirrus_conn_funcs, DRM_MODE_CONNECTOR_VGA); | ||
| 387 | |||
| 388 | } | ||
| 389 | |||
| 390 | /* ------------------------------------------------------------------ */ | ||
| 391 | /* cirrus (simple) display pipe */ | ||
| 392 | |||
| 393 | static enum drm_mode_status cirrus_pipe_mode_valid(struct drm_crtc *crtc, | ||
| 394 | const struct drm_display_mode *mode) | ||
| 395 | { | ||
| 396 | if (cirrus_check_size(mode->hdisplay, mode->vdisplay, NULL) < 0) | ||
| 397 | return MODE_BAD; | ||
| 398 | return MODE_OK; | ||
| 399 | } | ||
| 400 | |||
| 401 | static int cirrus_pipe_check(struct drm_simple_display_pipe *pipe, | ||
| 402 | struct drm_plane_state *plane_state, | ||
| 403 | struct drm_crtc_state *crtc_state) | ||
| 404 | { | ||
| 405 | struct drm_framebuffer *fb = plane_state->fb; | ||
| 406 | |||
| 407 | if (!fb) | ||
| 408 | return 0; | ||
| 409 | return cirrus_check_size(fb->width, fb->height, fb); | ||
| 410 | } | ||
| 411 | |||
| 412 | static void cirrus_pipe_enable(struct drm_simple_display_pipe *pipe, | ||
| 413 | struct drm_crtc_state *crtc_state, | ||
| 414 | struct drm_plane_state *plane_state) | ||
| 415 | { | ||
| 416 | struct cirrus_device *cirrus = pipe->crtc.dev->dev_private; | ||
| 417 | |||
| 418 | cirrus_mode_set(cirrus, &crtc_state->mode, plane_state->fb); | ||
| 419 | cirrus_fb_blit_fullscreen(plane_state->fb); | ||
| 420 | } | ||
| 421 | |||
| 422 | static void cirrus_pipe_update(struct drm_simple_display_pipe *pipe, | ||
| 423 | struct drm_plane_state *old_state) | ||
| 424 | { | ||
| 425 | struct cirrus_device *cirrus = pipe->crtc.dev->dev_private; | ||
| 426 | struct drm_plane_state *state = pipe->plane.state; | ||
| 427 | struct drm_crtc *crtc = &pipe->crtc; | ||
| 428 | struct drm_rect rect; | ||
| 429 | |||
| 430 | if (pipe->plane.state->fb && | ||
| 431 | cirrus->cpp != cirrus_cpp(pipe->plane.state->fb)) | ||
| 432 | cirrus_mode_set(cirrus, &crtc->mode, | ||
| 433 | pipe->plane.state->fb); | ||
| 434 | |||
| 435 | if (drm_atomic_helper_damage_merged(old_state, state, &rect)) | ||
| 436 | cirrus_fb_blit_rect(pipe->plane.state->fb, &rect); | ||
| 437 | |||
| 438 | if (crtc->state->event) { | ||
| 439 | spin_lock_irq(&crtc->dev->event_lock); | ||
| 440 | drm_crtc_send_vblank_event(crtc, crtc->state->event); | ||
| 441 | crtc->state->event = NULL; | ||
| 442 | spin_unlock_irq(&crtc->dev->event_lock); | ||
| 443 | } | ||
| 444 | } | ||
| 445 | |||
| 446 | static const struct drm_simple_display_pipe_funcs cirrus_pipe_funcs = { | ||
| 447 | .mode_valid = cirrus_pipe_mode_valid, | ||
| 448 | .check = cirrus_pipe_check, | ||
| 449 | .enable = cirrus_pipe_enable, | ||
| 450 | .update = cirrus_pipe_update, | ||
| 451 | }; | ||
| 452 | |||
| 453 | static const uint32_t cirrus_formats[] = { | ||
| 454 | DRM_FORMAT_RGB565, | ||
| 455 | DRM_FORMAT_RGB888, | ||
| 456 | DRM_FORMAT_XRGB8888, | ||
| 457 | }; | ||
| 458 | |||
| 459 | static const uint64_t cirrus_modifiers[] = { | ||
| 460 | DRM_FORMAT_MOD_LINEAR, | ||
| 461 | DRM_FORMAT_MOD_INVALID | ||
| 462 | }; | ||
| 463 | |||
| 464 | static int cirrus_pipe_init(struct cirrus_device *cirrus) | ||
| 465 | { | ||
| 466 | return drm_simple_display_pipe_init(&cirrus->dev, | ||
| 467 | &cirrus->pipe, | ||
| 468 | &cirrus_pipe_funcs, | ||
| 469 | cirrus_formats, | ||
| 470 | ARRAY_SIZE(cirrus_formats), | ||
| 471 | cirrus_modifiers, | ||
| 472 | &cirrus->conn); | ||
| 473 | } | ||
| 474 | |||
| 475 | /* ------------------------------------------------------------------ */ | ||
| 476 | /* cirrus framebuffers & mode config */ | ||
| 477 | |||
| 478 | static struct drm_framebuffer* | ||
| 479 | cirrus_fb_create(struct drm_device *dev, struct drm_file *file_priv, | ||
| 480 | const struct drm_mode_fb_cmd2 *mode_cmd) | ||
| 481 | { | ||
| 482 | if (mode_cmd->pixel_format != DRM_FORMAT_RGB565 && | ||
| 483 | mode_cmd->pixel_format != DRM_FORMAT_RGB888 && | ||
| 484 | mode_cmd->pixel_format != DRM_FORMAT_XRGB8888) | ||
| 485 | return ERR_PTR(-EINVAL); | ||
| 486 | if (cirrus_check_size(mode_cmd->width, mode_cmd->height, NULL) < 0) | ||
| 487 | return ERR_PTR(-EINVAL); | ||
| 488 | return drm_gem_fb_create_with_dirty(dev, file_priv, mode_cmd); | ||
| 489 | } | ||
| 490 | |||
| 491 | static const struct drm_mode_config_funcs cirrus_mode_config_funcs = { | ||
| 492 | .fb_create = cirrus_fb_create, | ||
| 493 | .atomic_check = drm_atomic_helper_check, | ||
| 494 | .atomic_commit = drm_atomic_helper_commit, | ||
| 495 | }; | ||
| 496 | |||
| 497 | static void cirrus_mode_config_init(struct cirrus_device *cirrus) | ||
| 498 | { | ||
| 499 | struct drm_device *dev = &cirrus->dev; | ||
| 500 | |||
| 501 | drm_mode_config_init(dev); | ||
| 502 | dev->mode_config.min_width = 0; | ||
| 503 | dev->mode_config.min_height = 0; | ||
| 504 | dev->mode_config.max_width = CIRRUS_MAX_PITCH / 2; | ||
| 505 | dev->mode_config.max_height = 1024; | ||
| 506 | dev->mode_config.preferred_depth = 16; | ||
| 507 | dev->mode_config.prefer_shadow = 0; | ||
| 508 | dev->mode_config.funcs = &cirrus_mode_config_funcs; | ||
| 509 | } | ||
| 510 | |||
| 511 | /* ------------------------------------------------------------------ */ | ||
| 512 | |||
| 513 | DEFINE_DRM_GEM_SHMEM_FOPS(cirrus_fops); | ||
| 514 | |||
| 515 | static struct drm_driver cirrus_driver = { | ||
| 516 | .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC | DRIVER_PRIME, | ||
| 517 | |||
| 518 | .name = DRIVER_NAME, | ||
| 519 | .desc = DRIVER_DESC, | ||
| 520 | .date = DRIVER_DATE, | ||
| 521 | .major = DRIVER_MAJOR, | ||
| 522 | .minor = DRIVER_MINOR, | ||
| 523 | |||
| 524 | .fops = &cirrus_fops, | ||
| 525 | DRM_GEM_SHMEM_DRIVER_OPS, | ||
| 526 | }; | ||
| 527 | |||
| 528 | static int cirrus_pci_probe(struct pci_dev *pdev, | ||
| 529 | const struct pci_device_id *ent) | ||
| 530 | { | ||
| 531 | struct drm_device *dev; | ||
| 532 | struct cirrus_device *cirrus; | ||
| 533 | int ret; | ||
| 534 | |||
| 535 | ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "cirrusdrmfb"); | ||
| 536 | if (ret) | ||
| 537 | return ret; | ||
| 538 | |||
| 539 | ret = pci_enable_device(pdev); | ||
| 540 | if (ret) | ||
| 541 | return ret; | ||
| 542 | |||
| 543 | ret = pci_request_regions(pdev, DRIVER_NAME); | ||
| 544 | if (ret) | ||
| 545 | return ret; | ||
| 546 | |||
| 547 | ret = -ENOMEM; | ||
| 548 | cirrus = kzalloc(sizeof(*cirrus), GFP_KERNEL); | ||
| 549 | if (cirrus == NULL) | ||
| 550 | goto err_pci_release; | ||
| 551 | |||
| 552 | dev = &cirrus->dev; | ||
| 553 | ret = drm_dev_init(dev, &cirrus_driver, &pdev->dev); | ||
| 554 | if (ret) | ||
| 555 | goto err_free_cirrus; | ||
| 556 | dev->dev_private = cirrus; | ||
| 557 | |||
| 558 | ret = -ENOMEM; | ||
| 559 | cirrus->vram = ioremap(pci_resource_start(pdev, 0), | ||
| 560 | pci_resource_len(pdev, 0)); | ||
| 561 | if (cirrus->vram == NULL) | ||
| 562 | goto err_dev_put; | ||
| 563 | |||
| 564 | cirrus->mmio = ioremap(pci_resource_start(pdev, 1), | ||
| 565 | pci_resource_len(pdev, 1)); | ||
| 566 | if (cirrus->mmio == NULL) | ||
| 567 | goto err_unmap_vram; | ||
| 568 | |||
| 569 | cirrus_mode_config_init(cirrus); | ||
| 570 | |||
| 571 | ret = cirrus_conn_init(cirrus); | ||
| 572 | if (ret < 0) | ||
| 573 | goto err_cleanup; | ||
| 574 | |||
| 575 | ret = cirrus_pipe_init(cirrus); | ||
| 576 | if (ret < 0) | ||
| 577 | goto err_cleanup; | ||
| 578 | |||
| 579 | drm_mode_config_reset(dev); | ||
| 580 | |||
| 581 | dev->pdev = pdev; | ||
| 582 | pci_set_drvdata(pdev, dev); | ||
| 583 | ret = drm_dev_register(dev, 0); | ||
| 584 | if (ret) | ||
| 585 | goto err_cleanup; | ||
| 586 | |||
| 587 | drm_fbdev_generic_setup(dev, dev->mode_config.preferred_depth); | ||
| 588 | return 0; | ||
| 589 | |||
| 590 | err_cleanup: | ||
| 591 | drm_mode_config_cleanup(dev); | ||
| 592 | iounmap(cirrus->mmio); | ||
| 593 | err_unmap_vram: | ||
| 594 | iounmap(cirrus->vram); | ||
| 595 | err_dev_put: | ||
| 596 | drm_dev_put(dev); | ||
| 597 | err_free_cirrus: | ||
| 598 | kfree(cirrus); | ||
| 599 | err_pci_release: | ||
| 600 | pci_release_regions(pdev); | ||
| 601 | return ret; | ||
| 602 | } | ||
| 603 | |||
| 604 | static void cirrus_pci_remove(struct pci_dev *pdev) | ||
| 605 | { | ||
| 606 | struct drm_device *dev = pci_get_drvdata(pdev); | ||
| 607 | struct cirrus_device *cirrus = dev->dev_private; | ||
| 608 | |||
| 609 | drm_dev_unregister(dev); | ||
| 610 | drm_mode_config_cleanup(dev); | ||
| 611 | iounmap(cirrus->mmio); | ||
| 612 | iounmap(cirrus->vram); | ||
| 613 | drm_dev_put(dev); | ||
| 614 | kfree(cirrus); | ||
| 615 | pci_release_regions(pdev); | ||
| 616 | } | ||
| 617 | |||
| 618 | static const struct pci_device_id pciidlist[] = { | ||
| 619 | { | ||
| 620 | .vendor = PCI_VENDOR_ID_CIRRUS, | ||
| 621 | .device = PCI_DEVICE_ID_CIRRUS_5446, | ||
| 622 | /* only bind to the cirrus chip in qemu */ | ||
| 623 | .subvendor = PCI_SUBVENDOR_ID_REDHAT_QUMRANET, | ||
| 624 | .subdevice = PCI_SUBDEVICE_ID_QEMU, | ||
| 625 | }, { | ||
| 626 | .vendor = PCI_VENDOR_ID_CIRRUS, | ||
| 627 | .device = PCI_DEVICE_ID_CIRRUS_5446, | ||
| 628 | .subvendor = PCI_VENDOR_ID_XEN, | ||
| 629 | .subdevice = 0x0001, | ||
| 630 | }, | ||
| 631 | { /* end if list */ } | ||
| 632 | }; | ||
| 633 | |||
| 634 | static struct pci_driver cirrus_pci_driver = { | ||
| 635 | .name = DRIVER_NAME, | ||
| 636 | .id_table = pciidlist, | ||
| 637 | .probe = cirrus_pci_probe, | ||
| 638 | .remove = cirrus_pci_remove, | ||
| 639 | }; | ||
| 640 | |||
| 641 | static int __init cirrus_init(void) | ||
| 642 | { | ||
| 643 | if (vgacon_text_force()) | ||
| 644 | return -EINVAL; | ||
| 645 | return pci_register_driver(&cirrus_pci_driver); | ||
| 646 | } | ||
| 647 | |||
| 648 | static void __exit cirrus_exit(void) | ||
| 649 | { | ||
| 650 | pci_unregister_driver(&cirrus_pci_driver); | ||
| 651 | } | ||
| 652 | |||
| 653 | module_init(cirrus_init); | ||
| 654 | module_exit(cirrus_exit); | ||
| 655 | |||
| 656 | MODULE_DEVICE_TABLE(pci, pciidlist); | ||
| 657 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.c b/drivers/gpu/drm/cirrus/cirrus_drv.c deleted file mode 100644 index 8ec880f3a322..000000000000 --- a/drivers/gpu/drm/cirrus/cirrus_drv.c +++ /dev/null | |||
| @@ -1,161 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2012 Red Hat <mjg@redhat.com> | ||
| 3 | * | ||
| 4 | * This file is subject to the terms and conditions of the GNU General | ||
| 5 | * Public License version 2. See the file COPYING in the main | ||
| 6 | * directory of this archive for more details. | ||
| 7 | * | ||
| 8 | * Authors: Matthew Garrett | ||
| 9 | * Dave Airlie | ||
| 10 | */ | ||
| 11 | #include <linux/module.h> | ||
| 12 | #include <linux/console.h> | ||
| 13 | #include <drm/drmP.h> | ||
| 14 | #include <drm/drm_crtc_helper.h> | ||
| 15 | #include <drm/drm_probe_helper.h> | ||
| 16 | |||
| 17 | #include "cirrus_drv.h" | ||
| 18 | |||
| 19 | int cirrus_modeset = -1; | ||
| 20 | int cirrus_bpp = 16; | ||
| 21 | |||
| 22 | MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); | ||
| 23 | module_param_named(modeset, cirrus_modeset, int, 0400); | ||
| 24 | MODULE_PARM_DESC(bpp, "Max bits-per-pixel (default:16)"); | ||
| 25 | module_param_named(bpp, cirrus_bpp, int, 0400); | ||
| 26 | |||
| 27 | /* | ||
| 28 | * This is the generic driver code. This binds the driver to the drm core, | ||
| 29 | * which then performs further device association and calls our graphics init | ||
| 30 | * functions | ||
| 31 | */ | ||
| 32 | |||
| 33 | static struct drm_driver driver; | ||
| 34 | |||
| 35 | /* only bind to the cirrus chip in qemu */ | ||
| 36 | static const struct pci_device_id pciidlist[] = { | ||
| 37 | { PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5446, | ||
| 38 | PCI_SUBVENDOR_ID_REDHAT_QUMRANET, PCI_SUBDEVICE_ID_QEMU, | ||
| 39 | 0, 0, 0 }, | ||
| 40 | { PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5446, PCI_VENDOR_ID_XEN, | ||
| 41 | 0x0001, 0, 0, 0 }, | ||
| 42 | {0,} | ||
| 43 | }; | ||
| 44 | |||
| 45 | |||
| 46 | static int cirrus_pci_probe(struct pci_dev *pdev, | ||
| 47 | const struct pci_device_id *ent) | ||
| 48 | { | ||
| 49 | int ret; | ||
| 50 | |||
| 51 | ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "cirrusdrmfb"); | ||
| 52 | if (ret) | ||
| 53 | return ret; | ||
| 54 | |||
| 55 | return drm_get_pci_dev(pdev, ent, &driver); | ||
| 56 | } | ||
| 57 | |||
| 58 | static void cirrus_pci_remove(struct pci_dev *pdev) | ||
| 59 | { | ||
| 60 | struct drm_device *dev = pci_get_drvdata(pdev); | ||
| 61 | |||
| 62 | drm_put_dev(dev); | ||
| 63 | } | ||
| 64 | |||
| 65 | #ifdef CONFIG_PM_SLEEP | ||
| 66 | static int cirrus_pm_suspend(struct device *dev) | ||
| 67 | { | ||
| 68 | struct pci_dev *pdev = to_pci_dev(dev); | ||
| 69 | struct drm_device *drm_dev = pci_get_drvdata(pdev); | ||
| 70 | struct cirrus_device *cdev = drm_dev->dev_private; | ||
| 71 | |||
| 72 | drm_kms_helper_poll_disable(drm_dev); | ||
| 73 | |||
| 74 | if (cdev->mode_info.gfbdev) { | ||
| 75 | console_lock(); | ||
| 76 | drm_fb_helper_set_suspend(&cdev->mode_info.gfbdev->helper, 1); | ||
| 77 | console_unlock(); | ||
| 78 | } | ||
| 79 | |||
| 80 | return 0; | ||
| 81 | } | ||
| 82 | |||
| 83 | static int cirrus_pm_resume(struct device *dev) | ||
| 84 | { | ||
| 85 | struct pci_dev *pdev = to_pci_dev(dev); | ||
| 86 | struct drm_device *drm_dev = pci_get_drvdata(pdev); | ||
| 87 | struct cirrus_device *cdev = drm_dev->dev_private; | ||
| 88 | |||
| 89 | drm_helper_resume_force_mode(drm_dev); | ||
| 90 | |||
| 91 | if (cdev->mode_info.gfbdev) { | ||
| 92 | console_lock(); | ||
| 93 | drm_fb_helper_set_suspend(&cdev->mode_info.gfbdev->helper, 0); | ||
| 94 | console_unlock(); | ||
| 95 | } | ||
| 96 | |||
| 97 | drm_kms_helper_poll_enable(drm_dev); | ||
| 98 | return 0; | ||
| 99 | } | ||
| 100 | #endif | ||
| 101 | |||
| 102 | static const struct file_operations cirrus_driver_fops = { | ||
| 103 | .owner = THIS_MODULE, | ||
| 104 | .open = drm_open, | ||
| 105 | .release = drm_release, | ||
| 106 | .unlocked_ioctl = drm_ioctl, | ||
| 107 | .mmap = cirrus_mmap, | ||
| 108 | .poll = drm_poll, | ||
| 109 | .compat_ioctl = drm_compat_ioctl, | ||
| 110 | }; | ||
| 111 | static struct drm_driver driver = { | ||
| 112 | .driver_features = DRIVER_MODESET | DRIVER_GEM, | ||
| 113 | .load = cirrus_driver_load, | ||
| 114 | .unload = cirrus_driver_unload, | ||
| 115 | .fops = &cirrus_driver_fops, | ||
| 116 | .name = DRIVER_NAME, | ||
| 117 | .desc = DRIVER_DESC, | ||
| 118 | .date = DRIVER_DATE, | ||
| 119 | .major = DRIVER_MAJOR, | ||
| 120 | .minor = DRIVER_MINOR, | ||
| 121 | .patchlevel = DRIVER_PATCHLEVEL, | ||
| 122 | .gem_free_object_unlocked = cirrus_gem_free_object, | ||
| 123 | .dumb_create = cirrus_dumb_create, | ||
| 124 | .dumb_map_offset = cirrus_dumb_mmap_offset, | ||
| 125 | }; | ||
| 126 | |||
| 127 | static const struct dev_pm_ops cirrus_pm_ops = { | ||
| 128 | SET_SYSTEM_SLEEP_PM_OPS(cirrus_pm_suspend, | ||
| 129 | cirrus_pm_resume) | ||
| 130 | }; | ||
| 131 | |||
| 132 | static struct pci_driver cirrus_pci_driver = { | ||
| 133 | .name = DRIVER_NAME, | ||
| 134 | .id_table = pciidlist, | ||
| 135 | .probe = cirrus_pci_probe, | ||
| 136 | .remove = cirrus_pci_remove, | ||
| 137 | .driver.pm = &cirrus_pm_ops, | ||
| 138 | }; | ||
| 139 | |||
| 140 | static int __init cirrus_init(void) | ||
| 141 | { | ||
| 142 | if (vgacon_text_force() && cirrus_modeset == -1) | ||
| 143 | return -EINVAL; | ||
| 144 | |||
| 145 | if (cirrus_modeset == 0) | ||
| 146 | return -EINVAL; | ||
| 147 | return pci_register_driver(&cirrus_pci_driver); | ||
| 148 | } | ||
| 149 | |||
| 150 | static void __exit cirrus_exit(void) | ||
| 151 | { | ||
| 152 | pci_unregister_driver(&cirrus_pci_driver); | ||
| 153 | } | ||
| 154 | |||
| 155 | module_init(cirrus_init); | ||
| 156 | module_exit(cirrus_exit); | ||
| 157 | |||
| 158 | MODULE_DEVICE_TABLE(pci, pciidlist); | ||
| 159 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
| 160 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 161 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c deleted file mode 100644 index 2e6128069fc3..000000000000 --- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c +++ /dev/null | |||
| @@ -1,309 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2012 Red Hat | ||
| 3 | * | ||
| 4 | * This file is subject to the terms and conditions of the GNU General | ||
| 5 | * Public License version 2. See the file COPYING in the main | ||
| 6 | * directory of this archive for more details. | ||
| 7 | * | ||
| 8 | * Authors: Matthew Garrett | ||
| 9 | * Dave Airlie | ||
| 10 | */ | ||
| 11 | #include <linux/module.h> | ||
| 12 | #include <drm/drmP.h> | ||
| 13 | #include <drm/drm_util.h> | ||
| 14 | #include <drm/drm_fb_helper.h> | ||
| 15 | #include <drm/drm_crtc_helper.h> | ||
| 16 | |||
| 17 | #include "cirrus_drv.h" | ||
| 18 | |||
| 19 | static void cirrus_dirty_update(struct cirrus_fbdev *afbdev, | ||
| 20 | int x, int y, int width, int height) | ||
| 21 | { | ||
| 22 | int i; | ||
| 23 | struct drm_gem_object *obj; | ||
| 24 | struct cirrus_bo *bo; | ||
| 25 | int src_offset, dst_offset; | ||
| 26 | int bpp = afbdev->gfb->format->cpp[0]; | ||
| 27 | int ret = -EBUSY; | ||
| 28 | bool unmap = false; | ||
| 29 | bool store_for_later = false; | ||
| 30 | int x2, y2; | ||
| 31 | unsigned long flags; | ||
| 32 | |||
| 33 | obj = afbdev->gfb->obj[0]; | ||
| 34 | bo = gem_to_cirrus_bo(obj); | ||
| 35 | |||
| 36 | /* | ||
| 37 | * try and reserve the BO, if we fail with busy | ||
| 38 | * then the BO is being moved and we should | ||
| 39 | * store up the damage until later. | ||
| 40 | */ | ||
| 41 | if (drm_can_sleep()) | ||
| 42 | ret = cirrus_bo_reserve(bo, true); | ||
| 43 | if (ret) { | ||
| 44 | if (ret != -EBUSY) | ||
| 45 | return; | ||
| 46 | store_for_later = true; | ||
| 47 | } | ||
| 48 | |||
| 49 | x2 = x + width - 1; | ||
| 50 | y2 = y + height - 1; | ||
| 51 | spin_lock_irqsave(&afbdev->dirty_lock, flags); | ||
| 52 | |||
| 53 | if (afbdev->y1 < y) | ||
| 54 | y = afbdev->y1; | ||
| 55 | if (afbdev->y2 > y2) | ||
| 56 | y2 = afbdev->y2; | ||
| 57 | if (afbdev->x1 < x) | ||
| 58 | x = afbdev->x1; | ||
| 59 | if (afbdev->x2 > x2) | ||
| 60 | x2 = afbdev->x2; | ||
| 61 | |||
| 62 | if (store_for_later) { | ||
| 63 | afbdev->x1 = x; | ||
| 64 | afbdev->x2 = x2; | ||
| 65 | afbdev->y1 = y; | ||
| 66 | afbdev->y2 = y2; | ||
| 67 | spin_unlock_irqrestore(&afbdev->dirty_lock, flags); | ||
| 68 | return; | ||
| 69 | } | ||
| 70 | |||
| 71 | afbdev->x1 = afbdev->y1 = INT_MAX; | ||
| 72 | afbdev->x2 = afbdev->y2 = 0; | ||
| 73 | spin_unlock_irqrestore(&afbdev->dirty_lock, flags); | ||
| 74 | |||
| 75 | if (!bo->kmap.virtual) { | ||
| 76 | ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); | ||
| 77 | if (ret) { | ||
| 78 | DRM_ERROR("failed to kmap fb updates\n"); | ||
| 79 | cirrus_bo_unreserve(bo); | ||
| 80 | return; | ||
| 81 | } | ||
| 82 | unmap = true; | ||
| 83 | } | ||
| 84 | for (i = y; i < y + height; i++) { | ||
| 85 | /* assume equal stride for now */ | ||
| 86 | src_offset = dst_offset = i * afbdev->gfb->pitches[0] + (x * bpp); | ||
| 87 | memcpy_toio(bo->kmap.virtual + src_offset, afbdev->sysram + src_offset, width * bpp); | ||
| 88 | |||
| 89 | } | ||
| 90 | if (unmap) | ||
| 91 | ttm_bo_kunmap(&bo->kmap); | ||
| 92 | |||
| 93 | cirrus_bo_unreserve(bo); | ||
| 94 | } | ||
| 95 | |||
| 96 | static void cirrus_fillrect(struct fb_info *info, | ||
| 97 | const struct fb_fillrect *rect) | ||
| 98 | { | ||
| 99 | struct cirrus_fbdev *afbdev = info->par; | ||
| 100 | drm_fb_helper_sys_fillrect(info, rect); | ||
| 101 | cirrus_dirty_update(afbdev, rect->dx, rect->dy, rect->width, | ||
| 102 | rect->height); | ||
| 103 | } | ||
| 104 | |||
| 105 | static void cirrus_copyarea(struct fb_info *info, | ||
| 106 | const struct fb_copyarea *area) | ||
| 107 | { | ||
| 108 | struct cirrus_fbdev *afbdev = info->par; | ||
| 109 | drm_fb_helper_sys_copyarea(info, area); | ||
| 110 | cirrus_dirty_update(afbdev, area->dx, area->dy, area->width, | ||
| 111 | area->height); | ||
| 112 | } | ||
| 113 | |||
| 114 | static void cirrus_imageblit(struct fb_info *info, | ||
| 115 | const struct fb_image *image) | ||
| 116 | { | ||
| 117 | struct cirrus_fbdev *afbdev = info->par; | ||
| 118 | drm_fb_helper_sys_imageblit(info, image); | ||
| 119 | cirrus_dirty_update(afbdev, image->dx, image->dy, image->width, | ||
| 120 | image->height); | ||
| 121 | } | ||
| 122 | |||
| 123 | |||
| 124 | static struct fb_ops cirrusfb_ops = { | ||
| 125 | .owner = THIS_MODULE, | ||
| 126 | .fb_check_var = drm_fb_helper_check_var, | ||
| 127 | .fb_set_par = drm_fb_helper_set_par, | ||
| 128 | .fb_fillrect = cirrus_fillrect, | ||
| 129 | .fb_copyarea = cirrus_copyarea, | ||
| 130 | .fb_imageblit = cirrus_imageblit, | ||
| 131 | .fb_pan_display = drm_fb_helper_pan_display, | ||
| 132 | .fb_blank = drm_fb_helper_blank, | ||
| 133 | .fb_setcmap = drm_fb_helper_setcmap, | ||
| 134 | }; | ||
| 135 | |||
| 136 | static int cirrusfb_create_object(struct cirrus_fbdev *afbdev, | ||
| 137 | const struct drm_mode_fb_cmd2 *mode_cmd, | ||
| 138 | struct drm_gem_object **gobj_p) | ||
| 139 | { | ||
| 140 | struct drm_device *dev = afbdev->helper.dev; | ||
| 141 | struct cirrus_device *cdev = dev->dev_private; | ||
| 142 | u32 bpp; | ||
| 143 | u32 size; | ||
| 144 | struct drm_gem_object *gobj; | ||
| 145 | int ret = 0; | ||
| 146 | |||
| 147 | bpp = drm_format_plane_cpp(mode_cmd->pixel_format, 0) * 8; | ||
| 148 | |||
| 149 | if (!cirrus_check_framebuffer(cdev, mode_cmd->width, mode_cmd->height, | ||
| 150 | bpp, mode_cmd->pitches[0])) | ||
| 151 | return -EINVAL; | ||
| 152 | |||
| 153 | size = mode_cmd->pitches[0] * mode_cmd->height; | ||
| 154 | ret = cirrus_gem_create(dev, size, true, &gobj); | ||
| 155 | if (ret) | ||
| 156 | return ret; | ||
| 157 | |||
| 158 | *gobj_p = gobj; | ||
| 159 | return ret; | ||
| 160 | } | ||
| 161 | |||
| 162 | static int cirrusfb_create(struct drm_fb_helper *helper, | ||
| 163 | struct drm_fb_helper_surface_size *sizes) | ||
| 164 | { | ||
| 165 | struct cirrus_fbdev *gfbdev = | ||
| 166 | container_of(helper, struct cirrus_fbdev, helper); | ||
| 167 | struct cirrus_device *cdev = gfbdev->helper.dev->dev_private; | ||
| 168 | struct fb_info *info; | ||
| 169 | struct drm_framebuffer *fb; | ||
| 170 | struct drm_mode_fb_cmd2 mode_cmd; | ||
| 171 | void *sysram; | ||
| 172 | struct drm_gem_object *gobj = NULL; | ||
| 173 | int size, ret; | ||
| 174 | |||
| 175 | mode_cmd.width = sizes->surface_width; | ||
| 176 | mode_cmd.height = sizes->surface_height; | ||
| 177 | mode_cmd.pitches[0] = mode_cmd.width * ((sizes->surface_bpp + 7) / 8); | ||
| 178 | mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, | ||
| 179 | sizes->surface_depth); | ||
| 180 | size = mode_cmd.pitches[0] * mode_cmd.height; | ||
| 181 | |||
| 182 | ret = cirrusfb_create_object(gfbdev, &mode_cmd, &gobj); | ||
| 183 | if (ret) { | ||
| 184 | DRM_ERROR("failed to create fbcon backing object %d\n", ret); | ||
| 185 | return ret; | ||
| 186 | } | ||
| 187 | |||
| 188 | sysram = vmalloc(size); | ||
| 189 | if (!sysram) | ||
| 190 | return -ENOMEM; | ||
| 191 | |||
| 192 | info = drm_fb_helper_alloc_fbi(helper); | ||
| 193 | if (IS_ERR(info)) { | ||
| 194 | ret = PTR_ERR(info); | ||
| 195 | goto err_vfree; | ||
| 196 | } | ||
| 197 | |||
| 198 | fb = kzalloc(sizeof(*fb), GFP_KERNEL); | ||
| 199 | if (!fb) { | ||
| 200 | ret = -ENOMEM; | ||
| 201 | goto err_drm_gem_object_put_unlocked; | ||
| 202 | } | ||
| 203 | |||
| 204 | ret = cirrus_framebuffer_init(cdev->dev, fb, &mode_cmd, gobj); | ||
| 205 | if (ret) | ||
| 206 | goto err_kfree; | ||
| 207 | |||
| 208 | gfbdev->sysram = sysram; | ||
| 209 | gfbdev->size = size; | ||
| 210 | gfbdev->gfb = fb; | ||
| 211 | |||
| 212 | /* setup helper */ | ||
| 213 | gfbdev->helper.fb = fb; | ||
| 214 | |||
| 215 | info->fbops = &cirrusfb_ops; | ||
| 216 | |||
| 217 | drm_fb_helper_fill_info(info, &gfbdev->helper, sizes); | ||
| 218 | |||
| 219 | /* setup aperture base/size for vesafb takeover */ | ||
| 220 | info->apertures->ranges[0].base = cdev->dev->mode_config.fb_base; | ||
| 221 | info->apertures->ranges[0].size = cdev->mc.vram_size; | ||
| 222 | |||
| 223 | info->fix.smem_start = cdev->dev->mode_config.fb_base; | ||
| 224 | info->fix.smem_len = cdev->mc.vram_size; | ||
| 225 | |||
| 226 | info->screen_base = sysram; | ||
| 227 | info->screen_size = size; | ||
| 228 | |||
| 229 | info->fix.mmio_start = 0; | ||
| 230 | info->fix.mmio_len = 0; | ||
| 231 | |||
| 232 | DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start); | ||
| 233 | DRM_INFO("vram aper at 0x%lX\n", (unsigned long)info->fix.smem_start); | ||
| 234 | DRM_INFO("size %lu\n", (unsigned long)info->fix.smem_len); | ||
| 235 | DRM_INFO("fb depth is %d\n", fb->format->depth); | ||
| 236 | DRM_INFO(" pitch is %d\n", fb->pitches[0]); | ||
| 237 | |||
| 238 | return 0; | ||
| 239 | |||
| 240 | err_kfree: | ||
| 241 | kfree(fb); | ||
| 242 | err_drm_gem_object_put_unlocked: | ||
| 243 | drm_gem_object_put_unlocked(gobj); | ||
| 244 | err_vfree: | ||
| 245 | vfree(sysram); | ||
| 246 | return ret; | ||
| 247 | } | ||
| 248 | |||
| 249 | static int cirrus_fbdev_destroy(struct drm_device *dev, | ||
| 250 | struct cirrus_fbdev *gfbdev) | ||
| 251 | { | ||
| 252 | struct drm_framebuffer *gfb = gfbdev->gfb; | ||
| 253 | |||
| 254 | drm_helper_force_disable_all(dev); | ||
| 255 | |||
| 256 | drm_fb_helper_unregister_fbi(&gfbdev->helper); | ||
| 257 | |||
| 258 | vfree(gfbdev->sysram); | ||
| 259 | drm_fb_helper_fini(&gfbdev->helper); | ||
| 260 | if (gfb) | ||
| 261 | drm_framebuffer_put(gfb); | ||
| 262 | |||
| 263 | return 0; | ||
| 264 | } | ||
| 265 | |||
| 266 | static const struct drm_fb_helper_funcs cirrus_fb_helper_funcs = { | ||
| 267 | .fb_probe = cirrusfb_create, | ||
| 268 | }; | ||
| 269 | |||
| 270 | int cirrus_fbdev_init(struct cirrus_device *cdev) | ||
| 271 | { | ||
| 272 | struct cirrus_fbdev *gfbdev; | ||
| 273 | int ret; | ||
| 274 | |||
| 275 | /*bpp_sel = 8;*/ | ||
| 276 | gfbdev = kzalloc(sizeof(struct cirrus_fbdev), GFP_KERNEL); | ||
| 277 | if (!gfbdev) | ||
| 278 | return -ENOMEM; | ||
| 279 | |||
| 280 | cdev->mode_info.gfbdev = gfbdev; | ||
| 281 | spin_lock_init(&gfbdev->dirty_lock); | ||
| 282 | |||
| 283 | drm_fb_helper_prepare(cdev->dev, &gfbdev->helper, | ||
| 284 | &cirrus_fb_helper_funcs); | ||
| 285 | |||
| 286 | ret = drm_fb_helper_init(cdev->dev, &gfbdev->helper, | ||
| 287 | CIRRUSFB_CONN_LIMIT); | ||
| 288 | if (ret) | ||
| 289 | return ret; | ||
| 290 | |||
| 291 | ret = drm_fb_helper_single_add_all_connectors(&gfbdev->helper); | ||
| 292 | if (ret) | ||
| 293 | return ret; | ||
| 294 | |||
| 295 | /* disable all the possible outputs/crtcs before entering KMS mode */ | ||
| 296 | drm_helper_disable_unused_functions(cdev->dev); | ||
| 297 | |||
| 298 | return drm_fb_helper_initial_config(&gfbdev->helper, cirrus_bpp); | ||
| 299 | } | ||
| 300 | |||
| 301 | void cirrus_fbdev_fini(struct cirrus_device *cdev) | ||
| 302 | { | ||
| 303 | if (!cdev->mode_info.gfbdev) | ||
| 304 | return; | ||
| 305 | |||
| 306 | cirrus_fbdev_destroy(cdev->dev, cdev->mode_info.gfbdev); | ||
| 307 | kfree(cdev->mode_info.gfbdev); | ||
| 308 | cdev->mode_info.gfbdev = NULL; | ||
| 309 | } | ||
diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c deleted file mode 100644 index 57f8fe6d020b..000000000000 --- a/drivers/gpu/drm/cirrus/cirrus_main.c +++ /dev/null | |||
| @@ -1,328 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2012 Red Hat | ||
| 3 | * | ||
| 4 | * This file is subject to the terms and conditions of the GNU General | ||
| 5 | * Public License version 2. See the file COPYING in the main | ||
| 6 | * directory of this archive for more details. | ||
| 7 | * | ||
| 8 | * Authors: Matthew Garrett | ||
| 9 | * Dave Airlie | ||
| 10 | */ | ||
| 11 | #include <drm/drmP.h> | ||
| 12 | #include <drm/drm_crtc_helper.h> | ||
| 13 | #include <drm/drm_gem_framebuffer_helper.h> | ||
| 14 | |||
| 15 | #include "cirrus_drv.h" | ||
| 16 | |||
| 17 | static const struct drm_framebuffer_funcs cirrus_fb_funcs = { | ||
| 18 | .create_handle = drm_gem_fb_create_handle, | ||
| 19 | .destroy = drm_gem_fb_destroy, | ||
| 20 | }; | ||
| 21 | |||
| 22 | int cirrus_framebuffer_init(struct drm_device *dev, | ||
| 23 | struct drm_framebuffer *gfb, | ||
| 24 | const struct drm_mode_fb_cmd2 *mode_cmd, | ||
| 25 | struct drm_gem_object *obj) | ||
| 26 | { | ||
| 27 | int ret; | ||
| 28 | |||
| 29 | drm_helper_mode_fill_fb_struct(dev, gfb, mode_cmd); | ||
| 30 | gfb->obj[0] = obj; | ||
| 31 | ret = drm_framebuffer_init(dev, gfb, &cirrus_fb_funcs); | ||
| 32 | if (ret) { | ||
| 33 | DRM_ERROR("drm_framebuffer_init failed: %d\n", ret); | ||
| 34 | return ret; | ||
| 35 | } | ||
| 36 | return 0; | ||
| 37 | } | ||
| 38 | |||
| 39 | static struct drm_framebuffer * | ||
| 40 | cirrus_user_framebuffer_create(struct drm_device *dev, | ||
| 41 | struct drm_file *filp, | ||
| 42 | const struct drm_mode_fb_cmd2 *mode_cmd) | ||
| 43 | { | ||
| 44 | struct cirrus_device *cdev = dev->dev_private; | ||
| 45 | struct drm_gem_object *obj; | ||
| 46 | struct drm_framebuffer *fb; | ||
| 47 | u32 bpp; | ||
| 48 | int ret; | ||
| 49 | |||
| 50 | bpp = drm_format_plane_cpp(mode_cmd->pixel_format, 0) * 8; | ||
| 51 | |||
| 52 | if (!cirrus_check_framebuffer(cdev, mode_cmd->width, mode_cmd->height, | ||
| 53 | bpp, mode_cmd->pitches[0])) | ||
| 54 | return ERR_PTR(-EINVAL); | ||
| 55 | |||
| 56 | obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]); | ||
| 57 | if (obj == NULL) | ||
| 58 | return ERR_PTR(-ENOENT); | ||
| 59 | |||
| 60 | fb = kzalloc(sizeof(*fb), GFP_KERNEL); | ||
| 61 | if (!fb) { | ||
| 62 | drm_gem_object_put_unlocked(obj); | ||
| 63 | return ERR_PTR(-ENOMEM); | ||
| 64 | } | ||
| 65 | |||
| 66 | ret = cirrus_framebuffer_init(dev, fb, mode_cmd, obj); | ||
| 67 | if (ret) { | ||
| 68 | drm_gem_object_put_unlocked(obj); | ||
| 69 | kfree(fb); | ||
| 70 | return ERR_PTR(ret); | ||
| 71 | } | ||
| 72 | return fb; | ||
| 73 | } | ||
| 74 | |||
| 75 | static const struct drm_mode_config_funcs cirrus_mode_funcs = { | ||
| 76 | .fb_create = cirrus_user_framebuffer_create, | ||
| 77 | }; | ||
| 78 | |||
| 79 | /* Unmap the framebuffer from the core and release the memory */ | ||
| 80 | static void cirrus_vram_fini(struct cirrus_device *cdev) | ||
| 81 | { | ||
| 82 | iounmap(cdev->rmmio); | ||
| 83 | cdev->rmmio = NULL; | ||
| 84 | if (cdev->mc.vram_base) | ||
| 85 | release_mem_region(cdev->mc.vram_base, cdev->mc.vram_size); | ||
| 86 | } | ||
| 87 | |||
| 88 | /* Map the framebuffer from the card and configure the core */ | ||
| 89 | static int cirrus_vram_init(struct cirrus_device *cdev) | ||
| 90 | { | ||
| 91 | /* BAR 0 is VRAM */ | ||
| 92 | cdev->mc.vram_base = pci_resource_start(cdev->dev->pdev, 0); | ||
| 93 | cdev->mc.vram_size = pci_resource_len(cdev->dev->pdev, 0); | ||
| 94 | |||
| 95 | if (!request_mem_region(cdev->mc.vram_base, cdev->mc.vram_size, | ||
| 96 | "cirrusdrmfb_vram")) { | ||
| 97 | DRM_ERROR("can't reserve VRAM\n"); | ||
| 98 | return -ENXIO; | ||
| 99 | } | ||
| 100 | |||
| 101 | return 0; | ||
| 102 | } | ||
| 103 | |||
| 104 | /* | ||
| 105 | * Our emulated hardware has two sets of memory. One is video RAM and can | ||
| 106 | * simply be used as a linear framebuffer - the other provides mmio access | ||
| 107 | * to the display registers. The latter can also be accessed via IO port | ||
| 108 | * access, but we map the range and use mmio to program them instead | ||
| 109 | */ | ||
| 110 | |||
| 111 | int cirrus_device_init(struct cirrus_device *cdev, | ||
| 112 | struct drm_device *ddev, | ||
| 113 | struct pci_dev *pdev, uint32_t flags) | ||
| 114 | { | ||
| 115 | int ret; | ||
| 116 | |||
| 117 | cdev->dev = ddev; | ||
| 118 | cdev->flags = flags; | ||
| 119 | |||
| 120 | /* Hardcode the number of CRTCs to 1 */ | ||
| 121 | cdev->num_crtc = 1; | ||
| 122 | |||
| 123 | /* BAR 0 is the framebuffer, BAR 1 contains registers */ | ||
| 124 | cdev->rmmio_base = pci_resource_start(cdev->dev->pdev, 1); | ||
| 125 | cdev->rmmio_size = pci_resource_len(cdev->dev->pdev, 1); | ||
| 126 | |||
| 127 | if (!request_mem_region(cdev->rmmio_base, cdev->rmmio_size, | ||
| 128 | "cirrusdrmfb_mmio")) { | ||
| 129 | DRM_ERROR("can't reserve mmio registers\n"); | ||
| 130 | return -ENOMEM; | ||
| 131 | } | ||
| 132 | |||
| 133 | cdev->rmmio = ioremap(cdev->rmmio_base, cdev->rmmio_size); | ||
| 134 | |||
| 135 | if (cdev->rmmio == NULL) | ||
| 136 | return -ENOMEM; | ||
| 137 | |||
| 138 | ret = cirrus_vram_init(cdev); | ||
| 139 | if (ret) { | ||
| 140 | release_mem_region(cdev->rmmio_base, cdev->rmmio_size); | ||
| 141 | return ret; | ||
| 142 | } | ||
| 143 | |||
| 144 | return 0; | ||
| 145 | } | ||
| 146 | |||
| 147 | void cirrus_device_fini(struct cirrus_device *cdev) | ||
| 148 | { | ||
| 149 | release_mem_region(cdev->rmmio_base, cdev->rmmio_size); | ||
| 150 | cirrus_vram_fini(cdev); | ||
| 151 | } | ||
| 152 | |||
| 153 | /* | ||
| 154 | * Functions here will be called by the core once it's bound the driver to | ||
| 155 | * a PCI device | ||
| 156 | */ | ||
| 157 | |||
| 158 | int cirrus_driver_load(struct drm_device *dev, unsigned long flags) | ||
| 159 | { | ||
| 160 | struct cirrus_device *cdev; | ||
| 161 | int r; | ||
| 162 | |||
| 163 | cdev = kzalloc(sizeof(struct cirrus_device), GFP_KERNEL); | ||
| 164 | if (cdev == NULL) | ||
| 165 | return -ENOMEM; | ||
| 166 | dev->dev_private = (void *)cdev; | ||
| 167 | |||
| 168 | r = cirrus_device_init(cdev, dev, dev->pdev, flags); | ||
| 169 | if (r) { | ||
| 170 | dev_err(&dev->pdev->dev, "Fatal error during GPU init: %d\n", r); | ||
| 171 | goto out; | ||
| 172 | } | ||
| 173 | |||
| 174 | r = cirrus_mm_init(cdev); | ||
| 175 | if (r) { | ||
| 176 | dev_err(&dev->pdev->dev, "fatal err on mm init\n"); | ||
| 177 | goto out; | ||
| 178 | } | ||
| 179 | |||
| 180 | /* | ||
| 181 | * cirrus_modeset_init() is initializing/registering the emulated fbdev | ||
| 182 | * and DRM internals can access/test some of the fields in | ||
| 183 | * mode_config->funcs as part of the fbdev registration process. | ||
| 184 | * Make sure dev->mode_config.funcs is properly set to avoid | ||
| 185 | * dereferencing a NULL pointer. | ||
| 186 | * FIXME: mode_config.funcs assignment should probably be done in | ||
| 187 | * cirrus_modeset_init() (that's a common pattern seen in other DRM | ||
| 188 | * drivers). | ||
| 189 | */ | ||
| 190 | dev->mode_config.funcs = &cirrus_mode_funcs; | ||
| 191 | r = cirrus_modeset_init(cdev); | ||
| 192 | if (r) { | ||
| 193 | dev_err(&dev->pdev->dev, "Fatal error during modeset init: %d\n", r); | ||
| 194 | goto out; | ||
| 195 | } | ||
| 196 | |||
| 197 | return 0; | ||
| 198 | out: | ||
| 199 | cirrus_driver_unload(dev); | ||
| 200 | return r; | ||
| 201 | } | ||
| 202 | |||
| 203 | void cirrus_driver_unload(struct drm_device *dev) | ||
| 204 | { | ||
| 205 | struct cirrus_device *cdev = dev->dev_private; | ||
| 206 | |||
| 207 | if (cdev == NULL) | ||
| 208 | return; | ||
| 209 | cirrus_modeset_fini(cdev); | ||
| 210 | cirrus_mm_fini(cdev); | ||
| 211 | cirrus_device_fini(cdev); | ||
| 212 | kfree(cdev); | ||
| 213 | dev->dev_private = NULL; | ||
| 214 | } | ||
| 215 | |||
| 216 | int cirrus_gem_create(struct drm_device *dev, | ||
| 217 | u32 size, bool iskernel, | ||
| 218 | struct drm_gem_object **obj) | ||
| 219 | { | ||
| 220 | struct cirrus_bo *cirrusbo; | ||
| 221 | int ret; | ||
| 222 | |||
| 223 | *obj = NULL; | ||
| 224 | |||
| 225 | size = roundup(size, PAGE_SIZE); | ||
| 226 | if (size == 0) | ||
| 227 | return -EINVAL; | ||
| 228 | |||
| 229 | ret = cirrus_bo_create(dev, size, 0, 0, &cirrusbo); | ||
| 230 | if (ret) { | ||
| 231 | if (ret != -ERESTARTSYS) | ||
| 232 | DRM_ERROR("failed to allocate GEM object\n"); | ||
| 233 | return ret; | ||
| 234 | } | ||
| 235 | *obj = &cirrusbo->gem; | ||
| 236 | return 0; | ||
| 237 | } | ||
| 238 | |||
| 239 | int cirrus_dumb_create(struct drm_file *file, | ||
| 240 | struct drm_device *dev, | ||
| 241 | struct drm_mode_create_dumb *args) | ||
| 242 | { | ||
| 243 | int ret; | ||
| 244 | struct drm_gem_object *gobj; | ||
| 245 | u32 handle; | ||
| 246 | |||
| 247 | args->pitch = args->width * ((args->bpp + 7) / 8); | ||
| 248 | args->size = args->pitch * args->height; | ||
| 249 | |||
| 250 | ret = cirrus_gem_create(dev, args->size, false, | ||
| 251 | &gobj); | ||
| 252 | if (ret) | ||
| 253 | return ret; | ||
| 254 | |||
| 255 | ret = drm_gem_handle_create(file, gobj, &handle); | ||
| 256 | drm_gem_object_put_unlocked(gobj); | ||
| 257 | if (ret) | ||
| 258 | return ret; | ||
| 259 | |||
| 260 | args->handle = handle; | ||
| 261 | return 0; | ||
| 262 | } | ||
| 263 | |||
| 264 | static void cirrus_bo_unref(struct cirrus_bo **bo) | ||
| 265 | { | ||
| 266 | struct ttm_buffer_object *tbo; | ||
| 267 | |||
| 268 | if ((*bo) == NULL) | ||
| 269 | return; | ||
| 270 | |||
| 271 | tbo = &((*bo)->bo); | ||
| 272 | ttm_bo_put(tbo); | ||
| 273 | *bo = NULL; | ||
| 274 | } | ||
| 275 | |||
| 276 | void cirrus_gem_free_object(struct drm_gem_object *obj) | ||
| 277 | { | ||
| 278 | struct cirrus_bo *cirrus_bo = gem_to_cirrus_bo(obj); | ||
| 279 | |||
| 280 | cirrus_bo_unref(&cirrus_bo); | ||
| 281 | } | ||
| 282 | |||
| 283 | |||
| 284 | static inline u64 cirrus_bo_mmap_offset(struct cirrus_bo *bo) | ||
| 285 | { | ||
| 286 | return drm_vma_node_offset_addr(&bo->bo.vma_node); | ||
| 287 | } | ||
| 288 | |||
| 289 | int | ||
| 290 | cirrus_dumb_mmap_offset(struct drm_file *file, | ||
| 291 | struct drm_device *dev, | ||
| 292 | uint32_t handle, | ||
| 293 | uint64_t *offset) | ||
| 294 | { | ||
| 295 | struct drm_gem_object *obj; | ||
| 296 | struct cirrus_bo *bo; | ||
| 297 | |||
| 298 | obj = drm_gem_object_lookup(file, handle); | ||
| 299 | if (obj == NULL) | ||
| 300 | return -ENOENT; | ||
| 301 | |||
| 302 | bo = gem_to_cirrus_bo(obj); | ||
| 303 | *offset = cirrus_bo_mmap_offset(bo); | ||
| 304 | |||
| 305 | drm_gem_object_put_unlocked(obj); | ||
| 306 | |||
| 307 | return 0; | ||
| 308 | } | ||
| 309 | |||
| 310 | bool cirrus_check_framebuffer(struct cirrus_device *cdev, int width, int height, | ||
| 311 | int bpp, int pitch) | ||
| 312 | { | ||
| 313 | const int max_pitch = 0x1FF << 3; /* (4096 - 1) & ~111b bytes */ | ||
| 314 | const int max_size = cdev->mc.vram_size; | ||
| 315 | |||
| 316 | if (bpp > cirrus_bpp) | ||
| 317 | return false; | ||
| 318 | if (bpp > 32) | ||
| 319 | return false; | ||
| 320 | |||
| 321 | if (pitch > max_pitch) | ||
| 322 | return false; | ||
| 323 | |||
| 324 | if (pitch * height > max_size) | ||
| 325 | return false; | ||
| 326 | |||
| 327 | return true; | ||
| 328 | } | ||
diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c deleted file mode 100644 index b109cd71426f..000000000000 --- a/drivers/gpu/drm/cirrus/cirrus_mode.c +++ /dev/null | |||
| @@ -1,617 +0,0 @@ | |||
| 1 | |||
| 2 | /* | ||
| 3 | * Copyright 2012 Red Hat | ||
| 4 | * | ||
| 5 | * This file is subject to the terms and conditions of the GNU General | ||
| 6 | * Public License version 2. See the file COPYING in the main | ||
| 7 | * directory of this archive for more details. | ||
| 8 | * | ||
| 9 | * Authors: Matthew Garrett | ||
| 10 | * Dave Airlie | ||
| 11 | * | ||
| 12 | * Portions of this code derived from cirrusfb.c: | ||
| 13 | * drivers/video/cirrusfb.c - driver for Cirrus Logic chipsets | ||
| 14 | * | ||
| 15 | * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com> | ||
| 16 | */ | ||
| 17 | #include <drm/drmP.h> | ||
| 18 | #include <drm/drm_crtc_helper.h> | ||
| 19 | #include <drm/drm_plane_helper.h> | ||
| 20 | #include <drm/drm_probe_helper.h> | ||
| 21 | |||
| 22 | #include <video/cirrus.h> | ||
| 23 | |||
| 24 | #include "cirrus_drv.h" | ||
| 25 | |||
| 26 | #define CIRRUS_LUT_SIZE 256 | ||
| 27 | |||
| 28 | #define PALETTE_INDEX 0x8 | ||
| 29 | #define PALETTE_DATA 0x9 | ||
| 30 | |||
| 31 | /* | ||
| 32 | * This file contains setup code for the CRTC. | ||
| 33 | */ | ||
| 34 | |||
| 35 | /* | ||
| 36 | * The DRM core requires DPMS functions, but they make little sense in our | ||
| 37 | * case and so are just stubs | ||
| 38 | */ | ||
| 39 | |||
| 40 | static void cirrus_crtc_dpms(struct drm_crtc *crtc, int mode) | ||
| 41 | { | ||
| 42 | struct drm_device *dev = crtc->dev; | ||
| 43 | struct cirrus_device *cdev = dev->dev_private; | ||
| 44 | u8 sr01, gr0e; | ||
| 45 | |||
| 46 | switch (mode) { | ||
| 47 | case DRM_MODE_DPMS_ON: | ||
| 48 | sr01 = 0x00; | ||
| 49 | gr0e = 0x00; | ||
| 50 | break; | ||
| 51 | case DRM_MODE_DPMS_STANDBY: | ||
| 52 | sr01 = 0x20; | ||
| 53 | gr0e = 0x02; | ||
| 54 | break; | ||
| 55 | case DRM_MODE_DPMS_SUSPEND: | ||
| 56 | sr01 = 0x20; | ||
| 57 | gr0e = 0x04; | ||
| 58 | break; | ||
| 59 | case DRM_MODE_DPMS_OFF: | ||
| 60 | sr01 = 0x20; | ||
| 61 | gr0e = 0x06; | ||
| 62 | break; | ||
| 63 | default: | ||
| 64 | return; | ||
| 65 | } | ||
| 66 | |||
| 67 | WREG8(SEQ_INDEX, 0x1); | ||
| 68 | sr01 |= RREG8(SEQ_DATA) & ~0x20; | ||
| 69 | WREG_SEQ(0x1, sr01); | ||
| 70 | |||
| 71 | WREG8(GFX_INDEX, 0xe); | ||
| 72 | gr0e |= RREG8(GFX_DATA) & ~0x06; | ||
| 73 | WREG_GFX(0xe, gr0e); | ||
| 74 | } | ||
| 75 | |||
| 76 | static void cirrus_set_start_address(struct drm_crtc *crtc, unsigned offset) | ||
| 77 | { | ||
| 78 | struct cirrus_device *cdev = crtc->dev->dev_private; | ||
| 79 | u32 addr; | ||
| 80 | u8 tmp; | ||
| 81 | |||
| 82 | addr = offset >> 2; | ||
| 83 | WREG_CRT(0x0c, (u8)((addr >> 8) & 0xff)); | ||
| 84 | WREG_CRT(0x0d, (u8)(addr & 0xff)); | ||
| 85 | |||
| 86 | WREG8(CRT_INDEX, 0x1b); | ||
| 87 | tmp = RREG8(CRT_DATA); | ||
| 88 | tmp &= 0xf2; | ||
| 89 | tmp |= (addr >> 16) & 0x01; | ||
| 90 | tmp |= (addr >> 15) & 0x0c; | ||
| 91 | WREG_CRT(0x1b, tmp); | ||
| 92 | WREG8(CRT_INDEX, 0x1d); | ||
| 93 | tmp = RREG8(CRT_DATA); | ||
| 94 | tmp &= 0x7f; | ||
| 95 | tmp |= (addr >> 12) & 0x80; | ||
| 96 | WREG_CRT(0x1d, tmp); | ||
| 97 | } | ||
| 98 | |||
| 99 | /* cirrus is different - we will force move buffers out of VRAM */ | ||
| 100 | static int cirrus_crtc_do_set_base(struct drm_crtc *crtc, | ||
| 101 | struct drm_framebuffer *fb, | ||
| 102 | int x, int y, int atomic) | ||
| 103 | { | ||
| 104 | struct cirrus_device *cdev = crtc->dev->dev_private; | ||
| 105 | struct cirrus_bo *bo; | ||
| 106 | int ret; | ||
| 107 | u64 gpu_addr; | ||
| 108 | |||
| 109 | /* push the previous fb to system ram */ | ||
| 110 | if (!atomic && fb) { | ||
| 111 | bo = gem_to_cirrus_bo(fb->obj[0]); | ||
| 112 | ret = cirrus_bo_reserve(bo, false); | ||
| 113 | if (ret) | ||
| 114 | return ret; | ||
| 115 | cirrus_bo_push_sysram(bo); | ||
| 116 | cirrus_bo_unreserve(bo); | ||
| 117 | } | ||
| 118 | |||
| 119 | bo = gem_to_cirrus_bo(crtc->primary->fb->obj[0]); | ||
| 120 | |||
| 121 | ret = cirrus_bo_reserve(bo, false); | ||
| 122 | if (ret) | ||
| 123 | return ret; | ||
| 124 | |||
| 125 | ret = cirrus_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr); | ||
| 126 | if (ret) { | ||
| 127 | cirrus_bo_unreserve(bo); | ||
| 128 | return ret; | ||
| 129 | } | ||
| 130 | |||
| 131 | if (cdev->mode_info.gfbdev->gfb == crtc->primary->fb) { | ||
| 132 | /* if pushing console in kmap it */ | ||
| 133 | ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); | ||
| 134 | if (ret) | ||
| 135 | DRM_ERROR("failed to kmap fbcon\n"); | ||
| 136 | } | ||
| 137 | cirrus_bo_unreserve(bo); | ||
| 138 | |||
| 139 | cirrus_set_start_address(crtc, (u32)gpu_addr); | ||
| 140 | return 0; | ||
| 141 | } | ||
| 142 | |||
| 143 | static int cirrus_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, | ||
| 144 | struct drm_framebuffer *old_fb) | ||
| 145 | { | ||
| 146 | return cirrus_crtc_do_set_base(crtc, old_fb, x, y, 0); | ||
| 147 | } | ||
| 148 | |||
| 149 | /* | ||
| 150 | * The meat of this driver. The core passes us a mode and we have to program | ||
| 151 | * it. The modesetting here is the bare minimum required to satisfy the qemu | ||
| 152 | * emulation of this hardware, and running this against a real device is | ||
| 153 | * likely to result in an inadequately programmed mode. We've already had | ||
| 154 | * the opportunity to modify the mode, so whatever we receive here should | ||
| 155 | * be something that can be correctly programmed and displayed | ||
| 156 | */ | ||
| 157 | static int cirrus_crtc_mode_set(struct drm_crtc *crtc, | ||
| 158 | struct drm_display_mode *mode, | ||
| 159 | struct drm_display_mode *adjusted_mode, | ||
| 160 | int x, int y, struct drm_framebuffer *old_fb) | ||
| 161 | { | ||
| 162 | struct drm_device *dev = crtc->dev; | ||
| 163 | struct cirrus_device *cdev = dev->dev_private; | ||
| 164 | const struct drm_framebuffer *fb = crtc->primary->fb; | ||
| 165 | int hsyncstart, hsyncend, htotal, hdispend; | ||
| 166 | int vtotal, vdispend; | ||
| 167 | int tmp; | ||
| 168 | int sr07 = 0, hdr = 0; | ||
| 169 | |||
| 170 | htotal = mode->htotal / 8; | ||
| 171 | hsyncend = mode->hsync_end / 8; | ||
| 172 | hsyncstart = mode->hsync_start / 8; | ||
| 173 | hdispend = mode->hdisplay / 8; | ||
| 174 | |||
| 175 | vtotal = mode->vtotal; | ||
| 176 | vdispend = mode->vdisplay; | ||
| 177 | |||
| 178 | vdispend -= 1; | ||
| 179 | vtotal -= 2; | ||
| 180 | |||
| 181 | htotal -= 5; | ||
| 182 | hdispend -= 1; | ||
| 183 | hsyncstart += 1; | ||
| 184 | hsyncend += 1; | ||
| 185 | |||
| 186 | WREG_CRT(VGA_CRTC_V_SYNC_END, 0x20); | ||
| 187 | WREG_CRT(VGA_CRTC_H_TOTAL, htotal); | ||
| 188 | WREG_CRT(VGA_CRTC_H_DISP, hdispend); | ||
| 189 | WREG_CRT(VGA_CRTC_H_SYNC_START, hsyncstart); | ||
| 190 | WREG_CRT(VGA_CRTC_H_SYNC_END, hsyncend); | ||
| 191 | WREG_CRT(VGA_CRTC_V_TOTAL, vtotal & 0xff); | ||
| 192 | WREG_CRT(VGA_CRTC_V_DISP_END, vdispend & 0xff); | ||
| 193 | |||
| 194 | tmp = 0x40; | ||
| 195 | if ((vdispend + 1) & 512) | ||
| 196 | tmp |= 0x20; | ||
| 197 | WREG_CRT(VGA_CRTC_MAX_SCAN, tmp); | ||
| 198 | |||
| 199 | /* | ||
| 200 | * Overflow bits for values that don't fit in the standard registers | ||
| 201 | */ | ||
| 202 | tmp = 16; | ||
| 203 | if (vtotal & 256) | ||
| 204 | tmp |= 1; | ||
| 205 | if (vdispend & 256) | ||
| 206 | tmp |= 2; | ||
| 207 | if ((vdispend + 1) & 256) | ||
| 208 | tmp |= 8; | ||
| 209 | if (vtotal & 512) | ||
| 210 | tmp |= 32; | ||
| 211 | if (vdispend & 512) | ||
| 212 | tmp |= 64; | ||
| 213 | WREG_CRT(VGA_CRTC_OVERFLOW, tmp); | ||
| 214 | |||
| 215 | tmp = 0; | ||
| 216 | |||
| 217 | /* More overflow bits */ | ||
| 218 | |||
| 219 | if ((htotal + 5) & 64) | ||
| 220 | tmp |= 16; | ||
| 221 | if ((htotal + 5) & 128) | ||
| 222 | tmp |= 32; | ||
| 223 | if (vtotal & 256) | ||
| 224 | tmp |= 64; | ||
| 225 | if (vtotal & 512) | ||
| 226 | tmp |= 128; | ||
| 227 | |||
| 228 | WREG_CRT(CL_CRT1A, tmp); | ||
| 229 | |||
| 230 | /* Disable Hercules/CGA compatibility */ | ||
| 231 | WREG_CRT(VGA_CRTC_MODE, 0x03); | ||
| 232 | |||
| 233 | WREG8(SEQ_INDEX, 0x7); | ||
| 234 | sr07 = RREG8(SEQ_DATA); | ||
| 235 | sr07 &= 0xe0; | ||
| 236 | hdr = 0; | ||
| 237 | switch (fb->format->cpp[0] * 8) { | ||
| 238 | case 8: | ||
| 239 | sr07 |= 0x11; | ||
| 240 | break; | ||
| 241 | case 16: | ||
| 242 | sr07 |= 0x17; | ||
| 243 | hdr = 0xc1; | ||
| 244 | break; | ||
| 245 | case 24: | ||
| 246 | sr07 |= 0x15; | ||
| 247 | hdr = 0xc5; | ||
| 248 | break; | ||
| 249 | case 32: | ||
| 250 | sr07 |= 0x19; | ||
| 251 | hdr = 0xc5; | ||
| 252 | break; | ||
| 253 | default: | ||
| 254 | return -1; | ||
| 255 | } | ||
| 256 | |||
| 257 | WREG_SEQ(0x7, sr07); | ||
| 258 | |||
| 259 | /* Program the pitch */ | ||
| 260 | tmp = fb->pitches[0] / 8; | ||
| 261 | WREG_CRT(VGA_CRTC_OFFSET, tmp); | ||
| 262 | |||
| 263 | /* Enable extended blanking and pitch bits, and enable full memory */ | ||
| 264 | tmp = 0x22; | ||
| 265 | tmp |= (fb->pitches[0] >> 7) & 0x10; | ||
| 266 | tmp |= (fb->pitches[0] >> 6) & 0x40; | ||
| 267 | WREG_CRT(0x1b, tmp); | ||
| 268 | |||
| 269 | /* Enable high-colour modes */ | ||
| 270 | WREG_GFX(VGA_GFX_MODE, 0x40); | ||
| 271 | |||
| 272 | /* And set graphics mode */ | ||
| 273 | WREG_GFX(VGA_GFX_MISC, 0x01); | ||
| 274 | |||
| 275 | WREG_HDR(hdr); | ||
| 276 | cirrus_crtc_do_set_base(crtc, old_fb, x, y, 0); | ||
| 277 | |||
| 278 | /* Unblank (needed on S3 resume, vgabios doesn't do it then) */ | ||
| 279 | outb(0x20, 0x3c0); | ||
| 280 | return 0; | ||
| 281 | } | ||
| 282 | |||
| 283 | /* | ||
| 284 | * This is called before a mode is programmed. A typical use might be to | ||
| 285 | * enable DPMS during the programming to avoid seeing intermediate stages, | ||
| 286 | * but that's not relevant to us | ||
| 287 | */ | ||
| 288 | static void cirrus_crtc_prepare(struct drm_crtc *crtc) | ||
| 289 | { | ||
| 290 | } | ||
| 291 | |||
| 292 | static void cirrus_crtc_load_lut(struct drm_crtc *crtc) | ||
| 293 | { | ||
| 294 | struct drm_device *dev = crtc->dev; | ||
| 295 | struct cirrus_device *cdev = dev->dev_private; | ||
| 296 | u16 *r, *g, *b; | ||
| 297 | int i; | ||
| 298 | |||
| 299 | if (!crtc->enabled) | ||
| 300 | return; | ||
| 301 | |||
| 302 | r = crtc->gamma_store; | ||
| 303 | g = r + crtc->gamma_size; | ||
| 304 | b = g + crtc->gamma_size; | ||
| 305 | |||
| 306 | for (i = 0; i < CIRRUS_LUT_SIZE; i++) { | ||
| 307 | /* VGA registers */ | ||
| 308 | WREG8(PALETTE_INDEX, i); | ||
| 309 | WREG8(PALETTE_DATA, *r++ >> 8); | ||
| 310 | WREG8(PALETTE_DATA, *g++ >> 8); | ||
| 311 | WREG8(PALETTE_DATA, *b++ >> 8); | ||
| 312 | } | ||
| 313 | } | ||
| 314 | |||
| 315 | /* | ||
| 316 | * This is called after a mode is programmed. It should reverse anything done | ||
| 317 | * by the prepare function | ||
| 318 | */ | ||
| 319 | static void cirrus_crtc_commit(struct drm_crtc *crtc) | ||
| 320 | { | ||
| 321 | cirrus_crtc_load_lut(crtc); | ||
| 322 | } | ||
| 323 | |||
| 324 | /* | ||
| 325 | * The core can pass us a set of gamma values to program. We actually only | ||
| 326 | * use this for 8-bit mode so can't perform smooth fades on deeper modes, | ||
| 327 | * but it's a requirement that we provide the function | ||
| 328 | */ | ||
| 329 | static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, | ||
| 330 | u16 *blue, uint32_t size, | ||
| 331 | struct drm_modeset_acquire_ctx *ctx) | ||
| 332 | { | ||
| 333 | cirrus_crtc_load_lut(crtc); | ||
| 334 | |||
| 335 | return 0; | ||
| 336 | } | ||
| 337 | |||
| 338 | /* Simple cleanup function */ | ||
| 339 | static void cirrus_crtc_destroy(struct drm_crtc *crtc) | ||
| 340 | { | ||
| 341 | struct cirrus_crtc *cirrus_crtc = to_cirrus_crtc(crtc); | ||
| 342 | |||
| 343 | drm_crtc_cleanup(crtc); | ||
| 344 | kfree(cirrus_crtc); | ||
| 345 | } | ||
| 346 | |||
| 347 | /* These provide the minimum set of functions required to handle a CRTC */ | ||
| 348 | static const struct drm_crtc_funcs cirrus_crtc_funcs = { | ||
| 349 | .gamma_set = cirrus_crtc_gamma_set, | ||
| 350 | .set_config = drm_crtc_helper_set_config, | ||
| 351 | .destroy = cirrus_crtc_destroy, | ||
| 352 | }; | ||
| 353 | |||
| 354 | static const struct drm_crtc_helper_funcs cirrus_helper_funcs = { | ||
| 355 | .dpms = cirrus_crtc_dpms, | ||
| 356 | .mode_set = cirrus_crtc_mode_set, | ||
| 357 | .mode_set_base = cirrus_crtc_mode_set_base, | ||
| 358 | .prepare = cirrus_crtc_prepare, | ||
| 359 | .commit = cirrus_crtc_commit, | ||
| 360 | }; | ||
| 361 | |||
| 362 | /* CRTC setup */ | ||
| 363 | static const uint32_t cirrus_formats_16[] = { | ||
| 364 | DRM_FORMAT_RGB565, | ||
| 365 | }; | ||
| 366 | |||
| 367 | static const uint32_t cirrus_formats_24[] = { | ||
| 368 | DRM_FORMAT_RGB888, | ||
| 369 | DRM_FORMAT_RGB565, | ||
| 370 | }; | ||
| 371 | |||
| 372 | static const uint32_t cirrus_formats_32[] = { | ||
| 373 | DRM_FORMAT_XRGB8888, | ||
| 374 | DRM_FORMAT_ARGB8888, | ||
| 375 | DRM_FORMAT_RGB888, | ||
| 376 | DRM_FORMAT_RGB565, | ||
| 377 | }; | ||
| 378 | |||
| 379 | static struct drm_plane *cirrus_primary_plane(struct drm_device *dev) | ||
| 380 | { | ||
| 381 | const uint32_t *formats; | ||
| 382 | uint32_t nformats; | ||
| 383 | struct drm_plane *primary; | ||
| 384 | int ret; | ||
| 385 | |||
| 386 | switch (cirrus_bpp) { | ||
| 387 | case 16: | ||
| 388 | formats = cirrus_formats_16; | ||
| 389 | nformats = ARRAY_SIZE(cirrus_formats_16); | ||
| 390 | break; | ||
| 391 | case 24: | ||
| 392 | formats = cirrus_formats_24; | ||
| 393 | nformats = ARRAY_SIZE(cirrus_formats_24); | ||
| 394 | break; | ||
| 395 | case 32: | ||
| 396 | formats = cirrus_formats_32; | ||
| 397 | nformats = ARRAY_SIZE(cirrus_formats_32); | ||
| 398 | break; | ||
| 399 | default: | ||
| 400 | return NULL; | ||
| 401 | } | ||
| 402 | |||
| 403 | primary = kzalloc(sizeof(*primary), GFP_KERNEL); | ||
| 404 | if (primary == NULL) { | ||
| 405 | DRM_DEBUG_KMS("Failed to allocate primary plane\n"); | ||
| 406 | return NULL; | ||
| 407 | } | ||
| 408 | |||
| 409 | ret = drm_universal_plane_init(dev, primary, 0, | ||
| 410 | &drm_primary_helper_funcs, | ||
| 411 | formats, nformats, | ||
| 412 | NULL, | ||
| 413 | DRM_PLANE_TYPE_PRIMARY, NULL); | ||
| 414 | if (ret) { | ||
| 415 | kfree(primary); | ||
| 416 | primary = NULL; | ||
| 417 | } | ||
| 418 | |||
| 419 | return primary; | ||
| 420 | } | ||
| 421 | |||
| 422 | static void cirrus_crtc_init(struct drm_device *dev) | ||
| 423 | { | ||
| 424 | struct cirrus_device *cdev = dev->dev_private; | ||
| 425 | struct cirrus_crtc *cirrus_crtc; | ||
| 426 | struct drm_plane *primary; | ||
| 427 | |||
| 428 | cirrus_crtc = kzalloc(sizeof(struct cirrus_crtc) + | ||
| 429 | (CIRRUSFB_CONN_LIMIT * sizeof(struct drm_connector *)), | ||
| 430 | GFP_KERNEL); | ||
| 431 | |||
| 432 | if (cirrus_crtc == NULL) | ||
| 433 | return; | ||
| 434 | |||
| 435 | primary = cirrus_primary_plane(dev); | ||
| 436 | if (primary == NULL) { | ||
| 437 | kfree(cirrus_crtc); | ||
| 438 | return; | ||
| 439 | } | ||
| 440 | |||
| 441 | drm_crtc_init_with_planes(dev, &cirrus_crtc->base, | ||
| 442 | primary, NULL, | ||
| 443 | &cirrus_crtc_funcs, NULL); | ||
| 444 | |||
| 445 | drm_mode_crtc_set_gamma_size(&cirrus_crtc->base, CIRRUS_LUT_SIZE); | ||
| 446 | cdev->mode_info.crtc = cirrus_crtc; | ||
| 447 | |||
| 448 | drm_crtc_helper_add(&cirrus_crtc->base, &cirrus_helper_funcs); | ||
| 449 | } | ||
| 450 | |||
| 451 | static void cirrus_encoder_mode_set(struct drm_encoder *encoder, | ||
| 452 | struct drm_display_mode *mode, | ||
| 453 | struct drm_display_mode *adjusted_mode) | ||
| 454 | { | ||
| 455 | } | ||
| 456 | |||
| 457 | static void cirrus_encoder_dpms(struct drm_encoder *encoder, int state) | ||
| 458 | { | ||
| 459 | return; | ||
| 460 | } | ||
| 461 | |||
| 462 | static void cirrus_encoder_prepare(struct drm_encoder *encoder) | ||
| 463 | { | ||
| 464 | } | ||
| 465 | |||
| 466 | static void cirrus_encoder_commit(struct drm_encoder *encoder) | ||
| 467 | { | ||
| 468 | } | ||
| 469 | |||
| 470 | static void cirrus_encoder_destroy(struct drm_encoder *encoder) | ||
| 471 | { | ||
| 472 | struct cirrus_encoder *cirrus_encoder = to_cirrus_encoder(encoder); | ||
| 473 | drm_encoder_cleanup(encoder); | ||
| 474 | kfree(cirrus_encoder); | ||
| 475 | } | ||
| 476 | |||
| 477 | static const struct drm_encoder_helper_funcs cirrus_encoder_helper_funcs = { | ||
| 478 | .dpms = cirrus_encoder_dpms, | ||
| 479 | .mode_set = cirrus_encoder_mode_set, | ||
| 480 | .prepare = cirrus_encoder_prepare, | ||
| 481 | .commit = cirrus_encoder_commit, | ||
| 482 | }; | ||
| 483 | |||
| 484 | static const struct drm_encoder_funcs cirrus_encoder_encoder_funcs = { | ||
| 485 | .destroy = cirrus_encoder_destroy, | ||
| 486 | }; | ||
| 487 | |||
| 488 | static struct drm_encoder *cirrus_encoder_init(struct drm_device *dev) | ||
| 489 | { | ||
| 490 | struct drm_encoder *encoder; | ||
| 491 | struct cirrus_encoder *cirrus_encoder; | ||
| 492 | |||
| 493 | cirrus_encoder = kzalloc(sizeof(struct cirrus_encoder), GFP_KERNEL); | ||
| 494 | if (!cirrus_encoder) | ||
| 495 | return NULL; | ||
| 496 | |||
| 497 | encoder = &cirrus_encoder->base; | ||
| 498 | encoder->possible_crtcs = 0x1; | ||
| 499 | |||
| 500 | drm_encoder_init(dev, encoder, &cirrus_encoder_encoder_funcs, | ||
| 501 | DRM_MODE_ENCODER_DAC, NULL); | ||
| 502 | drm_encoder_helper_add(encoder, &cirrus_encoder_helper_funcs); | ||
| 503 | |||
| 504 | return encoder; | ||
| 505 | } | ||
| 506 | |||
| 507 | |||
| 508 | static int cirrus_vga_get_modes(struct drm_connector *connector) | ||
| 509 | { | ||
| 510 | int count; | ||
| 511 | |||
| 512 | /* Just add a static list of modes */ | ||
| 513 | if (cirrus_bpp <= 24) { | ||
| 514 | count = drm_add_modes_noedid(connector, 1280, 1024); | ||
| 515 | drm_set_preferred_mode(connector, 1024, 768); | ||
| 516 | } else { | ||
| 517 | count = drm_add_modes_noedid(connector, 800, 600); | ||
| 518 | drm_set_preferred_mode(connector, 800, 600); | ||
| 519 | } | ||
| 520 | return count; | ||
| 521 | } | ||
| 522 | |||
| 523 | static struct drm_encoder *cirrus_connector_best_encoder(struct drm_connector | ||
| 524 | *connector) | ||
| 525 | { | ||
| 526 | int enc_id = connector->encoder_ids[0]; | ||
| 527 | /* pick the encoder ids */ | ||
| 528 | if (enc_id) | ||
| 529 | return drm_encoder_find(connector->dev, NULL, enc_id); | ||
| 530 | return NULL; | ||
| 531 | } | ||
| 532 | |||
| 533 | static void cirrus_connector_destroy(struct drm_connector *connector) | ||
| 534 | { | ||
| 535 | drm_connector_cleanup(connector); | ||
| 536 | kfree(connector); | ||
| 537 | } | ||
| 538 | |||
| 539 | static const struct drm_connector_helper_funcs cirrus_vga_connector_helper_funcs = { | ||
| 540 | .get_modes = cirrus_vga_get_modes, | ||
| 541 | .best_encoder = cirrus_connector_best_encoder, | ||
| 542 | }; | ||
| 543 | |||
| 544 | static const struct drm_connector_funcs cirrus_vga_connector_funcs = { | ||
| 545 | .dpms = drm_helper_connector_dpms, | ||
| 546 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
| 547 | .destroy = cirrus_connector_destroy, | ||
| 548 | }; | ||
| 549 | |||
| 550 | static struct drm_connector *cirrus_vga_init(struct drm_device *dev) | ||
| 551 | { | ||
| 552 | struct drm_connector *connector; | ||
| 553 | struct cirrus_connector *cirrus_connector; | ||
| 554 | |||
| 555 | cirrus_connector = kzalloc(sizeof(struct cirrus_connector), GFP_KERNEL); | ||
| 556 | if (!cirrus_connector) | ||
| 557 | return NULL; | ||
| 558 | |||
| 559 | connector = &cirrus_connector->base; | ||
| 560 | |||
| 561 | drm_connector_init(dev, connector, | ||
| 562 | &cirrus_vga_connector_funcs, DRM_MODE_CONNECTOR_VGA); | ||
| 563 | |||
| 564 | drm_connector_helper_add(connector, &cirrus_vga_connector_helper_funcs); | ||
| 565 | |||
| 566 | drm_connector_register(connector); | ||
| 567 | return connector; | ||
| 568 | } | ||
| 569 | |||
| 570 | |||
| 571 | int cirrus_modeset_init(struct cirrus_device *cdev) | ||
| 572 | { | ||
| 573 | struct drm_encoder *encoder; | ||
| 574 | struct drm_connector *connector; | ||
| 575 | int ret; | ||
| 576 | |||
| 577 | drm_mode_config_init(cdev->dev); | ||
| 578 | |||
| 579 | cdev->dev->mode_config.max_width = CIRRUS_MAX_FB_WIDTH; | ||
| 580 | cdev->dev->mode_config.max_height = CIRRUS_MAX_FB_HEIGHT; | ||
| 581 | |||
| 582 | cdev->dev->mode_config.fb_base = cdev->mc.vram_base; | ||
| 583 | cdev->dev->mode_config.preferred_depth = cirrus_bpp; | ||
| 584 | /* don't prefer a shadow on virt GPU */ | ||
| 585 | cdev->dev->mode_config.prefer_shadow = 0; | ||
| 586 | |||
| 587 | cirrus_crtc_init(cdev->dev); | ||
| 588 | |||
| 589 | encoder = cirrus_encoder_init(cdev->dev); | ||
| 590 | if (!encoder) { | ||
| 591 | DRM_ERROR("cirrus_encoder_init failed\n"); | ||
| 592 | return -1; | ||
| 593 | } | ||
| 594 | |||
| 595 | connector = cirrus_vga_init(cdev->dev); | ||
| 596 | if (!connector) { | ||
| 597 | DRM_ERROR("cirrus_vga_init failed\n"); | ||
| 598 | return -1; | ||
| 599 | } | ||
| 600 | |||
| 601 | drm_connector_attach_encoder(connector, encoder); | ||
| 602 | |||
| 603 | ret = cirrus_fbdev_init(cdev); | ||
| 604 | if (ret) { | ||
| 605 | DRM_ERROR("cirrus_fbdev_init failed\n"); | ||
| 606 | return ret; | ||
| 607 | } | ||
| 608 | |||
| 609 | return 0; | ||
| 610 | } | ||
| 611 | |||
| 612 | void cirrus_modeset_fini(struct cirrus_device *cdev) | ||
| 613 | { | ||
| 614 | cirrus_fbdev_fini(cdev); | ||
| 615 | drm_helper_force_disable_all(cdev->dev); | ||
| 616 | drm_mode_config_cleanup(cdev->dev); | ||
| 617 | } | ||
diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c new file mode 100644 index 000000000000..00d716f14173 --- /dev/null +++ b/drivers/gpu/drm/drm_format_helper.c | |||
| @@ -0,0 +1,326 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | /* | ||
| 3 | * Copyright (C) 2016 Noralf Trønnes | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/module.h> | ||
| 12 | #include <linux/slab.h> | ||
| 13 | |||
| 14 | #include <drm/drm_format_helper.h> | ||
| 15 | #include <drm/drm_framebuffer.h> | ||
| 16 | #include <drm/drm_fourcc.h> | ||
| 17 | #include <drm/drm_rect.h> | ||
| 18 | |||
| 19 | static void drm_fb_memcpy_lines(void *dst, unsigned int dst_pitch, | ||
| 20 | void *src, unsigned int src_pitch, | ||
| 21 | unsigned int linelength, unsigned int lines) | ||
| 22 | { | ||
| 23 | int line; | ||
| 24 | |||
| 25 | for (line = 0; line < lines; line++) { | ||
| 26 | memcpy(dst, src, linelength); | ||
| 27 | src += src_pitch; | ||
| 28 | dst += dst_pitch; | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 32 | /** | ||
| 33 | * drm_fb_memcpy - Copy clip buffer | ||
| 34 | * @dst: Destination buffer | ||
| 35 | * @vaddr: Source buffer | ||
| 36 | * @fb: DRM framebuffer | ||
| 37 | * @clip: Clip rectangle area to copy | ||
| 38 | * | ||
| 39 | * This function does not apply clipping on dst, i.e. the destination | ||
| 40 | * is a small buffer containing the clip rect only. | ||
| 41 | */ | ||
| 42 | void drm_fb_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb, | ||
| 43 | struct drm_rect *clip) | ||
| 44 | { | ||
| 45 | unsigned int cpp = drm_format_plane_cpp(fb->format->format, 0); | ||
| 46 | unsigned int offset = (clip->y1 * fb->pitches[0]) + (clip->x1 * cpp); | ||
| 47 | size_t len = (clip->x2 - clip->x1) * cpp; | ||
| 48 | |||
| 49 | drm_fb_memcpy_lines(dst, len, | ||
| 50 | vaddr + offset, fb->pitches[0], | ||
| 51 | len, clip->y2 - clip->y1); | ||
| 52 | } | ||
| 53 | EXPORT_SYMBOL(drm_fb_memcpy); | ||
| 54 | |||
| 55 | /** | ||
| 56 | * drm_fb_memcpy_dstclip - Copy clip buffer | ||
| 57 | * @dst: Destination buffer | ||
| 58 | * @vaddr: Source buffer | ||
| 59 | * @fb: DRM framebuffer | ||
| 60 | * @clip: Clip rectangle area to copy | ||
| 61 | * | ||
| 62 | * This function applies clipping on dst, i.e. the destination is a | ||
| 63 | * full framebuffer but only the clip rect content is copied over. | ||
| 64 | */ | ||
| 65 | void drm_fb_memcpy_dstclip(void *dst, void *vaddr, struct drm_framebuffer *fb, | ||
| 66 | struct drm_rect *clip) | ||
| 67 | { | ||
| 68 | unsigned int cpp = drm_format_plane_cpp(fb->format->format, 0); | ||
| 69 | unsigned int offset = (clip->y1 * fb->pitches[0]) + (clip->x1 * cpp); | ||
| 70 | size_t len = (clip->x2 - clip->x1) * cpp; | ||
| 71 | |||
| 72 | drm_fb_memcpy_lines(dst + offset, fb->pitches[0], | ||
| 73 | vaddr + offset, fb->pitches[0], | ||
| 74 | len, clip->y2 - clip->y1); | ||
| 75 | } | ||
| 76 | EXPORT_SYMBOL(drm_fb_memcpy_dstclip); | ||
| 77 | |||
| 78 | /** | ||
| 79 | * drm_fb_swab16 - Swap bytes into clip buffer | ||
| 80 | * @dst: RGB565 destination buffer | ||
| 81 | * @vaddr: RGB565 source buffer | ||
| 82 | * @fb: DRM framebuffer | ||
| 83 | * @clip: Clip rectangle area to copy | ||
| 84 | */ | ||
| 85 | void drm_fb_swab16(u16 *dst, void *vaddr, struct drm_framebuffer *fb, | ||
| 86 | struct drm_rect *clip) | ||
| 87 | { | ||
| 88 | size_t len = (clip->x2 - clip->x1) * sizeof(u16); | ||
| 89 | unsigned int x, y; | ||
| 90 | u16 *src, *buf; | ||
| 91 | |||
| 92 | /* | ||
| 93 | * The cma memory is write-combined so reads are uncached. | ||
| 94 | * Speed up by fetching one line at a time. | ||
| 95 | */ | ||
| 96 | buf = kmalloc(len, GFP_KERNEL); | ||
| 97 | if (!buf) | ||
| 98 | return; | ||
| 99 | |||
| 100 | for (y = clip->y1; y < clip->y2; y++) { | ||
| 101 | src = vaddr + (y * fb->pitches[0]); | ||
| 102 | src += clip->x1; | ||
| 103 | memcpy(buf, src, len); | ||
| 104 | src = buf; | ||
| 105 | for (x = clip->x1; x < clip->x2; x++) | ||
| 106 | *dst++ = swab16(*src++); | ||
| 107 | } | ||
| 108 | |||
| 109 | kfree(buf); | ||
| 110 | } | ||
| 111 | EXPORT_SYMBOL(drm_fb_swab16); | ||
| 112 | |||
| 113 | static void drm_fb_xrgb8888_to_rgb565_lines(void *dst, unsigned int dst_pitch, | ||
| 114 | void *src, unsigned int src_pitch, | ||
| 115 | unsigned int src_linelength, | ||
| 116 | unsigned int lines, | ||
| 117 | bool swap) | ||
| 118 | { | ||
| 119 | unsigned int linepixels = src_linelength / sizeof(u32); | ||
| 120 | unsigned int x, y; | ||
| 121 | u32 *sbuf; | ||
| 122 | u16 *dbuf, val16; | ||
| 123 | |||
| 124 | /* | ||
| 125 | * The cma memory is write-combined so reads are uncached. | ||
| 126 | * Speed up by fetching one line at a time. | ||
| 127 | */ | ||
| 128 | sbuf = kmalloc(src_linelength, GFP_KERNEL); | ||
| 129 | if (!sbuf) | ||
| 130 | return; | ||
| 131 | |||
| 132 | for (y = 0; y < lines; y++) { | ||
| 133 | memcpy(sbuf, src, src_linelength); | ||
| 134 | dbuf = dst; | ||
| 135 | for (x = 0; x < linepixels; x++) { | ||
| 136 | val16 = ((sbuf[x] & 0x00F80000) >> 8) | | ||
| 137 | ((sbuf[x] & 0x0000FC00) >> 5) | | ||
| 138 | ((sbuf[x] & 0x000000F8) >> 3); | ||
| 139 | if (swap) | ||
| 140 | *dbuf++ = swab16(val16); | ||
| 141 | else | ||
| 142 | *dbuf++ = val16; | ||
| 143 | } | ||
| 144 | src += src_pitch; | ||
| 145 | dst += dst_pitch; | ||
| 146 | } | ||
| 147 | |||
| 148 | kfree(sbuf); | ||
| 149 | } | ||
| 150 | |||
| 151 | /** | ||
| 152 | * drm_fb_xrgb8888_to_rgb565 - Convert XRGB8888 to RGB565 clip buffer | ||
| 153 | * @dst: RGB565 destination buffer | ||
| 154 | * @vaddr: XRGB8888 source buffer | ||
| 155 | * @fb: DRM framebuffer | ||
| 156 | * @clip: Clip rectangle area to copy | ||
| 157 | * @swap: Swap bytes | ||
| 158 | * | ||
| 159 | * Drivers can use this function for RGB565 devices that don't natively | ||
| 160 | * support XRGB8888. | ||
| 161 | * | ||
| 162 | * This function does not apply clipping on dst, i.e. the destination | ||
| 163 | * is a small buffer containing the clip rect only. | ||
| 164 | */ | ||
| 165 | void drm_fb_xrgb8888_to_rgb565(void *dst, void *vaddr, | ||
| 166 | struct drm_framebuffer *fb, | ||
| 167 | struct drm_rect *clip, bool swap) | ||
| 168 | { | ||
| 169 | unsigned int src_offset = (clip->y1 * fb->pitches[0]) | ||
| 170 | + (clip->x1 * sizeof(u32)); | ||
| 171 | size_t src_len = (clip->x2 - clip->x1) * sizeof(u32); | ||
| 172 | size_t dst_len = (clip->x2 - clip->x1) * sizeof(u16); | ||
| 173 | |||
| 174 | drm_fb_xrgb8888_to_rgb565_lines(dst, dst_len, | ||
| 175 | vaddr + src_offset, fb->pitches[0], | ||
| 176 | src_len, clip->y2 - clip->y1, | ||
| 177 | swap); | ||
| 178 | } | ||
| 179 | EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565); | ||
| 180 | |||
| 181 | /** | ||
| 182 | * drm_fb_xrgb8888_to_rgb565_dstclip - Convert XRGB8888 to RGB565 clip buffer | ||
| 183 | * @dst: RGB565 destination buffer | ||
| 184 | * @dst_pitch: destination buffer pitch | ||
| 185 | * @vaddr: XRGB8888 source buffer | ||
| 186 | * @fb: DRM framebuffer | ||
| 187 | * @clip: Clip rectangle area to copy | ||
| 188 | * @swap: Swap bytes | ||
| 189 | * | ||
| 190 | * Drivers can use this function for RGB565 devices that don't natively | ||
| 191 | * support XRGB8888. | ||
| 192 | * | ||
| 193 | * This function applies clipping on dst, i.e. the destination is a | ||
| 194 | * full framebuffer but only the clip rect content is copied over. | ||
| 195 | */ | ||
| 196 | void drm_fb_xrgb8888_to_rgb565_dstclip(void *dst, unsigned int dst_pitch, | ||
| 197 | void *vaddr, struct drm_framebuffer *fb, | ||
| 198 | struct drm_rect *clip, bool swap) | ||
| 199 | { | ||
| 200 | unsigned int src_offset = (clip->y1 * fb->pitches[0]) | ||
| 201 | + (clip->x1 * sizeof(u32)); | ||
| 202 | unsigned int dst_offset = (clip->y1 * dst_pitch) | ||
| 203 | + (clip->x1 * sizeof(u16)); | ||
| 204 | size_t src_len = (clip->x2 - clip->x1) * sizeof(u32); | ||
| 205 | |||
| 206 | drm_fb_xrgb8888_to_rgb565_lines(dst + dst_offset, dst_pitch, | ||
| 207 | vaddr + src_offset, fb->pitches[0], | ||
| 208 | src_len, clip->y2 - clip->y1, | ||
| 209 | swap); | ||
| 210 | } | ||
| 211 | EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565_dstclip); | ||
| 212 | |||
| 213 | static void drm_fb_xrgb8888_to_rgb888_lines(void *dst, unsigned int dst_pitch, | ||
| 214 | void *src, unsigned int src_pitch, | ||
| 215 | unsigned int src_linelength, | ||
| 216 | unsigned int lines) | ||
| 217 | { | ||
| 218 | unsigned int linepixels = src_linelength / 3; | ||
| 219 | unsigned int x, y; | ||
| 220 | u32 *sbuf; | ||
| 221 | u8 *dbuf; | ||
| 222 | |||
| 223 | sbuf = kmalloc(src_linelength, GFP_KERNEL); | ||
| 224 | if (!sbuf) | ||
| 225 | return; | ||
| 226 | |||
| 227 | for (y = 0; y < lines; y++) { | ||
| 228 | memcpy(sbuf, src, src_linelength); | ||
| 229 | dbuf = dst; | ||
| 230 | for (x = 0; x < linepixels; x++) { | ||
| 231 | *dbuf++ = (sbuf[x] & 0x000000FF) >> 0; | ||
| 232 | *dbuf++ = (sbuf[x] & 0x0000FF00) >> 8; | ||
| 233 | *dbuf++ = (sbuf[x] & 0x00FF0000) >> 16; | ||
| 234 | } | ||
| 235 | src += src_pitch; | ||
| 236 | dst += dst_pitch; | ||
| 237 | } | ||
| 238 | |||
| 239 | kfree(sbuf); | ||
| 240 | } | ||
| 241 | |||
| 242 | /** | ||
| 243 | * drm_fb_xrgb8888_to_rgb888_dstclip - Convert XRGB8888 to RGB888 clip buffer | ||
| 244 | * @dst: RGB565 destination buffer | ||
| 245 | * @dst_pitch: destination buffer pitch | ||
| 246 | * @vaddr: XRGB8888 source buffer | ||
| 247 | * @fb: DRM framebuffer | ||
| 248 | * @clip: Clip rectangle area to copy | ||
| 249 | * @dstclip: Clip destination too. | ||
| 250 | * | ||
| 251 | * Drivers can use this function for RGB888 devices that don't natively | ||
| 252 | * support XRGB8888. | ||
| 253 | * | ||
| 254 | * This function applies clipping on dst, i.e. the destination is a | ||
| 255 | * full framebuffer but only the clip rect content is copied over. | ||
| 256 | */ | ||
| 257 | void drm_fb_xrgb8888_to_rgb888_dstclip(void *dst, unsigned int dst_pitch, | ||
| 258 | void *vaddr, struct drm_framebuffer *fb, | ||
| 259 | struct drm_rect *clip) | ||
| 260 | { | ||
| 261 | unsigned int src_offset = (clip->y1 * fb->pitches[0]) | ||
| 262 | + (clip->x1 * sizeof(u32)); | ||
| 263 | unsigned int dst_offset = (clip->y1 * dst_pitch) | ||
| 264 | + (clip->x1 * 3); | ||
| 265 | size_t src_len = (clip->x2 - clip->x1) * sizeof(u32); | ||
| 266 | |||
| 267 | drm_fb_xrgb8888_to_rgb888_lines(dst + dst_offset, dst_pitch, | ||
| 268 | vaddr + src_offset, fb->pitches[0], | ||
| 269 | src_len, clip->y2 - clip->y1); | ||
| 270 | } | ||
| 271 | EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888_dstclip); | ||
| 272 | |||
| 273 | /** | ||
| 274 | * drm_fb_xrgb8888_to_gray8 - Convert XRGB8888 to grayscale | ||
| 275 | * @dst: 8-bit grayscale destination buffer | ||
| 276 | * @vaddr: XRGB8888 source buffer | ||
| 277 | * @fb: DRM framebuffer | ||
| 278 | * @clip: Clip rectangle area to copy | ||
| 279 | * | ||
| 280 | * Drm doesn't have native monochrome or grayscale support. | ||
| 281 | * Such drivers can announce the commonly supported XR24 format to userspace | ||
| 282 | * and use this function to convert to the native format. | ||
| 283 | * | ||
| 284 | * Monochrome drivers will use the most significant bit, | ||
| 285 | * where 1 means foreground color and 0 background color. | ||
| 286 | * | ||
| 287 | * ITU BT.601 is used for the RGB -> luma (brightness) conversion. | ||
| 288 | */ | ||
| 289 | void drm_fb_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb, | ||
| 290 | struct drm_rect *clip) | ||
| 291 | { | ||
| 292 | unsigned int len = (clip->x2 - clip->x1) * sizeof(u32); | ||
| 293 | unsigned int x, y; | ||
| 294 | void *buf; | ||
| 295 | u32 *src; | ||
| 296 | |||
| 297 | if (WARN_ON(fb->format->format != DRM_FORMAT_XRGB8888)) | ||
| 298 | return; | ||
| 299 | /* | ||
| 300 | * The cma memory is write-combined so reads are uncached. | ||
| 301 | * Speed up by fetching one line at a time. | ||
| 302 | */ | ||
| 303 | buf = kmalloc(len, GFP_KERNEL); | ||
| 304 | if (!buf) | ||
| 305 | return; | ||
| 306 | |||
| 307 | for (y = clip->y1; y < clip->y2; y++) { | ||
| 308 | src = vaddr + (y * fb->pitches[0]); | ||
| 309 | src += clip->x1; | ||
| 310 | memcpy(buf, src, len); | ||
| 311 | src = buf; | ||
| 312 | for (x = clip->x1; x < clip->x2; x++) { | ||
| 313 | u8 r = (*src & 0x00ff0000) >> 16; | ||
| 314 | u8 g = (*src & 0x0000ff00) >> 8; | ||
| 315 | u8 b = *src & 0x000000ff; | ||
| 316 | |||
| 317 | /* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */ | ||
| 318 | *dst++ = (3 * r + 6 * g + b) / 10; | ||
| 319 | src++; | ||
| 320 | } | ||
| 321 | } | ||
| 322 | |||
| 323 | kfree(buf); | ||
| 324 | } | ||
| 325 | EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8); | ||
| 326 | |||
diff --git a/drivers/gpu/drm/lima/Kconfig b/drivers/gpu/drm/lima/Kconfig index f11314448093..bb4ddc6bb0a6 100644 --- a/drivers/gpu/drm/lima/Kconfig +++ b/drivers/gpu/drm/lima/Kconfig | |||
| @@ -5,6 +5,9 @@ config DRM_LIMA | |||
| 5 | tristate "LIMA (DRM support for ARM Mali 400/450 GPU)" | 5 | tristate "LIMA (DRM support for ARM Mali 400/450 GPU)" |
| 6 | depends on DRM | 6 | depends on DRM |
| 7 | depends on ARM || ARM64 || COMPILE_TEST | 7 | depends on ARM || ARM64 || COMPILE_TEST |
| 8 | depends on MMU | ||
| 9 | depends on COMMON_CLK | ||
| 10 | depends on OF | ||
| 8 | select DRM_SCHED | 11 | select DRM_SCHED |
| 9 | help | 12 | help |
| 10 | DRM driver for ARM Mali 400/450 GPUs. | 13 | DRM driver for ARM Mali 400/450 GPUs. |
diff --git a/drivers/gpu/drm/lima/lima_gem.c b/drivers/gpu/drm/lima/lima_gem.c index 2d3cf96f6c58..1d69498bc17e 100644 --- a/drivers/gpu/drm/lima/lima_gem.c +++ b/drivers/gpu/drm/lima/lima_gem.c | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 OR MIT | 1 | // SPDX-License-Identifier: GPL-2.0 OR MIT |
| 2 | /* Copyright 2017-2019 Qiang Yu <yuq825@gmail.com> */ | 2 | /* Copyright 2017-2019 Qiang Yu <yuq825@gmail.com> */ |
| 3 | 3 | ||
| 4 | #include <linux/mm.h> | ||
| 4 | #include <linux/sync_file.h> | 5 | #include <linux/sync_file.h> |
| 5 | #include <linux/pfn_t.h> | 6 | #include <linux/pfn_t.h> |
| 6 | 7 | ||
diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c index 6d9311e254ef..5579f8ac3e3f 100644 --- a/drivers/gpu/drm/meson/meson_crtc.c +++ b/drivers/gpu/drm/meson/meson_crtc.c | |||
| @@ -39,12 +39,17 @@ | |||
| 39 | #include "meson_viu.h" | 39 | #include "meson_viu.h" |
| 40 | #include "meson_registers.h" | 40 | #include "meson_registers.h" |
| 41 | 41 | ||
| 42 | #define MESON_G12A_VIU_OFFSET 0x5ec0 | ||
| 43 | |||
| 42 | /* CRTC definition */ | 44 | /* CRTC definition */ |
| 43 | 45 | ||
| 44 | struct meson_crtc { | 46 | struct meson_crtc { |
| 45 | struct drm_crtc base; | 47 | struct drm_crtc base; |
| 46 | struct drm_pending_vblank_event *event; | 48 | struct drm_pending_vblank_event *event; |
| 47 | struct meson_drm *priv; | 49 | struct meson_drm *priv; |
| 50 | void (*enable_osd1)(struct meson_drm *priv); | ||
| 51 | void (*enable_vd1)(struct meson_drm *priv); | ||
| 52 | unsigned int viu_offset; | ||
| 48 | }; | 53 | }; |
| 49 | #define to_meson_crtc(x) container_of(x, struct meson_crtc, base) | 54 | #define to_meson_crtc(x) container_of(x, struct meson_crtc, base) |
| 50 | 55 | ||
| @@ -80,6 +85,44 @@ static const struct drm_crtc_funcs meson_crtc_funcs = { | |||
| 80 | 85 | ||
| 81 | }; | 86 | }; |
| 82 | 87 | ||
| 88 | static void meson_g12a_crtc_atomic_enable(struct drm_crtc *crtc, | ||
| 89 | struct drm_crtc_state *old_state) | ||
| 90 | { | ||
| 91 | struct meson_crtc *meson_crtc = to_meson_crtc(crtc); | ||
| 92 | struct drm_crtc_state *crtc_state = crtc->state; | ||
| 93 | struct meson_drm *priv = meson_crtc->priv; | ||
| 94 | |||
| 95 | DRM_DEBUG_DRIVER("\n"); | ||
| 96 | |||
| 97 | if (!crtc_state) { | ||
| 98 | DRM_ERROR("Invalid crtc_state\n"); | ||
| 99 | return; | ||
| 100 | } | ||
| 101 | |||
| 102 | /* VD1 Preblend vertical start/end */ | ||
| 103 | writel(FIELD_PREP(GENMASK(11, 0), 2303), | ||
| 104 | priv->io_base + _REG(VPP_PREBLEND_VD1_V_START_END)); | ||
| 105 | |||
| 106 | /* Setup Blender */ | ||
| 107 | writel(crtc_state->mode.hdisplay | | ||
| 108 | crtc_state->mode.vdisplay << 16, | ||
| 109 | priv->io_base + _REG(VPP_POSTBLEND_H_SIZE)); | ||
| 110 | |||
| 111 | writel_relaxed(0 << 16 | | ||
| 112 | (crtc_state->mode.hdisplay - 1), | ||
| 113 | priv->io_base + _REG(VPP_OSD1_BLD_H_SCOPE)); | ||
| 114 | writel_relaxed(0 << 16 | | ||
| 115 | (crtc_state->mode.vdisplay - 1), | ||
| 116 | priv->io_base + _REG(VPP_OSD1_BLD_V_SCOPE)); | ||
| 117 | writel_relaxed(crtc_state->mode.hdisplay << 16 | | ||
| 118 | crtc_state->mode.vdisplay, | ||
| 119 | priv->io_base + _REG(VPP_OUT_H_V_SIZE)); | ||
| 120 | |||
| 121 | drm_crtc_vblank_on(crtc); | ||
| 122 | |||
| 123 | priv->viu.osd1_enabled = true; | ||
| 124 | } | ||
| 125 | |||
| 83 | static void meson_crtc_atomic_enable(struct drm_crtc *crtc, | 126 | static void meson_crtc_atomic_enable(struct drm_crtc *crtc, |
| 84 | struct drm_crtc_state *old_state) | 127 | struct drm_crtc_state *old_state) |
| 85 | { | 128 | { |
| @@ -110,6 +153,31 @@ static void meson_crtc_atomic_enable(struct drm_crtc *crtc, | |||
| 110 | priv->viu.osd1_enabled = true; | 153 | priv->viu.osd1_enabled = true; |
| 111 | } | 154 | } |
| 112 | 155 | ||
| 156 | static void meson_g12a_crtc_atomic_disable(struct drm_crtc *crtc, | ||
| 157 | struct drm_crtc_state *old_state) | ||
| 158 | { | ||
| 159 | struct meson_crtc *meson_crtc = to_meson_crtc(crtc); | ||
| 160 | struct meson_drm *priv = meson_crtc->priv; | ||
| 161 | |||
| 162 | DRM_DEBUG_DRIVER("\n"); | ||
| 163 | |||
| 164 | drm_crtc_vblank_off(crtc); | ||
| 165 | |||
| 166 | priv->viu.osd1_enabled = false; | ||
| 167 | priv->viu.osd1_commit = false; | ||
| 168 | |||
| 169 | priv->viu.vd1_enabled = false; | ||
| 170 | priv->viu.vd1_commit = false; | ||
| 171 | |||
| 172 | if (crtc->state->event && !crtc->state->active) { | ||
| 173 | spin_lock_irq(&crtc->dev->event_lock); | ||
| 174 | drm_crtc_send_vblank_event(crtc, crtc->state->event); | ||
| 175 | spin_unlock_irq(&crtc->dev->event_lock); | ||
| 176 | |||
| 177 | crtc->state->event = NULL; | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 113 | static void meson_crtc_atomic_disable(struct drm_crtc *crtc, | 181 | static void meson_crtc_atomic_disable(struct drm_crtc *crtc, |
| 114 | struct drm_crtc_state *old_state) | 182 | struct drm_crtc_state *old_state) |
| 115 | { | 183 | { |
| @@ -173,6 +241,53 @@ static const struct drm_crtc_helper_funcs meson_crtc_helper_funcs = { | |||
| 173 | .atomic_disable = meson_crtc_atomic_disable, | 241 | .atomic_disable = meson_crtc_atomic_disable, |
| 174 | }; | 242 | }; |
| 175 | 243 | ||
| 244 | static const struct drm_crtc_helper_funcs meson_g12a_crtc_helper_funcs = { | ||
| 245 | .atomic_begin = meson_crtc_atomic_begin, | ||
| 246 | .atomic_flush = meson_crtc_atomic_flush, | ||
| 247 | .atomic_enable = meson_g12a_crtc_atomic_enable, | ||
| 248 | .atomic_disable = meson_g12a_crtc_atomic_disable, | ||
| 249 | }; | ||
| 250 | |||
| 251 | static void meson_crtc_enable_osd1(struct meson_drm *priv) | ||
| 252 | { | ||
| 253 | writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND, | ||
| 254 | priv->io_base + _REG(VPP_MISC)); | ||
| 255 | } | ||
| 256 | |||
| 257 | static void meson_g12a_crtc_enable_osd1(struct meson_drm *priv) | ||
| 258 | { | ||
| 259 | writel_relaxed(priv->viu.osd_blend_din0_scope_h, | ||
| 260 | priv->io_base + | ||
| 261 | _REG(VIU_OSD_BLEND_DIN0_SCOPE_H)); | ||
| 262 | writel_relaxed(priv->viu.osd_blend_din0_scope_v, | ||
| 263 | priv->io_base + | ||
| 264 | _REG(VIU_OSD_BLEND_DIN0_SCOPE_V)); | ||
| 265 | writel_relaxed(priv->viu.osb_blend0_size, | ||
| 266 | priv->io_base + | ||
| 267 | _REG(VIU_OSD_BLEND_BLEND0_SIZE)); | ||
| 268 | writel_relaxed(priv->viu.osb_blend1_size, | ||
| 269 | priv->io_base + | ||
| 270 | _REG(VIU_OSD_BLEND_BLEND1_SIZE)); | ||
| 271 | } | ||
| 272 | |||
| 273 | static void meson_crtc_enable_vd1(struct meson_drm *priv) | ||
| 274 | { | ||
| 275 | writel_bits_relaxed(VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | | ||
| 276 | VPP_COLOR_MNG_ENABLE, | ||
| 277 | VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | | ||
| 278 | VPP_COLOR_MNG_ENABLE, | ||
| 279 | priv->io_base + _REG(VPP_MISC)); | ||
| 280 | } | ||
| 281 | |||
| 282 | static void meson_g12a_crtc_enable_vd1(struct meson_drm *priv) | ||
| 283 | { | ||
| 284 | writel_relaxed(((1 << 16) | /* post bld premult*/ | ||
| 285 | (1 << 8) | /* post src */ | ||
| 286 | (1 << 4) | /* pre bld premult*/ | ||
| 287 | (1 << 0)), | ||
| 288 | priv->io_base + _REG(VD1_BLEND_SRC_CTRL)); | ||
| 289 | } | ||
| 290 | |||
| 176 | void meson_crtc_irq(struct meson_drm *priv) | 291 | void meson_crtc_irq(struct meson_drm *priv) |
| 177 | { | 292 | { |
| 178 | struct meson_crtc *meson_crtc = to_meson_crtc(priv->crtc); | 293 | struct meson_crtc *meson_crtc = to_meson_crtc(priv->crtc); |
| @@ -219,8 +334,8 @@ void meson_crtc_irq(struct meson_drm *priv) | |||
| 219 | MESON_CANVAS_BLKMODE_LINEAR, 0); | 334 | MESON_CANVAS_BLKMODE_LINEAR, 0); |
| 220 | 335 | ||
| 221 | /* Enable OSD1 */ | 336 | /* Enable OSD1 */ |
| 222 | writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND, | 337 | if (meson_crtc->enable_osd1) |
| 223 | priv->io_base + _REG(VPP_MISC)); | 338 | meson_crtc->enable_osd1(priv); |
| 224 | 339 | ||
| 225 | priv->viu.osd1_commit = false; | 340 | priv->viu.osd1_commit = false; |
| 226 | } | 341 | } |
| @@ -261,89 +376,133 @@ void meson_crtc_irq(struct meson_drm *priv) | |||
| 261 | }; | 376 | }; |
| 262 | 377 | ||
| 263 | writel_relaxed(priv->viu.vd1_if0_gen_reg, | 378 | writel_relaxed(priv->viu.vd1_if0_gen_reg, |
| 264 | priv->io_base + _REG(VD1_IF0_GEN_REG)); | 379 | priv->io_base + meson_crtc->viu_offset + |
| 380 | _REG(VD1_IF0_GEN_REG)); | ||
| 265 | writel_relaxed(priv->viu.vd1_if0_gen_reg, | 381 | writel_relaxed(priv->viu.vd1_if0_gen_reg, |
| 266 | priv->io_base + _REG(VD2_IF0_GEN_REG)); | 382 | priv->io_base + meson_crtc->viu_offset + |
| 383 | _REG(VD2_IF0_GEN_REG)); | ||
| 267 | writel_relaxed(priv->viu.vd1_if0_gen_reg2, | 384 | writel_relaxed(priv->viu.vd1_if0_gen_reg2, |
| 268 | priv->io_base + _REG(VD1_IF0_GEN_REG2)); | 385 | priv->io_base + meson_crtc->viu_offset + |
| 386 | _REG(VD1_IF0_GEN_REG2)); | ||
| 269 | writel_relaxed(priv->viu.viu_vd1_fmt_ctrl, | 387 | writel_relaxed(priv->viu.viu_vd1_fmt_ctrl, |
| 270 | priv->io_base + _REG(VIU_VD1_FMT_CTRL)); | 388 | priv->io_base + meson_crtc->viu_offset + |
| 389 | _REG(VIU_VD1_FMT_CTRL)); | ||
| 271 | writel_relaxed(priv->viu.viu_vd1_fmt_ctrl, | 390 | writel_relaxed(priv->viu.viu_vd1_fmt_ctrl, |
| 272 | priv->io_base + _REG(VIU_VD2_FMT_CTRL)); | 391 | priv->io_base + meson_crtc->viu_offset + |
| 392 | _REG(VIU_VD2_FMT_CTRL)); | ||
| 273 | writel_relaxed(priv->viu.viu_vd1_fmt_w, | 393 | writel_relaxed(priv->viu.viu_vd1_fmt_w, |
| 274 | priv->io_base + _REG(VIU_VD1_FMT_W)); | 394 | priv->io_base + meson_crtc->viu_offset + |
| 395 | _REG(VIU_VD1_FMT_W)); | ||
| 275 | writel_relaxed(priv->viu.viu_vd1_fmt_w, | 396 | writel_relaxed(priv->viu.viu_vd1_fmt_w, |
| 276 | priv->io_base + _REG(VIU_VD2_FMT_W)); | 397 | priv->io_base + meson_crtc->viu_offset + |
| 398 | _REG(VIU_VD2_FMT_W)); | ||
| 277 | writel_relaxed(priv->viu.vd1_if0_canvas0, | 399 | writel_relaxed(priv->viu.vd1_if0_canvas0, |
| 278 | priv->io_base + _REG(VD1_IF0_CANVAS0)); | 400 | priv->io_base + meson_crtc->viu_offset + |
| 401 | _REG(VD1_IF0_CANVAS0)); | ||
| 279 | writel_relaxed(priv->viu.vd1_if0_canvas0, | 402 | writel_relaxed(priv->viu.vd1_if0_canvas0, |
| 280 | priv->io_base + _REG(VD1_IF0_CANVAS1)); | 403 | priv->io_base + meson_crtc->viu_offset + |
| 404 | _REG(VD1_IF0_CANVAS1)); | ||
| 281 | writel_relaxed(priv->viu.vd1_if0_canvas0, | 405 | writel_relaxed(priv->viu.vd1_if0_canvas0, |
| 282 | priv->io_base + _REG(VD2_IF0_CANVAS0)); | 406 | priv->io_base + meson_crtc->viu_offset + |
| 407 | _REG(VD2_IF0_CANVAS0)); | ||
| 283 | writel_relaxed(priv->viu.vd1_if0_canvas0, | 408 | writel_relaxed(priv->viu.vd1_if0_canvas0, |
| 284 | priv->io_base + _REG(VD2_IF0_CANVAS1)); | 409 | priv->io_base + meson_crtc->viu_offset + |
| 410 | _REG(VD2_IF0_CANVAS1)); | ||
| 285 | writel_relaxed(priv->viu.vd1_if0_luma_x0, | 411 | writel_relaxed(priv->viu.vd1_if0_luma_x0, |
| 286 | priv->io_base + _REG(VD1_IF0_LUMA_X0)); | 412 | priv->io_base + meson_crtc->viu_offset + |
| 413 | _REG(VD1_IF0_LUMA_X0)); | ||
| 287 | writel_relaxed(priv->viu.vd1_if0_luma_x0, | 414 | writel_relaxed(priv->viu.vd1_if0_luma_x0, |
| 288 | priv->io_base + _REG(VD1_IF0_LUMA_X1)); | 415 | priv->io_base + meson_crtc->viu_offset + |
| 416 | _REG(VD1_IF0_LUMA_X1)); | ||
| 289 | writel_relaxed(priv->viu.vd1_if0_luma_x0, | 417 | writel_relaxed(priv->viu.vd1_if0_luma_x0, |
| 290 | priv->io_base + _REG(VD2_IF0_LUMA_X0)); | 418 | priv->io_base + meson_crtc->viu_offset + |
| 419 | _REG(VD2_IF0_LUMA_X0)); | ||
| 291 | writel_relaxed(priv->viu.vd1_if0_luma_x0, | 420 | writel_relaxed(priv->viu.vd1_if0_luma_x0, |
| 292 | priv->io_base + _REG(VD2_IF0_LUMA_X1)); | 421 | priv->io_base + meson_crtc->viu_offset + |
| 422 | _REG(VD2_IF0_LUMA_X1)); | ||
| 293 | writel_relaxed(priv->viu.vd1_if0_luma_y0, | 423 | writel_relaxed(priv->viu.vd1_if0_luma_y0, |
| 294 | priv->io_base + _REG(VD1_IF0_LUMA_Y0)); | 424 | priv->io_base + meson_crtc->viu_offset + |
| 425 | _REG(VD1_IF0_LUMA_Y0)); | ||
| 295 | writel_relaxed(priv->viu.vd1_if0_luma_y0, | 426 | writel_relaxed(priv->viu.vd1_if0_luma_y0, |
| 296 | priv->io_base + _REG(VD1_IF0_LUMA_Y1)); | 427 | priv->io_base + meson_crtc->viu_offset + |
| 428 | _REG(VD1_IF0_LUMA_Y1)); | ||
| 297 | writel_relaxed(priv->viu.vd1_if0_luma_y0, | 429 | writel_relaxed(priv->viu.vd1_if0_luma_y0, |
| 298 | priv->io_base + _REG(VD2_IF0_LUMA_Y0)); | 430 | priv->io_base + meson_crtc->viu_offset + |
| 431 | _REG(VD2_IF0_LUMA_Y0)); | ||
| 299 | writel_relaxed(priv->viu.vd1_if0_luma_y0, | 432 | writel_relaxed(priv->viu.vd1_if0_luma_y0, |
| 300 | priv->io_base + _REG(VD2_IF0_LUMA_Y1)); | 433 | priv->io_base + meson_crtc->viu_offset + |
| 434 | _REG(VD2_IF0_LUMA_Y1)); | ||
| 301 | writel_relaxed(priv->viu.vd1_if0_chroma_x0, | 435 | writel_relaxed(priv->viu.vd1_if0_chroma_x0, |
| 302 | priv->io_base + _REG(VD1_IF0_CHROMA_X0)); | 436 | priv->io_base + meson_crtc->viu_offset + |
| 437 | _REG(VD1_IF0_CHROMA_X0)); | ||
| 303 | writel_relaxed(priv->viu.vd1_if0_chroma_x0, | 438 | writel_relaxed(priv->viu.vd1_if0_chroma_x0, |
| 304 | priv->io_base + _REG(VD1_IF0_CHROMA_X1)); | 439 | priv->io_base + meson_crtc->viu_offset + |
| 440 | _REG(VD1_IF0_CHROMA_X1)); | ||
| 305 | writel_relaxed(priv->viu.vd1_if0_chroma_x0, | 441 | writel_relaxed(priv->viu.vd1_if0_chroma_x0, |
| 306 | priv->io_base + _REG(VD2_IF0_CHROMA_X0)); | 442 | priv->io_base + meson_crtc->viu_offset + |
| 443 | _REG(VD2_IF0_CHROMA_X0)); | ||
| 307 | writel_relaxed(priv->viu.vd1_if0_chroma_x0, | 444 | writel_relaxed(priv->viu.vd1_if0_chroma_x0, |
| 308 | priv->io_base + _REG(VD2_IF0_CHROMA_X1)); | 445 | priv->io_base + meson_crtc->viu_offset + |
| 446 | _REG(VD2_IF0_CHROMA_X1)); | ||
| 309 | writel_relaxed(priv->viu.vd1_if0_chroma_y0, | 447 | writel_relaxed(priv->viu.vd1_if0_chroma_y0, |
| 310 | priv->io_base + _REG(VD1_IF0_CHROMA_Y0)); | 448 | priv->io_base + meson_crtc->viu_offset + |
| 449 | _REG(VD1_IF0_CHROMA_Y0)); | ||
| 311 | writel_relaxed(priv->viu.vd1_if0_chroma_y0, | 450 | writel_relaxed(priv->viu.vd1_if0_chroma_y0, |
| 312 | priv->io_base + _REG(VD1_IF0_CHROMA_Y1)); | 451 | priv->io_base + meson_crtc->viu_offset + |
| 452 | _REG(VD1_IF0_CHROMA_Y1)); | ||
| 313 | writel_relaxed(priv->viu.vd1_if0_chroma_y0, | 453 | writel_relaxed(priv->viu.vd1_if0_chroma_y0, |
| 314 | priv->io_base + _REG(VD2_IF0_CHROMA_Y0)); | 454 | priv->io_base + meson_crtc->viu_offset + |
| 455 | _REG(VD2_IF0_CHROMA_Y0)); | ||
| 315 | writel_relaxed(priv->viu.vd1_if0_chroma_y0, | 456 | writel_relaxed(priv->viu.vd1_if0_chroma_y0, |
| 316 | priv->io_base + _REG(VD2_IF0_CHROMA_Y1)); | 457 | priv->io_base + meson_crtc->viu_offset + |
| 458 | _REG(VD2_IF0_CHROMA_Y1)); | ||
| 317 | writel_relaxed(priv->viu.vd1_if0_repeat_loop, | 459 | writel_relaxed(priv->viu.vd1_if0_repeat_loop, |
| 318 | priv->io_base + _REG(VD1_IF0_RPT_LOOP)); | 460 | priv->io_base + meson_crtc->viu_offset + |
| 461 | _REG(VD1_IF0_RPT_LOOP)); | ||
| 319 | writel_relaxed(priv->viu.vd1_if0_repeat_loop, | 462 | writel_relaxed(priv->viu.vd1_if0_repeat_loop, |
| 320 | priv->io_base + _REG(VD2_IF0_RPT_LOOP)); | 463 | priv->io_base + meson_crtc->viu_offset + |
| 464 | _REG(VD2_IF0_RPT_LOOP)); | ||
| 321 | writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, | 465 | writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, |
| 322 | priv->io_base + _REG(VD1_IF0_LUMA0_RPT_PAT)); | 466 | priv->io_base + meson_crtc->viu_offset + |
| 467 | _REG(VD1_IF0_LUMA0_RPT_PAT)); | ||
| 323 | writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, | 468 | writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, |
| 324 | priv->io_base + _REG(VD2_IF0_LUMA0_RPT_PAT)); | 469 | priv->io_base + meson_crtc->viu_offset + |
| 470 | _REG(VD2_IF0_LUMA0_RPT_PAT)); | ||
| 325 | writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, | 471 | writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, |
| 326 | priv->io_base + _REG(VD1_IF0_LUMA1_RPT_PAT)); | 472 | priv->io_base + meson_crtc->viu_offset + |
| 473 | _REG(VD1_IF0_LUMA1_RPT_PAT)); | ||
| 327 | writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, | 474 | writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, |
| 328 | priv->io_base + _REG(VD2_IF0_LUMA1_RPT_PAT)); | 475 | priv->io_base + meson_crtc->viu_offset + |
| 476 | _REG(VD2_IF0_LUMA1_RPT_PAT)); | ||
| 329 | writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, | 477 | writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, |
| 330 | priv->io_base + _REG(VD1_IF0_CHROMA0_RPT_PAT)); | 478 | priv->io_base + meson_crtc->viu_offset + |
| 479 | _REG(VD1_IF0_CHROMA0_RPT_PAT)); | ||
| 331 | writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, | 480 | writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, |
| 332 | priv->io_base + _REG(VD2_IF0_CHROMA0_RPT_PAT)); | 481 | priv->io_base + meson_crtc->viu_offset + |
| 482 | _REG(VD2_IF0_CHROMA0_RPT_PAT)); | ||
| 333 | writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, | 483 | writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, |
| 334 | priv->io_base + _REG(VD1_IF0_CHROMA1_RPT_PAT)); | 484 | priv->io_base + meson_crtc->viu_offset + |
| 485 | _REG(VD1_IF0_CHROMA1_RPT_PAT)); | ||
| 335 | writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, | 486 | writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, |
| 336 | priv->io_base + _REG(VD2_IF0_CHROMA1_RPT_PAT)); | 487 | priv->io_base + meson_crtc->viu_offset + |
| 337 | writel_relaxed(0, priv->io_base + _REG(VD1_IF0_LUMA_PSEL)); | 488 | _REG(VD2_IF0_CHROMA1_RPT_PAT)); |
| 338 | writel_relaxed(0, priv->io_base + _REG(VD1_IF0_CHROMA_PSEL)); | 489 | writel_relaxed(0, priv->io_base + meson_crtc->viu_offset + |
| 339 | writel_relaxed(0, priv->io_base + _REG(VD2_IF0_LUMA_PSEL)); | 490 | _REG(VD1_IF0_LUMA_PSEL)); |
| 340 | writel_relaxed(0, priv->io_base + _REG(VD2_IF0_CHROMA_PSEL)); | 491 | writel_relaxed(0, priv->io_base + meson_crtc->viu_offset + |
| 492 | _REG(VD1_IF0_CHROMA_PSEL)); | ||
| 493 | writel_relaxed(0, priv->io_base + meson_crtc->viu_offset + | ||
| 494 | _REG(VD2_IF0_LUMA_PSEL)); | ||
| 495 | writel_relaxed(0, priv->io_base + meson_crtc->viu_offset + | ||
| 496 | _REG(VD2_IF0_CHROMA_PSEL)); | ||
| 341 | writel_relaxed(priv->viu.vd1_range_map_y, | 497 | writel_relaxed(priv->viu.vd1_range_map_y, |
| 342 | priv->io_base + _REG(VD1_IF0_RANGE_MAP_Y)); | 498 | priv->io_base + meson_crtc->viu_offset + |
| 499 | _REG(VD1_IF0_RANGE_MAP_Y)); | ||
| 343 | writel_relaxed(priv->viu.vd1_range_map_cb, | 500 | writel_relaxed(priv->viu.vd1_range_map_cb, |
| 344 | priv->io_base + _REG(VD1_IF0_RANGE_MAP_CB)); | 501 | priv->io_base + meson_crtc->viu_offset + |
| 502 | _REG(VD1_IF0_RANGE_MAP_CB)); | ||
| 345 | writel_relaxed(priv->viu.vd1_range_map_cr, | 503 | writel_relaxed(priv->viu.vd1_range_map_cr, |
| 346 | priv->io_base + _REG(VD1_IF0_RANGE_MAP_CR)); | 504 | priv->io_base + meson_crtc->viu_offset + |
| 505 | _REG(VD1_IF0_RANGE_MAP_CR)); | ||
| 347 | writel_relaxed(0x78404, | 506 | writel_relaxed(0x78404, |
| 348 | priv->io_base + _REG(VPP_SC_MISC)); | 507 | priv->io_base + _REG(VPP_SC_MISC)); |
| 349 | writel_relaxed(priv->viu.vpp_pic_in_height, | 508 | writel_relaxed(priv->viu.vpp_pic_in_height, |
| @@ -389,11 +548,8 @@ void meson_crtc_irq(struct meson_drm *priv) | |||
| 389 | writel_relaxed(0x42, priv->io_base + _REG(VPP_SCALE_COEF_IDX)); | 548 | writel_relaxed(0x42, priv->io_base + _REG(VPP_SCALE_COEF_IDX)); |
| 390 | 549 | ||
| 391 | /* Enable VD1 */ | 550 | /* Enable VD1 */ |
| 392 | writel_bits_relaxed(VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | | 551 | if (meson_crtc->enable_vd1) |
| 393 | VPP_COLOR_MNG_ENABLE, | 552 | meson_crtc->enable_vd1(priv); |
| 394 | VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | | ||
| 395 | VPP_COLOR_MNG_ENABLE, | ||
| 396 | priv->io_base + _REG(VPP_MISC)); | ||
| 397 | 553 | ||
| 398 | priv->viu.vd1_commit = false; | 554 | priv->viu.vd1_commit = false; |
| 399 | } | 555 | } |
| @@ -430,7 +586,16 @@ int meson_crtc_create(struct meson_drm *priv) | |||
| 430 | return ret; | 586 | return ret; |
| 431 | } | 587 | } |
| 432 | 588 | ||
| 433 | drm_crtc_helper_add(crtc, &meson_crtc_helper_funcs); | 589 | if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { |
| 590 | meson_crtc->enable_osd1 = meson_g12a_crtc_enable_osd1; | ||
| 591 | meson_crtc->enable_vd1 = meson_g12a_crtc_enable_vd1; | ||
| 592 | meson_crtc->viu_offset = MESON_G12A_VIU_OFFSET; | ||
| 593 | drm_crtc_helper_add(crtc, &meson_g12a_crtc_helper_funcs); | ||
| 594 | } else { | ||
| 595 | meson_crtc->enable_osd1 = meson_crtc_enable_osd1; | ||
| 596 | meson_crtc->enable_vd1 = meson_crtc_enable_vd1; | ||
| 597 | drm_crtc_helper_add(crtc, &meson_crtc_helper_funcs); | ||
| 598 | } | ||
| 434 | 599 | ||
| 435 | priv->crtc = crtc; | 600 | priv->crtc = crtc; |
| 436 | 601 | ||
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index 70f9d7b85e8e..937cfabb95df 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c | |||
| @@ -444,6 +444,7 @@ static const struct of_device_id dt_match[] = { | |||
| 444 | { .compatible = "amlogic,meson-gxbb-vpu" }, | 444 | { .compatible = "amlogic,meson-gxbb-vpu" }, |
| 445 | { .compatible = "amlogic,meson-gxl-vpu" }, | 445 | { .compatible = "amlogic,meson-gxl-vpu" }, |
| 446 | { .compatible = "amlogic,meson-gxm-vpu" }, | 446 | { .compatible = "amlogic,meson-gxm-vpu" }, |
| 447 | { .compatible = "amlogic,meson-g12a-vpu" }, | ||
| 447 | {} | 448 | {} |
| 448 | }; | 449 | }; |
| 449 | MODULE_DEVICE_TABLE(of, dt_match); | 450 | MODULE_DEVICE_TABLE(of, dt_match); |
diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h index 214a7cb18ce2..9614baa836b9 100644 --- a/drivers/gpu/drm/meson/meson_drv.h +++ b/drivers/gpu/drm/meson/meson_drv.h | |||
| @@ -62,6 +62,10 @@ struct meson_drm { | |||
| 62 | uint32_t osd_sc_h_phase_step; | 62 | uint32_t osd_sc_h_phase_step; |
| 63 | uint32_t osd_sc_h_ctrl0; | 63 | uint32_t osd_sc_h_ctrl0; |
| 64 | uint32_t osd_sc_v_ctrl0; | 64 | uint32_t osd_sc_v_ctrl0; |
| 65 | uint32_t osd_blend_din0_scope_h; | ||
| 66 | uint32_t osd_blend_din0_scope_v; | ||
| 67 | uint32_t osb_blend0_size; | ||
| 68 | uint32_t osb_blend1_size; | ||
| 65 | 69 | ||
| 66 | bool vd1_enabled; | 70 | bool vd1_enabled; |
| 67 | bool vd1_commit; | 71 | bool vd1_commit; |
diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c index e28814f4ea6c..2a860d158f4f 100644 --- a/drivers/gpu/drm/meson/meson_dw_hdmi.c +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
| 21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
| 22 | #include <linux/component.h> | 22 | #include <linux/component.h> |
| 23 | #include <linux/of_device.h> | ||
| 23 | #include <linux/of_graph.h> | 24 | #include <linux/of_graph.h> |
| 24 | #include <linux/reset.h> | 25 | #include <linux/reset.h> |
| 25 | #include <linux/clk.h> | 26 | #include <linux/clk.h> |
| @@ -105,6 +106,7 @@ | |||
| 105 | #define HDMITX_TOP_ADDR_REG 0x0 | 106 | #define HDMITX_TOP_ADDR_REG 0x0 |
| 106 | #define HDMITX_TOP_DATA_REG 0x4 | 107 | #define HDMITX_TOP_DATA_REG 0x4 |
| 107 | #define HDMITX_TOP_CTRL_REG 0x8 | 108 | #define HDMITX_TOP_CTRL_REG 0x8 |
| 109 | #define HDMITX_TOP_G12A_OFFSET 0x8000 | ||
| 108 | 110 | ||
| 109 | /* Controller Communication Channel */ | 111 | /* Controller Communication Channel */ |
| 110 | #define HDMITX_DWC_ADDR_REG 0x10 | 112 | #define HDMITX_DWC_ADDR_REG 0x10 |
| @@ -118,6 +120,8 @@ | |||
| 118 | #define HHI_HDMI_PHY_CNTL1 0x3a4 /* 0xe9 */ | 120 | #define HHI_HDMI_PHY_CNTL1 0x3a4 /* 0xe9 */ |
| 119 | #define HHI_HDMI_PHY_CNTL2 0x3a8 /* 0xea */ | 121 | #define HHI_HDMI_PHY_CNTL2 0x3a8 /* 0xea */ |
| 120 | #define HHI_HDMI_PHY_CNTL3 0x3ac /* 0xeb */ | 122 | #define HHI_HDMI_PHY_CNTL3 0x3ac /* 0xeb */ |
| 123 | #define HHI_HDMI_PHY_CNTL4 0x3b0 /* 0xec */ | ||
| 124 | #define HHI_HDMI_PHY_CNTL5 0x3b4 /* 0xed */ | ||
| 121 | 125 | ||
| 122 | static DEFINE_SPINLOCK(reg_lock); | 126 | static DEFINE_SPINLOCK(reg_lock); |
| 123 | 127 | ||
| @@ -127,12 +131,26 @@ enum meson_venc_source { | |||
| 127 | MESON_VENC_SOURCE_ENCP = 2, | 131 | MESON_VENC_SOURCE_ENCP = 2, |
| 128 | }; | 132 | }; |
| 129 | 133 | ||
| 134 | struct meson_dw_hdmi; | ||
| 135 | |||
| 136 | struct meson_dw_hdmi_data { | ||
| 137 | unsigned int (*top_read)(struct meson_dw_hdmi *dw_hdmi, | ||
| 138 | unsigned int addr); | ||
| 139 | void (*top_write)(struct meson_dw_hdmi *dw_hdmi, | ||
| 140 | unsigned int addr, unsigned int data); | ||
| 141 | unsigned int (*dwc_read)(struct meson_dw_hdmi *dw_hdmi, | ||
| 142 | unsigned int addr); | ||
| 143 | void (*dwc_write)(struct meson_dw_hdmi *dw_hdmi, | ||
| 144 | unsigned int addr, unsigned int data); | ||
| 145 | }; | ||
| 146 | |||
| 130 | struct meson_dw_hdmi { | 147 | struct meson_dw_hdmi { |
| 131 | struct drm_encoder encoder; | 148 | struct drm_encoder encoder; |
| 132 | struct dw_hdmi_plat_data dw_plat_data; | 149 | struct dw_hdmi_plat_data dw_plat_data; |
| 133 | struct meson_drm *priv; | 150 | struct meson_drm *priv; |
| 134 | struct device *dev; | 151 | struct device *dev; |
| 135 | void __iomem *hdmitx; | 152 | void __iomem *hdmitx; |
| 153 | const struct meson_dw_hdmi_data *data; | ||
| 136 | struct reset_control *hdmitx_apb; | 154 | struct reset_control *hdmitx_apb; |
| 137 | struct reset_control *hdmitx_ctrl; | 155 | struct reset_control *hdmitx_ctrl; |
| 138 | struct reset_control *hdmitx_phy; | 156 | struct reset_control *hdmitx_phy; |
| @@ -174,6 +192,12 @@ static unsigned int dw_hdmi_top_read(struct meson_dw_hdmi *dw_hdmi, | |||
| 174 | return data; | 192 | return data; |
| 175 | } | 193 | } |
| 176 | 194 | ||
| 195 | static unsigned int dw_hdmi_g12a_top_read(struct meson_dw_hdmi *dw_hdmi, | ||
| 196 | unsigned int addr) | ||
| 197 | { | ||
| 198 | return readl(dw_hdmi->hdmitx + HDMITX_TOP_G12A_OFFSET + (addr << 2)); | ||
| 199 | } | ||
| 200 | |||
| 177 | static inline void dw_hdmi_top_write(struct meson_dw_hdmi *dw_hdmi, | 201 | static inline void dw_hdmi_top_write(struct meson_dw_hdmi *dw_hdmi, |
| 178 | unsigned int addr, unsigned int data) | 202 | unsigned int addr, unsigned int data) |
| 179 | { | 203 | { |
| @@ -191,18 +215,24 @@ static inline void dw_hdmi_top_write(struct meson_dw_hdmi *dw_hdmi, | |||
| 191 | spin_unlock_irqrestore(®_lock, flags); | 215 | spin_unlock_irqrestore(®_lock, flags); |
| 192 | } | 216 | } |
| 193 | 217 | ||
| 218 | static inline void dw_hdmi_g12a_top_write(struct meson_dw_hdmi *dw_hdmi, | ||
| 219 | unsigned int addr, unsigned int data) | ||
| 220 | { | ||
| 221 | writel(data, dw_hdmi->hdmitx + HDMITX_TOP_G12A_OFFSET + (addr << 2)); | ||
| 222 | } | ||
| 223 | |||
| 194 | /* Helper to change specific bits in PHY registers */ | 224 | /* Helper to change specific bits in PHY registers */ |
| 195 | static inline void dw_hdmi_top_write_bits(struct meson_dw_hdmi *dw_hdmi, | 225 | static inline void dw_hdmi_top_write_bits(struct meson_dw_hdmi *dw_hdmi, |
| 196 | unsigned int addr, | 226 | unsigned int addr, |
| 197 | unsigned int mask, | 227 | unsigned int mask, |
| 198 | unsigned int val) | 228 | unsigned int val) |
| 199 | { | 229 | { |
| 200 | unsigned int data = dw_hdmi_top_read(dw_hdmi, addr); | 230 | unsigned int data = dw_hdmi->data->top_read(dw_hdmi, addr); |
| 201 | 231 | ||
| 202 | data &= ~mask; | 232 | data &= ~mask; |
| 203 | data |= val; | 233 | data |= val; |
| 204 | 234 | ||
| 205 | dw_hdmi_top_write(dw_hdmi, addr, data); | 235 | dw_hdmi->data->top_write(dw_hdmi, addr, data); |
| 206 | } | 236 | } |
| 207 | 237 | ||
| 208 | static unsigned int dw_hdmi_dwc_read(struct meson_dw_hdmi *dw_hdmi, | 238 | static unsigned int dw_hdmi_dwc_read(struct meson_dw_hdmi *dw_hdmi, |
| @@ -226,6 +256,12 @@ static unsigned int dw_hdmi_dwc_read(struct meson_dw_hdmi *dw_hdmi, | |||
| 226 | return data; | 256 | return data; |
| 227 | } | 257 | } |
| 228 | 258 | ||
| 259 | static unsigned int dw_hdmi_g12a_dwc_read(struct meson_dw_hdmi *dw_hdmi, | ||
| 260 | unsigned int addr) | ||
| 261 | { | ||
| 262 | return readb(dw_hdmi->hdmitx + addr); | ||
| 263 | } | ||
| 264 | |||
| 229 | static inline void dw_hdmi_dwc_write(struct meson_dw_hdmi *dw_hdmi, | 265 | static inline void dw_hdmi_dwc_write(struct meson_dw_hdmi *dw_hdmi, |
| 230 | unsigned int addr, unsigned int data) | 266 | unsigned int addr, unsigned int data) |
| 231 | { | 267 | { |
| @@ -243,18 +279,24 @@ static inline void dw_hdmi_dwc_write(struct meson_dw_hdmi *dw_hdmi, | |||
| 243 | spin_unlock_irqrestore(®_lock, flags); | 279 | spin_unlock_irqrestore(®_lock, flags); |
| 244 | } | 280 | } |
| 245 | 281 | ||
| 282 | static inline void dw_hdmi_g12a_dwc_write(struct meson_dw_hdmi *dw_hdmi, | ||
| 283 | unsigned int addr, unsigned int data) | ||
| 284 | { | ||
| 285 | writeb(data, dw_hdmi->hdmitx + addr); | ||
| 286 | } | ||
| 287 | |||
| 246 | /* Helper to change specific bits in controller registers */ | 288 | /* Helper to change specific bits in controller registers */ |
| 247 | static inline void dw_hdmi_dwc_write_bits(struct meson_dw_hdmi *dw_hdmi, | 289 | static inline void dw_hdmi_dwc_write_bits(struct meson_dw_hdmi *dw_hdmi, |
| 248 | unsigned int addr, | 290 | unsigned int addr, |
| 249 | unsigned int mask, | 291 | unsigned int mask, |
| 250 | unsigned int val) | 292 | unsigned int val) |
| 251 | { | 293 | { |
| 252 | unsigned int data = dw_hdmi_dwc_read(dw_hdmi, addr); | 294 | unsigned int data = dw_hdmi->data->dwc_read(dw_hdmi, addr); |
| 253 | 295 | ||
| 254 | data &= ~mask; | 296 | data &= ~mask; |
| 255 | data |= val; | 297 | data |= val; |
| 256 | 298 | ||
| 257 | dw_hdmi_dwc_write(dw_hdmi, addr, data); | 299 | dw_hdmi->data->dwc_write(dw_hdmi, addr, data); |
| 258 | } | 300 | } |
| 259 | 301 | ||
| 260 | /* Bridge */ | 302 | /* Bridge */ |
| @@ -300,6 +342,24 @@ static void meson_hdmi_phy_setup_mode(struct meson_dw_hdmi *dw_hdmi, | |||
| 300 | regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33632122); | 342 | regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33632122); |
| 301 | regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2000115b); | 343 | regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2000115b); |
| 302 | } | 344 | } |
| 345 | } else if (dw_hdmi_is_compatible(dw_hdmi, | ||
| 346 | "amlogic,meson-g12a-dw-hdmi")) { | ||
| 347 | if (pixel_clock >= 371250) { | ||
| 348 | /* 5.94Gbps, 3.7125Gbps */ | ||
| 349 | regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x37eb65c4); | ||
| 350 | regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b); | ||
| 351 | regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x0000080b); | ||
| 352 | } else if (pixel_clock >= 297000) { | ||
| 353 | /* 2.97Gbps */ | ||
| 354 | regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33eb6262); | ||
| 355 | regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b); | ||
| 356 | regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x00000003); | ||
| 357 | } else { | ||
| 358 | /* 1.485Gbps, and below */ | ||
| 359 | regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33eb4242); | ||
| 360 | regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b); | ||
| 361 | regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x00000003); | ||
| 362 | } | ||
| 303 | } | 363 | } |
| 304 | } | 364 | } |
| 305 | 365 | ||
| @@ -375,7 +435,7 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, | |||
| 375 | regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0); | 435 | regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0); |
| 376 | 436 | ||
| 377 | /* Bring out of reset */ | 437 | /* Bring out of reset */ |
| 378 | dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_SW_RESET, 0); | 438 | dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_SW_RESET, 0); |
| 379 | 439 | ||
| 380 | /* Enable internal pixclk, tmds_clk, spdif_clk, i2s_clk, cecclk */ | 440 | /* Enable internal pixclk, tmds_clk, spdif_clk, i2s_clk, cecclk */ |
| 381 | dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL, | 441 | dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL, |
| @@ -384,24 +444,25 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, | |||
| 384 | 0x3 << 4, 0x3 << 4); | 444 | 0x3 << 4, 0x3 << 4); |
| 385 | 445 | ||
| 386 | /* Enable normal output to PHY */ | 446 | /* Enable normal output to PHY */ |
| 387 | dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12)); | 447 | dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12)); |
| 388 | 448 | ||
| 389 | /* TMDS pattern setup (TOFIX Handle the YUV420 case) */ | 449 | /* TMDS pattern setup (TOFIX Handle the YUV420 case) */ |
| 390 | if (mode->clock > 340000) { | 450 | if (mode->clock > 340000) { |
| 391 | dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0); | 451 | dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, |
| 392 | dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, | 452 | 0); |
| 453 | dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, | ||
| 393 | 0x03ff03ff); | 454 | 0x03ff03ff); |
| 394 | } else { | 455 | } else { |
| 395 | dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, | 456 | dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, |
| 396 | 0x001f001f); | 457 | 0x001f001f); |
| 397 | dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, | 458 | dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, |
| 398 | 0x001f001f); | 459 | 0x001f001f); |
| 399 | } | 460 | } |
| 400 | 461 | ||
| 401 | /* Load TMDS pattern */ | 462 | /* Load TMDS pattern */ |
| 402 | dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1); | 463 | dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1); |
| 403 | msleep(20); | 464 | msleep(20); |
| 404 | dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2); | 465 | dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2); |
| 405 | 466 | ||
| 406 | /* Setup PHY parameters */ | 467 | /* Setup PHY parameters */ |
| 407 | meson_hdmi_phy_setup_mode(dw_hdmi, mode); | 468 | meson_hdmi_phy_setup_mode(dw_hdmi, mode); |
| @@ -412,7 +473,8 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, | |||
| 412 | 473 | ||
| 413 | /* BIT_INVERT */ | 474 | /* BIT_INVERT */ |
| 414 | if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") || | 475 | if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") || |
| 415 | dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi")) | 476 | dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi") || |
| 477 | dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-g12a-dw-hdmi")) | ||
| 416 | regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, | 478 | regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, |
| 417 | BIT(17), 0); | 479 | BIT(17), 0); |
| 418 | else | 480 | else |
| @@ -480,7 +542,7 @@ static enum drm_connector_status dw_hdmi_read_hpd(struct dw_hdmi *hdmi, | |||
| 480 | { | 542 | { |
| 481 | struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; | 543 | struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; |
| 482 | 544 | ||
| 483 | return !!dw_hdmi_top_read(dw_hdmi, HDMITX_TOP_STAT0) ? | 545 | return !!dw_hdmi->data->top_read(dw_hdmi, HDMITX_TOP_STAT0) ? |
| 484 | connector_status_connected : connector_status_disconnected; | 546 | connector_status_connected : connector_status_disconnected; |
| 485 | } | 547 | } |
| 486 | 548 | ||
| @@ -490,11 +552,11 @@ static void dw_hdmi_setup_hpd(struct dw_hdmi *hdmi, | |||
| 490 | struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; | 552 | struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; |
| 491 | 553 | ||
| 492 | /* Setup HPD Filter */ | 554 | /* Setup HPD Filter */ |
| 493 | dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_HPD_FILTER, | 555 | dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_HPD_FILTER, |
| 494 | (0xa << 12) | 0xa0); | 556 | (0xa << 12) | 0xa0); |
| 495 | 557 | ||
| 496 | /* Clear interrupts */ | 558 | /* Clear interrupts */ |
| 497 | dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, | 559 | dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, |
| 498 | HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL); | 560 | HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL); |
| 499 | 561 | ||
| 500 | /* Unmask interrupts */ | 562 | /* Unmask interrupts */ |
| @@ -515,8 +577,8 @@ static irqreturn_t dw_hdmi_top_irq(int irq, void *dev_id) | |||
| 515 | struct meson_dw_hdmi *dw_hdmi = dev_id; | 577 | struct meson_dw_hdmi *dw_hdmi = dev_id; |
| 516 | u32 stat; | 578 | u32 stat; |
| 517 | 579 | ||
| 518 | stat = dw_hdmi_top_read(dw_hdmi, HDMITX_TOP_INTR_STAT); | 580 | stat = dw_hdmi->data->top_read(dw_hdmi, HDMITX_TOP_INTR_STAT); |
| 519 | dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, stat); | 581 | dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, stat); |
| 520 | 582 | ||
| 521 | /* HPD Events, handle in the threaded interrupt handler */ | 583 | /* HPD Events, handle in the threaded interrupt handler */ |
| 522 | if (stat & (HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL)) { | 584 | if (stat & (HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL)) { |
| @@ -685,7 +747,9 @@ static const struct drm_encoder_helper_funcs | |||
| 685 | static int meson_dw_hdmi_reg_read(void *context, unsigned int reg, | 747 | static int meson_dw_hdmi_reg_read(void *context, unsigned int reg, |
| 686 | unsigned int *result) | 748 | unsigned int *result) |
| 687 | { | 749 | { |
| 688 | *result = dw_hdmi_dwc_read(context, reg); | 750 | struct meson_dw_hdmi *dw_hdmi = context; |
| 751 | |||
| 752 | *result = dw_hdmi->data->dwc_read(dw_hdmi, reg); | ||
| 689 | 753 | ||
| 690 | return 0; | 754 | return 0; |
| 691 | 755 | ||
| @@ -694,7 +758,9 @@ static int meson_dw_hdmi_reg_read(void *context, unsigned int reg, | |||
| 694 | static int meson_dw_hdmi_reg_write(void *context, unsigned int reg, | 758 | static int meson_dw_hdmi_reg_write(void *context, unsigned int reg, |
| 695 | unsigned int val) | 759 | unsigned int val) |
| 696 | { | 760 | { |
| 697 | dw_hdmi_dwc_write(context, reg, val); | 761 | struct meson_dw_hdmi *dw_hdmi = context; |
| 762 | |||
| 763 | dw_hdmi->data->dwc_write(dw_hdmi, reg, val); | ||
| 698 | 764 | ||
| 699 | return 0; | 765 | return 0; |
| 700 | } | 766 | } |
| @@ -708,6 +774,20 @@ static const struct regmap_config meson_dw_hdmi_regmap_config = { | |||
| 708 | .fast_io = true, | 774 | .fast_io = true, |
| 709 | }; | 775 | }; |
| 710 | 776 | ||
| 777 | static const struct meson_dw_hdmi_data meson_dw_hdmi_gx_data = { | ||
| 778 | .top_read = dw_hdmi_top_read, | ||
| 779 | .top_write = dw_hdmi_top_write, | ||
| 780 | .dwc_read = dw_hdmi_dwc_read, | ||
| 781 | .dwc_write = dw_hdmi_dwc_write, | ||
| 782 | }; | ||
| 783 | |||
| 784 | static const struct meson_dw_hdmi_data meson_dw_hdmi_g12a_data = { | ||
| 785 | .top_read = dw_hdmi_g12a_top_read, | ||
| 786 | .top_write = dw_hdmi_g12a_top_write, | ||
| 787 | .dwc_read = dw_hdmi_g12a_dwc_read, | ||
| 788 | .dwc_write = dw_hdmi_g12a_dwc_write, | ||
| 789 | }; | ||
| 790 | |||
| 711 | static bool meson_hdmi_connector_is_available(struct device *dev) | 791 | static bool meson_hdmi_connector_is_available(struct device *dev) |
| 712 | { | 792 | { |
| 713 | struct device_node *ep, *remote; | 793 | struct device_node *ep, *remote; |
| @@ -734,6 +814,7 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, | |||
| 734 | void *data) | 814 | void *data) |
| 735 | { | 815 | { |
| 736 | struct platform_device *pdev = to_platform_device(dev); | 816 | struct platform_device *pdev = to_platform_device(dev); |
| 817 | const struct meson_dw_hdmi_data *match; | ||
| 737 | struct meson_dw_hdmi *meson_dw_hdmi; | 818 | struct meson_dw_hdmi *meson_dw_hdmi; |
| 738 | struct drm_device *drm = data; | 819 | struct drm_device *drm = data; |
| 739 | struct meson_drm *priv = drm->dev_private; | 820 | struct meson_drm *priv = drm->dev_private; |
| @@ -750,6 +831,12 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, | |||
| 750 | return -ENODEV; | 831 | return -ENODEV; |
| 751 | } | 832 | } |
| 752 | 833 | ||
| 834 | match = of_device_get_match_data(&pdev->dev); | ||
| 835 | if (!match) { | ||
| 836 | dev_err(&pdev->dev, "failed to get match data\n"); | ||
| 837 | return -ENODEV; | ||
| 838 | } | ||
| 839 | |||
| 753 | meson_dw_hdmi = devm_kzalloc(dev, sizeof(*meson_dw_hdmi), | 840 | meson_dw_hdmi = devm_kzalloc(dev, sizeof(*meson_dw_hdmi), |
| 754 | GFP_KERNEL); | 841 | GFP_KERNEL); |
| 755 | if (!meson_dw_hdmi) | 842 | if (!meson_dw_hdmi) |
| @@ -757,6 +844,7 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, | |||
| 757 | 844 | ||
| 758 | meson_dw_hdmi->priv = priv; | 845 | meson_dw_hdmi->priv = priv; |
| 759 | meson_dw_hdmi->dev = dev; | 846 | meson_dw_hdmi->dev = dev; |
| 847 | meson_dw_hdmi->data = match; | ||
| 760 | dw_plat_data = &meson_dw_hdmi->dw_plat_data; | 848 | dw_plat_data = &meson_dw_hdmi->dw_plat_data; |
| 761 | encoder = &meson_dw_hdmi->encoder; | 849 | encoder = &meson_dw_hdmi->encoder; |
| 762 | 850 | ||
| @@ -857,24 +945,28 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, | |||
| 857 | reset_control_reset(meson_dw_hdmi->hdmitx_phy); | 945 | reset_control_reset(meson_dw_hdmi->hdmitx_phy); |
| 858 | 946 | ||
| 859 | /* Enable APB3 fail on error */ | 947 | /* Enable APB3 fail on error */ |
| 860 | writel_bits_relaxed(BIT(15), BIT(15), | 948 | if (!meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { |
| 861 | meson_dw_hdmi->hdmitx + HDMITX_TOP_CTRL_REG); | 949 | writel_bits_relaxed(BIT(15), BIT(15), |
| 862 | writel_bits_relaxed(BIT(15), BIT(15), | 950 | meson_dw_hdmi->hdmitx + HDMITX_TOP_CTRL_REG); |
| 863 | meson_dw_hdmi->hdmitx + HDMITX_DWC_CTRL_REG); | 951 | writel_bits_relaxed(BIT(15), BIT(15), |
| 952 | meson_dw_hdmi->hdmitx + HDMITX_DWC_CTRL_REG); | ||
| 953 | } | ||
| 864 | 954 | ||
| 865 | /* Bring out of reset */ | 955 | /* Bring out of reset */ |
| 866 | dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_SW_RESET, 0); | 956 | meson_dw_hdmi->data->top_write(meson_dw_hdmi, |
| 957 | HDMITX_TOP_SW_RESET, 0); | ||
| 867 | 958 | ||
| 868 | msleep(20); | 959 | msleep(20); |
| 869 | 960 | ||
| 870 | dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_CLK_CNTL, 0xff); | 961 | meson_dw_hdmi->data->top_write(meson_dw_hdmi, |
| 962 | HDMITX_TOP_CLK_CNTL, 0xff); | ||
| 871 | 963 | ||
| 872 | /* Enable HDMI-TX Interrupt */ | 964 | /* Enable HDMI-TX Interrupt */ |
| 873 | dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, | 965 | meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, |
| 874 | HDMITX_TOP_INTR_CORE); | 966 | HDMITX_TOP_INTR_CORE); |
| 875 | 967 | ||
| 876 | dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_INTR_MASKN, | 968 | meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_INTR_MASKN, |
| 877 | HDMITX_TOP_INTR_CORE); | 969 | HDMITX_TOP_INTR_CORE); |
| 878 | 970 | ||
| 879 | /* Bridge / Connector */ | 971 | /* Bridge / Connector */ |
| 880 | 972 | ||
| @@ -923,9 +1015,14 @@ static int meson_dw_hdmi_remove(struct platform_device *pdev) | |||
| 923 | } | 1015 | } |
| 924 | 1016 | ||
| 925 | static const struct of_device_id meson_dw_hdmi_of_table[] = { | 1017 | static const struct of_device_id meson_dw_hdmi_of_table[] = { |
| 926 | { .compatible = "amlogic,meson-gxbb-dw-hdmi" }, | 1018 | { .compatible = "amlogic,meson-gxbb-dw-hdmi", |
| 927 | { .compatible = "amlogic,meson-gxl-dw-hdmi" }, | 1019 | .data = &meson_dw_hdmi_gx_data }, |
| 928 | { .compatible = "amlogic,meson-gxm-dw-hdmi" }, | 1020 | { .compatible = "amlogic,meson-gxl-dw-hdmi", |
| 1021 | .data = &meson_dw_hdmi_gx_data }, | ||
| 1022 | { .compatible = "amlogic,meson-gxm-dw-hdmi", | ||
| 1023 | .data = &meson_dw_hdmi_gx_data }, | ||
| 1024 | { .compatible = "amlogic,meson-g12a-dw-hdmi", | ||
| 1025 | .data = &meson_dw_hdmi_g12a_data }, | ||
| 929 | { } | 1026 | { } |
| 930 | }; | 1027 | }; |
| 931 | MODULE_DEVICE_TABLE(of, meson_dw_hdmi_of_table); | 1028 | MODULE_DEVICE_TABLE(of, meson_dw_hdmi_of_table); |
diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.h b/drivers/gpu/drm/meson/meson_dw_hdmi.h index 0b81183125e3..03e2f0c1a2d5 100644 --- a/drivers/gpu/drm/meson/meson_dw_hdmi.h +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.h | |||
| @@ -21,9 +21,12 @@ | |||
| 21 | #define __MESON_DW_HDMI_H | 21 | #define __MESON_DW_HDMI_H |
| 22 | 22 | ||
| 23 | /* | 23 | /* |
| 24 | * Bit 7 RW Reserved. Default 1. | 24 | * Bit 15-10: RW Reserved. Default 1 starting from G12A |
| 25 | * Bit 6 RW Reserved. Default 1. | 25 | * Bit 9 RW sw_reset_i2c starting from G12A |
| 26 | * Bit 5 RW Reserved. Default 1. | 26 | * Bit 8 RW sw_reset_axiarb starting from G12A |
| 27 | * Bit 7 RW Reserved. Default 1, sw_reset_emp starting from G12A | ||
| 28 | * Bit 6 RW Reserved. Default 1, sw_reset_flt starting from G12A | ||
| 29 | * Bit 5 RW Reserved. Default 1, sw_reset_hdcp22 starting from G12A | ||
| 27 | * Bit 4 RW sw_reset_phyif: PHY interface. 1=Apply reset; 0=Release from reset. | 30 | * Bit 4 RW sw_reset_phyif: PHY interface. 1=Apply reset; 0=Release from reset. |
| 28 | * Default 1. | 31 | * Default 1. |
| 29 | * Bit 3 RW sw_reset_intr: interrupt module. 1=Apply reset; | 32 | * Bit 3 RW sw_reset_intr: interrupt module. 1=Apply reset; |
| @@ -39,12 +42,16 @@ | |||
| 39 | #define HDMITX_TOP_SW_RESET (0x000) | 42 | #define HDMITX_TOP_SW_RESET (0x000) |
| 40 | 43 | ||
| 41 | /* | 44 | /* |
| 45 | * Bit 31 RW free_clk_en: 0=Enable clock gating for power saving; 1= Disable | ||
| 42 | * Bit 12 RW i2s_ws_inv:1=Invert i2s_ws; 0=No invert. Default 0. | 46 | * Bit 12 RW i2s_ws_inv:1=Invert i2s_ws; 0=No invert. Default 0. |
| 43 | * Bit 11 RW i2s_clk_inv: 1=Invert i2s_clk; 0=No invert. Default 0. | 47 | * Bit 11 RW i2s_clk_inv: 1=Invert i2s_clk; 0=No invert. Default 0. |
| 44 | * Bit 10 RW spdif_clk_inv: 1=Invert spdif_clk; 0=No invert. Default 0. | 48 | * Bit 10 RW spdif_clk_inv: 1=Invert spdif_clk; 0=No invert. Default 0. |
| 45 | * Bit 9 RW tmds_clk_inv: 1=Invert tmds_clk; 0=No invert. Default 0. | 49 | * Bit 9 RW tmds_clk_inv: 1=Invert tmds_clk; 0=No invert. Default 0. |
| 46 | * Bit 8 RW pixel_clk_inv: 1=Invert pixel_clk; 0=No invert. Default 0. | 50 | * Bit 8 RW pixel_clk_inv: 1=Invert pixel_clk; 0=No invert. Default 0. |
| 47 | * Bit 4 RW cec_clk_en: 1=enable cec_clk; 0=disable. Default 0. | 51 | * Bit 7 RW hdcp22_skpclk_en: starting from G12A, 1=enable; 0=disable |
| 52 | * Bit 6 RW hdcp22_esmclk_en: starting from G12A, 1=enable; 0=disable | ||
| 53 | * Bit 5 RW hdcp22_tmdsclk_en: starting from G12A, 1=enable; 0=disable | ||
| 54 | * Bit 4 RW cec_clk_en: 1=enable cec_clk; 0=disable. Default 0. Reserved for G12A | ||
| 48 | * Bit 3 RW i2s_clk_en: 1=enable i2s_clk; 0=disable. Default 0. | 55 | * Bit 3 RW i2s_clk_en: 1=enable i2s_clk; 0=disable. Default 0. |
| 49 | * Bit 2 RW spdif_clk_en: 1=enable spdif_clk; 0=disable. Default 0. | 56 | * Bit 2 RW spdif_clk_en: 1=enable spdif_clk; 0=disable. Default 0. |
| 50 | * Bit 1 RW tmds_clk_en: 1=enable tmds_clk; 0=disable. Default 0. | 57 | * Bit 1 RW tmds_clk_en: 1=enable tmds_clk; 0=disable. Default 0. |
| @@ -53,6 +60,8 @@ | |||
| 53 | #define HDMITX_TOP_CLK_CNTL (0x001) | 60 | #define HDMITX_TOP_CLK_CNTL (0x001) |
| 54 | 61 | ||
| 55 | /* | 62 | /* |
| 63 | * Bit 31:28 RW rxsense_glitch_width: starting from G12A | ||
| 64 | * Bit 27:16 RW rxsense_valid_width: starting from G12A | ||
| 56 | * Bit 11: 0 RW hpd_valid_width: filter out width <= M*1024. Default 0. | 65 | * Bit 11: 0 RW hpd_valid_width: filter out width <= M*1024. Default 0. |
| 57 | * Bit 15:12 RW hpd_glitch_width: filter out glitch <= N. Default 0. | 66 | * Bit 15:12 RW hpd_glitch_width: filter out glitch <= N. Default 0. |
| 58 | */ | 67 | */ |
| @@ -61,6 +70,9 @@ | |||
| 61 | /* | 70 | /* |
| 62 | * intr_maskn: MASK_N, one bit per interrupt source. | 71 | * intr_maskn: MASK_N, one bit per interrupt source. |
| 63 | * 1=Enable interrupt source; 0=Disable interrupt source. Default 0. | 72 | * 1=Enable interrupt source; 0=Disable interrupt source. Default 0. |
| 73 | * [ 7] rxsense_fall starting from G12A | ||
| 74 | * [ 6] rxsense_rise starting from G12A | ||
| 75 | * [ 5] err_i2c_timeout starting from G12A | ||
| 64 | * [ 4] hdcp22_rndnum_err | 76 | * [ 4] hdcp22_rndnum_err |
| 65 | * [ 3] nonce_rfrsh_rise | 77 | * [ 3] nonce_rfrsh_rise |
| 66 | * [ 2] hpd_fall_intr | 78 | * [ 2] hpd_fall_intr |
| @@ -73,6 +85,9 @@ | |||
| 73 | * Bit 30: 0 RW intr_stat: For each bit, write 1 to manually set the interrupt | 85 | * Bit 30: 0 RW intr_stat: For each bit, write 1 to manually set the interrupt |
| 74 | * bit, read back the interrupt status. | 86 | * bit, read back the interrupt status. |
| 75 | * Bit 31 R IP interrupt status | 87 | * Bit 31 R IP interrupt status |
| 88 | * Bit 7 RW rxsense_fall starting from G12A | ||
| 89 | * Bit 6 RW rxsense_rise starting from G12A | ||
| 90 | * Bit 5 RW err_i2c_timeout starting from G12A | ||
| 76 | * Bit 2 RW hpd_fall | 91 | * Bit 2 RW hpd_fall |
| 77 | * Bit 1 RW hpd_rise | 92 | * Bit 1 RW hpd_rise |
| 78 | * Bit 0 RW IP interrupt | 93 | * Bit 0 RW IP interrupt |
| @@ -80,6 +95,9 @@ | |||
| 80 | #define HDMITX_TOP_INTR_STAT (0x004) | 95 | #define HDMITX_TOP_INTR_STAT (0x004) |
| 81 | 96 | ||
| 82 | /* | 97 | /* |
| 98 | * [7] rxsense_fall starting from G12A | ||
| 99 | * [6] rxsense_rise starting from G12A | ||
| 100 | * [5] err_i2c_timeout starting from G12A | ||
| 83 | * [4] hdcp22_rndnum_err | 101 | * [4] hdcp22_rndnum_err |
| 84 | * [3] nonce_rfrsh_rise | 102 | * [3] nonce_rfrsh_rise |
| 85 | * [2] hpd_fall | 103 | * [2] hpd_fall |
| @@ -91,6 +109,8 @@ | |||
| 91 | #define HDMITX_TOP_INTR_CORE BIT(0) | 109 | #define HDMITX_TOP_INTR_CORE BIT(0) |
| 92 | #define HDMITX_TOP_INTR_HPD_RISE BIT(1) | 110 | #define HDMITX_TOP_INTR_HPD_RISE BIT(1) |
| 93 | #define HDMITX_TOP_INTR_HPD_FALL BIT(2) | 111 | #define HDMITX_TOP_INTR_HPD_FALL BIT(2) |
| 112 | #define HDMITX_TOP_INTR_RXSENSE_RISE BIT(6) | ||
| 113 | #define HDMITX_TOP_INTR_RXSENSE_FALL BIT(7) | ||
| 94 | 114 | ||
| 95 | /* Bit 14:12 RW tmds_sel: 3'b000=Output zero; 3'b001=Output normal TMDS data; | 115 | /* Bit 14:12 RW tmds_sel: 3'b000=Output zero; 3'b001=Output normal TMDS data; |
| 96 | * 3'b010=Output PRBS data; 3'b100=Output shift pattern. Default 0. | 116 | * 3'b010=Output PRBS data; 3'b100=Output shift pattern. Default 0. |
| @@ -140,7 +160,9 @@ | |||
| 140 | */ | 160 | */ |
| 141 | #define HDMITX_TOP_REVOCMEM_STAT (0x00D) | 161 | #define HDMITX_TOP_REVOCMEM_STAT (0x00D) |
| 142 | 162 | ||
| 143 | /* Bit 0 R filtered HPD status. */ | 163 | /* Bit 1 R filtered RxSense status |
| 164 | * Bit 0 R filtered HPD status. | ||
| 165 | */ | ||
| 144 | #define HDMITX_TOP_STAT0 (0x00E) | 166 | #define HDMITX_TOP_STAT0 (0x00E) |
| 145 | 167 | ||
| 146 | #endif /* __MESON_DW_HDMI_H */ | 168 | #endif /* __MESON_DW_HDMI_H */ |
diff --git a/drivers/gpu/drm/meson/meson_overlay.c b/drivers/gpu/drm/meson/meson_overlay.c index b54a22e483b9..bdbf925ff3e8 100644 --- a/drivers/gpu/drm/meson/meson_overlay.c +++ b/drivers/gpu/drm/meson/meson_overlay.c | |||
| @@ -516,8 +516,14 @@ static void meson_overlay_atomic_disable(struct drm_plane *plane, | |||
| 516 | priv->viu.vd1_enabled = false; | 516 | priv->viu.vd1_enabled = false; |
| 517 | 517 | ||
| 518 | /* Disable VD1 */ | 518 | /* Disable VD1 */ |
| 519 | writel_bits_relaxed(VPP_VD1_POSTBLEND | VPP_VD1_PREBLEND, 0, | 519 | if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { |
| 520 | priv->io_base + _REG(VPP_MISC)); | 520 | writel_relaxed(0, priv->io_base + _REG(VD1_BLEND_SRC_CTRL)); |
| 521 | writel_relaxed(0, priv->io_base + _REG(VD2_BLEND_SRC_CTRL)); | ||
| 522 | writel_relaxed(0, priv->io_base + _REG(VD1_IF0_GEN_REG + 0x17b0)); | ||
| 523 | writel_relaxed(0, priv->io_base + _REG(VD2_IF0_GEN_REG + 0x17b0)); | ||
| 524 | } else | ||
| 525 | writel_bits_relaxed(VPP_VD1_POSTBLEND | VPP_VD1_PREBLEND, 0, | ||
| 526 | priv->io_base + _REG(VPP_MISC)); | ||
| 521 | 527 | ||
| 522 | } | 528 | } |
| 523 | 529 | ||
diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c index b7786218cb10..bf8f1fab63aa 100644 --- a/drivers/gpu/drm/meson/meson_plane.c +++ b/drivers/gpu/drm/meson/meson_plane.c | |||
| @@ -294,6 +294,13 @@ static void meson_plane_atomic_update(struct drm_plane *plane, | |||
| 294 | priv->viu.osd1_blk0_cfg[3] = ((dest.x2 - 1) << 16) | dest.x1; | 294 | priv->viu.osd1_blk0_cfg[3] = ((dest.x2 - 1) << 16) | dest.x1; |
| 295 | priv->viu.osd1_blk0_cfg[4] = ((dest.y2 - 1) << 16) | dest.y1; | 295 | priv->viu.osd1_blk0_cfg[4] = ((dest.y2 - 1) << 16) | dest.y1; |
| 296 | 296 | ||
| 297 | if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { | ||
| 298 | priv->viu.osd_blend_din0_scope_h = ((dest.x2 - 1) << 16) | dest.x1; | ||
| 299 | priv->viu.osd_blend_din0_scope_v = ((dest.y2 - 1) << 16) | dest.y1; | ||
| 300 | priv->viu.osb_blend0_size = dst_h << 16 | dst_w; | ||
| 301 | priv->viu.osb_blend1_size = dst_h << 16 | dst_w; | ||
| 302 | } | ||
| 303 | |||
| 297 | /* Update Canvas with buffer address */ | 304 | /* Update Canvas with buffer address */ |
| 298 | gem = drm_fb_cma_get_gem_obj(fb, 0); | 305 | gem = drm_fb_cma_get_gem_obj(fb, 0); |
| 299 | 306 | ||
| @@ -320,8 +327,12 @@ static void meson_plane_atomic_disable(struct drm_plane *plane, | |||
| 320 | struct meson_drm *priv = meson_plane->priv; | 327 | struct meson_drm *priv = meson_plane->priv; |
| 321 | 328 | ||
| 322 | /* Disable OSD1 */ | 329 | /* Disable OSD1 */ |
| 323 | writel_bits_relaxed(VPP_OSD1_POSTBLEND, 0, | 330 | if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) |
| 324 | priv->io_base + _REG(VPP_MISC)); | 331 | writel_bits_relaxed(BIT(0) | BIT(21), 0, |
| 332 | priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); | ||
| 333 | else | ||
| 334 | writel_bits_relaxed(VPP_OSD1_POSTBLEND, 0, | ||
| 335 | priv->io_base + _REG(VPP_MISC)); | ||
| 325 | 336 | ||
| 326 | meson_plane->enabled = false; | 337 | meson_plane->enabled = false; |
| 327 | 338 | ||
diff --git a/drivers/gpu/drm/meson/meson_registers.h b/drivers/gpu/drm/meson/meson_registers.h index 5c7e02c703bc..cfaf90501bb1 100644 --- a/drivers/gpu/drm/meson/meson_registers.h +++ b/drivers/gpu/drm/meson/meson_registers.h | |||
| @@ -216,6 +216,29 @@ | |||
| 216 | #define VIU_OSD2_FIFO_CTRL_STAT 0x1a4b | 216 | #define VIU_OSD2_FIFO_CTRL_STAT 0x1a4b |
| 217 | #define VIU_OSD2_TEST_RDDATA 0x1a4c | 217 | #define VIU_OSD2_TEST_RDDATA 0x1a4c |
| 218 | #define VIU_OSD2_PROT_CTRL 0x1a4e | 218 | #define VIU_OSD2_PROT_CTRL 0x1a4e |
| 219 | #define VIU_OSD2_MALI_UNPACK_CTRL 0x1abd | ||
| 220 | #define VIU_OSD2_DIMM_CTRL 0x1acf | ||
| 221 | |||
| 222 | #define VIU_OSD3_CTRL_STAT 0x3d80 | ||
| 223 | #define VIU_OSD3_CTRL_STAT2 0x3d81 | ||
| 224 | #define VIU_OSD3_COLOR_ADDR 0x3d82 | ||
| 225 | #define VIU_OSD3_COLOR 0x3d83 | ||
| 226 | #define VIU_OSD3_TCOLOR_AG0 0x3d84 | ||
| 227 | #define VIU_OSD3_TCOLOR_AG1 0x3d85 | ||
| 228 | #define VIU_OSD3_TCOLOR_AG2 0x3d86 | ||
| 229 | #define VIU_OSD3_TCOLOR_AG3 0x3d87 | ||
| 230 | #define VIU_OSD3_BLK0_CFG_W0 0x3d88 | ||
| 231 | #define VIU_OSD3_BLK0_CFG_W1 0x3d8c | ||
| 232 | #define VIU_OSD3_BLK0_CFG_W2 0x3d90 | ||
| 233 | #define VIU_OSD3_BLK0_CFG_W3 0x3d94 | ||
| 234 | #define VIU_OSD3_BLK0_CFG_W4 0x3d98 | ||
| 235 | #define VIU_OSD3_BLK1_CFG_W4 0x3d99 | ||
| 236 | #define VIU_OSD3_BLK2_CFG_W4 0x3d9a | ||
| 237 | #define VIU_OSD3_FIFO_CTRL_STAT 0x3d9c | ||
| 238 | #define VIU_OSD3_TEST_RDDATA 0x3d9d | ||
| 239 | #define VIU_OSD3_PROT_CTRL 0x3d9e | ||
| 240 | #define VIU_OSD3_MALI_UNPACK_CTRL 0x3d9f | ||
| 241 | #define VIU_OSD3_DIMM_CTRL 0x3da0 | ||
| 219 | 242 | ||
| 220 | #define VD1_IF0_GEN_REG 0x1a50 | 243 | #define VD1_IF0_GEN_REG 0x1a50 |
| 221 | #define VD1_IF0_CANVAS0 0x1a51 | 244 | #define VD1_IF0_CANVAS0 0x1a51 |
| @@ -287,6 +310,27 @@ | |||
| 287 | #define VIU_OSD1_MATRIX_COEF31_32 0x1a9e | 310 | #define VIU_OSD1_MATRIX_COEF31_32 0x1a9e |
| 288 | #define VIU_OSD1_MATRIX_COEF40_41 0x1a9f | 311 | #define VIU_OSD1_MATRIX_COEF40_41 0x1a9f |
| 289 | #define VD1_IF0_GEN_REG3 0x1aa7 | 312 | #define VD1_IF0_GEN_REG3 0x1aa7 |
| 313 | |||
| 314 | #define VIU_OSD_BLENDO_H_START_END 0x1aa9 | ||
| 315 | #define VIU_OSD_BLENDO_V_START_END 0x1aaa | ||
| 316 | #define VIU_OSD_BLEND_GEN_CTRL0 0x1aab | ||
| 317 | #define VIU_OSD_BLEND_GEN_CTRL1 0x1aac | ||
| 318 | #define VIU_OSD_BLEND_DUMMY_DATA 0x1aad | ||
| 319 | #define VIU_OSD_BLEND_CURRENT_XY 0x1aae | ||
| 320 | |||
| 321 | #define VIU_OSD2_MATRIX_CTRL 0x1ab0 | ||
| 322 | #define VIU_OSD2_MATRIX_COEF00_01 0x1ab1 | ||
| 323 | #define VIU_OSD2_MATRIX_COEF02_10 0x1ab2 | ||
| 324 | #define VIU_OSD2_MATRIX_COEF11_12 0x1ab3 | ||
| 325 | #define VIU_OSD2_MATRIX_COEF20_21 0x1ab4 | ||
| 326 | #define VIU_OSD2_MATRIX_COEF22 0x1ab5 | ||
| 327 | #define VIU_OSD2_MATRIX_OFFSET0_1 0x1ab6 | ||
| 328 | #define VIU_OSD2_MATRIX_OFFSET2 0x1ab7 | ||
| 329 | #define VIU_OSD2_MATRIX_PRE_OFFSET0_1 0x1ab8 | ||
| 330 | #define VIU_OSD2_MATRIX_PRE_OFFSET2 0x1ab9 | ||
| 331 | #define VIU_OSD2_MATRIX_PROBE_COLOR 0x1aba | ||
| 332 | #define VIU_OSD2_MATRIX_HL_COLOR 0x1abb | ||
| 333 | #define VIU_OSD2_MATRIX_PROBE_POS 0x1abc | ||
| 290 | #define VIU_OSD1_EOTF_CTL 0x1ad4 | 334 | #define VIU_OSD1_EOTF_CTL 0x1ad4 |
| 291 | #define VIU_OSD1_EOTF_COEF00_01 0x1ad5 | 335 | #define VIU_OSD1_EOTF_COEF00_01 0x1ad5 |
| 292 | #define VIU_OSD1_EOTF_COEF02_10 0x1ad6 | 336 | #define VIU_OSD1_EOTF_COEF02_10 0x1ad6 |
| @@ -481,6 +525,82 @@ | |||
| 481 | #define VPP_OSD_SCALE_COEF 0x1dcd | 525 | #define VPP_OSD_SCALE_COEF 0x1dcd |
| 482 | #define VPP_INT_LINE_NUM 0x1dce | 526 | #define VPP_INT_LINE_NUM 0x1dce |
| 483 | 527 | ||
| 528 | #define VPP_WRAP_OSD1_MATRIX_COEF00_01 0x3d60 | ||
| 529 | #define VPP_WRAP_OSD1_MATRIX_COEF02_10 0x3d61 | ||
| 530 | #define VPP_WRAP_OSD1_MATRIX_COEF11_12 0x3d62 | ||
| 531 | #define VPP_WRAP_OSD1_MATRIX_COEF20_21 0x3d63 | ||
| 532 | #define VPP_WRAP_OSD1_MATRIX_COEF22 0x3d64 | ||
| 533 | #define VPP_WRAP_OSD1_MATRIX_COEF13_14 0x3d65 | ||
| 534 | #define VPP_WRAP_OSD1_MATRIX_COEF23_24 0x3d66 | ||
| 535 | #define VPP_WRAP_OSD1_MATRIX_COEF15_25 0x3d67 | ||
| 536 | #define VPP_WRAP_OSD1_MATRIX_CLIP 0x3d68 | ||
| 537 | #define VPP_WRAP_OSD1_MATRIX_OFFSET0_1 0x3d69 | ||
| 538 | #define VPP_WRAP_OSD1_MATRIX_OFFSET2 0x3d6a | ||
| 539 | #define VPP_WRAP_OSD1_MATRIX_PRE_OFFSET0_1 0x3d6b | ||
| 540 | #define VPP_WRAP_OSD1_MATRIX_PRE_OFFSET2 0x3d6c | ||
| 541 | #define VPP_WRAP_OSD1_MATRIX_EN_CTRL 0x3d6d | ||
| 542 | |||
| 543 | #define VPP_WRAP_OSD2_MATRIX_COEF00_01 0x3d70 | ||
| 544 | #define VPP_WRAP_OSD2_MATRIX_COEF02_10 0x3d71 | ||
| 545 | #define VPP_WRAP_OSD2_MATRIX_COEF11_12 0x3d72 | ||
| 546 | #define VPP_WRAP_OSD2_MATRIX_COEF20_21 0x3d73 | ||
| 547 | #define VPP_WRAP_OSD2_MATRIX_COEF22 0x3d74 | ||
| 548 | #define VPP_WRAP_OSD2_MATRIX_COEF13_14 0x3d75 | ||
| 549 | #define VPP_WRAP_OSD2_MATRIX_COEF23_24 0x3d76 | ||
| 550 | #define VPP_WRAP_OSD2_MATRIX_COEF15_25 0x3d77 | ||
| 551 | #define VPP_WRAP_OSD2_MATRIX_CLIP 0x3d78 | ||
| 552 | #define VPP_WRAP_OSD2_MATRIX_OFFSET0_1 0x3d79 | ||
| 553 | #define VPP_WRAP_OSD2_MATRIX_OFFSET2 0x3d7a | ||
| 554 | #define VPP_WRAP_OSD2_MATRIX_PRE_OFFSET0_1 0x3d7b | ||
| 555 | #define VPP_WRAP_OSD2_MATRIX_PRE_OFFSET2 0x3d7c | ||
| 556 | #define VPP_WRAP_OSD2_MATRIX_EN_CTRL 0x3d7d | ||
| 557 | |||
| 558 | #define VPP_WRAP_OSD3_MATRIX_COEF00_01 0x3db0 | ||
| 559 | #define VPP_WRAP_OSD3_MATRIX_COEF02_10 0x3db1 | ||
| 560 | #define VPP_WRAP_OSD3_MATRIX_COEF11_12 0x3db2 | ||
| 561 | #define VPP_WRAP_OSD3_MATRIX_COEF20_21 0x3db3 | ||
| 562 | #define VPP_WRAP_OSD3_MATRIX_COEF22 0x3db4 | ||
| 563 | #define VPP_WRAP_OSD3_MATRIX_COEF13_14 0x3db5 | ||
| 564 | #define VPP_WRAP_OSD3_MATRIX_COEF23_24 0x3db6 | ||
| 565 | #define VPP_WRAP_OSD3_MATRIX_COEF15_25 0x3db7 | ||
| 566 | #define VPP_WRAP_OSD3_MATRIX_CLIP 0x3db8 | ||
| 567 | #define VPP_WRAP_OSD3_MATRIX_OFFSET0_1 0x3db9 | ||
| 568 | #define VPP_WRAP_OSD3_MATRIX_OFFSET2 0x3dba | ||
| 569 | #define VPP_WRAP_OSD3_MATRIX_PRE_OFFSET0_1 0x3dbb | ||
| 570 | #define VPP_WRAP_OSD3_MATRIX_PRE_OFFSET2 0x3dbc | ||
| 571 | #define VPP_WRAP_OSD3_MATRIX_EN_CTRL 0x3dbd | ||
| 572 | |||
| 573 | /* osd2 scaler */ | ||
| 574 | #define OSD2_VSC_PHASE_STEP 0x3d00 | ||
| 575 | #define OSD2_VSC_INI_PHASE 0x3d01 | ||
| 576 | #define OSD2_VSC_CTRL0 0x3d02 | ||
| 577 | #define OSD2_HSC_PHASE_STEP 0x3d03 | ||
| 578 | #define OSD2_HSC_INI_PHASE 0x3d04 | ||
| 579 | #define OSD2_HSC_CTRL0 0x3d05 | ||
| 580 | #define OSD2_HSC_INI_PAT_CTRL 0x3d06 | ||
| 581 | #define OSD2_SC_DUMMY_DATA 0x3d07 | ||
| 582 | #define OSD2_SC_CTRL0 0x3d08 | ||
| 583 | #define OSD2_SCI_WH_M1 0x3d09 | ||
| 584 | #define OSD2_SCO_H_START_END 0x3d0a | ||
| 585 | #define OSD2_SCO_V_START_END 0x3d0b | ||
| 586 | #define OSD2_SCALE_COEF_IDX 0x3d18 | ||
| 587 | #define OSD2_SCALE_COEF 0x3d19 | ||
| 588 | |||
| 589 | /* osd34 scaler */ | ||
| 590 | #define OSD34_SCALE_COEF_IDX 0x3d1e | ||
| 591 | #define OSD34_SCALE_COEF 0x3d1f | ||
| 592 | #define OSD34_VSC_PHASE_STEP 0x3d20 | ||
| 593 | #define OSD34_VSC_INI_PHASE 0x3d21 | ||
| 594 | #define OSD34_VSC_CTRL0 0x3d22 | ||
| 595 | #define OSD34_HSC_PHASE_STEP 0x3d23 | ||
| 596 | #define OSD34_HSC_INI_PHASE 0x3d24 | ||
| 597 | #define OSD34_HSC_CTRL0 0x3d25 | ||
| 598 | #define OSD34_HSC_INI_PAT_CTRL 0x3d26 | ||
| 599 | #define OSD34_SC_DUMMY_DATA 0x3d27 | ||
| 600 | #define OSD34_SC_CTRL0 0x3d28 | ||
| 601 | #define OSD34_SCI_WH_M1 0x3d29 | ||
| 602 | #define OSD34_SCO_H_START_END 0x3d2a | ||
| 603 | #define OSD34_SCO_V_START_END 0x3d2b | ||
| 484 | /* viu2 */ | 604 | /* viu2 */ |
| 485 | #define VIU2_ADDR_START 0x1e00 | 605 | #define VIU2_ADDR_START 0x1e00 |
| 486 | #define VIU2_ADDR_END 0x1eff | 606 | #define VIU2_ADDR_END 0x1eff |
| @@ -1400,4 +1520,131 @@ | |||
| 1400 | #define OSDSR_YBIC_VCOEF0 0x3149 | 1520 | #define OSDSR_YBIC_VCOEF0 0x3149 |
| 1401 | #define OSDSR_CBIC_VCOEF0 0x314a | 1521 | #define OSDSR_CBIC_VCOEF0 0x314a |
| 1402 | 1522 | ||
| 1523 | /* osd afbcd on gxtvbb */ | ||
| 1524 | #define OSD1_AFBCD_ENABLE 0x31a0 | ||
| 1525 | #define OSD1_AFBCD_MODE 0x31a1 | ||
| 1526 | #define OSD1_AFBCD_SIZE_IN 0x31a2 | ||
| 1527 | #define OSD1_AFBCD_HDR_PTR 0x31a3 | ||
| 1528 | #define OSD1_AFBCD_FRAME_PTR 0x31a4 | ||
| 1529 | #define OSD1_AFBCD_CHROMA_PTR 0x31a5 | ||
| 1530 | #define OSD1_AFBCD_CONV_CTRL 0x31a6 | ||
| 1531 | #define OSD1_AFBCD_STATUS 0x31a8 | ||
| 1532 | #define OSD1_AFBCD_PIXEL_HSCOPE 0x31a9 | ||
| 1533 | #define OSD1_AFBCD_PIXEL_VSCOPE 0x31aa | ||
| 1534 | #define VIU_MISC_CTRL1 0x1a07 | ||
| 1535 | |||
| 1536 | /* add for gxm and 962e dv core2 */ | ||
| 1537 | #define DOLBY_CORE2A_SWAP_CTRL1 0x3434 | ||
| 1538 | #define DOLBY_CORE2A_SWAP_CTRL2 0x3435 | ||
| 1539 | |||
| 1540 | /* osd afbc on g12a */ | ||
| 1541 | #define VPU_MAFBC_BLOCK_ID 0x3a00 | ||
| 1542 | #define VPU_MAFBC_IRQ_RAW_STATUS 0x3a01 | ||
| 1543 | #define VPU_MAFBC_IRQ_CLEAR 0x3a02 | ||
| 1544 | #define VPU_MAFBC_IRQ_MASK 0x3a03 | ||
| 1545 | #define VPU_MAFBC_IRQ_STATUS 0x3a04 | ||
| 1546 | #define VPU_MAFBC_COMMAND 0x3a05 | ||
| 1547 | #define VPU_MAFBC_STATUS 0x3a06 | ||
| 1548 | #define VPU_MAFBC_SURFACE_CFG 0x3a07 | ||
| 1549 | |||
| 1550 | /* osd afbc on g12a */ | ||
| 1551 | #define VPU_MAFBC_HEADER_BUF_ADDR_LOW_S0 0x3a10 | ||
| 1552 | #define VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S0 0x3a11 | ||
| 1553 | #define VPU_MAFBC_FORMAT_SPECIFIER_S0 0x3a12 | ||
| 1554 | #define VPU_MAFBC_BUFFER_WIDTH_S0 0x3a13 | ||
| 1555 | #define VPU_MAFBC_BUFFER_HEIGHT_S0 0x3a14 | ||
| 1556 | #define VPU_MAFBC_BOUNDING_BOX_X_START_S0 0x3a15 | ||
| 1557 | #define VPU_MAFBC_BOUNDING_BOX_X_END_S0 0x3a16 | ||
| 1558 | #define VPU_MAFBC_BOUNDING_BOX_Y_START_S0 0x3a17 | ||
| 1559 | #define VPU_MAFBC_BOUNDING_BOX_Y_END_S0 0x3a18 | ||
| 1560 | #define VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S0 0x3a19 | ||
| 1561 | #define VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S0 0x3a1a | ||
| 1562 | #define VPU_MAFBC_OUTPUT_BUF_STRIDE_S0 0x3a1b | ||
| 1563 | #define VPU_MAFBC_PREFETCH_CFG_S0 0x3a1c | ||
| 1564 | |||
| 1565 | #define VPU_MAFBC_HEADER_BUF_ADDR_LOW_S1 0x3a30 | ||
| 1566 | #define VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S1 0x3a31 | ||
| 1567 | #define VPU_MAFBC_FORMAT_SPECIFIER_S1 0x3a32 | ||
| 1568 | #define VPU_MAFBC_BUFFER_WIDTH_S1 0x3a33 | ||
| 1569 | #define VPU_MAFBC_BUFFER_HEIGHT_S1 0x3a34 | ||
| 1570 | #define VPU_MAFBC_BOUNDING_BOX_X_START_S1 0x3a35 | ||
| 1571 | #define VPU_MAFBC_BOUNDING_BOX_X_END_S1 0x3a36 | ||
| 1572 | #define VPU_MAFBC_BOUNDING_BOX_Y_START_S1 0x3a37 | ||
| 1573 | #define VPU_MAFBC_BOUNDING_BOX_Y_END_S1 0x3a38 | ||
| 1574 | #define VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S1 0x3a39 | ||
| 1575 | #define VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S1 0x3a3a | ||
| 1576 | #define VPU_MAFBC_OUTPUT_BUF_STRIDE_S1 0x3a3b | ||
| 1577 | #define VPU_MAFBC_PREFETCH_CFG_S1 0x3a3c | ||
| 1578 | |||
| 1579 | #define VPU_MAFBC_HEADER_BUF_ADDR_LOW_S2 0x3a50 | ||
| 1580 | #define VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S2 0x3a51 | ||
| 1581 | #define VPU_MAFBC_FORMAT_SPECIFIER_S2 0x3a52 | ||
| 1582 | #define VPU_MAFBC_BUFFER_WIDTH_S2 0x3a53 | ||
| 1583 | #define VPU_MAFBC_BUFFER_HEIGHT_S2 0x3a54 | ||
| 1584 | #define VPU_MAFBC_BOUNDING_BOX_X_START_S2 0x3a55 | ||
| 1585 | #define VPU_MAFBC_BOUNDING_BOX_X_END_S2 0x3a56 | ||
| 1586 | #define VPU_MAFBC_BOUNDING_BOX_Y_START_S2 0x3a57 | ||
| 1587 | #define VPU_MAFBC_BOUNDING_BOX_Y_END_S2 0x3a58 | ||
| 1588 | #define VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S2 0x3a59 | ||
| 1589 | #define VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S2 0x3a5a | ||
| 1590 | #define VPU_MAFBC_OUTPUT_BUF_STRIDE_S2 0x3a5b | ||
| 1591 | #define VPU_MAFBC_PREFETCH_CFG_S2 0x3a5c | ||
| 1592 | |||
| 1593 | #define VPU_MAFBC_HEADER_BUF_ADDR_LOW_S3 0x3a70 | ||
| 1594 | #define VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S3 0x3a71 | ||
| 1595 | #define VPU_MAFBC_FORMAT_SPECIFIER_S3 0x3a72 | ||
| 1596 | #define VPU_MAFBC_BUFFER_WIDTH_S3 0x3a73 | ||
| 1597 | #define VPU_MAFBC_BUFFER_HEIGHT_S3 0x3a74 | ||
| 1598 | #define VPU_MAFBC_BOUNDING_BOX_X_START_S3 0x3a75 | ||
| 1599 | #define VPU_MAFBC_BOUNDING_BOX_X_END_S3 0x3a76 | ||
| 1600 | #define VPU_MAFBC_BOUNDING_BOX_Y_START_S3 0x3a77 | ||
| 1601 | #define VPU_MAFBC_BOUNDING_BOX_Y_END_S3 0x3a78 | ||
| 1602 | #define VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S3 0x3a79 | ||
| 1603 | #define VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S3 0x3a7a | ||
| 1604 | #define VPU_MAFBC_OUTPUT_BUF_STRIDE_S3 0x3a7b | ||
| 1605 | #define VPU_MAFBC_PREFETCH_CFG_S3 0x3a7c | ||
| 1606 | |||
| 1607 | #define DOLBY_PATH_CTRL 0x1a0c | ||
| 1608 | #define OSD_PATH_MISC_CTRL 0x1a0e | ||
| 1609 | #define MALI_AFBCD_TOP_CTRL 0x1a0f | ||
| 1610 | |||
| 1611 | #define VIU_OSD_BLEND_CTRL 0x39b0 | ||
| 1612 | #define VIU_OSD_BLEND_CTRL1 0x39c0 | ||
| 1613 | #define VIU_OSD_BLEND_DIN0_SCOPE_H 0x39b1 | ||
| 1614 | #define VIU_OSD_BLEND_DIN0_SCOPE_V 0x39b2 | ||
| 1615 | #define VIU_OSD_BLEND_DIN1_SCOPE_H 0x39b3 | ||
| 1616 | #define VIU_OSD_BLEND_DIN1_SCOPE_V 0x39b4 | ||
| 1617 | #define VIU_OSD_BLEND_DIN2_SCOPE_H 0x39b5 | ||
| 1618 | #define VIU_OSD_BLEND_DIN2_SCOPE_V 0x39b6 | ||
| 1619 | #define VIU_OSD_BLEND_DIN3_SCOPE_H 0x39b7 | ||
| 1620 | #define VIU_OSD_BLEND_DIN3_SCOPE_V 0x39b8 | ||
| 1621 | #define VIU_OSD_BLEND_DUMMY_DATA0 0x39b9 | ||
| 1622 | #define VIU_OSD_BLEND_DUMMY_ALPHA 0x39ba | ||
| 1623 | #define VIU_OSD_BLEND_BLEND0_SIZE 0x39bb | ||
| 1624 | #define VIU_OSD_BLEND_BLEND1_SIZE 0x39bc | ||
| 1625 | #define VIU_OSD_BLEND_RO_CURRENT_XY 0x39bf | ||
| 1626 | |||
| 1627 | #define VPP_OUT_H_V_SIZE 0x1da5 | ||
| 1628 | |||
| 1629 | #define VPP_VD2_HDR_IN_SIZE 0x1df0 | ||
| 1630 | #define VPP_OSD1_IN_SIZE 0x1df1 | ||
| 1631 | #define VPP_GCLK_CTRL2 0x1df2 | ||
| 1632 | #define VD2_PPS_DUMMY_DATA 0x1df4 | ||
| 1633 | #define VPP_OSD1_BLD_H_SCOPE 0x1df5 | ||
| 1634 | #define VPP_OSD1_BLD_V_SCOPE 0x1df6 | ||
| 1635 | #define VPP_OSD2_BLD_H_SCOPE 0x1df7 | ||
| 1636 | #define VPP_OSD2_BLD_V_SCOPE 0x1df8 | ||
| 1637 | #define VPP_WRBAK_CTRL 0x1df9 | ||
| 1638 | #define VPP_SLEEP_CTRL 0x1dfa | ||
| 1639 | #define VD1_BLEND_SRC_CTRL 0x1dfb | ||
| 1640 | #define VD2_BLEND_SRC_CTRL 0x1dfc | ||
| 1641 | #define OSD1_BLEND_SRC_CTRL 0x1dfd | ||
| 1642 | #define OSD2_BLEND_SRC_CTRL 0x1dfe | ||
| 1643 | |||
| 1644 | #define VPP_POST_BLEND_BLEND_DUMMY_DATA 0x3968 | ||
| 1645 | #define VPP_POST_BLEND_DUMMY_ALPHA 0x3969 | ||
| 1646 | #define VPP_RDARB_MODE 0x3978 | ||
| 1647 | #define VPP_RDARB_REQEN_SLV 0x3979 | ||
| 1648 | #define VPU_RDARB_MODE_L2C1 0x279d | ||
| 1649 | |||
| 1403 | #endif /* __MESON_REGISTERS_H */ | 1650 | #endif /* __MESON_REGISTERS_H */ |
diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c index f6ba35a405f8..b39034745444 100644 --- a/drivers/gpu/drm/meson/meson_vclk.c +++ b/drivers/gpu/drm/meson/meson_vclk.c | |||
| @@ -113,9 +113,12 @@ | |||
| 113 | #define HHI_HDMI_PLL_CNTL4 0x32C /* 0xcb offset in data sheet */ | 113 | #define HHI_HDMI_PLL_CNTL4 0x32C /* 0xcb offset in data sheet */ |
| 114 | #define HHI_HDMI_PLL_CNTL5 0x330 /* 0xcc offset in data sheet */ | 114 | #define HHI_HDMI_PLL_CNTL5 0x330 /* 0xcc offset in data sheet */ |
| 115 | #define HHI_HDMI_PLL_CNTL6 0x334 /* 0xcd offset in data sheet */ | 115 | #define HHI_HDMI_PLL_CNTL6 0x334 /* 0xcd offset in data sheet */ |
| 116 | #define HHI_HDMI_PLL_CNTL7 0x338 /* 0xce offset in data sheet */ | ||
| 116 | 117 | ||
| 117 | #define HDMI_PLL_RESET BIT(28) | 118 | #define HDMI_PLL_RESET BIT(28) |
| 119 | #define HDMI_PLL_RESET_G12A BIT(29) | ||
| 118 | #define HDMI_PLL_LOCK BIT(31) | 120 | #define HDMI_PLL_LOCK BIT(31) |
| 121 | #define HDMI_PLL_LOCK_G12A (3 << 30) | ||
| 119 | 122 | ||
| 120 | #define FREQ_1000_1001(_freq) DIV_ROUND_CLOSEST(_freq * 1000, 1001) | 123 | #define FREQ_1000_1001(_freq) DIV_ROUND_CLOSEST(_freq * 1000, 1001) |
| 121 | 124 | ||
| @@ -257,6 +260,10 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) | |||
| 257 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); | 260 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); |
| 258 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); | 261 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); |
| 259 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4800023d); | 262 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4800023d); |
| 263 | |||
| 264 | /* Poll for lock bit */ | ||
| 265 | regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, | ||
| 266 | (val & HDMI_PLL_LOCK), 10, 0); | ||
| 260 | } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || | 267 | } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || |
| 261 | meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { | 268 | meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { |
| 262 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4000027b); | 269 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4000027b); |
| @@ -271,11 +278,26 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) | |||
| 271 | HDMI_PLL_RESET, HDMI_PLL_RESET); | 278 | HDMI_PLL_RESET, HDMI_PLL_RESET); |
| 272 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, | 279 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, |
| 273 | HDMI_PLL_RESET, 0); | 280 | HDMI_PLL_RESET, 0); |
| 274 | } | ||
| 275 | 281 | ||
| 276 | /* Poll for lock bit */ | 282 | /* Poll for lock bit */ |
| 277 | regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, | 283 | regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, |
| 278 | (val & HDMI_PLL_LOCK), 10, 0); | 284 | (val & HDMI_PLL_LOCK), 10, 0); |
| 285 | } else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { | ||
| 286 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x1a0504f7); | ||
| 287 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00010000); | ||
| 288 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x00000000); | ||
| 289 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x6a28dc00); | ||
| 290 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x65771290); | ||
| 291 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x39272000); | ||
| 292 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL7, 0x56540000); | ||
| 293 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x3a0504f7); | ||
| 294 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x1a0504f7); | ||
| 295 | |||
| 296 | /* Poll for lock bit */ | ||
| 297 | regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, | ||
| 298 | ((val & HDMI_PLL_LOCK_G12A) == HDMI_PLL_LOCK_G12A), | ||
| 299 | 10, 0); | ||
| 300 | } | ||
| 279 | 301 | ||
| 280 | /* Disable VCLK2 */ | 302 | /* Disable VCLK2 */ |
| 281 | regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, 0); | 303 | regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, 0); |
| @@ -288,8 +310,13 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) | |||
| 288 | VCLK2_DIV_MASK, (55 - 1)); | 310 | VCLK2_DIV_MASK, (55 - 1)); |
| 289 | 311 | ||
| 290 | /* select vid_pll for vclk2 */ | 312 | /* select vid_pll for vclk2 */ |
| 291 | regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, | 313 | if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) |
| 292 | VCLK2_SEL_MASK, (4 << VCLK2_SEL_SHIFT)); | 314 | regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, |
| 315 | VCLK2_SEL_MASK, (0 << VCLK2_SEL_SHIFT)); | ||
| 316 | else | ||
| 317 | regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, | ||
| 318 | VCLK2_SEL_MASK, (4 << VCLK2_SEL_SHIFT)); | ||
| 319 | |||
| 293 | /* enable vclk2 gate */ | 320 | /* enable vclk2 gate */ |
| 294 | regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, VCLK2_EN); | 321 | regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, VCLK2_EN); |
| 295 | 322 | ||
| @@ -396,8 +423,8 @@ struct meson_vclk_params { | |||
| 396 | }, | 423 | }, |
| 397 | [MESON_VCLK_HDMI_297000] = { | 424 | [MESON_VCLK_HDMI_297000] = { |
| 398 | .pixel_freq = 297000, | 425 | .pixel_freq = 297000, |
| 399 | .pll_base_freq = 2970000, | 426 | .pll_base_freq = 5940000, |
| 400 | .pll_od1 = 1, | 427 | .pll_od1 = 2, |
| 401 | .pll_od2 = 1, | 428 | .pll_od2 = 1, |
| 402 | .pll_od3 = 1, | 429 | .pll_od3 = 1, |
| 403 | .vid_pll_div = VID_PLL_DIV_5, | 430 | .vid_pll_div = VID_PLL_DIV_5, |
| @@ -476,32 +503,80 @@ void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m, | |||
| 476 | /* Poll for lock bit */ | 503 | /* Poll for lock bit */ |
| 477 | regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, | 504 | regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, |
| 478 | (val & HDMI_PLL_LOCK), 10, 0); | 505 | (val & HDMI_PLL_LOCK), 10, 0); |
| 506 | } else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { | ||
| 507 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x0b3a0400 | m); | ||
| 508 | |||
| 509 | /* Enable and reset */ | ||
| 510 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, | ||
| 511 | 0x3 << 28, 0x3 << 28); | ||
| 512 | |||
| 513 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, frac); | ||
| 514 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x00000000); | ||
| 515 | |||
| 516 | /* G12A HDMI PLL Needs specific parameters for 5.4GHz */ | ||
| 517 | if (m >= 0xf7) { | ||
| 518 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0xea68dc00); | ||
| 519 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x65771290); | ||
| 520 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x39272000); | ||
| 521 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL7, 0x55540000); | ||
| 522 | } else { | ||
| 523 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0a691c00); | ||
| 524 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x33771290); | ||
| 525 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x39270000); | ||
| 526 | regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL7, 0x50540000); | ||
| 527 | } | ||
| 528 | |||
| 529 | do { | ||
| 530 | /* Reset PLL */ | ||
| 531 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, | ||
| 532 | HDMI_PLL_RESET_G12A, HDMI_PLL_RESET_G12A); | ||
| 533 | |||
| 534 | /* UN-Reset PLL */ | ||
| 535 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, | ||
| 536 | HDMI_PLL_RESET_G12A, 0); | ||
| 537 | |||
| 538 | /* Poll for lock bits */ | ||
| 539 | if (!regmap_read_poll_timeout(priv->hhi, | ||
| 540 | HHI_HDMI_PLL_CNTL, val, | ||
| 541 | ((val & HDMI_PLL_LOCK_G12A) | ||
| 542 | == HDMI_PLL_LOCK_G12A), | ||
| 543 | 10, 100)) | ||
| 544 | break; | ||
| 545 | } while(1); | ||
| 479 | } | 546 | } |
| 480 | 547 | ||
| 481 | if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) | 548 | if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) |
| 482 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, | 549 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, |
| 483 | 3 << 16, pll_od_to_reg(od1) << 16); | 550 | 3 << 16, pll_od_to_reg(od1) << 16); |
| 484 | else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || | 551 | else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || |
| 485 | meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) | 552 | meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) |
| 486 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, | 553 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, |
| 487 | 3 << 21, pll_od_to_reg(od1) << 21); | 554 | 3 << 21, pll_od_to_reg(od1) << 21); |
| 555 | else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) | ||
| 556 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, | ||
| 557 | 3 << 16, pll_od_to_reg(od1) << 16); | ||
| 488 | 558 | ||
| 489 | if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) | 559 | if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) |
| 490 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, | 560 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, |
| 491 | 3 << 22, pll_od_to_reg(od2) << 22); | 561 | 3 << 22, pll_od_to_reg(od2) << 22); |
| 492 | else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || | 562 | else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || |
| 493 | meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) | 563 | meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) |
| 494 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, | 564 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, |
| 495 | 3 << 23, pll_od_to_reg(od2) << 23); | 565 | 3 << 23, pll_od_to_reg(od2) << 23); |
| 566 | else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) | ||
| 567 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, | ||
| 568 | 3 << 18, pll_od_to_reg(od2) << 18); | ||
| 496 | 569 | ||
| 497 | if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) | 570 | if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) |
| 498 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, | 571 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, |
| 499 | 3 << 18, pll_od_to_reg(od3) << 18); | 572 | 3 << 18, pll_od_to_reg(od3) << 18); |
| 500 | else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || | 573 | else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || |
| 501 | meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) | 574 | meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) |
| 502 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, | 575 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, |
| 503 | 3 << 19, pll_od_to_reg(od3) << 19); | 576 | 3 << 19, pll_od_to_reg(od3) << 19); |
| 504 | 577 | else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) | |
| 578 | regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, | ||
| 579 | 3 << 20, pll_od_to_reg(od3) << 20); | ||
| 505 | } | 580 | } |
| 506 | 581 | ||
| 507 | #define XTAL_FREQ 24000 | 582 | #define XTAL_FREQ 24000 |
| @@ -518,6 +593,7 @@ static unsigned int meson_hdmi_pll_get_m(struct meson_drm *priv, | |||
| 518 | 593 | ||
| 519 | #define HDMI_FRAC_MAX_GXBB 4096 | 594 | #define HDMI_FRAC_MAX_GXBB 4096 |
| 520 | #define HDMI_FRAC_MAX_GXL 1024 | 595 | #define HDMI_FRAC_MAX_GXL 1024 |
| 596 | #define HDMI_FRAC_MAX_G12A 131072 | ||
| 521 | 597 | ||
| 522 | static unsigned int meson_hdmi_pll_get_frac(struct meson_drm *priv, | 598 | static unsigned int meson_hdmi_pll_get_frac(struct meson_drm *priv, |
| 523 | unsigned int m, | 599 | unsigned int m, |
| @@ -534,6 +610,9 @@ static unsigned int meson_hdmi_pll_get_frac(struct meson_drm *priv, | |||
| 534 | parent_freq *= 2; | 610 | parent_freq *= 2; |
| 535 | } | 611 | } |
| 536 | 612 | ||
| 613 | if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) | ||
| 614 | frac_max = HDMI_FRAC_MAX_G12A; | ||
| 615 | |||
| 537 | /* We can have a perfect match !*/ | 616 | /* We can have a perfect match !*/ |
| 538 | if (pll_freq / m == parent_freq && | 617 | if (pll_freq / m == parent_freq && |
| 539 | pll_freq % m == 0) | 618 | pll_freq % m == 0) |
| @@ -559,7 +638,8 @@ static bool meson_hdmi_pll_validate_params(struct meson_drm *priv, | |||
| 559 | if (frac >= HDMI_FRAC_MAX_GXBB) | 638 | if (frac >= HDMI_FRAC_MAX_GXBB) |
| 560 | return false; | 639 | return false; |
| 561 | } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || | 640 | } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || |
| 562 | meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { | 641 | meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu") || |
| 642 | meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { | ||
| 563 | /* Empiric supported min/max dividers */ | 643 | /* Empiric supported min/max dividers */ |
| 564 | if (m < 106 || m > 247) | 644 | if (m < 106 || m > 247) |
| 565 | return false; | 645 | return false; |
| @@ -714,6 +794,23 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq, | |||
| 714 | } | 794 | } |
| 715 | 795 | ||
| 716 | meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3); | 796 | meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3); |
| 797 | } else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { | ||
| 798 | switch (pll_base_freq) { | ||
| 799 | case 2970000: | ||
| 800 | m = 0x7b; | ||
| 801 | frac = vic_alternate_clock ? 0x140b4 : 0x18000; | ||
| 802 | break; | ||
| 803 | case 4320000: | ||
| 804 | m = vic_alternate_clock ? 0xb3 : 0xb4; | ||
| 805 | frac = vic_alternate_clock ? 0x1a3ee : 0; | ||
| 806 | break; | ||
| 807 | case 5940000: | ||
| 808 | m = 0xf7; | ||
| 809 | frac = vic_alternate_clock ? 0x8148 : 0x10000; | ||
| 810 | break; | ||
| 811 | } | ||
| 812 | |||
| 813 | meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3); | ||
| 717 | } | 814 | } |
| 718 | 815 | ||
| 719 | /* Setup vid_pll divider */ | 816 | /* Setup vid_pll divider */ |
diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c index 66d73a932d19..6faca7313339 100644 --- a/drivers/gpu/drm/meson/meson_venc.c +++ b/drivers/gpu/drm/meson/meson_venc.c | |||
| @@ -73,7 +73,9 @@ | |||
| 73 | /* HHI Registers */ | 73 | /* HHI Registers */ |
| 74 | #define HHI_GCLK_MPEG2 0x148 /* 0x52 offset in data sheet */ | 74 | #define HHI_GCLK_MPEG2 0x148 /* 0x52 offset in data sheet */ |
| 75 | #define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */ | 75 | #define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */ |
| 76 | #define HHI_VDAC_CNTL0_G12A 0x2EC /* 0xbd offset in data sheet */ | ||
| 76 | #define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */ | 77 | #define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */ |
| 78 | #define HHI_VDAC_CNTL1_G12A 0x2F0 /* 0xbe offset in data sheet */ | ||
| 77 | #define HHI_HDMI_PHY_CNTL0 0x3a0 /* 0xe8 offset in data sheet */ | 79 | #define HHI_HDMI_PHY_CNTL0 0x3a0 /* 0xe8 offset in data sheet */ |
| 78 | 80 | ||
| 79 | struct meson_cvbs_enci_mode meson_cvbs_enci_pal = { | 81 | struct meson_cvbs_enci_mode meson_cvbs_enci_pal = { |
| @@ -1675,8 +1677,13 @@ void meson_venc_disable_vsync(struct meson_drm *priv) | |||
| 1675 | void meson_venc_init(struct meson_drm *priv) | 1677 | void meson_venc_init(struct meson_drm *priv) |
| 1676 | { | 1678 | { |
| 1677 | /* Disable CVBS VDAC */ | 1679 | /* Disable CVBS VDAC */ |
| 1678 | regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0); | 1680 | if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { |
| 1679 | regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8); | 1681 | regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0); |
| 1682 | regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 8); | ||
| 1683 | } else { | ||
| 1684 | regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0); | ||
| 1685 | regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8); | ||
| 1686 | } | ||
| 1680 | 1687 | ||
| 1681 | /* Power Down Dacs */ | 1688 | /* Power Down Dacs */ |
| 1682 | writel_relaxed(0xff, priv->io_base + _REG(VENC_VDAC_SETTING)); | 1689 | writel_relaxed(0xff, priv->io_base + _REG(VENC_VDAC_SETTING)); |
diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c index d622d817b6df..2c5341c881c4 100644 --- a/drivers/gpu/drm/meson/meson_venc_cvbs.c +++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c | |||
| @@ -37,7 +37,9 @@ | |||
| 37 | 37 | ||
| 38 | /* HHI VDAC Registers */ | 38 | /* HHI VDAC Registers */ |
| 39 | #define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */ | 39 | #define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */ |
| 40 | #define HHI_VDAC_CNTL0_G12A 0x2EC /* 0xbd offset in data sheet */ | ||
| 40 | #define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */ | 41 | #define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */ |
| 42 | #define HHI_VDAC_CNTL1_G12A 0x2F0 /* 0xbe offset in data sheet */ | ||
| 41 | 43 | ||
| 42 | struct meson_venc_cvbs { | 44 | struct meson_venc_cvbs { |
| 43 | struct drm_encoder encoder; | 45 | struct drm_encoder encoder; |
| @@ -166,8 +168,13 @@ static void meson_venc_cvbs_encoder_disable(struct drm_encoder *encoder) | |||
| 166 | struct meson_drm *priv = meson_venc_cvbs->priv; | 168 | struct meson_drm *priv = meson_venc_cvbs->priv; |
| 167 | 169 | ||
| 168 | /* Disable CVBS VDAC */ | 170 | /* Disable CVBS VDAC */ |
| 169 | regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0); | 171 | if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { |
| 170 | regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8); | 172 | regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0); |
| 173 | regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 0); | ||
| 174 | } else { | ||
| 175 | regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0); | ||
| 176 | regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8); | ||
| 177 | } | ||
| 171 | } | 178 | } |
| 172 | 179 | ||
| 173 | static void meson_venc_cvbs_encoder_enable(struct drm_encoder *encoder) | 180 | static void meson_venc_cvbs_encoder_enable(struct drm_encoder *encoder) |
| @@ -179,13 +186,17 @@ static void meson_venc_cvbs_encoder_enable(struct drm_encoder *encoder) | |||
| 179 | /* VDAC0 source is not from ATV */ | 186 | /* VDAC0 source is not from ATV */ |
| 180 | writel_bits_relaxed(BIT(5), 0, priv->io_base + _REG(VENC_VDAC_DACSEL0)); | 187 | writel_bits_relaxed(BIT(5), 0, priv->io_base + _REG(VENC_VDAC_DACSEL0)); |
| 181 | 188 | ||
| 182 | if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) | 189 | if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { |
| 183 | regmap_write(priv->hhi, HHI_VDAC_CNTL0, 1); | 190 | regmap_write(priv->hhi, HHI_VDAC_CNTL0, 1); |
| 184 | else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || | 191 | regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0); |
| 185 | meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) | 192 | } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || |
| 193 | meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { | ||
| 186 | regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0xf0001); | 194 | regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0xf0001); |
| 187 | 195 | regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0); | |
| 188 | regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0); | 196 | } else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { |
| 197 | regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0x906001); | ||
| 198 | regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 0); | ||
| 199 | } | ||
| 189 | } | 200 | } |
| 190 | 201 | ||
| 191 | static void meson_venc_cvbs_encoder_mode_set(struct drm_encoder *encoder, | 202 | static void meson_venc_cvbs_encoder_mode_set(struct drm_encoder *encoder, |
diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c index ac0f3687e09a..0169c98b01c9 100644 --- a/drivers/gpu/drm/meson/meson_viu.c +++ b/drivers/gpu/drm/meson/meson_viu.c | |||
| @@ -90,6 +90,34 @@ static int eotf_bypass_coeff[EOTF_COEFF_SIZE] = { | |||
| 90 | EOTF_COEFF_RIGHTSHIFT /* right shift */ | 90 | EOTF_COEFF_RIGHTSHIFT /* right shift */ |
| 91 | }; | 91 | }; |
| 92 | 92 | ||
| 93 | void meson_viu_set_g12a_osd1_matrix(struct meson_drm *priv, int *m, | ||
| 94 | bool csc_on) | ||
| 95 | { | ||
| 96 | /* VPP WRAP OSD1 matrix */ | ||
| 97 | writel(((m[0] & 0xfff) << 16) | (m[1] & 0xfff), | ||
| 98 | priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_PRE_OFFSET0_1)); | ||
| 99 | writel(m[2] & 0xfff, | ||
| 100 | priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_PRE_OFFSET2)); | ||
| 101 | writel(((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff), | ||
| 102 | priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF00_01)); | ||
| 103 | writel(((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff), | ||
| 104 | priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF02_10)); | ||
| 105 | writel(((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff), | ||
| 106 | priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF11_12)); | ||
| 107 | writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff), | ||
| 108 | priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF20_21)); | ||
| 109 | writel((m[11] & 0x1fff) << 16, | ||
| 110 | priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF22)); | ||
| 111 | |||
| 112 | writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff), | ||
| 113 | priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_OFFSET0_1)); | ||
| 114 | writel(m[20] & 0xfff, | ||
| 115 | priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_OFFSET2)); | ||
| 116 | |||
| 117 | writel_bits_relaxed(BIT(0), csc_on ? BIT(0) : 0, | ||
| 118 | priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_EN_CTRL)); | ||
| 119 | } | ||
| 120 | |||
| 93 | void meson_viu_set_osd_matrix(struct meson_drm *priv, | 121 | void meson_viu_set_osd_matrix(struct meson_drm *priv, |
| 94 | enum viu_matrix_sel_e m_select, | 122 | enum viu_matrix_sel_e m_select, |
| 95 | int *m, bool csc_on) | 123 | int *m, bool csc_on) |
| @@ -336,14 +364,24 @@ void meson_viu_init(struct meson_drm *priv) | |||
| 336 | if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || | 364 | if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || |
| 337 | meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) | 365 | meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) |
| 338 | meson_viu_load_matrix(priv); | 366 | meson_viu_load_matrix(priv); |
| 367 | else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) | ||
| 368 | meson_viu_set_g12a_osd1_matrix(priv, RGB709_to_YUV709l_coeff, | ||
| 369 | true); | ||
| 339 | 370 | ||
| 340 | /* Initialize OSD1 fifo control register */ | 371 | /* Initialize OSD1 fifo control register */ |
| 341 | reg = BIT(0) | /* Urgent DDR request priority */ | 372 | reg = BIT(0) | /* Urgent DDR request priority */ |
| 342 | (4 << 5) | /* hold_fifo_lines */ | 373 | (4 << 5); /* hold_fifo_lines */ |
| 343 | (3 << 10) | /* burst length 64 */ | 374 | if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) |
| 344 | (32 << 12) | /* fifo_depth_val: 32*8=256 */ | 375 | reg |= (1 << 10) | /* burst length 32 */ |
| 345 | (2 << 22) | /* 4 words in 1 burst */ | 376 | (32 << 12) | /* fifo_depth_val: 32*8=256 */ |
| 346 | (2 << 24); | 377 | (2 << 22) | /* 4 words in 1 burst */ |
| 378 | (2 << 24) | | ||
| 379 | (1 << 31); | ||
| 380 | else | ||
| 381 | reg |= (3 << 10) | /* burst length 64 */ | ||
| 382 | (32 << 12) | /* fifo_depth_val: 32*8=256 */ | ||
| 383 | (2 << 22) | /* 4 words in 1 burst */ | ||
| 384 | (2 << 24); | ||
| 347 | writel_relaxed(reg, priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT)); | 385 | writel_relaxed(reg, priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT)); |
| 348 | writel_relaxed(reg, priv->io_base + _REG(VIU_OSD2_FIFO_CTRL_STAT)); | 386 | writel_relaxed(reg, priv->io_base + _REG(VIU_OSD2_FIFO_CTRL_STAT)); |
| 349 | 387 | ||
| @@ -369,6 +407,30 @@ void meson_viu_init(struct meson_drm *priv) | |||
| 369 | writel_relaxed(0x00FF00C0, | 407 | writel_relaxed(0x00FF00C0, |
| 370 | priv->io_base + _REG(VD2_IF0_LUMA_FIFO_SIZE)); | 408 | priv->io_base + _REG(VD2_IF0_LUMA_FIFO_SIZE)); |
| 371 | 409 | ||
| 410 | if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { | ||
| 411 | writel_relaxed(4 << 29 | | ||
| 412 | 1 << 27 | | ||
| 413 | 1 << 26 | /* blend_din0 input to blend0 */ | ||
| 414 | 1 << 25 | /* blend1_dout to blend2 */ | ||
| 415 | 1 << 24 | /* blend1_din3 input to blend1 */ | ||
| 416 | 1 << 20 | | ||
| 417 | 0 << 16 | | ||
| 418 | 1, | ||
| 419 | priv->io_base + _REG(VIU_OSD_BLEND_CTRL)); | ||
| 420 | writel_relaxed(3 << 8 | | ||
| 421 | 1 << 20, | ||
| 422 | priv->io_base + _REG(OSD1_BLEND_SRC_CTRL)); | ||
| 423 | writel_relaxed(1 << 20, | ||
| 424 | priv->io_base + _REG(OSD2_BLEND_SRC_CTRL)); | ||
| 425 | writel_relaxed(0, priv->io_base + _REG(VD1_BLEND_SRC_CTRL)); | ||
| 426 | writel_relaxed(0, priv->io_base + _REG(VD2_BLEND_SRC_CTRL)); | ||
| 427 | writel_relaxed(0, | ||
| 428 | priv->io_base + _REG(VIU_OSD_BLEND_DUMMY_DATA0)); | ||
| 429 | writel_relaxed(0, | ||
| 430 | priv->io_base + _REG(VIU_OSD_BLEND_DUMMY_ALPHA)); | ||
| 431 | writel_bits_relaxed(0x3 << 2, 0x3 << 2, | ||
| 432 | priv->io_base + _REG(DOLBY_PATH_CTRL)); | ||
| 433 | } | ||
| 372 | 434 | ||
| 373 | priv->viu.osd1_enabled = false; | 435 | priv->viu.osd1_enabled = false; |
| 374 | priv->viu.osd1_commit = false; | 436 | priv->viu.osd1_commit = false; |
diff --git a/drivers/gpu/drm/meson/meson_vpp.c b/drivers/gpu/drm/meson/meson_vpp.c index f9efb431e953..8c52a3455ef4 100644 --- a/drivers/gpu/drm/meson/meson_vpp.c +++ b/drivers/gpu/drm/meson/meson_vpp.c | |||
| @@ -112,32 +112,39 @@ void meson_vpp_init(struct meson_drm *priv) | |||
| 112 | writel_relaxed(0x20000, priv->io_base + _REG(VPP_DOLBY_CTRL)); | 112 | writel_relaxed(0x20000, priv->io_base + _REG(VPP_DOLBY_CTRL)); |
| 113 | writel_relaxed(0x1020080, | 113 | writel_relaxed(0x1020080, |
| 114 | priv->io_base + _REG(VPP_DUMMY_DATA1)); | 114 | priv->io_base + _REG(VPP_DUMMY_DATA1)); |
| 115 | } | 115 | } else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) |
| 116 | writel_relaxed(0xf, priv->io_base + _REG(DOLBY_PATH_CTRL)); | ||
| 116 | 117 | ||
| 117 | /* Initialize vpu fifo control registers */ | 118 | /* Initialize vpu fifo control registers */ |
| 118 | writel_relaxed(readl_relaxed(priv->io_base + _REG(VPP_OFIFO_SIZE)) | | 119 | if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) |
| 119 | 0x77f, priv->io_base + _REG(VPP_OFIFO_SIZE)); | 120 | writel_relaxed(0xfff << 20 | 0x1000, |
| 121 | priv->io_base + _REG(VPP_OFIFO_SIZE)); | ||
| 122 | else | ||
| 123 | writel_relaxed(readl_relaxed(priv->io_base + _REG(VPP_OFIFO_SIZE)) | | ||
| 124 | 0x77f, priv->io_base + _REG(VPP_OFIFO_SIZE)); | ||
| 120 | writel_relaxed(0x08080808, priv->io_base + _REG(VPP_HOLD_LINES)); | 125 | writel_relaxed(0x08080808, priv->io_base + _REG(VPP_HOLD_LINES)); |
| 121 | 126 | ||
| 122 | /* Turn off preblend */ | 127 | if (!meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { |
| 123 | writel_bits_relaxed(VPP_PREBLEND_ENABLE, 0, | 128 | /* Turn off preblend */ |
| 124 | priv->io_base + _REG(VPP_MISC)); | 129 | writel_bits_relaxed(VPP_PREBLEND_ENABLE, 0, |
| 125 | 130 | priv->io_base + _REG(VPP_MISC)); | |
| 126 | /* Turn off POSTBLEND */ | 131 | |
| 127 | writel_bits_relaxed(VPP_POSTBLEND_ENABLE, 0, | 132 | /* Turn off POSTBLEND */ |
| 128 | priv->io_base + _REG(VPP_MISC)); | 133 | writel_bits_relaxed(VPP_POSTBLEND_ENABLE, 0, |
| 129 | 134 | priv->io_base + _REG(VPP_MISC)); | |
| 130 | /* Force all planes off */ | 135 | |
| 131 | writel_bits_relaxed(VPP_OSD1_POSTBLEND | VPP_OSD2_POSTBLEND | | 136 | /* Force all planes off */ |
| 132 | VPP_VD1_POSTBLEND | VPP_VD2_POSTBLEND | | 137 | writel_bits_relaxed(VPP_OSD1_POSTBLEND | VPP_OSD2_POSTBLEND | |
| 133 | VPP_VD1_PREBLEND | VPP_VD2_PREBLEND, 0, | 138 | VPP_VD1_POSTBLEND | VPP_VD2_POSTBLEND | |
| 134 | priv->io_base + _REG(VPP_MISC)); | 139 | VPP_VD1_PREBLEND | VPP_VD2_PREBLEND, 0, |
| 135 | 140 | priv->io_base + _REG(VPP_MISC)); | |
| 136 | /* Setup default VD settings */ | 141 | |
| 137 | writel_relaxed(4096, | 142 | /* Setup default VD settings */ |
| 138 | priv->io_base + _REG(VPP_PREBLEND_VD1_H_START_END)); | 143 | writel_relaxed(4096, |
| 139 | writel_relaxed(4096, | 144 | priv->io_base + _REG(VPP_PREBLEND_VD1_H_START_END)); |
| 140 | priv->io_base + _REG(VPP_BLEND_VD2_H_START_END)); | 145 | writel_relaxed(4096, |
| 146 | priv->io_base + _REG(VPP_BLEND_VD2_H_START_END)); | ||
| 147 | } | ||
| 141 | 148 | ||
| 142 | /* Disable Scalers */ | 149 | /* Disable Scalers */ |
| 143 | writel_relaxed(0, priv->io_base + _REG(VPP_OSD_SC_CTRL0)); | 150 | writel_relaxed(0, priv->io_base + _REG(VPP_OSD_SC_CTRL0)); |
diff --git a/drivers/gpu/drm/panel/panel-rocktech-jh057n00900.c b/drivers/gpu/drm/panel/panel-rocktech-jh057n00900.c index 158a6d548068..d88ea8da2ec2 100644 --- a/drivers/gpu/drm/panel/panel-rocktech-jh057n00900.c +++ b/drivers/gpu/drm/panel/panel-rocktech-jh057n00900.c | |||
| @@ -123,7 +123,7 @@ static int jh057n_init_sequence(struct jh057n *ctx) | |||
| 123 | 123 | ||
| 124 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); | 124 | ret = mipi_dsi_dcs_exit_sleep_mode(dsi); |
| 125 | if (ret < 0) { | 125 | if (ret < 0) { |
| 126 | DRM_DEV_ERROR(dev, "Failed to exit sleep mode"); | 126 | DRM_DEV_ERROR(dev, "Failed to exit sleep mode\n"); |
| 127 | return ret; | 127 | return ret; |
| 128 | } | 128 | } |
| 129 | /* Panel is operational 120 msec after reset */ | 129 | /* Panel is operational 120 msec after reset */ |
| @@ -132,7 +132,7 @@ static int jh057n_init_sequence(struct jh057n *ctx) | |||
| 132 | if (ret) | 132 | if (ret) |
| 133 | return ret; | 133 | return ret; |
| 134 | 134 | ||
| 135 | DRM_DEV_DEBUG_DRIVER(dev, "Panel init sequence done"); | 135 | DRM_DEV_DEBUG_DRIVER(dev, "Panel init sequence done\n"); |
| 136 | return 0; | 136 | return 0; |
| 137 | } | 137 | } |
| 138 | 138 | ||
| @@ -172,7 +172,7 @@ static int jh057n_prepare(struct drm_panel *panel) | |||
| 172 | if (ctx->prepared) | 172 | if (ctx->prepared) |
| 173 | return 0; | 173 | return 0; |
| 174 | 174 | ||
| 175 | DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel."); | 175 | DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel\n"); |
| 176 | gpiod_set_value_cansleep(ctx->reset_gpio, 1); | 176 | gpiod_set_value_cansleep(ctx->reset_gpio, 1); |
| 177 | usleep_range(20, 40); | 177 | usleep_range(20, 40); |
| 178 | gpiod_set_value_cansleep(ctx->reset_gpio, 0); | 178 | gpiod_set_value_cansleep(ctx->reset_gpio, 0); |
| @@ -180,7 +180,8 @@ static int jh057n_prepare(struct drm_panel *panel) | |||
| 180 | 180 | ||
| 181 | ret = jh057n_init_sequence(ctx); | 181 | ret = jh057n_init_sequence(ctx); |
| 182 | if (ret < 0) { | 182 | if (ret < 0) { |
| 183 | DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d", ret); | 183 | DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n", |
| 184 | ret); | ||
| 184 | return ret; | 185 | return ret; |
| 185 | } | 186 | } |
| 186 | 187 | ||
| @@ -212,7 +213,7 @@ static int jh057n_get_modes(struct drm_panel *panel) | |||
| 212 | 213 | ||
| 213 | mode = drm_mode_duplicate(panel->drm, &default_mode); | 214 | mode = drm_mode_duplicate(panel->drm, &default_mode); |
| 214 | if (!mode) { | 215 | if (!mode) { |
| 215 | DRM_DEV_ERROR(ctx->dev, "Failed to add mode %ux%u@%u", | 216 | DRM_DEV_ERROR(ctx->dev, "Failed to add mode %ux%u@%u\n", |
| 216 | default_mode.hdisplay, default_mode.vdisplay, | 217 | default_mode.hdisplay, default_mode.vdisplay, |
| 217 | default_mode.vrefresh); | 218 | default_mode.vrefresh); |
| 218 | return -ENOMEM; | 219 | return -ENOMEM; |
| @@ -241,7 +242,7 @@ static int allpixelson_set(void *data, u64 val) | |||
| 241 | struct jh057n *ctx = data; | 242 | struct jh057n *ctx = data; |
| 242 | struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | 243 | struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); |
| 243 | 244 | ||
| 244 | DRM_DEV_DEBUG_DRIVER(ctx->dev, "Setting all pixels on"); | 245 | DRM_DEV_DEBUG_DRIVER(ctx->dev, "Setting all pixels on\n"); |
| 245 | dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON); | 246 | dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON); |
| 246 | msleep(val * 1000); | 247 | msleep(val * 1000); |
| 247 | /* Reset the panel to get video back */ | 248 | /* Reset the panel to get video back */ |
| @@ -290,7 +291,7 @@ static int jh057n_probe(struct mipi_dsi_device *dsi) | |||
| 290 | 291 | ||
| 291 | ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); | 292 | ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); |
| 292 | if (IS_ERR(ctx->reset_gpio)) { | 293 | if (IS_ERR(ctx->reset_gpio)) { |
| 293 | DRM_DEV_ERROR(dev, "cannot get reset gpio"); | 294 | DRM_DEV_ERROR(dev, "cannot get reset gpio\n"); |
| 294 | return PTR_ERR(ctx->reset_gpio); | 295 | return PTR_ERR(ctx->reset_gpio); |
| 295 | } | 296 | } |
| 296 | 297 | ||
| @@ -315,12 +316,12 @@ static int jh057n_probe(struct mipi_dsi_device *dsi) | |||
| 315 | 316 | ||
| 316 | ret = mipi_dsi_attach(dsi); | 317 | ret = mipi_dsi_attach(dsi); |
| 317 | if (ret < 0) { | 318 | if (ret < 0) { |
| 318 | DRM_DEV_ERROR(dev, "mipi_dsi_attach failed. Is host ready?"); | 319 | DRM_DEV_ERROR(dev, "mipi_dsi_attach failed. Is host ready?\n"); |
| 319 | drm_panel_remove(&ctx->panel); | 320 | drm_panel_remove(&ctx->panel); |
| 320 | return ret; | 321 | return ret; |
| 321 | } | 322 | } |
| 322 | 323 | ||
| 323 | DRM_DEV_INFO(dev, "%ux%u@%u %ubpp dsi %udl - ready", | 324 | DRM_DEV_INFO(dev, "%ux%u@%u %ubpp dsi %udl - ready\n", |
| 324 | default_mode.hdisplay, default_mode.vdisplay, | 325 | default_mode.hdisplay, default_mode.vdisplay, |
| 325 | default_mode.vrefresh, | 326 | default_mode.vrefresh, |
| 326 | mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes); | 327 | mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes); |
diff --git a/drivers/gpu/drm/pl111/pl111_versatile.c b/drivers/gpu/drm/pl111/pl111_versatile.c index b9baefdba38a..1c318ad32a8c 100644 --- a/drivers/gpu/drm/pl111/pl111_versatile.c +++ b/drivers/gpu/drm/pl111/pl111_versatile.c | |||
| @@ -330,6 +330,7 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv) | |||
| 330 | ret = vexpress_muxfpga_init(); | 330 | ret = vexpress_muxfpga_init(); |
| 331 | if (ret) { | 331 | if (ret) { |
| 332 | dev_err(dev, "unable to initialize muxfpga driver\n"); | 332 | dev_err(dev, "unable to initialize muxfpga driver\n"); |
| 333 | of_node_put(np); | ||
| 333 | return ret; | 334 | return ret; |
| 334 | } | 335 | } |
| 335 | 336 | ||
| @@ -337,17 +338,20 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv) | |||
| 337 | pdev = of_find_device_by_node(np); | 338 | pdev = of_find_device_by_node(np); |
| 338 | if (!pdev) { | 339 | if (!pdev) { |
| 339 | dev_err(dev, "can't find the sysreg device, deferring\n"); | 340 | dev_err(dev, "can't find the sysreg device, deferring\n"); |
| 341 | of_node_put(np); | ||
| 340 | return -EPROBE_DEFER; | 342 | return -EPROBE_DEFER; |
| 341 | } | 343 | } |
| 342 | map = dev_get_drvdata(&pdev->dev); | 344 | map = dev_get_drvdata(&pdev->dev); |
| 343 | if (!map) { | 345 | if (!map) { |
| 344 | dev_err(dev, "sysreg has not yet probed\n"); | 346 | dev_err(dev, "sysreg has not yet probed\n"); |
| 345 | platform_device_put(pdev); | 347 | platform_device_put(pdev); |
| 348 | of_node_put(np); | ||
| 346 | return -EPROBE_DEFER; | 349 | return -EPROBE_DEFER; |
| 347 | } | 350 | } |
| 348 | } else { | 351 | } else { |
| 349 | map = syscon_node_to_regmap(np); | 352 | map = syscon_node_to_regmap(np); |
| 350 | } | 353 | } |
| 354 | of_node_put(np); | ||
| 351 | 355 | ||
| 352 | if (IS_ERR(map)) { | 356 | if (IS_ERR(map)) { |
| 353 | dev_err(dev, "no Versatile syscon regmap\n"); | 357 | dev_err(dev, "no Versatile syscon regmap\n"); |
diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c b/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c index d7b38dfb6438..6d540d93758f 100644 --- a/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c +++ b/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c | |||
| @@ -26,164 +26,6 @@ static unsigned int spi_max; | |||
| 26 | module_param(spi_max, uint, 0400); | 26 | module_param(spi_max, uint, 0400); |
| 27 | MODULE_PARM_DESC(spi_max, "Set a lower SPI max transfer size"); | 27 | MODULE_PARM_DESC(spi_max, "Set a lower SPI max transfer size"); |
| 28 | 28 | ||
| 29 | /** | ||
| 30 | * tinydrm_memcpy - Copy clip buffer | ||
| 31 | * @dst: Destination buffer | ||
| 32 | * @vaddr: Source buffer | ||
| 33 | * @fb: DRM framebuffer | ||
| 34 | * @clip: Clip rectangle area to copy | ||
| 35 | */ | ||
| 36 | void tinydrm_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb, | ||
| 37 | struct drm_rect *clip) | ||
| 38 | { | ||
| 39 | unsigned int cpp = drm_format_plane_cpp(fb->format->format, 0); | ||
| 40 | unsigned int pitch = fb->pitches[0]; | ||
| 41 | void *src = vaddr + (clip->y1 * pitch) + (clip->x1 * cpp); | ||
| 42 | size_t len = (clip->x2 - clip->x1) * cpp; | ||
| 43 | unsigned int y; | ||
| 44 | |||
| 45 | for (y = clip->y1; y < clip->y2; y++) { | ||
| 46 | memcpy(dst, src, len); | ||
| 47 | src += pitch; | ||
| 48 | dst += len; | ||
| 49 | } | ||
| 50 | } | ||
| 51 | EXPORT_SYMBOL(tinydrm_memcpy); | ||
| 52 | |||
| 53 | /** | ||
| 54 | * tinydrm_swab16 - Swap bytes into clip buffer | ||
| 55 | * @dst: RGB565 destination buffer | ||
| 56 | * @vaddr: RGB565 source buffer | ||
| 57 | * @fb: DRM framebuffer | ||
| 58 | * @clip: Clip rectangle area to copy | ||
| 59 | */ | ||
| 60 | void tinydrm_swab16(u16 *dst, void *vaddr, struct drm_framebuffer *fb, | ||
| 61 | struct drm_rect *clip) | ||
| 62 | { | ||
| 63 | size_t len = (clip->x2 - clip->x1) * sizeof(u16); | ||
| 64 | unsigned int x, y; | ||
| 65 | u16 *src, *buf; | ||
| 66 | |||
| 67 | /* | ||
| 68 | * The cma memory is write-combined so reads are uncached. | ||
| 69 | * Speed up by fetching one line at a time. | ||
| 70 | */ | ||
| 71 | buf = kmalloc(len, GFP_KERNEL); | ||
| 72 | if (!buf) | ||
| 73 | return; | ||
| 74 | |||
| 75 | for (y = clip->y1; y < clip->y2; y++) { | ||
| 76 | src = vaddr + (y * fb->pitches[0]); | ||
| 77 | src += clip->x1; | ||
| 78 | memcpy(buf, src, len); | ||
| 79 | src = buf; | ||
| 80 | for (x = clip->x1; x < clip->x2; x++) | ||
| 81 | *dst++ = swab16(*src++); | ||
| 82 | } | ||
| 83 | |||
| 84 | kfree(buf); | ||
| 85 | } | ||
| 86 | EXPORT_SYMBOL(tinydrm_swab16); | ||
| 87 | |||
| 88 | /** | ||
| 89 | * tinydrm_xrgb8888_to_rgb565 - Convert XRGB8888 to RGB565 clip buffer | ||
| 90 | * @dst: RGB565 destination buffer | ||
| 91 | * @vaddr: XRGB8888 source buffer | ||
| 92 | * @fb: DRM framebuffer | ||
| 93 | * @clip: Clip rectangle area to copy | ||
| 94 | * @swap: Swap bytes | ||
| 95 | * | ||
| 96 | * Drivers can use this function for RGB565 devices that don't natively | ||
| 97 | * support XRGB8888. | ||
| 98 | */ | ||
| 99 | void tinydrm_xrgb8888_to_rgb565(u16 *dst, void *vaddr, | ||
| 100 | struct drm_framebuffer *fb, | ||
| 101 | struct drm_rect *clip, bool swap) | ||
| 102 | { | ||
| 103 | size_t len = (clip->x2 - clip->x1) * sizeof(u32); | ||
| 104 | unsigned int x, y; | ||
| 105 | u32 *src, *buf; | ||
| 106 | u16 val16; | ||
| 107 | |||
| 108 | buf = kmalloc(len, GFP_KERNEL); | ||
| 109 | if (!buf) | ||
| 110 | return; | ||
| 111 | |||
| 112 | for (y = clip->y1; y < clip->y2; y++) { | ||
| 113 | src = vaddr + (y * fb->pitches[0]); | ||
| 114 | src += clip->x1; | ||
| 115 | memcpy(buf, src, len); | ||
| 116 | src = buf; | ||
| 117 | for (x = clip->x1; x < clip->x2; x++) { | ||
| 118 | val16 = ((*src & 0x00F80000) >> 8) | | ||
| 119 | ((*src & 0x0000FC00) >> 5) | | ||
| 120 | ((*src & 0x000000F8) >> 3); | ||
| 121 | src++; | ||
| 122 | if (swap) | ||
| 123 | *dst++ = swab16(val16); | ||
| 124 | else | ||
| 125 | *dst++ = val16; | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | kfree(buf); | ||
| 130 | } | ||
| 131 | EXPORT_SYMBOL(tinydrm_xrgb8888_to_rgb565); | ||
| 132 | |||
| 133 | /** | ||
| 134 | * tinydrm_xrgb8888_to_gray8 - Convert XRGB8888 to grayscale | ||
| 135 | * @dst: 8-bit grayscale destination buffer | ||
| 136 | * @vaddr: XRGB8888 source buffer | ||
| 137 | * @fb: DRM framebuffer | ||
| 138 | * @clip: Clip rectangle area to copy | ||
| 139 | * | ||
| 140 | * Drm doesn't have native monochrome or grayscale support. | ||
| 141 | * Such drivers can announce the commonly supported XR24 format to userspace | ||
| 142 | * and use this function to convert to the native format. | ||
| 143 | * | ||
| 144 | * Monochrome drivers will use the most significant bit, | ||
| 145 | * where 1 means foreground color and 0 background color. | ||
| 146 | * | ||
| 147 | * ITU BT.601 is used for the RGB -> luma (brightness) conversion. | ||
| 148 | */ | ||
| 149 | void tinydrm_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb, | ||
| 150 | struct drm_rect *clip) | ||
| 151 | { | ||
| 152 | unsigned int len = (clip->x2 - clip->x1) * sizeof(u32); | ||
| 153 | unsigned int x, y; | ||
| 154 | void *buf; | ||
| 155 | u32 *src; | ||
| 156 | |||
| 157 | if (WARN_ON(fb->format->format != DRM_FORMAT_XRGB8888)) | ||
| 158 | return; | ||
| 159 | /* | ||
| 160 | * The cma memory is write-combined so reads are uncached. | ||
| 161 | * Speed up by fetching one line at a time. | ||
| 162 | */ | ||
| 163 | buf = kmalloc(len, GFP_KERNEL); | ||
| 164 | if (!buf) | ||
| 165 | return; | ||
| 166 | |||
| 167 | for (y = clip->y1; y < clip->y2; y++) { | ||
| 168 | src = vaddr + (y * fb->pitches[0]); | ||
| 169 | src += clip->x1; | ||
| 170 | memcpy(buf, src, len); | ||
| 171 | src = buf; | ||
| 172 | for (x = clip->x1; x < clip->x2; x++) { | ||
| 173 | u8 r = (*src & 0x00ff0000) >> 16; | ||
| 174 | u8 g = (*src & 0x0000ff00) >> 8; | ||
| 175 | u8 b = *src & 0x000000ff; | ||
| 176 | |||
| 177 | /* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */ | ||
| 178 | *dst++ = (3 * r + 6 * g + b) / 10; | ||
| 179 | src++; | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | kfree(buf); | ||
| 184 | } | ||
| 185 | EXPORT_SYMBOL(tinydrm_xrgb8888_to_gray8); | ||
| 186 | |||
| 187 | #if IS_ENABLED(CONFIG_SPI) | 29 | #if IS_ENABLED(CONFIG_SPI) |
| 188 | 30 | ||
| 189 | /** | 31 | /** |
diff --git a/drivers/gpu/drm/tinydrm/mipi-dbi.c b/drivers/gpu/drm/tinydrm/mipi-dbi.c index 869c8f56da3b..85761b4abb83 100644 --- a/drivers/gpu/drm/tinydrm/mipi-dbi.c +++ b/drivers/gpu/drm/tinydrm/mipi-dbi.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <drm/drm_drv.h> | 21 | #include <drm/drm_drv.h> |
| 22 | #include <drm/drm_fb_cma_helper.h> | 22 | #include <drm/drm_fb_cma_helper.h> |
| 23 | #include <drm/drm_gem_cma_helper.h> | 23 | #include <drm/drm_gem_cma_helper.h> |
| 24 | #include <drm/drm_format_helper.h> | ||
| 24 | #include <drm/drm_fourcc.h> | 25 | #include <drm/drm_fourcc.h> |
| 25 | #include <drm/drm_gem_framebuffer_helper.h> | 26 | #include <drm/drm_gem_framebuffer_helper.h> |
| 26 | #include <drm/drm_vblank.h> | 27 | #include <drm/drm_vblank.h> |
| @@ -218,12 +219,12 @@ int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb, | |||
| 218 | switch (fb->format->format) { | 219 | switch (fb->format->format) { |
| 219 | case DRM_FORMAT_RGB565: | 220 | case DRM_FORMAT_RGB565: |
| 220 | if (swap) | 221 | if (swap) |
| 221 | tinydrm_swab16(dst, src, fb, clip); | 222 | drm_fb_swab16(dst, src, fb, clip); |
| 222 | else | 223 | else |
| 223 | tinydrm_memcpy(dst, src, fb, clip); | 224 | drm_fb_memcpy(dst, src, fb, clip); |
| 224 | break; | 225 | break; |
| 225 | case DRM_FORMAT_XRGB8888: | 226 | case DRM_FORMAT_XRGB8888: |
| 226 | tinydrm_xrgb8888_to_rgb565(dst, src, fb, clip, swap); | 227 | drm_fb_xrgb8888_to_rgb565(dst, src, fb, clip, swap); |
| 227 | break; | 228 | break; |
| 228 | default: | 229 | default: |
| 229 | dev_err_once(fb->dev->dev, "Format is not supported: %s\n", | 230 | dev_err_once(fb->dev->dev, "Format is not supported: %s\n", |
diff --git a/drivers/gpu/drm/tinydrm/repaper.c b/drivers/gpu/drm/tinydrm/repaper.c index 3f3632457079..a29b8278324b 100644 --- a/drivers/gpu/drm/tinydrm/repaper.c +++ b/drivers/gpu/drm/tinydrm/repaper.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include <drm/drm_drv.h> | 31 | #include <drm/drm_drv.h> |
| 32 | #include <drm/drm_fb_cma_helper.h> | 32 | #include <drm/drm_fb_cma_helper.h> |
| 33 | #include <drm/drm_fb_helper.h> | 33 | #include <drm/drm_fb_helper.h> |
| 34 | #include <drm/drm_format_helper.h> | ||
| 34 | #include <drm/drm_gem_cma_helper.h> | 35 | #include <drm/drm_gem_cma_helper.h> |
| 35 | #include <drm/drm_gem_framebuffer_helper.h> | 36 | #include <drm/drm_gem_framebuffer_helper.h> |
| 36 | #include <drm/drm_rect.h> | 37 | #include <drm/drm_rect.h> |
| @@ -566,7 +567,7 @@ static int repaper_fb_dirty(struct drm_framebuffer *fb) | |||
| 566 | goto out_free; | 567 | goto out_free; |
| 567 | } | 568 | } |
| 568 | 569 | ||
| 569 | tinydrm_xrgb8888_to_gray8(buf, cma_obj->vaddr, fb, &clip); | 570 | drm_fb_xrgb8888_to_gray8(buf, cma_obj->vaddr, fb, &clip); |
| 570 | 571 | ||
| 571 | if (import_attach) { | 572 | if (import_attach) { |
| 572 | ret = dma_buf_end_cpu_access(import_attach->dmabuf, | 573 | ret = dma_buf_end_cpu_access(import_attach->dmabuf, |
diff --git a/drivers/gpu/drm/tinydrm/st7586.c b/drivers/gpu/drm/tinydrm/st7586.c index d99957bac532..560d7ac0cadc 100644 --- a/drivers/gpu/drm/tinydrm/st7586.c +++ b/drivers/gpu/drm/tinydrm/st7586.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include <drm/drm_drv.h> | 22 | #include <drm/drm_drv.h> |
| 23 | #include <drm/drm_fb_cma_helper.h> | 23 | #include <drm/drm_fb_cma_helper.h> |
| 24 | #include <drm/drm_fb_helper.h> | 24 | #include <drm/drm_fb_helper.h> |
| 25 | #include <drm/drm_format_helper.h> | ||
| 25 | #include <drm/drm_gem_cma_helper.h> | 26 | #include <drm/drm_gem_cma_helper.h> |
| 26 | #include <drm/drm_gem_framebuffer_helper.h> | 27 | #include <drm/drm_gem_framebuffer_helper.h> |
| 27 | #include <drm/drm_rect.h> | 28 | #include <drm/drm_rect.h> |
| @@ -77,7 +78,7 @@ static void st7586_xrgb8888_to_gray332(u8 *dst, void *vaddr, | |||
| 77 | if (!buf) | 78 | if (!buf) |
| 78 | return; | 79 | return; |
| 79 | 80 | ||
| 80 | tinydrm_xrgb8888_to_gray8(buf, vaddr, fb, clip); | 81 | drm_fb_xrgb8888_to_gray8(buf, vaddr, fb, clip); |
| 81 | src = buf; | 82 | src = buf; |
| 82 | 83 | ||
| 83 | for (y = clip->y1; y < clip->y2; y++) { | 84 | for (y = clip->y1; y < clip->y2; y++) { |
diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c index 69df84bdf904..f9dec08267dc 100644 --- a/drivers/gpu/drm/vc4/vc4_debugfs.c +++ b/drivers/gpu/drm/vc4/vc4_debugfs.c | |||
| @@ -48,7 +48,7 @@ vc4_debugfs_init(struct drm_minor *minor) | |||
| 48 | return 0; | 48 | return 0; |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | int vc4_debugfs_regset32(struct seq_file *m, void *unused) | 51 | static int vc4_debugfs_regset32(struct seq_file *m, void *unused) |
| 52 | { | 52 | { |
| 53 | struct drm_info_node *node = (struct drm_info_node *)m->private; | 53 | struct drm_info_node *node = (struct drm_info_node *)m->private; |
| 54 | struct debugfs_regset32 *regset = node->info_ent->data; | 54 | struct debugfs_regset32 *regset = node->info_ent->data; |
diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h new file mode 100644 index 000000000000..6f84380757ee --- /dev/null +++ b/include/drm/drm_format_helper.h | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2016 Noralf Trønnes | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation; either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #ifndef __LINUX_DRM_FORMAT_HELPER_H | ||
| 11 | #define __LINUX_DRM_FORMAT_HELPER_H | ||
| 12 | |||
| 13 | struct drm_framebuffer; | ||
| 14 | struct drm_rect; | ||
| 15 | |||
| 16 | void drm_fb_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb, | ||
| 17 | struct drm_rect *clip); | ||
| 18 | void drm_fb_memcpy_dstclip(void *dst, void *vaddr, struct drm_framebuffer *fb, | ||
| 19 | struct drm_rect *clip); | ||
| 20 | void drm_fb_swab16(u16 *dst, void *vaddr, struct drm_framebuffer *fb, | ||
| 21 | struct drm_rect *clip); | ||
| 22 | void drm_fb_xrgb8888_to_rgb565(void *dst, void *vaddr, | ||
| 23 | struct drm_framebuffer *fb, | ||
| 24 | struct drm_rect *clip, bool swap); | ||
| 25 | void drm_fb_xrgb8888_to_rgb565_dstclip(void *dst, unsigned int dst_pitch, | ||
| 26 | void *vaddr, struct drm_framebuffer *fb, | ||
| 27 | struct drm_rect *clip, bool swap); | ||
| 28 | void drm_fb_xrgb8888_to_rgb888_dstclip(void *dst, unsigned int dst_pitch, | ||
| 29 | void *vaddr, struct drm_framebuffer *fb, | ||
| 30 | struct drm_rect *clip); | ||
| 31 | void drm_fb_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb, | ||
| 32 | struct drm_rect *clip); | ||
| 33 | |||
| 34 | #endif /* __LINUX_DRM_FORMAT_HELPER_H */ | ||
diff --git a/include/drm/tinydrm/tinydrm-helpers.h b/include/drm/tinydrm/tinydrm-helpers.h index ae4a6abc43b5..7d259acb8826 100644 --- a/include/drm/tinydrm/tinydrm-helpers.h +++ b/include/drm/tinydrm/tinydrm-helpers.h | |||
| @@ -46,16 +46,6 @@ int tinydrm_display_pipe_init(struct drm_device *drm, | |||
| 46 | const struct drm_display_mode *mode, | 46 | const struct drm_display_mode *mode, |
| 47 | unsigned int rotation); | 47 | unsigned int rotation); |
| 48 | 48 | ||
| 49 | void tinydrm_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb, | ||
| 50 | struct drm_rect *clip); | ||
| 51 | void tinydrm_swab16(u16 *dst, void *vaddr, struct drm_framebuffer *fb, | ||
| 52 | struct drm_rect *clip); | ||
| 53 | void tinydrm_xrgb8888_to_rgb565(u16 *dst, void *vaddr, | ||
| 54 | struct drm_framebuffer *fb, | ||
| 55 | struct drm_rect *clip, bool swap); | ||
| 56 | void tinydrm_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb, | ||
| 57 | struct drm_rect *clip); | ||
| 58 | |||
| 59 | size_t tinydrm_spi_max_transfer_size(struct spi_device *spi, size_t max_len); | 49 | size_t tinydrm_spi_max_transfer_size(struct spi_device *spi, size_t max_len); |
| 60 | bool tinydrm_spi_bpw_supported(struct spi_device *spi, u8 bpw); | 50 | bool tinydrm_spi_bpw_supported(struct spi_device *spi, u8 bpw); |
| 61 | int tinydrm_spi_transfer(struct spi_device *spi, u32 speed_hz, | 51 | int tinydrm_spi_transfer(struct spi_device *spi, u32 speed_hz, |
