Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (c) Intel Corp. 2007.
0004  * All Rights Reserved.
0005  *
0006  * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
0007  * develop this driver.
0008  *
0009  * This file is part of the Carillo Ranch video subsystem driver.
0010  *
0011  * Authors:
0012  *   Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
0013  *   Alan Hourihane <alanh-at-tungstengraphics-dot-com>
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 /* The PLL Clock register sits on Host bridge */
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          * There are more clocks, but they are disabled on the CR board.
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");