forked from luck/tmp_suning_uos_patched
drm-misc-next for 5.2:
UAPI Changes: - None Cross-subsystem Changes: -MAINTAINERS: Add moderation flag for lima mailing list (Randy) -dt-bindings: Add Mali Bifrost bindings (Neil) -dt-bindings: Add G12A compatibility strings to meson bindings (Neil) Core Changes: -Add a handful of format helpers (Gerd) Driver Changes: -cirrus: Driver rewrite megapatch (Gerd) -meson: Add G12A support to meson driver (Neil) -lima: Couple fixes (Qiang) Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: Randy Dunlap <rdunlap@infradead.org> Cc: Neil Armstrong <narmstrong@baylibre.com> Cc: Qiang Yu <yuq825@gmail.com> -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEfxcpfMSgdnQMs+QqlvcN/ahKBwoFAlyuR6EACgkQlvcN/ahK BwqMIwgAswHcmbyBSq6Z1RPaq7VvStWsFfpA0QpWCyF5ZORTOPaC/eocOOnM01cP 5pqpQwdQWt/82JMm+k7TbBE+pTXlmnIk9dX907DcJpoyg9nTCvFHfOjKL1+YJMGs EaRcqzbYdBCo9ExwS8UFs+tl6DBwcWb462JeGqZg/IC3JGZgm7NrI9eFNho/v+q7 B4FYUQ9ZXbzkaxceVtRuULsRMB7y5Fuv5qWqVgMk6Dgk9kvulHSVgdMwkKu7bQzH lgi7wfcXYiF18MmdXc/B7GIHllecQEp68PYYXxvJyCr8f3NeLmNX/r9DgWqb4DEf 8Rgb802mNXy9hrOWEAT01NkdTyQdSQ== =KPnH -----END PGP SIGNATURE----- Merge tag 'drm-misc-next-2019-04-10' of git://anongit.freedesktop.org/drm/drm-misc into drm-next drm-misc-next for 5.2: UAPI Changes: - None Cross-subsystem Changes: -MAINTAINERS: Add moderation flag for lima mailing list (Randy) -dt-bindings: Add Mali Bifrost bindings (Neil) -dt-bindings: Add G12A compatibility strings to meson bindings (Neil) Core Changes: -Add a handful of format helpers (Gerd) Driver Changes: -cirrus: Driver rewrite megapatch (Gerd) -meson: Add G12A support to meson driver (Neil) -lima: Couple fixes (Qiang) Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: Randy Dunlap <rdunlap@infradead.org> Cc: Neil Armstrong <narmstrong@baylibre.com> Cc: Qiang Yu <yuq825@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com> From: Sean Paul <sean@poorly.run> Link: https://patchwork.freedesktop.org/patch/msgid/20190410194907.GA108842@art_vandelay
This commit is contained in:
commit
5c8c397c3e
|
@ -37,6 +37,7 @@ Required properties:
|
|||
- GXL (S905X, S905D) : "amlogic,meson-gxl-dw-hdmi"
|
||||
- GXM (S912) : "amlogic,meson-gxm-dw-hdmi"
|
||||
followed by the common "amlogic,meson-gx-dw-hdmi"
|
||||
- G12A (S905X2, S905Y2, S905D2) : "amlogic,meson-g12a-dw-hdmi"
|
||||
- reg: Physical base address and length of the controller's registers.
|
||||
- interrupts: The HDMI interrupt number
|
||||
- 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.
|
|||
S905X (GXL) VENC Input TMDS Output
|
||||
S905D (GXL) VENC Input TMDS Output
|
||||
S912 (GXM) VENC Input TMDS Output
|
||||
S905X2 (G12A) VENC Input TMDS Output
|
||||
S905Y2 (G12A) VENC Input TMDS Output
|
||||
S905D2 (G12A) VENC Input TMDS Output
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@ Required properties:
|
|||
- GXL (S905X, S905D) : "amlogic,meson-gxl-vpu"
|
||||
- GXM (S912) : "amlogic,meson-gxm-vpu"
|
||||
followed by the common "amlogic,meson-gx-vpu"
|
||||
- G12A (S905X2, S905Y2, S905D2) : "amlogic,meson-g12a-vpu"
|
||||
- reg: base address and size of he following memory-mapped regions :
|
||||
- vpu
|
||||
- hhi
|
||||
|
@ -83,6 +84,9 @@ corresponding to each VPU output.
|
|||
S905X (GXL) CVBS VDAC HDMI-TX
|
||||
S905D (GXL) CVBS VDAC HDMI-TX
|
||||
S912 (GXM) CVBS VDAC HDMI-TX
|
||||
S905X2 (G12A) CVBS VDAC HDMI-TX
|
||||
S905Y2 (G12A) CVBS VDAC HDMI-TX
|
||||
S905D2 (G12A) CVBS VDAC HDMI-TX
|
||||
|
||||
Example:
|
||||
|
||||
|
|
92
Documentation/devicetree/bindings/gpu/arm,mali-bifrost.txt
Normal file
92
Documentation/devicetree/bindings/gpu/arm,mali-bifrost.txt
Normal file
|
@ -0,0 +1,92 @@
|
|||
ARM Mali Bifrost GPU
|
||||
====================
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible :
|
||||
* Since Mali Bifrost GPU model/revision is fully discoverable by reading
|
||||
some determined registers, must contain the following:
|
||||
+ "arm,mali-bifrost"
|
||||
* which must be preceded by one of the following vendor specifics:
|
||||
+ "amlogic,meson-g12a-mali"
|
||||
|
||||
- reg : Physical base address of the device and length of the register area.
|
||||
|
||||
- interrupts : Contains the three IRQ lines required by Mali Bifrost devices,
|
||||
in the following defined order.
|
||||
|
||||
- interrupt-names : Contains the names of IRQ resources in this exact defined
|
||||
order: "job", "mmu", "gpu".
|
||||
|
||||
Optional properties:
|
||||
|
||||
- clocks : Phandle to clock for the Mali Bifrost device.
|
||||
|
||||
- mali-supply : Phandle to regulator for the Mali device. Refer to
|
||||
Documentation/devicetree/bindings/regulator/regulator.txt for details.
|
||||
|
||||
- operating-points-v2 : Refer to Documentation/devicetree/bindings/opp/opp.txt
|
||||
for details.
|
||||
|
||||
- resets : Phandle of the GPU reset line.
|
||||
|
||||
Vendor-specific bindings
|
||||
------------------------
|
||||
|
||||
The Mali GPU is integrated very differently from one SoC to
|
||||
another. In order to accommodate those differences, you have the option
|
||||
to specify one more vendor-specific compatible, among:
|
||||
|
||||
- "amlogic,meson-g12a-mali"
|
||||
Required properties:
|
||||
- resets : Should contain phandles of :
|
||||
+ GPU reset line
|
||||
+ GPU APB glue reset line
|
||||
|
||||
Example for a Mali-G31:
|
||||
|
||||
gpu@ffa30000 {
|
||||
compatible = "amlogic,meson-g12a-mali", "arm,mali-bifrost";
|
||||
reg = <0xffe40000 0x10000>;
|
||||
interrupts = <GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "job", "mmu", "gpu";
|
||||
clocks = <&clk CLKID_MALI>;
|
||||
mali-supply = <&vdd_gpu>;
|
||||
operating-points-v2 = <&gpu_opp_table>;
|
||||
resets = <&reset RESET_DVALIN_CAPB3>, <&reset RESET_DVALIN>;
|
||||
};
|
||||
|
||||
gpu_opp_table: opp_table0 {
|
||||
compatible = "operating-points-v2";
|
||||
|
||||
opp@533000000 {
|
||||
opp-hz = /bits/ 64 <533000000>;
|
||||
opp-microvolt = <1250000>;
|
||||
};
|
||||
opp@450000000 {
|
||||
opp-hz = /bits/ 64 <450000000>;
|
||||
opp-microvolt = <1150000>;
|
||||
};
|
||||
opp@400000000 {
|
||||
opp-hz = /bits/ 64 <400000000>;
|
||||
opp-microvolt = <1125000>;
|
||||
};
|
||||
opp@350000000 {
|
||||
opp-hz = /bits/ 64 <350000000>;
|
||||
opp-microvolt = <1075000>;
|
||||
};
|
||||
opp@266000000 {
|
||||
opp-hz = /bits/ 64 <266000000>;
|
||||
opp-microvolt = <1025000>;
|
||||
};
|
||||
opp@160000000 {
|
||||
opp-hz = /bits/ 64 <160000000>;
|
||||
opp-microvolt = <925000>;
|
||||
};
|
||||
opp@100000000 {
|
||||
opp-hz = /bits/ 64 <100000000>;
|
||||
opp-microvolt = <912500>;
|
||||
};
|
||||
};
|
|
@ -42,12 +42,6 @@ Video Encoder
|
|||
.. kernel-doc:: drivers/gpu/drm/meson/meson_venc.c
|
||||
:doc: Video Encoder
|
||||
|
||||
Video Canvas Management
|
||||
=======================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/meson/meson_canvas.c
|
||||
:doc: Canvas
|
||||
|
||||
Video Clocks
|
||||
============
|
||||
|
||||
|
|
|
@ -5209,7 +5209,7 @@ F: Documentation/devicetree/bindings/display/hisilicon/
|
|||
DRM DRIVERS FOR LIMA
|
||||
M: Qiang Yu <yuq825@gmail.com>
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
L: lima@lists.freedesktop.org
|
||||
L: lima@lists.freedesktop.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: drivers/gpu/drm/lima/
|
||||
F: include/uapi/drm/lima_drm.h
|
||||
|
|
|
@ -38,7 +38,8 @@ drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper
|
|||
drm_kms_helper_common.o drm_dp_dual_mode_helper.o \
|
||||
drm_simple_kms_helper.o drm_modeset_helper.o \
|
||||
drm_scdc_helper.o drm_gem_framebuffer_helper.o \
|
||||
drm_atomic_state_helper.o drm_damage_helper.o
|
||||
drm_atomic_state_helper.o drm_damage_helper.o \
|
||||
drm_format_helper.o
|
||||
|
||||
drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o
|
||||
drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
|
||||
|
|
|
@ -2,7 +2,7 @@ config DRM_CIRRUS_QEMU
|
|||
tristate "Cirrus driver for QEMU emulated device"
|
||||
depends on DRM && PCI && MMU
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_TTM
|
||||
select DRM_GEM_SHMEM_HELPER
|
||||
help
|
||||
This is a KMS driver for emulated cirrus device in qemu.
|
||||
It is *NOT* intended for real cirrus devices. This requires
|
||||
|
|
|
@ -1,4 +1 @@
|
|||
cirrus-y := cirrus_main.o cirrus_mode.o \
|
||||
cirrus_drv.o cirrus_fbdev.o cirrus_ttm.o
|
||||
|
||||
obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus.o
|
||||
|
|
657
drivers/gpu/drm/cirrus/cirrus.c
Normal file
657
drivers/gpu/drm/cirrus/cirrus.c
Normal file
|
@ -0,0 +1,657 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright 2012-2019 Red Hat
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General
|
||||
* Public License version 2. See the file COPYING in the main
|
||||
* directory of this archive for more details.
|
||||
*
|
||||
* Authors: Matthew Garrett
|
||||
* Dave Airlie
|
||||
* Gerd Hoffmann
|
||||
*
|
||||
* Portions of this code derived from cirrusfb.c:
|
||||
* drivers/video/cirrusfb.c - driver for Cirrus Logic chipsets
|
||||
*
|
||||
* Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com>
|
||||
*/
|
||||
|
||||
#include <linux/console.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include <video/cirrus.h>
|
||||
#include <video/vga.h>
|
||||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_atomic_state_helper.h>
|
||||
#include <drm/drm_connector.h>
|
||||
#include <drm/drm_damage_helper.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_file.h>
|
||||
#include <drm/drm_format_helper.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_gem_shmem_helper.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_ioctl.h>
|
||||
#include <drm/drm_modeset_helper_vtables.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <drm/drm_simple_kms_helper.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
|
||||
#define DRIVER_NAME "cirrus"
|
||||
#define DRIVER_DESC "qemu cirrus vga"
|
||||
#define DRIVER_DATE "2019"
|
||||
#define DRIVER_MAJOR 2
|
||||
#define DRIVER_MINOR 0
|
||||
|
||||
#define CIRRUS_MAX_PITCH (0x1FF << 3) /* (4096 - 1) & ~111b bytes */
|
||||
#define CIRRUS_VRAM_SIZE (4 * 1024 * 1024) /* 4 MB */
|
||||
|
||||
struct cirrus_device {
|
||||
struct drm_device dev;
|
||||
struct drm_simple_display_pipe pipe;
|
||||
struct drm_connector conn;
|
||||
unsigned int cpp;
|
||||
unsigned int pitch;
|
||||
void __iomem *vram;
|
||||
void __iomem *mmio;
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/*
|
||||
* The meat of this driver. The core passes us a mode and we have to program
|
||||
* it. The modesetting here is the bare minimum required to satisfy the qemu
|
||||
* emulation of this hardware, and running this against a real device is
|
||||
* likely to result in an inadequately programmed mode. We've already had
|
||||
* the opportunity to modify the mode, so whatever we receive here should
|
||||
* be something that can be correctly programmed and displayed
|
||||
*/
|
||||
|
||||
#define SEQ_INDEX 4
|
||||
#define SEQ_DATA 5
|
||||
|
||||
static u8 rreg_seq(struct cirrus_device *cirrus, u8 reg)
|
||||
{
|
||||
iowrite8(reg, cirrus->mmio + SEQ_INDEX);
|
||||
return ioread8(cirrus->mmio + SEQ_DATA);
|
||||
}
|
||||
|
||||
static void wreg_seq(struct cirrus_device *cirrus, u8 reg, u8 val)
|
||||
{
|
||||
iowrite8(reg, cirrus->mmio + SEQ_INDEX);
|
||||
iowrite8(val, cirrus->mmio + SEQ_DATA);
|
||||
}
|
||||
|
||||
#define CRT_INDEX 0x14
|
||||
#define CRT_DATA 0x15
|
||||
|
||||
static u8 rreg_crt(struct cirrus_device *cirrus, u8 reg)
|
||||
{
|
||||
iowrite8(reg, cirrus->mmio + CRT_INDEX);
|
||||
return ioread8(cirrus->mmio + CRT_DATA);
|
||||
}
|
||||
|
||||
static void wreg_crt(struct cirrus_device *cirrus, u8 reg, u8 val)
|
||||
{
|
||||
iowrite8(reg, cirrus->mmio + CRT_INDEX);
|
||||
iowrite8(val, cirrus->mmio + CRT_DATA);
|
||||
}
|
||||
|
||||
#define GFX_INDEX 0xe
|
||||
#define GFX_DATA 0xf
|
||||
|
||||
static void wreg_gfx(struct cirrus_device *cirrus, u8 reg, u8 val)
|
||||
{
|
||||
iowrite8(reg, cirrus->mmio + GFX_INDEX);
|
||||
iowrite8(val, cirrus->mmio + GFX_DATA);
|
||||
}
|
||||
|
||||
#define VGA_DAC_MASK 0x06
|
||||
|
||||
static void wreg_hdr(struct cirrus_device *cirrus, u8 val)
|
||||
{
|
||||
ioread8(cirrus->mmio + VGA_DAC_MASK);
|
||||
ioread8(cirrus->mmio + VGA_DAC_MASK);
|
||||
ioread8(cirrus->mmio + VGA_DAC_MASK);
|
||||
ioread8(cirrus->mmio + VGA_DAC_MASK);
|
||||
iowrite8(val, cirrus->mmio + VGA_DAC_MASK);
|
||||
}
|
||||
|
||||
static int cirrus_convert_to(struct drm_framebuffer *fb)
|
||||
{
|
||||
if (fb->format->cpp[0] == 4 && fb->pitches[0] > CIRRUS_MAX_PITCH) {
|
||||
if (fb->width * 3 <= CIRRUS_MAX_PITCH)
|
||||
/* convert from XR24 to RG24 */
|
||||
return 3;
|
||||
else
|
||||
/* convert from XR24 to RG16 */
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cirrus_cpp(struct drm_framebuffer *fb)
|
||||
{
|
||||
int convert_cpp = cirrus_convert_to(fb);
|
||||
|
||||
if (convert_cpp)
|
||||
return convert_cpp;
|
||||
return fb->format->cpp[0];
|
||||
}
|
||||
|
||||
static int cirrus_pitch(struct drm_framebuffer *fb)
|
||||
{
|
||||
int convert_cpp = cirrus_convert_to(fb);
|
||||
|
||||
if (convert_cpp)
|
||||
return convert_cpp * fb->width;
|
||||
return fb->pitches[0];
|
||||
}
|
||||
|
||||
static void cirrus_set_start_address(struct cirrus_device *cirrus, u32 offset)
|
||||
{
|
||||
u32 addr;
|
||||
u8 tmp;
|
||||
|
||||
addr = offset >> 2;
|
||||
wreg_crt(cirrus, 0x0c, (u8)((addr >> 8) & 0xff));
|
||||
wreg_crt(cirrus, 0x0d, (u8)(addr & 0xff));
|
||||
|
||||
tmp = rreg_crt(cirrus, 0x1b);
|
||||
tmp &= 0xf2;
|
||||
tmp |= (addr >> 16) & 0x01;
|
||||
tmp |= (addr >> 15) & 0x0c;
|
||||
wreg_crt(cirrus, 0x1b, tmp);
|
||||
|
||||
tmp = rreg_crt(cirrus, 0x1d);
|
||||
tmp &= 0x7f;
|
||||
tmp |= (addr >> 12) & 0x80;
|
||||
wreg_crt(cirrus, 0x1d, tmp);
|
||||
}
|
||||
|
||||
static int cirrus_mode_set(struct cirrus_device *cirrus,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_framebuffer *fb)
|
||||
{
|
||||
int hsyncstart, hsyncend, htotal, hdispend;
|
||||
int vtotal, vdispend;
|
||||
int tmp;
|
||||
int sr07 = 0, hdr = 0;
|
||||
|
||||
htotal = mode->htotal / 8;
|
||||
hsyncend = mode->hsync_end / 8;
|
||||
hsyncstart = mode->hsync_start / 8;
|
||||
hdispend = mode->hdisplay / 8;
|
||||
|
||||
vtotal = mode->vtotal;
|
||||
vdispend = mode->vdisplay;
|
||||
|
||||
vdispend -= 1;
|
||||
vtotal -= 2;
|
||||
|
||||
htotal -= 5;
|
||||
hdispend -= 1;
|
||||
hsyncstart += 1;
|
||||
hsyncend += 1;
|
||||
|
||||
wreg_crt(cirrus, VGA_CRTC_V_SYNC_END, 0x20);
|
||||
wreg_crt(cirrus, VGA_CRTC_H_TOTAL, htotal);
|
||||
wreg_crt(cirrus, VGA_CRTC_H_DISP, hdispend);
|
||||
wreg_crt(cirrus, VGA_CRTC_H_SYNC_START, hsyncstart);
|
||||
wreg_crt(cirrus, VGA_CRTC_H_SYNC_END, hsyncend);
|
||||
wreg_crt(cirrus, VGA_CRTC_V_TOTAL, vtotal & 0xff);
|
||||
wreg_crt(cirrus, VGA_CRTC_V_DISP_END, vdispend & 0xff);
|
||||
|
||||
tmp = 0x40;
|
||||
if ((vdispend + 1) & 512)
|
||||
tmp |= 0x20;
|
||||
wreg_crt(cirrus, VGA_CRTC_MAX_SCAN, tmp);
|
||||
|
||||
/*
|
||||
* Overflow bits for values that don't fit in the standard registers
|
||||
*/
|
||||
tmp = 0x10;
|
||||
if (vtotal & 0x100)
|
||||
tmp |= 0x01;
|
||||
if (vdispend & 0x100)
|
||||
tmp |= 0x02;
|
||||
if ((vdispend + 1) & 0x100)
|
||||
tmp |= 0x08;
|
||||
if (vtotal & 0x200)
|
||||
tmp |= 0x20;
|
||||
if (vdispend & 0x200)
|
||||
tmp |= 0x40;
|
||||
wreg_crt(cirrus, VGA_CRTC_OVERFLOW, tmp);
|
||||
|
||||
tmp = 0;
|
||||
|
||||
/* More overflow bits */
|
||||
|
||||
if ((htotal + 5) & 0x40)
|
||||
tmp |= 0x10;
|
||||
if ((htotal + 5) & 0x80)
|
||||
tmp |= 0x20;
|
||||
if (vtotal & 0x100)
|
||||
tmp |= 0x40;
|
||||
if (vtotal & 0x200)
|
||||
tmp |= 0x80;
|
||||
|
||||
wreg_crt(cirrus, CL_CRT1A, tmp);
|
||||
|
||||
/* Disable Hercules/CGA compatibility */
|
||||
wreg_crt(cirrus, VGA_CRTC_MODE, 0x03);
|
||||
|
||||
sr07 = rreg_seq(cirrus, 0x07);
|
||||
sr07 &= 0xe0;
|
||||
hdr = 0;
|
||||
|
||||
cirrus->cpp = cirrus_cpp(fb);
|
||||
switch (cirrus->cpp * 8) {
|
||||
case 8:
|
||||
sr07 |= 0x11;
|
||||
break;
|
||||
case 16:
|
||||
sr07 |= 0x17;
|
||||
hdr = 0xc1;
|
||||
break;
|
||||
case 24:
|
||||
sr07 |= 0x15;
|
||||
hdr = 0xc5;
|
||||
break;
|
||||
case 32:
|
||||
sr07 |= 0x19;
|
||||
hdr = 0xc5;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
wreg_seq(cirrus, 0x7, sr07);
|
||||
|
||||
/* Program the pitch */
|
||||
cirrus->pitch = cirrus_pitch(fb);
|
||||
tmp = cirrus->pitch / 8;
|
||||
wreg_crt(cirrus, VGA_CRTC_OFFSET, tmp);
|
||||
|
||||
/* Enable extended blanking and pitch bits, and enable full memory */
|
||||
tmp = 0x22;
|
||||
tmp |= (cirrus->pitch >> 7) & 0x10;
|
||||
tmp |= (cirrus->pitch >> 6) & 0x40;
|
||||
wreg_crt(cirrus, 0x1b, tmp);
|
||||
|
||||
/* Enable high-colour modes */
|
||||
wreg_gfx(cirrus, VGA_GFX_MODE, 0x40);
|
||||
|
||||
/* And set graphics mode */
|
||||
wreg_gfx(cirrus, VGA_GFX_MISC, 0x01);
|
||||
|
||||
wreg_hdr(cirrus, hdr);
|
||||
|
||||
cirrus_set_start_address(cirrus, 0);
|
||||
|
||||
/* Unblank (needed on S3 resume, vgabios doesn't do it then) */
|
||||
outb(0x20, 0x3c0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cirrus_fb_blit_rect(struct drm_framebuffer *fb,
|
||||
struct drm_rect *rect)
|
||||
{
|
||||
struct cirrus_device *cirrus = fb->dev->dev_private;
|
||||
void *vmap;
|
||||
|
||||
vmap = drm_gem_shmem_vmap(fb->obj[0]);
|
||||
if (!vmap)
|
||||
return -ENOMEM;
|
||||
|
||||
if (cirrus->cpp == fb->format->cpp[0])
|
||||
drm_fb_memcpy_dstclip(__io_virt(cirrus->vram),
|
||||
vmap, fb, rect);
|
||||
|
||||
else if (fb->format->cpp[0] == 4 && cirrus->cpp == 2)
|
||||
drm_fb_xrgb8888_to_rgb565_dstclip(__io_virt(cirrus->vram),
|
||||
cirrus->pitch,
|
||||
vmap, fb, rect, false);
|
||||
|
||||
else if (fb->format->cpp[0] == 4 && cirrus->cpp == 3)
|
||||
drm_fb_xrgb8888_to_rgb888_dstclip(__io_virt(cirrus->vram),
|
||||
cirrus->pitch,
|
||||
vmap, fb, rect);
|
||||
|
||||
else
|
||||
WARN_ON_ONCE("cpp mismatch");
|
||||
|
||||
drm_gem_shmem_vunmap(fb->obj[0], vmap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cirrus_fb_blit_fullscreen(struct drm_framebuffer *fb)
|
||||
{
|
||||
struct drm_rect fullscreen = {
|
||||
.x1 = 0,
|
||||
.x2 = fb->width,
|
||||
.y1 = 0,
|
||||
.y2 = fb->height,
|
||||
};
|
||||
return cirrus_fb_blit_rect(fb, &fullscreen);
|
||||
}
|
||||
|
||||
static int cirrus_check_size(int width, int height,
|
||||
struct drm_framebuffer *fb)
|
||||
{
|
||||
int pitch = width * 2;
|
||||
|
||||
if (fb)
|
||||
pitch = cirrus_pitch(fb);
|
||||
|
||||
if (pitch > CIRRUS_MAX_PITCH)
|
||||
return -EINVAL;
|
||||
if (pitch * height > CIRRUS_VRAM_SIZE)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* cirrus connector */
|
||||
|
||||
static int cirrus_conn_get_modes(struct drm_connector *conn)
|
||||
{
|
||||
int count;
|
||||
|
||||
count = drm_add_modes_noedid(conn,
|
||||
conn->dev->mode_config.max_width,
|
||||
conn->dev->mode_config.max_height);
|
||||
drm_set_preferred_mode(conn, 1024, 768);
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct drm_connector_helper_funcs cirrus_conn_helper_funcs = {
|
||||
.get_modes = cirrus_conn_get_modes,
|
||||
};
|
||||
|
||||
static const struct drm_connector_funcs cirrus_conn_funcs = {
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = drm_connector_cleanup,
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
};
|
||||
|
||||
static int cirrus_conn_init(struct cirrus_device *cirrus)
|
||||
{
|
||||
drm_connector_helper_add(&cirrus->conn, &cirrus_conn_helper_funcs);
|
||||
return drm_connector_init(&cirrus->dev, &cirrus->conn,
|
||||
&cirrus_conn_funcs, DRM_MODE_CONNECTOR_VGA);
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* cirrus (simple) display pipe */
|
||||
|
||||
static enum drm_mode_status cirrus_pipe_mode_valid(struct drm_crtc *crtc,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
if (cirrus_check_size(mode->hdisplay, mode->vdisplay, NULL) < 0)
|
||||
return MODE_BAD;
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static int cirrus_pipe_check(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_plane_state *plane_state,
|
||||
struct drm_crtc_state *crtc_state)
|
||||
{
|
||||
struct drm_framebuffer *fb = plane_state->fb;
|
||||
|
||||
if (!fb)
|
||||
return 0;
|
||||
return cirrus_check_size(fb->width, fb->height, fb);
|
||||
}
|
||||
|
||||
static void cirrus_pipe_enable(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_plane_state *plane_state)
|
||||
{
|
||||
struct cirrus_device *cirrus = pipe->crtc.dev->dev_private;
|
||||
|
||||
cirrus_mode_set(cirrus, &crtc_state->mode, plane_state->fb);
|
||||
cirrus_fb_blit_fullscreen(plane_state->fb);
|
||||
}
|
||||
|
||||
static void cirrus_pipe_update(struct drm_simple_display_pipe *pipe,
|
||||
struct drm_plane_state *old_state)
|
||||
{
|
||||
struct cirrus_device *cirrus = pipe->crtc.dev->dev_private;
|
||||
struct drm_plane_state *state = pipe->plane.state;
|
||||
struct drm_crtc *crtc = &pipe->crtc;
|
||||
struct drm_rect rect;
|
||||
|
||||
if (pipe->plane.state->fb &&
|
||||
cirrus->cpp != cirrus_cpp(pipe->plane.state->fb))
|
||||
cirrus_mode_set(cirrus, &crtc->mode,
|
||||
pipe->plane.state->fb);
|
||||
|
||||
if (drm_atomic_helper_damage_merged(old_state, state, &rect))
|
||||
cirrus_fb_blit_rect(pipe->plane.state->fb, &rect);
|
||||
|
||||
if (crtc->state->event) {
|
||||
spin_lock_irq(&crtc->dev->event_lock);
|
||||
drm_crtc_send_vblank_event(crtc, crtc->state->event);
|
||||
crtc->state->event = NULL;
|
||||
spin_unlock_irq(&crtc->dev->event_lock);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct drm_simple_display_pipe_funcs cirrus_pipe_funcs = {
|
||||
.mode_valid = cirrus_pipe_mode_valid,
|
||||
.check = cirrus_pipe_check,
|
||||
.enable = cirrus_pipe_enable,
|
||||
.update = cirrus_pipe_update,
|
||||
};
|
||||
|
||||
static const uint32_t cirrus_formats[] = {
|
||||
DRM_FORMAT_RGB565,
|
||||
DRM_FORMAT_RGB888,
|
||||
DRM_FORMAT_XRGB8888,
|
||||
};
|
||||
|
||||
static const uint64_t cirrus_modifiers[] = {
|
||||
DRM_FORMAT_MOD_LINEAR,
|
||||
DRM_FORMAT_MOD_INVALID
|
||||
};
|
||||
|
||||
static int cirrus_pipe_init(struct cirrus_device *cirrus)
|
||||
{
|
||||
return drm_simple_display_pipe_init(&cirrus->dev,
|
||||
&cirrus->pipe,
|
||||
&cirrus_pipe_funcs,
|
||||
cirrus_formats,
|
||||
ARRAY_SIZE(cirrus_formats),
|
||||
cirrus_modifiers,
|
||||
&cirrus->conn);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* cirrus framebuffers & mode config */
|
||||
|
||||
static struct drm_framebuffer*
|
||||
cirrus_fb_create(struct drm_device *dev, struct drm_file *file_priv,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd)
|
||||
{
|
||||
if (mode_cmd->pixel_format != DRM_FORMAT_RGB565 &&
|
||||
mode_cmd->pixel_format != DRM_FORMAT_RGB888 &&
|
||||
mode_cmd->pixel_format != DRM_FORMAT_XRGB8888)
|
||||
return ERR_PTR(-EINVAL);
|
||||
if (cirrus_check_size(mode_cmd->width, mode_cmd->height, NULL) < 0)
|
||||
return ERR_PTR(-EINVAL);
|
||||
return drm_gem_fb_create_with_dirty(dev, file_priv, mode_cmd);
|
||||
}
|
||||
|
||||
static const struct drm_mode_config_funcs cirrus_mode_config_funcs = {
|
||||
.fb_create = cirrus_fb_create,
|
||||
.atomic_check = drm_atomic_helper_check,
|
||||
.atomic_commit = drm_atomic_helper_commit,
|
||||
};
|
||||
|
||||
static void cirrus_mode_config_init(struct cirrus_device *cirrus)
|
||||
{
|
||||
struct drm_device *dev = &cirrus->dev;
|
||||
|
||||
drm_mode_config_init(dev);
|
||||
dev->mode_config.min_width = 0;
|
||||
dev->mode_config.min_height = 0;
|
||||
dev->mode_config.max_width = CIRRUS_MAX_PITCH / 2;
|
||||
dev->mode_config.max_height = 1024;
|
||||
dev->mode_config.preferred_depth = 16;
|
||||
dev->mode_config.prefer_shadow = 0;
|
||||
dev->mode_config.funcs = &cirrus_mode_config_funcs;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
DEFINE_DRM_GEM_SHMEM_FOPS(cirrus_fops);
|
||||
|
||||
static struct drm_driver cirrus_driver = {
|
||||
.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC | DRIVER_PRIME,
|
||||
|
||||
.name = DRIVER_NAME,
|
||||
.desc = DRIVER_DESC,
|
||||
.date = DRIVER_DATE,
|
||||
.major = DRIVER_MAJOR,
|
||||
.minor = DRIVER_MINOR,
|
||||
|
||||
.fops = &cirrus_fops,
|
||||
DRM_GEM_SHMEM_DRIVER_OPS,
|
||||
};
|
||||
|
||||
static int cirrus_pci_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *ent)
|
||||
{
|
||||
struct drm_device *dev;
|
||||
struct cirrus_device *cirrus;
|
||||
int ret;
|
||||
|
||||
ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "cirrusdrmfb");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pci_enable_device(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pci_request_regions(pdev, DRIVER_NAME);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = -ENOMEM;
|
||||
cirrus = kzalloc(sizeof(*cirrus), GFP_KERNEL);
|
||||
if (cirrus == NULL)
|
||||
goto err_pci_release;
|
||||
|
||||
dev = &cirrus->dev;
|
||||
ret = drm_dev_init(dev, &cirrus_driver, &pdev->dev);
|
||||
if (ret)
|
||||
goto err_free_cirrus;
|
||||
dev->dev_private = cirrus;
|
||||
|
||||
ret = -ENOMEM;
|
||||
cirrus->vram = ioremap(pci_resource_start(pdev, 0),
|
||||
pci_resource_len(pdev, 0));
|
||||
if (cirrus->vram == NULL)
|
||||
goto err_dev_put;
|
||||
|
||||
cirrus->mmio = ioremap(pci_resource_start(pdev, 1),
|
||||
pci_resource_len(pdev, 1));
|
||||
if (cirrus->mmio == NULL)
|
||||
goto err_unmap_vram;
|
||||
|
||||
cirrus_mode_config_init(cirrus);
|
||||
|
||||
ret = cirrus_conn_init(cirrus);
|
||||
if (ret < 0)
|
||||
goto err_cleanup;
|
||||
|
||||
ret = cirrus_pipe_init(cirrus);
|
||||
if (ret < 0)
|
||||
goto err_cleanup;
|
||||
|
||||
drm_mode_config_reset(dev);
|
||||
|
||||
dev->pdev = pdev;
|
||||
pci_set_drvdata(pdev, dev);
|
||||
ret = drm_dev_register(dev, 0);
|
||||
if (ret)
|
||||
goto err_cleanup;
|
||||
|
||||
drm_fbdev_generic_setup(dev, dev->mode_config.preferred_depth);
|
||||
return 0;
|
||||
|
||||
err_cleanup:
|
||||
drm_mode_config_cleanup(dev);
|
||||
iounmap(cirrus->mmio);
|
||||
err_unmap_vram:
|
||||
iounmap(cirrus->vram);
|
||||
err_dev_put:
|
||||
drm_dev_put(dev);
|
||||
err_free_cirrus:
|
||||
kfree(cirrus);
|
||||
err_pci_release:
|
||||
pci_release_regions(pdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cirrus_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct drm_device *dev = pci_get_drvdata(pdev);
|
||||
struct cirrus_device *cirrus = dev->dev_private;
|
||||
|
||||
drm_dev_unregister(dev);
|
||||
drm_mode_config_cleanup(dev);
|
||||
iounmap(cirrus->mmio);
|
||||
iounmap(cirrus->vram);
|
||||
drm_dev_put(dev);
|
||||
kfree(cirrus);
|
||||
pci_release_regions(pdev);
|
||||
}
|
||||
|
||||
static const struct pci_device_id pciidlist[] = {
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_CIRRUS,
|
||||
.device = PCI_DEVICE_ID_CIRRUS_5446,
|
||||
/* only bind to the cirrus chip in qemu */
|
||||
.subvendor = PCI_SUBVENDOR_ID_REDHAT_QUMRANET,
|
||||
.subdevice = PCI_SUBDEVICE_ID_QEMU,
|
||||
}, {
|
||||
.vendor = PCI_VENDOR_ID_CIRRUS,
|
||||
.device = PCI_DEVICE_ID_CIRRUS_5446,
|
||||
.subvendor = PCI_VENDOR_ID_XEN,
|
||||
.subdevice = 0x0001,
|
||||
},
|
||||
{ /* end if list */ }
|
||||
};
|
||||
|
||||
static struct pci_driver cirrus_pci_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = pciidlist,
|
||||
.probe = cirrus_pci_probe,
|
||||
.remove = cirrus_pci_remove,
|
||||
};
|
||||
|
||||
static int __init cirrus_init(void)
|
||||
{
|
||||
if (vgacon_text_force())
|
||||
return -EINVAL;
|
||||
return pci_register_driver(&cirrus_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit cirrus_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&cirrus_pci_driver);
|
||||
}
|
||||
|
||||
module_init(cirrus_init);
|
||||
module_exit(cirrus_exit);
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, pciidlist);
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1,161 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat <mjg@redhat.com>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General
|
||||
* Public License version 2. See the file COPYING in the main
|
||||
* directory of this archive for more details.
|
||||
*
|
||||
* Authors: Matthew Garrett
|
||||
* Dave Airlie
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/console.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
|
||||
#include "cirrus_drv.h"
|
||||
|
||||
int cirrus_modeset = -1;
|
||||
int cirrus_bpp = 16;
|
||||
|
||||
MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
|
||||
module_param_named(modeset, cirrus_modeset, int, 0400);
|
||||
MODULE_PARM_DESC(bpp, "Max bits-per-pixel (default:16)");
|
||||
module_param_named(bpp, cirrus_bpp, int, 0400);
|
||||
|
||||
/*
|
||||
* This is the generic driver code. This binds the driver to the drm core,
|
||||
* which then performs further device association and calls our graphics init
|
||||
* functions
|
||||
*/
|
||||
|
||||
static struct drm_driver driver;
|
||||
|
||||
/* only bind to the cirrus chip in qemu */
|
||||
static const struct pci_device_id pciidlist[] = {
|
||||
{ PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5446,
|
||||
PCI_SUBVENDOR_ID_REDHAT_QUMRANET, PCI_SUBDEVICE_ID_QEMU,
|
||||
0, 0, 0 },
|
||||
{ PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5446, PCI_VENDOR_ID_XEN,
|
||||
0x0001, 0, 0, 0 },
|
||||
{0,}
|
||||
};
|
||||
|
||||
|
||||
static int cirrus_pci_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *ent)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "cirrusdrmfb");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return drm_get_pci_dev(pdev, ent, &driver);
|
||||
}
|
||||
|
||||
static void cirrus_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct drm_device *dev = pci_get_drvdata(pdev);
|
||||
|
||||
drm_put_dev(dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int cirrus_pm_suspend(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
||||
struct cirrus_device *cdev = drm_dev->dev_private;
|
||||
|
||||
drm_kms_helper_poll_disable(drm_dev);
|
||||
|
||||
if (cdev->mode_info.gfbdev) {
|
||||
console_lock();
|
||||
drm_fb_helper_set_suspend(&cdev->mode_info.gfbdev->helper, 1);
|
||||
console_unlock();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cirrus_pm_resume(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
||||
struct cirrus_device *cdev = drm_dev->dev_private;
|
||||
|
||||
drm_helper_resume_force_mode(drm_dev);
|
||||
|
||||
if (cdev->mode_info.gfbdev) {
|
||||
console_lock();
|
||||
drm_fb_helper_set_suspend(&cdev->mode_info.gfbdev->helper, 0);
|
||||
console_unlock();
|
||||
}
|
||||
|
||||
drm_kms_helper_poll_enable(drm_dev);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct file_operations cirrus_driver_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = drm_open,
|
||||
.release = drm_release,
|
||||
.unlocked_ioctl = drm_ioctl,
|
||||
.mmap = cirrus_mmap,
|
||||
.poll = drm_poll,
|
||||
.compat_ioctl = drm_compat_ioctl,
|
||||
};
|
||||
static struct drm_driver driver = {
|
||||
.driver_features = DRIVER_MODESET | DRIVER_GEM,
|
||||
.load = cirrus_driver_load,
|
||||
.unload = cirrus_driver_unload,
|
||||
.fops = &cirrus_driver_fops,
|
||||
.name = DRIVER_NAME,
|
||||
.desc = DRIVER_DESC,
|
||||
.date = DRIVER_DATE,
|
||||
.major = DRIVER_MAJOR,
|
||||
.minor = DRIVER_MINOR,
|
||||
.patchlevel = DRIVER_PATCHLEVEL,
|
||||
.gem_free_object_unlocked = cirrus_gem_free_object,
|
||||
.dumb_create = cirrus_dumb_create,
|
||||
.dumb_map_offset = cirrus_dumb_mmap_offset,
|
||||
};
|
||||
|
||||
static const struct dev_pm_ops cirrus_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(cirrus_pm_suspend,
|
||||
cirrus_pm_resume)
|
||||
};
|
||||
|
||||
static struct pci_driver cirrus_pci_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = pciidlist,
|
||||
.probe = cirrus_pci_probe,
|
||||
.remove = cirrus_pci_remove,
|
||||
.driver.pm = &cirrus_pm_ops,
|
||||
};
|
||||
|
||||
static int __init cirrus_init(void)
|
||||
{
|
||||
if (vgacon_text_force() && cirrus_modeset == -1)
|
||||
return -EINVAL;
|
||||
|
||||
if (cirrus_modeset == 0)
|
||||
return -EINVAL;
|
||||
return pci_register_driver(&cirrus_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit cirrus_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&cirrus_pci_driver);
|
||||
}
|
||||
|
||||
module_init(cirrus_init);
|
||||
module_exit(cirrus_exit);
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, pciidlist);
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1,309 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General
|
||||
* Public License version 2. See the file COPYING in the main
|
||||
* directory of this archive for more details.
|
||||
*
|
||||
* Authors: Matthew Garrett
|
||||
* Dave Airlie
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_util.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
|
||||
#include "cirrus_drv.h"
|
||||
|
||||
static void cirrus_dirty_update(struct cirrus_fbdev *afbdev,
|
||||
int x, int y, int width, int height)
|
||||
{
|
||||
int i;
|
||||
struct drm_gem_object *obj;
|
||||
struct cirrus_bo *bo;
|
||||
int src_offset, dst_offset;
|
||||
int bpp = afbdev->gfb->format->cpp[0];
|
||||
int ret = -EBUSY;
|
||||
bool unmap = false;
|
||||
bool store_for_later = false;
|
||||
int x2, y2;
|
||||
unsigned long flags;
|
||||
|
||||
obj = afbdev->gfb->obj[0];
|
||||
bo = gem_to_cirrus_bo(obj);
|
||||
|
||||
/*
|
||||
* try and reserve the BO, if we fail with busy
|
||||
* then the BO is being moved and we should
|
||||
* store up the damage until later.
|
||||
*/
|
||||
if (drm_can_sleep())
|
||||
ret = cirrus_bo_reserve(bo, true);
|
||||
if (ret) {
|
||||
if (ret != -EBUSY)
|
||||
return;
|
||||
store_for_later = true;
|
||||
}
|
||||
|
||||
x2 = x + width - 1;
|
||||
y2 = y + height - 1;
|
||||
spin_lock_irqsave(&afbdev->dirty_lock, flags);
|
||||
|
||||
if (afbdev->y1 < y)
|
||||
y = afbdev->y1;
|
||||
if (afbdev->y2 > y2)
|
||||
y2 = afbdev->y2;
|
||||
if (afbdev->x1 < x)
|
||||
x = afbdev->x1;
|
||||
if (afbdev->x2 > x2)
|
||||
x2 = afbdev->x2;
|
||||
|
||||
if (store_for_later) {
|
||||
afbdev->x1 = x;
|
||||
afbdev->x2 = x2;
|
||||
afbdev->y1 = y;
|
||||
afbdev->y2 = y2;
|
||||
spin_unlock_irqrestore(&afbdev->dirty_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
afbdev->x1 = afbdev->y1 = INT_MAX;
|
||||
afbdev->x2 = afbdev->y2 = 0;
|
||||
spin_unlock_irqrestore(&afbdev->dirty_lock, flags);
|
||||
|
||||
if (!bo->kmap.virtual) {
|
||||
ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to kmap fb updates\n");
|
||||
cirrus_bo_unreserve(bo);
|
||||
return;
|
||||
}
|
||||
unmap = true;
|
||||
}
|
||||
for (i = y; i < y + height; i++) {
|
||||
/* assume equal stride for now */
|
||||
src_offset = dst_offset = i * afbdev->gfb->pitches[0] + (x * bpp);
|
||||
memcpy_toio(bo->kmap.virtual + src_offset, afbdev->sysram + src_offset, width * bpp);
|
||||
|
||||
}
|
||||
if (unmap)
|
||||
ttm_bo_kunmap(&bo->kmap);
|
||||
|
||||
cirrus_bo_unreserve(bo);
|
||||
}
|
||||
|
||||
static void cirrus_fillrect(struct fb_info *info,
|
||||
const struct fb_fillrect *rect)
|
||||
{
|
||||
struct cirrus_fbdev *afbdev = info->par;
|
||||
drm_fb_helper_sys_fillrect(info, rect);
|
||||
cirrus_dirty_update(afbdev, rect->dx, rect->dy, rect->width,
|
||||
rect->height);
|
||||
}
|
||||
|
||||
static void cirrus_copyarea(struct fb_info *info,
|
||||
const struct fb_copyarea *area)
|
||||
{
|
||||
struct cirrus_fbdev *afbdev = info->par;
|
||||
drm_fb_helper_sys_copyarea(info, area);
|
||||
cirrus_dirty_update(afbdev, area->dx, area->dy, area->width,
|
||||
area->height);
|
||||
}
|
||||
|
||||
static void cirrus_imageblit(struct fb_info *info,
|
||||
const struct fb_image *image)
|
||||
{
|
||||
struct cirrus_fbdev *afbdev = info->par;
|
||||
drm_fb_helper_sys_imageblit(info, image);
|
||||
cirrus_dirty_update(afbdev, image->dx, image->dy, image->width,
|
||||
image->height);
|
||||
}
|
||||
|
||||
|
||||
static struct fb_ops cirrusfb_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.fb_check_var = drm_fb_helper_check_var,
|
||||
.fb_set_par = drm_fb_helper_set_par,
|
||||
.fb_fillrect = cirrus_fillrect,
|
||||
.fb_copyarea = cirrus_copyarea,
|
||||
.fb_imageblit = cirrus_imageblit,
|
||||
.fb_pan_display = drm_fb_helper_pan_display,
|
||||
.fb_blank = drm_fb_helper_blank,
|
||||
.fb_setcmap = drm_fb_helper_setcmap,
|
||||
};
|
||||
|
||||
static int cirrusfb_create_object(struct cirrus_fbdev *afbdev,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_gem_object **gobj_p)
|
||||
{
|
||||
struct drm_device *dev = afbdev->helper.dev;
|
||||
struct cirrus_device *cdev = dev->dev_private;
|
||||
u32 bpp;
|
||||
u32 size;
|
||||
struct drm_gem_object *gobj;
|
||||
int ret = 0;
|
||||
|
||||
bpp = drm_format_plane_cpp(mode_cmd->pixel_format, 0) * 8;
|
||||
|
||||
if (!cirrus_check_framebuffer(cdev, mode_cmd->width, mode_cmd->height,
|
||||
bpp, mode_cmd->pitches[0]))
|
||||
return -EINVAL;
|
||||
|
||||
size = mode_cmd->pitches[0] * mode_cmd->height;
|
||||
ret = cirrus_gem_create(dev, size, true, &gobj);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*gobj_p = gobj;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cirrusfb_create(struct drm_fb_helper *helper,
|
||||
struct drm_fb_helper_surface_size *sizes)
|
||||
{
|
||||
struct cirrus_fbdev *gfbdev =
|
||||
container_of(helper, struct cirrus_fbdev, helper);
|
||||
struct cirrus_device *cdev = gfbdev->helper.dev->dev_private;
|
||||
struct fb_info *info;
|
||||
struct drm_framebuffer *fb;
|
||||
struct drm_mode_fb_cmd2 mode_cmd;
|
||||
void *sysram;
|
||||
struct drm_gem_object *gobj = NULL;
|
||||
int size, ret;
|
||||
|
||||
mode_cmd.width = sizes->surface_width;
|
||||
mode_cmd.height = sizes->surface_height;
|
||||
mode_cmd.pitches[0] = mode_cmd.width * ((sizes->surface_bpp + 7) / 8);
|
||||
mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
|
||||
sizes->surface_depth);
|
||||
size = mode_cmd.pitches[0] * mode_cmd.height;
|
||||
|
||||
ret = cirrusfb_create_object(gfbdev, &mode_cmd, &gobj);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to create fbcon backing object %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
sysram = vmalloc(size);
|
||||
if (!sysram)
|
||||
return -ENOMEM;
|
||||
|
||||
info = drm_fb_helper_alloc_fbi(helper);
|
||||
if (IS_ERR(info)) {
|
||||
ret = PTR_ERR(info);
|
||||
goto err_vfree;
|
||||
}
|
||||
|
||||
fb = kzalloc(sizeof(*fb), GFP_KERNEL);
|
||||
if (!fb) {
|
||||
ret = -ENOMEM;
|
||||
goto err_drm_gem_object_put_unlocked;
|
||||
}
|
||||
|
||||
ret = cirrus_framebuffer_init(cdev->dev, fb, &mode_cmd, gobj);
|
||||
if (ret)
|
||||
goto err_kfree;
|
||||
|
||||
gfbdev->sysram = sysram;
|
||||
gfbdev->size = size;
|
||||
gfbdev->gfb = fb;
|
||||
|
||||
/* setup helper */
|
||||
gfbdev->helper.fb = fb;
|
||||
|
||||
info->fbops = &cirrusfb_ops;
|
||||
|
||||
drm_fb_helper_fill_info(info, &gfbdev->helper, sizes);
|
||||
|
||||
/* setup aperture base/size for vesafb takeover */
|
||||
info->apertures->ranges[0].base = cdev->dev->mode_config.fb_base;
|
||||
info->apertures->ranges[0].size = cdev->mc.vram_size;
|
||||
|
||||
info->fix.smem_start = cdev->dev->mode_config.fb_base;
|
||||
info->fix.smem_len = cdev->mc.vram_size;
|
||||
|
||||
info->screen_base = sysram;
|
||||
info->screen_size = size;
|
||||
|
||||
info->fix.mmio_start = 0;
|
||||
info->fix.mmio_len = 0;
|
||||
|
||||
DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start);
|
||||
DRM_INFO("vram aper at 0x%lX\n", (unsigned long)info->fix.smem_start);
|
||||
DRM_INFO("size %lu\n", (unsigned long)info->fix.smem_len);
|
||||
DRM_INFO("fb depth is %d\n", fb->format->depth);
|
||||
DRM_INFO(" pitch is %d\n", fb->pitches[0]);
|
||||
|
||||
return 0;
|
||||
|
||||
err_kfree:
|
||||
kfree(fb);
|
||||
err_drm_gem_object_put_unlocked:
|
||||
drm_gem_object_put_unlocked(gobj);
|
||||
err_vfree:
|
||||
vfree(sysram);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cirrus_fbdev_destroy(struct drm_device *dev,
|
||||
struct cirrus_fbdev *gfbdev)
|
||||
{
|
||||
struct drm_framebuffer *gfb = gfbdev->gfb;
|
||||
|
||||
drm_helper_force_disable_all(dev);
|
||||
|
||||
drm_fb_helper_unregister_fbi(&gfbdev->helper);
|
||||
|
||||
vfree(gfbdev->sysram);
|
||||
drm_fb_helper_fini(&gfbdev->helper);
|
||||
if (gfb)
|
||||
drm_framebuffer_put(gfb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_fb_helper_funcs cirrus_fb_helper_funcs = {
|
||||
.fb_probe = cirrusfb_create,
|
||||
};
|
||||
|
||||
int cirrus_fbdev_init(struct cirrus_device *cdev)
|
||||
{
|
||||
struct cirrus_fbdev *gfbdev;
|
||||
int ret;
|
||||
|
||||
/*bpp_sel = 8;*/
|
||||
gfbdev = kzalloc(sizeof(struct cirrus_fbdev), GFP_KERNEL);
|
||||
if (!gfbdev)
|
||||
return -ENOMEM;
|
||||
|
||||
cdev->mode_info.gfbdev = gfbdev;
|
||||
spin_lock_init(&gfbdev->dirty_lock);
|
||||
|
||||
drm_fb_helper_prepare(cdev->dev, &gfbdev->helper,
|
||||
&cirrus_fb_helper_funcs);
|
||||
|
||||
ret = drm_fb_helper_init(cdev->dev, &gfbdev->helper,
|
||||
CIRRUSFB_CONN_LIMIT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = drm_fb_helper_single_add_all_connectors(&gfbdev->helper);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* disable all the possible outputs/crtcs before entering KMS mode */
|
||||
drm_helper_disable_unused_functions(cdev->dev);
|
||||
|
||||
return drm_fb_helper_initial_config(&gfbdev->helper, cirrus_bpp);
|
||||
}
|
||||
|
||||
void cirrus_fbdev_fini(struct cirrus_device *cdev)
|
||||
{
|
||||
if (!cdev->mode_info.gfbdev)
|
||||
return;
|
||||
|
||||
cirrus_fbdev_destroy(cdev->dev, cdev->mode_info.gfbdev);
|
||||
kfree(cdev->mode_info.gfbdev);
|
||||
cdev->mode_info.gfbdev = NULL;
|
||||
}
|
|
@ -1,328 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012 Red Hat
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General
|
||||
* Public License version 2. See the file COPYING in the main
|
||||
* directory of this archive for more details.
|
||||
*
|
||||
* Authors: Matthew Garrett
|
||||
* Dave Airlie
|
||||
*/
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
|
||||
#include "cirrus_drv.h"
|
||||
|
||||
static const struct drm_framebuffer_funcs cirrus_fb_funcs = {
|
||||
.create_handle = drm_gem_fb_create_handle,
|
||||
.destroy = drm_gem_fb_destroy,
|
||||
};
|
||||
|
||||
int cirrus_framebuffer_init(struct drm_device *dev,
|
||||
struct drm_framebuffer *gfb,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_gem_object *obj)
|
||||
{
|
||||
int ret;
|
||||
|
||||
drm_helper_mode_fill_fb_struct(dev, gfb, mode_cmd);
|
||||
gfb->obj[0] = obj;
|
||||
ret = drm_framebuffer_init(dev, gfb, &cirrus_fb_funcs);
|
||||
if (ret) {
|
||||
DRM_ERROR("drm_framebuffer_init failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct drm_framebuffer *
|
||||
cirrus_user_framebuffer_create(struct drm_device *dev,
|
||||
struct drm_file *filp,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd)
|
||||
{
|
||||
struct cirrus_device *cdev = dev->dev_private;
|
||||
struct drm_gem_object *obj;
|
||||
struct drm_framebuffer *fb;
|
||||
u32 bpp;
|
||||
int ret;
|
||||
|
||||
bpp = drm_format_plane_cpp(mode_cmd->pixel_format, 0) * 8;
|
||||
|
||||
if (!cirrus_check_framebuffer(cdev, mode_cmd->width, mode_cmd->height,
|
||||
bpp, mode_cmd->pitches[0]))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]);
|
||||
if (obj == NULL)
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
fb = kzalloc(sizeof(*fb), GFP_KERNEL);
|
||||
if (!fb) {
|
||||
drm_gem_object_put_unlocked(obj);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
ret = cirrus_framebuffer_init(dev, fb, mode_cmd, obj);
|
||||
if (ret) {
|
||||
drm_gem_object_put_unlocked(obj);
|
||||
kfree(fb);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
return fb;
|
||||
}
|
||||
|
||||
static const struct drm_mode_config_funcs cirrus_mode_funcs = {
|
||||
.fb_create = cirrus_user_framebuffer_create,
|
||||
};
|
||||
|
||||
/* Unmap the framebuffer from the core and release the memory */
|
||||
static void cirrus_vram_fini(struct cirrus_device *cdev)
|
||||
{
|
||||
iounmap(cdev->rmmio);
|
||||
cdev->rmmio = NULL;
|
||||
if (cdev->mc.vram_base)
|
||||
release_mem_region(cdev->mc.vram_base, cdev->mc.vram_size);
|
||||
}
|
||||
|
||||
/* Map the framebuffer from the card and configure the core */
|
||||
static int cirrus_vram_init(struct cirrus_device *cdev)
|
||||
{
|
||||
/* BAR 0 is VRAM */
|
||||
cdev->mc.vram_base = pci_resource_start(cdev->dev->pdev, 0);
|
||||
cdev->mc.vram_size = pci_resource_len(cdev->dev->pdev, 0);
|
||||
|
||||
if (!request_mem_region(cdev->mc.vram_base, cdev->mc.vram_size,
|
||||
"cirrusdrmfb_vram")) {
|
||||
DRM_ERROR("can't reserve VRAM\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Our emulated hardware has two sets of memory. One is video RAM and can
|
||||
* simply be used as a linear framebuffer - the other provides mmio access
|
||||
* to the display registers. The latter can also be accessed via IO port
|
||||
* access, but we map the range and use mmio to program them instead
|
||||
*/
|
||||
|
||||
int cirrus_device_init(struct cirrus_device *cdev,
|
||||
struct drm_device *ddev,
|
||||
struct pci_dev *pdev, uint32_t flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
cdev->dev = ddev;
|
||||
cdev->flags = flags;
|
||||
|
||||
/* Hardcode the number of CRTCs to 1 */
|
||||
cdev->num_crtc = 1;
|
||||
|
||||
/* BAR 0 is the framebuffer, BAR 1 contains registers */
|
||||
cdev->rmmio_base = pci_resource_start(cdev->dev->pdev, 1);
|
||||
cdev->rmmio_size = pci_resource_len(cdev->dev->pdev, 1);
|
||||
|
||||
if (!request_mem_region(cdev->rmmio_base, cdev->rmmio_size,
|
||||
"cirrusdrmfb_mmio")) {
|
||||
DRM_ERROR("can't reserve mmio registers\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
cdev->rmmio = ioremap(cdev->rmmio_base, cdev->rmmio_size);
|
||||
|
||||
if (cdev->rmmio == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = cirrus_vram_init(cdev);
|
||||
if (ret) {
|
||||
release_mem_region(cdev->rmmio_base, cdev->rmmio_size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cirrus_device_fini(struct cirrus_device *cdev)
|
||||
{
|
||||
release_mem_region(cdev->rmmio_base, cdev->rmmio_size);
|
||||
cirrus_vram_fini(cdev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Functions here will be called by the core once it's bound the driver to
|
||||
* a PCI device
|
||||
*/
|
||||
|
||||
int cirrus_driver_load(struct drm_device *dev, unsigned long flags)
|
||||
{
|
||||
struct cirrus_device *cdev;
|
||||
int r;
|
||||
|
||||
cdev = kzalloc(sizeof(struct cirrus_device), GFP_KERNEL);
|
||||
if (cdev == NULL)
|
||||
return -ENOMEM;
|
||||
dev->dev_private = (void *)cdev;
|
||||
|
||||
r = cirrus_device_init(cdev, dev, dev->pdev, flags);
|
||||
if (r) {
|
||||
dev_err(&dev->pdev->dev, "Fatal error during GPU init: %d\n", r);
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = cirrus_mm_init(cdev);
|
||||
if (r) {
|
||||
dev_err(&dev->pdev->dev, "fatal err on mm init\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* cirrus_modeset_init() is initializing/registering the emulated fbdev
|
||||
* and DRM internals can access/test some of the fields in
|
||||
* mode_config->funcs as part of the fbdev registration process.
|
||||
* Make sure dev->mode_config.funcs is properly set to avoid
|
||||
* dereferencing a NULL pointer.
|
||||
* FIXME: mode_config.funcs assignment should probably be done in
|
||||
* cirrus_modeset_init() (that's a common pattern seen in other DRM
|
||||
* drivers).
|
||||
*/
|
||||
dev->mode_config.funcs = &cirrus_mode_funcs;
|
||||
r = cirrus_modeset_init(cdev);
|
||||
if (r) {
|
||||
dev_err(&dev->pdev->dev, "Fatal error during modeset init: %d\n", r);
|
||||
goto out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
out:
|
||||
cirrus_driver_unload(dev);
|
||||
return r;
|
||||
}
|
||||
|
||||
void cirrus_driver_unload(struct drm_device *dev)
|
||||
{
|
||||
struct cirrus_device *cdev = dev->dev_private;
|
||||
|
||||
if (cdev == NULL)
|
||||
return;
|
||||
cirrus_modeset_fini(cdev);
|
||||
cirrus_mm_fini(cdev);
|
||||
cirrus_device_fini(cdev);
|
||||
kfree(cdev);
|
||||
dev->dev_private = NULL;
|
||||
}
|
||||
|
||||
int cirrus_gem_create(struct drm_device *dev,
|
||||
u32 size, bool iskernel,
|
||||
struct drm_gem_object **obj)
|
||||
{
|
||||
struct cirrus_bo *cirrusbo;
|
||||
int ret;
|
||||
|
||||
*obj = NULL;
|
||||
|
||||
size = roundup(size, PAGE_SIZE);
|
||||
if (size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = cirrus_bo_create(dev, size, 0, 0, &cirrusbo);
|
||||
if (ret) {
|
||||
if (ret != -ERESTARTSYS)
|
||||
DRM_ERROR("failed to allocate GEM object\n");
|
||||
return ret;
|
||||
}
|
||||
*obj = &cirrusbo->gem;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cirrus_dumb_create(struct drm_file *file,
|
||||
struct drm_device *dev,
|
||||
struct drm_mode_create_dumb *args)
|
||||
{
|
||||
int ret;
|
||||
struct drm_gem_object *gobj;
|
||||
u32 handle;
|
||||
|
||||
args->pitch = args->width * ((args->bpp + 7) / 8);
|
||||
args->size = args->pitch * args->height;
|
||||
|
||||
ret = cirrus_gem_create(dev, args->size, false,
|
||||
&gobj);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = drm_gem_handle_create(file, gobj, &handle);
|
||||
drm_gem_object_put_unlocked(gobj);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
args->handle = handle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cirrus_bo_unref(struct cirrus_bo **bo)
|
||||
{
|
||||
struct ttm_buffer_object *tbo;
|
||||
|
||||
if ((*bo) == NULL)
|
||||
return;
|
||||
|
||||
tbo = &((*bo)->bo);
|
||||
ttm_bo_put(tbo);
|
||||
*bo = NULL;
|
||||
}
|
||||
|
||||
void cirrus_gem_free_object(struct drm_gem_object *obj)
|
||||
{
|
||||
struct cirrus_bo *cirrus_bo = gem_to_cirrus_bo(obj);
|
||||
|
||||
cirrus_bo_unref(&cirrus_bo);
|
||||
}
|
||||
|
||||
|
||||
static inline u64 cirrus_bo_mmap_offset(struct cirrus_bo *bo)
|
||||
{
|
||||
return drm_vma_node_offset_addr(&bo->bo.vma_node);
|
||||
}
|
||||
|
||||
int
|
||||
cirrus_dumb_mmap_offset(struct drm_file *file,
|
||||
struct drm_device *dev,
|
||||
uint32_t handle,
|
||||
uint64_t *offset)
|
||||
{
|
||||
struct drm_gem_object *obj;
|
||||
struct cirrus_bo *bo;
|
||||
|
||||
obj = drm_gem_object_lookup(file, handle);
|
||||
if (obj == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
bo = gem_to_cirrus_bo(obj);
|
||||
*offset = cirrus_bo_mmap_offset(bo);
|
||||
|
||||
drm_gem_object_put_unlocked(obj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool cirrus_check_framebuffer(struct cirrus_device *cdev, int width, int height,
|
||||
int bpp, int pitch)
|
||||
{
|
||||
const int max_pitch = 0x1FF << 3; /* (4096 - 1) & ~111b bytes */
|
||||
const int max_size = cdev->mc.vram_size;
|
||||
|
||||
if (bpp > cirrus_bpp)
|
||||
return false;
|
||||
if (bpp > 32)
|
||||
return false;
|
||||
|
||||
if (pitch > max_pitch)
|
||||
return false;
|
||||
|
||||
if (pitch * height > max_size)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
|
@ -1,617 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2012 Red Hat
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General
|
||||
* Public License version 2. See the file COPYING in the main
|
||||
* directory of this archive for more details.
|
||||
*
|
||||
* Authors: Matthew Garrett
|
||||
* Dave Airlie
|
||||
*
|
||||
* Portions of this code derived from cirrusfb.c:
|
||||
* drivers/video/cirrusfb.c - driver for Cirrus Logic chipsets
|
||||
*
|
||||
* Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com>
|
||||
*/
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_plane_helper.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
|
||||
#include <video/cirrus.h>
|
||||
|
||||
#include "cirrus_drv.h"
|
||||
|
||||
#define CIRRUS_LUT_SIZE 256
|
||||
|
||||
#define PALETTE_INDEX 0x8
|
||||
#define PALETTE_DATA 0x9
|
||||
|
||||
/*
|
||||
* This file contains setup code for the CRTC.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The DRM core requires DPMS functions, but they make little sense in our
|
||||
* case and so are just stubs
|
||||
*/
|
||||
|
||||
static void cirrus_crtc_dpms(struct drm_crtc *crtc, int mode)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct cirrus_device *cdev = dev->dev_private;
|
||||
u8 sr01, gr0e;
|
||||
|
||||
switch (mode) {
|
||||
case DRM_MODE_DPMS_ON:
|
||||
sr01 = 0x00;
|
||||
gr0e = 0x00;
|
||||
break;
|
||||
case DRM_MODE_DPMS_STANDBY:
|
||||
sr01 = 0x20;
|
||||
gr0e = 0x02;
|
||||
break;
|
||||
case DRM_MODE_DPMS_SUSPEND:
|
||||
sr01 = 0x20;
|
||||
gr0e = 0x04;
|
||||
break;
|
||||
case DRM_MODE_DPMS_OFF:
|
||||
sr01 = 0x20;
|
||||
gr0e = 0x06;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
WREG8(SEQ_INDEX, 0x1);
|
||||
sr01 |= RREG8(SEQ_DATA) & ~0x20;
|
||||
WREG_SEQ(0x1, sr01);
|
||||
|
||||
WREG8(GFX_INDEX, 0xe);
|
||||
gr0e |= RREG8(GFX_DATA) & ~0x06;
|
||||
WREG_GFX(0xe, gr0e);
|
||||
}
|
||||
|
||||
static void cirrus_set_start_address(struct drm_crtc *crtc, unsigned offset)
|
||||
{
|
||||
struct cirrus_device *cdev = crtc->dev->dev_private;
|
||||
u32 addr;
|
||||
u8 tmp;
|
||||
|
||||
addr = offset >> 2;
|
||||
WREG_CRT(0x0c, (u8)((addr >> 8) & 0xff));
|
||||
WREG_CRT(0x0d, (u8)(addr & 0xff));
|
||||
|
||||
WREG8(CRT_INDEX, 0x1b);
|
||||
tmp = RREG8(CRT_DATA);
|
||||
tmp &= 0xf2;
|
||||
tmp |= (addr >> 16) & 0x01;
|
||||
tmp |= (addr >> 15) & 0x0c;
|
||||
WREG_CRT(0x1b, tmp);
|
||||
WREG8(CRT_INDEX, 0x1d);
|
||||
tmp = RREG8(CRT_DATA);
|
||||
tmp &= 0x7f;
|
||||
tmp |= (addr >> 12) & 0x80;
|
||||
WREG_CRT(0x1d, tmp);
|
||||
}
|
||||
|
||||
/* cirrus is different - we will force move buffers out of VRAM */
|
||||
static int cirrus_crtc_do_set_base(struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb,
|
||||
int x, int y, int atomic)
|
||||
{
|
||||
struct cirrus_device *cdev = crtc->dev->dev_private;
|
||||
struct cirrus_bo *bo;
|
||||
int ret;
|
||||
u64 gpu_addr;
|
||||
|
||||
/* push the previous fb to system ram */
|
||||
if (!atomic && fb) {
|
||||
bo = gem_to_cirrus_bo(fb->obj[0]);
|
||||
ret = cirrus_bo_reserve(bo, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
cirrus_bo_push_sysram(bo);
|
||||
cirrus_bo_unreserve(bo);
|
||||
}
|
||||
|
||||
bo = gem_to_cirrus_bo(crtc->primary->fb->obj[0]);
|
||||
|
||||
ret = cirrus_bo_reserve(bo, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = cirrus_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
|
||||
if (ret) {
|
||||
cirrus_bo_unreserve(bo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (cdev->mode_info.gfbdev->gfb == crtc->primary->fb) {
|
||||
/* if pushing console in kmap it */
|
||||
ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
|
||||
if (ret)
|
||||
DRM_ERROR("failed to kmap fbcon\n");
|
||||
}
|
||||
cirrus_bo_unreserve(bo);
|
||||
|
||||
cirrus_set_start_address(crtc, (u32)gpu_addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cirrus_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
|
||||
struct drm_framebuffer *old_fb)
|
||||
{
|
||||
return cirrus_crtc_do_set_base(crtc, old_fb, x, y, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* The meat of this driver. The core passes us a mode and we have to program
|
||||
* it. The modesetting here is the bare minimum required to satisfy the qemu
|
||||
* emulation of this hardware, and running this against a real device is
|
||||
* likely to result in an inadequately programmed mode. We've already had
|
||||
* the opportunity to modify the mode, so whatever we receive here should
|
||||
* be something that can be correctly programmed and displayed
|
||||
*/
|
||||
static int cirrus_crtc_mode_set(struct drm_crtc *crtc,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode,
|
||||
int x, int y, struct drm_framebuffer *old_fb)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct cirrus_device *cdev = dev->dev_private;
|
||||
const struct drm_framebuffer *fb = crtc->primary->fb;
|
||||
int hsyncstart, hsyncend, htotal, hdispend;
|
||||
int vtotal, vdispend;
|
||||
int tmp;
|
||||
int sr07 = 0, hdr = 0;
|
||||
|
||||
htotal = mode->htotal / 8;
|
||||
hsyncend = mode->hsync_end / 8;
|
||||
hsyncstart = mode->hsync_start / 8;
|
||||
hdispend = mode->hdisplay / 8;
|
||||
|
||||
vtotal = mode->vtotal;
|
||||
vdispend = mode->vdisplay;
|
||||
|
||||
vdispend -= 1;
|
||||
vtotal -= 2;
|
||||
|
||||
htotal -= 5;
|
||||
hdispend -= 1;
|
||||
hsyncstart += 1;
|
||||
hsyncend += 1;
|
||||
|
||||
WREG_CRT(VGA_CRTC_V_SYNC_END, 0x20);
|
||||
WREG_CRT(VGA_CRTC_H_TOTAL, htotal);
|
||||
WREG_CRT(VGA_CRTC_H_DISP, hdispend);
|
||||
WREG_CRT(VGA_CRTC_H_SYNC_START, hsyncstart);
|
||||
WREG_CRT(VGA_CRTC_H_SYNC_END, hsyncend);
|
||||
WREG_CRT(VGA_CRTC_V_TOTAL, vtotal & 0xff);
|
||||
WREG_CRT(VGA_CRTC_V_DISP_END, vdispend & 0xff);
|
||||
|
||||
tmp = 0x40;
|
||||
if ((vdispend + 1) & 512)
|
||||
tmp |= 0x20;
|
||||
WREG_CRT(VGA_CRTC_MAX_SCAN, tmp);
|
||||
|
||||
/*
|
||||
* Overflow bits for values that don't fit in the standard registers
|
||||
*/
|
||||
tmp = 16;
|
||||
if (vtotal & 256)
|
||||
tmp |= 1;
|
||||
if (vdispend & 256)
|
||||
tmp |= 2;
|
||||
if ((vdispend + 1) & 256)
|
||||
tmp |= 8;
|
||||
if (vtotal & 512)
|
||||
tmp |= 32;
|
||||
if (vdispend & 512)
|
||||
tmp |= 64;
|
||||
WREG_CRT(VGA_CRTC_OVERFLOW, tmp);
|
||||
|
||||
tmp = 0;
|
||||
|
||||
/* More overflow bits */
|
||||
|
||||
if ((htotal + 5) & 64)
|
||||
tmp |= 16;
|
||||
if ((htotal + 5) & 128)
|
||||
tmp |= 32;
|
||||
if (vtotal & 256)
|
||||
tmp |= 64;
|
||||
if (vtotal & 512)
|
||||
tmp |= 128;
|
||||
|
||||
WREG_CRT(CL_CRT1A, tmp);
|
||||
|
||||
/* Disable Hercules/CGA compatibility */
|
||||
WREG_CRT(VGA_CRTC_MODE, 0x03);
|
||||
|
||||
WREG8(SEQ_INDEX, 0x7);
|
||||
sr07 = RREG8(SEQ_DATA);
|
||||
sr07 &= 0xe0;
|
||||
hdr = 0;
|
||||
switch (fb->format->cpp[0] * 8) {
|
||||
case 8:
|
||||
sr07 |= 0x11;
|
||||
break;
|
||||
case 16:
|
||||
sr07 |= 0x17;
|
||||
hdr = 0xc1;
|
||||
break;
|
||||
case 24:
|
||||
sr07 |= 0x15;
|
||||
hdr = 0xc5;
|
||||
break;
|
||||
case 32:
|
||||
sr07 |= 0x19;
|
||||
hdr = 0xc5;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
WREG_SEQ(0x7, sr07);
|
||||
|
||||
/* Program the pitch */
|
||||
tmp = fb->pitches[0] / 8;
|
||||
WREG_CRT(VGA_CRTC_OFFSET, tmp);
|
||||
|
||||
/* Enable extended blanking and pitch bits, and enable full memory */
|
||||
tmp = 0x22;
|
||||
tmp |= (fb->pitches[0] >> 7) & 0x10;
|
||||
tmp |= (fb->pitches[0] >> 6) & 0x40;
|
||||
WREG_CRT(0x1b, tmp);
|
||||
|
||||
/* Enable high-colour modes */
|
||||
WREG_GFX(VGA_GFX_MODE, 0x40);
|
||||
|
||||
/* And set graphics mode */
|
||||
WREG_GFX(VGA_GFX_MISC, 0x01);
|
||||
|
||||
WREG_HDR(hdr);
|
||||
cirrus_crtc_do_set_base(crtc, old_fb, x, y, 0);
|
||||
|
||||
/* Unblank (needed on S3 resume, vgabios doesn't do it then) */
|
||||
outb(0x20, 0x3c0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called before a mode is programmed. A typical use might be to
|
||||
* enable DPMS during the programming to avoid seeing intermediate stages,
|
||||
* but that's not relevant to us
|
||||
*/
|
||||
static void cirrus_crtc_prepare(struct drm_crtc *crtc)
|
||||
{
|
||||
}
|
||||
|
||||
static void cirrus_crtc_load_lut(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct cirrus_device *cdev = dev->dev_private;
|
||||
u16 *r, *g, *b;
|
||||
int i;
|
||||
|
||||
if (!crtc->enabled)
|
||||
return;
|
||||
|
||||
r = crtc->gamma_store;
|
||||
g = r + crtc->gamma_size;
|
||||
b = g + crtc->gamma_size;
|
||||
|
||||
for (i = 0; i < CIRRUS_LUT_SIZE; i++) {
|
||||
/* VGA registers */
|
||||
WREG8(PALETTE_INDEX, i);
|
||||
WREG8(PALETTE_DATA, *r++ >> 8);
|
||||
WREG8(PALETTE_DATA, *g++ >> 8);
|
||||
WREG8(PALETTE_DATA, *b++ >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called after a mode is programmed. It should reverse anything done
|
||||
* by the prepare function
|
||||
*/
|
||||
static void cirrus_crtc_commit(struct drm_crtc *crtc)
|
||||
{
|
||||
cirrus_crtc_load_lut(crtc);
|
||||
}
|
||||
|
||||
/*
|
||||
* The core can pass us a set of gamma values to program. We actually only
|
||||
* use this for 8-bit mode so can't perform smooth fades on deeper modes,
|
||||
* but it's a requirement that we provide the function
|
||||
*/
|
||||
static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
|
||||
u16 *blue, uint32_t size,
|
||||
struct drm_modeset_acquire_ctx *ctx)
|
||||
{
|
||||
cirrus_crtc_load_lut(crtc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Simple cleanup function */
|
||||
static void cirrus_crtc_destroy(struct drm_crtc *crtc)
|
||||
{
|
||||
struct cirrus_crtc *cirrus_crtc = to_cirrus_crtc(crtc);
|
||||
|
||||
drm_crtc_cleanup(crtc);
|
||||
kfree(cirrus_crtc);
|
||||
}
|
||||
|
||||
/* These provide the minimum set of functions required to handle a CRTC */
|
||||
static const struct drm_crtc_funcs cirrus_crtc_funcs = {
|
||||
.gamma_set = cirrus_crtc_gamma_set,
|
||||
.set_config = drm_crtc_helper_set_config,
|
||||
.destroy = cirrus_crtc_destroy,
|
||||
};
|
||||
|
||||
static const struct drm_crtc_helper_funcs cirrus_helper_funcs = {
|
||||
.dpms = cirrus_crtc_dpms,
|
||||
.mode_set = cirrus_crtc_mode_set,
|
||||
.mode_set_base = cirrus_crtc_mode_set_base,
|
||||
.prepare = cirrus_crtc_prepare,
|
||||
.commit = cirrus_crtc_commit,
|
||||
};
|
||||
|
||||
/* CRTC setup */
|
||||
static const uint32_t cirrus_formats_16[] = {
|
||||
DRM_FORMAT_RGB565,
|
||||
};
|
||||
|
||||
static const uint32_t cirrus_formats_24[] = {
|
||||
DRM_FORMAT_RGB888,
|
||||
DRM_FORMAT_RGB565,
|
||||
};
|
||||
|
||||
static const uint32_t cirrus_formats_32[] = {
|
||||
DRM_FORMAT_XRGB8888,
|
||||
DRM_FORMAT_ARGB8888,
|
||||
DRM_FORMAT_RGB888,
|
||||
DRM_FORMAT_RGB565,
|
||||
};
|
||||
|
||||
static struct drm_plane *cirrus_primary_plane(struct drm_device *dev)
|
||||
{
|
||||
const uint32_t *formats;
|
||||
uint32_t nformats;
|
||||
struct drm_plane *primary;
|
||||
int ret;
|
||||
|
||||
switch (cirrus_bpp) {
|
||||
case 16:
|
||||
formats = cirrus_formats_16;
|
||||
nformats = ARRAY_SIZE(cirrus_formats_16);
|
||||
break;
|
||||
case 24:
|
||||
formats = cirrus_formats_24;
|
||||
nformats = ARRAY_SIZE(cirrus_formats_24);
|
||||
break;
|
||||
case 32:
|
||||
formats = cirrus_formats_32;
|
||||
nformats = ARRAY_SIZE(cirrus_formats_32);
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
primary = kzalloc(sizeof(*primary), GFP_KERNEL);
|
||||
if (primary == NULL) {
|
||||
DRM_DEBUG_KMS("Failed to allocate primary plane\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = drm_universal_plane_init(dev, primary, 0,
|
||||
&drm_primary_helper_funcs,
|
||||
formats, nformats,
|
||||
NULL,
|
||||
DRM_PLANE_TYPE_PRIMARY, NULL);
|
||||
if (ret) {
|
||||
kfree(primary);
|
||||
primary = NULL;
|
||||
}
|
||||
|
||||
return primary;
|
||||
}
|
||||
|
||||
static void cirrus_crtc_init(struct drm_device *dev)
|
||||
{
|
||||
struct cirrus_device *cdev = dev->dev_private;
|
||||
struct cirrus_crtc *cirrus_crtc;
|
||||
struct drm_plane *primary;
|
||||
|
||||
cirrus_crtc = kzalloc(sizeof(struct cirrus_crtc) +
|
||||
(CIRRUSFB_CONN_LIMIT * sizeof(struct drm_connector *)),
|
||||
GFP_KERNEL);
|
||||
|
||||
if (cirrus_crtc == NULL)
|
||||
return;
|
||||
|
||||
primary = cirrus_primary_plane(dev);
|
||||
if (primary == NULL) {
|
||||
kfree(cirrus_crtc);
|
||||
return;
|
||||
}
|
||||
|
||||
drm_crtc_init_with_planes(dev, &cirrus_crtc->base,
|
||||
primary, NULL,
|
||||
&cirrus_crtc_funcs, NULL);
|
||||
|
||||
drm_mode_crtc_set_gamma_size(&cirrus_crtc->base, CIRRUS_LUT_SIZE);
|
||||
cdev->mode_info.crtc = cirrus_crtc;
|
||||
|
||||
drm_crtc_helper_add(&cirrus_crtc->base, &cirrus_helper_funcs);
|
||||
}
|
||||
|
||||
static void cirrus_encoder_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
}
|
||||
|
||||
static void cirrus_encoder_dpms(struct drm_encoder *encoder, int state)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void cirrus_encoder_prepare(struct drm_encoder *encoder)
|
||||
{
|
||||
}
|
||||
|
||||
static void cirrus_encoder_commit(struct drm_encoder *encoder)
|
||||
{
|
||||
}
|
||||
|
||||
static void cirrus_encoder_destroy(struct drm_encoder *encoder)
|
||||
{
|
||||
struct cirrus_encoder *cirrus_encoder = to_cirrus_encoder(encoder);
|
||||
drm_encoder_cleanup(encoder);
|
||||
kfree(cirrus_encoder);
|
||||
}
|
||||
|
||||
static const struct drm_encoder_helper_funcs cirrus_encoder_helper_funcs = {
|
||||
.dpms = cirrus_encoder_dpms,
|
||||
.mode_set = cirrus_encoder_mode_set,
|
||||
.prepare = cirrus_encoder_prepare,
|
||||
.commit = cirrus_encoder_commit,
|
||||
};
|
||||
|
||||
static const struct drm_encoder_funcs cirrus_encoder_encoder_funcs = {
|
||||
.destroy = cirrus_encoder_destroy,
|
||||
};
|
||||
|
||||
static struct drm_encoder *cirrus_encoder_init(struct drm_device *dev)
|
||||
{
|
||||
struct drm_encoder *encoder;
|
||||
struct cirrus_encoder *cirrus_encoder;
|
||||
|
||||
cirrus_encoder = kzalloc(sizeof(struct cirrus_encoder), GFP_KERNEL);
|
||||
if (!cirrus_encoder)
|
||||
return NULL;
|
||||
|
||||
encoder = &cirrus_encoder->base;
|
||||
encoder->possible_crtcs = 0x1;
|
||||
|
||||
drm_encoder_init(dev, encoder, &cirrus_encoder_encoder_funcs,
|
||||
DRM_MODE_ENCODER_DAC, NULL);
|
||||
drm_encoder_helper_add(encoder, &cirrus_encoder_helper_funcs);
|
||||
|
||||
return encoder;
|
||||
}
|
||||
|
||||
|
||||
static int cirrus_vga_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
int count;
|
||||
|
||||
/* Just add a static list of modes */
|
||||
if (cirrus_bpp <= 24) {
|
||||
count = drm_add_modes_noedid(connector, 1280, 1024);
|
||||
drm_set_preferred_mode(connector, 1024, 768);
|
||||
} else {
|
||||
count = drm_add_modes_noedid(connector, 800, 600);
|
||||
drm_set_preferred_mode(connector, 800, 600);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct drm_encoder *cirrus_connector_best_encoder(struct drm_connector
|
||||
*connector)
|
||||
{
|
||||
int enc_id = connector->encoder_ids[0];
|
||||
/* pick the encoder ids */
|
||||
if (enc_id)
|
||||
return drm_encoder_find(connector->dev, NULL, enc_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void cirrus_connector_destroy(struct drm_connector *connector)
|
||||
{
|
||||
drm_connector_cleanup(connector);
|
||||
kfree(connector);
|
||||
}
|
||||
|
||||
static const struct drm_connector_helper_funcs cirrus_vga_connector_helper_funcs = {
|
||||
.get_modes = cirrus_vga_get_modes,
|
||||
.best_encoder = cirrus_connector_best_encoder,
|
||||
};
|
||||
|
||||
static const struct drm_connector_funcs cirrus_vga_connector_funcs = {
|
||||
.dpms = drm_helper_connector_dpms,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = cirrus_connector_destroy,
|
||||
};
|
||||
|
||||
static struct drm_connector *cirrus_vga_init(struct drm_device *dev)
|
||||
{
|
||||
struct drm_connector *connector;
|
||||
struct cirrus_connector *cirrus_connector;
|
||||
|
||||
cirrus_connector = kzalloc(sizeof(struct cirrus_connector), GFP_KERNEL);
|
||||
if (!cirrus_connector)
|
||||
return NULL;
|
||||
|
||||
connector = &cirrus_connector->base;
|
||||
|
||||
drm_connector_init(dev, connector,
|
||||
&cirrus_vga_connector_funcs, DRM_MODE_CONNECTOR_VGA);
|
||||
|
||||
drm_connector_helper_add(connector, &cirrus_vga_connector_helper_funcs);
|
||||
|
||||
drm_connector_register(connector);
|
||||
return connector;
|
||||
}
|
||||
|
||||
|
||||
int cirrus_modeset_init(struct cirrus_device *cdev)
|
||||
{
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_connector *connector;
|
||||
int ret;
|
||||
|
||||
drm_mode_config_init(cdev->dev);
|
||||
|
||||
cdev->dev->mode_config.max_width = CIRRUS_MAX_FB_WIDTH;
|
||||
cdev->dev->mode_config.max_height = CIRRUS_MAX_FB_HEIGHT;
|
||||
|
||||
cdev->dev->mode_config.fb_base = cdev->mc.vram_base;
|
||||
cdev->dev->mode_config.preferred_depth = cirrus_bpp;
|
||||
/* don't prefer a shadow on virt GPU */
|
||||
cdev->dev->mode_config.prefer_shadow = 0;
|
||||
|
||||
cirrus_crtc_init(cdev->dev);
|
||||
|
||||
encoder = cirrus_encoder_init(cdev->dev);
|
||||
if (!encoder) {
|
||||
DRM_ERROR("cirrus_encoder_init failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
connector = cirrus_vga_init(cdev->dev);
|
||||
if (!connector) {
|
||||
DRM_ERROR("cirrus_vga_init failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
drm_connector_attach_encoder(connector, encoder);
|
||||
|
||||
ret = cirrus_fbdev_init(cdev);
|
||||
if (ret) {
|
||||
DRM_ERROR("cirrus_fbdev_init failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cirrus_modeset_fini(struct cirrus_device *cdev)
|
||||
{
|
||||
cirrus_fbdev_fini(cdev);
|
||||
drm_helper_force_disable_all(cdev->dev);
|
||||
drm_mode_config_cleanup(cdev->dev);
|
||||
}
|
326
drivers/gpu/drm/drm_format_helper.c
Normal file
326
drivers/gpu/drm/drm_format_helper.c
Normal file
|
@ -0,0 +1,326 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2016 Noralf Trønnes
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <drm/drm_format_helper.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_rect.h>
|
||||
|
||||
static void drm_fb_memcpy_lines(void *dst, unsigned int dst_pitch,
|
||||
void *src, unsigned int src_pitch,
|
||||
unsigned int linelength, unsigned int lines)
|
||||
{
|
||||
int line;
|
||||
|
||||
for (line = 0; line < lines; line++) {
|
||||
memcpy(dst, src, linelength);
|
||||
src += src_pitch;
|
||||
dst += dst_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_fb_memcpy - Copy clip buffer
|
||||
* @dst: Destination buffer
|
||||
* @vaddr: Source buffer
|
||||
* @fb: DRM framebuffer
|
||||
* @clip: Clip rectangle area to copy
|
||||
*
|
||||
* This function does not apply clipping on dst, i.e. the destination
|
||||
* is a small buffer containing the clip rect only.
|
||||
*/
|
||||
void drm_fb_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb,
|
||||
struct drm_rect *clip)
|
||||
{
|
||||
unsigned int cpp = drm_format_plane_cpp(fb->format->format, 0);
|
||||
unsigned int offset = (clip->y1 * fb->pitches[0]) + (clip->x1 * cpp);
|
||||
size_t len = (clip->x2 - clip->x1) * cpp;
|
||||
|
||||
drm_fb_memcpy_lines(dst, len,
|
||||
vaddr + offset, fb->pitches[0],
|
||||
len, clip->y2 - clip->y1);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_memcpy);
|
||||
|
||||
/**
|
||||
* drm_fb_memcpy_dstclip - Copy clip buffer
|
||||
* @dst: Destination buffer
|
||||
* @vaddr: Source buffer
|
||||
* @fb: DRM framebuffer
|
||||
* @clip: Clip rectangle area to copy
|
||||
*
|
||||
* This function applies clipping on dst, i.e. the destination is a
|
||||
* full framebuffer but only the clip rect content is copied over.
|
||||
*/
|
||||
void drm_fb_memcpy_dstclip(void *dst, void *vaddr, struct drm_framebuffer *fb,
|
||||
struct drm_rect *clip)
|
||||
{
|
||||
unsigned int cpp = drm_format_plane_cpp(fb->format->format, 0);
|
||||
unsigned int offset = (clip->y1 * fb->pitches[0]) + (clip->x1 * cpp);
|
||||
size_t len = (clip->x2 - clip->x1) * cpp;
|
||||
|
||||
drm_fb_memcpy_lines(dst + offset, fb->pitches[0],
|
||||
vaddr + offset, fb->pitches[0],
|
||||
len, clip->y2 - clip->y1);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_memcpy_dstclip);
|
||||
|
||||
/**
|
||||
* drm_fb_swab16 - Swap bytes into clip buffer
|
||||
* @dst: RGB565 destination buffer
|
||||
* @vaddr: RGB565 source buffer
|
||||
* @fb: DRM framebuffer
|
||||
* @clip: Clip rectangle area to copy
|
||||
*/
|
||||
void drm_fb_swab16(u16 *dst, void *vaddr, struct drm_framebuffer *fb,
|
||||
struct drm_rect *clip)
|
||||
{
|
||||
size_t len = (clip->x2 - clip->x1) * sizeof(u16);
|
||||
unsigned int x, y;
|
||||
u16 *src, *buf;
|
||||
|
||||
/*
|
||||
* The cma memory is write-combined so reads are uncached.
|
||||
* Speed up by fetching one line at a time.
|
||||
*/
|
||||
buf = kmalloc(len, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return;
|
||||
|
||||
for (y = clip->y1; y < clip->y2; y++) {
|
||||
src = vaddr + (y * fb->pitches[0]);
|
||||
src += clip->x1;
|
||||
memcpy(buf, src, len);
|
||||
src = buf;
|
||||
for (x = clip->x1; x < clip->x2; x++)
|
||||
*dst++ = swab16(*src++);
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_swab16);
|
||||
|
||||
static void drm_fb_xrgb8888_to_rgb565_lines(void *dst, unsigned int dst_pitch,
|
||||
void *src, unsigned int src_pitch,
|
||||
unsigned int src_linelength,
|
||||
unsigned int lines,
|
||||
bool swap)
|
||||
{
|
||||
unsigned int linepixels = src_linelength / sizeof(u32);
|
||||
unsigned int x, y;
|
||||
u32 *sbuf;
|
||||
u16 *dbuf, val16;
|
||||
|
||||
/*
|
||||
* The cma memory is write-combined so reads are uncached.
|
||||
* Speed up by fetching one line at a time.
|
||||
*/
|
||||
sbuf = kmalloc(src_linelength, GFP_KERNEL);
|
||||
if (!sbuf)
|
||||
return;
|
||||
|
||||
for (y = 0; y < lines; y++) {
|
||||
memcpy(sbuf, src, src_linelength);
|
||||
dbuf = dst;
|
||||
for (x = 0; x < linepixels; x++) {
|
||||
val16 = ((sbuf[x] & 0x00F80000) >> 8) |
|
||||
((sbuf[x] & 0x0000FC00) >> 5) |
|
||||
((sbuf[x] & 0x000000F8) >> 3);
|
||||
if (swap)
|
||||
*dbuf++ = swab16(val16);
|
||||
else
|
||||
*dbuf++ = val16;
|
||||
}
|
||||
src += src_pitch;
|
||||
dst += dst_pitch;
|
||||
}
|
||||
|
||||
kfree(sbuf);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_fb_xrgb8888_to_rgb565 - Convert XRGB8888 to RGB565 clip buffer
|
||||
* @dst: RGB565 destination buffer
|
||||
* @vaddr: XRGB8888 source buffer
|
||||
* @fb: DRM framebuffer
|
||||
* @clip: Clip rectangle area to copy
|
||||
* @swap: Swap bytes
|
||||
*
|
||||
* Drivers can use this function for RGB565 devices that don't natively
|
||||
* support XRGB8888.
|
||||
*
|
||||
* This function does not apply clipping on dst, i.e. the destination
|
||||
* is a small buffer containing the clip rect only.
|
||||
*/
|
||||
void drm_fb_xrgb8888_to_rgb565(void *dst, void *vaddr,
|
||||
struct drm_framebuffer *fb,
|
||||
struct drm_rect *clip, bool swap)
|
||||
{
|
||||
unsigned int src_offset = (clip->y1 * fb->pitches[0])
|
||||
+ (clip->x1 * sizeof(u32));
|
||||
size_t src_len = (clip->x2 - clip->x1) * sizeof(u32);
|
||||
size_t dst_len = (clip->x2 - clip->x1) * sizeof(u16);
|
||||
|
||||
drm_fb_xrgb8888_to_rgb565_lines(dst, dst_len,
|
||||
vaddr + src_offset, fb->pitches[0],
|
||||
src_len, clip->y2 - clip->y1,
|
||||
swap);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565);
|
||||
|
||||
/**
|
||||
* drm_fb_xrgb8888_to_rgb565_dstclip - Convert XRGB8888 to RGB565 clip buffer
|
||||
* @dst: RGB565 destination buffer
|
||||
* @dst_pitch: destination buffer pitch
|
||||
* @vaddr: XRGB8888 source buffer
|
||||
* @fb: DRM framebuffer
|
||||
* @clip: Clip rectangle area to copy
|
||||
* @swap: Swap bytes
|
||||
*
|
||||
* Drivers can use this function for RGB565 devices that don't natively
|
||||
* support XRGB8888.
|
||||
*
|
||||
* This function applies clipping on dst, i.e. the destination is a
|
||||
* full framebuffer but only the clip rect content is copied over.
|
||||
*/
|
||||
void drm_fb_xrgb8888_to_rgb565_dstclip(void *dst, unsigned int dst_pitch,
|
||||
void *vaddr, struct drm_framebuffer *fb,
|
||||
struct drm_rect *clip, bool swap)
|
||||
{
|
||||
unsigned int src_offset = (clip->y1 * fb->pitches[0])
|
||||
+ (clip->x1 * sizeof(u32));
|
||||
unsigned int dst_offset = (clip->y1 * dst_pitch)
|
||||
+ (clip->x1 * sizeof(u16));
|
||||
size_t src_len = (clip->x2 - clip->x1) * sizeof(u32);
|
||||
|
||||
drm_fb_xrgb8888_to_rgb565_lines(dst + dst_offset, dst_pitch,
|
||||
vaddr + src_offset, fb->pitches[0],
|
||||
src_len, clip->y2 - clip->y1,
|
||||
swap);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565_dstclip);
|
||||
|
||||
static void drm_fb_xrgb8888_to_rgb888_lines(void *dst, unsigned int dst_pitch,
|
||||
void *src, unsigned int src_pitch,
|
||||
unsigned int src_linelength,
|
||||
unsigned int lines)
|
||||
{
|
||||
unsigned int linepixels = src_linelength / 3;
|
||||
unsigned int x, y;
|
||||
u32 *sbuf;
|
||||
u8 *dbuf;
|
||||
|
||||
sbuf = kmalloc(src_linelength, GFP_KERNEL);
|
||||
if (!sbuf)
|
||||
return;
|
||||
|
||||
for (y = 0; y < lines; y++) {
|
||||
memcpy(sbuf, src, src_linelength);
|
||||
dbuf = dst;
|
||||
for (x = 0; x < linepixels; x++) {
|
||||
*dbuf++ = (sbuf[x] & 0x000000FF) >> 0;
|
||||
*dbuf++ = (sbuf[x] & 0x0000FF00) >> 8;
|
||||
*dbuf++ = (sbuf[x] & 0x00FF0000) >> 16;
|
||||
}
|
||||
src += src_pitch;
|
||||
dst += dst_pitch;
|
||||
}
|
||||
|
||||
kfree(sbuf);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_fb_xrgb8888_to_rgb888_dstclip - Convert XRGB8888 to RGB888 clip buffer
|
||||
* @dst: RGB565 destination buffer
|
||||
* @dst_pitch: destination buffer pitch
|
||||
* @vaddr: XRGB8888 source buffer
|
||||
* @fb: DRM framebuffer
|
||||
* @clip: Clip rectangle area to copy
|
||||
* @dstclip: Clip destination too.
|
||||
*
|
||||
* Drivers can use this function for RGB888 devices that don't natively
|
||||
* support XRGB8888.
|
||||
*
|
||||
* This function applies clipping on dst, i.e. the destination is a
|
||||
* full framebuffer but only the clip rect content is copied over.
|
||||
*/
|
||||
void drm_fb_xrgb8888_to_rgb888_dstclip(void *dst, unsigned int dst_pitch,
|
||||
void *vaddr, struct drm_framebuffer *fb,
|
||||
struct drm_rect *clip)
|
||||
{
|
||||
unsigned int src_offset = (clip->y1 * fb->pitches[0])
|
||||
+ (clip->x1 * sizeof(u32));
|
||||
unsigned int dst_offset = (clip->y1 * dst_pitch)
|
||||
+ (clip->x1 * 3);
|
||||
size_t src_len = (clip->x2 - clip->x1) * sizeof(u32);
|
||||
|
||||
drm_fb_xrgb8888_to_rgb888_lines(dst + dst_offset, dst_pitch,
|
||||
vaddr + src_offset, fb->pitches[0],
|
||||
src_len, clip->y2 - clip->y1);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888_dstclip);
|
||||
|
||||
/**
|
||||
* drm_fb_xrgb8888_to_gray8 - Convert XRGB8888 to grayscale
|
||||
* @dst: 8-bit grayscale destination buffer
|
||||
* @vaddr: XRGB8888 source buffer
|
||||
* @fb: DRM framebuffer
|
||||
* @clip: Clip rectangle area to copy
|
||||
*
|
||||
* Drm doesn't have native monochrome or grayscale support.
|
||||
* Such drivers can announce the commonly supported XR24 format to userspace
|
||||
* and use this function to convert to the native format.
|
||||
*
|
||||
* Monochrome drivers will use the most significant bit,
|
||||
* where 1 means foreground color and 0 background color.
|
||||
*
|
||||
* ITU BT.601 is used for the RGB -> luma (brightness) conversion.
|
||||
*/
|
||||
void drm_fb_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb,
|
||||
struct drm_rect *clip)
|
||||
{
|
||||
unsigned int len = (clip->x2 - clip->x1) * sizeof(u32);
|
||||
unsigned int x, y;
|
||||
void *buf;
|
||||
u32 *src;
|
||||
|
||||
if (WARN_ON(fb->format->format != DRM_FORMAT_XRGB8888))
|
||||
return;
|
||||
/*
|
||||
* The cma memory is write-combined so reads are uncached.
|
||||
* Speed up by fetching one line at a time.
|
||||
*/
|
||||
buf = kmalloc(len, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return;
|
||||
|
||||
for (y = clip->y1; y < clip->y2; y++) {
|
||||
src = vaddr + (y * fb->pitches[0]);
|
||||
src += clip->x1;
|
||||
memcpy(buf, src, len);
|
||||
src = buf;
|
||||
for (x = clip->x1; x < clip->x2; x++) {
|
||||
u8 r = (*src & 0x00ff0000) >> 16;
|
||||
u8 g = (*src & 0x0000ff00) >> 8;
|
||||
u8 b = *src & 0x000000ff;
|
||||
|
||||
/* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
|
||||
*dst++ = (3 * r + 6 * g + b) / 10;
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8);
|
||||
|
|
@ -5,6 +5,9 @@ config DRM_LIMA
|
|||
tristate "LIMA (DRM support for ARM Mali 400/450 GPU)"
|
||||
depends on DRM
|
||||
depends on ARM || ARM64 || COMPILE_TEST
|
||||
depends on MMU
|
||||
depends on COMMON_CLK
|
||||
depends on OF
|
||||
select DRM_SCHED
|
||||
help
|
||||
DRM driver for ARM Mali 400/450 GPUs.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR MIT
|
||||
/* Copyright 2017-2019 Qiang Yu <yuq825@gmail.com> */
|
||||
|
||||
#include <linux/mm.h>
|
||||
#include <linux/sync_file.h>
|
||||
#include <linux/pfn_t.h>
|
||||
|
||||
|
|
|
@ -39,12 +39,17 @@
|
|||
#include "meson_viu.h"
|
||||
#include "meson_registers.h"
|
||||
|
||||
#define MESON_G12A_VIU_OFFSET 0x5ec0
|
||||
|
||||
/* CRTC definition */
|
||||
|
||||
struct meson_crtc {
|
||||
struct drm_crtc base;
|
||||
struct drm_pending_vblank_event *event;
|
||||
struct meson_drm *priv;
|
||||
void (*enable_osd1)(struct meson_drm *priv);
|
||||
void (*enable_vd1)(struct meson_drm *priv);
|
||||
unsigned int viu_offset;
|
||||
};
|
||||
#define to_meson_crtc(x) container_of(x, struct meson_crtc, base)
|
||||
|
||||
|
@ -80,6 +85,44 @@ static const struct drm_crtc_funcs meson_crtc_funcs = {
|
|||
|
||||
};
|
||||
|
||||
static void meson_g12a_crtc_atomic_enable(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_state)
|
||||
{
|
||||
struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
|
||||
struct drm_crtc_state *crtc_state = crtc->state;
|
||||
struct meson_drm *priv = meson_crtc->priv;
|
||||
|
||||
DRM_DEBUG_DRIVER("\n");
|
||||
|
||||
if (!crtc_state) {
|
||||
DRM_ERROR("Invalid crtc_state\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* VD1 Preblend vertical start/end */
|
||||
writel(FIELD_PREP(GENMASK(11, 0), 2303),
|
||||
priv->io_base + _REG(VPP_PREBLEND_VD1_V_START_END));
|
||||
|
||||
/* Setup Blender */
|
||||
writel(crtc_state->mode.hdisplay |
|
||||
crtc_state->mode.vdisplay << 16,
|
||||
priv->io_base + _REG(VPP_POSTBLEND_H_SIZE));
|
||||
|
||||
writel_relaxed(0 << 16 |
|
||||
(crtc_state->mode.hdisplay - 1),
|
||||
priv->io_base + _REG(VPP_OSD1_BLD_H_SCOPE));
|
||||
writel_relaxed(0 << 16 |
|
||||
(crtc_state->mode.vdisplay - 1),
|
||||
priv->io_base + _REG(VPP_OSD1_BLD_V_SCOPE));
|
||||
writel_relaxed(crtc_state->mode.hdisplay << 16 |
|
||||
crtc_state->mode.vdisplay,
|
||||
priv->io_base + _REG(VPP_OUT_H_V_SIZE));
|
||||
|
||||
drm_crtc_vblank_on(crtc);
|
||||
|
||||
priv->viu.osd1_enabled = true;
|
||||
}
|
||||
|
||||
static void meson_crtc_atomic_enable(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_state)
|
||||
{
|
||||
|
@ -110,6 +153,31 @@ static void meson_crtc_atomic_enable(struct drm_crtc *crtc,
|
|||
priv->viu.osd1_enabled = true;
|
||||
}
|
||||
|
||||
static void meson_g12a_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_state)
|
||||
{
|
||||
struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
|
||||
struct meson_drm *priv = meson_crtc->priv;
|
||||
|
||||
DRM_DEBUG_DRIVER("\n");
|
||||
|
||||
drm_crtc_vblank_off(crtc);
|
||||
|
||||
priv->viu.osd1_enabled = false;
|
||||
priv->viu.osd1_commit = false;
|
||||
|
||||
priv->viu.vd1_enabled = false;
|
||||
priv->viu.vd1_commit = false;
|
||||
|
||||
if (crtc->state->event && !crtc->state->active) {
|
||||
spin_lock_irq(&crtc->dev->event_lock);
|
||||
drm_crtc_send_vblank_event(crtc, crtc->state->event);
|
||||
spin_unlock_irq(&crtc->dev->event_lock);
|
||||
|
||||
crtc->state->event = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void meson_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_state)
|
||||
{
|
||||
|
@ -173,6 +241,53 @@ static const struct drm_crtc_helper_funcs meson_crtc_helper_funcs = {
|
|||
.atomic_disable = meson_crtc_atomic_disable,
|
||||
};
|
||||
|
||||
static const struct drm_crtc_helper_funcs meson_g12a_crtc_helper_funcs = {
|
||||
.atomic_begin = meson_crtc_atomic_begin,
|
||||
.atomic_flush = meson_crtc_atomic_flush,
|
||||
.atomic_enable = meson_g12a_crtc_atomic_enable,
|
||||
.atomic_disable = meson_g12a_crtc_atomic_disable,
|
||||
};
|
||||
|
||||
static void meson_crtc_enable_osd1(struct meson_drm *priv)
|
||||
{
|
||||
writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND,
|
||||
priv->io_base + _REG(VPP_MISC));
|
||||
}
|
||||
|
||||
static void meson_g12a_crtc_enable_osd1(struct meson_drm *priv)
|
||||
{
|
||||
writel_relaxed(priv->viu.osd_blend_din0_scope_h,
|
||||
priv->io_base +
|
||||
_REG(VIU_OSD_BLEND_DIN0_SCOPE_H));
|
||||
writel_relaxed(priv->viu.osd_blend_din0_scope_v,
|
||||
priv->io_base +
|
||||
_REG(VIU_OSD_BLEND_DIN0_SCOPE_V));
|
||||
writel_relaxed(priv->viu.osb_blend0_size,
|
||||
priv->io_base +
|
||||
_REG(VIU_OSD_BLEND_BLEND0_SIZE));
|
||||
writel_relaxed(priv->viu.osb_blend1_size,
|
||||
priv->io_base +
|
||||
_REG(VIU_OSD_BLEND_BLEND1_SIZE));
|
||||
}
|
||||
|
||||
static void meson_crtc_enable_vd1(struct meson_drm *priv)
|
||||
{
|
||||
writel_bits_relaxed(VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND |
|
||||
VPP_COLOR_MNG_ENABLE,
|
||||
VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND |
|
||||
VPP_COLOR_MNG_ENABLE,
|
||||
priv->io_base + _REG(VPP_MISC));
|
||||
}
|
||||
|
||||
static void meson_g12a_crtc_enable_vd1(struct meson_drm *priv)
|
||||
{
|
||||
writel_relaxed(((1 << 16) | /* post bld premult*/
|
||||
(1 << 8) | /* post src */
|
||||
(1 << 4) | /* pre bld premult*/
|
||||
(1 << 0)),
|
||||
priv->io_base + _REG(VD1_BLEND_SRC_CTRL));
|
||||
}
|
||||
|
||||
void meson_crtc_irq(struct meson_drm *priv)
|
||||
{
|
||||
struct meson_crtc *meson_crtc = to_meson_crtc(priv->crtc);
|
||||
|
@ -219,8 +334,8 @@ void meson_crtc_irq(struct meson_drm *priv)
|
|||
MESON_CANVAS_BLKMODE_LINEAR, 0);
|
||||
|
||||
/* Enable OSD1 */
|
||||
writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND,
|
||||
priv->io_base + _REG(VPP_MISC));
|
||||
if (meson_crtc->enable_osd1)
|
||||
meson_crtc->enable_osd1(priv);
|
||||
|
||||
priv->viu.osd1_commit = false;
|
||||
}
|
||||
|
@ -261,89 +376,133 @@ void meson_crtc_irq(struct meson_drm *priv)
|
|||
};
|
||||
|
||||
writel_relaxed(priv->viu.vd1_if0_gen_reg,
|
||||
priv->io_base + _REG(VD1_IF0_GEN_REG));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD1_IF0_GEN_REG));
|
||||
writel_relaxed(priv->viu.vd1_if0_gen_reg,
|
||||
priv->io_base + _REG(VD2_IF0_GEN_REG));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD2_IF0_GEN_REG));
|
||||
writel_relaxed(priv->viu.vd1_if0_gen_reg2,
|
||||
priv->io_base + _REG(VD1_IF0_GEN_REG2));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD1_IF0_GEN_REG2));
|
||||
writel_relaxed(priv->viu.viu_vd1_fmt_ctrl,
|
||||
priv->io_base + _REG(VIU_VD1_FMT_CTRL));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VIU_VD1_FMT_CTRL));
|
||||
writel_relaxed(priv->viu.viu_vd1_fmt_ctrl,
|
||||
priv->io_base + _REG(VIU_VD2_FMT_CTRL));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VIU_VD2_FMT_CTRL));
|
||||
writel_relaxed(priv->viu.viu_vd1_fmt_w,
|
||||
priv->io_base + _REG(VIU_VD1_FMT_W));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VIU_VD1_FMT_W));
|
||||
writel_relaxed(priv->viu.viu_vd1_fmt_w,
|
||||
priv->io_base + _REG(VIU_VD2_FMT_W));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VIU_VD2_FMT_W));
|
||||
writel_relaxed(priv->viu.vd1_if0_canvas0,
|
||||
priv->io_base + _REG(VD1_IF0_CANVAS0));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD1_IF0_CANVAS0));
|
||||
writel_relaxed(priv->viu.vd1_if0_canvas0,
|
||||
priv->io_base + _REG(VD1_IF0_CANVAS1));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD1_IF0_CANVAS1));
|
||||
writel_relaxed(priv->viu.vd1_if0_canvas0,
|
||||
priv->io_base + _REG(VD2_IF0_CANVAS0));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD2_IF0_CANVAS0));
|
||||
writel_relaxed(priv->viu.vd1_if0_canvas0,
|
||||
priv->io_base + _REG(VD2_IF0_CANVAS1));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD2_IF0_CANVAS1));
|
||||
writel_relaxed(priv->viu.vd1_if0_luma_x0,
|
||||
priv->io_base + _REG(VD1_IF0_LUMA_X0));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD1_IF0_LUMA_X0));
|
||||
writel_relaxed(priv->viu.vd1_if0_luma_x0,
|
||||
priv->io_base + _REG(VD1_IF0_LUMA_X1));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD1_IF0_LUMA_X1));
|
||||
writel_relaxed(priv->viu.vd1_if0_luma_x0,
|
||||
priv->io_base + _REG(VD2_IF0_LUMA_X0));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD2_IF0_LUMA_X0));
|
||||
writel_relaxed(priv->viu.vd1_if0_luma_x0,
|
||||
priv->io_base + _REG(VD2_IF0_LUMA_X1));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD2_IF0_LUMA_X1));
|
||||
writel_relaxed(priv->viu.vd1_if0_luma_y0,
|
||||
priv->io_base + _REG(VD1_IF0_LUMA_Y0));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD1_IF0_LUMA_Y0));
|
||||
writel_relaxed(priv->viu.vd1_if0_luma_y0,
|
||||
priv->io_base + _REG(VD1_IF0_LUMA_Y1));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD1_IF0_LUMA_Y1));
|
||||
writel_relaxed(priv->viu.vd1_if0_luma_y0,
|
||||
priv->io_base + _REG(VD2_IF0_LUMA_Y0));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD2_IF0_LUMA_Y0));
|
||||
writel_relaxed(priv->viu.vd1_if0_luma_y0,
|
||||
priv->io_base + _REG(VD2_IF0_LUMA_Y1));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD2_IF0_LUMA_Y1));
|
||||
writel_relaxed(priv->viu.vd1_if0_chroma_x0,
|
||||
priv->io_base + _REG(VD1_IF0_CHROMA_X0));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD1_IF0_CHROMA_X0));
|
||||
writel_relaxed(priv->viu.vd1_if0_chroma_x0,
|
||||
priv->io_base + _REG(VD1_IF0_CHROMA_X1));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD1_IF0_CHROMA_X1));
|
||||
writel_relaxed(priv->viu.vd1_if0_chroma_x0,
|
||||
priv->io_base + _REG(VD2_IF0_CHROMA_X0));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD2_IF0_CHROMA_X0));
|
||||
writel_relaxed(priv->viu.vd1_if0_chroma_x0,
|
||||
priv->io_base + _REG(VD2_IF0_CHROMA_X1));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD2_IF0_CHROMA_X1));
|
||||
writel_relaxed(priv->viu.vd1_if0_chroma_y0,
|
||||
priv->io_base + _REG(VD1_IF0_CHROMA_Y0));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD1_IF0_CHROMA_Y0));
|
||||
writel_relaxed(priv->viu.vd1_if0_chroma_y0,
|
||||
priv->io_base + _REG(VD1_IF0_CHROMA_Y1));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD1_IF0_CHROMA_Y1));
|
||||
writel_relaxed(priv->viu.vd1_if0_chroma_y0,
|
||||
priv->io_base + _REG(VD2_IF0_CHROMA_Y0));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD2_IF0_CHROMA_Y0));
|
||||
writel_relaxed(priv->viu.vd1_if0_chroma_y0,
|
||||
priv->io_base + _REG(VD2_IF0_CHROMA_Y1));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD2_IF0_CHROMA_Y1));
|
||||
writel_relaxed(priv->viu.vd1_if0_repeat_loop,
|
||||
priv->io_base + _REG(VD1_IF0_RPT_LOOP));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD1_IF0_RPT_LOOP));
|
||||
writel_relaxed(priv->viu.vd1_if0_repeat_loop,
|
||||
priv->io_base + _REG(VD2_IF0_RPT_LOOP));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD2_IF0_RPT_LOOP));
|
||||
writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat,
|
||||
priv->io_base + _REG(VD1_IF0_LUMA0_RPT_PAT));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD1_IF0_LUMA0_RPT_PAT));
|
||||
writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat,
|
||||
priv->io_base + _REG(VD2_IF0_LUMA0_RPT_PAT));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD2_IF0_LUMA0_RPT_PAT));
|
||||
writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat,
|
||||
priv->io_base + _REG(VD1_IF0_LUMA1_RPT_PAT));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD1_IF0_LUMA1_RPT_PAT));
|
||||
writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat,
|
||||
priv->io_base + _REG(VD2_IF0_LUMA1_RPT_PAT));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD2_IF0_LUMA1_RPT_PAT));
|
||||
writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat,
|
||||
priv->io_base + _REG(VD1_IF0_CHROMA0_RPT_PAT));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD1_IF0_CHROMA0_RPT_PAT));
|
||||
writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat,
|
||||
priv->io_base + _REG(VD2_IF0_CHROMA0_RPT_PAT));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD2_IF0_CHROMA0_RPT_PAT));
|
||||
writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat,
|
||||
priv->io_base + _REG(VD1_IF0_CHROMA1_RPT_PAT));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD1_IF0_CHROMA1_RPT_PAT));
|
||||
writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat,
|
||||
priv->io_base + _REG(VD2_IF0_CHROMA1_RPT_PAT));
|
||||
writel_relaxed(0, priv->io_base + _REG(VD1_IF0_LUMA_PSEL));
|
||||
writel_relaxed(0, priv->io_base + _REG(VD1_IF0_CHROMA_PSEL));
|
||||
writel_relaxed(0, priv->io_base + _REG(VD2_IF0_LUMA_PSEL));
|
||||
writel_relaxed(0, priv->io_base + _REG(VD2_IF0_CHROMA_PSEL));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD2_IF0_CHROMA1_RPT_PAT));
|
||||
writel_relaxed(0, priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD1_IF0_LUMA_PSEL));
|
||||
writel_relaxed(0, priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD1_IF0_CHROMA_PSEL));
|
||||
writel_relaxed(0, priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD2_IF0_LUMA_PSEL));
|
||||
writel_relaxed(0, priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD2_IF0_CHROMA_PSEL));
|
||||
writel_relaxed(priv->viu.vd1_range_map_y,
|
||||
priv->io_base + _REG(VD1_IF0_RANGE_MAP_Y));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD1_IF0_RANGE_MAP_Y));
|
||||
writel_relaxed(priv->viu.vd1_range_map_cb,
|
||||
priv->io_base + _REG(VD1_IF0_RANGE_MAP_CB));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD1_IF0_RANGE_MAP_CB));
|
||||
writel_relaxed(priv->viu.vd1_range_map_cr,
|
||||
priv->io_base + _REG(VD1_IF0_RANGE_MAP_CR));
|
||||
priv->io_base + meson_crtc->viu_offset +
|
||||
_REG(VD1_IF0_RANGE_MAP_CR));
|
||||
writel_relaxed(0x78404,
|
||||
priv->io_base + _REG(VPP_SC_MISC));
|
||||
writel_relaxed(priv->viu.vpp_pic_in_height,
|
||||
|
@ -389,11 +548,8 @@ void meson_crtc_irq(struct meson_drm *priv)
|
|||
writel_relaxed(0x42, priv->io_base + _REG(VPP_SCALE_COEF_IDX));
|
||||
|
||||
/* Enable VD1 */
|
||||
writel_bits_relaxed(VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND |
|
||||
VPP_COLOR_MNG_ENABLE,
|
||||
VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND |
|
||||
VPP_COLOR_MNG_ENABLE,
|
||||
priv->io_base + _REG(VPP_MISC));
|
||||
if (meson_crtc->enable_vd1)
|
||||
meson_crtc->enable_vd1(priv);
|
||||
|
||||
priv->viu.vd1_commit = false;
|
||||
}
|
||||
|
@ -430,7 +586,16 @@ int meson_crtc_create(struct meson_drm *priv)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
|
||||
meson_crtc->enable_osd1 = meson_g12a_crtc_enable_osd1;
|
||||
meson_crtc->enable_vd1 = meson_g12a_crtc_enable_vd1;
|
||||
meson_crtc->viu_offset = MESON_G12A_VIU_OFFSET;
|
||||
drm_crtc_helper_add(crtc, &meson_g12a_crtc_helper_funcs);
|
||||
} else {
|
||||
meson_crtc->enable_osd1 = meson_crtc_enable_osd1;
|
||||
meson_crtc->enable_vd1 = meson_crtc_enable_vd1;
|
||||
drm_crtc_helper_add(crtc, &meson_crtc_helper_funcs);
|
||||
}
|
||||
|
||||
priv->crtc = crtc;
|
||||
|
||||
|
|
|
@ -444,6 +444,7 @@ static const struct of_device_id dt_match[] = {
|
|||
{ .compatible = "amlogic,meson-gxbb-vpu" },
|
||||
{ .compatible = "amlogic,meson-gxl-vpu" },
|
||||
{ .compatible = "amlogic,meson-gxm-vpu" },
|
||||
{ .compatible = "amlogic,meson-g12a-vpu" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dt_match);
|
||||
|
|
|
@ -62,6 +62,10 @@ struct meson_drm {
|
|||
uint32_t osd_sc_h_phase_step;
|
||||
uint32_t osd_sc_h_ctrl0;
|
||||
uint32_t osd_sc_v_ctrl0;
|
||||
uint32_t osd_blend_din0_scope_h;
|
||||
uint32_t osd_blend_din0_scope_v;
|
||||
uint32_t osb_blend0_size;
|
||||
uint32_t osb_blend1_size;
|
||||
|
||||
bool vd1_enabled;
|
||||
bool vd1_commit;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/component.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/clk.h>
|
||||
|
@ -105,6 +106,7 @@
|
|||
#define HDMITX_TOP_ADDR_REG 0x0
|
||||
#define HDMITX_TOP_DATA_REG 0x4
|
||||
#define HDMITX_TOP_CTRL_REG 0x8
|
||||
#define HDMITX_TOP_G12A_OFFSET 0x8000
|
||||
|
||||
/* Controller Communication Channel */
|
||||
#define HDMITX_DWC_ADDR_REG 0x10
|
||||
|
@ -118,6 +120,8 @@
|
|||
#define HHI_HDMI_PHY_CNTL1 0x3a4 /* 0xe9 */
|
||||
#define HHI_HDMI_PHY_CNTL2 0x3a8 /* 0xea */
|
||||
#define HHI_HDMI_PHY_CNTL3 0x3ac /* 0xeb */
|
||||
#define HHI_HDMI_PHY_CNTL4 0x3b0 /* 0xec */
|
||||
#define HHI_HDMI_PHY_CNTL5 0x3b4 /* 0xed */
|
||||
|
||||
static DEFINE_SPINLOCK(reg_lock);
|
||||
|
||||
|
@ -127,12 +131,26 @@ enum meson_venc_source {
|
|||
MESON_VENC_SOURCE_ENCP = 2,
|
||||
};
|
||||
|
||||
struct meson_dw_hdmi;
|
||||
|
||||
struct meson_dw_hdmi_data {
|
||||
unsigned int (*top_read)(struct meson_dw_hdmi *dw_hdmi,
|
||||
unsigned int addr);
|
||||
void (*top_write)(struct meson_dw_hdmi *dw_hdmi,
|
||||
unsigned int addr, unsigned int data);
|
||||
unsigned int (*dwc_read)(struct meson_dw_hdmi *dw_hdmi,
|
||||
unsigned int addr);
|
||||
void (*dwc_write)(struct meson_dw_hdmi *dw_hdmi,
|
||||
unsigned int addr, unsigned int data);
|
||||
};
|
||||
|
||||
struct meson_dw_hdmi {
|
||||
struct drm_encoder encoder;
|
||||
struct dw_hdmi_plat_data dw_plat_data;
|
||||
struct meson_drm *priv;
|
||||
struct device *dev;
|
||||
void __iomem *hdmitx;
|
||||
const struct meson_dw_hdmi_data *data;
|
||||
struct reset_control *hdmitx_apb;
|
||||
struct reset_control *hdmitx_ctrl;
|
||||
struct reset_control *hdmitx_phy;
|
||||
|
@ -174,6 +192,12 @@ static unsigned int dw_hdmi_top_read(struct meson_dw_hdmi *dw_hdmi,
|
|||
return data;
|
||||
}
|
||||
|
||||
static unsigned int dw_hdmi_g12a_top_read(struct meson_dw_hdmi *dw_hdmi,
|
||||
unsigned int addr)
|
||||
{
|
||||
return readl(dw_hdmi->hdmitx + HDMITX_TOP_G12A_OFFSET + (addr << 2));
|
||||
}
|
||||
|
||||
static inline void dw_hdmi_top_write(struct meson_dw_hdmi *dw_hdmi,
|
||||
unsigned int addr, unsigned int data)
|
||||
{
|
||||
|
@ -191,18 +215,24 @@ static inline void dw_hdmi_top_write(struct meson_dw_hdmi *dw_hdmi,
|
|||
spin_unlock_irqrestore(®_lock, flags);
|
||||
}
|
||||
|
||||
static inline void dw_hdmi_g12a_top_write(struct meson_dw_hdmi *dw_hdmi,
|
||||
unsigned int addr, unsigned int data)
|
||||
{
|
||||
writel(data, dw_hdmi->hdmitx + HDMITX_TOP_G12A_OFFSET + (addr << 2));
|
||||
}
|
||||
|
||||
/* Helper to change specific bits in PHY registers */
|
||||
static inline void dw_hdmi_top_write_bits(struct meson_dw_hdmi *dw_hdmi,
|
||||
unsigned int addr,
|
||||
unsigned int mask,
|
||||
unsigned int val)
|
||||
{
|
||||
unsigned int data = dw_hdmi_top_read(dw_hdmi, addr);
|
||||
unsigned int data = dw_hdmi->data->top_read(dw_hdmi, addr);
|
||||
|
||||
data &= ~mask;
|
||||
data |= val;
|
||||
|
||||
dw_hdmi_top_write(dw_hdmi, addr, data);
|
||||
dw_hdmi->data->top_write(dw_hdmi, addr, data);
|
||||
}
|
||||
|
||||
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,
|
|||
return data;
|
||||
}
|
||||
|
||||
static unsigned int dw_hdmi_g12a_dwc_read(struct meson_dw_hdmi *dw_hdmi,
|
||||
unsigned int addr)
|
||||
{
|
||||
return readb(dw_hdmi->hdmitx + addr);
|
||||
}
|
||||
|
||||
static inline void dw_hdmi_dwc_write(struct meson_dw_hdmi *dw_hdmi,
|
||||
unsigned int addr, unsigned int data)
|
||||
{
|
||||
|
@ -243,18 +279,24 @@ static inline void dw_hdmi_dwc_write(struct meson_dw_hdmi *dw_hdmi,
|
|||
spin_unlock_irqrestore(®_lock, flags);
|
||||
}
|
||||
|
||||
static inline void dw_hdmi_g12a_dwc_write(struct meson_dw_hdmi *dw_hdmi,
|
||||
unsigned int addr, unsigned int data)
|
||||
{
|
||||
writeb(data, dw_hdmi->hdmitx + addr);
|
||||
}
|
||||
|
||||
/* Helper to change specific bits in controller registers */
|
||||
static inline void dw_hdmi_dwc_write_bits(struct meson_dw_hdmi *dw_hdmi,
|
||||
unsigned int addr,
|
||||
unsigned int mask,
|
||||
unsigned int val)
|
||||
{
|
||||
unsigned int data = dw_hdmi_dwc_read(dw_hdmi, addr);
|
||||
unsigned int data = dw_hdmi->data->dwc_read(dw_hdmi, addr);
|
||||
|
||||
data &= ~mask;
|
||||
data |= val;
|
||||
|
||||
dw_hdmi_dwc_write(dw_hdmi, addr, data);
|
||||
dw_hdmi->data->dwc_write(dw_hdmi, addr, data);
|
||||
}
|
||||
|
||||
/* Bridge */
|
||||
|
@ -300,6 +342,24 @@ static void meson_hdmi_phy_setup_mode(struct meson_dw_hdmi *dw_hdmi,
|
|||
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33632122);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2000115b);
|
||||
}
|
||||
} else if (dw_hdmi_is_compatible(dw_hdmi,
|
||||
"amlogic,meson-g12a-dw-hdmi")) {
|
||||
if (pixel_clock >= 371250) {
|
||||
/* 5.94Gbps, 3.7125Gbps */
|
||||
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x37eb65c4);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x0000080b);
|
||||
} else if (pixel_clock >= 297000) {
|
||||
/* 2.97Gbps */
|
||||
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33eb6262);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x00000003);
|
||||
} else {
|
||||
/* 1.485Gbps, and below */
|
||||
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33eb4242);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x00000003);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -375,7 +435,7 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
|
|||
regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0);
|
||||
|
||||
/* Bring out of reset */
|
||||
dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_SW_RESET, 0);
|
||||
dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_SW_RESET, 0);
|
||||
|
||||
/* Enable internal pixclk, tmds_clk, spdif_clk, i2s_clk, cecclk */
|
||||
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,
|
|||
0x3 << 4, 0x3 << 4);
|
||||
|
||||
/* Enable normal output to PHY */
|
||||
dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12));
|
||||
dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12));
|
||||
|
||||
/* TMDS pattern setup (TOFIX Handle the YUV420 case) */
|
||||
if (mode->clock > 340000) {
|
||||
dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0);
|
||||
dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23,
|
||||
dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01,
|
||||
0);
|
||||
dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23,
|
||||
0x03ff03ff);
|
||||
} else {
|
||||
dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01,
|
||||
dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01,
|
||||
0x001f001f);
|
||||
dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23,
|
||||
dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23,
|
||||
0x001f001f);
|
||||
}
|
||||
|
||||
/* Load TMDS pattern */
|
||||
dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1);
|
||||
dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1);
|
||||
msleep(20);
|
||||
dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2);
|
||||
dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2);
|
||||
|
||||
/* Setup PHY parameters */
|
||||
meson_hdmi_phy_setup_mode(dw_hdmi, mode);
|
||||
|
@ -412,7 +473,8 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
|
|||
|
||||
/* BIT_INVERT */
|
||||
if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") ||
|
||||
dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi"))
|
||||
dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi") ||
|
||||
dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-g12a-dw-hdmi"))
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1,
|
||||
BIT(17), 0);
|
||||
else
|
||||
|
@ -480,7 +542,7 @@ static enum drm_connector_status dw_hdmi_read_hpd(struct dw_hdmi *hdmi,
|
|||
{
|
||||
struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
|
||||
|
||||
return !!dw_hdmi_top_read(dw_hdmi, HDMITX_TOP_STAT0) ?
|
||||
return !!dw_hdmi->data->top_read(dw_hdmi, HDMITX_TOP_STAT0) ?
|
||||
connector_status_connected : connector_status_disconnected;
|
||||
}
|
||||
|
||||
|
@ -490,11 +552,11 @@ static void dw_hdmi_setup_hpd(struct dw_hdmi *hdmi,
|
|||
struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
|
||||
|
||||
/* Setup HPD Filter */
|
||||
dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_HPD_FILTER,
|
||||
dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_HPD_FILTER,
|
||||
(0xa << 12) | 0xa0);
|
||||
|
||||
/* Clear interrupts */
|
||||
dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR,
|
||||
dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR,
|
||||
HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL);
|
||||
|
||||
/* Unmask interrupts */
|
||||
|
@ -515,8 +577,8 @@ static irqreturn_t dw_hdmi_top_irq(int irq, void *dev_id)
|
|||
struct meson_dw_hdmi *dw_hdmi = dev_id;
|
||||
u32 stat;
|
||||
|
||||
stat = dw_hdmi_top_read(dw_hdmi, HDMITX_TOP_INTR_STAT);
|
||||
dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, stat);
|
||||
stat = dw_hdmi->data->top_read(dw_hdmi, HDMITX_TOP_INTR_STAT);
|
||||
dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, stat);
|
||||
|
||||
/* HPD Events, handle in the threaded interrupt handler */
|
||||
if (stat & (HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL)) {
|
||||
|
@ -685,7 +747,9 @@ static const struct drm_encoder_helper_funcs
|
|||
static int meson_dw_hdmi_reg_read(void *context, unsigned int reg,
|
||||
unsigned int *result)
|
||||
{
|
||||
*result = dw_hdmi_dwc_read(context, reg);
|
||||
struct meson_dw_hdmi *dw_hdmi = context;
|
||||
|
||||
*result = dw_hdmi->data->dwc_read(dw_hdmi, reg);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -694,7 +758,9 @@ static int meson_dw_hdmi_reg_read(void *context, unsigned int reg,
|
|||
static int meson_dw_hdmi_reg_write(void *context, unsigned int reg,
|
||||
unsigned int val)
|
||||
{
|
||||
dw_hdmi_dwc_write(context, reg, val);
|
||||
struct meson_dw_hdmi *dw_hdmi = context;
|
||||
|
||||
dw_hdmi->data->dwc_write(dw_hdmi, reg, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -708,6 +774,20 @@ static const struct regmap_config meson_dw_hdmi_regmap_config = {
|
|||
.fast_io = true,
|
||||
};
|
||||
|
||||
static const struct meson_dw_hdmi_data meson_dw_hdmi_gx_data = {
|
||||
.top_read = dw_hdmi_top_read,
|
||||
.top_write = dw_hdmi_top_write,
|
||||
.dwc_read = dw_hdmi_dwc_read,
|
||||
.dwc_write = dw_hdmi_dwc_write,
|
||||
};
|
||||
|
||||
static const struct meson_dw_hdmi_data meson_dw_hdmi_g12a_data = {
|
||||
.top_read = dw_hdmi_g12a_top_read,
|
||||
.top_write = dw_hdmi_g12a_top_write,
|
||||
.dwc_read = dw_hdmi_g12a_dwc_read,
|
||||
.dwc_write = dw_hdmi_g12a_dwc_write,
|
||||
};
|
||||
|
||||
static bool meson_hdmi_connector_is_available(struct device *dev)
|
||||
{
|
||||
struct device_node *ep, *remote;
|
||||
|
@ -734,6 +814,7 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
|
|||
void *data)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
const struct meson_dw_hdmi_data *match;
|
||||
struct meson_dw_hdmi *meson_dw_hdmi;
|
||||
struct drm_device *drm = data;
|
||||
struct meson_drm *priv = drm->dev_private;
|
||||
|
@ -750,6 +831,12 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
match = of_device_get_match_data(&pdev->dev);
|
||||
if (!match) {
|
||||
dev_err(&pdev->dev, "failed to get match data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
meson_dw_hdmi = devm_kzalloc(dev, sizeof(*meson_dw_hdmi),
|
||||
GFP_KERNEL);
|
||||
if (!meson_dw_hdmi)
|
||||
|
@ -757,6 +844,7 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
|
|||
|
||||
meson_dw_hdmi->priv = priv;
|
||||
meson_dw_hdmi->dev = dev;
|
||||
meson_dw_hdmi->data = match;
|
||||
dw_plat_data = &meson_dw_hdmi->dw_plat_data;
|
||||
encoder = &meson_dw_hdmi->encoder;
|
||||
|
||||
|
@ -857,23 +945,27 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
|
|||
reset_control_reset(meson_dw_hdmi->hdmitx_phy);
|
||||
|
||||
/* Enable APB3 fail on error */
|
||||
if (!meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
|
||||
writel_bits_relaxed(BIT(15), BIT(15),
|
||||
meson_dw_hdmi->hdmitx + HDMITX_TOP_CTRL_REG);
|
||||
writel_bits_relaxed(BIT(15), BIT(15),
|
||||
meson_dw_hdmi->hdmitx + HDMITX_DWC_CTRL_REG);
|
||||
}
|
||||
|
||||
/* Bring out of reset */
|
||||
dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_SW_RESET, 0);
|
||||
meson_dw_hdmi->data->top_write(meson_dw_hdmi,
|
||||
HDMITX_TOP_SW_RESET, 0);
|
||||
|
||||
msleep(20);
|
||||
|
||||
dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_CLK_CNTL, 0xff);
|
||||
meson_dw_hdmi->data->top_write(meson_dw_hdmi,
|
||||
HDMITX_TOP_CLK_CNTL, 0xff);
|
||||
|
||||
/* Enable HDMI-TX Interrupt */
|
||||
dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_INTR_STAT_CLR,
|
||||
meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_INTR_STAT_CLR,
|
||||
HDMITX_TOP_INTR_CORE);
|
||||
|
||||
dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_INTR_MASKN,
|
||||
meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_INTR_MASKN,
|
||||
HDMITX_TOP_INTR_CORE);
|
||||
|
||||
/* Bridge / Connector */
|
||||
|
@ -923,9 +1015,14 @@ static int meson_dw_hdmi_remove(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
static const struct of_device_id meson_dw_hdmi_of_table[] = {
|
||||
{ .compatible = "amlogic,meson-gxbb-dw-hdmi" },
|
||||
{ .compatible = "amlogic,meson-gxl-dw-hdmi" },
|
||||
{ .compatible = "amlogic,meson-gxm-dw-hdmi" },
|
||||
{ .compatible = "amlogic,meson-gxbb-dw-hdmi",
|
||||
.data = &meson_dw_hdmi_gx_data },
|
||||
{ .compatible = "amlogic,meson-gxl-dw-hdmi",
|
||||
.data = &meson_dw_hdmi_gx_data },
|
||||
{ .compatible = "amlogic,meson-gxm-dw-hdmi",
|
||||
.data = &meson_dw_hdmi_gx_data },
|
||||
{ .compatible = "amlogic,meson-g12a-dw-hdmi",
|
||||
.data = &meson_dw_hdmi_g12a_data },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, meson_dw_hdmi_of_table);
|
||||
|
|
|
@ -21,9 +21,12 @@
|
|||
#define __MESON_DW_HDMI_H
|
||||
|
||||
/*
|
||||
* Bit 7 RW Reserved. Default 1.
|
||||
* Bit 6 RW Reserved. Default 1.
|
||||
* Bit 5 RW Reserved. Default 1.
|
||||
* Bit 15-10: RW Reserved. Default 1 starting from G12A
|
||||
* Bit 9 RW sw_reset_i2c starting from G12A
|
||||
* Bit 8 RW sw_reset_axiarb starting from G12A
|
||||
* Bit 7 RW Reserved. Default 1, sw_reset_emp starting from G12A
|
||||
* Bit 6 RW Reserved. Default 1, sw_reset_flt starting from G12A
|
||||
* Bit 5 RW Reserved. Default 1, sw_reset_hdcp22 starting from G12A
|
||||
* Bit 4 RW sw_reset_phyif: PHY interface. 1=Apply reset; 0=Release from reset.
|
||||
* Default 1.
|
||||
* Bit 3 RW sw_reset_intr: interrupt module. 1=Apply reset;
|
||||
|
@ -39,12 +42,16 @@
|
|||
#define HDMITX_TOP_SW_RESET (0x000)
|
||||
|
||||
/*
|
||||
* Bit 31 RW free_clk_en: 0=Enable clock gating for power saving; 1= Disable
|
||||
* Bit 12 RW i2s_ws_inv:1=Invert i2s_ws; 0=No invert. Default 0.
|
||||
* Bit 11 RW i2s_clk_inv: 1=Invert i2s_clk; 0=No invert. Default 0.
|
||||
* Bit 10 RW spdif_clk_inv: 1=Invert spdif_clk; 0=No invert. Default 0.
|
||||
* Bit 9 RW tmds_clk_inv: 1=Invert tmds_clk; 0=No invert. Default 0.
|
||||
* Bit 8 RW pixel_clk_inv: 1=Invert pixel_clk; 0=No invert. Default 0.
|
||||
* Bit 4 RW cec_clk_en: 1=enable cec_clk; 0=disable. Default 0.
|
||||
* Bit 7 RW hdcp22_skpclk_en: starting from G12A, 1=enable; 0=disable
|
||||
* Bit 6 RW hdcp22_esmclk_en: starting from G12A, 1=enable; 0=disable
|
||||
* Bit 5 RW hdcp22_tmdsclk_en: starting from G12A, 1=enable; 0=disable
|
||||
* Bit 4 RW cec_clk_en: 1=enable cec_clk; 0=disable. Default 0. Reserved for G12A
|
||||
* Bit 3 RW i2s_clk_en: 1=enable i2s_clk; 0=disable. Default 0.
|
||||
* Bit 2 RW spdif_clk_en: 1=enable spdif_clk; 0=disable. Default 0.
|
||||
* Bit 1 RW tmds_clk_en: 1=enable tmds_clk; 0=disable. Default 0.
|
||||
|
@ -53,6 +60,8 @@
|
|||
#define HDMITX_TOP_CLK_CNTL (0x001)
|
||||
|
||||
/*
|
||||
* Bit 31:28 RW rxsense_glitch_width: starting from G12A
|
||||
* Bit 27:16 RW rxsense_valid_width: starting from G12A
|
||||
* Bit 11: 0 RW hpd_valid_width: filter out width <= M*1024. Default 0.
|
||||
* Bit 15:12 RW hpd_glitch_width: filter out glitch <= N. Default 0.
|
||||
*/
|
||||
|
@ -61,6 +70,9 @@
|
|||
/*
|
||||
* intr_maskn: MASK_N, one bit per interrupt source.
|
||||
* 1=Enable interrupt source; 0=Disable interrupt source. Default 0.
|
||||
* [ 7] rxsense_fall starting from G12A
|
||||
* [ 6] rxsense_rise starting from G12A
|
||||
* [ 5] err_i2c_timeout starting from G12A
|
||||
* [ 4] hdcp22_rndnum_err
|
||||
* [ 3] nonce_rfrsh_rise
|
||||
* [ 2] hpd_fall_intr
|
||||
|
@ -73,6 +85,9 @@
|
|||
* Bit 30: 0 RW intr_stat: For each bit, write 1 to manually set the interrupt
|
||||
* bit, read back the interrupt status.
|
||||
* Bit 31 R IP interrupt status
|
||||
* Bit 7 RW rxsense_fall starting from G12A
|
||||
* Bit 6 RW rxsense_rise starting from G12A
|
||||
* Bit 5 RW err_i2c_timeout starting from G12A
|
||||
* Bit 2 RW hpd_fall
|
||||
* Bit 1 RW hpd_rise
|
||||
* Bit 0 RW IP interrupt
|
||||
|
@ -80,6 +95,9 @@
|
|||
#define HDMITX_TOP_INTR_STAT (0x004)
|
||||
|
||||
/*
|
||||
* [7] rxsense_fall starting from G12A
|
||||
* [6] rxsense_rise starting from G12A
|
||||
* [5] err_i2c_timeout starting from G12A
|
||||
* [4] hdcp22_rndnum_err
|
||||
* [3] nonce_rfrsh_rise
|
||||
* [2] hpd_fall
|
||||
|
@ -91,6 +109,8 @@
|
|||
#define HDMITX_TOP_INTR_CORE BIT(0)
|
||||
#define HDMITX_TOP_INTR_HPD_RISE BIT(1)
|
||||
#define HDMITX_TOP_INTR_HPD_FALL BIT(2)
|
||||
#define HDMITX_TOP_INTR_RXSENSE_RISE BIT(6)
|
||||
#define HDMITX_TOP_INTR_RXSENSE_FALL BIT(7)
|
||||
|
||||
/* Bit 14:12 RW tmds_sel: 3'b000=Output zero; 3'b001=Output normal TMDS data;
|
||||
* 3'b010=Output PRBS data; 3'b100=Output shift pattern. Default 0.
|
||||
|
@ -140,7 +160,9 @@
|
|||
*/
|
||||
#define HDMITX_TOP_REVOCMEM_STAT (0x00D)
|
||||
|
||||
/* Bit 0 R filtered HPD status. */
|
||||
/* Bit 1 R filtered RxSense status
|
||||
* Bit 0 R filtered HPD status.
|
||||
*/
|
||||
#define HDMITX_TOP_STAT0 (0x00E)
|
||||
|
||||
#endif /* __MESON_DW_HDMI_H */
|
||||
|
|
|
@ -516,6 +516,12 @@ static void meson_overlay_atomic_disable(struct drm_plane *plane,
|
|||
priv->viu.vd1_enabled = false;
|
||||
|
||||
/* Disable VD1 */
|
||||
if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
|
||||
writel_relaxed(0, priv->io_base + _REG(VD1_BLEND_SRC_CTRL));
|
||||
writel_relaxed(0, priv->io_base + _REG(VD2_BLEND_SRC_CTRL));
|
||||
writel_relaxed(0, priv->io_base + _REG(VD1_IF0_GEN_REG + 0x17b0));
|
||||
writel_relaxed(0, priv->io_base + _REG(VD2_IF0_GEN_REG + 0x17b0));
|
||||
} else
|
||||
writel_bits_relaxed(VPP_VD1_POSTBLEND | VPP_VD1_PREBLEND, 0,
|
||||
priv->io_base + _REG(VPP_MISC));
|
||||
|
||||
|
|
|
@ -294,6 +294,13 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
|
|||
priv->viu.osd1_blk0_cfg[3] = ((dest.x2 - 1) << 16) | dest.x1;
|
||||
priv->viu.osd1_blk0_cfg[4] = ((dest.y2 - 1) << 16) | dest.y1;
|
||||
|
||||
if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
|
||||
priv->viu.osd_blend_din0_scope_h = ((dest.x2 - 1) << 16) | dest.x1;
|
||||
priv->viu.osd_blend_din0_scope_v = ((dest.y2 - 1) << 16) | dest.y1;
|
||||
priv->viu.osb_blend0_size = dst_h << 16 | dst_w;
|
||||
priv->viu.osb_blend1_size = dst_h << 16 | dst_w;
|
||||
}
|
||||
|
||||
/* Update Canvas with buffer address */
|
||||
gem = drm_fb_cma_get_gem_obj(fb, 0);
|
||||
|
||||
|
@ -320,6 +327,10 @@ static void meson_plane_atomic_disable(struct drm_plane *plane,
|
|||
struct meson_drm *priv = meson_plane->priv;
|
||||
|
||||
/* Disable OSD1 */
|
||||
if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
|
||||
writel_bits_relaxed(BIT(0) | BIT(21), 0,
|
||||
priv->io_base + _REG(VIU_OSD1_CTRL_STAT));
|
||||
else
|
||||
writel_bits_relaxed(VPP_OSD1_POSTBLEND, 0,
|
||||
priv->io_base + _REG(VPP_MISC));
|
||||
|
||||
|
|
|
@ -216,6 +216,29 @@
|
|||
#define VIU_OSD2_FIFO_CTRL_STAT 0x1a4b
|
||||
#define VIU_OSD2_TEST_RDDATA 0x1a4c
|
||||
#define VIU_OSD2_PROT_CTRL 0x1a4e
|
||||
#define VIU_OSD2_MALI_UNPACK_CTRL 0x1abd
|
||||
#define VIU_OSD2_DIMM_CTRL 0x1acf
|
||||
|
||||
#define VIU_OSD3_CTRL_STAT 0x3d80
|
||||
#define VIU_OSD3_CTRL_STAT2 0x3d81
|
||||
#define VIU_OSD3_COLOR_ADDR 0x3d82
|
||||
#define VIU_OSD3_COLOR 0x3d83
|
||||
#define VIU_OSD3_TCOLOR_AG0 0x3d84
|
||||
#define VIU_OSD3_TCOLOR_AG1 0x3d85
|
||||
#define VIU_OSD3_TCOLOR_AG2 0x3d86
|
||||
#define VIU_OSD3_TCOLOR_AG3 0x3d87
|
||||
#define VIU_OSD3_BLK0_CFG_W0 0x3d88
|
||||
#define VIU_OSD3_BLK0_CFG_W1 0x3d8c
|
||||
#define VIU_OSD3_BLK0_CFG_W2 0x3d90
|
||||
#define VIU_OSD3_BLK0_CFG_W3 0x3d94
|
||||
#define VIU_OSD3_BLK0_CFG_W4 0x3d98
|
||||
#define VIU_OSD3_BLK1_CFG_W4 0x3d99
|
||||
#define VIU_OSD3_BLK2_CFG_W4 0x3d9a
|
||||
#define VIU_OSD3_FIFO_CTRL_STAT 0x3d9c
|
||||
#define VIU_OSD3_TEST_RDDATA 0x3d9d
|
||||
#define VIU_OSD3_PROT_CTRL 0x3d9e
|
||||
#define VIU_OSD3_MALI_UNPACK_CTRL 0x3d9f
|
||||
#define VIU_OSD3_DIMM_CTRL 0x3da0
|
||||
|
||||
#define VD1_IF0_GEN_REG 0x1a50
|
||||
#define VD1_IF0_CANVAS0 0x1a51
|
||||
|
@ -287,6 +310,27 @@
|
|||
#define VIU_OSD1_MATRIX_COEF31_32 0x1a9e
|
||||
#define VIU_OSD1_MATRIX_COEF40_41 0x1a9f
|
||||
#define VD1_IF0_GEN_REG3 0x1aa7
|
||||
|
||||
#define VIU_OSD_BLENDO_H_START_END 0x1aa9
|
||||
#define VIU_OSD_BLENDO_V_START_END 0x1aaa
|
||||
#define VIU_OSD_BLEND_GEN_CTRL0 0x1aab
|
||||
#define VIU_OSD_BLEND_GEN_CTRL1 0x1aac
|
||||
#define VIU_OSD_BLEND_DUMMY_DATA 0x1aad
|
||||
#define VIU_OSD_BLEND_CURRENT_XY 0x1aae
|
||||
|
||||
#define VIU_OSD2_MATRIX_CTRL 0x1ab0
|
||||
#define VIU_OSD2_MATRIX_COEF00_01 0x1ab1
|
||||
#define VIU_OSD2_MATRIX_COEF02_10 0x1ab2
|
||||
#define VIU_OSD2_MATRIX_COEF11_12 0x1ab3
|
||||
#define VIU_OSD2_MATRIX_COEF20_21 0x1ab4
|
||||
#define VIU_OSD2_MATRIX_COEF22 0x1ab5
|
||||
#define VIU_OSD2_MATRIX_OFFSET0_1 0x1ab6
|
||||
#define VIU_OSD2_MATRIX_OFFSET2 0x1ab7
|
||||
#define VIU_OSD2_MATRIX_PRE_OFFSET0_1 0x1ab8
|
||||
#define VIU_OSD2_MATRIX_PRE_OFFSET2 0x1ab9
|
||||
#define VIU_OSD2_MATRIX_PROBE_COLOR 0x1aba
|
||||
#define VIU_OSD2_MATRIX_HL_COLOR 0x1abb
|
||||
#define VIU_OSD2_MATRIX_PROBE_POS 0x1abc
|
||||
#define VIU_OSD1_EOTF_CTL 0x1ad4
|
||||
#define VIU_OSD1_EOTF_COEF00_01 0x1ad5
|
||||
#define VIU_OSD1_EOTF_COEF02_10 0x1ad6
|
||||
|
@ -481,6 +525,82 @@
|
|||
#define VPP_OSD_SCALE_COEF 0x1dcd
|
||||
#define VPP_INT_LINE_NUM 0x1dce
|
||||
|
||||
#define VPP_WRAP_OSD1_MATRIX_COEF00_01 0x3d60
|
||||
#define VPP_WRAP_OSD1_MATRIX_COEF02_10 0x3d61
|
||||
#define VPP_WRAP_OSD1_MATRIX_COEF11_12 0x3d62
|
||||
#define VPP_WRAP_OSD1_MATRIX_COEF20_21 0x3d63
|
||||
#define VPP_WRAP_OSD1_MATRIX_COEF22 0x3d64
|
||||
#define VPP_WRAP_OSD1_MATRIX_COEF13_14 0x3d65
|
||||
#define VPP_WRAP_OSD1_MATRIX_COEF23_24 0x3d66
|
||||
#define VPP_WRAP_OSD1_MATRIX_COEF15_25 0x3d67
|
||||
#define VPP_WRAP_OSD1_MATRIX_CLIP 0x3d68
|
||||
#define VPP_WRAP_OSD1_MATRIX_OFFSET0_1 0x3d69
|
||||
#define VPP_WRAP_OSD1_MATRIX_OFFSET2 0x3d6a
|
||||
#define VPP_WRAP_OSD1_MATRIX_PRE_OFFSET0_1 0x3d6b
|
||||
#define VPP_WRAP_OSD1_MATRIX_PRE_OFFSET2 0x3d6c
|
||||
#define VPP_WRAP_OSD1_MATRIX_EN_CTRL 0x3d6d
|
||||
|
||||
#define VPP_WRAP_OSD2_MATRIX_COEF00_01 0x3d70
|
||||
#define VPP_WRAP_OSD2_MATRIX_COEF02_10 0x3d71
|
||||
#define VPP_WRAP_OSD2_MATRIX_COEF11_12 0x3d72
|
||||
#define VPP_WRAP_OSD2_MATRIX_COEF20_21 0x3d73
|
||||
#define VPP_WRAP_OSD2_MATRIX_COEF22 0x3d74
|
||||
#define VPP_WRAP_OSD2_MATRIX_COEF13_14 0x3d75
|
||||
#define VPP_WRAP_OSD2_MATRIX_COEF23_24 0x3d76
|
||||
#define VPP_WRAP_OSD2_MATRIX_COEF15_25 0x3d77
|
||||
#define VPP_WRAP_OSD2_MATRIX_CLIP 0x3d78
|
||||
#define VPP_WRAP_OSD2_MATRIX_OFFSET0_1 0x3d79
|
||||
#define VPP_WRAP_OSD2_MATRIX_OFFSET2 0x3d7a
|
||||
#define VPP_WRAP_OSD2_MATRIX_PRE_OFFSET0_1 0x3d7b
|
||||
#define VPP_WRAP_OSD2_MATRIX_PRE_OFFSET2 0x3d7c
|
||||
#define VPP_WRAP_OSD2_MATRIX_EN_CTRL 0x3d7d
|
||||
|
||||
#define VPP_WRAP_OSD3_MATRIX_COEF00_01 0x3db0
|
||||
#define VPP_WRAP_OSD3_MATRIX_COEF02_10 0x3db1
|
||||
#define VPP_WRAP_OSD3_MATRIX_COEF11_12 0x3db2
|
||||
#define VPP_WRAP_OSD3_MATRIX_COEF20_21 0x3db3
|
||||
#define VPP_WRAP_OSD3_MATRIX_COEF22 0x3db4
|
||||
#define VPP_WRAP_OSD3_MATRIX_COEF13_14 0x3db5
|
||||
#define VPP_WRAP_OSD3_MATRIX_COEF23_24 0x3db6
|
||||
#define VPP_WRAP_OSD3_MATRIX_COEF15_25 0x3db7
|
||||
#define VPP_WRAP_OSD3_MATRIX_CLIP 0x3db8
|
||||
#define VPP_WRAP_OSD3_MATRIX_OFFSET0_1 0x3db9
|
||||
#define VPP_WRAP_OSD3_MATRIX_OFFSET2 0x3dba
|
||||
#define VPP_WRAP_OSD3_MATRIX_PRE_OFFSET0_1 0x3dbb
|
||||
#define VPP_WRAP_OSD3_MATRIX_PRE_OFFSET2 0x3dbc
|
||||
#define VPP_WRAP_OSD3_MATRIX_EN_CTRL 0x3dbd
|
||||
|
||||
/* osd2 scaler */
|
||||
#define OSD2_VSC_PHASE_STEP 0x3d00
|
||||
#define OSD2_VSC_INI_PHASE 0x3d01
|
||||
#define OSD2_VSC_CTRL0 0x3d02
|
||||
#define OSD2_HSC_PHASE_STEP 0x3d03
|
||||
#define OSD2_HSC_INI_PHASE 0x3d04
|
||||
#define OSD2_HSC_CTRL0 0x3d05
|
||||
#define OSD2_HSC_INI_PAT_CTRL 0x3d06
|
||||
#define OSD2_SC_DUMMY_DATA 0x3d07
|
||||
#define OSD2_SC_CTRL0 0x3d08
|
||||
#define OSD2_SCI_WH_M1 0x3d09
|
||||
#define OSD2_SCO_H_START_END 0x3d0a
|
||||
#define OSD2_SCO_V_START_END 0x3d0b
|
||||
#define OSD2_SCALE_COEF_IDX 0x3d18
|
||||
#define OSD2_SCALE_COEF 0x3d19
|
||||
|
||||
/* osd34 scaler */
|
||||
#define OSD34_SCALE_COEF_IDX 0x3d1e
|
||||
#define OSD34_SCALE_COEF 0x3d1f
|
||||
#define OSD34_VSC_PHASE_STEP 0x3d20
|
||||
#define OSD34_VSC_INI_PHASE 0x3d21
|
||||
#define OSD34_VSC_CTRL0 0x3d22
|
||||
#define OSD34_HSC_PHASE_STEP 0x3d23
|
||||
#define OSD34_HSC_INI_PHASE 0x3d24
|
||||
#define OSD34_HSC_CTRL0 0x3d25
|
||||
#define OSD34_HSC_INI_PAT_CTRL 0x3d26
|
||||
#define OSD34_SC_DUMMY_DATA 0x3d27
|
||||
#define OSD34_SC_CTRL0 0x3d28
|
||||
#define OSD34_SCI_WH_M1 0x3d29
|
||||
#define OSD34_SCO_H_START_END 0x3d2a
|
||||
#define OSD34_SCO_V_START_END 0x3d2b
|
||||
/* viu2 */
|
||||
#define VIU2_ADDR_START 0x1e00
|
||||
#define VIU2_ADDR_END 0x1eff
|
||||
|
@ -1400,4 +1520,131 @@
|
|||
#define OSDSR_YBIC_VCOEF0 0x3149
|
||||
#define OSDSR_CBIC_VCOEF0 0x314a
|
||||
|
||||
/* osd afbcd on gxtvbb */
|
||||
#define OSD1_AFBCD_ENABLE 0x31a0
|
||||
#define OSD1_AFBCD_MODE 0x31a1
|
||||
#define OSD1_AFBCD_SIZE_IN 0x31a2
|
||||
#define OSD1_AFBCD_HDR_PTR 0x31a3
|
||||
#define OSD1_AFBCD_FRAME_PTR 0x31a4
|
||||
#define OSD1_AFBCD_CHROMA_PTR 0x31a5
|
||||
#define OSD1_AFBCD_CONV_CTRL 0x31a6
|
||||
#define OSD1_AFBCD_STATUS 0x31a8
|
||||
#define OSD1_AFBCD_PIXEL_HSCOPE 0x31a9
|
||||
#define OSD1_AFBCD_PIXEL_VSCOPE 0x31aa
|
||||
#define VIU_MISC_CTRL1 0x1a07
|
||||
|
||||
/* add for gxm and 962e dv core2 */
|
||||
#define DOLBY_CORE2A_SWAP_CTRL1 0x3434
|
||||
#define DOLBY_CORE2A_SWAP_CTRL2 0x3435
|
||||
|
||||
/* osd afbc on g12a */
|
||||
#define VPU_MAFBC_BLOCK_ID 0x3a00
|
||||
#define VPU_MAFBC_IRQ_RAW_STATUS 0x3a01
|
||||
#define VPU_MAFBC_IRQ_CLEAR 0x3a02
|
||||
#define VPU_MAFBC_IRQ_MASK 0x3a03
|
||||
#define VPU_MAFBC_IRQ_STATUS 0x3a04
|
||||
#define VPU_MAFBC_COMMAND 0x3a05
|
||||
#define VPU_MAFBC_STATUS 0x3a06
|
||||
#define VPU_MAFBC_SURFACE_CFG 0x3a07
|
||||
|
||||
/* osd afbc on g12a */
|
||||
#define VPU_MAFBC_HEADER_BUF_ADDR_LOW_S0 0x3a10
|
||||
#define VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S0 0x3a11
|
||||
#define VPU_MAFBC_FORMAT_SPECIFIER_S0 0x3a12
|
||||
#define VPU_MAFBC_BUFFER_WIDTH_S0 0x3a13
|
||||
#define VPU_MAFBC_BUFFER_HEIGHT_S0 0x3a14
|
||||
#define VPU_MAFBC_BOUNDING_BOX_X_START_S0 0x3a15
|
||||
#define VPU_MAFBC_BOUNDING_BOX_X_END_S0 0x3a16
|
||||
#define VPU_MAFBC_BOUNDING_BOX_Y_START_S0 0x3a17
|
||||
#define VPU_MAFBC_BOUNDING_BOX_Y_END_S0 0x3a18
|
||||
#define VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S0 0x3a19
|
||||
#define VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S0 0x3a1a
|
||||
#define VPU_MAFBC_OUTPUT_BUF_STRIDE_S0 0x3a1b
|
||||
#define VPU_MAFBC_PREFETCH_CFG_S0 0x3a1c
|
||||
|
||||
#define VPU_MAFBC_HEADER_BUF_ADDR_LOW_S1 0x3a30
|
||||
#define VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S1 0x3a31
|
||||
#define VPU_MAFBC_FORMAT_SPECIFIER_S1 0x3a32
|
||||
#define VPU_MAFBC_BUFFER_WIDTH_S1 0x3a33
|
||||
#define VPU_MAFBC_BUFFER_HEIGHT_S1 0x3a34
|
||||
#define VPU_MAFBC_BOUNDING_BOX_X_START_S1 0x3a35
|
||||
#define VPU_MAFBC_BOUNDING_BOX_X_END_S1 0x3a36
|
||||
#define VPU_MAFBC_BOUNDING_BOX_Y_START_S1 0x3a37
|
||||
#define VPU_MAFBC_BOUNDING_BOX_Y_END_S1 0x3a38
|
||||
#define VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S1 0x3a39
|
||||
#define VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S1 0x3a3a
|
||||
#define VPU_MAFBC_OUTPUT_BUF_STRIDE_S1 0x3a3b
|
||||
#define VPU_MAFBC_PREFETCH_CFG_S1 0x3a3c
|
||||
|
||||
#define VPU_MAFBC_HEADER_BUF_ADDR_LOW_S2 0x3a50
|
||||
#define VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S2 0x3a51
|
||||
#define VPU_MAFBC_FORMAT_SPECIFIER_S2 0x3a52
|
||||
#define VPU_MAFBC_BUFFER_WIDTH_S2 0x3a53
|
||||
#define VPU_MAFBC_BUFFER_HEIGHT_S2 0x3a54
|
||||
#define VPU_MAFBC_BOUNDING_BOX_X_START_S2 0x3a55
|
||||
#define VPU_MAFBC_BOUNDING_BOX_X_END_S2 0x3a56
|
||||
#define VPU_MAFBC_BOUNDING_BOX_Y_START_S2 0x3a57
|
||||
#define VPU_MAFBC_BOUNDING_BOX_Y_END_S2 0x3a58
|
||||
#define VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S2 0x3a59
|
||||
#define VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S2 0x3a5a
|
||||
#define VPU_MAFBC_OUTPUT_BUF_STRIDE_S2 0x3a5b
|
||||
#define VPU_MAFBC_PREFETCH_CFG_S2 0x3a5c
|
||||
|
||||
#define VPU_MAFBC_HEADER_BUF_ADDR_LOW_S3 0x3a70
|
||||
#define VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S3 0x3a71
|
||||
#define VPU_MAFBC_FORMAT_SPECIFIER_S3 0x3a72
|
||||
#define VPU_MAFBC_BUFFER_WIDTH_S3 0x3a73
|
||||
#define VPU_MAFBC_BUFFER_HEIGHT_S3 0x3a74
|
||||
#define VPU_MAFBC_BOUNDING_BOX_X_START_S3 0x3a75
|
||||
#define VPU_MAFBC_BOUNDING_BOX_X_END_S3 0x3a76
|
||||
#define VPU_MAFBC_BOUNDING_BOX_Y_START_S3 0x3a77
|
||||
#define VPU_MAFBC_BOUNDING_BOX_Y_END_S3 0x3a78
|
||||
#define VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S3 0x3a79
|
||||
#define VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S3 0x3a7a
|
||||
#define VPU_MAFBC_OUTPUT_BUF_STRIDE_S3 0x3a7b
|
||||
#define VPU_MAFBC_PREFETCH_CFG_S3 0x3a7c
|
||||
|
||||
#define DOLBY_PATH_CTRL 0x1a0c
|
||||
#define OSD_PATH_MISC_CTRL 0x1a0e
|
||||
#define MALI_AFBCD_TOP_CTRL 0x1a0f
|
||||
|
||||
#define VIU_OSD_BLEND_CTRL 0x39b0
|
||||
#define VIU_OSD_BLEND_CTRL1 0x39c0
|
||||
#define VIU_OSD_BLEND_DIN0_SCOPE_H 0x39b1
|
||||
#define VIU_OSD_BLEND_DIN0_SCOPE_V 0x39b2
|
||||
#define VIU_OSD_BLEND_DIN1_SCOPE_H 0x39b3
|
||||
#define VIU_OSD_BLEND_DIN1_SCOPE_V 0x39b4
|
||||
#define VIU_OSD_BLEND_DIN2_SCOPE_H 0x39b5
|
||||
#define VIU_OSD_BLEND_DIN2_SCOPE_V 0x39b6
|
||||
#define VIU_OSD_BLEND_DIN3_SCOPE_H 0x39b7
|
||||
#define VIU_OSD_BLEND_DIN3_SCOPE_V 0x39b8
|
||||
#define VIU_OSD_BLEND_DUMMY_DATA0 0x39b9
|
||||
#define VIU_OSD_BLEND_DUMMY_ALPHA 0x39ba
|
||||
#define VIU_OSD_BLEND_BLEND0_SIZE 0x39bb
|
||||
#define VIU_OSD_BLEND_BLEND1_SIZE 0x39bc
|
||||
#define VIU_OSD_BLEND_RO_CURRENT_XY 0x39bf
|
||||
|
||||
#define VPP_OUT_H_V_SIZE 0x1da5
|
||||
|
||||
#define VPP_VD2_HDR_IN_SIZE 0x1df0
|
||||
#define VPP_OSD1_IN_SIZE 0x1df1
|
||||
#define VPP_GCLK_CTRL2 0x1df2
|
||||
#define VD2_PPS_DUMMY_DATA 0x1df4
|
||||
#define VPP_OSD1_BLD_H_SCOPE 0x1df5
|
||||
#define VPP_OSD1_BLD_V_SCOPE 0x1df6
|
||||
#define VPP_OSD2_BLD_H_SCOPE 0x1df7
|
||||
#define VPP_OSD2_BLD_V_SCOPE 0x1df8
|
||||
#define VPP_WRBAK_CTRL 0x1df9
|
||||
#define VPP_SLEEP_CTRL 0x1dfa
|
||||
#define VD1_BLEND_SRC_CTRL 0x1dfb
|
||||
#define VD2_BLEND_SRC_CTRL 0x1dfc
|
||||
#define OSD1_BLEND_SRC_CTRL 0x1dfd
|
||||
#define OSD2_BLEND_SRC_CTRL 0x1dfe
|
||||
|
||||
#define VPP_POST_BLEND_BLEND_DUMMY_DATA 0x3968
|
||||
#define VPP_POST_BLEND_DUMMY_ALPHA 0x3969
|
||||
#define VPP_RDARB_MODE 0x3978
|
||||
#define VPP_RDARB_REQEN_SLV 0x3979
|
||||
#define VPU_RDARB_MODE_L2C1 0x279d
|
||||
|
||||
#endif /* __MESON_REGISTERS_H */
|
||||
|
|
|
@ -113,9 +113,12 @@
|
|||
#define HHI_HDMI_PLL_CNTL4 0x32C /* 0xcb offset in data sheet */
|
||||
#define HHI_HDMI_PLL_CNTL5 0x330 /* 0xcc offset in data sheet */
|
||||
#define HHI_HDMI_PLL_CNTL6 0x334 /* 0xcd offset in data sheet */
|
||||
#define HHI_HDMI_PLL_CNTL7 0x338 /* 0xce offset in data sheet */
|
||||
|
||||
#define HDMI_PLL_RESET BIT(28)
|
||||
#define HDMI_PLL_RESET_G12A BIT(29)
|
||||
#define HDMI_PLL_LOCK BIT(31)
|
||||
#define HDMI_PLL_LOCK_G12A (3 << 30)
|
||||
|
||||
#define FREQ_1000_1001(_freq) DIV_ROUND_CLOSEST(_freq * 1000, 1001)
|
||||
|
||||
|
@ -257,6 +260,10 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv)
|
|||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4800023d);
|
||||
|
||||
/* Poll for lock bit */
|
||||
regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val,
|
||||
(val & HDMI_PLL_LOCK), 10, 0);
|
||||
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
|
||||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4000027b);
|
||||
|
@ -271,11 +278,26 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv)
|
|||
HDMI_PLL_RESET, HDMI_PLL_RESET);
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
HDMI_PLL_RESET, 0);
|
||||
}
|
||||
|
||||
/* Poll for lock bit */
|
||||
regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val,
|
||||
(val & HDMI_PLL_LOCK), 10, 0);
|
||||
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x1a0504f7);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00010000);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x00000000);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x6a28dc00);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x65771290);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x39272000);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL7, 0x56540000);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x3a0504f7);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x1a0504f7);
|
||||
|
||||
/* Poll for lock bit */
|
||||
regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val,
|
||||
((val & HDMI_PLL_LOCK_G12A) == HDMI_PLL_LOCK_G12A),
|
||||
10, 0);
|
||||
}
|
||||
|
||||
/* Disable VCLK2 */
|
||||
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)
|
|||
VCLK2_DIV_MASK, (55 - 1));
|
||||
|
||||
/* select vid_pll for vclk2 */
|
||||
if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
|
||||
regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL,
|
||||
VCLK2_SEL_MASK, (0 << VCLK2_SEL_SHIFT));
|
||||
else
|
||||
regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL,
|
||||
VCLK2_SEL_MASK, (4 << VCLK2_SEL_SHIFT));
|
||||
|
||||
/* enable vclk2 gate */
|
||||
regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, VCLK2_EN);
|
||||
|
||||
|
@ -396,8 +423,8 @@ struct meson_vclk_params {
|
|||
},
|
||||
[MESON_VCLK_HDMI_297000] = {
|
||||
.pixel_freq = 297000,
|
||||
.pll_base_freq = 2970000,
|
||||
.pll_od1 = 1,
|
||||
.pll_base_freq = 5940000,
|
||||
.pll_od1 = 2,
|
||||
.pll_od2 = 1,
|
||||
.pll_od3 = 1,
|
||||
.vid_pll_div = VID_PLL_DIV_5,
|
||||
|
@ -476,6 +503,46 @@ void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m,
|
|||
/* Poll for lock bit */
|
||||
regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val,
|
||||
(val & HDMI_PLL_LOCK), 10, 0);
|
||||
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x0b3a0400 | m);
|
||||
|
||||
/* Enable and reset */
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
0x3 << 28, 0x3 << 28);
|
||||
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, frac);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x00000000);
|
||||
|
||||
/* G12A HDMI PLL Needs specific parameters for 5.4GHz */
|
||||
if (m >= 0xf7) {
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0xea68dc00);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x65771290);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x39272000);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL7, 0x55540000);
|
||||
} else {
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0a691c00);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x33771290);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x39270000);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL7, 0x50540000);
|
||||
}
|
||||
|
||||
do {
|
||||
/* Reset PLL */
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
HDMI_PLL_RESET_G12A, HDMI_PLL_RESET_G12A);
|
||||
|
||||
/* UN-Reset PLL */
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
HDMI_PLL_RESET_G12A, 0);
|
||||
|
||||
/* Poll for lock bits */
|
||||
if (!regmap_read_poll_timeout(priv->hhi,
|
||||
HHI_HDMI_PLL_CNTL, val,
|
||||
((val & HDMI_PLL_LOCK_G12A)
|
||||
== HDMI_PLL_LOCK_G12A),
|
||||
10, 100))
|
||||
break;
|
||||
} while(1);
|
||||
}
|
||||
|
||||
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
|
||||
|
@ -485,6 +552,9 @@ void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m,
|
|||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3,
|
||||
3 << 21, pll_od_to_reg(od1) << 21);
|
||||
else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
3 << 16, pll_od_to_reg(od1) << 16);
|
||||
|
||||
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
|
||||
|
@ -493,6 +563,9 @@ void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m,
|
|||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3,
|
||||
3 << 23, pll_od_to_reg(od2) << 23);
|
||||
else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
3 << 18, pll_od_to_reg(od2) << 18);
|
||||
|
||||
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
|
||||
|
@ -501,7 +574,9 @@ void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m,
|
|||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3,
|
||||
3 << 19, pll_od_to_reg(od3) << 19);
|
||||
|
||||
else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
3 << 20, pll_od_to_reg(od3) << 20);
|
||||
}
|
||||
|
||||
#define XTAL_FREQ 24000
|
||||
|
@ -518,6 +593,7 @@ static unsigned int meson_hdmi_pll_get_m(struct meson_drm *priv,
|
|||
|
||||
#define HDMI_FRAC_MAX_GXBB 4096
|
||||
#define HDMI_FRAC_MAX_GXL 1024
|
||||
#define HDMI_FRAC_MAX_G12A 131072
|
||||
|
||||
static unsigned int meson_hdmi_pll_get_frac(struct meson_drm *priv,
|
||||
unsigned int m,
|
||||
|
@ -534,6 +610,9 @@ static unsigned int meson_hdmi_pll_get_frac(struct meson_drm *priv,
|
|||
parent_freq *= 2;
|
||||
}
|
||||
|
||||
if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
|
||||
frac_max = HDMI_FRAC_MAX_G12A;
|
||||
|
||||
/* We can have a perfect match !*/
|
||||
if (pll_freq / m == parent_freq &&
|
||||
pll_freq % m == 0)
|
||||
|
@ -559,7 +638,8 @@ static bool meson_hdmi_pll_validate_params(struct meson_drm *priv,
|
|||
if (frac >= HDMI_FRAC_MAX_GXBB)
|
||||
return false;
|
||||
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
|
||||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
|
||||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu") ||
|
||||
meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
|
||||
/* Empiric supported min/max dividers */
|
||||
if (m < 106 || m > 247)
|
||||
return false;
|
||||
|
@ -713,6 +793,23 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq,
|
|||
break;
|
||||
}
|
||||
|
||||
meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
|
||||
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
|
||||
switch (pll_base_freq) {
|
||||
case 2970000:
|
||||
m = 0x7b;
|
||||
frac = vic_alternate_clock ? 0x140b4 : 0x18000;
|
||||
break;
|
||||
case 4320000:
|
||||
m = vic_alternate_clock ? 0xb3 : 0xb4;
|
||||
frac = vic_alternate_clock ? 0x1a3ee : 0;
|
||||
break;
|
||||
case 5940000:
|
||||
m = 0xf7;
|
||||
frac = vic_alternate_clock ? 0x8148 : 0x10000;
|
||||
break;
|
||||
}
|
||||
|
||||
meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
|
||||
}
|
||||
|
||||
|
|
|
@ -73,7 +73,9 @@
|
|||
/* HHI Registers */
|
||||
#define HHI_GCLK_MPEG2 0x148 /* 0x52 offset in data sheet */
|
||||
#define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */
|
||||
#define HHI_VDAC_CNTL0_G12A 0x2EC /* 0xbd offset in data sheet */
|
||||
#define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */
|
||||
#define HHI_VDAC_CNTL1_G12A 0x2F0 /* 0xbe offset in data sheet */
|
||||
#define HHI_HDMI_PHY_CNTL0 0x3a0 /* 0xe8 offset in data sheet */
|
||||
|
||||
struct meson_cvbs_enci_mode meson_cvbs_enci_pal = {
|
||||
|
@ -1675,8 +1677,13 @@ void meson_venc_disable_vsync(struct meson_drm *priv)
|
|||
void meson_venc_init(struct meson_drm *priv)
|
||||
{
|
||||
/* Disable CVBS VDAC */
|
||||
if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
|
||||
regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0);
|
||||
regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 8);
|
||||
} else {
|
||||
regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0);
|
||||
regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8);
|
||||
}
|
||||
|
||||
/* Power Down Dacs */
|
||||
writel_relaxed(0xff, priv->io_base + _REG(VENC_VDAC_SETTING));
|
||||
|
|
|
@ -37,7 +37,9 @@
|
|||
|
||||
/* HHI VDAC Registers */
|
||||
#define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */
|
||||
#define HHI_VDAC_CNTL0_G12A 0x2EC /* 0xbd offset in data sheet */
|
||||
#define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */
|
||||
#define HHI_VDAC_CNTL1_G12A 0x2F0 /* 0xbe offset in data sheet */
|
||||
|
||||
struct meson_venc_cvbs {
|
||||
struct drm_encoder encoder;
|
||||
|
@ -166,9 +168,14 @@ static void meson_venc_cvbs_encoder_disable(struct drm_encoder *encoder)
|
|||
struct meson_drm *priv = meson_venc_cvbs->priv;
|
||||
|
||||
/* Disable CVBS VDAC */
|
||||
if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
|
||||
regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0);
|
||||
regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 0);
|
||||
} else {
|
||||
regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0);
|
||||
regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
|||
/* VDAC0 source is not from ATV */
|
||||
writel_bits_relaxed(BIT(5), 0, priv->io_base + _REG(VENC_VDAC_DACSEL0));
|
||||
|
||||
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
|
||||
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
|
||||
regmap_write(priv->hhi, HHI_VDAC_CNTL0, 1);
|
||||
else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
|
||||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
|
||||
regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0xf0001);
|
||||
|
||||
regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0);
|
||||
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
|
||||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
|
||||
regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0xf0001);
|
||||
regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0);
|
||||
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
|
||||
regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0x906001);
|
||||
regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void meson_venc_cvbs_encoder_mode_set(struct drm_encoder *encoder,
|
||||
|
|
|
@ -90,6 +90,34 @@ static int eotf_bypass_coeff[EOTF_COEFF_SIZE] = {
|
|||
EOTF_COEFF_RIGHTSHIFT /* right shift */
|
||||
};
|
||||
|
||||
void meson_viu_set_g12a_osd1_matrix(struct meson_drm *priv, int *m,
|
||||
bool csc_on)
|
||||
{
|
||||
/* VPP WRAP OSD1 matrix */
|
||||
writel(((m[0] & 0xfff) << 16) | (m[1] & 0xfff),
|
||||
priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_PRE_OFFSET0_1));
|
||||
writel(m[2] & 0xfff,
|
||||
priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_PRE_OFFSET2));
|
||||
writel(((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff),
|
||||
priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF00_01));
|
||||
writel(((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff),
|
||||
priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF02_10));
|
||||
writel(((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff),
|
||||
priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF11_12));
|
||||
writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff),
|
||||
priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF20_21));
|
||||
writel((m[11] & 0x1fff) << 16,
|
||||
priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF22));
|
||||
|
||||
writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff),
|
||||
priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_OFFSET0_1));
|
||||
writel(m[20] & 0xfff,
|
||||
priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_OFFSET2));
|
||||
|
||||
writel_bits_relaxed(BIT(0), csc_on ? BIT(0) : 0,
|
||||
priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_EN_CTRL));
|
||||
}
|
||||
|
||||
void meson_viu_set_osd_matrix(struct meson_drm *priv,
|
||||
enum viu_matrix_sel_e m_select,
|
||||
int *m, bool csc_on)
|
||||
|
@ -336,11 +364,21 @@ void meson_viu_init(struct meson_drm *priv)
|
|||
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
|
||||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
|
||||
meson_viu_load_matrix(priv);
|
||||
else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
|
||||
meson_viu_set_g12a_osd1_matrix(priv, RGB709_to_YUV709l_coeff,
|
||||
true);
|
||||
|
||||
/* Initialize OSD1 fifo control register */
|
||||
reg = BIT(0) | /* Urgent DDR request priority */
|
||||
(4 << 5) | /* hold_fifo_lines */
|
||||
(3 << 10) | /* burst length 64 */
|
||||
(4 << 5); /* hold_fifo_lines */
|
||||
if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
|
||||
reg |= (1 << 10) | /* burst length 32 */
|
||||
(32 << 12) | /* fifo_depth_val: 32*8=256 */
|
||||
(2 << 22) | /* 4 words in 1 burst */
|
||||
(2 << 24) |
|
||||
(1 << 31);
|
||||
else
|
||||
reg |= (3 << 10) | /* burst length 64 */
|
||||
(32 << 12) | /* fifo_depth_val: 32*8=256 */
|
||||
(2 << 22) | /* 4 words in 1 burst */
|
||||
(2 << 24);
|
||||
|
@ -369,6 +407,30 @@ void meson_viu_init(struct meson_drm *priv)
|
|||
writel_relaxed(0x00FF00C0,
|
||||
priv->io_base + _REG(VD2_IF0_LUMA_FIFO_SIZE));
|
||||
|
||||
if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
|
||||
writel_relaxed(4 << 29 |
|
||||
1 << 27 |
|
||||
1 << 26 | /* blend_din0 input to blend0 */
|
||||
1 << 25 | /* blend1_dout to blend2 */
|
||||
1 << 24 | /* blend1_din3 input to blend1 */
|
||||
1 << 20 |
|
||||
0 << 16 |
|
||||
1,
|
||||
priv->io_base + _REG(VIU_OSD_BLEND_CTRL));
|
||||
writel_relaxed(3 << 8 |
|
||||
1 << 20,
|
||||
priv->io_base + _REG(OSD1_BLEND_SRC_CTRL));
|
||||
writel_relaxed(1 << 20,
|
||||
priv->io_base + _REG(OSD2_BLEND_SRC_CTRL));
|
||||
writel_relaxed(0, priv->io_base + _REG(VD1_BLEND_SRC_CTRL));
|
||||
writel_relaxed(0, priv->io_base + _REG(VD2_BLEND_SRC_CTRL));
|
||||
writel_relaxed(0,
|
||||
priv->io_base + _REG(VIU_OSD_BLEND_DUMMY_DATA0));
|
||||
writel_relaxed(0,
|
||||
priv->io_base + _REG(VIU_OSD_BLEND_DUMMY_ALPHA));
|
||||
writel_bits_relaxed(0x3 << 2, 0x3 << 2,
|
||||
priv->io_base + _REG(DOLBY_PATH_CTRL));
|
||||
}
|
||||
|
||||
priv->viu.osd1_enabled = false;
|
||||
priv->viu.osd1_commit = false;
|
||||
|
|
|
@ -112,13 +112,19 @@ void meson_vpp_init(struct meson_drm *priv)
|
|||
writel_relaxed(0x20000, priv->io_base + _REG(VPP_DOLBY_CTRL));
|
||||
writel_relaxed(0x1020080,
|
||||
priv->io_base + _REG(VPP_DUMMY_DATA1));
|
||||
}
|
||||
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
|
||||
writel_relaxed(0xf, priv->io_base + _REG(DOLBY_PATH_CTRL));
|
||||
|
||||
/* Initialize vpu fifo control registers */
|
||||
if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
|
||||
writel_relaxed(0xfff << 20 | 0x1000,
|
||||
priv->io_base + _REG(VPP_OFIFO_SIZE));
|
||||
else
|
||||
writel_relaxed(readl_relaxed(priv->io_base + _REG(VPP_OFIFO_SIZE)) |
|
||||
0x77f, priv->io_base + _REG(VPP_OFIFO_SIZE));
|
||||
writel_relaxed(0x08080808, priv->io_base + _REG(VPP_HOLD_LINES));
|
||||
|
||||
if (!meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
|
||||
/* Turn off preblend */
|
||||
writel_bits_relaxed(VPP_PREBLEND_ENABLE, 0,
|
||||
priv->io_base + _REG(VPP_MISC));
|
||||
|
@ -138,6 +144,7 @@ void meson_vpp_init(struct meson_drm *priv)
|
|||
priv->io_base + _REG(VPP_PREBLEND_VD1_H_START_END));
|
||||
writel_relaxed(4096,
|
||||
priv->io_base + _REG(VPP_BLEND_VD2_H_START_END));
|
||||
}
|
||||
|
||||
/* Disable Scalers */
|
||||
writel_relaxed(0, priv->io_base + _REG(VPP_OSD_SC_CTRL0));
|
||||
|
|
|
@ -123,7 +123,7 @@ static int jh057n_init_sequence(struct jh057n *ctx)
|
|||
|
||||
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(dev, "Failed to exit sleep mode");
|
||||
DRM_DEV_ERROR(dev, "Failed to exit sleep mode\n");
|
||||
return ret;
|
||||
}
|
||||
/* Panel is operational 120 msec after reset */
|
||||
|
@ -132,7 +132,7 @@ static int jh057n_init_sequence(struct jh057n *ctx)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
DRM_DEV_DEBUG_DRIVER(dev, "Panel init sequence done");
|
||||
DRM_DEV_DEBUG_DRIVER(dev, "Panel init sequence done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -172,7 +172,7 @@ static int jh057n_prepare(struct drm_panel *panel)
|
|||
if (ctx->prepared)
|
||||
return 0;
|
||||
|
||||
DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel.");
|
||||
DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel\n");
|
||||
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
|
||||
usleep_range(20, 40);
|
||||
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
|
||||
|
@ -180,7 +180,8 @@ static int jh057n_prepare(struct drm_panel *panel)
|
|||
|
||||
ret = jh057n_init_sequence(ctx);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d", ret);
|
||||
DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -212,7 +213,7 @@ static int jh057n_get_modes(struct drm_panel *panel)
|
|||
|
||||
mode = drm_mode_duplicate(panel->drm, &default_mode);
|
||||
if (!mode) {
|
||||
DRM_DEV_ERROR(ctx->dev, "Failed to add mode %ux%u@%u",
|
||||
DRM_DEV_ERROR(ctx->dev, "Failed to add mode %ux%u@%u\n",
|
||||
default_mode.hdisplay, default_mode.vdisplay,
|
||||
default_mode.vrefresh);
|
||||
return -ENOMEM;
|
||||
|
@ -241,7 +242,7 @@ static int allpixelson_set(void *data, u64 val)
|
|||
struct jh057n *ctx = data;
|
||||
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
|
||||
|
||||
DRM_DEV_DEBUG_DRIVER(ctx->dev, "Setting all pixels on");
|
||||
DRM_DEV_DEBUG_DRIVER(ctx->dev, "Setting all pixels on\n");
|
||||
dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON);
|
||||
msleep(val * 1000);
|
||||
/* Reset the panel to get video back */
|
||||
|
@ -290,7 +291,7 @@ static int jh057n_probe(struct mipi_dsi_device *dsi)
|
|||
|
||||
ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(ctx->reset_gpio)) {
|
||||
DRM_DEV_ERROR(dev, "cannot get reset gpio");
|
||||
DRM_DEV_ERROR(dev, "cannot get reset gpio\n");
|
||||
return PTR_ERR(ctx->reset_gpio);
|
||||
}
|
||||
|
||||
|
@ -315,12 +316,12 @@ static int jh057n_probe(struct mipi_dsi_device *dsi)
|
|||
|
||||
ret = mipi_dsi_attach(dsi);
|
||||
if (ret < 0) {
|
||||
DRM_DEV_ERROR(dev, "mipi_dsi_attach failed. Is host ready?");
|
||||
DRM_DEV_ERROR(dev, "mipi_dsi_attach failed. Is host ready?\n");
|
||||
drm_panel_remove(&ctx->panel);
|
||||
return ret;
|
||||
}
|
||||
|
||||
DRM_DEV_INFO(dev, "%ux%u@%u %ubpp dsi %udl - ready",
|
||||
DRM_DEV_INFO(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
|
||||
default_mode.hdisplay, default_mode.vdisplay,
|
||||
default_mode.vrefresh,
|
||||
mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
|
||||
|
|
|
@ -330,6 +330,7 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv)
|
|||
ret = vexpress_muxfpga_init();
|
||||
if (ret) {
|
||||
dev_err(dev, "unable to initialize muxfpga driver\n");
|
||||
of_node_put(np);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -337,17 +338,20 @@ int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv)
|
|||
pdev = of_find_device_by_node(np);
|
||||
if (!pdev) {
|
||||
dev_err(dev, "can't find the sysreg device, deferring\n");
|
||||
of_node_put(np);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
map = dev_get_drvdata(&pdev->dev);
|
||||
if (!map) {
|
||||
dev_err(dev, "sysreg has not yet probed\n");
|
||||
platform_device_put(pdev);
|
||||
of_node_put(np);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
} else {
|
||||
map = syscon_node_to_regmap(np);
|
||||
}
|
||||
of_node_put(np);
|
||||
|
||||
if (IS_ERR(map)) {
|
||||
dev_err(dev, "no Versatile syscon regmap\n");
|
||||
|
|
|
@ -26,164 +26,6 @@ static unsigned int spi_max;
|
|||
module_param(spi_max, uint, 0400);
|
||||
MODULE_PARM_DESC(spi_max, "Set a lower SPI max transfer size");
|
||||
|
||||
/**
|
||||
* tinydrm_memcpy - Copy clip buffer
|
||||
* @dst: Destination buffer
|
||||
* @vaddr: Source buffer
|
||||
* @fb: DRM framebuffer
|
||||
* @clip: Clip rectangle area to copy
|
||||
*/
|
||||
void tinydrm_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb,
|
||||
struct drm_rect *clip)
|
||||
{
|
||||
unsigned int cpp = drm_format_plane_cpp(fb->format->format, 0);
|
||||
unsigned int pitch = fb->pitches[0];
|
||||
void *src = vaddr + (clip->y1 * pitch) + (clip->x1 * cpp);
|
||||
size_t len = (clip->x2 - clip->x1) * cpp;
|
||||
unsigned int y;
|
||||
|
||||
for (y = clip->y1; y < clip->y2; y++) {
|
||||
memcpy(dst, src, len);
|
||||
src += pitch;
|
||||
dst += len;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(tinydrm_memcpy);
|
||||
|
||||
/**
|
||||
* tinydrm_swab16 - Swap bytes into clip buffer
|
||||
* @dst: RGB565 destination buffer
|
||||
* @vaddr: RGB565 source buffer
|
||||
* @fb: DRM framebuffer
|
||||
* @clip: Clip rectangle area to copy
|
||||
*/
|
||||
void tinydrm_swab16(u16 *dst, void *vaddr, struct drm_framebuffer *fb,
|
||||
struct drm_rect *clip)
|
||||
{
|
||||
size_t len = (clip->x2 - clip->x1) * sizeof(u16);
|
||||
unsigned int x, y;
|
||||
u16 *src, *buf;
|
||||
|
||||
/*
|
||||
* The cma memory is write-combined so reads are uncached.
|
||||
* Speed up by fetching one line at a time.
|
||||
*/
|
||||
buf = kmalloc(len, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return;
|
||||
|
||||
for (y = clip->y1; y < clip->y2; y++) {
|
||||
src = vaddr + (y * fb->pitches[0]);
|
||||
src += clip->x1;
|
||||
memcpy(buf, src, len);
|
||||
src = buf;
|
||||
for (x = clip->x1; x < clip->x2; x++)
|
||||
*dst++ = swab16(*src++);
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
}
|
||||
EXPORT_SYMBOL(tinydrm_swab16);
|
||||
|
||||
/**
|
||||
* tinydrm_xrgb8888_to_rgb565 - Convert XRGB8888 to RGB565 clip buffer
|
||||
* @dst: RGB565 destination buffer
|
||||
* @vaddr: XRGB8888 source buffer
|
||||
* @fb: DRM framebuffer
|
||||
* @clip: Clip rectangle area to copy
|
||||
* @swap: Swap bytes
|
||||
*
|
||||
* Drivers can use this function for RGB565 devices that don't natively
|
||||
* support XRGB8888.
|
||||
*/
|
||||
void tinydrm_xrgb8888_to_rgb565(u16 *dst, void *vaddr,
|
||||
struct drm_framebuffer *fb,
|
||||
struct drm_rect *clip, bool swap)
|
||||
{
|
||||
size_t len = (clip->x2 - clip->x1) * sizeof(u32);
|
||||
unsigned int x, y;
|
||||
u32 *src, *buf;
|
||||
u16 val16;
|
||||
|
||||
buf = kmalloc(len, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return;
|
||||
|
||||
for (y = clip->y1; y < clip->y2; y++) {
|
||||
src = vaddr + (y * fb->pitches[0]);
|
||||
src += clip->x1;
|
||||
memcpy(buf, src, len);
|
||||
src = buf;
|
||||
for (x = clip->x1; x < clip->x2; x++) {
|
||||
val16 = ((*src & 0x00F80000) >> 8) |
|
||||
((*src & 0x0000FC00) >> 5) |
|
||||
((*src & 0x000000F8) >> 3);
|
||||
src++;
|
||||
if (swap)
|
||||
*dst++ = swab16(val16);
|
||||
else
|
||||
*dst++ = val16;
|
||||
}
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
}
|
||||
EXPORT_SYMBOL(tinydrm_xrgb8888_to_rgb565);
|
||||
|
||||
/**
|
||||
* tinydrm_xrgb8888_to_gray8 - Convert XRGB8888 to grayscale
|
||||
* @dst: 8-bit grayscale destination buffer
|
||||
* @vaddr: XRGB8888 source buffer
|
||||
* @fb: DRM framebuffer
|
||||
* @clip: Clip rectangle area to copy
|
||||
*
|
||||
* Drm doesn't have native monochrome or grayscale support.
|
||||
* Such drivers can announce the commonly supported XR24 format to userspace
|
||||
* and use this function to convert to the native format.
|
||||
*
|
||||
* Monochrome drivers will use the most significant bit,
|
||||
* where 1 means foreground color and 0 background color.
|
||||
*
|
||||
* ITU BT.601 is used for the RGB -> luma (brightness) conversion.
|
||||
*/
|
||||
void tinydrm_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb,
|
||||
struct drm_rect *clip)
|
||||
{
|
||||
unsigned int len = (clip->x2 - clip->x1) * sizeof(u32);
|
||||
unsigned int x, y;
|
||||
void *buf;
|
||||
u32 *src;
|
||||
|
||||
if (WARN_ON(fb->format->format != DRM_FORMAT_XRGB8888))
|
||||
return;
|
||||
/*
|
||||
* The cma memory is write-combined so reads are uncached.
|
||||
* Speed up by fetching one line at a time.
|
||||
*/
|
||||
buf = kmalloc(len, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return;
|
||||
|
||||
for (y = clip->y1; y < clip->y2; y++) {
|
||||
src = vaddr + (y * fb->pitches[0]);
|
||||
src += clip->x1;
|
||||
memcpy(buf, src, len);
|
||||
src = buf;
|
||||
for (x = clip->x1; x < clip->x2; x++) {
|
||||
u8 r = (*src & 0x00ff0000) >> 16;
|
||||
u8 g = (*src & 0x0000ff00) >> 8;
|
||||
u8 b = *src & 0x000000ff;
|
||||
|
||||
/* ITU BT.601: Y = 0.299 R + 0.587 G + 0.114 B */
|
||||
*dst++ = (3 * r + 6 * g + b) / 10;
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
}
|
||||
EXPORT_SYMBOL(tinydrm_xrgb8888_to_gray8);
|
||||
|
||||
#if IS_ENABLED(CONFIG_SPI)
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fb_cma_helper.h>
|
||||
#include <drm/drm_gem_cma_helper.h>
|
||||
#include <drm/drm_format_helper.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
|
@ -218,12 +219,12 @@ int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb,
|
|||
switch (fb->format->format) {
|
||||
case DRM_FORMAT_RGB565:
|
||||
if (swap)
|
||||
tinydrm_swab16(dst, src, fb, clip);
|
||||
drm_fb_swab16(dst, src, fb, clip);
|
||||
else
|
||||
tinydrm_memcpy(dst, src, fb, clip);
|
||||
drm_fb_memcpy(dst, src, fb, clip);
|
||||
break;
|
||||
case DRM_FORMAT_XRGB8888:
|
||||
tinydrm_xrgb8888_to_rgb565(dst, src, fb, clip, swap);
|
||||
drm_fb_xrgb8888_to_rgb565(dst, src, fb, clip, swap);
|
||||
break;
|
||||
default:
|
||||
dev_err_once(fb->dev->dev, "Format is not supported: %s\n",
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fb_cma_helper.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_format_helper.h>
|
||||
#include <drm/drm_gem_cma_helper.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_rect.h>
|
||||
|
@ -566,7 +567,7 @@ static int repaper_fb_dirty(struct drm_framebuffer *fb)
|
|||
goto out_free;
|
||||
}
|
||||
|
||||
tinydrm_xrgb8888_to_gray8(buf, cma_obj->vaddr, fb, &clip);
|
||||
drm_fb_xrgb8888_to_gray8(buf, cma_obj->vaddr, fb, &clip);
|
||||
|
||||
if (import_attach) {
|
||||
ret = dma_buf_end_cpu_access(import_attach->dmabuf,
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fb_cma_helper.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_format_helper.h>
|
||||
#include <drm/drm_gem_cma_helper.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_rect.h>
|
||||
|
@ -77,7 +78,7 @@ static void st7586_xrgb8888_to_gray332(u8 *dst, void *vaddr,
|
|||
if (!buf)
|
||||
return;
|
||||
|
||||
tinydrm_xrgb8888_to_gray8(buf, vaddr, fb, clip);
|
||||
drm_fb_xrgb8888_to_gray8(buf, vaddr, fb, clip);
|
||||
src = buf;
|
||||
|
||||
for (y = clip->y1; y < clip->y2; y++) {
|
||||
|
|
|
@ -48,7 +48,7 @@ vc4_debugfs_init(struct drm_minor *minor)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int vc4_debugfs_regset32(struct seq_file *m, void *unused)
|
||||
static int vc4_debugfs_regset32(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *)m->private;
|
||||
struct debugfs_regset32 *regset = node->info_ent->data;
|
||||
|
|
34
include/drm/drm_format_helper.h
Normal file
34
include/drm/drm_format_helper.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Noralf Trønnes
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_DRM_FORMAT_HELPER_H
|
||||
#define __LINUX_DRM_FORMAT_HELPER_H
|
||||
|
||||
struct drm_framebuffer;
|
||||
struct drm_rect;
|
||||
|
||||
void drm_fb_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb,
|
||||
struct drm_rect *clip);
|
||||
void drm_fb_memcpy_dstclip(void *dst, void *vaddr, struct drm_framebuffer *fb,
|
||||
struct drm_rect *clip);
|
||||
void drm_fb_swab16(u16 *dst, void *vaddr, struct drm_framebuffer *fb,
|
||||
struct drm_rect *clip);
|
||||
void drm_fb_xrgb8888_to_rgb565(void *dst, void *vaddr,
|
||||
struct drm_framebuffer *fb,
|
||||
struct drm_rect *clip, bool swap);
|
||||
void drm_fb_xrgb8888_to_rgb565_dstclip(void *dst, unsigned int dst_pitch,
|
||||
void *vaddr, struct drm_framebuffer *fb,
|
||||
struct drm_rect *clip, bool swap);
|
||||
void drm_fb_xrgb8888_to_rgb888_dstclip(void *dst, unsigned int dst_pitch,
|
||||
void *vaddr, struct drm_framebuffer *fb,
|
||||
struct drm_rect *clip);
|
||||
void drm_fb_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb,
|
||||
struct drm_rect *clip);
|
||||
|
||||
#endif /* __LINUX_DRM_FORMAT_HELPER_H */
|
|
@ -46,16 +46,6 @@ int tinydrm_display_pipe_init(struct drm_device *drm,
|
|||
const struct drm_display_mode *mode,
|
||||
unsigned int rotation);
|
||||
|
||||
void tinydrm_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb,
|
||||
struct drm_rect *clip);
|
||||
void tinydrm_swab16(u16 *dst, void *vaddr, struct drm_framebuffer *fb,
|
||||
struct drm_rect *clip);
|
||||
void tinydrm_xrgb8888_to_rgb565(u16 *dst, void *vaddr,
|
||||
struct drm_framebuffer *fb,
|
||||
struct drm_rect *clip, bool swap);
|
||||
void tinydrm_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb,
|
||||
struct drm_rect *clip);
|
||||
|
||||
size_t tinydrm_spi_max_transfer_size(struct spi_device *spi, size_t max_len);
|
||||
bool tinydrm_spi_bpw_supported(struct spi_device *spi, u8 bpw);
|
||||
int tinydrm_spi_transfer(struct spi_device *spi, u32 speed_hz,
|
||||
|
|
Loading…
Reference in New Issue
Block a user