162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Marvell MV98DX3236 SoC clocks 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2012 Marvell 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Gregory CLEMENT <gregory.clement@free-electrons.com> 862306a36Sopenharmony_ci * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> 962306a36Sopenharmony_ci * Andrew Lunn <andrew@lunn.ch> 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/clk-provider.h> 1562306a36Sopenharmony_ci#include <linux/io.h> 1662306a36Sopenharmony_ci#include <linux/of.h> 1762306a36Sopenharmony_ci#include "common.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* 2162306a36Sopenharmony_ci * For 98DX4251 Sample At Reset the CPU, DDR and Main PLL clocks are all 2262306a36Sopenharmony_ci * defined at the same time 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * SAR1[20:18] : CPU frequency DDR frequency MPLL frequency 2562306a36Sopenharmony_ci * 0 = 400 MHz 400 MHz 800 MHz 2662306a36Sopenharmony_ci * 2 = 667 MHz 667 MHz 2000 MHz 2762306a36Sopenharmony_ci * 3 = 800 MHz 800 MHz 1600 MHz 2862306a36Sopenharmony_ci * others reserved. 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * For 98DX3236 Sample At Reset the CPU, DDR and Main PLL clocks are all 3162306a36Sopenharmony_ci * defined at the same time 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * SAR1[20:18] : CPU frequency DDR frequency MPLL frequency 3462306a36Sopenharmony_ci * 1 = 667 MHz 667 MHz 2000 MHz 3562306a36Sopenharmony_ci * 2 = 400 MHz 400 MHz 400 MHz 3662306a36Sopenharmony_ci * 3 = 800 MHz 800 MHz 800 MHz 3762306a36Sopenharmony_ci * 5 = 800 MHz 400 MHz 800 MHz 3862306a36Sopenharmony_ci * others reserved. 3962306a36Sopenharmony_ci */ 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT 18 4262306a36Sopenharmony_ci#define SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT_MASK 0x7 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic u32 __init mv98dx3236_get_tclk_freq(void __iomem *sar) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci /* Tclk = 200MHz, no SaR dependency */ 4762306a36Sopenharmony_ci return 200000000; 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic const u32 mv98dx3236_cpu_frequencies[] __initconst = { 5162306a36Sopenharmony_ci 0, 5262306a36Sopenharmony_ci 667000000, 5362306a36Sopenharmony_ci 400000000, 5462306a36Sopenharmony_ci 800000000, 5562306a36Sopenharmony_ci 0, 5662306a36Sopenharmony_ci 800000000, 5762306a36Sopenharmony_ci 0, 0, 5862306a36Sopenharmony_ci}; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic const u32 mv98dx4251_cpu_frequencies[] __initconst = { 6162306a36Sopenharmony_ci 400000000, 6262306a36Sopenharmony_ci 0, 6362306a36Sopenharmony_ci 667000000, 6462306a36Sopenharmony_ci 800000000, 6562306a36Sopenharmony_ci 0, 0, 0, 0, 6662306a36Sopenharmony_ci}; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic u32 __init mv98dx3236_get_cpu_freq(void __iomem *sar) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci u32 cpu_freq = 0; 7162306a36Sopenharmony_ci u8 cpu_freq_select = 0; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci cpu_freq_select = ((readl(sar) >> SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT) & 7462306a36Sopenharmony_ci SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT_MASK); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci if (of_machine_is_compatible("marvell,armadaxp-98dx4251")) 7762306a36Sopenharmony_ci cpu_freq = mv98dx4251_cpu_frequencies[cpu_freq_select]; 7862306a36Sopenharmony_ci else if (of_machine_is_compatible("marvell,armadaxp-98dx3236")) 7962306a36Sopenharmony_ci cpu_freq = mv98dx3236_cpu_frequencies[cpu_freq_select]; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci if (!cpu_freq) 8262306a36Sopenharmony_ci pr_err("CPU freq select unsupported %d\n", cpu_freq_select); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci return cpu_freq; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cienum { 8862306a36Sopenharmony_ci MV98DX3236_CPU_TO_DDR, 8962306a36Sopenharmony_ci MV98DX3236_CPU_TO_MPLL 9062306a36Sopenharmony_ci}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic const struct coreclk_ratio mv98dx3236_core_ratios[] __initconst = { 9362306a36Sopenharmony_ci { .id = MV98DX3236_CPU_TO_DDR, .name = "ddrclk" }, 9462306a36Sopenharmony_ci { .id = MV98DX3236_CPU_TO_MPLL, .name = "mpll" }, 9562306a36Sopenharmony_ci}; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic const int __initconst mv98dx3236_cpu_mpll_ratios[8][2] = { 9862306a36Sopenharmony_ci {0, 1}, {3, 1}, {1, 1}, {1, 1}, 9962306a36Sopenharmony_ci {0, 1}, {1, 1}, {0, 1}, {0, 1}, 10062306a36Sopenharmony_ci}; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic const int __initconst mv98dx3236_cpu_ddr_ratios[8][2] = { 10362306a36Sopenharmony_ci {0, 1}, {1, 1}, {1, 1}, {1, 1}, 10462306a36Sopenharmony_ci {0, 1}, {1, 2}, {0, 1}, {0, 1}, 10562306a36Sopenharmony_ci}; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic const int __initconst mv98dx4251_cpu_mpll_ratios[8][2] = { 10862306a36Sopenharmony_ci {2, 1}, {0, 1}, {3, 1}, {2, 1}, 10962306a36Sopenharmony_ci {0, 1}, {0, 1}, {0, 1}, {0, 1}, 11062306a36Sopenharmony_ci}; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic const int __initconst mv98dx4251_cpu_ddr_ratios[8][2] = { 11362306a36Sopenharmony_ci {1, 1}, {0, 1}, {1, 1}, {1, 1}, 11462306a36Sopenharmony_ci {0, 1}, {0, 1}, {0, 1}, {0, 1}, 11562306a36Sopenharmony_ci}; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic void __init mv98dx3236_get_clk_ratio( 11862306a36Sopenharmony_ci void __iomem *sar, int id, int *mult, int *div) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci u32 opt = ((readl(sar) >> SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT) & 12162306a36Sopenharmony_ci SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT_MASK); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci switch (id) { 12462306a36Sopenharmony_ci case MV98DX3236_CPU_TO_DDR: 12562306a36Sopenharmony_ci if (of_machine_is_compatible("marvell,armadaxp-98dx4251")) { 12662306a36Sopenharmony_ci *mult = mv98dx4251_cpu_ddr_ratios[opt][0]; 12762306a36Sopenharmony_ci *div = mv98dx4251_cpu_ddr_ratios[opt][1]; 12862306a36Sopenharmony_ci } else if (of_machine_is_compatible("marvell,armadaxp-98dx3236")) { 12962306a36Sopenharmony_ci *mult = mv98dx3236_cpu_ddr_ratios[opt][0]; 13062306a36Sopenharmony_ci *div = mv98dx3236_cpu_ddr_ratios[opt][1]; 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci break; 13362306a36Sopenharmony_ci case MV98DX3236_CPU_TO_MPLL: 13462306a36Sopenharmony_ci if (of_machine_is_compatible("marvell,armadaxp-98dx4251")) { 13562306a36Sopenharmony_ci *mult = mv98dx4251_cpu_mpll_ratios[opt][0]; 13662306a36Sopenharmony_ci *div = mv98dx4251_cpu_mpll_ratios[opt][1]; 13762306a36Sopenharmony_ci } else if (of_machine_is_compatible("marvell,armadaxp-98dx3236")) { 13862306a36Sopenharmony_ci *mult = mv98dx3236_cpu_mpll_ratios[opt][0]; 13962306a36Sopenharmony_ci *div = mv98dx3236_cpu_mpll_ratios[opt][1]; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci break; 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic const struct coreclk_soc_desc mv98dx3236_core_clocks = { 14662306a36Sopenharmony_ci .get_tclk_freq = mv98dx3236_get_tclk_freq, 14762306a36Sopenharmony_ci .get_cpu_freq = mv98dx3236_get_cpu_freq, 14862306a36Sopenharmony_ci .get_clk_ratio = mv98dx3236_get_clk_ratio, 14962306a36Sopenharmony_ci .ratios = mv98dx3236_core_ratios, 15062306a36Sopenharmony_ci .num_ratios = ARRAY_SIZE(mv98dx3236_core_ratios), 15162306a36Sopenharmony_ci}; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/* 15562306a36Sopenharmony_ci * Clock Gating Control 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic const struct clk_gating_soc_desc mv98dx3236_gating_desc[] __initconst = { 15962306a36Sopenharmony_ci { "ge1", NULL, 3, 0 }, 16062306a36Sopenharmony_ci { "ge0", NULL, 4, 0 }, 16162306a36Sopenharmony_ci { "pex00", NULL, 5, 0 }, 16262306a36Sopenharmony_ci { "sdio", NULL, 17, 0 }, 16362306a36Sopenharmony_ci { "usb0", NULL, 18, 0 }, 16462306a36Sopenharmony_ci { "xor0", NULL, 22, 0 }, 16562306a36Sopenharmony_ci { } 16662306a36Sopenharmony_ci}; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic void __init mv98dx3236_clk_init(struct device_node *np) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci struct device_node *cgnp = 17162306a36Sopenharmony_ci of_find_compatible_node(NULL, NULL, "marvell,mv98dx3236-gating-clock"); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci mvebu_coreclk_setup(np, &mv98dx3236_core_clocks); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (cgnp) { 17662306a36Sopenharmony_ci mvebu_clk_gating_setup(cgnp, mv98dx3236_gating_desc); 17762306a36Sopenharmony_ci of_node_put(cgnp); 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ciCLK_OF_DECLARE(mv98dx3236_clk, "marvell,mv98dx3236-core-clock", mv98dx3236_clk_init); 181