in platforms/512x/clock-commonclk.c [704:934]
static void __init mpc512x_clk_setup_clock_tree(struct device_node *np, int busfreq)
{
int sys_mul, sys_div, ips_div;
int mul, div;
size_t mclk_idx;
int freq;
/*
* developer's notes:
* - consider whether to handle clocks which have both gates and
* dividers via intermediates or by means of composites
* - fractional dividers appear to not map well to composites
* since they can be seen as a fixed multiplier and an
* adjustable divider, while composites can only combine at
* most one of a mux, div, and gate each into one 'struct clk'
* item
* - PSC/MSCAN/SPDIF clock generation OTOH already is very
* specific and cannot get mapped to composites (at least not
* a single one, maybe two of them, but then some of these
* intermediate clock signals get referenced elsewhere (e.g.
* in the clock frequency measurement, CFM) and thus need
* publicly available names
* - the current source layout appropriately reflects the
* hardware setup, and it works, so it's questionable whether
* further changes will result in big enough a benefit
*/
/* regardless of whether XTAL/OSC exists, have REF created */
mpc512x_clk_setup_ref_clock(np, busfreq, &sys_mul, &sys_div, &ips_div);
/* now setup the REF -> SYS -> CSB -> IPS hierarchy */
clks[MPC512x_CLK_SYS] = mpc512x_clk_factor("sys", "ref",
sys_mul, sys_div);
clks[MPC512x_CLK_CSB] = mpc512x_clk_factor("csb", "sys", 1, 2);
clks[MPC512x_CLK_IPS] = mpc512x_clk_divtable("ips", "csb",
&clkregs->scfr1, 23, 3,
divtab_2346);
/* now setup anything below SYS and CSB and IPS */
clks[MPC512x_CLK_DDR_UG] = mpc512x_clk_factor("ddr-ug", "sys", 1, 2);
/*
* the Reference Manual discusses that for SDHC only even divide
* ratios are supported because clock domain synchronization
* between 'per' and 'ipg' is broken;
* keep the divider's bit 0 cleared (per reset value), and only
* allow to setup the divider's bits 7:1, which results in that
* only even divide ratios can get configured upon rate changes;
* keep the "x4" name because this bit shift hack is an internal
* implementation detail, the "fractional divider with quarters"
* semantics remains
*/
clks[MPC512x_CLK_SDHC_x4] = mpc512x_clk_factor("sdhc-x4", "csb", 2, 1);
clks[MPC512x_CLK_SDHC_UG] = mpc512x_clk_divider("sdhc-ug", "sdhc-x4", 0,
&clkregs->scfr2, 1, 7,
CLK_DIVIDER_ONE_BASED);
if (soc_has_sdhc2()) {
clks[MPC512x_CLK_SDHC2_UG] = mpc512x_clk_divider(
"sdhc2-ug", "sdhc-x4", 0, &clkregs->scfr2,
9, 7, CLK_DIVIDER_ONE_BASED);
}
clks[MPC512x_CLK_DIU_x4] = mpc512x_clk_factor("diu-x4", "csb", 4, 1);
clks[MPC512x_CLK_DIU_UG] = mpc512x_clk_divider("diu-ug", "diu-x4", 0,
&clkregs->scfr1, 0, 8,
CLK_DIVIDER_ONE_BASED);
/*
* the "power architecture PLL" was setup from data which was
* sampled from the reset config word, at this point in time the
* configuration can be considered fixed and read only (i.e. no
* longer adjustable, or no longer in need of adjustment), which
* is why we don't register a PLL here but assume fixed factors
*/
mul = get_cpmf_mult_x2();
div = 2; /* compensate for the fractional factor */
clks[MPC512x_CLK_E300] = mpc512x_clk_factor("e300", "csb", mul, div);
if (soc_has_mbx()) {
clks[MPC512x_CLK_MBX_BUS_UG] = mpc512x_clk_factor(
"mbx-bus-ug", "csb", 1, 2);
clks[MPC512x_CLK_MBX_UG] = mpc512x_clk_divtable(
"mbx-ug", "mbx-bus-ug", &clkregs->scfr1,
14, 3, divtab_1234);
clks[MPC512x_CLK_MBX_3D_UG] = mpc512x_clk_factor(
"mbx-3d-ug", "mbx-ug", 1, 1);
}
if (soc_has_pci()) {
clks[MPC512x_CLK_PCI_UG] = mpc512x_clk_divtable(
"pci-ug", "csb", &clkregs->scfr1,
20, 3, divtab_2346);
}
if (soc_has_nfc_5125()) {
/*
* XXX TODO implement 5125 NFC clock setup logic,
* with high/low period counters in clkregs->scfr3,
* currently there are no users so it's ENOIMPL
*/
clks[MPC512x_CLK_NFC_UG] = ERR_PTR(-ENOTSUPP);
} else {
clks[MPC512x_CLK_NFC_UG] = mpc512x_clk_divtable(
"nfc-ug", "ips", &clkregs->scfr1,
8, 3, divtab_1234);
}
clks[MPC512x_CLK_LPC_UG] = mpc512x_clk_divtable("lpc-ug", "ips",
&clkregs->scfr1, 11, 3,
divtab_1234);
clks[MPC512x_CLK_LPC] = mpc512x_clk_gated("lpc", "lpc-ug",
&clkregs->sccr1, 30);
clks[MPC512x_CLK_NFC] = mpc512x_clk_gated("nfc", "nfc-ug",
&clkregs->sccr1, 29);
if (soc_has_pata()) {
clks[MPC512x_CLK_PATA] = mpc512x_clk_gated(
"pata", "ips", &clkregs->sccr1, 28);
}
/* for PSCs there is a "registers" gate and a bitrate MCLK subtree */
for (mclk_idx = 0; mclk_idx < soc_max_pscnum(); mclk_idx++) {
char name[12];
snprintf(name, sizeof(name), "psc%d", mclk_idx);
clks[MPC512x_CLK_PSC0 + mclk_idx] = mpc512x_clk_gated(
name, "ips", &clkregs->sccr1, 27 - mclk_idx);
mpc512x_clk_setup_mclk(&mclk_psc_data[mclk_idx], mclk_idx);
}
clks[MPC512x_CLK_PSC_FIFO] = mpc512x_clk_gated("psc-fifo", "ips",
&clkregs->sccr1, 15);
if (soc_has_sata()) {
clks[MPC512x_CLK_SATA] = mpc512x_clk_gated(
"sata", "ips", &clkregs->sccr1, 14);
}
clks[MPC512x_CLK_FEC] = mpc512x_clk_gated("fec", "ips",
&clkregs->sccr1, 13);
if (soc_has_pci()) {
clks[MPC512x_CLK_PCI] = mpc512x_clk_gated(
"pci", "pci-ug", &clkregs->sccr1, 11);
}
clks[MPC512x_CLK_DDR] = mpc512x_clk_gated("ddr", "ddr-ug",
&clkregs->sccr1, 10);
if (soc_has_fec2()) {
clks[MPC512x_CLK_FEC2] = mpc512x_clk_gated(
"fec2", "ips", &clkregs->sccr1, 9);
}
clks[MPC512x_CLK_DIU] = mpc512x_clk_gated("diu", "diu-ug",
&clkregs->sccr2, 31);
if (soc_has_axe()) {
clks[MPC512x_CLK_AXE] = mpc512x_clk_gated(
"axe", "csb", &clkregs->sccr2, 30);
}
clks[MPC512x_CLK_MEM] = mpc512x_clk_gated("mem", "ips",
&clkregs->sccr2, 29);
clks[MPC512x_CLK_USB1] = mpc512x_clk_gated("usb1", "csb",
&clkregs->sccr2, 28);
clks[MPC512x_CLK_USB2] = mpc512x_clk_gated("usb2", "csb",
&clkregs->sccr2, 27);
clks[MPC512x_CLK_I2C] = mpc512x_clk_gated("i2c", "ips",
&clkregs->sccr2, 26);
/* MSCAN differs from PSC with just one gate for multiple components */
clks[MPC512x_CLK_BDLC] = mpc512x_clk_gated("bdlc", "ips",
&clkregs->sccr2, 25);
for (mclk_idx = 0; mclk_idx < ARRAY_SIZE(mclk_mscan_data); mclk_idx++)
mpc512x_clk_setup_mclk(&mclk_mscan_data[mclk_idx], mclk_idx);
clks[MPC512x_CLK_SDHC] = mpc512x_clk_gated("sdhc", "sdhc-ug",
&clkregs->sccr2, 24);
/* there is only one SPDIF component, which shares MCLK support code */
if (soc_has_spdif()) {
clks[MPC512x_CLK_SPDIF] = mpc512x_clk_gated(
"spdif", "ips", &clkregs->sccr2, 23);
mpc512x_clk_setup_mclk(&mclk_spdif_data[0], 0);
}
if (soc_has_mbx()) {
clks[MPC512x_CLK_MBX_BUS] = mpc512x_clk_gated(
"mbx-bus", "mbx-bus-ug", &clkregs->sccr2, 22);
clks[MPC512x_CLK_MBX] = mpc512x_clk_gated(
"mbx", "mbx-ug", &clkregs->sccr2, 21);
clks[MPC512x_CLK_MBX_3D] = mpc512x_clk_gated(
"mbx-3d", "mbx-3d-ug", &clkregs->sccr2, 20);
}
clks[MPC512x_CLK_IIM] = mpc512x_clk_gated("iim", "csb",
&clkregs->sccr2, 19);
if (soc_has_viu()) {
clks[MPC512x_CLK_VIU] = mpc512x_clk_gated(
"viu", "csb", &clkregs->sccr2, 18);
}
if (soc_has_sdhc2()) {
clks[MPC512x_CLK_SDHC2] = mpc512x_clk_gated(
"sdhc-2", "sdhc2-ug", &clkregs->sccr2, 17);
}
if (soc_has_outclk()) {
size_t idx; /* used as mclk_idx, just to trim line length */
for (idx = 0; idx < ARRAY_SIZE(mclk_outclk_data); idx++)
mpc512x_clk_setup_mclk(&mclk_outclk_data[idx], idx);
}
/*
* externally provided clocks (when implemented in hardware,
* device tree may specify values which otherwise were unknown)
*/
freq = get_freq_from_dt("psc_mclk_in");
if (!freq)
freq = 25000000;
clks[MPC512x_CLK_PSC_MCLK_IN] = mpc512x_clk_fixed("psc_mclk_in", freq);
if (soc_has_mclk_mux0_canin()) {
freq = get_freq_from_dt("can_clk_in");
clks[MPC512x_CLK_CAN_CLK_IN] = mpc512x_clk_fixed(
"can_clk_in", freq);
} else {
freq = get_freq_from_dt("spdif_tx_in");
clks[MPC512x_CLK_SPDIF_TX_IN] = mpc512x_clk_fixed(
"spdif_tx_in", freq);
freq = get_freq_from_dt("spdif_rx_in");
clks[MPC512x_CLK_SPDIF_TX_IN] = mpc512x_clk_fixed(
"spdif_rx_in", freq);
}
/* fixed frequency for AC97, always 24.567MHz */
clks[MPC512x_CLK_AC97] = mpc512x_clk_fixed("ac97", 24567000);
/*
* pre-enable those "internal" clock items which never get
* claimed by any peripheral driver, to not have the clock
* subsystem disable them late at startup
*/
clk_prepare_enable(clks[MPC512x_CLK_DUMMY]);
clk_prepare_enable(clks[MPC512x_CLK_E300]); /* PowerPC CPU */
clk_prepare_enable(clks[MPC512x_CLK_DDR]); /* DRAM */
clk_prepare_enable(clks[MPC512x_CLK_MEM]); /* SRAM */
clk_prepare_enable(clks[MPC512x_CLK_IPS]); /* SoC periph */
clk_prepare_enable(clks[MPC512x_CLK_LPC]); /* boot media */
}