uboot/arch/arm/mach-sunxi/clock_sun9i.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2
   3/*
   4 * sun9i specific clock code
   5 *
   6 * (C) Copyright 2015 Hans de Goede <hdegoede@redhat.com>
   7 *
   8 * (C) Copyright 2016 Theobroma Systems Design und Consulting GmbH
   9 *                    Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
  10 */
  11
  12#include <common.h>
  13#include <asm/io.h>
  14#include <asm/arch/clock.h>
  15#include <asm/arch/prcm.h>
  16#include <asm/arch/sys_proto.h>
  17
  18
  19#ifdef CONFIG_SPL_BUILD
  20
  21void clock_init_safe(void)
  22{
  23        struct sunxi_ccm_reg * const ccm =
  24                (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
  25
  26        /* Set up PLL12 (peripheral 1) */
  27        clock_set_pll12(1200000000);
  28
  29        /* Set up PLL1 (cluster 0) and PLL2 (cluster 1) */
  30        clock_set_pll1(408000000);
  31        clock_set_pll2(408000000);
  32
  33        /* Set up PLL4 (peripheral 0) */
  34        clock_set_pll4(960000000);
  35
  36        /* Set up dividers for AXI0 and APB0 on cluster 0: PLL1 / 2 = 204MHz */
  37        writel(C0_CFG_AXI0_CLK_DIV_RATIO(2) |
  38               C0_CFG_APB0_CLK_DIV_RATIO(2), &ccm->c0_cfg);
  39
  40        /* AHB0: 120 MHz (PLL_PERIPH0 / 8) */
  41        writel(AHBx_SRC_PLL_PERIPH0 | AHBx_CLK_DIV_RATIO(8),
  42               &ccm->ahb0_cfg);
  43        /* AHB1: 240 MHz (PLL_PERIPH0 / 4) */
  44        writel(AHBx_SRC_PLL_PERIPH0 | AHBx_CLK_DIV_RATIO(4),
  45               &ccm->ahb1_cfg);
  46        /* AHB2: 120 MHz (PLL_PERIPH0 / 8) */
  47        writel(AHBx_SRC_PLL_PERIPH0 | AHBx_CLK_DIV_RATIO(8),
  48               &ccm->ahb2_cfg);
  49        /* APB0: 120 MHz (PLL_PERIPH0 / 8) */
  50        writel(APB0_SRC_PLL_PERIPH0 | APB0_CLK_DIV_RATIO(8),
  51               &ccm->apb0_cfg);
  52
  53        /* GTBUS: 400MHz (PERIPH0 div 3) */
  54        writel(GTBUS_SRC_PLL_PERIPH1 | GTBUS_CLK_DIV_RATIO(3),
  55               &ccm->gtbus_cfg);
  56        /* CCI400: 480MHz (PERIPH1 div 2) */
  57        writel(CCI400_SRC_PLL_PERIPH0 | CCI400_CLK_DIV_RATIO(2),
  58               &ccm->cci400_cfg);
  59
  60        /* Deassert DMA reset and open clock gating for DMA */
  61        setbits_le32(&ccm->ahb_reset1_cfg, (1 << 24));
  62        setbits_le32(&ccm->apb1_gate, (1 << 24));
  63
  64        /* set enable-bit in TSTAMP_CTRL_REG */
  65        writel(1, 0x01720000);
  66}
  67#endif
  68
  69void clock_init_uart(void)
  70{
  71        struct sunxi_ccm_reg *const ccm =
  72                (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
  73
  74        /* open the clock for uart */
  75        setbits_le32(&ccm->apb1_gate,
  76                     CLK_GATE_OPEN << (APB1_GATE_UART_SHIFT +
  77                                       CONFIG_CONS_INDEX - 1));
  78        /* deassert uart reset */
  79        setbits_le32(&ccm->apb1_reset_cfg,
  80                     1 << (APB1_RESET_UART_SHIFT +
  81                           CONFIG_CONS_INDEX - 1));
  82}
  83
  84#ifdef CONFIG_SPL_BUILD
  85void clock_set_pll1(unsigned int clk)
  86{
  87        struct sunxi_ccm_reg * const ccm =
  88                (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
  89        const int p = 0;
  90
  91        /* Switch cluster 0 to 24MHz clock while changing PLL1 */
  92        clrsetbits_le32(&ccm->cpu_clk_source, C0_CPUX_CLK_SRC_MASK,
  93                        C0_CPUX_CLK_SRC_OSC24M);
  94
  95        writel(CCM_PLL1_CTRL_EN | CCM_PLL1_CTRL_P(p) |
  96               CCM_PLL1_CLOCK_TIME_2 |
  97               CCM_PLL1_CTRL_N(clk / 24000000),
  98               &ccm->pll1_c0_cfg);
  99        /*
 100         * Don't bother with the stable-time registers, as it doesn't
 101         * wait until the PLL is stable.  Note, that even Allwinner
 102         * just uses a delay loop (or rather the AVS timer) for this
 103         * instead of the PLL_STABLE_STATUS register.
 104         */
 105        sdelay(2000);
 106
 107        /* Switch cluster 0 back to PLL1 */
 108        clrsetbits_le32(&ccm->cpu_clk_source, C0_CPUX_CLK_SRC_MASK,
 109                        C0_CPUX_CLK_SRC_PLL1);
 110}
 111
 112void clock_set_pll2(unsigned int clk)
 113{
 114        struct sunxi_ccm_reg * const ccm =
 115                (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 116        const int p = 0;
 117
 118        /* Switch cluster 1 to 24MHz clock while changing PLL2 */
 119        clrsetbits_le32(&ccm->cpu_clk_source, C1_CPUX_CLK_SRC_MASK,
 120                        C1_CPUX_CLK_SRC_OSC24M);
 121
 122        writel(CCM_PLL2_CTRL_EN | CCM_PLL2_CTRL_P(p) |
 123               CCM_PLL2_CLOCK_TIME_2 | CCM_PLL2_CTRL_N(clk / 24000000),
 124               &ccm->pll2_c1_cfg);
 125
 126        sdelay(2000);
 127
 128        /* Switch cluster 1 back to PLL2 */
 129        clrsetbits_le32(&ccm->cpu_clk_source, C1_CPUX_CLK_SRC_MASK,
 130                        C1_CPUX_CLK_SRC_PLL2);
 131}
 132
 133void clock_set_pll6(unsigned int clk)
 134{
 135        struct sunxi_ccm_reg * const ccm =
 136                (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 137        const int p = 0;
 138
 139        writel(CCM_PLL6_CTRL_EN | CCM_PLL6_CFG_UPDATE | CCM_PLL6_CTRL_P(p)
 140               | CCM_PLL6_CTRL_N(clk / 24000000),
 141               &ccm->pll6_ddr_cfg);
 142        do { } while (!(readl(&ccm->pll_stable_status) & PLL_DDR_STATUS));
 143
 144        sdelay(2000);
 145}
 146
 147void clock_set_pll12(unsigned int clk)
 148{
 149        struct sunxi_ccm_reg * const ccm =
 150                (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 151
 152        if (readl(&ccm->pll12_periph1_cfg) & CCM_PLL12_CTRL_EN)
 153                return;
 154
 155        writel(CCM_PLL12_CTRL_EN | CCM_PLL12_CTRL_N(clk / 24000000),
 156               &ccm->pll12_periph1_cfg);
 157
 158        sdelay(2000);
 159}
 160
 161
 162void clock_set_pll4(unsigned int clk)
 163{
 164        struct sunxi_ccm_reg * const ccm =
 165                (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 166
 167        writel(CCM_PLL4_CTRL_EN | CCM_PLL4_CTRL_N(clk / 24000000),
 168               &ccm->pll4_periph0_cfg);
 169
 170        sdelay(2000);
 171}
 172#endif
 173
 174int clock_twi_onoff(int port, int state)
 175{
 176        struct sunxi_ccm_reg *const ccm =
 177                (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 178
 179        if (port > 4)
 180                return -1;
 181
 182        /* set the apb reset and clock gate for twi */
 183        if (state) {
 184                setbits_le32(&ccm->apb1_gate,
 185                             CLK_GATE_OPEN << (APB1_GATE_TWI_SHIFT + port));
 186                setbits_le32(&ccm->apb1_reset_cfg,
 187                             1 << (APB1_RESET_TWI_SHIFT + port));
 188        } else {
 189                clrbits_le32(&ccm->apb1_reset_cfg,
 190                             1 << (APB1_RESET_TWI_SHIFT + port));
 191                clrbits_le32(&ccm->apb1_gate,
 192                             CLK_GATE_OPEN << (APB1_GATE_TWI_SHIFT + port));
 193        }
 194
 195        return 0;
 196}
 197
 198unsigned int clock_get_pll4_periph0(void)
 199{
 200        struct sunxi_ccm_reg *const ccm =
 201                (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
 202        uint32_t rval = readl(&ccm->pll4_periph0_cfg);
 203        int n = ((rval & CCM_PLL4_CTRL_N_MASK) >> CCM_PLL4_CTRL_N_SHIFT);
 204        int p = ((rval & CCM_PLL4_CTRL_P_MASK) >> CCM_PLL4_CTRL_P_SHIFT);
 205        int m = ((rval & CCM_PLL4_CTRL_M_MASK) >> CCM_PLL4_CTRL_M_SHIFT) + 1;
 206        const int k = 1;
 207
 208        return ((24000000 * n * k) >> p) / m;
 209}
 210