mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
195 lines
4.0 KiB
195 lines
4.0 KiB
// SPDX-License-Identifier: GPL-2.0-or-later |
|
/* |
|
* Copyright (c) Intel Corp. 2007. |
|
* All Rights Reserved. |
|
* |
|
* Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to |
|
* develop this driver. |
|
* |
|
* This file is part of the Carillo Ranch video subsystem driver. |
|
* |
|
* Authors: |
|
* Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> |
|
* Alan Hourihane <alanh-at-tungstengraphics-dot-com> |
|
*/ |
|
|
|
#include <linux/module.h> |
|
#include <linux/kernel.h> |
|
#include <linux/pci.h> |
|
#include <linux/errno.h> |
|
#include <linux/fb.h> |
|
#include "vermilion.h" |
|
|
|
/* The PLL Clock register sits on Host bridge */ |
|
#define CRVML_DEVICE_MCH 0x5001 |
|
#define CRVML_REG_MCHBAR 0x44 |
|
#define CRVML_REG_MCHEN 0x54 |
|
#define CRVML_MCHEN_BIT (1 << 28) |
|
#define CRVML_MCHMAP_SIZE 4096 |
|
#define CRVML_REG_CLOCK 0xc3c |
|
#define CRVML_CLOCK_SHIFT 8 |
|
#define CRVML_CLOCK_MASK 0x00000f00 |
|
|
|
static struct pci_dev *mch_dev; |
|
static u32 mch_bar; |
|
static void __iomem *mch_regs_base; |
|
static u32 saved_clock; |
|
|
|
static const unsigned crvml_clocks[] = { |
|
6750, |
|
13500, |
|
27000, |
|
29700, |
|
37125, |
|
54000, |
|
59400, |
|
74250, |
|
120000 |
|
/* |
|
* There are more clocks, but they are disabled on the CR board. |
|
*/ |
|
}; |
|
|
|
static const u32 crvml_clock_bits[] = { |
|
0x0a, |
|
0x09, |
|
0x08, |
|
0x07, |
|
0x06, |
|
0x05, |
|
0x04, |
|
0x03, |
|
0x0b |
|
}; |
|
|
|
static const unsigned crvml_num_clocks = ARRAY_SIZE(crvml_clocks); |
|
|
|
static int crvml_sys_restore(struct vml_sys *sys) |
|
{ |
|
void __iomem *clock_reg = mch_regs_base + CRVML_REG_CLOCK; |
|
|
|
iowrite32(saved_clock, clock_reg); |
|
ioread32(clock_reg); |
|
|
|
return 0; |
|
} |
|
|
|
static int crvml_sys_save(struct vml_sys *sys) |
|
{ |
|
void __iomem *clock_reg = mch_regs_base + CRVML_REG_CLOCK; |
|
|
|
saved_clock = ioread32(clock_reg); |
|
|
|
return 0; |
|
} |
|
|
|
static int crvml_nearest_index(const struct vml_sys *sys, int clock) |
|
{ |
|
int i; |
|
int cur_index = 0; |
|
int cur_diff; |
|
int diff; |
|
|
|
cur_diff = clock - crvml_clocks[0]; |
|
cur_diff = (cur_diff < 0) ? -cur_diff : cur_diff; |
|
for (i = 1; i < crvml_num_clocks; ++i) { |
|
diff = clock - crvml_clocks[i]; |
|
diff = (diff < 0) ? -diff : diff; |
|
if (diff < cur_diff) { |
|
cur_index = i; |
|
cur_diff = diff; |
|
} |
|
} |
|
return cur_index; |
|
} |
|
|
|
static int crvml_nearest_clock(const struct vml_sys *sys, int clock) |
|
{ |
|
return crvml_clocks[crvml_nearest_index(sys, clock)]; |
|
} |
|
|
|
static int crvml_set_clock(struct vml_sys *sys, int clock) |
|
{ |
|
void __iomem *clock_reg = mch_regs_base + CRVML_REG_CLOCK; |
|
int index; |
|
u32 clock_val; |
|
|
|
index = crvml_nearest_index(sys, clock); |
|
|
|
if (crvml_clocks[index] != clock) |
|
return -EINVAL; |
|
|
|
clock_val = ioread32(clock_reg) & ~CRVML_CLOCK_MASK; |
|
clock_val = crvml_clock_bits[index] << CRVML_CLOCK_SHIFT; |
|
iowrite32(clock_val, clock_reg); |
|
ioread32(clock_reg); |
|
|
|
return 0; |
|
} |
|
|
|
static struct vml_sys cr_pll_ops = { |
|
.name = "Carillo Ranch", |
|
.save = crvml_sys_save, |
|
.restore = crvml_sys_restore, |
|
.set_clock = crvml_set_clock, |
|
.nearest_clock = crvml_nearest_clock, |
|
}; |
|
|
|
static int __init cr_pll_init(void) |
|
{ |
|
int err; |
|
u32 dev_en; |
|
|
|
mch_dev = pci_get_device(PCI_VENDOR_ID_INTEL, |
|
CRVML_DEVICE_MCH, NULL); |
|
if (!mch_dev) { |
|
printk(KERN_ERR |
|
"Could not find Carillo Ranch MCH device.\n"); |
|
return -ENODEV; |
|
} |
|
|
|
pci_read_config_dword(mch_dev, CRVML_REG_MCHEN, &dev_en); |
|
if (!(dev_en & CRVML_MCHEN_BIT)) { |
|
printk(KERN_ERR |
|
"Carillo Ranch MCH device was not enabled.\n"); |
|
pci_dev_put(mch_dev); |
|
return -ENODEV; |
|
} |
|
|
|
pci_read_config_dword(mch_dev, CRVML_REG_MCHBAR, |
|
&mch_bar); |
|
mch_regs_base = |
|
ioremap(mch_bar, CRVML_MCHMAP_SIZE); |
|
if (!mch_regs_base) { |
|
printk(KERN_ERR |
|
"Carillo Ranch MCH device was not enabled.\n"); |
|
pci_dev_put(mch_dev); |
|
return -ENODEV; |
|
} |
|
|
|
err = vmlfb_register_subsys(&cr_pll_ops); |
|
if (err) { |
|
printk(KERN_ERR |
|
"Carillo Ranch failed to initialize vml_sys.\n"); |
|
iounmap(mch_regs_base); |
|
pci_dev_put(mch_dev); |
|
return err; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static void __exit cr_pll_exit(void) |
|
{ |
|
vmlfb_unregister_subsys(&cr_pll_ops); |
|
|
|
iounmap(mch_regs_base); |
|
pci_dev_put(mch_dev); |
|
} |
|
|
|
module_init(cr_pll_init); |
|
module_exit(cr_pll_exit); |
|
|
|
MODULE_AUTHOR("Tungsten Graphics Inc."); |
|
MODULE_DESCRIPTION("Carillo Ranch PLL Driver"); |
|
MODULE_LICENSE("GPL");
|
|
|