| // SPDX-License-Identifier: GPL-2.0-only |
| /* |
| * |
| * Copyright (C) 2010 John Crispin <john@phrozen.org> |
| * Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG |
| */ |
| |
| #include <linux/io.h> |
| #include <linux/export.h> |
| #include <linux/clk.h> |
| |
| #include <asm/time.h> |
| #include <asm/irq.h> |
| #include <asm/div64.h> |
| |
| #include <lantiq_soc.h> |
| |
| #include "../clk.h" |
| |
| static unsigned int ram_clocks[] = { |
| CLOCK_167M, CLOCK_133M, CLOCK_111M, CLOCK_83M }; |
| #define DDR_HZ ram_clocks[ltq_cgu_r32(CGU_SYS) & 0x3] |
| |
| /* legacy xway clock */ |
| #define CGU_SYS 0x10 |
| |
| /* vr9, ar10/grx390 clock */ |
| #define CGU_SYS_XRX 0x0c |
| #define CGU_IF_CLK_AR10 0x24 |
| |
| unsigned long ltq_danube_fpi_hz(void) |
| { |
| unsigned long ddr_clock = DDR_HZ; |
| |
| if (ltq_cgu_r32(CGU_SYS) & 0x40) |
| return ddr_clock >> 1; |
| return ddr_clock; |
| } |
| |
| unsigned long ltq_danube_cpu_hz(void) |
| { |
| switch (ltq_cgu_r32(CGU_SYS) & 0xc) { |
| case 0: |
| return CLOCK_333M; |
| case 4: |
| return DDR_HZ; |
| case 8: |
| return DDR_HZ << 1; |
| default: |
| return DDR_HZ >> 1; |
| } |
| } |
| |
| unsigned long ltq_danube_pp32_hz(void) |
| { |
| unsigned int clksys = (ltq_cgu_r32(CGU_SYS) >> 7) & 3; |
| unsigned long clk; |
| |
| switch (clksys) { |
| case 1: |
| clk = CLOCK_240M; |
| break; |
| case 2: |
| clk = CLOCK_222M; |
| break; |
| case 3: |
| clk = CLOCK_133M; |
| break; |
| default: |
| clk = CLOCK_266M; |
| break; |
| } |
| |
| return clk; |
| } |
| |
| unsigned long ltq_ar9_sys_hz(void) |
| { |
| if (((ltq_cgu_r32(CGU_SYS) >> 3) & 0x3) == 0x2) |
| return CLOCK_393M; |
| return CLOCK_333M; |
| } |
| |
| unsigned long ltq_ar9_fpi_hz(void) |
| { |
| unsigned long sys = ltq_ar9_sys_hz(); |
| |
| if (ltq_cgu_r32(CGU_SYS) & BIT(0)) |
| return sys / 3; |
| else |
| return sys / 2; |
| } |
| |
| unsigned long ltq_ar9_cpu_hz(void) |
| { |
| if (ltq_cgu_r32(CGU_SYS) & BIT(2)) |
| return ltq_ar9_fpi_hz(); |
| else |
| return ltq_ar9_sys_hz(); |
| } |
| |
| unsigned long ltq_vr9_cpu_hz(void) |
| { |
| unsigned int cpu_sel; |
| unsigned long clk; |
| |
| cpu_sel = (ltq_cgu_r32(CGU_SYS_XRX) >> 4) & 0xf; |
| |
| switch (cpu_sel) { |
| case 0: |
| clk = CLOCK_600M; |
| break; |
| case 1: |
| clk = CLOCK_500M; |
| break; |
| case 2: |
| clk = CLOCK_393M; |
| break; |
| case 3: |
| clk = CLOCK_333M; |
| break; |
| case 5: |
| case 6: |
| clk = CLOCK_196_608M; |
| break; |
| case 7: |
| clk = CLOCK_167M; |
| break; |
| case 4: |
| case 8: |
| case 9: |
| clk = CLOCK_125M; |
| break; |
| default: |
| clk = 0; |
| break; |
| } |
| |
| return clk; |
| } |
| |
| unsigned long ltq_vr9_fpi_hz(void) |
| { |
| unsigned int ocp_sel, cpu_clk; |
| unsigned long clk; |
| |
| cpu_clk = ltq_vr9_cpu_hz(); |
| ocp_sel = ltq_cgu_r32(CGU_SYS_XRX) & 0x3; |
| |
| switch (ocp_sel) { |
| case 0: |
| /* OCP ratio 1 */ |
| clk = cpu_clk; |
| break; |
| case 2: |
| /* OCP ratio 2 */ |
| clk = cpu_clk / 2; |
| break; |
| case 3: |
| /* OCP ratio 2.5 */ |
| clk = (cpu_clk * 2) / 5; |
| break; |
| case 4: |
| /* OCP ratio 3 */ |
| clk = cpu_clk / 3; |
| break; |
| default: |
| clk = 0; |
| break; |
| } |
| |
| return clk; |
| } |
| |
| unsigned long ltq_vr9_pp32_hz(void) |
| { |
| unsigned int clksys = (ltq_cgu_r32(CGU_SYS) >> 16) & 0x7; |
| unsigned long clk; |
| |
| switch (clksys) { |
| case 0: |
| clk = CLOCK_500M; |
| break; |
| case 1: |
| clk = CLOCK_432M; |
| break; |
| case 2: |
| clk = CLOCK_288M; |
| break; |
| default: |
| clk = CLOCK_500M; |
| break; |
| } |
| |
| return clk; |
| } |
| |
| unsigned long ltq_ar10_cpu_hz(void) |
| { |
| unsigned int clksys; |
| int cpu_fs = (ltq_cgu_r32(CGU_SYS_XRX) >> 8) & 0x1; |
| int freq_div = (ltq_cgu_r32(CGU_SYS_XRX) >> 4) & 0x7; |
| |
| switch (cpu_fs) { |
| case 0: |
| clksys = CLOCK_500M; |
| break; |
| case 1: |
| clksys = CLOCK_600M; |
| break; |
| default: |
| clksys = CLOCK_500M; |
| break; |
| } |
| |
| switch (freq_div) { |
| case 0: |
| return clksys; |
| case 1: |
| return clksys >> 1; |
| case 2: |
| return clksys >> 2; |
| default: |
| return clksys; |
| } |
| } |
| |
| unsigned long ltq_ar10_fpi_hz(void) |
| { |
| int freq_fpi = (ltq_cgu_r32(CGU_IF_CLK_AR10) >> 25) & 0xf; |
| |
| switch (freq_fpi) { |
| case 1: |
| return CLOCK_300M; |
| case 5: |
| return CLOCK_250M; |
| case 2: |
| return CLOCK_150M; |
| case 6: |
| return CLOCK_125M; |
| |
| default: |
| return CLOCK_125M; |
| } |
| } |
| |
| unsigned long ltq_ar10_pp32_hz(void) |
| { |
| unsigned int clksys = (ltq_cgu_r32(CGU_SYS) >> 16) & 0x7; |
| unsigned long clk; |
| |
| switch (clksys) { |
| case 1: |
| clk = CLOCK_250M; |
| break; |
| case 4: |
| clk = CLOCK_400M; |
| break; |
| default: |
| clk = CLOCK_250M; |
| break; |
| } |
| |
| return clk; |
| } |
| |
| unsigned long ltq_grx390_cpu_hz(void) |
| { |
| unsigned int clksys; |
| int cpu_fs = ((ltq_cgu_r32(CGU_SYS_XRX) >> 9) & 0x3); |
| int freq_div = ((ltq_cgu_r32(CGU_SYS_XRX) >> 4) & 0x7); |
| |
| switch (cpu_fs) { |
| case 0: |
| clksys = CLOCK_600M; |
| break; |
| case 1: |
| clksys = CLOCK_666M; |
| break; |
| case 2: |
| clksys = CLOCK_720M; |
| break; |
| default: |
| clksys = CLOCK_600M; |
| break; |
| } |
| |
| switch (freq_div) { |
| case 0: |
| return clksys; |
| case 1: |
| return clksys >> 1; |
| case 2: |
| return clksys >> 2; |
| default: |
| return clksys; |
| } |
| } |
| |
| unsigned long ltq_grx390_fpi_hz(void) |
| { |
| /* fpi clock is derived from ddr_clk */ |
| unsigned int clksys; |
| int cpu_fs = ((ltq_cgu_r32(CGU_SYS_XRX) >> 9) & 0x3); |
| int freq_div = ((ltq_cgu_r32(CGU_SYS_XRX)) & 0x7); |
| switch (cpu_fs) { |
| case 0: |
| clksys = CLOCK_600M; |
| break; |
| case 1: |
| clksys = CLOCK_666M; |
| break; |
| case 2: |
| clksys = CLOCK_720M; |
| break; |
| default: |
| clksys = CLOCK_600M; |
| break; |
| } |
| |
| switch (freq_div) { |
| case 1: |
| return clksys >> 1; |
| case 2: |
| return clksys >> 2; |
| default: |
| return clksys >> 1; |
| } |
| } |
| |
| unsigned long ltq_grx390_pp32_hz(void) |
| { |
| unsigned int clksys = (ltq_cgu_r32(CGU_SYS) >> 16) & 0x7; |
| unsigned long clk; |
| |
| switch (clksys) { |
| case 1: |
| clk = CLOCK_250M; |
| break; |
| case 2: |
| clk = CLOCK_432M; |
| break; |
| case 4: |
| clk = CLOCK_400M; |
| break; |
| default: |
| clk = CLOCK_250M; |
| break; |
| } |
| return clk; |
| } |