1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <stdint.h>
6 #include <threads.h>
7 #include <unistd.h>
8
9 #include <bits/limits.h>
10 #include <ddk/debug.h>
11
12 #include <zircon/assert.h>
13 #include <zircon/types.h>
14
15 #include <soc/aml-a113/a113-clocks.h>
16
17 #define DIV_ROUND_UP(n,d) ((n + d - 1) / d)
18
19 /* create instance of a113_clock_t and do basic initialization.
20 */
a113_clk_init(a113_clk_dev_t ** device)21 zx_status_t a113_clk_init(a113_clk_dev_t **device) {
22
23 *device = calloc(1, sizeof(a113_clk_dev_t));
24 if (!(*device)) {
25 return ZX_ERR_NO_MEMORY;
26 }
27
28 zx_handle_t resource = get_root_resource();
29 zx_status_t status;
30
31 status = mmio_buffer_init_physical(&(*device)->mmio, A113_CLOCKS_BASE_PHYS,PAGE_SIZE,
32 resource, ZX_CACHE_POLICY_UNCACHED_DEVICE);
33
34 if (status != ZX_OK) {
35 zxlogf(ERROR, "a113_clk_init: mmio_buffer_init_physical failed %d\n", status);
36 goto init_fail;
37 }
38 (*device)->regs_vaddr = (*device)->mmio.vaddr;
39
40 return ZX_OK;
41
42 init_fail:
43 mmio_buffer_release(&(*device)->mmio);
44 free(*device);
45 return status;
46 }
47
a113_clk_update_reg(a113_clk_dev_t * dev,uint32_t offset,uint32_t pos,uint32_t bits,uint32_t value)48 static void a113_clk_update_reg(a113_clk_dev_t *dev, uint32_t offset,
49 uint32_t pos,
50 uint32_t bits,
51 uint32_t value) {
52 uint32_t reg = a113_clk_get_reg(dev, offset);
53 reg &= ~(((1 << bits) - 1) << pos);
54 reg |= (value & ((1 << bits) - 1)) << pos;
55 a113_clk_set_reg(dev, offset, reg);
56 }
57
a113_clk_set_mpll2(a113_clk_dev_t * device,uint64_t rate,uint64_t * actual)58 zx_status_t a113_clk_set_mpll2(a113_clk_dev_t *device, uint64_t rate, uint64_t *actual) {
59 /* Overall ratio is reference/(n + sdm/16384)
60 In this case the 2.0GHz fixed rate pll is the reference
61 */
62 uint64_t n = A113_FIXED_PLL_RATE/rate; //calculate the integer ratio;
63 ZX_DEBUG_ASSERT( n < (1 << 9));
64
65 uint64_t sdm = DIV_ROUND_UP((A113_FIXED_PLL_RATE - n * rate) * SDM_FRACTIONALITY,
66 rate);
67 ZX_DEBUG_ASSERT(sdm < (1 << 14));
68 zxlogf(INFO,"%s sdm= %ld n= %ld\n",__func__,sdm,n);
69 a113_clk_update_reg(device, A113_HHI_MPLL_CNTL8, 0, 14, (uint32_t)sdm);
70 a113_clk_update_reg(device, A113_HHI_MPLL_CNTL8, 16, 9, (uint32_t)n);
71
72 // Enable sdm divider
73 a113_clk_update_reg(device, A113_HHI_MPLL_CNTL8, 15, 1, 1);
74 // Enable mpll2
75 a113_clk_update_reg(device, A113_HHI_MPLL_CNTL8, 14, 1, 1);
76 // Gate mpll2 through to rest of system
77 a113_clk_update_reg(device, A113_HHI_PLL_TOP_MISC, 2, 1, 1);
78
79 if (actual) {
80 *actual = ((uint64_t)SDM_FRACTIONALITY * A113_FIXED_PLL_RATE) /
81 ((SDM_FRACTIONALITY * n) +sdm);
82 }
83
84 return ZX_OK;
85 }
86