]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/bcma/driver_chipcommon_pmu.c
bcma: get CPU clock
[karo-tx-linux.git] / drivers / bcma / driver_chipcommon_pmu.c
1 /*
2  * Broadcom specific AMBA
3  * ChipCommon Power Management Unit driver
4  *
5  * Copyright 2009, Michael Buesch <m@bues.ch>
6  * Copyright 2007, Broadcom Corporation
7  *
8  * Licensed under the GNU/GPL. See COPYING for details.
9  */
10
11 #include "bcma_private.h"
12 #include <linux/bcma/bcma.h>
13
14 static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
15 {
16         bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
17         bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
18         return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
19 }
20
21 static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
22                                         u32 offset, u32 mask, u32 set)
23 {
24         u32 value;
25
26         bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
27         bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset);
28         bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
29         value = bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
30         value &= mask;
31         value |= set;
32         bcma_cc_write32(cc, BCMA_CC_CHIPCTL_DATA, value);
33         bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
34 }
35
36 static void bcma_pmu_pll_init(struct bcma_drv_cc *cc)
37 {
38         struct bcma_bus *bus = cc->core->bus;
39
40         switch (bus->chipinfo.id) {
41         case 0x4313:
42         case 0x4331:
43         case 43224:
44         case 43225:
45                 break;
46         default:
47                 pr_err("PLL init unknown for device 0x%04X\n",
48                         bus->chipinfo.id);
49         }
50 }
51
52 static void bcma_pmu_resources_init(struct bcma_drv_cc *cc)
53 {
54         struct bcma_bus *bus = cc->core->bus;
55         u32 min_msk = 0, max_msk = 0;
56
57         switch (bus->chipinfo.id) {
58         case 0x4313:
59                 min_msk = 0x200D;
60                 max_msk = 0xFFFF;
61                 break;
62         case 43224:
63         case 43225:
64                 break;
65         default:
66                 pr_err("PMU resource config unknown for device 0x%04X\n",
67                         bus->chipinfo.id);
68         }
69
70         /* Set the resource masks. */
71         if (min_msk)
72                 bcma_cc_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk);
73         if (max_msk)
74                 bcma_cc_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
75 }
76
77 void bcma_pmu_swreg_init(struct bcma_drv_cc *cc)
78 {
79         struct bcma_bus *bus = cc->core->bus;
80
81         switch (bus->chipinfo.id) {
82         case 0x4313:
83         case 0x4331:
84         case 43224:
85         case 43225:
86                 break;
87         default:
88                 pr_err("PMU switch/regulators init unknown for device "
89                         "0x%04X\n", bus->chipinfo.id);
90         }
91 }
92
93 void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
94 {
95         struct bcma_bus *bus = cc->core->bus;
96
97         switch (bus->chipinfo.id) {
98         case 0x4313:
99                 bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7);
100                 break;
101         case 0x4331:
102                 pr_err("Enabling Ext PA lines not implemented\n");
103                 break;
104         case 43224:
105                 if (bus->chipinfo.rev == 0) {
106                         pr_err("Workarounds for 43224 rev 0 not fully "
107                                 "implemented\n");
108                         bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x00F000F0);
109                 } else {
110                         bcma_chipco_chipctl_maskset(cc, 0, ~0, 0xF0);
111                 }
112                 break;
113         case 43225:
114                 break;
115         default:
116                 pr_err("Workarounds unknown for device 0x%04X\n",
117                         bus->chipinfo.id);
118         }
119 }
120
121 void bcma_pmu_init(struct bcma_drv_cc *cc)
122 {
123         u32 pmucap;
124
125         pmucap = bcma_cc_read32(cc, BCMA_CC_PMU_CAP);
126         cc->pmu.rev = (pmucap & BCMA_CC_PMU_CAP_REVISION);
127
128         pr_debug("Found rev %u PMU (capabilities 0x%08X)\n", cc->pmu.rev,
129                  pmucap);
130
131         if (cc->pmu.rev == 1)
132                 bcma_cc_mask32(cc, BCMA_CC_PMU_CTL,
133                               ~BCMA_CC_PMU_CTL_NOILPONW);
134         else
135                 bcma_cc_set32(cc, BCMA_CC_PMU_CTL,
136                              BCMA_CC_PMU_CTL_NOILPONW);
137
138         if (cc->core->id.id == 0x4329 && cc->core->id.rev == 2)
139                 pr_err("Fix for 4329b0 bad LPOM state not implemented!\n");
140
141         bcma_pmu_pll_init(cc);
142         bcma_pmu_resources_init(cc);
143         bcma_pmu_swreg_init(cc);
144         bcma_pmu_workarounds(cc);
145 }
146
147 u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc)
148 {
149         struct bcma_bus *bus = cc->core->bus;
150
151         switch (bus->chipinfo.id) {
152         case 0x4716:
153         case 0x4748:
154         case 47162:
155         case 0x4313:
156         case 0x5357:
157         case 0x4749:
158         case 53572:
159                 /* always 20Mhz */
160                 return 20000 * 1000;
161         case 0x5356:
162         case 0x5300:
163                 /* always 25Mhz */
164                 return 25000 * 1000;
165         default:
166                 pr_warn("No ALP clock specified for %04X device, "
167                         "pmu rev. %d, using default %d Hz\n",
168                         bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK);
169         }
170         return BCMA_CC_PMU_ALP_CLOCK;
171 }
172
173 /* Find the output of the "m" pll divider given pll controls that start with
174  * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
175  */
176 static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m)
177 {
178         u32 tmp, div, ndiv, p1, p2, fc;
179         struct bcma_bus *bus = cc->core->bus;
180
181         BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0));
182
183         BUG_ON(!m || m > 4);
184
185         if (bus->chipinfo.id == 0x5357 || bus->chipinfo.id == 0x4749) {
186                 /* Detect failure in clock setting */
187                 tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
188                 if (tmp & 0x40000)
189                         return 133 * 1000000;
190         }
191
192         tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_P1P2_OFF);
193         p1 = (tmp & BCMA_CC_PPL_P1_MASK) >> BCMA_CC_PPL_P1_SHIFT;
194         p2 = (tmp & BCMA_CC_PPL_P2_MASK) >> BCMA_CC_PPL_P2_SHIFT;
195
196         tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_M14_OFF);
197         div = (tmp >> ((m - 1) * BCMA_CC_PPL_MDIV_WIDTH)) &
198                 BCMA_CC_PPL_MDIV_MASK;
199
200         tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_NM5_OFF);
201         ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT;
202
203         /* Do calculation in Mhz */
204         fc = bcma_pmu_alp_clock(cc) / 1000000;
205         fc = (p1 * ndiv * fc) / p2;
206
207         /* Return clock in Hertz */
208         return (fc / div) * 1000000;
209 }
210
211 /* query bus clock frequency for PMU-enabled chipcommon */
212 u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
213 {
214         struct bcma_bus *bus = cc->core->bus;
215
216         switch (bus->chipinfo.id) {
217         case 0x4716:
218         case 0x4748:
219         case 47162:
220                 return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
221                                       BCMA_CC_PMU5_MAINPLL_SSB);
222         case 0x5356:
223                 return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0,
224                                       BCMA_CC_PMU5_MAINPLL_SSB);
225         case 0x5357:
226         case 0x4749:
227                 return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0,
228                                       BCMA_CC_PMU5_MAINPLL_SSB);
229         case 0x5300:
230                 return bcma_pmu_clock(cc, BCMA_CC_PMU4706_MAINPLL_PLL0,
231                                       BCMA_CC_PMU5_MAINPLL_SSB);
232         case 53572:
233                 return 75000000;
234         default:
235                 pr_warn("No backplane clock specified for %04X device, "
236                         "pmu rev. %d, using default %d Hz\n",
237                         bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK);
238         }
239         return BCMA_CC_PMU_HT_CLOCK;
240 }
241
242 /* query cpu clock frequency for PMU-enabled chipcommon */
243 u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc)
244 {
245         struct bcma_bus *bus = cc->core->bus;
246
247         if (bus->chipinfo.id == 53572)
248                 return 300000000;
249
250         if (cc->pmu.rev >= 5) {
251                 u32 pll;
252                 switch (bus->chipinfo.id) {
253                 case 0x5356:
254                         pll = BCMA_CC_PMU5356_MAINPLL_PLL0;
255                         break;
256                 case 0x5357:
257                 case 0x4749:
258                         pll = BCMA_CC_PMU5357_MAINPLL_PLL0;
259                         break;
260                 default:
261                         pll = BCMA_CC_PMU4716_MAINPLL_PLL0;
262                         break;
263                 }
264
265                 /* TODO: if (bus->chipinfo.id == 0x5300)
266                   return si_4706_pmu_clock(sih, osh, cc, PMU4706_MAINPLL_PLL0, PMU5_MAINPLL_CPU); */
267                 return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU);
268         }
269
270         return bcma_pmu_get_clockcontrol(cc);
271 }