Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) Intel Corp. 2007.
4 * All Rights Reserved.
5 *
6 * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
7 * develop this driver.
8 *
9 * This file is part of the Carillo Ranch video subsystem driver.
10 *
11 * Authors:
12 * Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
13 * Alan Hourihane <alanh-at-tungstengraphics-dot-com>
14 */
15
16#include <linux/module.h>
17#include <linux/kernel.h>
18#include <linux/pci.h>
19#include <linux/errno.h>
20#include <linux/fb.h>
21#include "vermilion.h"
22
23/* The PLL Clock register sits on Host bridge */
24#define CRVML_DEVICE_MCH 0x5001
25#define CRVML_REG_MCHBAR 0x44
26#define CRVML_REG_MCHEN 0x54
27#define CRVML_MCHEN_BIT (1 << 28)
28#define CRVML_MCHMAP_SIZE 4096
29#define CRVML_REG_CLOCK 0xc3c
30#define CRVML_CLOCK_SHIFT 8
31#define CRVML_CLOCK_MASK 0x00000f00
32
33static struct pci_dev *mch_dev;
34static u32 mch_bar;
35static void __iomem *mch_regs_base;
36static u32 saved_clock;
37
38static const unsigned crvml_clocks[] = {
39 6750,
40 13500,
41 27000,
42 29700,
43 37125,
44 54000,
45 59400,
46 74250,
47 120000
48 /*
49 * There are more clocks, but they are disabled on the CR board.
50 */
51};
52
53static const u32 crvml_clock_bits[] = {
54 0x0a,
55 0x09,
56 0x08,
57 0x07,
58 0x06,
59 0x05,
60 0x04,
61 0x03,
62 0x0b
63};
64
65static const unsigned crvml_num_clocks = ARRAY_SIZE(crvml_clocks);
66
67static int crvml_sys_restore(struct vml_sys *sys)
68{
69 void __iomem *clock_reg = mch_regs_base + CRVML_REG_CLOCK;
70
71 iowrite32(saved_clock, clock_reg);
72 ioread32(clock_reg);
73
74 return 0;
75}
76
77static int crvml_sys_save(struct vml_sys *sys)
78{
79 void __iomem *clock_reg = mch_regs_base + CRVML_REG_CLOCK;
80
81 saved_clock = ioread32(clock_reg);
82
83 return 0;
84}
85
86static int crvml_nearest_index(const struct vml_sys *sys, int clock)
87{
88 int i;
89 int cur_index = 0;
90 int cur_diff;
91 int diff;
92
93 cur_diff = clock - crvml_clocks[0];
94 cur_diff = (cur_diff < 0) ? -cur_diff : cur_diff;
95 for (i = 1; i < crvml_num_clocks; ++i) {
96 diff = clock - crvml_clocks[i];
97 diff = (diff < 0) ? -diff : diff;
98 if (diff < cur_diff) {
99 cur_index = i;
100 cur_diff = diff;
101 }
102 }
103 return cur_index;
104}
105
106static int crvml_nearest_clock(const struct vml_sys *sys, int clock)
107{
108 return crvml_clocks[crvml_nearest_index(sys, clock)];
109}
110
111static int crvml_set_clock(struct vml_sys *sys, int clock)
112{
113 void __iomem *clock_reg = mch_regs_base + CRVML_REG_CLOCK;
114 int index;
115 u32 clock_val;
116
117 index = crvml_nearest_index(sys, clock);
118
119 if (crvml_clocks[index] != clock)
120 return -EINVAL;
121
122 clock_val = ioread32(clock_reg) & ~CRVML_CLOCK_MASK;
123 clock_val = crvml_clock_bits[index] << CRVML_CLOCK_SHIFT;
124 iowrite32(clock_val, clock_reg);
125 ioread32(clock_reg);
126
127 return 0;
128}
129
130static struct vml_sys cr_pll_ops = {
131 .name = "Carillo Ranch",
132 .save = crvml_sys_save,
133 .restore = crvml_sys_restore,
134 .set_clock = crvml_set_clock,
135 .nearest_clock = crvml_nearest_clock,
136};
137
138static int __init cr_pll_init(void)
139{
140 int err;
141 u32 dev_en;
142
143 mch_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
144 CRVML_DEVICE_MCH, NULL);
145 if (!mch_dev) {
146 printk(KERN_ERR
147 "Could not find Carillo Ranch MCH device.\n");
148 return -ENODEV;
149 }
150
151 pci_read_config_dword(mch_dev, CRVML_REG_MCHEN, &dev_en);
152 if (!(dev_en & CRVML_MCHEN_BIT)) {
153 printk(KERN_ERR
154 "Carillo Ranch MCH device was not enabled.\n");
155 pci_dev_put(mch_dev);
156 return -ENODEV;
157 }
158
159 pci_read_config_dword(mch_dev, CRVML_REG_MCHBAR,
160 &mch_bar);
161 mch_regs_base =
162 ioremap(mch_bar, CRVML_MCHMAP_SIZE);
163 if (!mch_regs_base) {
164 printk(KERN_ERR
165 "Carillo Ranch MCH device was not enabled.\n");
166 pci_dev_put(mch_dev);
167 return -ENODEV;
168 }
169
170 err = vmlfb_register_subsys(&cr_pll_ops);
171 if (err) {
172 printk(KERN_ERR
173 "Carillo Ranch failed to initialize vml_sys.\n");
174 iounmap(mch_regs_base);
175 pci_dev_put(mch_dev);
176 return err;
177 }
178
179 return 0;
180}
181
182static void __exit cr_pll_exit(void)
183{
184 vmlfb_unregister_subsys(&cr_pll_ops);
185
186 iounmap(mch_regs_base);
187 pci_dev_put(mch_dev);
188}
189
190module_init(cr_pll_init);
191module_exit(cr_pll_exit);
192
193MODULE_AUTHOR("Tungsten Graphics Inc.");
194MODULE_DESCRIPTION("Carillo Ranch PLL Driver");
195MODULE_LICENSE("GPL");