blob: 2ffaddc8f6a4df272e63f7b9092f6691ccc93378 [file] [log] [blame]
// Copyright 2022 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 <algorithm>
#include <iterator>
#include <fbl/alloc_checker.h>
#include <soc/aml-a5/a5-hiu.h>
#include <soc/aml-a5/a5-hw.h>
namespace amlogic_clock::a5 {
constexpr uint32_t kA5HifiPllSize = 8 * sizeof(uint32_t);
constexpr uint32_t kA5MpllSize = 2 * sizeof(uint32_t);
#define HHI_PLL_RATE(_rate, _n, _m, _frac, _od) \
{ .rate = _rate, .n = _n, .m = _m, .frac = _frac, .od = _od, }
static constexpr hhi_pll_rate_t a5_sys_pll_support_rates[] = {
HHI_PLL_RATE(1'200'000'000, 0, 0, 0, 0), // padding, unused
};
static constexpr hhi_pll_rate_t a5_hifipll_support_rates[] = {
HHI_PLL_RATE(768'000'000, 1, 128, 27307, 2), // 768'000'000 HZ
};
#undef HHI_PLL_RATE
#define HHI_MPLL_RATE(_rate, _n_in, _sdm_in) \
{ .rate = _rate, .n = _n_in, .m = 0, .frac = _sdm_in, .od = 0, }
static constexpr hhi_pll_rate_t a5_mpll_support_rates[] = {
HHI_MPLL_RATE(491'520'000, 4, 1131),
};
#undef HHI_MPLL_RATE
static constexpr struct reg_sequence a5_hifipll_default[] = {
{.reg_offset = 0x0 << 2, .def = 0x30020480, .delay_us = 0},
{.reg_offset = 0x1 << 2, .def = 0x00006aab, .delay_us = 0},
{.reg_offset = 0x2 << 2, .def = 0x00000000, .delay_us = 0},
{.reg_offset = 0x3 << 2, .def = 0x6a285c00, .delay_us = 0},
{.reg_offset = 0x4 << 2, .def = 0x65771290, .delay_us = 0},
{.reg_offset = 0x5 << 2, .def = 0x39272000, .delay_us = 0},
{.reg_offset = 0x6 << 2, .def = 0x56540000, .delay_us = 0}, // 768'000'000 HZ
};
static constexpr meson_clk_pll_data_t a5_hifipll_rates = {
.init_regs = a5_hifipll_default,
.init_count = std::size(a5_hifipll_default),
};
static constexpr struct reg_sequence a5_mpll_default[] = {
{.reg_offset = 0x0 << 2, .def = 0x4040046B, .delay_us = 0}, // 491'520'000 HZ
{.reg_offset = 0x1 << 2, .def = 0x40000033, .delay_us = 0},
};
static constexpr meson_clk_pll_data_t a5_mpll_rates = {
.init_regs = a5_mpll_default,
.init_count = std::size(a5_mpll_default),
};
std::unique_ptr<AmlMesonPllDevice> CreatePllDevice(fdf::MmioBuffer* mmio, const uint32_t pll_num) {
switch (pll_num) {
case SYS_PLL:
return AmlA5SysPllDevice::Create(
cpp20::span(a5_sys_pll_support_rates, std::size(a5_sys_pll_support_rates)));
case HIFI_PLL:
return AmlA5HifiPllDevice::Create(
mmio->View(A5_ANACTRL_HIFIPLL_CTRL0, kA5HifiPllSize), &a5_hifipll_rates,
cpp20::span(a5_hifipll_support_rates, std::size(a5_hifipll_support_rates)));
case MPLL0:
return AmlA5MpllDevice::Create(
mmio->View(A5_ANACTRL_MPLL_CTRL1, kA5MpllSize), &a5_mpll_rates,
cpp20::span(a5_mpll_support_rates, std::size(a5_mpll_support_rates)));
case MPLL1:
return AmlA5MpllDevice::Create(
mmio->View(A5_ANACTRL_MPLL_CTRL3, kA5MpllSize), &a5_mpll_rates,
cpp20::span(a5_mpll_support_rates, std::size(a5_mpll_support_rates)));
case MPLL2:
return AmlA5MpllDevice::Create(
mmio->View(A5_ANACTRL_MPLL_CTRL5, kA5MpllSize), &a5_mpll_rates,
cpp20::span(a5_mpll_support_rates, std::size(a5_mpll_support_rates)));
case MPLL3:
return AmlA5MpllDevice::Create(
mmio->View(A5_ANACTRL_MPLL_CTRL7, kA5MpllSize), &a5_mpll_rates,
cpp20::span(a5_mpll_support_rates, std::size(a5_mpll_support_rates)));
default:
ZX_ASSERT_MSG(0, "Not supported");
break;
}
ZX_ASSERT(0);
return nullptr;
}
std::unique_ptr<AmlMesonPllDevice> AmlA5SysPllDevice::Create(
const cpp20::span<const hhi_pll_rate_t> rates_table) {
fbl::AllocChecker ac;
auto dev = std::unique_ptr<AmlA5SysPllDevice>(new (&ac) AmlA5SysPllDevice(rates_table));
if (!ac.check()) {
return nullptr;
}
ZX_ASSERT(dev->Initialize() == ZX_OK);
return dev;
}
std::unique_ptr<AmlMesonPllDevice> AmlA5HifiPllDevice::Create(
fdf::MmioView view, const meson_clk_pll_data_t* data,
const cpp20::span<const hhi_pll_rate_t> rates_table) {
fbl::AllocChecker ac;
auto dev = std::unique_ptr<AmlA5HifiPllDevice>(
new (&ac) AmlA5HifiPllDevice(std::move(view), data, rates_table));
if (!ac.check()) {
return nullptr;
}
ZX_ASSERT(dev->Initialize() == ZX_OK);
return dev;
}
std::unique_ptr<AmlMesonPllDevice> AmlA5MpllDevice::Create(
fdf::MmioView view, const meson_clk_pll_data_t* data,
const cpp20::span<const hhi_pll_rate_t> rates_table) {
fbl::AllocChecker ac;
auto dev = std::unique_ptr<AmlA5MpllDevice>(
new (&ac) AmlA5MpllDevice(std::move(view), data, rates_table));
if (!ac.check()) {
return nullptr;
}
ZX_ASSERT(dev->Initialize() == ZX_OK);
return dev;
}
} // namespace amlogic_clock::a5