Merge tag 'drm-misc-next-2018-04-26' of git://anongit.freedesktop.org/drm/drm-misc into drm-next
drm-misc-next for v4.18: UAPI Changes: - Add support for a generic plane alpha property to sun4i, rcar-du and atmel-hclcdc. (Maxime) Core Changes: - Stop looking at legacy plane->fb and crtc members in atomic drivers. (Ville) - mode_valid return type fixes. (Luc) - Handle zpos normalization in the core. (Peter) Driver Changes: - Implement CTM, plane alpha and generic async cursor support in vc4. (Stefan) - Various fixes for HPD and aux chan in drm_bridge/analogix_dp. (Lin, Zain, Douglas) - Add support for MIPI DSI to sun4i. (Maxime) Signed-off-by: Dave Airlie <airlied@redhat.com> # gpg: Signature made Thu 26 Apr 2018 08:21:01 PM AEST # gpg: using RSA key FE558C72A67013C3 # gpg: Can't check signature: public key not found Link: https://patchwork.freedesktop.org/patch/msgid/b33da7eb-efc9-ae6f-6f69-b7acd6df6797@mblankhorst.nl
Dieser Commit ist enthalten in:
@@ -40,6 +40,16 @@ config DRM_SUN4I_BACKEND
|
||||
do some alpha blending and feed graphics to TCON. If M is
|
||||
selected the module will be called sun4i-backend.
|
||||
|
||||
config DRM_SUN6I_DSI
|
||||
tristate "Allwinner A31 MIPI-DSI Controller Support"
|
||||
default MACH_SUN8I
|
||||
select CRC_CCITT
|
||||
select DRM_MIPI_DSI
|
||||
help
|
||||
Choose this option if you want have an Allwinner SoC with
|
||||
MIPI-DSI support. If M is selected the module will be called
|
||||
sun6i-dsi
|
||||
|
||||
config DRM_SUN8I_DW_HDMI
|
||||
tristate "Support for Allwinner version of DesignWare HDMI"
|
||||
depends on DRM_SUN4I
|
||||
|
@@ -24,6 +24,9 @@ sun4i-tcon-y += sun4i_lvds.o
|
||||
sun4i-tcon-y += sun4i_tcon.o
|
||||
sun4i-tcon-y += sun4i_rgb.o
|
||||
|
||||
sun6i-dsi-y += sun6i_mipi_dphy.o
|
||||
sun6i-dsi-y += sun6i_mipi_dsi.o
|
||||
|
||||
obj-$(CONFIG_DRM_SUN4I) += sun4i-drm.o
|
||||
obj-$(CONFIG_DRM_SUN4I) += sun4i-tcon.o
|
||||
obj-$(CONFIG_DRM_SUN4I) += sun4i_tv.o
|
||||
@@ -31,5 +34,6 @@ obj-$(CONFIG_DRM_SUN4I) += sun6i_drc.o
|
||||
|
||||
obj-$(CONFIG_DRM_SUN4I_BACKEND) += sun4i-backend.o sun4i-frontend.o
|
||||
obj-$(CONFIG_DRM_SUN4I_HDMI) += sun4i-drm-hdmi.o
|
||||
obj-$(CONFIG_DRM_SUN6I_DSI) += sun6i-dsi.o
|
||||
obj-$(CONFIG_DRM_SUN8I_DW_HDMI) += sun8i-drm-hdmi.o
|
||||
obj-$(CONFIG_DRM_SUN8I_MIXER) += sun8i-mixer.o
|
||||
|
@@ -295,6 +295,15 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
|
||||
DRM_DEBUG_DRIVER("Switching display backend interlaced mode %s\n",
|
||||
interlaced ? "on" : "off");
|
||||
|
||||
val = SUN4I_BACKEND_ATTCTL_REG0_LAY_GLBALPHA(state->alpha >> 8);
|
||||
if (state->alpha != DRM_BLEND_ALPHA_OPAQUE)
|
||||
val |= SUN4I_BACKEND_ATTCTL_REG0_LAY_GLBALPHA_EN;
|
||||
regmap_update_bits(backend->engine.regs,
|
||||
SUN4I_BACKEND_ATTCTL_REG0(layer),
|
||||
SUN4I_BACKEND_ATTCTL_REG0_LAY_GLBALPHA_MASK |
|
||||
SUN4I_BACKEND_ATTCTL_REG0_LAY_GLBALPHA_EN,
|
||||
val);
|
||||
|
||||
if (sun4i_backend_format_is_yuv(fb->format->format))
|
||||
return sun4i_backend_update_yuv_format(backend, layer, plane);
|
||||
|
||||
@@ -490,7 +499,7 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
|
||||
DRM_DEBUG_DRIVER("Plane FB format is %s\n",
|
||||
drm_get_format_name(fb->format->format,
|
||||
&format_name));
|
||||
if (fb->format->has_alpha)
|
||||
if (fb->format->has_alpha || (plane_state->alpha != DRM_BLEND_ALPHA_OPAQUE))
|
||||
num_alpha_planes++;
|
||||
|
||||
if (sun4i_backend_format_is_yuv(fb->format->format)) {
|
||||
@@ -548,7 +557,8 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
|
||||
}
|
||||
|
||||
/* We can't have an alpha plane at the lowest position */
|
||||
if (plane_states[0]->fb->format->has_alpha)
|
||||
if (plane_states[0]->fb->format->has_alpha ||
|
||||
(plane_states[0]->alpha != DRM_BLEND_ALPHA_OPAQUE))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 1; i < num_planes; i++) {
|
||||
@@ -560,7 +570,7 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
|
||||
* The only alpha position is the lowest plane of the
|
||||
* second pipe.
|
||||
*/
|
||||
if (fb->format->has_alpha)
|
||||
if (fb->format->has_alpha || (p_state->alpha != DRM_BLEND_ALPHA_OPAQUE))
|
||||
current_pipe++;
|
||||
|
||||
s_state->pipe = current_pipe;
|
||||
|
@@ -68,12 +68,15 @@
|
||||
#define SUN4I_BACKEND_CKMIN_REG 0x884
|
||||
#define SUN4I_BACKEND_CKCFG_REG 0x888
|
||||
#define SUN4I_BACKEND_ATTCTL_REG0(l) (0x890 + (0x4 * (l)))
|
||||
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_GLBALPHA_MASK GENMASK(31, 24)
|
||||
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_GLBALPHA(x) ((x) << 24)
|
||||
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK BIT(15)
|
||||
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(x) ((x) << 15)
|
||||
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK GENMASK(11, 10)
|
||||
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(x) ((x) << 10)
|
||||
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN BIT(2)
|
||||
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN BIT(1)
|
||||
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_GLBALPHA_EN BIT(0)
|
||||
|
||||
#define SUN4I_BACKEND_ATTCTL_REG1(l) (0x8a0 + (0x4 * (l)))
|
||||
#define SUN4I_BACKEND_ATTCTL_REG1_LAY_HSCAFCT GENMASK(15, 14)
|
||||
|
@@ -37,6 +37,7 @@ static void sun4i_backend_layer_reset(struct drm_plane *plane)
|
||||
if (state) {
|
||||
plane->state = &state->state;
|
||||
plane->state->plane = plane;
|
||||
plane->state->alpha = DRM_BLEND_ALPHA_OPAQUE;
|
||||
plane->state->zpos = layer->id;
|
||||
}
|
||||
}
|
||||
@@ -167,6 +168,7 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
|
||||
&sun4i_backend_layer_helper_funcs);
|
||||
layer->backend = backend;
|
||||
|
||||
drm_plane_create_alpha_property(&layer->plane);
|
||||
drm_plane_create_zpos_property(&layer->plane, 0, 0,
|
||||
SUN4I_BACKEND_NUM_LAYERS - 1);
|
||||
|
||||
|
@@ -35,6 +35,7 @@
|
||||
#include "sun4i_lvds.h"
|
||||
#include "sun4i_rgb.h"
|
||||
#include "sun4i_tcon.h"
|
||||
#include "sun6i_mipi_dsi.h"
|
||||
#include "sunxi_engine.h"
|
||||
|
||||
static struct drm_connector *sun4i_tcon_get_connector(const struct drm_encoder *encoder)
|
||||
@@ -169,6 +170,7 @@ void sun4i_tcon_set_status(struct sun4i_tcon *tcon,
|
||||
case DRM_MODE_ENCODER_LVDS:
|
||||
is_lvds = true;
|
||||
/* Fallthrough */
|
||||
case DRM_MODE_ENCODER_DSI:
|
||||
case DRM_MODE_ENCODER_NONE:
|
||||
channel = 0;
|
||||
break;
|
||||
@@ -201,7 +203,8 @@ void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable)
|
||||
DRM_DEBUG_DRIVER("%sabling VBLANK interrupt\n", enable ? "En" : "Dis");
|
||||
|
||||
mask = SUN4I_TCON_GINT0_VBLANK_ENABLE(0) |
|
||||
SUN4I_TCON_GINT0_VBLANK_ENABLE(1);
|
||||
SUN4I_TCON_GINT0_VBLANK_ENABLE(1) |
|
||||
SUN4I_TCON_GINT0_TCON0_TRI_FINISH_ENABLE;
|
||||
|
||||
if (enable)
|
||||
val = mask;
|
||||
@@ -273,6 +276,71 @@ static void sun4i_tcon0_mode_set_common(struct sun4i_tcon *tcon,
|
||||
SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
|
||||
}
|
||||
|
||||
static void sun4i_tcon0_mode_set_cpu(struct sun4i_tcon *tcon,
|
||||
struct mipi_dsi_device *device,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
u8 bpp = mipi_dsi_pixel_format_to_bpp(device->format);
|
||||
u8 lanes = device->lanes;
|
||||
u32 block_space, start_delay;
|
||||
u32 tcon_div;
|
||||
|
||||
tcon->dclk_min_div = 4;
|
||||
tcon->dclk_max_div = 127;
|
||||
|
||||
sun4i_tcon0_mode_set_common(tcon, mode);
|
||||
|
||||
regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
|
||||
SUN4I_TCON0_CTL_IF_MASK,
|
||||
SUN4I_TCON0_CTL_IF_8080);
|
||||
|
||||
regmap_write(tcon->regs, SUN4I_TCON_ECC_FIFO_REG,
|
||||
SUN4I_TCON_ECC_FIFO_EN);
|
||||
|
||||
regmap_write(tcon->regs, SUN4I_TCON0_CPU_IF_REG,
|
||||
SUN4I_TCON0_CPU_IF_MODE_DSI |
|
||||
SUN4I_TCON0_CPU_IF_TRI_FIFO_FLUSH |
|
||||
SUN4I_TCON0_CPU_IF_TRI_FIFO_EN |
|
||||
SUN4I_TCON0_CPU_IF_TRI_EN);
|
||||
|
||||
/*
|
||||
* This looks suspicious, but it works...
|
||||
*
|
||||
* The datasheet says that this should be set higher than 20 *
|
||||
* pixel cycle, but it's not clear what a pixel cycle is.
|
||||
*/
|
||||
regmap_read(tcon->regs, SUN4I_TCON0_DCLK_REG, &tcon_div);
|
||||
tcon_div &= GENMASK(6, 0);
|
||||
block_space = mode->htotal * bpp / (tcon_div * lanes);
|
||||
block_space -= mode->hdisplay + 40;
|
||||
|
||||
regmap_write(tcon->regs, SUN4I_TCON0_CPU_TRI0_REG,
|
||||
SUN4I_TCON0_CPU_TRI0_BLOCK_SPACE(block_space) |
|
||||
SUN4I_TCON0_CPU_TRI0_BLOCK_SIZE(mode->hdisplay));
|
||||
|
||||
regmap_write(tcon->regs, SUN4I_TCON0_CPU_TRI1_REG,
|
||||
SUN4I_TCON0_CPU_TRI1_BLOCK_NUM(mode->vdisplay));
|
||||
|
||||
start_delay = (mode->crtc_vtotal - mode->crtc_vdisplay - 10 - 1);
|
||||
start_delay = start_delay * mode->crtc_htotal * 149;
|
||||
start_delay = start_delay / (mode->crtc_clock / 1000) / 8;
|
||||
regmap_write(tcon->regs, SUN4I_TCON0_CPU_TRI2_REG,
|
||||
SUN4I_TCON0_CPU_TRI2_TRANS_START_SET(10) |
|
||||
SUN4I_TCON0_CPU_TRI2_START_DELAY(start_delay));
|
||||
|
||||
/*
|
||||
* The Allwinner BSP has a comment that the period should be
|
||||
* the display clock * 15, but uses an hardcoded 3000...
|
||||
*/
|
||||
regmap_write(tcon->regs, SUN4I_TCON_SAFE_PERIOD_REG,
|
||||
SUN4I_TCON_SAFE_PERIOD_NUM(3000) |
|
||||
SUN4I_TCON_SAFE_PERIOD_MODE(3));
|
||||
|
||||
/* Enable the output on the pins */
|
||||
regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG,
|
||||
0xe0000000);
|
||||
}
|
||||
|
||||
static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon,
|
||||
const struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode)
|
||||
@@ -538,7 +606,17 @@ void sun4i_tcon_mode_set(struct sun4i_tcon *tcon,
|
||||
const struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct sun6i_dsi *dsi;
|
||||
|
||||
switch (encoder->encoder_type) {
|
||||
case DRM_MODE_ENCODER_DSI:
|
||||
/*
|
||||
* This is not really elegant, but it's the "cleaner"
|
||||
* way I could think of...
|
||||
*/
|
||||
dsi = encoder_to_sun6i_dsi(encoder);
|
||||
sun4i_tcon0_mode_set_cpu(tcon, dsi->device, mode);
|
||||
break;
|
||||
case DRM_MODE_ENCODER_LVDS:
|
||||
sun4i_tcon0_mode_set_lvds(tcon, encoder, mode);
|
||||
break;
|
||||
@@ -582,7 +660,8 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private)
|
||||
regmap_read(tcon->regs, SUN4I_TCON_GINT0_REG, &status);
|
||||
|
||||
if (!(status & (SUN4I_TCON_GINT0_VBLANK_INT(0) |
|
||||
SUN4I_TCON_GINT0_VBLANK_INT(1))))
|
||||
SUN4I_TCON_GINT0_VBLANK_INT(1) |
|
||||
SUN4I_TCON_GINT0_TCON0_TRI_FINISH_INT)))
|
||||
return IRQ_NONE;
|
||||
|
||||
drm_crtc_handle_vblank(&scrtc->crtc);
|
||||
@@ -591,7 +670,8 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private)
|
||||
/* Acknowledge the interrupt */
|
||||
regmap_update_bits(tcon->regs, SUN4I_TCON_GINT0_REG,
|
||||
SUN4I_TCON_GINT0_VBLANK_INT(0) |
|
||||
SUN4I_TCON_GINT0_VBLANK_INT(1),
|
||||
SUN4I_TCON_GINT0_VBLANK_INT(1) |
|
||||
SUN4I_TCON_GINT0_TCON0_TRI_FINISH_INT,
|
||||
0);
|
||||
|
||||
if (engine->ops->vblank_quirk)
|
||||
|
@@ -28,13 +28,32 @@
|
||||
|
||||
#define SUN4I_TCON_GINT0_REG 0x4
|
||||
#define SUN4I_TCON_GINT0_VBLANK_ENABLE(pipe) BIT(31 - (pipe))
|
||||
#define SUN4I_TCON_GINT0_TCON0_TRI_FINISH_ENABLE BIT(27)
|
||||
#define SUN4I_TCON_GINT0_TCON0_TRI_COUNTER_ENABLE BIT(26)
|
||||
#define SUN4I_TCON_GINT0_VBLANK_INT(pipe) BIT(15 - (pipe))
|
||||
#define SUN4I_TCON_GINT0_TCON0_TRI_FINISH_INT BIT(11)
|
||||
#define SUN4I_TCON_GINT0_TCON0_TRI_COUNTER_INT BIT(10)
|
||||
|
||||
#define SUN4I_TCON_GINT1_REG 0x8
|
||||
|
||||
#define SUN4I_TCON_FRM_CTL_REG 0x10
|
||||
#define SUN4I_TCON_FRM_CTL_EN BIT(31)
|
||||
|
||||
#define SUN4I_TCON_FRM_SEED_PR_REG 0x14
|
||||
#define SUN4I_TCON_FRM_SEED_PG_REG 0x18
|
||||
#define SUN4I_TCON_FRM_SEED_PB_REG 0x1c
|
||||
#define SUN4I_TCON_FRM_SEED_LR_REG 0x20
|
||||
#define SUN4I_TCON_FRM_SEED_LG_REG 0x24
|
||||
#define SUN4I_TCON_FRM_SEED_LB_REG 0x28
|
||||
#define SUN4I_TCON_FRM_TBL0_REG 0x2c
|
||||
#define SUN4I_TCON_FRM_TBL1_REG 0x30
|
||||
#define SUN4I_TCON_FRM_TBL2_REG 0x34
|
||||
#define SUN4I_TCON_FRM_TBL3_REG 0x38
|
||||
|
||||
#define SUN4I_TCON0_CTL_REG 0x40
|
||||
#define SUN4I_TCON0_CTL_TCON_ENABLE BIT(31)
|
||||
#define SUN4I_TCON0_CTL_IF_MASK GENMASK(25, 24)
|
||||
#define SUN4I_TCON0_CTL_IF_8080 (1 << 24)
|
||||
#define SUN4I_TCON0_CTL_CLK_DELAY_MASK GENMASK(8, 4)
|
||||
#define SUN4I_TCON0_CTL_CLK_DELAY(delay) ((delay << 4) & SUN4I_TCON0_CTL_CLK_DELAY_MASK)
|
||||
#define SUN4I_TCON0_CTL_SRC_SEL_MASK GENMASK(2, 0)
|
||||
@@ -61,7 +80,14 @@
|
||||
#define SUN4I_TCON0_BASIC3_V_SYNC(height) (((height) - 1) & 0x7ff)
|
||||
|
||||
#define SUN4I_TCON0_HV_IF_REG 0x58
|
||||
|
||||
#define SUN4I_TCON0_CPU_IF_REG 0x60
|
||||
#define SUN4I_TCON0_CPU_IF_MODE_MASK GENMASK(31, 28)
|
||||
#define SUN4I_TCON0_CPU_IF_MODE_DSI (1 << 28)
|
||||
#define SUN4I_TCON0_CPU_IF_TRI_FIFO_FLUSH BIT(16)
|
||||
#define SUN4I_TCON0_CPU_IF_TRI_FIFO_EN BIT(2)
|
||||
#define SUN4I_TCON0_CPU_IF_TRI_EN BIT(0)
|
||||
|
||||
#define SUN4I_TCON0_CPU_WR_REG 0x64
|
||||
#define SUN4I_TCON0_CPU_RD0_REG 0x68
|
||||
#define SUN4I_TCON0_CPU_RDA_REG 0x6c
|
||||
@@ -128,6 +154,10 @@
|
||||
|
||||
#define SUN4I_TCON1_IO_POL_REG 0xf0
|
||||
#define SUN4I_TCON1_IO_TRI_REG 0xf4
|
||||
|
||||
#define SUN4I_TCON_ECC_FIFO_REG 0xf8
|
||||
#define SUN4I_TCON_ECC_FIFO_EN BIT(3)
|
||||
|
||||
#define SUN4I_TCON_CEU_CTL_REG 0x100
|
||||
#define SUN4I_TCON_CEU_MUL_RR_REG 0x110
|
||||
#define SUN4I_TCON_CEU_MUL_RG_REG 0x114
|
||||
@@ -144,6 +174,22 @@
|
||||
#define SUN4I_TCON_CEU_RANGE_R_REG 0x140
|
||||
#define SUN4I_TCON_CEU_RANGE_G_REG 0x144
|
||||
#define SUN4I_TCON_CEU_RANGE_B_REG 0x148
|
||||
|
||||
#define SUN4I_TCON0_CPU_TRI0_REG 0x160
|
||||
#define SUN4I_TCON0_CPU_TRI0_BLOCK_SPACE(space) ((((space) - 1) & 0xfff) << 16)
|
||||
#define SUN4I_TCON0_CPU_TRI0_BLOCK_SIZE(size) (((size) - 1) & 0xfff)
|
||||
|
||||
#define SUN4I_TCON0_CPU_TRI1_REG 0x164
|
||||
#define SUN4I_TCON0_CPU_TRI1_BLOCK_NUM(num) (((num) - 1) & 0xffff)
|
||||
|
||||
#define SUN4I_TCON0_CPU_TRI2_REG 0x168
|
||||
#define SUN4I_TCON0_CPU_TRI2_START_DELAY(delay) (((delay) & 0xffff) << 16)
|
||||
#define SUN4I_TCON0_CPU_TRI2_TRANS_START_SET(set) ((set) & 0xfff)
|
||||
|
||||
#define SUN4I_TCON_SAFE_PERIOD_REG 0x1f0
|
||||
#define SUN4I_TCON_SAFE_PERIOD_NUM(num) (((num) & 0xfff) << 16)
|
||||
#define SUN4I_TCON_SAFE_PERIOD_MODE(mode) ((mode) & 0x3)
|
||||
|
||||
#define SUN4I_TCON_MUX_CTRL_REG 0x200
|
||||
|
||||
#define SUN4I_TCON0_LVDS_ANA0_REG 0x220
|
||||
|
292
drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c
Normale Datei
292
drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c
Normale Datei
@@ -0,0 +1,292 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2016 Allwinnertech Co., Ltd.
|
||||
* Copyright (C) 2017-2018 Bootlin
|
||||
*
|
||||
* Maxime Ripard <maxime.ripard@free-electrons.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include "sun6i_mipi_dsi.h"
|
||||
|
||||
#define SUN6I_DPHY_GCTL_REG 0x00
|
||||
#define SUN6I_DPHY_GCTL_LANE_NUM(n) ((((n) - 1) & 3) << 4)
|
||||
#define SUN6I_DPHY_GCTL_EN BIT(0)
|
||||
|
||||
#define SUN6I_DPHY_TX_CTL_REG 0x04
|
||||
#define SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT BIT(28)
|
||||
|
||||
#define SUN6I_DPHY_TX_TIME0_REG 0x10
|
||||
#define SUN6I_DPHY_TX_TIME0_HS_TRAIL(n) (((n) & 0xff) << 24)
|
||||
#define SUN6I_DPHY_TX_TIME0_HS_PREPARE(n) (((n) & 0xff) << 16)
|
||||
#define SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(n) ((n) & 0xff)
|
||||
|
||||
#define SUN6I_DPHY_TX_TIME1_REG 0x14
|
||||
#define SUN6I_DPHY_TX_TIME1_CLK_POST(n) (((n) & 0xff) << 24)
|
||||
#define SUN6I_DPHY_TX_TIME1_CLK_PRE(n) (((n) & 0xff) << 16)
|
||||
#define SUN6I_DPHY_TX_TIME1_CLK_ZERO(n) (((n) & 0xff) << 8)
|
||||
#define SUN6I_DPHY_TX_TIME1_CLK_PREPARE(n) ((n) & 0xff)
|
||||
|
||||
#define SUN6I_DPHY_TX_TIME2_REG 0x18
|
||||
#define SUN6I_DPHY_TX_TIME2_CLK_TRAIL(n) ((n) & 0xff)
|
||||
|
||||
#define SUN6I_DPHY_TX_TIME3_REG 0x1c
|
||||
|
||||
#define SUN6I_DPHY_TX_TIME4_REG 0x20
|
||||
#define SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(n) (((n) & 0xff) << 8)
|
||||
#define SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(n) ((n) & 0xff)
|
||||
|
||||
#define SUN6I_DPHY_ANA0_REG 0x4c
|
||||
#define SUN6I_DPHY_ANA0_REG_PWS BIT(31)
|
||||
#define SUN6I_DPHY_ANA0_REG_DMPC BIT(28)
|
||||
#define SUN6I_DPHY_ANA0_REG_DMPD(n) (((n) & 0xf) << 24)
|
||||
#define SUN6I_DPHY_ANA0_REG_SLV(n) (((n) & 7) << 12)
|
||||
#define SUN6I_DPHY_ANA0_REG_DEN(n) (((n) & 0xf) << 8)
|
||||
|
||||
#define SUN6I_DPHY_ANA1_REG 0x50
|
||||
#define SUN6I_DPHY_ANA1_REG_VTTMODE BIT(31)
|
||||
#define SUN6I_DPHY_ANA1_REG_CSMPS(n) (((n) & 3) << 28)
|
||||
#define SUN6I_DPHY_ANA1_REG_SVTT(n) (((n) & 0xf) << 24)
|
||||
|
||||
#define SUN6I_DPHY_ANA2_REG 0x54
|
||||
#define SUN6I_DPHY_ANA2_EN_P2S_CPU(n) (((n) & 0xf) << 24)
|
||||
#define SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK GENMASK(27, 24)
|
||||
#define SUN6I_DPHY_ANA2_EN_CK_CPU BIT(4)
|
||||
#define SUN6I_DPHY_ANA2_REG_ENIB BIT(1)
|
||||
|
||||
#define SUN6I_DPHY_ANA3_REG 0x58
|
||||
#define SUN6I_DPHY_ANA3_EN_VTTD(n) (((n) & 0xf) << 28)
|
||||
#define SUN6I_DPHY_ANA3_EN_VTTD_MASK GENMASK(31, 28)
|
||||
#define SUN6I_DPHY_ANA3_EN_VTTC BIT(27)
|
||||
#define SUN6I_DPHY_ANA3_EN_DIV BIT(26)
|
||||
#define SUN6I_DPHY_ANA3_EN_LDOC BIT(25)
|
||||
#define SUN6I_DPHY_ANA3_EN_LDOD BIT(24)
|
||||
#define SUN6I_DPHY_ANA3_EN_LDOR BIT(18)
|
||||
|
||||
#define SUN6I_DPHY_ANA4_REG 0x5c
|
||||
#define SUN6I_DPHY_ANA4_REG_DMPLVC BIT(24)
|
||||
#define SUN6I_DPHY_ANA4_REG_DMPLVD(n) (((n) & 0xf) << 20)
|
||||
#define SUN6I_DPHY_ANA4_REG_CKDV(n) (((n) & 0x1f) << 12)
|
||||
#define SUN6I_DPHY_ANA4_REG_TMSC(n) (((n) & 3) << 10)
|
||||
#define SUN6I_DPHY_ANA4_REG_TMSD(n) (((n) & 3) << 8)
|
||||
#define SUN6I_DPHY_ANA4_REG_TXDNSC(n) (((n) & 3) << 6)
|
||||
#define SUN6I_DPHY_ANA4_REG_TXDNSD(n) (((n) & 3) << 4)
|
||||
#define SUN6I_DPHY_ANA4_REG_TXPUSC(n) (((n) & 3) << 2)
|
||||
#define SUN6I_DPHY_ANA4_REG_TXPUSD(n) ((n) & 3)
|
||||
|
||||
#define SUN6I_DPHY_DBG5_REG 0xf4
|
||||
|
||||
int sun6i_dphy_init(struct sun6i_dphy *dphy, unsigned int lanes)
|
||||
{
|
||||
reset_control_deassert(dphy->reset);
|
||||
clk_prepare_enable(dphy->mod_clk);
|
||||
clk_set_rate_exclusive(dphy->mod_clk, 150000000);
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_TX_CTL_REG,
|
||||
SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT);
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME0_REG,
|
||||
SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(14) |
|
||||
SUN6I_DPHY_TX_TIME0_HS_PREPARE(6) |
|
||||
SUN6I_DPHY_TX_TIME0_HS_TRAIL(10));
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME1_REG,
|
||||
SUN6I_DPHY_TX_TIME1_CLK_PREPARE(7) |
|
||||
SUN6I_DPHY_TX_TIME1_CLK_ZERO(50) |
|
||||
SUN6I_DPHY_TX_TIME1_CLK_PRE(3) |
|
||||
SUN6I_DPHY_TX_TIME1_CLK_POST(10));
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME2_REG,
|
||||
SUN6I_DPHY_TX_TIME2_CLK_TRAIL(30));
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME3_REG, 0);
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME4_REG,
|
||||
SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(3) |
|
||||
SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(3));
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG,
|
||||
SUN6I_DPHY_GCTL_LANE_NUM(lanes) |
|
||||
SUN6I_DPHY_GCTL_EN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sun6i_dphy_power_on(struct sun6i_dphy *dphy, unsigned int lanes)
|
||||
{
|
||||
u8 lanes_mask = GENMASK(lanes - 1, 0);
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG,
|
||||
SUN6I_DPHY_ANA0_REG_PWS |
|
||||
SUN6I_DPHY_ANA0_REG_DMPC |
|
||||
SUN6I_DPHY_ANA0_REG_SLV(7) |
|
||||
SUN6I_DPHY_ANA0_REG_DMPD(lanes_mask) |
|
||||
SUN6I_DPHY_ANA0_REG_DEN(lanes_mask));
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG,
|
||||
SUN6I_DPHY_ANA1_REG_CSMPS(1) |
|
||||
SUN6I_DPHY_ANA1_REG_SVTT(7));
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG,
|
||||
SUN6I_DPHY_ANA4_REG_CKDV(1) |
|
||||
SUN6I_DPHY_ANA4_REG_TMSC(1) |
|
||||
SUN6I_DPHY_ANA4_REG_TMSD(1) |
|
||||
SUN6I_DPHY_ANA4_REG_TXDNSC(1) |
|
||||
SUN6I_DPHY_ANA4_REG_TXDNSD(1) |
|
||||
SUN6I_DPHY_ANA4_REG_TXPUSC(1) |
|
||||
SUN6I_DPHY_ANA4_REG_TXPUSD(1) |
|
||||
SUN6I_DPHY_ANA4_REG_DMPLVC |
|
||||
SUN6I_DPHY_ANA4_REG_DMPLVD(lanes_mask));
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG,
|
||||
SUN6I_DPHY_ANA2_REG_ENIB);
|
||||
udelay(5);
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG,
|
||||
SUN6I_DPHY_ANA3_EN_LDOR |
|
||||
SUN6I_DPHY_ANA3_EN_LDOC |
|
||||
SUN6I_DPHY_ANA3_EN_LDOD);
|
||||
udelay(1);
|
||||
|
||||
regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG,
|
||||
SUN6I_DPHY_ANA3_EN_VTTC |
|
||||
SUN6I_DPHY_ANA3_EN_VTTD_MASK,
|
||||
SUN6I_DPHY_ANA3_EN_VTTC |
|
||||
SUN6I_DPHY_ANA3_EN_VTTD(lanes_mask));
|
||||
udelay(1);
|
||||
|
||||
regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG,
|
||||
SUN6I_DPHY_ANA3_EN_DIV,
|
||||
SUN6I_DPHY_ANA3_EN_DIV);
|
||||
udelay(1);
|
||||
|
||||
regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG,
|
||||
SUN6I_DPHY_ANA2_EN_CK_CPU,
|
||||
SUN6I_DPHY_ANA2_EN_CK_CPU);
|
||||
udelay(1);
|
||||
|
||||
regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG,
|
||||
SUN6I_DPHY_ANA1_REG_VTTMODE,
|
||||
SUN6I_DPHY_ANA1_REG_VTTMODE);
|
||||
|
||||
regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG,
|
||||
SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK,
|
||||
SUN6I_DPHY_ANA2_EN_P2S_CPU(lanes_mask));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sun6i_dphy_power_off(struct sun6i_dphy *dphy)
|
||||
{
|
||||
regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG,
|
||||
SUN6I_DPHY_ANA1_REG_VTTMODE, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sun6i_dphy_exit(struct sun6i_dphy *dphy)
|
||||
{
|
||||
clk_rate_exclusive_put(dphy->mod_clk);
|
||||
clk_disable_unprepare(dphy->mod_clk);
|
||||
reset_control_assert(dphy->reset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct regmap_config sun6i_dphy_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.max_register = SUN6I_DPHY_DBG5_REG,
|
||||
.name = "mipi-dphy",
|
||||
};
|
||||
|
||||
static const struct of_device_id sun6i_dphy_of_table[] = {
|
||||
{ .compatible = "allwinner,sun6i-a31-mipi-dphy" },
|
||||
{ }
|
||||
};
|
||||
|
||||
int sun6i_dphy_probe(struct sun6i_dsi *dsi, struct device_node *node)
|
||||
{
|
||||
struct sun6i_dphy *dphy;
|
||||
struct resource res;
|
||||
void __iomem *regs;
|
||||
int ret;
|
||||
|
||||
if (!of_match_node(sun6i_dphy_of_table, node)) {
|
||||
dev_err(dsi->dev, "Incompatible D-PHY\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dphy = devm_kzalloc(dsi->dev, sizeof(*dphy), GFP_KERNEL);
|
||||
if (!dphy)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = of_address_to_resource(node, 0, &res);
|
||||
if (ret) {
|
||||
dev_err(dsi->dev, "phy: Couldn't get our resources\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
regs = devm_ioremap_resource(dsi->dev, &res);
|
||||
if (IS_ERR(regs)) {
|
||||
dev_err(dsi->dev, "Couldn't map the DPHY encoder registers\n");
|
||||
return PTR_ERR(regs);
|
||||
}
|
||||
|
||||
dphy->regs = devm_regmap_init_mmio(dsi->dev, regs,
|
||||
&sun6i_dphy_regmap_config);
|
||||
if (IS_ERR(dphy->regs)) {
|
||||
dev_err(dsi->dev, "Couldn't create the DPHY encoder regmap\n");
|
||||
return PTR_ERR(dphy->regs);
|
||||
}
|
||||
|
||||
dphy->reset = of_reset_control_get_shared(node, NULL);
|
||||
if (IS_ERR(dphy->reset)) {
|
||||
dev_err(dsi->dev, "Couldn't get our reset line\n");
|
||||
return PTR_ERR(dphy->reset);
|
||||
}
|
||||
|
||||
dphy->bus_clk = of_clk_get_by_name(node, "bus");
|
||||
if (IS_ERR(dphy->bus_clk)) {
|
||||
dev_err(dsi->dev, "Couldn't get the DPHY bus clock\n");
|
||||
ret = PTR_ERR(dphy->bus_clk);
|
||||
goto err_free_reset;
|
||||
}
|
||||
regmap_mmio_attach_clk(dphy->regs, dphy->bus_clk);
|
||||
|
||||
dphy->mod_clk = of_clk_get_by_name(node, "mod");
|
||||
if (IS_ERR(dphy->mod_clk)) {
|
||||
dev_err(dsi->dev, "Couldn't get the DPHY mod clock\n");
|
||||
ret = PTR_ERR(dphy->mod_clk);
|
||||
goto err_free_bus;
|
||||
}
|
||||
|
||||
dsi->dphy = dphy;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_bus:
|
||||
regmap_mmio_detach_clk(dphy->regs);
|
||||
clk_put(dphy->bus_clk);
|
||||
err_free_reset:
|
||||
reset_control_put(dphy->reset);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sun6i_dphy_remove(struct sun6i_dsi *dsi)
|
||||
{
|
||||
struct sun6i_dphy *dphy = dsi->dphy;
|
||||
|
||||
regmap_mmio_detach_clk(dphy->regs);
|
||||
clk_put(dphy->mod_clk);
|
||||
clk_put(dphy->bus_clk);
|
||||
reset_control_put(dphy->reset);
|
||||
|
||||
return 0;
|
||||
}
|
1107
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
Normale Datei
1107
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
Normale Datei
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
63
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
Normale Datei
63
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
Normale Datei
@@ -0,0 +1,63 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2016 Allwinnertech Co., Ltd.
|
||||
* Copyright (C) 2017-2018 Bootlin
|
||||
*
|
||||
* Maxime Ripard <maxime.ripard@bootlin.com>
|
||||
*/
|
||||
|
||||
#ifndef _SUN6I_MIPI_DSI_H_
|
||||
#define _SUN6I_MIPI_DSI_H_
|
||||
|
||||
#include <drm/drm_connector.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <drm/drm_mipi_dsi.h>
|
||||
|
||||
struct sun6i_dphy {
|
||||
struct clk *bus_clk;
|
||||
struct clk *mod_clk;
|
||||
struct regmap *regs;
|
||||
struct reset_control *reset;
|
||||
};
|
||||
|
||||
struct sun6i_dsi {
|
||||
struct drm_connector connector;
|
||||
struct drm_encoder encoder;
|
||||
struct mipi_dsi_host host;
|
||||
|
||||
struct clk *bus_clk;
|
||||
struct clk *mod_clk;
|
||||
struct regmap *regs;
|
||||
struct reset_control *reset;
|
||||
struct sun6i_dphy *dphy;
|
||||
|
||||
struct device *dev;
|
||||
struct sun4i_drv *drv;
|
||||
struct mipi_dsi_device *device;
|
||||
struct drm_panel *panel;
|
||||
};
|
||||
|
||||
static inline struct sun6i_dsi *host_to_sun6i_dsi(struct mipi_dsi_host *host)
|
||||
{
|
||||
return container_of(host, struct sun6i_dsi, host);
|
||||
};
|
||||
|
||||
static inline struct sun6i_dsi *connector_to_sun6i_dsi(struct drm_connector *connector)
|
||||
{
|
||||
return container_of(connector, struct sun6i_dsi, connector);
|
||||
};
|
||||
|
||||
static inline struct sun6i_dsi *encoder_to_sun6i_dsi(const struct drm_encoder *encoder)
|
||||
{
|
||||
return container_of(encoder, struct sun6i_dsi, encoder);
|
||||
};
|
||||
|
||||
int sun6i_dphy_probe(struct sun6i_dsi *dsi, struct device_node *node);
|
||||
int sun6i_dphy_remove(struct sun6i_dsi *dsi);
|
||||
|
||||
int sun6i_dphy_init(struct sun6i_dphy *dphy, unsigned int lanes);
|
||||
int sun6i_dphy_power_on(struct sun6i_dphy *dphy, unsigned int lanes);
|
||||
int sun6i_dphy_power_off(struct sun6i_dphy *dphy);
|
||||
int sun6i_dphy_exit(struct sun6i_dphy *dphy);
|
||||
|
||||
#endif /* _SUN6I_MIPI_DSI_H_ */
|
In neuem Issue referenzieren
Einen Benutzer sperren