static void __init berlin2q_clock_setup(struct device_node *np) { const char *parent_names[9]; struct clk *clk; int n; gbase = of_iomap(np, 0); if (!gbase) { pr_err("%s: Unable to map global base\n", np->full_name); return; } /* BG2Q CPU PLL is not part of global registers */ cpupll_base = of_iomap(np, 1); if (!cpupll_base) { pr_err("%s: Unable to map cpupll base\n", np->full_name); iounmap(gbase); return; } /* overwrite default clock names with DT provided ones */ clk = of_clk_get_by_name(np, clk_names[REFCLK]); if (!IS_ERR(clk)) { clk_names[REFCLK] = __clk_get_name(clk); clk_put(clk); } /* simple register PLLs */ clk = berlin2_pll_register(&bg2q_pll_map, gbase + REG_SYSPLLCTL0, clk_names[SYSPLL], clk_names[REFCLK], 0); if (IS_ERR(clk)) goto bg2q_fail; clk = berlin2_pll_register(&bg2q_pll_map, cpupll_base, clk_names[CPUPLL], clk_names[REFCLK], 0); if (IS_ERR(clk)) goto bg2q_fail; /* TODO: add BG2Q AVPLL */ /* * TODO: add reference clock bypass switches: * memPLLSWBypass, cpuPLLSWBypass, and sysPLLSWBypass */ /* clock divider cells */ for (n = 0; n < ARRAY_SIZE(bg2q_divs); n++) { const struct berlin2_div_data *dd = &bg2q_divs[n]; int k; for (k = 0; k < dd->num_parents; k++) parent_names[k] = clk_names[dd->parent_ids[k]]; clks[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase, dd->name, dd->div_flags, parent_names, dd->num_parents, dd->flags, &lock); } /* clock gate cells */ for (n = 0; n < ARRAY_SIZE(bg2q_gates); n++) { const struct berlin2_gate_data *gd = &bg2q_gates[n]; clks[CLKID_GFX2DAXI + n] = clk_register_gate(NULL, gd->name, gd->parent_name, gd->flags, gbase + REG_CLKENABLE, gd->bit_idx, 0, &lock); } /* * twdclk is derived from cpu/3 * TODO: use cpupll until cpuclk is not available */ clks[CLKID_TWD] = clk_register_fixed_factor(NULL, "twd", clk_names[CPUPLL], 0, 1, 3); /* check for errors on leaf clocks */ for (n = 0; n < MAX_CLKS; n++) { if (!IS_ERR(clks[n])) continue; pr_err("%s: Unable to register leaf clock %d\n", np->full_name, n); goto bg2q_fail; } /* register clk-provider */ clk_data.clks = clks; clk_data.clk_num = MAX_CLKS; of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); return; bg2q_fail: iounmap(cpupll_base); iounmap(gbase); }
static void __init berlin2_clock_setup(struct device_node *np) { struct device_node *parent_np = of_get_parent(np); const char *parent_names[9]; struct clk *clk; struct clk_hw *hw; struct clk_hw **hws; u8 avpll_flags = 0; int n, ret; clk_data = kzalloc(struct_size(clk_data, hws, MAX_CLKS), GFP_KERNEL); if (!clk_data) return; clk_data->num = MAX_CLKS; hws = clk_data->hws; gbase = of_iomap(parent_np, 0); if (!gbase) return; /* overwrite default clock names with DT provided ones */ clk = of_clk_get_by_name(np, clk_names[REFCLK]); if (!IS_ERR(clk)) { clk_names[REFCLK] = __clk_get_name(clk); clk_put(clk); } clk = of_clk_get_by_name(np, clk_names[VIDEO_EXT0]); if (!IS_ERR(clk)) { clk_names[VIDEO_EXT0] = __clk_get_name(clk); clk_put(clk); } /* simple register PLLs */ ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_SYSPLLCTL0, clk_names[SYSPLL], clk_names[REFCLK], 0); if (ret) goto bg2_fail; ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_MEMPLLCTL0, clk_names[MEMPLL], clk_names[REFCLK], 0); if (ret) goto bg2_fail; ret = berlin2_pll_register(&bg2_pll_map, gbase + REG_CPUPLLCTL0, clk_names[CPUPLL], clk_names[REFCLK], 0); if (ret) goto bg2_fail; if (of_device_is_compatible(np, "marvell,berlin2-global-register")) avpll_flags |= BERLIN2_AVPLL_SCRAMBLE_QUIRK; /* audio/video VCOs */ ret = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL0, "avpll_vcoA", clk_names[REFCLK], avpll_flags, 0); if (ret) goto bg2_fail; for (n = 0; n < 8; n++) { ret = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL0, clk_names[AVPLL_A1 + n], n, "avpll_vcoA", avpll_flags, 0); if (ret) goto bg2_fail; } ret = berlin2_avpll_vco_register(gbase + REG_AVPLLCTL31, "avpll_vcoB", clk_names[REFCLK], BERLIN2_AVPLL_BIT_QUIRK | avpll_flags, 0); if (ret) goto bg2_fail; for (n = 0; n < 8; n++) { ret = berlin2_avpll_channel_register(gbase + REG_AVPLLCTL31, clk_names[AVPLL_B1 + n], n, "avpll_vcoB", BERLIN2_AVPLL_BIT_QUIRK | avpll_flags, 0); if (ret) goto bg2_fail; } /* reference clock bypass switches */ parent_names[0] = clk_names[SYSPLL]; parent_names[1] = clk_names[REFCLK]; hw = clk_hw_register_mux(NULL, "syspll_byp", parent_names, 2, 0, gbase + REG_CLKSWITCH0, 0, 1, 0, &lock); if (IS_ERR(hw)) goto bg2_fail; clk_names[SYSPLL] = clk_hw_get_name(hw); parent_names[0] = clk_names[MEMPLL]; parent_names[1] = clk_names[REFCLK]; hw = clk_hw_register_mux(NULL, "mempll_byp", parent_names, 2, 0, gbase + REG_CLKSWITCH0, 1, 1, 0, &lock); if (IS_ERR(hw)) goto bg2_fail; clk_names[MEMPLL] = clk_hw_get_name(hw); parent_names[0] = clk_names[CPUPLL]; parent_names[1] = clk_names[REFCLK]; hw = clk_hw_register_mux(NULL, "cpupll_byp", parent_names, 2, 0, gbase + REG_CLKSWITCH0, 2, 1, 0, &lock); if (IS_ERR(hw)) goto bg2_fail; clk_names[CPUPLL] = clk_hw_get_name(hw); /* clock muxes */ parent_names[0] = clk_names[AVPLL_B3]; parent_names[1] = clk_names[AVPLL_A3]; hw = clk_hw_register_mux(NULL, clk_names[AUDIO1_PLL], parent_names, 2, 0, gbase + REG_CLKSELECT2, 29, 1, 0, &lock); if (IS_ERR(hw)) goto bg2_fail; parent_names[0] = clk_names[VIDEO0_PLL]; parent_names[1] = clk_names[VIDEO_EXT0]; hw = clk_hw_register_mux(NULL, clk_names[VIDEO0_IN], parent_names, 2, 0, gbase + REG_CLKSELECT3, 4, 1, 0, &lock); if (IS_ERR(hw)) goto bg2_fail; parent_names[0] = clk_names[VIDEO1_PLL]; parent_names[1] = clk_names[VIDEO_EXT0]; hw = clk_hw_register_mux(NULL, clk_names[VIDEO1_IN], parent_names, 2, 0, gbase + REG_CLKSELECT3, 6, 1, 0, &lock); if (IS_ERR(hw)) goto bg2_fail; parent_names[0] = clk_names[AVPLL_A2]; parent_names[1] = clk_names[AVPLL_B2]; hw = clk_hw_register_mux(NULL, clk_names[VIDEO1_PLL], parent_names, 2, 0, gbase + REG_CLKSELECT3, 7, 1, 0, &lock); if (IS_ERR(hw)) goto bg2_fail; parent_names[0] = clk_names[VIDEO2_PLL]; parent_names[1] = clk_names[VIDEO_EXT0]; hw = clk_hw_register_mux(NULL, clk_names[VIDEO2_IN], parent_names, 2, 0, gbase + REG_CLKSELECT3, 9, 1, 0, &lock); if (IS_ERR(hw)) goto bg2_fail; parent_names[0] = clk_names[AVPLL_B1]; parent_names[1] = clk_names[AVPLL_A5]; hw = clk_hw_register_mux(NULL, clk_names[VIDEO2_PLL], parent_names, 2, 0, gbase + REG_CLKSELECT3, 10, 1, 0, &lock); if (IS_ERR(hw)) goto bg2_fail; /* clock divider cells */ for (n = 0; n < ARRAY_SIZE(bg2_divs); n++) { const struct berlin2_div_data *dd = &bg2_divs[n]; int k; for (k = 0; k < dd->num_parents; k++) parent_names[k] = clk_names[dd->parent_ids[k]]; hws[CLKID_SYS + n] = berlin2_div_register(&dd->map, gbase, dd->name, dd->div_flags, parent_names, dd->num_parents, dd->flags, &lock); } /* clock gate cells */ for (n = 0; n < ARRAY_SIZE(bg2_gates); n++) { const struct berlin2_gate_data *gd = &bg2_gates[n]; hws[CLKID_GETH0 + n] = clk_hw_register_gate(NULL, gd->name, gd->parent_name, gd->flags, gbase + REG_CLKENABLE, gd->bit_idx, 0, &lock); } /* twdclk is derived from cpu/3 */ hws[CLKID_TWD] = clk_hw_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3); /* check for errors on leaf clocks */ for (n = 0; n < MAX_CLKS; n++) { if (!IS_ERR(hws[n])) continue; pr_err("%pOF: Unable to register leaf clock %d\n", np, n); goto bg2_fail; } /* register clk-provider */ of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data); return; bg2_fail: iounmap(gbase); }