Received: by 2002:ac0:a594:0:0:0:0:0 with SMTP id m20-v6csp3044378imm; Thu, 17 May 2018 02:21:15 -0700 (PDT) X-Google-Smtp-Source: AB8JxZoB4m8PXXemzmJQk3epWriDTqIz4ZkvpBM5PIglWGSKnCrCsNTrEKaRKCBuw6bex4II06r2 X-Received: by 2002:a17:902:8d81:: with SMTP id v1-v6mr4262889plo.383.1526548875197; Thu, 17 May 2018 02:21:15 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1526548875; cv=none; d=google.com; s=arc-20160816; b=twRlPGgH7oILwYcORjS3Oll/3rxyC5HSCqxKDrp2ZxB5fisEyl+rsA796LAe+OJSBc 1bm5xSvH6YEHGbV+mOabQgdpRaqa61jKGS5/4sqwXPmp6zPmJsKb88Kv8LwMkUYkesWu 1lVT7Lu8/4Ysd9ANP0hCufMrQqvi+eeYp+KWTN/O9IWOPApnBNy8ftS+JAf11EHNS42f zmbYaYlOmQR1ffQ6+DPVRVbWtjQzkhrsZJmStClLrYt5W857JPlK9EbetcdO8U7HJPpj Up2PAEPnoC593DcOYYuDxbfDWgocVrhmsgRr5pLH6BeK16b7zLRzkUhH8zWXhSlAvG/m qngg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:date:subject:cc:to:from :arc-authentication-results; bh=sXKltUtXD/C/4m1O3bmHJYvzLz4UfuLmB8QrpoRir8w=; b=LNefwTh8iVBHWfBVqvnG5X/hsujmIXZP6RX8WaBhA9UdQdMDZJGE5uQRfFAFbr01iV H8pyyBTGItUJXLD1sp14pHasqQZVgfbwcHRkrDF7n6rbBm3ViZKePugDBK3FVJmG9ij/ 5KElW5UBACmbeZafJ+/RqEC2GniIjLxKW4SI1/tp2nECC7nxqK8yaqeMMNCBrteqFE4d r890ZKZd88NjDPqFDilqUu1Enh3RUGxVw/DXmm36AMVZ2N3DVLRiJQxO8wznYOtbemXt uo0USGvVFM167hb0dV/k92u5I/4zY8eVZNcSdm5fePuVjB3ZVneFptLx45CcYJgXmMw0 tNOg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-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 l36-v6si4782760plg.82.2018.05.17.02.21.00; Thu, 17 May 2018 02:21:15 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-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 linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751533AbeEQJSP (ORCPT + 99 others); Thu, 17 May 2018 05:18:15 -0400 Received: from mail-pg0-f66.google.com ([74.125.83.66]:46503 "EHLO mail-pg0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750825AbeEQJSK (ORCPT ); Thu, 17 May 2018 05:18:10 -0400 Received: by mail-pg0-f66.google.com with SMTP id u8-v6so1550076pgp.13; Thu, 17 May 2018 02:18:10 -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; bh=sXKltUtXD/C/4m1O3bmHJYvzLz4UfuLmB8QrpoRir8w=; b=WG3pSvyPyu95mK1Bnx+q9Xo5wZzswUZD9xVOnsFGUT5oUJPpAZV0Om4by+OuVVCF3P pDATu5R0/gOmsp3h6eBcQWpCIcMk7zp9MQvu7S6pcVHj4hMPaNEMs1tI1SM5bHVL/tO0 NHmuLLy/0/um3D7hZCXxokP+z7Sstb781he6XzWWCgKK2zfOcFNK9BH2PIcE51k9NJce VF1EnQj8RvS7Z+ymlGqd4XbEVK7xBwxFZLd48ru/ylJTZP6GkdZFHKhFUgbB5BF/DzAC IbYoNKcDwZ7Ury/aIu2Kpd05piYl2xhSHkXWb8WeoIGiHLa0jJr7m6USnEf+V7eiSqEi vNWQ== X-Gm-Message-State: ALKqPwfd+7J0bYl7gJGZWWY9qAjR/pFz/vR1leoag+2lGL31HUCxK6Rf jy6DxvmG5dGMOuCRDi/+R4s= X-Received: by 2002:a63:7256:: with SMTP id c22-v6mr12392pgn.318.1526548690084; Thu, 17 May 2018 02:18:10 -0700 (PDT) Received: from localhost.localdomain ([103.29.142.67]) by smtp.gmail.com with ESMTPSA id k24-v6sm10592175pfi.37.2018.05.17.02.18.04 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 17 May 2018 02:18:08 -0700 (PDT) From: Lin Huang To: seanpaul@chromium.org, airlied@linux.ie, zyw@rock-chips.com Cc: dianders@chromium.org, briannorris@chromium.org, linux-rockchip@lists.infradead.org, heiko@sntech.de, daniel.vetter@intel.com, jani.nikula@linux.intel.com, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, eballetbo@gmail.com, robh+dt@kernel.org, devicetree@vger.kernel.org, Lin Huang Subject: [PATCH v5 1/4] drm/rockchip: add transfer function for cdn-dp Date: Thu, 17 May 2018 17:17:57 +0800 Message-Id: <1526548680-2552-1-git-send-email-hl@rock-chips.com> X-Mailer: git-send-email 2.7.4 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Chris Zhong We may support training outside firmware, so we need support dpcd read/write to get the message or do some setting with display. Signed-off-by: Chris Zhong Signed-off-by: Lin Huang Reviewed-by: Sean Paul Reviewed-by: Enric Balletbo --- Changes in v2: - update patch following Enric suggest Changes in v3: - None Changes in v4: - None Changes in v5: - None drivers/gpu/drm/rockchip/cdn-dp-core.c | 55 +++++++++++++++++++++++---- drivers/gpu/drm/rockchip/cdn-dp-core.h | 1 + drivers/gpu/drm/rockchip/cdn-dp-reg.c | 69 ++++++++++++++++++++++++++++++---- drivers/gpu/drm/rockchip/cdn-dp-reg.h | 14 ++++++- 4 files changed, 122 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index c6fbdcd..cce64c1 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -176,8 +176,8 @@ static int cdn_dp_get_sink_count(struct cdn_dp_device *dp, u8 *sink_count) u8 value; *sink_count = 0; - ret = cdn_dp_dpcd_read(dp, DP_SINK_COUNT, &value, 1); - if (ret) + ret = drm_dp_dpcd_read(&dp->aux, DP_SINK_COUNT, &value, 1); + if (ret < 0) return ret; *sink_count = DP_GET_SINK_COUNT(value); @@ -374,9 +374,9 @@ static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp) if (!cdn_dp_check_sink_connection(dp)) return -ENODEV; - ret = cdn_dp_dpcd_read(dp, DP_DPCD_REV, dp->dpcd, - DP_RECEIVER_CAP_SIZE); - if (ret) { + ret = drm_dp_dpcd_read(&dp->aux, DP_DPCD_REV, dp->dpcd, + sizeof(dp->dpcd)); + if (ret < 0) { DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret); return ret; } @@ -582,8 +582,8 @@ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp) if (!port || !dp->link.rate || !dp->link.num_lanes) return false; - if (cdn_dp_dpcd_read(dp, DP_LANE0_1_STATUS, link_status, - DP_LINK_STATUS_SIZE)) { + if (drm_dp_dpcd_read_link_status(&dp->aux, link_status) != + DP_LINK_STATUS_SIZE) { DRM_ERROR("Failed to get link status\n"); return false; } @@ -1012,6 +1012,40 @@ static int cdn_dp_pd_event(struct notifier_block *nb, return NOTIFY_DONE; } +static ssize_t cdn_dp_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + struct cdn_dp_device *dp = container_of(aux, struct cdn_dp_device, aux); + int ret; + u8 status; + + switch (msg->request & ~DP_AUX_I2C_MOT) { + case DP_AUX_NATIVE_WRITE: + case DP_AUX_I2C_WRITE: + case DP_AUX_I2C_WRITE_STATUS_UPDATE: + ret = cdn_dp_dpcd_write(dp, msg->address, msg->buffer, + msg->size); + break; + case DP_AUX_NATIVE_READ: + case DP_AUX_I2C_READ: + ret = cdn_dp_dpcd_read(dp, msg->address, msg->buffer, + msg->size); + break; + default: + return -EINVAL; + } + + status = cdn_dp_get_aux_status(dp); + if (status == AUX_STATUS_ACK) + msg->reply = DP_AUX_NATIVE_REPLY_ACK; + else if (status == AUX_STATUS_NACK) + msg->reply = DP_AUX_NATIVE_REPLY_NACK; + else if (status == AUX_STATUS_DEFER) + msg->reply = DP_AUX_NATIVE_REPLY_DEFER; + + return ret; +} + static int cdn_dp_bind(struct device *dev, struct device *master, void *data) { struct cdn_dp_device *dp = dev_get_drvdata(dev); @@ -1030,6 +1064,13 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data) dp->active = false; dp->active_port = -1; dp->fw_loaded = false; + dp->aux.name = "DP-AUX"; + dp->aux.transfer = cdn_dp_aux_transfer; + dp->aux.dev = dev; + + ret = drm_dp_aux_register(&dp->aux); + if (ret) + return ret; INIT_WORK(&dp->event_work, cdn_dp_pd_event_work); diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index f57e296..46159b2 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -78,6 +78,7 @@ struct cdn_dp_device { struct platform_device *audio_pdev; struct work_struct event_work; struct edid *edid; + struct drm_dp_aux aux; struct mutex lock; bool connected; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c index eb3042c..979355d 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c @@ -221,7 +221,12 @@ static int cdn_dp_reg_write_bit(struct cdn_dp_device *dp, u16 addr, sizeof(field), field); } -int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len) +/* + * Returns the number of bytes transferred on success, or a negative + * error code on failure. -ETIMEDOUT is returned if mailbox message was + * not send successfully; + */ +ssize_t cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len) { u8 msg[5], reg[5]; int ret; @@ -247,24 +252,41 @@ int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len) goto err_dpcd_read; ret = cdn_dp_mailbox_read_receive(dp, data, len); + if (!ret) + return len; err_dpcd_read: + DRM_DEV_ERROR(dp->dev, "dpcd read failed: %d\n", ret); return ret; } -int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value) +#define CDN_AUX_HEADER_SIZE 5 +#define CDN_AUX_MSG_SIZE 20 +/* + * Returns the number of bytes transferred on success, or a negative error + * code on failure. -ETIMEDOUT is returned if mailbox message was not send + * success; -EINVAL is returned if get the wrong data size after message + * is sent + */ +ssize_t cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len) { - u8 msg[6], reg[5]; + u8 msg[CDN_AUX_MSG_SIZE + CDN_AUX_HEADER_SIZE]; + u8 reg[CDN_AUX_HEADER_SIZE]; int ret; - msg[0] = 0; - msg[1] = 1; + if (WARN_ON(len > CDN_AUX_MSG_SIZE) || WARN_ON(len <= 0)) + return -EINVAL; + + msg[0] = (len >> 8) & 0xff; + msg[1] = len & 0xff; msg[2] = (addr >> 16) & 0xff; msg[3] = (addr >> 8) & 0xff; msg[4] = addr & 0xff; - msg[5] = value; + + memcpy(msg + CDN_AUX_HEADER_SIZE, data, len); + ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_DPCD, - sizeof(msg), msg); + CDN_AUX_HEADER_SIZE + len, msg); if (ret) goto err_dpcd_write; @@ -277,8 +299,12 @@ int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value) if (ret) goto err_dpcd_write; - if (addr != (reg[2] << 16 | reg[3] << 8 | reg[4])) + if ((len != (reg[0] << 8 | reg[1])) || + (addr != (reg[2] << 16 | reg[3] << 8 | reg[4]))) { ret = -EINVAL; + } else { + return len; + } err_dpcd_write: if (ret) @@ -286,6 +312,33 @@ int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value) return ret; } +int cdn_dp_get_aux_status(struct cdn_dp_device *dp) +{ + u8 status; + int ret; + + ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, + DPTX_GET_LAST_AUX_STAUS, 0, NULL); + if (ret) + goto err_get_hpd; + + ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, + DPTX_GET_LAST_AUX_STAUS, + sizeof(status)); + if (ret) + goto err_get_hpd; + + ret = cdn_dp_mailbox_read_receive(dp, &status, sizeof(status)); + if (ret) + goto err_get_hpd; + + return status; + +err_get_hpd: + DRM_DEV_ERROR(dp->dev, "get aux status failed: %d\n", ret); + return ret; +} + int cdn_dp_load_firmware(struct cdn_dp_device *dp, const u32 *i_mem, u32 i_size, const u32 *d_mem, u32 d_size) { diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.h b/drivers/gpu/drm/rockchip/cdn-dp-reg.h index c4bbb4a83..6580b11 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.h @@ -328,6 +328,13 @@ #define GENERAL_BUS_SETTINGS 0x03 #define GENERAL_TEST_ACCESS 0x04 +/* AUX status*/ +#define AUX_STATUS_ACK 0 +#define AUX_STATUS_NACK 1 +#define AUX_STATUS_DEFER 2 +#define AUX_STATUS_SINK_ERROR 3 +#define AUX_STATUS_BUS_ERROR 4 + #define DPTX_SET_POWER_MNG 0x00 #define DPTX_SET_HOST_CAPABILITIES 0x01 #define DPTX_GET_EDID 0x02 @@ -469,8 +476,11 @@ int cdn_dp_set_host_cap(struct cdn_dp_device *dp, u8 lanes, bool flip); int cdn_dp_event_config(struct cdn_dp_device *dp); u32 cdn_dp_get_event(struct cdn_dp_device *dp); int cdn_dp_get_hpd_status(struct cdn_dp_device *dp); -int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value); -int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len); +ssize_t cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, + u8 *data, u16 len); +ssize_t cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, + u8 *data, u16 len); +int cdn_dp_get_aux_status(struct cdn_dp_device *dp); int cdn_dp_get_edid_block(void *dp, u8 *edid, unsigned int block, size_t length); int cdn_dp_train_link(struct cdn_dp_device *dp); -- 2.7.4