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}