0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #include <linux/module.h>
0017 #include <linux/kernel.h>
0018 #include <linux/pci.h>
0019 #include <linux/errno.h>
0020 #include <linux/fb.h>
0021 #include "vermilion.h"
0022
0023
0024 #define CRVML_DEVICE_MCH 0x5001
0025 #define CRVML_REG_MCHBAR 0x44
0026 #define CRVML_REG_MCHEN 0x54
0027 #define CRVML_MCHEN_BIT (1 << 28)
0028 #define CRVML_MCHMAP_SIZE 4096
0029 #define CRVML_REG_CLOCK 0xc3c
0030 #define CRVML_CLOCK_SHIFT 8
0031 #define CRVML_CLOCK_MASK 0x00000f00
0032
0033 static struct pci_dev *mch_dev;
0034 static u32 mch_bar;
0035 static void __iomem *mch_regs_base;
0036 static u32 saved_clock;
0037
0038 static const unsigned crvml_clocks[] = {
0039 6750,
0040 13500,
0041 27000,
0042 29700,
0043 37125,
0044 54000,
0045 59400,
0046 74250,
0047 120000
0048
0049
0050
0051 };
0052
0053 static const u32 crvml_clock_bits[] = {
0054 0x0a,
0055 0x09,
0056 0x08,
0057 0x07,
0058 0x06,
0059 0x05,
0060 0x04,
0061 0x03,
0062 0x0b
0063 };
0064
0065 static const unsigned crvml_num_clocks = ARRAY_SIZE(crvml_clocks);
0066
0067 static int crvml_sys_restore(struct vml_sys *sys)
0068 {
0069 void __iomem *clock_reg = mch_regs_base + CRVML_REG_CLOCK;
0070
0071 iowrite32(saved_clock, clock_reg);
0072 ioread32(clock_reg);
0073
0074 return 0;
0075 }
0076
0077 static int crvml_sys_save(struct vml_sys *sys)
0078 {
0079 void __iomem *clock_reg = mch_regs_base + CRVML_REG_CLOCK;
0080
0081 saved_clock = ioread32(clock_reg);
0082
0083 return 0;
0084 }
0085
0086 static int crvml_nearest_index(const struct vml_sys *sys, int clock)
0087 {
0088 int i;
0089 int cur_index = 0;
0090 int cur_diff;
0091 int diff;
0092
0093 cur_diff = clock - crvml_clocks[0];
0094 cur_diff = (cur_diff < 0) ? -cur_diff : cur_diff;
0095 for (i = 1; i < crvml_num_clocks; ++i) {
0096 diff = clock - crvml_clocks[i];
0097 diff = (diff < 0) ? -diff : diff;
0098 if (diff < cur_diff) {
0099 cur_index = i;
0100 cur_diff = diff;
0101 }
0102 }
0103 return cur_index;
0104 }
0105
0106 static int crvml_nearest_clock(const struct vml_sys *sys, int clock)
0107 {
0108 return crvml_clocks[crvml_nearest_index(sys, clock)];
0109 }
0110
0111 static int crvml_set_clock(struct vml_sys *sys, int clock)
0112 {
0113 void __iomem *clock_reg = mch_regs_base + CRVML_REG_CLOCK;
0114 int index;
0115 u32 clock_val;
0116
0117 index = crvml_nearest_index(sys, clock);
0118
0119 if (crvml_clocks[index] != clock)
0120 return -EINVAL;
0121
0122 clock_val = ioread32(clock_reg) & ~CRVML_CLOCK_MASK;
0123 clock_val = crvml_clock_bits[index] << CRVML_CLOCK_SHIFT;
0124 iowrite32(clock_val, clock_reg);
0125 ioread32(clock_reg);
0126
0127 return 0;
0128 }
0129
0130 static struct vml_sys cr_pll_ops = {
0131 .name = "Carillo Ranch",
0132 .save = crvml_sys_save,
0133 .restore = crvml_sys_restore,
0134 .set_clock = crvml_set_clock,
0135 .nearest_clock = crvml_nearest_clock,
0136 };
0137
0138 static int __init cr_pll_init(void)
0139 {
0140 int err;
0141 u32 dev_en;
0142
0143 mch_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
0144 CRVML_DEVICE_MCH, NULL);
0145 if (!mch_dev) {
0146 printk(KERN_ERR
0147 "Could not find Carillo Ranch MCH device.\n");
0148 return -ENODEV;
0149 }
0150
0151 pci_read_config_dword(mch_dev, CRVML_REG_MCHEN, &dev_en);
0152 if (!(dev_en & CRVML_MCHEN_BIT)) {
0153 printk(KERN_ERR
0154 "Carillo Ranch MCH device was not enabled.\n");
0155 pci_dev_put(mch_dev);
0156 return -ENODEV;
0157 }
0158
0159 pci_read_config_dword(mch_dev, CRVML_REG_MCHBAR,
0160 &mch_bar);
0161 mch_regs_base =
0162 ioremap(mch_bar, CRVML_MCHMAP_SIZE);
0163 if (!mch_regs_base) {
0164 printk(KERN_ERR
0165 "Carillo Ranch MCH device was not enabled.\n");
0166 pci_dev_put(mch_dev);
0167 return -ENODEV;
0168 }
0169
0170 err = vmlfb_register_subsys(&cr_pll_ops);
0171 if (err) {
0172 printk(KERN_ERR
0173 "Carillo Ranch failed to initialize vml_sys.\n");
0174 iounmap(mch_regs_base);
0175 pci_dev_put(mch_dev);
0176 return err;
0177 }
0178
0179 return 0;
0180 }
0181
0182 static void __exit cr_pll_exit(void)
0183 {
0184 vmlfb_unregister_subsys(&cr_pll_ops);
0185
0186 iounmap(mch_regs_base);
0187 pci_dev_put(mch_dev);
0188 }
0189
0190 module_init(cr_pll_init);
0191 module_exit(cr_pll_exit);
0192
0193 MODULE_AUTHOR("Tungsten Graphics Inc.");
0194 MODULE_DESCRIPTION("Carillo Ranch PLL Driver");
0195 MODULE_LICENSE("GPL");