diff options
author | Archit Taneja <architt@codeaurora.org> | 2018-01-17 01:05:27 -0500 |
---|---|---|
committer | Rob Clark <robdclark@gmail.com> | 2018-02-20 10:41:21 -0500 |
commit | ff73ff19406098f71ec7628b951e0765f1df8128 (patch) | |
tree | 453848b889f930350430d98cb518abc0d42ae796 /drivers | |
parent | 28e4309ab9c2bade2a93bd3b4c583be5ec440b84 (diff) |
drm/msm/dsi: Populate the 10nm PHY funcs
Populate the PHY ops with the downstream driver as reference.
There are a couple of TODOs which need to be resolved:
- The PHY timings are all hardcoded for now. This needs to be replaced
with automatic calculations once we get/understand them.
- There are some lane configuration registers which use a new
representation between physical and logical lane mappings. For now,
we've hardcoced them to follow the default mapping (i.e
logical 0 -> phy 0, logical 1 -> phy 1 etc).
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Signed-off-by: Rob Clark <robdclark@gmail.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c index b7545fb63bf5..0af951aaeea1 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c | |||
@@ -8,9 +8,208 @@ | |||
8 | #include "dsi_phy.h" | 8 | #include "dsi_phy.h" |
9 | #include "dsi.xml.h" | 9 | #include "dsi.xml.h" |
10 | 10 | ||
11 | static int dsi_phy_hw_v3_0_is_pll_on(struct msm_dsi_phy *phy) | ||
12 | { | ||
13 | void __iomem *base = phy->base; | ||
14 | u32 data = 0; | ||
15 | |||
16 | data = dsi_phy_read(base + REG_DSI_10nm_PHY_CMN_PLL_CNTRL); | ||
17 | mb(); /* make sure read happened */ | ||
18 | |||
19 | return (data & BIT(0)); | ||
20 | } | ||
21 | |||
22 | static void dsi_phy_hw_v3_0_config_lpcdrx(struct msm_dsi_phy *phy, bool enable) | ||
23 | { | ||
24 | void __iomem *lane_base = phy->lane_base; | ||
25 | int phy_lane_0 = 0; /* TODO: Support all lane swap configs */ | ||
26 | |||
27 | /* | ||
28 | * LPRX and CDRX need to enabled only for physical data lane | ||
29 | * corresponding to the logical data lane 0 | ||
30 | */ | ||
31 | if (enable) | ||
32 | dsi_phy_write(lane_base + | ||
33 | REG_DSI_10nm_PHY_LN_LPRX_CTRL(phy_lane_0), 0x3); | ||
34 | else | ||
35 | dsi_phy_write(lane_base + | ||
36 | REG_DSI_10nm_PHY_LN_LPRX_CTRL(phy_lane_0), 0); | ||
37 | } | ||
38 | |||
39 | static void dsi_phy_hw_v3_0_lane_settings(struct msm_dsi_phy *phy) | ||
40 | { | ||
41 | int i; | ||
42 | u8 tx_dctrl[] = { 0x00, 0x00, 0x00, 0x04, 0x01 }; | ||
43 | void __iomem *lane_base = phy->lane_base; | ||
44 | |||
45 | /* Strength ctrl settings */ | ||
46 | for (i = 0; i < 5; i++) { | ||
47 | dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_LPTX_STR_CTRL(i), | ||
48 | 0x55); | ||
49 | /* | ||
50 | * Disable LPRX and CDRX for all lanes. And later on, it will | ||
51 | * be only enabled for the physical data lane corresponding | ||
52 | * to the logical data lane 0 | ||
53 | */ | ||
54 | dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_LPRX_CTRL(i), 0); | ||
55 | dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_PIN_SWAP(i), 0x0); | ||
56 | dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_HSTX_STR_CTRL(i), | ||
57 | 0x88); | ||
58 | } | ||
59 | |||
60 | dsi_phy_hw_v3_0_config_lpcdrx(phy, true); | ||
61 | |||
62 | /* other settings */ | ||
63 | for (i = 0; i < 5; i++) { | ||
64 | dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG0(i), 0x0); | ||
65 | dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG1(i), 0x0); | ||
66 | dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG2(i), 0x0); | ||
67 | dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_CFG3(i), | ||
68 | i == 4 ? 0x80 : 0x0); | ||
69 | dsi_phy_write(lane_base + | ||
70 | REG_DSI_10nm_PHY_LN_OFFSET_TOP_CTRL(i), 0x0); | ||
71 | dsi_phy_write(lane_base + | ||
72 | REG_DSI_10nm_PHY_LN_OFFSET_BOT_CTRL(i), 0x0); | ||
73 | dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(i), | ||
74 | tx_dctrl[i]); | ||
75 | } | ||
76 | |||
77 | /* Toggle BIT 0 to release freeze I/0 */ | ||
78 | dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(3), 0x05); | ||
79 | dsi_phy_write(lane_base + REG_DSI_10nm_PHY_LN_TX_DCTRL(3), 0x04); | ||
80 | } | ||
81 | |||
82 | static int msm_dsi_dphy_timing_calc_v3(struct msm_dsi_dphy_timing *timing, | ||
83 | struct msm_dsi_phy_clk_request *clk_req) | ||
84 | { | ||
85 | /* | ||
86 | * TODO: These params need to be computed, they're currently hardcoded | ||
87 | * for a 1440x2560@60Hz panel with a byteclk of 100.618 Mhz, and a | ||
88 | * default escape clock of 19.2 Mhz. | ||
89 | */ | ||
90 | |||
91 | timing->hs_halfbyte_en = 0; | ||
92 | timing->clk_zero = 0x1c; | ||
93 | timing->clk_prepare = 0x07; | ||
94 | timing->clk_trail = 0x07; | ||
95 | timing->hs_exit = 0x23; | ||
96 | timing->hs_zero = 0x21; | ||
97 | timing->hs_prepare = 0x07; | ||
98 | timing->hs_trail = 0x07; | ||
99 | timing->hs_rqst = 0x05; | ||
100 | timing->ta_sure = 0x00; | ||
101 | timing->ta_go = 0x03; | ||
102 | timing->ta_get = 0x04; | ||
103 | |||
104 | timing->shared_timings.clk_pre = 0x2d; | ||
105 | timing->shared_timings.clk_post = 0x0d; | ||
106 | |||
107 | return 0; | ||
108 | } | ||
109 | |||
11 | static int dsi_10nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id, | 110 | static int dsi_10nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id, |
12 | struct msm_dsi_phy_clk_request *clk_req) | 111 | struct msm_dsi_phy_clk_request *clk_req) |
13 | { | 112 | { |
113 | int ret; | ||
114 | u32 status; | ||
115 | u32 const delay_us = 5; | ||
116 | u32 const timeout_us = 1000; | ||
117 | struct msm_dsi_dphy_timing *timing = &phy->timing; | ||
118 | void __iomem *base = phy->base; | ||
119 | u32 data; | ||
120 | |||
121 | DBG(""); | ||
122 | |||
123 | if (msm_dsi_dphy_timing_calc_v3(timing, clk_req)) { | ||
124 | dev_err(&phy->pdev->dev, | ||
125 | "%s: D-PHY timing calculation failed\n", __func__); | ||
126 | return -EINVAL; | ||
127 | } | ||
128 | |||
129 | if (dsi_phy_hw_v3_0_is_pll_on(phy)) | ||
130 | pr_warn("PLL turned on before configuring PHY\n"); | ||
131 | |||
132 | /* wait for REFGEN READY */ | ||
133 | ret = readl_poll_timeout_atomic(base + REG_DSI_10nm_PHY_CMN_PHY_STATUS, | ||
134 | status, (status & BIT(0)), | ||
135 | delay_us, timeout_us); | ||
136 | if (ret) { | ||
137 | pr_err("Ref gen not ready. Aborting\n"); | ||
138 | return -EINVAL; | ||
139 | } | ||
140 | |||
141 | /* de-assert digital and pll power down */ | ||
142 | data = BIT(6) | BIT(5); | ||
143 | dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_0, data); | ||
144 | |||
145 | /* Assert PLL core reset */ | ||
146 | dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_PLL_CNTRL, 0x00); | ||
147 | |||
148 | /* turn off resync FIFO */ | ||
149 | dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0x00); | ||
150 | |||
151 | /* Select MS1 byte-clk */ | ||
152 | dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_GLBL_CTRL, 0x10); | ||
153 | |||
154 | /* Enable LDO */ | ||
155 | dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_VREG_CTRL, 0x59); | ||
156 | |||
157 | /* Configure PHY lane swap (TODO: we need to calculate this) */ | ||
158 | dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_LANE_CFG0, 0x21); | ||
159 | dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_LANE_CFG1, 0x84); | ||
160 | |||
161 | /* DSI PHY timings */ | ||
162 | dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_0, | ||
163 | timing->hs_halfbyte_en); | ||
164 | dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_1, | ||
165 | timing->clk_zero); | ||
166 | dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_2, | ||
167 | timing->clk_prepare); | ||
168 | dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_3, | ||
169 | timing->clk_trail); | ||
170 | dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_4, | ||
171 | timing->hs_exit); | ||
172 | dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_5, | ||
173 | timing->hs_zero); | ||
174 | dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_6, | ||
175 | timing->hs_prepare); | ||
176 | dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_7, | ||
177 | timing->hs_trail); | ||
178 | dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_8, | ||
179 | timing->hs_rqst); | ||
180 | dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_9, | ||
181 | timing->ta_go | (timing->ta_sure << 3)); | ||
182 | dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_10, | ||
183 | timing->ta_get); | ||
184 | dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_TIMING_CTRL_11, | ||
185 | 0x00); | ||
186 | |||
187 | /* Remove power down from all blocks */ | ||
188 | dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_0, 0x7f); | ||
189 | |||
190 | /* power up lanes */ | ||
191 | data = dsi_phy_read(base + REG_DSI_10nm_PHY_CMN_CTRL_0); | ||
192 | |||
193 | /* TODO: only power up lanes that are used */ | ||
194 | data |= 0x1F; | ||
195 | dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_0, data); | ||
196 | dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_LANE_CTRL0, 0x1F); | ||
197 | |||
198 | /* Select full-rate mode */ | ||
199 | dsi_phy_write(base + REG_DSI_10nm_PHY_CMN_CTRL_2, 0x40); | ||
200 | |||
201 | ret = msm_dsi_pll_set_usecase(phy->pll, phy->usecase); | ||
202 | if (ret) { | ||
203 | dev_err(&phy->pdev->dev, "%s: set pll usecase failed, %d\n", | ||
204 | __func__, ret); | ||
205 | return ret; | ||
206 | } | ||
207 | |||
208 | /* DSI lane settings */ | ||
209 | dsi_phy_hw_v3_0_lane_settings(phy); | ||
210 | |||
211 | DBG("DSI%d PHY enabled", phy->id); | ||
212 | |||
14 | return 0; | 213 | return 0; |
15 | } | 214 | } |
16 | 215 | ||