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:
Dave Airlie
2018-04-30 09:32:34 +10:00
Commit 0ab390262c
165 geänderte Dateien mit 8500 neuen und 1097 gelöschten Zeilen

Datei anzeigen

@@ -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

Datei anzeigen

@@ -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

Datei anzeigen

@@ -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;

Datei anzeigen

@@ -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)

Datei anzeigen

@@ -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);

Datei anzeigen

@@ -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)

Datei anzeigen

@@ -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

Datei anzeigen

@@ -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;
}

Datei-Diff unterdrückt, da er zu groß ist Diff laden

Datei anzeigen

@@ -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_ */