move ifxmips uboot to package/
[openwrt/svn-archive/archive.git] / package / uboot-ifxmips / files / cpu / mips / danube / ifx_cgu.c
diff --git a/package/uboot-ifxmips/files/cpu/mips/danube/ifx_cgu.c b/package/uboot-ifxmips/files/cpu/mips/danube/ifx_cgu.c
new file mode 100644 (file)
index 0000000..3fe13dd
--- /dev/null
@@ -0,0 +1,1086 @@
+/*\r
+ * ########################################################################\r
+ *\r
+ *  This program is free software; you can distribute it and/or modify it\r
+ *  under the terms of the GNU General Public License (Version 2) as\r
+ *  published by the Free Software Foundation.\r
+ *\r
+ *  This program is distributed in the hope it will be useful, but WITHOUT\r
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\r
+ *  for more details.\r
+ *\r
+ *  You should have received a copy of the GNU General Public License along\r
+ *  with this program; if not, write to the Free Software Foundation, Inc.,\r
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.\r
+ *\r
+ * ########################################################################\r
+ *\r
+ * danube_cgu.c\r
+ *\r
+ *  Description:\r
+ *    device driver of clock generation unit of Danube chip\r
+ *  Author:\r
+ *    Samuels Xu Liang\r
+ *  Created:\r
+ *    19 Jul 2005\r
+ *  History & Modification Tag:\r
+ *  ___________________________________________________________________________\r
+ *  |  Tag   |                  Comments                   | Modifier & Time  |\r
+ *  |--------+---------------------------------------------+------------------|\r
+ *  |  S0.0  | First version of this driver and the tag is | Samuels Xu Liang |\r
+ *  |        | implied.                                    |   19 Jul 2005    |\r
+ *  ---------------------------------------------------------------------------\r
+ *\r
+ */\r
+\r
+\r
+/*\r
+ * ####################################\r
+ *              Head File\r
+ * ####################################\r
+ */\r
+\r
+/*\r
+ *  Common Head File\r
+ */\r
+#include <linux/config.h>\r
+#include <linux/kernel.h>\r
+#include <linux/module.h>\r
+#include <linux/version.h>\r
+#include <linux/types.h>\r
+#include <linux/fs.h>\r
+#include <linux/miscdevice.h>\r
+#include <linux/init.h>\r
+#include <asm/uaccess.h>\r
+#include <asm/unistd.h>\r
+#include <asm/irq.h>\r
+#include <linux/errno.h>\r
+\r
+/*\r
+ *  Chip Specific Head File\r
+ */\r
+#include "ifx_cgu.h"\r
+\r
+\r
+/*\r
+ * ####################################\r
+ *              Definition\r
+ * ####################################\r
+ */\r
+\r
+#define DEBUG_ON_AMAZON                 1\r
+#define DEBUG_PRINT_INFO                1\r
+\r
+/*\r
+ *  Frequency of Clock Direct Feed from The Analog Line Driver Chip\r
+ */\r
+#define BASIC_INPUT_CLOCK_FREQUENCY     35328000\r
+\r
+/*\r
+ *  Bits Operation\r
+ */\r
+#define GET_BITS(x, msb, lsb)           (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb))\r
+#define SET_BITS(x, msb, lsb, value)    (((x) & ~(((1 << ((msb) + 1)) - 1) ^ ((1 << (lsb)) - 1))) | (((value) & ((1 << (1 + (msb) - (lsb))) - 1)) << (lsb)))\r
+\r
+/*\r
+ *  CGU Register Mapping\r
+ */\r
+#define DANUBE_CGU                      (KSEG1 + 0x1F103000)\r
+#define DANUBE_CGU_DIV                  ((volatile u32*)(DANUBE_CGU + 0x0000))\r
+#define DANUBE_CGU_PLL_NMK0             ((volatile u32*)(DANUBE_CGU + 0x0004))\r
+#define DANUBE_CGU_PLL_SR0              ((volatile u32*)(DANUBE_CGU + 0x0008))\r
+#define DANUBE_CGU_PLL_NMK1             ((volatile u32*)(DANUBE_CGU + 0x000C))\r
+#define DANUBE_CGU_PLL_SR1              ((volatile u32*)(DANUBE_CGU + 0x0010))\r
+#define DANUBE_CGU_PLL_SR2              ((volatile u32*)(DANUBE_CGU + 0x0014))\r
+#define DANUBE_CGU_IF_CLK               ((volatile u32*)(DANUBE_CGU + 0x0018))\r
+#define DANUBE_CGU_OSC_CTRL             ((volatile u32*)(DANUBE_CGU + 0x001C))\r
+#define DANUBE_CGU_SMD                  ((volatile u32*)(DANUBE_CGU + 0x0020))\r
+#define DANUBE_CGU_CRD                  ((volatile u32*)(DANUBE_CGU + 0x0024))\r
+#define DANUBE_CGU_CT1SR                ((volatile u32*)(DANUBE_CGU + 0x0028))\r
+#define DANUBE_CGU_CT2SR                ((volatile u32*)(DANUBE_CGU + 0x002C))\r
+#define DANUBE_CGU_PCMCR                ((volatile u32*)(DANUBE_CGU + 0x0030))\r
+#define DANUBE_CGU_MUX                  ((volatile u32*)(DANUBE_CGU + 0x0034))\r
+\r
+/*\r
+ *  CGU Divider Register\r
+ */\r
+#define CGU_DIV_SFTR                    (*DANUBE_CGU_DIV & (1 << 31))\r
+#define CGU_DIV_DIVE                    (*DANUBE_CGU_DIV & (1 << 16))\r
+#define CGU_DIV_IOR                     GET_BITS(*DANUBE_CGU_DIV, 5, 4)\r
+#define CGU_DIV_FKS                     GET_BITS(*DANUBE_CGU_DIV, 3, 2)\r
+#define CGU_DIV_FBS                     GET_BITS(*DANUBE_CGU_DIV, 1, 0)\r
+\r
+/*\r
+ *  CGU PLL0 NMK Register\r
+ */\r
+#define CGU_PLL_NMK0_PLLN               ((*DANUBE_CGU_PLL_NMK0 & (0xFFFFFFFF ^ ((1 << 24) - 1))) >> 24)\r
+#define CGU_PLL_NMK0_PLLM               GET_BITS(*DANUBE_CGU_PLL_NMK0, 23, 20)\r
+#define CGU_PLL_NMK0_PLLK               GET_BITS(*DANUBE_CGU_PLL_NMK0, 19, 0)\r
+\r
+/*\r
+ *  CGU PLL0 Status Register\r
+ */\r
+#define CGU_PLL_SR0_PLLDIV              ((*DANUBE_CGU_PLL_SR0 & (0xFFFFFFFF ^ ((1 << 28) - 1))) >> 28)\r
+#define CGU_PLL_SR0_PLLDEN              (*DANUBE_CGU_PLL_SR0 & (1 << 26))\r
+#define CGU_PLL_SR0_PLLPSE              GET_BITS(*DANUBE_CGU_PLL_SR0, 5, 4)\r
+#define CGU_PLL_SR0_PLLB                (*DANUBE_CGU_PLL_SR0 & (1 << 2))\r
+#define CGU_PLL_SR0_PLLL                (*DANUBE_CGU_PLL_SR0 & (1 << 1))\r
+#define CGU_PLL_SR0_PLLEN               (*DANUBE_CGU_PLL_SR0 & (1 << 0))\r
+\r
+#define CGU_PLL_SR0_DSMSEL              1\r
+#define CGU_PLL_SR0_PHASE_DIV_EN        1\r
+\r
+/*\r
+ *  CGU PLL1 NMK Register\r
+ */\r
+#define CGU_PLL_NMK1_PLLN               ((*DANUBE_CGU_PLL_NMK1 & (0xFFFFFFFF ^ ((1 << 24) - 1))) >> 24)\r
+#define CGU_PLL_NMK1_PLLM               GET_BITS(*DANUBE_CGU_PLL_NMK1, 23, 20)\r
+#define CGU_PLL_NMK1_PLLK               GET_BITS(*DANUBE_CGU_PLL_NMK1, 19, 0)\r
+\r
+/*\r
+ *  CGU PLL1 Status Register\r
+ */\r
+#define CGU_PLL_SR1_PLLDIV              ((*DANUBE_CGU_PLL_SR1 & (0xFFFFFFFF ^ ((1 << 28) - 1))) >> 28)\r
+#define CGU_PLL_SR1_PLLDEN              (*DANUBE_CGU_PLL_SR1 & (1 << 26))\r
+#define CGU_PLL_SR1_PLLPSE              GET_BITS(*DANUBE_CGU_PLL_SR1, 5, 4)\r
+#define CGU_PLL_SR1_PLLB                (*DANUBE_CGU_PLL_SR1 & (1 << 2))\r
+#define CGU_PLL_SR1_PLLL                (*DANUBE_CGU_PLL_SR1 & (1 << 1))\r
+#define CGU_PLL_SR1_PLLEN               (*DANUBE_CGU_PLL_SR1 & (1 << 0))\r
+\r
+#define CGU_PLL_SR1_DSMSEL              1\r
+#define CGU_PLL_SR1_PHASE_DIV_EN        1\r
+\r
+/*\r
+ *  CGU PLL2 Status Register\r
+ */\r
+#define CGU_PLL_SR2_PLLDIV              ((*DANUBE_CGU_PLL_SR2 & (0xFFFFFFFF ^ ((1 << 28) - 1))) >> 28)\r
+#define CGU_PLL_SR2_PLLDEN              (*DANUBE_CGU_PLL_SR2 & (1 << 27))\r
+#define CGU_PLL_SR2_PLLN                GET_BITS(*DANUBE_CGU_PLL_SR2, 25, 20)\r
+#define CGU_PLL_SR2_PLLM                GET_BITS(*DANUBE_CGU_PLL_SR2, 19, 16)\r
+#define CGU_PLL_SR2_PLLPS               (*DANUBE_CGU_PLL_SR2 & (1 << 5))\r
+#define CGU_PLL_SR2_PLLPE               (*DANUBE_CGU_PLL_SR2 & (1 << 4))\r
+#define CGU_PLL_SR2_PLLB                (*DANUBE_CGU_PLL_SR2 & (1 << 2))\r
+#define CGU_PLL_SR2_PLLL                (*DANUBE_CGU_PLL_SR2 & (1 << 1))\r
+#define CGU_PLL_SR2_PLLEN               (*DANUBE_CGU_PLL_SR2 & (1 << 0))\r
+\r
+/*\r
+ *  CGU Interface Clock Register\r
+ */\r
+#define CGU_IF_CLK_CLKOD0               GET_BITS(*DANUBE_CGU_IF_CLK, 27, 26)\r
+#define CGU_IF_CLK_CLKOD1               GET_BITS(*DANUBE_CGU_IF_CLK, 25, 24)\r
+#define CGU_IF_CLK_CLKOD2               GET_BITS(*DANUBE_CGU_IF_CLK, 23, 22)\r
+#define CGU_IF_CLK_CLKOD3               GET_BITS(*DANUBE_CGU_IF_CLK, 21, 20)\r
+#define CGU_IF_CLK_PDA                  (*DANUBE_CGU_IF_CLK & (1 << 18))\r
+#define CGU_IF_CLK_PCI_B                (*DANUBE_CGU_IF_CLK & (1 << 17))\r
+#define CGU_IF_CLK_PCIBM                (*DANUBE_CGU_IF_CLK & (1 << 16))\r
+#define CGU_IF_CLK_MIICS                (*DANUBE_CGU_IF_CLK & (1 << 3))\r
+#define CGU_IF_CLK_USBCS                (*DANUBE_CGU_IF_CLK & (1 << 2))\r
+#define CGU_IF_CLK_PCIF                 (*DANUBE_CGU_IF_CLK & (1 << 1))\r
+#define CGU_IF_CLK_PCIS                 (*DANUBE_CGU_IF_CLK & (1 << 0))\r
+\r
+/*\r
+ *  CGU Oscillator Control Register\r
+ */\r
+#define CGU_OSC_CTRL                    GET_BITS(*DANUBE_CGU_OSC_CTRL, 1, 0)\r
+\r
+/*\r
+ *  CGU SDRAM Memory Delay Register\r
+ */\r
+#define CGU_SMD_CLKI                    (*DANUBE_CGU_SMD & (1 << 31))\r
+#define CGU_SMD_MIDS                    GET_BITS(*DANUBE_CGU_SMD, 17, 12)\r
+#define CGU_SMD_MODS                    GET_BITS(*DANUBE_CGU_SMD, 11, 6)\r
+#define CGU_SMD_MDSEL                   GET_BITS(*DANUBE_CGU_SMD, 5, 0)\r
+\r
+/*\r
+ *  CGU CPU Clock Reduction Register\r
+ */\r
+#define CGU_CRD_SFTR                    (*DANUBE_CGU_CRD & (1 << 31))\r
+#define CGU_CRD_DIVE                    (*DANUBE_CGU_CRD & (1 << 16))\r
+#define CGU_CRD_CRD1                    GET_BITS(*DANUBE_CGU_CRD, 3, 2)\r
+#define CGU_CRD_CRD                     GET_BITS(*DANUBE_CGU_CRD, 1, 0)\r
+\r
+/*\r
+ *  CGU CT Status Register 1\r
+ */\r
+#define CGU_CT1SR_PDOUT                 GET_BITS(*DANUBE_CGU_CT1SR, 13, 0)\r
+\r
+/*\r
+ *  CGU CT Status Register 2\r
+ */\r
+#define CGU_CT2SR_PLL1K                 GET_BITS(*DANUBE_CGU_CT2SR, 9, 0)\r
+\r
+/*\r
+ *  CGU PCM Control Register\r
+ */\r
+#define CGU_PCMCR_DCL1                  GET_BITS(*DANUBE_CGU_PCMCR, 27, 25)\r
+#define CGU_PCMCR_MUXDCL                (*DANUBE_CGU_PCMCR & (1 << 22))\r
+#define CGU_PCMCR_MUXFSC                (*DANUBE_CGU_PCMCR & (1 << 18))\r
+#define CGU_PCMCR_PCM_SL                (*DANUBE_CGU_PCMCR & (1 << 13))\r
+#define CGU_PCMCR_DNTR                  (*DANUBE_CGU_PCMCR & (1 << 12))\r
+\r
+/*\r
+ *  CGU Clock Mux Register\r
+ */\r
+#define CGU_MUX_MII_CLK                 (*DANUBE_CGU_MUX & (1 << 6))\r
+#define CGU_MUX_SUB_SYS                 GET_BITS(*DANUBE_CGU_MUX, 5, 3)\r
+#define CGU_MUX_PP32                    GET_BITS(*DANUBE_CGU_MUX, 1, 0)\r
+\r
+\r
+/*\r
+ * ####################################\r
+ * Preparation of Debug on Amazon Chip\r
+ * ####################################\r
+ */\r
+\r
+/*\r
+ *  If try module on Amazon chip, prepare some tricks to prevent invalid memory write.\r
+ */\r
+#if defined(DEBUG_ON_AMAZON) && DEBUG_ON_AMAZON\r
+    u32 g_pFakeRegisters[0x0100];\r
+\r
+    #undef  DANUBE_CGU\r
+    #define DANUBE_CGU                  ((u32)g_pFakeRegisters)\r
+#endif  //  defined(DEBUG_ON_AMAZON) && DEBUG_ON_AMAZON\r
+\r
+\r
+/*\r
+ * ####################################\r
+ *              Data Type\r
+ * ####################################\r
+ */\r
+\r
+\r
+/*\r
+ * ####################################\r
+ *             Declaration\r
+ * ####################################\r
+ */\r
+\r
+/*\r
+ *  Pre-declaration of File Operations\r
+ */\r
+static ssize_t cgu_read(struct file *, char *, size_t, loff_t *);\r
+static ssize_t cgu_write(struct file *, const char *, size_t, loff_t *);\r
+static int cgu_ioctl(struct inode *, struct file *, unsigned int, unsigned long);\r
+static int cgu_open(struct inode *, struct file *);\r
+static int cgu_release(struct inode *, struct file *);\r
+\r
+/*\r
+ *  Pre-declaration of 64-bit Unsigned Integer Operation\r
+ */\r
+static inline void uint64_multiply(unsigned int, unsigned int, unsigned int *);\r
+static inline void uint64_divide(unsigned int *, unsigned int, unsigned int *, unsigned int *);\r
+\r
+/*\r
+ *  Calculate PLL Frequency\r
+ */\r
+static inline u32 cal_dsm(u32, u32);\r
+static inline u32 mash_dsm(u32, u32, u32);\r
+static inline u32 ssff_dsm_1(u32, u32, u32);\r
+static inline u32 ssff_dsm_2(u32, u32, u32);\r
+static inline u32 dsm(u32 M, u32, u32, int, int);\r
+static inline u32 cgu_get_pll0_fosc(void);\r
+static inline u32 cgu_get_pll0_fps(void);\r
+static inline u32 cgu_get_pll0_fdiv(void);\r
+static inline u32 cgu_get_pll1_fosc(void);\r
+static inline u32 cgu_get_pll1_fps(void);\r
+static inline u32 cgu_get_pll1_fdiv(void);\r
+static inline u32 cgu_get_pll2_fosc(void);\r
+static inline u32 cgu_get_pll2_fps(void);\r
+\r
+/*\r
+ *  Export Functions\r
+ */\r
+u32 cgu_get_mips_clock(int);\r
+u32 cgu_get_cpu_clock(void);\r
+u32 cgu_get_io_region_clock(void);\r
+u32 cgu_get_fpi_bus_clock(int);\r
+u32 cgu_get_pp32_clock(void);\r
+u32 cgu_get_pci_clock(void);\r
+u32 cgu_get_ethernet_clock(void);\r
+u32 cgu_get_usb_clock(void);\r
+u32 cgu_get_clockout(int);\r
+\r
+\r
+/*\r
+ * ####################################\r
+ *            Local Variable\r
+ * ####################################\r
+ */\r
+\r
+static struct file_operations cgu_fops = {\r
+    owner:      THIS_MODULE,\r
+    llseek:     no_llseek,\r
+    read:       cgu_read,\r
+    write:      cgu_write,\r
+    ioctl:      cgu_ioctl,\r
+    open:       cgu_open,\r
+    release:    cgu_release\r
+};\r
+\r
+static struct miscdevice cgu_miscdev = {\r
+    MISC_DYNAMIC_MINOR,\r
+    "danube_cgu_dev",\r
+    &cgu_fops\r
+};\r
+\r
+\r
+/*\r
+ * ####################################\r
+ *           Global Variable\r
+ * ####################################\r
+ */\r
+\r
+\r
+/*\r
+ * ####################################\r
+ *            Local Function\r
+ * ####################################\r
+ */\r
+\r
+static ssize_t cgu_read(struct file *file, char *buf, size_t count, loff_t *ppos)\r
+{\r
+    return -EPERM;\r
+}\r
+\r
+static ssize_t cgu_write(struct file *file, const char *buf, size_t count, loff_t *ppos)\r
+{\r
+    return -EPERM;\r
+}\r
+\r
+static int cgu_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)\r
+{\r
+    int ret = 0;\r
+    struct cgu_clock_rates rates;\r
+\r
+    if ( _IOC_TYPE(cmd) != CGU_IOC_MAGIC\r
+        || _IOC_NR(cmd) >= CGU_IOC_MAXNR )\r
+        return -ENOTTY;\r
+\r
+    if ( _IOC_DIR(cmd) & _IOC_READ )\r
+        ret = !access_ok(VERIFY_WRITE, arg, _IOC_SIZE(cmd));\r
+    else if ( _IOC_DIR(cmd) & _IOC_WRITE )\r
+        ret = !access_ok(VERIFY_READ, arg, _IOC_SIZE(cmd));\r
+    if ( ret )\r
+        return -EFAULT;\r
+\r
+    switch ( cmd )\r
+    {\r
+    case CGU_GET_CLOCK_RATES:\r
+        /*  Calculate Clock Rates   */\r
+        rates.mips0     = cgu_get_mips_clock(0);\r
+        rates.mips1     = cgu_get_mips_clock(1);\r
+        rates.cpu       = cgu_get_cpu_clock();\r
+        rates.io_region = cgu_get_io_region_clock();\r
+        rates.fpi_bus1  = cgu_get_fpi_bus_clock(1);\r
+        rates.fpi_bus2  = cgu_get_fpi_bus_clock(2);\r
+        rates.pp32      = cgu_get_pp32_clock();\r
+        rates.pci       = cgu_get_pci_clock();\r
+        rates.ethernet  = cgu_get_ethernet_clock();\r
+        rates.usb       = cgu_get_usb_clock();\r
+        rates.clockout0 = cgu_get_clockout(0);\r
+        rates.clockout1 = cgu_get_clockout(1);\r
+        rates.clockout2 = cgu_get_clockout(2);\r
+        rates.clockout3 = cgu_get_clockout(3);\r
+        /*  Copy to User Space      */\r
+        copy_to_user((char*)arg, (char*)&rates, sizeof(rates));\r
+\r
+        ret = 0;\r
+        break;\r
+    default:\r
+        ret = -ENOTTY;\r
+    }\r
+\r
+    return ret;\r
+}\r
+\r
+static int cgu_open(struct inode *inode, struct file *file)\r
+{\r
+    return 0;\r
+}\r
+\r
+static int cgu_release(struct inode *inode, struct file *file)\r
+{\r
+    return 0;\r
+}\r
+\r
+/*\r
+ *  Description:\r
+ *    calculate 64-bit multiplication result of two 32-bit unsigned integer\r
+ *  Input:\r
+ *    u32Multiplier1 --- u32 (32-bit), one of the multipliers\r
+ *    u32Multiplier2 --- u32 (32-bit), the other multiplier\r
+ *    u32Result      --- u32[2], array to retrieve the multiplication result,\r
+ *                       index 0 is high word, index 1 is low word\r
+ *  Output:\r
+*    none\r
+ */\r
+static inline void uint64_multiply(u32 u32Multiplier1, u32 u32Multiplier2, u32 u32Result[2])\r
+{\r
+       u32 u32Multiplier1LowWord = u32Multiplier1 & 0xFFFF;\r
+       u32 u32Multiplier1HighWord = u32Multiplier1 >> 16;\r
+       u32 u32Multiplier2LowWord = u32Multiplier2 & 0xFFFF;\r
+       u32 u32Multiplier2HighWord = u32Multiplier2 >> 16;\r
+       u32 u32Combo1, u32Combo2, u32Combo3, u32Combo4;\r
+       u32 u32Word1, u32Word2, u32Word3, u32Word4;\r
+\r
+       u32Combo1 = u32Multiplier1LowWord * u32Multiplier2LowWord;\r
+       u32Combo2 = u32Multiplier1HighWord * u32Multiplier2LowWord;\r
+       u32Combo3 = u32Multiplier1LowWord * u32Multiplier2HighWord;\r
+       u32Combo4 = u32Multiplier1HighWord * u32Multiplier2HighWord;\r
+\r
+       u32Word1 = u32Combo1 & 0xFFFF;\r
+       u32Word2 = (u32Combo1 >> 16) + (u32Combo2 & 0xFFFF) + (u32Combo3 & 0xFFFF);\r
+       u32Word3 = (u32Combo2 >> 16) + (u32Combo3 >> 16) + (u32Combo4 & 0xFFFF) + (u32Word2 >> 16);\r
+       u32Word4 = (u32Combo4 >> 16) + (u32Word3 >> 16);\r
+\r
+       u32Result[0] = (u32Word4 << 16) | u32Word3;\r
+       u32Result[1] = (u32Word2 << 16) | u32Word1;\r
+}\r
+\r
+/*\r
+ *  Description:\r
+ *    divide 64-bit unsigned integer with 32-bit unsigned integer\r
+ *  Input:\r
+ *    u32Numerator   --- u32[2], index 0 is high word of numerator, while\r
+ *                       index 1 is low word of numerator\r
+ *    u32Denominator --- u32 (32-bit), the denominator in division, this\r
+ *                       parameter can not be zero, or lead to unpredictable\r
+ *                       result\r
+ *    pu32Quotient   --- u32 *, the pointer to retrieve 32-bit quotient, null\r
+ *                       pointer means ignore quotient\r
+ *    pu32Residue    --- u32 *, the pointer to retrieve 32-bit residue null\r
+ *                       pointer means ignore residue\r
+ *  Output:\r
+ *    none\r
+ */\r
+static inline void uint64_divide(u32 u32Numerator[2], u32 u32Denominator, u32 *pu32Quotient, u32 *pu32Residue)\r
+{\r
+       u32 u32DWord1, u32DWord2, u32DWord3;\r
+       u32 u32Quotient;\r
+       int i;\r
+\r
+       u32DWord3 = 0;\r
+       u32DWord2 = u32Numerator[0];\r
+       u32DWord1 = u32Numerator[1];\r
+\r
+       u32Quotient = 0;\r
+\r
+       for ( i = 0; i < 64; i++ )\r
+       {\r
+               u32DWord3 = (u32DWord3 << 1) | (u32DWord2 >> 31);\r
+               u32DWord2 = (u32DWord2 << 1) | (u32DWord1 >> 31);\r
+               u32DWord1 <<= 1;\r
+               u32Quotient <<= 1;\r
+               if ( u32DWord3 >= u32Denominator )\r
+               {\r
+                       u32DWord3 -= u32Denominator;\r
+                       u32Quotient |= 1;\r
+               }\r
+       }\r
+       if ( pu32Quotient )\r
+           *pu32Quotient = u32Quotient;\r
+       if ( pu32Residue )\r
+           *pu32Residue = u32DWord3;\r
+}\r
+\r
+/*\r
+ *  Description:\r
+ *    common routine to calculate PLL frequency\r
+ *  Input:\r
+ *    num --- u32, numerator\r
+ *    den --- u32, denominator\r
+ *  Output:\r
+ *    u32 --- frequency the PLL output\r
+ */\r
+static inline u32 cal_dsm(u32 num, u32 den)\r
+{\r
+    u32 ret;\r
+    u32 temp[2];\r
+    u32 residue;\r
+\r
+    uint64_multiply(num, BASIC_INPUT_CLOCK_FREQUENCY, temp);\r
+    uint64_divide(temp, den, &ret, &residue);\r
+    if ( (residue << 1) >= den )\r
+        ret++;\r
+\r
+    return ret;\r
+}\r
+\r
+/*\r
+ *  Description:\r
+ *    calculate PLL frequency following MASH-DSM\r
+ *  Input:\r
+ *    M   --- u32, denominator coefficient\r
+ *    N   --- u32, numerator integer coefficient\r
+ *    K   --- u32, numerator fraction coefficient\r
+ *  Output:\r
+ *    u32 --- frequency the PLL output\r
+ */\r
+static inline u32 mash_dsm(u32 M, u32 N, u32 K)\r
+{\r
+    u32 num = ((N + 1) << 10) + K;\r
+    u32 den = (M + 1) << 10;\r
+\r
+    return cal_dsm(num, den);\r
+}\r
+\r
+/*\r
+ *  Description:\r
+ *    calculate PLL frequency following SSFF-DSM (0.25 < fraction < 0.75)\r
+ *  Input:\r
+ *    M   --- u32, denominator coefficient\r
+ *    N   --- u32, numerator integer coefficient\r
+ *    K   --- u32, numerator fraction coefficient\r
+ *  Output:\r
+ *    u32 --- frequency the PLL output\r
+ */\r
+static inline u32 ssff_dsm_1(u32 M, u32 N, u32 K)\r
+{\r
+    u32 num = ((N + 1) << 11) + K + 512;\r
+    u32 den = (M + 1) << 11;\r
+\r
+    return cal_dsm(num, den);\r
+}\r
+\r
+/*\r
+ *  Description:\r
+ *    calculate PLL frequency following SSFF-DSM\r
+ *    (fraction < 0.125 || fraction > 0.875)\r
+ *  Input:\r
+ *    M   --- u32, denominator coefficient\r
+ *    N   --- u32, numerator integer coefficient\r
+ *    K   --- u32, numerator fraction coefficient\r
+ *  Output:\r
+ *    u32 --- frequency the PLL output\r
+ */\r
+static inline u32 ssff_dsm_2(u32 M, u32 N, u32 K)\r
+{\r
+    u32 num = K >= 512 ? ((N + 1) << 12) + K - 512 : ((N + 1) << 12) + K + 3584;\r
+    u32 den = (M + 1) << 12;\r
+\r
+    return cal_dsm(num, den);\r
+}\r
+\r
+/*\r
+ *  Description:\r
+ *    calculate PLL frequency\r
+ *  Input:\r
+ *    M            --- u32, denominator coefficient\r
+ *    N            --- u32, numerator integer coefficient\r
+ *    K            --- u32, numerator fraction coefficient\r
+ *    dsmsel       --- int, 0: MASH-DSM, 1: SSFF-DSM\r
+ *    phase_div_en --- int, 0: 0.25 < fraction < 0.75\r
+ *                          1: fraction < 0.125 || fraction > 0.875\r
+ *  Output:\r
+ *    u32          --- frequency the PLL output\r
+ */\r
+static inline u32 dsm(u32 M, u32 N, u32 K, int dsmsel, int phase_div_en)\r
+{\r
+    if ( !dsmsel )\r
+        return mash_dsm(M, N, K);\r
+    else\r
+        if ( !phase_div_en )\r
+            return ssff_dsm_1(M, N, K);\r
+        else\r
+            return ssff_dsm_2(M, N, K);\r
+}\r
+\r
+/*\r
+ *  Description:\r
+ *    get oscillate frequency of PLL0\r
+ *  Input:\r
+ *    none\r
+ *  Output:\r
+ *    u32 --- frequency of PLL0 Fosc\r
+ */\r
+static inline u32 cgu_get_pll0_fosc(void)\r
+{\r
+    return CGU_PLL_SR0_PLLB ? BASIC_INPUT_CLOCK_FREQUENCY : dsm(CGU_PLL_NMK0_PLLM, CGU_PLL_NMK0_PLLN, CGU_PLL_NMK0_PLLK, CGU_PLL_SR0_DSMSEL, CGU_PLL_SR0_PHASE_DIV_EN);\r
+}\r
+\r
+/*\r
+ *  Description:\r
+ *    get output frequency of PLL0 phase shifter\r
+ *  Input:\r
+ *    none\r
+ *  Output:\r
+ *    u32 --- frequency of PLL0 Fps\r
+ */\r
+static inline u32 cgu_get_pll0_fps(void)\r
+{\r
+    register u32 fps = cgu_get_pll0_fosc();\r
+\r
+    switch ( CGU_PLL_SR0_PLLPSE )\r
+    {\r
+    case 1:\r
+        /*  1.5     */\r
+        fps = ((fps << 1) + 1) / 3; break;\r
+    case 2:\r
+        /*  1.25    */\r
+        fps = ((fps << 2) + 2) / 5; break;\r
+    case 3:\r
+        /*  3.5     */\r
+        fps = ((fps << 1) + 3) / 7;\r
+    }\r
+    return fps;\r
+}\r
+\r
+/*\r
+ *  Description:\r
+ *    get output frequency of PLL0 output divider\r
+ *  Input:\r
+ *    none\r
+ *  Output:\r
+ *    u32 --- frequency of PLL0 Fdiv\r
+ */\r
+static inline u32 cgu_get_pll0_fdiv(void)\r
+{\r
+    register u32 fdiv = cgu_get_pll0_fosc();\r
+\r
+    if ( CGU_PLL_SR0_PLLDEN )\r
+        fdiv = (fdiv + (CGU_PLL_SR0_PLLDIV + 1) / 2) / (CGU_PLL_SR0_PLLDIV + 1);\r
+    return fdiv;\r
+}\r
+\r
+/*\r
+ *  Description:\r
+ *    get oscillate frequency of PLL1\r
+ *  Input:\r
+ *    none\r
+ *  Output:\r
+ *    u32 --- frequency of PLL1 Fosc\r
+ */\r
+static inline u32 cgu_get_pll1_fosc(void)\r
+{\r
+    return CGU_PLL_SR1_PLLB ? BASIC_INPUT_CLOCK_FREQUENCY : dsm(CGU_PLL_NMK1_PLLM, CGU_PLL_NMK1_PLLN, CGU_PLL_NMK1_PLLK, CGU_PLL_SR1_DSMSEL, CGU_PLL_SR1_PHASE_DIV_EN);\r
+}\r
+\r
+/*\r
+ *  Description:\r
+ *    get output frequency of PLL1 phase shifter\r
+ *  Input:\r
+ *    none\r
+ *  Output:\r
+ *    u32 --- frequency of PLL1 Fps\r
+ */\r
+static inline u32 cgu_get_pll1_fps(void)\r
+{\r
+    register u32 fps = cgu_get_pll1_fosc();\r
+\r
+    switch ( CGU_PLL_SR1_PLLPSE )\r
+    {\r
+    case 1:\r
+        /*  1.5     */\r
+        fps = ((fps << 1) + 1) / 3; break;\r
+    case 2:\r
+        /*  1.25    */\r
+        fps = ((fps << 2) + 2) / 5; break;\r
+    case 3:\r
+        /*  3.5     */\r
+        fps = ((fps << 1) + 3) / 7;\r
+    }\r
+    return fps;\r
+}\r
+\r
+/*\r
+ *  Description:\r
+ *    get output frequency of PLL1 output divider\r
+ *  Input:\r
+ *    none\r
+ *  Output:\r
+ *    u32 --- frequency of PLL1 Fdiv\r
+ */\r
+static inline u32 cgu_get_pll1_fdiv(void)\r
+{\r
+    register u32 fdiv = cgu_get_pll1_fosc();\r
+\r
+    if ( CGU_PLL_SR1_PLLDEN )\r
+        fdiv = (fdiv + (CGU_PLL_SR1_PLLDIV + 1) / 2) / (CGU_PLL_SR1_PLLDIV + 1);\r
+    return fdiv;\r
+}\r
+\r
+/*\r
+ *  Description:\r
+ *    get oscillate frequency of PLL2\r
+ *  Input:\r
+ *    none\r
+ *  Output:\r
+ *    u32 --- frequency of PLL2 Fosc\r
+ */\r
+static inline u32 cgu_get_pll2_fosc(void)\r
+{\r
+    u32 ret;\r
+    u32 temp[2];\r
+    u32 residue;\r
+\r
+    uint64_multiply((CGU_PLL_SR2_PLLN + 1) * 8, cgu_get_pll0_fdiv(), temp);\r
+    uint64_divide(temp, CGU_PLL_SR2_PLLM + 1, &ret, &residue);\r
+    if ( (residue << 1) >= CGU_PLL_SR2_PLLM )\r
+        ret++;\r
+\r
+    return ret;\r
+}\r
+\r
+/*\r
+ *  Description:\r
+ *    get output frequency of PLL2 phase shifter\r
+ *  Input:\r
+ *    none\r
+ *  Output:\r
+ *    u32 --- frequency of PLL2 Fps\r
+ */\r
+static inline u32 cgu_get_pll2_fps(void)\r
+{\r
+    register u32 fps = cgu_get_pll2_fosc();\r
+\r
+    if ( CGU_PLL_SR2_PLLPE )\r
+    {\r
+        if ( CGU_PLL_SR2_PLLPS )\r
+            /*  1.25    */\r
+            fps = ((fps << 3) + 4) / 9;\r
+        else\r
+            /*  1.125   */\r
+            fps = ((fps << 2) + 2) / 5;\r
+    }\r
+\r
+    return fps;\r
+}\r
+\r
+\r
+/*\r
+ * ####################################\r
+ *           Global Function\r
+ * ####################################\r
+ */\r
+\r
+/*\r
+ *  Description:\r
+ *    get frequency of MIPS (0: core, 1: DSP)\r
+ *  Input:\r
+ *    cpu --- int, 0: core, 1: DSP\r
+ *  Output:\r
+ *    u32 --- frequency of MIPS coprocessor (0: core, 1: DSP)\r
+ */\r
+u32 cgu_get_mips_clock(int cpu)\r
+{\r
+    register u32 ret = cgu_get_pll0_fosc();\r
+\r
+    if ( CGU_CRD_CRD )\r
+        ret = (ret + (CGU_CRD_CRD >> 1)) / (CGU_CRD_CRD + 1);\r
+    if ( cpu == 0 && CGU_CRD_CRD1 )\r
+        ret >>= CGU_CRD_CRD1;\r
+    return ret;\r
+}\r
+\r
+/*\r
+ *  Description:\r
+ *    get frequency of MIPS core\r
+ *  Input:\r
+ *    none\r
+ *  Output:\r
+ *    u32 --- frequency of MIPS core\r
+ */\r
+u32 cgu_get_cpu_clock(void)\r
+{\r
+    return cgu_get_mips_clock(0);\r
+}\r
+\r
+/*\r
+ *  Description:\r
+ *    get frequency of sub-system and memory controller\r
+ *  Input:\r
+ *    none\r
+ *  Output:\r
+ *    u32 --- frequency of sub-system and memory controller\r
+ */\r
+u32 cgu_get_io_region_clock(void)\r
+{\r
+    register u32 ret = (CGU_MUX_SUB_SYS > 4) ? cgu_get_pll0_fosc() : cgu_get_mips_clock(1);\r
+\r
+    switch ( CGU_MUX_SUB_SYS )\r
+    {\r
+    case 0:\r
+        break;\r
+    case 1:\r
+    default:\r
+        ret = (ret + 1) >> 1; break;\r
+    case 2:\r
+        ret = (ret + 1) / 3; break;\r
+    case 3:\r
+        ret = (ret + 2) >> 2; break;\r
+    case 5:\r
+        ret = ((ret << 1) + 1) / 3; break;\r
+    case 6:\r
+        ret = ((ret << 1) + 2) / 5;\r
+    }\r
+\r
+    return ret;\r
+}\r
+\r
+/*\r
+ *  Description:\r
+ *    get frequency of FPI bus\r
+ *  Input:\r
+ *    fpi --- int, 1: FPI bus 1 (FBS1/Fast FPI Bus), 2: FPI bus 2 (FBS2)\r
+ *  Output:\r
+ *    u32 --- frequency of FPI bus\r
+ */\r
+u32 cgu_get_fpi_bus_clock(int fpi)\r
+{\r
+    register u32 ret = cgu_get_io_region_clock();\r
+\r
+    if ( fpi == 2 )\r
+        ret >>= 1;\r
+    return ret;\r
+}\r
+\r
+/*\r
+ *  Description:\r
+ *    get frequency of PP32 processor\r
+ *  Input:\r
+ *    none\r
+ *  Output:\r
+ *    u32 --- frequency of PP32 processor\r
+ */\r
+u32 cgu_get_pp32_clock(void)\r
+{\r
+    register u32 ret;\r
+\r
+    switch ( CGU_MUX_PP32 )\r
+    {\r
+    case 0:\r
+    default:\r
+        ret = ((cgu_get_pll2_fosc() << 2) + 2) / 5; break;\r
+    case 1:\r
+        ret = ((cgu_get_pll2_fosc() << 3) + 4) / 9; break;\r
+    case 2:\r
+        ret = cgu_get_fpi_bus_clock(1); break;\r
+    case 3:\r
+        ret = cgu_get_mips_clock(1);\r
+    }\r
+\r
+    return ret;\r
+}\r
+\r
+/*\r
+ *  Description:\r
+ *    get frequency of PCI bus\r
+ *  Input:\r
+ *    none\r
+ *  Output:\r
+ *    u32 --- frequency of PCI bus\r
+ */\r
+u32 cgu_get_pci_clock(void)\r
+{\r
+    register u32 ret = 0;\r
+\r
+    if ( !CGU_IF_CLK_PCIS )\r
+    {\r
+        ret = cgu_get_pll2_fosc();\r
+        if ( CGU_IF_CLK_PCIF )\r
+            ret = (ret + 2) / 5;\r
+        else\r
+            ret = (ret + 4) / 9;\r
+    }\r
+\r
+    return ret;\r
+}\r
+\r
+/*\r
+ *  Description:\r
+ *    get frequency of ethernet module (MII)\r
+ *  Input:\r
+ *    none\r
+ *  Output:\r
+ *    u32 --- frequency of ethernet module\r
+ */\r
+u32 cgu_get_ethernet_clock(void)\r
+{\r
+    register u32 ret = 0;\r
+\r
+    if ( !CGU_IF_CLK_MIICS )\r
+    {\r
+        ret = cgu_get_pll2_fosc();\r
+        if ( CGU_MUX_MII_CLK )\r
+            ret = (ret + 3) / 6;\r
+        else\r
+            ret = (ret + 6) / 12;\r
+    }\r
+\r
+    return ret;\r
+}\r
+\r
+/*\r
+ *  Description:\r
+ *    get frequency of USB\r
+ *  Input:\r
+ *    none\r
+ *  Output:\r
+ *    u32 --- frequency of USB\r
+ */\r
+u32 cgu_get_usb_clock(void)\r
+{\r
+    return CGU_IF_CLK_USBCS ? 12000000 : (cgu_get_pll2_fosc() + 12) / 25;\r
+}\r
+\r
+/*\r
+ *  Description:\r
+ *    get frequency of CLK_OUT pin\r
+ *  Input:\r
+ *    clkout --- int, clock out pin number\r
+ *  Output:\r
+ *    u32    --- frequency of CLK_OUT pin\r
+ */\r
+u32 cgu_get_clockout(int clkout)\r
+{\r
+    u32 fosc1 = cgu_get_pll1_fosc();\r
+    u32 fosc2 = cgu_get_pll2_fosc();\r
+\r
+    if ( clkout > 3 || clkout < 0 )\r
+        return 0;\r
+\r
+    switch ( ((u32)clkout << 2) | GET_BITS(*DANUBE_CGU_IF_CLK, 21 + clkout * 2, 20 + clkout * 2) )\r
+    {\r
+    case 0: /*  32.768KHz   */\r
+    case 14:\r
+        return (fosc1 + 6000) / 12000;\r
+    case 1: /*  1.536MHz    */\r
+        return (fosc1 + 128) / 256;\r
+    case 2: /*  2.5MHz      */\r
+        return (fosc2 + 60) / 120;\r
+    case 3: /*  12MHz       */\r
+    case 5:\r
+    case 12:\r
+        return (fosc2 + 12) / 25;\r
+    case 4: /*  40MHz       */\r
+        return (fosc2 * 2 + 7) / 15;\r
+    case 6: /*  24MHz       */\r
+        return (fosc2 * 2 + 12) / 25;\r
+    case 7: /*  48MHz       */\r
+        return (fosc2 * 4 + 12) / 25;\r
+    case 8: /*  25MHz       */\r
+    case 15:\r
+        return (fosc2 + 6) / 12;\r
+    case 9: /*  50MHz       */\r
+    case 13:\r
+        return (fosc2 + 3) / 6;\r
+    case 10:/*  30MHz       */\r
+        return (fosc2 + 5) / 10;\r
+    case 11:/*  60MHz       */\r
+        return (fosc2 + 2) / 5;\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+\r
+/*\r
+ * ####################################\r
+ *           Init/Cleanup API\r
+ * ####################################\r
+ */\r
+\r
+/*\r
+ *  Description:\r
+ *    register device\r
+ *  Input:\r
+ *    none\r
+ *  Output:\r
+ *    0    --- successful\r
+ *    else --- failure, usually it is negative value of error code\r
+ */\r
+int __init danube_cgu_init(void)\r
+{\r
+    int ret;\r
+\r
+    ret = misc_register(&cgu_miscdev);\r
+    if ( ret )\r
+    {\r
+        printk(KERN_ERR "cgu: can't misc_register\n");\r
+        return ret;\r
+    }\r
+    else\r
+        printk(KERN_INFO "cgu: misc_register on minor = %d\n", cgu_miscdev.minor);\r
+\r
+    /*\r
+     *  initialize fake registers to do testing on Amazon\r
+     */\r
+#if defined(DEBUG_ON_AMAZON) && DEBUG_ON_AMAZON\r
+    #ifdef  DEBUG_PRINT_INFO\r
+    #undef  DEBUG_PRINT_INFO\r
+    #endif\r
+    #define DEBUG_PRINT_INFO    1\r
+\r
+    *DANUBE_CGU_DIV         = 0x00010019;\r
+    *DANUBE_CGU_PLL_NMK0    = 0x416002C3;\r
+    *DANUBE_CGU_PLL_SR0     = 0x74000013;\r
+    *DANUBE_CGU_PLL_NMK1    = 0x4C60009C;\r
+    *DANUBE_CGU_PLL_SR1     = 0x54000013;\r
+    *DANUBE_CGU_PLL_SR2     = 0x58890013;\r
+    *DANUBE_CGU_IF_CLK      = 0x00000000;\r
+    *DANUBE_CGU_OSC_CTRL    = 0x00000000;\r
+    *DANUBE_CGU_SMD         = 0x00000000;\r
+    *DANUBE_CGU_CRD         = 0x00010000;\r
+    *DANUBE_CGU_CT1SR       = 0x00000000;\r
+    *DANUBE_CGU_CT2SR       = CGU_PLL_NMK1_PLLK;\r
+    *DANUBE_CGU_PCMCR       = 0x00000000;\r
+    *DANUBE_CGU_MUX         = 0x00000008;\r
+#endif  //  defined(DEBUG_ON_AMAZON) && DEBUG_ON_AMAZON\r
+\r
+    /*\r
+     *  for testing only\r
+     */\r
+#if defined(DEBUG_PRINT_INFO) && DEBUG_PRINT_INFO\r
+    printk("pll0 N = %d, M = %d, K = %d, DIV = %d\n", CGU_PLL_NMK0_PLLN, CGU_PLL_NMK0_PLLM, CGU_PLL_NMK0_PLLK, CGU_PLL_SR0_PLLDIV);\r
+    printk("pll1 N = %d, M = %d, K = %d, DIV = %d\n", CGU_PLL_NMK1_PLLN, CGU_PLL_NMK1_PLLM, CGU_PLL_NMK1_PLLK, CGU_PLL_SR1_PLLDIV);\r
+    printk("pll2 N = %d, M = %d, DIV = %d\n", CGU_PLL_SR2_PLLN, CGU_PLL_SR2_PLLM, CGU_PLL_SR2_PLLDIV);\r
+    printk("pll0_fosc    = %d\n", cgu_get_pll0_fosc());\r
+    printk("pll0_fps     = %d\n", cgu_get_pll0_fps());\r
+    printk("pll0_fdiv    = %d\n", cgu_get_pll0_fdiv());\r
+    printk("pll1_fosc    = %d\n", cgu_get_pll1_fosc());\r
+    printk("pll1_fps     = %d\n", cgu_get_pll1_fps());\r
+    printk("pll1_fdiv    = %d\n", cgu_get_pll1_fdiv());\r
+    printk("pll2_fosc    = %d\n", cgu_get_pll2_fosc());\r
+    printk("pll2_fps     = %d\n", cgu_get_pll2_fps());\r
+    printk("mips0 clock  = %d\n", cgu_get_mips_clock(0));\r
+    printk("mips1 clock  = %d\n", cgu_get_mips_clock(1));\r
+    printk("cpu clock    = %d\n", cgu_get_cpu_clock());\r
+    printk("IO region    = %d\n", cgu_get_io_region_clock());\r
+    printk("FPI bus 1    = %d\n", cgu_get_fpi_bus_clock(1));\r
+    printk("FPI bus 2    = %d\n", cgu_get_fpi_bus_clock(2));\r
+    printk("PP32 clock   = %d\n", cgu_get_pp32_clock());\r
+    printk("PCI clock    = %d\n", cgu_get_pci_clock());\r
+    printk("Ethernet     = %d\n", cgu_get_ethernet_clock());\r
+    printk("USB clock    = %d\n", cgu_get_usb_clock());\r
+    printk("Clockout0    = %d\n", cgu_get_clockout(0));\r
+    printk("Clockout1    = %d\n", cgu_get_clockout(1));\r
+    printk("Clockout2    = %d\n", cgu_get_clockout(2));\r
+    printk("Clockout3    = %d\n", cgu_get_clockout(3));\r
+#endif  //  defined(DEBUG_PRINT_INFO) && DEBUG_PRINT_INFO\r
+\r
+    return 0;\r
+}\r
+\r
+/*\r
+ *  Description:\r
+ *    deregister device\r
+ *  Input:\r
+ *    none\r
+ *  Output:\r
+ *    none\r
+ */\r
+void __exit danube_cgu_exit(void)\r
+{\r
+    int ret;\r
+\r
+    ret = misc_deregister(&cgu_miscdev);\r
+    if ( ret )\r
+        printk(KERN_ERR "cgu: can't misc_deregister, get error number %d\n", -ret);\r
+    else\r
+        printk(KERN_INFO "cgu: misc_deregister successfully\n");\r
+}\r
+\r
+module_init(danube_cgu_init);\r
+module_exit(danube_cgu_exit);\r