Fixes for NVIDIA Tegra124 clocks:
- EMC clock have standard peripheral clock block. Use it. - Implement full frequency set method for PLLD2. This PLL is used as HDMI pixel clock so we must be able to set it to wide range of frequencies, within 5% tolerance allowed by HDMI specification. Due to this, full state space search (over m, n, p fields) is necessary. MFC after: 3 weeks
This commit is contained in:
parent
3b29466b94
commit
6f1eb3052e
@ -189,8 +189,6 @@ PLIST(mux_pll_srcs) = {"osc_div_clk", NULL, "pllP_out0", NULL}; /* FIXME */
|
||||
PLIST(mux_plle_src1) = {"osc_div_clk", "pllP_out0"};
|
||||
PLIST(mux_plle_src) = {"pllE_src1", "pllREFE_out"};
|
||||
PLIST(mux_plld_out0_plld2_out0) = {"pllD_out0", "pllD2_out0"};
|
||||
PLIST(mux_pllmcp_clkm) = {"pllM_out0", "pllC_out0", "pllP_out0", "clk_m",
|
||||
"pllM_UD", "pllC2_out0", "pllC3_out0", "pllC_UD"};
|
||||
PLIST(mux_xusb_hs) = {"xusb_ss_div2", "pllU_60"};
|
||||
PLIST(mux_xusb_ss) = {"pc_xusb_ss", "osc_div_clk"};
|
||||
|
||||
@ -240,7 +238,6 @@ static struct clk_mux_def tegra124_mux_clks[] = {
|
||||
/* Base peripheral clocks. */
|
||||
MUX(0, "dsia_mux", mux_plld_out0_plld2_out0, PLLD_BASE, 25, 1),
|
||||
MUX(0, "dsib_mux", mux_plld_out0_plld2_out0, PLLD2_BASE, 25, 1),
|
||||
MUX(0, "emc_mux", mux_pllmcp_clkm, CLK_SOURCE_EMC, 29, 3),
|
||||
|
||||
/* USB. */
|
||||
MUX(TEGRA124_CLK_XUSB_HS_SRC, "xusb_hs", mux_xusb_hs, CLK_SOURCE_XUSB_SS, 25, 1),
|
||||
|
@ -126,6 +126,10 @@ PLIST(mux_m_c_p_a_c2_c3_clkm_c4) =
|
||||
PLIST(mux_m_c_p_clkm_mud_c2_c3) =
|
||||
{"pllM_out0", "pllC_out0", "pllP_out0", "clk_m",
|
||||
"pllM_UD", "pllC2_out0", "pllC3_out0"};
|
||||
PLIST(mux_m_c_p_clkm_mud_c2_c3_cud) =
|
||||
{"pllM_out0", "pllC_out0", "pllP_out0", "clk_m",
|
||||
"pllM_UD", "pllC2_out0", "pllC3_out0", "pllC_UD"};
|
||||
|
||||
PLIST(mux_m_c2_c_c3_p_N_a) =
|
||||
{"pllM_out0", "pllC2_out0", "pllC_out0", "pllC3_out0",
|
||||
"pllP_out0", NULL, "pllA_out0"};
|
||||
@ -260,7 +264,7 @@ static struct pgate_def pgate_def[] = {
|
||||
GATE(I2C2, "i2c2", "pc_i2c2", H(22)),
|
||||
GATE(UARTC, "uartc", "pc_uartc", H(23)),
|
||||
GATE(MIPI_CAL, "mipi_cal", "clk_m", H(24)),
|
||||
GATE(EMC, "emc", "emc_mux", H(25)),
|
||||
GATE(EMC, "emc", "pc_emc_2x", H(25)),
|
||||
GATE(USB2, "usb2", "clk_m", H(26)),
|
||||
GATE(USB3, "usb3", "clk_m", H(27)),
|
||||
GATE(VDE, "vde", "pc_vde", H(29)),
|
||||
@ -356,7 +360,7 @@ static struct pgate_def pgate_def[] = {
|
||||
/* GATE(CAM_MCLK, "CAM_MCLK", "clk_m", X(4)), */
|
||||
/* GATE(CAM_MCLK2, "CAM_MCLK2", "clk_m", X(5)), */
|
||||
GATE(I2C6, "i2c6", "pc_i2c6", X(6)),
|
||||
/* GATE(VIM2_CLK, "vim2_clk", clk_m, X(11)), */
|
||||
GATE(VIM2_CLK, "vim2_clk", "clk_m", X(11)),
|
||||
/* GATE(EMC_DLL, "emc_dll", "pc_emc_dll", X(14)), */
|
||||
GATE(HDMI_AUDIO, "hdmi_audio", "pc_hdmi_audio", X(16)),
|
||||
GATE(CLK72MHZ, "clk72mhz", "pc_clk72mhz", X(17)),
|
||||
@ -373,17 +377,18 @@ static struct pgate_def pgate_def[] = {
|
||||
#define DCF_HAVE_ENA 0x0200 /* Block with enable bit */
|
||||
#define DCF_HAVE_DIV 0x0400 /* Block with divider */
|
||||
|
||||
/* Mark block with additional bis / functionality. */
|
||||
/* Mark block with additional bits / functionality. */
|
||||
#define DCF_IS_MASK 0x00FF
|
||||
#define DCF_IS_UART 0x0001
|
||||
#define DCF_IS_VI 0x0002
|
||||
#define DCF_IS_HOST1X 0x0003
|
||||
#define DCF_IS_XUSB_SS 0x0004
|
||||
#define DCF_IS_EMC_DLL 0x0005
|
||||
#define FDS_IS_SATA 0x0006
|
||||
#define DCF_IS_SATA 0x0006
|
||||
#define DCF_IS_VIC 0x0007
|
||||
#define DCF_IS_AUDIO 0x0008
|
||||
#define DCF_IS_SOR0 0x0009
|
||||
#define DCF_IS_EMC 0x000A
|
||||
|
||||
/* Basic pheripheral clock */
|
||||
#define PER_CLK(_id, cn, pl, r, diw, fiw, f) \
|
||||
@ -438,7 +443,7 @@ static struct periph_def periph_def[] = {
|
||||
CLK_8_1(0, "pc_host1x", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_HOST1X, DCF_IS_HOST1X),
|
||||
CLK_8_1(0, "pc_hdmi", mux_p_m_d_a_c_d2_clkm, CLK_SOURCE_HDMI, 0),
|
||||
CLK16_0(0, "pc_i2c2", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_I2C2, 0),
|
||||
/* EMC 8 */
|
||||
CLK_8_1(0, "pc_emc_2x", mux_m_c_p_clkm_mud_c2_c3_cud, CLK_SOURCE_EMC, DCF_IS_EMC),
|
||||
CLK16_1(0, "pc_uartc", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_UARTC, DCF_IS_UART),
|
||||
CLK_8_1(0, "pc_vi_sensor", mux_m_c2_c_c3_p_N_a, CLK_SOURCE_VI_SENSOR, 0),
|
||||
CLK_8_1(0, "pc_spi4", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_SPI4, 0),
|
||||
@ -476,7 +481,7 @@ static struct periph_def periph_def[] = {
|
||||
/* SYS */
|
||||
CLK_8_1(0, "pc_sor0", mux_p_m_d_a_c_d2_clkm, CLK_SOURCE_SOR0, DCF_IS_SOR0),
|
||||
CLK_8_1(0, "pc_sata_oob", mux_p_N_c_N_m_N_clkm, CLK_SOURCE_SATA_OOB, 0),
|
||||
CLK_8_1(0, "pc_sata", mux_p_N_c_N_m_N_clkm, CLK_SOURCE_SATA, FDS_IS_SATA),
|
||||
CLK_8_1(0, "pc_sata", mux_p_N_c_N_m_N_clkm, CLK_SOURCE_SATA, DCF_IS_SATA),
|
||||
CLK_8_1(0, "pc_hda", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_HDA, 0),
|
||||
CLK_8_1(TEGRA124_CLK_XUSB_HOST_SRC,
|
||||
"pc_xusb_core_host", mux_clkm_p_c2_c_c3_refre, CLK_SOURCE_XUSB_CORE_HOST, 0),
|
||||
|
@ -713,6 +713,7 @@ pll_set_std(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags,
|
||||
return (ERANGE);
|
||||
|
||||
*fout = ((fin / m) * n) /p;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -771,7 +772,6 @@ pllc_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags)
|
||||
{
|
||||
uint32_t m, n, p;
|
||||
|
||||
|
||||
p = 2;
|
||||
m = 1;
|
||||
n = (*fout * p * m + fin / 2)/ fin;
|
||||
@ -779,20 +779,89 @@ pllc_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags)
|
||||
return (pll_set_std( sc, fin, fout, flags, m, n, p));
|
||||
}
|
||||
|
||||
/*
|
||||
* PLLD2 is used as source for pixel clock for HDMI.
|
||||
* We must be able to set it frequency very flexibly and
|
||||
* precisely (within 5% tolerance limit allowed by HDMI specs).
|
||||
*
|
||||
* For this reason, it is necessary to search the full state space.
|
||||
* Fortunately, thanks to early cycle terminations, performance
|
||||
* is within acceptable limits.
|
||||
*/
|
||||
#define PLLD2_PFD_MIN 12000000 /* 12 MHz */
|
||||
#define PLLD2_PFD_MAX 38000000 /* 38 MHz */
|
||||
#define PLLD2_VCO_MIN 600000000 /* 600 MHz */
|
||||
#define PLLD2_VCO_MAX 1200000000 /* 1.2 GHz */
|
||||
|
||||
static int
|
||||
plld2_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags)
|
||||
{
|
||||
uint32_t m, n, p;
|
||||
uint32_t best_m, best_n, best_p;
|
||||
uint64_t vco, pfd;
|
||||
int64_t err, best_err;
|
||||
struct mnp_bits *mnp_bits;
|
||||
struct pdiv_table *tbl;
|
||||
int p_idx, rv;
|
||||
|
||||
p = 2;
|
||||
m = 1;
|
||||
n = (*fout * p * m + fin / 2)/ fin;
|
||||
dprintf("%s: m: %d, n: %d, p: %d\n", __func__, m, n, p);
|
||||
return (pll_set_std(sc, fin, fout, flags, m, n, p));
|
||||
mnp_bits = &sc->mnp_bits;
|
||||
tbl = sc->pdiv_table;
|
||||
best_err = INT64_MAX;
|
||||
|
||||
for (p_idx = 0; tbl[p_idx].divider != 0; p_idx++) {
|
||||
p = tbl[p_idx].divider;
|
||||
|
||||
/* Check constraints */
|
||||
vco = *fout * p;
|
||||
if (vco < PLLD2_VCO_MIN)
|
||||
continue;
|
||||
if (vco > PLLD2_VCO_MAX)
|
||||
break;
|
||||
|
||||
for (m = 1; m < (1 << mnp_bits->m_width); m++) {
|
||||
n = (*fout * p * m + fin / 2) / fin;
|
||||
|
||||
/* Check constraints */
|
||||
if (n == 0)
|
||||
continue;
|
||||
if (n >= (1 << mnp_bits->n_width))
|
||||
break;
|
||||
vco = (fin * n) / m;
|
||||
if (vco > PLLD2_VCO_MAX || vco < PLLD2_VCO_MIN)
|
||||
continue;
|
||||
pfd = fin / m;
|
||||
if (pfd > PLLD2_PFD_MAX || vco < PLLD2_PFD_MIN)
|
||||
continue;
|
||||
|
||||
/* Constraints passed, save best result */
|
||||
err = *fout - vco / p;
|
||||
if (err < 0)
|
||||
err = -err;
|
||||
if (err < best_err) {
|
||||
best_err = err;
|
||||
best_p = p;
|
||||
best_m = m;
|
||||
best_n = n;
|
||||
}
|
||||
if (err == 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
done:
|
||||
/*
|
||||
* HDMI specification allows 5% pixel clock tolerance,
|
||||
* we will by a slightly stricter
|
||||
*/
|
||||
if (best_err > ((*fout * 100) / 4))
|
||||
return (ERANGE);
|
||||
|
||||
if (flags & CLK_SET_DRYRUN)
|
||||
return (0);
|
||||
rv = pll_set_std(sc, fin, fout, flags, best_m, best_n, best_p);
|
||||
/* XXXX Panic for rv == ERANGE ? */
|
||||
return (rv);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
pllrefe_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags)
|
||||
{
|
||||
@ -883,8 +952,8 @@ tegra124_pll_set_freq(struct clknode *clknode, uint64_t fin, uint64_t *fout,
|
||||
struct pll_sc *sc;
|
||||
|
||||
sc = clknode_get_softc(clknode);
|
||||
dprintf("%s: Requested freq: %llu, input freq: %llu\n", __func__,
|
||||
*fout, fin);
|
||||
dprintf("%s: %s requested freq: %llu, input freq: %llu\n", __func__,
|
||||
clknode_get_name(clknode), *fout, fin);
|
||||
switch (sc->type) {
|
||||
case PLL_A:
|
||||
rv = plla_set_freq(sc, fin, fout, flags);
|
||||
|
Loading…
Reference in New Issue
Block a user