cpu.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:3k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/arch/arm/mach-integrator/cpu.c
  3.  *
  4.  *  Copyright (C) 2001 Deep Blue Solutions Ltd.
  5.  *
  6.  *  $Id: cpu.c,v 1.2 2001/09/22 12:11:17 rmk Exp $
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify
  9.  * it under the terms of the GNU General Public License version 2 as
  10.  * published by the Free Software Foundation.
  11.  *
  12.  * CPU support functions
  13.  */
  14. #include <linux/config.h>
  15. #include <linux/types.h>
  16. #include <linux/kernel.h>
  17. #include <linux/cpufreq.h>
  18. #include <linux/init.h>
  19. #include <asm/hardware.h>
  20. #include <asm/io.h>
  21. #define CM_ID   (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_ID_OFFSET)
  22. #define CM_OSC (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_OSC_OFFSET)
  23. #define CM_STAT (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_STAT_OFFSET)
  24. #define CM_LOCK (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET)
  25. struct vco {
  26. unsigned char vdw;
  27. unsigned char od;
  28. };
  29. /*
  30.  * Divisors for each OD setting.
  31.  */
  32. static unsigned char cc_divisor[8] = { 10, 2, 8, 4, 5, 7, 9, 6 };
  33. static unsigned int vco_to_freq(struct vco vco, int factor)
  34. {
  35. return 2000 * (vco.vdw + 8) / cc_divisor[vco.od] / factor;
  36. }
  37. #ifdef CONFIG_CPU_FREQ
  38. /*
  39.  * Divisor indexes for in ascending divisor order
  40.  */
  41. static unsigned char s2od[] = { 1, 3, 4, 7, 5, 2, 6, 0 };
  42. static struct vco freq_to_vco(unsigned int freq_khz, int factor)
  43. {
  44. struct vco vco = {0, 0};
  45. unsigned int i, f;
  46. freq_khz *= factor;
  47. for (i = 0; i < 8; i++) {
  48. f = freq_khz * cc_divisor[s2od[i]];
  49. /* f must be between 10MHz and 320MHz */
  50. if (f > 10000 && f <= 320000)
  51. break;
  52. }
  53. vco.od  = s2od[i];
  54. vco.vdw = f / 2000 - 8;
  55. return vco;
  56. }
  57. /*
  58.  * Validate the speed in khz.  If it is outside our
  59.  * range, then return the lowest.
  60.  */
  61. unsigned int integrator_validatespeed(unsigned int freq_khz)
  62. {
  63. struct vco vco;
  64. if (freq_khz < 12000)
  65. freq_khz = 12000;
  66. if (freq_khz > 160000)
  67. freq_khz = 160000;
  68. vco = freq_to_vco(freq_khz, 1);
  69. if (vco.vdw < 4 || vco.vdw > 152)
  70. return -EINVAL;
  71. return vco_to_freq(vco, 1);
  72. }
  73. void integrator_setspeed(unsigned int freq_khz)
  74. {
  75. struct vco vco = freq_to_vco(freq_khz, 1);
  76. u_int cm_osc;
  77. cm_osc = __raw_readl(CM_OSC);
  78. cm_osc &= 0xfffff800;
  79. cm_osc |= vco.vdw | vco.od << 8;
  80. __raw_writel(0xa05f, CM_LOCK);
  81. __raw_writel(cm_osc, CM_OSC);
  82. __raw_writel(0, CM_LOCK);
  83. }
  84. #endif
  85. static int __init cpu_init(void)
  86. {
  87. u_int cm_osc, cm_stat, cpu_freq_khz, mem_freq_khz;
  88. struct vco vco;
  89. cm_osc = __raw_readl(CM_OSC);
  90. vco.od  = (cm_osc >> 20) & 7;
  91. vco.vdw = (cm_osc >> 12) & 255;
  92. mem_freq_khz = vco_to_freq(vco, 2);
  93. printk(KERN_INFO "Memory clock = %d.%03d MHzn",
  94. mem_freq_khz / 1000, mem_freq_khz % 1000);
  95. vco.od = (cm_osc >> 8) & 7;
  96. vco.vdw = cm_osc & 255;
  97. cpu_freq_khz = vco_to_freq(vco, 1);
  98. #ifdef CONFIG_CPU_FREQ
  99. cpufreq_init(cpu_freq_khz, 1000, 0);
  100. cpufreq_setfunctions(integrator_validatespeed, integrator_setspeed);
  101. #endif
  102. cm_stat = __raw_readl(CM_STAT);
  103. printk("Module id: %dn", cm_stat & 255);
  104. return 0;
  105. }
  106. __initcall(cpu_init);