1// Copyright 2018 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// Temporary Clock and PLL management until the clock protocol is fully
6// developed.
7
8
9#include <hwreg/bitfields.h>
10#include <hwreg/mmio.h>
11#include <hw/reg.h>
12#include <zircon/syscalls.h>
13
14#include "aml-pcie-clk.h"
15
16#define AXG_MIPI_CNTL0 0xa5b80000
17
18#define PCIE_PLL_CNTL0 0x36
19#define PCIE_PLL_CNTL1 0x37
20#define PCIE_PLL_CNTL2 0x38
21#define PCIE_PLL_CNTL3 0x39
22#define PCIE_PLL_CNTL4 0x3A
23#define PCIE_PLL_CNTL5 0x3B
24#define PCIE_PLL_CNTL6 0x3C
25
26#define AXG_PCIE_PLL_CNTL0 0x400106c8
27#define AXG_PCIE_PLL_CNTL1 0x0084a2aa
28#define AXG_PCIE_PLL_CNTL2 0xb75020be
29#define AXG_PCIE_PLL_CNTL3 0x0a47488e
30#define AXG_PCIE_PLL_CNTL4 0xc000004d
31#define AXG_PCIE_PLL_CNTL5 0x00078000
32#define AXG_PCIE_PLL_CNTL6 0x002323c6
33
34#define MESON_PLL_ENABLE (1 << 30)
35#define MESON_PLL_RESET  (1 << 29)
36
37class MesonPLLControl0 : public hwreg::RegisterBase<MesonPLLControl0, uint32_t> {
38  public:
39    DEF_FIELD(8, 0, m);
40    DEF_FIELD(13, 9, n);
41    DEF_FIELD(17, 16, od);
42    DEF_BIT(29, reset);
43    DEF_BIT(30, enable);
44    DEF_BIT(31, lock);
45
46    static auto Get() {return hwreg::RegisterAddr<MesonPLLControl0>(0); }
47};
48
49class MesonPLLControl1 : public hwreg::RegisterBase<MesonPLLControl1, uint32_t> {
50  public:
51    DEF_FIELD(11, 0, div_frac);
52    DEF_BIT(12, div_mode);
53    DEF_FIELD(14, 13, dcvc_in);
54    DEF_FIELD(16, 15, dco_sdmck_sel);
55    DEF_BIT(17, dco_m_en);
56    DEF_BIT(18, dco_band_opt);
57    DEF_FIELD(21, 19, data_sel);
58    DEF_FIELD(23, 22, afc_nt);
59    DEF_FIELD(25, 24, afc_hold_t);
60    DEF_FIELD(27, 26, afc_dsel_in);
61    DEF_BIT(28, afc_dsel_bypass);
62    DEF_BIT(29, afc_clk_sel);
63    DEF_FIELD(31, 30, acq_r_ctr);
64
65    static auto Get() {return hwreg::RegisterAddr<MesonPLLControl1>(0); }
66};
67
68class MesonPLLControl6 : public hwreg::RegisterBase<MesonPLLControl6, uint32_t> {
69  public:
70    DEF_FIELD(7, 6, od2);
71    DEF_BIT(2, cml_input_sel1);
72    DEF_BIT(1, cml_input_sel0);
73    DEF_BIT(0, cml_input_en);
74
75    static auto Get() { return hwreg::RegisterAddr<MesonPLLControl6>(0); }
76};
77
78
79zx_status_t PllSetRate(zx_vaddr_t regbase) {
80    // TODO(gkalsi): This statically configures the PCIe PLL to run at
81    //               100mhz. When we write a real clock driver, we want this
82    //               value to be configurable.
83
84    volatile uint32_t* regs = (volatile uint32_t*)regbase;
85
86    writel(AXG_MIPI_CNTL0, regs + 0);
87    writel(AXG_PCIE_PLL_CNTL0, regs + PCIE_PLL_CNTL0);
88    writel(AXG_PCIE_PLL_CNTL1, regs + PCIE_PLL_CNTL1);
89    writel(AXG_PCIE_PLL_CNTL2, regs + PCIE_PLL_CNTL2);
90    writel(AXG_PCIE_PLL_CNTL3, regs + PCIE_PLL_CNTL3);
91    writel(AXG_PCIE_PLL_CNTL4, regs + PCIE_PLL_CNTL4);
92    writel(AXG_PCIE_PLL_CNTL5, regs + PCIE_PLL_CNTL5);
93    writel(AXG_PCIE_PLL_CNTL6, regs + PCIE_PLL_CNTL6);
94
95    hwreg::RegisterIo cntl0_mmio(regs + PCIE_PLL_CNTL0);
96    hwreg::RegisterIo cntl1_mmio(regs + PCIE_PLL_CNTL1);
97    hwreg::RegisterIo cntl6_mmio(regs + PCIE_PLL_CNTL6);
98
99    auto cntl0 = MesonPLLControl0::Get().ReadFrom(&cntl0_mmio);
100
101    cntl0.set_enable(1);
102    cntl0.set_reset(0);
103    cntl0.WriteTo(&cntl0_mmio);
104
105    cntl0.set_m(200);
106    cntl0.set_n(3);
107    cntl0.set_od(1);
108    cntl0.WriteTo(&cntl0_mmio);
109
110    auto cntl1 = MesonPLLControl1::Get().ReadFrom(&cntl1_mmio);
111    cntl1.set_div_frac(0);
112    cntl1.WriteTo(&cntl1_mmio);
113
114    auto cntl6 = MesonPLLControl6::Get().ReadFrom(&cntl6_mmio);
115    cntl6.set_od2(3);
116    cntl6.set_cml_input_sel1(1);
117    cntl6.set_cml_input_sel0(1);
118    cntl6.set_cml_input_en(1);
119    cntl6.WriteTo(&cntl6_mmio);
120
121    // Assert the Reset pin on the PLL
122    cntl0.set_reset(1);
123    cntl0.WriteTo(&cntl0_mmio);
124
125    // Wait for the reset to take effect
126    zx_nanosleep(zx_deadline_after(ZX_MSEC(10)));
127
128    // De-assert the reset pin
129    cntl0.set_reset(0);
130    cntl0.WriteTo(&cntl0_mmio);
131
132    // Wait for the PLL parameters to lock.
133    const uint64_t kTimeout = 24000000;
134    for (uint64_t attempts = 0; attempts < kTimeout; ++attempts) {
135        auto cntl0 = MesonPLLControl0::Get().ReadFrom(&cntl0_mmio);
136
137        // PLL has successfully locked?
138        if (cntl0.lock()) return ZX_OK;
139    }
140
141    return ZX_ERR_TIMED_OUT;
142}