viafb: Separate global and fb-specific data
[deliverable/linux.git] / drivers / video / via / via-core.c
CommitLineData
f045f77b
JC
1/*
2 * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved.
3 * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
4 * Copyright 2009 Jonathan Corbet <corbet@lwn.net>
5 */
6
7/*
8 * Core code for the Via multifunction framebuffer device.
9 */
24b4d82e
JC
10#include "via-core.h"
11#include "via_i2c.h"
12#include "global.h"
13
f045f77b
JC
14#include <linux/module.h>
15#include <linux/platform_device.h>
f045f77b
JC
16
17/*
18 * The default port config.
19 */
20static struct via_port_cfg adap_configs[] = {
21 [VIA_PORT_26] = { VIA_PORT_I2C, VIA_MODE_OFF, VIASR, 0x26 },
22 [VIA_PORT_31] = { VIA_PORT_I2C, VIA_MODE_I2C, VIASR, 0x31 },
23 [VIA_PORT_25] = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x25 },
24 [VIA_PORT_2C] = { VIA_PORT_GPIO, VIA_MODE_I2C, VIASR, 0x2c },
25 [VIA_PORT_3D] = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x3d },
26 { 0, 0, 0, 0 }
27};
28
24b4d82e
JC
29/*
30 * We currently only support one viafb device (will there ever be
31 * more than one?), so just declare it globally here.
32 */
33static struct viafb_dev global_dev;
34
35
36/*
37 * Figure out how big our framebuffer memory is. Kind of ugly,
38 * but evidently we can't trust the information found in the
39 * fbdev configuration area.
40 */
41static u16 via_function3[] = {
42 CLE266_FUNCTION3, KM400_FUNCTION3, CN400_FUNCTION3, CN700_FUNCTION3,
43 CX700_FUNCTION3, KM800_FUNCTION3, KM890_FUNCTION3, P4M890_FUNCTION3,
44 P4M900_FUNCTION3, VX800_FUNCTION3, VX855_FUNCTION3,
45};
46
47/* Get the BIOS-configured framebuffer size from PCI configuration space
48 * of function 3 in the respective chipset */
49static int viafb_get_fb_size_from_pci(int chip_type)
50{
51 int i;
52 u8 offset = 0;
53 u32 FBSize;
54 u32 VideoMemSize;
55
56 /* search for the "FUNCTION3" device in this chipset */
57 for (i = 0; i < ARRAY_SIZE(via_function3); i++) {
58 struct pci_dev *pdev;
59
60 pdev = pci_get_device(PCI_VENDOR_ID_VIA, via_function3[i],
61 NULL);
62 if (!pdev)
63 continue;
64
65 DEBUG_MSG(KERN_INFO "Device ID = %x\n", pdev->device);
66
67 switch (pdev->device) {
68 case CLE266_FUNCTION3:
69 case KM400_FUNCTION3:
70 offset = 0xE0;
71 break;
72 case CN400_FUNCTION3:
73 case CN700_FUNCTION3:
74 case CX700_FUNCTION3:
75 case KM800_FUNCTION3:
76 case KM890_FUNCTION3:
77 case P4M890_FUNCTION3:
78 case P4M900_FUNCTION3:
79 case VX800_FUNCTION3:
80 case VX855_FUNCTION3:
81 /*case CN750_FUNCTION3: */
82 offset = 0xA0;
83 break;
84 }
85
86 if (!offset)
87 break;
88
89 pci_read_config_dword(pdev, offset, &FBSize);
90 pci_dev_put(pdev);
91 }
92
93 if (!offset) {
94 printk(KERN_ERR "cannot determine framebuffer size\n");
95 return -EIO;
96 }
97
98 FBSize = FBSize & 0x00007000;
99 DEBUG_MSG(KERN_INFO "FB Size = %x\n", FBSize);
100
101 if (chip_type < UNICHROME_CX700) {
102 switch (FBSize) {
103 case 0x00004000:
104 VideoMemSize = (16 << 20); /*16M */
105 break;
106
107 case 0x00005000:
108 VideoMemSize = (32 << 20); /*32M */
109 break;
110
111 case 0x00006000:
112 VideoMemSize = (64 << 20); /*64M */
113 break;
114
115 default:
116 VideoMemSize = (32 << 20); /*32M */
117 break;
118 }
119 } else {
120 switch (FBSize) {
121 case 0x00001000:
122 VideoMemSize = (8 << 20); /*8M */
123 break;
124
125 case 0x00002000:
126 VideoMemSize = (16 << 20); /*16M */
127 break;
128
129 case 0x00003000:
130 VideoMemSize = (32 << 20); /*32M */
131 break;
132
133 case 0x00004000:
134 VideoMemSize = (64 << 20); /*64M */
135 break;
136
137 case 0x00005000:
138 VideoMemSize = (128 << 20); /*128M */
139 break;
140
141 case 0x00006000:
142 VideoMemSize = (256 << 20); /*256M */
143 break;
144
145 case 0x00007000: /* Only on VX855/875 */
146 VideoMemSize = (512 << 20); /*512M */
147 break;
148
149 default:
150 VideoMemSize = (32 << 20); /*32M */
151 break;
152 }
153 }
154
155 return VideoMemSize;
156}
157
158
159/*
160 * Figure out and map our MMIO regions.
161 */
162static int __devinit via_pci_setup_mmio(struct viafb_dev *vdev)
163{
164 /*
165 * Hook up to the device registers.
166 */
167 vdev->engine_start = pci_resource_start(vdev->pdev, 1);
168 vdev->engine_len = pci_resource_len(vdev->pdev, 1);
169 /* If this fails, others will notice later */
170 vdev->engine_mmio = ioremap_nocache(vdev->engine_start,
171 vdev->engine_len);
172
173 /*
174 * Likewise with I/O memory.
175 */
176 vdev->fbmem_start = pci_resource_start(vdev->pdev, 0);
177 vdev->fbmem_len = viafb_get_fb_size_from_pci(vdev->chip_type);
178 if (vdev->fbmem_len < 0)
179 return vdev->fbmem_len;
180 vdev->fbmem = ioremap_nocache(vdev->fbmem_start, vdev->fbmem_len);
181 if (vdev->fbmem == NULL)
182 return -ENOMEM;
183 return 0;
184}
185
186static void __devexit via_pci_teardown_mmio(struct viafb_dev *vdev)
187{
188 iounmap(vdev->fbmem);
189 iounmap(vdev->engine_mmio);
190}
191
f045f77b
JC
192
193static int __devinit via_pci_probe(struct pci_dev *pdev,
194 const struct pci_device_id *ent)
195{
196 int ret;
197
198 ret = pci_enable_device(pdev);
199 if (ret)
200 return ret;
24b4d82e
JC
201 /*
202 * Global device initialization.
203 */
204 memset(&global_dev, 0, sizeof(global_dev));
205 global_dev.pdev = pdev;
206 global_dev.chip_type = ent->driver_data;
207 spin_lock_init(&global_dev.reg_lock);
208 ret = via_pci_setup_mmio(&global_dev);
209 if (ret)
210 goto out_disable;
f045f77b
JC
211 /*
212 * Create the I2C busses. Bailing out on failure seems extreme,
213 * but that's what the code did before.
214 */
215 ret = viafb_create_i2c_busses(adap_configs);
216 if (ret)
24b4d82e 217 goto out_teardown;
f045f77b
JC
218 /*
219 * Set up the framebuffer.
220 */
24b4d82e 221 ret = via_fb_pci_probe(&global_dev);
f045f77b
JC
222 if (ret)
223 goto out_i2c;
224 return 0;
225
226out_i2c:
227 viafb_delete_i2c_busses();
24b4d82e
JC
228out_teardown:
229 via_pci_teardown_mmio(&global_dev);
f045f77b
JC
230out_disable:
231 pci_disable_device(pdev);
232 return ret;
233}
234
235static void __devexit via_pci_remove(struct pci_dev *pdev)
236{
237 viafb_delete_i2c_busses();
238 via_fb_pci_remove(pdev);
24b4d82e 239 via_pci_teardown_mmio(&global_dev);
f045f77b
JC
240 pci_disable_device(pdev);
241}
242
243
244static struct pci_device_id via_pci_table[] __devinitdata = {
245 { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CLE266_DID),
246 .driver_data = UNICHROME_CLE266 },
247 { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_PM800_DID),
248 .driver_data = UNICHROME_PM800 },
249 { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K400_DID),
250 .driver_data = UNICHROME_K400 },
251 { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K800_DID),
252 .driver_data = UNICHROME_K800 },
253 { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M890_DID),
254 .driver_data = UNICHROME_CN700 },
255 { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K8M890_DID),
256 .driver_data = UNICHROME_K8M890 },
257 { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CX700_DID),
258 .driver_data = UNICHROME_CX700 },
259 { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M900_DID),
260 .driver_data = UNICHROME_P4M900 },
261 { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CN750_DID),
262 .driver_data = UNICHROME_CN750 },
263 { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX800_DID),
264 .driver_data = UNICHROME_VX800 },
265 { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX855_DID),
266 .driver_data = UNICHROME_VX855 },
267 { }
268};
269MODULE_DEVICE_TABLE(pci, via_pci_table);
270
271static struct pci_driver via_driver = {
272 .name = "viafb",
273 .id_table = via_pci_table,
274 .probe = via_pci_probe,
275 .remove = __devexit_p(via_pci_remove),
276};
277
278static int __init via_core_init(void)
279{
280 int ret;
281
282 ret = viafb_init();
283 if (ret)
284 return ret;
285 return pci_register_driver(&via_driver);
286}
287
288static void __exit via_core_exit(void)
289{
290 pci_unregister_driver(&via_driver);
291 viafb_exit();
292}
293
294module_init(via_core_init);
295module_exit(via_core_exit);
This page took 0.034243 seconds and 5 git commands to generate.