forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 431
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
drm: Add support for Amlogic Meson Graphic Controller
The Amlogic Meson Display controller is composed of several components : DMC|---------------VPU (Video Processing Unit)----------------|------HHI------| | vd1 _______ _____________ _________________ | | D |-------| |----| | | | | HDMI PLL | D | vd2 | VIU | | Video Post | | Video Encoders |<---|-----VCLK | R |-------| |----| Processing | | | | | | osd2 | | | |---| Enci ----------|----|-----VDAC------| R |-------| CSC |----| Scalers | | Encp ----------|----|----HDMI-TX----| A | osd1 | | | Blenders | | Encl ----------|----|---------------| M |-------|______|----|____________| |________________| | | ___|__________________________________________________________|_______________| VIU: Video Input Unit --------------------- The Video Input Unit is in charge of the pixel scanout from the DDR memory. It fetches the frames addresses, stride and parameters from the "Canvas" memory. This part is also in charge of the CSC (Colorspace Conversion). It can handle 2 OSD Planes and 2 Video Planes. VPP: Video Post Processing -------------------------- The Video Post Processing is in charge of the scaling and blending of the various planes into a single pixel stream. There is a special "pre-blending" used by the video planes with a dedicated scaler and a "post-blending" to merge with the OSD Planes. The OSD planes also have a dedicated scaler for one of the OSD. VENC: Video Encoders -------------------- The VENC is composed of the multiple pixel encoders : - ENCI : Interlace Video encoder for CVBS and Interlace HDMI - ENCP : Progressive Video Encoder for HDMI - ENCL : LCD LVDS Encoder The VENC Unit gets a Pixel Clocks (VCLK) from a dedicated HDMI PLL and clock tree and provides the scanout clock to the VPP and VIU. The ENCI is connected to a single VDAC for Composite Output. The ENCI and ENCP are connected to an on-chip HDMI Transceiver. This driver is a DRM/KMS driver using the following DRM components : - GEM-CMA - PRIME-CMA - Atomic Modesetting - FBDev-CMA For the following SoCs : - GXBB Family (S905) - GXL Family (S905X, S905D) - GXM Family (S912) The current driver only supports the CVBS PAL/NTSC output modes, but the CRTC/Planes management should support bigger modes. But Advanced Colorspace Conversion, Scaling and HDMI Modes will be added in a second time. The Device Tree bindings makes use of the endpoints video interface definitions to connect to the optional CVBS and in the future the HDMI Connector nodes. HDMI Support is planned for a next release. Acked-by: Daniel Vetter <[email protected]> Signed-off-by: Neil Armstrong <[email protected]>
- Loading branch information
1 parent
bc33b0c
commit bbbe775
Showing
23 changed files
with
3,876 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
config DRM_MESON | ||
tristate "DRM Support for Amlogic Meson Display Controller" | ||
depends on DRM && OF && (ARM || ARM64) | ||
depends on ARCH_MESON || COMPILE_TEST | ||
select DRM_KMS_HELPER | ||
select DRM_KMS_CMA_HELPER | ||
select DRM_GEM_CMA_HELPER | ||
select VIDEOMODE_HELPERS | ||
select REGMAP_MMIO |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
meson-y := meson_drv.o meson_plane.o meson_crtc.o meson_venc_cvbs.o | ||
meson-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_canvas.o | ||
|
||
obj-$(CONFIG_DRM_MESON) += meson.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/* | ||
* Copyright (C) 2016 BayLibre, SAS | ||
* Author: Neil Armstrong <[email protected]> | ||
* Copyright (C) 2015 Amlogic, Inc. All rights reserved. | ||
* Copyright (C) 2014 Endless Mobile | ||
* | ||
* 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. | ||
* | ||
* This program is distributed in the hope that it will be useful, but | ||
* WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
* General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#include <linux/kernel.h> | ||
#include <linux/module.h> | ||
#include "meson_drv.h" | ||
#include "meson_canvas.h" | ||
#include "meson_registers.h" | ||
|
||
/* | ||
* CANVAS is a memory zone where physical memory frames information | ||
* are stored for the VIU to scanout. | ||
*/ | ||
|
||
/* DMC Registers */ | ||
#define DMC_CAV_LUT_DATAL 0x48 /* 0x12 offset in data sheet */ | ||
#define CANVAS_WIDTH_LBIT 29 | ||
#define CANVAS_WIDTH_LWID 3 | ||
#define DMC_CAV_LUT_DATAH 0x4c /* 0x13 offset in data sheet */ | ||
#define CANVAS_WIDTH_HBIT 0 | ||
#define CANVAS_HEIGHT_BIT 9 | ||
#define CANVAS_BLKMODE_BIT 24 | ||
#define DMC_CAV_LUT_ADDR 0x50 /* 0x14 offset in data sheet */ | ||
#define CANVAS_LUT_WR_EN (0x2 << 8) | ||
#define CANVAS_LUT_RD_EN (0x1 << 8) | ||
|
||
void meson_canvas_setup(struct meson_drm *priv, | ||
uint32_t canvas_index, uint32_t addr, | ||
uint32_t stride, uint32_t height, | ||
unsigned int wrap, | ||
unsigned int blkmode) | ||
{ | ||
unsigned int val; | ||
|
||
regmap_write(priv->dmc, DMC_CAV_LUT_DATAL, | ||
(((addr + 7) >> 3)) | | ||
(((stride + 7) >> 3) << CANVAS_WIDTH_LBIT)); | ||
|
||
regmap_write(priv->dmc, DMC_CAV_LUT_DATAH, | ||
((((stride + 7) >> 3) >> CANVAS_WIDTH_LWID) << | ||
CANVAS_WIDTH_HBIT) | | ||
(height << CANVAS_HEIGHT_BIT) | | ||
(wrap << 22) | | ||
(blkmode << CANVAS_BLKMODE_BIT)); | ||
|
||
regmap_write(priv->dmc, DMC_CAV_LUT_ADDR, | ||
CANVAS_LUT_WR_EN | canvas_index); | ||
|
||
/* Force a read-back to make sure everything is flushed. */ | ||
regmap_read(priv->dmc, DMC_CAV_LUT_DATAH, &val); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/* | ||
* Copyright (C) 2016 BayLibre, SAS | ||
* Author: Neil Armstrong <[email protected]> | ||
* Copyright (C) 2014 Endless Mobile | ||
* | ||
* 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. | ||
* | ||
* This program is distributed in the hope that it will be useful, but | ||
* WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
* General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
/* Canvas LUT Memory */ | ||
|
||
#ifndef __MESON_CANVAS_H | ||
#define __MESON_CANVAS_H | ||
|
||
#define MESON_CANVAS_ID_OSD1 0x4e | ||
|
||
/* Canvas configuration. */ | ||
#define MESON_CANVAS_WRAP_NONE 0x00 | ||
#define MESON_CANVAS_WRAP_X 0x01 | ||
#define MESON_CANVAS_WRAP_Y 0x02 | ||
|
||
#define MESON_CANVAS_BLKMODE_LINEAR 0x00 | ||
#define MESON_CANVAS_BLKMODE_32x32 0x01 | ||
#define MESON_CANVAS_BLKMODE_64x64 0x02 | ||
|
||
void meson_canvas_setup(struct meson_drm *priv, | ||
uint32_t canvas_index, uint32_t addr, | ||
uint32_t stride, uint32_t height, | ||
unsigned int wrap, | ||
unsigned int blkmode); | ||
|
||
#endif /* __MESON_CANVAS_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
/* | ||
* Copyright (C) 2016 BayLibre, SAS | ||
* Author: Neil Armstrong <[email protected]> | ||
* Copyright (C) 2015 Amlogic, Inc. All rights reserved. | ||
* Copyright (C) 2014 Endless Mobile | ||
* | ||
* 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. | ||
* | ||
* This program is distributed in the hope that it will be useful, but | ||
* WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
* General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
* | ||
* Written by: | ||
* Jasper St. Pierre <[email protected]> | ||
*/ | ||
|
||
#include <linux/kernel.h> | ||
#include <linux/module.h> | ||
#include <linux/mutex.h> | ||
#include <linux/platform_device.h> | ||
#include <drm/drmP.h> | ||
#include <drm/drm_atomic.h> | ||
#include <drm/drm_atomic_helper.h> | ||
#include <drm/drm_flip_work.h> | ||
#include <drm/drm_crtc_helper.h> | ||
|
||
#include "meson_crtc.h" | ||
#include "meson_plane.h" | ||
#include "meson_vpp.h" | ||
#include "meson_viu.h" | ||
#include "meson_registers.h" | ||
|
||
/* CRTC definition */ | ||
|
||
struct meson_crtc { | ||
struct drm_crtc base; | ||
struct drm_pending_vblank_event *event; | ||
struct meson_drm *priv; | ||
}; | ||
#define to_meson_crtc(x) container_of(x, struct meson_crtc, base) | ||
|
||
/* CRTC */ | ||
|
||
static const struct drm_crtc_funcs meson_crtc_funcs = { | ||
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, | ||
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, | ||
.destroy = drm_crtc_cleanup, | ||
.page_flip = drm_atomic_helper_page_flip, | ||
.reset = drm_atomic_helper_crtc_reset, | ||
.set_config = drm_atomic_helper_set_config, | ||
}; | ||
|
||
static void meson_crtc_enable(struct drm_crtc *crtc) | ||
{ | ||
struct meson_crtc *meson_crtc = to_meson_crtc(crtc); | ||
struct drm_plane *plane = meson_crtc->priv->primary_plane; | ||
struct meson_drm *priv = meson_crtc->priv; | ||
|
||
/* Enable VPP Postblend */ | ||
writel(plane->state->crtc_w, | ||
priv->io_base + _REG(VPP_POSTBLEND_H_SIZE)); | ||
|
||
writel_bits_relaxed(VPP_POSTBLEND_ENABLE, VPP_POSTBLEND_ENABLE, | ||
priv->io_base + _REG(VPP_MISC)); | ||
|
||
priv->viu.osd1_enabled = true; | ||
} | ||
|
||
static void meson_crtc_disable(struct drm_crtc *crtc) | ||
{ | ||
struct meson_crtc *meson_crtc = to_meson_crtc(crtc); | ||
struct meson_drm *priv = meson_crtc->priv; | ||
|
||
priv->viu.osd1_enabled = false; | ||
|
||
/* Disable VPP Postblend */ | ||
writel_bits_relaxed(VPP_POSTBLEND_ENABLE, 0, | ||
priv->io_base + _REG(VPP_MISC)); | ||
|
||
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_begin(struct drm_crtc *crtc, | ||
struct drm_crtc_state *state) | ||
{ | ||
struct meson_crtc *meson_crtc = to_meson_crtc(crtc); | ||
unsigned long flags; | ||
|
||
if (crtc->state->event) { | ||
WARN_ON(drm_crtc_vblank_get(crtc) != 0); | ||
|
||
spin_lock_irqsave(&crtc->dev->event_lock, flags); | ||
meson_crtc->event = crtc->state->event; | ||
spin_unlock_irqrestore(&crtc->dev->event_lock, flags); | ||
crtc->state->event = NULL; | ||
} | ||
} | ||
|
||
static void meson_crtc_atomic_flush(struct drm_crtc *crtc, | ||
struct drm_crtc_state *old_crtc_state) | ||
{ | ||
struct meson_crtc *meson_crtc = to_meson_crtc(crtc); | ||
struct meson_drm *priv = meson_crtc->priv; | ||
|
||
if (priv->viu.osd1_enabled) | ||
priv->viu.osd1_commit = true; | ||
} | ||
|
||
static const struct drm_crtc_helper_funcs meson_crtc_helper_funcs = { | ||
.enable = meson_crtc_enable, | ||
.disable = meson_crtc_disable, | ||
.atomic_begin = meson_crtc_atomic_begin, | ||
.atomic_flush = meson_crtc_atomic_flush, | ||
}; | ||
|
||
void meson_crtc_irq(struct meson_drm *priv) | ||
{ | ||
struct meson_crtc *meson_crtc = to_meson_crtc(priv->crtc); | ||
unsigned long flags; | ||
|
||
/* Update the OSD registers */ | ||
if (priv->viu.osd1_enabled && priv->viu.osd1_commit) { | ||
writel_relaxed(priv->viu.osd1_ctrl_stat, | ||
priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); | ||
writel_relaxed(priv->viu.osd1_blk0_cfg[0], | ||
priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W0)); | ||
writel_relaxed(priv->viu.osd1_blk0_cfg[1], | ||
priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W1)); | ||
writel_relaxed(priv->viu.osd1_blk0_cfg[2], | ||
priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W2)); | ||
writel_relaxed(priv->viu.osd1_blk0_cfg[3], | ||
priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W3)); | ||
writel_relaxed(priv->viu.osd1_blk0_cfg[4], | ||
priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W4)); | ||
|
||
/* If output is interlace, make use of the Scaler */ | ||
if (priv->viu.osd1_interlace) { | ||
struct drm_plane *plane = priv->primary_plane; | ||
struct drm_plane_state *state = plane->state; | ||
struct drm_rect dest = { | ||
.x1 = state->crtc_x, | ||
.y1 = state->crtc_y, | ||
.x2 = state->crtc_x + state->crtc_w, | ||
.y2 = state->crtc_y + state->crtc_h, | ||
}; | ||
|
||
meson_vpp_setup_interlace_vscaler_osd1(priv, &dest); | ||
} else | ||
meson_vpp_disable_interlace_vscaler_osd1(priv); | ||
|
||
/* Enable OSD1 */ | ||
writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND, | ||
priv->io_base + _REG(VPP_MISC)); | ||
|
||
priv->viu.osd1_commit = false; | ||
} | ||
|
||
drm_crtc_handle_vblank(priv->crtc); | ||
|
||
spin_lock_irqsave(&priv->drm->event_lock, flags); | ||
if (meson_crtc->event) { | ||
drm_crtc_send_vblank_event(priv->crtc, meson_crtc->event); | ||
drm_crtc_vblank_put(priv->crtc); | ||
meson_crtc->event = NULL; | ||
} | ||
spin_unlock_irqrestore(&priv->drm->event_lock, flags); | ||
} | ||
|
||
int meson_crtc_create(struct meson_drm *priv) | ||
{ | ||
struct meson_crtc *meson_crtc; | ||
struct drm_crtc *crtc; | ||
int ret; | ||
|
||
meson_crtc = devm_kzalloc(priv->drm->dev, sizeof(*meson_crtc), | ||
GFP_KERNEL); | ||
if (!meson_crtc) | ||
return -ENOMEM; | ||
|
||
meson_crtc->priv = priv; | ||
crtc = &meson_crtc->base; | ||
ret = drm_crtc_init_with_planes(priv->drm, crtc, | ||
priv->primary_plane, NULL, | ||
&meson_crtc_funcs, "meson_crtc"); | ||
if (ret) { | ||
dev_err(priv->drm->dev, "Failed to init CRTC\n"); | ||
return ret; | ||
} | ||
|
||
drm_crtc_helper_add(crtc, &meson_crtc_helper_funcs); | ||
|
||
priv->crtc = crtc; | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/* | ||
* Copyright (C) 2016 BayLibre, SAS | ||
* Author: Neil Armstrong <[email protected]> | ||
* Copyright (C) 2014 Endless Mobile | ||
* | ||
* 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. | ||
* | ||
* This program is distributed in the hope that it will be useful, but | ||
* WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
* General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
* | ||
* Written by: | ||
* Jasper St. Pierre <[email protected]> | ||
*/ | ||
|
||
#ifndef __MESON_CRTC_H | ||
#define __MESON_CRTC_H | ||
|
||
#include "meson_drv.h" | ||
|
||
int meson_crtc_create(struct meson_drm *priv); | ||
|
||
void meson_crtc_irq(struct meson_drm *priv); | ||
|
||
#endif /* __MESON_CRTC_H */ |
Oops, something went wrong.