Received: by 2002:a25:23cc:0:0:0:0:0 with SMTP id j195csp446728ybj; Tue, 5 May 2020 01:27:25 -0700 (PDT) X-Google-Smtp-Source: APiQypJjZFmWKcgzbQCutcoqPWBrYE11jppM5AS7wBe4HhH7Lma9ja9Dw2atLRmwr+zEpMdaHZ6Y X-Received: by 2002:a05:6402:686:: with SMTP id f6mr1634478edy.136.1588667245496; Tue, 05 May 2020 01:27:25 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1588667245; cv=none; d=google.com; s=arc-20160816; b=prWYIIoxuHvnzwsXtVfVpD70zVeN4hPTFmO5QhctT1gOyu3fywxJz1XVzOOjspdiD8 holN/DYd2ZZNXBPZBFQYHlLivr1KatPzfNJqpN1TErbdLQwjjPKBHlm1X7DMddJ7TqtE t9OOf3jUfZWbddH3DET2+qhmnSH7fS1M8fDmYsb41VHm62I9vnGJMuvO7ADlJKFYie5Y eW58w1ZbuN0ILJTEWk1ibfpNQ12zdeksEv5sTKaMLLv/CJ+uwRdp6D8pYHEXR9l1Dl1X MMvJb5oLVzAeSV9MqG3XgQrwfsElbCWtnskNB2sbIZOak0lewMJutEMPKhJcfbSI8+fM 9bNQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:in-reply-to:content-disposition :mime-version:references:message-id:subject:cc:to:from:date :dkim-signature; bh=hrJjOjaWwqazTIlqrEbCOY/XtKsLb2c4OFphAvfmdGk=; b=pksxYWZWmHSKFbO0lltopa4HiBc+hUfs9H3eXt1K35ZHtfqt8Oq9lb0tkwvR8MMjqb 2osCc9RLo3fVGU0Wh/l4jcxBdvP9e4xGKpPhlzTy0awEvK3ihdDZ6JaH5gfjLt71GNsr dKZj+21dHoxW7JMyiZYOb06ncyFRlANhIkXX69BhbnadTAF5zhx5bniW3ndV1H8wj0Qq bk1o6/84AGA9Q7V5SdzFCaPkD3nlOdqfwpHyYirEVmc6d5BIbKThYsHRFXpIgfKWADVN d5LlClZTy55L+6aNkJHWmY9+JEofon/do7vHB5Cs2JKq38eQEXnydRAuPpuBll4iBhgA oHIw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass (test mode) header.i=@ideasonboard.com header.s=mail header.b=jyS3r+8I; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id c2si679207ejd.263.2020.05.05.01.27.02; Tue, 05 May 2020 01:27:25 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass (test mode) header.i=@ideasonboard.com header.s=mail header.b=jyS3r+8I; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728498AbgEEIYp (ORCPT + 99 others); Tue, 5 May 2020 04:24:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50324 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1725320AbgEEIYo (ORCPT ); Tue, 5 May 2020 04:24:44 -0400 Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 93174C061A0F; Tue, 5 May 2020 01:24:44 -0700 (PDT) Received: from pendragon.ideasonboard.com (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id CD92A542; Tue, 5 May 2020 10:24:41 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1588667082; bh=K/OJh48zGNT78SlVNOwf5w0V7ZXOE1Xg23O044fx8sw=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=jyS3r+8IzBwPQtU1IuirZ0ch5WrFVcklVSMD/H39tp1sK5Wy9mLINXROlwuS315zo nBHeuPebnJvTgU6yxoBCvyPmhNZRf1UC95RwPCcEXu9oQO+sJTvcIWZwRrK2BZMOpo BGlJ/sNOtZlEaQadu0FMohyo7ahbSbHJbmwOZ0kA= Date: Tue, 5 May 2020 11:24:36 +0300 From: Laurent Pinchart To: Douglas Anderson Cc: Andrzej Hajda , Neil Armstrong , robdclark@chromium.org, seanpaul@chromium.org, linux-arm-msm@vger.kernel.org, Daniel Vetter , David Airlie , Jernej Skrabec , Jonas Karlman , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org Subject: Re: [PATCH] drm/bridge: ti-sn65dsi86: Implement lane reordering + polarity Message-ID: <20200505082436.GD9658@pendragon.ideasonboard.com> References: <20200504213624.1.Ibc8eeddcee94984a608d6900b46f9ffde4045da4@changeid> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline In-Reply-To: <20200504213624.1.Ibc8eeddcee94984a608d6900b46f9ffde4045da4@changeid> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Douglas, Thank you for the patch. On Mon, May 04, 2020 at 09:36:31PM -0700, Douglas Anderson wrote: > The ti-sn65dsi86 MIPI DSI to eDP bridge chip supports arbitrary > remapping of eDP lanes and also polarity inversion. Both of these > features have been described in the device tree bindings for the > device since the beginning but were never implemented in the driver. > Implement both of them. > > Part of this change also allows you to (via the same device tree > bindings) specify to use fewer than the max number of DP lanes that > the panel reports. This could be useful if your display supports more > lanes but only a few are hooked up on your board. > > Signed-off-by: Douglas Anderson > --- > This patch is based upon my my outstanding series[1] not because there > is any real requirement but simply to avoid merge conflicts. I > believe that my previous series is ready to land. If, however, you'd > prefer that I rebase this patch somewhere atop something else then > please shout. > > [1] https://lore.kernel.org/r/20200430194617.197510-1-dianders@chromium.org > > drivers/gpu/drm/bridge/ti-sn65dsi86.c | 75 ++++++++++++++++++++++----- > 1 file changed, 62 insertions(+), 13 deletions(-) > > diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c > index 1a125423eb07..52cca54b525f 100644 > --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c > +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c > @@ -50,8 +50,12 @@ > #define SN_CHA_VERTICAL_BACK_PORCH_REG 0x36 > #define SN_CHA_HORIZONTAL_FRONT_PORCH_REG 0x38 > #define SN_CHA_VERTICAL_FRONT_PORCH_REG 0x3A > +#define SN_LN_ASSIGN_REG 0x59 > +#define LN_ASSIGN_WIDTH 2 > #define SN_ENH_FRAME_REG 0x5A > #define VSTREAM_ENABLE BIT(3) > +#define LN_POLRS_OFFSET 4 > +#define LN_POLRS_MASK 0xf0 > #define SN_DATA_FORMAT_REG 0x5B > #define BPP_18_RGB BIT(0) > #define SN_HPD_DISABLE_REG 0x5C > @@ -98,6 +102,7 @@ > > #define SN_REGULATOR_SUPPLY_NUM 4 > > +#define SN_MAX_DP_LANES 4 > #define SN_NUM_GPIOS 4 > > /** > @@ -115,6 +120,8 @@ > * @enable_gpio: The GPIO we toggle to enable the bridge. > * @supplies: Data for bulk enabling/disabling our regulators. > * @dp_lanes: Count of dp_lanes we're using. > + * @ln_assign: Value to program to the LN_ASSIGN register. > + * @ln_polr: Value for the 4-bit LN_POLRS field of SN_ENH_FRAME_REG. > * > * @gchip: If we expose our GPIOs, this is used. > * @gchip_output: A cache of whether we've set GPIOs to output. This > @@ -140,6 +147,8 @@ struct ti_sn_bridge { > struct gpio_desc *enable_gpio; > struct regulator_bulk_data supplies[SN_REGULATOR_SUPPLY_NUM]; > int dp_lanes; > + u8 ln_assign; > + u8 ln_polrs; > > struct gpio_chip gchip; > DECLARE_BITMAP(gchip_output, SN_NUM_GPIOS); > @@ -707,26 +716,20 @@ static void ti_sn_bridge_enable(struct drm_bridge *bridge) > int dp_rate_idx; > unsigned int val; > int ret = -EINVAL; > + int max_dp_lanes; > > - /* > - * Run with the maximum number of lanes that the DP sink supports. > - * > - * Depending use cases, we might want to revisit this later because: > - * - It's plausible that someone may have run fewer lines to the > - * sink than the sink actually supports, assuming that the lines > - * will just be driven at a higher rate. > - * - The DP spec seems to indicate that it's more important to minimize > - * the number of lanes than the link rate. > - * > - * If we do revisit, it would be important to measure the power impact. > - */ > - pdata->dp_lanes = ti_sn_get_max_lanes(pdata); > + max_dp_lanes = ti_sn_get_max_lanes(pdata); > + pdata->dp_lanes = min(pdata->dp_lanes, max_dp_lanes); > > /* DSI_A lane config */ > val = CHA_DSI_LANES(4 - pdata->dsi->lanes); > regmap_update_bits(pdata->regmap, SN_DSI_LANES_REG, > CHA_DSI_LANES_MASK, val); > > + regmap_write(pdata->regmap, SN_LN_ASSIGN_REG, pdata->ln_assign); > + regmap_update_bits(pdata->regmap, SN_ENH_FRAME_REG, LN_POLRS_MASK, > + pdata->ln_polrs << LN_POLRS_OFFSET); > + > /* set dsi clk frequency value */ > ti_sn_bridge_set_dsi_rate(pdata); > > @@ -1063,6 +1066,50 @@ static int ti_sn_setup_gpio_controller(struct ti_sn_bridge *pdata) > return ret; > } > > +static void ti_sn_bridge_parse_lanes(struct ti_sn_bridge *pdata, > + struct device_node *np) > +{ > + u32 lane_assignments[SN_MAX_DP_LANES] = { 0, 1, 2, 3 }; > + u32 lane_polarities[SN_MAX_DP_LANES] = { }; > + struct device_node *endpoint; > + u8 ln_assign = 0; > + u8 ln_polrs = 0; > + int dp_lanes; > + int i; > + > + /* > + * Read config from the device tree about lane remapping and lane > + * polarities. These are optional and we assume identity map and > + * normal polarity if nothing is specified. It's OK to specify just > + * data-lanes but not lane-polarities but not vice versa. > + */ > + endpoint = of_graph_get_endpoint_by_regs(np, 1, -1); Shouldn't you check for endpoint == NULL and fail probe if it is ? > + dp_lanes = of_property_count_u32_elems(endpoint, "data-lanes"); > + if (dp_lanes > 0) { > + of_property_read_u32_array(endpoint, "data-lanes", > + lane_assignments, dp_lanes); > + of_property_read_u32_array(endpoint, "lane-polarities", > + lane_polarities, dp_lanes); Similarly, with a buggy DT, you may have a buffer overrun here. I would first check that dp_lanes <= SN_MAX_DP_LANES and error out otherwise. > + } else { > + dp_lanes = SN_MAX_DP_LANES; > + } > + > + /* > + * Convert into register format. Loop over all lanes even if > + * data-lanes had fewer elements so that we nicely initialize > + * the LN_ASSIGN register. > + */ > + for (i = SN_MAX_DP_LANES - 1; i >= 0; i--) { > + ln_assign = ln_assign << LN_ASSIGN_WIDTH | lane_assignments[i]; > + ln_polrs = ln_polrs << 1 | lane_polarities[i]; > + } The datasheet documents the lane remapping register as allowing pretty much any combination, but "Table 12. Logical to Physical Supported Combinations" only documents a subset (for instance data-lanes = <2 3> isn't allowed in that table). Should we guard against invalid configurations ? > + > + /* Stash in our struct for when we power on */ > + pdata->dp_lanes = dp_lanes; > + pdata->ln_assign = ln_assign; > + pdata->ln_polrs = ln_polrs; > +} > + > static int ti_sn_bridge_probe(struct i2c_client *client, > const struct i2c_device_id *id) > { > @@ -1105,6 +1152,8 @@ static int ti_sn_bridge_probe(struct i2c_client *client, > return ret; > } > > + ti_sn_bridge_parse_lanes(pdata, client->dev.of_node); > + > ret = ti_sn_bridge_parse_regulators(pdata); > if (ret) { > DRM_ERROR("failed to parse regulators\n"); > -- Regards, Laurent Pinchart