From patchwork Fri Aug 10 15:55:16 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sean Paul X-Patchwork-Id: 10562877 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D9ACF174A for ; Fri, 10 Aug 2018 15:55:28 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CA3642BD47 for ; Fri, 10 Aug 2018 15:55:28 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id BE07F2BD7B; Fri, 10 Aug 2018 15:55:28 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 3B4EF2BD47 for ; Fri, 10 Aug 2018 15:55:28 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 710176E95A; Fri, 10 Aug 2018 15:55:26 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mail-yw1-xc42.google.com (mail-yw1-xc42.google.com [IPv6:2607:f8b0:4864:20::c42]) by gabe.freedesktop.org (Postfix) with ESMTPS id 382806E95A for ; Fri, 10 Aug 2018 15:55:25 +0000 (UTC) Received: by mail-yw1-xc42.google.com with SMTP id z143-v6so8913513ywa.7 for ; Fri, 10 Aug 2018 08:55:25 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=39E6cSkSDz7QcUR02ogmT63nQhQWwz7KWuK76EsF/GE=; b=bCRJ4vhHSh6AKTrD6ewCtC9s0dp48Jswvv0j1ytwH9CEjzSy0DwdVUXIjIrYRLWE22 1rfafIatqAG5DAAFTFmaRl0og7cfRfd2E+8veE1TE4Ljki2UfMF+CnsxsWLCUte9uzNI cOzQtxTlyP8zBa1zeE9D7WMvn8bYxUJrw1cGwtjPDUBlrUBhgx7fsTe587IADPZNo/rZ xEF7WiMu0wOPrRXVpyUzFXj22e4YexjLCkr8k3/1LFIHvEtlo61MS9yZmDINjInDmD3X 9bOpShjSXFqzEVq6sfjb/xh/JOg4WqmxjVeHKrHUWeEDvntwPnzDDtzT1bY7H5ZyQnl7 zSbQ== X-Gm-Message-State: AOUpUlHSFYq01GRpo6B2tRCdknnchhfO0o/985FX5OShFbd1x9uxn8hQ t2k0APGgzb1a7/lsYCRCmeiqlW434oQ= X-Google-Smtp-Source: AA+uWPzMJp+Qtm8UmEbIkMJ4I8CYOJUJvRKS/r2Hf0lQjWrShpRtk3yX4yw4QeJxPHm0FUiqzhYd/g== X-Received: by 2002:a81:5803:: with SMTP id m3-v6mr4084391ywb.312.1533916524156; Fri, 10 Aug 2018 08:55:24 -0700 (PDT) Received: from rosewood.cam.corp.google.com ([2620:0:1013:11:ad55:b1db:adfe:3b9f]) by smtp.gmail.com with ESMTPSA id r69-v6sm3291897ywh.44.2018.08.10.08.55.23 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 10 Aug 2018 08:55:23 -0700 (PDT) From: Sean Paul To: dri-devel@lists.freedesktop.org Subject: [PATCH v2] drm/bridge: sn65dsi86: Implement AUX channel Date: Fri, 10 Aug 2018 11:55:16 -0400 Message-Id: <20180810155522.58882-1-seanpaul@chromium.org> X-Mailer: git-send-email 2.18.0.597.ga71716f1ad-goog MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sandeep Panda , Laurent Pinchart Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Virus-Scanned: ClamAV using ClamSMTP This was hand-rolled in the first version, and will surely be useful as we expand the driver to support more varied use cases. Changes in v2: - Change subject prefix s/panel/bridge/ - Downgrade warning in poll function to error message - Fix DP_EDP_CONFIGURATION_SET write value (Sandeep) - Mask upper 8 bits of msg->address (Sandeep) - Check aux cmd status for errors after completing the send (Sandeep) - Remove length check since it's covered in the aux status - Flip the READ check in transfer to WRITE check + early exit Cc: Sandeep Panda Signed-off-by: Sean Paul --- drivers/gpu/drm/bridge/ti-sn65dsi86.c | 119 ++++++++++++++++++++++++-- 1 file changed, 111 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index 1b6e8b72be58..02df26fd0084 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -7,12 +7,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -29,12 +31,15 @@ #define SN_DATARATE_CONFIG_REG 0x94 #define SN_PLL_ENABLE_REG 0x0D #define SN_SCRAMBLE_CONFIG_REG 0x95 -#define SN_AUX_WDATA0_REG 0x64 +#define SN_AUX_WDATA_REG(x) (0x64 + x) #define SN_AUX_ADDR_19_16_REG 0x74 #define SN_AUX_ADDR_15_8_REG 0x75 #define SN_AUX_ADDR_7_0_REG 0x76 #define SN_AUX_LENGTH_REG 0x77 #define SN_AUX_CMD_REG 0x78 +#define AUX_CMD_SEND 0x01 +#define AUX_CMD_REQ(x) (x << 4) +#define SN_AUX_RDATA_REG(x) (0x79 + x) #define SN_ML_TX_MODE_REG 0x96 /* video config specific registers */ #define SN_CHA_ACTIVE_LINE_LENGTH_LOW_REG 0x20 @@ -48,6 +53,10 @@ #define SN_CHA_HORIZONTAL_FRONT_PORCH_REG 0x38 #define SN_CHA_VERTICAL_FRONT_PORCH_REG 0x3A #define SN_DATA_FORMAT_REG 0x5B +#define SN_AUX_CMD_STATUS_REG 0xF4 +#define AUX_IRQ_STATUS_AUX_RPLY_TOUT BIT(3) +#define AUX_IRQ_STATUS_AUX_SHORT BIT(5) +#define AUX_IRQ_STATUS_NAT_I2C_FAIL BIT(6) #define MIN_DSI_CLK_FREQ_MHZ 40 @@ -64,6 +73,9 @@ #define SN_DP_DATA_RATE_OFFSET 5 #define SN_SYNC_POLARITY_OFFSET 7 +/* Matches DP_AUX_MAX_PAYLOAD_BYTES (for now) */ +#define SN_AUX_MAX_PAYLOAD_BYTES 16 + #define SN_ENABLE_VID_STREAM_BIT BIT(3) #define SN_REFCLK_FREQ_BITS GENMASK(3, 1) #define SN_DSIA_NUM_LANES_BITS GENMASK(4, 3) @@ -76,6 +88,7 @@ struct ti_sn_bridge { struct device *dev; struct regmap *regmap; + struct drm_dp_aux aux; struct drm_bridge bridge; struct drm_connector connector; struct device_node *host_node; @@ -473,13 +486,8 @@ static void ti_sn_bridge_enable(struct drm_bridge *bridge) * authentication method. We need to enable this method in the eDP panel * at DisplayPort address 0x0010A prior to link training. */ - regmap_write(pdata->regmap, SN_AUX_WDATA0_REG, 0x01); - regmap_write(pdata->regmap, SN_AUX_ADDR_19_16_REG, 0x00); - regmap_write(pdata->regmap, SN_AUX_ADDR_15_8_REG, 0x01); - regmap_write(pdata->regmap, SN_AUX_ADDR_7_0_REG, 0x0A); - regmap_write(pdata->regmap, SN_AUX_LENGTH_REG, 0x01); - regmap_write(pdata->regmap, SN_AUX_CMD_REG, 0x81); - usleep_range(10000, 10500); /* 10ms delay recommended by spec */ + drm_dp_dpcd_writeb(&pdata->aux, DP_EDP_CONFIGURATION_SET, + DP_ALTERNATE_SCRAMBLER_RESET_ENABLE); /* Semi auto link training mode */ regmap_write(pdata->regmap, SN_ML_TX_MODE_REG, 0x0A); @@ -527,6 +535,96 @@ static const struct drm_bridge_funcs ti_sn_bridge_funcs = { .post_disable = ti_sn_bridge_post_disable, }; +static struct ti_sn_bridge *aux_to_ti_sn_bridge(struct drm_dp_aux *aux) +{ + return container_of(aux, struct ti_sn_bridge, aux); +} + +static bool ti_sn_cmd_done(struct ti_sn_bridge *pdata) +{ + int ret; + unsigned int val; + + ret = regmap_read(pdata->regmap, SN_AUX_CMD_REG, &val); + if (ret) { + DRM_ERROR("Error returned reading AUX_CMD_REG (%d)\n", ret); + return true; + } + + return !(val & AUX_CMD_SEND); +} + +static ssize_t ti_sn_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + struct ti_sn_bridge *pdata = aux_to_ti_sn_bridge(aux); + u32 request = msg->request & ~DP_AUX_I2C_MOT; + u32 request_val = AUX_CMD_REQ(msg->request); + u8 *buf = (u8 *)msg->buffer; + unsigned int val; + bool cmd_done; + int ret, i; + + if (msg->size > SN_AUX_MAX_PAYLOAD_BYTES) + return -EINVAL; + + switch (request) { + case DP_AUX_NATIVE_WRITE: + case DP_AUX_I2C_WRITE: + case DP_AUX_NATIVE_READ: + case DP_AUX_I2C_READ: + regmap_write(pdata->regmap, SN_AUX_CMD_REG, request_val); + break; + default: + return -EINVAL; + } + + regmap_write(pdata->regmap, SN_AUX_ADDR_19_16_REG, + (msg->address >> 16) & 0xF); + regmap_write(pdata->regmap, SN_AUX_ADDR_15_8_REG, + (msg->address >> 8) & 0xFF); + regmap_write(pdata->regmap, SN_AUX_ADDR_7_0_REG, msg->address & 0xFF); + + regmap_write(pdata->regmap, SN_AUX_LENGTH_REG, msg->size); + + if (request == DP_AUX_NATIVE_WRITE || request == DP_AUX_I2C_WRITE) { + for (i = 0; i < msg->size; i++) + regmap_write(pdata->regmap, SN_AUX_WDATA_REG(i), + buf[i]); + } + + regmap_write(pdata->regmap, SN_AUX_CMD_REG, request_val | AUX_CMD_SEND); + + ret = readx_poll_timeout(ti_sn_cmd_done, pdata, cmd_done, cmd_done, + 200, 50 * 1000); + if (ret) + return ret; + + ret = regmap_read(pdata->regmap, SN_AUX_CMD_STATUS_REG, &val); + if (ret) + return ret; + else if ((val & AUX_IRQ_STATUS_NAT_I2C_FAIL) + || (val & AUX_IRQ_STATUS_AUX_RPLY_TOUT) + || (val & AUX_IRQ_STATUS_AUX_SHORT)) + return -ENXIO; + + if (request == DP_AUX_NATIVE_WRITE || request == DP_AUX_I2C_WRITE) + return msg->size; + + for (i = 0; i < msg->size; i++) { + unsigned int val; + ret = regmap_read(pdata->regmap, SN_AUX_RDATA_REG(i), + &val); + if (ret) + return ret; + + WARN_ON(val & ~0xFF); + buf[i] = (u8)(val & 0xFF); + } + + return msg->size; +} + static int ti_sn_bridge_parse_dsi_host(struct ti_sn_bridge *pdata) { struct device_node *np = pdata->dev->of_node; @@ -606,6 +704,11 @@ static int ti_sn_bridge_probe(struct i2c_client *client, i2c_set_clientdata(client, pdata); + pdata->aux.name = "ti-sn65dsi86-aux"; + pdata->aux.dev = pdata->dev; + pdata->aux.transfer = ti_sn_aux_transfer; + drm_dp_aux_register(&pdata->aux); + pdata->bridge.funcs = &ti_sn_bridge_funcs; pdata->bridge.of_node = client->dev.of_node;