Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/msm/dsi: Add support for 28nm PHY on 8960

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 <architt@codeaurora.org>
Signed-off-by: Rob Clark <robdclark@gmail.com>

authored by

Archit Taneja and committed by
Rob Clark
225380b3 e6c4c78c

+210
+8
drivers/gpu/drm/msm/Kconfig
··· 54 54 default y 55 55 help 56 56 Choose this option if the 20nm DSI PHY is used on the platform. 57 + 58 + config DRM_MSM_DSI_28NM_8960_PHY 59 + bool "Enable DSI 28nm 8960 PHY driver in MSM DRM" 60 + depends on DRM_MSM_DSI 61 + default y 62 + help 63 + Choose this option if the 28nm DSI PHY 8960 variant is used on the 64 + platform.
+1
drivers/gpu/drm/msm/Makefile
··· 63 63 64 64 msm-$(CONFIG_DRM_MSM_DSI_28NM_PHY) += dsi/phy/dsi_phy_28nm.o 65 65 msm-$(CONFIG_DRM_MSM_DSI_20NM_PHY) += dsi/phy/dsi_phy_20nm.o 66 + msm-$(CONFIG_DRM_MSM_DSI_28NM_8960_PHY) += dsi/phy/dsi_phy_28nm_8960.o 66 67 67 68 ifeq ($(CONFIG_DRM_MSM_DSI_PLL),y) 68 69 msm-y += dsi/pll/dsi_pll.o
+1
drivers/gpu/drm/msm/dsi/dsi.h
··· 31 31 MSM_DSI_PHY_28NM_HPM, 32 32 MSM_DSI_PHY_28NM_LP, 33 33 MSM_DSI_PHY_20NM, 34 + MSM_DSI_PHY_28NM_8960, 34 35 MSM_DSI_PHY_MAX 35 36 }; 36 37
+4
drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
··· 277 277 { .compatible = "qcom,dsi-phy-20nm", 278 278 .data = &dsi_phy_20nm_cfgs }, 279 279 #endif 280 + #ifdef CONFIG_DRM_MSM_DSI_28NM_8960_PHY 281 + { .compatible = "qcom,dsi-phy-28nm-8960", 282 + .data = &dsi_phy_28nm_8960_cfgs }, 283 + #endif 280 284 {} 281 285 }; 282 286
+1
drivers/gpu/drm/msm/dsi/phy/dsi_phy.h
··· 43 43 extern const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_cfgs; 44 44 extern const struct msm_dsi_phy_cfg dsi_phy_28nm_lp_cfgs; 45 45 extern const struct msm_dsi_phy_cfg dsi_phy_20nm_cfgs; 46 + extern const struct msm_dsi_phy_cfg dsi_phy_28nm_8960_cfgs; 46 47 47 48 struct msm_dsi_dphy_timing { 48 49 u32 clk_pre;
+195
drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c
··· 1 + /* 2 + * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 and 6 + * only version 2 as published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + */ 13 + 14 + #include "dsi_phy.h" 15 + #include "dsi.xml.h" 16 + 17 + static void dsi_28nm_dphy_set_timing(struct msm_dsi_phy *phy, 18 + struct msm_dsi_dphy_timing *timing) 19 + { 20 + void __iomem *base = phy->base; 21 + 22 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_0, 23 + DSI_28nm_8960_PHY_TIMING_CTRL_0_CLK_ZERO(timing->clk_zero)); 24 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_1, 25 + DSI_28nm_8960_PHY_TIMING_CTRL_1_CLK_TRAIL(timing->clk_trail)); 26 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_2, 27 + DSI_28nm_8960_PHY_TIMING_CTRL_2_CLK_PREPARE(timing->clk_prepare)); 28 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_3, 0x0); 29 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_4, 30 + DSI_28nm_8960_PHY_TIMING_CTRL_4_HS_EXIT(timing->hs_exit)); 31 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_5, 32 + DSI_28nm_8960_PHY_TIMING_CTRL_5_HS_ZERO(timing->hs_zero)); 33 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_6, 34 + DSI_28nm_8960_PHY_TIMING_CTRL_6_HS_PREPARE(timing->hs_prepare)); 35 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_7, 36 + DSI_28nm_8960_PHY_TIMING_CTRL_7_HS_TRAIL(timing->hs_trail)); 37 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_8, 38 + DSI_28nm_8960_PHY_TIMING_CTRL_8_HS_RQST(timing->hs_rqst)); 39 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_9, 40 + DSI_28nm_8960_PHY_TIMING_CTRL_9_TA_GO(timing->ta_go) | 41 + DSI_28nm_8960_PHY_TIMING_CTRL_9_TA_SURE(timing->ta_sure)); 42 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_10, 43 + DSI_28nm_8960_PHY_TIMING_CTRL_10_TA_GET(timing->ta_get)); 44 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_11, 45 + DSI_28nm_8960_PHY_TIMING_CTRL_11_TRIG3_CMD(0)); 46 + } 47 + 48 + static void dsi_28nm_phy_regulator_init(struct msm_dsi_phy *phy) 49 + { 50 + void __iomem *base = phy->reg_base; 51 + 52 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_0, 0x3); 53 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_1, 1); 54 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_2, 1); 55 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_3, 0); 56 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_4, 57 + 0x100); 58 + } 59 + 60 + static void dsi_28nm_phy_regulator_ctrl(struct msm_dsi_phy *phy) 61 + { 62 + void __iomem *base = phy->reg_base; 63 + 64 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_0, 0x3); 65 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_1, 0xa); 66 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_2, 0x4); 67 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_3, 0x0); 68 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_4, 0x20); 69 + } 70 + 71 + static void dsi_28nm_phy_calibration(struct msm_dsi_phy *phy) 72 + { 73 + void __iomem *base = phy->reg_base; 74 + u32 status; 75 + int i = 5000; 76 + 77 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CAL_PWR_CFG, 78 + 0x3); 79 + 80 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_SW_CFG_2, 0x0); 81 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_HW_CFG_1, 0x5a); 82 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_HW_CFG_3, 0x10); 83 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_HW_CFG_4, 0x1); 84 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_HW_CFG_0, 0x1); 85 + 86 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_HW_TRIGGER, 0x1); 87 + usleep_range(5000, 6000); 88 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_HW_TRIGGER, 0x0); 89 + 90 + do { 91 + status = dsi_phy_read(base + 92 + REG_DSI_28nm_8960_PHY_MISC_CAL_STATUS); 93 + 94 + if (!(status & DSI_28nm_8960_PHY_MISC_CAL_STATUS_CAL_BUSY)) 95 + break; 96 + 97 + udelay(1); 98 + } while (--i > 0); 99 + } 100 + 101 + static void dsi_28nm_phy_lane_config(struct msm_dsi_phy *phy) 102 + { 103 + void __iomem *base = phy->base; 104 + int i; 105 + 106 + for (i = 0; i < 4; i++) { 107 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_CFG_0(i), 0x80); 108 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_CFG_1(i), 0x45); 109 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_CFG_2(i), 0x00); 110 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_TEST_DATAPATH(i), 111 + 0x00); 112 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_TEST_STR_0(i), 113 + 0x01); 114 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_TEST_STR_1(i), 115 + 0x66); 116 + } 117 + 118 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LNCK_CFG_0, 0x40); 119 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LNCK_CFG_1, 0x67); 120 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LNCK_CFG_2, 0x0); 121 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LNCK_TEST_DATAPATH, 0x0); 122 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LNCK_TEST_STR0, 0x1); 123 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LNCK_TEST_STR1, 0x88); 124 + } 125 + 126 + static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id, 127 + const unsigned long bit_rate, const unsigned long esc_rate) 128 + { 129 + struct msm_dsi_dphy_timing *timing = &phy->timing; 130 + void __iomem *base = phy->base; 131 + 132 + DBG(""); 133 + 134 + if (msm_dsi_dphy_timing_calc(timing, bit_rate, esc_rate)) { 135 + dev_err(&phy->pdev->dev, 136 + "%s: D-PHY timing calculation failed\n", __func__); 137 + return -EINVAL; 138 + } 139 + 140 + dsi_28nm_phy_regulator_init(phy); 141 + 142 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LDO_CTRL, 0x04); 143 + 144 + /* strength control */ 145 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_STRENGTH_0, 0xff); 146 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_STRENGTH_1, 0x00); 147 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_STRENGTH_2, 0x06); 148 + 149 + /* phy ctrl */ 150 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_CTRL_0, 0x5f); 151 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_CTRL_1, 0x00); 152 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_CTRL_2, 0x00); 153 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_CTRL_3, 0x10); 154 + 155 + dsi_28nm_phy_regulator_ctrl(phy); 156 + 157 + dsi_28nm_phy_calibration(phy); 158 + 159 + dsi_28nm_phy_lane_config(phy); 160 + 161 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_BIST_CTRL_4, 0x0f); 162 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_BIST_CTRL_1, 0x03); 163 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_BIST_CTRL_0, 0x03); 164 + dsi_phy_write(base + REG_DSI_28nm_8960_PHY_BIST_CTRL_4, 0x0); 165 + 166 + dsi_28nm_dphy_set_timing(phy, timing); 167 + 168 + return 0; 169 + } 170 + 171 + static void dsi_28nm_phy_disable(struct msm_dsi_phy *phy) 172 + { 173 + dsi_phy_write(phy->base + REG_DSI_28nm_8960_PHY_CTRL_0, 0x0); 174 + 175 + /* 176 + * Wait for the registers writes to complete in order to 177 + * ensure that the phy is completely disabled 178 + */ 179 + wmb(); 180 + } 181 + 182 + const struct msm_dsi_phy_cfg dsi_phy_28nm_8960_cfgs = { 183 + .type = MSM_DSI_PHY_28NM_8960, 184 + .src_pll_truthtable = { {true, true}, {false, true} }, 185 + .reg_cfg = { 186 + .num = 1, 187 + .regs = { 188 + {"vddio", 1800000, 1800000, 100000, 100}, 189 + }, 190 + }, 191 + .ops = { 192 + .enable = dsi_28nm_phy_enable, 193 + .disable = dsi_28nm_phy_disable, 194 + }, 195 + };