| /* |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 as published |
| * by the Free Software Foundation. |
| * |
| * Copyright (C) 2010 John Crispin <blogic@openwrt.org> |
| */ |
| |
| #include <linux/io.h> |
| #include <linux/export.h> |
| #include <linux/init.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 clock */ |
| #define CGU_SYS_VR9 0x0c |
| #define CGU_IF_CLK_VR9 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; |
| return sys >> 1; |
| } |
| |
| 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_VR9) >> 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_VR9) & 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) & 3; |
| unsigned long clk; |
| |
| switch (clksys) { |
| case 1: |
| clk = CLOCK_450M; |
| break; |
| case 2: |
| clk = CLOCK_300M; |
| break; |
| default: |
| clk = CLOCK_500M; |
| break; |
| } |
| |
| return clk; |
| } |