]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/avr32/cpu/at32ap700x/clk.c
Add GPL-2.0+ SPDX-License-Identifier to source files
[karo-tx-uboot.git] / arch / avr32 / cpu / at32ap700x / clk.c
1 /*
2  * Copyright (C) 2005-2008 Atmel Corporation
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6 #include <common.h>
7
8 #include <asm/io.h>
9
10 #include <asm/arch/clk.h>
11 #include <asm/arch/hardware.h>
12 #include <asm/arch/portmux.h>
13
14 #include "sm.h"
15
16 void clk_init(void)
17 {
18         uint32_t cksel;
19
20         /* in case of soft resets, disable watchdog */
21         sm_writel(WDT_CTRL, SM_BF(KEY, 0x55));
22         sm_writel(WDT_CTRL, SM_BF(KEY, 0xaa));
23
24 #ifdef CONFIG_PLL
25         /* Initialize the PLL */
26         sm_writel(PM_PLL0, (SM_BF(PLLCOUNT, CONFIG_SYS_PLL0_SUPPRESS_CYCLES)
27                             | SM_BF(PLLMUL, CONFIG_SYS_PLL0_MUL - 1)
28                             | SM_BF(PLLDIV, CONFIG_SYS_PLL0_DIV - 1)
29                             | SM_BF(PLLOPT, CONFIG_SYS_PLL0_OPT)
30                             | SM_BF(PLLOSC, 0)
31                             | SM_BIT(PLLEN)));
32
33         /* Wait for lock */
34         while (!(sm_readl(PM_ISR) & SM_BIT(LOCK0))) ;
35 #endif
36
37         /* Set up clocks for the CPU and all peripheral buses */
38         cksel = 0;
39         if (CONFIG_SYS_CLKDIV_CPU)
40                 cksel |= SM_BIT(CPUDIV) | SM_BF(CPUSEL, CONFIG_SYS_CLKDIV_CPU - 1);
41         if (CONFIG_SYS_CLKDIV_HSB)
42                 cksel |= SM_BIT(HSBDIV) | SM_BF(HSBSEL, CONFIG_SYS_CLKDIV_HSB - 1);
43         if (CONFIG_SYS_CLKDIV_PBA)
44                 cksel |= SM_BIT(PBADIV) | SM_BF(PBASEL, CONFIG_SYS_CLKDIV_PBA - 1);
45         if (CONFIG_SYS_CLKDIV_PBB)
46                 cksel |= SM_BIT(PBBDIV) | SM_BF(PBBSEL, CONFIG_SYS_CLKDIV_PBB - 1);
47         sm_writel(PM_CKSEL, cksel);
48
49 #ifdef CONFIG_PLL
50         /* Use PLL0 as main clock */
51         sm_writel(PM_MCCTRL, SM_BIT(PLLSEL));
52
53 #ifdef CONFIG_LCD
54         /* Set up pixel clock for the LCDC */
55         sm_writel(PM_GCCTRL(7), SM_BIT(PLLSEL) | SM_BIT(CEN));
56 #endif
57 #endif
58 }
59
60 unsigned long __gclk_set_rate(unsigned int id, enum gclk_parent parent,
61                 unsigned long rate, unsigned long parent_rate)
62 {
63         unsigned long divider;
64
65         if (rate == 0 || parent_rate == 0) {
66                 sm_writel(PM_GCCTRL(id), 0);
67                 return 0;
68         }
69
70         divider = (parent_rate + rate / 2) / rate;
71         if (divider <= 1) {
72                 sm_writel(PM_GCCTRL(id), parent | SM_BIT(CEN));
73                 rate = parent_rate;
74         } else {
75                 divider = min(255, divider / 2 - 1);
76                 sm_writel(PM_GCCTRL(id), parent | SM_BIT(CEN) | SM_BIT(DIVEN)
77                                 | SM_BF(DIV, divider));
78                 rate = parent_rate / (2 * (divider + 1));
79         }
80
81         return rate;
82 }