blob: 0fc6088e3ee10e23584df8203a92ad39dfd15b33 [file] [log] [blame]
Haavard Skinnemoen546f9542008-05-02 15:21:40 +02001/*
2 * Copyright (C) 2005-2008 Atmel Corporation
3 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02004 * SPDX-License-Identifier: GPL-2.0+
Haavard Skinnemoen546f9542008-05-02 15:21:40 +02005 */
6#include <common.h>
7
8#include <asm/io.h>
9
10#include <asm/arch/clk.h>
Andreas Bießmann94156fa2010-11-04 23:15:30 +000011#include <asm/arch/hardware.h>
Haavard Skinnemoen1cbd2f02008-08-31 18:05:32 +020012#include <asm/arch/portmux.h>
Haavard Skinnemoen546f9542008-05-02 15:21:40 +020013
14#include "sm.h"
15
16void 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 */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020026 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)
Haavard Skinnemoen546f9542008-05-02 15:21:40 +020030 | 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;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020039 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);
Haavard Skinnemoen546f9542008-05-02 15:21:40 +020047 sm_writel(PM_CKSEL, cksel);
48
49#ifdef CONFIG_PLL
50 /* Use PLL0 as main clock */
51 sm_writel(PM_MCCTRL, SM_BIT(PLLSEL));
Mark Jacksonc563e482009-07-21 11:11:37 +010052
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
Haavard Skinnemoen546f9542008-05-02 15:21:40 +020057#endif
58}
Haavard Skinnemoen1cbd2f02008-08-31 18:05:32 +020059
60unsigned 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 {
Masahiro Yamadadb204642014-11-07 03:03:31 +090075 divider = min(255UL, divider / 2 - 1);
Haavard Skinnemoen1cbd2f02008-08-31 18:05:32 +020076 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}