// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2015 Endless Mobile, Inc.
* Author: Carlo Caione <carlo@endlessm.com>
*
* Copyright (c) 2016 BayLibre, Inc.
* Michael Turquette <mturquette@baylibre.com>
*/
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/init.h>
#include <linux/mfd/syscon.h>
#include <linux/of_address.h>
#include <linux/reset-controller.h>
#include <linux/slab.h>
#include <linux/regmap.h>
#include "clk-regmap.h"
#include "meson-clkc-utils.h"
#include "clk-pll.h"
#include "clk-mpll.h"
#include <dt-bindings/clock/meson8b-clkc.h>
#include <dt-bindings/reset/amlogic,meson8b-clkc-reset.h>
/*
* Clock controller register offsets
*
* Register offsets from the HardKernel[0] data sheet must be multiplied
* by 4 before adding them to the base address to get the right value
*
* [0] https://dn.odroid.com/S805/Datasheet/S805_Datasheet%20V0.8%2020150126.pdf
*/
#define HHI_GP_PLL_CNTL 0x40
#define HHI_GP_PLL_CNTL2 0x44
#define HHI_GP_PLL_CNTL3 0x48
#define HHI_GP_PLL_CNTL4 0x4C
#define HHI_GP_PLL_CNTL5 0x50
#define HHI_VIID_CLK_DIV 0x128
#define HHI_VIID_CLK_CNTL 0x12c
#define HHI_GCLK_MPEG0 0x140
#define HHI_GCLK_MPEG1 0x144
#define HHI_GCLK_MPEG2 0x148
#define HHI_GCLK_OTHER 0x150
#define HHI_GCLK_AO 0x154
#define HHI_SYS_CPU_CLK_CNTL1 0x15c
#define HHI_VID_CLK_DIV 0x164
#define HHI_MPEG_CLK_CNTL 0x174
#define HHI_AUD_CLK_CNTL 0x178
#define HHI_VID_CLK_CNTL 0x17c
#define HHI_AUD_CLK_CNTL2 0x190
#define HHI_VID_CLK_CNTL2 0x194
#define HHI_VID_DIVIDER_CNTL 0x198
#define HHI_SYS_CPU_CLK_CNTL0 0x19c
#define HHI_MALI_CLK_CNTL 0x1b0
#define HHI_VPU_CLK_CNTL 0x1bc
#define HHI_HDMI_CLK_CNTL 0x1cc
#define HHI_VDEC_CLK_CNTL 0x1e0
#define HHI_VDEC2_CLK_CNTL 0x1e4
#define HHI_VDEC3_CLK_CNTL 0x1e8
#define HHI_NAND_CLK_CNTL 0x25c
#define HHI_MPLL_CNTL 0x280
#define HHI_SYS_PLL_CNTL 0x300
#define HHI_VID_PLL_CNTL 0x320
#define HHI_VID_PLL_CNTL2 0x324
#define HHI_VID_PLL_CNTL3 0x328
#define HHI_VID_PLL_CNTL4 0x32c
#define HHI_VID_PLL_CNTL5 0x330
#define HHI_VID_PLL_CNTL6 0x334
#define HHI_VID2_PLL_CNTL 0x380
#define HHI_VID2_PLL_CNTL2 0x384
#define HHI_VID2_PLL_CNTL3 0x388
#define HHI_VID2_PLL_CNTL4 0x38c
#define HHI_VID2_PLL_CNTL5 0x390
#define HHI_VID2_PLL_CNTL6 0x394
/*
* MPLL register offeset taken from the S905 datasheet. Vendor kernel source
* confirm these are the same for the S805.
*/
#define HHI_MPLL_CNTL 0x280
#define HHI_MPLL_CNTL2 0x284
#define HHI_MPLL_CNTL3 0x288
#define HHI_MPLL_CNTL4 0x28c
#define HHI_MPLL_CNTL5 0x290
#define HHI_MPLL_CNTL6 0x294
#define HHI_MPLL_CNTL7 0x298
#define HHI_MPLL_CNTL8 0x29c
#define HHI_MPLL_CNTL9 0x2a0
#define HHI_MPLL_CNTL10 0x2a4
struct meson8b_clk_reset {
struct reset_controller_dev reset;
struct regmap *regmap;
};
static const struct pll_params_table sys_pll_params_table[] = {
PLL_PARAMS(50, 1),
PLL_PARAMS(51, 1),
PLL_PARAMS(52, 1),
PLL_PARAMS(53, 1),
PLL_PARAMS(54, 1),
PLL_PARAMS(55, 1),
PLL_PARAMS(56, 1),
PLL_PARAMS(57, 1),
PLL_PARAMS(58, 1),
PLL_PARAMS(59, 1),
PLL_PARAMS(60, 1),
PLL_PARAMS(61, 1),
PLL_PARAMS(62, 1),
PLL_PARAMS(63, 1),
PLL_PARAMS(64, 1),
PLL_PARAMS(65, 1),
PLL_PARAMS(66, 1),
PLL_PARAMS(67, 1),
PLL_PARAMS(68, 1),
PLL_PARAMS(84, 1),
{
/* sentinel */ },
};
static struct clk_regmap meson8b_fixed_pll_dco = {
.data = &(
struct meson_clk_pll_data){
.en = {
.reg_off = HHI_MPLL_CNTL,
.shift = 30,
.width = 1,
},
.m = {
.reg_off = HHI_MPLL_CNTL,
.shift = 0,
.width = 9,
},
.n = {
.reg_off = HHI_MPLL_CNTL,
.shift = 9,
.width = 5,
},
.frac = {
.reg_off = HHI_MPLL_CNTL2,
.shift = 0,
.width = 12,
},
.l = {
.reg_off = HHI_MPLL_CNTL,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_MPLL_CNTL,
.shift = 29,
.width = 1,
},
},
.hw.init = &(
struct clk_init_data){
.name =
"fixed_pll_dco",
.ops = &meson_clk_pll_ro_ops,
.parent_data = &(
const struct clk_parent_data) {
.fw_name =
"xtal",
.name =
"xtal",
.index = -1,
},
.num_parents = 1,
},
};
static struct clk_regmap meson8b_fixed_pll = {
.data = &(
struct clk_regmap_div_data){
.offset = HHI_MPLL_CNTL,
.shift = 16,
.width = 2,
.flags = CLK_DIVIDER_POWER_OF_TWO,
},
.hw.init = &(
struct clk_init_data){
.name =
"fixed_pll",
.ops = &clk_regmap_divider_ro_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_fixed_pll_dco.hw
},
.num_parents = 1,
/*
* This clock won't ever change at runtime so
* CLK_SET_RATE_PARENT is not required
*/
},
};
static struct clk_fixed_factor hdmi_pll_dco_in = {
.mult = 2,
.div = 1,
.hw.init = &(
struct clk_init_data){
.name =
"hdmi_pll_dco_in",
.ops = &clk_fixed_factor_ops,
.parent_data = &(
const struct clk_parent_data) {
.fw_name =
"xtal",
.index = -1,
},
.num_parents = 1,
},
};
/*
* Taken from the vendor driver for the 2970/2975MHz (both only differ in the
* FRAC part in HHI_VID_PLL_CNTL2) where these values are identical for Meson8,
* Meson8b and Meson8m2. This doubles the input (or output - it's not clear
* which one but the result is the same) clock. The vendor driver additionally
* has the following comment about: "optimise HPLL VCO 2.97GHz performance".
*/
static const struct reg_sequence meson8b_hdmi_pll_init_regs[] = {
{ .reg = HHI_VID_PLL_CNTL2, .def = 0x69c84000 },
{ .reg = HHI_VID_PLL_CNTL3, .def = 0x8a46c023 },
{ .reg = HHI_VID_PLL_CNTL4, .def = 0x4123b100 },
{ .reg = HHI_VID_PLL_CNTL5, .def = 0x00012385 },
{ .reg = HHI_VID2_PLL_CNTL2, .def = 0x0430a800 },
};
static const struct pll_params_table hdmi_pll_params_table[] = {
PLL_PARAMS(40, 1),
PLL_PARAMS(42, 1),
PLL_PARAMS(44, 1),
PLL_PARAMS(45, 1),
PLL_PARAMS(49, 1),
PLL_PARAMS(52, 1),
PLL_PARAMS(54, 1),
PLL_PARAMS(56, 1),
PLL_PARAMS(59, 1),
PLL_PARAMS(60, 1),
PLL_PARAMS(61, 1),
PLL_PARAMS(62, 1),
PLL_PARAMS(64, 1),
PLL_PARAMS(66, 1),
PLL_PARAMS(68, 1),
PLL_PARAMS(71, 1),
PLL_PARAMS(82, 1),
{
/* sentinel */ }
};
static struct clk_regmap meson8b_hdmi_pll_dco = {
.data = &(
struct meson_clk_pll_data){
.en = {
.reg_off = HHI_VID_PLL_CNTL,
.shift = 30,
.width = 1,
},
.m = {
.reg_off = HHI_VID_PLL_CNTL,
.shift = 0,
.width = 9,
},
.n = {
.reg_off = HHI_VID_PLL_CNTL,
.shift = 10,
.width = 5,
},
.frac = {
.reg_off = HHI_VID_PLL_CNTL2,
.shift = 0,
.width = 12,
},
.l = {
.reg_off = HHI_VID_PLL_CNTL,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_VID_PLL_CNTL,
.shift = 29,
.width = 1,
},
.table = hdmi_pll_params_table,
.init_regs = meson8b_hdmi_pll_init_regs,
.init_count = ARRAY_SIZE(meson8b_hdmi_pll_init_regs),
},
.hw.init = &(
struct clk_init_data){
/* sometimes also called "HPLL" or "HPLL PLL" */
.name =
"hdmi_pll_dco",
.ops = &meson_clk_pll_ops,
.parent_hws = (
const struct clk_hw *[]) {
&hdmi_pll_dco_in.hw
},
.num_parents = 1,
},
};
static struct clk_regmap meson8b_hdmi_pll_lvds_out = {
.data = &(
struct clk_regmap_div_data){
.offset = HHI_VID_PLL_CNTL,
.shift = 16,
.width = 2,
.flags = CLK_DIVIDER_POWER_OF_TWO,
},
.hw.init = &(
struct clk_init_data){
.name =
"hdmi_pll_lvds_out",
.ops = &clk_regmap_divider_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_hdmi_pll_dco.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_hdmi_pll_hdmi_out = {
.data = &(
struct clk_regmap_div_data){
.offset = HHI_VID_PLL_CNTL,
.shift = 18,
.width = 2,
.flags = CLK_DIVIDER_POWER_OF_TWO,
},
.hw.init = &(
struct clk_init_data){
.name =
"hdmi_pll_hdmi_out",
.ops = &clk_regmap_divider_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_hdmi_pll_dco.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_sys_pll_dco = {
.data = &(
struct meson_clk_pll_data){
.en = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 30,
.width = 1,
},
.m = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 0,
.width = 9,
},
.n = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 9,
.width = 5,
},
.l = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 29,
.width = 1,
},
.table = sys_pll_params_table,
},
.hw.init = &(
struct clk_init_data){
.name =
"sys_pll_dco",
.ops = &meson_clk_pll_ops,
.parent_data = &(
const struct clk_parent_data) {
.fw_name =
"xtal",
.name =
"xtal",
.index = -1,
},
.num_parents = 1,
},
};
static struct clk_regmap meson8b_sys_pll = {
.data = &(
struct clk_regmap_div_data){
.offset = HHI_SYS_PLL_CNTL,
.shift = 16,
.width = 2,
.flags = CLK_DIVIDER_POWER_OF_TWO,
},
.hw.init = &(
struct clk_init_data){
.name =
"sys_pll",
.ops = &clk_regmap_divider_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_sys_pll_dco.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_fixed_factor meson8b_fclk_div2_div = {
.mult = 1,
.div = 2,
.hw.init = &(
struct clk_init_data){
.name =
"fclk_div2_div",
.ops = &clk_fixed_factor_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_fixed_pll.hw
},
.num_parents = 1,
},
};
static struct clk_regmap meson8b_fclk_div2 = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL6,
.bit_idx = 27,
},
.hw.init = &(
struct clk_init_data){
.name =
"fclk_div2",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_fclk_div2_div.hw
},
.num_parents = 1,
},
};
static struct clk_fixed_factor meson8b_fclk_div3_div = {
.mult = 1,
.div = 3,
.hw.init = &(
struct clk_init_data){
.name =
"fclk_div3_div",
.ops = &clk_fixed_factor_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_fixed_pll.hw
},
.num_parents = 1,
},
};
static struct clk_regmap meson8b_fclk_div3 = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL6,
.bit_idx = 28,
},
.hw.init = &(
struct clk_init_data){
.name =
"fclk_div3",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_fclk_div3_div.hw
},
.num_parents = 1,
},
};
static struct clk_fixed_factor meson8b_fclk_div4_div = {
.mult = 1,
.div = 4,
.hw.init = &(
struct clk_init_data){
.name =
"fclk_div4_div",
.ops = &clk_fixed_factor_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_fixed_pll.hw
},
.num_parents = 1,
},
};
static struct clk_regmap meson8b_fclk_div4 = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL6,
.bit_idx = 29,
},
.hw.init = &(
struct clk_init_data){
.name =
"fclk_div4",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_fclk_div4_div.hw
},
.num_parents = 1,
},
};
static struct clk_fixed_factor meson8b_fclk_div5_div = {
.mult = 1,
.div = 5,
.hw.init = &(
struct clk_init_data){
.name =
"fclk_div5_div",
.ops = &clk_fixed_factor_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_fixed_pll.hw
},
.num_parents = 1,
},
};
static struct clk_regmap meson8b_fclk_div5 = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL6,
.bit_idx = 30,
},
.hw.init = &(
struct clk_init_data){
.name =
"fclk_div5",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_fclk_div5_div.hw
},
.num_parents = 1,
},
};
static struct clk_fixed_factor meson8b_fclk_div7_div = {
.mult = 1,
.div = 7,
.hw.init = &(
struct clk_init_data){
.name =
"fclk_div7_div",
.ops = &clk_fixed_factor_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_fixed_pll.hw
},
.num_parents = 1,
},
};
static struct clk_regmap meson8b_fclk_div7 = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL6,
.bit_idx = 31,
},
.hw.init = &(
struct clk_init_data){
.name =
"fclk_div7",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_fclk_div7_div.hw
},
.num_parents = 1,
},
};
static struct clk_regmap meson8b_mpll_prediv = {
.data = &(
struct clk_regmap_div_data){
.offset = HHI_MPLL_CNTL5,
.shift = 12,
.width = 1,
},
.hw.init = &(
struct clk_init_data){
.name =
"mpll_prediv",
.ops = &clk_regmap_divider_ro_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_fixed_pll.hw
},
.num_parents = 1,
},
};
static struct clk_regmap meson8b_mpll0_div = {
.data = &(
struct meson_clk_mpll_data){
.sdm = {
.reg_off = HHI_MPLL_CNTL7,
.shift = 0,
.width = 14,
},
.sdm_en = {
.reg_off = HHI_MPLL_CNTL7,
.shift = 15,
.width = 1,
},
.n2 = {
.reg_off = HHI_MPLL_CNTL7,
.shift = 16,
.width = 9,
},
.ssen = {
.reg_off = HHI_MPLL_CNTL,
.shift = 25,
.width = 1,
},
},
.hw.init = &(
struct clk_init_data){
.name =
"mpll0_div",
.ops = &meson_clk_mpll_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_mpll_prediv.hw
},
.num_parents = 1,
},
};
static struct clk_regmap meson8b_mpll0 = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL7,
.bit_idx = 14,
},
.hw.init = &(
struct clk_init_data){
.name =
"mpll0",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_mpll0_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_mpll1_div = {
.data = &(
struct meson_clk_mpll_data){
.sdm = {
.reg_off = HHI_MPLL_CNTL8,
.shift = 0,
.width = 14,
},
.sdm_en = {
.reg_off = HHI_MPLL_CNTL8,
.shift = 15,
.width = 1,
},
.n2 = {
.reg_off = HHI_MPLL_CNTL8,
.shift = 16,
.width = 9,
},
},
.hw.init = &(
struct clk_init_data){
.name =
"mpll1_div",
.ops = &meson_clk_mpll_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_mpll_prediv.hw
},
.num_parents = 1,
},
};
static struct clk_regmap meson8b_mpll1 = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL8,
.bit_idx = 14,
},
.hw.init = &(
struct clk_init_data){
.name =
"mpll1",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_mpll1_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_mpll2_div = {
.data = &(
struct meson_clk_mpll_data){
.sdm = {
.reg_off = HHI_MPLL_CNTL9,
.shift = 0,
.width = 14,
},
.sdm_en = {
.reg_off = HHI_MPLL_CNTL9,
.shift = 15,
.width = 1,
},
.n2 = {
.reg_off = HHI_MPLL_CNTL9,
.shift = 16,
.width = 9,
},
},
.hw.init = &(
struct clk_init_data){
.name =
"mpll2_div",
.ops = &meson_clk_mpll_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_mpll_prediv.hw
},
.num_parents = 1,
},
};
static struct clk_regmap meson8b_mpll2 = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_MPLL_CNTL9,
.bit_idx = 14,
},
.hw.init = &(
struct clk_init_data){
.name =
"mpll2",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_mpll2_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static u32 mux_table_clk81[] = { 6, 5, 7 };
static struct clk_regmap meson8b_mpeg_clk_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_MPEG_CLK_CNTL,
.mask = 0x7,
.shift = 12,
.table = mux_table_clk81,
},
.hw.init = &(
struct clk_init_data){
.name =
"mpeg_clk_sel",
.ops = &clk_regmap_mux_ro_ops,
/*
* FIXME bits 14:12 selects from 8 possible parents:
* xtal, 1'b0 (wtf), fclk_div7, mpll_clkout1, mpll_clkout2,
* fclk_div4, fclk_div3, fclk_div5
*/
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_fclk_div3.hw,
&meson8b_fclk_div4.hw,
&meson8b_fclk_div5.hw,
},
.num_parents = 3,
},
};
static struct clk_regmap meson8b_mpeg_clk_div = {
.data = &(
struct clk_regmap_div_data){
.offset = HHI_MPEG_CLK_CNTL,
.shift = 0,
.width = 7,
},
.hw.init = &(
struct clk_init_data){
.name =
"mpeg_clk_div",
.ops = &clk_regmap_divider_ro_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_mpeg_clk_sel.hw
},
.num_parents = 1,
},
};
static struct clk_regmap meson8b_clk81 = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_MPEG_CLK_CNTL,
.bit_idx = 7,
},
.hw.init = &(
struct clk_init_data){
.name =
"clk81",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_mpeg_clk_div.hw
},
.num_parents = 1,
.flags = CLK_IS_CRITICAL,
},
};
static struct clk_regmap meson8b_cpu_in_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_SYS_CPU_CLK_CNTL0,
.mask = 0x1,
.shift = 0,
},
.hw.init = &(
struct clk_init_data){
.name =
"cpu_in_sel",
.ops = &clk_regmap_mux_ops,
.parent_data = (
const struct clk_parent_data[]) {
{ .fw_name =
"xtal", .name =
"xtal", .index = -1, },
{ .hw = &meson8b_sys_pll.hw, },
},
.num_parents = 2,
.flags = (CLK_SET_RATE_PARENT |
CLK_SET_RATE_NO_REPARENT),
},
};
static struct clk_fixed_factor meson8b_cpu_in_div2 = {
.mult = 1,
.div = 2,
.hw.init = &(
struct clk_init_data){
.name =
"cpu_in_div2",
.ops = &clk_fixed_factor_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_cpu_in_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_fixed_factor meson8b_cpu_in_div3 = {
.mult = 1,
.div = 3,
.hw.init = &(
struct clk_init_data){
.name =
"cpu_in_div3",
.ops = &clk_fixed_factor_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_cpu_in_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static const struct clk_div_table cpu_scale_table[] = {
{ .val = 1, .div = 4 },
{ .val = 2, .div = 6 },
{ .val = 3, .div = 8 },
{ .val = 4, .div = 10 },
{ .val = 5, .div = 12 },
{ .val = 6, .div = 14 },
{ .val = 7, .div = 16 },
{ .val = 8, .div = 18 },
{
/* sentinel */ },
};
static struct clk_regmap meson8b_cpu_scale_div = {
.data = &(
struct clk_regmap_div_data){
.offset = HHI_SYS_CPU_CLK_CNTL1,
.shift = 20,
.width = 10,
.table = cpu_scale_table,
.flags = CLK_DIVIDER_ALLOW_ZERO,
},
.hw.init = &(
struct clk_init_data){
.name =
"cpu_scale_div",
.ops = &clk_regmap_divider_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_cpu_in_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static u32 mux_table_cpu_scale_out_sel[] = { 0, 1, 3 };
static struct clk_regmap meson8b_cpu_scale_out_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_SYS_CPU_CLK_CNTL0,
.mask = 0x3,
.shift = 2,
.table = mux_table_cpu_scale_out_sel,
},
.hw.init = &(
struct clk_init_data){
.name =
"cpu_scale_out_sel",
.ops = &clk_regmap_mux_ops,
/*
* NOTE: We are skipping the parent with value 0x2 (which is
* meson8b_cpu_in_div3) because it results in a duty cycle of
* 33% which makes the system unstable and can result in a
* lockup of the whole system.
*/
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_cpu_in_sel.hw,
&meson8b_cpu_in_div2.hw,
&meson8b_cpu_scale_div.hw,
},
.num_parents = 3,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_cpu_clk = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_SYS_CPU_CLK_CNTL0,
.mask = 0x1,
.shift = 7,
},
.hw.init = &(
struct clk_init_data){
.name =
"cpu_clk",
.ops = &clk_regmap_mux_ops,
.parent_data = (
const struct clk_parent_data[]) {
{ .fw_name =
"xtal", .name =
"xtal", .index = -1, },
{ .hw = &meson8b_cpu_scale_out_sel.hw, },
},
.num_parents = 2,
.flags = (CLK_SET_RATE_PARENT |
CLK_SET_RATE_NO_REPARENT |
CLK_IS_CRITICAL),
},
};
static struct clk_regmap meson8b_nand_clk_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_NAND_CLK_CNTL,
.mask = 0x7,
.shift = 9,
.flags = CLK_MUX_ROUND_CLOSEST,
},
.hw.init = &(
struct clk_init_data){
.name =
"nand_clk_sel",
.ops = &clk_regmap_mux_ops,
/* FIXME all other parents are unknown: */
.parent_data = (
const struct clk_parent_data[]) {
{ .hw = &meson8b_fclk_div4.hw, },
{ .hw = &meson8b_fclk_div3.hw, },
{ .hw = &meson8b_fclk_div5.hw, },
{ .hw = &meson8b_fclk_div7.hw, },
{ .fw_name =
"xtal", .name =
"xtal", .index = -1, },
},
.num_parents = 5,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_nand_clk_div = {
.data = &(
struct clk_regmap_div_data){
.offset = HHI_NAND_CLK_CNTL,
.shift = 0,
.width = 7,
.flags = CLK_DIVIDER_ROUND_CLOSEST,
},
.hw.init = &(
struct clk_init_data){
.name =
"nand_clk_div",
.ops = &clk_regmap_divider_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_nand_clk_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_nand_clk_gate = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_NAND_CLK_CNTL,
.bit_idx = 8,
},
.hw.init = &(
struct clk_init_data){
.name =
"nand_clk_gate",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_nand_clk_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_fixed_factor meson8b_cpu_clk_div2 = {
.mult = 1,
.div = 2,
.hw.init = &(
struct clk_init_data){
.name =
"cpu_clk_div2",
.ops = &clk_fixed_factor_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_cpu_clk.hw
},
.num_parents = 1,
},
};
static struct clk_fixed_factor meson8b_cpu_clk_div3 = {
.mult = 1,
.div = 3,
.hw.init = &(
struct clk_init_data){
.name =
"cpu_clk_div3",
.ops = &clk_fixed_factor_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_cpu_clk.hw
},
.num_parents = 1,
},
};
static struct clk_fixed_factor meson8b_cpu_clk_div4 = {
.mult = 1,
.div = 4,
.hw.init = &(
struct clk_init_data){
.name =
"cpu_clk_div4",
.ops = &clk_fixed_factor_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_cpu_clk.hw
},
.num_parents = 1,
},
};
static struct clk_fixed_factor meson8b_cpu_clk_div5 = {
.mult = 1,
.div = 5,
.hw.init = &(
struct clk_init_data){
.name =
"cpu_clk_div5",
.ops = &clk_fixed_factor_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_cpu_clk.hw
},
.num_parents = 1,
},
};
static struct clk_fixed_factor meson8b_cpu_clk_div6 = {
.mult = 1,
.div = 6,
.hw.init = &(
struct clk_init_data){
.name =
"cpu_clk_div6",
.ops = &clk_fixed_factor_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_cpu_clk.hw
},
.num_parents = 1,
},
};
static struct clk_fixed_factor meson8b_cpu_clk_div7 = {
.mult = 1,
.div = 7,
.hw.init = &(
struct clk_init_data){
.name =
"cpu_clk_div7",
.ops = &clk_fixed_factor_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_cpu_clk.hw
},
.num_parents = 1,
},
};
static struct clk_fixed_factor meson8b_cpu_clk_div8 = {
.mult = 1,
.div = 8,
.hw.init = &(
struct clk_init_data){
.name =
"cpu_clk_div8",
.ops = &clk_fixed_factor_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_cpu_clk.hw
},
.num_parents = 1,
},
};
static u32 mux_table_apb[] = { 1, 2, 3, 4, 5, 6, 7 };
static struct clk_regmap meson8b_apb_clk_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_SYS_CPU_CLK_CNTL1,
.mask = 0x7,
.shift = 3,
.table = mux_table_apb,
},
.hw.init = &(
struct clk_init_data){
.name =
"apb_clk_sel",
.ops = &clk_regmap_mux_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_cpu_clk_div2.hw,
&meson8b_cpu_clk_div3.hw,
&meson8b_cpu_clk_div4.hw,
&meson8b_cpu_clk_div5.hw,
&meson8b_cpu_clk_div6.hw,
&meson8b_cpu_clk_div7.hw,
&meson8b_cpu_clk_div8.hw,
},
.num_parents = 7,
},
};
static struct clk_regmap meson8b_apb_clk_gate = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_SYS_CPU_CLK_CNTL1,
.bit_idx = 16,
.flags = CLK_GATE_SET_TO_DISABLE,
},
.hw.init = &(
struct clk_init_data){
.name =
"apb_clk_dis",
.ops = &clk_regmap_gate_ro_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_apb_clk_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_periph_clk_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_SYS_CPU_CLK_CNTL1,
.mask = 0x7,
.shift = 6,
},
.hw.init = &(
struct clk_init_data){
.name =
"periph_clk_sel",
.ops = &clk_regmap_mux_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_cpu_clk_div2.hw,
&meson8b_cpu_clk_div3.hw,
&meson8b_cpu_clk_div4.hw,
&meson8b_cpu_clk_div5.hw,
&meson8b_cpu_clk_div6.hw,
&meson8b_cpu_clk_div7.hw,
&meson8b_cpu_clk_div8.hw,
},
.num_parents = 7,
},
};
static struct clk_regmap meson8b_periph_clk_gate = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_SYS_CPU_CLK_CNTL1,
.bit_idx = 17,
.flags = CLK_GATE_SET_TO_DISABLE,
},
.hw.init = &(
struct clk_init_data){
.name =
"periph_clk_dis",
.ops = &clk_regmap_gate_ro_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_periph_clk_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static u32 mux_table_axi[] = { 1, 2, 3, 4, 5, 6, 7 };
static struct clk_regmap meson8b_axi_clk_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_SYS_CPU_CLK_CNTL1,
.mask = 0x7,
.shift = 9,
.table = mux_table_axi,
},
.hw.init = &(
struct clk_init_data){
.name =
"axi_clk_sel",
.ops = &clk_regmap_mux_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_cpu_clk_div2.hw,
&meson8b_cpu_clk_div3.hw,
&meson8b_cpu_clk_div4.hw,
&meson8b_cpu_clk_div5.hw,
&meson8b_cpu_clk_div6.hw,
&meson8b_cpu_clk_div7.hw,
&meson8b_cpu_clk_div8.hw,
},
.num_parents = 7,
},
};
static struct clk_regmap meson8b_axi_clk_gate = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_SYS_CPU_CLK_CNTL1,
.bit_idx = 18,
.flags = CLK_GATE_SET_TO_DISABLE,
},
.hw.init = &(
struct clk_init_data){
.name =
"axi_clk_dis",
.ops = &clk_regmap_gate_ro_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_axi_clk_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_l2_dram_clk_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_SYS_CPU_CLK_CNTL1,
.mask = 0x7,
.shift = 12,
},
.hw.init = &(
struct clk_init_data){
.name =
"l2_dram_clk_sel",
.ops = &clk_regmap_mux_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_cpu_clk_div2.hw,
&meson8b_cpu_clk_div3.hw,
&meson8b_cpu_clk_div4.hw,
&meson8b_cpu_clk_div5.hw,
&meson8b_cpu_clk_div6.hw,
&meson8b_cpu_clk_div7.hw,
&meson8b_cpu_clk_div8.hw,
},
.num_parents = 7,
},
};
static struct clk_regmap meson8b_l2_dram_clk_gate = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_SYS_CPU_CLK_CNTL1,
.bit_idx = 19,
.flags = CLK_GATE_SET_TO_DISABLE,
},
.hw.init = &(
struct clk_init_data){
.name =
"l2_dram_clk_dis",
.ops = &clk_regmap_gate_ro_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_l2_dram_clk_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
/* also called LVDS_CLK_EN */
static struct clk_regmap meson8b_vid_pll_lvds_en = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VID_DIVIDER_CNTL,
.bit_idx = 11,
},
.hw.init = &(
struct clk_init_data){
.name =
"vid_pll_lvds_en",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_hdmi_pll_lvds_out.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vid_pll_in_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_VID_DIVIDER_CNTL,
.mask = 0x1,
.shift = 15,
},
.hw.init = &(
struct clk_init_data){
.name =
"vid_pll_in_sel",
.ops = &clk_regmap_mux_ops,
/*
* TODO: depending on the SoC there is also a second parent:
* Meson8: unknown
* Meson8b: hdmi_pll_dco
* Meson8m2: vid2_pll
*/
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vid_pll_lvds_en.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vid_pll_in_en = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VID_DIVIDER_CNTL,
.bit_idx = 16,
},
.hw.init = &(
struct clk_init_data){
.name =
"vid_pll_in_en",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vid_pll_in_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vid_pll_pre_div = {
.data = &(
struct clk_regmap_div_data){
.offset = HHI_VID_DIVIDER_CNTL,
.shift = 4,
.width = 3,
},
.hw.init = &(
struct clk_init_data){
.name =
"vid_pll_pre_div",
.ops = &clk_regmap_divider_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vid_pll_in_en.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vid_pll_post_div = {
.data = &(
struct clk_regmap_div_data){
.offset = HHI_VID_DIVIDER_CNTL,
.shift = 12,
.width = 3,
},
.hw.init = &(
struct clk_init_data){
.name =
"vid_pll_post_div",
.ops = &clk_regmap_divider_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vid_pll_pre_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vid_pll = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_VID_DIVIDER_CNTL,
.mask = 0x3,
.shift = 8,
},
.hw.init = &(
struct clk_init_data){
.name =
"vid_pll",
.ops = &clk_regmap_mux_ops,
/* TODO: parent 0x2 is vid_pll_pre_div_mult7_div2 */
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vid_pll_pre_div.hw,
&meson8b_vid_pll_post_div.hw,
},
.num_parents = 2,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vid_pll_final_div = {
.data = &(
struct clk_regmap_div_data){
.offset = HHI_VID_CLK_DIV,
.shift = 0,
.width = 8,
},
.hw.init = &(
struct clk_init_data){
.name =
"vid_pll_final_div",
.ops = &clk_regmap_divider_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vid_pll.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static const struct clk_hw *meson8b_vclk_mux_parent_hws[] = {
&meson8b_vid_pll_final_div.hw,
&meson8b_fclk_div4.hw,
&meson8b_fclk_div3.hw,
&meson8b_fclk_div5.hw,
&meson8b_vid_pll_final_div.hw,
&meson8b_fclk_div7.hw,
&meson8b_mpll1.hw,
};
static struct clk_regmap meson8b_vclk_in_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_VID_CLK_CNTL,
.mask = 0x7,
.shift = 16,
},
.hw.init = &(
struct clk_init_data){
.name =
"vclk_in_sel",
.ops = &clk_regmap_mux_ops,
.parent_hws = meson8b_vclk_mux_parent_hws,
.num_parents = ARRAY_SIZE(meson8b_vclk_mux_parent_hws),
.flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
},
};
static struct clk_regmap meson8b_vclk_in_en = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VID_CLK_DIV,
.bit_idx = 16,
},
.hw.init = &(
struct clk_init_data){
.name =
"vclk_in_en",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vclk_in_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vclk_en = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VID_CLK_CNTL,
.bit_idx = 19,
},
.hw.init = &(
struct clk_init_data){
.name =
"vclk_en",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vclk_in_en.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vclk_div1_gate = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VID_CLK_CNTL,
.bit_idx = 0,
},
.hw.init = &(
struct clk_init_data){
.name =
"vclk_div1_en",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vclk_en.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_fixed_factor meson8b_vclk_div2_div = {
.mult = 1,
.div = 2,
.hw.init = &(
struct clk_init_data){
.name =
"vclk_div2",
.ops = &clk_fixed_factor_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vclk_en.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
}
};
static struct clk_regmap meson8b_vclk_div2_div_gate = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VID_CLK_CNTL,
.bit_idx = 1,
},
.hw.init = &(
struct clk_init_data){
.name =
"vclk_div2_en",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vclk_div2_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_fixed_factor meson8b_vclk_div4_div = {
.mult = 1,
.div = 4,
.hw.init = &(
struct clk_init_data){
.name =
"vclk_div4",
.ops = &clk_fixed_factor_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vclk_en.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
}
};
static struct clk_regmap meson8b_vclk_div4_div_gate = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VID_CLK_CNTL,
.bit_idx = 2,
},
.hw.init = &(
struct clk_init_data){
.name =
"vclk_div4_en",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vclk_div4_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_fixed_factor meson8b_vclk_div6_div = {
.mult = 1,
.div = 6,
.hw.init = &(
struct clk_init_data){
.name =
"vclk_div6",
.ops = &clk_fixed_factor_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vclk_en.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
}
};
static struct clk_regmap meson8b_vclk_div6_div_gate = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VID_CLK_CNTL,
.bit_idx = 3,
},
.hw.init = &(
struct clk_init_data){
.name =
"vclk_div6_en",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vclk_div6_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_fixed_factor meson8b_vclk_div12_div = {
.mult = 1,
.div = 12,
.hw.init = &(
struct clk_init_data){
.name =
"vclk_div12",
.ops = &clk_fixed_factor_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vclk_en.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
}
};
static struct clk_regmap meson8b_vclk_div12_div_gate = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VID_CLK_CNTL,
.bit_idx = 4,
},
.hw.init = &(
struct clk_init_data){
.name =
"vclk_div12_en",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vclk_div12_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vclk2_in_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_VIID_CLK_CNTL,
.mask = 0x7,
.shift = 16,
},
.hw.init = &(
struct clk_init_data){
.name =
"vclk2_in_sel",
.ops = &clk_regmap_mux_ops,
.parent_hws = meson8b_vclk_mux_parent_hws,
.num_parents = ARRAY_SIZE(meson8b_vclk_mux_parent_hws),
.flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
},
};
static struct clk_regmap meson8b_vclk2_clk_in_en = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VIID_CLK_DIV,
.bit_idx = 16,
},
.hw.init = &(
struct clk_init_data){
.name =
"vclk2_in_en",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vclk2_in_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vclk2_clk_en = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VIID_CLK_DIV,
.bit_idx = 19,
},
.hw.init = &(
struct clk_init_data){
.name =
"vclk2_en",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vclk2_clk_in_en.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vclk2_div1_gate = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VIID_CLK_DIV,
.bit_idx = 0,
},
.hw.init = &(
struct clk_init_data){
.name =
"vclk2_div1_en",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vclk2_clk_en.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_fixed_factor meson8b_vclk2_div2_div = {
.mult = 1,
.div = 2,
.hw.init = &(
struct clk_init_data){
.name =
"vclk2_div2",
.ops = &clk_fixed_factor_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vclk2_clk_en.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
}
};
static struct clk_regmap meson8b_vclk2_div2_div_gate = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VIID_CLK_DIV,
.bit_idx = 1,
},
.hw.init = &(
struct clk_init_data){
.name =
"vclk2_div2_en",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vclk2_div2_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_fixed_factor meson8b_vclk2_div4_div = {
.mult = 1,
.div = 4,
.hw.init = &(
struct clk_init_data){
.name =
"vclk2_div4",
.ops = &clk_fixed_factor_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vclk2_clk_en.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
}
};
static struct clk_regmap meson8b_vclk2_div4_div_gate = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VIID_CLK_DIV,
.bit_idx = 2,
},
.hw.init = &(
struct clk_init_data){
.name =
"vclk2_div4_en",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vclk2_div4_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_fixed_factor meson8b_vclk2_div6_div = {
.mult = 1,
.div = 6,
.hw.init = &(
struct clk_init_data){
.name =
"vclk2_div6",
.ops = &clk_fixed_factor_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vclk2_clk_en.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
}
};
static struct clk_regmap meson8b_vclk2_div6_div_gate = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VIID_CLK_DIV,
.bit_idx = 3,
},
.hw.init = &(
struct clk_init_data){
.name =
"vclk2_div6_en",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vclk2_div6_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_fixed_factor meson8b_vclk2_div12_div = {
.mult = 1,
.div = 12,
.hw.init = &(
struct clk_init_data){
.name =
"vclk2_div12",
.ops = &clk_fixed_factor_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vclk2_clk_en.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
}
};
static struct clk_regmap meson8b_vclk2_div12_div_gate = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VIID_CLK_DIV,
.bit_idx = 4,
},
.hw.init = &(
struct clk_init_data){
.name =
"vclk2_div12_en",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vclk2_div12_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static const struct clk_hw *meson8b_vclk_enc_mux_parent_hws[] = {
&meson8b_vclk_div1_gate.hw,
&meson8b_vclk_div2_div_gate.hw,
&meson8b_vclk_div4_div_gate.hw,
&meson8b_vclk_div6_div_gate.hw,
&meson8b_vclk_div12_div_gate.hw,
};
static struct clk_regmap meson8b_cts_enct_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_VID_CLK_DIV,
.mask = 0xf,
.shift = 20,
},
.hw.init = &(
struct clk_init_data){
.name =
"cts_enct_sel",
.ops = &clk_regmap_mux_ops,
.parent_hws = meson8b_vclk_enc_mux_parent_hws,
.num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parent_hws),
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_cts_enct = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VID_CLK_CNTL2,
.bit_idx = 1,
},
.hw.init = &(
struct clk_init_data){
.name =
"cts_enct",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_cts_enct_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_cts_encp_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_VID_CLK_DIV,
.mask = 0xf,
.shift = 24,
},
.hw.init = &(
struct clk_init_data){
.name =
"cts_encp_sel",
.ops = &clk_regmap_mux_ops,
.parent_hws = meson8b_vclk_enc_mux_parent_hws,
.num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parent_hws),
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_cts_encp = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VID_CLK_CNTL2,
.bit_idx = 2,
},
.hw.init = &(
struct clk_init_data){
.name =
"cts_encp",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_cts_encp_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_cts_enci_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_VID_CLK_DIV,
.mask = 0xf,
.shift = 28,
},
.hw.init = &(
struct clk_init_data){
.name =
"cts_enci_sel",
.ops = &clk_regmap_mux_ops,
.parent_hws = meson8b_vclk_enc_mux_parent_hws,
.num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parent_hws),
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_cts_enci = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VID_CLK_CNTL2,
.bit_idx = 0,
},
.hw.init = &(
struct clk_init_data){
.name =
"cts_enci",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_cts_enci_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_hdmi_tx_pixel_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_HDMI_CLK_CNTL,
.mask = 0xf,
.shift = 16,
},
.hw.init = &(
struct clk_init_data){
.name =
"hdmi_tx_pixel_sel",
.ops = &clk_regmap_mux_ops,
.parent_hws = meson8b_vclk_enc_mux_parent_hws,
.num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parent_hws),
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_hdmi_tx_pixel = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VID_CLK_CNTL2,
.bit_idx = 5,
},
.hw.init = &(
struct clk_init_data){
.name =
"hdmi_tx_pixel",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_hdmi_tx_pixel_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static const struct clk_hw *meson8b_vclk2_enc_mux_parent_hws[] = {
&meson8b_vclk2_div1_gate.hw,
&meson8b_vclk2_div2_div_gate.hw,
&meson8b_vclk2_div4_div_gate.hw,
&meson8b_vclk2_div6_div_gate.hw,
&meson8b_vclk2_div12_div_gate.hw,
};
static struct clk_regmap meson8b_cts_encl_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_VIID_CLK_DIV,
.mask = 0xf,
.shift = 12,
},
.hw.init = &(
struct clk_init_data){
.name =
"cts_encl_sel",
.ops = &clk_regmap_mux_ops,
.parent_hws = meson8b_vclk2_enc_mux_parent_hws,
.num_parents = ARRAY_SIZE(meson8b_vclk2_enc_mux_parent_hws),
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_cts_encl = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VID_CLK_CNTL2,
.bit_idx = 3,
},
.hw.init = &(
struct clk_init_data){
.name =
"cts_encl",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_cts_encl_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_cts_vdac0_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_VIID_CLK_DIV,
.mask = 0xf,
.shift = 28,
},
.hw.init = &(
struct clk_init_data){
.name =
"cts_vdac0_sel",
.ops = &clk_regmap_mux_ops,
.parent_hws = meson8b_vclk2_enc_mux_parent_hws,
.num_parents = ARRAY_SIZE(meson8b_vclk2_enc_mux_parent_hws),
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_cts_vdac0 = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VID_CLK_CNTL2,
.bit_idx = 4,
},
.hw.init = &(
struct clk_init_data){
.name =
"cts_vdac0",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_cts_vdac0_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_hdmi_sys_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_HDMI_CLK_CNTL,
.mask = 0x3,
.shift = 9,
.flags = CLK_MUX_ROUND_CLOSEST,
},
.hw.init = &(
struct clk_init_data){
.name =
"hdmi_sys_sel",
.ops = &clk_regmap_mux_ops,
/* FIXME: all other parents are unknown */
.parent_data = &(
const struct clk_parent_data) {
.fw_name =
"xtal",
.name =
"xtal",
.index = -1,
},
.num_parents = 1,
.flags = CLK_SET_RATE_NO_REPARENT,
},
};
static struct clk_regmap meson8b_hdmi_sys_div = {
.data = &(
struct clk_regmap_div_data){
.offset = HHI_HDMI_CLK_CNTL,
.shift = 0,
.width = 7,
},
.hw.init = &(
struct clk_init_data){
.name =
"hdmi_sys_div",
.ops = &clk_regmap_divider_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_hdmi_sys_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_hdmi_sys = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_HDMI_CLK_CNTL,
.bit_idx = 8,
},
.hw.init = &(
struct clk_init_data) {
.name =
"hdmi_sys",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_hdmi_sys_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
/*
* The MALI IP is clocked by two identical clocks (mali_0 and mali_1)
* muxed by a glitch-free switch on Meson8b and Meson8m2. The CCF can
* actually manage this glitch-free mux because it does top-to-bottom
* updates the each clock tree and switches to the "inactive" one when
* CLK_SET_RATE_GATE is set.
* Meson8 only has mali_0 and no glitch-free mux.
*/
static const struct clk_parent_data meson8b_mali_0_1_parent_data[] = {
{ .fw_name =
"xtal", .name =
"xtal", .index = -1, },
{ .hw = &meson8b_mpll2.hw, },
{ .hw = &meson8b_mpll1.hw, },
{ .hw = &meson8b_fclk_div7.hw, },
{ .hw = &meson8b_fclk_div4.hw, },
{ .hw = &meson8b_fclk_div3.hw, },
{ .hw = &meson8b_fclk_div5.hw, },
};
static u32 meson8b_mali_0_1_mux_table[] = { 0, 2, 3, 4, 5, 6, 7 };
static struct clk_regmap meson8b_mali_0_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_MALI_CLK_CNTL,
.mask = 0x7,
.shift = 9,
.table = meson8b_mali_0_1_mux_table,
},
.hw.init = &(
struct clk_init_data){
.name =
"mali_0_sel",
.ops = &clk_regmap_mux_ops,
.parent_data = meson8b_mali_0_1_parent_data,
.num_parents = ARRAY_SIZE(meson8b_mali_0_1_parent_data),
/*
* Don't propagate rate changes up because the only changeable
* parents are mpll1 and mpll2 but we need those for audio and
* RGMII (Ethernet). We don't want to change the audio or
* Ethernet clocks when setting the GPU frequency.
*/
.flags = 0,
},
};
static struct clk_regmap meson8b_mali_0_div = {
.data = &(
struct clk_regmap_div_data){
.offset = HHI_MALI_CLK_CNTL,
.shift = 0,
.width = 7,
},
.hw.init = &(
struct clk_init_data){
.name =
"mali_0_div",
.ops = &clk_regmap_divider_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_mali_0_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_mali_0 = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_MALI_CLK_CNTL,
.bit_idx = 8,
},
.hw.init = &(
struct clk_init_data){
.name =
"mali_0",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_mali_0_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_mali_1_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_MALI_CLK_CNTL,
.mask = 0x7,
.shift = 25,
.table = meson8b_mali_0_1_mux_table,
},
.hw.init = &(
struct clk_init_data){
.name =
"mali_1_sel",
.ops = &clk_regmap_mux_ops,
.parent_data = meson8b_mali_0_1_parent_data,
.num_parents = ARRAY_SIZE(meson8b_mali_0_1_parent_data),
/*
* Don't propagate rate changes up because the only changeable
* parents are mpll1 and mpll2 but we need those for audio and
* RGMII (Ethernet). We don't want to change the audio or
* Ethernet clocks when setting the GPU frequency.
*/
.flags = 0,
},
};
static struct clk_regmap meson8b_mali_1_div = {
.data = &(
struct clk_regmap_div_data){
.offset = HHI_MALI_CLK_CNTL,
.shift = 16,
.width = 7,
},
.hw.init = &(
struct clk_init_data){
.name =
"mali_1_div",
.ops = &clk_regmap_divider_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_mali_1_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_mali_1 = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_MALI_CLK_CNTL,
.bit_idx = 24,
},
.hw.init = &(
struct clk_init_data){
.name =
"mali_1",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_mali_1_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_mali = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_MALI_CLK_CNTL,
.mask = 1,
.shift = 31,
},
.hw.init = &(
struct clk_init_data){
.name =
"mali",
.ops = &clk_regmap_mux_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_mali_0.hw,
&meson8b_mali_1.hw,
},
.num_parents = 2,
.flags = CLK_SET_RATE_PARENT,
},
};
static const struct reg_sequence meson8m2_gp_pll_init_regs[] = {
{ .reg = HHI_GP_PLL_CNTL2, .def = 0x59c88000 },
{ .reg = HHI_GP_PLL_CNTL3, .def = 0xca463823 },
{ .reg = HHI_GP_PLL_CNTL4, .def = 0x0286a027 },
{ .reg = HHI_GP_PLL_CNTL5, .def = 0x00003000 },
};
static const struct pll_params_table meson8m2_gp_pll_params_table[] = {
PLL_PARAMS(182, 3),
{
/* sentinel */ },
};
static struct clk_regmap meson8m2_gp_pll_dco = {
.data = &(
struct meson_clk_pll_data){
.en = {
.reg_off = HHI_GP_PLL_CNTL,
.shift = 30,
.width = 1,
},
.m = {
.reg_off = HHI_GP_PLL_CNTL,
.shift = 0,
.width = 9,
},
.n = {
.reg_off = HHI_GP_PLL_CNTL,
.shift = 9,
.width = 5,
},
.l = {
.reg_off = HHI_GP_PLL_CNTL,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_GP_PLL_CNTL,
.shift = 29,
.width = 1,
},
.table = meson8m2_gp_pll_params_table,
.init_regs = meson8m2_gp_pll_init_regs,
.init_count = ARRAY_SIZE(meson8m2_gp_pll_init_regs),
},
.hw.init = &(
struct clk_init_data){
.name =
"gp_pll_dco",
.ops = &meson_clk_pll_ops,
.parent_data = &(
const struct clk_parent_data) {
.fw_name =
"xtal",
.name =
"xtal",
.index = -1,
},
.num_parents = 1,
},
};
static struct clk_regmap meson8m2_gp_pll = {
.data = &(
struct clk_regmap_div_data){
.offset = HHI_GP_PLL_CNTL,
.shift = 16,
.width = 2,
.flags = CLK_DIVIDER_POWER_OF_TWO,
},
.hw.init = &(
struct clk_init_data){
.name =
"gp_pll",
.ops = &clk_regmap_divider_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8m2_gp_pll_dco.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static const struct clk_hw *meson8b_vpu_0_1_parent_hws[] = {
&meson8b_fclk_div4.hw,
&meson8b_fclk_div3.hw,
&meson8b_fclk_div5.hw,
&meson8b_fclk_div7.hw,
};
static const struct clk_hw *mmeson8m2_vpu_0_1_parent_hws[] = {
&meson8b_fclk_div4.hw,
&meson8b_fclk_div3.hw,
&meson8b_fclk_div5.hw,
&meson8m2_gp_pll.hw,
};
static struct clk_regmap meson8b_vpu_0_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_VPU_CLK_CNTL,
.mask = 0x3,
.shift = 9,
},
.hw.init = &(
struct clk_init_data){
.name =
"vpu_0_sel",
.ops = &clk_regmap_mux_ops,
.parent_hws = meson8b_vpu_0_1_parent_hws,
.num_parents = ARRAY_SIZE(meson8b_vpu_0_1_parent_hws),
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8m2_vpu_0_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_VPU_CLK_CNTL,
.mask = 0x3,
.shift = 9,
},
.hw.init = &(
struct clk_init_data){
.name =
"vpu_0_sel",
.ops = &clk_regmap_mux_ops,
.parent_hws = mmeson8m2_vpu_0_1_parent_hws,
.num_parents = ARRAY_SIZE(mmeson8m2_vpu_0_1_parent_hws),
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vpu_0_div = {
.data = &(
struct clk_regmap_div_data){
.offset = HHI_VPU_CLK_CNTL,
.shift = 0,
.width = 7,
},
.hw.init = &(
struct clk_init_data){
.name =
"vpu_0_div",
.ops = &clk_regmap_divider_ops,
.parent_data = &(
const struct clk_parent_data) {
/*
* Note:
* meson8b and meson8m2 have different vpu_0_sels (with
* different struct clk_hw). We fallback to the global
* naming string mechanism so vpu_0_div picks up the
* appropriate one.
*/
.name =
"vpu_0_sel",
.index = -1,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vpu_0 = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VPU_CLK_CNTL,
.bit_idx = 8,
},
.hw.init = &(
struct clk_init_data) {
.name =
"vpu_0",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vpu_0_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vpu_1_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_VPU_CLK_CNTL,
.mask = 0x3,
.shift = 25,
},
.hw.init = &(
struct clk_init_data){
.name =
"vpu_1_sel",
.ops = &clk_regmap_mux_ops,
.parent_hws = meson8b_vpu_0_1_parent_hws,
.num_parents = ARRAY_SIZE(meson8b_vpu_0_1_parent_hws),
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8m2_vpu_1_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_VPU_CLK_CNTL,
.mask = 0x3,
.shift = 25,
},
.hw.init = &(
struct clk_init_data){
.name =
"vpu_1_sel",
.ops = &clk_regmap_mux_ops,
.parent_hws = mmeson8m2_vpu_0_1_parent_hws,
.num_parents = ARRAY_SIZE(mmeson8m2_vpu_0_1_parent_hws),
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vpu_1_div = {
.data = &(
struct clk_regmap_div_data){
.offset = HHI_VPU_CLK_CNTL,
.shift = 16,
.width = 7,
},
.hw.init = &(
struct clk_init_data){
.name =
"vpu_1_div",
.ops = &clk_regmap_divider_ops,
.parent_data = &(
const struct clk_parent_data) {
/*
* Note:
* meson8b and meson8m2 have different vpu_1_sels (with
* different struct clk_hw). We fallback to the global
* naming string mechanism so vpu_1_div picks up the
* appropriate one.
*/
.name =
"vpu_1_sel",
.index = -1,
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vpu_1 = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VPU_CLK_CNTL,
.bit_idx = 24,
},
.hw.init = &(
struct clk_init_data) {
.name =
"vpu_1",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vpu_1_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT,
},
};
/*
* The VPU clock has two identical clock trees (vpu_0 and vpu_1)
* muxed by a glitch-free switch on Meson8b and Meson8m2. The CCF can
* actually manage this glitch-free mux because it does top-to-bottom
* updates the each clock tree and switches to the "inactive" one when
* CLK_SET_RATE_GATE is set.
* Meson8 only has vpu_0 and no glitch-free mux.
*/
static struct clk_regmap meson8b_vpu = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_VPU_CLK_CNTL,
.mask = 1,
.shift = 31,
},
.hw.init = &(
struct clk_init_data){
.name =
"vpu",
.ops = &clk_regmap_mux_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vpu_0.hw,
&meson8b_vpu_1.hw,
},
.num_parents = 2,
.flags = CLK_SET_RATE_PARENT,
},
};
static const struct clk_hw *meson8b_vdec_parent_hws[] = {
&meson8b_fclk_div4.hw,
&meson8b_fclk_div3.hw,
&meson8b_fclk_div5.hw,
&meson8b_fclk_div7.hw,
&meson8b_mpll2.hw,
&meson8b_mpll1.hw,
};
static struct clk_regmap meson8b_vdec_1_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_VDEC_CLK_CNTL,
.mask = 0x3,
.shift = 9,
.flags = CLK_MUX_ROUND_CLOSEST,
},
.hw.init = &(
struct clk_init_data){
.name =
"vdec_1_sel",
.ops = &clk_regmap_mux_ops,
.parent_hws = meson8b_vdec_parent_hws,
.num_parents = ARRAY_SIZE(meson8b_vdec_parent_hws),
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vdec_1_1_div = {
.data = &(
struct clk_regmap_div_data){
.offset = HHI_VDEC_CLK_CNTL,
.shift = 0,
.width = 7,
.flags = CLK_DIVIDER_ROUND_CLOSEST,
},
.hw.init = &(
struct clk_init_data){
.name =
"vdec_1_1_div",
.ops = &clk_regmap_divider_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vdec_1_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vdec_1_1 = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VDEC_CLK_CNTL,
.bit_idx = 8,
},
.hw.init = &(
struct clk_init_data) {
.name =
"vdec_1_1",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vdec_1_1_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vdec_1_2_div = {
.data = &(
struct clk_regmap_div_data){
.offset = HHI_VDEC3_CLK_CNTL,
.shift = 0,
.width = 7,
.flags = CLK_DIVIDER_ROUND_CLOSEST,
},
.hw.init = &(
struct clk_init_data){
.name =
"vdec_1_2_div",
.ops = &clk_regmap_divider_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vdec_1_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vdec_1_2 = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VDEC3_CLK_CNTL,
.bit_idx = 8,
},
.hw.init = &(
struct clk_init_data) {
.name =
"vdec_1_2",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vdec_1_2_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vdec_1 = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_VDEC3_CLK_CNTL,
.mask = 0x1,
.shift = 15,
.flags = CLK_MUX_ROUND_CLOSEST,
},
.hw.init = &(
struct clk_init_data){
.name =
"vdec_1",
.ops = &clk_regmap_mux_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vdec_1_1.hw,
&meson8b_vdec_1_2.hw,
},
.num_parents = 2,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vdec_hcodec_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_VDEC_CLK_CNTL,
.mask = 0x3,
.shift = 25,
.flags = CLK_MUX_ROUND_CLOSEST,
},
.hw.init = &(
struct clk_init_data){
.name =
"vdec_hcodec_sel",
.ops = &clk_regmap_mux_ops,
.parent_hws = meson8b_vdec_parent_hws,
.num_parents = ARRAY_SIZE(meson8b_vdec_parent_hws),
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vdec_hcodec_div = {
.data = &(
struct clk_regmap_div_data){
.offset = HHI_VDEC_CLK_CNTL,
.shift = 16,
.width = 7,
.flags = CLK_DIVIDER_ROUND_CLOSEST,
},
.hw.init = &(
struct clk_init_data){
.name =
"vdec_hcodec_div",
.ops = &clk_regmap_divider_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vdec_hcodec_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vdec_hcodec = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VDEC_CLK_CNTL,
.bit_idx = 24,
},
.hw.init = &(
struct clk_init_data) {
.name =
"vdec_hcodec",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vdec_hcodec_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vdec_2_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_VDEC2_CLK_CNTL,
.mask = 0x3,
.shift = 9,
.flags = CLK_MUX_ROUND_CLOSEST,
},
.hw.init = &(
struct clk_init_data){
.name =
"vdec_2_sel",
.ops = &clk_regmap_mux_ops,
.parent_hws = meson8b_vdec_parent_hws,
.num_parents = ARRAY_SIZE(meson8b_vdec_parent_hws),
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vdec_2_div = {
.data = &(
struct clk_regmap_div_data){
.offset = HHI_VDEC2_CLK_CNTL,
.shift = 0,
.width = 7,
.flags = CLK_DIVIDER_ROUND_CLOSEST,
},
.hw.init = &(
struct clk_init_data){
.name =
"vdec_2_div",
.ops = &clk_regmap_divider_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vdec_2_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vdec_2 = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VDEC2_CLK_CNTL,
.bit_idx = 8,
},
.hw.init = &(
struct clk_init_data) {
.name =
"vdec_2",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vdec_2_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vdec_hevc_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_VDEC2_CLK_CNTL,
.mask = 0x3,
.shift = 25,
.flags = CLK_MUX_ROUND_CLOSEST,
},
.hw.init = &(
struct clk_init_data){
.name =
"vdec_hevc_sel",
.ops = &clk_regmap_mux_ops,
.parent_hws = meson8b_vdec_parent_hws,
.num_parents = ARRAY_SIZE(meson8b_vdec_parent_hws),
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vdec_hevc_div = {
.data = &(
struct clk_regmap_div_data){
.offset = HHI_VDEC2_CLK_CNTL,
.shift = 16,
.width = 7,
.flags = CLK_DIVIDER_ROUND_CLOSEST,
},
.hw.init = &(
struct clk_init_data){
.name =
"vdec_hevc_div",
.ops = &clk_regmap_divider_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vdec_hevc_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vdec_hevc_en = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_VDEC2_CLK_CNTL,
.bit_idx = 24,
},
.hw.init = &(
struct clk_init_data) {
.name =
"vdec_hevc_en",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vdec_hevc_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_vdec_hevc = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_VDEC2_CLK_CNTL,
.mask = 0x1,
.shift = 31,
.flags = CLK_MUX_ROUND_CLOSEST,
},
.hw.init = &(
struct clk_init_data){
.name =
"vdec_hevc",
.ops = &clk_regmap_mux_ops,
/* TODO: The second parent is currently unknown */
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_vdec_hevc_en.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
/* TODO: the clock at index 0 is "DDR_PLL" which we don't support yet */
static const struct clk_hw *meson8b_cts_amclk_parent_hws[] = {
&meson8b_mpll0.hw,
&meson8b_mpll1.hw,
&meson8b_mpll2.hw
};
static u32 meson8b_cts_amclk_mux_table[] = { 1, 2, 3 };
static struct clk_regmap meson8b_cts_amclk_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_AUD_CLK_CNTL,
.mask = 0x3,
.shift = 9,
.table = meson8b_cts_amclk_mux_table,
.flags = CLK_MUX_ROUND_CLOSEST,
},
.hw.init = &(
struct clk_init_data){
.name =
"cts_amclk_sel",
.ops = &clk_regmap_mux_ops,
.parent_hws = meson8b_cts_amclk_parent_hws,
.num_parents = ARRAY_SIZE(meson8b_cts_amclk_parent_hws),
},
};
static struct clk_regmap meson8b_cts_amclk_div = {
.data = &(
struct clk_regmap_div_data) {
.offset = HHI_AUD_CLK_CNTL,
.shift = 0,
.width = 8,
.flags = CLK_DIVIDER_ROUND_CLOSEST,
},
.hw.init = &(
struct clk_init_data){
.name =
"cts_amclk_div",
.ops = &clk_regmap_divider_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_cts_amclk_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_cts_amclk = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_AUD_CLK_CNTL,
.bit_idx = 8,
},
.hw.init = &(
struct clk_init_data){
.name =
"cts_amclk",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_cts_amclk_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
/* TODO: the clock at index 0 is "DDR_PLL" which we don't support yet */
static const struct clk_hw *meson8b_cts_mclk_i958_parent_hws[] = {
&meson8b_mpll0.hw,
&meson8b_mpll1.hw,
&meson8b_mpll2.hw
};
static u32 meson8b_cts_mclk_i958_mux_table[] = { 1, 2, 3 };
static struct clk_regmap meson8b_cts_mclk_i958_sel = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_AUD_CLK_CNTL2,
.mask = 0x3,
.shift = 25,
.table = meson8b_cts_mclk_i958_mux_table,
.flags = CLK_MUX_ROUND_CLOSEST,
},
.hw.init = &(
struct clk_init_data) {
.name =
"cts_mclk_i958_sel",
.ops = &clk_regmap_mux_ops,
.parent_hws = meson8b_cts_mclk_i958_parent_hws,
.num_parents = ARRAY_SIZE(meson8b_cts_mclk_i958_parent_hws),
},
};
static struct clk_regmap meson8b_cts_mclk_i958_div = {
.data = &(
struct clk_regmap_div_data){
.offset = HHI_AUD_CLK_CNTL2,
.shift = 16,
.width = 8,
.flags = CLK_DIVIDER_ROUND_CLOSEST,
},
.hw.init = &(
struct clk_init_data) {
.name =
"cts_mclk_i958_div",
.ops = &clk_regmap_divider_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_cts_mclk_i958_sel.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_cts_mclk_i958 = {
.data = &(
struct clk_regmap_gate_data){
.offset = HHI_AUD_CLK_CNTL2,
.bit_idx = 24,
},
.hw.init = &(
struct clk_init_data){
.name =
"cts_mclk_i958",
.ops = &clk_regmap_gate_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_cts_mclk_i958_div.hw
},
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_cts_i958 = {
.data = &(
struct clk_regmap_mux_data){
.offset = HHI_AUD_CLK_CNTL2,
.mask = 0x1,
.shift = 27,
},
.hw.init = &(
struct clk_init_data){
.name =
"cts_i958",
.ops = &clk_regmap_mux_ops,
.parent_hws = (
const struct clk_hw *[]) {
&meson8b_cts_amclk.hw,
--> --------------------
--> maximum size reached
--> --------------------