Path: blob/master/arch/mips/lantiq/xway/clk-xway.c
10818 views
/*1* This program is free software; you can redistribute it and/or modify it2* under the terms of the GNU General Public License version 2 as published3* by the Free Software Foundation.4*5* Copyright (C) 2010 John Crispin <[email protected]>6*/78#include <linux/io.h>9#include <linux/module.h>10#include <linux/init.h>11#include <linux/clk.h>1213#include <asm/time.h>14#include <asm/irq.h>15#include <asm/div64.h>1617#include <lantiq_soc.h>1819static unsigned int ltq_ram_clocks[] = {20CLOCK_167M, CLOCK_133M, CLOCK_111M, CLOCK_83M };21#define DDR_HZ ltq_ram_clocks[ltq_cgu_r32(LTQ_CGU_SYS) & 0x3]2223#define BASIC_FREQUENCY_1 3532800024#define BASIC_FREQUENCY_2 3600000025#define BASIS_REQUENCY_USB 120000002627#define GET_BITS(x, msb, lsb) \28(((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb))2930#define LTQ_CGU_PLL0_CFG 0x000431#define LTQ_CGU_PLL1_CFG 0x000832#define LTQ_CGU_PLL2_CFG 0x000C33#define LTQ_CGU_SYS 0x001034#define LTQ_CGU_UPDATE 0x001435#define LTQ_CGU_IF_CLK 0x001836#define LTQ_CGU_OSC_CON 0x001C37#define LTQ_CGU_SMD 0x002038#define LTQ_CGU_CT1SR 0x002839#define LTQ_CGU_CT2SR 0x002C40#define LTQ_CGU_PCMCR 0x003041#define LTQ_CGU_PCI_CR 0x003442#define LTQ_CGU_PD_PC 0x003843#define LTQ_CGU_FMR 0x003C4445#define CGU_PLL0_PHASE_DIVIDER_ENABLE \46(ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 31))47#define CGU_PLL0_BYPASS \48(ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 30))49#define CGU_PLL0_CFG_DSMSEL \50(ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 28))51#define CGU_PLL0_CFG_FRAC_EN \52(ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 27))53#define CGU_PLL1_SRC \54(ltq_cgu_r32(LTQ_CGU_PLL1_CFG) & (1 << 31))55#define CGU_PLL2_PHASE_DIVIDER_ENABLE \56(ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & (1 << 20))57#define CGU_SYS_FPI_SEL (1 << 6)58#define CGU_SYS_DDR_SEL 0x359#define CGU_PLL0_SRC (1 << 29)6061#define CGU_PLL0_CFG_PLLK GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 26, 17)62#define CGU_PLL0_CFG_PLLN GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 12, 6)63#define CGU_PLL0_CFG_PLLM GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 5, 2)64#define CGU_PLL2_SRC GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 18, 17)65#define CGU_PLL2_CFG_INPUT_DIV GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 16, 13)6667static unsigned int ltq_get_pll0_fdiv(void);6869static inline unsigned int get_input_clock(int pll)70{71switch (pll) {72case 0:73if (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & CGU_PLL0_SRC)74return BASIS_REQUENCY_USB;75else if (CGU_PLL0_PHASE_DIVIDER_ENABLE)76return BASIC_FREQUENCY_1;77else78return BASIC_FREQUENCY_2;79case 1:80if (CGU_PLL1_SRC)81return BASIS_REQUENCY_USB;82else if (CGU_PLL0_PHASE_DIVIDER_ENABLE)83return BASIC_FREQUENCY_1;84else85return BASIC_FREQUENCY_2;86case 2:87switch (CGU_PLL2_SRC) {88case 0:89return ltq_get_pll0_fdiv();90case 1:91return CGU_PLL2_PHASE_DIVIDER_ENABLE ?92BASIC_FREQUENCY_1 :93BASIC_FREQUENCY_2;94case 2:95return BASIS_REQUENCY_USB;96}97default:98return 0;99}100}101102static inline unsigned int cal_dsm(int pll, unsigned int num, unsigned int den)103{104u64 res, clock = get_input_clock(pll);105106res = num * clock;107do_div(res, den);108return res;109}110111static inline unsigned int mash_dsm(int pll, unsigned int M, unsigned int N,112unsigned int K)113{114unsigned int num = ((N + 1) << 10) + K;115unsigned int den = (M + 1) << 10;116117return cal_dsm(pll, num, den);118}119120static inline unsigned int ssff_dsm_1(int pll, unsigned int M, unsigned int N,121unsigned int K)122{123unsigned int num = ((N + 1) << 11) + K + 512;124unsigned int den = (M + 1) << 11;125126return cal_dsm(pll, num, den);127}128129static inline unsigned int ssff_dsm_2(int pll, unsigned int M, unsigned int N,130unsigned int K)131{132unsigned int num = K >= 512 ?133((N + 1) << 12) + K - 512 : ((N + 1) << 12) + K + 3584;134unsigned int den = (M + 1) << 12;135136return cal_dsm(pll, num, den);137}138139static inline unsigned int dsm(int pll, unsigned int M, unsigned int N,140unsigned int K, unsigned int dsmsel, unsigned int phase_div_en)141{142if (!dsmsel)143return mash_dsm(pll, M, N, K);144else if (!phase_div_en)145return mash_dsm(pll, M, N, K);146else147return ssff_dsm_2(pll, M, N, K);148}149150static inline unsigned int ltq_get_pll0_fosc(void)151{152if (CGU_PLL0_BYPASS)153return get_input_clock(0);154else155return !CGU_PLL0_CFG_FRAC_EN156? dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, 0,157CGU_PLL0_CFG_DSMSEL,158CGU_PLL0_PHASE_DIVIDER_ENABLE)159: dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN,160CGU_PLL0_CFG_PLLK, CGU_PLL0_CFG_DSMSEL,161CGU_PLL0_PHASE_DIVIDER_ENABLE);162}163164static unsigned int ltq_get_pll0_fdiv(void)165{166unsigned int div = CGU_PLL2_CFG_INPUT_DIV + 1;167168return (ltq_get_pll0_fosc() + (div >> 1)) / div;169}170171unsigned int ltq_get_io_region_clock(void)172{173unsigned int ret = ltq_get_pll0_fosc();174175switch (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & CGU_SYS_DDR_SEL) {176default:177case 0:178return (ret + 1) / 2;179case 1:180return (ret * 2 + 2) / 5;181case 2:182return (ret + 1) / 3;183case 3:184return (ret + 2) / 4;185}186}187EXPORT_SYMBOL(ltq_get_io_region_clock);188189unsigned int ltq_get_fpi_bus_clock(int fpi)190{191unsigned int ret = ltq_get_io_region_clock();192193if ((fpi == 2) && (ltq_cgu_r32(LTQ_CGU_SYS) & CGU_SYS_FPI_SEL))194ret >>= 1;195return ret;196}197EXPORT_SYMBOL(ltq_get_fpi_bus_clock);198199unsigned int ltq_get_cpu_hz(void)200{201switch (ltq_cgu_r32(LTQ_CGU_SYS) & 0xc) {202case 0:203return CLOCK_333M;204case 4:205return DDR_HZ;206case 8:207return DDR_HZ << 1;208default:209return DDR_HZ >> 1;210}211}212EXPORT_SYMBOL(ltq_get_cpu_hz);213214unsigned int ltq_get_fpi_hz(void)215{216unsigned int ddr_clock = DDR_HZ;217218if (ltq_cgu_r32(LTQ_CGU_SYS) & 0x40)219return ddr_clock >> 1;220return ddr_clock;221}222EXPORT_SYMBOL(ltq_get_fpi_hz);223224225