From patchwork Tue Dec 5 15:10:20 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxime Ripard X-Patchwork-Id: 120673 Delivered-To: patch@linaro.org Received: by 10.140.22.227 with SMTP id 90csp5864213qgn; Tue, 5 Dec 2017 07:10:48 -0800 (PST) X-Google-Smtp-Source: AGs4zMauJhBXGDRkxdf9eTJ6Jet5ZNTyOTpxPCmEudd/FOCzW/lv9IFbrE8JpkLAUlaRVN+HKje+ X-Received: by 10.159.249.73 with SMTP id h9mr18153701pls.6.1512486647942; Tue, 05 Dec 2017 07:10:47 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1512486647; cv=none; d=google.com; s=arc-20160816; b=yM0L9APmvg0OQDmxm/8dvGk3jHrEs3eyU3BOK3b8/tvN8hKctpyG9CzCVySjcUa5Jk aQy9BbGqPd+RdujIlFhdcA9qNS0lBq/nIqpc49N4doBdP80LMzZNQmkclhND3+iZUFWN +6eTuuQogtnOedyCBcLT8uOqBgL2R+LM0xjWTKtggQndydubLs8HSO7kCTPbBqBDgTSa R/QviPcwTPWyF4t63f8H+3IEenfrVK4c2ygPkCBVviLPBKdvFbSE56gIxzMS0aB1jKDy PnhGbIvmVZueO0wa9bxZjjVEK1mfOkyw1nNYkKtlvz4fAHwdq3ZtMgT0eldj7nzMRr0m e42Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:references :in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=ItCoFMp3181pJ3yFPPdFc7jaltV5GbFWhg68/nlDktg=; b=pG0dOe6FbsdI1Va0OVIr+nZVvPoMRcEZyenLxYBelUoXI7qGhoNC6i/gZzP8G2BP5a FyQGaPxOdCrO4xjnyjYHlgLJqhOHIEKRl7lehfylILE0ap5Xf1jpuUIRXFZf4DLe8gJM Ck4zIO2zFq4Dp5lgVll65NcS+Z4ZGHS5wmKNgiU7y2+X83bwctFdMp5RNwFug7LrcwZO u3tbrBSLcI1fWoa6Addq/VpxwSSlGRGzduKXqY1tRPqxcOaXUk+HXil4snpcCGqSS5yT I18A/250L962Rzfdqroc9urm540PRJ9SQDr17ElKjEAs7z784GLOv2GfhEfz6uGdSKSM EJJw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id w12si198503pld.479.2017.12.05.07.10.47; Tue, 05 Dec 2017 07:10:47 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752938AbdLEPKp (ORCPT + 6 others); Tue, 5 Dec 2017 10:10:45 -0500 Received: from mail.free-electrons.com ([62.4.15.54]:56122 "EHLO mail.free-electrons.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752872AbdLEPKm (ORCPT ); Tue, 5 Dec 2017 10:10:42 -0500 Received: by mail.free-electrons.com (Postfix, from userid 110) id C74A520989; Tue, 5 Dec 2017 16:10:40 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on mail.free-electrons.com X-Spam-Level: X-Spam-Status: No, score=-1.0 required=5.0 tests=ALL_TRUSTED,SHORTCIRCUIT, URIBL_BLOCKED shortcircuit=ham autolearn=disabled version=3.4.0 Received: from localhost (LStLambert-657-1-97-87.w90-63.abo.wanadoo.fr [90.63.216.87]) by mail.free-electrons.com (Postfix) with ESMTPSA id 8DDFD206F1; Tue, 5 Dec 2017 16:10:40 +0100 (CET) From: Maxime Ripard To: Daniel Vetter , David Airlie , Chen-Yu Tsai , Maxime Ripard Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Mark Rutland , Rob Herring , linux-arm-kernel@lists.infradead.org, plaes@plaes.org, icenowy@aosc.io, Thomas Petazzoni , jernej.skrabec@siol.net, devicetree@vger.kernel.org Subject: [PATCH v3 08/15] drm/sun4i: Add LVDS support Date: Tue, 5 Dec 2017 16:10:20 +0100 Message-Id: X-Mailer: git-send-email 2.14.3 In-Reply-To: References: In-Reply-To: References: Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org The TCON supports the LVDS interface to output to a panel or a bridge. Let's add support for it. Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/Makefile | 1 +- drivers/gpu/drm/sun4i/sun4i_lvds.c | 183 +++++++++++++++++++++++- drivers/gpu/drm/sun4i/sun4i_lvds.h | 18 ++- drivers/gpu/drm/sun4i/sun4i_tcon.c | 238 +++++++++++++++++++++++++++++- drivers/gpu/drm/sun4i/sun4i_tcon.h | 29 ++++- 5 files changed, 467 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/drm/sun4i/sun4i_lvds.c create mode 100644 drivers/gpu/drm/sun4i/sun4i_lvds.h -- git-series 0.9.1 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile index 82a6ac57fbe3..2b37a6abbb1d 100644 --- a/drivers/gpu/drm/sun4i/Makefile +++ b/drivers/gpu/drm/sun4i/Makefile @@ -15,6 +15,7 @@ sun8i-mixer-y += sun8i_mixer.o sun8i_ui_layer.o \ sun4i-tcon-y += sun4i_crtc.o sun4i-tcon-y += sun4i_dotclock.o +sun4i-tcon-y += sun4i_lvds.o sun4i-tcon-y += sun4i_tcon.o sun4i-tcon-y += sun4i_rgb.o diff --git a/drivers/gpu/drm/sun4i/sun4i_lvds.c b/drivers/gpu/drm/sun4i/sun4i_lvds.c new file mode 100644 index 000000000000..635a3f505ecb --- /dev/null +++ b/drivers/gpu/drm/sun4i/sun4i_lvds.c @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2015 NextThing Co + * Copyright (C) 2015-2017 Free Electrons + * + * Maxime Ripard + * + * 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 + +#include +#include +#include +#include +#include + +#include "sun4i_crtc.h" +#include "sun4i_tcon.h" +#include "sun4i_lvds.h" + +struct sun4i_lvds { + struct drm_connector connector; + struct drm_encoder encoder; + + struct sun4i_tcon *tcon; +}; + +static inline struct sun4i_lvds * +drm_connector_to_sun4i_lvds(struct drm_connector *connector) +{ + return container_of(connector, struct sun4i_lvds, + connector); +} + +static inline struct sun4i_lvds * +drm_encoder_to_sun4i_lvds(struct drm_encoder *encoder) +{ + return container_of(encoder, struct sun4i_lvds, + encoder); +} + +static int sun4i_lvds_get_modes(struct drm_connector *connector) +{ + struct sun4i_lvds *lvds = + drm_connector_to_sun4i_lvds(connector); + struct sun4i_tcon *tcon = lvds->tcon; + + return drm_panel_get_modes(tcon->panel); +} + +static struct drm_connector_helper_funcs sun4i_lvds_con_helper_funcs = { + .get_modes = sun4i_lvds_get_modes, +}; + +static void +sun4i_lvds_connector_destroy(struct drm_connector *connector) +{ + struct sun4i_lvds *lvds = drm_connector_to_sun4i_lvds(connector); + struct sun4i_tcon *tcon = lvds->tcon; + + drm_panel_detach(tcon->panel); + drm_connector_cleanup(connector); +} + +static const struct drm_connector_funcs sun4i_lvds_con_funcs = { + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = sun4i_lvds_connector_destroy, + .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 void sun4i_lvds_encoder_enable(struct drm_encoder *encoder) +{ + struct sun4i_lvds *lvds = drm_encoder_to_sun4i_lvds(encoder); + struct sun4i_tcon *tcon = lvds->tcon; + + DRM_DEBUG_DRIVER("Enabling LVDS output\n"); + + if (!IS_ERR(tcon->panel)) { + drm_panel_prepare(tcon->panel); + drm_panel_enable(tcon->panel); + } +} + +static void sun4i_lvds_encoder_disable(struct drm_encoder *encoder) +{ + struct sun4i_lvds *lvds = drm_encoder_to_sun4i_lvds(encoder); + struct sun4i_tcon *tcon = lvds->tcon; + + DRM_DEBUG_DRIVER("Disabling LVDS output\n"); + + if (!IS_ERR(tcon->panel)) { + drm_panel_disable(tcon->panel); + drm_panel_unprepare(tcon->panel); + } +} + +static const struct drm_encoder_helper_funcs sun4i_lvds_enc_helper_funcs = { + .disable = sun4i_lvds_encoder_disable, + .enable = sun4i_lvds_encoder_enable, +}; + +static const struct drm_encoder_funcs sun4i_lvds_enc_funcs = { + .destroy = drm_encoder_cleanup, +}; + +int sun4i_lvds_init(struct drm_device *drm, struct sun4i_tcon *tcon) +{ + struct drm_encoder *encoder; + struct drm_bridge *bridge; + struct sun4i_lvds *lvds; + int ret; + + lvds = devm_kzalloc(drm->dev, sizeof(*lvds), GFP_KERNEL); + if (!lvds) + return -ENOMEM; + lvds->tcon = tcon; + encoder = &lvds->encoder; + + ret = drm_of_find_panel_or_bridge(tcon->dev->of_node, 1, 0, + &tcon->panel, &bridge); + if (ret) { + dev_info(drm->dev, "No panel or bridge found... LVDS output disabled\n"); + return 0; + } + + drm_encoder_helper_add(&lvds->encoder, + &sun4i_lvds_enc_helper_funcs); + ret = drm_encoder_init(drm, + &lvds->encoder, + &sun4i_lvds_enc_funcs, + DRM_MODE_ENCODER_LVDS, + NULL); + if (ret) { + dev_err(drm->dev, "Couldn't initialise the lvds encoder\n"); + goto err_out; + } + + /* The LVDS encoder can only work with the TCON channel 0 */ + lvds->encoder.possible_crtcs = BIT(drm_crtc_index(&tcon->crtc->crtc)); + + if (tcon->panel) { + drm_connector_helper_add(&lvds->connector, + &sun4i_lvds_con_helper_funcs); + ret = drm_connector_init(drm, &lvds->connector, + &sun4i_lvds_con_funcs, + DRM_MODE_CONNECTOR_LVDS); + if (ret) { + dev_err(drm->dev, "Couldn't initialise the lvds connector\n"); + goto err_cleanup_connector; + } + + drm_mode_connector_attach_encoder(&lvds->connector, + &lvds->encoder); + + ret = drm_panel_attach(tcon->panel, &lvds->connector); + if (ret) { + dev_err(drm->dev, "Couldn't attach our panel\n"); + goto err_cleanup_connector; + } + } + + if (bridge) { + ret = drm_bridge_attach(encoder, bridge, NULL); + if (ret) { + dev_err(drm->dev, "Couldn't attach our bridge\n"); + goto err_cleanup_connector; + } + } + + return 0; + +err_cleanup_connector: + drm_encoder_cleanup(&lvds->encoder); +err_out: + return ret; +} +EXPORT_SYMBOL(sun4i_lvds_init); diff --git a/drivers/gpu/drm/sun4i/sun4i_lvds.h b/drivers/gpu/drm/sun4i/sun4i_lvds.h new file mode 100644 index 000000000000..1b8fad4b82c3 --- /dev/null +++ b/drivers/gpu/drm/sun4i/sun4i_lvds.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2015 NextThing Co + * Copyright (C) 2015-2017 Free Electrons + * + * Maxime Ripard + * + * 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 _SUN4I_LVDS_H_ +#define _SUN4I_LVDS_H_ + +int sun4i_lvds_init(struct drm_device *drm, struct sun4i_tcon *tcon); + +#endif /* _SUN4I_LVDS_H_ */ diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 46e28ca1f676..92f4738101e6 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -31,10 +31,52 @@ #include "sun4i_crtc.h" #include "sun4i_dotclock.h" #include "sun4i_drv.h" +#include "sun4i_lvds.h" #include "sun4i_rgb.h" #include "sun4i_tcon.h" #include "sunxi_engine.h" +static struct drm_connector *sun4i_tcon_get_connector(const struct drm_encoder *encoder) +{ + struct drm_connector *connector; + struct drm_connector_list_iter iter; + + drm_connector_list_iter_begin(encoder->dev, &iter); + drm_for_each_connector_iter(connector, &iter) + if (connector->encoder == encoder) { + drm_connector_list_iter_end(&iter); + return connector; + } + drm_connector_list_iter_end(&iter); + + return NULL; +} + +static int sun4i_tcon_get_pixel_depth(const struct drm_encoder *encoder) +{ + struct drm_connector *connector; + struct drm_display_info *info; + + connector = sun4i_tcon_get_connector(encoder); + if (!connector) + return -EINVAL; + + info = &connector->display_info; + if (info->num_bus_formats != 1) + return -EINVAL; + + switch (info->bus_formats[0]) { + case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: + return 18; + + case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: + case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: + return 24; + } + + return -EINVAL; +} + static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel, bool enabled) { @@ -65,13 +107,58 @@ static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel, clk_disable_unprepare(clk); } +static void sun4i_tcon_lvds_set_status(struct sun4i_tcon *tcon, + const struct drm_encoder *encoder, + bool enabled) +{ + if (enabled) { + u8 val; + + regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_IF_REG, + SUN4I_TCON0_LVDS_IF_EN, + SUN4I_TCON0_LVDS_IF_EN); + + regmap_write(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG, + SUN4I_TCON0_LVDS_ANA0_C(2) | + SUN4I_TCON0_LVDS_ANA0_V(3) | + SUN4I_TCON0_LVDS_ANA0_PD(2) | + SUN4I_TCON0_LVDS_ANA0_EN_LDO); + udelay(2); + + regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG, + SUN4I_TCON0_LVDS_ANA0_EN_MB, + SUN4I_TCON0_LVDS_ANA0_EN_MB); + udelay(2); + + regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG, + SUN4I_TCON0_LVDS_ANA0_EN_DRVC, + SUN4I_TCON0_LVDS_ANA0_EN_DRVC); + + if (sun4i_tcon_get_pixel_depth(encoder) == 18) + val = 7; + else + val = 0xf; + + regmap_write_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG, + SUN4I_TCON0_LVDS_ANA0_EN_DRVD(0xf), + SUN4I_TCON0_LVDS_ANA0_EN_DRVD(val)); + } else { + regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_IF_REG, + SUN4I_TCON0_LVDS_IF_EN, 0); + } +} + void sun4i_tcon_set_status(struct sun4i_tcon *tcon, const struct drm_encoder *encoder, bool enabled) { + bool is_lvds = false; int channel; switch (encoder->encoder_type) { + case DRM_MODE_ENCODER_LVDS: + is_lvds = true; + /* Fallthrough */ case DRM_MODE_ENCODER_NONE: channel = 0; break; @@ -84,10 +171,16 @@ void sun4i_tcon_set_status(struct sun4i_tcon *tcon, return; } + if (is_lvds && !enabled) + sun4i_tcon_lvds_set_status(tcon, encoder, false); + regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG, SUN4I_TCON_GCTL_TCON_ENABLE, enabled ? SUN4I_TCON_GCTL_TCON_ENABLE : 0); + if (is_lvds && enabled) + sun4i_tcon_lvds_set_status(tcon, encoder, true); + sun4i_tcon_channel_set_status(tcon, channel, enabled); } @@ -170,6 +263,78 @@ static void sun4i_tcon0_mode_set_common(struct sun4i_tcon *tcon, SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay)); } +static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon, + const struct drm_encoder *encoder, + const struct drm_display_mode *mode) +{ + unsigned int bp; + u8 clk_delay; + u32 reg, val = 0; + + tcon->dclk_min_div = 7; + tcon->dclk_max_div = 7; + sun4i_tcon0_mode_set_common(tcon, mode); + + /* Adjust clock delay */ + clk_delay = sun4i_tcon_get_clk_delay(mode, 0); + regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG, + SUN4I_TCON0_CTL_CLK_DELAY_MASK, + SUN4I_TCON0_CTL_CLK_DELAY(clk_delay)); + + /* + * This is called a backporch in the register documentation, + * but it really is the back porch + hsync + */ + bp = mode->crtc_htotal - mode->crtc_hsync_start; + DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n", + mode->crtc_htotal, bp); + + /* Set horizontal display timings */ + regmap_write(tcon->regs, SUN4I_TCON0_BASIC1_REG, + SUN4I_TCON0_BASIC1_H_TOTAL(mode->htotal) | + SUN4I_TCON0_BASIC1_H_BACKPORCH(bp)); + + /* + * This is called a backporch in the register documentation, + * but it really is the back porch + hsync + */ + bp = mode->crtc_vtotal - mode->crtc_vsync_start; + DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n", + mode->crtc_vtotal, bp); + + /* Set vertical display timings */ + regmap_write(tcon->regs, SUN4I_TCON0_BASIC2_REG, + SUN4I_TCON0_BASIC2_V_TOTAL(mode->crtc_vtotal * 2) | + SUN4I_TCON0_BASIC2_V_BACKPORCH(bp)); + + reg = SUN4I_TCON0_LVDS_IF_CLK_SEL_TCON0 | + SUN4I_TCON0_LVDS_IF_DATA_POL_NORMAL | + SUN4I_TCON0_LVDS_IF_CLK_POL_NORMAL; + if (sun4i_tcon_get_pixel_depth(encoder) == 24) + reg |= SUN4I_TCON0_LVDS_IF_BITWIDTH_24BITS; + else + reg |= SUN4I_TCON0_LVDS_IF_BITWIDTH_18BITS; + + regmap_write(tcon->regs, SUN4I_TCON0_LVDS_IF_REG, reg); + + /* Setup the polarity of the various signals */ + if (!(mode->flags & DRM_MODE_FLAG_PHSYNC)) + val |= SUN4I_TCON0_IO_POL_HSYNC_POSITIVE; + + if (!(mode->flags & DRM_MODE_FLAG_PVSYNC)) + val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE; + + regmap_write(tcon->regs, SUN4I_TCON0_IO_POL_REG, val); + + /* Map output pins to channel 0 */ + regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG, + SUN4I_TCON_GCTL_IOMAP_MASK, + SUN4I_TCON_GCTL_IOMAP_TCON0); + + /* Enable the output on the pins */ + regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, 0xe0000000); +} + static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon, const struct drm_display_mode *mode) { @@ -336,6 +501,9 @@ void sun4i_tcon_mode_set(struct sun4i_tcon *tcon, const struct drm_display_mode *mode) { switch (encoder->encoder_type) { + case DRM_MODE_ENCODER_LVDS: + sun4i_tcon0_mode_set_lvds(tcon, encoder, mode); + break; case DRM_MODE_ENCODER_NONE: sun4i_tcon0_mode_set_rgb(tcon, mode); sun4i_tcon_set_mux(tcon, 0, encoder); @@ -667,7 +835,9 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, struct drm_device *drm = data; struct sun4i_drv *drv = drm->dev_private; struct sunxi_engine *engine; + struct device_node *remote; struct sun4i_tcon *tcon; + bool has_lvds_rst, has_lvds_pll, can_lvds; int ret; engine = sun4i_tcon_find_engine(drv, dev->of_node); @@ -698,6 +868,54 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, return ret; } + /* + * This can only be made optional since we've had DT nodes + * without the LVDS reset properties. + * + * If the property is missing, just disable LVDS, and print a + * warning. + */ + tcon->lvds_rst = devm_reset_control_get_optional(dev, "lvds"); + if (IS_ERR(tcon->lvds_rst)) { + dev_err(dev, "Couldn't get our reset line\n"); + return PTR_ERR(tcon->lvds_rst); + } else if (tcon->lvds_rst) { + has_lvds_rst = true; + reset_control_reset(tcon->lvds_rst); + } else { + has_lvds_rst = false; + } + + /* + * This can only be made optional since we've had DT nodes + * without the LVDS reset properties. + * + * If the property is missing, just disable LVDS, and print a + * warning. + */ + if (tcon->quirks->has_lvds_pll) { + tcon->lvds_pll = devm_clk_get(dev, "pll-lvds"); + if (IS_ERR(tcon->lvds_pll)) { + if (PTR_ERR(tcon->lvds_pll) == -ENOENT) { + has_lvds_pll = false; + } else { + dev_err(dev, "Couldn't get the LVDS PLL\n"); + return PTR_ERR(tcon->lvds_rst); + } + } else { + has_lvds_pll = true; + } + } + + if (!has_lvds_rst || (tcon->quirks->has_lvds_pll && !has_lvds_pll)) { + dev_warn(dev, + "Missing LVDS properties, Please upgrade your DT\n"); + dev_warn(dev, "LVDS output disabled\n"); + can_lvds = false; + } else { + can_lvds = true; + } + ret = sun4i_tcon_init_clocks(dev, tcon); if (ret) { dev_err(dev, "Couldn't init our TCON clocks\n"); @@ -729,7 +947,21 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, goto err_free_dotclock; } - ret = sun4i_rgb_init(drm, tcon); + /* + * If we have an LVDS panel connected to the TCON, we should + * just probe the LVDS connector. Otherwise, just probe RGB as + * we used to. + */ + remote = of_graph_get_remote_node(dev->of_node, 1, 0); + if (of_device_is_compatible(remote, "panel-lvds")) + if (can_lvds) + ret = sun4i_lvds_init(drm, tcon); + else + ret = -EINVAL; + else + ret = sun4i_rgb_init(drm, tcon); + of_node_put(remote); + if (ret < 0) goto err_free_dotclock; @@ -879,12 +1111,14 @@ static const struct sun4i_tcon_quirks sun5i_a13_quirks = { static const struct sun4i_tcon_quirks sun6i_a31_quirks = { .has_channel_1 = true, + .has_lvds_pll = true, .needs_de_be_mux = true, .set_mux = sun6i_tcon_set_mux, }; static const struct sun4i_tcon_quirks sun6i_a31s_quirks = { .has_channel_1 = true, + .has_lvds_pll = true, .needs_de_be_mux = true, }; @@ -895,7 +1129,7 @@ static const struct sun4i_tcon_quirks sun7i_a20_quirks = { }; static const struct sun4i_tcon_quirks sun8i_a33_quirks = { - /* nothing is supported */ + .has_lvds_pll = true, }; static const struct sun4i_tcon_quirks sun8i_v3s_quirks = { diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h index bd3ad7684870..6e801a6325a1 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.h +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h @@ -70,7 +70,21 @@ #define SUN4I_TCON0_TTL2_REG 0x78 #define SUN4I_TCON0_TTL3_REG 0x7c #define SUN4I_TCON0_TTL4_REG 0x80 + #define SUN4I_TCON0_LVDS_IF_REG 0x84 +#define SUN4I_TCON0_LVDS_IF_EN BIT(31) +#define SUN4I_TCON0_LVDS_IF_BITWIDTH_MASK BIT(26) +#define SUN4I_TCON0_LVDS_IF_BITWIDTH_18BITS (1 << 26) +#define SUN4I_TCON0_LVDS_IF_BITWIDTH_24BITS (0 << 26) +#define SUN4I_TCON0_LVDS_IF_CLK_SEL_MASK BIT(20) +#define SUN4I_TCON0_LVDS_IF_CLK_SEL_TCON0 (1 << 20) +#define SUN4I_TCON0_LVDS_IF_CLK_POL_MASK BIT(4) +#define SUN4I_TCON0_LVDS_IF_CLK_POL_NORMAL (1 << 4) +#define SUN4I_TCON0_LVDS_IF_CLK_POL_INV (0 << 4) +#define SUN4I_TCON0_LVDS_IF_DATA_POL_MASK GENMASK(3, 0) +#define SUN4I_TCON0_LVDS_IF_DATA_POL_NORMAL (0xf) +#define SUN4I_TCON0_LVDS_IF_DATA_POL_INV (0) + #define SUN4I_TCON0_IO_POL_REG 0x88 #define SUN4I_TCON0_IO_POL_DCLK_PHASE(phase) ((phase & 3) << 28) #define SUN4I_TCON0_IO_POL_HSYNC_POSITIVE BIT(25) @@ -131,6 +145,16 @@ #define SUN4I_TCON_CEU_RANGE_G_REG 0x144 #define SUN4I_TCON_CEU_RANGE_B_REG 0x148 #define SUN4I_TCON_MUX_CTRL_REG 0x200 + +#define SUN4I_TCON0_LVDS_ANA0_REG 0x220 +#define SUN4I_TCON0_LVDS_ANA0_EN_MB BIT(31) +#define SUN4I_TCON0_LVDS_ANA0_EN_LDO BIT(30) +#define SUN4I_TCON0_LVDS_ANA0_EN_DRVC BIT(24) +#define SUN4I_TCON0_LVDS_ANA0_EN_DRVD(x) (((x) & 0xf) << 20) +#define SUN4I_TCON0_LVDS_ANA0_C(x) (((x) & 3) << 17) +#define SUN4I_TCON0_LVDS_ANA0_V(x) (((x) & 3) << 8) +#define SUN4I_TCON0_LVDS_ANA0_PD(x) (((x) & 3) << 4) + #define SUN4I_TCON1_FILL_CTL_REG 0x300 #define SUN4I_TCON1_FILL_BEG0_REG 0x304 #define SUN4I_TCON1_FILL_END0_REG 0x308 @@ -149,6 +173,7 @@ struct sun4i_tcon; struct sun4i_tcon_quirks { bool has_channel_1; /* a33 does not have channel 1 */ + bool has_lvds_pll; /* Can we mux the LVDS clock to a PLL? */ bool needs_de_be_mux; /* sun6i needs mux to select backend */ /* callback to handle tcon muxing options */ @@ -167,6 +192,9 @@ struct sun4i_tcon { struct clk *sclk0; struct clk *sclk1; + /* Possible mux for the LVDS clock */ + struct clk *lvds_pll; + /* Pixel clock */ struct clk *dclk; u8 dclk_max_div; @@ -174,6 +202,7 @@ struct sun4i_tcon { /* Reset control */ struct reset_control *lcd_rst; + struct reset_control *lvds_rst; struct drm_panel *panel; From patchwork Tue Dec 5 15:10:22 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxime Ripard X-Patchwork-Id: 120671 Delivered-To: patch@linaro.org Received: by 10.140.22.227 with SMTP id 90csp5864067qgn; Tue, 5 Dec 2017 07:10:42 -0800 (PST) X-Google-Smtp-Source: AGs4zMbVK8Z21EqtpYghZPHRfPcajywgslxf04+xvPAz9/lUhPMvqAqCo2vh2ixQvF+n97hPU+kg X-Received: by 10.98.205.5 with SMTP id o5mr23271299pfg.39.1512486642231; Tue, 05 Dec 2017 07:10:42 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1512486642; cv=none; d=google.com; s=arc-20160816; b=g6uBRzchrb1P1nkUqQbwzYA65biSQrt1zwH6WIb1m3mh1rd90KB6ejVG1oPDescqoF TnIstx3ojlyOb5UkdoRrxGsCLoO4I2aprnP3Yqzsm43XvedeweCrdU2iHqKMyoC01LUP 1Ptl5o2dGsdVb3NsFbpZed6WJTY9iTvoXORHiLGISSUgjuadpACg0L1Vl0hgWmk74t0q zToC60thyNgav3YDMLStHsV+oGDjkxKVRo/LRZr+r69k6M23kwPXAFKqO0vXUlZ6gz2/ ca3nKdG+ifPkFm9qLHhQf5ozdvEjwpMFjaR3W4waIjA2viOqPrCi2Y9+xmWxuXwKvv2H ucew== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:references :in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=JPAP/bv1t7sWrLo0pPRw2M7EprABBbKvh5WjnOlx/XY=; b=bYkSjXFCWOsghUb1zdvkiENT8t9OAPynT3L3j8sYNPiXtEMTDPo8vkn1zz8eK2LyPS x98x5XDkszY+F7yyExkk55u/EOy7T02iw1Gxf+zrILahmh8ClftGgjq/aR2fiXR9Zjrt r+HWadD23ozS53bCqQ2Y0wQb7JPaG2C7JbrnCS/688mNU01mm85cmJUGBsHvqQzAKj3x nHlyqYyOQQCZei/LFEhT0KIFYKHkEdu1HvMaQbb7BebAGDiY3CvDj4HnZ8DsgHalsFbt H8A4hElfd1vZLcA/N02MrCKTDX56RzAbE6erXoOv7bGXgOoyyF9VEZzWaVJwaduwrxSk EgVA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id w12si198503pld.479.2017.12.05.07.10.42; Tue, 05 Dec 2017 07:10:42 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752858AbdLEPKk (ORCPT + 6 others); Tue, 5 Dec 2017 10:10:40 -0500 Received: from mail.free-electrons.com ([62.4.15.54]:56074 "EHLO mail.free-electrons.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752841AbdLEPKi (ORCPT ); Tue, 5 Dec 2017 10:10:38 -0500 Received: by mail.free-electrons.com (Postfix, from userid 110) id 3C2F520739; Tue, 5 Dec 2017 16:10:36 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on mail.free-electrons.com X-Spam-Level: X-Spam-Status: No, score=-1.0 required=5.0 tests=ALL_TRUSTED,SHORTCIRCUIT shortcircuit=ham autolearn=disabled version=3.4.0 Received: from localhost (LStLambert-657-1-97-87.w90-63.abo.wanadoo.fr [90.63.216.87]) by mail.free-electrons.com (Postfix) with ESMTPSA id 0B5DD203A2; Tue, 5 Dec 2017 16:10:36 +0100 (CET) From: Maxime Ripard To: Daniel Vetter , David Airlie , Chen-Yu Tsai , Maxime Ripard Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Mark Rutland , Rob Herring , linux-arm-kernel@lists.infradead.org, plaes@plaes.org, icenowy@aosc.io, Thomas Petazzoni , jernej.skrabec@siol.net, devicetree@vger.kernel.org Subject: [PATCH v3 10/15] ARM: dts: sun8i: a83t: Add display pipeline Date: Tue, 5 Dec 2017 16:10:22 +0100 Message-Id: <97d3cee9d0d7a92893f646d72643bac520de5f05.1512486553.git-series.maxime.ripard@free-electrons.com> X-Mailer: git-send-email 2.14.3 In-Reply-To: References: In-Reply-To: References: Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org The display pipeline on the A83T is mainly composed of the mixers and TCONs, plus various encoders. Let's add the first mixer and TCON to the DTSI since the only board I have can use only the LVDS output on the first TCON. The other parts will be added eventually. Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun8i-a83t.dtsi | 79 ++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+) -- git-series 0.9.1 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Reviewed-by: Chen-Yu Tsai diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi index 19acae1b4089..e4db38c717d9 100644 --- a/arch/arm/boot/dts/sun8i-a83t.dtsi +++ b/arch/arm/boot/dts/sun8i-a83t.dtsi @@ -45,8 +45,10 @@ #include #include +#include #include #include +#include #include / { @@ -151,6 +153,12 @@ }; }; + de: display-engine { + compatible = "allwinner,sun8i-a83t-display-engine"; + allwinner,pipelines = <&mixer0>; + status = "disabled"; + }; + memory { reg = <0x40000000 0x80000000>; device_type = "memory"; @@ -162,6 +170,44 @@ #size-cells = <1>; ranges; + display_clocks: clock@1000000 { + compatible = "allwinner,sun8i-a83t-de2-clk"; + reg = <0x01000000 0x100000>; + clocks = <&ccu CLK_PLL_DE>, + <&ccu CLK_BUS_DE>; + clock-names = "mod", + "bus"; + resets = <&ccu RST_BUS_DE>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + mixer0: mixer@1100000 { + compatible = "allwinner,sun8i-a83t-de2-mixer-0"; + reg = <0x01100000 0x100000>; + clocks = <&display_clocks CLK_BUS_MIXER0>, + <&display_clocks CLK_MIXER0>; + clock-names = "bus", + "mod"; + resets = <&display_clocks RST_MIXER0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + mixer0_out: port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + mixer0_out_tcon0: endpoint@0 { + reg = <0>; + remote-endpoint = <&tcon0_in_mixer0>; + }; + }; + }; + }; + syscon: syscon@1c00000 { compatible = "allwinner,sun8i-a83t-system-controller", "syscon"; @@ -177,6 +223,39 @@ #dma-cells = <1>; }; + tcon0: lcd-controller@1c0c000 { + compatible = "allwinner,sun8i-a83t-tcon-lcd"; + reg = <0x01c0c000 0x1000>; + interrupts = ; + clocks = <&ccu CLK_BUS_TCON0>, <&ccu CLK_TCON0>; + clock-names = "ahb", "tcon-ch0"; + clock-output-names = "tcon-pixel-clock"; + resets = <&ccu RST_BUS_TCON0>, <&ccu RST_BUS_LVDS>; + reset-names = "lcd", "lvds"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + tcon0_in: port@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + tcon0_in_mixer0: endpoint@0 { + reg = <0>; + remote-endpoint = <&mixer0_out_tcon0>; + }; + }; + + tcon0_out: port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + }; + }; + mmc0: mmc@1c0f000 { compatible = "allwinner,sun8i-a83t-mmc", "allwinner,sun7i-a20-mmc"; From patchwork Tue Dec 5 15:10:26 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxime Ripard X-Patchwork-Id: 120681 Delivered-To: patch@linaro.org Received: by 10.140.22.227 with SMTP id 90csp5865193qgn; Tue, 5 Dec 2017 07:11:31 -0800 (PST) X-Google-Smtp-Source: AGs4zMZAxkFoAkbTQCWgyUsKbKHScEy+AfkTBrG8vshoNhIFvmiKRtsl589cQVRSMpkU3kQV+Mpu X-Received: by 10.98.166.148 with SMTP id r20mr23264764pfl.80.1512486691631; Tue, 05 Dec 2017 07:11:31 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1512486691; cv=none; d=google.com; s=arc-20160816; b=c9M25TnUTWNqri3aoL3qDXAPum0RiGFB2XGG/znMPLLKwRVhQOeUlfPLoKCUcHC/uA Dm2rs/GejbFNx0KK38WVBhL4LyNSJHt/IRYk1HzgLJTEACyxTsUb5VUOtXepOJsaqx+D PfO3hqRzFjxJobiKYZmgoEzg2LjO055nMfeBzO1LtNR4zdgMq4WpneMAgMRByxbqgqdh NVOA1Mq3rr1a6AwNhx15098dCENqDtB4sLvq+YLNUgkg8iMeWkZTzc1Sd2ChNEKaUvTH sv+wzqFe3Zfbs8b5XglgeORvtiQZFhppHjz0P9Fq5aI9M9dUZnQI+uXr9FzjxKFfb7SU H1qw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:references :in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=H+5ltG2FIRD5u9H6wT7FGwmTgOlZvIsldIfGI2Hj7E8=; b=pV+cmq24s0CPB+khQL6QBqo+4w4rgUh+gtah4Wdj/HSqfobPd5IN3MeBpvlZi79GYd wxMy0F4R8EgrtkrFUzQFompZPq3Wrf+3eL7EaAy6ROvBiaeb+tS1jrTfGfJkC+OBmyTc 4BVV48xf8KlxAZiinnmnoBMPzoExyfn3tPzt3eZ+ZwglKq2y5MTjwGoFq0IQpXbQdEyc rtKEYvXsVbjFWvqSkw4uAVf70PoqXhQe+enSOyXSr7ntqVhCziqcn+JvRUHwzvE5IiqJ 8gwNDtrCO7rFFvuGz95iCnMZnJFbP8orZaPFLpIBcU7oQyIaT4X8JbhTjDCW1R1iZOYw YCkA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id e7si189988plt.807.2017.12.05.07.11.31; Tue, 05 Dec 2017 07:11:31 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752979AbdLEPLa (ORCPT + 6 others); Tue, 5 Dec 2017 10:11:30 -0500 Received: from mail.free-electrons.com ([62.4.15.54]:56202 "EHLO mail.free-electrons.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752945AbdLEPKr (ORCPT ); Tue, 5 Dec 2017 10:10:47 -0500 Received: by mail.free-electrons.com (Postfix, from userid 110) id 370F2209B2; Tue, 5 Dec 2017 16:10:45 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on mail.free-electrons.com X-Spam-Level: X-Spam-Status: No, score=-1.0 required=5.0 tests=ALL_TRUSTED,SHORTCIRCUIT, URIBL_BLOCKED shortcircuit=ham autolearn=disabled version=3.4.0 Received: from localhost (LStLambert-657-1-97-87.w90-63.abo.wanadoo.fr [90.63.216.87]) by mail.free-electrons.com (Postfix) with ESMTPSA id 0DBCC203A2; Tue, 5 Dec 2017 16:10:45 +0100 (CET) From: Maxime Ripard To: Daniel Vetter , David Airlie , Chen-Yu Tsai , Maxime Ripard Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Mark Rutland , Rob Herring , linux-arm-kernel@lists.infradead.org, plaes@plaes.org, icenowy@aosc.io, Thomas Petazzoni , jernej.skrabec@siol.net, devicetree@vger.kernel.org Subject: [PATCH v3 14/15] ARM: dts: sun8i: a711: Reinstate the PMIC compatible Date: Tue, 5 Dec 2017 16:10:26 +0100 Message-Id: <25b482f19587ff195582995c11ee9d07f5bf42d2.1512486553.git-series.maxime.ripard@free-electrons.com> X-Mailer: git-send-email 2.14.3 In-Reply-To: References: In-Reply-To: References: Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org When we added the regulator support in commit 90c5d7cdae64 ("ARM: dts: sun8i: a711: Add regulator support"), we also dropped the PMIC's compatible. Since it's not in the PMIC DTSI, unlike most other PMIC DTSI, it obviously wasn't probing anymore. Re-add it so that everything works again. Fixes: 90c5d7cdae64 ("ARM: dts: sun8i: a711: Add regulator support") Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts | 1 + 1 file changed, 1 insertion(+) -- git-series 0.9.1 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Reviewed-by: Chen-Yu Tsai diff --git a/arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts b/arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts index 98715538932f..a021ee6da396 100644 --- a/arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts +++ b/arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts @@ -146,6 +146,7 @@ status = "okay"; axp81x: pmic@3a3 { + compatible = "x-powers,axp813"; reg = <0x3a3>; interrupt-parent = <&r_intc>; interrupts = <0 IRQ_TYPE_LEVEL_LOW>;