/* * Copyright 2016 IBM Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ #include #include #include #include #include static void __init aspeed_of_clkin_clk_init(struct device_node *node) { struct clk *clk; void __iomem *base; int reg, rate; const char *name = node->name; of_property_read_string(node, "clock-output-names", &name); base = of_iomap(node, 0); if (!base) { pr_err("%s: of_iomap failed\n", node->full_name); return; } /* Strap register SCU70 */ reg = readl(base) & BIT(23); iounmap(base); if (reg) rate = 25 * 1000 * 1000; else rate = 24 * 1000 * 1000; clk = clk_register_fixed_rate(NULL, name, NULL, 0, rate); if (IS_ERR(clk)) { pr_err("%s: failed to register clock\n", node->full_name); return; } clk_register_clkdev(clk, NULL, name); of_clk_add_provider(node, of_clk_src_simple_get, clk); } CLK_OF_DECLARE(aspeed_clkin_clock, "aspeed,g5-clkin-clock", aspeed_of_clkin_clk_init); static void __init aspeed_of_hpll_clk_init(struct device_node *node) { struct clk *clk, *clkin_clk; void __iomem *base; int reg, rate, clkin; const char *name = node->name; const char *parent_name; of_property_read_string(node, "clock-output-names", &name); parent_name = of_clk_get_parent_name(node, 0); base = of_iomap(node, 0); if (!base) { pr_err("%s: of_iomap failed\n", node->full_name); return; } /* H-PLL parameter register SCU24 */ reg = readl(base); iounmap(base); clkin_clk = of_clk_get(node, 0); if (IS_ERR(clkin_clk)) { pr_err("%s: of_clk_get failed\n", node->full_name); return; } clkin = clk_get_rate(clkin_clk); if (reg & BIT(21)) { rate = 0; } else if (reg & BIT(20)) { rate = clkin; } else { int p = (reg >> 13) & 0x3f; int m = (reg >> 5) & 0xff; int n = reg & 0x1f; rate = clkin * ((m + 1) / (n + 1)) / (p + 1); } clk = clk_register_fixed_rate(NULL, name, parent_name, 0, rate); if (IS_ERR(clk)) { pr_err("%s: failed to register clock\n", node->full_name); return; } clk_register_clkdev(clk, NULL, name); of_clk_add_provider(node, of_clk_src_simple_get, clk); } CLK_OF_DECLARE(aspeed_hpll_clock, "aspeed,g5-hpll-clock", aspeed_of_hpll_clk_init); static void __init aspeed_of_ahb_clk_init(struct device_node *node) { struct clk *clk, *hpll_clk; void __iomem *base; int reg, rate, hpll; const char *name = node->name; const char *parent_name; of_property_read_string(node, "clock-output-names", &name); parent_name = of_clk_get_parent_name(node, 0); /* Strap register SCU70 */ base = of_iomap(node, 0); if (!base) { pr_err("%s: of_iomap failed\n", node->full_name); return; } /* bits 11:9 define the AXI/AHB clock frequency ratio */ reg = (readl(base) >> 9) & 0x07; iounmap(base); /* A value of zero is undefined */ WARN_ON(reg == 0); hpll_clk = of_clk_get(node, 0); if (IS_ERR(hpll_clk)) { pr_err("%s: of_clk_get failed\n", node->full_name); return; } hpll = clk_get_rate(hpll_clk); rate = hpll / 2 / (reg + 1); clk = clk_register_fixed_rate(NULL, name, parent_name, 0, rate); if (IS_ERR(clk)) { pr_err("%s: failed to register clock\n", node->full_name); return; } clk_register_clkdev(clk, NULL, name); of_clk_add_provider(node, of_clk_src_simple_get, clk); } CLK_OF_DECLARE(aspeed_ahb_clock, "aspeed,g5-ahb-clock", aspeed_of_ahb_clk_init); static void __init aspeed_of_apb_clk_init(struct device_node *node) { struct clk *clk, *hpll_clk; void __iomem *base; int reg, rate; const char *name = node->name; const char *parent_name; of_property_read_string(node, "clock-output-names", &name); parent_name = of_clk_get_parent_name(node, 0); /* Clock selection register SCU08 */ base = of_iomap(node, 0); if (!base) { pr_err("%s: of_iomap failed\n", node->full_name); return; } reg = readl(base) >> 23 & 0x7; iounmap(base); hpll_clk = of_clk_get(node, 0); if (IS_ERR(hpll_clk)) { pr_err("%s: of_clk_get failed\n", node->full_name); return; } rate = clk_get_rate(hpll_clk) / (4 * (reg + 1)); clk = clk_register_fixed_rate(NULL, name, parent_name, 0, rate); if (IS_ERR(clk)) { pr_err("%s: failed to register clock\n", node->full_name); return; } clk_register_clkdev(clk, NULL, name); of_clk_add_provider(node, of_clk_src_simple_get, clk); } CLK_OF_DECLARE(aspeed_apb_clock, "aspeed,g5-apb-clock", aspeed_of_apb_clk_init);