blob: 30550392b5ec849337bce086353a3258ed24b6a6 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdint.h>
#include <stdlib.h>
#include <threads.h>
#include <unistd.h>
#include <zircon/assert.h>
#include <zircon/types.h>
#include <bits/limits.h>
#include <soc/aml-a113/a113-clocks.h>
#define DIV_ROUND_UP(n, d) ((n + d - 1) / d)
namespace {
void a113_clk_update_reg(fdf::MmioBuffer *dev, uint32_t offset, uint32_t pos, uint32_t bits,
uint32_t value) {
uint32_t reg = a113_clk_get_reg(dev, offset);
reg &= ~(((1 << bits) - 1) << pos);
reg |= (value & ((1 << bits) - 1)) << pos;
a113_clk_set_reg(dev, offset, reg);
}
} // namespace
zx_status_t a113_clk_set_mpll2(fdf::MmioBuffer *device, uint64_t rate, uint64_t *actual) {
/* Overall ratio is reference/(n + sdm/16384)
In this case the 2.0GHz fixed rate pll is the reference
*/
uint64_t n = A113_FIXED_PLL_RATE / rate; // calculate the integer ratio;
ZX_DEBUG_ASSERT(n < (1 << 9));
uint64_t sdm = DIV_ROUND_UP((A113_FIXED_PLL_RATE - n * rate) * SDM_FRACTIONALITY, rate);
ZX_DEBUG_ASSERT(sdm < (1 << 14));
a113_clk_update_reg(device, A113_HHI_MPLL_CNTL8, 0, 14, static_cast<uint32_t>(sdm));
a113_clk_update_reg(device, A113_HHI_MPLL_CNTL8, 16, 9, static_cast<uint32_t>(n));
// Enable sdm divider
a113_clk_update_reg(device, A113_HHI_MPLL_CNTL8, 15, 1, 1);
// Enable mpll2
a113_clk_update_reg(device, A113_HHI_MPLL_CNTL8, 14, 1, 1);
// Gate mpll2 through to rest of system
a113_clk_update_reg(device, A113_HHI_PLL_TOP_MISC, 2, 1, 1);
if (actual) {
*actual = (static_cast<uint64_t>(SDM_FRACTIONALITY) * A113_FIXED_PLL_RATE) /
((SDM_FRACTIONALITY * n) + sdm);
}
return ZX_OK;
}