]>
Commit | Line | Data |
---|---|---|
afbf8899 JR |
1 | /* |
2 | * Copyright (C) ST-Ericsson SA 2009 | |
3 | * | |
1a459660 | 4 | * SPDX-License-Identifier: GPL-2.0+ |
afbf8899 JR |
5 | */ |
6 | ||
7 | #include <config.h> | |
8 | #include <common.h> | |
10ed93dc | 9 | #include <malloc.h> |
afbf8899 JR |
10 | #include <i2c.h> |
11 | #include <asm/types.h> | |
12 | #include <asm/io.h> | |
13 | #include <asm/errno.h> | |
14 | #include <asm/arch/clock.h> | |
15 | #include <asm/arch/gpio.h> | |
16 | #include <asm/arch/hardware.h> | |
17 | #include <asm/arch/sys_proto.h> | |
42cb8fb6 | 18 | #include <asm/arch/prcmu.h> |
9652de7c | 19 | #ifdef CONFIG_MMC |
afbf8899 JR |
20 | #include "../../../drivers/mmc/arm_pl180_mmci.h" |
21 | #endif | |
22 | ||
23 | #define NOMADIK_PER4_BASE (0x80150000) | |
24 | #define NOMADIK_BACKUPRAM0_BASE (NOMADIK_PER4_BASE + 0x00000) | |
25 | #define NOMADIK_BACKUPRAM1_BASE (NOMADIK_PER4_BASE + 0x01000) | |
26 | ||
27 | /* Power, Reset, Clock Management Unit */ | |
28 | /* | |
29 | * SVA: Smart Video Accelerator | |
30 | * SIA: Smart Imaging Accelerator | |
31 | * SGA: Smart Graphic accelerator | |
32 | * B2R2: Graphic blitter | |
33 | */ | |
afbf8899 JR |
34 | #define PRCM_ARMCLKFIX_MGT_REG (PRCMU_BASE + 0x000) |
35 | #define PRCM_ACLK_MGT_REG (PRCMU_BASE + 0x004) | |
36 | #define PRCM_SVAMMDSPCLK_MGT_REG (PRCMU_BASE + 0x008) | |
37 | #define PRCM_SIAMMDSPCLK_MGT_REG (PRCMU_BASE + 0x00C) | |
38 | #define PRCM_SAAMMDSPCLK_MGT_REG (PRCMU_BASE + 0x010) | |
39 | #define PRCM_SGACLK_MGT_REG (PRCMU_BASE + 0x014) | |
40 | #define PRCM_UARTCLK_MGT_REG (PRCMU_BASE + 0x018) | |
41 | #define PRCM_MSPCLK_MGT_REG (PRCMU_BASE + 0x01C) | |
42 | #define PRCM_I2CCLK_MGT_REG (PRCMU_BASE + 0x020) | |
43 | #define PRCM_SDMMCCLK_MGT_REG (PRCMU_BASE + 0x024) | |
44 | #define PRCM_SLIMCLK_MGT_REG (PRCMU_BASE + 0x028) | |
45 | #define PRCM_PER1CLK_MGT_REG (PRCMU_BASE + 0x02C) | |
46 | #define PRCM_PER2CLK_MGT_REG (PRCMU_BASE + 0x030) | |
47 | #define PRCM_PER3CLK_MGT_REG (PRCMU_BASE + 0x034) | |
48 | #define PRCM_PER5CLK_MGT_REG (PRCMU_BASE + 0x038) | |
49 | #define PRCM_PER6CLK_MGT_REG (PRCMU_BASE + 0x03C) | |
50 | #define PRCM_PER7CLK_MGT_REG (PRCMU_BASE + 0x040) | |
51 | #define PRCM_DMACLK_MGT_REG (PRCMU_BASE + 0x074) | |
52 | #define PRCM_B2R2CLK_MGT_REG (PRCMU_BASE + 0x078) | |
53 | ||
54 | #define PRCM_PLLSOC0_FREQ_REG (PRCMU_BASE + 0x080) | |
55 | #define PRCM_PLLSOC1_FREQ_REG (PRCMU_BASE + 0x084) | |
56 | #define PRCM_PLLARM_FREQ_REG (PRCMU_BASE + 0x088) | |
57 | #define PRCM_PLLDDR_FREQ_REG (PRCMU_BASE + 0x08C) | |
58 | #define PRCM_ARM_CHGCLKREQ_REG (PRCMU_BASE + 0x114) | |
59 | ||
60 | #define PRCM_TCR (PRCMU_BASE + 0x1C8) | |
61 | ||
62 | /* | |
63 | * Memory controller register | |
64 | */ | |
65 | #define DMC_BASE_ADDR 0x80156000 | |
66 | #define DMC_CTL_97 (DMC_BASE_ADDR + 0x184) | |
67 | ||
68 | int board_id; /* set in board_late_init() */ | |
69 | ||
70 | /* PLLs for clock management registers */ | |
71 | enum { | |
72 | GATED = 0, | |
73 | PLLSOC0, /* pllsw = 001, ffs() = 1 */ | |
74 | PLLSOC1, /* pllsw = 010, ffs() = 2 */ | |
75 | PLLDDR, /* pllsw = 100, ffs() = 3 */ | |
76 | PLLARM, | |
77 | }; | |
78 | ||
79 | static struct pll_freq_regs { | |
80 | int idx; /* index fror pll_name and pll_khz arrays */ | |
81 | uint32_t addr; | |
82 | } pll_freq_regs[] = { | |
83 | {PLLSOC0, PRCM_PLLSOC0_FREQ_REG}, | |
84 | {PLLSOC1, PRCM_PLLSOC1_FREQ_REG}, | |
85 | {PLLDDR, PRCM_PLLDDR_FREQ_REG}, | |
86 | {PLLARM, PRCM_PLLARM_FREQ_REG}, | |
87 | {0, 0}, | |
88 | }; | |
89 | ||
90 | static const char *pll_name[5] = {"GATED", "SOC0", "SOC1", "DDR", "ARM"}; | |
91 | static uint32_t pll_khz[5]; /* use ffs(pllsw(reg)) as index for 0..3 */ | |
92 | ||
93 | static struct clk_mgt_regs { | |
94 | uint32_t addr; | |
95 | uint32_t val; | |
96 | const char *descr; | |
97 | } clk_mgt_regs[] = { | |
98 | /* register content taken from bootrom settings */ | |
99 | {PRCM_ARMCLKFIX_MGT_REG, 0x0120, "ARMCLKFIX"}, /* ena, SOC0/0, ??? */ | |
100 | {PRCM_ACLK_MGT_REG, 0x0125, "ACLK"}, /* ena, SOC0/5, 160 MHz */ | |
101 | {PRCM_SVAMMDSPCLK_MGT_REG, 0x1122, "SVA"}, /* ena, SOC0/2, 400 MHz */ | |
102 | {PRCM_SIAMMDSPCLK_MGT_REG, 0x0022, "SIA"}, /* dis, SOC0/2, 400 MHz */ | |
103 | {PRCM_SAAMMDSPCLK_MGT_REG, 0x0822, "SAA"}, /* dis, SOC0/4, 200 MHz */ | |
104 | {PRCM_SGACLK_MGT_REG, 0x0024, "SGA"}, /* dis, SOC0/4, 200 MHz */ | |
105 | {PRCM_UARTCLK_MGT_REG, 0x0300, "UART"}, /* ena, GATED, CLK38 */ | |
106 | {PRCM_MSPCLK_MGT_REG, 0x0200, "MSP"}, /* dis, GATED, CLK38 */ | |
107 | {PRCM_I2CCLK_MGT_REG, 0x0130, "I2C"}, /* ena, SOC0/16, 50 MHz */ | |
108 | {PRCM_SDMMCCLK_MGT_REG, 0x0130, "SDMMC"}, /* ena, SOC0/16, 50 MHz */ | |
109 | {PRCM_PER1CLK_MGT_REG, 0x126, "PER1"}, /* ena, SOC0/6, 133 MHz */ | |
110 | {PRCM_PER2CLK_MGT_REG, 0x126, "PER2"}, /* ena, SOC0/6, 133 MHz */ | |
111 | {PRCM_PER3CLK_MGT_REG, 0x126, "PER3"}, /* ena, SOC0/6, 133 MHz */ | |
112 | {PRCM_PER5CLK_MGT_REG, 0x126, "PER5"}, /* ena, SOC0/6, 133 MHz */ | |
113 | {PRCM_PER6CLK_MGT_REG, 0x126, "PER6"}, /* ena, SOC0/6, 133 MHz */ | |
114 | {PRCM_PER7CLK_MGT_REG, 0x128, "PER7"}, /* ena, SOC0/8, 100 MHz */ | |
115 | {PRCM_DMACLK_MGT_REG, 0x125, "DMA"}, /* ena, SOC0/5, 160 MHz */ | |
116 | {PRCM_B2R2CLK_MGT_REG, 0x025, "B2R2"}, /* dis, SOC0/5, 160 MHz */ | |
117 | {0, 0, NULL}, | |
118 | }; | |
119 | ||
120 | static void init_regs(void); | |
121 | ||
122 | DECLARE_GLOBAL_DATA_PTR; | |
123 | #if defined(CONFIG_SHOW_BOOT_PROGRESS) | |
124 | void show_boot_progress(int progress) | |
125 | { | |
126 | printf("Boot reached stage %d\n", progress); | |
127 | } | |
128 | #endif | |
129 | ||
afbf8899 JR |
130 | /* |
131 | * Miscellaneous platform dependent initialisations | |
132 | */ | |
133 | ||
134 | int board_early_init_f(void) | |
135 | { | |
136 | init_regs(); | |
137 | return 0; | |
138 | } | |
139 | ||
140 | int board_init(void) | |
141 | { | |
142 | uint32_t unused_cols_rows; | |
143 | unsigned int nrows; | |
144 | unsigned int ncols; | |
145 | ||
146 | gd->bd->bi_arch_number = 0x1A4; | |
147 | gd->bd->bi_boot_params = 0x00000100; | |
148 | gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE; | |
149 | ||
150 | /* | |
151 | * Assumption: 2 CS active, both CS have same layout. | |
152 | * 15 rows max, 11 cols max (controller spec). | |
153 | * memory chip has 8 banks, I/O width 32 bit. | |
154 | * The correct way would be to read MR#8: I/O width and density, | |
155 | * but this requires locking against the PRCMU firmware. | |
156 | * Simplified approach: | |
157 | * Read number of unused rows and columns from mem controller. | |
158 | * size = nCS x 2^(rows+cols) x nbanks x buswidth_bytes | |
159 | */ | |
160 | unused_cols_rows = readl(DMC_CTL_97); | |
161 | nrows = 15 - (unused_cols_rows & 0x07); | |
162 | ncols = 11 - ((unused_cols_rows & 0x0700) >> 8); | |
163 | gd->bd->bi_dram[0].size = 2 * (1 << (nrows + ncols)) * 8 * 4; | |
164 | ||
165 | icache_enable(); | |
166 | ||
167 | return 0; | |
168 | } | |
169 | ||
170 | int dram_init(void) | |
171 | { | |
172 | gd->ram_size = PHYS_SDRAM_SIZE_1; | |
173 | ||
174 | return 0; | |
175 | } | |
176 | ||
177 | unsigned int addr_vall_arr[] = { | |
178 | 0x8011F000, 0x0000FFFF, /* Clocks for HSI TODO: Enable reqd only */ | |
179 | 0x8011F008, 0x00001CFF, /* Clocks for HSI TODO: Enable reqd only */ | |
180 | 0x8000F000, 0x00007FFF, /* Clocks for I2C TODO: Enable reqd only */ | |
181 | 0x8000F008, 0x00007FFF, /* Clocks for I2C TODO: Enable reqd only */ | |
182 | 0x80157020, 0x00000150, /* I2C 48MHz clock */ | |
183 | 0x8012F000, 0x00007FFF, /* Clocks for SD TODO: Enable reqd only */ | |
184 | 0x8012F008, 0x00007FFF, /* Clocks for SD TODO: Enable reqd only */ | |
185 | 0xA03DF000, 0x0000000D, /* Clock for MTU Timers */ | |
186 | 0x8011E00C, 0x00000000, /* GPIO ALT FUNC for EMMC */ | |
187 | 0x8011E004, 0x0000FFE0, /* GPIO ALT FUNC for EMMC */ | |
188 | 0x8011E020, 0x0000FFE0, /* GPIO ALT FUNC for EMMC */ | |
189 | 0x8011E024, 0x00000000, /* GPIO ALT FUNC for EMMC */ | |
190 | 0x8012E000, 0x20000000, /* GPIO ALT FUNC for UART */ | |
191 | 0x8012E00C, 0x00000000, /* GPIO ALT FUNC for SD */ | |
192 | 0x8012E004, 0x0FFC0000, /* GPIO ALT FUNC for SD */ | |
193 | 0x8012E020, 0x60000000, /* GPIO ALT FUNC for SD */ | |
194 | 0x8012E024, 0x60000000, /* GPIO ALT FUNC for SD */ | |
195 | 0x801571E4, 0x0000000C, /* PRCMU settings for B2R2, | |
196 | PRCM_APE_RESETN_SET_REG */ | |
197 | 0x80157024, 0x00000130, /* PRCMU settings for EMMC/SD */ | |
198 | 0xA03FF000, 0x00000003, /* USB */ | |
199 | 0xA03FF008, 0x00000001, /* USB */ | |
200 | 0xA03FE00C, 0x00000000, /* USB */ | |
201 | 0xA03FE020, 0x00000FFF, /* USB */ | |
202 | 0xA03FE024, 0x00000000 /* USB */ | |
203 | }; | |
204 | ||
9660e442 | 205 | #ifdef CONFIG_BOARD_LATE_INIT |
afbf8899 JR |
206 | /* |
207 | * called after all initialisation were done, but before the generic | |
208 | * mmc_initialize(). | |
209 | */ | |
210 | int board_late_init(void) | |
211 | { | |
212 | uchar byte; | |
213 | ||
214 | /* | |
215 | * Determine and set board_id environment variable | |
216 | * 0: mop500, 1: href500 | |
217 | * Above boards have different GPIO expander chips which we can | |
218 | * distinguish by the chip id. | |
219 | * | |
220 | * The board_id environment variable is needed for the Linux bootargs. | |
221 | */ | |
222 | (void) i2c_set_bus_num(0); | |
223 | (void) i2c_read(CONFIG_SYS_I2C_GPIOE_ADDR, 0x80, 1, &byte, 1); | |
224 | if (byte == 0x01) { | |
225 | board_id = 0; | |
226 | setenv("board_id", "0"); | |
227 | } else { | |
228 | board_id = 1; | |
229 | setenv("board_id", "1"); | |
230 | } | |
231 | #ifdef CONFIG_MMC | |
1e37322e | 232 | u8500_mmc_power_init(); |
afbf8899 JR |
233 | |
234 | /* | |
235 | * config extended GPIO pins for level shifter and | |
236 | * SDMMC_ENABLE | |
237 | */ | |
238 | if (board_id == 0) { | |
239 | /* MOP500 */ | |
240 | byte = 0x0c; | |
241 | (void) i2c_write(CONFIG_SYS_I2C_GPIOE_ADDR, 0x89, 1, &byte, 1); | |
242 | (void) i2c_write(CONFIG_SYS_I2C_GPIOE_ADDR, 0x83, 1, &byte, 1); | |
243 | } else { | |
244 | /* HREF */ | |
245 | /* set the direction of GPIO KPY9 and KPY10 */ | |
246 | byte = 0x06; | |
247 | (void) i2c_write(CONFIG_SYS_I2C_GPIOE_ADDR, 0xC8, 1, &byte, 1); | |
248 | /* must be a multibyte access */ | |
249 | (void) i2c_write(CONFIG_SYS_I2C_GPIOE_ADDR, 0xC4, 1, | |
250 | (uchar []) {0x06, 0x06}, 2); | |
251 | } | |
252 | #endif /* CONFIG_MMC */ | |
253 | /* | |
254 | * Create a memargs variable which points uses either the memargs256 or | |
255 | * memargs512 environment variable, depending on the memory size. | |
256 | * memargs is used to build the bootargs, memargs256 and memargs512 are | |
257 | * stored in the environment. | |
258 | */ | |
259 | if (gd->bd->bi_dram[0].size == 0x10000000) { | |
260 | setenv("memargs", "setenv bootargs ${bootargs} ${memargs256}"); | |
261 | setenv("mem", "256M"); | |
262 | } else { | |
263 | setenv("memargs", "setenv bootargs ${bootargs} ${memargs512}"); | |
264 | setenv("mem", "512M"); | |
265 | } | |
266 | ||
267 | return 0; | |
268 | } | |
9660e442 | 269 | #endif /* CONFIG_BOARD_LATE_INIT */ |
afbf8899 JR |
270 | |
271 | static void early_gpio_setup(struct gpio_register *gpio_reg, u32 bits) | |
272 | { | |
273 | writel(readl(&gpio_reg->gpio_dats) | bits, &gpio_reg->gpio_dats); | |
274 | writel(readl(&gpio_reg->gpio_pdis) & ~bits, &gpio_reg->gpio_pdis); | |
275 | } | |
276 | ||
277 | static void init_regs(void) | |
278 | { | |
279 | /* FIXME Remove magic register array settings for ED also */ | |
280 | struct prcmu *prcmu = (struct prcmu *) U8500_PRCMU_BASE; | |
281 | ||
282 | /* Enable timers */ | |
283 | writel(1 << 17, &prcmu->tcr); | |
284 | ||
285 | u8500_prcmu_enable(&prcmu->per1clk_mgt); | |
286 | u8500_prcmu_enable(&prcmu->per2clk_mgt); | |
287 | u8500_prcmu_enable(&prcmu->per3clk_mgt); | |
288 | u8500_prcmu_enable(&prcmu->per5clk_mgt); | |
289 | u8500_prcmu_enable(&prcmu->per6clk_mgt); | |
290 | u8500_prcmu_enable(&prcmu->per7clk_mgt); | |
291 | ||
292 | u8500_prcmu_enable(&prcmu->uartclk_mgt); | |
293 | u8500_prcmu_enable(&prcmu->i2cclk_mgt); | |
294 | ||
295 | u8500_prcmu_enable(&prcmu->sdmmcclk_mgt); | |
296 | ||
297 | u8500_clock_enable(1, 9, -1); /* GPIO0 */ | |
298 | ||
299 | u8500_clock_enable(2, 11, -1); /* GPIO1 */ | |
300 | ||
301 | u8500_clock_enable(3, 8, -1); /* GPIO2 */ | |
302 | u8500_clock_enable(5, 1, -1); /* GPIO3 */ | |
303 | ||
304 | u8500_clock_enable(3, 6, 6); /* UART2 */ | |
305 | ||
306 | gpio_altfuncenable(GPIO_ALT_I2C_0, "I2C0"); | |
307 | u8500_clock_enable(3, 3, 3); /* I2C0 */ | |
308 | ||
309 | early_gpio_setup((struct gpio_register *)U8500_GPIO_0_BASE, 0x60000000); | |
310 | gpio_altfuncenable(GPIO_ALT_UART_2, "UART2"); | |
311 | ||
312 | early_gpio_setup((struct gpio_register *)U8500_GPIO_6_BASE, 0x0000ffe0); | |
313 | gpio_altfuncenable(GPIO_ALT_EMMC, "EMMC"); | |
314 | ||
315 | early_gpio_setup((struct gpio_register *)U8500_GPIO_0_BASE, 0x0000ffe0); | |
316 | gpio_altfuncenable(GPIO_ALT_SD_CARD0, "SDCARD"); | |
317 | ||
318 | u8500_clock_enable(1, 5, 5); /* SDI0 */ | |
319 | u8500_clock_enable(2, 4, 2); /* SDI4 */ | |
320 | ||
321 | u8500_clock_enable(6, 7, -1); /* MTU0 */ | |
322 | u8500_clock_enable(3, 4, 4); /* SDI2 */ | |
323 | ||
324 | early_gpio_setup((struct gpio_register *)U8500_GPIO_4_BASE, 0x000007ff); | |
325 | gpio_altfuncenable(GPIO_ALT_POP_EMMC, "EMMC"); | |
326 | ||
327 | /* | |
328 | * Enabling clocks for all devices which are AMBA devices in the | |
329 | * kernel. Otherwise they will not get probe()'d because the | |
330 | * peripheral ID register will not be powered. | |
331 | */ | |
332 | ||
333 | /* XXX: some of these differ between ED/V1 */ | |
334 | ||
335 | u8500_clock_enable(1, 1, 1); /* UART1 */ | |
336 | u8500_clock_enable(1, 0, 0); /* UART0 */ | |
337 | ||
338 | u8500_clock_enable(3, 2, 2); /* SSP1 */ | |
339 | u8500_clock_enable(3, 1, 1); /* SSP0 */ | |
340 | ||
341 | u8500_clock_enable(2, 8, -1); /* SPI0 */ | |
342 | u8500_clock_enable(2, 5, 3); /* MSP2 */ | |
343 | } | |
344 | ||
345 | #ifdef CONFIG_MMC | |
346 | static int u8500_mmci_board_init(void) | |
347 | { | |
348 | enum gpio_error error; | |
349 | struct gpio_register *gpio_base_address; | |
350 | ||
351 | gpio_base_address = (void *)(U8500_GPIO_0_BASE); | |
352 | gpio_base_address->gpio_dats |= 0xFFC0000; | |
353 | gpio_base_address->gpio_pdis &= ~0xFFC0000; | |
354 | ||
355 | /* save the GPIO0 AFSELA register */ | |
356 | error = gpio_altfuncenable(GPIO_ALT_SD_CARD0, "MMC"); | |
357 | if (error != GPIO_OK) { | |
358 | printf("u8500_mmci_board_init() gpio_altfuncenable failed\n"); | |
359 | return -ENODEV; | |
360 | } | |
361 | return 0; | |
362 | } | |
363 | ||
364 | int board_mmc_init(bd_t *bd) | |
365 | { | |
10ed93dc JR |
366 | struct pl180_mmc_host *host; |
367 | ||
afbf8899 JR |
368 | if (u8500_mmci_board_init()) |
369 | return -ENODEV; | |
370 | ||
10ed93dc JR |
371 | host = malloc(sizeof(struct pl180_mmc_host)); |
372 | if (!host) | |
373 | return -ENOMEM; | |
374 | memset(host, 0, sizeof(*host)); | |
375 | ||
376 | strcpy(host->name, "MMC"); | |
377 | host->base = (struct sdi_registers *)CONFIG_ARM_PL180_MMCI_BASE; | |
378 | host->pwr_init = INIT_PWR; | |
379 | host->clkdiv_init = SDI_CLKCR_CLKDIV_INIT_V1 | SDI_CLKCR_CLKEN; | |
380 | host->voltages = VOLTAGE_WINDOW_MMC; | |
381 | host->caps = 0; | |
382 | host->clock_in = ARM_MCLK; | |
383 | host->clock_min = ARM_MCLK / (2 * (SDI_CLKCR_CLKDIV_INIT_V1 + 1)); | |
384 | host->clock_max = CONFIG_ARM_PL180_MMCI_CLOCK_FREQ; | |
385 | ||
386 | return arm_pl180_mmci_init(host); | |
afbf8899 JR |
387 | } |
388 | #endif | |
389 | ||
390 | ||
391 | /* | |
392 | * get_pll_freq_khz - return PLL frequency in kHz | |
393 | */ | |
394 | static uint32_t get_pll_freq_khz(uint32_t inclk_khz, uint32_t freq_reg) | |
395 | { | |
396 | uint32_t idf, ldf, odf, seldiv, phi; | |
397 | ||
398 | /* | |
399 | * PLLOUTCLK = PHI = (INCLK*LDF)/(2*ODF*IDF) if SELDIV2=0 | |
400 | * PLLOUTCLK = PHI = (INCLK*LDF)/(4*ODF*IDF) if SELDIV2=1 | |
401 | * where: | |
402 | * IDF=R(2:0) (when R=000, IDF=1d) | |
403 | * LDF = 2*D(7:0) (D must be greater than or equal to 6) | |
404 | * ODF = N(5:0) (when N=000000, 0DF=1d) | |
405 | */ | |
406 | ||
407 | idf = (freq_reg & 0x70000) >> 16; | |
408 | ldf = (freq_reg & 0xff) * 2; | |
409 | odf = (freq_reg & 0x3f00) >> 8; | |
410 | seldiv = (freq_reg & 0x01000000) >> 24; | |
411 | phi = (inclk_khz * ldf) / (2 * odf * idf); | |
412 | if (seldiv) | |
413 | phi = phi/2; | |
414 | ||
415 | return phi; | |
416 | } | |
417 | ||
418 | int do_clkinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | |
419 | { | |
420 | uint32_t inclk_khz; | |
421 | uint32_t reg, phi; | |
422 | uint32_t clk_khz; | |
423 | unsigned int clk_sel; | |
424 | struct clk_mgt_regs *clks = clk_mgt_regs; | |
425 | struct pll_freq_regs *plls = pll_freq_regs; | |
426 | ||
427 | /* | |
428 | * Go through list of PLLs. | |
429 | * Initialise pll out frequency array (pll_khz) and print frequency. | |
430 | */ | |
431 | inclk_khz = 38400; /* 38.4 MHz */ | |
432 | while (plls->addr) { | |
433 | reg = readl(plls->addr); | |
434 | phi = get_pll_freq_khz(inclk_khz, reg); | |
435 | pll_khz[plls->idx] = phi; | |
436 | printf("%s PLL out frequency: %d.%d Mhz\n", | |
437 | pll_name[plls->idx], phi/1000, phi % 1000); | |
438 | plls++; | |
439 | } | |
440 | ||
441 | /* check ARM clock source */ | |
442 | reg = readl(PRCM_ARM_CHGCLKREQ_REG); | |
443 | printf("A9 running on %s\n", | |
444 | (reg & 1) ? "external clock" : "ARM PLL"); | |
445 | ||
446 | /* go through list of clk_mgt_reg */ | |
447 | printf("\n%19s %9s %7s %9s enabled\n", | |
448 | "name(addr)", "value", "PLL", "CLK[MHz]"); | |
449 | while (clks->addr) { | |
450 | reg = readl(clks->addr); | |
451 | ||
452 | /* convert bit position into array index */ | |
453 | clk_sel = ffs((reg >> 5) & 0x7); /* PLLSW[2:0] */ | |
454 | ||
455 | if (reg & 0x200) | |
456 | clk_khz = 38400; /* CLK38 is set */ | |
457 | else if ((reg & 0x1f) == 0) | |
458 | /* ARMCLKFIX_MGT is 0x120, e.g. div = 0 ! */ | |
459 | clk_khz = 0; | |
460 | else | |
461 | clk_khz = pll_khz[clk_sel] / (reg & 0x1f); | |
462 | ||
463 | printf("%9s(%08x): %08x, %6s, %4d.%03d, %s\n", | |
464 | clks->descr, clks->addr, reg, pll_name[clk_sel], | |
465 | clk_khz / 1000, clk_khz % 1000, | |
466 | (reg & 0x100) ? "ena" : "dis"); | |
467 | clks++; | |
468 | } | |
469 | ||
470 | return 0; | |
471 | } | |
472 | ||
473 | U_BOOT_CMD( | |
474 | clkinfo, 1, 1, do_clkinfo, | |
475 | "print clock info", | |
476 | "" | |
477 | ); |