1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * linux/drivers/video/kyro/STG4000InitDevice.c
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2000 Imagination Technologies Ltd
5*4882a593Smuzhiyun * Copyright (C) 2002 STMicroelectronics
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * This file is subject to the terms and conditions of the GNU General Public
8*4882a593Smuzhiyun * License. See the file COPYING in the main directory of this archive
9*4882a593Smuzhiyun * for more details.
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <linux/kernel.h>
13*4882a593Smuzhiyun #include <linux/errno.h>
14*4882a593Smuzhiyun #include <linux/types.h>
15*4882a593Smuzhiyun #include <linux/pci.h>
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include "STG4000Reg.h"
18*4882a593Smuzhiyun #include "STG4000Interface.h"
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun /* SDRAM fixed settings */
21*4882a593Smuzhiyun #define SDRAM_CFG_0 0x49A1
22*4882a593Smuzhiyun #define SDRAM_CFG_1 0xA732
23*4882a593Smuzhiyun #define SDRAM_CFG_2 0x31
24*4882a593Smuzhiyun #define SDRAM_ARB_CFG 0xA0
25*4882a593Smuzhiyun #define SDRAM_REFRESH 0x20
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun /* Reset values */
28*4882a593Smuzhiyun #define PMX2_SOFTRESET_DAC_RST 0x0001
29*4882a593Smuzhiyun #define PMX2_SOFTRESET_C1_RST 0x0004
30*4882a593Smuzhiyun #define PMX2_SOFTRESET_C2_RST 0x0008
31*4882a593Smuzhiyun #define PMX2_SOFTRESET_3D_RST 0x0010
32*4882a593Smuzhiyun #define PMX2_SOFTRESET_VIDIN_RST 0x0020
33*4882a593Smuzhiyun #define PMX2_SOFTRESET_TLB_RST 0x0040
34*4882a593Smuzhiyun #define PMX2_SOFTRESET_SD_RST 0x0080
35*4882a593Smuzhiyun #define PMX2_SOFTRESET_VGA_RST 0x0100
36*4882a593Smuzhiyun #define PMX2_SOFTRESET_ROM_RST 0x0200 /* reserved bit, do not reset */
37*4882a593Smuzhiyun #define PMX2_SOFTRESET_TA_RST 0x0400
38*4882a593Smuzhiyun #define PMX2_SOFTRESET_REG_RST 0x4000
39*4882a593Smuzhiyun #define PMX2_SOFTRESET_ALL 0x7fff
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun /* Core clock freq */
42*4882a593Smuzhiyun #define CORE_PLL_FREQ 1000000
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun /* Reference Clock freq */
45*4882a593Smuzhiyun #define REF_FREQ 14318
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun /* PCI Registers */
48*4882a593Smuzhiyun static u16 CorePllControl = 0x70;
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun #define PCI_CONFIG_SUBSYS_ID 0x2e
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun /* Misc */
53*4882a593Smuzhiyun #define CORE_PLL_MODE_REG_0_7 3
54*4882a593Smuzhiyun #define CORE_PLL_MODE_REG_8_15 2
55*4882a593Smuzhiyun #define CORE_PLL_MODE_CONFIG_REG 1
56*4882a593Smuzhiyun #define DAC_PLL_CONFIG_REG 0
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun #define STG_MAX_VCO 500000
59*4882a593Smuzhiyun #define STG_MIN_VCO 100000
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun /* PLL Clock */
62*4882a593Smuzhiyun #define STG4K3_PLL_SCALER 8 /* scale numbers by 2^8 for fixed point calc */
63*4882a593Smuzhiyun #define STG4K3_PLL_MIN_R 2 /* Minimum multiplier */
64*4882a593Smuzhiyun #define STG4K3_PLL_MAX_R 33 /* Max */
65*4882a593Smuzhiyun #define STG4K3_PLL_MIN_F 2 /* Minimum divisor */
66*4882a593Smuzhiyun #define STG4K3_PLL_MAX_F 513 /* Max */
67*4882a593Smuzhiyun #define STG4K3_PLL_MIN_OD 0 /* Min output divider (shift) */
68*4882a593Smuzhiyun #define STG4K3_PLL_MAX_OD 2 /* Max */
69*4882a593Smuzhiyun #define STG4K3_PLL_MIN_VCO_SC (100000000 >> STG4K3_PLL_SCALER) /* Min VCO rate */
70*4882a593Smuzhiyun #define STG4K3_PLL_MAX_VCO_SC (500000000 >> STG4K3_PLL_SCALER) /* Max VCO rate */
71*4882a593Smuzhiyun #define STG4K3_PLL_MINR_VCO_SC (100000000 >> STG4K3_PLL_SCALER) /* Min VCO rate (restricted) */
72*4882a593Smuzhiyun #define STG4K3_PLL_MAXR_VCO_SC (500000000 >> STG4K3_PLL_SCALER) /* Max VCO rate (restricted) */
73*4882a593Smuzhiyun #define STG4K3_PLL_MINR_VCO 100000000 /* Min VCO rate (restricted) */
74*4882a593Smuzhiyun #define STG4K3_PLL_MAX_VCO 500000000 /* Max VCO rate */
75*4882a593Smuzhiyun #define STG4K3_PLL_MAXR_VCO 500000000 /* Max VCO rate (restricted) */
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun #define OS_DELAY(X) \
78*4882a593Smuzhiyun { \
79*4882a593Smuzhiyun volatile u32 i,count=0; \
80*4882a593Smuzhiyun for(i=0;i<X;i++) count++; \
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun
InitSDRAMRegisters(volatile STG4000REG __iomem * pSTGReg,u32 dwSubSysID,u32 dwRevID)83*4882a593Smuzhiyun static u32 InitSDRAMRegisters(volatile STG4000REG __iomem *pSTGReg,
84*4882a593Smuzhiyun u32 dwSubSysID, u32 dwRevID)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun u32 adwSDRAMArgCfg0[] = { 0xa0, 0x80, 0xa0, 0xa0, 0xa0 };
87*4882a593Smuzhiyun u32 adwSDRAMCfg1[] = { 0x8732, 0x8732, 0xa732, 0xa732, 0x8732 };
88*4882a593Smuzhiyun u32 adwSDRAMCfg2[] = { 0x87d2, 0x87d2, 0xa7d2, 0x87d2, 0xa7d2 };
89*4882a593Smuzhiyun u32 adwSDRAMRsh[] = { 36, 39, 40 };
90*4882a593Smuzhiyun u32 adwChipSpeed[] = { 110, 120, 125 };
91*4882a593Smuzhiyun u32 dwMemTypeIdx;
92*4882a593Smuzhiyun u32 dwChipSpeedIdx;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun /* Get memory tpye and chip speed indexs from the SubSysDevID */
95*4882a593Smuzhiyun dwMemTypeIdx = (dwSubSysID & 0x70) >> 4;
96*4882a593Smuzhiyun dwChipSpeedIdx = (dwSubSysID & 0x180) >> 7;
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun if (dwMemTypeIdx > 4 || dwChipSpeedIdx > 2)
99*4882a593Smuzhiyun return 0;
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun /* Program SD-RAM interface */
102*4882a593Smuzhiyun STG_WRITE_REG(SDRAMArbiterConf, adwSDRAMArgCfg0[dwMemTypeIdx]);
103*4882a593Smuzhiyun if (dwRevID < 5) {
104*4882a593Smuzhiyun STG_WRITE_REG(SDRAMConf0, 0x49A1);
105*4882a593Smuzhiyun STG_WRITE_REG(SDRAMConf1, adwSDRAMCfg1[dwMemTypeIdx]);
106*4882a593Smuzhiyun } else {
107*4882a593Smuzhiyun STG_WRITE_REG(SDRAMConf0, 0x4DF1);
108*4882a593Smuzhiyun STG_WRITE_REG(SDRAMConf1, adwSDRAMCfg2[dwMemTypeIdx]);
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun STG_WRITE_REG(SDRAMConf2, 0x31);
112*4882a593Smuzhiyun STG_WRITE_REG(SDRAMRefresh, adwSDRAMRsh[dwChipSpeedIdx]);
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun return adwChipSpeed[dwChipSpeedIdx] * 10000;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
ProgramClock(u32 refClock,u32 coreClock,u32 * FOut,u32 * ROut,u32 * POut)117*4882a593Smuzhiyun u32 ProgramClock(u32 refClock,
118*4882a593Smuzhiyun u32 coreClock,
119*4882a593Smuzhiyun u32 * FOut, u32 * ROut, u32 * POut)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun u32 R = 0, F = 0, OD = 0, ODIndex = 0;
122*4882a593Smuzhiyun u32 ulBestR = 0, ulBestF = 0, ulBestOD = 0;
123*4882a593Smuzhiyun u32 ulBestClk = 0, ulBestScore = 0;
124*4882a593Smuzhiyun u32 ulScore, ulPhaseScore, ulVcoScore;
125*4882a593Smuzhiyun u32 ulTmp = 0, ulVCO;
126*4882a593Smuzhiyun u32 ulScaleClockReq, ulMinClock, ulMaxClock;
127*4882a593Smuzhiyun u32 ODValues[] = { 1, 2, 0 };
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun /* Translate clock in Hz */
130*4882a593Smuzhiyun coreClock *= 100; /* in Hz */
131*4882a593Smuzhiyun refClock *= 1000; /* in Hz */
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun /* Work out acceptable clock
134*4882a593Smuzhiyun * The method calculates ~ +- 0.4% (1/256)
135*4882a593Smuzhiyun */
136*4882a593Smuzhiyun ulMinClock = coreClock - (coreClock >> 8);
137*4882a593Smuzhiyun ulMaxClock = coreClock + (coreClock >> 8);
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun /* Scale clock required for use in calculations */
140*4882a593Smuzhiyun ulScaleClockReq = coreClock >> STG4K3_PLL_SCALER;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun /* Iterate through post divider values */
143*4882a593Smuzhiyun for (ODIndex = 0; ODIndex < 3; ODIndex++) {
144*4882a593Smuzhiyun OD = ODValues[ODIndex];
145*4882a593Smuzhiyun R = STG4K3_PLL_MIN_R;
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun /* loop for pre-divider from min to max */
148*4882a593Smuzhiyun while (R <= STG4K3_PLL_MAX_R) {
149*4882a593Smuzhiyun /* estimate required feedback multiplier */
150*4882a593Smuzhiyun ulTmp = R * (ulScaleClockReq << OD);
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun /* F = ClkRequired * R * (2^OD) / Fref */
153*4882a593Smuzhiyun F = (u32)(ulTmp / (refClock >> STG4K3_PLL_SCALER));
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun /* compensate for accuracy */
156*4882a593Smuzhiyun if (F > STG4K3_PLL_MIN_F)
157*4882a593Smuzhiyun F--;
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun /*
161*4882a593Smuzhiyun * We should be close to our target frequency (if it's
162*4882a593Smuzhiyun * achievable with current OD & R) let's iterate
163*4882a593Smuzhiyun * through F for best fit
164*4882a593Smuzhiyun */
165*4882a593Smuzhiyun while ((F >= STG4K3_PLL_MIN_F) &&
166*4882a593Smuzhiyun (F <= STG4K3_PLL_MAX_F)) {
167*4882a593Smuzhiyun /* Calc VCO at full accuracy */
168*4882a593Smuzhiyun ulVCO = refClock / R;
169*4882a593Smuzhiyun ulVCO = F * ulVCO;
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun /*
172*4882a593Smuzhiyun * Check it's within restricted VCO range
173*4882a593Smuzhiyun * unless of course the desired frequency is
174*4882a593Smuzhiyun * above the restricted range, then test
175*4882a593Smuzhiyun * against VCO limit
176*4882a593Smuzhiyun */
177*4882a593Smuzhiyun if ((ulVCO >= STG4K3_PLL_MINR_VCO) &&
178*4882a593Smuzhiyun ((ulVCO <= STG4K3_PLL_MAXR_VCO) ||
179*4882a593Smuzhiyun ((coreClock > STG4K3_PLL_MAXR_VCO)
180*4882a593Smuzhiyun && (ulVCO <= STG4K3_PLL_MAX_VCO)))) {
181*4882a593Smuzhiyun ulTmp = (ulVCO >> OD); /* Clock = VCO / (2^OD) */
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun /* Is this clock good enough? */
184*4882a593Smuzhiyun if ((ulTmp >= ulMinClock)
185*4882a593Smuzhiyun && (ulTmp <= ulMaxClock)) {
186*4882a593Smuzhiyun ulPhaseScore = (((refClock / R) - (refClock / STG4K3_PLL_MAX_R))) / ((refClock - (refClock / STG4K3_PLL_MAX_R)) >> 10);
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun ulVcoScore = ((ulVCO - STG4K3_PLL_MINR_VCO)) / ((STG4K3_PLL_MAXR_VCO - STG4K3_PLL_MINR_VCO) >> 10);
189*4882a593Smuzhiyun ulScore = ulPhaseScore + ulVcoScore;
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun if (!ulBestScore) {
192*4882a593Smuzhiyun ulBestOD = OD;
193*4882a593Smuzhiyun ulBestF = F;
194*4882a593Smuzhiyun ulBestR = R;
195*4882a593Smuzhiyun ulBestClk = ulTmp;
196*4882a593Smuzhiyun ulBestScore =
197*4882a593Smuzhiyun ulScore;
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun /* is this better, ( aim for highest Score) */
200*4882a593Smuzhiyun /*--------------------------------------------------------------------------
201*4882a593Smuzhiyun Here we want to use a scoring system which will take account of both the
202*4882a593Smuzhiyun value at the phase comparater and the VCO output
203*4882a593Smuzhiyun to do this we will use a cumulative score between the two
204*4882a593Smuzhiyun The way this ends up is that we choose the first value in the loop anyway
205*4882a593Smuzhiyun but we shall keep this code in case new restrictions come into play
206*4882a593Smuzhiyun --------------------------------------------------------------------------*/
207*4882a593Smuzhiyun if ((ulScore >= ulBestScore) && (OD > 0)) {
208*4882a593Smuzhiyun ulBestOD = OD;
209*4882a593Smuzhiyun ulBestF = F;
210*4882a593Smuzhiyun ulBestR = R;
211*4882a593Smuzhiyun ulBestClk = ulTmp;
212*4882a593Smuzhiyun ulBestScore =
213*4882a593Smuzhiyun ulScore;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun F++;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun R++;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun /*
224*4882a593Smuzhiyun did we find anything?
225*4882a593Smuzhiyun Then return RFOD
226*4882a593Smuzhiyun */
227*4882a593Smuzhiyun if (ulBestScore) {
228*4882a593Smuzhiyun *ROut = ulBestR;
229*4882a593Smuzhiyun *FOut = ulBestF;
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun if ((ulBestOD == 2) || (ulBestOD == 3)) {
232*4882a593Smuzhiyun *POut = 3;
233*4882a593Smuzhiyun } else
234*4882a593Smuzhiyun *POut = ulBestOD;
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun return (ulBestClk);
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun
SetCoreClockPLL(volatile STG4000REG __iomem * pSTGReg,struct pci_dev * pDev)241*4882a593Smuzhiyun int SetCoreClockPLL(volatile STG4000REG __iomem *pSTGReg, struct pci_dev *pDev)
242*4882a593Smuzhiyun {
243*4882a593Smuzhiyun u32 F, R, P;
244*4882a593Smuzhiyun u16 core_pll = 0, sub;
245*4882a593Smuzhiyun u32 tmp;
246*4882a593Smuzhiyun u32 ulChipSpeed;
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun STG_WRITE_REG(IntMask, 0xFFFF);
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun /* Disable Primary Core Thread0 */
251*4882a593Smuzhiyun tmp = STG_READ_REG(Thread0Enable);
252*4882a593Smuzhiyun CLEAR_BIT(0);
253*4882a593Smuzhiyun STG_WRITE_REG(Thread0Enable, tmp);
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun /* Disable Primary Core Thread1 */
256*4882a593Smuzhiyun tmp = STG_READ_REG(Thread1Enable);
257*4882a593Smuzhiyun CLEAR_BIT(0);
258*4882a593Smuzhiyun STG_WRITE_REG(Thread1Enable, tmp);
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun STG_WRITE_REG(SoftwareReset,
261*4882a593Smuzhiyun PMX2_SOFTRESET_REG_RST | PMX2_SOFTRESET_ROM_RST);
262*4882a593Smuzhiyun STG_WRITE_REG(SoftwareReset,
263*4882a593Smuzhiyun PMX2_SOFTRESET_REG_RST | PMX2_SOFTRESET_TA_RST |
264*4882a593Smuzhiyun PMX2_SOFTRESET_ROM_RST);
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun /* Need to play around to reset TA */
267*4882a593Smuzhiyun STG_WRITE_REG(TAConfiguration, 0);
268*4882a593Smuzhiyun STG_WRITE_REG(SoftwareReset,
269*4882a593Smuzhiyun PMX2_SOFTRESET_REG_RST | PMX2_SOFTRESET_ROM_RST);
270*4882a593Smuzhiyun STG_WRITE_REG(SoftwareReset,
271*4882a593Smuzhiyun PMX2_SOFTRESET_REG_RST | PMX2_SOFTRESET_TA_RST |
272*4882a593Smuzhiyun PMX2_SOFTRESET_ROM_RST);
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun pci_read_config_word(pDev, PCI_CONFIG_SUBSYS_ID, &sub);
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun ulChipSpeed = InitSDRAMRegisters(pSTGReg, (u32)sub,
277*4882a593Smuzhiyun (u32)pDev->revision);
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun if (ulChipSpeed == 0)
280*4882a593Smuzhiyun return -EINVAL;
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun ProgramClock(REF_FREQ, CORE_PLL_FREQ, &F, &R, &P);
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun core_pll |= ((P) | ((F - 2) << 2) | ((R - 2) << 11));
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun /* Set Core PLL Control to Core PLL Mode */
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun /* Send bits 0:7 of the Core PLL Mode register */
289*4882a593Smuzhiyun tmp = ((CORE_PLL_MODE_REG_0_7 << 8) | (core_pll & 0x00FF));
290*4882a593Smuzhiyun pci_write_config_word(pDev, CorePllControl, tmp);
291*4882a593Smuzhiyun /* Without some delay between the PCI config writes the clock does
292*4882a593Smuzhiyun not reliably set when the code is compiled -O3
293*4882a593Smuzhiyun */
294*4882a593Smuzhiyun OS_DELAY(1000000);
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun tmp |= SET_BIT(14);
297*4882a593Smuzhiyun pci_write_config_word(pDev, CorePllControl, tmp);
298*4882a593Smuzhiyun OS_DELAY(1000000);
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun /* Send bits 8:15 of the Core PLL Mode register */
301*4882a593Smuzhiyun tmp =
302*4882a593Smuzhiyun ((CORE_PLL_MODE_REG_8_15 << 8) | ((core_pll & 0xFF00) >> 8));
303*4882a593Smuzhiyun pci_write_config_word(pDev, CorePllControl, tmp);
304*4882a593Smuzhiyun OS_DELAY(1000000);
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun tmp |= SET_BIT(14);
307*4882a593Smuzhiyun pci_write_config_word(pDev, CorePllControl, tmp);
308*4882a593Smuzhiyun OS_DELAY(1000000);
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun STG_WRITE_REG(SoftwareReset, PMX2_SOFTRESET_ALL);
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun #if 0
313*4882a593Smuzhiyun /* Enable Primary Core Thread0 */
314*4882a593Smuzhiyun tmp = ((STG_READ_REG(Thread0Enable)) | SET_BIT(0));
315*4882a593Smuzhiyun STG_WRITE_REG(Thread0Enable, tmp);
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun /* Enable Primary Core Thread1 */
318*4882a593Smuzhiyun tmp = ((STG_READ_REG(Thread1Enable)) | SET_BIT(0));
319*4882a593Smuzhiyun STG_WRITE_REG(Thread1Enable, tmp);
320*4882a593Smuzhiyun #endif
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun return 0;
323*4882a593Smuzhiyun }
324