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#include <ddk/debug.h> 6#include <hw/reg.h> 7 8#include <zircon/assert.h> 9#include <zircon/types.h> 10 11#include <soc/aml-s905d2/s905d2-hiu.h> 12#include <soc/aml-s905d2/s905d2-hw.h> 13 14zx_status_t s905d2_hiu_init(zx_handle_t bti, aml_hiu_dev_t* device) { 15 16 zx_handle_t resource = get_root_resource(); 17 zx_status_t status; 18 19 status = io_buffer_init_physical(&device->regs_iobuff, bti, S905D2_HIU_BASE, 20 S905D2_HIU_LENGTH, resource, 21 ZX_CACHE_POLICY_UNCACHED_DEVICE); 22 if (status != ZX_OK) { 23 zxlogf(ERROR, "%s: io_buffer_init_physical failed %d\n", __func__, status); 24 return status; 25 } 26 27 device->virt_regs = (zx_vaddr_t)(io_buffer_virt(&device->regs_iobuff)); 28 29 return ZX_OK; 30} 31 32static zx_status_t s905d2_pll_init_regs(aml_pll_dev_t* pll_dev) { 33 aml_hiu_dev_t* device = pll_dev->hiu; 34 35 if (pll_dev->pll_num == HIFI_PLL) { 36 //write config values 37 hiu_clk_set_reg(device, HHI_HIFI_PLL_CNTL1, G12A_HIFI_PLL_CNTL1); 38 hiu_clk_set_reg(device, HHI_HIFI_PLL_CNTL2, G12A_HIFI_PLL_CNTL2); 39 hiu_clk_set_reg(device, HHI_HIFI_PLL_CNTL3, G12A_HIFI_PLL_CNTL3); 40 hiu_clk_set_reg(device, HHI_HIFI_PLL_CNTL4, G12A_HIFI_PLL_CNTL4); 41 hiu_clk_set_reg(device, HHI_HIFI_PLL_CNTL5, G12A_HIFI_PLL_CNTL5); 42 hiu_clk_set_reg(device, HHI_HIFI_PLL_CNTL6, G12A_HIFI_PLL_CNTL6); 43 zx_nanosleep(zx_deadline_after(ZX_USEC(10))); 44 return ZX_OK; 45 } else if (pll_dev->pll_num == SYS_PLL) { 46 //write config values 47 hiu_clk_set_reg(device, HHI_SYS_PLL_CNTL1, G12A_SYS_PLL_CNTL1); 48 hiu_clk_set_reg(device, HHI_SYS_PLL_CNTL2, G12A_SYS_PLL_CNTL2); 49 hiu_clk_set_reg(device, HHI_SYS_PLL_CNTL3, G12A_SYS_PLL_CNTL3); 50 hiu_clk_set_reg(device, HHI_SYS_PLL_CNTL4, G12A_SYS_PLL_CNTL4); 51 hiu_clk_set_reg(device, HHI_SYS_PLL_CNTL5, G12A_SYS_PLL_CNTL5); 52 hiu_clk_set_reg(device, HHI_SYS_PLL_CNTL6, G12A_SYS_PLL_CNTL6); 53 zx_nanosleep(zx_deadline_after(ZX_USEC(10))); 54 return ZX_OK; 55 } else if (pll_dev->pll_num == GP0_PLL) { 56 //write config values 57 hiu_clk_set_reg(device, HHI_GP0_PLL_CNTL1, G12A_GP0_PLL_CNTL1); 58 hiu_clk_set_reg(device, HHI_GP0_PLL_CNTL2, G12A_GP0_PLL_CNTL2); 59 hiu_clk_set_reg(device, HHI_GP0_PLL_CNTL3, G12A_GP0_PLL_CNTL3); 60 hiu_clk_set_reg(device, HHI_GP0_PLL_CNTL4, G12A_GP0_PLL_CNTL4); 61 hiu_clk_set_reg(device, HHI_GP0_PLL_CNTL5, G12A_GP0_PLL_CNTL5); 62 hiu_clk_set_reg(device, HHI_GP0_PLL_CNTL6, G12A_GP0_PLL_CNTL6); 63 zx_nanosleep(zx_deadline_after(ZX_USEC(10))); 64 return ZX_OK; 65 } 66 return ZX_OK; 67} 68 69zx_status_t s905d2_pll_init(aml_hiu_dev_t* device, aml_pll_dev_t* pll_dev, hhi_plls_t pll_num) { 70 ZX_DEBUG_ASSERT(device); 71 ZX_DEBUG_ASSERT(pll_dev); 72 73 pll_dev->hiu = device; 74 75 pll_dev->rate_table = s905d2_pll_get_rate_table(pll_num); 76 pll_dev->rate_idx = 0; 77 pll_dev->frequency = 0; 78 pll_dev->pll_num = pll_num; 79 pll_dev->rate_count = s905d2_get_rate_table_count(pll_num); 80 81 ZX_DEBUG_ASSERT(pll_dev->rate_table); 82 ZX_DEBUG_ASSERT(pll_dev->rate_count); 83 84 //Disable and reset the pll 85 s905d2_pll_disable(pll_dev); 86 //Write configuration registers 87 return s905d2_pll_init_regs(pll_dev); 88} 89 90bool s905d2_pll_disable(aml_pll_dev_t* pll_dev) { 91 uint32_t offs = hiu_get_pll_offs(pll_dev); 92 uint32_t ctl0 = hiu_clk_get_reg(pll_dev->hiu, offs); 93 94 bool retval = ctl0 & HHI_PLL_CNTL0_EN; 95 96 ctl0 = (ctl0 & ~HHI_PLL_CNTL0_EN) | HHI_PLL_CNTL0_RESET; 97 hiu_clk_set_reg(pll_dev->hiu, offs, ctl0); 98 99 return retval; 100} 101 102zx_status_t s905d2_pll_ena(aml_pll_dev_t* pll_dev) { 103 ZX_DEBUG_ASSERT(pll_dev); 104 105 uint32_t offs = hiu_get_pll_offs(pll_dev); 106 uint32_t reg_val = hiu_clk_get_reg(pll_dev->hiu, offs); 107 108 // Set Enable bit 109 reg_val |= HHI_PLL_CNTL0_EN; 110 hiu_clk_set_reg(pll_dev->hiu, offs, reg_val); 111 zx_nanosleep(zx_deadline_after(ZX_USEC(50))); 112 113 // Clear Reset bit 114 reg_val &= ~HHI_PLL_CNTL0_RESET; 115 hiu_clk_set_reg(pll_dev->hiu, offs, reg_val); 116 117 uint32_t wait_count = 100; 118 while (wait_count) { 119 if (hiu_clk_get_reg(pll_dev->hiu, offs) & HHI_PLL_LOCK) { 120 return ZX_OK; 121 } 122 zx_nanosleep(zx_deadline_after(ZX_USEC(10))); 123 wait_count--; 124 } 125 126 return ZX_ERR_TIMED_OUT; 127} 128 129/* Notes: 130 -VCO needs to be between 3-6GHz per the datasheet. It appears that if you 131 provide values which would result in a VCO outside of this range, it will 132 still oscillate, but at unknown (but likely close to target) frequency. 133*/ 134zx_status_t s905d2_pll_set_rate(aml_pll_dev_t* pll_dev, uint64_t freq) { 135 ZX_DEBUG_ASSERT(pll_dev); 136 137 const hhi_pll_rate_t* pll_rate; 138 139 zx_status_t status = s905d2_pll_fetch_rate(pll_dev, freq, &pll_rate); 140 if (status != ZX_OK) { 141 return status; 142 } 143 //Disable/reset the pll, save previous state 144 bool ena = s905d2_pll_disable(pll_dev); 145 146 //Initialize the registers to defaults (may not be retained after reset) 147 s905d2_pll_init_regs(pll_dev); 148 149 uint32_t offs = hiu_get_pll_offs(pll_dev); 150 uint32_t ctl0 = hiu_clk_get_reg(pll_dev->hiu, offs); 151 152 ctl0 &= ~HHI_PLL_CNTL0_M; 153 ctl0 |= pll_rate->m << HHI_PLL_CNTL0_M_SHIFT; 154 155 ctl0 &= ~HHI_PLL_CNTL0_N; 156 ctl0 |= pll_rate->n << HHI_PLL_CNTL0_N_SHIFT; 157 158 ctl0 &= ~HHI_PLL_CNTL0_OD; 159 ctl0 |= pll_rate->od << HHI_PLL_CNTL0_OD_SHIFT; 160 161 hiu_clk_set_reg(pll_dev->hiu, offs, ctl0); 162 163 hiu_clk_set_reg(pll_dev->hiu, offs + 4, pll_rate->frac); 164 165 if (ena) { 166 return s905d2_pll_ena(pll_dev); 167 } 168 169 return ZX_OK; 170} 171