18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Marvell MV98DX3236 SoC clocks 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2012 Marvell 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Gregory CLEMENT <gregory.clement@free-electrons.com> 88c2ecf20Sopenharmony_ci * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> 98c2ecf20Sopenharmony_ci * Andrew Lunn <andrew@lunn.ch> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 158c2ecf20Sopenharmony_ci#include <linux/io.h> 168c2ecf20Sopenharmony_ci#include <linux/of.h> 178c2ecf20Sopenharmony_ci#include "common.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* 218c2ecf20Sopenharmony_ci * For 98DX4251 Sample At Reset the CPU, DDR and Main PLL clocks are all 228c2ecf20Sopenharmony_ci * defined at the same time 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * SAR1[20:18] : CPU frequency DDR frequency MPLL frequency 258c2ecf20Sopenharmony_ci * 0 = 400 MHz 400 MHz 800 MHz 268c2ecf20Sopenharmony_ci * 2 = 667 MHz 667 MHz 2000 MHz 278c2ecf20Sopenharmony_ci * 3 = 800 MHz 800 MHz 1600 MHz 288c2ecf20Sopenharmony_ci * others reserved. 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * For 98DX3236 Sample At Reset the CPU, DDR and Main PLL clocks are all 318c2ecf20Sopenharmony_ci * defined at the same time 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * SAR1[20:18] : CPU frequency DDR frequency MPLL frequency 348c2ecf20Sopenharmony_ci * 1 = 667 MHz 667 MHz 2000 MHz 358c2ecf20Sopenharmony_ci * 2 = 400 MHz 400 MHz 400 MHz 368c2ecf20Sopenharmony_ci * 3 = 800 MHz 800 MHz 800 MHz 378c2ecf20Sopenharmony_ci * 5 = 800 MHz 400 MHz 800 MHz 388c2ecf20Sopenharmony_ci * others reserved. 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT 18 428c2ecf20Sopenharmony_ci#define SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT_MASK 0x7 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic u32 __init mv98dx3236_get_tclk_freq(void __iomem *sar) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci /* Tclk = 200MHz, no SaR dependency */ 478c2ecf20Sopenharmony_ci return 200000000; 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic const u32 mv98dx3236_cpu_frequencies[] __initconst = { 518c2ecf20Sopenharmony_ci 0, 528c2ecf20Sopenharmony_ci 667000000, 538c2ecf20Sopenharmony_ci 400000000, 548c2ecf20Sopenharmony_ci 800000000, 558c2ecf20Sopenharmony_ci 0, 568c2ecf20Sopenharmony_ci 800000000, 578c2ecf20Sopenharmony_ci 0, 0, 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic const u32 mv98dx4251_cpu_frequencies[] __initconst = { 618c2ecf20Sopenharmony_ci 400000000, 628c2ecf20Sopenharmony_ci 0, 638c2ecf20Sopenharmony_ci 667000000, 648c2ecf20Sopenharmony_ci 800000000, 658c2ecf20Sopenharmony_ci 0, 0, 0, 0, 668c2ecf20Sopenharmony_ci}; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic u32 __init mv98dx3236_get_cpu_freq(void __iomem *sar) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci u32 cpu_freq = 0; 718c2ecf20Sopenharmony_ci u8 cpu_freq_select = 0; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci cpu_freq_select = ((readl(sar) >> SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT) & 748c2ecf20Sopenharmony_ci SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT_MASK); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci if (of_machine_is_compatible("marvell,armadaxp-98dx4251")) 778c2ecf20Sopenharmony_ci cpu_freq = mv98dx4251_cpu_frequencies[cpu_freq_select]; 788c2ecf20Sopenharmony_ci else if (of_machine_is_compatible("marvell,armadaxp-98dx3236")) 798c2ecf20Sopenharmony_ci cpu_freq = mv98dx3236_cpu_frequencies[cpu_freq_select]; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (!cpu_freq) 828c2ecf20Sopenharmony_ci pr_err("CPU freq select unsupported %d\n", cpu_freq_select); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci return cpu_freq; 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cienum { 888c2ecf20Sopenharmony_ci MV98DX3236_CPU_TO_DDR, 898c2ecf20Sopenharmony_ci MV98DX3236_CPU_TO_MPLL 908c2ecf20Sopenharmony_ci}; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic const struct coreclk_ratio mv98dx3236_core_ratios[] __initconst = { 938c2ecf20Sopenharmony_ci { .id = MV98DX3236_CPU_TO_DDR, .name = "ddrclk" }, 948c2ecf20Sopenharmony_ci { .id = MV98DX3236_CPU_TO_MPLL, .name = "mpll" }, 958c2ecf20Sopenharmony_ci}; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic const int __initconst mv98dx3236_cpu_mpll_ratios[8][2] = { 988c2ecf20Sopenharmony_ci {0, 1}, {3, 1}, {1, 1}, {1, 1}, 998c2ecf20Sopenharmony_ci {0, 1}, {1, 1}, {0, 1}, {0, 1}, 1008c2ecf20Sopenharmony_ci}; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic const int __initconst mv98dx3236_cpu_ddr_ratios[8][2] = { 1038c2ecf20Sopenharmony_ci {0, 1}, {1, 1}, {1, 1}, {1, 1}, 1048c2ecf20Sopenharmony_ci {0, 1}, {1, 2}, {0, 1}, {0, 1}, 1058c2ecf20Sopenharmony_ci}; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic const int __initconst mv98dx4251_cpu_mpll_ratios[8][2] = { 1088c2ecf20Sopenharmony_ci {2, 1}, {0, 1}, {3, 1}, {2, 1}, 1098c2ecf20Sopenharmony_ci {0, 1}, {0, 1}, {0, 1}, {0, 1}, 1108c2ecf20Sopenharmony_ci}; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic const int __initconst mv98dx4251_cpu_ddr_ratios[8][2] = { 1138c2ecf20Sopenharmony_ci {1, 1}, {0, 1}, {1, 1}, {1, 1}, 1148c2ecf20Sopenharmony_ci {0, 1}, {0, 1}, {0, 1}, {0, 1}, 1158c2ecf20Sopenharmony_ci}; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic void __init mv98dx3236_get_clk_ratio( 1188c2ecf20Sopenharmony_ci void __iomem *sar, int id, int *mult, int *div) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci u32 opt = ((readl(sar) >> SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT) & 1218c2ecf20Sopenharmony_ci SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT_MASK); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci switch (id) { 1248c2ecf20Sopenharmony_ci case MV98DX3236_CPU_TO_DDR: 1258c2ecf20Sopenharmony_ci if (of_machine_is_compatible("marvell,armadaxp-98dx4251")) { 1268c2ecf20Sopenharmony_ci *mult = mv98dx4251_cpu_ddr_ratios[opt][0]; 1278c2ecf20Sopenharmony_ci *div = mv98dx4251_cpu_ddr_ratios[opt][1]; 1288c2ecf20Sopenharmony_ci } else if (of_machine_is_compatible("marvell,armadaxp-98dx3236")) { 1298c2ecf20Sopenharmony_ci *mult = mv98dx3236_cpu_ddr_ratios[opt][0]; 1308c2ecf20Sopenharmony_ci *div = mv98dx3236_cpu_ddr_ratios[opt][1]; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci break; 1338c2ecf20Sopenharmony_ci case MV98DX3236_CPU_TO_MPLL: 1348c2ecf20Sopenharmony_ci if (of_machine_is_compatible("marvell,armadaxp-98dx4251")) { 1358c2ecf20Sopenharmony_ci *mult = mv98dx4251_cpu_mpll_ratios[opt][0]; 1368c2ecf20Sopenharmony_ci *div = mv98dx4251_cpu_mpll_ratios[opt][1]; 1378c2ecf20Sopenharmony_ci } else if (of_machine_is_compatible("marvell,armadaxp-98dx3236")) { 1388c2ecf20Sopenharmony_ci *mult = mv98dx3236_cpu_mpll_ratios[opt][0]; 1398c2ecf20Sopenharmony_ci *div = mv98dx3236_cpu_mpll_ratios[opt][1]; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci break; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic const struct coreclk_soc_desc mv98dx3236_core_clocks = { 1468c2ecf20Sopenharmony_ci .get_tclk_freq = mv98dx3236_get_tclk_freq, 1478c2ecf20Sopenharmony_ci .get_cpu_freq = mv98dx3236_get_cpu_freq, 1488c2ecf20Sopenharmony_ci .get_clk_ratio = mv98dx3236_get_clk_ratio, 1498c2ecf20Sopenharmony_ci .ratios = mv98dx3236_core_ratios, 1508c2ecf20Sopenharmony_ci .num_ratios = ARRAY_SIZE(mv98dx3236_core_ratios), 1518c2ecf20Sopenharmony_ci}; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci/* 1558c2ecf20Sopenharmony_ci * Clock Gating Control 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic const struct clk_gating_soc_desc mv98dx3236_gating_desc[] __initconst = { 1598c2ecf20Sopenharmony_ci { "ge1", NULL, 3, 0 }, 1608c2ecf20Sopenharmony_ci { "ge0", NULL, 4, 0 }, 1618c2ecf20Sopenharmony_ci { "pex00", NULL, 5, 0 }, 1628c2ecf20Sopenharmony_ci { "sdio", NULL, 17, 0 }, 1638c2ecf20Sopenharmony_ci { "usb0", NULL, 18, 0 }, 1648c2ecf20Sopenharmony_ci { "xor0", NULL, 22, 0 }, 1658c2ecf20Sopenharmony_ci { } 1668c2ecf20Sopenharmony_ci}; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic void __init mv98dx3236_clk_init(struct device_node *np) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci struct device_node *cgnp = 1718c2ecf20Sopenharmony_ci of_find_compatible_node(NULL, NULL, "marvell,mv98dx3236-gating-clock"); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci mvebu_coreclk_setup(np, &mv98dx3236_core_clocks); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (cgnp) { 1768c2ecf20Sopenharmony_ci mvebu_clk_gating_setup(cgnp, mv98dx3236_gating_desc); 1778c2ecf20Sopenharmony_ci of_node_put(cgnp); 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ciCLK_OF_DECLARE(mv98dx3236_clk, "marvell,mv98dx3236-core-clock", mv98dx3236_clk_init); 181