From patchwork Wed Nov 18 10:55:22 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Archit Taneja X-Patchwork-Id: 7647941 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id EC9E4BF90C for ; Wed, 18 Nov 2015 10:55:48 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 8714120620 for ; Wed, 18 Nov 2015 10:55:47 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 13CCA2022A for ; Wed, 18 Nov 2015 10:55:46 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 3EB356E56C; Wed, 18 Nov 2015 02:55:45 -0800 (PST) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from smtp.codeaurora.org (smtp.codeaurora.org [198.145.29.96]) by gabe.freedesktop.org (Postfix) with ESMTPS id 79D426E56C for ; Wed, 18 Nov 2015 02:55:44 -0800 (PST) Received: from smtp.codeaurora.org (localhost [127.0.0.1]) by smtp.codeaurora.org (Postfix) with ESMTP id 472151415BB; Wed, 18 Nov 2015 10:55:44 +0000 (UTC) Received: by smtp.codeaurora.org (Postfix, from userid 486) id 31B091415C5; Wed, 18 Nov 2015 10:55:44 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-4.8 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from localhost (unknown [202.46.23.61]) (using TLSv1.2 with cipher DHE-RSA-AES128-SHA (128/128 bits)) (No client certificate requested) (Authenticated sender: architt@smtp.codeaurora.org) by smtp.codeaurora.org (Postfix) with ESMTPSA id 61ADA1415BB; Wed, 18 Nov 2015 10:55:42 +0000 (UTC) From: Archit Taneja To: dri-devel@lists.freedesktop.org, robdclark@gmail.com Subject: [PATCH v2 01/10] drm/msm/dsi: Add support for 28nm PHY on 8960 Date: Wed, 18 Nov 2015 16:25:22 +0530 Message-Id: <1447844131-4182-2-git-send-email-architt@codeaurora.org> X-Mailer: git-send-email 1.8.2.1 In-Reply-To: <1447844131-4182-1-git-send-email-architt@codeaurora.org> References: <1444827544-25656-1-git-send-email-architt@codeaurora.org> <1447844131-4182-1-git-send-email-architt@codeaurora.org> X-Virus-Scanned: ClamAV using ClamSMTP Cc: linux-arm-msm@vger.kernel.org X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Virus-Scanned: ClamAV using ClamSMTP DSI PHY on MSM8960 and APQ8064 is a 28nm PHY that's different from the supported 28nm LP PHY found in newer chips. Add support for the new PHY. Signed-off-by: Archit Taneja --- drivers/gpu/drm/msm/Kconfig | 8 + drivers/gpu/drm/msm/Makefile | 1 + drivers/gpu/drm/msm/dsi/dsi.h | 1 + drivers/gpu/drm/msm/dsi/phy/dsi_phy.c | 4 + drivers/gpu/drm/msm/dsi/phy/dsi_phy.h | 1 + drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c | 195 ++++++++++++++++++++++++ 6 files changed, 210 insertions(+) create mode 100644 drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 84d3ec9..215495c 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -54,3 +54,11 @@ config DRM_MSM_DSI_20NM_PHY default y help Choose this option if the 20nm DSI PHY is used on the platform. + +config DRM_MSM_DSI_28NM_8960_PHY + bool "Enable DSI 28nm 8960 PHY driver in MSM DRM" + depends on DRM_MSM_DSI + default y + help + Choose this option if the 28nm DSI PHY 8960 variant is used on the + platform. diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 1c90290..7523eca 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -62,6 +62,7 @@ msm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi.o \ msm-$(CONFIG_DRM_MSM_DSI_28NM_PHY) += dsi/phy/dsi_phy_28nm.o msm-$(CONFIG_DRM_MSM_DSI_20NM_PHY) += dsi/phy/dsi_phy_20nm.o +msm-$(CONFIG_DRM_MSM_DSI_28NM_8960_PHY) += dsi/phy/dsi_phy_28nm_8960.o ifeq ($(CONFIG_DRM_MSM_DSI_PLL),y) msm-y += dsi/pll/dsi_pll.o diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h index 5f5a373..8140e8b 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.h +++ b/drivers/gpu/drm/msm/dsi/dsi.h @@ -31,6 +31,7 @@ enum msm_dsi_phy_type { MSM_DSI_PHY_28NM_HPM, MSM_DSI_PHY_28NM_LP, MSM_DSI_PHY_20NM, + MSM_DSI_PHY_28NM_8960, MSM_DSI_PHY_MAX }; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index f1f955f..91a95fb 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c @@ -277,6 +277,10 @@ static const struct of_device_id dsi_phy_dt_match[] = { { .compatible = "qcom,dsi-phy-20nm", .data = &dsi_phy_20nm_cfgs }, #endif +#ifdef CONFIG_DRM_MSM_DSI_28NM_8960_PHY + { .compatible = "qcom,dsi-phy-28nm-8960", + .data = &dsi_phy_28nm_8960_cfgs }, +#endif {} }; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h index 0456b25..0d54ed0 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h @@ -43,6 +43,7 @@ struct msm_dsi_phy_cfg { extern const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_28nm_lp_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_20nm_cfgs; +extern const struct msm_dsi_phy_cfg dsi_phy_28nm_8960_cfgs; struct msm_dsi_dphy_timing { u32 clk_pre; diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c new file mode 100644 index 0000000..197b039 --- /dev/null +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "dsi_phy.h" +#include "dsi.xml.h" + +static void dsi_28nm_dphy_set_timing(struct msm_dsi_phy *phy, + struct msm_dsi_dphy_timing *timing) +{ + void __iomem *base = phy->base; + + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_0, + DSI_28nm_8960_PHY_TIMING_CTRL_0_CLK_ZERO(timing->clk_zero)); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_1, + DSI_28nm_8960_PHY_TIMING_CTRL_1_CLK_TRAIL(timing->clk_trail)); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_2, + DSI_28nm_8960_PHY_TIMING_CTRL_2_CLK_PREPARE(timing->clk_prepare)); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_3, 0x0); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_4, + DSI_28nm_8960_PHY_TIMING_CTRL_4_HS_EXIT(timing->hs_exit)); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_5, + DSI_28nm_8960_PHY_TIMING_CTRL_5_HS_ZERO(timing->hs_zero)); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_6, + DSI_28nm_8960_PHY_TIMING_CTRL_6_HS_PREPARE(timing->hs_prepare)); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_7, + DSI_28nm_8960_PHY_TIMING_CTRL_7_HS_TRAIL(timing->hs_trail)); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_8, + DSI_28nm_8960_PHY_TIMING_CTRL_8_HS_RQST(timing->hs_rqst)); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_9, + DSI_28nm_8960_PHY_TIMING_CTRL_9_TA_GO(timing->ta_go) | + DSI_28nm_8960_PHY_TIMING_CTRL_9_TA_SURE(timing->ta_sure)); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_10, + DSI_28nm_8960_PHY_TIMING_CTRL_10_TA_GET(timing->ta_get)); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_11, + DSI_28nm_8960_PHY_TIMING_CTRL_11_TRIG3_CMD(0)); +} + +static void dsi_28nm_phy_regulator_init(struct msm_dsi_phy *phy) +{ + void __iomem *base = phy->reg_base; + + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_0, 0x3); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_1, 1); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_2, 1); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_3, 0); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_4, + 0x100); +} + +static void dsi_28nm_phy_regulator_ctrl(struct msm_dsi_phy *phy) +{ + void __iomem *base = phy->reg_base; + + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_0, 0x3); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_1, 0xa); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_2, 0x4); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_3, 0x0); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_4, 0x20); +} + +static void dsi_28nm_phy_calibration(struct msm_dsi_phy *phy) +{ + void __iomem *base = phy->reg_base; + u32 status; + int i = 5000; + + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CAL_PWR_CFG, + 0x3); + + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_SW_CFG_2, 0x0); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_HW_CFG_1, 0x5a); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_HW_CFG_3, 0x10); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_HW_CFG_4, 0x1); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_HW_CFG_0, 0x1); + + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_HW_TRIGGER, 0x1); + usleep_range(5000, 6000); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_HW_TRIGGER, 0x0); + + do { + status = dsi_phy_read(base + + REG_DSI_28nm_8960_PHY_MISC_CAL_STATUS); + + if (!(status & DSI_28nm_8960_PHY_MISC_CAL_STATUS_CAL_BUSY)) + break; + + udelay(1); + } while (--i > 0); +} + +static void dsi_28nm_phy_lane_config(struct msm_dsi_phy *phy) +{ + void __iomem *base = phy->base; + int i; + + for (i = 0; i < 4; i++) { + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_CFG_0(i), 0x80); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_CFG_1(i), 0x45); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_CFG_2(i), 0x00); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_TEST_DATAPATH(i), + 0x00); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_TEST_STR_0(i), + 0x01); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_TEST_STR_1(i), + 0x66); + } + + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LNCK_CFG_0, 0x40); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LNCK_CFG_1, 0x67); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LNCK_CFG_2, 0x0); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LNCK_TEST_DATAPATH, 0x0); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LNCK_TEST_STR0, 0x1); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LNCK_TEST_STR1, 0x88); +} + +static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id, + const unsigned long bit_rate, const unsigned long esc_rate) +{ + struct msm_dsi_dphy_timing *timing = &phy->timing; + void __iomem *base = phy->base; + + DBG(""); + + if (msm_dsi_dphy_timing_calc(timing, bit_rate, esc_rate)) { + dev_err(&phy->pdev->dev, + "%s: D-PHY timing calculation failed\n", __func__); + return -EINVAL; + } + + dsi_28nm_phy_regulator_init(phy); + + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LDO_CTRL, 0x04); + + /* strength control */ + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_STRENGTH_0, 0xff); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_STRENGTH_1, 0x00); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_STRENGTH_2, 0x06); + + /* phy ctrl */ + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_CTRL_0, 0x5f); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_CTRL_1, 0x00); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_CTRL_2, 0x00); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_CTRL_3, 0x10); + + dsi_28nm_phy_regulator_ctrl(phy); + + dsi_28nm_phy_calibration(phy); + + dsi_28nm_phy_lane_config(phy); + + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_BIST_CTRL_4, 0x0f); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_BIST_CTRL_1, 0x03); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_BIST_CTRL_0, 0x03); + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_BIST_CTRL_4, 0x0); + + dsi_28nm_dphy_set_timing(phy, timing); + + return 0; +} + +static void dsi_28nm_phy_disable(struct msm_dsi_phy *phy) +{ + dsi_phy_write(phy->base + REG_DSI_28nm_8960_PHY_CTRL_0, 0x0); + + /* + * Wait for the registers writes to complete in order to + * ensure that the phy is completely disabled + */ + wmb(); +} + +const struct msm_dsi_phy_cfg dsi_phy_28nm_8960_cfgs = { + .type = MSM_DSI_PHY_28NM_8960, + .src_pll_truthtable = { {true, true}, {false, true} }, + .reg_cfg = { + .num = 1, + .regs = { + {"vddio", 1800000, 1800000, 100000, 100}, + }, + }, + .ops = { + .enable = dsi_28nm_phy_enable, + .disable = dsi_28nm_phy_disable, + }, +};