Path: blob/main/sys/arm/nvidia/tegra124/tegra124_clk_pll.c
39507 views
/*-1* Copyright (c) 2016 Michal Meloun <[email protected]>2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND14* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE15* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE16* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE17* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS19* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)20* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT21* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY22* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF23* SUCH DAMAGE.24*/2526#include <sys/param.h>27#include <sys/systm.h>28#include <sys/bus.h>29#include <sys/lock.h>30#include <sys/mutex.h>31#include <sys/rman.h>3233#include <machine/bus.h>3435#include <dev/clk/clk.h>3637#include <dt-bindings/clock/tegra124-car.h>38#include "tegra124_car.h"3940/* #define TEGRA_PLL_DEBUG */41#ifdef TEGRA_PLL_DEBUG42#define dprintf(...) printf(__VA_ARGS__)43#else44#define dprintf(...)45#endif4647/* All PLLs. */48enum pll_type {49PLL_M,50PLL_X,51PLL_C,52PLL_C2,53PLL_C3,54PLL_C4,55PLL_P,56PLL_A,57PLL_U,58PLL_D,59PLL_D2,60PLL_DP,61PLL_E,62PLL_REFE};6364/* Common base register bits. */65#define PLL_BASE_BYPASS (1U << 31)66#define PLL_BASE_ENABLE (1 << 30)67#define PLL_BASE_REFDISABLE (1 << 29)68#define PLL_BASE_LOCK (1 << 27)69#define PLL_BASE_DIVM_SHIFT 070#define PLL_BASE_DIVN_SHIFT 87172#define PLLRE_MISC_LOCK (1 << 24)7374#define PLL_MISC_LOCK_ENABLE (1 << 18)75#define PLLC_MISC_LOCK_ENABLE (1 << 24)76#define PLLDU_MISC_LOCK_ENABLE (1 << 22)77#define PLLRE_MISC_LOCK_ENABLE (1 << 30)78#define PLLSS_MISC_LOCK_ENABLE (1 << 30)7980#define PLLC_IDDQ_BIT 2681#define PLLX_IDDQ_BIT 382#define PLLRE_IDDQ_BIT 1683#define PLLSS_IDDQ_BIT 198485#define PLL_LOCK_TIMEOUT 50008687/* Post divider <-> register value mapping. */88struct pdiv_table {89uint32_t divider; /* real divider */90uint32_t value; /* register value */91};9293/* Bits definition of M, N and P fields. */94struct mnp_bits {95uint32_t m_width;96uint32_t n_width;97uint32_t p_width;98uint32_t p_shift;99};100101struct clk_pll_def {102struct clknode_init_def clkdef;103enum pll_type type;104uint32_t base_reg;105uint32_t misc_reg;106uint32_t lock_mask;107uint32_t lock_enable;108uint32_t iddq_reg;109uint32_t iddq_mask;110uint32_t flags;111struct pdiv_table *pdiv_table;112struct mnp_bits mnp_bits;113};114115#define PLL(_id, cname, pname) \116.clkdef.id = _id, \117.clkdef.name = cname, \118.clkdef.parent_names = (const char *[]){pname}, \119.clkdef.parent_cnt = 1, \120.clkdef.flags = CLK_NODE_STATIC_STRINGS121122/* Tegra K1 PLLs123PLLM: Clock source for EMC 2x clock124PLLX: Clock source for the fast CPU cluster and the shadow CPU125PLLC: Clock source for general use126PLLC2: Clock source for engine scaling127PLLC3: Clock source for engine scaling128PLLC4: Clock source for ISP/VI units129PLLP: Clock source for most peripherals130PLLA: Audio clock sources: (11.2896 MHz, 12.288 MHz, 24.576 MHz)131PLLU: Clock source for USB PHY, provides 12/60/480 MHz132PLLD: Clock sources for the DSI and display subsystem133PLLD2: Clock sources for the DSI and display subsystem134refPLLe:135PLLE: generate the 100 MHz reference clock for USB 3.0 (spread spectrum)136PLLDP: Clock source for eDP/LVDS (spread spectrum)137138DFLLCPU: DFLL clock source for the fast CPU cluster139GPCPLL: Clock source for the GPU140*/141142static struct pdiv_table pllm_map[] = {143{1, 0},144{2, 1},145{0, 0}146};147148static struct pdiv_table pllxc_map[] = {149{ 1, 0},150{ 2, 1},151{ 3, 2},152{ 4, 3},153{ 5, 4},154{ 6, 5},155{ 8, 6},156{10, 7},157{12, 8},158{16, 9},159{12, 10},160{16, 11},161{20, 12},162{24, 13},163{32, 14},164{ 0, 0}165};166167static struct pdiv_table pllc_map[] = {168{ 1, 0},169{ 2, 1},170{ 3, 2},171{ 4, 3},172{ 6, 4},173{ 8, 5},174{12, 6},175{16, 7},176{ 0, 0}177};178179static struct pdiv_table pll12g_ssd_esd_map[] = {180{ 1, 0},181{ 2, 1},182{ 3, 2},183{ 4, 3},184{ 5, 4},185{ 6, 5},186{ 8, 6},187{10, 7},188{12, 8},189{16, 9},190{12, 10},191{16, 11},192{20, 12},193{24, 13},194{32, 14},195{ 0, 0}196};197198static struct pdiv_table pllu_map[] = {199{1, 1},200{2, 0},201{0, 0}202};203204static struct pdiv_table pllrefe_map[] = {205{1, 0},206{2, 1},207{3, 2},208{4, 3},209{5, 4},210{6, 5},211{0, 0},212};213214static struct clk_pll_def pll_clks[] = {215/* PLLM: 880 MHz Clock source for EMC 2x clock */216{217PLL(TEGRA124_CLK_PLL_M, "pllM_out0", "osc_div_clk"),218.type = PLL_M,219.base_reg = PLLM_BASE,220.misc_reg = PLLM_MISC,221.lock_mask = PLL_BASE_LOCK,222.lock_enable = PLL_MISC_LOCK_ENABLE,223.pdiv_table = pllm_map,224.mnp_bits = {8, 8, 1, 20},225},226/* PLLX: 1GHz Clock source for the fast CPU cluster and the shadow CPU */227{228PLL(TEGRA124_CLK_PLL_X, "pllX_out", "osc_div_clk"),229.type = PLL_X,230.base_reg = PLLX_BASE,231.misc_reg = PLLX_MISC,232.lock_mask = PLL_BASE_LOCK,233.lock_enable = PLL_MISC_LOCK_ENABLE,234.iddq_reg = PLLX_MISC3,235.iddq_mask = 1 << PLLX_IDDQ_BIT,236.pdiv_table = pllxc_map,237.mnp_bits = {8, 8, 4, 20},238},239/* PLLC: 600 MHz Clock source for general use */240{241PLL(TEGRA124_CLK_PLL_C, "pllC_out0", "osc_div_clk"),242.type = PLL_C,243.base_reg = PLLC_BASE,244.misc_reg = PLLC_MISC,245.lock_mask = PLL_BASE_LOCK,246.lock_enable = PLLC_MISC_LOCK_ENABLE,247.iddq_reg = PLLC_MISC,248.iddq_mask = 1 << PLLC_IDDQ_BIT,249.pdiv_table = pllc_map,250.mnp_bits = {8, 8, 4, 20},251},252/* PLLC2: 600 MHz Clock source for engine scaling */253{254PLL(TEGRA124_CLK_PLL_C2, "pllC2_out0", "osc_div_clk"),255.type = PLL_C2,256.base_reg = PLLC2_BASE,257.misc_reg = PLLC2_MISC,258.lock_mask = PLL_BASE_LOCK,259.lock_enable = PLL_MISC_LOCK_ENABLE,260.pdiv_table = pllc_map,261.mnp_bits = {2, 8, 3, 20},262},263/* PLLC3: 600 MHz Clock source for engine scaling */264{265PLL(TEGRA124_CLK_PLL_C3, "pllC3_out0", "osc_div_clk"),266.type = PLL_C3,267.base_reg = PLLC3_BASE,268.misc_reg = PLLC3_MISC,269.lock_mask = PLL_BASE_LOCK,270.lock_enable = PLL_MISC_LOCK_ENABLE,271.pdiv_table = pllc_map,272.mnp_bits = {2, 8, 3, 20},273},274/* PLLC4: 600 MHz Clock source for ISP/VI units */275{276PLL(TEGRA124_CLK_PLL_C4, "pllC4_out0", "pllC4_src"),277.type = PLL_C4,278.base_reg = PLLC4_BASE,279.misc_reg = PLLC4_MISC,280.lock_mask = PLL_BASE_LOCK,281.lock_enable = PLLSS_MISC_LOCK_ENABLE,282.iddq_reg = PLLC4_BASE,283.iddq_mask = 1 << PLLSS_IDDQ_BIT,284.pdiv_table = pll12g_ssd_esd_map,285.mnp_bits = {8, 8, 4, 20},286},287/* PLLP: 408 MHz Clock source for most peripherals */288{289PLL(TEGRA124_CLK_PLL_P, "pllP_out0", "osc_div_clk"),290.type = PLL_P,291.base_reg = PLLP_BASE,292.misc_reg = PLLP_MISC,293.lock_mask = PLL_BASE_LOCK,294.lock_enable = PLL_MISC_LOCK_ENABLE,295.mnp_bits = {5, 10, 3, 20},296},297/* PLLA: Audio clock sources: (11.2896 MHz, 12.288 MHz, 24.576 MHz) */298{299PLL(TEGRA124_CLK_PLL_A, "pllA_out", "pllP_out1"),300.type = PLL_A,301.base_reg = PLLA_BASE,302.misc_reg = PLLA_MISC,303.lock_mask = PLL_BASE_LOCK,304.lock_enable = PLL_MISC_LOCK_ENABLE,305.mnp_bits = {5, 10, 3, 20},306},307/* PLLU: 480 MHz Clock source for USB PHY, provides 12/60/480 MHz */308{309PLL(TEGRA124_CLK_PLL_U, "pllU_out", "osc_div_clk"),310.type = PLL_U,311.base_reg = PLLU_BASE,312.misc_reg = PLLU_MISC,313.lock_mask = PLL_BASE_LOCK,314.lock_enable = PLLDU_MISC_LOCK_ENABLE,315.pdiv_table = pllu_map,316.mnp_bits = {5, 10, 1, 20},317},318/* PLLD: 600 MHz Clock sources for the DSI and display subsystem */319{320PLL(TEGRA124_CLK_PLL_D, "pllD_out", "osc_div_clk"),321.type = PLL_D,322.base_reg = PLLD_BASE,323.misc_reg = PLLD_MISC,324.lock_mask = PLL_BASE_LOCK,325.lock_enable = PLL_MISC_LOCK_ENABLE,326.mnp_bits = {5, 11, 3, 20},327},328/* PLLD2: 600 MHz Clock sources for the DSI and display subsystem */329{330PLL(TEGRA124_CLK_PLL_D2, "pllD2_out", "pllD2_src"),331.type = PLL_D2,332.base_reg = PLLD2_BASE,333.misc_reg = PLLD2_MISC,334.lock_mask = PLL_BASE_LOCK,335.lock_enable = PLLSS_MISC_LOCK_ENABLE,336.iddq_reg = PLLD2_BASE,337.iddq_mask = 1 << PLLSS_IDDQ_BIT,338.pdiv_table = pll12g_ssd_esd_map,339.mnp_bits = {8, 8, 4, 20},340},341/* refPLLe: */342{343PLL(0, "pllREFE_out", "osc_div_clk"),344.type = PLL_REFE,345.base_reg = PLLRE_BASE,346.misc_reg = PLLRE_MISC,347.lock_mask = PLLRE_MISC_LOCK,348.lock_enable = PLLRE_MISC_LOCK_ENABLE,349.iddq_reg = PLLRE_MISC,350.iddq_mask = 1 << PLLRE_IDDQ_BIT,351.pdiv_table = pllrefe_map,352.mnp_bits = {8, 8, 4, 16},353},354/* PLLE: generate the 100 MHz reference clock for USB 3.0 (spread spectrum) */355{356PLL(TEGRA124_CLK_PLL_E, "pllE_out0", "pllE_src"),357.type = PLL_E,358.base_reg = PLLE_BASE,359.misc_reg = PLLE_MISC,360.lock_mask = PLLE_MISC_LOCK,361.lock_enable = PLLE_MISC_LOCK_ENABLE,362.mnp_bits = {8, 8, 4, 24},363},364/* PLLDP: 600 MHz Clock source for eDP/LVDS (spread spectrum) */365{366PLL(0, "pllDP_out0", "pllDP_src"),367.type = PLL_DP,368.base_reg = PLLDP_BASE,369.misc_reg = PLLDP_MISC,370.lock_mask = PLL_BASE_LOCK,371.lock_enable = PLLSS_MISC_LOCK_ENABLE,372.iddq_reg = PLLDP_BASE,373.iddq_mask = 1 << PLLSS_IDDQ_BIT,374.pdiv_table = pll12g_ssd_esd_map,375.mnp_bits = {8, 8, 4, 20},376},377};378379static int tegra124_pll_init(struct clknode *clk, device_t dev);380static int tegra124_pll_set_gate(struct clknode *clk, bool enable);381static int tegra124_pll_get_gate(struct clknode *clk, bool *enabled);382static int tegra124_pll_recalc(struct clknode *clk, uint64_t *freq);383static int tegra124_pll_set_freq(struct clknode *clknode, uint64_t fin,384uint64_t *fout, int flags, int *stop);385struct pll_sc {386device_t clkdev;387enum pll_type type;388uint32_t base_reg;389uint32_t misc_reg;390uint32_t lock_mask;391uint32_t lock_enable;392uint32_t iddq_reg;393uint32_t iddq_mask;394uint32_t flags;395struct pdiv_table *pdiv_table;396struct mnp_bits mnp_bits;397};398399static clknode_method_t tegra124_pll_methods[] = {400/* Device interface */401CLKNODEMETHOD(clknode_init, tegra124_pll_init),402CLKNODEMETHOD(clknode_set_gate, tegra124_pll_set_gate),403CLKNODEMETHOD(clknode_get_gate, tegra124_pll_get_gate),404CLKNODEMETHOD(clknode_recalc_freq, tegra124_pll_recalc),405CLKNODEMETHOD(clknode_set_freq, tegra124_pll_set_freq),406CLKNODEMETHOD_END407};408DEFINE_CLASS_1(tegra124_pll, tegra124_pll_class, tegra124_pll_methods,409sizeof(struct pll_sc), clknode_class);410411static int412pll_enable(struct pll_sc *sc)413{414uint32_t reg;415416RD4(sc, sc->base_reg, ®);417if (sc->type != PLL_E)418reg &= ~PLL_BASE_BYPASS;419reg |= PLL_BASE_ENABLE;420WR4(sc, sc->base_reg, reg);421return (0);422}423424static int425pll_disable(struct pll_sc *sc)426{427uint32_t reg;428429RD4(sc, sc->base_reg, ®);430if (sc->type != PLL_E)431reg |= PLL_BASE_BYPASS;432reg &= ~PLL_BASE_ENABLE;433WR4(sc, sc->base_reg, reg);434return (0);435}436437static uint32_t438pdiv_to_reg(struct pll_sc *sc, uint32_t p_div)439{440struct pdiv_table *tbl;441442tbl = sc->pdiv_table;443if (tbl == NULL)444return (ffs(p_div) - 1);445446while (tbl->divider != 0) {447if (p_div <= tbl->divider)448return (tbl->value);449tbl++;450}451return (0xFFFFFFFF);452}453454static uint32_t455reg_to_pdiv(struct pll_sc *sc, uint32_t reg)456{457struct pdiv_table *tbl;458459tbl = sc->pdiv_table;460if (tbl == NULL)461return (1 << reg);462463while (tbl->divider) {464if (reg == tbl->value)465return (tbl->divider);466tbl++;467}468return (0);469}470471static uint32_t472get_masked(uint32_t val, uint32_t shift, uint32_t width)473{474475return ((val >> shift) & ((1 << width) - 1));476}477478static uint32_t479set_masked(uint32_t val, uint32_t v, uint32_t shift, uint32_t width)480{481482val &= ~(((1 << width) - 1) << shift);483val |= (v & ((1 << width) - 1)) << shift;484return (val);485}486487static void488get_divisors(struct pll_sc *sc, uint32_t *m, uint32_t *n, uint32_t *p)489{490uint32_t val;491struct mnp_bits *mnp_bits;492493mnp_bits = &sc->mnp_bits;494RD4(sc, sc->base_reg, &val);495*m = get_masked(val, PLL_BASE_DIVM_SHIFT, mnp_bits->m_width);496*n = get_masked(val, PLL_BASE_DIVN_SHIFT, mnp_bits->n_width);497*p = get_masked(val, mnp_bits->p_shift, mnp_bits->p_width);498}499500static uint32_t501set_divisors(struct pll_sc *sc, uint32_t val, uint32_t m, uint32_t n,502uint32_t p)503{504struct mnp_bits *mnp_bits;505506mnp_bits = &sc->mnp_bits;507val = set_masked(val, m, PLL_BASE_DIVM_SHIFT, mnp_bits->m_width);508val = set_masked(val, n, PLL_BASE_DIVN_SHIFT, mnp_bits->n_width);509val = set_masked(val, p, mnp_bits->p_shift, mnp_bits->p_width);510return (val);511}512513static bool514is_locked(struct pll_sc *sc)515{516uint32_t reg;517518switch (sc->type) {519case PLL_REFE:520RD4(sc, sc->misc_reg, ®);521reg &= PLLRE_MISC_LOCK;522break;523524case PLL_E:525RD4(sc, sc->misc_reg, ®);526reg &= PLLE_MISC_LOCK;527break;528529default:530RD4(sc, sc->base_reg, ®);531reg &= PLL_BASE_LOCK;532break;533}534return (reg != 0);535}536537static int538wait_for_lock(struct pll_sc *sc)539{540int i;541542for (i = PLL_LOCK_TIMEOUT / 10; i > 0; i--) {543if (is_locked(sc))544break;545DELAY(10);546}547if (i <= 0) {548printf("PLL lock timeout\n");549return (ETIMEDOUT);550}551return (0);552}553554static int555plle_enable(struct pll_sc *sc)556{557uint32_t reg;558int rv;559uint32_t pll_m = 1;560uint32_t pll_n = 200;561uint32_t pll_p = 13;562uint32_t pll_cml = 13;563564/* Disable lock override. */565RD4(sc, sc->base_reg, ®);566reg &= ~PLLE_BASE_LOCK_OVERRIDE;567WR4(sc, sc->base_reg, reg);568569RD4(sc, PLLE_AUX, ®);570reg |= PLLE_AUX_ENABLE_SWCTL;571reg &= ~PLLE_AUX_SEQ_ENABLE;572WR4(sc, PLLE_AUX, reg);573DELAY(10);574575RD4(sc, sc->misc_reg, ®);576reg |= PLLE_MISC_LOCK_ENABLE;577reg |= PLLE_MISC_IDDQ_SWCTL;578reg &= ~PLLE_MISC_IDDQ_OVERRIDE_VALUE;579reg |= PLLE_MISC_PTS;580reg |= PLLE_MISC_VREG_BG_CTRL_MASK;581reg |= PLLE_MISC_VREG_CTRL_MASK;582WR4(sc, sc->misc_reg, reg);583DELAY(10);584585RD4(sc, PLLE_SS_CNTL, ®);586reg |= PLLE_SS_CNTL_DISABLE;587WR4(sc, PLLE_SS_CNTL, reg);588589RD4(sc, sc->base_reg, ®);590reg = set_divisors(sc, reg, pll_m, pll_n, pll_p);591reg &= ~(PLLE_BASE_DIVCML_MASK << PLLE_BASE_DIVCML_SHIFT);592reg |= pll_cml << PLLE_BASE_DIVCML_SHIFT;593WR4(sc, sc->base_reg, reg);594DELAY(10);595596pll_enable(sc);597rv = wait_for_lock(sc);598if (rv != 0)599return (rv);600601RD4(sc, PLLE_SS_CNTL, ®);602reg &= ~PLLE_SS_CNTL_SSCCENTER;603reg &= ~PLLE_SS_CNTL_SSCINVERT;604reg &= ~PLLE_SS_CNTL_COEFFICIENTS_MASK;605reg |= PLLE_SS_CNTL_COEFFICIENTS_VAL;606WR4(sc, PLLE_SS_CNTL, reg);607reg &= ~PLLE_SS_CNTL_SSCBYP;608reg &= ~PLLE_SS_CNTL_BYPASS_SS;609WR4(sc, PLLE_SS_CNTL, reg);610DELAY(10);611612reg &= ~PLLE_SS_CNTL_INTERP_RESET;613WR4(sc, PLLE_SS_CNTL, reg);614DELAY(10);615616/* HW control of brick pll. */617RD4(sc, sc->misc_reg, ®);618reg &= ~PLLE_MISC_IDDQ_SWCTL;619WR4(sc, sc->misc_reg, reg);620621RD4(sc, PLLE_AUX, ®);622reg |= PLLE_AUX_USE_LOCKDET;623reg |= PLLE_AUX_SEQ_START_STATE;624reg &= ~PLLE_AUX_ENABLE_SWCTL;625reg &= ~PLLE_AUX_SS_SWCTL;626WR4(sc, PLLE_AUX, reg);627reg |= PLLE_AUX_SEQ_START_STATE;628DELAY(10);629reg |= PLLE_AUX_SEQ_ENABLE;630WR4(sc, PLLE_AUX, reg);631632RD4(sc, XUSBIO_PLL_CFG0, ®);633reg |= XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET;634reg |= XUSBIO_PLL_CFG0_SEQ_START_STATE;635reg &= ~XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL;636reg &= ~XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL;637WR4(sc, XUSBIO_PLL_CFG0, reg);638DELAY(10);639640reg |= XUSBIO_PLL_CFG0_SEQ_ENABLE;641WR4(sc, XUSBIO_PLL_CFG0, reg);642643/* Enable HW control and unreset SATA PLL. */644RD4(sc, SATA_PLL_CFG0, ®);645reg &= ~SATA_PLL_CFG0_PADPLL_RESET_SWCTL;646reg &= ~SATA_PLL_CFG0_PADPLL_RESET_OVERRIDE_VALUE;647reg |= SATA_PLL_CFG0_PADPLL_USE_LOCKDET;648reg &= ~SATA_PLL_CFG0_SEQ_IN_SWCTL;649reg &= ~SATA_PLL_CFG0_SEQ_RESET_INPUT_VALUE;650reg &= ~SATA_PLL_CFG0_SEQ_LANE_PD_INPUT_VALUE;651reg &= ~SATA_PLL_CFG0_SEQ_PADPLL_PD_INPUT_VALUE;652reg &= ~SATA_PLL_CFG0_SEQ_ENABLE;653reg |= SATA_PLL_CFG0_SEQ_START_STATE;654WR4(sc, SATA_PLL_CFG0, reg);655DELAY(10);656reg |= SATA_PLL_CFG0_SEQ_ENABLE;657WR4(sc, SATA_PLL_CFG0, reg);658659/* Enable HW control of PCIe PLL. */660RD4(sc, PCIE_PLL_CFG0, ®);661reg |= PCIE_PLL_CFG0_SEQ_ENABLE;662WR4(sc, PCIE_PLL_CFG0, reg);663664return (0);665}666667static int668tegra124_pll_set_gate(struct clknode *clknode, bool enable)669{670int rv;671struct pll_sc *sc;672673sc = clknode_get_softc(clknode);674if (enable == 0) {675rv = pll_disable(sc);676return(rv);677}678679if (sc->type == PLL_E)680rv = plle_enable(sc);681else682rv = pll_enable(sc);683return (rv);684}685686static int687tegra124_pll_get_gate(struct clknode *clknode, bool *enabled)688{689uint32_t reg;690struct pll_sc *sc;691692sc = clknode_get_softc(clknode);693RD4(sc, sc->base_reg, ®);694*enabled = reg & PLL_BASE_ENABLE ? true: false;695WR4(sc, sc->base_reg, reg);696return (0);697}698699static int700pll_set_std(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags,701uint32_t m, uint32_t n, uint32_t p)702{703uint32_t reg;704struct mnp_bits *mnp_bits;705int rv;706707mnp_bits = &sc->mnp_bits;708if (m >= (1 << mnp_bits->m_width))709return (ERANGE);710if (n >= (1 << mnp_bits->n_width))711return (ERANGE);712if (pdiv_to_reg(sc, p) >= (1 << mnp_bits->p_width))713return (ERANGE);714715if (flags & CLK_SET_DRYRUN) {716if (((flags & (CLK_SET_ROUND_UP | CLK_SET_ROUND_DOWN)) == 0) &&717(*fout != (((fin / m) * n) /p)))718return (ERANGE);719720*fout = ((fin / m) * n) /p;721722return (0);723}724725pll_disable(sc);726727/* take pll out of IDDQ */728if (sc->iddq_reg != 0)729MD4(sc, sc->iddq_reg, sc->iddq_mask, 0);730731RD4(sc, sc->base_reg, ®);732reg = set_masked(reg, m, PLL_BASE_DIVM_SHIFT, mnp_bits->m_width);733reg = set_masked(reg, n, PLL_BASE_DIVN_SHIFT, mnp_bits->n_width);734reg = set_masked(reg, pdiv_to_reg(sc, p), mnp_bits->p_shift,735mnp_bits->p_width);736WR4(sc, sc->base_reg, reg);737738/* Enable PLL. */739RD4(sc, sc->base_reg, ®);740reg |= PLL_BASE_ENABLE;741WR4(sc, sc->base_reg, reg);742743/* Enable lock detection. */744RD4(sc, sc->misc_reg, ®);745reg |= sc->lock_enable;746WR4(sc, sc->misc_reg, reg);747748rv = wait_for_lock(sc);749if (rv != 0) {750/* Disable PLL */751RD4(sc, sc->base_reg, ®);752reg &= ~PLL_BASE_ENABLE;753WR4(sc, sc->base_reg, reg);754return (rv);755}756RD4(sc, sc->misc_reg, ®);757758pll_enable(sc);759*fout = ((fin / m) * n) / p;760return 0;761}762763static int764plla_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags)765{766uint32_t m, n, p;767768p = 1;769m = 5;770n = (*fout * p * m + fin / 2)/ fin;771dprintf("%s: m: %d, n: %d, p: %d\n", __func__, m, n, p);772return (pll_set_std(sc, fin, fout, flags, m, n, p));773}774775static int776pllc_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags)777{778uint32_t m, n, p;779780p = 2;781m = 1;782n = (*fout * p * m + fin / 2)/ fin;783dprintf("%s: m: %d, n: %d, p: %d\n", __func__, m, n, p);784return (pll_set_std( sc, fin, fout, flags, m, n, p));785}786787/*788* PLLD2 is used as source for pixel clock for HDMI.789* We must be able to set it frequency very flexibly and790* precisely (within 5% tolerance limit allowed by HDMI specs).791*792* For this reason, it is necessary to search the full state space.793* Fortunately, thanks to early cycle terminations, performance794* is within acceptable limits.795*/796#define PLLD2_PFD_MIN 12000000 /* 12 MHz */797#define PLLD2_PFD_MAX 38000000 /* 38 MHz */798#define PLLD2_VCO_MIN 600000000 /* 600 MHz */799#define PLLD2_VCO_MAX 1200000000 /* 1.2 GHz */800801static int802plld2_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags)803{804uint32_t m, n, p;805uint32_t best_m, best_n, best_p;806uint64_t vco, pfd;807int64_t err, best_err;808struct mnp_bits *mnp_bits;809struct pdiv_table *tbl;810int p_idx, rv;811812mnp_bits = &sc->mnp_bits;813tbl = sc->pdiv_table;814best_err = INT64_MAX;815816for (p_idx = 0; tbl[p_idx].divider != 0; p_idx++) {817p = tbl[p_idx].divider;818819/* Check constraints */820vco = *fout * p;821if (vco < PLLD2_VCO_MIN)822continue;823if (vco > PLLD2_VCO_MAX)824break;825826for (m = 1; m < (1 << mnp_bits->m_width); m++) {827n = (*fout * p * m + fin / 2) / fin;828829/* Check constraints */830if (n == 0)831continue;832if (n >= (1 << mnp_bits->n_width))833break;834vco = (fin * n) / m;835if (vco > PLLD2_VCO_MAX || vco < PLLD2_VCO_MIN)836continue;837pfd = fin / m;838if (pfd > PLLD2_PFD_MAX || vco < PLLD2_PFD_MIN)839continue;840841/* Constraints passed, save best result */842err = *fout - vco / p;843if (err < 0)844err = -err;845if (err < best_err) {846best_err = err;847best_p = p;848best_m = m;849best_n = n;850}851if (err == 0)852goto done;853}854}855done:856/*857* HDMI specification allows 5% pixel clock tolerance,858* we will by a slightly stricter859*/860if (best_err > ((*fout * 100) / 4))861return (ERANGE);862863if (flags & CLK_SET_DRYRUN)864return (0);865rv = pll_set_std(sc, fin, fout, flags, best_m, best_n, best_p);866/* XXXX Panic for rv == ERANGE ? */867return (rv);868}869870static int871pllrefe_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags)872{873uint32_t m, n, p;874875m = 1;876p = 1;877n = *fout * p * m / fin;878dprintf("%s: m: %d, n: %d, p: %d\n", __func__, m, n, p);879return (pll_set_std(sc, fin, fout, flags, m, n, p));880}881882static int883pllx_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags)884{885uint32_t reg;886uint32_t m, n, p;887struct mnp_bits *mnp_bits;888int rv;889890mnp_bits = &sc->mnp_bits;891892p = 1;893m = 1;894n = (*fout * p * m + fin / 2)/ fin;895dprintf("%s: m: %d, n: %d, p: %d\n", __func__, m, n, p);896897if (m >= (1 << mnp_bits->m_width))898return (ERANGE);899if (n >= (1 << mnp_bits->n_width))900return (ERANGE);901if (pdiv_to_reg(sc, p) >= (1 << mnp_bits->p_width))902return (ERANGE);903904if (flags & CLK_SET_DRYRUN) {905if (((flags & (CLK_SET_ROUND_UP | CLK_SET_ROUND_DOWN)) == 0) &&906(*fout != (((fin / m) * n) /p)))907return (ERANGE);908*fout = ((fin / m) * n) /p;909return (0);910}911912/* PLLX doesn't have bypass, disable it first. */913RD4(sc, sc->base_reg, ®);914reg &= ~PLL_BASE_ENABLE;915WR4(sc, sc->base_reg, reg);916917/* Set PLL. */918RD4(sc, sc->base_reg, ®);919reg = set_masked(reg, m, PLL_BASE_DIVM_SHIFT, mnp_bits->m_width);920reg = set_masked(reg, n, PLL_BASE_DIVN_SHIFT, mnp_bits->n_width);921reg = set_masked(reg, pdiv_to_reg(sc, p), mnp_bits->p_shift,922mnp_bits->p_width);923WR4(sc, sc->base_reg, reg);924RD4(sc, sc->base_reg, ®);925DELAY(100);926927/* Enable lock detection. */928RD4(sc, sc->misc_reg, ®);929reg |= sc->lock_enable;930WR4(sc, sc->misc_reg, reg);931932/* Enable PLL. */933RD4(sc, sc->base_reg, ®);934reg |= PLL_BASE_ENABLE;935WR4(sc, sc->base_reg, reg);936937rv = wait_for_lock(sc);938if (rv != 0) {939/* Disable PLL */940RD4(sc, sc->base_reg, ®);941reg &= ~PLL_BASE_ENABLE;942WR4(sc, sc->base_reg, reg);943return (rv);944}945RD4(sc, sc->misc_reg, ®);946947*fout = ((fin / m) * n) / p;948return (0);949}950951static int952tegra124_pll_set_freq(struct clknode *clknode, uint64_t fin, uint64_t *fout,953int flags, int *stop)954{955*stop = 1;956int rv;957struct pll_sc *sc;958959sc = clknode_get_softc(clknode);960dprintf("%s: %s requested freq: %llu, input freq: %llu\n", __func__,961clknode_get_name(clknode), *fout, fin);962switch (sc->type) {963case PLL_A:964rv = plla_set_freq(sc, fin, fout, flags);965break;966case PLL_C:967rv = pllc_set_freq(sc, fin, fout, flags);968break;969case PLL_D2:970rv = plld2_set_freq(sc, fin, fout, flags);971break;972973case PLL_REFE:974rv = pllrefe_set_freq(sc, fin, fout, flags);975break;976977case PLL_X:978rv = pllx_set_freq(sc, fin, fout, flags);979break;980981case PLL_U:982if (*fout == 480000000) /* PLLU is fixed to 480 MHz */983rv = 0;984else985rv = ERANGE;986break;987default:988rv = ENXIO;989break;990}991992return (rv);993}994995static int996tegra124_pll_init(struct clknode *clk, device_t dev)997{998struct pll_sc *sc;999uint32_t reg;10001001sc = clknode_get_softc(clk);10021003/* If PLL is enabled, enable lock detect too. */1004RD4(sc, sc->base_reg, ®);1005if (reg & PLL_BASE_ENABLE) {1006RD4(sc, sc->misc_reg, ®);1007reg |= sc->lock_enable;1008WR4(sc, sc->misc_reg, reg);1009}1010if (sc->type == PLL_REFE) {1011RD4(sc, sc->misc_reg, ®);1012reg &= ~(1 << 29); /* Diasble lock override */1013WR4(sc, sc->misc_reg, reg);1014}10151016clknode_init_parent_idx(clk, 0);1017return(0);1018}10191020static int1021tegra124_pll_recalc(struct clknode *clk, uint64_t *freq)1022{1023struct pll_sc *sc;1024uint32_t m, n, p, pr;1025uint32_t reg, misc_reg;10261027sc = clknode_get_softc(clk);10281029RD4(sc, sc->base_reg, ®);1030RD4(sc, sc->misc_reg, &misc_reg);10311032get_divisors(sc, &m, &n, &pr);1033if (sc->type != PLL_E)1034p = reg_to_pdiv(sc, pr);1035else1036p = 2 * (pr - 1);10371038dprintf("%s: %s (0x%08x, 0x%08x) - m: %d, n: %d, p: %d (%d): "1039"e: %d, r: %d, o: %d - %s\n", __func__,1040clknode_get_name(clk), reg, misc_reg, m, n, p, pr,1041(reg >> 30) & 1, (reg >> 29) & 1, (reg >> 28) & 1,1042is_locked(sc) ? "locked" : "unlocked");10431044if ((m == 0) || (n == 0) || (p == 0)) {1045*freq = 0;1046return (EINVAL);1047}1048*freq = ((*freq / m) * n) / p;1049return (0);1050}10511052static int1053pll_register(struct clkdom *clkdom, struct clk_pll_def *clkdef)1054{1055struct clknode *clk;1056struct pll_sc *sc;10571058clk = clknode_create(clkdom, &tegra124_pll_class, &clkdef->clkdef);1059if (clk == NULL)1060return (ENXIO);10611062sc = clknode_get_softc(clk);1063sc->clkdev = clknode_get_device(clk);1064sc->type = clkdef->type;1065sc->base_reg = clkdef->base_reg;1066sc->misc_reg = clkdef->misc_reg;1067sc->lock_mask = clkdef->lock_mask;1068sc->lock_enable = clkdef->lock_enable;1069sc->iddq_reg = clkdef->iddq_reg;1070sc->iddq_mask = clkdef->iddq_mask;1071sc->flags = clkdef->flags;1072sc->pdiv_table = clkdef->pdiv_table;1073sc->mnp_bits = clkdef->mnp_bits;1074clknode_register(clkdom, clk);1075return (0);1076}10771078static void config_utmi_pll(struct tegra124_car_softc *sc)1079{1080uint32_t reg;1081/*1082* XXX Simplified UTMIP settings for 12MHz base clock.1083*/1084#define ENABLE_DELAY_COUNT 0x021085#define STABLE_COUNT 0x2F1086#define ACTIVE_DELAY_COUNT 0x041087#define XTAL_FREQ_COUNT 0x7610881089CLKDEV_READ_4(sc->dev, UTMIP_PLL_CFG2, ®);1090reg &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);1091reg |= UTMIP_PLL_CFG2_STABLE_COUNT(STABLE_COUNT);1092reg &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);1093reg |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(ACTIVE_DELAY_COUNT);1094reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN;1095reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN;1096reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN;1097CLKDEV_WRITE_4(sc->dev, UTMIP_PLL_CFG2, reg);10981099CLKDEV_READ_4(sc->dev, UTMIP_PLL_CFG1, ®);1100reg &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);1101reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(ENABLE_DELAY_COUNT);1102reg &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);1103reg |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(XTAL_FREQ_COUNT);1104reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;1105reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN;1106reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERUP;1107reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN;1108CLKDEV_WRITE_4(sc->dev, UTMIP_PLL_CFG1, reg);11091110/* Prepare UTMIP requencer. */1111CLKDEV_READ_4(sc->dev, UTMIPLL_HW_PWRDN_CFG0, ®);1112reg |= UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET;1113reg &= ~UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL;1114reg |= UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE;1115CLKDEV_WRITE_4(sc->dev, UTMIPLL_HW_PWRDN_CFG0, reg);11161117/* Powerup UTMIP. */1118CLKDEV_READ_4(sc->dev, UTMIP_PLL_CFG1, ®);1119reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;1120reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;1121CLKDEV_WRITE_4(sc->dev, UTMIP_PLL_CFG1, reg);1122DELAY(10);11231124/* SW override for UTMIPLL */1125CLKDEV_READ_4(sc->dev, UTMIPLL_HW_PWRDN_CFG0, ®);1126reg |= UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL;1127reg &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE;1128CLKDEV_WRITE_4(sc->dev, UTMIPLL_HW_PWRDN_CFG0, reg);1129DELAY(10);11301131/* HW control of UTMIPLL. */1132CLKDEV_READ_4(sc->dev, UTMIPLL_HW_PWRDN_CFG0, ®);1133reg |= UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE;1134CLKDEV_WRITE_4(sc->dev, UTMIPLL_HW_PWRDN_CFG0, reg);1135}11361137void1138tegra124_init_plls(struct tegra124_car_softc *sc)1139{1140int i, rv;11411142for (i = 0; i < nitems(pll_clks); i++) {1143rv = pll_register(sc->clkdom, pll_clks + i);1144if (rv != 0)1145panic("pll_register failed");1146}1147config_utmi_pll(sc);11481149}115011511152