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 * 4)
19 #define PCIE_PLL_CNTL1 (0x37 * 4)
20 #define PCIE_PLL_CNTL2 (0x38 * 4)
21 #define PCIE_PLL_CNTL3 (0x39 * 4)
22 #define PCIE_PLL_CNTL4 (0x3A * 4)
23 #define PCIE_PLL_CNTL5 (0x3B * 4)
24 #define PCIE_PLL_CNTL6 (0x3C * 4)
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
37 class 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
Get()46 static auto Get() {return hwreg::RegisterAddr<MesonPLLControl0>(PCIE_PLL_CNTL0); }
47 };
48
49 class 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
Get()65 static auto Get() {return hwreg::RegisterAddr<MesonPLLControl1>(PCIE_PLL_CNTL1); }
66 };
67
68 class 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
Get()75 static auto Get() { return hwreg::RegisterAddr<MesonPLLControl6>(PCIE_PLL_CNTL6); }
76 };
77
78
PllSetRate(ddk::MmioBuffer * mmio)79 zx_status_t PllSetRate(ddk::MmioBuffer* mmio) {
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 mmio->Write32(AXG_MIPI_CNTL0, 0);
85 mmio->Write32(AXG_PCIE_PLL_CNTL0, PCIE_PLL_CNTL0);
86 mmio->Write32(AXG_PCIE_PLL_CNTL1, PCIE_PLL_CNTL1);
87 mmio->Write32(AXG_PCIE_PLL_CNTL2, PCIE_PLL_CNTL2);
88 mmio->Write32(AXG_PCIE_PLL_CNTL3, PCIE_PLL_CNTL3);
89 mmio->Write32(AXG_PCIE_PLL_CNTL4, PCIE_PLL_CNTL4);
90 mmio->Write32(AXG_PCIE_PLL_CNTL5, PCIE_PLL_CNTL5);
91 mmio->Write32(AXG_PCIE_PLL_CNTL6, PCIE_PLL_CNTL6);
92
93 auto cntl0 = MesonPLLControl0::Get().ReadFrom(mmio);
94
95 cntl0.set_enable(1);
96 cntl0.set_reset(0);
97 cntl0.WriteTo(mmio);
98
99 cntl0.set_m(200);
100 cntl0.set_n(3);
101 cntl0.set_od(1);
102 cntl0.WriteTo(mmio);
103
104 auto cntl1 = MesonPLLControl1::Get().ReadFrom(mmio);
105 cntl1.set_div_frac(0);
106 cntl1.WriteTo(mmio);
107
108 auto cntl6 = MesonPLLControl6::Get().ReadFrom(mmio);
109 cntl6.set_od2(3);
110 cntl6.set_cml_input_sel1(1);
111 cntl6.set_cml_input_sel0(1);
112 cntl6.set_cml_input_en(1);
113 cntl6.WriteTo(mmio);
114
115 // Assert the Reset pin on the PLL
116 cntl0.set_reset(1);
117 cntl0.WriteTo(mmio);
118
119 // Wait for the reset to take effect
120 zx_nanosleep(zx_deadline_after(ZX_MSEC(10)));
121
122 // De-assert the reset pin
123 cntl0.set_reset(0);
124 cntl0.WriteTo(mmio);
125
126 // Wait for the PLL parameters to lock.
127 const uint64_t kTimeout = 24000000;
128 for (uint64_t attempts = 0; attempts < kTimeout; ++attempts) {
129 auto cntl0 = MesonPLLControl0::Get().ReadFrom(mmio);
130
131 // PLL has successfully locked?
132 if (cntl0.lock()) return ZX_OK;
133 }
134
135 return ZX_ERR_TIMED_OUT;
136 }
137