/* * Copyright (c) 2025-2026 Texas Instruments Incorporated - https://www.ti.com * * SPDX-License-Identifier: BSD-3-Clause */ /* * TI Generic PLL API Header * * This header defines the common PLL data structures and interfaces shared * across different PLL variants. It provides PLL table entries, PLL data * structures for configuration parameters (VCO ranges, dividers, multipliers), * and the common PLL frequency calculation functions. */ #ifndef TI_CLK_PLL_H #define TI_CLK_PLL_H #include #include /* * PLL table entry * * This describes a precomputed PLL setting. This should be preferred * over brute force calculated settings. Additionally, PLL table entries * can be outside spec'd PLL parameters such as minimum VCO frequency. * * Note that the input frequency is not specified but the input frequency * range can be calculated from the given parameters. * * Current data type sizes are chosen based on currently supported PLLs. * If support for an additional PLL with a larger range is added, then * the data sizes will either need to increase or be selected at compile * time. */ struct ti_pll_table_entry { /* Minimum output frequency */ uint32_t freq_min_hz; /* Maximum output frequency */ uint32_t freq_max_hz; /* Multiplier setting */ uint16_t pllm; /* Input divider setting */ uint8_t plld; /* Output divider setting */ uint8_t clkod; /* Fractional multiplier part */ uint32_t pllfm; }; /* The SoC specific table of precomputed PLL settings */ extern const struct ti_pll_table_entry ti_soc_pll_table[]; /* PLL specific const clock data. */ struct ti_clk_data_pll { /* Common const clock data */ struct ti_clk_drv_data data; /* * Precomputed PLL entries * * Points to an array of indexes into the PLL table. NULL if there are no * entries. */ const uint8_t *pll_entries; /* * Number of PLL entries * * Number of valid entries in pll_entries array. */ size_t pll_entries_count; /* * VCO range. * * This points to the valid VCO frequency range in the range table. */ uint8_t vco_range_idx; /* * VCO input range. * * This points to the valid VCO input frequency range in the range * table. */ uint8_t vco_in_range_idx; /* * Default frequency. * * This points to an index in the default frequency table. This * allows the PLL to be programmed to a specific frequency at boot * time. A table entry of 0 indicates that the current state of * the hardware should be used. */ uint8_t default_freq_idx; /* * Device Group. * * Device group(s) this PLL is contained in or DEVGRP_ALL to * indicate unspecified. */ devgrp_t devgrp; /* * Enable fractional support. * * True to enable fractional support if supported by this PLL. If * this is false, fractional frequencies can still be read, but * new fractional frequencies cannot be programmed. */ bool fractional_support; }; /* Const PLL data for use by the pll_calc function. */ struct ti_pll_data { /* Maximum PLL divider. */ uint32_t plld_max; /* Maximum PLL multiplier. */ uint32_t pllm_max; /* Bits of fractional PLL multiplier. */ uint32_t pllfm_bits; /* Maximum PLL post-divider. */ uint32_t clkod_max; /* * Indicate if a divider is valid. * * Some PLLs cannot use all values in their range, such as odd or * even values. This callback allows the pll_calc function to skip * over invalid values. */ bool (*plld_valid)(struct ti_clk *clkp, uint32_t plld); /* * Indicate if a multiplier is valid. * * Some PLLs cannot use all values in their range, such as odd or * even values. This callback allows the pll_calc function to skip * over invalid values. */ bool (*pllm_valid)(struct ti_clk *clkp, uint32_t pllm, bool is_frac); /* * Stride value for a given pllm. * * Some PLLs have additional multipliers enabled to reach certain * pllm values. Normally, these are handled by treating the values * in between possible values as invalid. However, when dealing with * fractional multipliers the pll_calc function must understand that * the fractional multiplier will also be multiplied by this value. * * Provide the extra multiplier value that gets applied at a given * pllm value. */ uint32_t (*pllm_stride)(struct ti_clk *clkp, uint32_t pllm); /* * Indicate if a post-divider is valid. * * Some PLLs cannot use all values in their range, such as odd or * even values. This callback allows the pll_calc function to skip * over invalid values. */ bool (*clkod_valid)(struct ti_clk *clkp, uint32_t clkod); /* * Indicate a bin for this setting combination. * * Some PLLs prefer certain combinations or ranges of settings over * others, such as a multiplier below 512. Binning allows pll_calc * to act on that preference. This function returns a bin number for * each pllm/plld/clkod combination passed. pll_calc will always * prefer a setting with a higher bin value over a lower bin value. */ int32_t (*bin)(struct ti_clk *clkp, uint32_t plld, uint32_t pllm, bool is_frac, uint32_t clkod); /* * Try to find a larger pllm value that exists in a better bin * * The pll calculation code functions by testing every allowable plld * and clkod combination. For each combination, it tests a pllm value * that produces a frequency at or below the target, and a pllm value * that produces a frequency above the target. However, this may skip * certain plld/pllm/clkod combinations that are in a better bin. * This function allows the pll driver code to return a larger pllm * value that is in a better bin than the current pllm value. It * will be called by the pll calculation code until it returns 0. * * Note that the pll calculation function will assume the pllm value * returned is valid and will not call pllm_valid to test it. */ uint32_t (*bin_next_pllm)(struct ti_clk *clkp, uint32_t plld, uint32_t pllm, uint32_t clkod); /* * Try to find a smaller pllm value that exists in a better bin * * The pll calculation code functions by testing every allowable plld * and clkod combination. For each combination, it tests a pllm value * that produces a frequency at or below the target, and a pllm value * that produces a frequency above the target. However, this may skip * certain plld/pllm/clkod combinations that are in a better bin. * This function allows the pll driver code to return a smaller pllm * value that is in a better bin than the current pllm value. It * will be called by the pll calculation code until it returns 0. * * Note that the pll calculation function will assume the pllm value * returned is valid and will not call pllm_valid to test it. */ uint32_t (*bin_prev_pllm)(struct ti_clk *clkp, uint32_t plld, uint32_t pllm, uint32_t clkod); /* * Return fitness value based on VCO frequency. * * While PLLs already have a maximum and minimum allowable VCO * frequency, many prefer certain VCO frequencies over others. If the * bin and frequency delta of a given pllm/plld/clkod combination are * identical, the vco_fitness function is used to pick a preferred * combination. */ uint32_t (*vco_fitness)(struct ti_clk *clkp, uint32_t vco, bool is_frac); }; /** * ti_pll_calc() - Calculate ideal PLL settings. * @clk: The PLL to calculate settings for. * @pll_data: The const parameters of the PLL that give allowable settings and preferences. * @input: The input frequency in Hz. * @output: The desired output frequency in Hz. * @min: The minimum acceptable output frequency in Hz. * @max: The maximum acceptable output frequency in Hz. * @plld: Storage for generated divider value. * @pllm: Storage for generated multiplier value. * @pllfm: Storage for generated fractional multiplier value. * @clkod: Storage for generated post-divider value. * * This calculates the ideal settings that can be used to generate an output * frequenccy given an input frequency and PLL properties. It iterates through * possible divider, multiplier, and post-divider values to find the best * combination. Preferences are sorted by: * - bin * - frequency delta * - VCO fitness * Where bin is the bin value returned by the bin callback, frequency delta * is the difference between the desired frequency and generated frequency, * and VCO fitness is the fitness value returned by the vco_fitness callback. * * Return: Frequency produced with the calculated plld/pllm/clkod * values. 0 if no combination could produce an output * between min and max. */ uint32_t ti_pll_calc(struct ti_clk *clkp, const struct ti_pll_data *pll_d, uint32_t input, uint32_t output, uint32_t min, uint32_t max, uint32_t *plld, uint32_t *pllm, uint32_t *pllfm, uint32_t *clkod); /** * ti_pll_init() - Base PLL initialization function * @clk: The PLL to calculate settings for. * * This contains the common PLL initialization code. This includes setting * the default frequency if applicable. * * Return: 0 on success, error code on error. */ int32_t ti_pll_init(struct ti_clk *clkp); #endif /* TI_CLK_PLL_H */