1caab277bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2ea184891SArchit Taneja /*
3ea184891SArchit Taneja * Copyright (c) 2016, The Linux Foundation. All rights reserved.
4ea184891SArchit Taneja * Copyright (C) 2013 Red Hat
5ea184891SArchit Taneja * Author: Rob Clark <robdclark@gmail.com>
6ea184891SArchit Taneja */
7ea184891SArchit Taneja
8ea184891SArchit Taneja #include <linux/clk-provider.h>
9feea39a8SSam Ravnborg #include <linux/delay.h>
10feea39a8SSam Ravnborg
11ea184891SArchit Taneja #include "hdmi.h"
12ea184891SArchit Taneja
13ea184891SArchit Taneja struct hdmi_pll_8960 {
14ea184891SArchit Taneja struct platform_device *pdev;
15ea184891SArchit Taneja struct clk_hw clk_hw;
16ea184891SArchit Taneja void __iomem *mmio;
17ea184891SArchit Taneja
18ea184891SArchit Taneja unsigned long pixclk;
19ea184891SArchit Taneja };
20ea184891SArchit Taneja
21ea184891SArchit Taneja #define hw_clk_to_pll(x) container_of(x, struct hdmi_pll_8960, clk_hw)
22ea184891SArchit Taneja
23ea184891SArchit Taneja /*
24ea184891SArchit Taneja * HDMI PLL:
25ea184891SArchit Taneja *
26ea184891SArchit Taneja * To get the parent clock setup properly, we need to plug in hdmi pll
27ea184891SArchit Taneja * configuration into common-clock-framework.
28ea184891SArchit Taneja */
29ea184891SArchit Taneja
30ea184891SArchit Taneja struct pll_rate {
31ea184891SArchit Taneja unsigned long rate;
32ea184891SArchit Taneja int num_reg;
33ea184891SArchit Taneja struct {
34ea184891SArchit Taneja u32 val;
35ea184891SArchit Taneja u32 reg;
36ea184891SArchit Taneja } conf[32];
37ea184891SArchit Taneja };
38ea184891SArchit Taneja
39ea184891SArchit Taneja /* NOTE: keep sorted highest freq to lowest: */
40ea184891SArchit Taneja static const struct pll_rate freqtbl[] = {
41ea184891SArchit Taneja { 154000000, 14, {
42ea184891SArchit Taneja { 0x08, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
43ea184891SArchit Taneja { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
44ea184891SArchit Taneja { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
45ea184891SArchit Taneja { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
46ea184891SArchit Taneja { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
47ea184891SArchit Taneja { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
48ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
49ea184891SArchit Taneja { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
50ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
51ea184891SArchit Taneja { 0x0d, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
52ea184891SArchit Taneja { 0x4d, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
53ea184891SArchit Taneja { 0x5e, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
54ea184891SArchit Taneja { 0x42, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
55ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
56ea184891SArchit Taneja }
57ea184891SArchit Taneja },
58ea184891SArchit Taneja /* 1080p60/1080p50 case */
59ea184891SArchit Taneja { 148500000, 27, {
60ea184891SArchit Taneja { 0x02, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
61ea184891SArchit Taneja { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG },
62ea184891SArchit Taneja { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
63ea184891SArchit Taneja { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
64ea184891SArchit Taneja { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG },
65ea184891SArchit Taneja { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG },
66ea184891SArchit Taneja { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B },
67ea184891SArchit Taneja { 0x76, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
68ea184891SArchit Taneja { 0x01, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
69ea184891SArchit Taneja { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
70ea184891SArchit Taneja { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
71ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
72ea184891SArchit Taneja { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0 },
73ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1 },
74ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2 },
75ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG3 },
76ea184891SArchit Taneja { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0 },
77ea184891SArchit Taneja { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1 },
78ea184891SArchit Taneja { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2 },
79ea184891SArchit Taneja { 0xe6, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
80ea184891SArchit Taneja { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
81ea184891SArchit Taneja { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
82ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
83ea184891SArchit Taneja { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
84ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
85ea184891SArchit Taneja { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 },
86ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 },
87ea184891SArchit Taneja }
88ea184891SArchit Taneja },
89ea184891SArchit Taneja { 108000000, 13, {
90ea184891SArchit Taneja { 0x08, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
91ea184891SArchit Taneja { 0x21, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
92ea184891SArchit Taneja { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
93ea184891SArchit Taneja { 0x1c, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
94ea184891SArchit Taneja { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
95ea184891SArchit Taneja { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
96ea184891SArchit Taneja { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
97ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
98ea184891SArchit Taneja { 0x49, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
99ea184891SArchit Taneja { 0x49, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
100ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
101ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
102ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
103ea184891SArchit Taneja }
104ea184891SArchit Taneja },
105ea184891SArchit Taneja /* 720p60/720p50/1080i60/1080i50/1080p24/1080p30/1080p25 */
106ea184891SArchit Taneja { 74250000, 8, {
107ea184891SArchit Taneja { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B },
108ea184891SArchit Taneja { 0x12, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
109ea184891SArchit Taneja { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
110ea184891SArchit Taneja { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
111ea184891SArchit Taneja { 0x76, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
112ea184891SArchit Taneja { 0xe6, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
113ea184891SArchit Taneja { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
114ea184891SArchit Taneja { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
115ea184891SArchit Taneja }
116ea184891SArchit Taneja },
117ea184891SArchit Taneja { 74176000, 14, {
118ea184891SArchit Taneja { 0x18, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
119ea184891SArchit Taneja { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
120ea184891SArchit Taneja { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
121ea184891SArchit Taneja { 0xe5, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
122ea184891SArchit Taneja { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
123ea184891SArchit Taneja { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
124ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
125ea184891SArchit Taneja { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
126ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
127ea184891SArchit Taneja { 0x0c, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
128ea184891SArchit Taneja { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
129ea184891SArchit Taneja { 0x7d, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
130ea184891SArchit Taneja { 0xbc, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
131ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
132ea184891SArchit Taneja }
133ea184891SArchit Taneja },
134ea184891SArchit Taneja { 65000000, 14, {
135ea184891SArchit Taneja { 0x18, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
136ea184891SArchit Taneja { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
137ea184891SArchit Taneja { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
138ea184891SArchit Taneja { 0x8a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
139ea184891SArchit Taneja { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
140ea184891SArchit Taneja { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
141ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
142ea184891SArchit Taneja { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
143ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
144ea184891SArchit Taneja { 0x0b, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
145ea184891SArchit Taneja { 0x4b, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
146ea184891SArchit Taneja { 0x7b, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
147ea184891SArchit Taneja { 0x09, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
148ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
149ea184891SArchit Taneja }
150ea184891SArchit Taneja },
151ea184891SArchit Taneja /* 480p60/480i60 */
152ea184891SArchit Taneja { 27030000, 18, {
153ea184891SArchit Taneja { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B },
154ea184891SArchit Taneja { 0x38, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
155ea184891SArchit Taneja { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG },
156ea184891SArchit Taneja { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
157ea184891SArchit Taneja { 0xff, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
158ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
159ea184891SArchit Taneja { 0x4e, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
160ea184891SArchit Taneja { 0xd7, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
161ea184891SArchit Taneja { 0x03, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
162ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
163ea184891SArchit Taneja { 0x2a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
164ea184891SArchit Taneja { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
165ea184891SArchit Taneja { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
166ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
167ea184891SArchit Taneja { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
168ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
169ea184891SArchit Taneja { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 },
170ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 },
171ea184891SArchit Taneja }
172ea184891SArchit Taneja },
173ea184891SArchit Taneja /* 576p50/576i50 */
174ea184891SArchit Taneja { 27000000, 27, {
175ea184891SArchit Taneja { 0x32, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
176ea184891SArchit Taneja { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG },
177ea184891SArchit Taneja { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
178ea184891SArchit Taneja { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
179ea184891SArchit Taneja { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG },
180ea184891SArchit Taneja { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG },
181ea184891SArchit Taneja { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B },
182ea184891SArchit Taneja { 0x7b, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
183ea184891SArchit Taneja { 0x01, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
184ea184891SArchit Taneja { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
185ea184891SArchit Taneja { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
186ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
187ea184891SArchit Taneja { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0 },
188ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1 },
189ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2 },
190ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG3 },
191ea184891SArchit Taneja { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0 },
192ea184891SArchit Taneja { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1 },
193ea184891SArchit Taneja { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2 },
194ea184891SArchit Taneja { 0x2a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
195ea184891SArchit Taneja { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
196ea184891SArchit Taneja { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
197ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
198ea184891SArchit Taneja { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
199ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
200ea184891SArchit Taneja { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 },
201ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 },
202ea184891SArchit Taneja }
203ea184891SArchit Taneja },
204ea184891SArchit Taneja /* 640x480p60 */
205ea184891SArchit Taneja { 25200000, 27, {
206ea184891SArchit Taneja { 0x32, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
207ea184891SArchit Taneja { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG },
208ea184891SArchit Taneja { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
209ea184891SArchit Taneja { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
210ea184891SArchit Taneja { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG },
211ea184891SArchit Taneja { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG },
212ea184891SArchit Taneja { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B },
213ea184891SArchit Taneja { 0x77, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
214ea184891SArchit Taneja { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
215ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
216ea184891SArchit Taneja { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
217ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
218ea184891SArchit Taneja { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0 },
219ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1 },
220ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2 },
221ea184891SArchit Taneja { 0x20, REG_HDMI_8960_PHY_PLL_SSC_CFG3 },
222ea184891SArchit Taneja { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0 },
223ea184891SArchit Taneja { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1 },
224ea184891SArchit Taneja { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2 },
225ea184891SArchit Taneja { 0xf4, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
226ea184891SArchit Taneja { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
227ea184891SArchit Taneja { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
228ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
229ea184891SArchit Taneja { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
230ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
231ea184891SArchit Taneja { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 },
232ea184891SArchit Taneja { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 },
233ea184891SArchit Taneja }
234ea184891SArchit Taneja },
235ea184891SArchit Taneja };
236ea184891SArchit Taneja
pll_write(struct hdmi_pll_8960 * pll,u32 reg,u32 data)237ea184891SArchit Taneja static inline void pll_write(struct hdmi_pll_8960 *pll, u32 reg, u32 data)
238ea184891SArchit Taneja {
239ea184891SArchit Taneja msm_writel(data, pll->mmio + reg);
240ea184891SArchit Taneja }
241ea184891SArchit Taneja
pll_read(struct hdmi_pll_8960 * pll,u32 reg)242ea184891SArchit Taneja static inline u32 pll_read(struct hdmi_pll_8960 *pll, u32 reg)
243ea184891SArchit Taneja {
244ea184891SArchit Taneja return msm_readl(pll->mmio + reg);
245ea184891SArchit Taneja }
246ea184891SArchit Taneja
pll_get_phy(struct hdmi_pll_8960 * pll)247ea184891SArchit Taneja static inline struct hdmi_phy *pll_get_phy(struct hdmi_pll_8960 *pll)
248ea184891SArchit Taneja {
249ea184891SArchit Taneja return platform_get_drvdata(pll->pdev);
250ea184891SArchit Taneja }
251ea184891SArchit Taneja
hdmi_pll_enable(struct clk_hw * hw)252ea184891SArchit Taneja static int hdmi_pll_enable(struct clk_hw *hw)
253ea184891SArchit Taneja {
254ea184891SArchit Taneja struct hdmi_pll_8960 *pll = hw_clk_to_pll(hw);
255ea184891SArchit Taneja struct hdmi_phy *phy = pll_get_phy(pll);
256ea184891SArchit Taneja int timeout_count, pll_lock_retry = 10;
257ea184891SArchit Taneja unsigned int val;
258ea184891SArchit Taneja
259ea184891SArchit Taneja DBG("");
260ea184891SArchit Taneja
261ea184891SArchit Taneja /* Assert PLL S/W reset */
262ea184891SArchit Taneja pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x8d);
263ea184891SArchit Taneja pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0, 0x10);
264ea184891SArchit Taneja pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1, 0x1a);
265ea184891SArchit Taneja
266ea184891SArchit Taneja /* Wait for a short time before de-asserting
267ea184891SArchit Taneja * to allow the hardware to complete its job.
268ea184891SArchit Taneja * This much of delay should be fine for hardware
269ea184891SArchit Taneja * to assert and de-assert.
270ea184891SArchit Taneja */
271ea184891SArchit Taneja udelay(10);
272ea184891SArchit Taneja
273ea184891SArchit Taneja /* De-assert PLL S/W reset */
274ea184891SArchit Taneja pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x0d);
275ea184891SArchit Taneja
276ea184891SArchit Taneja val = hdmi_phy_read(phy, REG_HDMI_8960_PHY_REG12);
277ea184891SArchit Taneja val |= HDMI_8960_PHY_REG12_SW_RESET;
278ea184891SArchit Taneja /* Assert PHY S/W reset */
279ea184891SArchit Taneja hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG12, val);
280ea184891SArchit Taneja val &= ~HDMI_8960_PHY_REG12_SW_RESET;
281ea184891SArchit Taneja /*
282ea184891SArchit Taneja * Wait for a short time before de-asserting to allow the hardware to
283ea184891SArchit Taneja * complete its job. This much of delay should be fine for hardware to
284ea184891SArchit Taneja * assert and de-assert.
285ea184891SArchit Taneja */
286ea184891SArchit Taneja udelay(10);
287ea184891SArchit Taneja /* De-assert PHY S/W reset */
288ea184891SArchit Taneja hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG12, val);
289ea184891SArchit Taneja hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG2, 0x3f);
290ea184891SArchit Taneja
291ea184891SArchit Taneja val = hdmi_phy_read(phy, REG_HDMI_8960_PHY_REG12);
292ea184891SArchit Taneja val |= HDMI_8960_PHY_REG12_PWRDN_B;
293ea184891SArchit Taneja hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG12, val);
294ea184891SArchit Taneja /* Wait 10 us for enabling global power for PHY */
295ea184891SArchit Taneja mb();
296ea184891SArchit Taneja udelay(10);
297ea184891SArchit Taneja
298ea184891SArchit Taneja val = pll_read(pll, REG_HDMI_8960_PHY_PLL_PWRDN_B);
299ea184891SArchit Taneja val |= HDMI_8960_PHY_PLL_PWRDN_B_PLL_PWRDN_B;
300ea184891SArchit Taneja val &= ~HDMI_8960_PHY_PLL_PWRDN_B_PD_PLL;
301ea184891SArchit Taneja pll_write(pll, REG_HDMI_8960_PHY_PLL_PWRDN_B, val);
302ea184891SArchit Taneja hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG2, 0x80);
303ea184891SArchit Taneja
304ea184891SArchit Taneja timeout_count = 1000;
305ea184891SArchit Taneja while (--pll_lock_retry > 0) {
306ea184891SArchit Taneja /* are we there yet? */
307ea184891SArchit Taneja val = pll_read(pll, REG_HDMI_8960_PHY_PLL_STATUS0);
308ea184891SArchit Taneja if (val & HDMI_8960_PHY_PLL_STATUS0_PLL_LOCK)
309ea184891SArchit Taneja break;
310ea184891SArchit Taneja
311ea184891SArchit Taneja udelay(1);
312ea184891SArchit Taneja
313ea184891SArchit Taneja if (--timeout_count > 0)
314ea184891SArchit Taneja continue;
315ea184891SArchit Taneja
316ea184891SArchit Taneja /*
317ea184891SArchit Taneja * PLL has still not locked.
318ea184891SArchit Taneja * Do a software reset and try again
319ea184891SArchit Taneja * Assert PLL S/W reset first
320ea184891SArchit Taneja */
321ea184891SArchit Taneja pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x8d);
322ea184891SArchit Taneja udelay(10);
323ea184891SArchit Taneja pll_write(pll, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x0d);
324ea184891SArchit Taneja
325ea184891SArchit Taneja /*
326ea184891SArchit Taneja * Wait for a short duration for the PLL calibration
327ea184891SArchit Taneja * before checking if the PLL gets locked
328ea184891SArchit Taneja */
329ea184891SArchit Taneja udelay(350);
330ea184891SArchit Taneja
331ea184891SArchit Taneja timeout_count = 1000;
332ea184891SArchit Taneja }
333ea184891SArchit Taneja
334ea184891SArchit Taneja return 0;
335ea184891SArchit Taneja }
336ea184891SArchit Taneja
hdmi_pll_disable(struct clk_hw * hw)337ea184891SArchit Taneja static void hdmi_pll_disable(struct clk_hw *hw)
338ea184891SArchit Taneja {
339ea184891SArchit Taneja struct hdmi_pll_8960 *pll = hw_clk_to_pll(hw);
340ea184891SArchit Taneja struct hdmi_phy *phy = pll_get_phy(pll);
341ea184891SArchit Taneja unsigned int val;
342ea184891SArchit Taneja
343ea184891SArchit Taneja DBG("");
344ea184891SArchit Taneja
345ea184891SArchit Taneja val = hdmi_phy_read(phy, REG_HDMI_8960_PHY_REG12);
346ea184891SArchit Taneja val &= ~HDMI_8960_PHY_REG12_PWRDN_B;
347ea184891SArchit Taneja hdmi_phy_write(phy, REG_HDMI_8960_PHY_REG12, val);
348ea184891SArchit Taneja
349ea184891SArchit Taneja val = pll_read(pll, REG_HDMI_8960_PHY_PLL_PWRDN_B);
350ea184891SArchit Taneja val |= HDMI_8960_PHY_REG12_SW_RESET;
351ea184891SArchit Taneja val &= ~HDMI_8960_PHY_REG12_PWRDN_B;
352ea184891SArchit Taneja pll_write(pll, REG_HDMI_8960_PHY_PLL_PWRDN_B, val);
353ea184891SArchit Taneja /* Make sure HDMI PHY/PLL are powered down */
354ea184891SArchit Taneja mb();
355ea184891SArchit Taneja }
356ea184891SArchit Taneja
find_rate(unsigned long rate)357ea184891SArchit Taneja static const struct pll_rate *find_rate(unsigned long rate)
358ea184891SArchit Taneja {
359ea184891SArchit Taneja int i;
360ea184891SArchit Taneja
361ea184891SArchit Taneja for (i = 1; i < ARRAY_SIZE(freqtbl); i++)
362ea184891SArchit Taneja if (rate > freqtbl[i].rate)
363ea184891SArchit Taneja return &freqtbl[i - 1];
364ea184891SArchit Taneja
365ea184891SArchit Taneja return &freqtbl[i - 1];
366ea184891SArchit Taneja }
367ea184891SArchit Taneja
hdmi_pll_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)368ea184891SArchit Taneja static unsigned long hdmi_pll_recalc_rate(struct clk_hw *hw,
369ea184891SArchit Taneja unsigned long parent_rate)
370ea184891SArchit Taneja {
371ea184891SArchit Taneja struct hdmi_pll_8960 *pll = hw_clk_to_pll(hw);
372ea184891SArchit Taneja
373ea184891SArchit Taneja return pll->pixclk;
374ea184891SArchit Taneja }
375ea184891SArchit Taneja
hdmi_pll_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * parent_rate)376ea184891SArchit Taneja static long hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate,
377ea184891SArchit Taneja unsigned long *parent_rate)
378ea184891SArchit Taneja {
379ea184891SArchit Taneja const struct pll_rate *pll_rate = find_rate(rate);
380ea184891SArchit Taneja
381ea184891SArchit Taneja return pll_rate->rate;
382ea184891SArchit Taneja }
383ea184891SArchit Taneja
hdmi_pll_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)384ea184891SArchit Taneja static int hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
385ea184891SArchit Taneja unsigned long parent_rate)
386ea184891SArchit Taneja {
387ea184891SArchit Taneja struct hdmi_pll_8960 *pll = hw_clk_to_pll(hw);
388ea184891SArchit Taneja const struct pll_rate *pll_rate = find_rate(rate);
389ea184891SArchit Taneja int i;
390ea184891SArchit Taneja
391ea184891SArchit Taneja DBG("rate=%lu", rate);
392ea184891SArchit Taneja
393ea184891SArchit Taneja for (i = 0; i < pll_rate->num_reg; i++)
394ea184891SArchit Taneja pll_write(pll, pll_rate->conf[i].reg, pll_rate->conf[i].val);
395ea184891SArchit Taneja
396ea184891SArchit Taneja pll->pixclk = rate;
397ea184891SArchit Taneja
398ea184891SArchit Taneja return 0;
399ea184891SArchit Taneja }
400ea184891SArchit Taneja
401ea184891SArchit Taneja static const struct clk_ops hdmi_pll_ops = {
402ea184891SArchit Taneja .enable = hdmi_pll_enable,
403ea184891SArchit Taneja .disable = hdmi_pll_disable,
404ea184891SArchit Taneja .recalc_rate = hdmi_pll_recalc_rate,
405ea184891SArchit Taneja .round_rate = hdmi_pll_round_rate,
406ea184891SArchit Taneja .set_rate = hdmi_pll_set_rate,
407ea184891SArchit Taneja };
408ea184891SArchit Taneja
409a42964ceSDmitry Baryshkov static const struct clk_parent_data hdmi_pll_parents[] = {
410a42964ceSDmitry Baryshkov { .fw_name = "pxo", .name = "pxo_board" },
411ea184891SArchit Taneja };
412ea184891SArchit Taneja
413ea184891SArchit Taneja static struct clk_init_data pll_init = {
414ea184891SArchit Taneja .name = "hdmi_pll",
415ea184891SArchit Taneja .ops = &hdmi_pll_ops,
416a42964ceSDmitry Baryshkov .parent_data = hdmi_pll_parents,
417ea184891SArchit Taneja .num_parents = ARRAY_SIZE(hdmi_pll_parents),
41873b65b19SArchit Taneja .flags = CLK_IGNORE_UNUSED,
419ea184891SArchit Taneja };
420ea184891SArchit Taneja
msm_hdmi_pll_8960_init(struct platform_device * pdev)421fcda50c8SArnd Bergmann int msm_hdmi_pll_8960_init(struct platform_device *pdev)
422ea184891SArchit Taneja {
423ea184891SArchit Taneja struct device *dev = &pdev->dev;
424ea184891SArchit Taneja struct hdmi_pll_8960 *pll;
425*59817b90SDmitry Baryshkov int i, ret;
426ea184891SArchit Taneja
427ea184891SArchit Taneja /* sanity check: */
428ea184891SArchit Taneja for (i = 0; i < (ARRAY_SIZE(freqtbl) - 1); i++)
429ea184891SArchit Taneja if (WARN_ON(freqtbl[i].rate < freqtbl[i + 1].rate))
430ea184891SArchit Taneja return -EINVAL;
431ea184891SArchit Taneja
432ea184891SArchit Taneja pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
433ea184891SArchit Taneja if (!pll)
434ea184891SArchit Taneja return -ENOMEM;
435ea184891SArchit Taneja
436c0e745d7SDmitry Baryshkov pll->mmio = msm_ioremap(pdev, "hdmi_pll");
437ea184891SArchit Taneja if (IS_ERR(pll->mmio)) {
4386a41da17SMamta Shukla DRM_DEV_ERROR(dev, "failed to map pll base\n");
439ea184891SArchit Taneja return -ENOMEM;
440ea184891SArchit Taneja }
441ea184891SArchit Taneja
442ea184891SArchit Taneja pll->pdev = pdev;
443ea184891SArchit Taneja pll->clk_hw.init = &pll_init;
444ea184891SArchit Taneja
445*59817b90SDmitry Baryshkov ret = devm_clk_hw_register(dev, &pll->clk_hw);
446*59817b90SDmitry Baryshkov if (ret < 0) {
4476a41da17SMamta Shukla DRM_DEV_ERROR(dev, "failed to register pll clock\n");
448*59817b90SDmitry Baryshkov return ret;
449*59817b90SDmitry Baryshkov }
450*59817b90SDmitry Baryshkov
451*59817b90SDmitry Baryshkov ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &pll->clk_hw);
452*59817b90SDmitry Baryshkov if (ret) {
453*59817b90SDmitry Baryshkov DRM_DEV_ERROR(dev, "%s: failed to register clk provider: %d\n", __func__, ret);
454*59817b90SDmitry Baryshkov return ret;
455ea184891SArchit Taneja }
456ea184891SArchit Taneja
457ea184891SArchit Taneja return 0;
458ea184891SArchit Taneja }
459